1. Identifying Successful Projects

a) Success by category

There are several ways to identify success of a project:

- State (state): Whether a campaign was successful or not - Pledged Amount (pledged) - Achievement Ratio: Create a variable achievement_ratio by calculating the percentage of the original monetary goal reached by the actual amount pledged (that is pledged/goal x 100) - Number of backers (backers_count) - How quickly the goal was reached (difference between launched_at and state_changed_at) for those campaigns that were successful

Use one or more of these measures to visually summarize which categories were most successful in attracting funding on kickstarter. Briefly summarize your findings.

ks <- read_csv("kickstarter_projects_2020_02.csv")
ks %>%
  filter(state != "live") %>%
  group_by(top_category) %>%
  tally(sort = TRUE) %>%
  head()
ks_2 <- ks %>%
  filter(state != "live") %>%
  mutate(state = factor(state, levels = c("successful", "suspended", "canceled", "failed"))) %>%
  mutate(state_cat = case_when(
    state == "successful" ~ "successful",
    TRUE                  ~ "not successful")) %>%
  mutate(state_cat = factor(state_cat, levels = c("successful", "not successful"))) %>%
  mutate(achievement_ratio = pledged/goal*100) %>%
  mutate(deadline_2 = ymd(deadline)) %>%
  mutate(deadline_3 = as.POSIXct(deadline_2, tz = Sys.timezone())) %>%
  mutate(launched_at_2 = ymd(launched_at)) %>%
  mutate(launched_at_3 = as.POSIXct(launched_at_2, tz = Sys.timezone())) %>%
  mutate(state_changed_at_2 = ymd(state_changed_at)) %>%
  mutate(state_changed_at_3 = as.POSIXct(state_changed_at_2, tz = Sys.timezone())) %>%
  mutate(days_to_deadline = as.numeric(difftime(deadline_3, launched_at_3, units = "days")))%>%
  mutate(days_to_change_state = as.numeric(difftime(state_changed_at_3, launched_at_3, units = "days")))%>%
  mutate(funding_days_pct = as.numeric(days_to_change_state)/as.numeric(days_to_deadline)) %>%
  mutate(top_category_2 = case_when(
     top_category == "music"          ~ "music",
     top_category == "film & video"   ~ "film & video",
     top_category == "art"            ~ "art",
     top_category == "publishing"     ~ "publishing",
     top_category == "technology"     ~ "technology",
     top_category == "food"           ~ "food",
     TRUE                             ~ "other")) %>%
  mutate(top_category_2 = factor(top_category_2, levels = c("music", "film & video", "art", "publishing", "technology", "food", "other")))
theme_solar_pretty <- function()
  {
    theme_solarized(base_size = 12, base_family = "Trebuchet MS") %+replace% 
    theme(text = element_text(color = "#586e75"), 
          plot.title = element_text(size = 13, face = "bold", hjust = 0),
          plot.subtitle = element_text(hjust = 0),
          axis.title = element_text(face = "bold"), 
          legend.title = element_text(face = "bold"),
          element_line(size = 0.5, color = "#586e75"), 
          panel.background = element_blank(),
          panel.grid.major.x = element_line(),
          panel.grid.minor.x = element_blank(), 
          panel.grid.major.y = element_line(),
          panel.grid.minor.y = element_blank())
  }
ggplot() + 
  geom_jitter(data = ks_2, aes(x = goal/1000, y = backers_count, color = factor(state)), size = 1) +
  geom_smooth(data = subset(ks_2, state == "successful"), aes(x = goal/1000, y = backers_count), 
              lwd = 1.5, se = FALSE, color = "#586e75") +
  theme_solar_pretty() +
  scale_color_solarized(accent = 'yellow') +
  theme(legend.title = element_blank(), legend.position = "top") +
  scale_x_continuous(labels = function(x) paste0("$", x, "K")) +
  scale_y_continuous(labels = comma) +
  coord_cartesian(xlim = c(0, 1000), ylim = c(0, 50000)) +
  xlab(NULL) +
  ylab("Number of backers\n") +
  labs(title = "Campaign popularity by funding goal", 
       subtitle = "\nA goal less than $2,000 is the most likely to succeed\n", 
       caption = "\nSource: webrobots.io") +
  ggplot2::annotate(geom = "text", x = 1025, y = 40000, label = "Only successful campaigns \nhave a positive corelation ", 
                    hjust = "right", fontface = "bold", size = 4, color = "#586e75")
ks_3 <- ks_2 %>%
  filter(goal <= 10000) %>%
  mutate(goal_cat = cut(goal, breaks = 5, labels = c("20%", "40%", "60%", "80%", "100%"))) %>%
  mutate(state_2 = state) %>%
  mutate(state_2 = factor(state_2, levels = c("suspended", "canceled", "failed", "successful")))
state_levels <- ks_3 %>%
  group_by(state) %>%
  summarise_at(vars(backers_count), sum) %>%
  arrange(desc(backers_count)) %>%
  select(state) %>%
  mutate(state = as.character(state)) %>%
  flatten() %>%
  unlist()
ggplot(ks_3, aes(x = goal_cat, fill = state)) + 
  geom_bar(position = "stack", stat = "count") +
  theme_solar_pretty() +
  scale_fill_solarized(accent = 'yellow') +
  theme(legend.title = element_blank(), legend.position = "top", panel.grid.major.x = element_blank()) +
  scale_x_discrete(labels = c("$10 - $2,000", "$2K - $4K", "$4K - $6K", 
                              "$6K - $8K", "$8K - $10K")) +
  scale_y_continuous(labels = comma) +
  ylab(NULL) +
  xlab(NULL) +
  labs(title = "Campaign success by fundraising goal", 
       subtitle = "\nA goal less than $2,000 is the most likely to succeed\n", 
       caption = "\nSource: webrobots.io")

I have limited the data to campaigns with goals under $10,000. The smaller gthe goal,the more likely a campaign is to succeed. Campaigns with goals under $6,000 are more likely than not to succeed, whereas campaigns with goals over $6,000 are at least 50% likely to fail.

ggplot(data = subset(ks_2, top_category_2 != "other"), aes(fill = state_cat, x = top_category_2)) + 
  geom_bar(position = "dodge", stat = "count") +
  theme_solar_pretty() +
  scale_fill_solarized(accent = 'yellow') +
  theme(legend.title = element_blank(), legend.position = "top", panel.grid.major.x = element_blank()) +
  scale_x_discrete(labels = c("Music", "Film & Video", "Art", 
                              "Publishing", "Technology", "Food", "Other")) +
  scale_y_continuous(labels = comma) +
  ylab(NULL) +
  xlab(NULL) +
  labs(title = "Campaign success vs. failure by topic", 
       subtitle = "\nMusic is the most successful category, food is the least successful\n", 
       caption = "\nSource: webrobots.io")

I have limited the data to campaigns in the 6 most popular categories. Music and publishing campaigns are two times as likely to succeed instead of fail, film + video and art campaigns are slightly more than 50% likely to succeed, and technology and food campaigns are more likely than not to fail.

BONUS ONLY: b) Success by location

Now, use the location information to calculate the total number of successful projects by state (if you are ambitious, normalize by population). Also, identify the Top 50 “innovative” cities in the U.S. (by whatever measure you find plausible). Provide a leaflet map showing the most innovative states and cities in the U.S. on a single map based on these information.

2. Writing your success story

Each project contains a blurb – a short description of the project. While not the full description of the project, the short headline is arguably important for inducing interest in the project (and ultimately popularity and success). Let’s analyze the text.

a) Cleaning the text and word cloud

To reduce the time for analysis, select the 1000 most successful projects and a sample of 1000 unsuccessful projects. Use the cleaning functions introduced in lecture (or write your own in addition) to remove unnecessary words (stop words), syntax, punctuation, numbers, white space etc. Note, that many projects use their own unique brand names in upper cases, so try to remove these fully capitalized words as well (since we are aiming to identify common words across descriptions). Stem the words left over and complete the stems. Create a document-term-matrix.

Provide a word cloud of the most frequent or important words (your choice which frequency measure you choose) among the most successful projects.

In order to create the corpus without splitting and rejoining the original data, I took both the top and bottom 1000 rows based on achievement ratio.

ks_3 <- ks_2 %>%
  mutate(doc_id = id) %>%
  mutate(text = blurb)
ks_4 <- ks_3 %>%
  select(doc_id, text, backers_count, goal, pledged, state, top_category, top_category_2, achievement_ratio, days_to_change_state, funding_days_pct)
ks_top_bottom <- ks_4 %>%
  filter(state != ("canceled")) %>%
  filter(state != ("suspended")) %>%
  arrange(desc(achievement_ratio)) %>%
  filter(!row_number() %in% 001001:116851)
ks_meta <- ks_top_bottom %>%
  select(!text) 
ks_ds <- DataframeSource(ks_top_bottom)
ks_corpus <- VCorpus(ks_ds)

I was unable to reattach the metadata after completing the stems for the corpus text, so I will also created two separate corpuses of the top successful campaigns and a random sample of failed campaigns:

top_s <- ks_4 %>%
  filter(state == "successful") %>%
  top_n(1000, achievement_ratio)
sample_f <- ks_4 %>%
  filter(state == "failed") %>%
  sample_n(1000)
ks_ds_s <- DataframeSource(top_s)
ks_corpus_s <- VCorpus(ks_ds_s)
ks_ds_f <- DataframeSource(sample_f)
ks_corpus_f <- VCorpus(ks_ds_f)
clean_corpus <- function(corpus){
  require(tm)
  require(qdap)
  corpus <- tm_map(corpus, content_transformer(tolower))
  corpus <- tm_map(corpus, content_transformer(replace_abbreviation))
  corpus <- tm_map(corpus, content_transformer(replace_contraction))
  corpus <- tm_map(corpus, content_transformer(replace_symbol))
  corpus <- tm_map(corpus, content_transformer(bracketX))
  corpus <- tm_map(corpus, removeWords, c(stopwords("en")))
  corpus <- tm_map(corpus, removePunctuation)
  corpus <- tm_map(corpus, removeNumbers)
  corpus <- tm_map(corpus, stripWhitespace)
  return(corpus)
  }
ks_corpus_s_clean <- clean_corpus(ks_corpus_s)
ks_corpus_f_clean <- clean_corpus(ks_corpus_f)
ks_corpus_s_clean_stemmed <- tm_map(ks_corpus_s_clean, stemDocument)
ks_corpus_f_clean_stemmed <- tm_map(ks_corpus_f_clean, stemDocument)
stemCompletionBrambor <- function(x, dictionary) {
   x <- unlist(strsplit(as.character(x), " "))
   x <- x[x != ""]
   x <- stemCompletion(x, dictionary = dictionary)
   x <- paste(x, sep = "", collapse = " ")
   PlainTextDocument(stripWhitespace(x))
   }
no_cores <- detectCores() - 1
ks_corpus_s_final <- mclapply(ks_corpus_s_clean_stemmed, stemCompletionBrambor, dictionary = ks_corpus_s_clean, mc.cores = no_cores)
ks_corpus_f_final <- mclapply(ks_corpus_f_clean_stemmed, stemCompletionBrambor, dictionary = ks_corpus_f_clean, mc.cores = no_cores)
ks_corpus_s_final <- as.VCorpus(ks_corpus_s_final)
ks_corpus_f_final <- as.VCorpus(ks_corpus_f_final)
ks_tdm_s <- TermDocumentMatrix(ks_corpus_s_final)
ks_tdm_s_tidy <- tidytext::tidy(ks_tdm_s)
ks_tdm_f <- TermDocumentMatrix(ks_corpus_f_final)
ks_tdm_f_tidy <- tidytext::tidy(ks_tdm_f)
ks_tf_idf_s <- ks_tdm_s_tidy %>%
  bind_tf_idf(term, document, count) %>%
  arrange(desc(tf)) 
wordcloud(ks_tf_idf_s$term, ks_tf_idf_s$tf, max.words = 100, title.bg.colors = "#fdf6e3", colors = "#859900")

b) Success in words

Provide a pyramid plot to show how the words between successful and unsuccessful projects differ in frequency. A selection of 10-20 top words is sufficient here.

Since I was unable to reattach the metadata in Question 1a, I could not create plots for common or different words.

ks_tf_idf_f <- ks_tdm_f_tidy %>%
  bind_tf_idf(term, document, count) %>%
  arrange(desc(tf)) 
wordcloud(ks_tf_idf_f$term, ks_tf_idf_f$tf, max.words = 100, colors = "#cb4b16")

c) Simplicity as a virtue

These blurbs are short in length (max. 150 characters) but let’s see whether brevity and simplicity still matters. Calculate a readability measure (Flesh Reading Ease, Flesh Kincaid or any other comparable measure) for the texts. Visualize the relationship between the readability measure and one of the measures of success. Briefly comment on your finding.

