Intro

When I first started blogging I decided to collect some data about the TV Show Friends. I ended up writing about “the frequency of characters’ shared plotlines, or character groupings, throughout the span of the entire show.” However, I collected this data by manually going through the episodes and recording the relevant groupings. Now, I return to this topic with new data obtained by web scraping the television show scripts. Giora Simchoni just recently put out a post on this and I am seeking to use his structure for scraping and go from there. In short, I am using Giora’s data and making new visuals from his work.

Data Scraping

First, I scrape the data using Giora’s code verbatim in order to yield personLines_df. Once I have followed Giora’s code, I can manipulate the resulting dataframe in order to make my own visuals! Quick note here: Episodes 199 (Season 9, ep 15) and 203 (Season 9, ep 19) are missing from this dataset. (So, this gives data on 226 episodes. Two part episodes are included as one since they have a single script.)

Lines spoken over the course of the show

First, I make my own version of the bar chart that Giora has in his blog post, illustrating the total number of lines for each of the 6 main characters.

#in eps 32-33 abbreviations are used for some of the characters
#let's standardize
personLines_df$person[personLines_df$person == "chan" | personLines_df$person == "chandler "] <- "chandler"
personLines_df$person[personLines_df$person == "phoe" | personLines_df$person == "phoebe "] <- "phoebe"
personLines_df$person[personLines_df$person == "mnca" | personLines_df$person == "monica "] <- "monica"
personLines_df$person[personLines_df$person == "rach" | personLines_df$person == "rachel "] <- "rachel"
#make all other characters "other"
personLines_df$person[!(personLines_df$person == "monica" | personLines_df$person == "rachel" | personLines_df$person == "joey" |personLines_df$person == "phoebe" |personLines_df$person == "ross" |personLines_df$person == "chandler" )] <- "other"
#get dataframe with totals
total_lines <- personLines_df %>%
  count(person) %>%
  arrange(-n)

Now, I can plot my barchart. So, first, I define my custom theme, as per usual.

#Load more libraries
library(ggplot2);library(ggrepel); library(extrafont); library(ggthemes);library(reshape);library(grid);
library(scales);library(RColorBrewer);library(gridExtra)
#Define theme for my visuals
my_theme <- function() {
  # Define colors for the chart
  palette <- brewer.pal("Greys", n=9)
  color.background = palette[2]
  color.grid.major = palette[4]
  color.panel = palette[3]
  color.axis.text = palette[9]
  color.axis.title = palette[9]
  color.title = palette[9]
  # Create basic construction of chart
  theme_bw(base_size=9, base_family="Friends") + 
  #Seems like a good time to use the Friends-TV-show-specific font  
  # Set the entire chart region to a light gray color
  theme(panel.background=element_rect(fill=color.panel, color=color.background)) +
  theme(plot.background=element_rect(fill=color.background, color=color.background)) +
  theme(panel.border=element_rect(color=color.background)) +
  # Format grid
  theme(panel.grid.major=element_line(color=color.grid.major,size=.25)) +
  theme(panel.grid.minor=element_blank()) +
  theme(axis.ticks=element_blank()) +
  # Format legend
  theme(legend.position="right") +
  theme(legend.background = element_rect(fill=color.background)) +
  theme(legend.text = element_text(size=7,color=color.axis.title)) + 
  theme(legend.title = element_text(size=0,face="bold", color=color.axis.title)) + 
  
  #Format facet labels
  theme(strip.text.x = element_text(size = 8, face="bold"))+
  # Format title and axes labels these and tick marks
  theme(plot.title=element_text(color=color.title, size=18, face="bold", hjust=0)) +
  theme(axis.text.x=element_text(size=6,color=color.axis.text)) +
  theme(axis.text.y=element_text(size=6,color=color.axis.text)) +
  theme(axis.title.x=element_text(size=8,color=color.axis.title, vjust=-1, face="bold")) +
  theme(axis.title.y=element_text(size=8,color=color.axis.title, vjust=1.8, face="bold")) +
  #Format title and facet_wrap title
  theme(strip.text = element_text(size=8), plot.title = element_text(size = 10, face = "bold", colour = "black", vjust = 1, hjust=0.5))+
    
  # Plot margins
  theme(plot.margin = unit(c(.2, .2, .2, .2), "cm"))
}

Then I plot the barchart.

ggplot(data=total_lines, aes(x=person, y=n, group=person, color=person, fill=person, label=n)) + scale_fill_brewer(palette = "Set3") + 
  scale_color_brewer(palette = "Set3") +
  geom_bar(stat="identity")+
  my_theme()+ theme(legend.position="none")+ theme(plot.title = element_text( hjust = 0))+theme(axis.text.x=element_text(size=9))+
  geom_text(size = 2, color="black", family="Friends", position = position_stack(vjust = 0.5))+
  labs(x="", y="")+
  ggtitle("The One With All The Quantifiable Friendships", subtitle="Total Lines Spoken by Each Character and Others")

ggsave("total.png", width=7, height=4.5, dpi=900)

Episode by episode

I want to visualize the lines spoken by the 6 main characters and others over the course of the show. Giora does this in a few aggregated ways but I am now going to show this epsiode by episode. So, I first make some manipulations to get a count of lines for each character and episode pairing.

episodes_df$ID <- as.numeric(rownames(episodes_df))
  
ep_person_lines <- personLines_df %>%
  count(person, episodeTitle, episodeNum, season) 
epi<-episodes_df[c("ID", "episodeTitle")]
ep_lines<-merge(epi, ep_person_lines, by="episodeTitle")
ep_lines

Now I have the data in a form I can graph, so I call ggplot to make some graphs. I went through a number of attempts to get my final product. First, I simply showed the time series of lines spoken for each character all on the same graph.

ggplot(data=ep_lines, aes(x=ID, y=n, group=person, color=person)) + scale_fill_brewer(palette = "Set3") + 
  scale_color_brewer(palette = "Set3") +
  geom_line(size=0.5, alpha=1)+
  my_theme() +theme(plot.title = element_text( hjust = 0))+
  labs(x="Episode Number", y="")+
  
  ggtitle("The One With All The Quantifiable Friendships", subtitle = "Lines Spoken Over All The Episodes")

NA

The above is very hard to get anything out of visually, so I had an idea based on previous work I did on demographics in the science PhD’s. So, I try making a stacked area graph.

p<-ggplot(data=ep_lines, aes(x=ID, y=n, group=person, fill=person, color=person))+ 
  scale_fill_brewer(palette = "Set3") + 
  scale_color_brewer(palette = "Set3") +
  my_theme()+theme(plot.title = element_text( hjust = 0))+
  labs(x="Episode Number", y="")+
  ggtitle("The One With All The Quantifiable Friendships", subtitle = "Lines Spoken Over All The Episodes")
#Stacked area graph
p+geom_area(aes(fill=person), position='stack')

I make a nightingale graph also (for fun).

#Nightingale Graph
p+geom_area(aes(fill=person), position='stack')+coord_polar()+ theme(plot.title = element_text(size = 8))

However, the differences in lines for each character aren’t super visible still due to the major differences in total episode lines–mainly due to the fact that there are single scripts for two part episodes, which messes with the scale. For this season, it’s worth looking into percentages of lines for characters by episode instead.

# Make percentage figures
# First calculate total lines for each ep
lines_total<-ep_lines %>%
  group_by(ID) %>%
  summarise(n=sum(n))
lines_new<-merge(ep_lines, lines_total, by=c("ID"))
lines_new$perc<-lines_new$n.x/lines_new$n.y

Time for plotting…

p<-ggplot(data=lines_new, aes(x=ID, y=perc, group=person, fill=person, color=person)) + 
  scale_fill_brewer(palette = "Set3") + 
  scale_color_brewer(palette = "Set3") +
  my_theme()+theme(plot.title = element_text( hjust = 0))+
  labs(x="Episode Number", y="")+
  scale_y_continuous(labels = percent_format())+
  ggtitle("The One With All The Quantifiable Friendships", subtitle = "Percentage of Lines Spoken Across The Episodes")
#Stacked area graph
p+geom_area(aes(fill=person), position='stack')

ggsave("lines1.png", width=7, height=4.5, dpi=900)

Tell me the above doesn’t look just like Rachel’s English Trifle! Layer on layer on layer…

#Nightingale graphs
p+geom_bar(stat="identity", aes(fill=person), position='stack')+ 
  coord_polar()+
  theme(plot.title = element_text(size=8.8))

ggsave("lines2.png", width=7, height=4.5, dpi=900)

