TidyTuesday week 29 Scooby Doo Episodes, data from Kaggle and aggregated by plummye.

# load libaries
library(tidyverse)
library(scales)
library(lubridate)
library(skimr)
library(tidytext)
library(ggtext)
library(ggpubr)
library(colorspace)
library(ggsci)
library(viridis)
library(gggrid) 
library(packcircles)
library(ggmosaic)
library(ggbump)
library(ggsankey)
# import data
scoobydoo <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-07-13/scoobydoo.csv')

# import data (change NULL to NA)
scoobydoo1 <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2021/2021-07-13/scoobydoo.csv', na="NULL")
# summary

# numeric variables
scoobydoo1 %>% 
  select_if(is.numeric) %>%
  skim()

# logical variables
scoobydoo1 %>% 
  select_if(is.logical) %>%
  skim()

# character variables
scoobydoo1 %>% 
  select_if(is.character) %>%
  mutate_if(is.character,as.factor) %>%
  skim()

Main character action count in TV series

# tv series: action count by character
table1 = scoobydoo %>% 
  filter(format=="TV Series") %>%
  select(index,caught_fred:snack_scooby) %>%
  pivot_longer(!index) %>%
  extract(name, c("type", "char"), "(.*)_(.*)") %>%
  filter(value=="TRUE") %>%
  group_by(type, char) %>% 
  tally() 

p1 = table1 %>% 
  mutate(char=str_to_title(char)) %>%
  ggplot(aes(x=type, y=n, fill=type)) + 
  geom_bar(stat="identity",width=0.9, alpha=0.95) + 
  facet_wrap(~char, ncol=5) + 
  scale_fill_manual(values=c("#76a2ca","#cd7e05","#b2bb1b","#7c68ae")) +
  scale_x_discrete(expand=c(.3,.3)) +
  theme_minimal() + 
  theme(panel.grid.major.x=element_blank(),
        panel.grid.minor.y=element_blank(),
        plot.subtitle=element_markdown(size=10, face="bold", hjust=0.5),
        axis.text.x=element_blank(),
        strip.text=element_text(face="bold", size=8),
        legend.position="none",
        plot.title.position = "plot",
        plot.title=element_text(hjust=0.5, face="bold",size=12),
        axis.title=element_blank(),
        #plot.background = element_rect(fill="#f5f7f5", color=NA),
        plot.margin=unit(c(1,1,0.5,1),"cm"),
        axis.text.y=element_text(size=7),
        panel.grid=element_line(color="#bccbc0", linetype = 3)) + 
  labs(subtitle= "<span style = 'color:#76a2ca'><b>Captured</b></span>, 
       <span style = 'color:#cd7e05'><b>Caught</b></span>,
       <span style = 'color:#b2bb1b'><b>Snack eaten</b></span>, and
       <span style = 'color:#7c68ae'><b>Unmask</b></span><br>",
       title="Scooby Doo TV Series")
# tv series: captured vs caught
d1 = scoobydoo %>% 
  filter(format=="TV Series") %>%
  select(index,caught_fred:captured_scooby) %>%
  pivot_longer(!index) %>%
  extract(name, c("type", "char"), "(.*)_(.*)") %>%
  filter(value=="TRUE") %>%
  group_by(type, char) %>% 
  tally() %>%
  ungroup() 

d2 = d1 %>% 
  group_by(char) %>%
  mutate(diff= n-lag(n),
         diff2=ifelse(is.na(diff),mean(diff,na.rm=T),diff),
         cat = ifelse(diff2>0,"Caught > Captured","Captured > Caught")) %>%
  arrange(char, type) %>%
  select(-diff) %>%
  ungroup() %>%
  mutate(char=str_to_title(char),
         type=str_to_title(type))

d3 = d2 %>% group_by(char) %>% mutate(mea= median(n)) %>% filter(type=="Caught")

p2 = d2 %>%
  ggplot(aes(y=fct_rev(char), x=n)) + 
  geom_point(aes(shape=type),size=3) + 
  geom_line(aes(group=char, color=cat)) + 
  scale_shape_manual(values=c(1,19)) + 
  scale_color_manual(values =c("#76a2ca","#cd7e05")) + 
  scale_x_continuous(limits=c(0,120), breaks=seq(30,120,20)) +
  geom_text(data = d3, 
            aes(x=mea, y= char, label=abs(diff2)),size=3, color="black", vjust=-0.9) + 
  geom_text(data =d3, aes(x=0, y=char, label=char, color=cat), size=4, hjust=0, fontface="bold",
            show.legend = F) + 
  theme(legend.position = "top",
        axis.text.y=element_blank(),
        axis.title=element_blank(),
        plot.margin=unit(c(1,1,0.5,1),"cm"),
        plot.title.position = "plot",
        plot.title=element_text(face="bold", hjust=0.5,size=12),
        panel.grid.minor=element_blank()) + 
  labs(x="Count", y="Character", shape="", color="",
       title="Scooby Doo TV Series: Captured vs. Caught",
       caption="\nTidy Tuesday Week 29 | Data from Kaggle")  + 
  guides(shape = guide_legend(order = 1),color = guide_legend(order = 2, override.aes = list(size = 2)))
# combine p1 and p2
ggarrange(p1,p2,nrow=2)

ALT text: Bar plot and dot plot showing the action count of main characters in Scooby Doo TV series. Bar plot shows count of captured, caught, snack eaten and unmask by main characters, where Daphnie has more snacks eaten than caught. Dot plot shows the count of captured vs. caught, where Fred and Scooby has more caught than captured while the others (Daphnie, Shaggy and Velma) has more captured than caught.

Proportion of real monsters by format

# packing circles chart

data2a = scoobydoo %>% 
  group_by(format,monster_real) %>% tally() %>% 
  mutate(prop=n/sum(n),prop = round(prop*100)) %>% ungroup()

data2b = data2a %>% group_by(format) %>% count(wt=prop) %>% ungroup()

data2c = data2b %>% 
  pmap_df(
  .f = ~circleProgressiveLayout(rep(0.5, ..2))) %>% 
  mutate(format = rep(data2a$format, data2a$prop),
         monster_real = rep(data2a$monster_real, data2a$prop)
  )

# graphic params
my_gpar <- gpar(
  col = "black",
  fontsize = 7
)

# plot
p3 =plot2 = data2c%>% 
    ggplot(aes(x, y, fill = monster_real)) + 
    geom_point(size = 2.75,pch = 21, color="white") + 
  facet_wrap(~format) + 
  scale_fill_manual(values=c("#128a84","#D0D61B","#F7921E")) +
  scale_y_continuous(expand=c(.1,.1)) +
  scale_x_continuous(expand=c(.2,.2)) +
  theme_void() +
  theme(legend.position="top",
        plot.title=element_text(hjust=0.5, face="bold", size=12),
        plot.subtitle=element_text(hjust=0.5, size=8),
        strip.text.x=element_text(size=8,face="bold", margin=margin(b=5,t=5)),
        plot.caption=element_text(size=8),
        legend.text = element_text(size=8),
        plot.margin=unit(c(.5,.5,.5,.5),"cm"),
        legend.margin=margin(t = 0, unit='cm'),
        legend.box.margin=margin(t=-10, b=0)) +
  guides(fill=guide_legend(ncol=3,title.position = "top", 
                           title.hjust = .5, override.aes = list(size=3))) + 
  labs(subtitle="(Proportion of real monsters, where each dot represents 1%)", fill="",
       title="Real Monsters in Scooby Doo, by Format")
p3

Proportion of monster type

# proportion of monster type
scoobydoo1 %>% separate_rows(monster_type,sep=",", convert=T) %>%
  select(index, monster_type) %>%
  drop_na(monster_type) %>%
  mutate(monster_type=str_trim(monster_type),
         monster_type=recode(monster_type, 
                             Disguised = "Disguise",
                             Disguised = "Disugised",
                             Possessed="Possessed Object"
                             )) %>%
  #count(monster_type, sort=T) %>%
  filter(monster_type!="NULL") %>%
  mutate(mt = fct_lump(monster_type, 10)) %>%
  count(mt, sort=T) %>%
  mutate(perc= paste0(sprintf("%2.1f", n/sum(n)*100),"%"),
         mt = fct_rev(fct_inorder(mt)),
         mt = fct_relevel(mt, "Other",after=0),
         col=case_when(row_number()==1 ~ "#76a2ca", 
                         row_number()==2 ~ "#cd7e05",
                         row_number()==3 ~ "#b2bb1b",
                         row_number()==4 ~ "#7c68ae",
                         mt =="Other" ~"grey70",
         TRUE~"grey55")) %>%
  ggplot(aes(y=mt, x=n, fill=col)) + 
  geom_col(width=0.7, show.legend = F, alpha=0.95) +
  scale_fill_identity() + 
  scale_color_identity() + 
  geom_text(aes(label=perc), size=3, color="white", hjust=1.3,fontface="bold") + 
  geom_text(aes(x=-5, label=mt, color=col),size=3.5, hjust=1, fontface="bold") + 
  scale_x_continuous(expand=expansion(mult=c(.3,.1))) +
  theme_void() + 
  theme(plot.subtitle=element_text(hjust=0.06),
        plot.margin=unit(c(1,1,1,1),"cm")) +
  labs(subtitle="Proportion of monster types in Scooby Doo\n")

Proportion of monster gender by format

