Note: This notebook was updated on Tuesday 16th September, 3:00 PM to correct a data preprocessing error, which erroneously filtered out some data from being including in the summaries. The correction is viewable here. This has been corrected.


1 Introduction

This notebook contains the data analysis for the charts and numbers used on our site, CBFC.WATCH. To ensure full transparency with our readers, we are publishing our methodology and the R code used to generate the statistics for various parts of the site, as well as to provide a starting point for others who may be curious about how to use the data.

We explore these questions:

  1. Do some regional CBFC offices require more modifications than others?
  2. How have the primary reasons for censorship (e.g., violence, profanity, sexual content) trended over time?
  3. How much footage is typically removed from a film?
  4. Which specific censorship categories are becoming more frequent, and which are declining?
  5. What specific words and themes are most associated with each major censorship category?
  6. Which specific films have had the most footage removed by each regional office?

1.1 Data Loading and Preparation

Importing the dataset, correcting data types, and standardizing categorical information like language and regional office names.

data <- read_csv("https://github.com/diagram-chasing/censor-board-cuts/raw/refs/heads/master/data/data.csv", 
                 col_types = cols(.default = "c")) %>%
  mutate(
    cert_date = as.Date(cert_date),
    total_modified_time_secs = as.numeric(total_modified_time_secs),
    deleted_secs = as.numeric(deleted_secs),
    replaced_secs = as.numeric(replaced_secs),
    inserted_secs = as.numeric(inserted_secs)
  ) %>%
  # The 'certifier' column contains a string like "Examining Committee, Mumbai".
  # We extract the regional office name by splitting the string by the comma
  # and taking the last element.
  mutate(
    office = str_split(certifier, ",") %>%
      map_chr(last) %>%
      str_trim()
  ) %>%
  separate_rows(ai_content_types, sep = "\\|") %>%
  mutate(ai_content_types = str_trim(ai_content_types))%>%
  # Filter out any rows where the content type is empty after separation.
 # filter(ai_content_types != "") %>%
  # Standardize language names to correct for typos and variations in the raw data
  mutate(
    language = case_when(
      language == "Oriya" ~ "Odia",
      language == "Gujrati" ~ "Gujarati",
      language == "Chhatisgarhi" ~ "Chhattisgarhi",
      language == "Hariyanvi" ~ "Haryanvi",
      language == "Hindi Dub" ~ "Hindi Dubbed",
      TRUE ~ language
    )
  ) %>%
  filter(!is.na(language))

1.2 Exploratory Data Analysis

1.2.1 Languages in the Dataset

Counting how many films for each language in the dataset. We’ll show the top ones.

films_by_language_data <- data %>%
  distinct(id, language) %>%
  count(language, sort = TRUE) %>%
  top_n(10, n) %>%
  mutate(language = fct_reorder(language, n))

write_json(films_by_language_data, "films_by_language.json", pretty = TRUE, auto_unbox = TRUE)

films_by_language_data %>%
  ggplot(aes(x = n, y = language)) +
  geom_col(fill = tertiary_color, alpha = 0.9) +
  geom_text(aes(label = comma(n)), hjust = -0.15, size = 3.5, color = "gray20") +
  scale_x_continuous(
    labels = comma,
    expand = expansion(mult = c(0, 0.12))
  ) +
  labs(
    title = "Top 15 Languages by Number of Films Censored",
    subtitle = "Hindi, Telugu, and Tamil are the languages with the most films",
    x = "Number of Unique Films",
    y = NULL
  ) +
  theme_cbfc()

1.2.2 Reasons for Modification

The most common reasons for modifications, based on the AI-classified content types.

mods_by_content_data <- data %>%
  filter(!is.na(ai_content_types)) %>%
  count(ai_content_types, sort = TRUE) %>%
  top_n(15, n) %>%
  mutate(
    pretty_name = str_replace_all(ai_content_types, "_", " ") %>% str_to_title(),
    pretty_name = fct_reorder(pretty_name, n)
  )

write_json(mods_by_content_data, "modifications_by_content.json", pretty = TRUE, auto_unbox = TRUE)

mods_by_content_data %>%
  ggplot(aes(x = n, y = pretty_name)) +
  geom_col(fill = secondary_color, alpha = 0.9) +
  geom_text(aes(label = comma(n)), hjust = -0.15, size = 3, color = "gray20") +
  scale_x_continuous(
    labels = comma,
    expand = expansion(mult = c(0, 0.1))
  ) +
  labs(
    title = "Most Common Reasons for Film Modifications",
    x = "Number of Modifications",
    y = "Content Category"
  ) +
  theme_cbfc()

1.2.3 Duration of Edits by Action

We’ve classified each modification log into verbs depending on what action was taken. For example, adding a smoking disclaimer might be an ‘Insertion’ but removing an entire scene is ‘Deletion’. There are also replacements, audio modifications, visual modifications (such as blurs), and so on. We can look at the general distribution for each of these edits.

duration_summary <- data %>%
  filter(total_modified_time_secs > 0, !is.na(ai_action)) %>%
  group_by(ai_action) %>%
  summarise(
    min = min(total_modified_time_secs, na.rm = TRUE),
    q1 = quantile(total_modified_time_secs, 0.25, na.rm = TRUE),
    median = median(total_modified_time_secs, na.rm = TRUE),
    q3 = quantile(total_modified_time_secs, 0.75, na.rm = TRUE),
    max = max(total_modified_time_secs, na.rm = TRUE),
    count = n(),
    .groups = 'drop'
  ) %>%
  mutate(pretty_name = str_replace_all(ai_action, "_", " ") %>% str_to_title()) %>%
  arrange(median)


# Export sample of raw data for BoxX component
duration_boxplot_data <- data %>%
   filter(
    total_modified_time_secs > 0, 
    total_modified_time_secs < 1400, # Found that anything above this is mostly incorrectly entered data
    !is.na(ai_action),
    ai_action != 'content_overlay',
    movie_name != 'ARISHADVARGA' # this movie clearly has a data processing error where the times are added cumulatively https://archive.org/details/cbfc-ecinepramaan-100020292100000261
  ) %>%
  mutate(pretty_name = str_replace_all(ai_action, "_", " ") %>% str_to_title()) %>%
  group_by(ai_action, pretty_name) %>%
  # Sample up to 500 points. If a group has < 500 points, it will take all of them.
  slice_sample(n = 500) %>%
  ungroup() %>%
  select(
    action = ai_action,
    category = pretty_name, 
    duration = total_modified_time_secs
  )


write_json(duration_summary, "duration_by_action_summary.json", pretty = TRUE, auto_unbox = TRUE)
write_json(duration_boxplot_data, "duration_by_action_boxplot.json", pretty = TRUE, auto_unbox = TRUE)

  duration_boxplot_data %>% 
  ggplot(aes(
    x = fct_reorder(category, duration, .fun = median),
    y = duration,
    fill = category
  )) +
  geom_boxplot(show.legend = FALSE, alpha = 0.8, fill = wes_colors[3]) +
  scale_y_log10(
    breaks = c(1, 10, 60, 300, 1800),
    labels = c("1 sec", "10 secs", "1 min", "5 mins", "30 mins")
  ) +
  coord_flip() +
  labs(
    title = "How Long are Different Types of Edits?",
    subtitle = "Distribution of modification durations for each action type on a logarithmic scale.",
    x = NULL,
    y = "Duration of Modification"
  ) +
  theme_cbfc()

1.3 Modification Reasons by Movie Rating

The dataset includes tags for what reason a particular modification was made; violence, profanity and so on. While I have a pretty good idea of what this will give, we can see what is the breakdown of each reason by the rating for that movie (rating is the U, UA, A classification for who can watch the movie).

rating_breakdown <- data %>%
  filter(rating %in% c("U", "UA", "A"), !is.na(ai_content_types)) %>%
  mutate(content_category = case_when(
    ai_content_types %in% c("sexual_explicit", "sexual_suggestive") ~ "Sexual Content",
    ai_content_types == "profanity" ~ "Profanity",
    ai_content_types == "violence" ~ "Violence",
    ai_content_types == "substance" ~ "Substance Use",
    ai_content_types == "religious" ~ "Religious Content",
    ai_content_types == "political" ~ "Political Content",
    TRUE ~ "Other"
  )) %>%
  count(rating, content_category, name = "modification_count", sort = TRUE) %>%
  group_by(rating) %>%
  mutate(percentage = modification_count / sum(modification_count)) %>%
  ungroup()

common_types <- rating_breakdown %>%
  filter(content_category != "Other") %>%
  group_by(content_category) %>%
  summarise(total = sum(modification_count), .groups = 'drop') %>%
  pull(content_category)

rating_breakdown %>%
  filter(content_category %in% common_types) %>%
  ggplot(aes(
    x = percentage,
    y = fct_reorder(content_category, percentage, .desc = FALSE),
    fill = rating
  )) +
  geom_col(color = "white", linewidth = 0.5) +
  facet_wrap(~rating, scales = "free_y", ncol = 3) +
  scale_x_continuous(labels = percent_format(accuracy = 1)) +
  scale_fill_manual(
    values = c("U" = wes_colors[1], "UA" = wes_colors[2], "A" = wes_colors[3])
  ) +
  labs(
    title = "Censorship reasons by film rating",
    subtitle = "Proportional breakdown of modification reasons within each film rating category.",
    x = "% of all modifications for this rating",
    y = NULL
  ) +
  theme_cbfc() +
  theme(
    strip.text = element_text(size = 14, face = "bold", color = "gray20", margin = margin(t = 5, b = 10)),
    strip.background = element_blank(),
    panel.grid.major.x = element_line(color = "gray90", linetype = "dotted"),
    panel.spacing.x = unit(2, "lines"),
    legend.position = "none"
  )

write_json(rating_breakdown, "rating_breakdown.json", pretty = TRUE, auto_unbox = TRUE)

1.4 Average Cut Time by Regional Office

Different regional offices of the CBFC may apply censorship standards differently. Here, we calculate the average total time modified per film for each major office. We filter out extreme outliers (films with more than 30 minutes of cuts) and only include offices that have certified a sufficient number of films (at least 50).

film_summary <- data %>%
  filter(!is.na(office) & !str_detect(office, "\\.mp4$")) %>%
  group_by(id, movie_name, office) %>%
  summarise(
    total_secs = sum(total_modified_time_secs, na.rm = TRUE),
    .groups = 'drop'
  ) %>%
  filter(total_secs > 0, total_secs < 1800)

office_stats <- film_summary %>%
  group_by(office) %>%
  filter(n() >= 50) %>%
  summarise(
    film_count = n(),
    mean_total_secs = mean(total_secs, na.rm = TRUE),
    se = sd(total_secs, na.rm = TRUE) / sqrt(n()),
    ci_lower_secs = pmax(0, mean_total_secs - 1.96 * se),
    ci_upper_secs = mean_total_secs + 1.96 * se,
    .groups = 'drop'
  ) %>%
  arrange(desc(mean_total_secs))

write_json(office_stats, "cuts_by_office.json", pretty = TRUE, auto_unbox = TRUE)

summary_table <- office_stats %>%
  mutate(
    `Average Time` = format_seconds(mean_total_secs),
    `95% CI Lower` = format_seconds(ci_lower_secs),
    `95% CI Upper` = format_seconds(ci_upper_secs)
  ) %>%
  select(
    Office = office,
    `Films Analyzed` = film_count,
    `Average Time`,
    `95% CI Lower`,
    `95% CI Upper`
  )

summary_table %>%
  gt() %>%
  tab_header(
    title = "Average Modification Time per Film by CBFC Regional Office",
    subtitle = "Analysis of offices with at least 50 certified films"
  ) %>%
  tab_style(
    style = list(
      cell_fill(color = wes_colors[1], alpha = 0.3),
      cell_text(weight = "bold")
    ),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = cell_text(align = "center"),
    locations = cells_body(columns = c(`Films Analyzed`, `Average Time`, `95% CI Lower`, `95% CI Upper`))
  ) %>%
  cols_align(
    align = "left",
    columns = Office
  ) %>%
  tab_options(
    table.font.names = "Atkinson Hyperlegible",
    heading.title.font.size = 16,
    heading.subtitle.font.size = 12,
    column_labels.font.size = 12,
    table.font.size = 11
  )
Average Modification Time per Film by CBFC Regional Office
Analysis of offices with at least 50 certified films
Office Films Analyzed Average Time 95% CI Lower 95% CI Upper
Cuttack 118 9m 10s 7m 38s 10m 43s
Delhi 442 4m 06s 3m 33s 4m 38s
Mumbai 6573 3m 51s 3m 42s 3m 59s
Thiruvananthpuram 688 3m 16s 2m 55s 3m 36s
Chennai 1657 3m 05s 2m 52s 3m 19s
Kolkata 209 2m 32s 1m 59s 3m 04s
Bangalore 982 2m 13s 1m 59s 2m 27s
Hyderabad 1055 2m 01s 1m 49s 2m 13s

1.6 Distribution of Modification Durations

This histogram shows the distribution of total modification times for films that had at least one cut. Approximately half of the films in the dataset have ‘zero seconds’ of edits (meaning modifications might have been made but they were not logged with a duration of edit); this chart focuses only on those that have duration values.

film_data <- data %>%
  group_by(id) %>%
  summarise(
    total_modified_time_secs = sum(total_modified_time_secs, na.rm = TRUE),
    .groups = 'drop'
  )

total_films <- nrow(film_data)
percent_zero <- mean(film_data$total_modified_time_secs == 0, na.rm = TRUE)
film_data_positive <- film_data %>% filter(total_modified_time_secs > 0)
median_val_positive <- median(film_data_positive$total_modified_time_secs)