ks_text <- ks_top_bottom %>%
  select(text) %>%
  deframe()
ks_text_vec <- VectorSource(ks_text)
ks_text_corpus <- VCorpus(ks_text_vec)
ks_corpus_q <- corpus(ks_corpus)
ks_corpus_q$backers_count <- ks_meta$backers_count
ks_corpus_q$goal <- ks_meta$goal
ks_corpus_q$pledged <- ks_meta$pledged
ks_corpus_q$state <- ks_meta$state
ks_corpus_q$top_category <- ks_meta$top_category
ks_corpus_q$top_category_2 <- ks_meta$top_category_2
ks_corpus_q$achievement_ratio <- ks_meta$achievement_ratio
ks_corpus_q$days_to_change_state <- ks_meta$days_to_change_state
ks_corpus_q$funding_days_pct <- ks_meta$funding_days_pct
ks_text_name <- ks_top_bottom %>% 
  select(doc_id) %>%
  mutate(doc_id = as.character(doc_id)) %>%
  deframe()
docnames(ks_corpus_q) <- ks_text_name
ks_corpus_q_read <- textstat_readability(ks_corpus_q, measure = 'Flesch.Kincaid')
ks_corpus_q_read_clean <- ks_corpus_q_read %>%
  mutate(fkgl = Flesch.Kincaid) %>%
  select(!Flesch.Kincaid) %>%
  mutate(fkgl_int = as.integer(fkgl + 0.5)) %>%
  mutate(fkgl_cat = cut(fkgl_int, breaks = c(-3, 1, 5, 9, 13, 17, Inf), ordered_result = TRUE, labels = paste("Level", 1:6, sep = " "))) %>%
  mutate(fkgl_cat = case_when(
    fkgl_cat == "Level 1" ~ "No School",
    fkgl_cat == "Level 2" ~ "Elementary School",
    fkgl_cat == "Level 3" ~ "Middle School",
    fkgl_cat == "Level 4" ~ "High School",
    fkgl_cat == "Level 5" ~ "College",
    fkgl_cat == "Level 6" ~ "Graduate School")) %>% 
  mutate(fkgl_cat = ordered(fkgl_cat, levels = c("No School", "Elementary School", "Middle School", "High School", "College", 
                                                "Graduate School"))) %>%
  mutate(fkgl_cat_2 = cut(fkgl_int, breaks = c(-3, 1, 7, 13, 19, Inf), ordered_result = TRUE, labels = paste("Level", 1:5, sep = " "))) %>%
  mutate(fkgl_cat_2 = case_when(
    fkgl_cat_2 == "Level 1" ~ "No School",
    fkgl_cat_2 == "Level 2" ~ "1-6 Years",
    fkgl_cat_2 == "Level 3" ~ "7-12 Years",
    fkgl_cat_2 == "Level 4" ~ "13-18 Years",
    fkgl_cat_2 == "Level 5" ~ "19+ Years")) %>% 
  mutate(fkgl_cat_2 = ordered(fkgl_cat_2, levels = c("No School", "1-6 Years", "1-8 Years", "7-12 Years", "13-18 Years", "19+ Years")))
ks_corpus_q_df <- data_frame(
  document = ks_meta$doc_id,
  backers_count = ks_meta$backers_count,
  goal = ks_meta$goal,
  pledged = ks_meta$pledged,
  state = ks_meta$state,
  top_category = ks_meta$top_category,
  top_category_2 = ks_meta$top_category_2,
  achievement_ratio = ks_meta$achievement_ratio,
  days_to_change_state = ks_meta$days_to_change_state,
  funding_days_pct = ks_meta$funding_days_pct,
  words = ntoken(ks_corpus_q))
ks_corpus_q_df_clean <- ks_corpus_q_df %>%
  mutate(document = as.character(document), 
         backers_count = as.numeric(backers_count),
         goal = as.numeric(goal),
         pledged = as.numeric(pledged),
         achievement_ratio = as.numeric(achievement_ratio),
         days_to_change_state = as.numeric(days_to_change_state),
         funding_days_pct = as.numeric(funding_days_pct),
         words = as.numeric(words)) %>%
  mutate(top_category_2 = factor(top_category_2, levels = c("music", "film & video", "art", "publishing", "technology", "food", "other")))
ks_corpus_fkgl <- inner_join(ks_corpus_q_df_clean, ks_corpus_q_read_clean, by = "document")
ggplot(data = subset(ks_corpus_fkgl, state == "successful"), 
       aes(x = fkgl_cat, y = backers_count, fill = fkgl_cat)) +
  geom_violin(color = "#073642", size = 0.3) +
  theme_solar_pretty() +
  scale_fill_solarized(accent = 'yellow') +
  theme(legend.position = "none", panel.grid.major.x = element_blank()) +
  scale_x_discrete(labels = c("No School", "Elementary\nSchool", "Middle\nSchool", 
                              "High School", "College", "Graduate\nSchool")) +
  scale_y_continuous(labels = comma, limits = c(0,10000)) +
  xlab("\nFlesch-Kinkaid readability score") +
  ylab(NULL) +
  labs(title = "Successful campaign popularity by reading level", 
       subtitle = "\nReading levels with the most backers also have many campaigns with only a few backers\n", 
       caption = "Source: webrobots.io")

I have limited the data to campaigns with fewer than 10,000 backers. Campaigns with reading levels between elementary school and college are more likely to get above 5,000 backers, but a large proportion of these campaigns garner less than 1,000 backers. This pattenr is likely due to the small smaple size of campaigns with very low and very high scores.

state_med_fkgl <- ddply(ks_corpus_fkgl, "state", summarise, med = median(fkgl))
ggplot(ks_corpus_fkgl, aes(x = fkgl, color = state)) + 
  geom_density(size = .75) +
  geom_vline(data = state_med_fkgl, aes(xintercept = med, color = state), linetype = "dashed", size = .75) +
  theme_solar_pretty() +
  scale_colour_solarized(accent = 'yellow') +
  theme(legend.title = element_blank(), legend.position = "top") +
  scale_x_continuous(breaks = c(-3, 0, 3, 6, 9, 12, 15, 18, 21), limits = c(-3, 23)) +
  scale_y_continuous(breaks = c(0, .03, .06, .09)) +
  xlab("\nFlesch-Kinkaid readability score") +
  ylab("Density\n") +
  labs(title = "Successful vs. failed campaigns by reading level",
       subtitle = "\nCampaigns succeed most often with a score between 6 and 10\n",
       caption = "Source: webrobots.io")

The sweet spot for success appears to be a reading level between 6th and 10th grade. Within this boundary, successful campaigns have the greatest density. Slightly outside this boundary on both sides, failed campaigns have the greatest density. Also, the median readability score for successful campaigns is only slightly lower than the median score for failed campaigns.

3. Sentiment

Now, let’s check whether the use of positive/negative words or specific emotions helps a project to be successful.

a) Stay positive

Calculate the tone of each text based on the positive and negative words that are being used. You can rely on the Hu & Liu dictionary provided in lecture or use the Bing dictionary contained in the tidytext package (tidytext::sentiments). Visualize the relationship between tone of the document and success. Briefly comment.

bing_dict <- as.dictionary(get_sentiments("bing"))
bing_dict_ks_dtm <- dfm(ks_corpus_q, dictionary = bing_dict)
bing_dict_ks_df <- melt(as.matrix(bing_dict_ks_dtm)) %>%
  spread(key = features, value = value) %>%
  mutate(document = as.numeric(docs)) %>%
  select(!docs) %>%
  mutate(pos_score = as.integer(positive-negative)) %>%
  mutate(pos_score_cat = as.factor(pos_score)) %>%
  mutate(pos_ratio = (positive+1)/(negative+1)) 
  
ks_corpus_bing <- inner_join(ks_corpus_q_df, bing_dict_ks_df, by = "document")
ggplot(data = ks_corpus_bing, aes(x = pos_score, y = backers_count, color = state)) +
  geom_jitter() +
  xlim(-3.5, 4.5) +
  theme_solar_pretty() +
  scale_color_solarized(accent = 'yellow') +
  theme(legend.position = "none", panel.grid.major.x = element_blank()) +
  scale_y_continuous(labels = comma, limits = c(0, 10000)) +
  xlab("\nBing positivity score") +
  ylab("Number of backers\n") +
  labs(title = "Campaign popularity by positivity", 
       subtitle = "\nNeutral and slightly positive cmapaigns are the most successful\n", 
       caption = "Source: webrobots.io")

I have limited the data to campaigns with fewer than 10,000 backers. Campaigns with positivity scores between 0 and 2 are the most likely to have more than 5,000 backers.

ggplot(data = ks_corpus_bing, aes(x = pos_score, color = state)) +
  geom_density(size = .75) +
  xlim(-4, 6) +
  theme_solar_pretty() +
  scale_color_solarized(accent = 'yellow') +
  theme(legend.title = element_blank(), legend.position = "top") +
  scale_y_continuous(breaks = c(0, .2, .4, .6, .8)) +
  xlab("\nBing positivity score") +
  ylab("Density\n") +
  labs(title = "Successful vs. failed campaigns by positivity",
       subtitle = "\n...\n",
       caption = "Source: webrobots.io")

Campaigns on the extremes of the positivity scale (very positive or negative) have a higher success rate than campaigns with neutral or slightly positive scores. This suggests that campaign blurbs with emotive language do better than those with a more flat affect.

b) Positive vs. negative

Segregate all 2,000 blurbs into positive and negative texts based on their polarity score calculated in step (a). Now, collapse the positive and negative texts into two larger documents. Create a document-term-matrix based on this collapsed set of two documents. Generate a comparison cloud showing the most-frequent positive and negative words.

ks_corpus_bing <- ks_corpus_bing %>%
  mutate(sent_cat = case_when(
    pos_ratio >= 1 ~ "positive",
    TRUE           ~ "negative"))
ks_docs_pos <- ks_corpus_bing %>%
  filter(sent_cat == "positive") %>%
  mutate(doc_id = document) %>%
  select(doc_id)
ks_docs_neg <- ks_corpus_bing %>%
  filter(sent_cat == "negative") %>%
  mutate(doc_id = document) %>%
  select(doc_id)
ks_pos <- inner_join(ks_docs_pos, ks_top_bottom, key = doc_id)
ks_neg <- inner_join(ks_docs_neg, ks_top_bottom, key = doc_id)
ks_ds_pos <- DataframeSource(ks_pos)
ks_corpus_pos <- VCorpus(ks_ds_pos)
ks_ds_neg <- DataframeSource(ks_neg)
ks_corpus_neg <- VCorpus(ks_ds_neg)
ks_corpus_pos_clean <- clean_corpus(ks_corpus_pos)
no_cores <- detectCores() - 1
ks_corpus_pos_final <- mclapply(ks_corpus_pos_clean_stemmed, stemCompletionBrambor, dictionary = ks_corpus_pos_clean, mc.cores = no_cores)
ks_corpus_pos_final <- as.VCorpus(ks_corpus_pos_final)
ks_corpus_neg_final <- as.VCorpus(ks_corpus_neg_final)
ks_tdm_pos <- TermDocumentMatrix(ks_corpus_pos_final)
ks_tdm_pos_tidy <- tidytext::tidy(ks_tdm_pos)
ks_tdm_neg <- TermDocumentMatrix(ks_corpus_neg_final)
ks_tdm_neg_tidy <- tidytext::tidy(ks_tdm_neg)
ks_tf_idf_pos <- ks_tdm_pos_tidy %>%
  bind_tf_idf(term, document, count) %>%
  arrange(desc(tf)) 
wordcloud(ks_tf_idf_pos$term, ks_tf_idf_pos$tf, max.words = 100, colors = "#b58900")

ks_tf_idf_neg <- ks_tdm_neg_tidy %>%
  bind_tf_idf(term, document, count) %>%
  arrange(desc(tf)) 
wordcloud(ks_tf_idf_neg$term, ks_tf_idf_neg$tf, max.words = 100, colors = "#268bd2")

c) Get in their mind

Now, use the NRC Word-Emotion Association Lexicon in the tidytext package to identify a larger set of emotions (anger, anticipation, disgust, fear, joy, sadness, surprise, trust). Again, visualize the relationship between the use of words from these categories and success. What is your finding?

nrc_dict <- as.dictionary(get_sentiments("nrc"))
nrc_dict_ks_dtm <- dfm(ks_corpus_q, dictionary = nrc_dict)
nrc_dict_ks_df <- melt(as.matrix(nrc_dict_ks_dtm)) %>%
  spread(key = features, value = value) %>%
  mutate(document = as.numeric(docs)) %>%
  select(!docs) %>%
  mutate(sent_score = anger + anticipation + disgust + fear + joy + sadness + surprise + trust)