# monster gender
scoobydoo1 %>% select(index, format, monster_gender) %>%
  drop_na(format, monster_gender) %>%
  separate_rows(monster_gender,sep=",", convert=T) %>%
  filter(monster_gender!="",monster_gender!="None") %>%
  group_by(format, monster_gender) %>% tally() %>%
  mutate(prop=round(n/sum(n),3)) %>%
  ggplot(aes(y=fct_rev(format), x=prop, fill=monster_gender)) + 
  geom_col(position=position_dodge2(width=0.2,preserve = "single"), width=0.5,alpha=0.8) + 
  scale_fill_manual(values=c("#ee9b00","#005f73")) +
  scale_x_continuous(labels=scales::percent_format(),position="top") +
  scale_y_discrete(labels = function(x) str_wrap(x, width = 10)) + 
  theme_minimal() +
  theme(legend.position="top",
        panel.grid.minor=element_blank(),
        axis.title=element_blank(),
        legend.justification = "left",
        legend.margin = margin(l=15),
        plot.title.position = "plot",
        axis.text.x.top = element_text(margin = margin(b = -10, unit = "pt")),
        axis.text.y.left = element_text(margin = margin(r = -10, unit = "pt")),
        plot.margin=unit(c(1,1,1,1),"cm")) + 
  guides(fill=guide_legend(keyheight = 1, keywidth = 0.4, reverse=T)) + 
  labs(fill="",
       subtitle="Proportion of monster gender by format") 

# percentage of female monsters by monster amount
gender_amount = scoobydoo1 %>% 
  drop_na(monster_gender,monster_amount) %>%
  #mutate(ma = fct_lump(factor(monster_amount),5, other_level = "5 and above")) %>%
  select(index, monster_amount, monster_gender) %>%
  separate_rows(monster_gender,sep=",", convert=T) %>%
  group_by(index,monster_amount) %>% 
  count(monster_gender) %>%
  ungroup() %>%
  filter(monster_gender!="",
         monster_gender!="None") %>%
  group_by(monster_amount, monster_gender) %>% tally(n) %>%
  mutate(prop=round(n/sum(n),3))
  
gender_amount %>% filter(monster_gender=="Female") %>% arrange(desc(prop))

Monster gender and amount

# mosiac plot: monster gender and monster amount
x= scoobydoo1 %>% 
  drop_na(monster_gender,monster_amount) %>%
  #mutate(ma = fct_lump(factor(monster_amount),4, other_level = "5 and above")) %>%
  select(index, monster_amount, monster_gender) %>%
  separate_rows(monster_gender,sep=",", convert=T) %>%
  filter(monster_gender!="",
         monster_gender!="None")

ggplot(data = x) + geom_mosaic(aes(x=product(monster_gender,monster_amount), fill=monster_gender)) + 
  scale_fill_manual(values=c("#ee9b00","#005f73")) + 
  theme(panel.grid=element_line(size=.3),
        plot.margin=unit(c(1,2,1,2),"cm"),
        legend.position = "none",
        axis.title=element_text(size = 9),
        plot.title.position = "plot") + 
  labs(x="Monster amount", y="Monster gender",
       subtitle="Monster amount and gender")

Monster count, imdb score, format

# monster count, imdb score, format
scoobydoo %>% 
  mutate(imdb2 = parse_number(imdb)) %>%
  drop_na(imdb2) %>%
  filter(format!="Movie (Theatrical)") %>%
  ggplot(aes(x=monster_amount, y=imdb2, color=format)) + 
  geom_point(alpha=0.5) +
  scale_color_npg() + 
  theme_light(base_size=10) +
  theme(legend.position = "none",
        panel.grid.minor=element_blank(),
        panel.grid.major=element_line(size=.3),
        strip.text=element_text(size = 9),
        strip.background = element_rect(fill="slategrey")) + 
  facet_wrap(~format) + 
  labs(x="Monster count", y="IMDB rating",
       subtitle = "Monster count and IMDB rating, by format")

TV series: monster_amount and imdb score

# TV series: monster_amount and imdb score 
scoobydoo1 %>% drop_na(imdb,monster_amount) %>%
  mutate(ma = fct_lump(factor(monster_amount),5, other_level = "5 and above")) %>%
  filter(format=="TV Series") %>%
  ggplot(aes(x=ma, y=imdb,color=ma)) + 
  geom_half_boxplot(outlier.size=-1) + 
  geom_half_point(alpha=0.7) + 
  theme(legend.position = "none",
        plot.margin=unit(c(1,2,1,1),"cm"),
        panel.grid.minor=element_blank(),
        axis.text=element_text(size=9),
        axis.title.x=element_text(margin=margin(t=10),size=9),
        axis.title.y = element_text(margin=margin(r=10),size=9),
        plot.title.position = "plot") + 
  scale_color_npg() + 
  labs(x= "Monster amount", y="IMDB score",
       subtitle="IMDB score by monster amount\n")

Monster amount and network

# monster amount ny network
scoobydoo %>% 
  mutate(network2 = fct_lump(network,7)) %>%
  ggplot(aes(y=fct_rev(network2), x=monster_amount, color=network2, fill=network2)) + 
  geom_density_ridges(
    jittered_points = TRUE,
    position = position_points_jitter(width = 0.05, height = 0),
    point_shape = '|', point_size = 3, point_alpha = 0.7, alpha = 0.3,
  ) +
  scale_fill_d3() +
  scale_color_d3() +
  scale_y_discrete(expand=expansion(mult=c(0.1,0.25))) +
  theme(panel.grid.minor=element_blank(),
        legend.position="none",
        plot.title.position = "plot",
        axis.title=element_text(size=9)) + 
  labs(y="Network", x="Monster amount", subtitle="Monster amount by network")

Date aired and snacks rank

# most unmask by
as_decade <- function(year) {
  return(round(year / 10) * 10)
}

`%not_in%` <- Negate(`%in%`)

unmask_rank <-
  scoobydoo1 %>%
  select(starts_with('unmask'), date_aired) %>%
  mutate(across(where(is.character),
                as.logical)) %>%
  mutate(year = year(date_aired),
         decade = as_decade(year)) %>%
  pivot_longer(where(is.logical),
               names_to = 'unmask_by',
               names_prefix = 'unmask_') %>%
  mutate(unmask_by = str_to_title(unmask_by)) %>%
  filter(unmask_by %not_in% c('Other', 'Not')) %>%
  count(unmask_by, decade, wt = value) %>%
  arrange(desc(n)) %>%
  group_by(decade) %>%
  mutate(rank = rank(n, ties.method = 'first')) %>%
  ungroup()

unmask_rank %>%
  ggplot(aes(x = decade, y = rank, color = unmask_by)) +
  geom_bump(smooth = 8) +
  geom_point() +
  geom_text(data =  unmask_rank %>% filter(decade == min(decade)),
            aes(x = decade - 1, label = unmask_by), size = 3.5, hjust = 1, fontface = 'bold')  +
  geom_text(data =  unmask_rank %>% filter(decade == max(decade)),
            aes(x = decade + 1, label = unmask_by), size = 3.5, hjust = 0,fontface = 'bold') +
  geom_bump(size = 1.5, smooth = 8) +
  geom_point(size = 3) +
  #scale_y_reverse(breaks = seq(1, 5, 1), expand=c(0.05,0.05)) +
  #scale_y_discrete(breaks = seq(1, 5, 1), expand=c(0.05,0.05)) +
  scale_x_continuous(limits = c(1965, 2025),breaks = seq(1970, 2020, 10), expand=c(0.05,0.05)) + 
  scale_color_manual(values=c("#966a00","#79af30","#622486","#F7801E","#76a2ca")) +
  scale_shape_manual(values=c(21:25)) +
  theme_light(base_size = 10) +
  theme(legend.position = "none",
        panel.grid = element_blank(),
        panel.border=element_blank(),
        axis.title=element_blank(),
        plot.title.position="plot",
        plot.margin=unit(c(1.5,2,1.5,2),"cm")
        ) + 
  labs(subtitle="Characters with most unmask by decade\n")

Date aired, cumulative snacks, cumulative caught

# date aired
theme_set(theme_minimal(base_size = 10)) 
theme_update(legend.position = "none", 
        axis.title = element_text(size=9),
        plot.margin=unit(c(0.5,0.5,0.5,0.5),"cm"),
        plot.title.position = "plot",
        panel.grid.minor=element_blank())

# cumulative snack (date_aired)
snack_tab = scoobydoo %>%
  select(index,
         series_name,
         season,
         title,
         date_aired,
         starts_with("snack")) %>%
  pivot_longer(starts_with("snack")) %>%
  group_by(name) %>%
  arrange(date_aired) %>%
  mutate(cumulative = ifelse(value == TRUE, 1, 0),
         cumulative = cumsum(cumulative),
         name = str_to_title(gsub("snack_", "", name)),
         name=case_when(name == "Daphnie"~"Daphne",
                        TRUE ~ name))

plot1 = snack_tab %>% 
  arrange(date_aired) %>% 
  ggplot(aes(x=date_aired, y=cumulative))+
  geom_path(aes(color=name), size=1)+
  geom_text(data=. %>% group_by(name) %>% arrange(date_aired) %>% slice(n()) ,
                  aes(color=name, label=name), hjust=0, nudge_x = 100, size=3, fontface="bold")+
  scale_x_date(limits=c(min(unmask$date_aired), max(unmask$date_aired)+3000)) + 
  scale_color_manual(values=c("#966a00","#79af30","#622486","#F7801E","#76a2ca")) +
  labs(x="Date aired", y="Cumulative", subtitle="Snack eaten by\n")


# cumulative snack (date_aired)
caught_tab = scoobydoo %>%
  select(index,
         series_name,
         season,
         title,
         date_aired,
         starts_with("caught")) %>%
  select(-caught_not,-caught_other) %>%
  pivot_longer(starts_with("caught")) %>%
  group_by(name) %>%
  arrange(date_aired) %>%
  mutate(cumulative = ifelse(value == TRUE, 1, 0),
         cumulative = cumsum(cumulative),
         name = str_to_title(gsub("caught_", "", name)),
         name=case_when(name == "Daphnie"~"Daphne",
                        TRUE ~ name))