The two visible gaps in that graph are due to missing observations for two episodes.

#Line
p+geom_line(size=0.5)

ggsave("lines3.png", width=7, height=4.5, dpi=900)

This last graph is useful for seeing outlier episodes in terms of who was abnormally overserved or underserved by the writing of a particular episode. While no one ever spoke the majority of the lines in the group for an episode, there are a few times people come close. Similarly, there are a few times characters come close to not speaking at all.

lines_new <- lines_new %>%
  arrange(-perc) 
lines_new

The highest percentage of lines in an episode is Chandler for The One with Christmas in Tulsa. Makes sense. Second place is Joey in The One With Joey’s Interview.

lines_new <- lines_new %>%
  arrange(perc) 
head(lines_new, 5)

The most gang-driven episode is The One The Last Night, as only 1 line in that episode is spoken by someone outside the 6 main characters. The above table shows the 5 episodes that have the highest percentage of lines spoken by the gang.

Maybe we want to forget about the others in this post and just focus on the main 6 characters. If we do that then we get a picture of how central or tangential characters were to specific episodes. Ie, Monica only speaks ~1.5% of lines in The One With The Ring and same for Ross in The One With The Cuffs.

#take out other options
lines_new_no_other<-lines_new[!(lines_new$person=="other"),]
lines_new_no_other <- lines_new_no_other %>%
  arrange(perc) 
lines_new_no_other

We can also look at the episodes certain characters are most dominant in. See below.

lines_new_no_other <- lines_new_no_other %>%
  arrange(-perc) 
lines_new_no_other

Gender and lines

What if I group the women and men together and then look at the visuals…would certain periods of time be more male/female dominated?

lines_new_no_other$gender[lines_new_no_other$person == "rachel" |lines_new_no_other$person == "phoebe" |lines_new_no_other$person == "monica" ] <- "Women"
lines_new_no_other$gender[ lines_new_no_other$person == "joey" |lines_new_no_other$person == "chandler" |lines_new_no_other$person == "ross" ] <- "Men"
lines_gender<-lines_new_no_other[c("episodeTitle", "episodeNum", "season", "gender", "n.x", "ID")]
lines_gender_final<-lines_gender %>%
  group_by(gender, ID) %>%
  summarise(n=sum(n.x))
l2<-lines_gender %>%
  group_by(ID) %>%
  summarise(tot=sum(n.x))
gender<-merge(l2, lines_gender_final, by="ID")
gender<-merge(gender, epi, by="ID")
gender$perc<-gender$n/gender$tot

Now, I plot the balance over time.

p<-ggplot(data=gender, aes(x=ID, y=perc, group=gender, fill=gender, color=gender)) + 
  scale_fill_brewer(palette = "Set2") + 
  scale_color_brewer(palette = "Set2") +
  my_theme()+theme(plot.title = element_text( hjust = 0))+
  labs(x="Episode Number", y="")+
  scale_y_continuous(labels = percent_format())+
  ggtitle("The One With All The Quantifiable Friendships", subtitle = "Percentage of Lines Spoken Across the Gang By Gender")
#Stacked area graph
p+geom_area(aes(fill=gender), position='stack')

ggsave("gender1.png", width=7, height=4.5, dpi=900)
p+geom_line(size=0.5)

ggsave("gender2.png", width=7, height=4.5, dpi=900)

The above shows there are three episodes that stand-out in terms of giving one gender of the gang more lines than the other percentage-wise

gender <- gender %>%
  arrange(-perc) 
gender

They are: The One Where Chandler Crosses A Line (Chandler kisses Joey’s girlfriend and confrontation ensues), The One With Joey’s Interview, and The One With Mac and C.H.E.E.S.E..

Two episodes are actually exactly 50-50: The One Where Rachel Finds Out and The One With The Thanksgiving Flashbacks!

How many are >50% men speaking?

gender_new<-gender[gender$gender=="Men",]
gender_new<-gender_new[gender_new$perc > 0.50,]
nrow(gender_new)
[1] 118

So 118/226 (52.2%) of the available episodes with >50% lines given to men in the group.

Who mentions whom?

Here I am adapting Giora’s code. The change I’m making is to include nicknames like Mon, Rach, Pheebs, and Joe.

library(dplyr); library(stringr); library(purrr)
m <- personLines_df %>%
  filter(person %in% c("chandler", "ross", "joey", "monica", "rachel", "phoebe")) %>%
  mutate(chandler = map_int(line, str_count, "chandler"),
         ross = map_int(line, str_count, "ross"),
         joey = map_int(line, str_count, "joey"),
         joe = map_int(line, str_count, "joe "),
         monica = map_int(line, str_count, "monica"),
         mon = map_int(line, str_count, "mon "),
         rachel = map_int(line, str_count, "rachel"),
         rach = map_int(line, str_count, "rach "),
         phoebe = map_int(line, str_count, "phoebe"),
         pheebs = map_int(line, str_count, "pheebs")) %>%
  select(person, chandler, joey, joe, monica, mon, phoebe, pheebs, rachel, rach, ross) %>%
  group_by(person) %>%
  summarise_each(funs(sum))
m

Look how much the characters say Pheebs! That’s by far the most important nickname to add in.

m$monica<-m$monica+m$mon
m$phoebe<-m$pheebs+m$phoebe
m$rachel<-m$rachel+m$rach
m$joey<-m$joe+m$joey
m<-m[,c("person", "chandler", "joey", "monica", "phoebe", "rachel", "ross")]
m

So the above is our updated dataframe with nicknames included. Now, to graph, I want to mutate this a bit…

library(reshape)
m<-as.data.frame(m)
mnew <- reshape(m, varying = c("chandler", "monica","ross", "rachel","phoebe", "joey"), 
                     v.names = "count",
                     timevar = "friend_mention", 
                     times = c("chandler", "monica","ross", "rachel","phoebe", "joey"), 
                     direction = "long")
mnew<-mnew[c("person", "friend_mention", "count")]

Now, I use faceting to graph my updated version of Giora’s collected data.

library(ggplot2)
ggplot(data=mnew, aes(x=friend_mention, y=count, group=friend_mention,
                      fill=friend_mention, label=count)) + 
  scale_fill_brewer(palette = "Set3", guide = guide_legend(title = "Friend Mentioned")) + 
  geom_bar(stat="identity")+
  facet_wrap(~person, ncol=3)+
  my_theme()+ theme(plot.title = element_text( hjust = 0))+theme(axis.text.x=element_text(size=0))+
  geom_text(size = 1, color="black", family="Friends", position = position_stack(vjust = 0.5))+
  labs(x="", y="")+
  ggtitle("The One With All The Quantifiable Friendships", subtitle="Mentions by Friends... of Friends")+ 
  theme(legend.title = element_text(size=6,face="bold"))

ggsave("mentions.png", width=7, height=4.5, dpi=900)

Wow, Rachel likes saying Ross.

Alright, that’s a wrap!

Screen goes dark and…

Executive Producer: Alex Albright