ks_corpus_nrc <- inner_join(ks_corpus_q_df, nrc_dict_ks_df, by = "document")
ggplot(data = ks_corpus_nrc, aes(x = anticipation, color = state)) +
  geom_density(size = .75) +
  xlim(0,4) +
  ylim(0,1.6) +
  theme_solar_pretty() +
  scale_color_solarized(accent = 'yellow') +
  theme(legend.title = element_blank(), legend.position = "top") +
  xlab("\nNRC anticipation score") +
  ylab("Density\n") +
  labs(title = "Successful vs. failed campaigns by anticipation",
       subtitle = "\n...\n",
       caption = "Source: webrobots.io")

ggplot(data = ks_corpus_nrc, aes(x = joy, color = state)) +
  geom_density(size = .75) +
  xlim(0,4) +
  ylim(0,1.6) +
  theme_solar_pretty() +
  scale_color_solarized(accent = 'yellow') +
  theme(legend.title = element_blank(), legend.position = "top") +
  xlab("\nNRC joy score") +
  ylab("Density\n") +
  labs(title = "Successful vs. failed campaigns by joy",
       subtitle = "\n...\n",
       caption = "Source: webrobots.io")

ggplot(data = ks_corpus_nrc, aes(x = trust, color = state)) +
  geom_density(size = .75) +
  xlim(0,4) +
  ylim(0,1.6) +
  theme_solar_pretty() +
  scale_color_solarized(accent = 'yellow') +
  theme(legend.title = element_blank(), legend.position = "top") +
  xlab("\nNRC trust score") +
  ylab("Density\n") +
  labs(title = "Successful vs. failed campaigns by trust",
       subtitle = "\n...\n",
       caption = "Source: webrobots.io")

I limited the data to campaigns with emotion scores less than 4. I looked at anticipation, joy, and trust, which I consider the most likely to inspire support for Kickstarter campaigns. However, for each emotion, campaigns with low scores are more likely to succeed, whereas those with higher scores were more likely to fail.

ggplot(data = ks_corpus_nrc, aes(x = sent_score, color = state)) +
  geom_density(size = .75) +
  xlim(0,20) +
  theme_solar_pretty() +
  scale_color_solarized(accent = 'yellow') +
  theme(legend.title = element_blank(), legend.position = "top") +
  xlab("\nNRC total sentiment score") +
  ylab("Density\n") +
  labs(title = "Successful vs. failed campaigns by all emotions",
       subtitle = "\n...\n",
       caption = "Source: webrobots.io")

I then combined the scores for all emotions into a single “emotive” score. Campaigns with lower scores for any emotion are the most likely to be successful. The sweet spot appears to be scores between 0 and 3.