plot2 = caught_tab %>%
  arrange(date_aired) %>% 
  ggplot(aes(x=date_aired, y=cumulative))+
  geom_path(aes(color=name), size=1)+
  geom_text(data=. %>% group_by(name) %>% arrange(date_aired) %>% slice(n()) ,
                  aes(color=name, label=name), hjust=0, nudge_x = 100, size=3, fontface="bold")+
  scale_x_date(limits=c(min(unmask$date_aired), max(unmask$date_aired)+3000)) + 
  scale_color_manual(values=c("#966a00","#79af30","#622486","#F7801E","#76a2ca")) +
  labs(x="Date aired", y="Cumulative",subtitle="Caught by\n")

ggarrange(plot1,plot2, ncol=2)

Sankey chart

stab <- scoobydoo %>% 
  filter(format != c("Crossover", "Movie", "Movie (Theatrical)")) %>% 
  select(
    c("index"), 
    starts_with(c("caught", "captured", "unmask","snack")), 
    -ends_with(c("other", "not"))) %>% 
  pivot_longer(
    cols = starts_with(c("caught", "captured", "unmask","snack")),
    names_to = c("action", "character"), 
    names_sep = "_",
    values_to = "value") %>% 
  mutate(character=case_when(character == "daphnie"~"daphne",
                        TRUE ~ character)) %>%
  mutate(
    value = as.integer(as.logical(value)), 
    action = recode(
      action, 
      unmask = "unmasked\nmonster",
      caught = "caught\nmonster",
      captured = "was captured",
      snack = "snack"),
    character = unlist(TC(character))) %>% 
  filter(value != 0) 

stab_long<- stab  %>% 
  make_long(character, action) 
stab_long %>% 
  ggplot(aes(x = x, next_x = next_x, node = node, next_node = next_node, fill = factor(node), label = node)) + 
  geom_sankey(flow.alpha = .6) +
  geom_sankey_label(size = 3, color = "black", fill = "white") + 
  scale_fill_manual(values=c("grey20","#ea7317","#119da4","#ffc857","#4b3f72",
                             "grey40","grey60","#90be6d","grey")) + 
  theme_void() + 
  theme(legend.position = "none")

# amount
amount = scoobydoo %>% 
  filter(format=="TV Series") %>%
  select(date_aired, suspects_amount, culprit_amount, monster_amount) %>%
  mutate(Suspect = cumsum(suspects_amount),
         Culprit = cumsum(culprit_amount),
         Monster = cumsum(monster_amount)) %>%
  select(-suspects_amount,-culprit_amount, -monster_amount) %>%
  pivot_longer(!date_aired) 

amount %>%
  ggplot(aes(x=date_aired, y=value)) + 
  geom_path(aes(color=name), size=1) + 
  geom_text(data=. %>% group_by(name) %>% arrange(date_aired) %>% slice(n()) ,
                  aes(color=name, label=name), hjust=0, nudge_x = 100, size=3.5, fontface="bold")+
  scale_color_manual(values=c("#b2bb1b","#cd7e05","#76a2ca")) + 
  scale_x_date(limits=c(min(unmask$date_aired), max(unmask$date_aired)+3000)) + 
  theme(plot.margin=unit(c(1,2,1,2),"cm")) +
  labs(x="Date aired", y="Cumulative amount", subtitle="Scooby Doo TV Series (1969 to 2021)\nCumulative suspect, monster and culprit amount\n")

Phrase, monster subtype, motive

# phrase count
scoobydoo1 %>% 
  select(index,jeepers:rooby_rooby_roo) %>%
  pivot_longer(!index) %>%
  filter(value!=0) %>%
  mutate(phrase= str_replace_all(name, "_"," "),
         phrase = str_to_title(phrase)) %>%
  group_by(phrase) %>% tally(value, sort=T) 

# monster subtype count
scoobydoo1 %>% 
  separate_rows(monster_subtype,sep=",", convert=T) %>%
  drop_na(monster_subtype) %>%
  count(monster_subtype, sort=T)

# motive count
scoobydoo1 %>% 
  count(motive, sort=T)