p_dist <- ggplot(film_data_positive, aes(x = total_modified_time_secs)) +
  geom_histogram(
    aes(y = after_stat(count) / total_films * 100),
    fill = wes_colors[2],
    bins = 40,
    boundary = 0
  ) +
  geom_vline(
    xintercept = median_val_positive,
    linetype = "dashed",
    color = "gray20",
    linewidth = 0.8
  ) +
  # Use a log10 scale on the x-axis because the data is highly skewed.
  scale_x_log10(
    breaks = c(1, 10, 60, 300, 1800),
    labels = c("1s", "10s", "1m", "5m", "30m")
  ) +
  scale_y_continuous(
    expand = expansion(mult = c(0, 0.05)),
    labels = percent_format(scale = 1)
  ) +
  labs(
    title = "Distribution of Modification Times",
    subtitle = str_glue("Comparing total modification time for films with at least one cut.
                        This chart excludes the {percent(percent_zero, accuracy=1)} of films with zero modifications."),
    x = "Total Modification Time (Logarithmic Scale)",
    y = "Percent of All Films"
  ) +
  theme_cbfc() +
  theme(
    panel.grid.major.x = element_blank()
  )

print(p_dist)

# Export the data used for the histogram to a JSON file.
# We use ggplot_build() to extract the computed data from the plot object.
hist_data_for_export <- ggplot_build(p_dist)$data[[1]] %>%
  select(x_min = xmin, x_max = xmax, count, y_percent_total = y)

export_data_dist <- list(
  histogram_bins = hist_data_for_export,
  statistics = list(
    median_positive_secs = median_val_positive,
    total_films = total_films,
    percent_zero_mods = percent_zero
  ),
  axis_config = list(
    breaks = c(1, 10, 60, 300, 1800),
    labels = c("1s", "10s", "1m", "5m", "30m")
  )
)

write_json(export_data_dist, "histogram_data.json", pretty = TRUE, auto_unbox = TRUE)

1.8 Keyword Co-occurrence Network

This analysis explores which terms tend to appear together within the same film’s modification records.

We calculate the pairwise correlation between the 50 most common keywords and visualize the results as a network graph.

This contains a lot of NSFW stuff, but hiding it would…probably defeat the point.

reference_words <- data %>%
  filter(!is.na(ai_reference)) %>%
  mutate(word = str_split(tolower(ai_reference), "\\|")) %>%
  unnest(word) %>%
  filter(!is.na(word), !str_detect(word, "violence|scene|visual|dialogue")) %>%
  select(id, word)

word_counts <- reference_words %>%
  count(word, sort = TRUE)

word_pairs <- reference_words %>%
  filter(word %in% (word_counts %>% top_n(50, n) %>% pull(word))) %>%
  pairwise_cor(item = word, feature = id, sort = TRUE)

word_pairs %>%
  filter(correlation > 0.05) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
  geom_edge_link(aes(edge_alpha = correlation), show.legend = FALSE) +
  geom_node_point(color = wes_colors[3], size = 5) +
  geom_node_text(aes(label = name), repel = TRUE) +
  theme_void() +
  labs(
    title = "Which Censorship Terms Appear Together?",
    subtitle = "Co-occurrence network of the 50 most common keywords in CBFC modification records."
  )

# Export co-occurrence network data
network_export <- list(
  word_counts = word_counts %>% top_n(50, n),
  word_pairs = word_pairs %>% filter(correlation > 0.05)
)
write_json(network_export, "keyword_network.json", pretty = TRUE, auto_unbox = TRUE)

1.9 Most Important Keywords by Category (TF-IDF)

While the network graph shows which words co-occur, it doesn’t tell us which words are most characteristic of a specific censorship category. For that, we use a metric called Term Frequency-Inverse Document Frequency (TF-IDF).

TF-IDF identifies words that are common within one category (e.g., “blood” in the “violence” category) but are relatively rare in all other categories.

reference_tokens <- data %>%
  filter(!is.na(ai_reference), !is.na(ai_content_types)) %>%
  select(ai_content_types, ai_reference) %>%
  mutate(word = str_split(tolower(ai_reference), "\\|")) %>%
  unnest(word) %>%
  filter(word != "")

reference_tfidf <- reference_tokens %>%
  count(ai_content_types, word, sort = TRUE) %>%
  bind_tf_idf(term = word, document = ai_content_types, n = n) %>%
  arrange(desc(tf_idf))

top_terms_table <- reference_tfidf %>%
  group_by(ai_content_types) %>%
  slice_max(order_by = tf_idf, n = 5) %>%
  ungroup() %>%
  select(Category = ai_content_types, Term = word, `TF-IDF` = tf_idf) %>%
  filter(Category %in% c("violence", "profanity", "sexual_suggestive", "substance", "political", "religious"))

top_terms_table %>%
  gt() %>%
  tab_header(
    title = "Most Distinctive Keywords by Censorship Category",
    subtitle = "Using Term Frequency-Inverse Document Frequency (TF-IDF) analysis"
  ) %>%
  fmt_number(
    columns = `TF-IDF`,
    decimals = 3
  ) %>%
  tab_style(
    style = list(
      cell_fill(color = wes_colors[2], alpha = 0.3),
      cell_text(weight = "bold")
    ),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = cell_text(transform = "capitalize"),
    locations = cells_body(columns = Category)
  ) %>%
  tab_style(
    style = cell_text(style = "italic"),
    locations = cells_body(columns = Term)
  ) %>%
  cols_align(
    align = "center",
    columns = `TF-IDF`
  ) %>%
  tab_options(
    table.font.names = "Atkinson Hyperlegible",
    heading.title.font.size = 16,
    heading.subtitle.font.size = 12,
    column_labels.font.size = 12,
    table.font.size = 11,
    row_group.font.weight = "bold"
  )
Most Distinctive Keywords by Censorship Category
Using Term Frequency-Inverse Document Frequency (TF-IDF) analysis
Category Term TF-IDF
political national flag 0.020
political modi 0.015
political indian flag 0.009
political pakistan 0.007
political political leaders 0.007
profanity munda 0.005
profanity bhenchod 0.004
profanity iththa 0.003
profanity bhadkov 0.003
profanity maal 0.003
religious superstition 0.044
religious black magic 0.015
religious religion 0.014
religious superstitions 0.012
religious religious sentiments 0.011
sexual_suggestive kissing scene 0.022
sexual_suggestive cleavage 0.019
sexual_suggestive sexual_suggestive 0.018
sexual_suggestive kissing 0.017
sexual_suggestive love making scene 0.017
substance tobacco 0.028
substance liquor label 0.017
substance akshay kumar 0.016
substance liquor labels 0.015
substance rahul dravid 0.014
violence blood 0.032
violence bloodshed 0.009
violence killing scene 0.007
violence dead bodies 0.007
violence dead body 0.006
write_json(reference_tfidf %>% slice_head(n = 300), "tfidf_analysis.json", pretty = TRUE, auto_unbox = TRUE)

1.10 Top Censored Films by Office

Identifies the top films that had the most time removed by each major CBFC regional office.

film_level_summary <- data %>%
  filter(!is.na(office) & !str_detect(office, "\\.mp4$")) %>%
  group_by(id, movie_name, office, language, cert_date, cert_no) %>%
  summarise(
    total_cuts = n(),
    total_time_removed_secs = sum(total_modified_time_secs, na.rm = TRUE),
    .groups = 'drop'
  ) %>%
  filter(total_time_removed_secs > 0, total_time_removed_secs < 1800) %>%
  mutate(
    year = map2_dbl(cert_date, cert_no, ~ extract_year(.x, .y)),
    cleaned_name = map_chr(movie_name, clean_name),
    slug = map2_chr(cleaned_name, year, make_slug)
  )

top_censored_by_office <- film_level_summary %>%
  group_by(office) %>%
  arrange(desc(total_time_removed_secs)) %>%
  slice_head(n = 10) %>%
  ungroup() %>%
  mutate(
    duration_formatted = format_seconds(total_time_removed_secs)
  ) %>%
  arrange(office, desc(total_time_removed_secs)) %>%
  select(Office = office, Language = language, `Film Name` = cleaned_name, 
         `Time Removed` = duration_formatted, `Total Cuts` = total_cuts, Slug = slug)

display_table <- top_censored_by_office %>%
  select(-Slug)

display_table %>%
  gt() %>%
  tab_header(
    title = "Top 10 Most Censored Films by Time Removed",
    subtitle = "Films with the highest modification times for each regional office"
  ) %>%
  tab_style(
    style = list(
      cell_fill(color = wes_colors[3], alpha = 0.3),
      cell_text(weight = "bold")
    ),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = cell_text(style = "italic"),
    locations = cells_body(columns = `Film Name`)
  ) %>%
  cols_align(
    align = "center",
    columns = c(Language, `Time Removed`, `Total Cuts`)
  ) %>%
  cols_align(
    align = "left",
    columns = c(Office, `Film Name`)
  ) %>%
  tab_options(
    table.font.names = "Atkinson Hyperlegible",
    heading.title.font.size = 16,
    heading.subtitle.font.size = 12,
    column_labels.font.size = 12,
    table.font.size = 11
  ) %>%
  tab_style(
    style = cell_borders(
      sides = c("top", "bottom"),
      color = "lightgray",
      weight = px(1)
    ),
    locations = cells_body()
  )
Top 10 Most Censored Films by Time Removed
Films with the highest modification times for each regional office
Office Language Film Name Time Removed Total Cuts
Bangalore Kannada NEGILA ODEYA 26m 22s 5
Bangalore Tamil ROCKY 24m 16s 6
Bangalore Kannada DAMAYANTHI 23m 21s 13
Bangalore Tamil GAJAKESSARI 23m 05s 8
Bangalore Hindi REHNA NAHI BIN TERE 23m 02s 1
Bangalore Tamil GOOGLY 22m 03s 6
Bangalore Hindi KISS 21m 36s 8
Bangalore Kannada M E S T R I (REVISED) 20m 52s 23
Bangalore Tamil RUSTUM 20m 19s 6
Bangalore Kannada TIGER GALLI 19m 45s 188
Chennai Telugu PULIDEBBA (REVISED) 28m 25s 18
Chennai Tamil PATCHIRAJA PARAVAI 26m 42s 4
Chennai Tamil 'AALAPIRANTHAVAN' (REVISED) 25m 23s 27
Chennai Tamil NERAM NALLA NERAM (REVISED) 25m 01s 29
Chennai Tamil NAAN UNNA NINACHEN (REVISED) 24m 34s 28
Chennai Tamil THEEVIRAM 23m 43s 10
Chennai Hindi GHAJINI 23m 27s 7
Chennai Hindi AANGILA PADAM 22m 57s 6
Chennai Telugu BANDIPOTU SIMHAM (REVISED) 22m 47s 22
Chennai Telugu PAGA PATTINA SIMHAM (REVISED) 22m 28s 18
Cuttack Bhojpuri IDDARAMMAYILATHO 28m 53s 7
Cuttack Odia TOR MOR LOVE STORY 27m 57s 10
Cuttack Awadhi VETTAIKAARAN 26m 25s 6
Cuttack Odia MU LOVER NO - 1 26m 10s 11
Cuttack Bhojpuri V I P 2 25m 56s 6
Cuttack Odia PREMA TOTE DURU JUHARA 25m 54s 7
Cuttack Odia JHIATE TO PARI 25m 43s 6
Cuttack Odia DASAHARA 23m 23s 7
Cuttack Bhojpuri MISHRA FOR SALE 23m 12s 7
Cuttack Bhojpuri SOWKHYAM 23m 02s 6
Delhi Hindustani LAKSHMI 28m 11s 6
Delhi Hindustani ROWDY MUNNA 27m 39s 7
Delhi Bhojpuri KHALEJA (MAHESH KHALEJA) 27m 22s 7
Delhi Odia CHANDRAMUKHI 27m 00s 7
Delhi Hindustani D J 26m 50s 6
Delhi Hindustani SUPER 26m 35s 7
Delhi Awadhi POWER RETURNS ( RACE GURRAM ) 24m 47s 5
Delhi Hindustani RACHHA 23m 30s 5
Delhi Odia DHARMADURAI 22m 31s 8
Delhi Odia TARAK 22m 28s 8
Guwahati Hindi CAPITAL 3m 00s 5
Guwahati Manipuri NGAMNABA LANFAMSE 2m 45s 8
Guwahati Bodo BEKAR ROMEO 1m 38s 6
Guwahati Hindi Dubbed BARUN RAI AND THE HOUSE ON THE CLIFF 1m 34s 10
Guwahati Assamese RAKSHAK - THE SAVIOUR 1m 08s 3
Guwahati Assamese BAD BOYS 0m 50s 2
Guwahati Assamese RONGATAPU 1982 0m 32s 3
Guwahati Khasi KYNJAH 0m 27s 7
Guwahati Hindi KOOKI 0m 24s 6
Guwahati Assamese MOI ETI NIXHASOR (KODUWA - THE NIGHTBIRD) 0m 18s 1
Hyderabad Telugu "NARAKASURA" 25m 00s 15
Hyderabad Telugu NANI 23m 51s 40
Hyderabad Telugu ALLUDA MAJAAKAA 23m 11s 38
Hyderabad Malayalam SIMHA MUGHAM 20m 46s 27
Hyderabad Telugu "I LOVE YOU IDIOT" 18m 54s 1
Hyderabad Hindi SAMAJAVARAGAMANA 18m 39s 6
Hyderabad Telugu AASHAADAM PELLIKODUKU ( A TO UA) 17m 03s 19
Hyderabad Hindi KONAPURAMLO JARIGINA KATHA 16m 48s 7
Hyderabad Hindi "SPARK LIFE" 16m 33s 16
Hyderabad Telugu 1948 AKHANDA BHARATH 16m 25s 19
Kolkata Bengali BAGHER BACCHA 28m 24s 8
Kolkata Bengali DESHBHOKTO KHILADI 27m 57s 8
Kolkata Bengali PYAR KI JUNG 21m 39s 6
Kolkata Bengali VANDE BHARAT (SAVE INDIA) 16m 15s 4
Kolkata Bengali MAAHIYA (REVISED) 13m 23s 11
Kolkata Bengali MAHANAYAK UTTAM KUMAR ( THE METRO STATION ) ( REVISED) 11m 43s 9
Kolkata Bengali PORNOMOCHI (REVISED) 10m 24s 44
Kolkata Bengali LAAL RANGER DUNIYA (REVISED) 9m 36s 65
Kolkata Bengali KOLIJUGER SHIKHONDI 9m 23s 4
Kolkata Bengali CIRCLE (REVISED) 9m 19s 21
Mumbai Hindustani MASS 29m 52s 7
Mumbai Bhojpuri DAROGA BABUNI 29m 50s 35
Mumbai Bhojpuri JIYAB SHAAN SE 29m 46s 6
Mumbai Hindustani DON ( DON SEENU) 29m 44s 6
Mumbai Urdu PALAHATI BRAHMA NAIDU - SHEZADA 29m 43s 6
Mumbai Hindustani NAKSHATRAM 29m 43s 1
Mumbai Bengali SAPTAMA INDRIYA 29m 38s 6
Mumbai Hindi HAI 29m 37s 9
Mumbai Hindustani AATAADISTHA 29m 35s 7
Mumbai Hindi DARINGBAAZ KHILADI RETURNS (THOOTTAL POO MALARUM) 29m 24s 8
Thiruvananthpuram Kannada MARCO 29m 32s 2
Thiruvananthpuram Malayalam THANKAMANI 26m 05s 8
Thiruvananthpuram Malayalam ARDHARAATHRI (REVISED) 25m 10s 21
Thiruvananthpuram Malayalam ARTHARAATHRI PANTHRANDU MUTHAL AARU VARE 25m 07s 4
Thiruvananthpuram Malayalam PANI 24m 20s 5
Thiruvananthpuram Malayalam ATTENTION PLEASE 22m 28s 3
Thiruvananthpuram Malayalam VIRAL 2020 22m 24s 2
Thiruvananthpuram Malayalam UDAL 21m 39s 69
Thiruvananthpuram Malayalam KARIMPULI (RE-REVISED) 21m 32s 17
Thiruvananthpuram Malayalam ARIKU 20m 10s 4
# Export top censored films data with slug included
write_json(top_censored_by_office, "top_censored_films.json", pretty = TRUE, auto_unbox = TRUE)

1.11 Further Information

For more details, interactive charts, and the full explorer, please visit our project website: https://cbfc.watch

The analysis was conducted by Aman Bhargava and Vivek Matthew for Diagram Chasing.

1.11.1 How to Cite

Bhargava, A., Matthew, V., & Diagram Chasing. (2025). Analyzing Film Censorship in India: CBFC Watch. Retrieved from https://cbfc.watch.

BibTeX Entry

For use in LaTeX documents, you can use the following BibTeX entry:

@misc{Bhargava2025CBFC,
  author = {Bhargava, Aman and Matthew, Vivek and {Diagram Chasing}},
  title  = {Analyzing Film Censorship in India: CBFC Watch},
  year   = {2025},
  month  = {September},
  howpublished = {\url{https://cbfc.watch}},
  note   = {Analysis and visualizations by Diagram Chasing. Last accessed: \today}
}
LS0tCnRpdGxlOiAiQW5hbHl6aW5nIEZpbG0gQ2Vuc29yc2hpcCBpbiBJbmRpYTogQ0JGQyBXYXRjaCIKYXV0aG9yOiAiQW5hbHlzaXMgYnkgQW1hbiBCaGFyZ2F2YSBhbmQgVml2ZWsgTWF0dGhldywgRGlhZ3JhbSBDaGFzaW5nIgpkYXRlOiAiVXBkYXRlZDogYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICBmaWdfd2lkdGg6IDEwCiAgICBmaWdfaGVpZ2h0OiA2CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIGtlZXBfbWQ6IGZhbHNlCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKPHN0eWxlPgpAaW1wb3J0IHVybCgnaHR0cHM6Ly9mb250cy5nb29nbGVhcGlzLmNvbS9jc3MyP2ZhbWlseT1BdGtpbnNvbitIeXBlcmxlZ2libGU6d2dodEA0MDA7NzAwJmRpc3BsYXk9c3dhcCcpOwoKYm9keSB7CiAgZm9udC1mYW1pbHk6ICdBdGtpbnNvbiBIeXBlcmxlZ2libGUnLCBzYW5zLXNlcmlmOwogIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWNvbG9yLXNlcGlhKTsKICBjb2xvcjogdmFyKC0tY29sb3Itc2VwaWEtYnJvd24pOwogIGxpbmUtaGVpZ2h0OiAxLjY7CiAgbWF4LXdpZHRoOiAxMjAwcHg7CiAgbWFyZ2luOiAwIGF1dG87CiAgcGFkZGluZzogMnJlbTsKfQo8L3N0eWxlPgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoem9vKQpsaWJyYXJ5KGpzb25saXRlKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHdpZHlyKQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoZm9yY2F0cykKbGlicmFyeSh3ZXNhbmRlcnNvbikKbGlicmFyeShndCkKCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBlY2hvID0gVFJVRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgbWVzc2FnZSA9IEZBTFNFLAogIGZpZy53aWR0aCA9IDEwLAogIGZpZy5oZWlnaHQgPSA2LAogIGRwaSA9IDMwMCwKICBvdXQud2lkdGggPSAiMTAwJSIKKQoKb3B0aW9ucyhzY2lwZW4gPSA5OTkpCgp3ZXNfY29sb3JzIDwtIHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMSIsIDgsIHR5cGUgPSAiY29udGludW91cyIpCnByaW1hcnlfY29sb3IgPC0gIiMzMTgyYmQiCnNlY29uZGFyeV9jb2xvciA8LSAiI2RlNzdhZSIKdGVydGlhcnlfY29sb3IgPC0gIiMyYzdmYjgiCgp0aGVtZV9jYmZjIDwtIGZ1bmN0aW9uKCkgewogIHRoZW1lX21pbmltYWwoYmFzZV9mYW1pbHkgPSAic2FucyIpICsKICAgIHRoZW1lKAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiwgbWFyZ2luID0gbWFyZ2luKGIgPSA4KSksCiAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExLCBjb2xvciA9ICJncmF5NDAiLCBtYXJnaW4gPSBtYXJnaW4oYiA9IDE1KSksCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiZ3JheTQwIiksCiAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExLCBmYWNlID0gImJvbGQiLCBjb2xvciA9ICJncmF5MjAiKSwKICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMjAsIDI1LCAyMCwgMjUpCiAgICApCn0KCmNsZWFuX25hbWUgPC0gZnVuY3Rpb24obmFtZSkgewogIGlmIChpcy5uYShuYW1lKSB8fCBuYW1lID09ICIiKSByZXR1cm4oIiIpCiAgbmFtZSA8LSBzdHJfdHJpbShuYW1lKSAlPiUKICAgIHN0cl9yZXBsYWNlKCJbXFwuLCE/OzpdKyQiLCAiIikgJT4lCiAgICBzdHJfcmVwbGFjZSgiXltcXC4sIT87Ol0rIiwgIiIpICU+JQogICAgc3RyX3JlcGxhY2UoJ14iezIsM30oLis/KSJ7MiwzfSQnLCAiXFwxIikgJT4lCiAgICBzdHJfcmVwbGFjZSgiXicoLis/KSckIiwgIlxcMSIpICU+JQogICAgc3RyX3JlcGxhY2UoIlxcKiskIiwgIiIpICU+JQogICAgc3RyX3JlcGxhY2VfYWxsKCJcXHMrIiwgIiAiKQogIHN0cl90cmltKG5hbWUpCn0KCm1ha2Vfc2x1ZyA8LSBmdW5jdGlvbihuYW1lLCB5ZWFyKSB7CiAgaWYgKGlzLm5hKG5hbWUpIHx8IG5hbWUgPT0gIiIpIHJldHVybigidW5rbm93biIpCiAgc2x1ZyA8LSBjbGVhbl9uYW1lKG5hbWUpICU+JSAKICAgIHN0cl90b19sb3dlcigpICU+JQogICAgc3RyX3JlcGxhY2VfYWxsKCJbXlxcd1xccy1dIiwgIiIpICU+JQogICAgc3RyX3JlcGxhY2VfYWxsKCJbXFxzLV0rIiwgIi0iKSAlPiUKICAgIHN0cl9yZXBsYWNlX2FsbCgiXi0rfC0rJCIsICIiKQogIAogIGlmICghaXMubmEoeWVhcikgJiYgeWVhciAhPSAiIikgewogICAgcGFzdGUwKHNsdWcsICItIiwgeWVhcikKICB9IGVsc2UgewogICAgc2x1ZwogIH0KfQoKZXh0cmFjdF95ZWFyIDwtIGZ1bmN0aW9uKGNlcnRfZGF0ZSwgY2VydF9ubyA9IE5VTEwpIHsKICBpZiAoaXMubnVsbChjZXJ0X2RhdGUpKSBjZXJ0X2RhdGUgPC0gTkEKICBpZiAoaXMubnVsbChjZXJ0X25vKSkgY2VydF9ubyA8LSBOQQogIAogIGlmICghaXMubmEoY2VydF9kYXRlKSkgewogICAgY2VydF9kYXRlX3N0ciA8LSBhcy5jaGFyYWN0ZXIoY2VydF9kYXRlKQogICAgaWYgKGNlcnRfZGF0ZV9zdHIgIT0gIiIgJiYgY2VydF9kYXRlX3N0ciAhPSAiTkEiKSB7CiAgICAgIHRyeUNhdGNoKHsKICAgICAgICB5ZWFyX2Zyb21fZGF0ZSA8LSB5ZWFyKGFzLkRhdGUoY2VydF9kYXRlX3N0ciwgZm9ybWF0ID0gIiVZLSVtLSVkIikpCiAgICAgICAgaWYgKCFpcy5uYSh5ZWFyX2Zyb21fZGF0ZSkpIHJldHVybih5ZWFyX2Zyb21fZGF0ZSkKICAgICAgfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7fSkKICAgIH0KICB9CiAgCiAgaWYgKCFpcy5uYShjZXJ0X25vKSkgewogICAgY2VydF9ub19zdHIgPC0gYXMuY2hhcmFjdGVyKGNlcnRfbm8pCiAgICBpZiAoY2VydF9ub19zdHIgIT0gIiIgJiYgY2VydF9ub19zdHIgIT0gIk5BIikgewogICAgICB0cnlDYXRjaCh7CiAgICAgICAgcGFydHMgPC0gc3RyX3NwbGl0KGNlcnRfbm9fc3RyLCAiLSIpW1sxXV0KICAgICAgICBpZiAobGVuZ3RoKHBhcnRzKSA+PSAyKSB7CiAgICAgICAgICBiZWZvcmVfbGFzdCA8LSBwYXJ0c1tsZW5ndGgocGFydHMpIC0gMV0KICAgICAgICAgIHllYXJfbWF0Y2ggPC0gc3RyX2V4dHJhY3QoYmVmb3JlX2xhc3QsICJcXGR7NH0kIikKICAgICAgICAgIGlmICghaXMubmEoeWVhcl9tYXRjaCkpIHsKICAgICAgICAgICAgeWVhcl92YWwgPC0gYXMubnVtZXJpYyh5ZWFyX21hdGNoKQogICAgICAgICAgICBpZiAoeWVhcl92YWwgPj0gMTkwMCAmJiB5ZWFyX3ZhbCA8PSAyMDkwKSB7CiAgICAgICAgICAgICAgcmV0dXJuKHllYXJfdmFsKQogICAgICAgICAgICB9CiAgICAgICAgICB9CiAgICAgICAgfQogICAgICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHt9KQogICAgfQogIH0KICAKICByZXR1cm4oTkFfcmVhbF8pCn0KCmZvcm1hdF9zZWNvbmRzIDwtIGZ1bmN0aW9uKHNlY3MpIHsKICBtaW51dGVzIDwtIGZsb29yKHNlY3MgLyA2MCkKICBzZWNvbmRzIDwtIHJvdW5kKHNlY3MgJSUgNjApCiAgcmV0dXJuKHNwcmludGYoIiVkbSAlMDJkcyIsIG1pbnV0ZXMsIHNlY29uZHMpKQp9CmBgYAoKLS0tCgoKKipOb3RlKio6IFRoaXMgbm90ZWJvb2sgd2FzIHVwZGF0ZWQgb24gVHVlc2RheSAxNnRoIFNlcHRlbWJlciwgMzowMCBQTSB0byBjb3JyZWN0IGEgZGF0YSBwcmVwcm9jZXNzaW5nIGVycm9yLCB3aGljaCBlcnJvbmVvdXNseSBmaWx0ZXJlZCBvdXQgc29tZSBkYXRhIGZyb20gYmVpbmcgaW5jbHVkaW5nIGluIHRoZSBzdW1tYXJpZXMuIFRoZSBjb3JyZWN0aW9uIGlzIFt2aWV3YWJsZSBoZXJlXShodHRwczovL2dpdGh1Yi5jb20vZGlhZ3JhbS1jaGFzaW5nL2NiZmMtd2F0Y2gvY29tbWl0LzQ4MTZkM2RjMTUzMDYxZmZhYmFjZDg5ZDc5NWMwN2Q3MjJjNWJkNDIjZGlmZi0yOGRmZWJiMTU3OGFhZTNlMTZiYzIxMzRlYjVjZTRmYTBkY2QwM2ZkNWFmZjEyN2QxMjBmNzVhNmY2ZjFjY2U3TDE5NS1SMjAzKS4gVGhpcyBoYXMgYmVlbiBjb3JyZWN0ZWQuIAoKCi0tLQoKIyBJbnRyb2R1Y3Rpb24KClRoaXMgbm90ZWJvb2sgY29udGFpbnMgdGhlIGRhdGEgYW5hbHlzaXMgZm9yIHRoZSBjaGFydHMgYW5kIG51bWJlcnMgdXNlZCBvbiBvdXIgc2l0ZSwgW0NCRkMuV0FUQ0hdKGh0dHBzOi8vY2JmYy53YXRjaCkuIFRvIGVuc3VyZSBmdWxsIHRyYW5zcGFyZW5jeSB3aXRoIG91ciByZWFkZXJzLCB3ZSBhcmUgcHVibGlzaGluZyBvdXIgbWV0aG9kb2xvZ3kgYW5kIHRoZSBSIGNvZGUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgc3RhdGlzdGljcyBmb3IgdmFyaW91cyBwYXJ0cyBvZiB0aGUgc2l0ZSwgYXMgd2VsbCBhcyB0byBwcm92aWRlIGEgc3RhcnRpbmcgcG9pbnQgZm9yIG90aGVycyB3aG8gbWF5IGJlIGN1cmlvdXMgYWJvdXQgaG93IHRvIHVzZSB0aGUgZGF0YS4KCldlIGV4cGxvcmUgdGhlc2UgcXVlc3Rpb25zOgoKMS4gRG8gc29tZSByZWdpb25hbCBDQkZDIG9mZmljZXMgcmVxdWlyZSBtb3JlIG1vZGlmaWNhdGlvbnMgdGhhbiBvdGhlcnM/CjIuIEhvdyBoYXZlIHRoZSBwcmltYXJ5IHJlYXNvbnMgZm9yIGNlbnNvcnNoaXAgKGUuZy4sIHZpb2xlbmNlLCBwcm9mYW5pdHksIHNleHVhbCBjb250ZW50KSB0cmVuZGVkIG92ZXIgdGltZT8KMy4gSG93IG11Y2ggZm9vdGFnZSBpcyB0eXBpY2FsbHkgcmVtb3ZlZCBmcm9tIGEgZmlsbT8KNC4gV2hpY2ggc3BlY2lmaWMgY2Vuc29yc2hpcCBjYXRlZ29yaWVzIGFyZSBiZWNvbWluZyBtb3JlIGZyZXF1ZW50LCBhbmQgd2hpY2ggYXJlIGRlY2xpbmluZz8KNS4gV2hhdCBzcGVjaWZpYyB3b3JkcyBhbmQgdGhlbWVzIGFyZSBtb3N0IGFzc29jaWF0ZWQgd2l0aCBlYWNoIG1ham9yIGNlbnNvcnNoaXAgY2F0ZWdvcnk/CjYuIFdoaWNoIHNwZWNpZmljIGZpbG1zIGhhdmUgaGFkIHRoZSBtb3N0IGZvb3RhZ2UgcmVtb3ZlZCBieSBlYWNoIHJlZ2lvbmFsIG9mZmljZT8KCiMjIERhdGEgTG9hZGluZyBhbmQgUHJlcGFyYXRpb24KCkltcG9ydGluZyB0aGUgZGF0YXNldCwgY29ycmVjdGluZyBkYXRhIHR5cGVzLCBhbmQgc3RhbmRhcmRpemluZyBjYXRlZ29yaWNhbCBpbmZvcm1hdGlvbiBsaWtlIGxhbmd1YWdlIGFuZCByZWdpb25hbCBvZmZpY2UgbmFtZXMuCgpgYGB7ciBsb2FkLWFuZC1jbGVhbi1kYXRhfQpkYXRhIDwtIHJlYWRfY3N2KCJodHRwczovL2dpdGh1Yi5jb20vZGlhZ3JhbS1jaGFzaW5nL2NlbnNvci1ib2FyZC1jdXRzL3Jhdy9yZWZzL2hlYWRzL21hc3Rlci9kYXRhL2RhdGEuY3N2IiwgCiAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyguZGVmYXVsdCA9ICJjIikpICU+JQogIG11dGF0ZSgKICAgIGNlcnRfZGF0ZSA9IGFzLkRhdGUoY2VydF9kYXRlKSwKICAgIHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcyA9IGFzLm51bWVyaWModG90YWxfbW9kaWZpZWRfdGltZV9zZWNzKSwKICAgIGRlbGV0ZWRfc2VjcyA9IGFzLm51bWVyaWMoZGVsZXRlZF9zZWNzKSwKICAgIHJlcGxhY2VkX3NlY3MgPSBhcy5udW1lcmljKHJlcGxhY2VkX3NlY3MpLAogICAgaW5zZXJ0ZWRfc2VjcyA9IGFzLm51bWVyaWMoaW5zZXJ0ZWRfc2VjcykKICApICU+JQogICMgVGhlICdjZXJ0aWZpZXInIGNvbHVtbiBjb250YWlucyBhIHN0cmluZyBsaWtlICJFeGFtaW5pbmcgQ29tbWl0dGVlLCBNdW1iYWkiLgogICMgV2UgZXh0cmFjdCB0aGUgcmVnaW9uYWwgb2ZmaWNlIG5hbWUgYnkgc3BsaXR0aW5nIHRoZSBzdHJpbmcgYnkgdGhlIGNvbW1hCiAgIyBhbmQgdGFraW5nIHRoZSBsYXN0IGVsZW1lbnQuCiAgbXV0YXRlKAogICAgb2ZmaWNlID0gc3RyX3NwbGl0KGNlcnRpZmllciwgIiwiKSAlPiUKICAgICAgbWFwX2NocihsYXN0KSAlPiUKICAgICAgc3RyX3RyaW0oKQogICkgJT4lCiAgc2VwYXJhdGVfcm93cyhhaV9jb250ZW50X3R5cGVzLCBzZXAgPSAiXFx8IikgJT4lCiAgbXV0YXRlKGFpX2NvbnRlbnRfdHlwZXMgPSBzdHJfdHJpbShhaV9jb250ZW50X3R5cGVzKSklPiUKICAjIEZpbHRlciBvdXQgYW55IHJvd3Mgd2hlcmUgdGhlIGNvbnRlbnQgdHlwZSBpcyBlbXB0eSBhZnRlciBzZXBhcmF0aW9uLgogIyBmaWx0ZXIoYWlfY29udGVudF90eXBlcyAhPSAiIikgJT4lCiAgIyBTdGFuZGFyZGl6ZSBsYW5ndWFnZSBuYW1lcyB0byBjb3JyZWN0IGZvciB0eXBvcyBhbmQgdmFyaWF0aW9ucyBpbiB0aGUgcmF3IGRhdGEKICBtdXRhdGUoCiAgICBsYW5ndWFnZSA9IGNhc2Vfd2hlbigKICAgICAgbGFuZ3VhZ2UgPT0gIk9yaXlhIiB+ICJPZGlhIiwKICAgICAgbGFuZ3VhZ2UgPT0gIkd1anJhdGkiIH4gIkd1amFyYXRpIiwKICAgICAgbGFuZ3VhZ2UgPT0gIkNoaGF0aXNnYXJoaSIgfiAiQ2hoYXR0aXNnYXJoaSIsCiAgICAgIGxhbmd1YWdlID09ICJIYXJpeWFudmkiIH4gIkhhcnlhbnZpIiwKICAgICAgbGFuZ3VhZ2UgPT0gIkhpbmRpIER1YiIgfiAiSGluZGkgRHViYmVkIiwKICAgICAgVFJVRSB+IGxhbmd1YWdlCiAgICApCiAgKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGxhbmd1YWdlKSkKYGBgCgpgYGB7ciBvdXRwdXQtYmFkLXdvcmRzLCBpbmNsdWRlPUZBTFNFfQoKIyBQcm9jZXNzIHRoZSBhaV9yZWZlcmVuY2UgY29sdW1uIHRvIGZpbmQgdGhlIG1vc3QgY29tbW9uIHdvcmRzIHdlIGNhbiBibHVyIG91dCBvbiB0aGUgc2l0ZSBpbiBTRlcgbW9kZQojIEZvY3VzIG9uIHRoZSBtb3N0IG9mZmVuc2l2ZSBjYXRlZ29yaWVzOiBwcm9mYW5pdHkgYW5kIHNleHVhbCBjb250ZW50CmNvbW1vbl93b3Jkc190b19ibHVyIDwtIGRhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShhaV9yZWZlcmVuY2UpLCAKICAgICAgICAgYWlfY29udGVudF90eXBlcyAlaW4lIGMoInByb2Zhbml0eSIsICJzZXh1YWxfZXhwbGljaXQiLCAic2V4dWFsX3N1Z2dlc3RpdmUiKSkgJT4lCiAgbXV0YXRlKHdvcmQgPSBzdHJfc3BsaXQodG9sb3dlcihhaV9yZWZlcmVuY2UpLCAiXFx8IikpICU+JQogIHVubmVzdCh3b3JkKSAlPiUKICBmaWx0ZXIod29yZCAhPSAiIiwgCiAhd29yZCAlaW4lIGMoJ2FidXNlJywgJ2FjaWQnLCAnYWRpdHlhJywgJ2FsY29ob2wnLCAnYW1tYW4nLCAnYW1tYScsICdhbmphbGknLCAnYW5pdGhhJywgJ2FudXJhZGhhJywgJ2FyanVuJywgJ2FydW4nLCAnYXJ5YW4nLCAnYXNoYScsICdhdW50eScsICdiYWQgbGFuZ3VhZ2UnLCAnYmFkIHdvcmRzJywgJ2JhbmFuYScsICdiZWQnLCAnYmVlcicsICdiZWxseScsICdiaXQnLCAnYmxvb2QnLCAnYmxvdXNlJywgJ2JvZHknLCAnYm9tYicsICdib3knLCAnYm95cycsICdidW0nLCAnY2hlc3QnLCAnY2hyaXN0JywgJ2Nsb3RoZXMnLCAnY29jYWluZScsICdjb3VwbGUnLCAnY3JpbWUnLCAnY3VzcyB3b3JkJywgJ2RhbmNlJywgJ2RhbmNpbmcnLCAnZGFybGluZycsICdkZWFkIGJvZHknLCAnZGVyb2dhdG9yeSB3b3JkJywgJ2RpYWxvZ3VlJywgJ2RvZycsICdkb2xsJywgJ2RvbmdhJywgJ2RvdWJsZSBtZWFuaW5nJywgJ2RyZXNzJywgJ2RydWcnLCAnZHJ1Z3MnLCAnZWxpemFiZXRoJywgJ2Vuam95JywgJ2ZhY2UnLCAnZmlnaHQnLCAnZmlndXJlJywgJ2ZpbG0nLCAnZmluZ2VyJywgJ2ZvdWwgd29yZCcsICdmcmVzaCcsICdnYXknLCAnZ2VldGhhJywgJ2dob3N0JywgJ2dpcmwnLCAnZ2lybHMnLCAnZ29kJywgJ2dvcGknLCAnZ3VuJywgJ2hhbmQnLCAnaGFyYW0nLCAnaGVsbCcsICdoZXJvJywgJ2hlcm9pbicsICdoZXJvaW5lJywgJ2hvdCcsICdodWdnaW5nJywgJ2lkaW90JywgJ2luZGlhbicsICdpbmR1JywgJ2l0ZW0nLCAnaXRlbSBzb25nJywgJ2phaScsICdqYXlhbWFsaW5pJywgJ2plbm55JywgJ2plc3VzJywgJ2thc2knLCAna2lsbGluZycsICdraXJhbicsICdrcmlzaG5hJywgJ2t1bWFyJywgJ2xhZGtpJywgJ2xhZHknLCAnbGFkaWVzJywgJ2xha3NobWknLCAnbGVnJywgJ2xlZ3MnLCAnbGVzYmlhbicsICdsaXF1b3InLCAnbG92ZScsICdseXJpY3MnLCAnbWFhJywgJ21hbGxpa2EnLCAnbWFuJywgJ21hbmknLCAnbWFyaWp1YW5hJywgJ21hc3NhZ2UnLCAnbWF0dGVyJywgJ21lbicsICdtZW50YWwnLCAnbW9oYW4nLCAnbW9uZXknLCAnbW90aGVyJywgJ21vdmllJywgJ211cmRlcicsICdtdXNsaW0nLCAnbmFpbmEnLCAnbmF2ZWwnLCAnb2ZmJywgJ29ic2NlbmUgd29yZCcsICdwYW50JywgJ3BlcmlvZCcsICdwZXJzb24nLCAncGhvbmUnLCAncGllY2UnLCAncG9saWNlJywgJ3ByZWduYW50JywgJ3ByaXlhJywgJ3Byb2Zhbml0eScsICdwc3ljaG8nLCAncmFkaGEnLCAncmFnaHUnLCAncmFnaW5pJywgJ3JhamEnLCAncmFqdScsICdyYW11JywgJ3JhbXlhJywgJ3JhbmknLCAncmFzY2FsJywgJ3JhdmknLCAncmVraGEnLCAncm9tYW5jZScsICdyb21hbmNpbmcnLCAncm93ZHknLCAncnVtJywgJ3NhZCcsICdzYW50aGknLCAnc2FyZWUnLCAnc2NlbmUnLCAnc2V4dWFsX2V4cGxpY2l0JywgJ3NleHVhbF9zdWdnZXN0aXZlJywgJ3NoYWtlZWxhJywgJ3NoYW50aGknLCAnc2lkJywgJ3NpbGsgc21pdGhhJywgJ3Npc3RlcicsICdza2lydCcsICdzbGFwcGluZycsICdzbW9raW5nJywgJ3NvbicsICdzb25nJywgJ3N1bWF0aGknLCAnc3VubnkgbGVvbmUnLCAnc3VyeWEnLCAndGVhY2hlcicsICd0aGlnaCcsICd0aGlnaHMnLCAndG91Y2hpbmcnLCAndHJhbnNnZW5kZXInLCAndmFzdScsICd2aWpheScsICd2aWpqdScsICd2aWtyYW0nLCAndmlvbGVuY2UnLCAndmlzaG51JywgJ3Z1bGdhcicsICd3YWlzdCcsICd3aWZlJywgJ3dpbmUnLCAnd29tYW4nLCAnd29tZW4nLCAnd29yZCcsICd3b3JkcycsICd5b3UnKQogICkgJT4lCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpICU+JQogIHNsaWNlX2hlYWQobiA9IDUwMCkgJT4lIAogIHB1bGwod29yZCkKCndyaXRlX2pzb24oY29tbW9uX3dvcmRzX3RvX2JsdXIsICJiYWRfd29yZHMuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQoKYGBgCgojIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCgojIyMgTGFuZ3VhZ2VzIGluIHRoZSBEYXRhc2V0CgpDb3VudGluZyBob3cgbWFueSBmaWxtcyBmb3IgZWFjaCBsYW5ndWFnZSBpbiB0aGUgZGF0YXNldC4gV2UnbGwgc2hvdyB0aGUgdG9wIG9uZXMuCgpgYGB7ciBsYW5ndWFnZXMtY2hhcnR9CmZpbG1zX2J5X2xhbmd1YWdlX2RhdGEgPC0gZGF0YSAlPiUKICBkaXN0aW5jdChpZCwgbGFuZ3VhZ2UpICU+JQogIGNvdW50KGxhbmd1YWdlLCBzb3J0ID0gVFJVRSkgJT4lCiAgdG9wX24oMTAsIG4pICU+JQogIG11dGF0ZShsYW5ndWFnZSA9IGZjdF9yZW9yZGVyKGxhbmd1YWdlLCBuKSkKCndyaXRlX2pzb24oZmlsbXNfYnlfbGFuZ3VhZ2VfZGF0YSwgImZpbG1zX2J5X2xhbmd1YWdlLmpzb24iLCBwcmV0dHkgPSBUUlVFLCBhdXRvX3VuYm94ID0gVFJVRSkKCmZpbG1zX2J5X2xhbmd1YWdlX2RhdGEgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IGxhbmd1YWdlKSkgKwogIGdlb21fY29sKGZpbGwgPSB0ZXJ0aWFyeV9jb2xvciwgYWxwaGEgPSAwLjkpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY29tbWEobikpLCBoanVzdCA9IC0wLjE1LCBzaXplID0gMy41LCBjb2xvciA9ICJncmF5MjAiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKAogICAgbGFiZWxzID0gY29tbWEsCiAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4xMikpCiAgKSArCiAgbGFicygKICAgIHRpdGxlID0gIlRvcCAxNSBMYW5ndWFnZXMgYnkgTnVtYmVyIG9mIEZpbG1zIENlbnNvcmVkIiwKICAgIHN1YnRpdGxlID0gIkhpbmRpLCBUZWx1Z3UsIGFuZCBUYW1pbCBhcmUgdGhlIGxhbmd1YWdlcyB3aXRoIHRoZSBtb3N0IGZpbG1zIiwKICAgIHggPSAiTnVtYmVyIG9mIFVuaXF1ZSBGaWxtcyIsCiAgICB5ID0gTlVMTAogICkgKwogIHRoZW1lX2NiZmMoKQpgYGAKCiMjIyBSZWFzb25zIGZvciBNb2RpZmljYXRpb24KClRoZSBtb3N0IGNvbW1vbiByZWFzb25zIGZvciBtb2RpZmljYXRpb25zLCBiYXNlZCBvbiB0aGUgQUktY2xhc3NpZmllZCBjb250ZW50IHR5cGVzLgoKYGBge3IgbW9kaWZpY2F0aW9ucy1jaGFydH0KbW9kc19ieV9jb250ZW50X2RhdGEgPC0gZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKGFpX2NvbnRlbnRfdHlwZXMpKSAlPiUKICBjb3VudChhaV9jb250ZW50X3R5cGVzLCBzb3J0ID0gVFJVRSkgJT4lCiAgdG9wX24oMTUsIG4pICU+JQogIG11dGF0ZSgKICAgIHByZXR0eV9uYW1lID0gc3RyX3JlcGxhY2VfYWxsKGFpX2NvbnRlbnRfdHlwZXMsICJfIiwgIiAiKSAlPiUgc3RyX3RvX3RpdGxlKCksCiAgICBwcmV0dHlfbmFtZSA9IGZjdF9yZW9yZGVyKHByZXR0eV9uYW1lLCBuKQogICkKCndyaXRlX2pzb24obW9kc19ieV9jb250ZW50X2RhdGEsICJtb2RpZmljYXRpb25zX2J5X2NvbnRlbnQuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQoKbW9kc19ieV9jb250ZW50X2RhdGEgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IHByZXR0eV9uYW1lKSkgKwogIGdlb21fY29sKGZpbGwgPSBzZWNvbmRhcnlfY29sb3IsIGFscGhhID0gMC45KSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGNvbW1hKG4pKSwgaGp1c3QgPSAtMC4xNSwgc2l6ZSA9IDMsIGNvbG9yID0gImdyYXkyMCIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICBsYWJlbHMgPSBjb21tYSwKICAgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwLjEpKQogICkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJNb3N0IENvbW1vbiBSZWFzb25zIGZvciBGaWxtIE1vZGlmaWNhdGlvbnMiLAogICAgeCA9ICJOdW1iZXIgb2YgTW9kaWZpY2F0aW9ucyIsCiAgICB5ID0gIkNvbnRlbnQgQ2F0ZWdvcnkiCiAgKSArCiAgdGhlbWVfY2JmYygpCmBgYAoKIyMjIER1cmF0aW9uIG9mIEVkaXRzIGJ5IEFjdGlvbgoKV2UndmUgY2xhc3NpZmllZCBlYWNoIG1vZGlmaWNhdGlvbiBsb2cgaW50byB2ZXJicyBkZXBlbmRpbmcgb24gd2hhdCBhY3Rpb24gd2FzIHRha2VuLiBGb3IgZXhhbXBsZSwgYWRkaW5nIGEgc21va2luZyBkaXNjbGFpbWVyIG1pZ2h0IGJlIGFuICdJbnNlcnRpb24nIGJ1dCByZW1vdmluZyBhbiBlbnRpcmUgc2NlbmUgaXMgJ0RlbGV0aW9uJy4gVGhlcmUgYXJlIGFsc28gcmVwbGFjZW1lbnRzLCBhdWRpbyBtb2RpZmljYXRpb25zLCB2aXN1YWwgbW9kaWZpY2F0aW9ucyAoc3VjaCBhcyBibHVycyksIGFuZCBzbyBvbi4gV2UgY2FuIGxvb2sgYXQgdGhlIGdlbmVyYWwgZGlzdHJpYnV0aW9uIGZvciBlYWNoIG9mIHRoZXNlIGVkaXRzLgoKYGBge3IgZHVyYXRpb24tYm94cGxvdH0KZHVyYXRpb25fc3VtbWFyeSA8LSBkYXRhICU+JQogIGZpbHRlcih0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MgPiAwLCAhaXMubmEoYWlfYWN0aW9uKSkgJT4lCiAgZ3JvdXBfYnkoYWlfYWN0aW9uKSAlPiUKICBzdW1tYXJpc2UoCiAgICBtaW4gPSBtaW4odG90YWxfbW9kaWZpZWRfdGltZV9zZWNzLCBuYS5ybSA9IFRSVUUpLAogICAgcTEgPSBxdWFudGlsZSh0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MsIDAuMjUsIG5hLnJtID0gVFJVRSksCiAgICBtZWRpYW4gPSBtZWRpYW4odG90YWxfbW9kaWZpZWRfdGltZV9zZWNzLCBuYS5ybSA9IFRSVUUpLAogICAgcTMgPSBxdWFudGlsZSh0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MsIDAuNzUsIG5hLnJtID0gVFJVRSksCiAgICBtYXggPSBtYXgodG90YWxfbW9kaWZpZWRfdGltZV9zZWNzLCBuYS5ybSA9IFRSVUUpLAogICAgY291bnQgPSBuKCksCiAgICAuZ3JvdXBzID0gJ2Ryb3AnCiAgKSAlPiUKICBtdXRhdGUocHJldHR5X25hbWUgPSBzdHJfcmVwbGFjZV9hbGwoYWlfYWN0aW9uLCAiXyIsICIgIikgJT4lIHN0cl90b190aXRsZSgpKSAlPiUKICBhcnJhbmdlKG1lZGlhbikKCgojIEV4cG9ydCBzYW1wbGUgb2YgcmF3IGRhdGEgZm9yIEJveFggY29tcG9uZW50CmR1cmF0aW9uX2JveHBsb3RfZGF0YSA8LSBkYXRhICU+JQogICBmaWx0ZXIoCiAgICB0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MgPiAwLCAKICAgIHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcyA8IDE0MDAsICMgRm91bmQgdGhhdCBhbnl0aGluZyBhYm92ZSB0aGlzIGlzIG1vc3RseSBpbmNvcnJlY3RseSBlbnRlcmVkIGRhdGEKICAgICFpcy5uYShhaV9hY3Rpb24pLAogICAgYWlfYWN0aW9uICE9ICdjb250ZW50X292ZXJsYXknLAogICAgbW92aWVfbmFtZSAhPSAnQVJJU0hBRFZBUkdBJyAjIHRoaXMgbW92aWUgY2xlYXJseSBoYXMgYSBkYXRhIHByb2Nlc3NpbmcgZXJyb3Igd2hlcmUgdGhlIHRpbWVzIGFyZSBhZGRlZCBjdW11bGF0aXZlbHkgaHR0cHM6Ly9hcmNoaXZlLm9yZy9kZXRhaWxzL2NiZmMtZWNpbmVwcmFtYWFuLTEwMDAyMDI5MjEwMDAwMDI2MQogICkgJT4lCiAgbXV0YXRlKHByZXR0eV9uYW1lID0gc3RyX3JlcGxhY2VfYWxsKGFpX2FjdGlvbiwgIl8iLCAiICIpICU+JSBzdHJfdG9fdGl0bGUoKSkgJT4lCiAgZ3JvdXBfYnkoYWlfYWN0aW9uLCBwcmV0dHlfbmFtZSkgJT4lCiAgIyBTYW1wbGUgdXAgdG8gNTAwIHBvaW50cy4gSWYgYSBncm91cCBoYXMgPCA1MDAgcG9pbnRzLCBpdCB3aWxsIHRha2UgYWxsIG9mIHRoZW0uCiAgc2xpY2Vfc2FtcGxlKG4gPSA1MDApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoCiAgICBhY3Rpb24gPSBhaV9hY3Rpb24sCiAgICBjYXRlZ29yeSA9IHByZXR0eV9uYW1lLCAKICAgIGR1cmF0aW9uID0gdG90YWxfbW9kaWZpZWRfdGltZV9zZWNzCiAgKQoKCndyaXRlX2pzb24oZHVyYXRpb25fc3VtbWFyeSwgImR1cmF0aW9uX2J5X2FjdGlvbl9zdW1tYXJ5Lmpzb24iLCBwcmV0dHkgPSBUUlVFLCBhdXRvX3VuYm94ID0gVFJVRSkKd3JpdGVfanNvbihkdXJhdGlvbl9ib3hwbG90X2RhdGEsICJkdXJhdGlvbl9ieV9hY3Rpb25fYm94cGxvdC5qc29uIiwgcHJldHR5ID0gVFJVRSwgYXV0b191bmJveCA9IFRSVUUpCgogIGR1cmF0aW9uX2JveHBsb3RfZGF0YSAlPiUgCiAgZ2dwbG90KGFlcygKICAgIHggPSBmY3RfcmVvcmRlcihjYXRlZ29yeSwgZHVyYXRpb24sIC5mdW4gPSBtZWRpYW4pLAogICAgeSA9IGR1cmF0aW9uLAogICAgZmlsbCA9IGNhdGVnb3J5CiAgKSkgKwogIGdlb21fYm94cGxvdChzaG93LmxlZ2VuZCA9IEZBTFNFLCBhbHBoYSA9IDAuOCwgZmlsbCA9IHdlc19jb2xvcnNbM10pICsKICBzY2FsZV95X2xvZzEwKAogICAgYnJlYWtzID0gYygxLCAxMCwgNjAsIDMwMCwgMTgwMCksCiAgICBsYWJlbHMgPSBjKCIxIHNlYyIsICIxMCBzZWNzIiwgIjEgbWluIiwgIjUgbWlucyIsICIzMCBtaW5zIikKICApICsKICBjb29yZF9mbGlwKCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJIb3cgTG9uZyBhcmUgRGlmZmVyZW50IFR5cGVzIG9mIEVkaXRzPyIsCiAgICBzdWJ0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgbW9kaWZpY2F0aW9uIGR1cmF0aW9ucyBmb3IgZWFjaCBhY3Rpb24gdHlwZSBvbiBhIGxvZ2FyaXRobWljIHNjYWxlLiIsCiAgICB4ID0gTlVMTCwKICAgIHkgPSAiRHVyYXRpb24gb2YgTW9kaWZpY2F0aW9uIgogICkgKwogIHRoZW1lX2NiZmMoKQpgYGAKCiMjIE1vZGlmaWNhdGlvbiBSZWFzb25zIGJ5IE1vdmllIFJhdGluZwoKVGhlIGRhdGFzZXQgaW5jbHVkZXMgdGFncyBmb3Igd2hhdCByZWFzb24gYSBwYXJ0aWN1bGFyIG1vZGlmaWNhdGlvbiB3YXMgbWFkZTsgdmlvbGVuY2UsIHByb2Zhbml0eSBhbmQgc28gb24uIFdoaWxlIEkgaGF2ZSBhIHByZXR0eSBnb29kIGlkZWEgb2Ygd2hhdCB0aGlzIHdpbGwgZ2l2ZSwgd2UgY2FuIHNlZSB3aGF0IGlzIHRoZSBicmVha2Rvd24gb2YgZWFjaCByZWFzb24gYnkgdGhlIHJhdGluZyBmb3IgdGhhdCBtb3ZpZSAocmF0aW5nIGlzIHRoZSBgVWAsIGBVQWAsIGBBYCBjbGFzc2lmaWNhdGlvbiBmb3Igd2hvIGNhbiB3YXRjaCB0aGUgbW92aWUpLgoKYGBge3IgcmF0aW5nLWJyZWFrZG93bn0KcmF0aW5nX2JyZWFrZG93biA8LSBkYXRhICU+JQogIGZpbHRlcihyYXRpbmcgJWluJSBjKCJVIiwgIlVBIiwgIkEiKSwgIWlzLm5hKGFpX2NvbnRlbnRfdHlwZXMpKSAlPiUKICBtdXRhdGUoY29udGVudF9jYXRlZ29yeSA9IGNhc2Vfd2hlbigKICAgIGFpX2NvbnRlbnRfdHlwZXMgJWluJSBjKCJzZXh1YWxfZXhwbGljaXQiLCAic2V4dWFsX3N1Z2dlc3RpdmUiKSB+ICJTZXh1YWwgQ29udGVudCIsCiAgICBhaV9jb250ZW50X3R5cGVzID09ICJwcm9mYW5pdHkiIH4gIlByb2Zhbml0eSIsCiAgICBhaV9jb250ZW50X3R5cGVzID09ICJ2aW9sZW5jZSIgfiAiVmlvbGVuY2UiLAogICAgYWlfY29udGVudF90eXBlcyA9PSAic3Vic3RhbmNlIiB+ICJTdWJzdGFuY2UgVXNlIiwKICAgIGFpX2NvbnRlbnRfdHlwZXMgPT0gInJlbGlnaW91cyIgfiAiUmVsaWdpb3VzIENvbnRlbnQiLAogICAgYWlfY29udGVudF90eXBlcyA9PSAicG9saXRpY2FsIiB+ICJQb2xpdGljYWwgQ29udGVudCIsCiAgICBUUlVFIH4gIk90aGVyIgogICkpICU+JQogIGNvdW50KHJhdGluZywgY29udGVudF9jYXRlZ29yeSwgbmFtZSA9ICJtb2RpZmljYXRpb25fY291bnQiLCBzb3J0ID0gVFJVRSkgJT4lCiAgZ3JvdXBfYnkocmF0aW5nKSAlPiUKICBtdXRhdGUocGVyY2VudGFnZSA9IG1vZGlmaWNhdGlvbl9jb3VudCAvIHN1bShtb2RpZmljYXRpb25fY291bnQpKSAlPiUKICB1bmdyb3VwKCkKCmNvbW1vbl90eXBlcyA8LSByYXRpbmdfYnJlYWtkb3duICU+JQogIGZpbHRlcihjb250ZW50X2NhdGVnb3J5ICE9ICJPdGhlciIpICU+JQogIGdyb3VwX2J5KGNvbnRlbnRfY2F0ZWdvcnkpICU+JQogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShtb2RpZmljYXRpb25fY291bnQpLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUKICBwdWxsKGNvbnRlbnRfY2F0ZWdvcnkpCgpyYXRpbmdfYnJlYWtkb3duICU+JQogIGZpbHRlcihjb250ZW50X2NhdGVnb3J5ICVpbiUgY29tbW9uX3R5cGVzKSAlPiUKICBnZ3Bsb3QoYWVzKAogICAgeCA9IHBlcmNlbnRhZ2UsCiAgICB5ID0gZmN0X3Jlb3JkZXIoY29udGVudF9jYXRlZ29yeSwgcGVyY2VudGFnZSwgLmRlc2MgPSBGQUxTRSksCiAgICBmaWxsID0gcmF0aW5nCiAgKSkgKwogIGdlb21fY29sKGNvbG9yID0gIndoaXRlIiwgbGluZXdpZHRoID0gMC41KSArCiAgZmFjZXRfd3JhcCh+cmF0aW5nLCBzY2FsZXMgPSAiZnJlZV95IiwgbmNvbCA9IDMpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgdmFsdWVzID0gYygiVSIgPSB3ZXNfY29sb3JzWzFdLCAiVUEiID0gd2VzX2NvbG9yc1syXSwgIkEiID0gd2VzX2NvbG9yc1szXSkKICApICsKICBsYWJzKAogICAgdGl0bGUgPSAiQ2Vuc29yc2hpcCByZWFzb25zIGJ5IGZpbG0gcmF0aW5nIiwKICAgIHN1YnRpdGxlID0gIlByb3BvcnRpb25hbCBicmVha2Rvd24gb2YgbW9kaWZpY2F0aW9uIHJlYXNvbnMgd2l0aGluIGVhY2ggZmlsbSByYXRpbmcgY2F0ZWdvcnkuIiwKICAgIHggPSAiJSBvZiBhbGwgbW9kaWZpY2F0aW9ucyBmb3IgdGhpcyByYXRpbmciLAogICAgeSA9IE5VTEwKICApICsKICB0aGVtZV9jYmZjKCkgKwogIHRoZW1lKAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gImdyYXkyMCIsIG1hcmdpbiA9IG1hcmdpbih0ID0gNSwgYiA9IDEwKSksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXk5MCIsIGxpbmV0eXBlID0gImRvdHRlZCIpLAogICAgcGFuZWwuc3BhY2luZy54ID0gdW5pdCgyLCAibGluZXMiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIgogICkKCndyaXRlX2pzb24ocmF0aW5nX2JyZWFrZG93biwgInJhdGluZ19icmVha2Rvd24uanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQpgYGAKCiMjIEF2ZXJhZ2UgQ3V0IFRpbWUgYnkgUmVnaW9uYWwgT2ZmaWNlCgpEaWZmZXJlbnQgcmVnaW9uYWwgb2ZmaWNlcyBvZiB0aGUgQ0JGQyBtYXkgYXBwbHkgY2Vuc29yc2hpcCBzdGFuZGFyZHMgZGlmZmVyZW50bHkuIEhlcmUsIHdlIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSB0b3RhbCB0aW1lIG1vZGlmaWVkIHBlciBmaWxtIGZvciBlYWNoIG1ham9yIG9mZmljZS4gV2UgZmlsdGVyIG91dCBleHRyZW1lIG91dGxpZXJzIChmaWxtcyB3aXRoIG1vcmUgdGhhbiAzMCBtaW51dGVzIG9mIGN1dHMpIGFuZCBvbmx5IGluY2x1ZGUgb2ZmaWNlcyB0aGF0IGhhdmUgY2VydGlmaWVkIGEgc3VmZmljaWVudCBudW1iZXIgb2YgZmlsbXMgKGF0IGxlYXN0IDUwKS4KCmBgYHtyIGN1dHMtYnktb2ZmaWNlLXN0YXRzfQpmaWxtX3N1bW1hcnkgPC0gZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKG9mZmljZSkgJiAhc3RyX2RldGVjdChvZmZpY2UsICJcXC5tcDQkIikpICU+JQogIGdyb3VwX2J5KGlkLCBtb3ZpZV9uYW1lLCBvZmZpY2UpICU+JQogIHN1bW1hcmlzZSgKICAgIHRvdGFsX3NlY3MgPSBzdW0odG90YWxfbW9kaWZpZWRfdGltZV9zZWNzLCBuYS5ybSA9IFRSVUUpLAogICAgLmdyb3VwcyA9ICdkcm9wJwogICkgJT4lCiAgZmlsdGVyKHRvdGFsX3NlY3MgPiAwLCB0b3RhbF9zZWNzIDwgMTgwMCkKCm9mZmljZV9zdGF0cyA8LSBmaWxtX3N1bW1hcnkgJT4lCiAgZ3JvdXBfYnkob2ZmaWNlKSAlPiUKICBmaWx0ZXIobigpID49IDUwKSAlPiUKICBzdW1tYXJpc2UoCiAgICBmaWxtX2NvdW50ID0gbigpLAogICAgbWVhbl90b3RhbF9zZWNzID0gbWVhbih0b3RhbF9zZWNzLCBuYS5ybSA9IFRSVUUpLAogICAgc2UgPSBzZCh0b3RhbF9zZWNzLCBuYS5ybSA9IFRSVUUpIC8gc3FydChuKCkpLAogICAgY2lfbG93ZXJfc2VjcyA9IHBtYXgoMCwgbWVhbl90b3RhbF9zZWNzIC0gMS45NiAqIHNlKSwKICAgIGNpX3VwcGVyX3NlY3MgPSBtZWFuX3RvdGFsX3NlY3MgKyAxLjk2ICogc2UsCiAgICAuZ3JvdXBzID0gJ2Ryb3AnCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MobWVhbl90b3RhbF9zZWNzKSkKCndyaXRlX2pzb24ob2ZmaWNlX3N0YXRzLCAiY3V0c19ieV9vZmZpY2UuanNvbiIsIHByZXR0eSA9IFRSVUUsIGF1dG9fdW5ib3ggPSBUUlVFKQoKc3VtbWFyeV90YWJsZSA8LSBvZmZpY2Vfc3RhdHMgJT4lCiAgbXV0YXRlKAogICAgYEF2ZXJhZ2UgVGltZWAgPSBmb3JtYXRfc2Vjb25kcyhtZWFuX3RvdGFsX3NlY3MpLAogICAgYDk1JSBDSSBMb3dlcmAgPSBmb3JtYXRfc2Vjb25kcyhjaV9sb3dlcl9zZWNzKSwKICAgIGA5NSUgQ0kgVXBwZXJgID0gZm9ybWF0X3NlY29uZHMoY2lfdXBwZXJfc2VjcykKICApICU+JQogIHNlbGVjdCgKICAgIE9mZmljZSA9IG9mZmljZSwKICAgIGBGaWxtcyBBbmFseXplZGAgPSBmaWxtX2NvdW50LAogICAgYEF2ZXJhZ2UgVGltZWAsCiAgICBgOTUlIENJIExvd2VyYCwKICAgIGA5NSUgQ0kgVXBwZXJgCiAgKQoKc3VtbWFyeV90YWJsZSAlPiUKICBndCgpICU+JQogIHRhYl9oZWFkZXIoCiAgICB0aXRsZSA9ICJBdmVyYWdlIE1vZGlmaWNhdGlvbiBUaW1lIHBlciBGaWxtIGJ5IENCRkMgUmVnaW9uYWwgT2ZmaWNlIiwKICAgIHN1YnRpdGxlID0gIkFuYWx5c2lzIG9mIG9mZmljZXMgd2l0aCBhdCBsZWFzdCA1MCBjZXJ0aWZpZWQgZmlsbXMiCiAgKSAlPiUKICB0YWJfc3R5bGUoCiAgICBzdHlsZSA9IGxpc3QoCiAgICAgIGNlbGxfZmlsbChjb2xvciA9IHdlc19jb2xvcnNbMV0sIGFscGhhID0gMC4zKSwKICAgICAgY2VsbF90ZXh0KHdlaWdodCA9ICJib2xkIikKICAgICksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19jb2x1bW5fbGFiZWxzKCkKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF90ZXh0KGFsaWduID0gImNlbnRlciIpLAogICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gYyhgRmlsbXMgQW5hbHl6ZWRgLCBgQXZlcmFnZSBUaW1lYCwgYDk1JSBDSSBMb3dlcmAsIGA5NSUgQ0kgVXBwZXJgKSkKICApICU+JQogIGNvbHNfYWxpZ24oCiAgICBhbGlnbiA9ICJsZWZ0IiwKICAgIGNvbHVtbnMgPSBPZmZpY2UKICApICU+JQogIHRhYl9vcHRpb25zKAogICAgdGFibGUuZm9udC5uYW1lcyA9ICJBdGtpbnNvbiBIeXBlcmxlZ2libGUiLAogICAgaGVhZGluZy50aXRsZS5mb250LnNpemUgPSAxNiwKICAgIGhlYWRpbmcuc3VidGl0bGUuZm9udC5zaXplID0gMTIsCiAgICBjb2x1bW5fbGFiZWxzLmZvbnQuc2l6ZSA9IDEyLAogICAgdGFibGUuZm9udC5zaXplID0gMTEKICApCmBgYAoKIyMgVHJlbmRzIGluIENlbnNvcnNoaXAgQ29udGVudCBUeXBlcwoKSGF2ZSB0aGUgcmVhc29ucyBmb3IgZmlsbSBjZW5zb3JzaGlwIGNoYW5nZWQgb3ZlciB0aW1lPyBUaGlzIGFuYWx5c2lzIHRyYWNrcyB0aGUgY2hhbmdlcyBpbiBkaWZmZXJlbnQgbW9kaWZpY2F0aW9uIHR5cGVzIChWaW9sZW5jZSwgUHJvZmFuaXR5LCBTZXh1YWwgQ29udGVudCwgZXRjLikgb24gYSBtb250aGx5IGJhc2lzLgoKRm9yIGVhY2ggY2F0ZWdvcnksIHdlIGNhbGN1bGF0ZSBpdHMgZGV2aWF0aW9uIGZyb20gaXRzIG93biBoaXN0b3JpY2FsIGF2ZXJhZ2UgKHRoZSAiYmFzZWxpbmUiKS4gVGhpcyBtZXRob2QgY2xlYXJseSBzaG93cyBwZXJpb2RzIHdoZW4gYSBjZXJ0YWluIHR5cGUgb2YgY29udGVudCB3YXMgY2Vuc29yZWQgbW9yZSBvciBsZXNzIGZyZXF1ZW50bHkgdGhhbiB1c3VhbC4gV2UgYWxzbyBhcHBseSBhIDMtbW9udGggbW92aW5nIGF2ZXJhZ2UgdG8gc21vb3RoIG91dCBzaG9ydC10ZXJtIG5vaXNlIGFuZCByZXZlYWwgdGhlIHVuZGVybHlpbmcgdHJlbmQuCgpgYGB7ciBjb250ZW50LXRyZW5kcy1jaGFydH0KaW50ZXJwb2xhdGVfYXRfemVybyA8LSBmdW5jdGlvbihkZikgewogIHNpZ25fY2hhbmdlIDwtIHdoaWNoKGRpZmYoc2lnbihkZiRkZXZpYXRpb25fcGN0X3Ntb290aCkpICE9IDApCiAgaWYgKGxlbmd0aChzaWduX2NoYW5nZSkgPT0gMCkgcmV0dXJuKGRmKQogIAogIGludGVycG9sYXRlZCA8LSBtYXBfZGYoc2lnbl9jaGFuZ2UsIH57CiAgICBzbGljZSA8LSBkZlsueDooLnggKyAxKSwgXQogICAgemVyb19jcm9zc19kYXRlIDwtIGFwcHJveChzbGljZSRkZXZpYXRpb25fcGN0X3Ntb290aCwgYXMubnVtZXJpYyhzbGljZSR5ZWFyX21vbnRoKSwgeG91dCA9IDApJHkKICAgIGlmIChpcy5uYSh6ZXJvX2Nyb3NzX2RhdGUpKSByZXR1cm4odGliYmxlKCkpCiAgICB0aWJibGUoCiAgICAgIHllYXJfbW9udGggPSBhcy5EYXRlKHplcm9fY3Jvc3NfZGF0ZSwgb3JpZ2luID0gIjE5NzAtMDEtMDEiKSwKICAgICAgZGV2aWF0aW9uX3BjdF9zbW9vdGggPSAwLAogICAgICBhYm92ZV9iYXNlbGluZSA9IHNsaWNlJGFib3ZlX2Jhc2VsaW5lWzJdLAogICAgICBjb250ZW50X3R5cGUgPSBzbGljZSRjb250ZW50X3R5cGVbMV0sCiAgICAgIGJhc2VsaW5lX3JhdGUgPSBzbGljZSRiYXNlbGluZV9yYXRlWzFdCiAgICApCiAgfSkKICAKICBiaW5kX3Jvd3MoZGYsIGludGVycG9sYXRlZCkgJT4lIGFycmFuZ2UoeWVhcl9tb250aCkKfQoKY2hhcnRfZGF0YSA8LSBkYXRhICU+JQogIG11dGF0ZSgKICAgIHllYXJfbW9udGggPSBmbG9vcl9kYXRlKGNlcnRfZGF0ZSwgIm1vbnRoIiksCiAgICBjb250ZW50X3R5cGUgPSBjYXNlX3doZW4oCiAgICAgIGFpX2NvbnRlbnRfdHlwZXMgJWluJSBjKCJzZXh1YWxfZXhwbGljaXQiLCAic2V4dWFsX3N1Z2dlc3RpdmUiKSB+ICJTZXh1YWwgQ29udGVudCIsCiAgICAgIGFpX2NvbnRlbnRfdHlwZXMgPT0gInByb2Zhbml0eSIgfiAiUHJvZmFuaXR5IiwKICAgICAgYWlfY29udGVudF90eXBlcyA9PSAidmlvbGVuY2UiIH4gIlZpb2xlbmNlIiwKICAgICAgYWlfY29udGVudF90eXBlcyA9PSAic3Vic3RhbmNlIiB+ICJTdWJzdGFuY2UgVXNlIiwKICAgICAgYWlfY29udGVudF90eXBlcyA9PSAicmVsaWdpb3VzIiB+ICJSZWxpZ2lvdXMgQ29udGVudCIsCiAgICAgIGFpX2NvbnRlbnRfdHlwZXMgPT0gInBvbGl0aWNhbCIgfiAiUG9saXRpY2FsIENvbnRlbnQiLAogICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXwogICAgKQogICkgJT4lCiAgZmlsdGVyKCFpcy5uYShjb250ZW50X3R5cGUpKSAlPiUKICBncm91cF9ieSh5ZWFyX21vbnRoLCBjb250ZW50X3R5cGUpICU+JQogIHN1bW1hcmlzZShmaWxtc193aXRoX21vZHMgPSBuX2Rpc3RpbmN0KGNlcnRpZmljYXRlX2lkKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgbGVmdF9qb2luKAogICAgZGF0YSAlPiUKICAgICAgbXV0YXRlKHllYXJfbW9udGggPSBmbG9vcl9kYXRlKGNlcnRfZGF0ZSwgIm1vbnRoIikpICU+JQogICAgICBncm91cF9ieSh5ZWFyX21vbnRoKSAlPiUKICAgICAgc3VtbWFyaXNlKHRvdGFsX2ZpbG1zID0gbl9kaXN0aW5jdChjZXJ0aWZpY2F0ZV9pZCkpLAogICAgYnkgPSAieWVhcl9tb250aCIKICApICU+JQogIG11dGF0ZShyYXRlID0gZmlsbXNfd2l0aF9tb2RzIC8gdG90YWxfZmlsbXMpICU+JQogIGZpbHRlcih0b3RhbF9maWxtcyA+PSAxMCkgJT4lCiAgZ3JvdXBfYnkoY29udGVudF90eXBlKSAlPiUKICBhcnJhbmdlKHllYXJfbW9udGgpICU+JQogIG11dGF0ZSgKICAgIGJhc2VsaW5lX3JhdGUgPSBtZWFuKHJhdGUpLAogICAgZGV2aWF0aW9uX3BjdCA9IChyYXRlIC0gYmFzZWxpbmVfcmF0ZSkgLyBiYXNlbGluZV9yYXRlICogMTAwLAogICAgZGV2aWF0aW9uX3BjdF9zbW9vdGggPSB6b286OnJvbGxtZWFuKGRldmlhdGlvbl9wY3QsIGsgPSAzLCBmaWxsID0gTkEsIGFsaWduID0gImNlbnRlciIpLAogICAgYWJvdmVfYmFzZWxpbmUgPSBpZmVsc2UoaXMubmEoZGV2aWF0aW9uX3BjdF9zbW9vdGgpLCBOQSwgZGV2aWF0aW9uX3BjdF9zbW9vdGggPiAwKQogICkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcighaXMubmEoZGV2aWF0aW9uX3BjdF9zbW9vdGgpKSAlPiUKICBtdXRhdGUoY29udGVudF90eXBlID0gZmN0X3Jlb3JkZXIoY29udGVudF90eXBlLCBiYXNlbGluZV9yYXRlLCAuZGVzYyA9IFRSVUUpKSAlPiUKICBncm91cF9ieShjb250ZW50X3R5cGUpICU+JQogIGdyb3VwX21vZGlmeSh+IGludGVycG9sYXRlX2F0X3plcm8oLngpKSAlPiUKICB1bmdyb3VwKCkKCmdncGxvdChjaGFydF9kYXRhLCBhZXMoeCA9IHllYXJfbW9udGgsIHkgPSBkZXZpYXRpb25fcGN0X3Ntb290aCwgY29sb3IgPSBhYm92ZV9iYXNlbGluZSwgZ3JvdXAgPSAxKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gImdyZXk0MCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2xpbmUobGluZXdpZHRoID0gMS4yKSArCiAgZmFjZXRfd3JhcCh+Y29udGVudF90eXBlLCBuY29sID0gMykgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgIHZhbHVlcyA9IGMoIlRSVUUiID0gd2VzX2NvbG9yc1s1XSwgIkZBTFNFIiA9IHdlc19jb2xvcnNbMV0pLAogICAgbGFiZWxzID0gYygiQmVsb3cgQmFzZWxpbmUiLCAiQWJvdmUgQmFzZWxpbmUiKSwKICAgIG5hbWUgPSBOVUxMCiAgKSArCiAgc2NhbGVfeF9kYXRlKAogICAgZGF0ZV9sYWJlbHMgPSAiJyV5IiwKICAgIGRhdGVfYnJlYWtzID0gIjIgeWVhcnMiLAogICAgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDIsIDAuMDIpKQogICkgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHBhc3RlMChpZmVsc2UoeCA+PSAwLCAiKyIsICIiKSwgcm91bmQoeCwgMCksICIlIikKICApICsKICBsYWJzKAogICAgdGl0bGUgPSAiQ2Vuc29yc2hpcCBQYXR0ZXJucyB2cy4gSGlzdG9yaWNhbCBBdmVyYWdlIiwKICAgIGNhcHRpb24gPSAiTm90ZTogRGFzaGVkIGxpbmUgaXMgdGhlIGJhc2VsaW5lIGF2ZXJhZ2UgZm9yIHRoYXQgY2F0ZWdvcnkuIFJlZCBpbmRpY2F0ZXMgbW9udGhzIHdpdGggYWJvdmUtYXZlcmFnZSBjZW5zb3JzaGlwIHJhdGVzOyBibHVlIGlzIGJlbG93LWF2ZXJhZ2UuXG5BIDMtbW9udGggbW92aW5nIGF2ZXJhZ2UgaGFzIGJlZW4gYXBwbGllZCB0byBzbW9vdGggdHJlbmRzLiBTb3VyY2U6IENlbnRyYWwgQm9hcmQgb2YgRmlsbSBDZXJ0aWZpY2F0aW9uLiIsCiAgICB4ID0gTlVMTCwKICAgIHkgPSAiRGV2aWF0aW9uIGZyb20gQmFzZWxpbmUiCiAgKSArCiAgdGhlbWVfY2JmYygpICsKICB0aGVtZSgKICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgY29sb3IgPSAiZ3JleTUwIiwgaGp1c3QgPSAwLCBtYXJnaW4gPSBtYXJnaW4odCA9IDE2KSksCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXk5MCIsIGxpbmV3aWR0aCA9IDAuNCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICkKCndyaXRlX2pzb24oY2hhcnRfZGF0YSwgImNvbnRlbnRfdHJlbmRzLmpzb24iLCBwcmV0dHkgPSBUUlVFLCBhdXRvX3VuYm94ID0gVFJVRSkKYGBgCgojIyBEaXN0cmlidXRpb24gb2YgTW9kaWZpY2F0aW9uIER1cmF0aW9ucwoKVGhpcyBoaXN0b2dyYW0gc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0b3RhbCBtb2RpZmljYXRpb24gdGltZXMgZm9yIGZpbG1zIHRoYXQgaGFkIGF0IGxlYXN0IG9uZSBjdXQuIEFwcHJveGltYXRlbHkgaGFsZiBvZiB0aGUgZmlsbXMgaW4gdGhlIGRhdGFzZXQgaGF2ZSAnemVybyBzZWNvbmRzJyBvZiBlZGl0cyAobWVhbmluZyBtb2RpZmljYXRpb25zIG1pZ2h0IGhhdmUgYmVlbiBtYWRlIGJ1dCB0aGV5IHdlcmUgbm90IGxvZ2dlZCB3aXRoIGEgZHVyYXRpb24gb2YgZWRpdCk7IHRoaXMgY2hhcnQgZm9jdXNlcyBvbmx5IG9uIHRob3NlIHRoYXQgaGF2ZSBkdXJhdGlvbiB2YWx1ZXMuCgpgYGB7ciBkdXJhdGlvbi1kaXN0cmlidXRpb24tY2hhcnR9CmZpbG1fZGF0YSA8LSBkYXRhICU+JQogIGdyb3VwX2J5KGlkKSAlPiUKICBzdW1tYXJpc2UoCiAgICB0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MgPSBzdW0odG90YWxfbW9kaWZpZWRfdGltZV9zZWNzLCBuYS5ybSA9IFRSVUUpLAogICAgLmdyb3VwcyA9ICdkcm9wJwogICkKCnRvdGFsX2ZpbG1zIDwtIG5yb3coZmlsbV9kYXRhKQpwZXJjZW50X3plcm8gPC0gbWVhbihmaWxtX2RhdGEkdG90YWxfbW9kaWZpZWRfdGltZV9zZWNzID09IDAsIG5hLnJtID0gVFJVRSkKZmlsbV9kYXRhX3Bvc2l0aXZlIDwtIGZpbG1fZGF0YSAlPiUgZmlsdGVyKHRvdGFsX21vZGlmaWVkX3RpbWVfc2VjcyA+IDApCm1lZGlhbl92YWxfcG9zaXRpdmUgPC0gbWVkaWFuKGZpbG1fZGF0YV9wb3NpdGl2ZSR0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MpCgpwX2Rpc3QgPC0gZ2dwbG90KGZpbG1fZGF0YV9wb3NpdGl2ZSwgYWVzKHggPSB0b3RhbF9tb2RpZmllZF90aW1lX3NlY3MpKSArCiAgZ2VvbV9oaXN0b2dyYW0oCiAgICBhZXMoeSA9IGFmdGVyX3N0YXQoY291bnQpIC8gdG90YWxfZmlsbXMgKiAxMDApLAogICAgZmlsbCA9IHdlc19jb2xvcnNbMl0sCiAgICBiaW5zID0gNDAsCiAgICBib3VuZGFyeSA9IDAKICApICsKICBnZW9tX3ZsaW5lKAogICAgeGludGVyY2VwdCA9IG1lZGlhbl92YWxfcG9zaXRpdmUsCiAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLAogICAgY29sb3IgPSAiZ3JheTIwIiwKICAgIGxpbmV3aWR0aCA9IDAuOAogICkgKwogICMgVXNlIGEgbG9nMTAgc2NhbGUgb24gdGhlIHgtYXhpcyBiZWNhdXNlIHRoZSBkYXRhIGlzIGhpZ2hseSBza2V3ZWQuCiAgc2NhbGVfeF9sb2cxMCgKICAgIGJyZWFrcyA9IGMoMSwgMTAsIDYwLCAzMDAsIDE4MDApLAogICAgbGFiZWxzID0gYygiMXMiLCAiMTBzIiwgIjFtIiwgIjVtIiwgIjMwbSIpCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDAuMDUpKSwKICAgIGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KHNjYWxlID0gMSkKICApICsKICBsYWJzKAogICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIE1vZGlmaWNhdGlvbiBUaW1lcyIsCiAgICBzdWJ0aXRsZSA9IHN0cl9nbHVlKCJDb21wYXJpbmcgdG90YWwgbW9kaWZpY2F0aW9uIHRpbWUgZm9yIGZpbG1zIHdpdGggYXQgbGVhc3Qgb25lIGN1dC4KICAgICAgICAgICAgICAgICAgICAgICAgVGhpcyBjaGFydCBleGNsdWRlcyB0aGUge3BlcmNlbnQocGVyY2VudF96ZXJvLCBhY2N1cmFjeT0xKX0gb2YgZmlsbXMgd2l0aCB6ZXJvIG1vZGlmaWNhdGlvbnMuIiksCiAgICB4ID0gIlRvdGFsIE1vZGlmaWNhdGlvbiBUaW1lIChMb2dhcml0aG1pYyBTY2FsZSkiLAogICAgeSA9ICJQZXJjZW50IG9mIEFsbCBGaWxtcyIKICApICsKICB0aGVtZV9jYmZjKCkgKwogIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKcHJpbnQocF9kaXN0KQoKIyBFeHBvcnQgdGhlIGRhdGEgdXNlZCBmb3IgdGhlIGhpc3RvZ3JhbSB0byBhIEpTT04gZmlsZS4KIyBXZSB1c2UgZ2dwbG90X2J1aWxkKCkgdG8gZXh0cmFjdCB0aGUgY29tcHV0ZWQgZGF0YSBmcm9tIHRoZSBwbG90IG9iamVjdC4KaGlzdF9kYXRhX2Zvcl9leHBvcnQgPC0gZ2dwbG90X2J1aWxkKHBfZGlzdCkkZGF0YVtbMV1dICU+JQogIHNlbGVjdCh4X21pbiA9IHhtaW4sIHhfbWF4ID0geG1heCwgY291bnQsIHlfcGVyY2VudF90b3RhbCA9IHkpCgpleHBvcnRfZGF0YV9kaXN0IDwtIGxpc3QoCiAgaGlzdG9ncmFtX2JpbnMgPSBoaXN0X2RhdGFfZm9yX2V4cG9ydCwKICBzdGF0aXN0aWNzID0gbGlzdCgKICAgIG1lZGlhbl9wb3NpdGl2ZV9zZWNzID0gbWVkaWFuX3ZhbF9wb3NpdGl2ZSwKICAgIHRvdGFsX2ZpbG1zID0gdG90YWxfZmlsbXMsCiAgICBwZXJjZW50X3plcm9fbW9kcyA9IHBlcmNlbnRfemVybwogICksCiAgYXhpc19jb25maWcgPSBsaXN0KAogICAgYnJlYWtzID0gYygxLCAxMCwgNjAsIDMwMCwgMTgwMCksCiAgICBsYWJlbHMgPSBjKCIxcyIsICIxMHMiLCAiMW0iLCAiNW0iLCAiMzBtIikKICApCikKCndyaXRlX2pzb24oZXhwb3J0X2RhdGFfZGlzdCwgImhpc3RvZ3JhbV9kYXRhLmpzb24iLCBwcmV0dHkgPSBUUlVFLCBhdXRvX3VuYm94ID0gVFJVRSkKYGBgCgojIyBJZGVudGlmeWluZyBUcmVuZGluZyBDZW5zb3JzaGlwIENhdGVnb3JpZXMKClRvIGRldGVybWluZSB3aGljaCBjZW5zb3JzaGlwIGNhdGVnb3JpZXMgYXJlIGluY3JlYXNpbmcgb3IgZGVjcmVhc2luZyBvdmVyIHRpbWUsIHdlIHVzZSBhIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwuCgpBIHBvc2l0aXZlIHNsb3BlIGZyb20gdGhlIG1vZGVsIGluZGljYXRlcyBhbiBpbmNyZWFzaW5nIHRyZW5kLCB3aGlsZSBhIG5lZ2F0aXZlIHNsb3BlIGluZGljYXRlcyBhIGRlY3JlYXNpbmcgdHJlbmQuIFdlIHRoZW4gdmlzdWFsaXplIHRoZSB0b3AgdGhyZWUgZmFzdGVzdC1pbmNyZWFzaW5nIGFuZCBmYXN0ZXN0LWRlY3JlYXNpbmcgY2F0ZWdvcmllcyBzaW5jZSAyMDE4LgoKVGhpcyBpcyBiYXNlZCBvbiBbSnVsaWEgU2lsZ2UncyBleGNlbGxlbnQgYXJ0aWNsZSBkZW1vbnN0cmF0aW5nIGEgc2ltaWxhciB0eXBlIG9mIGFuYWx5c2lzXShodHRwczovL2p1bGlhc2lsZ2UuY29tL2Jsb2cvcmVkZGl0LXJlc3BvbmRzLykuCgpgYGB7ciB0cmVuZGluZy1jYXRlZ29yaWVzLWFuYWx5c2lzfQpjYXRlZ29yaWVzX2J5X3F1YXJ0ZXIgPC0gZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKGNlcnRfZGF0ZSksICFpcy5uYShhaV9jb250ZW50X3R5cGVzKSwgY2VydF9kYXRlID49IGFzLkRhdGUoIjIwMTgtMDEtMDEiKSkgJT4lCiAgbXV0YXRlKHF1YXJ0ZXIgPSBmbG9vcl9kYXRlKGNlcnRfZGF0ZSwgdW5pdCA9ICIzIG1vbnRocyIpKSAlPiUKICBjb3VudChxdWFydGVyLCBhaV9jb250ZW50X3R5cGVzLCBuYW1lID0gImNhdGVnb3J5X2NvdW50IikgJT4lCiAgZ3JvdXBfYnkocXVhcnRlcikgJT4lCiAgbXV0YXRlKHF1YXJ0ZXJfdG90YWxfY3V0cyA9IHN1bShjYXRlZ29yeV9jb3VudCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieShhaV9jb250ZW50X3R5cGVzKSAlPiUKICBmaWx0ZXIoc3VtKGNhdGVnb3J5X2NvdW50KSA+IDEwMCkgJT4lCiAgdW5ncm91cCgpCgpjYXRlZ29yeV9tb2RlbHMgPC0gY2F0ZWdvcmllc19ieV9xdWFydGVyICU+JQogIG5lc3QoZGF0YSA9IC1haV9jb250ZW50X3R5cGVzKSAlPiUKICAjICh0b3RhbCAtIGNhdGVnb3J5KSBhcyBhIGZ1bmN0aW9uIG9mIHRpbWUgKHF1YXJ0ZXIpLgogIG11dGF0ZSgKICAgIG1vZGVsID0gbWFwKGRhdGEsIH4gZ2xtKAogICAgICBjYmluZChjYXRlZ29yeV9jb3VudCwgcXVhcnRlcl90b3RhbF9jdXRzIC0gY2F0ZWdvcnlfY291bnQpIH4gcXVhcnRlciwKICAgICAgZGF0YSA9IC4sCiAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIKICAgICkpCiAgKQoKc2xvcGVzIDwtIGNhdGVnb3J5X21vZGVscyAlPiUKICBtdXRhdGUodGlkaWVkID0gbWFwKG1vZGVsLCB0aWR5KSkgJT4lCiAgdW5uZXN0KHRpZGllZCkgJT4lCiAgZmlsdGVyKHRlcm0gPT0gInF1YXJ0ZXIiKSAlPiUKICBhcnJhbmdlKGRlc2MoZXN0aW1hdGUpKQoKdHJlbmRzX3RvX3Bsb3QgPC0gYmluZF9yb3dzKAogIHNsb3BlcyAlPiUgdG9wX24oMywgZXN0aW1hdGUpLAogIHNsb3BlcyAlPiUgdG9wX24oLTMsIGVzdGltYXRlKQopCgpnZ3Bsb3QoCiAgY2F0ZWdvcmllc19ieV9xdWFydGVyICU+JSBpbm5lcl9qb2luKHRyZW5kc190b19wbG90LCBieSA9ICJhaV9jb250ZW50X3R5cGVzIiksCiAgYWVzKHggPSBxdWFydGVyLCB5ID0gY2F0ZWdvcnlfY291bnQgLyBxdWFydGVyX3RvdGFsX2N1dHMsIAogICAgICBjb2xvciA9IGZjdF9yZW9yZGVyMihhaV9jb250ZW50X3R5cGVzLCBxdWFydGVyLCBjYXRlZ29yeV9jb3VudCkpCikgKwogIGdlb21fbGluZShhbHBoYSA9IDAuOCwgbGluZXdpZHRoID0gMS4yKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMC41KSArCiAgZmFjZXRfd3JhcCh+IGlmZWxzZShlc3RpbWF0ZSA+IDAsICJJbmNyZWFzaW5nIFRyZW5kcyIsICJEZWNyZWFzaW5nIFRyZW5kcyIpLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHdlc19jb2xvcnMpICsKICBsYWJzKAogICAgdGl0bGUgPSAiV2hpY2ggQ2Vuc29yc2hpcCBDYXRlZ29yaWVzIEhhdmUgVHJlbmRlZCBVcCBvciBEb3duPyIsCiAgICBzdWJ0aXRsZSA9ICJQcm9wb3J0aW9uIG9mIGFsbCBtb2RpZmljYXRpb25zIHBlciBxdWFydGVyIHNpbmNlIDIwMTgsIHdpdGggYSBsaW5lYXIgdHJlbmRsaW5lLiIsCiAgICB4ID0gIkRhdGUgb2YgQ2VydGlmaWNhdGlvbiIsCiAgICB5ID0gIlBlcmNlbnQgb2YgQWxsIEN1dHMgaW4gUXVhcnRlciIsCiAgICBjb2xvciA9ICJDb250ZW50IFR5cGUiCiAgKSArCiAgdGhlbWVfY2JmYygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCiMgRXhwb3J0IHRyZW5kaW5nIGNhdGVnb3JpZXMgZGF0YQojIENyZWF0ZSBjbGVhbiB2ZXJzaW9uIG9mIHRyZW5kc190b19wbG90IHdpdGhvdXQgbW9kZWwgb2JqZWN0cwp0cmVuZHNfY2xlYW4gPC0gdHJlbmRzX3RvX3Bsb3QgJT4lIAogIHNlbGVjdChhaV9jb250ZW50X3R5cGVzLCBlc3RpbWF0ZSwgc3RkLmVycm9yLCBzdGF0aXN0aWMsIHAudmFsdWUpCgp0cmVuZGluZ19leHBvcnQgPC0gbGlzdCgKICBzbG9wZXMgPSBzbG9wZXMgJT4lIHNlbGVjdChhaV9jb250ZW50X3R5cGVzLCBlc3RpbWF0ZSwgc3RkLmVycm9yLCBzdGF0aXN0aWMsIHAudmFsdWUpLAogIHF1YXJ0ZXJseV9kYXRhID0gY2F0ZWdvcmllc19ieV9xdWFydGVyICU+JQogICAgaW5uZXJfam9pbih0cmVuZHNfY2xlYW4sIGJ5ID0gImFpX2NvbnRlbnRfdHlwZXMiKSAlPiUKICAgIHNlbGVjdChxdWFydGVyLCBhaV9jb250ZW50X3R5cGVzLCBjYXRlZ29yeV9jb3VudCwgcXVhcnRlcl90b3RhbF9jdXRzLCAKICAgICAgICAgICBlc3RpbWF0ZSwgc3RkLmVycm9yLCBzdGF0aXN0aWMsIHAudmFsdWUpCikKd3JpdGVfanNvbih0cmVuZGluZ19leHBvcnQsICJ0cmVuZGluZ19jYXRlZ29yaWVzLmpzb24iLCBwcmV0dHkgPSBUUlVFLCBhdXRvX3VuYm94ID0gVFJVRSkKYGBgCgojIyBLZXl3b3JkIENvLW9jY3VycmVuY2UgTmV0d29yawoKVGhpcyBhbmFseXNpcyBleHBsb3JlcyB3aGljaCB0ZXJtcyB0ZW5kIHRvIGFwcGVhciB0b2dldGhlciB3aXRoaW4gdGhlIHNhbWUgZmlsbSdzIG1vZGlmaWNhdGlvbiByZWNvcmRzLgoKV2UgY2FsY3VsYXRlIHRoZSBwYWlyd2lzZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSA1MCBtb3N0IGNvbW1vbiBrZXl3b3JkcyBhbmQgdmlzdWFsaXplIHRoZSByZXN1bHRzIGFzIGEgbmV0d29yayBncmFwaC4KCioqVGhpcyBjb250YWlucyBhIGxvdCBvZiBOU0ZXIHN0dWZmLCBidXQgaGlkaW5nIGl0IHdvdWxkLi4ucHJvYmFibHkgZGVmZWF0IHRoZSBwb2ludCoqLgoKYGBge3IgY28tb2NjdXJyZW5jZS1uZXR3b3JrfQpyZWZlcmVuY2Vfd29yZHMgPC0gZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKGFpX3JlZmVyZW5jZSkpICU+JQogIG11dGF0ZSh3b3JkID0gc3RyX3NwbGl0KHRvbG93ZXIoYWlfcmVmZXJlbmNlKSwgIlxcfCIpKSAlPiUKICB1bm5lc3Qod29yZCkgJT4lCiAgZmlsdGVyKCFpcy5uYSh3b3JkKSwgIXN0cl9kZXRlY3Qod29yZCwgInZpb2xlbmNlfHNjZW5lfHZpc3VhbHxkaWFsb2d1ZSIpKSAlPiUKICBzZWxlY3QoaWQsIHdvcmQpCgp3b3JkX2NvdW50cyA8LSByZWZlcmVuY2Vfd29yZHMgJT4lCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpCgp3b3JkX3BhaXJzIDwtIHJlZmVyZW5jZV93b3JkcyAlPiUKICBmaWx0ZXIod29yZCAlaW4lICh3b3JkX2NvdW50cyAlPiUgdG9wX24oNTAsIG4pICU+JSBwdWxsKHdvcmQpKSkgJT4lCiAgcGFpcndpc2VfY29yKGl0ZW0gPSB3b3JkLCBmZWF0dXJlID0gaWQsIHNvcnQgPSBUUlVFKQoKd29yZF9wYWlycyAlPiUKICBmaWx0ZXIoY29ycmVsYXRpb24gPiAwLjA1KSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogIGdlb21fZWRnZV9saW5rKGFlcyhlZGdlX2FscGhhID0gY29ycmVsYXRpb24pLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9ub2RlX3BvaW50KGNvbG9yID0gd2VzX2NvbG9yc1szXSwgc2l6ZSA9IDUpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWwgPSBUUlVFKSArCiAgdGhlbWVfdm9pZCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiV2hpY2ggQ2Vuc29yc2hpcCBUZXJtcyBBcHBlYXIgVG9nZXRoZXI/IiwKICAgIHN1YnRpdGxlID0gIkNvLW9jY3VycmVuY2UgbmV0d29yayBvZiB0aGUgNTAgbW9zdCBjb21tb24ga2V5d29yZHMgaW4gQ0JGQyBtb2RpZmljYXRpb24gcmVjb3Jkcy4iCiAgKQoKIyBFeHBvcnQgY28tb2NjdXJyZW5jZSBuZXR3b3JrIGRhdGEKbmV0d29ya19leHBvcnQgPC0gbGlzdCgKICB3b3JkX2NvdW50cyA9IHdvcmRfY291bnRzICU+JSB0b3Bfbig1MCwgbiksCiAgd29yZF9wYWlycyA9IHdvcmRfcGFpcnMgJT4lIGZpbHRlcihjb3JyZWxhdGlvbiA+IDAuMDUpCikKd3JpdGVfanNvbihuZXR3b3JrX2V4cG9ydCwgImtleXdvcmRfbmV0d29yay5qc29uIiwgcHJldHR5ID0gVFJVRSwgYXV0b191bmJveCA9IFRSVUUpCmBgYAoKIyMgTW9zdCBJbXBvcnRhbnQgS2V5d29yZHMgYnkgQ2F0ZWdvcnkgKFRGLUlERikKCldoaWxlIHRoZSBuZXR3b3JrIGdyYXBoIHNob3dzIHdoaWNoIHdvcmRzIGNvLW9jY3VyLCBpdCBkb2Vzbid0IHRlbGwgdXMgd2hpY2ggd29yZHMgYXJlIG1vc3QgY2hhcmFjdGVyaXN0aWMgb2YgYSAqc3BlY2lmaWMgY2Vuc29yc2hpcCBjYXRlZ29yeSouIEZvciB0aGF0LCB3ZSB1c2UgYSBtZXRyaWMgY2FsbGVkIFtUZXJtIEZyZXF1ZW5jeS1JbnZlcnNlIERvY3VtZW50IEZyZXF1ZW5jeSAoVEYtSURGKV0oaHR0cHM6Ly93d3cudGlkeXRleHRtaW5pbmcuY29tL3RmaWRmKS4KClRGLUlERiBpZGVudGlmaWVzIHdvcmRzIHRoYXQgYXJlIGNvbW1vbiB3aXRoaW4gb25lIGNhdGVnb3J5IChlLmcuLCAiYmxvb2QiIGluIHRoZSAidmlvbGVuY2UiIGNhdGVnb3J5KSBidXQgYXJlIHJlbGF0aXZlbHkgcmFyZSBpbiBhbGwgb3RoZXIgY2F0ZWdvcmllcy4KCmBgYHtyIHRmaWRmLWFuYWx5c2lzfQpyZWZlcmVuY2VfdG9rZW5zIDwtIGRhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShhaV9yZWZlcmVuY2UpLCAhaXMubmEoYWlfY29udGVudF90eXBlcykpICU+JQogIHNlbGVjdChhaV9jb250ZW50X3R5cGVzLCBhaV9yZWZlcmVuY2UpICU+JQogIG11dGF0ZSh3b3JkID0gc3RyX3NwbGl0KHRvbG93ZXIoYWlfcmVmZXJlbmNlKSwgIlxcfCIpKSAlPiUKICB1bm5lc3Qod29yZCkgJT4lCiAgZmlsdGVyKHdvcmQgIT0gIiIpCgpyZWZlcmVuY2VfdGZpZGYgPC0gcmVmZXJlbmNlX3Rva2VucyAlPiUKICBjb3VudChhaV9jb250ZW50X3R5cGVzLCB3b3JkLCBzb3J0ID0gVFJVRSkgJT4lCiAgYmluZF90Zl9pZGYodGVybSA9IHdvcmQsIGRvY3VtZW50ID0gYWlfY29udGVudF90eXBlcywgbiA9IG4pICU+JQogIGFycmFuZ2UoZGVzYyh0Zl9pZGYpKQoKdG9wX3Rlcm1zX3RhYmxlIDwtIHJlZmVyZW5jZV90ZmlkZiAlPiUKICBncm91cF9ieShhaV9jb250ZW50X3R5cGVzKSAlPiUKICBzbGljZV9tYXgob3JkZXJfYnkgPSB0Zl9pZGYsIG4gPSA1KSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KENhdGVnb3J5ID0gYWlfY29udGVudF90eXBlcywgVGVybSA9IHdvcmQsIGBURi1JREZgID0gdGZfaWRmKSAlPiUKICBmaWx0ZXIoQ2F0ZWdvcnkgJWluJSBjKCJ2aW9sZW5jZSIsICJwcm9mYW5pdHkiLCAic2V4dWFsX3N1Z2dlc3RpdmUiLCAic3Vic3RhbmNlIiwgInBvbGl0aWNhbCIsICJyZWxpZ2lvdXMiKSkKCnRvcF90ZXJtc190YWJsZSAlPiUKICBndCgpICU+JQogIHRhYl9oZWFkZXIoCiAgICB0aXRsZSA9ICJNb3N0IERpc3RpbmN0aXZlIEtleXdvcmRzIGJ5IENlbnNvcnNoaXAgQ2F0ZWdvcnkiLAogICAgc3VidGl0bGUgPSAiVXNpbmcgVGVybSBGcmVxdWVuY3ktSW52ZXJzZSBEb2N1bWVudCBGcmVxdWVuY3kgKFRGLUlERikgYW5hbHlzaXMiCiAgKSAlPiUKICBmbXRfbnVtYmVyKAogICAgY29sdW1ucyA9IGBURi1JREZgLAogICAgZGVjaW1hbHMgPSAzCiAgKSAlPiUKICB0YWJfc3R5bGUoCiAgICBzdHlsZSA9IGxpc3QoCiAgICAgIGNlbGxfZmlsbChjb2xvciA9IHdlc19jb2xvcnNbMl0sIGFscGhhID0gMC4zKSwKICAgICAgY2VsbF90ZXh0KHdlaWdodCA9ICJib2xkIikKICAgICksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19jb2x1bW5fbGFiZWxzKCkKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF90ZXh0KHRyYW5zZm9ybSA9ICJjYXBpdGFsaXplIiksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBDYXRlZ29yeSkKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF90ZXh0KHN0eWxlID0gIml0YWxpYyIpLAogICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gVGVybSkKICApICU+JQogIGNvbHNfYWxpZ24oCiAgICBhbGlnbiA9ICJjZW50ZXIiLAogICAgY29sdW1ucyA9IGBURi1JREZgCiAgKSAlPiUKICB0YWJfb3B0aW9ucygKICAgIHRhYmxlLmZvbnQubmFtZXMgPSAiQXRraW5zb24gSHlwZXJsZWdpYmxlIiwKICAgIGhlYWRpbmcudGl0bGUuZm9udC5zaXplID0gMTYsCiAgICBoZWFkaW5nLnN1YnRpdGxlLmZvbnQuc2l6ZSA9IDEyLAogICAgY29sdW1uX2xhYmVscy5mb250LnNpemUgPSAxMiwKICAgIHRhYmxlLmZvbnQuc2l6ZSA9IDExLAogICAgcm93X2dyb3VwLmZvbnQud2VpZ2h0ID0gImJvbGQiCiAgKQoKd3JpdGVfanNvbihyZWZlcmVuY2VfdGZpZGYgJT4lIHNsaWNlX2hlYWQobiA9IDMwMCksICJ0ZmlkZl9hbmFseXNpcy5qc29uIiwgcHJldHR5ID0gVFJVRSwgYXV0b191bmJveCA9IFRSVUUpCmBgYAoKIyMgVG9wIENlbnNvcmVkIEZpbG1zIGJ5IE9mZmljZQoKSWRlbnRpZmllcyB0aGUgdG9wIGZpbG1zIHRoYXQgaGFkIHRoZSBtb3N0IHRpbWUgcmVtb3ZlZCBieSBlYWNoIG1ham9yIENCRkMgcmVnaW9uYWwgb2ZmaWNlLgoKYGBge3IgdG9wLWNlbnNvcmVkLWZpbG1zLWJ5LW9mZmljZX0KZmlsbV9sZXZlbF9zdW1tYXJ5IDwtIGRhdGEgJT4lCiAgZmlsdGVyKCFpcy5uYShvZmZpY2UpICYgIXN0cl9kZXRlY3Qob2ZmaWNlLCAiXFwubXA0JCIpKSAlPiUKICBncm91cF9ieShpZCwgbW92aWVfbmFtZSwgb2ZmaWNlLCBsYW5ndWFnZSwgY2VydF9kYXRlLCBjZXJ0X25vKSAlPiUKICBzdW1tYXJpc2UoCiAgICB0b3RhbF9jdXRzID0gbigpLAogICAgdG90YWxfdGltZV9yZW1vdmVkX3NlY3MgPSBzdW0odG90YWxfbW9kaWZpZWRfdGltZV9zZWNzLCBuYS5ybSA9IFRSVUUpLAogICAgLmdyb3VwcyA9ICdkcm9wJwogICkgJT4lCiAgZmlsdGVyKHRvdGFsX3RpbWVfcmVtb3ZlZF9zZWNzID4gMCwgdG90YWxfdGltZV9yZW1vdmVkX3NlY3MgPCAxODAwKSAlPiUKICBtdXRhdGUoCiAgICB5ZWFyID0gbWFwMl9kYmwoY2VydF9kYXRlLCBjZXJ0X25vLCB+IGV4dHJhY3RfeWVhcigueCwgLnkpKSwKICAgIGNsZWFuZWRfbmFtZSA9IG1hcF9jaHIobW92aWVfbmFtZSwgY2xlYW5fbmFtZSksCiAgICBzbHVnID0gbWFwMl9jaHIoY2xlYW5lZF9uYW1lLCB5ZWFyLCBtYWtlX3NsdWcpCiAgKQoKdG9wX2NlbnNvcmVkX2J5X29mZmljZSA8LSBmaWxtX2xldmVsX3N1bW1hcnkgJT4lCiAgZ3JvdXBfYnkob2ZmaWNlKSAlPiUKICBhcnJhbmdlKGRlc2ModG90YWxfdGltZV9yZW1vdmVkX3NlY3MpKSAlPiUKICBzbGljZV9oZWFkKG4gPSAxMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZSgKICAgIGR1cmF0aW9uX2Zvcm1hdHRlZCA9IGZvcm1hdF9zZWNvbmRzKHRvdGFsX3RpbWVfcmVtb3ZlZF9zZWNzKQogICkgJT4lCiAgYXJyYW5nZShvZmZpY2UsIGRlc2ModG90YWxfdGltZV9yZW1vdmVkX3NlY3MpKSAlPiUKICBzZWxlY3QoT2ZmaWNlID0gb2ZmaWNlLCBMYW5ndWFnZSA9IGxhbmd1YWdlLCBgRmlsbSBOYW1lYCA9IGNsZWFuZWRfbmFtZSwgCiAgICAgICAgIGBUaW1lIFJlbW92ZWRgID0gZHVyYXRpb25fZm9ybWF0dGVkLCBgVG90YWwgQ3V0c2AgPSB0b3RhbF9jdXRzLCBTbHVnID0gc2x1ZykKCmRpc3BsYXlfdGFibGUgPC0gdG9wX2NlbnNvcmVkX2J5X29mZmljZSAlPiUKICBzZWxlY3QoLVNsdWcpCgpkaXNwbGF5X3RhYmxlICU+JQogIGd0KCkgJT4lCiAgdGFiX2hlYWRlcigKICAgIHRpdGxlID0gIlRvcCAxMCBNb3N0IENlbnNvcmVkIEZpbG1zIGJ5IFRpbWUgUmVtb3ZlZCIsCiAgICBzdWJ0aXRsZSA9ICJGaWxtcyB3aXRoIHRoZSBoaWdoZXN0IG1vZGlmaWNhdGlvbiB0aW1lcyBmb3IgZWFjaCByZWdpb25hbCBvZmZpY2UiCiAgKSAlPiUKICB0YWJfc3R5bGUoCiAgICBzdHlsZSA9IGxpc3QoCiAgICAgIGNlbGxfZmlsbChjb2xvciA9IHdlc19jb2xvcnNbM10sIGFscGhhID0gMC4zKSwKICAgICAgY2VsbF90ZXh0KHdlaWdodCA9ICJib2xkIikKICAgICksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19jb2x1bW5fbGFiZWxzKCkKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF90ZXh0KHN0eWxlID0gIml0YWxpYyIpLAogICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gYEZpbG0gTmFtZWApCiAgKSAlPiUKICBjb2xzX2FsaWduKAogICAgYWxpZ24gPSAiY2VudGVyIiwKICAgIGNvbHVtbnMgPSBjKExhbmd1YWdlLCBgVGltZSBSZW1vdmVkYCwgYFRvdGFsIEN1dHNgKQogICkgJT4lCiAgY29sc19hbGlnbigKICAgIGFsaWduID0gImxlZnQiLAogICAgY29sdW1ucyA9IGMoT2ZmaWNlLCBgRmlsbSBOYW1lYCkKICApICU+JQogIHRhYl9vcHRpb25zKAogICAgdGFibGUuZm9udC5uYW1lcyA9ICJBdGtpbnNvbiBIeXBlcmxlZ2libGUiLAogICAgaGVhZGluZy50aXRsZS5mb250LnNpemUgPSAxNiwKICAgIGhlYWRpbmcuc3VidGl0bGUuZm9udC5zaXplID0gMTIsCiAgICBjb2x1bW5fbGFiZWxzLmZvbnQuc2l6ZSA9IDEyLAogICAgdGFibGUuZm9udC5zaXplID0gMTEKICApICU+JQogIHRhYl9zdHlsZSgKICAgIHN0eWxlID0gY2VsbF9ib3JkZXJzKAogICAgICBzaWRlcyA9IGMoInRvcCIsICJib3R0b20iKSwKICAgICAgY29sb3IgPSAibGlnaHRncmF5IiwKICAgICAgd2VpZ2h0ID0gcHgoMSkKICAgICksCiAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KCkKICApCgojIEV4cG9ydCB0b3AgY2Vuc29yZWQgZmlsbXMgZGF0YSB3aXRoIHNsdWcgaW5jbHVkZWQKd3JpdGVfanNvbih0b3BfY2Vuc29yZWRfYnlfb2ZmaWNlLCAidG9wX2NlbnNvcmVkX2ZpbG1zLmpzb24iLCBwcmV0dHkgPSBUUlVFLCBhdXRvX3VuYm94ID0gVFJVRSkKYGBgCgojIyBGdXJ0aGVyIEluZm9ybWF0aW9uCgpGb3IgbW9yZSBkZXRhaWxzLCBpbnRlcmFjdGl2ZSBjaGFydHMsIGFuZCB0aGUgZnVsbCBleHBsb3JlciwgcGxlYXNlIHZpc2l0IG91ciBwcm9qZWN0IHdlYnNpdGU6IGh0dHBzOi8vY2JmYy53YXRjaAoKVGhlIGFuYWx5c2lzIHdhcyBjb25kdWN0ZWQgYnkgQW1hbiBCaGFyZ2F2YSBhbmQgVml2ZWsgTWF0dGhldyBmb3IgRGlhZ3JhbSBDaGFzaW5nLgoKIyMjIEhvdyB0byBDaXRlCgpgYGAKQmhhcmdhdmEsIEEuLCBNYXR0aGV3LCBWLiwgJiBEaWFncmFtIENoYXNpbmcuICgyMDI1KS4gQW5hbHl6aW5nIEZpbG0gQ2Vuc29yc2hpcCBpbiBJbmRpYTogQ0JGQyBXYXRjaC4gUmV0cmlldmVkIGZyb20gaHR0cHM6Ly9jYmZjLndhdGNoLgpgYGAKCioqQmliVGVYIEVudHJ5KioKCkZvciB1c2UgaW4gTGFUZVggZG9jdW1lbnRzLCB5b3UgY2FuIHVzZSB0aGUgZm9sbG93aW5nIEJpYlRlWCBlbnRyeToKCmBgYGJpYnRleApAbWlzY3tCaGFyZ2F2YTIwMjVDQkZDLAogIGF1dGhvciA9IHtCaGFyZ2F2YSwgQW1hbiBhbmQgTWF0dGhldywgVml2ZWsgYW5kIHtEaWFncmFtIENoYXNpbmd9fSwKICB0aXRsZSAgPSB7QW5hbHl6aW5nIEZpbG0gQ2Vuc29yc2hpcCBpbiBJbmRpYTogQ0JGQyBXYXRjaH0sCiAgeWVhciAgID0gezIwMjV9LAogIG1vbnRoICA9IHtTZXB0ZW1iZXJ9LAogIGhvd3B1Ymxpc2hlZCA9IHtcdXJse2h0dHBzOi8vY2JmYy53YXRjaH19LAogIG5vdGUgICA9IHtBbmFseXNpcyBhbmQgdmlzdWFsaXphdGlvbnMgYnkgRGlhZ3JhbSBDaGFzaW5nLiBMYXN0IGFjY2Vzc2VkOiBcdG9kYXl9Cn0KYGBgCg==