LS0tCnRpdGxlOiAnVGhlIE9uZSBXaXRoIEFsbCBUaGUgUXVhbnRpZmlhYmxlIEZyaWVuZHNoaXBzIENvbnRpbnVlZCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgojIEludHJvCldoZW4gSSBmaXJzdCBzdGFydGVkIGJsb2dnaW5nIEkgZGVjaWRlZCB0byBjb2xsZWN0IHNvbWUgZGF0YSBhYm91dCB0aGUgVFYgU2hvdyAqRnJpZW5kcyouIEkgZW5kZWQgdXAgd3JpdGluZyBhYm91dCAidGhlIGZyZXF1ZW5jeSBvZiBjaGFyYWN0ZXJz4oCZIHNoYXJlZCBwbG90bGluZXMsIG9yIGNoYXJhY3RlciBncm91cGluZ3MsIHRocm91Z2hvdXQgdGhlIHNwYW4gb2YgdGhlIGVudGlyZSBzaG93LiIgSG93ZXZlciwgSSBjb2xsZWN0ZWQgdGhpcyBkYXRhIGJ5IG1hbnVhbGx5IGdvaW5nIHRocm91Z2ggdGhlIGVwaXNvZGVzIGFuZCByZWNvcmRpbmcgdGhlIHJlbGV2YW50IGdyb3VwaW5ncy4gTm93LCBJIHJldHVybiB0byB0aGlzIHRvcGljIHdpdGggbmV3IGRhdGEgb2J0YWluZWQgYnkgd2ViIHNjcmFwaW5nIHRoZSB0ZWxldmlzaW9uIHNob3cgc2NyaXB0cy4gW0dpb3JhIFNpbWNob25pIGp1c3QgcmVjZW50bHkgcHV0IG91dCBhIHBvc3Qgb24gdGhpc10oaHR0cDovL2dpb3Jhc2ltY2hvbmkuY29tLzIwMTcvMDYvMDQvMjAxNy0wNi0wNC10aGUtb25lLXdpdGgtZnJpZW5kcy8pIGFuZCBJIGFtIHNlZWtpbmcgdG8gdXNlIGhpcyBzdHJ1Y3R1cmUgZm9yIHNjcmFwaW5nIGFuZCBnbyBmcm9tIHRoZXJlLiBJbiBzaG9ydCwgSSBhbSB1c2luZyBHaW9yYSdzIGRhdGEgYW5kIG1ha2luZyBuZXcgdmlzdWFscyBmcm9tIGhpcyB3b3JrLgoKIyBEYXRhIFNjcmFwaW5nCkZpcnN0LCBJIHNjcmFwZSB0aGUgZGF0YSB1c2luZyBbR2lvcmEncyBjb2RlXShodHRwOi8vZ2lvcmFzaW1jaG9uaS5jb20vMjAxNy8wNi8wNC8yMDE3LTA2LTA0LXRoZS1vbmUtd2l0aC1mcmllbmRzLykgdmVyYmF0aW0gaW4gb3JkZXIgdG8geWllbGQgYGBgcGVyc29uTGluZXNfZGYgYGBgLiBPbmNlIEkgaGF2ZSBmb2xsb3dlZCBHaW9yYSdzIGNvZGUsIEkgY2FuIG1hbmlwdWxhdGUgdGhlIHJlc3VsdGluZyBkYXRhZnJhbWUgaW4gb3JkZXIgdG8gbWFrZSBteSBvd24gdmlzdWFscyEgUXVpY2sgbm90ZSBoZXJlOiBFcGlzb2RlcyAxOTkgKFNlYXNvbiA5LCBlcCAxNSkgYW5kIDIwMyAoU2Vhc29uIDksIGVwIDE5KSBhcmUgbWlzc2luZyBmcm9tIHRoaXMgZGF0YXNldC4gKFNvLCB0aGlzIGdpdmVzIGRhdGEgb24gMjI2IGVwaXNvZGVzLiBUd28gcGFydCBlcGlzb2RlcyBhcmUgaW5jbHVkZWQgYXMgb25lIHNpbmNlIHRoZXkgaGF2ZSBhIHNpbmdsZSBzY3JpcHQuKQpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShwbHlyKTtsaWJyYXJ5KGRwbHlyKQpgYGAKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShydmVzdCkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KG1hZ3JpdHRyKQoKZXh0cmFjdFNlYXNvbiA8LSBmdW5jdGlvbihsaW5rKSB7CiAgaWYgKHN0YXJ0c1dpdGgobGluaywgIjEwIikpIHsKICAgIDEwCiAgfSBlbHNlIHsKICAgIHN0cl9zcGxpdChsaW5rLCAic2Vhc29ufC8iKVtbMV1dWzJdICU+JSBhcy5udW1lcmljKCkKICB9Cn0KCmV4dHJhY3RUaXRsZSA8LSBmdW5jdGlvbihzZWFzb24sIGh0bWwpIHsKICB0aXRsZSA8LSBodG1sX25vZGVzKGh0bWwsICJ0aXRsZSIpICU+JSBodG1sX3RleHQoKSAlPiUgcGFzdGUoY29sbGFwc2UgPSAiICIpCiAgaWYgKHNlYXNvbiA9PSAxMCkgewogICAgdGl0bGUgPC0gc3RyX3NwbGl0KHRpdGxlLCAiIC0gIilbWzFdXVszXQogIH0KICBpZiAoc2Vhc29uICE9IDkgJiBsZW5ndGgodGl0bGUpID4gMCkgewogICAgdGl0bGUKICB9IGVsc2UgewogICAgIiIKICB9Cn0KCmdldFNlYXNvbjlUaXRsZXMgPC0gZnVuY3Rpb24oKSB7CiAgdGl0bGVzIDwtIHJlYWRfaHRtbCgiaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRnJpZW5kc18oc2Vhc29uXzkpIikgJT4lCiAgICBodG1sX25vZGVzKCIuc3VtbWFyeSIpICU+JQogICAgaHRtbF90ZXh0KCkKICBtYXBfY2hyKHRpdGxlc1s0OjI2XSwgZnVuY3Rpb24oeCkgc3RyX3NwbGl0KHgsICJcIiIpW1sxXV1bMl0pCn0KCnVybCA8LSAiaHR0cDovL2xpdmVzaW5hYm94LmNvbS9mcmllbmRzL3NjcmlwdHMuc2h0bWwiCgplcGlzb2Rlc19kZiA8LSByZWFkX2h0bWwodXJsKSAlPiUKICBodG1sX25vZGVzKCJhIikgJT4lCiAgaHRtbF9hdHRyKCJocmVmIikgJT4lCiAgdGliYmxlKGxpbmsgPSAuKSAlPiUKICBzbGljZSg0NjoyNzUpICU+JQogIHVuaXF1ZSgpICU+JQogIG11dGF0ZShzZWFzb24gPSBtYXBfZGJsKGxpbmssIGV4dHJhY3RTZWFzb24pLAogICAgICAgICBodG1sID0gbWFwKHBhc3RlMCgiaHR0cDovL2xpdmVzaW5hYm94LmNvbS9mcmllbmRzLyIsIGxpbmspLCByZWFkX2h0bWwpLAogICAgICAgICBlcGlzb2RlVGl0bGUgPSBtYXAyX2NocihzZWFzb24sIGh0bWwsIGV4dHJhY3RUaXRsZSkpICU+JQogIGZpbHRlcighc3RhcnRzV2l0aChlcGlzb2RlVGl0bGUsICJGcmllbmRzIikpICU+JQogIGdyb3VwX2J5KHNlYXNvbikgJT4lCiAgbXV0YXRlKGVwaXNvZGVOdW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKQoKZXBpc29kZXNfZGYkZXBpc29kZVRpdGxlW2VwaXNvZGVzX2RmJHNlYXNvbiA9PSA5XSA8LSBnZXRTZWFzb245VGl0bGVzKCkKCmVwaXNvZGVzX2RmICU+JSBzZWxlY3QoLWxpbmspCgpnZXRQZXJvbkxpbmVQYWlycyA8LSBmdW5jdGlvbihodG1sKSB7CiAgaHRtbCAlPiUKICAgIGh0bWxfbm9kZXMoImJvZHkiKSAlPiUKICAgIGh0bWxfbm9kZXMoInAiKSAlPiUKICAgIGh0bWxfdGV4dCgpICU+JQogICAgdGliYmxlKHRleHQgPSAuKSAlPiUKICAgIGZpbHRlcihzdHJfZGV0ZWN0KHRleHQsICJeW0EtWl1bYS16QS1aLiBdKzoiKSkgJT4lCiAgICB1bmxpc3QoKSAlPiUKICAgIHVubmFtZSgpICU+JQogICAgc3RyX3RvX2xvd2VyKCkgJT4lCiAgICBzdHJfcmVwbGFjZV9hbGwoIlxuIiwgIiAiKSAlPiUKICAgIHN0cl9yZXBsYWNlKCI6IiwgIlxcfFxcfCIpCn0KCmdldFBlcm9uTGluZVBhaXJzU2Vhc29uSXJyZWd1bGFycyA8LSBmdW5jdGlvbihodG1sKSB7CiAgaHRtbCAlPiUKICAgIGh0bWxfbm9kZXMoImJvZHkiKSAlPiUKICAgIGh0bWxfdGV4dCgpICU+JQogICAgc3RyX3NwbGl0KC4sICJcbiIpICU+JQogICAgdW5saXN0ICU+JQogICAgdGliYmxlKHRleHQgPSAuKSAlPiUKICAgIGZpbHRlcihzdHJfZGV0ZWN0KHRleHQsICJeW0EtWl1bYS16QS1aLiBdKzoiKSkgJT4lCiAgICB1bmxpc3QoKSAlPiUKICAgIHVubmFtZSgpICU+JQogICAgc3RyX3RvX2xvd2VyKCkgJT4lCiAgICBzdHJfcmVwbGFjZV9hbGwoIlxuIiwgIiAiKSAlPiUKICAgIHN0cl9yZXBsYWNlKCI6IiwgIlxcfFxcfCIpCn0KCnBlcnNvbkxpbmVzX2RmIDwtIGVwaXNvZGVzX2RmICU+JQogIGZpbHRlcighKHNlYXNvbiA9PSAyICYgZXBpc29kZU51bSAlaW4lIGMoOSwgMTI6MjMpKSAmCiAgICAgICAgICAgIShzZWFzb24gPT0gOSAmIGVwaXNvZGVOdW0gJWluJSBjKDcsIDExLCAxNSkpKSAlPiUKICBtdXRhdGUocGVyc29uTGluZSA9IG1hcChodG1sLCBnZXRQZXJvbkxpbmVQYWlycykpCgppcnJlZ3VsYXJzIDwtIGVwaXNvZGVzX2RmICU+JQogIGZpbHRlcigoc2Vhc29uID09IDIgJiBlcGlzb2RlTnVtICVpbiUgYyg5LCAxMjoyMykpIHwKICAgICAgICAgICAoc2Vhc29uID09IDkgJiBlcGlzb2RlTnVtICVpbiUgYyg3LCAxMSwgMTUpKSkgJT4lCiAgbXV0YXRlKHBlcnNvbkxpbmUgPSBtYXAoaHRtbCwgZ2V0UGVyb25MaW5lUGFpcnNTZWFzb25JcnJlZ3VsYXJzKSkKCnBlcnNvbkxpbmVzX2RmICU8PiUKICByYmluZChpcnJlZ3VsYXJzKSAlPiUKICBncm91cF9ieShzZWFzb24sIGVwaXNvZGVOdW0sIGVwaXNvZGVUaXRsZSkgJT4lCiAgdW5uZXN0KHBlcnNvbkxpbmUpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZXBhcmF0ZShwZXJzb25MaW5lLCBjKCJwZXJzb24iLCAibGluZSIpLCBzZXAgPSAiXFx8XFx8IikgJT4lCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHBlcnNvbiwgIiBieSIpKQoKcGVyc29uTGluZXNfZGYgJT4lIHNlbGVjdChzZWFzb24sIGVwaXNvZGVOdW0sIHBlcnNvbiwgbGluZSkKYGBgCgojIExpbmVzIHNwb2tlbiBvdmVyIHRoZSBjb3Vyc2Ugb2YgdGhlIHNob3cKRmlyc3QsIEkgbWFrZSBteSBvd24gdmVyc2lvbiBvZiB0aGUgYmFyIGNoYXJ0IHRoYXQgR2lvcmEgaGFzIGluIGhpcyBibG9nIHBvc3QsIGlsbHVzdHJhdGluZyB0aGUgdG90YWwgbnVtYmVyIG9mIGxpbmVzIGZvciBlYWNoIG9mIHRoZSA2IG1haW4gY2hhcmFjdGVycy4KYGBge3J9CiNpbiBlcHMgMzItMzMgYWJicmV2aWF0aW9ucyBhcmUgdXNlZCBmb3Igc29tZSBvZiB0aGUgY2hhcmFjdGVycwojbGV0J3Mgc3RhbmRhcmRpemUKcGVyc29uTGluZXNfZGYkcGVyc29uW3BlcnNvbkxpbmVzX2RmJHBlcnNvbiA9PSAiY2hhbiIgfCBwZXJzb25MaW5lc19kZiRwZXJzb24gPT0gImNoYW5kbGVyICJdIDwtICJjaGFuZGxlciIKcGVyc29uTGluZXNfZGYkcGVyc29uW3BlcnNvbkxpbmVzX2RmJHBlcnNvbiA9PSAicGhvZSIgfCBwZXJzb25MaW5lc19kZiRwZXJzb24gPT0gInBob2ViZSAiXSA8LSAicGhvZWJlIgpwZXJzb25MaW5lc19kZiRwZXJzb25bcGVyc29uTGluZXNfZGYkcGVyc29uID09ICJtbmNhIiB8IHBlcnNvbkxpbmVzX2RmJHBlcnNvbiA9PSAibW9uaWNhICJdIDwtICJtb25pY2EiCnBlcnNvbkxpbmVzX2RmJHBlcnNvbltwZXJzb25MaW5lc19kZiRwZXJzb24gPT0gInJhY2giIHwgcGVyc29uTGluZXNfZGYkcGVyc29uID09ICJyYWNoZWwgIl0gPC0gInJhY2hlbCIKI21ha2UgYWxsIG90aGVyIGNoYXJhY3RlcnMgIm90aGVyIgpwZXJzb25MaW5lc19kZiRwZXJzb25bIShwZXJzb25MaW5lc19kZiRwZXJzb24gPT0gIm1vbmljYSIgfCBwZXJzb25MaW5lc19kZiRwZXJzb24gPT0gInJhY2hlbCIgfCBwZXJzb25MaW5lc19kZiRwZXJzb24gPT0gImpvZXkiIHxwZXJzb25MaW5lc19kZiRwZXJzb24gPT0gInBob2ViZSIgfHBlcnNvbkxpbmVzX2RmJHBlcnNvbiA9PSAicm9zcyIgfHBlcnNvbkxpbmVzX2RmJHBlcnNvbiA9PSAiY2hhbmRsZXIiICldIDwtICJvdGhlciIKCiNnZXQgZGF0YWZyYW1lIHdpdGggdG90YWxzCnRvdGFsX2xpbmVzIDwtIHBlcnNvbkxpbmVzX2RmICU+JQogIGNvdW50KHBlcnNvbikgJT4lCiAgYXJyYW5nZSgtbikKYGBgCk5vdywgSSBjYW4gcGxvdCBteSBiYXJjaGFydC4gU28sIGZpcnN0LCBJIGRlZmluZSBteSBjdXN0b20gdGhlbWUsIGFzIHBlciB1c3VhbC4KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNMb2FkIG1vcmUgbGlicmFyaWVzCmxpYnJhcnkoZ2dwbG90Mik7bGlicmFyeShnZ3JlcGVsKTsgbGlicmFyeShleHRyYWZvbnQpOyBsaWJyYXJ5KGdndGhlbWVzKTtsaWJyYXJ5KHJlc2hhcGUpO2xpYnJhcnkoZ3JpZCk7CmxpYnJhcnkoc2NhbGVzKTtsaWJyYXJ5KFJDb2xvckJyZXdlcik7bGlicmFyeShncmlkRXh0cmEpCgojRGVmaW5lIHRoZW1lIGZvciBteSB2aXN1YWxzCm15X3RoZW1lIDwtIGZ1bmN0aW9uKCkgewoKICAjIERlZmluZSBjb2xvcnMgZm9yIHRoZSBjaGFydAogIHBhbGV0dGUgPC0gYnJld2VyLnBhbCgiR3JleXMiLCBuPTkpCiAgY29sb3IuYmFja2dyb3VuZCA9IHBhbGV0dGVbMl0KICBjb2xvci5ncmlkLm1ham9yID0gcGFsZXR0ZVs0XQogIGNvbG9yLnBhbmVsID0gcGFsZXR0ZVszXQogIGNvbG9yLmF4aXMudGV4dCA9IHBhbGV0dGVbOV0KICBjb2xvci5heGlzLnRpdGxlID0gcGFsZXR0ZVs5XQogIGNvbG9yLnRpdGxlID0gcGFsZXR0ZVs5XQoKICAjIENyZWF0ZSBiYXNpYyBjb25zdHJ1Y3Rpb24gb2YgY2hhcnQKICB0aGVtZV9idyhiYXNlX3NpemU9OSwgYmFzZV9mYW1pbHk9IkZyaWVuZHMiKSArIAogICNTZWVtcyBsaWtlIGEgZ29vZCB0aW1lIHRvIHVzZSB0aGUgRnJpZW5kcy1UVi1zaG93LXNwZWNpZmljIGZvbnQgIAoKICAjIFNldCB0aGUgZW50aXJlIGNoYXJ0IHJlZ2lvbiB0byBhIGxpZ2h0IGdyYXkgY29sb3IKICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kPWVsZW1lbnRfcmVjdChmaWxsPWNvbG9yLnBhbmVsLCBjb2xvcj1jb2xvci5iYWNrZ3JvdW5kKSkgKwogIHRoZW1lKHBsb3QuYmFja2dyb3VuZD1lbGVtZW50X3JlY3QoZmlsbD1jb2xvci5iYWNrZ3JvdW5kLCBjb2xvcj1jb2xvci5iYWNrZ3JvdW5kKSkgKwogIHRoZW1lKHBhbmVsLmJvcmRlcj1lbGVtZW50X3JlY3QoY29sb3I9Y29sb3IuYmFja2dyb3VuZCkpICsKCiAgIyBGb3JtYXQgZ3JpZAogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9saW5lKGNvbG9yPWNvbG9yLmdyaWQubWFqb3Isc2l6ZT0uMjUpKSArCiAgdGhlbWUocGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCkpICsKICB0aGVtZShheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSkgKwoKICAjIEZvcm1hdCBsZWdlbmQKICB0aGVtZShsZWdlbmQucG9zaXRpb249InJpZ2h0IikgKwogIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGw9Y29sb3IuYmFja2dyb3VuZCkpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTcsY29sb3I9Y29sb3IuYXhpcy50aXRsZSkpICsgCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MCxmYWNlPSJib2xkIiwgY29sb3I9Y29sb3IuYXhpcy50aXRsZSkpICsgCiAgCiAgI0Zvcm1hdCBmYWNldCBsYWJlbHMKICB0aGVtZShzdHJpcC50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgsIGZhY2U9ImJvbGQiKSkrCgogICMgRm9ybWF0IHRpdGxlIGFuZCBheGVzIGxhYmVscyB0aGVzZSBhbmQgdGljayBtYXJrcwogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGNvbG9yPWNvbG9yLnRpdGxlLCBzaXplPTE4LCBmYWNlPSJib2xkIiwgaGp1c3Q9MCkpICsKICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02LGNvbG9yPWNvbG9yLmF4aXMudGV4dCkpICsKICB0aGVtZShheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02LGNvbG9yPWNvbG9yLmF4aXMudGV4dCkpICsKICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF90ZXh0KHNpemU9OCxjb2xvcj1jb2xvci5heGlzLnRpdGxlLCB2anVzdD0tMSwgZmFjZT0iYm9sZCIpKSArCiAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfdGV4dChzaXplPTgsY29sb3I9Y29sb3IuYXhpcy50aXRsZSwgdmp1c3Q9MS44LCBmYWNlPSJib2xkIikpICsKCiAgI0Zvcm1hdCB0aXRsZSBhbmQgZmFjZXRfd3JhcCB0aXRsZQogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT04KSwgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGZhY2UgPSAiYm9sZCIsIGNvbG91ciA9ICJibGFjayIsIHZqdXN0ID0gMSwgaGp1c3Q9MC41KSkrCiAgICAKICAjIFBsb3QgbWFyZ2lucwogIHRoZW1lKHBsb3QubWFyZ2luID0gdW5pdChjKC4yLCAuMiwgLjIsIC4yKSwgImNtIikpCn0KYGBgClRoZW4gSSBwbG90IHRoZSBiYXJjaGFydC4KYGBge3J9CmdncGxvdChkYXRhPXRvdGFsX2xpbmVzLCBhZXMoeD1wZXJzb24sIHk9biwgZ3JvdXA9cGVyc29uLCBjb2xvcj1wZXJzb24sIGZpbGw9cGVyc29uLCBsYWJlbD1uKSkgKyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSArIAogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICBteV90aGVtZSgpKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCggaGp1c3QgPSAwKSkrdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9OSkpKwogIGdlb21fdGV4dChzaXplID0gMiwgY29sb3I9ImJsYWNrIiwgZmFtaWx5PSJGcmllbmRzIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpKwogIGxhYnMoeD0iIiwgeT0iIikrCiAgZ2d0aXRsZSgiVGhlIE9uZSBXaXRoIEFsbCBUaGUgUXVhbnRpZmlhYmxlIEZyaWVuZHNoaXBzIiwgc3VidGl0bGU9IlRvdGFsIExpbmVzIFNwb2tlbiBieSBFYWNoIENoYXJhY3RlciBhbmQgT3RoZXJzIikKYGBgCmBgYHtyfQpnZ3NhdmUoInRvdGFsLnBuZyIsIHdpZHRoPTcsIGhlaWdodD00LjUsIGRwaT05MDApCmBgYAoKIyBFcGlzb2RlIGJ5IGVwaXNvZGUKSSB3YW50IHRvIHZpc3VhbGl6ZSB0aGUgbGluZXMgc3Bva2VuIGJ5IHRoZSA2IG1haW4gY2hhcmFjdGVycyBhbmQgKm90aGVycyogb3ZlciB0aGUgY291cnNlIG9mIHRoZSBzaG93LiBHaW9yYSBkb2VzIHRoaXMgaW4gYSBmZXcgYWdncmVnYXRlZCB3YXlzIGJ1dCBJIGFtIG5vdyBnb2luZyB0byBzaG93IHRoaXMgKmVwc2lvZGUgYnkgZXBpc29kZSouIFNvLCBJIGZpcnN0IG1ha2Ugc29tZSBtYW5pcHVsYXRpb25zIHRvIGdldCBhIGNvdW50IG9mIGxpbmVzIGZvciBlYWNoIGNoYXJhY3RlciBhbmQgZXBpc29kZSBwYWlyaW5nLiAKCmBgYHtyfQplcGlzb2Rlc19kZiRJRCA8LSBhcy5udW1lcmljKHJvd25hbWVzKGVwaXNvZGVzX2RmKSkKICAKZXBfcGVyc29uX2xpbmVzIDwtIHBlcnNvbkxpbmVzX2RmICU+JQogIGNvdW50KHBlcnNvbiwgZXBpc29kZVRpdGxlLCBlcGlzb2RlTnVtLCBzZWFzb24pIAoKZXBpPC1lcGlzb2Rlc19kZltjKCJJRCIsICJlcGlzb2RlVGl0bGUiKV0KZXBfbGluZXM8LW1lcmdlKGVwaSwgZXBfcGVyc29uX2xpbmVzLCBieT0iZXBpc29kZVRpdGxlIikKCmVwX2xpbmVzCmBgYAoKTm93IEkgaGF2ZSB0aGUgZGF0YSBpbiBhIGZvcm0gSSBjYW4gZ3JhcGgsIHNvIEkgY2FsbCBnZ3Bsb3QgdG8gbWFrZSBzb21lIGdyYXBocy4gSSB3ZW50IHRocm91Z2ggYSBudW1iZXIgb2YgYXR0ZW1wdHMgdG8gZ2V0IG15IGZpbmFsIHByb2R1Y3QuIEZpcnN0LCBJIHNpbXBseSBzaG93ZWQgdGhlIHRpbWUgc2VyaWVzIG9mIGxpbmVzIHNwb2tlbiBmb3IgZWFjaCBjaGFyYWN0ZXIgYWxsIG9uIHRoZSBzYW1lIGdyYXBoLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRhPWVwX2xpbmVzLCBhZXMoeD1JRCwgeT1uLCBncm91cD1wZXJzb24sIGNvbG9yPXBlcnNvbikpICsgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKyAKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKwogIGdlb21fbGluZShzaXplPTAuNSwgYWxwaGE9MSkrCiAgbXlfdGhlbWUoKSArdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCggaGp1c3QgPSAwKSkrCiAgbGFicyh4PSJFcGlzb2RlIE51bWJlciIsIHk9IiIpKwogIAogIGdndGl0bGUoIlRoZSBPbmUgV2l0aCBBbGwgVGhlIFF1YW50aWZpYWJsZSBGcmllbmRzaGlwcyIsIHN1YnRpdGxlID0gIkxpbmVzIFNwb2tlbiBPdmVyIEFsbCBUaGUgRXBpc29kZXMiKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmBgYApUaGUgYWJvdmUgaXMgdmVyeSBoYXJkIHRvIGdldCBhbnl0aGluZyBvdXQgb2YgdmlzdWFsbHksIHNvIEkgaGFkIGFuIGlkZWEgYmFzZWQgb24gcHJldmlvdXMgd29yayBJIGRpZCBvbiBbZGVtb2dyYXBoaWNzIGluIHRoZSBzY2llbmNlIFBoRCdzXShodHRwczovL3RoZWxpdHRsZWRhdGFzZXQuY29tLzIwMTUvMTIvMzEvdGhpcy1wb3N0LWlzLWJyb3VnaHQtdG8teW91LWJ5LXRoZS1uYXRpb25hbC1zY2llbmNlLWZvdW5kYXRpb24vKS4gU28sIEkgdHJ5IG1ha2luZyBhIHN0YWNrZWQgYXJlYSBncmFwaC4KCmBgYHtyLCBlY2hvPVRSVUV9CnA8LWdncGxvdChkYXRhPWVwX2xpbmVzLCBhZXMoeD1JRCwgeT1uLCBncm91cD1wZXJzb24sIGZpbGw9cGVyc29uLCBjb2xvcj1wZXJzb24pKSsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKyAKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIikgKwogIG15X3RoZW1lKCkrdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCggaGp1c3QgPSAwKSkrCiAgbGFicyh4PSJFcGlzb2RlIE51bWJlciIsIHk9IiIpKwogIGdndGl0bGUoIlRoZSBPbmUgV2l0aCBBbGwgVGhlIFF1YW50aWZpYWJsZSBGcmllbmRzaGlwcyIsIHN1YnRpdGxlID0gIkxpbmVzIFNwb2tlbiBPdmVyIEFsbCBUaGUgRXBpc29kZXMiKQojU3RhY2tlZCBhcmVhIGdyYXBoCnArZ2VvbV9hcmVhKGFlcyhmaWxsPXBlcnNvbiksIHBvc2l0aW9uPSdzdGFjaycpCgpgYGAKCkkgbWFrZSBhIG5pZ2h0aW5nYWxlIGdyYXBoIGFsc28gKGZvciBmdW4pLiAKCmBgYHtyLCBlY2hvPVRSVUV9CiNOaWdodGluZ2FsZSBHcmFwaApwK2dlb21fYXJlYShhZXMoZmlsbD1wZXJzb24pLCBwb3NpdGlvbj0nc3RhY2snKStjb29yZF9wb2xhcigpKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKYGBgCkhvd2V2ZXIsIHRoZSBkaWZmZXJlbmNlcyBpbiBsaW5lcyBmb3IgZWFjaCBjaGFyYWN0ZXIgYXJlbid0IHN1cGVyIHZpc2libGUgc3RpbGwgZHVlIHRvIHRoZSBtYWpvciBkaWZmZXJlbmNlcyBpbiB0b3RhbCBlcGlzb2RlIGxpbmVzLS1tYWlubHkgZHVlIHRvIHRoZSBmYWN0IHRoYXQgdGhlcmUgYXJlIHNpbmdsZSBzY3JpcHRzIGZvciB0d28gcGFydCBlcGlzb2Rlcywgd2hpY2ggbWVzc2VzIHdpdGggdGhlIHNjYWxlLiBGb3IgdGhpcyBzZWFzb24sIGl0J3Mgd29ydGggbG9va2luZyBpbnRvIHBlcmNlbnRhZ2VzIG9mIGxpbmVzIGZvciBjaGFyYWN0ZXJzIGJ5IGVwaXNvZGUgaW5zdGVhZC4KYGBge3J9CiMgTWFrZSBwZXJjZW50YWdlIGZpZ3VyZXMKIyBGaXJzdCBjYWxjdWxhdGUgdG90YWwgbGluZXMgZm9yIGVhY2ggZXAKbGluZXNfdG90YWw8LWVwX2xpbmVzICU+JQogIGdyb3VwX2J5KElEKSAlPiUKICBzdW1tYXJpc2Uobj1zdW0obikpCgpsaW5lc19uZXc8LW1lcmdlKGVwX2xpbmVzLCBsaW5lc190b3RhbCwgYnk9YygiSUQiKSkKbGluZXNfbmV3JHBlcmM8LWxpbmVzX25ldyRuLngvbGluZXNfbmV3JG4ueQpgYGAKVGltZSBmb3IgcGxvdHRpbmcuLi4KYGBge3J9CnA8LWdncGxvdChkYXRhPWxpbmVzX25ldywgYWVzKHg9SUQsIHk9cGVyYywgZ3JvdXA9cGVyc29uLCBmaWxsPXBlcnNvbiwgY29sb3I9cGVyc29uKSkgKyAKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSArIAogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDMiKSArCiAgbXlfdGhlbWUoKSt0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KCBoanVzdCA9IDApKSsKICBsYWJzKHg9IkVwaXNvZGUgTnVtYmVyIiwgeT0iIikrCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpKwogIGdndGl0bGUoIlRoZSBPbmUgV2l0aCBBbGwgVGhlIFF1YW50aWZpYWJsZSBGcmllbmRzaGlwcyIsIHN1YnRpdGxlID0gIlBlcmNlbnRhZ2Ugb2YgTGluZXMgU3Bva2VuIEFjcm9zcyBUaGUgRXBpc29kZXMiKQoKI1N0YWNrZWQgYXJlYSBncmFwaApwK2dlb21fYXJlYShhZXMoZmlsbD1wZXJzb24pLCBwb3NpdGlvbj0nc3RhY2snKQoKYGBgCmBgYHtyfQpnZ3NhdmUoImxpbmVzMS5wbmciLCB3aWR0aD03LCBoZWlnaHQ9NC41LCBkcGk9OTAwKQpgYGAKClRlbGwgbWUgdGhlIGFib3ZlIGRvZXNuJ3QgbG9vayBqdXN0IGxpa2UgUmFjaGVsJ3MgRW5nbGlzaCBUcmlmbGUhIFtMYXllciBvbiBsYXllciBvbiBsYXllci4uLl0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1HMDhwcUFhSmk1aykKYGBge3J9CiNOaWdodGluZ2FsZSBncmFwaHMKcCtnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGFlcyhmaWxsPXBlcnNvbiksIHBvc2l0aW9uPSdzdGFjaycpKyAKICBjb29yZF9wb2xhcigpKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT04LjgpKQpgYGAKCmBgYHtyfQpnZ3NhdmUoImxpbmVzMi5wbmciLCB3aWR0aD03LCBoZWlnaHQ9NC41LCBkcGk9OTAwKQpgYGAKVGhlIHR3byB2aXNpYmxlIGdhcHMgaW4gdGhhdCBncmFwaCBhcmUgZHVlIHRvIG1pc3Npbmcgb2JzZXJ2YXRpb25zIGZvciB0d28gZXBpc29kZXMuCmBgYHtyfQojTGluZQpwK2dlb21fbGluZShzaXplPTAuNSkKYGBgCmBgYHtyfQpnZ3NhdmUoImxpbmVzMy5wbmciLCB3aWR0aD03LCBoZWlnaHQ9NC41LCBkcGk9OTAwKQpgYGAKClRoaXMgbGFzdCBncmFwaCBpcyB1c2VmdWwgZm9yIHNlZWluZyBvdXRsaWVyIGVwaXNvZGVzIGluIHRlcm1zIG9mIHdobyB3YXMgYWJub3JtYWxseSBvdmVyc2VydmVkIG9yIHVuZGVyc2VydmVkIGJ5IHRoZSB3cml0aW5nIG9mIGEgcGFydGljdWxhciBlcGlzb2RlLiBXaGlsZSBubyBvbmUgZXZlciBzcG9rZSB0aGUgbWFqb3JpdHkgb2YgdGhlIGxpbmVzIGluIHRoZSBncm91cCBmb3IgYW4gZXBpc29kZSwgdGhlcmUgYXJlIGEgZmV3IHRpbWVzIHBlb3BsZSBjb21lIGNsb3NlLiBTaW1pbGFybHksIHRoZXJlIGFyZSBhIGZldyB0aW1lcyBjaGFyYWN0ZXJzIGNvbWUgY2xvc2UgdG8gbm90IHNwZWFraW5nIGF0IGFsbC4KCmBgYHtyfQpsaW5lc19uZXcgPC0gbGluZXNfbmV3ICU+JQogIGFycmFuZ2UoLXBlcmMpIApsaW5lc19uZXcKYGBgCgpUaGUgaGlnaGVzdCBwZXJjZW50YWdlIG9mIGxpbmVzIGluIGFuIGVwaXNvZGUgaXMgQ2hhbmRsZXIgZm9yICpUaGUgT25lIHdpdGggQ2hyaXN0bWFzIGluIFR1bHNhKi4gTWFrZXMgc2Vuc2UuIFNlY29uZCBwbGFjZSBpcyBKb2V5IGluICpUaGUgT25lIFdpdGggSm9leSdzIEludGVydmlldyouCgpgYGB7cn0KbGluZXNfbmV3IDwtIGxpbmVzX25ldyAlPiUKICBhcnJhbmdlKHBlcmMpIApoZWFkKGxpbmVzX25ldywgNSkKYGBgClRoZSBtb3N0IGdhbmctZHJpdmVuIGVwaXNvZGUgaXMgKlRoZSBPbmUgVGhlIExhc3QgTmlnaHQqLCBhcyBvbmx5IDEgbGluZSBpbiB0aGF0IGVwaXNvZGUgaXMgc3Bva2VuIGJ5IHNvbWVvbmUgb3V0c2lkZSB0aGUgNiBtYWluIGNoYXJhY3RlcnMuIFRoZSBhYm92ZSB0YWJsZSBzaG93cyB0aGUgNSBlcGlzb2RlcyB0aGF0IGhhdmUgdGhlIGhpZ2hlc3QgcGVyY2VudGFnZSBvZiBsaW5lcyBzcG9rZW4gYnkgdGhlIGdhbmcuIAoKTWF5YmUgd2Ugd2FudCB0byBmb3JnZXQgYWJvdXQgdGhlICpvdGhlcnMqIGluIHRoaXMgcG9zdCBhbmQganVzdCBmb2N1cyBvbiB0aGUgbWFpbiA2IGNoYXJhY3RlcnMuIElmIHdlIGRvIHRoYXQgdGhlbiB3ZSBnZXQgYSBwaWN0dXJlIG9mIGhvdyBjZW50cmFsIG9yIHRhbmdlbnRpYWwgY2hhcmFjdGVycyB3ZXJlIHRvIHNwZWNpZmljIGVwaXNvZGVzLiBJZSwgTW9uaWNhIG9ubHkgc3BlYWtzIH4xLjUlIG9mIGxpbmVzIGluICpUaGUgT25lIFdpdGggVGhlIFJpbmcqIGFuZCBzYW1lIGZvciBSb3NzIGluICpUaGUgT25lIFdpdGggVGhlIEN1ZmZzKi4gCmBgYHtyfQojdGFrZSBvdXQgb3RoZXIgb3B0aW9ucwpsaW5lc19uZXdfbm9fb3RoZXI8LWxpbmVzX25ld1shKGxpbmVzX25ldyRwZXJzb249PSJvdGhlciIpLF0KCmxpbmVzX25ld19ub19vdGhlciA8LSBsaW5lc19uZXdfbm9fb3RoZXIgJT4lCiAgYXJyYW5nZShwZXJjKSAKbGluZXNfbmV3X25vX290aGVyCmBgYAoKV2UgY2FuIGFsc28gbG9vayBhdCB0aGUgZXBpc29kZXMgY2VydGFpbiBjaGFyYWN0ZXJzIGFyZSBtb3N0IGRvbWluYW50IGluLiBTZWUgYmVsb3cuCmBgYHtyfQpsaW5lc19uZXdfbm9fb3RoZXIgPC0gbGluZXNfbmV3X25vX290aGVyICU+JQogIGFycmFuZ2UoLXBlcmMpIApsaW5lc19uZXdfbm9fb3RoZXIKYGBgCgojR2VuZGVyIGFuZCBsaW5lcwpXaGF0IGlmIEkgZ3JvdXAgdGhlIHdvbWVuIGFuZCBtZW4gdG9nZXRoZXIgYW5kIHRoZW4gbG9vayBhdCB0aGUgdmlzdWFscy4uLndvdWxkIGNlcnRhaW4gcGVyaW9kcyBvZiB0aW1lIGJlIG1vcmUgbWFsZS9mZW1hbGUgZG9taW5hdGVkPwpgYGB7cn0KbGluZXNfbmV3X25vX290aGVyJGdlbmRlcltsaW5lc19uZXdfbm9fb3RoZXIkcGVyc29uID09ICJyYWNoZWwiIHxsaW5lc19uZXdfbm9fb3RoZXIkcGVyc29uID09ICJwaG9lYmUiIHxsaW5lc19uZXdfbm9fb3RoZXIkcGVyc29uID09ICJtb25pY2EiIF0gPC0gIldvbWVuIgpsaW5lc19uZXdfbm9fb3RoZXIkZ2VuZGVyWyBsaW5lc19uZXdfbm9fb3RoZXIkcGVyc29uID09ICJqb2V5IiB8bGluZXNfbmV3X25vX290aGVyJHBlcnNvbiA9PSAiY2hhbmRsZXIiIHxsaW5lc19uZXdfbm9fb3RoZXIkcGVyc29uID09ICJyb3NzIiBdIDwtICJNZW4iCgpsaW5lc19nZW5kZXI8LWxpbmVzX25ld19ub19vdGhlcltjKCJlcGlzb2RlVGl0bGUiLCAiZXBpc29kZU51bSIsICJzZWFzb24iLCAiZ2VuZGVyIiwgIm4ueCIsICJJRCIpXQoKbGluZXNfZ2VuZGVyX2ZpbmFsPC1saW5lc19nZW5kZXIgJT4lCiAgZ3JvdXBfYnkoZ2VuZGVyLCBJRCkgJT4lCiAgc3VtbWFyaXNlKG49c3VtKG4ueCkpCgpsMjwtbGluZXNfZ2VuZGVyICU+JQogIGdyb3VwX2J5KElEKSAlPiUKICBzdW1tYXJpc2UodG90PXN1bShuLngpKQoKZ2VuZGVyPC1tZXJnZShsMiwgbGluZXNfZ2VuZGVyX2ZpbmFsLCBieT0iSUQiKQpnZW5kZXI8LW1lcmdlKGdlbmRlciwgZXBpLCBieT0iSUQiKQpnZW5kZXIkcGVyYzwtZ2VuZGVyJG4vZ2VuZGVyJHRvdApgYGAKTm93LCBJIHBsb3QgdGhlIGJhbGFuY2Ugb3ZlciB0aW1lLgpgYGB7cn0KcDwtZ2dwbG90KGRhdGE9Z2VuZGVyLCBhZXMoeD1JRCwgeT1wZXJjLCBncm91cD1nZW5kZXIsIGZpbGw9Z2VuZGVyLCBjb2xvcj1nZW5kZXIpKSArIAogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsgCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsKICBteV90aGVtZSgpK3RoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoIGhqdXN0ID0gMCkpKwogIGxhYnMoeD0iRXBpc29kZSBOdW1iZXIiLCB5PSIiKSsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkrCiAgZ2d0aXRsZSgiVGhlIE9uZSBXaXRoIEFsbCBUaGUgUXVhbnRpZmlhYmxlIEZyaWVuZHNoaXBzIiwgc3VidGl0bGUgPSAiUGVyY2VudGFnZSBvZiBMaW5lcyBTcG9rZW4gQWNyb3NzIHRoZSBHYW5nIEJ5IEdlbmRlciIpCgojU3RhY2tlZCBhcmVhIGdyYXBoCnArZ2VvbV9hcmVhKGFlcyhmaWxsPWdlbmRlciksIHBvc2l0aW9uPSdzdGFjaycpCmBgYApgYGB7cn0KZ2dzYXZlKCJnZW5kZXIxLnBuZyIsIHdpZHRoPTcsIGhlaWdodD00LjUsIGRwaT05MDApCmBgYAoKYGBge3J9CnArZ2VvbV9saW5lKHNpemU9MC41KQpgYGAKYGBge3J9Cmdnc2F2ZSgiZ2VuZGVyMi5wbmciLCB3aWR0aD03LCBoZWlnaHQ9NC41LCBkcGk9OTAwKQpgYGAKClRoZSBhYm92ZSBzaG93cyB0aGVyZSBhcmUgdGhyZWUgZXBpc29kZXMgdGhhdCBzdGFuZC1vdXQgaW4gdGVybXMgb2YgZ2l2aW5nIG9uZSBnZW5kZXIgb2YgdGhlIGdhbmcgbW9yZSBsaW5lcyB0aGFuIHRoZSBvdGhlciBwZXJjZW50YWdlLXdpc2UKCmBgYHtyfQpnZW5kZXIgPC0gZ2VuZGVyICU+JQogIGFycmFuZ2UoLXBlcmMpIApnZW5kZXIKYGBgClRoZXkgYXJlOiAqVGhlIE9uZSBXaGVyZSBDaGFuZGxlciBDcm9zc2VzIEEgTGluZSogKENoYW5kbGVyIGtpc3NlcyBKb2V5J3MgZ2lybGZyaWVuZCBhbmQgY29uZnJvbnRhdGlvbiBlbnN1ZXMpLCAqVGhlIE9uZSBXaXRoIEpvZXkncyBJbnRlcnZpZXcqLCBhbmQgKlRoZSBPbmUgV2l0aCBNYWMgYW5kIEMuSC5FLkUuUy5FLiouCgpUd28gZXBpc29kZXMgYXJlIGFjdHVhbGx5IGV4YWN0bHkgNTAtNTA6ICpUaGUgT25lIFdoZXJlIFJhY2hlbCBGaW5kcyBPdXQqIGFuZCAqVGhlIE9uZSBXaXRoIFRoZSBUaGFua3NnaXZpbmcgRmxhc2hiYWNrcyohCgpIb3cgbWFueSBhcmUgPjUwJSBtZW4gc3BlYWtpbmc/CmBgYHtyLCBlY2hvPVRSVUV9CmdlbmRlcl9uZXc8LWdlbmRlcltnZW5kZXIkZ2VuZGVyPT0iTWVuIixdCmdlbmRlcl9uZXc8LWdlbmRlcl9uZXdbZ2VuZGVyX25ldyRwZXJjID4gMC41MCxdCm5yb3coZ2VuZGVyX25ldykKYGBgClNvIDExOC8yMjYgKDUyLjIlKSBvZiB0aGUgYXZhaWxhYmxlIGVwaXNvZGVzIHdpdGggPjUwJSBsaW5lcyBnaXZlbiB0byBtZW4gaW4gdGhlIGdyb3VwLgoKI1dobyBtZW50aW9ucyB3aG9tPwpIZXJlIEkgYW0gYWRhcHRpbmcgW0dpb3JhJ3MgY29kZV0oaHR0cDovL2dpb3Jhc2ltY2hvbmkuY29tLzIwMTcvMDYvMDQvMjAxNy0wNi0wNC10aGUtb25lLXdpdGgtZnJpZW5kcy8pLiBUaGUgY2hhbmdlIEknbSBtYWtpbmcgaXMgdG8gaW5jbHVkZSBuaWNrbmFtZXMgbGlrZSAqTW9uKiwgKlJhY2gqLCAqUGhlZWJzKiwgYW5kICpKb2UqLgpgYGB7cn0KbGlicmFyeShkcGx5cik7IGxpYnJhcnkoc3RyaW5ncik7IGxpYnJhcnkocHVycnIpCm0gPC0gcGVyc29uTGluZXNfZGYgJT4lCiAgZmlsdGVyKHBlcnNvbiAlaW4lIGMoImNoYW5kbGVyIiwgInJvc3MiLCAiam9leSIsICJtb25pY2EiLCAicmFjaGVsIiwgInBob2ViZSIpKSAlPiUKICBtdXRhdGUoY2hhbmRsZXIgPSBtYXBfaW50KGxpbmUsIHN0cl9jb3VudCwgImNoYW5kbGVyIiksCiAgICAgICAgIHJvc3MgPSBtYXBfaW50KGxpbmUsIHN0cl9jb3VudCwgInJvc3MiKSwKICAgICAgICAgam9leSA9IG1hcF9pbnQobGluZSwgc3RyX2NvdW50LCAiam9leSIpLAogICAgICAgICBqb2UgPSBtYXBfaW50KGxpbmUsIHN0cl9jb3VudCwgImpvZSAiKSwKICAgICAgICAgbW9uaWNhID0gbWFwX2ludChsaW5lLCBzdHJfY291bnQsICJtb25pY2EiKSwKICAgICAgICAgbW9uID0gbWFwX2ludChsaW5lLCBzdHJfY291bnQsICJtb24gIiksCiAgICAgICAgIHJhY2hlbCA9IG1hcF9pbnQobGluZSwgc3RyX2NvdW50LCAicmFjaGVsIiksCiAgICAgICAgIHJhY2ggPSBtYXBfaW50KGxpbmUsIHN0cl9jb3VudCwgInJhY2ggIiksCiAgICAgICAgIHBob2ViZSA9IG1hcF9pbnQobGluZSwgc3RyX2NvdW50LCAicGhvZWJlIiksCiAgICAgICAgIHBoZWVicyA9IG1hcF9pbnQobGluZSwgc3RyX2NvdW50LCAicGhlZWJzIikpICU+JQogIHNlbGVjdChwZXJzb24sIGNoYW5kbGVyLCBqb2V5LCBqb2UsIG1vbmljYSwgbW9uLCBwaG9lYmUsIHBoZWVicywgcmFjaGVsLCByYWNoLCByb3NzKSAlPiUKICBncm91cF9ieShwZXJzb24pICU+JQogIHN1bW1hcmlzZV9lYWNoKGZ1bnMoc3VtKSkKCm0KYGBgCkxvb2sgaG93IG11Y2ggdGhlIGNoYXJhY3RlcnMgc2F5IFBoZWVicyEgVGhhdCdzIGJ5IGZhciB0aGUgbW9zdCBpbXBvcnRhbnQgbmlja25hbWUgdG8gYWRkIGluLgoKYGBge3J9Cm0kbW9uaWNhPC1tJG1vbmljYSttJG1vbgptJHBob2ViZTwtbSRwaGVlYnMrbSRwaG9lYmUKbSRyYWNoZWw8LW0kcmFjaGVsK20kcmFjaAptJGpvZXk8LW0kam9lK20kam9leQptPC1tWyxjKCJwZXJzb24iLCAiY2hhbmRsZXIiLCAiam9leSIsICJtb25pY2EiLCAicGhvZWJlIiwgInJhY2hlbCIsICJyb3NzIildCm0KYGBgClNvIHRoZSBhYm92ZSBpcyBvdXIgdXBkYXRlZCBkYXRhZnJhbWUgd2l0aCBuaWNrbmFtZXMgaW5jbHVkZWQuCk5vdywgdG8gZ3JhcGgsIEkgd2FudCB0byBtdXRhdGUgdGhpcyBhIGJpdC4uLgpgYGB7cn0KbGlicmFyeShyZXNoYXBlKQptPC1hcy5kYXRhLmZyYW1lKG0pCm1uZXcgPC0gcmVzaGFwZShtLCB2YXJ5aW5nID0gYygiY2hhbmRsZXIiLCAibW9uaWNhIiwicm9zcyIsICJyYWNoZWwiLCJwaG9lYmUiLCAiam9leSIpLCAKICAgICAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJjb3VudCIsCiAgICAgICAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiZnJpZW5kX21lbnRpb24iLCAKICAgICAgICAgICAgICAgICAgICAgdGltZXMgPSBjKCJjaGFuZGxlciIsICJtb25pY2EiLCJyb3NzIiwgInJhY2hlbCIsInBob2ViZSIsICJqb2V5IiksIAogICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAibG9uZyIpCm1uZXc8LW1uZXdbYygicGVyc29uIiwgImZyaWVuZF9tZW50aW9uIiwgImNvdW50IildCmBgYAoKTm93LCBJIHVzZSBmYWNldGluZyB0byBncmFwaCBteSB1cGRhdGVkIHZlcnNpb24gb2YgR2lvcmEncyBjb2xsZWN0ZWQgZGF0YS4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkYXRhPW1uZXcsIGFlcyh4PWZyaWVuZF9tZW50aW9uLCB5PWNvdW50LCBncm91cD1mcmllbmRfbWVudGlvbiwKICAgICAgICAgICAgICAgICAgICAgIGZpbGw9ZnJpZW5kX21lbnRpb24sIGxhYmVsPWNvdW50KSkgKyAKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBndWlkZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJGcmllbmQgTWVudGlvbmVkIikpICsgCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSsKICBmYWNldF93cmFwKH5wZXJzb24sIG5jb2w9MykrCiAgbXlfdGhlbWUoKSsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCggaGp1c3QgPSAwKSkrdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MCkpKwogIGdlb21fdGV4dChzaXplID0gMSwgY29sb3I9ImJsYWNrIiwgZmFtaWx5PSJGcmllbmRzIiwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpKwogIGxhYnMoeD0iIiwgeT0iIikrCiAgZ2d0aXRsZSgiVGhlIE9uZSBXaXRoIEFsbCBUaGUgUXVhbnRpZmlhYmxlIEZyaWVuZHNoaXBzIiwgc3VidGl0bGU9Ik1lbnRpb25zIGJ5IEZyaWVuZHMuLi4gb2YgRnJpZW5kcyIpKyAKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT02LGZhY2U9ImJvbGQiKSkKYGBgCmBgYHtyfQpnZ3NhdmUoIm1lbnRpb25zLnBuZyIsIHdpZHRoPTcsIGhlaWdodD00LjUsIGRwaT05MDApCmBgYAoKV293LCBSYWNoZWwgbGlrZXMgc2F5aW5nICpSb3NzKi4KCiMjIEFscmlnaHQsIHRoYXQncyBhIHdyYXAhCiMjIyBTY3JlZW4gZ29lcyBkYXJrIGFuZC4uLgojRXhlY3V0aXZlIFByb2R1Y2VyOiBBbGV4IEFsYnJpZ2h0Cg==