LS0tCnRpdGxlOiAiVGlkeSBUdWVzZGF5IFdlZWsgMjkvMjAyMSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKW1RpZHlUdWVzZGF5XShodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5KSB3ZWVrIDI5IFtTY29vYnkgRG9vIEVwaXNvZGVzXShodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L2Jsb2IvbWFzdGVyL2RhdGEvMjAyMS8yMDIxLTA3LTEzL3JlYWRtZS5tZCksIGRhdGEgZnJvbSBbS2FnZ2xlXShodHRwczovL3d3dy5rYWdnbGUuY29tL3dpbGxpYW1zY2hvb2xlbWFuL3Njb29ieWRvby1jb21wbGV0ZSkgYW5kIGFnZ3JlZ2F0ZWQgYnkgIFtwbHVtbXllXShodHRwczovL3d3dy5rYWdnbGUuY29tL3dpbGxpYW1zY2hvb2xlbWFuKS4KCgpgYGB7cn0KIyBsb2FkIGxpYmFyaWVzCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoc2tpbXIpCmxpYnJhcnkodGlkeXRleHQpCmxpYnJhcnkoZ2d0ZXh0KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeShjb2xvcnNwYWNlKQpsaWJyYXJ5KGdnc2NpKQpsaWJyYXJ5KHZpcmlkaXMpCmxpYnJhcnkoZ2dncmlkKSAKbGlicmFyeShwYWNrY2lyY2xlcykKbGlicmFyeShnZ21vc2FpYykKbGlicmFyeShnZ2J1bXApCmxpYnJhcnkoZ2dzYW5rZXkpCmBgYAoKYGBge3IsIG1lc3NhZ2U9Rn0KIyBpbXBvcnQgZGF0YQpzY29vYnlkb28gPC0gcmVhZHI6OnJlYWRfY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L21hc3Rlci9kYXRhLzIwMjEvMjAyMS0wNy0xMy9zY29vYnlkb28uY3N2JykKCiMgaW1wb3J0IGRhdGEgKGNoYW5nZSBOVUxMIHRvIE5BKQpzY29vYnlkb28xIDwtIHJlYWRyOjpyZWFkX2NzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9tYXN0ZXIvZGF0YS8yMDIxLzIwMjEtMDctMTMvc2Nvb2J5ZG9vLmNzdicsIG5hPSJOVUxMIikKYGBgCgpgYGB7cn0KIyBzdW1tYXJ5CgojIG51bWVyaWMgdmFyaWFibGVzCnNjb29ieWRvbzEgJT4lIAogIHNlbGVjdF9pZihpcy5udW1lcmljKSAlPiUKICBza2ltKCkKCiMgbG9naWNhbCB2YXJpYWJsZXMKc2Nvb2J5ZG9vMSAlPiUgCiAgc2VsZWN0X2lmKGlzLmxvZ2ljYWwpICU+JQogIHNraW0oKQoKIyBjaGFyYWN0ZXIgdmFyaWFibGVzCnNjb29ieWRvbzEgJT4lIAogIHNlbGVjdF9pZihpcy5jaGFyYWN0ZXIpICU+JQogIG11dGF0ZV9pZihpcy5jaGFyYWN0ZXIsYXMuZmFjdG9yKSAlPiUKICBza2ltKCkKYGBgCgoKIyMjIyBNYWluIGNoYXJhY3RlciBhY3Rpb24gY291bnQgaW4gVFYgc2VyaWVzCiogc2hhcmVkIG9uIFtUd2l0dGVyXShodHRwczovL3R3aXR0ZXIuY29tL2xlZW9sbmV5My9zdGF0dXMvMTQxNDg0Mzk4Mjg3NDY0ODU3NykKCmBgYHtyfQojIHR2IHNlcmllczogYWN0aW9uIGNvdW50IGJ5IGNoYXJhY3Rlcgp0YWJsZTEgPSBzY29vYnlkb28gJT4lIAogIGZpbHRlcihmb3JtYXQ9PSJUViBTZXJpZXMiKSAlPiUKICBzZWxlY3QoaW5kZXgsY2F1Z2h0X2ZyZWQ6c25hY2tfc2Nvb2J5KSAlPiUKICBwaXZvdF9sb25nZXIoIWluZGV4KSAlPiUKICBleHRyYWN0KG5hbWUsIGMoInR5cGUiLCAiY2hhciIpLCAiKC4qKV8oLiopIikgJT4lCiAgZmlsdGVyKHZhbHVlPT0iVFJVRSIpICU+JQogIGdyb3VwX2J5KHR5cGUsIGNoYXIpICU+JSAKICB0YWxseSgpIAoKcDEgPSB0YWJsZTEgJT4lIAogIG11dGF0ZShjaGFyPXN0cl90b190aXRsZShjaGFyKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXR5cGUsIHk9biwgZmlsbD10eXBlKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsd2lkdGg9MC45LCBhbHBoYT0wLjk1KSArIAogIGZhY2V0X3dyYXAofmNoYXIsIG5jb2w9NSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzc2YTJjYSIsIiNjZDdlMDUiLCIjYjJiYjFiIiwiIzdjNjhhZSIpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQ9YyguMywuMykpICsKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5zdWJ0aXRsZT1lbGVtZW50X21hcmtkb3duKHNpemU9MTAsIGZhY2U9ImJvbGQiLCBoanVzdD0wLjUpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBzdHJpcC50ZXh0PWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiwgc2l6ZT04KSwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC41LCBmYWNlPSJib2xkIixzaXplPTEyKSwKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAjcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9IiNmNWY3ZjUiLCBjb2xvcj1OQSksCiAgICAgICAgcGxvdC5tYXJnaW49dW5pdChjKDEsMSwwLjUsMSksImNtIiksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NyksCiAgICAgICAgcGFuZWwuZ3JpZD1lbGVtZW50X2xpbmUoY29sb3I9IiNiY2NiYzAiLCBsaW5ldHlwZSA9IDMpKSArIAogIGxhYnMoc3VidGl0bGU9ICI8c3BhbiBzdHlsZSA9ICdjb2xvcjojNzZhMmNhJz48Yj5DYXB0dXJlZDwvYj48L3NwYW4+LCAKICAgICAgIDxzcGFuIHN0eWxlID0gJ2NvbG9yOiNjZDdlMDUnPjxiPkNhdWdodDwvYj48L3NwYW4+LAogICAgICAgPHNwYW4gc3R5bGUgPSAnY29sb3I6I2IyYmIxYic+PGI+U25hY2sgZWF0ZW48L2I+PC9zcGFuPiwgYW5kCiAgICAgICA8c3BhbiBzdHlsZSA9ICdjb2xvcjojN2M2OGFlJz48Yj5Vbm1hc2s8L2I+PC9zcGFuPjxicj4iLAogICAgICAgdGl0bGU9IlNjb29ieSBEb28gVFYgU2VyaWVzIikKYGBgCgpgYGB7cn0KIyB0diBzZXJpZXM6IGNhcHR1cmVkIHZzIGNhdWdodApkMSA9IHNjb29ieWRvbyAlPiUgCiAgZmlsdGVyKGZvcm1hdD09IlRWIFNlcmllcyIpICU+JQogIHNlbGVjdChpbmRleCxjYXVnaHRfZnJlZDpjYXB0dXJlZF9zY29vYnkpICU+JQogIHBpdm90X2xvbmdlcighaW5kZXgpICU+JQogIGV4dHJhY3QobmFtZSwgYygidHlwZSIsICJjaGFyIiksICIoLiopXyguKikiKSAlPiUKICBmaWx0ZXIodmFsdWU9PSJUUlVFIikgJT4lCiAgZ3JvdXBfYnkodHlwZSwgY2hhcikgJT4lIAogIHRhbGx5KCkgJT4lCiAgdW5ncm91cCgpIAoKZDIgPSBkMSAlPiUgCiAgZ3JvdXBfYnkoY2hhcikgJT4lCiAgbXV0YXRlKGRpZmY9IG4tbGFnKG4pLAogICAgICAgICBkaWZmMj1pZmVsc2UoaXMubmEoZGlmZiksbWVhbihkaWZmLG5hLnJtPVQpLGRpZmYpLAogICAgICAgICBjYXQgPSBpZmVsc2UoZGlmZjI+MCwiQ2F1Z2h0ID4gQ2FwdHVyZWQiLCJDYXB0dXJlZCA+IENhdWdodCIpKSAlPiUKICBhcnJhbmdlKGNoYXIsIHR5cGUpICU+JQogIHNlbGVjdCgtZGlmZikgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShjaGFyPXN0cl90b190aXRsZShjaGFyKSwKICAgICAgICAgdHlwZT1zdHJfdG9fdGl0bGUodHlwZSkpCgpkMyA9IGQyICU+JSBncm91cF9ieShjaGFyKSAlPiUgbXV0YXRlKG1lYT0gbWVkaWFuKG4pKSAlPiUgZmlsdGVyKHR5cGU9PSJDYXVnaHQiKQoKcDIgPSBkMiAlPiUKICBnZ3Bsb3QoYWVzKHk9ZmN0X3JldihjaGFyKSwgeD1uKSkgKyAKICBnZW9tX3BvaW50KGFlcyhzaGFwZT10eXBlKSxzaXplPTMpICsgCiAgZ2VvbV9saW5lKGFlcyhncm91cD1jaGFyLCBjb2xvcj1jYXQpKSArIAogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxLDE5KSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID1jKCIjNzZhMmNhIiwiI2NkN2UwNSIpKSArIAogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YygwLDEyMCksIGJyZWFrcz1zZXEoMzAsMTIwLDIwKSkgKwogIGdlb21fdGV4dChkYXRhID0gZDMsIAogICAgICAgICAgICBhZXMoeD1tZWEsIHk9IGNoYXIsIGxhYmVsPWFicyhkaWZmMikpLHNpemU9MywgY29sb3I9ImJsYWNrIiwgdmp1c3Q9LTAuOSkgKyAKICBnZW9tX3RleHQoZGF0YSA9ZDMsIGFlcyh4PTAsIHk9Y2hhciwgbGFiZWw9Y2hhciwgY29sb3I9Y2F0KSwgc2l6ZT00LCBoanVzdD0wLCBmb250ZmFjZT0iYm9sZCIsCiAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5tYXJnaW49dW5pdChjKDEsMSwwLjUsMSksImNtIiksCiAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChmYWNlPSJib2xkIiwgaGp1c3Q9MC41LHNpemU9MTIpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpKSArIAogIGxhYnMoeD0iQ291bnQiLCB5PSJDaGFyYWN0ZXIiLCBzaGFwZT0iIiwgY29sb3I9IiIsCiAgICAgICB0aXRsZT0iU2Nvb2J5IERvbyBUViBTZXJpZXM6IENhcHR1cmVkIHZzLiBDYXVnaHQiLAogICAgICAgY2FwdGlvbj0iXG5UaWR5IFR1ZXNkYXkgV2VlayAyOSB8IERhdGEgZnJvbSBLYWdnbGUiKSAgKyAKICBndWlkZXMoc2hhcGUgPSBndWlkZV9sZWdlbmQob3JkZXIgPSAxKSxjb2xvciA9IGd1aWRlX2xlZ2VuZChvcmRlciA9IDIsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIpKSkKYGBgCgpgYGB7cixmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0zLjV9CiMgY29tYmluZSBwMSBhbmQgcDIKZ2dhcnJhbmdlKHAxLHAyLG5yb3c9MikKYGBgCgpBTFQgdGV4dDogQmFyIHBsb3QgYW5kIGRvdCBwbG90IHNob3dpbmcgdGhlIGFjdGlvbiBjb3VudCBvZiBtYWluIGNoYXJhY3RlcnMgaW4gU2Nvb2J5IERvbyBUViBzZXJpZXMuIEJhciBwbG90IHNob3dzIGNvdW50IG9mIGNhcHR1cmVkLCBjYXVnaHQsIHNuYWNrIGVhdGVuIGFuZCB1bm1hc2sgYnkgbWFpbiBjaGFyYWN0ZXJzLCB3aGVyZSBEYXBobmllIGhhcyBtb3JlIHNuYWNrcyBlYXRlbiB0aGFuIGNhdWdodC4gRG90IHBsb3Qgc2hvd3MgdGhlIGNvdW50IG9mIGNhcHR1cmVkIHZzLiBjYXVnaHQsIHdoZXJlIEZyZWQgYW5kIFNjb29ieSBoYXMgbW9yZSBjYXVnaHQgdGhhbiBjYXB0dXJlZCB3aGlsZSB0aGUgb3RoZXJzIChEYXBobmllLCBTaGFnZ3kgYW5kIFZlbG1hKSBoYXMgbW9yZSBjYXB0dXJlZCB0aGFuIGNhdWdodC4gCgoKCiMjIyMgUHJvcG9ydGlvbiBvZiByZWFsIG1vbnN0ZXJzIGJ5IGZvcm1hdAoKYGBge3J9CiMgcGFja2luZyBjaXJjbGVzIGNoYXJ0CgpkYXRhMmEgPSBzY29vYnlkb28gJT4lIAogIGdyb3VwX2J5KGZvcm1hdCxtb25zdGVyX3JlYWwpICU+JSB0YWxseSgpICU+JSAKICBtdXRhdGUocHJvcD1uL3N1bShuKSxwcm9wID0gcm91bmQocHJvcCoxMDApKSAlPiUgdW5ncm91cCgpCgpkYXRhMmIgPSBkYXRhMmEgJT4lIGdyb3VwX2J5KGZvcm1hdCkgJT4lIGNvdW50KHd0PXByb3ApICU+JSB1bmdyb3VwKCkKCmRhdGEyYyA9IGRhdGEyYiAlPiUgCiAgcG1hcF9kZigKICAuZiA9IH5jaXJjbGVQcm9ncmVzc2l2ZUxheW91dChyZXAoMC41LCAuLjIpKSkgJT4lIAogIG11dGF0ZShmb3JtYXQgPSByZXAoZGF0YTJhJGZvcm1hdCwgZGF0YTJhJHByb3ApLAogICAgICAgICBtb25zdGVyX3JlYWwgPSByZXAoZGF0YTJhJG1vbnN0ZXJfcmVhbCwgZGF0YTJhJHByb3ApCiAgKQoKIyBncmFwaGljIHBhcmFtcwpteV9ncGFyIDwtIGdwYXIoCiAgY29sID0gImJsYWNrIiwKICBmb250c2l6ZSA9IDcKKQoKIyBwbG90CnAzID1wbG90MiA9IGRhdGEyYyU+JSAKICAgIGdncGxvdChhZXMoeCwgeSwgZmlsbCA9IG1vbnN0ZXJfcmVhbCkpICsgCiAgICBnZW9tX3BvaW50KHNpemUgPSAyLjc1LHBjaCA9IDIxLCBjb2xvcj0id2hpdGUiKSArIAogIGZhY2V0X3dyYXAofmZvcm1hdCkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiIzEyOGE4NCIsIiNEMEQ2MUIiLCIjRjc5MjFFIikpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoLjEsLjEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZD1jKC4yLC4yKSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiLAogICAgICAgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSwgZmFjZT0iYm9sZCIsIHNpemU9MTIpLAogICAgICAgIHBsb3Quc3VidGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSwgc2l6ZT04KSwKICAgICAgICBzdHJpcC50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9OCxmYWNlPSJib2xkIiwgbWFyZ2luPW1hcmdpbihiPTUsdD01KSksCiAgICAgICAgcGxvdC5jYXB0aW9uPWVsZW1lbnRfdGV4dChzaXplPTgpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OCksCiAgICAgICAgcGxvdC5tYXJnaW49dW5pdChjKC41LC41LC41LC41KSwiY20iKSwKICAgICAgICBsZWdlbmQubWFyZ2luPW1hcmdpbih0ID0gMCwgdW5pdD0nY20nKSwKICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbj1tYXJnaW4odD0tMTAsIGI9MCkpICsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQobmNvbD0zLHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZS5oanVzdCA9IC41LCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9MykpKSArIAogIGxhYnMoc3VidGl0bGU9IihQcm9wb3J0aW9uIG9mIHJlYWwgbW9uc3RlcnMsIHdoZXJlIGVhY2ggZG90IHJlcHJlc2VudHMgMSUpIiwgZmlsbD0iIiwKICAgICAgIHRpdGxlPSJSZWFsIE1vbnN0ZXJzIGluIFNjb29ieSBEb28sIGJ5IEZvcm1hdCIpCnAzCmBgYAoKIyMjIyBQcm9wb3J0aW9uIG9mIG1vbnN0ZXIgdHlwZSAKCmBgYHtyfQojIHByb3BvcnRpb24gb2YgbW9uc3RlciB0eXBlCnNjb29ieWRvbzEgJT4lIHNlcGFyYXRlX3Jvd3MobW9uc3Rlcl90eXBlLHNlcD0iLCIsIGNvbnZlcnQ9VCkgJT4lCiAgc2VsZWN0KGluZGV4LCBtb25zdGVyX3R5cGUpICU+JQogIGRyb3BfbmEobW9uc3Rlcl90eXBlKSAlPiUKICBtdXRhdGUobW9uc3Rlcl90eXBlPXN0cl90cmltKG1vbnN0ZXJfdHlwZSksCiAgICAgICAgIG1vbnN0ZXJfdHlwZT1yZWNvZGUobW9uc3Rlcl90eXBlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEaXNndWlzZWQgPSAiRGlzZ3Vpc2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpc2d1aXNlZCA9ICJEaXN1Z2lzZWQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBvc3Nlc3NlZD0iUG9zc2Vzc2VkIE9iamVjdCIKICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUKICAjY291bnQobW9uc3Rlcl90eXBlLCBzb3J0PVQpICU+JQogIGZpbHRlcihtb25zdGVyX3R5cGUhPSJOVUxMIikgJT4lCiAgbXV0YXRlKG10ID0gZmN0X2x1bXAobW9uc3Rlcl90eXBlLCAxMCkpICU+JQogIGNvdW50KG10LCBzb3J0PVQpICU+JQogIG11dGF0ZShwZXJjPSBwYXN0ZTAoc3ByaW50ZigiJTIuMWYiLCBuL3N1bShuKSoxMDApLCIlIiksCiAgICAgICAgIG10ID0gZmN0X3JldihmY3RfaW5vcmRlcihtdCkpLAogICAgICAgICBtdCA9IGZjdF9yZWxldmVsKG10LCAiT3RoZXIiLGFmdGVyPTApLAogICAgICAgICBjb2w9Y2FzZV93aGVuKHJvd19udW1iZXIoKT09MSB+ICIjNzZhMmNhIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICByb3dfbnVtYmVyKCk9PTIgfiAiI2NkN2UwNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICByb3dfbnVtYmVyKCk9PTMgfiAiI2IyYmIxYiIsCiAgICAgICAgICAgICAgICAgICAgICAgICByb3dfbnVtYmVyKCk9PTQgfiAiIzdjNjhhZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBtdCA9PSJPdGhlciIgfiJncmV5NzAiLAogICAgICAgICBUUlVFfiJncmV5NTUiKSkgJT4lCiAgZ2dwbG90KGFlcyh5PW10LCB4PW4sIGZpbGw9Y29sKSkgKyAKICBnZW9tX2NvbCh3aWR0aD0wLjcsIHNob3cubGVnZW5kID0gRiwgYWxwaGE9MC45NSkgKwogIHNjYWxlX2ZpbGxfaWRlbnRpdHkoKSArIAogIHNjYWxlX2NvbG9yX2lkZW50aXR5KCkgKyAKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBlcmMpLCBzaXplPTMsIGNvbG9yPSJ3aGl0ZSIsIGhqdXN0PTEuMyxmb250ZmFjZT0iYm9sZCIpICsgCiAgZ2VvbV90ZXh0KGFlcyh4PS01LCBsYWJlbD1tdCwgY29sb3I9Y29sKSxzaXplPTMuNSwgaGp1c3Q9MSwgZm9udGZhY2U9ImJvbGQiKSArIAogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQ9ZXhwYW5zaW9uKG11bHQ9YyguMywuMSkpKSArCiAgdGhlbWVfdm9pZCgpICsgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZT1lbGVtZW50X3RleHQoaGp1c3Q9MC4wNiksCiAgICAgICAgcGxvdC5tYXJnaW49dW5pdChjKDEsMSwxLDEpLCJjbSIpKSArCiAgbGFicyhzdWJ0aXRsZT0iUHJvcG9ydGlvbiBvZiBtb25zdGVyIHR5cGVzIGluIFNjb29ieSBEb29cbiIpCmBgYAoKCgojIyMjIFByb3BvcnRpb24gb2YgbW9uc3RlciBnZW5kZXIgYnkgZm9ybWF0CgpgYGB7cn0KIyBtb25zdGVyIGdlbmRlcgpzY29vYnlkb28xICU+JSBzZWxlY3QoaW5kZXgsIGZvcm1hdCwgbW9uc3Rlcl9nZW5kZXIpICU+JQogIGRyb3BfbmEoZm9ybWF0LCBtb25zdGVyX2dlbmRlcikgJT4lCiAgc2VwYXJhdGVfcm93cyhtb25zdGVyX2dlbmRlcixzZXA9IiwiLCBjb252ZXJ0PVQpICU+JQogIGZpbHRlcihtb25zdGVyX2dlbmRlciE9IiIsbW9uc3Rlcl9nZW5kZXIhPSJOb25lIikgJT4lCiAgZ3JvdXBfYnkoZm9ybWF0LCBtb25zdGVyX2dlbmRlcikgJT4lIHRhbGx5KCkgJT4lCiAgbXV0YXRlKHByb3A9cm91bmQobi9zdW0obiksMykpICU+JQogIGdncGxvdChhZXMoeT1mY3RfcmV2KGZvcm1hdCksIHg9cHJvcCwgZmlsbD1tb25zdGVyX2dlbmRlcikpICsgCiAgZ2VvbV9jb2wocG9zaXRpb249cG9zaXRpb25fZG9kZ2UyKHdpZHRoPTAuMixwcmVzZXJ2ZSA9ICJzaW5nbGUiKSwgd2lkdGg9MC41LGFscGhhPTAuOCkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI2VlOWIwMCIsIiMwMDVmNzMiKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHM9c2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLHBvc2l0aW9uPSJ0b3AiKSArCiAgc2NhbGVfeV9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJfd3JhcCh4LCB3aWR0aCA9IDEwKSkgKyAKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0idG9wIiwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQuanVzdGlmaWNhdGlvbiA9ICJsZWZ0IiwKICAgICAgICBsZWdlbmQubWFyZ2luID0gbWFyZ2luKGw9MTUpLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgYXhpcy50ZXh0LngudG9wID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihiID0gLTEwLCB1bml0ID0gInB0IikpLAogICAgICAgIGF4aXMudGV4dC55LmxlZnQgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAtMTAsIHVuaXQgPSAicHQiKSksCiAgICAgICAgcGxvdC5tYXJnaW49dW5pdChjKDEsMSwxLDEpLCJjbSIpKSArIAogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZChrZXloZWlnaHQgPSAxLCBrZXl3aWR0aCA9IDAuNCwgcmV2ZXJzZT1UKSkgKyAKICBsYWJzKGZpbGw9IiIsCiAgICAgICBzdWJ0aXRsZT0iUHJvcG9ydGlvbiBvZiBtb25zdGVyIGdlbmRlciBieSBmb3JtYXQiKSAKYGBgCgoKYGBge3J9CiMgcGVyY2VudGFnZSBvZiBmZW1hbGUgbW9uc3RlcnMgYnkgbW9uc3RlciBhbW91bnQKZ2VuZGVyX2Ftb3VudCA9IHNjb29ieWRvbzEgJT4lIAogIGRyb3BfbmEobW9uc3Rlcl9nZW5kZXIsbW9uc3Rlcl9hbW91bnQpICU+JQogICNtdXRhdGUobWEgPSBmY3RfbHVtcChmYWN0b3IobW9uc3Rlcl9hbW91bnQpLDUsIG90aGVyX2xldmVsID0gIjUgYW5kIGFib3ZlIikpICU+JQogIHNlbGVjdChpbmRleCwgbW9uc3Rlcl9hbW91bnQsIG1vbnN0ZXJfZ2VuZGVyKSAlPiUKICBzZXBhcmF0ZV9yb3dzKG1vbnN0ZXJfZ2VuZGVyLHNlcD0iLCIsIGNvbnZlcnQ9VCkgJT4lCiAgZ3JvdXBfYnkoaW5kZXgsbW9uc3Rlcl9hbW91bnQpICU+JSAKICBjb3VudChtb25zdGVyX2dlbmRlcikgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcihtb25zdGVyX2dlbmRlciE9IiIsCiAgICAgICAgIG1vbnN0ZXJfZ2VuZGVyIT0iTm9uZSIpICU+JQogIGdyb3VwX2J5KG1vbnN0ZXJfYW1vdW50LCBtb25zdGVyX2dlbmRlcikgJT4lIHRhbGx5KG4pICU+JQogIG11dGF0ZShwcm9wPXJvdW5kKG4vc3VtKG4pLDMpKQogIApnZW5kZXJfYW1vdW50ICU+JSBmaWx0ZXIobW9uc3Rlcl9nZW5kZXI9PSJGZW1hbGUiKSAlPiUgYXJyYW5nZShkZXNjKHByb3ApKQpgYGAKCiMjIyMgTW9uc3RlciBnZW5kZXIgYW5kIGFtb3VudAoKYGBge3J9CiMgbW9zaWFjIHBsb3Q6IG1vbnN0ZXIgZ2VuZGVyIGFuZCBtb25zdGVyIGFtb3VudAp4PSBzY29vYnlkb28xICU+JSAKICBkcm9wX25hKG1vbnN0ZXJfZ2VuZGVyLG1vbnN0ZXJfYW1vdW50KSAlPiUKICAjbXV0YXRlKG1hID0gZmN0X2x1bXAoZmFjdG9yKG1vbnN0ZXJfYW1vdW50KSw0LCBvdGhlcl9sZXZlbCA9ICI1IGFuZCBhYm92ZSIpKSAlPiUKICBzZWxlY3QoaW5kZXgsIG1vbnN0ZXJfYW1vdW50LCBtb25zdGVyX2dlbmRlcikgJT4lCiAgc2VwYXJhdGVfcm93cyhtb25zdGVyX2dlbmRlcixzZXA9IiwiLCBjb252ZXJ0PVQpICU+JQogIGZpbHRlcihtb25zdGVyX2dlbmRlciE9IiIsCiAgICAgICAgIG1vbnN0ZXJfZ2VuZGVyIT0iTm9uZSIpCgpnZ3Bsb3QoZGF0YSA9IHgpICsgZ2VvbV9tb3NhaWMoYWVzKHg9cHJvZHVjdChtb25zdGVyX2dlbmRlcixtb25zdGVyX2Ftb3VudCksIGZpbGw9bW9uc3Rlcl9nZW5kZXIpKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjZWU5YjAwIiwiIzAwNWY3MyIpKSArIAogIHRoZW1lKHBhbmVsLmdyaWQ9ZWxlbWVudF9saW5lKHNpemU9LjMpLAogICAgICAgIHBsb3QubWFyZ2luPXVuaXQoYygxLDIsMSwyKSwiY20iKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIpICsgCiAgbGFicyh4PSJNb25zdGVyIGFtb3VudCIsIHk9Ik1vbnN0ZXIgZ2VuZGVyIiwKICAgICAgIHN1YnRpdGxlPSJNb25zdGVyIGFtb3VudCBhbmQgZ2VuZGVyIikKYGBgCgojIyMjIE1vbnN0ZXIgY291bnQsIGltZGIgc2NvcmUsIGZvcm1hdAoKYGBge3IsIHdhcm5pbmc9Rn0KIyBtb25zdGVyIGNvdW50LCBpbWRiIHNjb3JlLCBmb3JtYXQKc2Nvb2J5ZG9vICU+JSAKICBtdXRhdGUoaW1kYjIgPSBwYXJzZV9udW1iZXIoaW1kYikpICU+JQogIGRyb3BfbmEoaW1kYjIpICU+JQogIGZpbHRlcihmb3JtYXQhPSJNb3ZpZSAoVGhlYXRyaWNhbCkiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9bW9uc3Rlcl9hbW91bnQsIHk9aW1kYjIsIGNvbG9yPWZvcm1hdCkpICsgCiAgZ2VvbV9wb2ludChhbHBoYT0wLjUpICsKICBzY2FsZV9jb2xvcl9ucGcoKSArIAogIHRoZW1lX2xpZ2h0KGJhc2Vfc2l6ZT0xMCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfbGluZShzaXplPS4zKSwKICAgICAgICBzdHJpcC50ZXh0PWVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSJzbGF0ZWdyZXkiKSkgKyAKICBmYWNldF93cmFwKH5mb3JtYXQpICsgCiAgbGFicyh4PSJNb25zdGVyIGNvdW50IiwgeT0iSU1EQiByYXRpbmciLAogICAgICAgc3VidGl0bGUgPSAiTW9uc3RlciBjb3VudCBhbmQgSU1EQiByYXRpbmcsIGJ5IGZvcm1hdCIpCmBgYAoKIyMjIyBUViBzZXJpZXM6IG1vbnN0ZXJfYW1vdW50IGFuZCBpbWRiIHNjb3JlCgpgYGB7cn0KIyBUViBzZXJpZXM6IG1vbnN0ZXJfYW1vdW50IGFuZCBpbWRiIHNjb3JlIApzY29vYnlkb28xICU+JSBkcm9wX25hKGltZGIsbW9uc3Rlcl9hbW91bnQpICU+JQogIG11dGF0ZShtYSA9IGZjdF9sdW1wKGZhY3Rvcihtb25zdGVyX2Ftb3VudCksNSwgb3RoZXJfbGV2ZWwgPSAiNSBhbmQgYWJvdmUiKSkgJT4lCiAgZmlsdGVyKGZvcm1hdD09IlRWIFNlcmllcyIpICU+JQogIGdncGxvdChhZXMoeD1tYSwgeT1pbWRiLGNvbG9yPW1hKSkgKyAKICBnZW9tX2hhbGZfYm94cGxvdChvdXRsaWVyLnNpemU9LTEpICsgCiAgZ2VvbV9oYWxmX3BvaW50KGFscGhhPTAuNykgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGxvdC5tYXJnaW49dW5pdChjKDEsMiwxLDEpLCJjbSIpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT05KSwKICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KG1hcmdpbj1tYXJnaW4odD0xMCksc2l6ZT05KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luPW1hcmdpbihyPTEwKSxzaXplPTkpLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIpICsgCiAgc2NhbGVfY29sb3JfbnBnKCkgKyAKICBsYWJzKHg9ICJNb25zdGVyIGFtb3VudCIsIHk9IklNREIgc2NvcmUiLAogICAgICAgc3VidGl0bGU9IklNREIgc2NvcmUgYnkgbW9uc3RlciBhbW91bnRcbiIpCmBgYAoKIyMjIyBNb25zdGVyIGFtb3VudCBhbmQgbmV0d29yawoKYGBge3IsIHdhcm5pbmc9RiwgbWVzc2FnZT1GfQojIG1vbnN0ZXIgYW1vdW50IG55IG5ldHdvcmsKc2Nvb2J5ZG9vICU+JSAKICBtdXRhdGUobmV0d29yazIgPSBmY3RfbHVtcChuZXR3b3JrLDcpKSAlPiUKICBnZ3Bsb3QoYWVzKHk9ZmN0X3JldihuZXR3b3JrMiksIHg9bW9uc3Rlcl9hbW91bnQsIGNvbG9yPW5ldHdvcmsyLCBmaWxsPW5ldHdvcmsyKSkgKyAKICBnZW9tX2RlbnNpdHlfcmlkZ2VzKAogICAgaml0dGVyZWRfcG9pbnRzID0gVFJVRSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fcG9pbnRzX2ppdHRlcih3aWR0aCA9IDAuMDUsIGhlaWdodCA9IDApLAogICAgcG9pbnRfc2hhcGUgPSAnfCcsIHBvaW50X3NpemUgPSAzLCBwb2ludF9hbHBoYSA9IDAuNywgYWxwaGEgPSAwLjMsCiAgKSArCiAgc2NhbGVfZmlsbF9kMygpICsKICBzY2FsZV9jb2xvcl9kMygpICsKICBzY2FsZV95X2Rpc2NyZXRlKGV4cGFuZD1leHBhbnNpb24obXVsdD1jKDAuMSwwLjI1KSkpICsKICB0aGVtZShwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb24gPSAicGxvdCIsCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT05KSkgKyAKICBsYWJzKHk9Ik5ldHdvcmsiLCB4PSJNb25zdGVyIGFtb3VudCIsIHN1YnRpdGxlPSJNb25zdGVyIGFtb3VudCBieSBuZXR3b3JrIikKYGBgCgojIyMgRGF0ZSBhaXJlZCBhbmQgc25hY2tzIHJhbmsKKiByZWZlcmVuY2U6IGh0dHBzOi8vdHdpdHRlci5jb20vaXNpdG1hbnUvc3RhdHVzLzE0MTUwNTg0MDU4MTE2NDY0NjUvcGhvdG8vMQoKYGBge3J9CiMgbW9zdCB1bm1hc2sgYnkKYXNfZGVjYWRlIDwtIGZ1bmN0aW9uKHllYXIpIHsKICByZXR1cm4ocm91bmQoeWVhciAvIDEwKSAqIDEwKQp9CgpgJW5vdF9pbiVgIDwtIE5lZ2F0ZShgJWluJWApCgp1bm1hc2tfcmFuayA8LQogIHNjb29ieWRvbzEgJT4lCiAgc2VsZWN0KHN0YXJ0c193aXRoKCd1bm1hc2snKSwgZGF0ZV9haXJlZCkgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5jaGFyYWN0ZXIpLAogICAgICAgICAgICAgICAgYXMubG9naWNhbCkpICU+JQogIG11dGF0ZSh5ZWFyID0geWVhcihkYXRlX2FpcmVkKSwKICAgICAgICAgZGVjYWRlID0gYXNfZGVjYWRlKHllYXIpKSAlPiUKICBwaXZvdF9sb25nZXIod2hlcmUoaXMubG9naWNhbCksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gJ3VubWFza19ieScsCiAgICAgICAgICAgICAgIG5hbWVzX3ByZWZpeCA9ICd1bm1hc2tfJykgJT4lCiAgbXV0YXRlKHVubWFza19ieSA9IHN0cl90b190aXRsZSh1bm1hc2tfYnkpKSAlPiUKICBmaWx0ZXIodW5tYXNrX2J5ICVub3RfaW4lIGMoJ090aGVyJywgJ05vdCcpKSAlPiUKICBjb3VudCh1bm1hc2tfYnksIGRlY2FkZSwgd3QgPSB2YWx1ZSkgJT4lCiAgYXJyYW5nZShkZXNjKG4pKSAlPiUKICBncm91cF9ieShkZWNhZGUpICU+JQogIG11dGF0ZShyYW5rID0gcmFuayhuLCB0aWVzLm1ldGhvZCA9ICdmaXJzdCcpKSAlPiUKICB1bmdyb3VwKCkKCnVubWFza19yYW5rICU+JQogIGdncGxvdChhZXMoeCA9IGRlY2FkZSwgeSA9IHJhbmssIGNvbG9yID0gdW5tYXNrX2J5KSkgKwogIGdlb21fYnVtcChzbW9vdGggPSA4KSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3RleHQoZGF0YSA9ICB1bm1hc2tfcmFuayAlPiUgZmlsdGVyKGRlY2FkZSA9PSBtaW4oZGVjYWRlKSksCiAgICAgICAgICAgIGFlcyh4ID0gZGVjYWRlIC0gMSwgbGFiZWwgPSB1bm1hc2tfYnkpLCBzaXplID0gMy41LCBoanVzdCA9IDEsIGZvbnRmYWNlID0gJ2JvbGQnKSAgKwogIGdlb21fdGV4dChkYXRhID0gIHVubWFza19yYW5rICU+JSBmaWx0ZXIoZGVjYWRlID09IG1heChkZWNhZGUpKSwKICAgICAgICAgICAgYWVzKHggPSBkZWNhZGUgKyAxLCBsYWJlbCA9IHVubWFza19ieSksIHNpemUgPSAzLjUsIGhqdXN0ID0gMCxmb250ZmFjZSA9ICdib2xkJykgKwogIGdlb21fYnVtcChzaXplID0gMS41LCBzbW9vdGggPSA4KSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogICNzY2FsZV95X3JldmVyc2UoYnJlYWtzID0gc2VxKDEsIDUsIDEpLCBleHBhbmQ9YygwLjA1LDAuMDUpKSArCiAgI3NjYWxlX3lfZGlzY3JldGUoYnJlYWtzID0gc2VxKDEsIDUsIDEpLCBleHBhbmQ9YygwLjA1LDAuMDUpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMTk2NSwgMjAyNSksYnJlYWtzID0gc2VxKDE5NzAsIDIwMjAsIDEwKSwgZXhwYW5kPWMoMC4wNSwwLjA1KSkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiM5NjZhMDAiLCIjNzlhZjMwIiwiIzYyMjQ4NiIsIiNGNzgwMUUiLCIjNzZhMmNhIikpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjE6MjUpKSArCiAgdGhlbWVfbGlnaHQoYmFzZV9zaXplID0gMTApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXI9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QudGl0bGUucG9zaXRpb249InBsb3QiLAogICAgICAgIHBsb3QubWFyZ2luPXVuaXQoYygxLjUsMiwxLjUsMiksImNtIikKICAgICAgICApICsgCiAgbGFicyhzdWJ0aXRsZT0iQ2hhcmFjdGVycyB3aXRoIG1vc3QgdW5tYXNrIGJ5IGRlY2FkZVxuIikKYGBgCgojIyMgRGF0ZSBhaXJlZCwgY3VtdWxhdGl2ZSBzbmFja3MsIGN1bXVsYXRpdmUgY2F1Z2h0CiogcmVmZXJlbmNlOiBodHRwczovL3R3aXR0ZXIuY29tL2V0bWNraW5sZXkvc3RhdHVzLzE0MTUwMTU5Njc5NTcxNzYzMjkvcGhvdG8vMQoKYGBge3IsZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9Mn0KIyBkYXRlIGFpcmVkCnRoZW1lX3NldCh0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEwKSkgCnRoZW1lX3VwZGF0ZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT05KSwKICAgICAgICBwbG90Lm1hcmdpbj11bml0KGMoMC41LDAuNSwwLjUsMC41KSwiY20iKSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIHBhbmVsLmdyaWQubWlub3I9ZWxlbWVudF9ibGFuaygpKQoKIyBjdW11bGF0aXZlIHNuYWNrIChkYXRlX2FpcmVkKQpzbmFja190YWIgPSBzY29vYnlkb28gJT4lCiAgc2VsZWN0KGluZGV4LAogICAgICAgICBzZXJpZXNfbmFtZSwKICAgICAgICAgc2Vhc29uLAogICAgICAgICB0aXRsZSwKICAgICAgICAgZGF0ZV9haXJlZCwKICAgICAgICAgc3RhcnRzX3dpdGgoInNuYWNrIikpICU+JQogIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgic25hY2siKSkgJT4lCiAgZ3JvdXBfYnkobmFtZSkgJT4lCiAgYXJyYW5nZShkYXRlX2FpcmVkKSAlPiUKICBtdXRhdGUoY3VtdWxhdGl2ZSA9IGlmZWxzZSh2YWx1ZSA9PSBUUlVFLCAxLCAwKSwKICAgICAgICAgY3VtdWxhdGl2ZSA9IGN1bXN1bShjdW11bGF0aXZlKSwKICAgICAgICAgbmFtZSA9IHN0cl90b190aXRsZShnc3ViKCJzbmFja18iLCAiIiwgbmFtZSkpLAogICAgICAgICBuYW1lPWNhc2Vfd2hlbihuYW1lID09ICJEYXBobmllIn4iRGFwaG5lIiwKICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IG5hbWUpKQoKcGxvdDEgPSBzbmFja190YWIgJT4lIAogIGFycmFuZ2UoZGF0ZV9haXJlZCkgJT4lIAogIGdncGxvdChhZXMoeD1kYXRlX2FpcmVkLCB5PWN1bXVsYXRpdmUpKSsKICBnZW9tX3BhdGgoYWVzKGNvbG9yPW5hbWUpLCBzaXplPTEpKwogIGdlb21fdGV4dChkYXRhPS4gJT4lIGdyb3VwX2J5KG5hbWUpICU+JSBhcnJhbmdlKGRhdGVfYWlyZWQpICU+JSBzbGljZShuKCkpICwKICAgICAgICAgICAgICAgICAgYWVzKGNvbG9yPW5hbWUsIGxhYmVsPW5hbWUpLCBoanVzdD0wLCBudWRnZV94ID0gMTAwLCBzaXplPTMsIGZvbnRmYWNlPSJib2xkIikrCiAgc2NhbGVfeF9kYXRlKGxpbWl0cz1jKG1pbih1bm1hc2skZGF0ZV9haXJlZCksIG1heCh1bm1hc2skZGF0ZV9haXJlZCkrMzAwMCkpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjOTY2YTAwIiwiIzc5YWYzMCIsIiM2MjI0ODYiLCIjRjc4MDFFIiwiIzc2YTJjYSIpKSArCiAgbGFicyh4PSJEYXRlIGFpcmVkIiwgeT0iQ3VtdWxhdGl2ZSIsIHN1YnRpdGxlPSJTbmFjayBlYXRlbiBieVxuIikKCgojIGN1bXVsYXRpdmUgc25hY2sgKGRhdGVfYWlyZWQpCmNhdWdodF90YWIgPSBzY29vYnlkb28gJT4lCiAgc2VsZWN0KGluZGV4LAogICAgICAgICBzZXJpZXNfbmFtZSwKICAgICAgICAgc2Vhc29uLAogICAgICAgICB0aXRsZSwKICAgICAgICAgZGF0ZV9haXJlZCwKICAgICAgICAgc3RhcnRzX3dpdGgoImNhdWdodCIpKSAlPiUKICBzZWxlY3QoLWNhdWdodF9ub3QsLWNhdWdodF9vdGhlcikgJT4lCiAgcGl2b3RfbG9uZ2VyKHN0YXJ0c193aXRoKCJjYXVnaHQiKSkgJT4lCiAgZ3JvdXBfYnkobmFtZSkgJT4lCiAgYXJyYW5nZShkYXRlX2FpcmVkKSAlPiUKICBtdXRhdGUoY3VtdWxhdGl2ZSA9IGlmZWxzZSh2YWx1ZSA9PSBUUlVFLCAxLCAwKSwKICAgICAgICAgY3VtdWxhdGl2ZSA9IGN1bXN1bShjdW11bGF0aXZlKSwKICAgICAgICAgbmFtZSA9IHN0cl90b190aXRsZShnc3ViKCJjYXVnaHRfIiwgIiIsIG5hbWUpKSwKICAgICAgICAgbmFtZT1jYXNlX3doZW4obmFtZSA9PSAiRGFwaG5pZSJ+IkRhcGhuZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBuYW1lKSkKCnBsb3QyID0gY2F1Z2h0X3RhYiAlPiUKICBhcnJhbmdlKGRhdGVfYWlyZWQpICU+JSAKICBnZ3Bsb3QoYWVzKHg9ZGF0ZV9haXJlZCwgeT1jdW11bGF0aXZlKSkrCiAgZ2VvbV9wYXRoKGFlcyhjb2xvcj1uYW1lKSwgc2l6ZT0xKSsKICBnZW9tX3RleHQoZGF0YT0uICU+JSBncm91cF9ieShuYW1lKSAlPiUgYXJyYW5nZShkYXRlX2FpcmVkKSAlPiUgc2xpY2UobigpKSAsCiAgICAgICAgICAgICAgICAgIGFlcyhjb2xvcj1uYW1lLCBsYWJlbD1uYW1lKSwgaGp1c3Q9MCwgbnVkZ2VfeCA9IDEwMCwgc2l6ZT0zLCBmb250ZmFjZT0iYm9sZCIpKwogIHNjYWxlX3hfZGF0ZShsaW1pdHM9YyhtaW4odW5tYXNrJGRhdGVfYWlyZWQpLCBtYXgodW5tYXNrJGRhdGVfYWlyZWQpKzMwMDApKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiIzk2NmEwMCIsIiM3OWFmMzAiLCIjNjIyNDg2IiwiI0Y3ODAxRSIsIiM3NmEyY2EiKSkgKwogIGxhYnMoeD0iRGF0ZSBhaXJlZCIsIHk9IkN1bXVsYXRpdmUiLHN1YnRpdGxlPSJDYXVnaHQgYnlcbiIpCgpnZ2FycmFuZ2UocGxvdDEscGxvdDIsIG5jb2w9MikKYGBgCgoKIyMjIyBTYW5rZXkgY2hhcnQKKiByZWZlcmVuY2U6IGh0dHBzOi8vdHdpdHRlci5jb20vYWxsaXNvbmtvaF8vc3RhdHVzLzE0MTQ5MjUwNzU0MzkwOTk5MDkvcGhvdG8vMQoKYGBge3J9CnN0YWIgPC0gc2Nvb2J5ZG9vICU+JSAKICBmaWx0ZXIoZm9ybWF0ICE9IGMoIkNyb3Nzb3ZlciIsICJNb3ZpZSIsICJNb3ZpZSAoVGhlYXRyaWNhbCkiKSkgJT4lIAogIHNlbGVjdCgKICAgIGMoImluZGV4IiksIAogICAgc3RhcnRzX3dpdGgoYygiY2F1Z2h0IiwgImNhcHR1cmVkIiwgInVubWFzayIsInNuYWNrIikpLCAKICAgIC1lbmRzX3dpdGgoYygib3RoZXIiLCAibm90IikpKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IHN0YXJ0c193aXRoKGMoImNhdWdodCIsICJjYXB0dXJlZCIsICJ1bm1hc2siLCJzbmFjayIpKSwKICAgIG5hbWVzX3RvID0gYygiYWN0aW9uIiwgImNoYXJhY3RlciIpLCAKICAgIG5hbWVzX3NlcCA9ICJfIiwKICAgIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JSAKICBtdXRhdGUoY2hhcmFjdGVyPWNhc2Vfd2hlbihjaGFyYWN0ZXIgPT0gImRhcGhuaWUifiJkYXBobmUiLAogICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gY2hhcmFjdGVyKSkgJT4lCiAgbXV0YXRlKAogICAgdmFsdWUgPSBhcy5pbnRlZ2VyKGFzLmxvZ2ljYWwodmFsdWUpKSwgCiAgICBhY3Rpb24gPSByZWNvZGUoCiAgICAgIGFjdGlvbiwgCiAgICAgIHVubWFzayA9ICJ1bm1hc2tlZFxubW9uc3RlciIsCiAgICAgIGNhdWdodCA9ICJjYXVnaHRcbm1vbnN0ZXIiLAogICAgICBjYXB0dXJlZCA9ICJ3YXMgY2FwdHVyZWQiLAogICAgICBzbmFjayA9ICJzbmFjayIpLAogICAgY2hhcmFjdGVyID0gdW5saXN0KFRDKGNoYXJhY3RlcikpKSAlPiUgCiAgZmlsdGVyKHZhbHVlICE9IDApIAoKc3RhYl9sb25nPC0gc3RhYiAgJT4lIAogIG1ha2VfbG9uZyhjaGFyYWN0ZXIsIGFjdGlvbikgCmBgYAoKCmBgYHtyfQpzdGFiX2xvbmcgJT4lIAogIGdncGxvdChhZXMoeCA9IHgsIG5leHRfeCA9IG5leHRfeCwgbm9kZSA9IG5vZGUsIG5leHRfbm9kZSA9IG5leHRfbm9kZSwgZmlsbCA9IGZhY3Rvcihub2RlKSwgbGFiZWwgPSBub2RlKSkgKyAKICBnZW9tX3NhbmtleShmbG93LmFscGhhID0gLjYpICsKICBnZW9tX3NhbmtleV9sYWJlbChzaXplID0gMywgY29sb3IgPSAiYmxhY2siLCBmaWxsID0gIndoaXRlIikgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiZ3JleTIwIiwiI2VhNzMxNyIsIiMxMTlkYTQiLCIjZmZjODU3IiwiIzRiM2Y3MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImdyZXk0MCIsImdyZXk2MCIsIiM5MGJlNmQiLCJncmV5IikpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCgpgYGB7cn0KIyBhbW91bnQKYW1vdW50ID0gc2Nvb2J5ZG9vICU+JSAKICBmaWx0ZXIoZm9ybWF0PT0iVFYgU2VyaWVzIikgJT4lCiAgc2VsZWN0KGRhdGVfYWlyZWQsIHN1c3BlY3RzX2Ftb3VudCwgY3VscHJpdF9hbW91bnQsIG1vbnN0ZXJfYW1vdW50KSAlPiUKICBtdXRhdGUoU3VzcGVjdCA9IGN1bXN1bShzdXNwZWN0c19hbW91bnQpLAogICAgICAgICBDdWxwcml0ID0gY3Vtc3VtKGN1bHByaXRfYW1vdW50KSwKICAgICAgICAgTW9uc3RlciA9IGN1bXN1bShtb25zdGVyX2Ftb3VudCkpICU+JQogIHNlbGVjdCgtc3VzcGVjdHNfYW1vdW50LC1jdWxwcml0X2Ftb3VudCwgLW1vbnN0ZXJfYW1vdW50KSAlPiUKICBwaXZvdF9sb25nZXIoIWRhdGVfYWlyZWQpIAoKYW1vdW50ICU+JQogIGdncGxvdChhZXMoeD1kYXRlX2FpcmVkLCB5PXZhbHVlKSkgKyAKICBnZW9tX3BhdGgoYWVzKGNvbG9yPW5hbWUpLCBzaXplPTEpICsgCiAgZ2VvbV90ZXh0KGRhdGE9LiAlPiUgZ3JvdXBfYnkobmFtZSkgJT4lIGFycmFuZ2UoZGF0ZV9haXJlZCkgJT4lIHNsaWNlKG4oKSkgLAogICAgICAgICAgICAgICAgICBhZXMoY29sb3I9bmFtZSwgbGFiZWw9bmFtZSksIGhqdXN0PTAsIG51ZGdlX3ggPSAxMDAsIHNpemU9My41LCBmb250ZmFjZT0iYm9sZCIpKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiI2IyYmIxYiIsIiNjZDdlMDUiLCIjNzZhMmNhIikpICsgCiAgc2NhbGVfeF9kYXRlKGxpbWl0cz1jKG1pbih1bm1hc2skZGF0ZV9haXJlZCksIG1heCh1bm1hc2skZGF0ZV9haXJlZCkrMzAwMCkpICsgCiAgdGhlbWUocGxvdC5tYXJnaW49dW5pdChjKDEsMiwxLDIpLCJjbSIpKSArCiAgbGFicyh4PSJEYXRlIGFpcmVkIiwgeT0iQ3VtdWxhdGl2ZSBhbW91bnQiLCBzdWJ0aXRsZT0iU2Nvb2J5IERvbyBUViBTZXJpZXMgKDE5NjkgdG8gMjAyMSlcbkN1bXVsYXRpdmUgc3VzcGVjdCwgbW9uc3RlciBhbmQgY3VscHJpdCBhbW91bnRcbiIpCmBgYAoKIyMjIyBQaHJhc2UsIG1vbnN0ZXIgc3VidHlwZSwgbW90aXZlCmBgYHtyfQojIHBocmFzZSBjb3VudApzY29vYnlkb28xICU+JSAKICBzZWxlY3QoaW5kZXgsamVlcGVyczpyb29ieV9yb29ieV9yb28pICU+JQogIHBpdm90X2xvbmdlcighaW5kZXgpICU+JQogIGZpbHRlcih2YWx1ZSE9MCkgJT4lCiAgbXV0YXRlKHBocmFzZT0gc3RyX3JlcGxhY2VfYWxsKG5hbWUsICJfIiwiICIpLAogICAgICAgICBwaHJhc2UgPSBzdHJfdG9fdGl0bGUocGhyYXNlKSkgJT4lCiAgZ3JvdXBfYnkocGhyYXNlKSAlPiUgdGFsbHkodmFsdWUsIHNvcnQ9VCkgCgojIG1vbnN0ZXIgc3VidHlwZSBjb3VudApzY29vYnlkb28xICU+JSAKICBzZXBhcmF0ZV9yb3dzKG1vbnN0ZXJfc3VidHlwZSxzZXA9IiwiLCBjb252ZXJ0PVQpICU+JQogIGRyb3BfbmEobW9uc3Rlcl9zdWJ0eXBlKSAlPiUKICBjb3VudChtb25zdGVyX3N1YnR5cGUsIHNvcnQ9VCkKCiMgbW90aXZlIGNvdW50CnNjb29ieWRvbzEgJT4lIAogIGNvdW50KG1vdGl2ZSwgc29ydD1UKQpgYGA=