LS0tCnRpdGxlOiAiSG9tZXdvcmsgMzogS2lja3N0YXJ0ZXIiCmF1dGhvcjogIkFsaXNvbiBSeWxhbmQiCmRhdGU6ICJBcHJpbCAyMCwgMjAyMCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3IgU2V0dXAsIGluY2x1ZGUgPSBGQUxTRSwgcmVzdWx0cyA9ICdoaWRlJywgd2FybmluZyA9IEZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHBhY21hbikKCnBfbG9hZCh0aWR5dmVyc2UsIGx1YnJpZGF0ZSwgZ2dwbG90MiwgZ2d0aGVtZXMsIHRtLCBxZGFwLCBxdWFudGVkYSwgU25vd2JhbGxDLCBwYXJhbGxlbCwgTkxQLCB0aWR5dGV4dCwgd29yZGNsb3VkLCBwbG90cml4LCBSQ29sb3JCcmV3ZXIsIHBseXIsIGZvcmNhdHMsIGV4dHJhZm9udCwgc2NhbGVzLCByZXNoYXBlMiwgc3RyaW5nciwgdGV4dGRhdGEpCmBgYAoKIyMgMS4gSWRlbnRpZnlpbmcgU3VjY2Vzc2Z1bCBQcm9qZWN0cwoKIyMjIGEpIFN1Y2Nlc3MgYnkgY2F0ZWdvcnkKCipUaGVyZSBhcmUgc2V2ZXJhbCB3YXlzIHRvIGlkZW50aWZ5IHN1Y2Nlc3Mgb2YgYSBwcm9qZWN0OioKCiotIFN0YXRlIChzdGF0ZSk6IFdoZXRoZXIgYSBjYW1wYWlnbiB3YXMgc3VjY2Vzc2Z1bCBvciBub3QqCiotIFBsZWRnZWQgQW1vdW50IChwbGVkZ2VkKSoKKi0gQWNoaWV2ZW1lbnQgUmF0aW86IENyZWF0ZSBhIHZhcmlhYmxlIGFjaGlldmVtZW50X3JhdGlvIGJ5IGNhbGN1bGF0aW5nIHRoZSBwZXJjZW50YWdlIG9mIHRoZSBvcmlnaW5hbCBtb25ldGFyeSBnb2FsIHJlYWNoZWQgYnkgdGhlIGFjdHVhbCBhbW91bnQgcGxlZGdlZCAodGhhdCBpcyBwbGVkZ2VkL2dvYWwgeCAxMDApKgoqLSBOdW1iZXIgb2YgYmFja2VycyAoYmFja2Vyc19jb3VudCkqCiotIEhvdyBxdWlja2x5IHRoZSBnb2FsIHdhcyByZWFjaGVkIChkaWZmZXJlbmNlIGJldHdlZW4gbGF1bmNoZWRfYXQgYW5kIHN0YXRlX2NoYW5nZWRfYXQpIGZvciB0aG9zZSBjYW1wYWlnbnMgdGhhdCB3ZXJlIHN1Y2Nlc3NmdWwqCgoqVXNlIG9uZSBvciBtb3JlIG9mIHRoZXNlIG1lYXN1cmVzIHRvIHZpc3VhbGx5IHN1bW1hcml6ZSB3aGljaCBjYXRlZ29yaWVzIHdlcmUgbW9zdCBzdWNjZXNzZnVsIGluIGF0dHJhY3RpbmcgZnVuZGluZyBvbiBraWNrc3RhcnRlci4gQnJpZWZseSBzdW1tYXJpemUgeW91ciBmaW5kaW5ncy4qCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCByZXN1bHQgPSAnaGlkZSd9CmtzIDwtIHJlYWRfY3N2KCJraWNrc3RhcnRlcl9wcm9qZWN0c18yMDIwXzAyLmNzdiIpCmBgYAoKYGBge3IsIHJlc3VsdCA9ICdoaWRlJ30Ka3MgJT4lCiAgZmlsdGVyKHN0YXRlICE9ICJsaXZlIikgJT4lCiAgZ3JvdXBfYnkodG9wX2NhdGVnb3J5KSAlPiUKICB0YWxseShzb3J0ID0gVFJVRSkgJT4lCiAgaGVhZCgpCmBgYAoKYGBge3J9CmtzXzIgPC0ga3MgJT4lCiAgZmlsdGVyKHN0YXRlICE9ICJsaXZlIikgJT4lCiAgbXV0YXRlKHN0YXRlID0gZmFjdG9yKHN0YXRlLCBsZXZlbHMgPSBjKCJzdWNjZXNzZnVsIiwgInN1c3BlbmRlZCIsICJjYW5jZWxlZCIsICJmYWlsZWQiKSkpICU+JQogIG11dGF0ZShzdGF0ZV9jYXQgPSBjYXNlX3doZW4oCiAgICBzdGF0ZSA9PSAic3VjY2Vzc2Z1bCIgfiAic3VjY2Vzc2Z1bCIsCiAgICBUUlVFICAgICAgICAgICAgICAgICAgfiAibm90IHN1Y2Nlc3NmdWwiKSkgJT4lCiAgbXV0YXRlKHN0YXRlX2NhdCA9IGZhY3RvcihzdGF0ZV9jYXQsIGxldmVscyA9IGMoInN1Y2Nlc3NmdWwiLCAibm90IHN1Y2Nlc3NmdWwiKSkpICU+JQogIG11dGF0ZShhY2hpZXZlbWVudF9yYXRpbyA9IHBsZWRnZWQvZ29hbCoxMDApICU+JQogIG11dGF0ZShkZWFkbGluZV8yID0geW1kKGRlYWRsaW5lKSkgJT4lCiAgbXV0YXRlKGRlYWRsaW5lXzMgPSBhcy5QT1NJWGN0KGRlYWRsaW5lXzIsIHR6ID0gU3lzLnRpbWV6b25lKCkpKSAlPiUKICBtdXRhdGUobGF1bmNoZWRfYXRfMiA9IHltZChsYXVuY2hlZF9hdCkpICU+JQogIG11dGF0ZShsYXVuY2hlZF9hdF8zID0gYXMuUE9TSVhjdChsYXVuY2hlZF9hdF8yLCB0eiA9IFN5cy50aW1lem9uZSgpKSkgJT4lCiAgbXV0YXRlKHN0YXRlX2NoYW5nZWRfYXRfMiA9IHltZChzdGF0ZV9jaGFuZ2VkX2F0KSkgJT4lCiAgbXV0YXRlKHN0YXRlX2NoYW5nZWRfYXRfMyA9IGFzLlBPU0lYY3Qoc3RhdGVfY2hhbmdlZF9hdF8yLCB0eiA9IFN5cy50aW1lem9uZSgpKSkgJT4lCiAgbXV0YXRlKGRheXNfdG9fZGVhZGxpbmUgPSBhcy5udW1lcmljKGRpZmZ0aW1lKGRlYWRsaW5lXzMsIGxhdW5jaGVkX2F0XzMsIHVuaXRzID0gImRheXMiKSkpJT4lCiAgbXV0YXRlKGRheXNfdG9fY2hhbmdlX3N0YXRlID0gYXMubnVtZXJpYyhkaWZmdGltZShzdGF0ZV9jaGFuZ2VkX2F0XzMsIGxhdW5jaGVkX2F0XzMsIHVuaXRzID0gImRheXMiKSkpJT4lCiAgbXV0YXRlKGZ1bmRpbmdfZGF5c19wY3QgPSBhcy5udW1lcmljKGRheXNfdG9fY2hhbmdlX3N0YXRlKS9hcy5udW1lcmljKGRheXNfdG9fZGVhZGxpbmUpKSAlPiUKICBtdXRhdGUodG9wX2NhdGVnb3J5XzIgPSBjYXNlX3doZW4oCiAgICAgdG9wX2NhdGVnb3J5ID09ICJtdXNpYyIgICAgICAgICAgfiAibXVzaWMiLAogICAgIHRvcF9jYXRlZ29yeSA9PSAiZmlsbSAmIHZpZGVvIiAgIH4gImZpbG0gJiB2aWRlbyIsCiAgICAgdG9wX2NhdGVnb3J5ID09ICJhcnQiICAgICAgICAgICAgfiAiYXJ0IiwKICAgICB0b3BfY2F0ZWdvcnkgPT0gInB1Ymxpc2hpbmciICAgICB+ICJwdWJsaXNoaW5nIiwKICAgICB0b3BfY2F0ZWdvcnkgPT0gInRlY2hub2xvZ3kiICAgICB+ICJ0ZWNobm9sb2d5IiwKICAgICB0b3BfY2F0ZWdvcnkgPT0gImZvb2QiICAgICAgICAgICB+ICJmb29kIiwKICAgICBUUlVFICAgICAgICAgICAgICAgICAgICAgICAgICAgICB+ICJvdGhlciIpKSAlPiUKICBtdXRhdGUodG9wX2NhdGVnb3J5XzIgPSBmYWN0b3IodG9wX2NhdGVnb3J5XzIsIGxldmVscyA9IGMoIm11c2ljIiwgImZpbG0gJiB2aWRlbyIsICJhcnQiLCAicHVibGlzaGluZyIsICJ0ZWNobm9sb2d5IiwgImZvb2QiLCAib3RoZXIiKSkpCmBgYAoKYGBge3J9CnRoZW1lX3NvbGFyX3ByZXR0eSA8LSBmdW5jdGlvbigpCiAgewogICAgdGhlbWVfc29sYXJpemVkKGJhc2Vfc2l6ZSA9IDEyLCBiYXNlX2ZhbWlseSA9ICJUcmVidWNoZXQgTVMiKSAlK3JlcGxhY2UlIAogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjNTg2ZTc1IiksIAogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMCksCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwKICAgICAgICAgIGVsZW1lbnRfbGluZShzaXplID0gMC41LCBjb2xvciA9ICIjNTg2ZTc1IiksIAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZSgpLAogICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZSgpLAogICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpKQogIH0KYGBgCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CmdncGxvdCgpICsgCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGtzXzIsIGFlcyh4ID0gZ29hbC8xMDAwLCB5ID0gYmFja2Vyc19jb3VudCwgY29sb3IgPSBmYWN0b3Ioc3RhdGUpKSwgc2l6ZSA9IDEpICsKICBnZW9tX3Ntb290aChkYXRhID0gc3Vic2V0KGtzXzIsIHN0YXRlID09ICJzdWNjZXNzZnVsIiksIGFlcyh4ID0gZ29hbC8xMDAwLCB5ID0gYmFja2Vyc19jb3VudCksIAogICAgICAgICAgICAgIGx3ZCA9IDEuNSwgc2UgPSBGQUxTRSwgY29sb3IgPSAiIzU4NmU3NSIpICsKICB0aGVtZV9zb2xhcl9wcmV0dHkoKSArCiAgc2NhbGVfY29sb3Jfc29sYXJpemVkKGFjY2VudCA9ICd5ZWxsb3cnKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBmdW5jdGlvbih4KSBwYXN0ZTAoIiQiLCB4LCAiSyIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDEwMDApLCB5bGltID0gYygwLCA1MDAwMCkpICsKICB4bGFiKE5VTEwpICsKICB5bGFiKCJOdW1iZXIgb2YgYmFja2Vyc1xuIikgKwogIGxhYnModGl0bGUgPSAiQ2FtcGFpZ24gcG9wdWxhcml0eSBieSBmdW5kaW5nIGdvYWwiLCAKICAgICAgIHN1YnRpdGxlID0gIlxuQSBnb2FsIGxlc3MgdGhhbiAkMiwwMDAgaXMgdGhlIG1vc3QgbGlrZWx5IHRvIHN1Y2NlZWRcbiIsIAogICAgICAgY2FwdGlvbiA9ICJcblNvdXJjZTogd2Vicm9ib3RzLmlvIikgKwogIGdncGxvdDI6OmFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSAxMDI1LCB5ID0gNDAwMDAsIGxhYmVsID0gIk9ubHkgc3VjY2Vzc2Z1bCBjYW1wYWlnbnMgXG5oYXZlIGEgcG9zaXRpdmUgY29yZWxhdGlvbiAiLCAKICAgICAgICAgICAgICAgICAgICBoanVzdCA9ICJyaWdodCIsIGZvbnRmYWNlID0gImJvbGQiLCBzaXplID0gNCwgY29sb3IgPSAiIzU4NmU3NSIpCmBgYAoKYGBge3J9CmtzXzMgPC0ga3NfMiAlPiUKICBmaWx0ZXIoZ29hbCA8PSAxMDAwMCkgJT4lCiAgbXV0YXRlKGdvYWxfY2F0ID0gY3V0KGdvYWwsIGJyZWFrcyA9IDUsIGxhYmVscyA9IGMoIjIwJSIsICI0MCUiLCAiNjAlIiwgIjgwJSIsICIxMDAlIikpKSAlPiUKICBtdXRhdGUoc3RhdGVfMiA9IHN0YXRlKSAlPiUKICBtdXRhdGUoc3RhdGVfMiA9IGZhY3RvcihzdGF0ZV8yLCBsZXZlbHMgPSBjKCJzdXNwZW5kZWQiLCAiY2FuY2VsZWQiLCAiZmFpbGVkIiwgInN1Y2Nlc3NmdWwiKSkpCgpzdGF0ZV9sZXZlbHMgPC0ga3NfMyAlPiUKICBncm91cF9ieShzdGF0ZSkgJT4lCiAgc3VtbWFyaXNlX2F0KHZhcnMoYmFja2Vyc19jb3VudCksIHN1bSkgJT4lCiAgYXJyYW5nZShkZXNjKGJhY2tlcnNfY291bnQpKSAlPiUKICBzZWxlY3Qoc3RhdGUpICU+JQogIG11dGF0ZShzdGF0ZSA9IGFzLmNoYXJhY3RlcihzdGF0ZSkpICU+JQogIGZsYXR0ZW4oKSAlPiUKICB1bmxpc3QoKQpgYGAKCmBgYHtyfQpnZ3Bsb3Qoa3NfMywgYWVzKHggPSBnb2FsX2NhdCwgZmlsbCA9IHN0YXRlKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIsIHN0YXQgPSAiY291bnQiKSArCiAgdGhlbWVfc29sYXJfcHJldHR5KCkgKwogIHNjYWxlX2ZpbGxfc29sYXJpemVkKGFjY2VudCA9ICd5ZWxsb3cnKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBjKCIkMTAgLSAkMiwwMDAiLCAiJDJLIC0gJDRLIiwgIiQ0SyAtICQ2SyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiJDZLIC0gJDhLIiwgIiQ4SyAtICQxMEsiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIHlsYWIoTlVMTCkgKwogIHhsYWIoTlVMTCkgKwogIGxhYnModGl0bGUgPSAiQ2FtcGFpZ24gc3VjY2VzcyBieSBmdW5kcmFpc2luZyBnb2FsIiwgCiAgICAgICBzdWJ0aXRsZSA9ICJcblNtYWxsZXIgZ29hbHMgaGF2ZSBhIGdyZWF0ZXIgY2hhbmNlIG9mIHN1Y2Nlc3NcbiIsIAogICAgICAgY2FwdGlvbiA9ICJcblNvdXJjZTogd2Vicm9ib3RzLmlvIikKYGBgCgpJIGhhdmUgbGltaXRlZCB0aGUgZGF0YSB0byBjYW1wYWlnbnMgd2l0aCBnb2FscyB1bmRlciBgJGAxMCwwMDAuIFRoZSBzbWFsbGVyIGd0aGUgZ29hbCx0aGUgbW9yZSBsaWtlbHkgYSBjYW1wYWlnbiBpcyB0byBzdWNjZWVkLiBDYW1wYWlnbnMgd2l0aCBnb2FscyB1bmRlciBgJGA2LDAwMCBhcmUgbW9yZSBsaWtlbHkgdGhhbiBub3QgdG8gc3VjY2VlZCwgd2hlcmVhcyBjYW1wYWlnbnMgd2l0aCBnb2FscyBvdmVyIGAkYDYsMDAwIGFyZSBhdCBsZWFzdCA1MCUgbGlrZWx5IHRvIGZhaWwuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBzdWJzZXQoa3NfMiwgdG9wX2NhdGVnb3J5XzIgIT0gIm90aGVyIiksIGFlcyhmaWxsID0gc3RhdGVfY2F0LCB4ID0gdG9wX2NhdGVnb3J5XzIpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdCA9ICJjb3VudCIpICsKICB0aGVtZV9zb2xhcl9wcmV0dHkoKSArCiAgc2NhbGVfZmlsbF9zb2xhcml6ZWQoYWNjZW50ID0gJ3llbGxvdycpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIk11c2ljIiwgIkZpbG0gJiBWaWRlbyIsICJBcnQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlB1Ymxpc2hpbmciLCAiVGVjaG5vbG9neSIsICJGb29kIiwgIk90aGVyIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsKICB5bGFiKE5VTEwpICsKICB4bGFiKE5VTEwpICsKICBsYWJzKHRpdGxlID0gIkNhbXBhaWduIHN1Y2Nlc3MgdnMuIGZhaWx1cmUgYnkgdG9waWMiLCAKICAgICAgIHN1YnRpdGxlID0gIlxuTXVzaWMgaXMgdGhlIG1vc3Qgc3VjY2Vzc2Z1bCBjYXRlZ29yeSwgZm9vZCBpcyB0aGUgbGVhc3Qgc3VjY2Vzc2Z1bFxuIiwgCiAgICAgICBjYXB0aW9uID0gIlxuU291cmNlOiB3ZWJyb2JvdHMuaW8iKQpgYGAKCkkgaGF2ZSBsaW1pdGVkIHRoZSBkYXRhIHRvIGNhbXBhaWducyBpbiB0aGUgNiBtb3N0IHBvcHVsYXIgY2F0ZWdvcmllcy4gTXVzaWMgYW5kIHB1Ymxpc2hpbmcgY2FtcGFpZ25zIGFyZSB0d28gdGltZXMgYXMgbGlrZWx5IHRvIHN1Y2NlZWQgaW5zdGVhZCBvZiBmYWlsLCBmaWxtICsgdmlkZW8gYW5kIGFydCBjYW1wYWlnbnMgYXJlIHNsaWdodGx5IG1vcmUgdGhhbiA1MCUgbGlrZWx5IHRvIHN1Y2NlZWQsIGFuZCB0ZWNobm9sb2d5IGFuZCBmb29kIGNhbXBhaWducyBhcmUgbW9yZSBsaWtlbHkgdGhhbiBub3QgdG8gZmFpbC4KCiMjIyBCT05VUyBPTkxZOiBiKSBTdWNjZXNzIGJ5IGxvY2F0aW9uCgoqTm93LCB1c2UgdGhlIGxvY2F0aW9uIGluZm9ybWF0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIHN1Y2Nlc3NmdWwgcHJvamVjdHMgYnkgc3RhdGUgKGlmIHlvdSBhcmUgYW1iaXRpb3VzLCBub3JtYWxpemUgYnkgcG9wdWxhdGlvbikuIEFsc28sIGlkZW50aWZ5IHRoZSBUb3AgNTAg4oCcaW5ub3ZhdGl2ZeKAnSBjaXRpZXMgaW4gdGhlIFUuUy4gKGJ5IHdoYXRldmVyIG1lYXN1cmUgeW91IGZpbmQgcGxhdXNpYmxlKS4gUHJvdmlkZSBhIGxlYWZsZXQgbWFwIHNob3dpbmcgdGhlIG1vc3QgaW5ub3ZhdGl2ZSBzdGF0ZXMgYW5kIGNpdGllcyBpbiB0aGUgVS5TLiBvbiBhIHNpbmdsZSBtYXAgYmFzZWQgb24gdGhlc2UgaW5mb3JtYXRpb24uKgoKCiMjIDIuIFdyaXRpbmcgeW91ciBzdWNjZXNzIHN0b3J5CgoqRWFjaCBwcm9qZWN0IGNvbnRhaW5zIGEgYmx1cmIg4oCTIGEgc2hvcnQgZGVzY3JpcHRpb24gb2YgdGhlIHByb2plY3QuIFdoaWxlIG5vdCB0aGUgZnVsbCBkZXNjcmlwdGlvbiBvZiB0aGUgcHJvamVjdCwgdGhlIHNob3J0IGhlYWRsaW5lIGlzIGFyZ3VhYmx5IGltcG9ydGFudCBmb3IgaW5kdWNpbmcgaW50ZXJlc3QgaW4gdGhlIHByb2plY3QgKGFuZCB1bHRpbWF0ZWx5IHBvcHVsYXJpdHkgYW5kIHN1Y2Nlc3MpLiBMZXTigJlzIGFuYWx5emUgdGhlIHRleHQuKgoKIyMjIGEpIENsZWFuaW5nIHRoZSB0ZXh0IGFuZCB3b3JkIGNsb3VkCgoqVG8gcmVkdWNlIHRoZSB0aW1lIGZvciBhbmFseXNpcywgc2VsZWN0IHRoZSAxMDAwIG1vc3Qgc3VjY2Vzc2Z1bCBwcm9qZWN0cyBhbmQgYSBzYW1wbGUgb2YgMTAwMCB1bnN1Y2Nlc3NmdWwgcHJvamVjdHMuIFVzZSB0aGUgY2xlYW5pbmcgZnVuY3Rpb25zIGludHJvZHVjZWQgaW4gbGVjdHVyZSAob3Igd3JpdGUgeW91ciBvd24gaW4gYWRkaXRpb24pIHRvIHJlbW92ZSB1bm5lY2Vzc2FyeSB3b3JkcyAoc3RvcCB3b3JkcyksIHN5bnRheCwgcHVuY3R1YXRpb24sIG51bWJlcnMsIHdoaXRlIHNwYWNlIGV0Yy4gTm90ZSwgdGhhdCBtYW55IHByb2plY3RzIHVzZSB0aGVpciBvd24gdW5pcXVlIGJyYW5kIG5hbWVzIGluIHVwcGVyIGNhc2VzLCBzbyB0cnkgdG8gcmVtb3ZlIHRoZXNlIGZ1bGx5IGNhcGl0YWxpemVkIHdvcmRzIGFzIHdlbGwgKHNpbmNlIHdlIGFyZSBhaW1pbmcgdG8gaWRlbnRpZnkgY29tbW9uIHdvcmRzIGFjcm9zcyBkZXNjcmlwdGlvbnMpLiBTdGVtIHRoZSB3b3JkcyBsZWZ0IG92ZXIgYW5kIGNvbXBsZXRlIHRoZSBzdGVtcy4gQ3JlYXRlIGEgZG9jdW1lbnQtdGVybS1tYXRyaXguKgoKKlByb3ZpZGUgYSB3b3JkIGNsb3VkIG9mIHRoZSBtb3N0IGZyZXF1ZW50IG9yIGltcG9ydGFudCB3b3JkcyAoeW91ciBjaG9pY2Ugd2hpY2ggZnJlcXVlbmN5IG1lYXN1cmUgeW91IGNob29zZSkgYW1vbmcgdGhlIG1vc3Qgc3VjY2Vzc2Z1bCBwcm9qZWN0cy4qCgpJbiBvcmRlciB0byBjcmVhdGUgdGhlIGNvcnB1cyB3aXRob3V0IHNwbGl0dGluZyBhbmQgcmVqb2luaW5nIHRoZSBvcmlnaW5hbCBkYXRhLCBJIHRvb2sgYm90aCB0aGUgdG9wIGFuZCBib3R0b20gMTAwMCByb3dzIGJhc2VkIG9uIGFjaGlldmVtZW50IHJhdGlvLgoKYGBge3J9CmtzXzMgPC0ga3NfMiAlPiUKICBtdXRhdGUoZG9jX2lkID0gaWQpICU+JQogIG11dGF0ZSh0ZXh0ID0gYmx1cmIpCgprc180IDwtIGtzXzMgJT4lCiAgc2VsZWN0KGRvY19pZCwgdGV4dCwgYmFja2Vyc19jb3VudCwgZ29hbCwgcGxlZGdlZCwgc3RhdGUsIHRvcF9jYXRlZ29yeSwgdG9wX2NhdGVnb3J5XzIsIGFjaGlldmVtZW50X3JhdGlvLCBkYXlzX3RvX2NoYW5nZV9zdGF0ZSwgZnVuZGluZ19kYXlzX3BjdCkKCmtzX3RvcF9ib3R0b20gPC0ga3NfNCAlPiUKICBmaWx0ZXIoc3RhdGUgIT0gKCJjYW5jZWxlZCIpKSAlPiUKICBmaWx0ZXIoc3RhdGUgIT0gKCJzdXNwZW5kZWQiKSkgJT4lCiAgYXJyYW5nZShkZXNjKGFjaGlldmVtZW50X3JhdGlvKSkgJT4lCiAgZmlsdGVyKCFyb3dfbnVtYmVyKCkgJWluJSAwMDEwMDE6MTE2ODUxKQoKa3NfbWV0YSA8LSBrc190b3BfYm90dG9tICU+JQogIHNlbGVjdCghdGV4dCkgCgprc19kcyA8LSBEYXRhZnJhbWVTb3VyY2Uoa3NfdG9wX2JvdHRvbSkKa3NfY29ycHVzIDwtIFZDb3JwdXMoa3NfZHMpCmBgYAoKSSB3YXMgdW5hYmxlIHRvIHJlYXR0YWNoIHRoZSBtZXRhZGF0YSBhZnRlciBjb21wbGV0aW5nIHRoZSBzdGVtcyBmb3IgdGhlIGNvcnB1cyB0ZXh0LCBzbyBJIHdpbGwgYWxzbyBjcmVhdGVkIHR3byBzZXBhcmF0ZSBjb3JwdXNlcyBvZiB0aGUgdG9wIHN1Y2Nlc3NmdWwgY2FtcGFpZ25zIGFuZCBhIHJhbmRvbSBzYW1wbGUgb2YgZmFpbGVkIGNhbXBhaWduczoKCmBgYHtyfQp0b3BfcyA8LSBrc180ICU+JQogIGZpbHRlcihzdGF0ZSA9PSAic3VjY2Vzc2Z1bCIpICU+JQogIHRvcF9uKDEwMDAsIGFjaGlldmVtZW50X3JhdGlvKQoKc2FtcGxlX2YgPC0ga3NfNCAlPiUKICBmaWx0ZXIoc3RhdGUgPT0gImZhaWxlZCIpICU+JQogIHNhbXBsZV9uKDEwMDApCgprc19kc19zIDwtIERhdGFmcmFtZVNvdXJjZSh0b3BfcykKa3NfY29ycHVzX3MgPC0gVkNvcnB1cyhrc19kc19zKQoKa3NfZHNfZiA8LSBEYXRhZnJhbWVTb3VyY2Uoc2FtcGxlX2YpCmtzX2NvcnB1c19mIDwtIFZDb3JwdXMoa3NfZHNfZikKYGBgCgpgYGB7cn0KY2xlYW5fY29ycHVzIDwtIGZ1bmN0aW9uKGNvcnB1cyl7CiAgcmVxdWlyZSh0bSkKICByZXF1aXJlKHFkYXApCiAgY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpCiAgY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIGNvbnRlbnRfdHJhbnNmb3JtZXIocmVwbGFjZV9hYmJyZXZpYXRpb24pKQogIGNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBjb250ZW50X3RyYW5zZm9ybWVyKHJlcGxhY2VfY29udHJhY3Rpb24pKQogIGNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBjb250ZW50X3RyYW5zZm9ybWVyKHJlcGxhY2Vfc3ltYm9sKSkKICBjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgY29udGVudF90cmFuc2Zvcm1lcihicmFja2V0WCkpCiAgY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBjKHN0b3B3b3JkcygiZW4iKSkpCiAgY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKQogIGNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVOdW1iZXJzKQogIGNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBzdHJpcFdoaXRlc3BhY2UpCiAgcmV0dXJuKGNvcnB1cykKICB9CmBgYAoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRX0Ka3NfY29ycHVzX3NfY2xlYW4gPC0gY2xlYW5fY29ycHVzKGtzX2NvcnB1c19zKQprc19jb3JwdXNfZl9jbGVhbiA8LSBjbGVhbl9jb3JwdXMoa3NfY29ycHVzX2YpCgprc19jb3JwdXNfc19jbGVhbl9zdGVtbWVkIDwtIHRtX21hcChrc19jb3JwdXNfc19jbGVhbiwgc3RlbURvY3VtZW50KQprc19jb3JwdXNfZl9jbGVhbl9zdGVtbWVkIDwtIHRtX21hcChrc19jb3JwdXNfZl9jbGVhbiwgc3RlbURvY3VtZW50KQpgYGAKCmBgYHtyfQpzdGVtQ29tcGxldGlvbkJyYW1ib3IgPC0gZnVuY3Rpb24oeCwgZGljdGlvbmFyeSkgewogICB4IDwtIHVubGlzdChzdHJzcGxpdChhcy5jaGFyYWN0ZXIoeCksICIgIikpCiAgIHggPC0geFt4ICE9ICIiXQogICB4IDwtIHN0ZW1Db21wbGV0aW9uKHgsIGRpY3Rpb25hcnkgPSBkaWN0aW9uYXJ5KQogICB4IDwtIHBhc3RlKHgsIHNlcCA9ICIiLCBjb2xsYXBzZSA9ICIgIikKICAgUGxhaW5UZXh0RG9jdW1lbnQoc3RyaXBXaGl0ZXNwYWNlKHgpKQogICB9CmBgYAoKYGBge3J9Cm5vX2NvcmVzIDwtIGRldGVjdENvcmVzKCkgLSAxCgprc19jb3JwdXNfc19maW5hbCA8LSBtY2xhcHBseShrc19jb3JwdXNfc19jbGVhbl9zdGVtbWVkLCBzdGVtQ29tcGxldGlvbkJyYW1ib3IsIGRpY3Rpb25hcnkgPSBrc19jb3JwdXNfc19jbGVhbiwgbWMuY29yZXMgPSBub19jb3JlcykKa3NfY29ycHVzX2ZfZmluYWwgPC0gbWNsYXBwbHkoa3NfY29ycHVzX2ZfY2xlYW5fc3RlbW1lZCwgc3RlbUNvbXBsZXRpb25CcmFtYm9yLCBkaWN0aW9uYXJ5ID0ga3NfY29ycHVzX2ZfY2xlYW4sIG1jLmNvcmVzID0gbm9fY29yZXMpCmBgYAoKYGBge3J9CmtzX2NvcnB1c19zX2ZpbmFsIDwtIGFzLlZDb3JwdXMoa3NfY29ycHVzX3NfZmluYWwpCmtzX2NvcnB1c19mX2ZpbmFsIDwtIGFzLlZDb3JwdXMoa3NfY29ycHVzX2ZfZmluYWwpCmBgYAoKYGBge3J9CmtzX3RkbV9zIDwtIFRlcm1Eb2N1bWVudE1hdHJpeChrc19jb3JwdXNfc19maW5hbCkKa3NfdGRtX3NfdGlkeSA8LSB0aWR5dGV4dDo6dGlkeShrc190ZG1fcykKCmtzX3RkbV9mIDwtIFRlcm1Eb2N1bWVudE1hdHJpeChrc19jb3JwdXNfZl9maW5hbCkKa3NfdGRtX2ZfdGlkeSA8LSB0aWR5dGV4dDo6dGlkeShrc190ZG1fZikKYGBgCgpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQprc190Zl9pZGZfcyA8LSBrc190ZG1fc190aWR5ICU+JQogIGJpbmRfdGZfaWRmKHRlcm0sIGRvY3VtZW50LCBjb3VudCkgJT4lCiAgYXJyYW5nZShkZXNjKHRmKSkgCgp3b3JkY2xvdWQoa3NfdGZfaWRmX3MkdGVybSwga3NfdGZfaWRmX3MkdGYsIG1heC53b3JkcyA9IDEwMCwgdGl0bGUuYmcuY29sb3JzID0gIiNmZGY2ZTMiLCBjb2xvcnMgPSAiIzg1OTkwMCIpCmBgYAoKIyMjIGIpIFN1Y2Nlc3MgaW4gd29yZHMKCipQcm92aWRlIGEgcHlyYW1pZCBwbG90IHRvIHNob3cgaG93IHRoZSB3b3JkcyBiZXR3ZWVuIHN1Y2Nlc3NmdWwgYW5kIHVuc3VjY2Vzc2Z1bCBwcm9qZWN0cyBkaWZmZXIgaW4gZnJlcXVlbmN5LiBBIHNlbGVjdGlvbiBvZiAxMC0yMCB0b3Agd29yZHMgaXMgc3VmZmljaWVudCBoZXJlLioKClNpbmNlIEkgd2FzIHVuYWJsZSB0byByZWF0dGFjaCB0aGUgbWV0YWRhdGEgaW4gUXVlc3Rpb24gMWEsIEkgY291bGQgbm90IGNyZWF0ZSBwbG90cyBmb3IgY29tbW9uIG9yIGRpZmZlcmVudCB3b3Jkcy4gCgpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQprc190Zl9pZGZfZiA8LSBrc190ZG1fZl90aWR5ICU+JQogIGJpbmRfdGZfaWRmKHRlcm0sIGRvY3VtZW50LCBjb3VudCkgJT4lCiAgYXJyYW5nZShkZXNjKHRmKSkgCgp3b3JkY2xvdWQoa3NfdGZfaWRmX2YkdGVybSwga3NfdGZfaWRmX2YkdGYsIG1heC53b3JkcyA9IDEwMCwgY29sb3JzID0gIiNjYjRiMTYiKQpgYGAKCiMjIyBjKSBTaW1wbGljaXR5IGFzIGEgdmlydHVlCgoqVGhlc2UgYmx1cmJzIGFyZSBzaG9ydCBpbiBsZW5ndGggKG1heC4gMTUwIGNoYXJhY3RlcnMpIGJ1dCBsZXTigJlzIHNlZSB3aGV0aGVyIGJyZXZpdHkgYW5kIHNpbXBsaWNpdHkgc3RpbGwgbWF0dGVycy4gQ2FsY3VsYXRlIGEgcmVhZGFiaWxpdHkgbWVhc3VyZSAoRmxlc2ggUmVhZGluZyBFYXNlLCBGbGVzaCBLaW5jYWlkIG9yIGFueSBvdGhlciBjb21wYXJhYmxlIG1lYXN1cmUpIGZvciB0aGUgdGV4dHMuIFZpc3VhbGl6ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHJlYWRhYmlsaXR5IG1lYXN1cmUgYW5kIG9uZSBvZiB0aGUgbWVhc3VyZXMgb2Ygc3VjY2Vzcy4gQnJpZWZseSBjb21tZW50IG9uIHlvdXIgZmluZGluZy4qCgpgYGB7cn0Ka3NfdGV4dCA8LSBrc190b3BfYm90dG9tICU+JQogIHNlbGVjdCh0ZXh0KSAlPiUKICBkZWZyYW1lKCkKCmtzX3RleHRfdmVjIDwtIFZlY3RvclNvdXJjZShrc190ZXh0KQprc190ZXh0X2NvcnB1cyA8LSBWQ29ycHVzKGtzX3RleHRfdmVjKQoKa3NfY29ycHVzX3EgPC0gY29ycHVzKGtzX2NvcnB1cykKCmtzX2NvcnB1c19xJGJhY2tlcnNfY291bnQgPC0ga3NfbWV0YSRiYWNrZXJzX2NvdW50CmtzX2NvcnB1c19xJGdvYWwgPC0ga3NfbWV0YSRnb2FsCmtzX2NvcnB1c19xJHBsZWRnZWQgPC0ga3NfbWV0YSRwbGVkZ2VkCmtzX2NvcnB1c19xJHN0YXRlIDwtIGtzX21ldGEkc3RhdGUKa3NfY29ycHVzX3EkdG9wX2NhdGVnb3J5IDwtIGtzX21ldGEkdG9wX2NhdGVnb3J5CmtzX2NvcnB1c19xJHRvcF9jYXRlZ29yeV8yIDwtIGtzX21ldGEkdG9wX2NhdGVnb3J5XzIKa3NfY29ycHVzX3EkYWNoaWV2ZW1lbnRfcmF0aW8gPC0ga3NfbWV0YSRhY2hpZXZlbWVudF9yYXRpbwprc19jb3JwdXNfcSRkYXlzX3RvX2NoYW5nZV9zdGF0ZSA8LSBrc19tZXRhJGRheXNfdG9fY2hhbmdlX3N0YXRlCmtzX2NvcnB1c19xJGZ1bmRpbmdfZGF5c19wY3QgPC0ga3NfbWV0YSRmdW5kaW5nX2RheXNfcGN0CmBgYAoKYGBge3J9CmtzX3RleHRfbmFtZSA8LSBrc190b3BfYm90dG9tICU+JSAKICBzZWxlY3QoZG9jX2lkKSAlPiUKICBtdXRhdGUoZG9jX2lkID0gYXMuY2hhcmFjdGVyKGRvY19pZCkpICU+JQogIGRlZnJhbWUoKQoKZG9jbmFtZXMoa3NfY29ycHVzX3EpIDwtIGtzX3RleHRfbmFtZQoKa3NfY29ycHVzX3FfcmVhZCA8LSB0ZXh0c3RhdF9yZWFkYWJpbGl0eShrc19jb3JwdXNfcSwgbWVhc3VyZSA9ICdGbGVzY2guS2luY2FpZCcpCgprc19jb3JwdXNfcV9yZWFkX2NsZWFuIDwtIGtzX2NvcnB1c19xX3JlYWQgJT4lCiAgbXV0YXRlKGZrZ2wgPSBGbGVzY2guS2luY2FpZCkgJT4lCiAgc2VsZWN0KCFGbGVzY2guS2luY2FpZCkgJT4lCiAgbXV0YXRlKGZrZ2xfaW50ID0gYXMuaW50ZWdlcihma2dsICsgMC41KSkgJT4lCiAgbXV0YXRlKGZrZ2xfY2F0ID0gY3V0KGZrZ2xfaW50LCBicmVha3MgPSBjKC0zLCAxLCA1LCA5LCAxMywgMTcsIEluZiksIG9yZGVyZWRfcmVzdWx0ID0gVFJVRSwgbGFiZWxzID0gcGFzdGUoIkxldmVsIiwgMTo2LCBzZXAgPSAiICIpKSkgJT4lCiAgbXV0YXRlKGZrZ2xfY2F0ID0gY2FzZV93aGVuKAogICAgZmtnbF9jYXQgPT0gIkxldmVsIDEiIH4gIk5vIFNjaG9vbCIsCiAgICBma2dsX2NhdCA9PSAiTGV2ZWwgMiIgfiAiRWxlbWVudGFyeSBTY2hvb2wiLAogICAgZmtnbF9jYXQgPT0gIkxldmVsIDMiIH4gIk1pZGRsZSBTY2hvb2wiLAogICAgZmtnbF9jYXQgPT0gIkxldmVsIDQiIH4gIkhpZ2ggU2Nob29sIiwKICAgIGZrZ2xfY2F0ID09ICJMZXZlbCA1IiB+ICJDb2xsZWdlIiwKICAgIGZrZ2xfY2F0ID09ICJMZXZlbCA2IiB+ICJHcmFkdWF0ZSBTY2hvb2wiKSkgJT4lIAogIG11dGF0ZShma2dsX2NhdCA9IG9yZGVyZWQoZmtnbF9jYXQsIGxldmVscyA9IGMoIk5vIFNjaG9vbCIsICJFbGVtZW50YXJ5IFNjaG9vbCIsICJNaWRkbGUgU2Nob29sIiwgIkhpZ2ggU2Nob29sIiwgIkNvbGxlZ2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkdyYWR1YXRlIFNjaG9vbCIpKSkgJT4lCiAgbXV0YXRlKGZrZ2xfY2F0XzIgPSBjdXQoZmtnbF9pbnQsIGJyZWFrcyA9IGMoLTMsIDEsIDcsIDEzLCAxOSwgSW5mKSwgb3JkZXJlZF9yZXN1bHQgPSBUUlVFLCBsYWJlbHMgPSBwYXN0ZSgiTGV2ZWwiLCAxOjUsIHNlcCA9ICIgIikpKSAlPiUKICBtdXRhdGUoZmtnbF9jYXRfMiA9IGNhc2Vfd2hlbigKICAgIGZrZ2xfY2F0XzIgPT0gIkxldmVsIDEiIH4gIk5vIFNjaG9vbCIsCiAgICBma2dsX2NhdF8yID09ICJMZXZlbCAyIiB+ICIxLTYgWWVhcnMiLAogICAgZmtnbF9jYXRfMiA9PSAiTGV2ZWwgMyIgfiAiNy0xMiBZZWFycyIsCiAgICBma2dsX2NhdF8yID09ICJMZXZlbCA0IiB+ICIxMy0xOCBZZWFycyIsCiAgICBma2dsX2NhdF8yID09ICJMZXZlbCA1IiB+ICIxOSsgWWVhcnMiKSkgJT4lIAogIG11dGF0ZShma2dsX2NhdF8yID0gb3JkZXJlZChma2dsX2NhdF8yLCBsZXZlbHMgPSBjKCJObyBTY2hvb2wiLCAiMS02IFllYXJzIiwgIjEtOCBZZWFycyIsICI3LTEyIFllYXJzIiwgIjEzLTE4IFllYXJzIiwgIjE5KyBZZWFycyIpKSkKYGBgCgpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQprc19jb3JwdXNfcV9kZiA8LSBkYXRhX2ZyYW1lKAogIGRvY3VtZW50ID0ga3NfbWV0YSRkb2NfaWQsCiAgYmFja2Vyc19jb3VudCA9IGtzX21ldGEkYmFja2Vyc19jb3VudCwKICBnb2FsID0ga3NfbWV0YSRnb2FsLAogIHBsZWRnZWQgPSBrc19tZXRhJHBsZWRnZWQsCiAgc3RhdGUgPSBrc19tZXRhJHN0YXRlLAogIHRvcF9jYXRlZ29yeSA9IGtzX21ldGEkdG9wX2NhdGVnb3J5LAogIHRvcF9jYXRlZ29yeV8yID0ga3NfbWV0YSR0b3BfY2F0ZWdvcnlfMiwKICBhY2hpZXZlbWVudF9yYXRpbyA9IGtzX21ldGEkYWNoaWV2ZW1lbnRfcmF0aW8sCiAgZGF5c190b19jaGFuZ2Vfc3RhdGUgPSBrc19tZXRhJGRheXNfdG9fY2hhbmdlX3N0YXRlLAogIGZ1bmRpbmdfZGF5c19wY3QgPSBrc19tZXRhJGZ1bmRpbmdfZGF5c19wY3QsCiAgd29yZHMgPSBudG9rZW4oa3NfY29ycHVzX3EpKQpgYGAKCmBgYHtyfQprc19jb3JwdXNfcV9kZl9jbGVhbiA8LSBrc19jb3JwdXNfcV9kZiAlPiUKICBtdXRhdGUoZG9jdW1lbnQgPSBhcy5jaGFyYWN0ZXIoZG9jdW1lbnQpLCAKICAgICAgICAgYmFja2Vyc19jb3VudCA9IGFzLm51bWVyaWMoYmFja2Vyc19jb3VudCksCiAgICAgICAgIGdvYWwgPSBhcy5udW1lcmljKGdvYWwpLAogICAgICAgICBwbGVkZ2VkID0gYXMubnVtZXJpYyhwbGVkZ2VkKSwKICAgICAgICAgYWNoaWV2ZW1lbnRfcmF0aW8gPSBhcy5udW1lcmljKGFjaGlldmVtZW50X3JhdGlvKSwKICAgICAgICAgZGF5c190b19jaGFuZ2Vfc3RhdGUgPSBhcy5udW1lcmljKGRheXNfdG9fY2hhbmdlX3N0YXRlKSwKICAgICAgICAgZnVuZGluZ19kYXlzX3BjdCA9IGFzLm51bWVyaWMoZnVuZGluZ19kYXlzX3BjdCksCiAgICAgICAgIHdvcmRzID0gYXMubnVtZXJpYyh3b3JkcykpICU+JQogIG11dGF0ZSh0b3BfY2F0ZWdvcnlfMiA9IGZhY3Rvcih0b3BfY2F0ZWdvcnlfMiwgbGV2ZWxzID0gYygibXVzaWMiLCAiZmlsbSAmIHZpZGVvIiwgImFydCIsICJwdWJsaXNoaW5nIiwgInRlY2hub2xvZ3kiLCAiZm9vZCIsICJvdGhlciIpKSkKYGBgCgpgYGB7cn0Ka3NfY29ycHVzX2ZrZ2wgPC0gaW5uZXJfam9pbihrc19jb3JwdXNfcV9kZl9jbGVhbiwga3NfY29ycHVzX3FfcmVhZF9jbGVhbiwgYnkgPSAiZG9jdW1lbnQiKQpgYGAKCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9CmdncGxvdChkYXRhID0gc3Vic2V0KGtzX2NvcnB1c19ma2dsLCBzdGF0ZSA9PSAic3VjY2Vzc2Z1bCIpLCAKICAgICAgIGFlcyh4ID0gZmtnbF9jYXQsIHkgPSBiYWNrZXJzX2NvdW50LCBmaWxsID0gZmtnbF9jYXQpKSArCiAgZ2VvbV92aW9saW4oY29sb3IgPSAiIzA3MzY0MiIsIHNpemUgPSAwLjMpICsKICB0aGVtZV9zb2xhcl9wcmV0dHkoKSArCiAgc2NhbGVfZmlsbF9zb2xhcml6ZWQoYWNjZW50ID0gJ3llbGxvdycpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiTm8gU2Nob29sIiwgIkVsZW1lbnRhcnlcblNjaG9vbCIsICJNaWRkbGVcblNjaG9vbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSGlnaCBTY2hvb2wiLCAiQ29sbGVnZSIsICJHcmFkdWF0ZVxuU2Nob29sIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGxpbWl0cyA9IGMoMCwxMDAwMCkpICsKICB4bGFiKCJcbkZsZXNjaC1LaW5rYWlkIHJlYWRhYmlsaXR5IHNjb3JlIikgKwogIHlsYWIoTlVMTCkgKwogIGxhYnModGl0bGUgPSAiU3VjY2Vzc2Z1bCBjYW1wYWlnbiBwb3B1bGFyaXR5IGJ5IHJlYWRpbmcgbGV2ZWwiLCAKICAgICAgIHN1YnRpdGxlID0gIlxuRWxlbWVudGFyeS0gdG8gbWlkZGxlLXNjaG9vbCByZWFkaW5nIGxldmVscyBhcmUgdGhlIG1vc3Qgc3VjY2Vzc2Z1bCBhbmQgcG9wdWxhclxuIiwgCiAgICAgICBjYXB0aW9uID0gIlNvdXJjZTogd2Vicm9ib3RzLmlvIikKYGBgCgpJIGhhdmUgbGltaXRlZCB0aGUgZGF0YSB0byBjYW1wYWlnbnMgd2l0aCBmZXdlciB0aGFuIDEwLDAwMCBiYWNrZXJzLiBDYW1wYWlnbnMgd2l0aCByZWFkaW5nIGxldmVscyBiZXR3ZWVuIGVsZW1lbnRhcnkgc2Nob29sIGFuZCBjb2xsZWdlIGFyZSBtb3JlIGxpa2VseSB0byBnZXQgYWJvdmUgNSwwMDAgYmFja2VycywgYnV0IGEgbGFyZ2UgcHJvcG9ydGlvbiBvZiB0aGVzZSBjYW1wYWlnbnMgZ2FybmVyIGxlc3MgdGhhbiAxLDAwMCBiYWNrZXJzLiBUaGlzIHBhdHRlbnIgaXMgbGlrZWx5IGR1ZSB0byB0aGUgc21hbGwgc21hcGxlIHNpemUgb2YgY2FtcGFpZ25zIHdpdGggdmVyeSBsb3cgYW5kIHZlcnkgaGlnaCBzY29yZXMuIAoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0Kc3RhdGVfbWVkX2ZrZ2wgPC0gZGRwbHkoa3NfY29ycHVzX2ZrZ2wsICJzdGF0ZSIsIHN1bW1hcmlzZSwgbWVkID0gbWVkaWFuKGZrZ2wpKQoKZ2dwbG90KGtzX2NvcnB1c19ma2dsLCBhZXMoeCA9IGZrZ2wsIGNvbG9yID0gc3RhdGUpKSArIAogIGdlb21fZGVuc2l0eShzaXplID0gLjc1KSArCiAgZ2VvbV92bGluZShkYXRhID0gc3RhdGVfbWVkX2ZrZ2wsIGFlcyh4aW50ZXJjZXB0ID0gbWVkLCBjb2xvciA9IHN0YXRlKSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IC43NSkgKwogIHRoZW1lX3NvbGFyX3ByZXR0eSgpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKGFjY2VudCA9ICd5ZWxsb3cnKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKC0zLCAwLCAzLCA2LCA5LCAxMiwgMTUsIDE4LCAyMSksIGxpbWl0cyA9IGMoLTMsIDIzKSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDAsIC4wMywgLjA2LCAuMDkpKSArCiAgeGxhYigiXG5GbGVzY2gtS2lua2FpZCByZWFkYWJpbGl0eSBzY29yZSIpICsKICB5bGFiKCJEZW5zaXR5XG4iKSArCiAgbGFicyh0aXRsZSA9ICJTdWNjZXNzZnVsIHZzLiBmYWlsZWQgY2FtcGFpZ25zIGJ5IHJlYWRpbmcgbGV2ZWwiLAogICAgICAgc3VidGl0bGUgPSAiXG5DYW1wYWlnbnMgc3VjY2VlZCBtb3N0IG9mdGVuIHdpdGggYSBzY29yZSBiZXR3ZWVuIDYgYW5kIDEwXG4iLAogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IHdlYnJvYm90cy5pbyIpCmBgYAoKVGhlIHN3ZWV0IHNwb3QgZm9yIHN1Y2Nlc3MgYXBwZWFycyB0byBiZSBhIHJlYWRpbmcgbGV2ZWwgYmV0d2VlbiA2dGggYW5kIDEwdGggZ3JhZGUuIFdpdGhpbiB0aGlzIGJvdW5kYXJ5LCBzdWNjZXNzZnVsIGNhbXBhaWducyBoYXZlIHRoZSBncmVhdGVzdCBkZW5zaXR5LiBTbGlnaHRseSBvdXRzaWRlIHRoaXMgYm91bmRhcnkgb24gYm90aCBzaWRlcywgZmFpbGVkIGNhbXBhaWducyBoYXZlIHRoZSBncmVhdGVzdCBkZW5zaXR5LiBBbHNvLCB0aGUgbWVkaWFuIHJlYWRhYmlsaXR5IHNjb3JlIGZvciBzdWNjZXNzZnVsIGNhbXBhaWducyBpcyBvbmx5IHNsaWdodGx5IGxvd2VyIHRoYW4gdGhlIG1lZGlhbiBzY29yZSBmb3IgZmFpbGVkIGNhbXBhaWducy4KCgojIyAzLiBTZW50aW1lbnQKCipOb3csIGxldOKAmXMgY2hlY2sgd2hldGhlciB0aGUgdXNlIG9mIHBvc2l0aXZlL25lZ2F0aXZlIHdvcmRzIG9yIHNwZWNpZmljIGVtb3Rpb25zIGhlbHBzIGEgcHJvamVjdCB0byBiZSBzdWNjZXNzZnVsLioKCiMjIyBhKSBTdGF5IHBvc2l0aXZlCgoqQ2FsY3VsYXRlIHRoZSB0b25lIG9mIGVhY2ggdGV4dCBiYXNlZCBvbiB0aGUgcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIHdvcmRzIHRoYXQgYXJlIGJlaW5nIHVzZWQuIFlvdSBjYW4gcmVseSBvbiB0aGUgSHUgJiBMaXUgZGljdGlvbmFyeSBwcm92aWRlZCBpbiBsZWN0dXJlIG9yIHVzZSB0aGUgQmluZyBkaWN0aW9uYXJ5IGNvbnRhaW5lZCBpbiB0aGUgdGlkeXRleHQgcGFja2FnZSAodGlkeXRleHQ6OnNlbnRpbWVudHMpLiBWaXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRvbmUgb2YgdGhlIGRvY3VtZW50IGFuZCBzdWNjZXNzLiBCcmllZmx5IGNvbW1lbnQuKgoKYGBge3J9CmJpbmdfZGljdCA8LSBhcy5kaWN0aW9uYXJ5KGdldF9zZW50aW1lbnRzKCJiaW5nIikpCgpiaW5nX2RpY3Rfa3NfZHRtIDwtIGRmbShrc19jb3JwdXNfcSwgZGljdGlvbmFyeSA9IGJpbmdfZGljdCkKCmJpbmdfZGljdF9rc19kZiA8LSBtZWx0KGFzLm1hdHJpeChiaW5nX2RpY3Rfa3NfZHRtKSkgJT4lCiAgc3ByZWFkKGtleSA9IGZlYXR1cmVzLCB2YWx1ZSA9IHZhbHVlKSAlPiUKICBtdXRhdGUoZG9jdW1lbnQgPSBhcy5udW1lcmljKGRvY3MpKSAlPiUKICBzZWxlY3QoIWRvY3MpICU+JQogIG11dGF0ZShwb3Nfc2NvcmUgPSBhcy5pbnRlZ2VyKHBvc2l0aXZlLW5lZ2F0aXZlKSkgJT4lCiAgbXV0YXRlKHBvc19zY29yZV9jYXQgPSBhcy5mYWN0b3IocG9zX3Njb3JlKSkgJT4lCiAgbXV0YXRlKHBvc19yYXRpbyA9IChwb3NpdGl2ZSsxKS8obmVnYXRpdmUrMSkpIAogIAprc19jb3JwdXNfYmluZyA8LSBpbm5lcl9qb2luKGtzX2NvcnB1c19xX2RmLCBiaW5nX2RpY3Rfa3NfZGYsIGJ5ID0gImRvY3VtZW50IikKYGBgCgpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQpnZ3Bsb3QoZGF0YSA9IGtzX2NvcnB1c19iaW5nLCBhZXMoeCA9IHBvc19zY29yZSwgeSA9IGJhY2tlcnNfY291bnQsIGNvbG9yID0gc3RhdGUpKSArCiAgZ2VvbV9qaXR0ZXIoKSArCiAgeGxpbSgtMy41LCA0LjUpICsKICB0aGVtZV9zb2xhcl9wcmV0dHkoKSArCiAgc2NhbGVfY29sb3Jfc29sYXJpemVkKGFjY2VudCA9ICd5ZWxsb3cnKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGxpbWl0cyA9IGMoMCwgMTAwMDApKSArCiAgeGxhYigiXG5CaW5nIHBvc2l0aXZpdHkgc2NvcmUiKSArCiAgeWxhYigiTnVtYmVyIG9mIGJhY2tlcnNcbiIpICsKICBsYWJzKHRpdGxlID0gIkNhbXBhaWduIHBvcHVsYXJpdHkgYnkgcG9zaXRpdml0eSIsIAogICAgICAgc3VidGl0bGUgPSAiXG5OZXV0cmFsIGFuZCBzbGlnaHRseSBwb3NpdGl2ZSBjYW1wYWlnbnMgYXJlIHRoZSBtb3N0IHBvcHVsYXJcbiIsIAogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IHdlYnJvYm90cy5pbyIpCmBgYAoKSSBoYXZlIGxpbWl0ZWQgdGhlIGRhdGEgdG8gY2FtcGFpZ25zIHdpdGggZmV3ZXIgdGhhbiAxMCwwMDAgYmFja2Vycy4gQ2FtcGFpZ25zIHdpdGggcG9zaXRpdml0eSBzY29yZXMgYmV0d2VlbiAwIGFuZCAyIGFyZSB0aGUgbW9zdCBsaWtlbHkgdG8gaGF2ZSBtb3JlIHRoYW4gNSwwMDAgYmFja2Vycy4KCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9CmdncGxvdChkYXRhID0ga3NfY29ycHVzX2JpbmcsIGFlcyh4ID0gcG9zX3Njb3JlLCBjb2xvciA9IHN0YXRlKSkgKwogIGdlb21fZGVuc2l0eShzaXplID0gLjc1KSArCiAgeGxpbSgtNCwgNikgKwogIHRoZW1lX3NvbGFyX3ByZXR0eSgpICsKICBzY2FsZV9jb2xvcl9zb2xhcml6ZWQoYWNjZW50ID0gJ3llbGxvdycpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoMCwgLjIsIC40LCAuNiwgLjgpKSArCiAgeGxhYigiXG5CaW5nIHBvc2l0aXZpdHkgc2NvcmUiKSArCiAgeWxhYigiRGVuc2l0eVxuIikgKwogIGxhYnModGl0bGUgPSAiU3VjY2Vzc2Z1bCB2cy4gZmFpbGVkIGNhbXBhaWducyBieSBwb3NpdGl2aXR5IiwKICAgICAgIHN1YnRpdGxlID0gIlxuU2xpZ2h0bHkgbmVnYXRpdmUgY2FtcGFpZ25zIGhhdmUgdGhlIGhpZ2hlc3QgcmF0ZSBvZiBzdWNjZXNzXG4iLAogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IHdlYnJvYm90cy5pbyIpCmBgYAoKQ2FtcGFpZ25zIG9uIHRoZSBleHRyZW1lcyBvZiB0aGUgcG9zaXRpdml0eSBzY2FsZSAodmVyeSBwb3NpdGl2ZSBvciBuZWdhdGl2ZSkgaGF2ZSBhIGhpZ2hlciBzdWNjZXNzIHJhdGUgdGhhbiBjYW1wYWlnbnMgd2l0aCBuZXV0cmFsIG9yIHNsaWdodGx5IHBvc2l0aXZlIHNjb3Jlcy4gVGhpcyBzdWdnZXN0cyB0aGF0IGNhbXBhaWduIGJsdXJicyB3aXRoIGVtb3RpdmUgbGFuZ3VhZ2UgZG8gYmV0dGVyIHRoYW4gdGhvc2Ugd2l0aCBhIG1vcmUgZmxhdCBhZmZlY3QuCgojIyMgYikgUG9zaXRpdmUgdnMuIG5lZ2F0aXZlCgoqU2VncmVnYXRlIGFsbCAyLDAwMCBibHVyYnMgaW50byBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgdGV4dHMgYmFzZWQgb24gdGhlaXIgcG9sYXJpdHkgc2NvcmUgY2FsY3VsYXRlZCBpbiBzdGVwIChhKS4gTm93LCBjb2xsYXBzZSB0aGUgcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIHRleHRzIGludG8gdHdvIGxhcmdlciBkb2N1bWVudHMuIENyZWF0ZSBhIGRvY3VtZW50LXRlcm0tbWF0cml4IGJhc2VkIG9uIHRoaXMgY29sbGFwc2VkIHNldCBvZiB0d28gZG9jdW1lbnRzLiBHZW5lcmF0ZSBhIGNvbXBhcmlzb24gY2xvdWQgc2hvd2luZyB0aGUgbW9zdC1mcmVxdWVudCBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgd29yZHMuKgoKYGBge3J9CmtzX2NvcnB1c19iaW5nIDwtIGtzX2NvcnB1c19iaW5nICU+JQogIG11dGF0ZShzZW50X2NhdCA9IGNhc2Vfd2hlbigKICAgIHBvc19yYXRpbyA+PSAxIH4gInBvc2l0aXZlIiwKICAgIFRSVUUgICAgICAgICAgIH4gIm5lZ2F0aXZlIikpCgprc19kb2NzX3BvcyA8LSBrc19jb3JwdXNfYmluZyAlPiUKICBmaWx0ZXIoc2VudF9jYXQgPT0gInBvc2l0aXZlIikgJT4lCiAgbXV0YXRlKGRvY19pZCA9IGRvY3VtZW50KSAlPiUKICBzZWxlY3QoZG9jX2lkKQoKa3NfZG9jc19uZWcgPC0ga3NfY29ycHVzX2JpbmcgJT4lCiAgZmlsdGVyKHNlbnRfY2F0ID09ICJuZWdhdGl2ZSIpICU+JQogIG11dGF0ZShkb2NfaWQgPSBkb2N1bWVudCkgJT4lCiAgc2VsZWN0KGRvY19pZCkKYGBgCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQprc19wb3MgPC0gaW5uZXJfam9pbihrc19kb2NzX3Bvcywga3NfdG9wX2JvdHRvbSwga2V5ID0gZG9jX2lkKQprc19uZWcgPC0gaW5uZXJfam9pbihrc19kb2NzX25lZywga3NfdG9wX2JvdHRvbSwga2V5ID0gZG9jX2lkKQoKa3NfZHNfcG9zIDwtIERhdGFmcmFtZVNvdXJjZShrc19wb3MpCmtzX2NvcnB1c19wb3MgPC0gVkNvcnB1cyhrc19kc19wb3MpCgprc19kc19uZWcgPC0gRGF0YWZyYW1lU291cmNlKGtzX25lZykKa3NfY29ycHVzX25lZyA8LSBWQ29ycHVzKGtzX2RzX25lZykKYGBgCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFfQprc19jb3JwdXNfcG9zX2NsZWFuIDwtIGNsZWFuX2NvcnB1cyhrc19jb3JwdXNfcG9zKQprc19jb3JwdXNfbmVnX2NsZWFuIDwtIGNsZWFuX2NvcnB1cyhrc19jb3JwdXNfbmVnKQoKa3NfY29ycHVzX3Bvc19jbGVhbl9zdGVtbWVkIDwtIHRtX21hcChrc19jb3JwdXNfcG9zX2NsZWFuLCBzdGVtRG9jdW1lbnQpCmtzX2NvcnB1c19uZWdfY2xlYW5fc3RlbW1lZCA8LSB0bV9tYXAoa3NfY29ycHVzX25lZ19jbGVhbiwgc3RlbURvY3VtZW50KQpgYGAKCmBgYHtyfQpub19jb3JlcyA8LSBkZXRlY3RDb3JlcygpIC0gMQoKa3NfY29ycHVzX3Bvc19maW5hbCA8LSBtY2xhcHBseShrc19jb3JwdXNfcG9zX2NsZWFuX3N0ZW1tZWQsIHN0ZW1Db21wbGV0aW9uQnJhbWJvciwgZGljdGlvbmFyeSA9IGtzX2NvcnB1c19wb3NfY2xlYW4sIG1jLmNvcmVzID0gbm9fY29yZXMpCmtzX2NvcnB1c19uZWdfZmluYWwgPC0gbWNsYXBwbHkoa3NfY29ycHVzX25lZ19jbGVhbl9zdGVtbWVkLCBzdGVtQ29tcGxldGlvbkJyYW1ib3IsIGRpY3Rpb25hcnkgPSBrc19jb3JwdXNfbmVnX2NsZWFuLCBtYy5jb3JlcyA9IG5vX2NvcmVzKQpgYGAKCmBgYHtyfQprc19jb3JwdXNfcG9zX2ZpbmFsIDwtIGFzLlZDb3JwdXMoa3NfY29ycHVzX3Bvc19maW5hbCkKa3NfY29ycHVzX25lZ19maW5hbCA8LSBhcy5WQ29ycHVzKGtzX2NvcnB1c19uZWdfZmluYWwpCmBgYAoKYGBge3J9CmtzX3RkbV9wb3MgPC0gVGVybURvY3VtZW50TWF0cml4KGtzX2NvcnB1c19wb3NfZmluYWwpCmtzX3RkbV9wb3NfdGlkeSA8LSB0aWR5dGV4dDo6dGlkeShrc190ZG1fcG9zKQoKa3NfdGRtX25lZyA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoa3NfY29ycHVzX25lZ19maW5hbCkKa3NfdGRtX25lZ190aWR5IDwtIHRpZHl0ZXh0Ojp0aWR5KGtzX3RkbV9uZWcpCmBgYAoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0Ka3NfdGZfaWRmX3BvcyA8LSBrc190ZG1fcG9zX3RpZHkgJT4lCiAgYmluZF90Zl9pZGYodGVybSwgZG9jdW1lbnQsIGNvdW50KSAlPiUKICBhcnJhbmdlKGRlc2ModGYpKSAKCndvcmRjbG91ZChrc190Zl9pZGZfcG9zJHRlcm0sIGtzX3RmX2lkZl9wb3MkdGYsIG1heC53b3JkcyA9IDEwMCwgY29sb3JzID0gIiNiNTg5MDAiKQpgYGAKCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9CmtzX3RmX2lkZl9uZWcgPC0ga3NfdGRtX25lZ190aWR5ICU+JQogIGJpbmRfdGZfaWRmKHRlcm0sIGRvY3VtZW50LCBjb3VudCkgJT4lCiAgYXJyYW5nZShkZXNjKHRmKSkgCgp3b3JkY2xvdWQoa3NfdGZfaWRmX25lZyR0ZXJtLCBrc190Zl9pZGZfbmVnJHRmLCBtYXgud29yZHMgPSAxMDAsIGNvbG9ycyA9ICIjMjY4YmQyIikKYGBgCgojIyMgYykgR2V0IGluIHRoZWlyIG1pbmQKCipOb3csIHVzZSB0aGUgTlJDIFdvcmQtRW1vdGlvbiBBc3NvY2lhdGlvbiBMZXhpY29uIGluIHRoZSB0aWR5dGV4dCBwYWNrYWdlIHRvIGlkZW50aWZ5IGEgbGFyZ2VyIHNldCBvZiBlbW90aW9ucyAoYW5nZXIsIGFudGljaXBhdGlvbiwgZGlzZ3VzdCwgZmVhciwgam95LCBzYWRuZXNzLCBzdXJwcmlzZSwgdHJ1c3QpLiBBZ2FpbiwgdmlzdWFsaXplIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdXNlIG9mIHdvcmRzIGZyb20gdGhlc2UgY2F0ZWdvcmllcyBhbmQgc3VjY2Vzcy4gV2hhdCBpcyB5b3VyIGZpbmRpbmc/KgoKYGBge3J9Cm5yY19kaWN0IDwtIGFzLmRpY3Rpb25hcnkoZ2V0X3NlbnRpbWVudHMoIm5yYyIpKQoKbnJjX2RpY3Rfa3NfZHRtIDwtIGRmbShrc19jb3JwdXNfcSwgZGljdGlvbmFyeSA9IG5yY19kaWN0KQoKbnJjX2RpY3Rfa3NfZGYgPC0gbWVsdChhcy5tYXRyaXgobnJjX2RpY3Rfa3NfZHRtKSkgJT4lCiAgc3ByZWFkKGtleSA9IGZlYXR1cmVzLCB2YWx1ZSA9IHZhbHVlKSAlPiUKICBtdXRhdGUoZG9jdW1lbnQgPSBhcy5udW1lcmljKGRvY3MpKSAlPiUKICBzZWxlY3QoIWRvY3MpICU+JQogIG11dGF0ZShzZW50X3Njb3JlID0gYW5nZXIgKyBhbnRpY2lwYXRpb24gKyBkaXNndXN0ICsgZmVhciArIGpveSArIHNhZG5lc3MgKyBzdXJwcmlzZSArIHRydXN0KQoKa3NfY29ycHVzX25yYyA8LSBpbm5lcl9qb2luKGtzX2NvcnB1c19xX2RmLCBucmNfZGljdF9rc19kZiwgYnkgPSAiZG9jdW1lbnQiKQpgYGAKCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9CmdncGxvdChkYXRhID0ga3NfY29ycHVzX25yYywgYWVzKHggPSBhbnRpY2lwYXRpb24sIGNvbG9yID0gc3RhdGUpKSArCiAgZ2VvbV9kZW5zaXR5KHNpemUgPSAuNzUpICsKICB4bGltKDAsNCkgKwogIHlsaW0oMCwxLjYpICsKICB0aGVtZV9zb2xhcl9wcmV0dHkoKSArCiAgc2NhbGVfY29sb3Jfc29sYXJpemVkKGFjY2VudCA9ICd5ZWxsb3cnKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKwogIHhsYWIoIlxuTlJDIGFudGljaXBhdGlvbiBzY29yZSIpICsKICB5bGFiKCJEZW5zaXR5XG4iKSArCiAgbGFicyh0aXRsZSA9ICJTdWNjZXNzZnVsIHZzLiBmYWlsZWQgY2FtcGFpZ25zIGJ5IGFudGljaXBhdGlvbiIsCiAgICAgICBjYXB0aW9uID0gIlNvdXJjZTogd2Vicm9ib3RzLmlvIikKYGBgCgpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQpnZ3Bsb3QoZGF0YSA9IGtzX2NvcnB1c19ucmMsIGFlcyh4ID0gam95LCBjb2xvciA9IHN0YXRlKSkgKwogIGdlb21fZGVuc2l0eShzaXplID0gLjc1KSArCiAgeGxpbSgwLDQpICsKICB5bGltKDAsMS42KSArCiAgdGhlbWVfc29sYXJfcHJldHR5KCkgKwogIHNjYWxlX2NvbG9yX3NvbGFyaXplZChhY2NlbnQgPSAneWVsbG93JykgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsKICB4bGFiKCJcbk5SQyBqb3kgc2NvcmUiKSArCiAgeWxhYigiRGVuc2l0eVxuIikgKwogIGxhYnModGl0bGUgPSAiU3VjY2Vzc2Z1bCB2cy4gZmFpbGVkIGNhbXBhaWducyBieSBqb3kiLAogICAgICAgY2FwdGlvbiA9ICJTb3VyY2U6IHdlYnJvYm90cy5pbyIpCmBgYAoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRX0KZ2dwbG90KGRhdGEgPSBrc19jb3JwdXNfbnJjLCBhZXMoeCA9IHRydXN0LCBjb2xvciA9IHN0YXRlKSkgKwogIGdlb21fZGVuc2l0eShzaXplID0gLjc1KSArCiAgeGxpbSgwLDQpICsKICB5bGltKDAsMS42KSArCiAgdGhlbWVfc29sYXJfcHJldHR5KCkgKwogIHNjYWxlX2NvbG9yX3NvbGFyaXplZChhY2NlbnQgPSAneWVsbG93JykgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsKICB4bGFiKCJcbk5SQyB0cnVzdCBzY29yZSIpICsKICB5bGFiKCJEZW5zaXR5XG4iKSArCiAgbGFicyh0aXRsZSA9ICJTdWNjZXNzZnVsIHZzLiBmYWlsZWQgY2FtcGFpZ25zIGJ5IHRydXN0IiwKICAgICAgIGNhcHRpb24gPSAiU291cmNlOiB3ZWJyb2JvdHMuaW8iKQpgYGAKCkkgbGltaXRlZCB0aGUgZGF0YSB0byBjYW1wYWlnbnMgd2l0aCBlbW90aW9uIHNjb3JlcyBsZXNzIHRoYW4gNC4gSSBsb29rZWQgYXQgYW50aWNpcGF0aW9uLCBqb3ksIGFuZCB0cnVzdCwgd2hpY2ggSSBjb25zaWRlciB0aGUgbW9zdCBsaWtlbHkgdG8gaW5zcGlyZSBzdXBwb3J0IGZvciBLaWNrc3RhcnRlciBjYW1wYWlnbnMuIEhvd2V2ZXIsIGZvciBlYWNoIGVtb3Rpb24sIGNhbXBhaWducyB3aXRoIGxvdyBzY29yZXMgYXJlIG1vcmUgbGlrZWx5IHRvIHN1Y2NlZWQsIHdoZXJlYXMgdGhvc2Ugd2l0aCBoaWdoZXIgc2NvcmVzIHdlcmUgbW9yZSBsaWtlbHkgdG8gZmFpbC4KCmBgYHtyLCB3YXJuaW5nID0gRkFMU0V9CmdncGxvdChkYXRhID0ga3NfY29ycHVzX25yYywgYWVzKHggPSBzZW50X3Njb3JlLCBjb2xvciA9IHN0YXRlKSkgKwogIGdlb21fZGVuc2l0eShzaXplID0gLjc1KSArCiAgeGxpbSgwLDIwKSArCiAgdGhlbWVfc29sYXJfcHJldHR5KCkgKwogIHNjYWxlX2NvbG9yX3NvbGFyaXplZChhY2NlbnQgPSAneWVsbG93JykgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIpICsKICB4bGFiKCJcbk5SQyB0b3RhbCBzZW50aW1lbnQgc2NvcmUiKSArCiAgeWxhYigiRGVuc2l0eVxuIikgKwogIGxhYnModGl0bGUgPSAiU3VjY2Vzc2Z1bCB2cy4gZmFpbGVkIGNhbXBhaWducyBieSBhbGwgZW1vdGlvbnMiLAogICAgICAgc3VidGl0bGUgPSAiXG4uLi5cbiIsCiAgICAgICBjYXB0aW9uID0gIlNvdXJjZTogd2Vicm9ib3RzLmlvIikKYGBgCgpJIHRoZW4gY29tYmluZWQgdGhlIHNjb3JlcyBmb3IgYWxsIGVtb3Rpb25zIGludG8gYSBzaW5nbGUgImVtb3RpdmUiIHNjb3JlLiBDYW1wYWlnbnMgd2l0aCBsb3dlciBzY29yZXMgZm9yIGFueSBlbW90aW9uIGFyZSB0aGUgbW9zdCBsaWtlbHkgdG8gYmUgc3VjY2Vzc2Z1bC4gVGhlIHN3ZWV0IHNwb3QgYXBwZWFycyB0byBiZSBzY29yZXMgYmV0d2VlbiAwIGFuZCAzLgo=