• You should open the file in a browser other than Firefox (sic!) - Microsoft Edge is fine.

  • In order to R Notebook HTML file, you have to execute this Rmd file in its directory/folder - not in the root! of repository setwd("....where Rmd is located...") && rmarkdown::render("Edge.Rmd").

  • The source code for this R Notebook can be found at GitHub: https://github.com/dmpe/r


1 Objectives - Crowdsourcing Data Analysis 2

Description set out in https://docs.google.com/document/d/1fXQBLdWydISskOKhoq8gl5unuwsv7VA3pkKY4IWFS6o/edit.

In short, trying to confirm or rebut following:

Hypothesis 1: “A woman’s tendency to participate actively in the conversation correlates positively with the number of females in the discussion.”

Hypothesis 2: “Higher status participants are more verbose than are lower status participants.”

When finished, report my results using this survey: https://esmt.az1.qualtrics.com/jfe/form/SV_eaOyF0q39J6CVKZ


1.1 Variable Description of Data

Type: 1 for annual question, 2 for conversation

  • Edge does an annual question every year; some examples are “what scientific idea is ready for retirement?” and “What will change everything?” People then write in with their answers. So all of the text is written and asynchronous

  • What Edge refers to as a conversation can actually be multiple things. Some of these are written essays by a single person, some are transcripts of a speech, and some are transcripts of a conversation (either between two or more guests or an interview).

Limited_Information is described as: equals 1 if we could only find limited information about the person (e.g. they commented in 2013 but we only have their job title from 2012), 0 otherwise

Role: Either author (=1) or commentator (=2)

Female Contributions: the number of times a woman speaks in a specific conversation, it does not always equal the number of unique women in a conversation (see below)

Female Participation: simply female contributors/(number of total contributions); the percentage of comments that are made by a woman

Unique Contributors: Unique Male Contributors + Unique Female Contributors

Unique Male Contributors: the number of unique male contributors

Unique Female Contributors: the number of unique female contributors

Unique Female Participation: the percentage of unique female participants; Unique Female Contributors divided by Unique Contributors

Academic: 1 = the person is in academia, 0 = they are not

Other columns are described in the corresponding PDF file.


1.2 Settings

You can control the default appearance with options:

  • options(tibble.print_max = n, tibble.print_min = m): if there are more than n rows, print only the first m rows. Use options(tibble.print_max = Inf) to always show all rows.

  • options(tibble.width = Inf) will print all columns, regardless of the width of the screen.

From vignette:

#options(tibble.print_max = Inf, tibble.width = Inf)
set.seed(1234)

1.3 Loading libraries

# data wrangling
library(tidyverse)
library(reshape2)
library(scales)
library(tidyr)

# imputation & missingness + other
#library(mice)
#library(mi)
#library(Amelia)
library(VIM)
library(moments)
library(devtools)

# markdown Rmd + table styling
library(kableExtra)

# for plotting - arranging/positioning
library(grid)
library(gridExtra)

# plotting
library(GGally)
library(ggthemes)
library(plotly)
library(visdat)
library(corrplot)

1.4 Read Data

edgeDS <- read_csv("edge1.1EditedFixed.csv", na = c("NA", "", " ", "#N/A"), trim_ws = T)

2 First some pre-processing

vis_dat(edgeDS[,1:70], warn_large_data = F)

2.1 Deal with data problems

# print(problems(edgeDS))

# I can either delete or fix row no. 1817 because it is broken mess. I fixed it in csv. 
# edgeDS <- edgeDS[-c(1817),]

# Replace 'Not Available' & 'Pending' with NA
edgeDS$PhD_Year[edgeDS$PhD_Year == "Not Available"] <- NA
edgeDS$PhD_Year[edgeDS$PhD_Year == "Pending"] <- NA

# Aha...
edgeDS$Academic[edgeDS$Id == "david_c_geary"] <- 1

#Gender Issues
edgeDS$Male[edgeDS$Id == "benedict_carey"] <- 1
edgeDS$Female[edgeDS$Id == "benedict_carey"] <- 0

2.2 Missing values

Number of rows that have some missing values:

missing_data <- edgeDS[!complete.cases(edgeDS),]
nrow(missing_data) 
[1] 7689

List variables with most missing values: 41 have some missing values

# delete those columns which contain...
mis <- edgeDS[, -grep("dummy|Unique|Contributions|Numerals", colnames(edgeDS))]

arrange(aggr(mis, col=mdc(1:2), numbers=TRUE, sortVars=TRUE, labels=names(mis), 
        cex.axis = .4, gap=3, prop = F, plot = F)$missings, desc(Count))[1:43, ]

2.3 Apply factors to various columns where it makes sense

And rename variable Academic from 0/1 to more descriptive Non_Academicians/Academicians

cols <- c("Type", "Live", "Role", "TwoAuthors", "Limited_Information", 
          "Female", "Male", "Academic", "Job_Title_S", "Job_Title_S_num", 
          "Department_S" ,"Department_S_num" ,"Discipline", "HavePhD", 
          "AuthorAndCommenter", "PhD_Institution_SR_Bin", "Workplace_SR_Bin", 
          "SR_Ranking_Dif", "PhD_Institution_US_IR_Bin", "Workplace_US_IR_Bin", 
          "USA_I_Ranking_Dif", "PhD_Institution_US_Bin", "Workplace_US_Bin", 
          "USA_Ranking_Dif", "AcademicHierarchyStrict")

edgeDS[cols] <- lapply(edgeDS[cols], factor)

Transform two variables from factor to character to give them more meaning (similar to above).

edgeDS$Academic <- recode(edgeDS$Academic, 
                          `1` = "Academicians", 
                          `0` = "Non_Academicians", 
                          .default = "Unknown")

edgeDS$Gender <- recode(edgeDS$Female, 
                        `1` = "Female", 
                        `0` = "Male", 
                        .default = "Unknown")

Drop now female & male columns and reorder data frame.

edgeDS <- edgeDS[, !(names(edgeDS) %in% c("Female", "Male"))]
edgeDS <- edgeDS[, c(1,2,3,4,5,185,6:184)]

Potentially, transform year (do not evaluate though)

numToChar <- function(x) { ux = unique(x); formatC(ux)[match(x, ux)] }
edgeDS$Year <- year(as.Date(numToChar(edgeDS$Year), "%Y"))

2.4 Show data

What is the structure of dataset?

str(edgeDS[,5:15])
Classes 'tbl_df', 'tbl' and 'data.frame':   7975 obs. of  11 variables:
 $ ThreadId                   : num  1 1 1 1 1 1 1 1 1 1 ...
 $ Gender                     : Factor w/ 2 levels "Male","Female": 1 1 2 1 2 1 2 1 2 2 ...
 $ Male_Contributions         : num  141 141 141 141 141 141 141 141 141 141 ...
 $ Female_Contributions       : num  36 36 36 36 36 36 36 36 36 36 ...
 $ FemaleParticipation        : num  0.203 0.203 0.203 0.203 0.203 ...
 $ NumberofAuthorContributions: num  0 0 0 0 0 0 0 0 0 0 ...
 $ DebateSize                 : num  177 177 177 177 177 177 177 177 177 177 ...
 $ Live                       : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ...
 $ UniqueContributors         : num  177 177 177 177 177 177 177 177 177 177 ...
 $ UniqueMaleContributors     : num  141 141 141 141 141 141 141 141 141 141 ...
 $ UniqueFemaleContributors   : num  36 36 36 36 36 36 36 36 36 36 ...
vis_dat(edgeDS[,1:70], warn_large_data = F)

Do not evaluate code below because the output would be too large.

head(edgeDS)
summary(edgeDS) # print summaries of each variable

3 My own questions

3.1 How many times can a specific number of characters be observed?

But first take a broader look on the dataset. tail()/head() will report (i.e. print) only last/first 6 values.

Who has contributed the most in all discussions?

tail(sort(table(edgeDS$Id))) 

    richard_h_thaler                 EDGE        steven_pinker 
                 196                  203                  213 
    napoleon_chagnon sendhil_mullainathan        john_brockman 
                 214                  326                  504 

How many unique participants are there?

length(unique(edgeDS$Id)) 
[1] 728

And overall number of unique values per each variable (printed only first and last 6)?

Year 19
Title 522
Link 523
Type 2
ThreadId 522
Gender 3
Quote 608
Apostro 698
Parenth 262
OtherP 558
AllPct 1899
Number.Characters 3814

And hey, look, that’s interesting. While there are just 522 unique titles, there are 523 unique links. Using count function, I show number of observations (i.e. links) per title.

And indeed, there are two same titles for different EDGE’s conversations. Preface from 2011 and Preface from 2008.

count(edgeDS, Title, Link)[304:305, ]
count_numberOfChars_small <- arrange(count(edgeDS, Number.Characters)[, c(2,1)], desc(n))[1:20,]
count_numberOfChars <- arrange(count(edgeDS, Number.Characters)[, c(2,1)], desc(n))

Moreover, out of almost 7975 observations, I can see that 30.7% of comments have a lenght of 1.

Another 9.02% of comments have a character lenght of 2.

kable(head(count_numberOfChars_small, 10), "html",
      col.names = c("Number of comments...", "that have char lenght of...")) %>% 
  kable_styling(bootstrap_options = c("hover", "condensed"), full_width = F)
Number of comments… that have char lenght of…
34 32
32 25
32 33
31 26
31 34
30 13
30 31
30 36
30 39
29 20

The most common length of a comment is 32 which occurs in 34 comments.


A parallel coordinate plot shows how many times can a specific number of characters be observed. Here are only 20 vertices - “connections”. I let the user figure out what is nicer and more understandable - I like the first one more.

p1 <- ggparcoord(data = count_numberOfChars_small, columns = c(1, 2), scale = "globalminmax") + 
  scale_y_continuous(breaks = seq(0,60, by=2), 
                     sec.axis = sec_axis(~., name = "Number of characters", 
                                         breaks = seq(0,60, by=5))) + 
  labs(y = "Number of occurrences", x = "", 
       title = "TOP 20 connections - from # of comments to length of comments") +
  scale_fill_ptol() + 
  theme_minimal() + 
  theme(axis.title.x=element_blank(), 
        axis.text.x=element_blank(), 
        axis.ticks.x=element_blank()) + 
  geom_segment(mapping = aes(x = 1, y = n, xend = 2, yend= Number.Characters), 
               inherit.aes = F, 
               data = count_numberOfChars_small, 
               arrow=arrow(length=unit(0.2,"cm")))

p2 <- ggparcoord(data = count_numberOfChars_small, columns = c(2, 1), scale = "globalminmax") + 
  scale_y_continuous(breaks = seq(0,60, by=2), 
                     sec.axis = sec_axis(~., name = "Number of occurrences", 
                                         breaks = seq(0,60, by=5))) + 
  labs(y = "Number of characters", x = "", 
       title = "TOP 20 connections - from length of comments to # of comments") +
  scale_fill_ptol() + 
  theme_minimal() + 
  theme(axis.title.x=element_blank(), 
        axis.text.x=element_blank(), 
        axis.ticks.x=element_blank()) + 
  geom_segment(mapping = aes(x = 1, y = Number.Characters, xend = 2, yend=n ), 
               inherit.aes = F, 
               data = count_numberOfChars_small, 
               arrow=arrow(length=unit(0.1,"cm")))
grid.arrange(p1, p2, ncol=2)

Source 1 / Source 2 / GGPlot2 - geom_segment


3.2 Relationship between debate size and academicians.

Namely, what is the relationship between number of all debaters and a group of academicians over the years? Did it mean that if you participated as an academician in the conversations, the debate size was also increasing?

Let’s find it out :) First, however, prepare the dataset.

edgeDS_academiciansInDebates <- edgeDS %>% 
  filter(Type == 2) %>% # just "conversations" (not annual questions) written by either 1 or 2 authors
  select(Year, ThreadId, DebateSize, Academic) %>% 
  group_by_all() %>% 
  tally %>% 
  spread(Academic, n, fill = 0)
  
colnames(edgeDS_academiciansInDebates)[4] <- "NumberOf_Non_Academicians"
colnames(edgeDS_academiciansInDebates)[5] <- "NumberOf_Academicians"
colnames(edgeDS_academiciansInDebates)[6] <- "Unknown"
Year ThreadId DebateSize NumberOf_Non_Academicians NumberOf_Academicians Unknown
1996 19 7 4 3 0
1996 20 6 1 5 0
1996 21 13 4 9 0

Source for tally & spread code


How does debate size relate to the number of academicians? I make a simple linear regression to find out.

lm_aca_deb <- lm(DebateSize ~ NumberOf_Academicians, data = edgeDS_academiciansInDebates)
summary(lm_aca_deb)

Call:
lm(formula = DebateSize ~ NumberOf_Academicians, data = edgeDS_academiciansInDebates)

Residuals:
     Min       1Q   Median       3Q      Max 
-100.767   -4.014   -2.791   -2.014   94.408 

Coefficients:
                      Estimate Std. Error t value Pr(>|t|)    
(Intercept)            3.79110    0.56725   6.683 6.21e-11 ***
NumberOf_Academicians  1.22242    0.02292  53.324  < 2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 12.37 on 503 degrees of freedom
Multiple R-squared:  0.8497,    Adjusted R-squared:  0.8494 
F-statistic:  2843 on 1 and 503 DF,  p-value: < 2.2e-16

The mean debate size will grow by 1.2224209 as the number of academicians increases by 1. If there are zero academicians, the debate size predicts to be 3.7911047. (Here is nice article on how to interpret LM)


Now, summarize number of academicians by year (from all conversations).

year_aca_sum <- edgeDS_academiciansInDebates[,c(1,3,5)] %>% 
  group_by(Year) %>% 
  summarise(DebateSize = sum(DebateSize),
            NumberOf_Academicians_all = sum(NumberOf_Academicians), 
            Proportion = NumberOf_Academicians_all/DebateSize)
Year DebateSize NumberOf_Academicians_all Proportion
1996 194 123 0.6340206
1997 416 101 0.2427885
1998 250 51 0.2040000


3.3 What is proportion of contributors in debates?

Let’s now look on how different groups contribute in debates.

First, I start with (non-)academicians and hence need the right data.

year_aca_byGroup <- edgeDS_academiciansInDebates[,c(1,3,4,5,6)] %>% 
  group_by(Year) %>% 
  summarise(DebateSize = sum(DebateSize), 
            Academicians = sum(NumberOf_Academicians), 
            Non_Academicians = sum(NumberOf_Non_Academicians), 
            Unknown = sum(Unknown))
Year DebateSize Academicians Non_Academicians Unknown
1996 194 123 71 0
1997 416 101 315 0
1998 250 51 183 16
1999 396 94 276 26
2000 250 66 118 66
2001 187 68 69 50

Clearly, academicians prevail in majority of debates as the number of outsiders (non-aca + unknown) declined significantly over last few years.

Also, the number of participants in debates does not grow much - the summary statistics are: Min. : 52.0 , 1st Qu.: 107.5 , Median : 228.0 , Mean : 296.2 , 3rd Qu.: 389.5 , Max. :1256.0 . The mean size of conversations is just shy of 300.

year_aca_byGroup.long <- melt(year_aca_byGroup, id.vars = c(1,2))

k1 <- ggplot(data = year_aca_byGroup.long, aes(x = Year, y = value, fill = variable)) + 
  geom_col(position = position_stack(reverse = TRUE)) + 
  geom_line(aes(x = Year, y=DebateSize), data=year_aca_byGroup.long) +
  scale_y_continuous(breaks = seq(0, 1300, by = 100)) + 
  ggtitle("Number and type of debaters per year") + 
  labs(y = "Number of Participants") +
  theme_minimal() + scale_fill_ptol() + 
  theme(legend.position="none")

year_aca_byGroup.long$variable <- factor(year_aca_byGroup.long$variable, 
                                         levels = c("Unknown","Non_Academicians","Academicians" , 
                                                    ordered = T))

k2 <- ggplot(year_aca_byGroup.long, aes(x = Year, y = value, fill = variable)) + 
    geom_bar(stat="identity", position="fill") + 
    scale_y_continuous(breaks = seq(0,1,by=0.1), labels = percent) +
    labs(y = "Percent", fill = "Type", title = "Debaters' proportionality per year by background") + 
    theme_minimal() + # scale_fill_ptol() +
    scale_fill_manual(
      values=c("Academicians"="#4477AA", "Non_Academicians"="#DDCC77", "Unknown"="#CC6677")) +
    scale_colour_manual(
      values=c("Academicians"="#4477AA", "Non_Academicians"="#DDCC77", "Unknown"="#CC6677"), 
      labels=c("Academicians", "Non_Academicians", "Unknown")) +
    labs(fill = "Group")
grid.arrange(k1, k2, ncol=2)

Source #1 unused / Source #2 position fill / Source #3 for Percent bar plot / Source #4 for position_stack reverse / Source #5 for deleting first legend


The same now with gender.

edgeDS_genderInDebates <- edgeDS %>% 
  filter(Type == 2) %>% # just "conversations" (not annual questions) written by either 1 or 2 authors
  select(Year, ThreadId, DebateSize, Gender) %>% 
  group_by_all() %>% 
  tally %>% 
  spread(Gender, n, fill = 0) %>% 
  ungroup() %>% 
  select(Year, Male, Female, `<NA>`) %>% 
  group_by(Year) %>% 
  summarise(Male = sum(Male), Female = sum(Female), Unknown = sum(`<NA>`))

edgeDS_genderInDebates.long <- melt(edgeDS_genderInDebates, id.vars = c(1)) #2,3
edgeDS_genderInDebates.long$variable <- factor(edgeDS_genderInDebates.long$variable, 
                                               levels = c("Unknown","Female","Male" , ordered = T))

ggplot(edgeDS_genderInDebates.long, aes(x = Year, y = value, fill = variable, label = value)) + 
    geom_bar(stat="identity", position="fill") + 
    geom_text(aes(label = value), 
              size = 4, position = position_fill(vjust = 0.5)) +
    scale_y_continuous(breaks = seq(0,1,by=0.05), labels = percent) +
    labs(y = "Percent", fill = "Type") + 
    ggtitle ("Debaters' proportionality per year by Gender", 
             subtitle = "Number present number of debaters per gender") + 
    theme_minimal() + 
    scale_fill_manual(
      values=c("Male"="#4477AA", "Female"="#DDCC77", "Unknown"="#CC6677")) +
    scale_colour_manual(
      values=c("Male"="#4477AA", "Female"="#DDCC77", "Unknown"="#CC6677"), 
      labels=c("Male", "Female", "Unknown")) +
    labs(fill = "Gender")

In recent years, after 2010, number of women has increased somewhat.


4 Hypothesis No. 1: Women’s tendency

Hypothesis 1: “A woman’s tendency to participate actively in the conversation correlates positively with the number of females in the discussion.”

I start however first with a broad look on the data. Hence, I create data that can be used for later (prints only 5 columns).

edgeDS_conversations <- edgeDS %>% 
  filter(Type == 2) %>% 
  select(-Link, -Title, -Order, -Text,-Limited_Information, -starts_with("dummy")) %>% 
  select(-(62:144))
Year Type ThreadId Gender Male_Contributions
1996 2 19 Male 7
1996 2 19 Male 7
1996 2 19 Male 7
1996 2 19 Male 7
1996 2 19 Male 7
1996 2 19 Male 7

4.1 Does the ratio of men/women increase over the years ?

What is number of contributions (~ # of comments) and unique people who contribute by gender per year.

edgeDS_conversations_q1 <- edgeDS_conversations %>% 
  select(Year, ThreadId, Male_Contributions, Female_Contributions, UniqueMaleContributors, UniqueFemaleContributors) %>% 
  group_by_all() %>%
  distinct(.keep_all = TRUE) %>% 
  group_by(Year) %>% 
  summarise(Total_Male_Contributions = sum(Male_Contributions),
            Total_Female_Contributions = sum(Female_Contributions),
            Total_Contributions = Total_Male_Contributions + Total_Female_Contributions,
            Total_UniqueMaleContributors = sum(UniqueMaleContributors), 
            Total_UniqueFemaleContributors = sum(UniqueFemaleContributors), 
            Total_Unique_Contributions = Total_UniqueMaleContributors + Total_UniqueFemaleContributors)
Year Total_Male_Contributions Total_Female_Contributions Total_Contributions Total_UniqueMaleContributors Total_UniqueFemaleContributors Total_Unique_Contributions
1996 188 6 194 187 6 193
1997 410 6 416 74 6 80
1998 219 15 234 28 6 34
1999 327 43 370 49 7 56
2000 158 26 184 71 10 81
2001 136 1 137 86 4 90

Explanation for hike in 2008: The big spike would be attributed to the financial crises where I would assume that a lot of people were searching for job at home and had a lot of time to invest into Edge conversations.

Both, the unique number of contributors (left plot) and total number of contributions in debates is growing for both genders - albeit just a little.

r1 <- ggplot(edgeDS_conversations_q1, aes(x= Year)) + 
  geom_point(aes(y = Total_UniqueMaleContributors, colour = "Male Contr.")) + 
  geom_line(aes(y = Total_UniqueMaleContributors, colour = "Male Contr.")) +
  stat_smooth(aes(y = Total_UniqueMaleContributors, colour = "Male Contr."), 
              method = "lm", col = "#1695A3") + 
  geom_point(aes(y = Total_UniqueFemaleContributors, colour = "Female Contr.")) + 
  geom_line(aes(y = Total_UniqueFemaleContributors, colour = "Female Contr.")) +
  stat_smooth(aes(y = Total_UniqueFemaleContributors, colour = "Female Contr."), 
              method = "lm", col = "#450003") + 
  ylab("# of Unique people contributing by Gender") + labs(color = "Gender") + 
  ggtitle("Unique Contributors over years") +
  theme_minimal() + scale_fill_ptol() + theme(legend.position="none") +
  scale_x_continuous(breaks = pretty(edgeDS_conversations_q1$Year, n = 19)) + 
  scale_y_continuous(breaks = seq(0, 200, by = 25), limits = c(0, 200))

r2 <- ggplot(edgeDS_conversations_q1, aes(x= Year)) + 
  geom_point(aes(y = Total_Male_Contributions, colour = "Male Contr.")) + 
  geom_line(aes(y = Total_Male_Contributions, colour = "Male Contr.")) +
  stat_smooth(aes(y = Total_Male_Contributions, colour = "Male Contr."), 
              method = "lm", col = "#1695A3") + 
  geom_point(aes(y = Total_Female_Contributions, colour = "Female Contr.")) + 
  geom_line(aes(y = Total_Female_Contributions, colour = "Female Contr.")) +
  stat_smooth(aes(y = Total_Female_Contributions, colour = "Female Contr."), 
              method = "lm", col = "#450003") + 
  ylab("Total Contributions by Gender") + labs(color = "Gender") + 
  ggtitle("Total Contributions by Men are volatile", 
          subtitle = "While those by Women stay pretty much the same") +
  theme_minimal() + scale_fill_ptol() +
  scale_x_continuous(breaks = pretty(edgeDS_conversations_q1$Year, n = 19)) + 
  scale_y_continuous(breaks = seq(0, 1250, by = 100))

grid.arrange(r1, r2, ncol= 2)

Source #1, Source #2


4.2 Faceting on various variables

We can now look on how the participation of women has increased over the years - considering that there might be differences between those in Academia with PhD or where the author and commenter are the same person.

The plot below shows e.g. that there are no women who are academicians and don’t have their PhD. Every women is either academician with PhD. or is a non-academician with either PhD or without one.

women_part_by_year <- edgeDS_conversations %>% 
  select(Year, Gender, Female_Contributions, Live, Academic, 
         TwoAuthors, HavePhD, AuthorAndCommenter) %>% 
  filter(Gender == "Female") %>% 
  group_by_all() %>% 
  tally %>% 
  spread(Gender, n, fill = 0)

women_part_by_year$Live <- ifelse(women_part_by_year$Live == 0, "Written TP", "Transcribed TP")
women_part_by_year$TwoAuthors <- ifelse(women_part_by_year$TwoAuthors == 1, "2 authors", "1 author")
women_part_by_year$HavePhD <- ifelse(women_part_by_year$HavePhD == 1, "Have PHD", "Don't have PHD")
women_part_by_year$AuthorAndCommenter <- ifelse(women_part_by_year$AuthorAndCommenter == 1,
                                                "Both author and commentator", "Otherwise")
colnames(women_part_by_year)[8] <- "#_of_Females"

men_part_by_year <- edgeDS_conversations %>% 
  select(Year, Gender, Male_Contributions, Live, Academic, 
         TwoAuthors, HavePhD, AuthorAndCommenter) %>% 
  filter(Gender == "Male") %>% 
  group_by_all() %>% 
  tally %>% 
  spread(Gender, n, fill = 0)

men_part_by_year$Live <- ifelse(men_part_by_year$Live == 0, "Written TP", "Transcribed TP")
men_part_by_year$TwoAuthors <- ifelse(men_part_by_year$TwoAuthors == 1, "2 authors", "1 author")
men_part_by_year$HavePhD <- ifelse(men_part_by_year$HavePhD == 1, "Have PHD", "Don't have PHD")
men_part_by_year$AuthorAndCommenter <- ifelse(men_part_by_year$AuthorAndCommenter == 1,
                                                "Both author and commentator", "Otherwise")
colnames(men_part_by_year)[8] <- "#_of_Males"


d1 <- ggplot(women_part_by_year, aes(x=Year, y = Female_Contributions)) + 
  geom_point() + facet_grid(Academic ~ HavePhD) + 
  theme_minimal() + scale_fill_ptol() + 
  ggtitle("Female contributions and impact of being academician with/out PhD.", 
          subtitle = "There are no women in the academia without PhD.")

d2 <- ggplot(men_part_by_year, aes(x=Year, y = Male_Contributions)) + 
  geom_point() + facet_grid(Academic ~ HavePhD) + 
  theme_minimal() + scale_fill_ptol() + 
  ggtitle("Male contributions and impact of being academician with/out PhD.", 
          subtitle = "Here, there are actually men who don't have PhD. but are in academia")

grid.arrange(d1,d2,ncol=2)


d3 <- ggplot(women_part_by_year, aes(x=Year, y = Female_Contributions)) + 
  geom_point() + facet_grid(AuthorAndCommenter ~ TwoAuthors) + 
  theme_minimal() + scale_fill_ptol() + 
  ggtitle("Female contributions to the articles where the author and commenter is", 
          subtitle = "same person and where comments can be written by two people")

d4 <- ggplot(men_part_by_year, aes(x=Year, y = Male_Contributions)) + 
  geom_point() + facet_grid(AuthorAndCommenter ~ TwoAuthors) + 
  theme_minimal() + scale_fill_ptol() + 
  ggtitle("Male contributions to the articles where the author and commenter is", 
          subtitle = "same person and where comments can be written by up 2 people")

grid.arrange(d3,d4,ncol=2)


Skewness function confirms that all distributions are highly skewed. E.g. contributions of women to the transcribed text pieces (top-left plot) is visibly skewed to the left (being ‘+’) - i.e. the curve is right-leaning.


On the other hand, the bottom-left distribution is more normally distributed than others having the lowest skewness of just 1.4.

We can also conduct skewness test of D’Agostino. This is also confirmed because of the low p-value, i.e. the null-hypothesis that [our distributions] are normally distributed can be rejected, which is the case here

skew_fem_tran <- skewness(women_part_by_year$Female_Contributions[women_part_by_year$Live == "Transcribed TP"])
agostino.test(women_part_by_year$Female_Contributions[women_part_by_year$Live == "Transcribed TP"])

    D'Agostino skewness test

data:  women_part_by_year$Female_Contributions[women_part_by_year$Live ==     "Transcribed TP"]
skew = 2.1243, z = 4.3596, p-value = 1.303e-05
alternative hypothesis: data have a skewness
skew_fem_writ <- skewness(women_part_by_year$Female_Contributions[women_part_by_year$Live == "Written TP"])
agostino.test(women_part_by_year$Female_Contributions[women_part_by_year$Live == "Written TP"])

    D'Agostino skewness test

data:  women_part_by_year$Female_Contributions[women_part_by_year$Live ==     "Written TP"]
skew = 1.4393, z = 3.8910, p-value = 9.983e-05
alternative hypothesis: data have a skewness
skew_m_tran <- skewness(men_part_by_year$Male_Contributions[men_part_by_year$Live == "Transcribed TP"])

skew_m_writ <- skewness(men_part_by_year$Male_Contributions[men_part_by_year$Live == "Written TP"])

df_annotationsForFacets <- data.frame(Live = c("Transcribed TP", "Written TP", "Transcribed TP", "Written TP"), 
                                      value = c(skew_fem_tran, skew_fem_writ, skew_m_tran, skew_m_writ), 
                                      x = 2005, y= c(30, 30, 300, 300))

Source #1 / Source #2 / Source #3

d5 <- ggplot(women_part_by_year, aes(x=Year, y = Female_Contributions)) + 
  geom_point() + facet_grid(Live ~ . ) +
  theme_minimal() + scale_fill_ptol() + 
  ggtitle("Female contributions to the Transcribed or Written Text Pieces", 
          subtitle = "Somewhat skew to the right - right-leaning curve") + 
  geom_text(data = df_annotationsForFacets[1:2,], 
            aes(x=x, y=y, label = paste("Skewness = ", round(value,2))), 
            inherit.aes = FALSE)
            
            
d6 <- ggplot(men_part_by_year, aes(x=Year, y = Male_Contributions)) + 
  geom_point() + facet_grid(Live ~ . ) + 
  theme_minimal() + scale_fill_ptol() + 
  ggtitle("Male contributions to the Transcribed or Written Text Pieces", 
          subtitle = "Relatively equally spread") +
  geom_text(data = df_annotationsForFacets[3:4,], 
            aes(x=x, y=y, label = paste("Skewness = ", round(value,2))), 
            inherit.aes = FALSE)

grid.arrange(d5,d6,ncol=2)

Source #1 /


4.3 Female participation per Year

Again prepare the data for later use.

PeoplePerThreadID <- edgeDS_conversations %>% 
  select(Year, ThreadId, Male_Contributions, 
         Female_Contributions, FemaleParticipation, 
         DebateSize, UniqueContributors, UniqueMaleContributors, 
         UniqueFemaleContributors, UniqueFemaleParticipation) %>% 
  distinct(.keep_all = TRUE) %>% 
  select(Year, FemaleParticipation) %>% 
  group_by(Year) %>% 
  mutate(AvgFemaleParticipationPerYear = mean(FemaleParticipation),
         MedianFemaleParticipationPerYear = median(FemaleParticipation),
         SumFemaleParticipationPerYear = sum(FemaleParticipation))

ratio <- edgeDS_conversations_q1$Total_Female_Contributions/edgeDS_conversations_q1$Total_Contributions

Independently of how one calculates the (average) female participation, the trend is still growing.

q1 <- ggplot(PeoplePerThreadID, aes(x = Year, y = AvgFemaleParticipationPerYear)) +
  geom_point() + 
  ggtitle("Female Participation per Year is slightly increasing", 
          subtitle = "Calculation based on averaging 'Female Participation' (from dataset)") +
  geom_line() + 
  ylab("Avarage Female Participation") +
  geom_smooth(method = "lm", se = T, show.legend = TRUE) +
  scale_y_continuous(breaks = seq(0, 1, by = 0.1), limits = c(0, 1)) +
  scale_x_continuous(breaks = pretty(PeoplePerThreadID$Year, n = 19)) +
  theme_minimal() + scale_fill_ptol() 

q2 <- ggplot(edgeDS_conversations_q1, aes(x=Year)) + geom_point(aes(y=ratio)) + geom_line(aes(y=ratio)) +
  ggtitle("Here it is also growing", 
          subtitle = "Calculation based on total fe(male) contributions per year") +
  theme_minimal() + scale_fill_ptol() + ylab("Total_Female_Contributions/Total_Contributions") +
  scale_x_continuous(breaks = pretty(edgeDS_conversations_q1$Year, n = 19)) + 
  scale_y_continuous(breaks = seq(0, 1, by = 0.1), limits = c(0, 1))

grid.arrange(q1,q2, ncol=2)


4.4 Correlations

For reminder:

Hypothesis 1: “A woman’s tendency to participate actively in the conversation correlates positively with the number of (I guess unique) females in the discussion.”

cor_data <- edgeDS %>% 
  filter(Role == 1, Gender == "Female", Type == 2) %>% 
  select(-Link, -Id_num, -ThreadId, -Year, -Title,-Role,-Type, 
         -Order, -Text,-Limited_Information,-Gender, -starts_with("dummy"))

all_factors_names <- as.data.frame(sapply(cor_data, is.factor))
all_factors_names$name <- rownames(all_factors_names)
all_factors_names <- all_factors_names[all_factors_names$`sapply(cor_data, is.factor)` == TRUE,]
cor_data <- cor_data[ , !(names(cor_data) %in% all_factors_names$name)]


all_char_names <- as.data.frame(sapply(cor_data, is.character))
all_char_names$name <- rownames(all_char_names)
all_char_names <- all_char_names[all_char_names$`sapply(cor_data, is.character)` == TRUE,]
cor_data <- cor_data[ , !(names(cor_data) %in% all_char_names$name)]
cor_data <- cor_data[ , -c(26:106)]


M <- cor(as.data.frame(cor_data), use = "pairwise.complete.obs")

Idea: If an author is a woman, then there is potentially a higher engagement with other women as well (those could be more interesting to contribute).

Result: Yet correlation - at least for the case of Female Contributions - doesn’t confirm this.

cor(cor_data$Female_Contributions, cor_data$UniqueFemaleContributors)
[1] -0.1779973

This is opposite with Female Participation where there is a strong correlation between the normal Female Participation ratio and the unique one.

cor(cor_data$FemaleParticipation, cor_data$UniqueFemaleParticipation)
[1] 0.7275177

Plot correlation matrix.

corrplot(M)

ggcorr(M, nbreaks = 6, palette = "RdGy", label = TRUE, label_size = 3, 
       label_color = "white", hjust = 0.75, size = 2.5, angle = -5,layout.exp = 5)


5 Hypothesis No. 2: Verbosity

Hypothesis 2: “Higher status participants are more verbose than are lower status participants.”

My Definition of ‘Status’: I define “higher status” as being solely dependent on the person’s background, workplace (i.e. where (s)he comes from), his/her job (and if academicians, then also the department, discipline, academic rank and citations) and whether (s)he has a PhD and from which institution, etc. I use data from the dataset, exclusively.

edgeDS_verbosity <- edgeDS %>% 
  select(Year, Academic, Limited_Information, H_Index, i10_Index, Role, Gender, 
         HavePhD, DebateSize, Job_Title_S, Department_S, Discipline, 
         PhD_Institution_SR_Bin, AcademicHierarchyStrict, Number.Characters) %>% 
  group_by_all()

5.1 Look at different variables and how they impact how much people write to conversation and annual questions.

Group of academia <> Number of characters

ggplotly(
  ggplot(edgeDS_verbosity, aes(Academic, Number.Characters)) + geom_boxplot() + 
  scale_y_continuous(breaks = seq(0,4000, by = 200), limits = NA) + 
  coord_cartesian(ylim =c(0,4000)) +
  xlab("Group") + ylab("Number of characters") + 
  ggtitle("Number of characters by group (both genders)") +
  theme_minimal() + scale_fill_ptol()
) %>% layout(xaxis = list(ticktext = c("Non_Academicians", "Academicians", "NA")))

Hopefully one day plotly R will fix subtitle issues

Avarage number of characters by academicians and later non-academicians:

edgeDS_verbosity_aca_y <- edgeDS_verbosity %>% filter(Academic == "Academicians") 
mean(edgeDS_verbosity_aca_y$Number.Characters) 
[1] 3333.498
edgeDS_verbosity_aca_n <- edgeDS_verbosity %>% filter(Academic == "Non_Academicians") 
mean(edgeDS_verbosity_aca_n$Number.Characters)
[1] 2495.364

Source #1


Does the number of characters in the comments depend anyhow on person’s job title? Well, only slightly.

ggplotly(
  ggplot(edgeDS_verbosity, aes(Job_Title_S, Number.Characters)) + geom_boxplot() + 
    scale_y_continuous(breaks = seq(0,20000, by = 1000), limits = c(0,190000)) + 
    xlab("Job Title") + ylab("Number of characters") + 
    ggtitle("When graduate students write, then it is always quite a lot", 
            subtitle = "maybe there are some in NA or Other bins") +
    theme_minimal() + scale_fill_ptol() + coord_flip(ylim =c(0,6000))
) %>% layout(margin = list(l = 200))

Also, of those academic people, departments/fields they come from and work in - does it have any impact on how much they write?

ggplotly(
  ggplot(edgeDS_verbosity, aes(Department_S, Number.Characters)) + geom_boxplot() +
    coord_flip(ylim =c(0,45000)) +
    scale_y_continuous(breaks = seq(0,45000, by = 5000), limits = c(0,190000)) +
    xlab("Academic Department") + ylab("Number of characters") + 
    theme_minimal() + scale_fill_ptol() 
)

Discipline also seems to have an impact. The difference between “Professions” and “Other” (“NA”) is also quite significant.

ggplotly(
  ggplot(edgeDS_verbosity, aes(Discipline, Number.Characters)) + 
    geom_boxplot() + #coord_flip()  + 
    xlab("Academic Discipline") + ylab("Number of characters") + 
    scale_y_continuous(breaks = seq(0, 100000, by = 1000), limits = NA) + 
    coord_cartesian(ylim =c(0,10000)) +  
    stat_summary(fun.y=mean, fun.args = list(na.rm = F), 
                 na.rm = T, geom="point", size=2.5, color="green") +  
    ggtitle("Box Plot of number of characters by academic discipline", 
         subtitle = "Green Point shows an average/mean") +
    theme_minimal() + scale_fill_ptol()  
)

edgeDS_verbosity_disc_diff <- edgeDS_verbosity %>% 
  dplyr::ungroup() %>% 
  dplyr::select(Discipline, Number.Characters) %>% 
  dplyr::group_by(Discipline) %>% 
  dplyr::summarize(min_Number.Characters = min(Number.Characters), 
            #minDisciplineName = Discipline[which.min(Number.Characters)], 
            max_Number.Characters = max(Number.Characters), 
            #maxDisciplineName = Discipline[which.max(Number.Characters)],
            mean_Number.Characters = round(mean(Number.Characters, na.rm = T),2)
            ) %>% 
  dplyr::mutate(difference_max_min = max_Number.Characters-min_Number.Characters)

Source #1

Discipline min_Number.Characters max_Number.Characters mean_Number.Characters difference_max_min
Formal Sciences 13 28219 3003.34 28206
Humanities 4 56874 3251.17 56870
Natural Sciences 4 84762 4194.41 84758
Professions 11 87374 3972.31 87363
Social Sciences 3 118762 2891.57 118759
NA 3 91341 2335.37 91338

The Shanghai Ranking of their PhD Institution vs. number of characters they write. Like

  • 1 = university was ranked between 1 and 50

  • 2 = university was ranked between 51 and 100

  • etc.

ggplotly(
  ggplot(edgeDS_verbosity, aes(PhD_Institution_SR_Bin, Number.Characters)) + 
    geom_boxplot() +
    coord_cartesian(ylim =c(0,7000)) + 
    ggtitle("Shanghai Rankings of their PhD Institution")+
    scale_y_continuous(breaks = seq(0,10000, by = 500), limits = c(0,190000)) +
    theme_minimal() + scale_fill_ptol()
) %>% layout(xaxis = list(ticktext = c("1-50", "51-100", 
                          "101-150", "151-200", 
                          "201-300", "301-400", "401-510", "NA"), showgrid = F))

By AcademicHierarchyStrict:

ggplotly(
  ggplot(edgeDS_verbosity, aes(AcademicHierarchyStrict, Number.Characters)) + 
  geom_boxplot() +
  coord_cartesian(ylim =c(0,6000)) + 
  scale_y_continuous(breaks = seq(0,10000, by = 500), limits = c(0,190000)) +
  theme_minimal() + scale_fill_ptol()
) %>% layout(xaxis = list(title = "Academic Hierarchy", 
             ticktext = c("Graduate Student", "Postdoctoral", 
                          "Assistant Prof.", "Associate Prof.", 
                          "Professor", "Chaired Prof.", "NA"), showgrid = F))

More verbose when they have PhD? Yes!

ggplotly(
  ggplot(edgeDS_verbosity, aes(HavePhD, Number.Characters)) + geom_boxplot() +
    coord_cartesian(ylim =c(0,4000)) + 
    scale_y_continuous(breaks = seq(0,10000, by = 250), limits = c(0,190000)) +
    theme_minimal() + scale_fill_ptol()
) %>% layout(xaxis = list(title = "Are they Doctor of Philosophy?", 
                          ticktext = c("Dont have PhD", "Have PhD", "NA")))

How much people with/out PhD write on average?

edgeDS_verbosity_hphd_y <- edgeDS_verbosity %>% filter(HavePhD == 1)
mean(edgeDS_verbosity_hphd_y$Number.Characters)
[1] 3238.645
edgeDS_verbosity_hphd_n <- edgeDS_verbosity %>% filter(HavePhD == 0) 
mean(edgeDS_verbosity_hphd_n$Number.Characters)
[1] 2304.422

By Gender

ggplotly(
  ggplot(edgeDS_verbosity, aes(Gender, Number.Characters)) + geom_boxplot() +
    coord_cartesian(ylim =c(0,5000)) + 
    scale_y_continuous(breaks = seq(0,10000, by = 500), limits = c(0,190000)) +
    theme_minimal() + scale_fill_ptol()
) %>% layout(xaxis = list(title = "Gender", ticktext = c("Male", "Female", "NA")))

Role ?

ggplotly(
  ggplot(edgeDS_verbosity, aes(Role, Number.Characters)) + geom_boxplot() +
  coord_cartesian(ylim =c(0,5000)) + 
  scale_y_continuous(breaks = seq(0,10000, by = 500), limits = c(0,190000))
) %>% layout(xaxis = list(title = "Who were debaters?", ticktext = c("Author", "Commentator")))

The most comments are written when the debate size is below 200 people.

ggplot(edgeDS_verbosity, aes(DebateSize, Number.Characters)) +
    coord_cartesian(ylim =c(0,7000)) + 
    scale_y_continuous(breaks = seq(0,10000, by = 500), limits = c(0,190000)) +
    geom_boxplot(aes(group = cut_interval(DebateSize, 10)))


Create bins for h-index and i10-index (citations)

edgeDS_verbosity$hindex_bin <- cut(edgeDS_verbosity$H_Index, breaks=seq(0,150, by = 15), labels=c("0-15","15-30","30-45", "45-60", "60-75", "75-90", "90-105", "105-120", "120-135", "135-150"))

ggplotly(
  ggplot(edgeDS_verbosity, aes(hindex_bin, Number.Characters)) + 
    geom_boxplot() +
    coord_cartesian(ylim =c(0,7000)) + 
    scale_y_continuous(breaks = seq(0,10000, by = 500), limits = c(0,190000))
)

edgeDS_verbosity$i10_bin <- cut(edgeDS_verbosity$i10_Index, breaks=seq(0,600, by = 40))

ggplotly(
  ggplot(edgeDS_verbosity, aes(i10_bin, Number.Characters)) + geom_boxplot() +
    geom_boxplot() +
    coord_cartesian(ylim =c(0,13000)) +
    scale_y_continuous(breaks = seq(0,15000, by = 1000), limits = c(0,190000))
)
rm(edgeDS_verbosity_aca_n, edgeDS_verbosity_aca_y, df_annotationsForFacets, edgeDS_verbosity_hphd_y, 
   edgeDS_verbosity_disc_diff, edgeDS_verbosity_hphd_n, edgeDS_verbosity)

5.2 Compare higher status participants with all the rest.

5.2.1 Comparison #1: Top 100 in Academia with PhD

What I call “High Flyers” are somebody who is in Academia with PhD (from TOP 100 universities according to Shanghai Ranking and US News and World Reported - union) and where their university workplace was also ranked in TOP 100 (union).

high_flyers <- edgeDS %>% 
  filter(Academic == "Academicians" & HavePhD == 1) %>% 
  filter(PhD_Institution_SR_Bin %in% c(1,2) | PhD_Institution_US_IR_Bin %in% c(1,2)) %>% 
  filter(Workplace_SR_Bin %in% c(1,2) | Workplace_US_IR_Bin %in% c(1,2)) %>% 
  select(Year, Number.Characters) %>% 
  group_by(Year) %>% 
  summarise(Number.Characters = sum(Number.Characters)) %>% 
  mutate(type = "high_flyers")

high_flyers_oppo <- edgeDS %>% 
  filter(!(Academic == "Academicians" & HavePhD == 1)) %>% 
  filter(!(PhD_Institution_SR_Bin %in% c(1,2) | PhD_Institution_US_IR_Bin %in% c(1,2))) %>% 
  filter(!(Workplace_SR_Bin %in% c(1,2) | Workplace_US_IR_Bin %in% c(1,2))) %>% 
  write_csv("~/documents/R-github/Crowdsourcing_Data_Analysis_2_EDGE_org/high_flyers_oppo.csv") %>% 
  select(Year, Number.Characters) %>% 
  group_by(Year) %>% 
  summarise(Number.Characters = sum(Number.Characters)) %>% 
  mutate(type = "high_flyers_oppo")
  
df <- rbind(high_flyers,high_flyers_oppo )

After data are prepared, plot them now.

ggplot(df, aes(x=Year, y = Number.Characters, fill = as.factor(type))) + 
  geom_bar(position="dodge", stat="identity") + # geom_line(aes(color = as.factor(type))) +
  theme_minimal() + scale_fill_ptol() + 
  labs(fill = "Type", color = "Type") +
  scale_x_continuous(breaks = pretty(unique(df$Year), n = 19)) + 
  scale_y_continuous(breaks = seq(0,1000000, by = 50000), labels = comma) + 
  ggtitle("Cummulative sum of characters per year and group", 
          subtitle = "Except for a few years where it is almost equal or even higher, 
          high flyers comment much more than non-high-flyers.")


6 R Session/Devtools

sessionInfo()
R version 3.4.1 (2017-06-30)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 17.04

Matrix products: default
BLAS: /usr/lib/libblas/libblas.so.3.7.0
LAPACK: /usr/lib/lapack/liblapack.so.3.7.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods  
[8] base     

other attached packages:
 [1] rsconnect_0.8.4      bindrcpp_0.2         corrplot_0.77       
 [4] visdat_0.1.0         plotly_4.7.1         ggthemes_3.4.0      
 [7] GGally_1.3.2         gridExtra_2.2.1      kableExtra_0.3.0    
[10] devtools_1.13.3      moments_0.14         VIM_4.7.0           
[13] data.table_1.10.4    colorspace_1.3-2     scales_0.4.1.9002   
[16] reshape2_1.4.2       forcats_0.2.0        stringr_1.2.0       
[19] dplyr_0.7.2.9000     purrr_0.2.3          readr_1.1.1.9000    
[22] tidyr_0.6.3          tibble_1.3.3         ggplot2_2.2.1.9000  
[25] tidyverse_1.1.1.9000 rmarkdown_1.6.0.9001 knitr_1.16          

loaded via a namespace (and not attached):
 [1] nlme_3.1-131       bitops_1.0-6       pbkrtest_0.4-7    
 [4] lubridate_1.6.0    RColorBrewer_1.1-2 httr_1.2.1        
 [7] rprojroot_1.2      tools_3.4.1        backports_1.1.0   
[10] R6_2.2.2           lazyeval_0.2.0     mgcv_1.8-18       
[13] nnet_7.3-12        withr_2.0.0        sp_1.2-5          
[16] mnormt_1.5-5       compiler_3.4.1     rvest_0.3.2       
[19] quantreg_5.33      SparseM_1.77       xml2_1.1.1        
[22] labeling_0.3       DEoptimR_1.0-8     lmtest_0.9-35     
[25] psych_1.7.5        robustbase_0.92-7  digest_0.6.12     
[28] foreign_0.8-69     minqa_1.2.4        base64enc_0.1-3   
[31] pkgconfig_2.0.1    htmltools_0.3.6    boxes_0.0.0.9000  
[34] lme4_1.1-13        highr_0.6          htmlwidgets_0.9   
[37] rlang_0.1.1.9000   readxl_1.0.0       rstudioapi_0.6    
[40] shiny_1.0.3.9002   bindr_0.1          zoo_1.8-0         
[43] jsonlite_1.5       crosstalk_1.0.0    car_2.1-5         
[46] RCurl_1.95-4.8     magrittr_1.5       Matrix_1.2-10     
[49] Rcpp_0.12.12       munsell_0.4.3      stringi_1.1.5     
[52] yaml_2.1.14        RJSONIO_1.3-0      MASS_7.3-47       
[55] plyr_1.8.4         parallel_3.4.1     crayon_1.3.2.9000 
[58] lattice_0.20-35    haven_1.1.0        splines_3.4.1     
[61] hms_0.3            boot_1.3-20        codetools_0.2-15  
[64] clisymbols_1.2.0   glue_1.1.1         evaluate_0.10.1   
[67] laeken_0.4.6       modelr_0.1.1       vcd_1.4-3         
[70] httpuv_1.3.5       nloptr_1.0.4       MatrixModels_0.4-1
[73] cellranger_1.1.0   gtable_0.2.0       reshape_0.8.6     
[76] assertthat_0.2.0   mime_0.5           xtable_1.8-2      
[79] broom_0.4.2        e1071_1.6-8        class_7.3-14      
[82] viridisLite_0.2.0  memoise_1.1.0     
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgRWRnZS5vcmcgRGF0YSIKYXV0aG9yOiAiRE1QRSBAIEdpdEh1YiIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWIgJWQgJVknKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY3NzOiByZXBvcnRfc3R5bGVzLmNzcwogICAgaGlnaGxpZ2h0OiBoYWRkb2NrCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgc2VsZl9jb250YWluZWQ6IHllcwogICAgdGhlbWU6IHJlYWRhYmxlCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHllcwogICAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgICAgdG9jX2RlcHRoOiAzCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKKioqCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GfQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHJtYXJrZG93bikKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBjYWNoZSA9IFRSVUUpCmBgYAoKLSBZb3Ugc2hvdWxkIG9wZW4gdGhlIGZpbGUgaW4gYSBicm93c2VyIG90aGVyIHRoYW4gRmlyZWZveCAoc2ljISkgLSBNaWNyb3NvZnQgRWRnZSBpcyBmaW5lLiAKCi0gSW4gb3JkZXIgdG8gUiBOb3RlYm9vayBIVE1MIGZpbGUsIHlvdSBoYXZlIHRvIGV4ZWN1dGUgdGhpcyBSbWQgZmlsZSBpbiBpdHMgZGlyZWN0b3J5L2ZvbGRlciAtIG5vdCBpbiB0aGUgcm9vdCEgb2YgcmVwb3NpdG9yeSBgc2V0d2QoIi4uLi53aGVyZSBSbWQgaXMgbG9jYXRlZC4uLiIpICYmIHJtYXJrZG93bjo6cmVuZGVyKCJFZGdlLlJtZCIpYC4KCi0gVGhlICoqc291cmNlIGNvZGUqKiBmb3IgdGhpcyBSIE5vdGVib29rIGNhbiBiZSBmb3VuZCBhdCBHaXRIdWI6IDxodHRwczovL2dpdGh1Yi5jb20vZG1wZS9yPgoKKioqCgojIE9iamVjdGl2ZXMgLSBDcm93ZHNvdXJjaW5nIERhdGEgQW5hbHlzaXMgMgoKRGVzY3JpcHRpb24gc2V0IG91dCBpbiA8aHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vZG9jdW1lbnQvZC8xZlhRQkxkV3lkSVNza09LaG9xOGdsNXVudXdzdjdWQTNwa0tZNElXRlM2by9lZGl0Pi4KCkluIHNob3J0LCB0cnlpbmcgdG8gY29uZmlybSBvciByZWJ1dCBmb2xsb3dpbmc6Cgo+IEh5cG90aGVzaXMgMTogIkEgd29tYW4ncyB0ZW5kZW5jeSB0byBwYXJ0aWNpcGF0ZSBhY3RpdmVseSBpbiB0aGUgY29udmVyc2F0aW9uIGNvcnJlbGF0ZXMgcG9zaXRpdmVseSB3aXRoIHRoZSBudW1iZXIgb2YgZmVtYWxlcyBpbiB0aGUgZGlzY3Vzc2lvbi4iCgo+IEh5cG90aGVzaXMgMjogIkhpZ2hlciBzdGF0dXMgcGFydGljaXBhbnRzIGFyZSBtb3JlIHZlcmJvc2UgdGhhbiBhcmUgbG93ZXIgc3RhdHVzIHBhcnRpY2lwYW50cy4iCiAKV2hlbiBmaW5pc2hlZCwgcmVwb3J0IG15IHJlc3VsdHMgdXNpbmcgdGhpcyBzdXJ2ZXk6IDxodHRwczovL2VzbXQuYXoxLnF1YWx0cmljcy5jb20vamZlL2Zvcm0vU1ZfZWFPeUYwcTM5SjZDVktaPgoKKioqCgojIyBWYXJpYWJsZSBEZXNjcmlwdGlvbiBvZiBEYXRhCgoqKlR5cGUqKjogMSBmb3IgYW5udWFsIHF1ZXN0aW9uLCAyIGZvciBjb252ZXJzYXRpb24KCi0gRWRnZSBkb2VzIGFuIGFubnVhbCBxdWVzdGlvbiBldmVyeSB5ZWFyOyBzb21lIGV4YW1wbGVzIGFyZSAid2hhdCBzY2llbnRpZmljIGlkZWEgaXMgcmVhZHkgZm9yIHJldGlyZW1lbnQ/IiBhbmQgIldoYXQgd2lsbCBjaGFuZ2UgZXZlcnl0aGluZz8iIFBlb3BsZSB0aGVuIHdyaXRlIGluIHdpdGggdGhlaXIgYW5zd2Vycy4gU28gYWxsIG9mIHRoZSB0ZXh0IGlzCndyaXR0ZW4gYW5kIGFzeW5jaHJvbm91cwoKLSBXaGF0IEVkZ2UgcmVmZXJzIHRvIGFzIGEgY29udmVyc2F0aW9uIGNhbiBhY3R1YWxseSBiZSBtdWx0aXBsZSB0aGluZ3MuIFNvbWUgb2YgdGhlc2UgYXJlIHdyaXR0ZW4gZXNzYXlzIGJ5IGEgc2luZ2xlIHBlcnNvbiwgc29tZSBhcmUgdHJhbnNjcmlwdHMgb2YgYSBzcGVlY2gsIGFuZCBzb21lIGFyZSB0cmFuc2NyaXB0cyBvZiBhIGNvbnZlcnNhdGlvbiAoZWl0aGVyIGJldHdlZW4KdHdvIG9yIG1vcmUgZ3Vlc3RzIG9yIGFuIGludGVydmlldykuCgoqKkxpbWl0ZWRfSW5mb3JtYXRpb24qKiBpcyBkZXNjcmliZWQgYXM6IGVxdWFscyAxIGlmIHdlIGNvdWxkIG9ubHkgZmluZCBsaW1pdGVkIGluZm9ybWF0aW9uIGFib3V0IHRoZSBwZXJzb24gCihlLmcuIHRoZXkgY29tbWVudGVkIGluIDIwMTMgYnV0IHdlIG9ubHkgaGF2ZSB0aGVpciBqb2IgdGl0bGUgZnJvbSAyMDEyKSwgMCBvdGhlcndpc2UKCioqUm9sZSoqOiBFaXRoZXIgYXV0aG9yICg9MSkgb3IgY29tbWVudGF0b3IgKD0yKQoKKipGZW1hbGUgQ29udHJpYnV0aW9ucyoqOiB0aGUgbnVtYmVyIG9mIHRpbWVzIGEgd29tYW4gc3BlYWtzIGluIGEgc3BlY2lmaWMgY29udmVyc2F0aW9uLCBpdCBkb2VzIG5vdCBhbHdheXMgZXF1YWwgdGhlIG51bWJlciBvZiB1bmlxdWUgd29tZW4gaW4gYSBjb252ZXJzYXRpb24gKHNlZSBiZWxvdykKCioqRmVtYWxlIFBhcnRpY2lwYXRpb24qKjogc2ltcGx5IGZlbWFsZSBjb250cmlidXRvcnMvKG51bWJlciBvZiB0b3RhbCBjb250cmlidXRpb25zKTsgdGhlIHBlcmNlbnRhZ2Ugb2YgY29tbWVudHMgdGhhdCBhcmUgbWFkZSBieSBhIHdvbWFuCgoqKlVuaXF1ZSBDb250cmlidXRvcnMqKjogVW5pcXVlIE1hbGUgQ29udHJpYnV0b3JzICsgVW5pcXVlIEZlbWFsZSBDb250cmlidXRvcnMKCioqVW5pcXVlIE1hbGUgQ29udHJpYnV0b3JzKio6IHRoZSBudW1iZXIgb2YgdW5pcXVlIG1hbGUgY29udHJpYnV0b3JzIAoKKipVbmlxdWUgRmVtYWxlIENvbnRyaWJ1dG9ycyoqOiB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBmZW1hbGUgY29udHJpYnV0b3JzCgoqKlVuaXF1ZSBGZW1hbGUgUGFydGljaXBhdGlvbioqOiB0aGUgcGVyY2VudGFnZSBvZiB1bmlxdWUgZmVtYWxlIHBhcnRpY2lwYW50czsgVW5pcXVlIEZlbWFsZSBDb250cmlidXRvcnMgZGl2aWRlZCBieSBVbmlxdWUgQ29udHJpYnV0b3JzCgoqKkFjYWRlbWljKio6IDEgPSB0aGUgcGVyc29uIGlzIGluIGFjYWRlbWlhLCAwID0gdGhleSBhcmUgbm90CgoqKl9PdGhlcl8qKiBjb2x1bW5zIGFyZSBkZXNjcmliZWQgaW4gdGhlIGNvcnJlc3BvbmRpbmcgWyoqUERGKiogZmlsZV0oaHR0cHM6Ly9naXRodWIuY29tL2RtcGUvcikuIAoKKioqCgojIyBTZXR0aW5ncwoKWW91IGNhbiBjb250cm9sIHRoZSBkZWZhdWx0IGFwcGVhcmFuY2Ugd2l0aCBvcHRpb25zOgoKLSBgb3B0aW9ucyh0aWJibGUucHJpbnRfbWF4ID0gbiwgdGliYmxlLnByaW50X21pbiA9IG0pYDogaWYgdGhlcmUgYXJlIG1vcmUgdGhhbiBuIHJvd3MsIHByaW50IG9ubHkgdGhlIGZpcnN0IG0gcm93cy4gVXNlIGBvcHRpb25zKHRpYmJsZS5wcmludF9tYXggPSBJbmYpYCB0byBhbHdheXMgc2hvdyBhbGwgcm93cy4KCi0gYG9wdGlvbnModGliYmxlLndpZHRoID0gSW5mKWAgd2lsbCBwcmludCBhbGwgY29sdW1ucywgcmVnYXJkbGVzcyBvZiB0aGUgd2lkdGggb2YgdGhlIHNjcmVlbi4KCkZyb20gW3ZpZ25ldHRlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdGliYmxlL3ZpZ25ldHRlcy90aWJibGUuaHRtbCk6CgpgYGB7cn0KI29wdGlvbnModGliYmxlLnByaW50X21heCA9IEluZiwgdGliYmxlLndpZHRoID0gSW5mKQpzZXQuc2VlZCgxMjM0KQpgYGAKCioqKgoKIyMgTG9hZGluZyBsaWJyYXJpZXMKCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIGRhdGEgd3JhbmdsaW5nCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeSh0aWR5cikKCiMgaW1wdXRhdGlvbiAmIG1pc3NpbmduZXNzICsgb3RoZXIKI2xpYnJhcnkobWljZSkKI2xpYnJhcnkobWkpCiNsaWJyYXJ5KEFtZWxpYSkKbGlicmFyeShWSU0pCmxpYnJhcnkobW9tZW50cykKbGlicmFyeShkZXZ0b29scykKCiMgbWFya2Rvd24gUm1kICsgdGFibGUgc3R5bGluZwpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIGZvciBwbG90dGluZyAtIGFycmFuZ2luZy9wb3NpdGlvbmluZwpsaWJyYXJ5KGdyaWQpCmxpYnJhcnkoZ3JpZEV4dHJhKQoKIyBwbG90dGluZwpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeShwbG90bHkpCmxpYnJhcnkodmlzZGF0KQpsaWJyYXJ5KGNvcnJwbG90KQpgYGAKCioqKgoKIyMgUmVhZCBEYXRhCgpgYGB7ciwgZXZhbD1ULCBlY2hvPVQsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQplZGdlRFMgPC0gcmVhZF9jc3YoImVkZ2UxLjFFZGl0ZWRGaXhlZC5jc3YiLCBuYSA9IGMoIk5BIiwgIiIsICIgIiwgIiNOL0EiKSwgdHJpbV93cyA9IFQpCmBgYAoKKioqCgojIEZpcnN0IHNvbWUgcHJlLXByb2Nlc3NpbmcKCmBgYHtyfQp2aXNfZGF0KGVkZ2VEU1ssMTo3MF0sIHdhcm5fbGFyZ2VfZGF0YSA9IEYpCmBgYAoKIyMgRGVhbCB3aXRoIGRhdGEgcHJvYmxlbXMKCmBgYHtyLCBldmFsPVQsIGVjaG89VH0KIyBwcmludChwcm9ibGVtcyhlZGdlRFMpKQoKIyBJIGNhbiBlaXRoZXIgZGVsZXRlIG9yIGZpeCByb3cgbm8uIDE4MTcgYmVjYXVzZSBpdCBpcyBicm9rZW4gbWVzcy4gSSBmaXhlZCBpdCBpbiBjc3YuIAojIGVkZ2VEUyA8LSBlZGdlRFNbLWMoMTgxNyksXQoKIyBSZXBsYWNlICdOb3QgQXZhaWxhYmxlJyAmICdQZW5kaW5nJyB3aXRoIE5BCmVkZ2VEUyRQaERfWWVhcltlZGdlRFMkUGhEX1llYXIgPT0gIk5vdCBBdmFpbGFibGUiXSA8LSBOQQplZGdlRFMkUGhEX1llYXJbZWRnZURTJFBoRF9ZZWFyID09ICJQZW5kaW5nIl0gPC0gTkEKCiMgQWhhLi4uCmVkZ2VEUyRBY2FkZW1pY1tlZGdlRFMkSWQgPT0gImRhdmlkX2NfZ2VhcnkiXSA8LSAxCgojR2VuZGVyIElzc3VlcwplZGdlRFMkTWFsZVtlZGdlRFMkSWQgPT0gImJlbmVkaWN0X2NhcmV5Il0gPC0gMQplZGdlRFMkRmVtYWxlW2VkZ2VEUyRJZCA9PSAiYmVuZWRpY3RfY2FyZXkiXSA8LSAwCmBgYAoqKioKCiMjIE1pc3NpbmcgdmFsdWVzCgpOdW1iZXIgb2Ygcm93cyB0aGF0IGhhdmUgc29tZSBtaXNzaW5nIHZhbHVlczoKCmBgYHtyfQptaXNzaW5nX2RhdGEgPC0gZWRnZURTWyFjb21wbGV0ZS5jYXNlcyhlZGdlRFMpLF0KbnJvdyhtaXNzaW5nX2RhdGEpIApgYGAKCkxpc3QgdmFyaWFibGVzIHdpdGggbW9zdCBtaXNzaW5nIHZhbHVlczogNDEgaGF2ZSBzb21lIG1pc3NpbmcgdmFsdWVzCgpgYGB7ciwgcm93cy5wcmludD0xMH0KIyBkZWxldGUgdGhvc2UgY29sdW1ucyB3aGljaCBjb250YWluLi4uCm1pcyA8LSBlZGdlRFNbLCAtZ3JlcCgiZHVtbXl8VW5pcXVlfENvbnRyaWJ1dGlvbnN8TnVtZXJhbHMiLCBjb2xuYW1lcyhlZGdlRFMpKV0KCmFycmFuZ2UoYWdncihtaXMsIGNvbD1tZGMoMToyKSwgbnVtYmVycz1UUlVFLCBzb3J0VmFycz1UUlVFLCBsYWJlbHM9bmFtZXMobWlzKSwgCiAgICAgICAgY2V4LmF4aXMgPSAuNCwgZ2FwPTMsIHByb3AgPSBGLCBwbG90ID0gRikkbWlzc2luZ3MsIGRlc2MoQ291bnQpKVsxOjQzLCBdCmBgYAoKYGBge3IsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9CmFnZ3IobWlzWywgMTo5MF0sIGNvbD1tZGMoMToyKSwgbnVtYmVycz1UUlVFLCBzb3J0VmFycz1UUlVFLCBsYWJlbHM9bmFtZXMobWlzKSwgCiAgICAgY2V4LmF4aXM9LjQsIGdhcD0zLCBwcm9wID0gRiwgcGxvdCA9IFQpCm1pc3NtYXAobWlzKQpoZWFkKG1kLnBhdHRlcm4obWlzKSkKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpybShtaXMsIG1pc3NpbmdfZGF0YSkKYGBgCgoqKioKCiMjIEFwcGx5IGZhY3RvcnMgdG8gdmFyaW91cyBjb2x1bW5zIHdoZXJlIGl0IG1ha2VzIHNlbnNlCgpBbmQgcmVuYW1lIHZhcmlhYmxlIGBBY2FkZW1pY2AgZnJvbSAwLzEgdG8gbW9yZSBkZXNjcmlwdGl2ZSBOb25fQWNhZGVtaWNpYW5zL0FjYWRlbWljaWFucwoKYGBge3J9CmNvbHMgPC0gYygiVHlwZSIsICJMaXZlIiwgIlJvbGUiLCAiVHdvQXV0aG9ycyIsICJMaW1pdGVkX0luZm9ybWF0aW9uIiwgCiAgICAgICAgICAiRmVtYWxlIiwgIk1hbGUiLCAiQWNhZGVtaWMiLCAiSm9iX1RpdGxlX1MiLCAiSm9iX1RpdGxlX1NfbnVtIiwgCiAgICAgICAgICAiRGVwYXJ0bWVudF9TIiAsIkRlcGFydG1lbnRfU19udW0iICwiRGlzY2lwbGluZSIsICJIYXZlUGhEIiwgCiAgICAgICAgICAiQXV0aG9yQW5kQ29tbWVudGVyIiwgIlBoRF9JbnN0aXR1dGlvbl9TUl9CaW4iLCAiV29ya3BsYWNlX1NSX0JpbiIsIAogICAgICAgICAgIlNSX1JhbmtpbmdfRGlmIiwgIlBoRF9JbnN0aXR1dGlvbl9VU19JUl9CaW4iLCAiV29ya3BsYWNlX1VTX0lSX0JpbiIsIAogICAgICAgICAgIlVTQV9JX1JhbmtpbmdfRGlmIiwgIlBoRF9JbnN0aXR1dGlvbl9VU19CaW4iLCAiV29ya3BsYWNlX1VTX0JpbiIsIAogICAgICAgICAgIlVTQV9SYW5raW5nX0RpZiIsICJBY2FkZW1pY0hpZXJhcmNoeVN0cmljdCIpCgplZGdlRFNbY29sc10gPC0gbGFwcGx5KGVkZ2VEU1tjb2xzXSwgZmFjdG9yKQpgYGAKClRyYW5zZm9ybSB0d28gdmFyaWFibGVzIGZyb20gKipmYWN0b3IqKiB0byAqKmNoYXJhY3RlcioqIHRvIGdpdmUgdGhlbSBtb3JlIG1lYW5pbmcgKHNpbWlsYXIgdG8gYWJvdmUpLgoKYGBge3J9CmVkZ2VEUyRBY2FkZW1pYyA8LSByZWNvZGUoZWRnZURTJEFjYWRlbWljLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSAiQWNhZGVtaWNpYW5zIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgYDBgID0gIk5vbl9BY2FkZW1pY2lhbnMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9ICJVbmtub3duIikKCmVkZ2VEUyRHZW5kZXIgPC0gcmVjb2RlKGVkZ2VEUyRGZW1hbGUsIAogICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSAiRmVtYWxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGAwYCA9ICJNYWxlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgIC5kZWZhdWx0ID0gIlVua25vd24iKQpgYGAKCkRyb3Agbm93IGZlbWFsZSAmIG1hbGUgY29sdW1ucyBhbmQgcmVvcmRlciBkYXRhIGZyYW1lLgoKYGBge3J9CmVkZ2VEUyA8LSBlZGdlRFNbLCAhKG5hbWVzKGVkZ2VEUykgJWluJSBjKCJGZW1hbGUiLCAiTWFsZSIpKV0KZWRnZURTIDwtIGVkZ2VEU1ssIGMoMSwyLDMsNCw1LDE4NSw2OjE4NCldCmBgYAoKUG90ZW50aWFsbHksIHRyYW5zZm9ybSB5ZWFyIChkbyBub3QgZXZhbHVhdGUgdGhvdWdoKQoKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0KbnVtVG9DaGFyIDwtIGZ1bmN0aW9uKHgpIHsgdXggPSB1bmlxdWUoeCk7IGZvcm1hdEModXgpW21hdGNoKHgsIHV4KV0gfQplZGdlRFMkWWVhciA8LSB5ZWFyKGFzLkRhdGUobnVtVG9DaGFyKGVkZ2VEUyRZZWFyKSwgIiVZIikpCmBgYAoqKioKIyMgU2hvdyBkYXRhCgpXaGF0IGlzIHRoZSBzdHJ1Y3R1cmUgb2YgZGF0YXNldD8KCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0Kc3RyKGVkZ2VEU1ssNToxNV0pCnZpc19kYXQoZWRnZURTWywxOjcwXSwgd2Fybl9sYXJnZV9kYXRhID0gRikKYGBgCgpEbyBub3QgZXZhbHVhdGUgY29kZSBiZWxvdyBiZWNhdXNlIHRoZSBvdXRwdXQgd291bGQgYmUgdG9vIGxhcmdlLiAKCmBgYHtyLGV2YWw9RkFMU0UsIGVjaG89VH0KaGVhZChlZGdlRFMpCnN1bW1hcnkoZWRnZURTKSAjIHByaW50IHN1bW1hcmllcyBvZiBlYWNoIHZhcmlhYmxlCmBgYAoqKioKIyBNeSBvd24gcXVlc3Rpb25zCgojIyBIb3cgbWFueSB0aW1lcyBjYW4gYSBzcGVjaWZpYyBudW1iZXIgb2YgY2hhcmFjdGVycyBiZSBvYnNlcnZlZD8KCioqQnV0IGZpcnN0KiogdGFrZSBhIGJyb2FkZXIgbG9vayBvbiB0aGUgZGF0YXNldC4gYHRhaWwoKWAvYGhlYWQoKWAgd2lsbCByZXBvcnQgKGkuZS4gcHJpbnQpIG9ubHkgbGFzdC9maXJzdCA2IHZhbHVlcy4gCgpXaG8gaGFzIGNvbnRyaWJ1dGVkIHRoZSBtb3N0IGluIGFsbCBkaXNjdXNzaW9ucz8KCmBgYHtyfQp0YWlsKHNvcnQodGFibGUoZWRnZURTJElkKSkpIApgYGAKCkhvdyBtYW55IHVuaXF1ZSBwYXJ0aWNpcGFudHMgYXJlIHRoZXJlPwoKYGBge3J9Cmxlbmd0aCh1bmlxdWUoZWRnZURTJElkKSkgCmBgYAoKQW5kIG92ZXJhbGwgbnVtYmVyIG9mIHVuaXF1ZSB2YWx1ZXMgcGVyIGVhY2ggdmFyaWFibGUgKHByaW50ZWQgb25seSBmaXJzdCBhbmQgbGFzdCA2KT8gCgpgYGB7ciBlY2hvPUZBTFNFfQprYWJsZShoZWFkKHJhcHBseShlZGdlRFMsZnVuY3Rpb24oeClsZW5ndGgodW5pcXVlKHgpKSkpLCAiaHRtbCIpICU+JSAKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygiaG92ZXIiLCAiY29uZGVuc2VkIiksIGZ1bGxfd2lkdGggPSBGKQoKa2FibGUodGFpbChyYXBwbHkoZWRnZURTLGZ1bmN0aW9uKHgpbGVuZ3RoKHVuaXF1ZSh4KSkpKSwgImh0bWwiKSAlPiUgCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoImhvdmVyIiwgImNvbmRlbnNlZCIpLCBmdWxsX3dpZHRoID0gRikKYGBgCgpBbmQgaGV5LCBsb29rLCB0aGF0J3MgKippbnRlcmVzdGluZyoqLiBXaGlsZSB0aGVyZSBhcmUganVzdCA1MjIgdW5pcXVlIHRpdGxlcywgdGhlcmUgYXJlIDUyMyB1bmlxdWUgbGlua3MuIFVzaW5nIGBjb3VudGAgZnVuY3Rpb24sIEkgc2hvdyBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIChpLmUuIGxpbmtzKSBwZXIgdGl0bGUuIAoKQW5kIGluZGVlZCwgdGhlcmUgYXJlIHR3byBzYW1lIHRpdGxlcyBmb3IgZGlmZmVyZW50IEVER0UncyBjb252ZXJzYXRpb25zLiBbUHJlZmFjZSBmcm9tIDIwMTFdKGh0dHBzOi8vd3d3LmVkZ2Uub3JnL2NvbnZlcnNhdGlvbi9wcmVmYWNlKSBhbmQgW1ByZWZhY2UgZnJvbSAyMDA4XShodHRwczovL3d3dy5lZGdlLm9yZy9jb252ZXJzYXRpb24vcHJlZmFjZS1vZi13aGF0cy1uZXh0KS4KCmBgYHtyfQpjb3VudChlZGdlRFMsIFRpdGxlLCBMaW5rKVszMDQ6MzA1LCBdCmNvdW50X251bWJlck9mQ2hhcnNfc21hbGwgPC0gYXJyYW5nZShjb3VudChlZGdlRFMsIE51bWJlci5DaGFyYWN0ZXJzKVssIGMoMiwxKV0sIGRlc2MobikpWzE6MjAsXQpjb3VudF9udW1iZXJPZkNoYXJzIDwtIGFycmFuZ2UoY291bnQoZWRnZURTLCBOdW1iZXIuQ2hhcmFjdGVycylbLCBjKDIsMSldLCBkZXNjKG4pKQpgYGAKCk1vcmVvdmVyLCBvdXQgb2YgYWxtb3N0IGByIG5yb3coZWRnZURTKWAgb2JzZXJ2YXRpb25zLCBJIGNhbiBzZWUgdGhhdCAqKmByIHBlcmNlbnQobGVuZ3RoKGNvdW50X251bWJlck9mQ2hhcnMkbltjb3VudF9udW1iZXJPZkNoYXJzJG4gPT0gMV0pL25yb3coZWRnZURTKSlgKiogb2YgY29tbWVudHMgaGF2ZSBhIGxlbmdodCBvZiAqKjEqKi4KCkFub3RoZXIgKipgciBwZXJjZW50KGxlbmd0aChjb3VudF9udW1iZXJPZkNoYXJzJG5bY291bnRfbnVtYmVyT2ZDaGFycyRuID09IDJdKS9ucm93KGVkZ2VEUykpYCoqIG9mIGNvbW1lbnRzIGhhdmUgYSBjaGFyYWN0ZXIgbGVuZ2h0IG9mICoqMioqLgoKYGBge3J9CmthYmxlKGhlYWQoY291bnRfbnVtYmVyT2ZDaGFyc19zbWFsbCwgMTApLCAiaHRtbCIsCiAgICAgIGNvbC5uYW1lcyA9IGMoIk51bWJlciBvZiBjb21tZW50cy4uLiIsICJ0aGF0IGhhdmUgY2hhciBsZW5naHQgb2YuLi4iKSkgJT4lIAogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJob3ZlciIsICJjb25kZW5zZWQiKSwgZnVsbF93aWR0aCA9IEYpCmBgYAoKVGhlIG1vc3QgY29tbW9uIGxlbmd0aCBvZiBhIGNvbW1lbnQgaXMgYHIgYXMubnVtZXJpYyhjb3VudF9udW1iZXJPZkNoYXJzWzEsMl0pYCB3aGljaCBvY2N1cnMgaW4gYHIgYXMubnVtZXJpYyhjb3VudF9udW1iZXJPZkNoYXJzWzEsMV0pYCBjb21tZW50cy4KCioqKgoKQSA8c3Ryb25nPipwYXJhbGxlbCBjb29yZGluYXRlIHBsb3QqPC9zdHJvbmc+IHNob3dzIGhvdyBtYW55IHRpbWVzIGNhbiBhIHNwZWNpZmljIG51bWJlciBvZiBjaGFyYWN0ZXJzIGJlIG9ic2VydmVkLiBIZXJlIGFyZSBvbmx5IDIwIHZlcnRpY2VzIC0gImNvbm5lY3Rpb25zIi4gSSBsZXQgdGhlIHVzZXIgZmlndXJlIG91dCB3aGF0IGlzIG5pY2VyIGFuZCBtb3JlIHVuZGVyc3RhbmRhYmxlIC0gSSBsaWtlIHRoZSBmaXJzdCBvbmUgbW9yZS4KCmBgYHtyIGV2YWw9VCwgZWNobz1ULCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNSwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CnAxIDwtIGdncGFyY29vcmQoZGF0YSA9IGNvdW50X251bWJlck9mQ2hhcnNfc21hbGwsIGNvbHVtbnMgPSBjKDEsIDIpLCBzY2FsZSA9ICJnbG9iYWxtaW5tYXgiKSArIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCw2MCwgYnk9MiksIAogICAgICAgICAgICAgICAgICAgICBzZWMuYXhpcyA9IHNlY19heGlzKH4uLCBuYW1lID0gIk51bWJlciBvZiBjaGFyYWN0ZXJzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsNjAsIGJ5PTUpKSkgKyAKICBsYWJzKHkgPSAiTnVtYmVyIG9mIG9jY3VycmVuY2VzIiwgeCA9ICIiLCAKICAgICAgIHRpdGxlID0gIlRPUCAyMCBjb25uZWN0aW9ucyAtIGZyb20gIyBvZiBjb21tZW50cyB0byBsZW5ndGggb2YgY29tbWVudHMiKSArCiAgc2NhbGVfZmlsbF9wdG9sKCkgKyAKICB0aGVtZV9taW5pbWFsKCkgKyAKICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCkpICsgCiAgZ2VvbV9zZWdtZW50KG1hcHBpbmcgPSBhZXMoeCA9IDEsIHkgPSBuLCB4ZW5kID0gMiwgeWVuZD0gTnVtYmVyLkNoYXJhY3RlcnMpLCAKICAgICAgICAgICAgICAgaW5oZXJpdC5hZXMgPSBGLCAKICAgICAgICAgICAgICAgZGF0YSA9IGNvdW50X251bWJlck9mQ2hhcnNfc21hbGwsIAogICAgICAgICAgICAgICBhcnJvdz1hcnJvdyhsZW5ndGg9dW5pdCgwLjIsImNtIikpKQoKcDIgPC0gZ2dwYXJjb29yZChkYXRhID0gY291bnRfbnVtYmVyT2ZDaGFyc19zbWFsbCwgY29sdW1ucyA9IGMoMiwgMSksIHNjYWxlID0gImdsb2JhbG1pbm1heCIpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDYwLCBieT0yKSwgCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXMofi4sIG5hbWUgPSAiTnVtYmVyIG9mIG9jY3VycmVuY2VzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsNjAsIGJ5PTUpKSkgKyAKICBsYWJzKHkgPSAiTnVtYmVyIG9mIGNoYXJhY3RlcnMiLCB4ID0gIiIsIAogICAgICAgdGl0bGUgPSAiVE9QIDIwIGNvbm5lY3Rpb25zIC0gZnJvbSBsZW5ndGggb2YgY29tbWVudHMgdG8gIyBvZiBjb21tZW50cyIpICsKICBzY2FsZV9maWxsX3B0b2woKSArIAogIHRoZW1lX21pbmltYWwoKSArIAogIHRoZW1lKGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkgKyAKICBnZW9tX3NlZ21lbnQobWFwcGluZyA9IGFlcyh4ID0gMSwgeSA9IE51bWJlci5DaGFyYWN0ZXJzLCB4ZW5kID0gMiwgeWVuZD1uICksIAogICAgICAgICAgICAgICBpbmhlcml0LmFlcyA9IEYsIAogICAgICAgICAgICAgICBkYXRhID0gY291bnRfbnVtYmVyT2ZDaGFyc19zbWFsbCwgCiAgICAgICAgICAgICAgIGFycm93PWFycm93KGxlbmd0aD11bml0KDAuMSwiY20iKSkpCmdyaWQuYXJyYW5nZShwMSwgcDIsIG5jb2w9MikKYGBgCgpbU291cmNlIDFdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8yNzg2MjE0OSkgLyBbU291cmNlIDJdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8yOTMxMDczOCkgLyBbR0dQbG90MiAtIGdlb21fc2VnbWVudF0oaHR0cDovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2VvbV9zZWdtZW50Lmh0bWwpCgoqKioKCiMjIFJlbGF0aW9uc2hpcCBiZXR3ZWVuIGRlYmF0ZSBzaXplIGFuZCBhY2FkZW1pY2lhbnMuCgpOYW1lbHksIHdoYXQgaXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG51bWJlciBvZiBhbGwgZGViYXRlcnMgYW5kIGEgZ3JvdXAgb2YgYWNhZGVtaWNpYW5zIG92ZXIgdGhlIHllYXJzPwpEaWQgaXQgbWVhbiB0aGF0IGlmIHlvdSBwYXJ0aWNpcGF0ZWQgYXMgYW4gYWNhZGVtaWNpYW4gaW4gdGhlIGNvbnZlcnNhdGlvbnMsIHRoZSBkZWJhdGUgc2l6ZSB3YXMgYWxzbyBpbmNyZWFzaW5nPyAKCkxldCdzIGZpbmQgaXQgb3V0IDopIEZpcnN0LCBob3dldmVyLCBwcmVwYXJlIHRoZSBkYXRhc2V0LgoKYGBge3J9CmVkZ2VEU19hY2FkZW1pY2lhbnNJbkRlYmF0ZXMgPC0gZWRnZURTICU+JSAKICBmaWx0ZXIoVHlwZSA9PSAyKSAlPiUgIyBqdXN0ICJjb252ZXJzYXRpb25zIiAobm90IGFubnVhbCBxdWVzdGlvbnMpIHdyaXR0ZW4gYnkgZWl0aGVyIDEgb3IgMiBhdXRob3JzCiAgc2VsZWN0KFllYXIsIFRocmVhZElkLCBEZWJhdGVTaXplLCBBY2FkZW1pYykgJT4lIAogIGdyb3VwX2J5X2FsbCgpICU+JSAKICB0YWxseSAlPiUgCiAgc3ByZWFkKEFjYWRlbWljLCBuLCBmaWxsID0gMCkKICAKY29sbmFtZXMoZWRnZURTX2FjYWRlbWljaWFuc0luRGViYXRlcylbNF0gPC0gIk51bWJlck9mX05vbl9BY2FkZW1pY2lhbnMiCmNvbG5hbWVzKGVkZ2VEU19hY2FkZW1pY2lhbnNJbkRlYmF0ZXMpWzVdIDwtICJOdW1iZXJPZl9BY2FkZW1pY2lhbnMiCmNvbG5hbWVzKGVkZ2VEU19hY2FkZW1pY2lhbnNJbkRlYmF0ZXMpWzZdIDwtICJVbmtub3duIgpgYGAKCmBgYHtyIGVjaG89RkFMU0V9CmthYmxlKGhlYWQoZWRnZURTX2FjYWRlbWljaWFuc0luRGViYXRlcywgMyksICJodG1sIikgJT4lIAogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJob3ZlciIsICJjb25kZW5zZWQiKSwgZnVsbF93aWR0aCA9IEYpICMgdGFibGUgc25pcHBldApgYGAKCltTb3VyY2UgZm9yIHRhbGx5ICYgc3ByZWFkIGNvZGVdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS80MTczNTcyMSkKCioqKgoKSG93IGRvZXMgZGViYXRlIHNpemUgcmVsYXRlIHRvIHRoZSBudW1iZXIgb2YgYWNhZGVtaWNpYW5zPyBJIG1ha2UgYSBzaW1wbGUgbGluZWFyIHJlZ3Jlc3Npb24gdG8gZmluZCBvdXQuIAoKYGBge3J9CmxtX2FjYV9kZWIgPC0gbG0oRGViYXRlU2l6ZSB+IE51bWJlck9mX0FjYWRlbWljaWFucywgZGF0YSA9IGVkZ2VEU19hY2FkZW1pY2lhbnNJbkRlYmF0ZXMpCnN1bW1hcnkobG1fYWNhX2RlYikKYGBgCgpUaGUgbWVhbiBkZWJhdGUgc2l6ZSB3aWxsIGdyb3cgYnkgYHIgbG1fYWNhX2RlYiRjb2VmZmljaWVudHNbMl1gIGFzIHRoZSBudW1iZXIgb2YgYWNhZGVtaWNpYW5zIGluY3JlYXNlcyBieSAxLiAKSWYgdGhlcmUgYXJlIHplcm8gYWNhZGVtaWNpYW5zLCB0aGUgZGViYXRlIHNpemUgcHJlZGljdHMgdG8gYmUgYHIgbG1fYWNhX2RlYiRjb2VmZmljaWVudHNbMV1gLiAKWyhIZXJlIGlzIG5pY2UgYXJ0aWNsZSBvbiBob3cgdG8gaW50ZXJwcmV0IExNKV0oaHR0cHM6Ly9vbmxpbmVjb3Vyc2VzLnNjaWVuY2UucHN1LmVkdS9zdGF0NTAxL25vZGUvMjUyKQoKKioqCgpOb3csIHN1bW1hcml6ZSBudW1iZXIgb2YgYWNhZGVtaWNpYW5zIGJ5IHllYXIgKGZyb20gYWxsIGNvbnZlcnNhdGlvbnMpLgoKYGBge3J9CnllYXJfYWNhX3N1bSA8LSBlZGdlRFNfYWNhZGVtaWNpYW5zSW5EZWJhdGVzWyxjKDEsMyw1KV0gJT4lIAogIGdyb3VwX2J5KFllYXIpICU+JSAKICBzdW1tYXJpc2UoRGViYXRlU2l6ZSA9IHN1bShEZWJhdGVTaXplKSwKICAgICAgICAgICAgTnVtYmVyT2ZfQWNhZGVtaWNpYW5zX2FsbCA9IHN1bShOdW1iZXJPZl9BY2FkZW1pY2lhbnMpLCAKICAgICAgICAgICAgUHJvcG9ydGlvbiA9IE51bWJlck9mX0FjYWRlbWljaWFuc19hbGwvRGViYXRlU2l6ZSkKYGBgCgpgYGB7ciBlY2hvPUZBTFNFfQprYWJsZShoZWFkKHllYXJfYWNhX3N1bSwgMyksICJodG1sIikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoImhvdmVyIiwgImNvbmRlbnNlZCIpLCBmdWxsX3dpZHRoID0gRikKYGBgCgpgYGB7ciBlY2hvPUZBTFNFLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNX0KZzMgPC0gZ2dwbG90KHllYXJfYWNhX3N1bSwgYWVzKHggPSBZZWFyLCB5ID0gTnVtYmVyT2ZfQWNhZGVtaWNpYW5zX2FsbCkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFQsIHNob3cubGVnZW5kID0gVFJVRSwgc3BhbiA9IDAuMykgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwcmV0dHkoeWVhcl9hY2Ffc3VtJFllYXIsIG4gPSAxOSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gcHJldHR5KHllYXJfYWNhX3N1bSROdW1iZXJPZl9BY2FkZW1pY2lhbnNfYWxsLCAyMCkpICsgCiAgc2NhbGVfZmlsbF9wdG9sKCkgKyB0aGVtZV9taW5pbWFsKCkgKwogIGdndGl0bGUoIk51bWJlciBvZiBhY2FkZW1pY2lhbnMgaW4gYWxsIGNvbnZlcnNhdGlvbnMgcGVyIFllYXIiLCAKICAgICAgICAgIHN1YnRpdGxlID0gIkhhcyB2ZXJ5IHNtYWxsIGdyb3dpbmcgdGVuZGVuY3kuIikgKyAKICB5bGFiKCJOdW1iZXIgb2YgQWNhZGVtaWNpYW5zIikgCgpnNCA8LSBnZ3Bsb3QoeWVhcl9hY2Ffc3VtLCBhZXMoeCA9IFllYXIsIHkgPSBQcm9wb3J0aW9uKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVCwgc2hvdy5sZWdlbmQgPSBUUlVFLCBzcGFuID0gMC4zKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHByZXR0eSh5ZWFyX2FjYV9zdW0kWWVhciwgbiA9IDE5KSkgKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBwcmV0dHkoeWVhcl9hY2Ffc3VtJFByb3BvcnRpb24sIDEwKSkgKyAKICBzY2FsZV9maWxsX3B0b2woKSArIHRoZW1lX21pbmltYWwoKSArCiAgZ2d0aXRsZSgiUHJvcG9ydGlvbiBvZiBhY2FkZW1pY2lhbnMgaW4gZGViYXRlcyIsIAogICAgICAgICAgc3VidGl0bGUgPSAiYnkgeWVhci4gSGFzIGdyb3duIG92ZXIgdGhlIHllYXJzIHF1aXRlIHNpZ25pZmljYW50bHkuIikgKyAKICB5bGFiKCJOdW1iZXIgb2YgQWNhZGVtaWNpYW5zL0RlYmF0ZSBTaXplIikgCgpncmlkLmFycmFuZ2UoZzMsIGc0LCBuY29sPTIpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0UsIGVjaG89RiwgZXZhbD1GfQojIEFuZCBwZXJjZW50YWdlcz8KcGVyY2FudGFnZSA8LSBwZXJjZW50KHllYXJfYWNhX3N1bSROdW1iZXJPZl9BY2FkZW1pY2lhbnNfYWxsIC8geWVhcl9hY2Ffc3VtJERlYmF0ZVNpemUpCnByb3BvcnRpb25zX2luX2RlYmF0ZXMgPC0gY2JpbmQoeWVhcl9hY2Ffc3VtJFllYXIsIHBlcmNhbnRhZ2UpCnRhaWwocHJvcG9ydGlvbnNfaW5fZGViYXRlcykgIyBzaG93IHBlcmNlbnRhZ2VzIGZyb20gcmVjZW50IHllYXJzCmBgYAogICAgCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9RiwgZXZhbD1GLCBlY2hvPUZ9Cj4gUmVzaWR1YWxzIGFyZSBub3Qgc3ltbWV0cmljYWwgYW5kICJ0aGF0IG1lYW5zIHRoYXQgdGhlIG1vZGVsIHByZWRpY3RzIGNlcnRhaW4gcG9pbnRzIHRoYXQgZmFsbCBmYXIgYXdheSBmcm9tIHRoZSBhY3R1YWwgb2JzZXJ2ZWQgcG9pbnRzIi4gW1NvdXJjZV0oaHR0cHM6Ly9mZWxpcGVyZWdvLmdpdGh1Yi5pby9ibG9nLzIwMTUvMTAvMjMvSW50ZXJwcmV0aW5nLU1vZGVsLU91dHB1dC1Jbi1SKQoKPiBUaGUgbW9kZWwgZG9lc250IGZpdCB3ZWxsIHRoZSBhY3R1YWwgZGF0YS4gUl4yIGlzIGxvdywgaGVuY2UgY29ycmVsYXRpb24gaXMgYWxzbyBsb3cgLSBvZiBqdXN0IGByIHBlcmNlbnQoc3VtbWFyeSh5ZWFyX2FjYV9zdW1fbG0pJHIuc3F1YXJlZClgCmBgYAoKKioqCgojIyBXaGF0IGlzIHByb3BvcnRpb24gb2YgY29udHJpYnV0b3JzIGluIGRlYmF0ZXM/CgpMZXQncyBub3cgbG9vayBvbiBob3cgZGlmZmVyZW50IGdyb3VwcyBjb250cmlidXRlIGluIGRlYmF0ZXMuCgpGaXJzdCwgSSBzdGFydCB3aXRoIChub24tKWFjYWRlbWljaWFucyBhbmQgaGVuY2UgbmVlZCB0aGUgcmlnaHQgZGF0YS4KCmBgYHtyfQp5ZWFyX2FjYV9ieUdyb3VwIDwtIGVkZ2VEU19hY2FkZW1pY2lhbnNJbkRlYmF0ZXNbLGMoMSwzLDQsNSw2KV0gJT4lIAogIGdyb3VwX2J5KFllYXIpICU+JSAKICBzdW1tYXJpc2UoRGViYXRlU2l6ZSA9IHN1bShEZWJhdGVTaXplKSwgCiAgICAgICAgICAgIEFjYWRlbWljaWFucyA9IHN1bShOdW1iZXJPZl9BY2FkZW1pY2lhbnMpLCAKICAgICAgICAgICAgTm9uX0FjYWRlbWljaWFucyA9IHN1bShOdW1iZXJPZl9Ob25fQWNhZGVtaWNpYW5zKSwgCiAgICAgICAgICAgIFVua25vd24gPSBzdW0oVW5rbm93bikpCmBgYAoKYGBge3IgZWNobz1GQUxTRX0Ka2FibGUoaGVhZCh5ZWFyX2FjYV9ieUdyb3VwKSwgImh0bWwiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygiaG92ZXIiLCAiY29uZGVuc2VkIiksIGZ1bGxfd2lkdGggPSBGKQpgYGAKCkNsZWFybHksICoqYWNhZGVtaWNpYW5zIHByZXZhaWwgaW4gbWFqb3JpdHkqKiBvZiBkZWJhdGVzIGFzIHRoZSBudW1iZXIgb2Ygb3V0c2lkZXJzIChub24tYWNhICsgdW5rbm93bikgZGVjbGluZWQgCnNpZ25pZmljYW50bHkgb3ZlciBsYXN0IGZldyB5ZWFycy4gCgpBbHNvLCB0aGUgbnVtYmVyIG9mIHBhcnRpY2lwYW50cyBpbiBkZWJhdGVzIGRvZXMgbm90IGdyb3cgbXVjaCAtIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgYXJlOiAKYHIgc3VtbWFyeSh5ZWFyX2FjYV9ieUdyb3VwWzJdKWAuIFRoZSBtZWFuIHNpemUgb2YgY29udmVyc2F0aW9ucyBpcyBqdXN0IHNoeSBvZiAzMDAuCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xNSwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CnllYXJfYWNhX2J5R3JvdXAubG9uZyA8LSBtZWx0KHllYXJfYWNhX2J5R3JvdXAsIGlkLnZhcnMgPSBjKDEsMikpCgprMSA8LSBnZ3Bsb3QoZGF0YSA9IHllYXJfYWNhX2J5R3JvdXAubG9uZywgYWVzKHggPSBZZWFyLCB5ID0gdmFsdWUsIGZpbGwgPSB2YXJpYWJsZSkpICsgCiAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayhyZXZlcnNlID0gVFJVRSkpICsgCiAgZ2VvbV9saW5lKGFlcyh4ID0gWWVhciwgeT1EZWJhdGVTaXplKSwgZGF0YT15ZWFyX2FjYV9ieUdyb3VwLmxvbmcpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEzMDAsIGJ5ID0gMTAwKSkgKyAKICBnZ3RpdGxlKCJOdW1iZXIgYW5kIHR5cGUgb2YgZGViYXRlcnMgcGVyIHllYXIiKSArIAogIGxhYnMoeSA9ICJOdW1iZXIgb2YgUGFydGljaXBhbnRzIikgKwogIHRoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfcHRvbCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikKCnllYXJfYWNhX2J5R3JvdXAubG9uZyR2YXJpYWJsZSA8LSBmYWN0b3IoeWVhcl9hY2FfYnlHcm91cC5sb25nJHZhcmlhYmxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJVbmtub3duIiwiTm9uX0FjYWRlbWljaWFucyIsIkFjYWRlbWljaWFucyIgLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWQgPSBUKSkKCmsyIDwtIGdncGxvdCh5ZWFyX2FjYV9ieUdyb3VwLmxvbmcsIGFlcyh4ID0gWWVhciwgeSA9IHZhbHVlLCBmaWxsID0gdmFyaWFibGUpKSArIAogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj0iZmlsbCIpICsgCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMSxieT0wLjEpLCBsYWJlbHMgPSBwZXJjZW50KSArCiAgICBsYWJzKHkgPSAiUGVyY2VudCIsIGZpbGwgPSAiVHlwZSIsIHRpdGxlID0gIkRlYmF0ZXJzJyBwcm9wb3J0aW9uYWxpdHkgcGVyIHllYXIgYnkgYmFja2dyb3VuZCIpICsgCiAgICB0aGVtZV9taW5pbWFsKCkgKyAjIHNjYWxlX2ZpbGxfcHRvbCgpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgICB2YWx1ZXM9YygiQWNhZGVtaWNpYW5zIj0iIzQ0NzdBQSIsICJOb25fQWNhZGVtaWNpYW5zIj0iI0REQ0M3NyIsICJVbmtub3duIj0iI0NDNjY3NyIpKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKAogICAgICB2YWx1ZXM9YygiQWNhZGVtaWNpYW5zIj0iIzQ0NzdBQSIsICJOb25fQWNhZGVtaWNpYW5zIj0iI0REQ0M3NyIsICJVbmtub3duIj0iI0NDNjY3NyIpLCAKICAgICAgbGFiZWxzPWMoIkFjYWRlbWljaWFucyIsICJOb25fQWNhZGVtaWNpYW5zIiwgIlVua25vd24iKSkgKwogICAgbGFicyhmaWxsID0gIkdyb3VwIikKZ3JpZC5hcnJhbmdlKGsxLCBrMiwgbmNvbD0yKQpgYGAKCltTb3VyY2UgIzEgdW51c2VkXShodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzc4MTg5NjUpIC8gW1NvdXJjZSAjMiBwb3NpdGlvbiBmaWxsXShodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMTEwMjY0MzIpIC8gW1NvdXJjZSAjMyBmb3IgUGVyY2VudCBiYXIgcGxvdF0oaHR0cDovL3d3dy5yLWdyYXBoLWdhbGxlcnkuY29tLzQ4LWdyb3VwZWQtYmFycGxvdC13aXRoLWdncGxvdDIvKSAvIFtTb3VyY2UgIzQgZm9yIHBvc2l0aW9uX3N0YWNrIHJldmVyc2VdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zNDYzNzcwMykgLyBbU291cmNlICM1IGZvciBkZWxldGluZyBmaXJzdCBsZWdlbmRdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zNTYyMjM1OCkKCioqKgoKVGhlIHNhbWUgbm93IHdpdGggZ2VuZGVyLiAKCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KZWRnZURTX2dlbmRlckluRGViYXRlcyA8LSBlZGdlRFMgJT4lIAogIGZpbHRlcihUeXBlID09IDIpICU+JSAjIGp1c3QgImNvbnZlcnNhdGlvbnMiIChub3QgYW5udWFsIHF1ZXN0aW9ucykgd3JpdHRlbiBieSBlaXRoZXIgMSBvciAyIGF1dGhvcnMKICBzZWxlY3QoWWVhciwgVGhyZWFkSWQsIERlYmF0ZVNpemUsIEdlbmRlcikgJT4lIAogIGdyb3VwX2J5X2FsbCgpICU+JSAKICB0YWxseSAlPiUgCiAgc3ByZWFkKEdlbmRlciwgbiwgZmlsbCA9IDApICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIHNlbGVjdChZZWFyLCBNYWxlLCBGZW1hbGUsIGA8TkE+YCkgJT4lIAogIGdyb3VwX2J5KFllYXIpICU+JSAKICBzdW1tYXJpc2UoTWFsZSA9IHN1bShNYWxlKSwgRmVtYWxlID0gc3VtKEZlbWFsZSksIFVua25vd24gPSBzdW0oYDxOQT5gKSkKCmVkZ2VEU19nZW5kZXJJbkRlYmF0ZXMubG9uZyA8LSBtZWx0KGVkZ2VEU19nZW5kZXJJbkRlYmF0ZXMsIGlkLnZhcnMgPSBjKDEpKSAjMiwzCmVkZ2VEU19nZW5kZXJJbkRlYmF0ZXMubG9uZyR2YXJpYWJsZSA8LSBmYWN0b3IoZWRnZURTX2dlbmRlckluRGViYXRlcy5sb25nJHZhcmlhYmxlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJVbmtub3duIiwiRmVtYWxlIiwiTWFsZSIgLCBvcmRlcmVkID0gVCkpCgpnZ3Bsb3QoZWRnZURTX2dlbmRlckluRGViYXRlcy5sb25nLCBhZXMoeCA9IFllYXIsIHkgPSB2YWx1ZSwgZmlsbCA9IHZhcmlhYmxlLCBsYWJlbCA9IHZhbHVlKSkgKyAKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImZpbGwiKSArIAogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHZhbHVlKSwgCiAgICAgICAgICAgICAgc2l6ZSA9IDQsIHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbCh2anVzdCA9IDAuNSkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxLGJ5PTAuMDUpLCBsYWJlbHMgPSBwZXJjZW50KSArCiAgICBsYWJzKHkgPSAiUGVyY2VudCIsIGZpbGwgPSAiVHlwZSIpICsgCiAgICBnZ3RpdGxlICgiRGViYXRlcnMnIHByb3BvcnRpb25hbGl0eSBwZXIgeWVhciBieSBHZW5kZXIiLCAKICAgICAgICAgICAgIHN1YnRpdGxlID0gIk51bWJlciBwcmVzZW50IG51bWJlciBvZiBkZWJhdGVycyBwZXIgZ2VuZGVyIikgKyAKICAgIHRoZW1lX21pbmltYWwoKSArIAogICAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICAgIHZhbHVlcz1jKCJNYWxlIj0iIzQ0NzdBQSIsICJGZW1hbGUiPSIjRERDQzc3IiwgIlVua25vd24iPSIjQ0M2Njc3IikpICsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwoCiAgICAgIHZhbHVlcz1jKCJNYWxlIj0iIzQ0NzdBQSIsICJGZW1hbGUiPSIjRERDQzc3IiwgIlVua25vd24iPSIjQ0M2Njc3IiksIAogICAgICBsYWJlbHM9YygiTWFsZSIsICJGZW1hbGUiLCAiVW5rbm93biIpKSArCiAgICBsYWJzKGZpbGwgPSAiR2VuZGVyIikKICAgIApgYGAKCkluIHJlY2VudCB5ZWFycywgYWZ0ZXIgMjAxMCwgbnVtYmVyIG9mIHdvbWVuIGhhcyBpbmNyZWFzZWQgc29tZXdoYXQuIAoKYGBge3IgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CiMgTm93LCByZW1vdmUgZGF0YXNldHMgdG8gZnJlZSBSQU0Kcm0oY291bnRfbnVtYmVyT2ZDaGFycywgeWVhcl9hY2FfYnlHcm91cC5sb25nLCB5ZWFyX2FjYV9zdW0sIGVkZ2VEU19hY2FkZW1pY2lhbnNJbkRlYmF0ZXMsIGVkZ2VEU19nZW5kZXJJbkRlYmF0ZXMsCiAgIGczLGc0LGxtX2FjYV9kZWIscDEscDIseWVhcl9hY2FfYnlHcm91cCwgazEsIGsyLCBjb3VudF9udW1iZXJPZkNoYXJzX3NtYWxsLCBlZGdlRFNfZ2VuZGVySW5EZWJhdGVzLmxvbmcpCmBgYAoKKioqCgojIEh5cG90aGVzaXMgTm8uIDE6IFdvbWVuJ3MgdGVuZGVuY3kgCgo+IEh5cG90aGVzaXMgMTogIkEgd29tYW4ncyB0ZW5kZW5jeSB0byBwYXJ0aWNpcGF0ZSBhY3RpdmVseSBpbiB0aGUgY29udmVyc2F0aW9uIGNvcnJlbGF0ZXMgcG9zaXRpdmVseSB3aXRoIHRoZSBudW1iZXIgb2YgZmVtYWxlcyBpbiB0aGUgZGlzY3Vzc2lvbi4iCgpJIHN0YXJ0IGhvd2V2ZXIgZmlyc3Qgd2l0aCBhIGJyb2FkIGxvb2sgb24gdGhlIGRhdGEuIEhlbmNlLCBJIGNyZWF0ZSBkYXRhIHRoYXQgY2FuIGJlIHVzZWQgZm9yIGxhdGVyIChwcmludHMgb25seSA1IGNvbHVtbnMpLgoKYGBge3J9CmVkZ2VEU19jb252ZXJzYXRpb25zIDwtIGVkZ2VEUyAlPiUgCiAgZmlsdGVyKFR5cGUgPT0gMikgJT4lIAogIHNlbGVjdCgtTGluaywgLVRpdGxlLCAtT3JkZXIsIC1UZXh0LC1MaW1pdGVkX0luZm9ybWF0aW9uLCAtc3RhcnRzX3dpdGgoImR1bW15IikpICU+JSAKICBzZWxlY3QoLSg2MjoxNDQpKQpgYGAKCmBgYHtyIGVjaG89RkFMU0V9CmthYmxlKGhlYWQoZWRnZURTX2NvbnZlcnNhdGlvbnNbLDE6NV0pLCAiaHRtbCIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJob3ZlciIsICJjb25kZW5zZWQiKSwgZnVsbF93aWR0aCA9IEYpCmBgYAoKKioqCgojIyBEb2VzIHRoZSByYXRpbyBvZiBtZW4vd29tZW4gaW5jcmVhc2Ugb3ZlciB0aGUgeWVhcnMgPwoKV2hhdCBpcyBudW1iZXIgb2YgY29udHJpYnV0aW9ucyAofiAjIG9mIGNvbW1lbnRzKSBhbmQgdW5pcXVlIHBlb3BsZSB3aG8gY29udHJpYnV0ZSBieSBnZW5kZXIgcGVyIHllYXIuCgpgYGB7cn0KZWRnZURTX2NvbnZlcnNhdGlvbnNfcTEgPC0gZWRnZURTX2NvbnZlcnNhdGlvbnMgJT4lIAogIHNlbGVjdChZZWFyLCBUaHJlYWRJZCwgTWFsZV9Db250cmlidXRpb25zLCBGZW1hbGVfQ29udHJpYnV0aW9ucywgVW5pcXVlTWFsZUNvbnRyaWJ1dG9ycywgVW5pcXVlRmVtYWxlQ29udHJpYnV0b3JzKSAlPiUgCiAgZ3JvdXBfYnlfYWxsKCkgJT4lCiAgZGlzdGluY3QoLmtlZXBfYWxsID0gVFJVRSkgJT4lIAogIGdyb3VwX2J5KFllYXIpICU+JSAKICBzdW1tYXJpc2UoVG90YWxfTWFsZV9Db250cmlidXRpb25zID0gc3VtKE1hbGVfQ29udHJpYnV0aW9ucyksCiAgICAgICAgICAgIFRvdGFsX0ZlbWFsZV9Db250cmlidXRpb25zID0gc3VtKEZlbWFsZV9Db250cmlidXRpb25zKSwKICAgICAgICAgICAgVG90YWxfQ29udHJpYnV0aW9ucyA9IFRvdGFsX01hbGVfQ29udHJpYnV0aW9ucyArIFRvdGFsX0ZlbWFsZV9Db250cmlidXRpb25zLAogICAgICAgICAgICBUb3RhbF9VbmlxdWVNYWxlQ29udHJpYnV0b3JzID0gc3VtKFVuaXF1ZU1hbGVDb250cmlidXRvcnMpLCAKICAgICAgICAgICAgVG90YWxfVW5pcXVlRmVtYWxlQ29udHJpYnV0b3JzID0gc3VtKFVuaXF1ZUZlbWFsZUNvbnRyaWJ1dG9ycyksIAogICAgICAgICAgICBUb3RhbF9VbmlxdWVfQ29udHJpYnV0aW9ucyA9IFRvdGFsX1VuaXF1ZU1hbGVDb250cmlidXRvcnMgKyBUb3RhbF9VbmlxdWVGZW1hbGVDb250cmlidXRvcnMpCmBgYAoKYGBge3IgZWNobz1GQUxTRX0Ka2FibGUoaGVhZChlZGdlRFNfY29udmVyc2F0aW9uc19xMSksICJodG1sIikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoImhvdmVyIiwgImNvbmRlbnNlZCIpLCBmb250X3NpemUgPSAxMCkKYGBgCgoqKkV4cGxhbmF0aW9uIGZvciBoaWtlIGluIDIwMDgqKjogVGhlIGJpZyBzcGlrZSB3b3VsZCBiZSBhdHRyaWJ1dGVkIHRvIHRoZSBmaW5hbmNpYWwgY3Jpc2VzIHdoZXJlIEkgd291bGQgYXNzdW1lIHRoYXQgCmEgbG90IG9mIHBlb3BsZSB3ZXJlIHNlYXJjaGluZyBmb3Igam9iIGF0IGhvbWUgYW5kIGhhZCBhIGxvdCBvZiB0aW1lIHRvIGludmVzdCBpbnRvIEVkZ2UgY29udmVyc2F0aW9ucy4gCgpCb3RoLCB0aGUgdW5pcXVlIG51bWJlciBvZiBjb250cmlidXRvcnMgKGxlZnQgcGxvdCkgYW5kIHRvdGFsIG51bWJlciBvZiBjb250cmlidXRpb25zIGluIGRlYmF0ZXMgaXMgZ3Jvd2luZyBmb3IgYm90aCBnZW5kZXJzIC0gYWxiZWl0IGp1c3QgYSBsaXR0bGUuIAoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE1LCBtZXNzYWdlPUYsIHdhcm5pbmc9RiB9CnIxIDwtIGdncGxvdChlZGdlRFNfY29udmVyc2F0aW9uc19xMSwgYWVzKHg9IFllYXIpKSArIAogIGdlb21fcG9pbnQoYWVzKHkgPSBUb3RhbF9VbmlxdWVNYWxlQ29udHJpYnV0b3JzLCBjb2xvdXIgPSAiTWFsZSBDb250ci4iKSkgKyAKICBnZW9tX2xpbmUoYWVzKHkgPSBUb3RhbF9VbmlxdWVNYWxlQ29udHJpYnV0b3JzLCBjb2xvdXIgPSAiTWFsZSBDb250ci4iKSkgKwogIHN0YXRfc21vb3RoKGFlcyh5ID0gVG90YWxfVW5pcXVlTWFsZUNvbnRyaWJ1dG9ycywgY29sb3VyID0gIk1hbGUgQ29udHIuIiksIAogICAgICAgICAgICAgIG1ldGhvZCA9ICJsbSIsIGNvbCA9ICIjMTY5NUEzIikgKyAKICBnZW9tX3BvaW50KGFlcyh5ID0gVG90YWxfVW5pcXVlRmVtYWxlQ29udHJpYnV0b3JzLCBjb2xvdXIgPSAiRmVtYWxlIENvbnRyLiIpKSArIAogIGdlb21fbGluZShhZXMoeSA9IFRvdGFsX1VuaXF1ZUZlbWFsZUNvbnRyaWJ1dG9ycywgY29sb3VyID0gIkZlbWFsZSBDb250ci4iKSkgKwogIHN0YXRfc21vb3RoKGFlcyh5ID0gVG90YWxfVW5pcXVlRmVtYWxlQ29udHJpYnV0b3JzLCBjb2xvdXIgPSAiRmVtYWxlIENvbnRyLiIpLCAKICAgICAgICAgICAgICBtZXRob2QgPSAibG0iLCBjb2wgPSAiIzQ1MDAwMyIpICsgCiAgeWxhYigiIyBvZiBVbmlxdWUgcGVvcGxlIGNvbnRyaWJ1dGluZyBieSBHZW5kZXIiKSArIGxhYnMoY29sb3IgPSAiR2VuZGVyIikgKyAKICBnZ3RpdGxlKCJVbmlxdWUgQ29udHJpYnV0b3JzIG92ZXIgeWVhcnMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgc2NhbGVfZmlsbF9wdG9sKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHByZXR0eShlZGdlRFNfY29udmVyc2F0aW9uc19xMSRZZWFyLCBuID0gMTkpKSArIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMjAwLCBieSA9IDI1KSwgbGltaXRzID0gYygwLCAyMDApKQoKcjIgPC0gZ2dwbG90KGVkZ2VEU19jb252ZXJzYXRpb25zX3ExLCBhZXMoeD0gWWVhcikpICsgCiAgZ2VvbV9wb2ludChhZXMoeSA9IFRvdGFsX01hbGVfQ29udHJpYnV0aW9ucywgY29sb3VyID0gIk1hbGUgQ29udHIuIikpICsgCiAgZ2VvbV9saW5lKGFlcyh5ID0gVG90YWxfTWFsZV9Db250cmlidXRpb25zLCBjb2xvdXIgPSAiTWFsZSBDb250ci4iKSkgKwogIHN0YXRfc21vb3RoKGFlcyh5ID0gVG90YWxfTWFsZV9Db250cmlidXRpb25zLCBjb2xvdXIgPSAiTWFsZSBDb250ci4iKSwgCiAgICAgICAgICAgICAgbWV0aG9kID0gImxtIiwgY29sID0gIiMxNjk1QTMiKSArIAogIGdlb21fcG9pbnQoYWVzKHkgPSBUb3RhbF9GZW1hbGVfQ29udHJpYnV0aW9ucywgY29sb3VyID0gIkZlbWFsZSBDb250ci4iKSkgKyAKICBnZW9tX2xpbmUoYWVzKHkgPSBUb3RhbF9GZW1hbGVfQ29udHJpYnV0aW9ucywgY29sb3VyID0gIkZlbWFsZSBDb250ci4iKSkgKwogIHN0YXRfc21vb3RoKGFlcyh5ID0gVG90YWxfRmVtYWxlX0NvbnRyaWJ1dGlvbnMsIGNvbG91ciA9ICJGZW1hbGUgQ29udHIuIiksIAogICAgICAgICAgICAgIG1ldGhvZCA9ICJsbSIsIGNvbCA9ICIjNDUwMDAzIikgKyAKICB5bGFiKCJUb3RhbCBDb250cmlidXRpb25zIGJ5IEdlbmRlciIpICsgbGFicyhjb2xvciA9ICJHZW5kZXIiKSArIAogIGdndGl0bGUoIlRvdGFsIENvbnRyaWJ1dGlvbnMgYnkgTWVuIGFyZSB2b2xhdGlsZSIsIAogICAgICAgICAgc3VidGl0bGUgPSAiV2hpbGUgdGhvc2UgYnkgV29tZW4gc3RheSBwcmV0dHkgbXVjaCB0aGUgc2FtZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX3B0b2woKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHByZXR0eShlZGdlRFNfY29udmVyc2F0aW9uc19xMSRZZWFyLCBuID0gMTkpKSArIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTI1MCwgYnkgPSAxMDApKQoKZ3JpZC5hcnJhbmdlKHIxLCByMiwgbmNvbD0gMikKYGBgCgpbU291cmNlICMxXShodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzg5Mzg3ODEpLCBbU291cmNlICMyXShodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMTAzNTgzODgpCgoqKioKCiMjIEZhY2V0aW5nIG9uIHZhcmlvdXMgdmFyaWFibGVzCgpXZSBjYW4gbm93IGxvb2sgb24gaG93IHRoZSBwYXJ0aWNpcGF0aW9uIG9mIHdvbWVuIGhhcyBpbmNyZWFzZWQgb3ZlciB0aGUgeWVhcnMgLSBjb25zaWRlcmluZyB0aGF0IHRoZXJlIG1pZ2h0IGJlIApkaWZmZXJlbmNlcyBiZXR3ZWVuIHRob3NlIGluIEFjYWRlbWlhIHdpdGggUGhEIG9yIHdoZXJlIHRoZSBhdXRob3IgYW5kIGNvbW1lbnRlciBhcmUgdGhlIHNhbWUgcGVyc29uLiAgCgpUaGUgcGxvdCBiZWxvdyBzaG93cyBlLmcuIHRoYXQgdGhlcmUgYXJlIG5vIHdvbWVuIHdobyBhcmUgYWNhZGVtaWNpYW5zIGFuZCBkb24ndCBoYXZlIHRoZWlyIFBoRC4gRXZlcnkgd29tZW4gaXMgZWl0aGVyIGFjYWRlbWljaWFuIHdpdGggUGhELiBvciBpcyBhIG5vbi1hY2FkZW1pY2lhbiB3aXRoIGVpdGhlciBQaEQgb3Igd2l0aG91dCBvbmUuIAoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE1LCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0Kd29tZW5fcGFydF9ieV95ZWFyIDwtIGVkZ2VEU19jb252ZXJzYXRpb25zICU+JSAKICBzZWxlY3QoWWVhciwgR2VuZGVyLCBGZW1hbGVfQ29udHJpYnV0aW9ucywgTGl2ZSwgQWNhZGVtaWMsIAogICAgICAgICBUd29BdXRob3JzLCBIYXZlUGhELCBBdXRob3JBbmRDb21tZW50ZXIpICU+JSAKICBmaWx0ZXIoR2VuZGVyID09ICJGZW1hbGUiKSAlPiUgCiAgZ3JvdXBfYnlfYWxsKCkgJT4lIAogIHRhbGx5ICU+JSAKICBzcHJlYWQoR2VuZGVyLCBuLCBmaWxsID0gMCkKCndvbWVuX3BhcnRfYnlfeWVhciRMaXZlIDwtIGlmZWxzZSh3b21lbl9wYXJ0X2J5X3llYXIkTGl2ZSA9PSAwLCAiV3JpdHRlbiBUUCIsICJUcmFuc2NyaWJlZCBUUCIpCndvbWVuX3BhcnRfYnlfeWVhciRUd29BdXRob3JzIDwtIGlmZWxzZSh3b21lbl9wYXJ0X2J5X3llYXIkVHdvQXV0aG9ycyA9PSAxLCAiMiBhdXRob3JzIiwgIjEgYXV0aG9yIikKd29tZW5fcGFydF9ieV95ZWFyJEhhdmVQaEQgPC0gaWZlbHNlKHdvbWVuX3BhcnRfYnlfeWVhciRIYXZlUGhEID09IDEsICJIYXZlIFBIRCIsICJEb24ndCBoYXZlIFBIRCIpCndvbWVuX3BhcnRfYnlfeWVhciRBdXRob3JBbmRDb21tZW50ZXIgPC0gaWZlbHNlKHdvbWVuX3BhcnRfYnlfeWVhciRBdXRob3JBbmRDb21tZW50ZXIgPT0gMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkJvdGggYXV0aG9yIGFuZCBjb21tZW50YXRvciIsICJPdGhlcndpc2UiKQpjb2xuYW1lcyh3b21lbl9wYXJ0X2J5X3llYXIpWzhdIDwtICIjX29mX0ZlbWFsZXMiCgptZW5fcGFydF9ieV95ZWFyIDwtIGVkZ2VEU19jb252ZXJzYXRpb25zICU+JSAKICBzZWxlY3QoWWVhciwgR2VuZGVyLCBNYWxlX0NvbnRyaWJ1dGlvbnMsIExpdmUsIEFjYWRlbWljLCAKICAgICAgICAgVHdvQXV0aG9ycywgSGF2ZVBoRCwgQXV0aG9yQW5kQ29tbWVudGVyKSAlPiUgCiAgZmlsdGVyKEdlbmRlciA9PSAiTWFsZSIpICU+JSAKICBncm91cF9ieV9hbGwoKSAlPiUgCiAgdGFsbHkgJT4lIAogIHNwcmVhZChHZW5kZXIsIG4sIGZpbGwgPSAwKQoKbWVuX3BhcnRfYnlfeWVhciRMaXZlIDwtIGlmZWxzZShtZW5fcGFydF9ieV95ZWFyJExpdmUgPT0gMCwgIldyaXR0ZW4gVFAiLCAiVHJhbnNjcmliZWQgVFAiKQptZW5fcGFydF9ieV95ZWFyJFR3b0F1dGhvcnMgPC0gaWZlbHNlKG1lbl9wYXJ0X2J5X3llYXIkVHdvQXV0aG9ycyA9PSAxLCAiMiBhdXRob3JzIiwgIjEgYXV0aG9yIikKbWVuX3BhcnRfYnlfeWVhciRIYXZlUGhEIDwtIGlmZWxzZShtZW5fcGFydF9ieV95ZWFyJEhhdmVQaEQgPT0gMSwgIkhhdmUgUEhEIiwgIkRvbid0IGhhdmUgUEhEIikKbWVuX3BhcnRfYnlfeWVhciRBdXRob3JBbmRDb21tZW50ZXIgPC0gaWZlbHNlKG1lbl9wYXJ0X2J5X3llYXIkQXV0aG9yQW5kQ29tbWVudGVyID09IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCb3RoIGF1dGhvciBhbmQgY29tbWVudGF0b3IiLCAiT3RoZXJ3aXNlIikKY29sbmFtZXMobWVuX3BhcnRfYnlfeWVhcilbOF0gPC0gIiNfb2ZfTWFsZXMiCgoKZDEgPC0gZ2dwbG90KHdvbWVuX3BhcnRfYnlfeWVhciwgYWVzKHg9WWVhciwgeSA9IEZlbWFsZV9Db250cmlidXRpb25zKSkgKyAKICBnZW9tX3BvaW50KCkgKyBmYWNldF9ncmlkKEFjYWRlbWljIH4gSGF2ZVBoRCkgKyAKICB0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX3B0b2woKSArIAogIGdndGl0bGUoIkZlbWFsZSBjb250cmlidXRpb25zIGFuZCBpbXBhY3Qgb2YgYmVpbmcgYWNhZGVtaWNpYW4gd2l0aC9vdXQgUGhELiIsIAogICAgICAgICAgc3VidGl0bGUgPSAiVGhlcmUgYXJlIG5vIHdvbWVuIGluIHRoZSBhY2FkZW1pYSB3aXRob3V0IFBoRC4iKQoKZDIgPC0gZ2dwbG90KG1lbl9wYXJ0X2J5X3llYXIsIGFlcyh4PVllYXIsIHkgPSBNYWxlX0NvbnRyaWJ1dGlvbnMpKSArIAogIGdlb21fcG9pbnQoKSArIGZhY2V0X2dyaWQoQWNhZGVtaWMgfiBIYXZlUGhEKSArIAogIHRoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfcHRvbCgpICsgCiAgZ2d0aXRsZSgiTWFsZSBjb250cmlidXRpb25zIGFuZCBpbXBhY3Qgb2YgYmVpbmcgYWNhZGVtaWNpYW4gd2l0aC9vdXQgUGhELiIsIAogICAgICAgICAgc3VidGl0bGUgPSAiSGVyZSwgdGhlcmUgYXJlIGFjdHVhbGx5IG1lbiB3aG8gZG9uJ3QgaGF2ZSBQaEQuIGJ1dCBhcmUgaW4gYWNhZGVtaWEiKQoKZ3JpZC5hcnJhbmdlKGQxLGQyLG5jb2w9MikKYGBgCgoqKioKCmBgYHtyLGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE1LCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KZDMgPC0gZ2dwbG90KHdvbWVuX3BhcnRfYnlfeWVhciwgYWVzKHg9WWVhciwgeSA9IEZlbWFsZV9Db250cmlidXRpb25zKSkgKyAKICBnZW9tX3BvaW50KCkgKyBmYWNldF9ncmlkKEF1dGhvckFuZENvbW1lbnRlciB+IFR3b0F1dGhvcnMpICsgCiAgdGhlbWVfbWluaW1hbCgpICsgc2NhbGVfZmlsbF9wdG9sKCkgKyAKICBnZ3RpdGxlKCJGZW1hbGUgY29udHJpYnV0aW9ucyB0byB0aGUgYXJ0aWNsZXMgd2hlcmUgdGhlIGF1dGhvciBhbmQgY29tbWVudGVyIGlzIiwgCiAgICAgICAgICBzdWJ0aXRsZSA9ICJzYW1lIHBlcnNvbiBhbmQgd2hlcmUgY29tbWVudHMgY2FuIGJlIHdyaXR0ZW4gYnkgdHdvIHBlb3BsZSIpCgpkNCA8LSBnZ3Bsb3QobWVuX3BhcnRfYnlfeWVhciwgYWVzKHg9WWVhciwgeSA9IE1hbGVfQ29udHJpYnV0aW9ucykpICsgCiAgZ2VvbV9wb2ludCgpICsgZmFjZXRfZ3JpZChBdXRob3JBbmRDb21tZW50ZXIgfiBUd29BdXRob3JzKSArIAogIHRoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfcHRvbCgpICsgCiAgZ2d0aXRsZSgiTWFsZSBjb250cmlidXRpb25zIHRvIHRoZSBhcnRpY2xlcyB3aGVyZSB0aGUgYXV0aG9yIGFuZCBjb21tZW50ZXIgaXMiLCAKICAgICAgICAgIHN1YnRpdGxlID0gInNhbWUgcGVyc29uIGFuZCB3aGVyZSBjb21tZW50cyBjYW4gYmUgd3JpdHRlbiBieSB1cCAyIHBlb3BsZSIpCgpncmlkLmFycmFuZ2UoZDMsZDQsbmNvbD0yKQpgYGAKCioqKgoKYFNrZXduZXNzYCBmdW5jdGlvbiBjb25maXJtcyB0aGF0IGFsbCBkaXN0cmlidXRpb25zIGFyZSBoaWdobHkgc2tld2VkLiBFLmcuIGNvbnRyaWJ1dGlvbnMgb2Ygd29tZW4gdG8gdGhlIHRyYW5zY3JpYmVkIHRleHQgcGllY2VzICh0b3AtbGVmdCBwbG90KSBpcyB2aXNpYmx5IHNrZXdlZCB0byB0aGUgbGVmdCAoYmVpbmcgJysnKSAtIAppLmUuIHRoZSBbY3VydmUgaXMgcmlnaHQtbGVhbmluZ10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU2tld25lc3MjSW50cm9kdWN0aW9uKS4KClwKCk9uIHRoZSBvdGhlciBoYW5kLCB0aGUgYm90dG9tLWxlZnQgZGlzdHJpYnV0aW9uIGlzIG1vcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgdGhhbiBvdGhlcnMgaGF2aW5nIHRoZSBsb3dlc3Qgc2tld25lc3Mgb2YganVzdCAxLjQuIAoKV2UgY2FuIGFsc28gY29uZHVjdCBza2V3bmVzcyB0ZXN0IG9mIEQnQWdvc3Rpbm8uIFRoaXMgaXMgYWxzbyBjb25maXJtZWQgYmVjYXVzZSBvZiB0aGUgbG93IHAtdmFsdWUsIGkuZS4gYHRoZSBudWxsLWh5cG90aGVzaXMgdGhhdCBbb3VyIGRpc3RyaWJ1dGlvbnNdIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZCBjYW4gYmUgcmVqZWN0ZWQsIHdoaWNoIGlzIHRoZSBjYXNlIGhlcmVgCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CnNrZXdfZmVtX3RyYW4gPC0gc2tld25lc3Mod29tZW5fcGFydF9ieV95ZWFyJEZlbWFsZV9Db250cmlidXRpb25zW3dvbWVuX3BhcnRfYnlfeWVhciRMaXZlID09ICJUcmFuc2NyaWJlZCBUUCJdKQphZ29zdGluby50ZXN0KHdvbWVuX3BhcnRfYnlfeWVhciRGZW1hbGVfQ29udHJpYnV0aW9uc1t3b21lbl9wYXJ0X2J5X3llYXIkTGl2ZSA9PSAiVHJhbnNjcmliZWQgVFAiXSkKCnNrZXdfZmVtX3dyaXQgPC0gc2tld25lc3Mod29tZW5fcGFydF9ieV95ZWFyJEZlbWFsZV9Db250cmlidXRpb25zW3dvbWVuX3BhcnRfYnlfeWVhciRMaXZlID09ICJXcml0dGVuIFRQIl0pCmFnb3N0aW5vLnRlc3Qod29tZW5fcGFydF9ieV95ZWFyJEZlbWFsZV9Db250cmlidXRpb25zW3dvbWVuX3BhcnRfYnlfeWVhciRMaXZlID09ICJXcml0dGVuIFRQIl0pCgoKCnNrZXdfbV90cmFuIDwtIHNrZXduZXNzKG1lbl9wYXJ0X2J5X3llYXIkTWFsZV9Db250cmlidXRpb25zW21lbl9wYXJ0X2J5X3llYXIkTGl2ZSA9PSAiVHJhbnNjcmliZWQgVFAiXSkKCnNrZXdfbV93cml0IDwtIHNrZXduZXNzKG1lbl9wYXJ0X2J5X3llYXIkTWFsZV9Db250cmlidXRpb25zW21lbl9wYXJ0X2J5X3llYXIkTGl2ZSA9PSAiV3JpdHRlbiBUUCJdKQoKZGZfYW5ub3RhdGlvbnNGb3JGYWNldHMgPC0gZGF0YS5mcmFtZShMaXZlID0gYygiVHJhbnNjcmliZWQgVFAiLCAiV3JpdHRlbiBUUCIsICJUcmFuc2NyaWJlZCBUUCIsICJXcml0dGVuIFRQIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gYyhza2V3X2ZlbV90cmFuLCBza2V3X2ZlbV93cml0LCBza2V3X21fdHJhbiwgc2tld19tX3dyaXQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gMjAwNSwgeT0gYygzMCwgMzAsIDMwMCwgMzAwKSkKCmBgYApbU291cmNlICMxXShodHRwczovL3N0YXRiYW5kaXQud29yZHByZXNzLmNvbS8yMDE2LzEwLzIwL2Fubm90YXRlZC1mYWNldHMtd2l0aC1nZ3Bsb3QyLykgLyBbU291cmNlICMyXShodHRwOi8vci1zdGF0aXN0aWNzLmNvL1N0YXRpc3RpY2FsLVRlc3RzLWluLVIuaHRtbCkgLyBbU291cmNlICMzXShodHRwOi8vd3d3LnJlYWwtc3RhdGlzdGljcy5jb20vdGVzdHMtbm9ybWFsaXR5LWFuZC1zeW1tZXRyeS9zdGF0aXN0aWNhbC10ZXN0cy1ub3JtYWxpdHktc3ltbWV0cnkvZGFnb3N0aW5vLXBlYXJzb24tdGVzdC8pCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTUsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpkNSA8LSBnZ3Bsb3Qod29tZW5fcGFydF9ieV95ZWFyLCBhZXMoeD1ZZWFyLCB5ID0gRmVtYWxlX0NvbnRyaWJ1dGlvbnMpKSArIAogIGdlb21fcG9pbnQoKSArIGZhY2V0X2dyaWQoTGl2ZSB+IC4gKSArCiAgdGhlbWVfbWluaW1hbCgpICsgc2NhbGVfZmlsbF9wdG9sKCkgKyAKICBnZ3RpdGxlKCJGZW1hbGUgY29udHJpYnV0aW9ucyB0byB0aGUgVHJhbnNjcmliZWQgb3IgV3JpdHRlbiBUZXh0IFBpZWNlcyIsIAogICAgICAgICAgc3VidGl0bGUgPSAiU29tZXdoYXQgc2tldyB0byB0aGUgcmlnaHQgLSByaWdodC1sZWFuaW5nIGN1cnZlIikgKyAKICBnZW9tX3RleHQoZGF0YSA9IGRmX2Fubm90YXRpb25zRm9yRmFjZXRzWzE6MixdLCAKICAgICAgICAgICAgYWVzKHg9eCwgeT15LCBsYWJlbCA9IHBhc3RlKCJTa2V3bmVzcyA9ICIsIHJvdW5kKHZhbHVlLDIpKSksIAogICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFKQogICAgICAgICAgICAKICAgICAgICAgICAgCmQ2IDwtIGdncGxvdChtZW5fcGFydF9ieV95ZWFyLCBhZXMoeD1ZZWFyLCB5ID0gTWFsZV9Db250cmlidXRpb25zKSkgKyAKICBnZW9tX3BvaW50KCkgKyBmYWNldF9ncmlkKExpdmUgfiAuICkgKyAKICB0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX3B0b2woKSArIAogIGdndGl0bGUoIk1hbGUgY29udHJpYnV0aW9ucyB0byB0aGUgVHJhbnNjcmliZWQgb3IgV3JpdHRlbiBUZXh0IFBpZWNlcyIsIAogICAgICAgICAgc3VidGl0bGUgPSAiUmVsYXRpdmVseSBlcXVhbGx5IHNwcmVhZCIpICsKICBnZW9tX3RleHQoZGF0YSA9IGRmX2Fubm90YXRpb25zRm9yRmFjZXRzWzM6NCxdLCAKICAgICAgICAgICAgYWVzKHg9eCwgeT15LCBsYWJlbCA9IHBhc3RlKCJTa2V3bmVzcyA9ICIsIHJvdW5kKHZhbHVlLDIpKSksIAogICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFKQoKZ3JpZC5hcnJhbmdlKGQ1LGQ2LG5jb2w9MikKYGBgCltTb3VyY2UgIzFdKGh0dHBzOi8vYnJvd25tYXRoLmNvbS9zdGF0L3NoYXBlLmh0bSkgLyAKCioqKgoKIyMgRmVtYWxlIHBhcnRpY2lwYXRpb24gcGVyIFllYXIKCkFnYWluIHByZXBhcmUgdGhlIGRhdGEgZm9yIGxhdGVyIHVzZS4KCmBgYHtyfQpQZW9wbGVQZXJUaHJlYWRJRCA8LSBlZGdlRFNfY29udmVyc2F0aW9ucyAlPiUgCiAgc2VsZWN0KFllYXIsIFRocmVhZElkLCBNYWxlX0NvbnRyaWJ1dGlvbnMsIAogICAgICAgICBGZW1hbGVfQ29udHJpYnV0aW9ucywgRmVtYWxlUGFydGljaXBhdGlvbiwgCiAgICAgICAgIERlYmF0ZVNpemUsIFVuaXF1ZUNvbnRyaWJ1dG9ycywgVW5pcXVlTWFsZUNvbnRyaWJ1dG9ycywgCiAgICAgICAgIFVuaXF1ZUZlbWFsZUNvbnRyaWJ1dG9ycywgVW5pcXVlRmVtYWxlUGFydGljaXBhdGlvbikgJT4lIAogIGRpc3RpbmN0KC5rZWVwX2FsbCA9IFRSVUUpICU+JSAKICBzZWxlY3QoWWVhciwgRmVtYWxlUGFydGljaXBhdGlvbikgJT4lIAogIGdyb3VwX2J5KFllYXIpICU+JSAKICBtdXRhdGUoQXZnRmVtYWxlUGFydGljaXBhdGlvblBlclllYXIgPSBtZWFuKEZlbWFsZVBhcnRpY2lwYXRpb24pLAogICAgICAgICBNZWRpYW5GZW1hbGVQYXJ0aWNpcGF0aW9uUGVyWWVhciA9IG1lZGlhbihGZW1hbGVQYXJ0aWNpcGF0aW9uKSwKICAgICAgICAgU3VtRmVtYWxlUGFydGljaXBhdGlvblBlclllYXIgPSBzdW0oRmVtYWxlUGFydGljaXBhdGlvbikpCgpyYXRpbyA8LSBlZGdlRFNfY29udmVyc2F0aW9uc19xMSRUb3RhbF9GZW1hbGVfQ29udHJpYnV0aW9ucy9lZGdlRFNfY29udmVyc2F0aW9uc19xMSRUb3RhbF9Db250cmlidXRpb25zCmBgYAoKSW5kZXBlbmRlbnRseSBvZiBob3cgb25lIGNhbGN1bGF0ZXMgdGhlIChhdmVyYWdlKSBmZW1hbGUgcGFydGljaXBhdGlvbiwgdGhlIHRyZW5kIGlzIHN0aWxsIGdyb3dpbmcuIAoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE1LCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KcTEgPC0gZ2dwbG90KFBlb3BsZVBlclRocmVhZElELCBhZXMoeCA9IFllYXIsIHkgPSBBdmdGZW1hbGVQYXJ0aWNpcGF0aW9uUGVyWWVhcikpICsKICBnZW9tX3BvaW50KCkgKyAKICBnZ3RpdGxlKCJGZW1hbGUgUGFydGljaXBhdGlvbiBwZXIgWWVhciBpcyBzbGlnaHRseSBpbmNyZWFzaW5nIiwgCiAgICAgICAgICBzdWJ0aXRsZSA9ICJDYWxjdWxhdGlvbiBiYXNlZCBvbiBhdmVyYWdpbmcgJ0ZlbWFsZSBQYXJ0aWNpcGF0aW9uJyAoZnJvbSBkYXRhc2V0KSIpICsKICBnZW9tX2xpbmUoKSArIAogIHlsYWIoIkF2YXJhZ2UgRmVtYWxlIFBhcnRpY2lwYXRpb24iKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBULCBzaG93LmxlZ2VuZCA9IFRSVUUpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEsIGJ5ID0gMC4xKSwgbGltaXRzID0gYygwLCAxKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwcmV0dHkoUGVvcGxlUGVyVGhyZWFkSUQkWWVhciwgbiA9IDE5KSkgKwogIHRoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfcHRvbCgpIAoKcTIgPC0gZ2dwbG90KGVkZ2VEU19jb252ZXJzYXRpb25zX3ExLCBhZXMoeD1ZZWFyKSkgKyBnZW9tX3BvaW50KGFlcyh5PXJhdGlvKSkgKyBnZW9tX2xpbmUoYWVzKHk9cmF0aW8pKSArCiAgZ2d0aXRsZSgiSGVyZSBpdCBpcyBhbHNvIGdyb3dpbmciLCAKICAgICAgICAgIHN1YnRpdGxlID0gIkNhbGN1bGF0aW9uIGJhc2VkIG9uIHRvdGFsIGZlKG1hbGUpIGNvbnRyaWJ1dGlvbnMgcGVyIHllYXIiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgc2NhbGVfZmlsbF9wdG9sKCkgKyB5bGFiKCJUb3RhbF9GZW1hbGVfQ29udHJpYnV0aW9ucy9Ub3RhbF9Db250cmlidXRpb25zIikgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBwcmV0dHkoZWRnZURTX2NvbnZlcnNhdGlvbnNfcTEkWWVhciwgbiA9IDE5KSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEsIGJ5ID0gMC4xKSwgbGltaXRzID0gYygwLCAxKSkKCmdyaWQuYXJyYW5nZShxMSxxMiwgbmNvbD0yKQpgYGAKCioqKgoKIyMgQ29ycmVsYXRpb25zCgpGb3IgcmVtaW5kZXI6Cgo+IEh5cG90aGVzaXMgMTogIkEgd29tYW4ncyB0ZW5kZW5jeSB0byBwYXJ0aWNpcGF0ZSBhY3RpdmVseSBpbiB0aGUgY29udmVyc2F0aW9uIGNvcnJlbGF0ZXMgcG9zaXRpdmVseSB3aXRoIHRoZSBudW1iZXIgb2YgKEkgZ3Vlc3MgdW5pcXVlKSBmZW1hbGVzIGluIHRoZSBkaXNjdXNzaW9uLiIKCmBgYHtyfQpjb3JfZGF0YSA8LSBlZGdlRFMgJT4lIAogIGZpbHRlcihSb2xlID09IDEsIEdlbmRlciA9PSAiRmVtYWxlIiwgVHlwZSA9PSAyKSAlPiUgCiAgc2VsZWN0KC1MaW5rLCAtSWRfbnVtLCAtVGhyZWFkSWQsIC1ZZWFyLCAtVGl0bGUsLVJvbGUsLVR5cGUsIAogICAgICAgICAtT3JkZXIsIC1UZXh0LC1MaW1pdGVkX0luZm9ybWF0aW9uLC1HZW5kZXIsIC1zdGFydHNfd2l0aCgiZHVtbXkiKSkKCmFsbF9mYWN0b3JzX25hbWVzIDwtIGFzLmRhdGEuZnJhbWUoc2FwcGx5KGNvcl9kYXRhLCBpcy5mYWN0b3IpKQphbGxfZmFjdG9yc19uYW1lcyRuYW1lIDwtIHJvd25hbWVzKGFsbF9mYWN0b3JzX25hbWVzKQphbGxfZmFjdG9yc19uYW1lcyA8LSBhbGxfZmFjdG9yc19uYW1lc1thbGxfZmFjdG9yc19uYW1lcyRgc2FwcGx5KGNvcl9kYXRhLCBpcy5mYWN0b3IpYCA9PSBUUlVFLF0KY29yX2RhdGEgPC0gY29yX2RhdGFbICwgIShuYW1lcyhjb3JfZGF0YSkgJWluJSBhbGxfZmFjdG9yc19uYW1lcyRuYW1lKV0KCgphbGxfY2hhcl9uYW1lcyA8LSBhcy5kYXRhLmZyYW1lKHNhcHBseShjb3JfZGF0YSwgaXMuY2hhcmFjdGVyKSkKYWxsX2NoYXJfbmFtZXMkbmFtZSA8LSByb3duYW1lcyhhbGxfY2hhcl9uYW1lcykKYWxsX2NoYXJfbmFtZXMgPC0gYWxsX2NoYXJfbmFtZXNbYWxsX2NoYXJfbmFtZXMkYHNhcHBseShjb3JfZGF0YSwgaXMuY2hhcmFjdGVyKWAgPT0gVFJVRSxdCmNvcl9kYXRhIDwtIGNvcl9kYXRhWyAsICEobmFtZXMoY29yX2RhdGEpICVpbiUgYWxsX2NoYXJfbmFtZXMkbmFtZSldCmNvcl9kYXRhIDwtIGNvcl9kYXRhWyAsIC1jKDI2OjEwNildCgoKTSA8LSBjb3IoYXMuZGF0YS5mcmFtZShjb3JfZGF0YSksIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQpgYGAKCioqSWRlYSoqOiBJZiBhbiBhdXRob3IgaXMgYSB3b21hbiwgdGhlbiB0aGVyZSBpcyBwb3RlbnRpYWxseSBhIGhpZ2hlciBlbmdhZ2VtZW50IHdpdGggb3RoZXIgd29tZW4gYXMgd2VsbCAodGhvc2UgY291bGQgYmUgbW9yZSBpbnRlcmVzdGluZyB0byBjb250cmlidXRlKS4gCgoqKlJlc3VsdCoqOiBZZXQgY29ycmVsYXRpb24gLSBhdCBsZWFzdCBmb3IgdGhlIGNhc2Ugb2YgRmVtYWxlIENvbnRyaWJ1dGlvbnMgLSBkb2Vzbid0IGNvbmZpcm0gdGhpcy4gCgpgYGB7cn0KY29yKGNvcl9kYXRhJEZlbWFsZV9Db250cmlidXRpb25zLCBjb3JfZGF0YSRVbmlxdWVGZW1hbGVDb250cmlidXRvcnMpCmBgYAoKVGhpcyBpcyBvcHBvc2l0ZSB3aXRoIEZlbWFsZSBQYXJ0aWNpcGF0aW9uIHdoZXJlIHRoZXJlIGlzIGEgc3Ryb25nIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlICpub3JtYWwqIEZlbWFsZSBQYXJ0aWNpcGF0aW9uIHJhdGlvIGFuZCB0aGUgKnVuaXF1ZSogb25lLgoKYGBge3J9CmNvcihjb3JfZGF0YSRGZW1hbGVQYXJ0aWNpcGF0aW9uLCBjb3JfZGF0YSRVbmlxdWVGZW1hbGVQYXJ0aWNpcGF0aW9uKQpgYGAKCioqKgoKUGxvdCBjb3JyZWxhdGlvbiBtYXRyaXguCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTUsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpjb3JycGxvdChNKQpnZ2NvcnIoTSwgbmJyZWFrcyA9IDYsIHBhbGV0dGUgPSAiUmRHeSIsIGxhYmVsID0gVFJVRSwgbGFiZWxfc2l6ZSA9IDMsIAogICAgICAgbGFiZWxfY29sb3IgPSAid2hpdGUiLCBoanVzdCA9IDAuNzUsIHNpemUgPSAyLjUsIGFuZ2xlID0gLTUsbGF5b3V0LmV4cCA9IDUpCmBgYAoKYGBge3IgaW5jbHVkZT1GQUxTRSwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CiMgTm93LCByZW1vdmUgZGF0YXNldHMgdG8gZnJlZSBSQU0Kcm0oUGVvcGxlUGVyVGhyZWFkSUQsIHdvbWVuX3BhcnRfYnlfeWVhciwgYWxsX2NoYXJfbmFtZXMsCiAgIGVkZ2VEU19jb252ZXJzYXRpb25zX3ExLCBxMSxxMiwgcjEsIHIyLCBhbGxfZmFjdG9yc19uYW1lcywgY29yX2RhdGEsIAogICBkMSxkMixkMyxkNCxkNSxkNiwgTSwgbWVuX3BhcnRfYnlfeWVhciwgZWRnZURTX2NvbnZlcnNhdGlvbnMpCmBgYAoKKioqCgojIEh5cG90aGVzaXMgTm8uIDI6IFZlcmJvc2l0eSAKCj4gSHlwb3RoZXNpcyAyOiAiSGlnaGVyIHN0YXR1cyBwYXJ0aWNpcGFudHMgYXJlIG1vcmUgdmVyYm9zZSB0aGFuIGFyZSBsb3dlciBzdGF0dXMgcGFydGljaXBhbnRzLiIKCioqTXkgRGVmaW5pdGlvbiBvZiAnU3RhdHVzJzoqKiBJIGRlZmluZSAiaGlnaGVyIHN0YXR1cyIgYXMgYmVpbmcgc29sZWx5IGRlcGVuZGVudCBvbiB0aGUgcGVyc29uJ3MgYmFja2dyb3VuZCwgd29ya3BsYWNlIChpLmUuIHdoZXJlIChzKWhlIGNvbWVzIGZyb20pLCBoaXMvaGVyIGpvYiAoYW5kIGlmIGFjYWRlbWljaWFucywgdGhlbiBhbHNvIHRoZSBkZXBhcnRtZW50LCBkaXNjaXBsaW5lLCBhY2FkZW1pYyByYW5rIGFuZCAgY2l0YXRpb25zKSBhbmQgd2hldGhlciAocyloZSBoYXMgYSBQaEQgYW5kIGZyb20gd2hpY2ggaW5zdGl0dXRpb24sIGV0Yy4gSSB1c2UgZGF0YSBmcm9tIHRoZSBkYXRhc2V0LCBleGNsdXNpdmVseS4gIAoKYGBge3J9CmVkZ2VEU192ZXJib3NpdHkgPC0gZWRnZURTICU+JSAKICBzZWxlY3QoWWVhciwgQWNhZGVtaWMsIExpbWl0ZWRfSW5mb3JtYXRpb24sIEhfSW5kZXgsIGkxMF9JbmRleCwgUm9sZSwgR2VuZGVyLCAKICAgICAgICAgSGF2ZVBoRCwgRGViYXRlU2l6ZSwgSm9iX1RpdGxlX1MsIERlcGFydG1lbnRfUywgRGlzY2lwbGluZSwgCiAgICAgICAgIFBoRF9JbnN0aXR1dGlvbl9TUl9CaW4sIEFjYWRlbWljSGllcmFyY2h5U3RyaWN0LCBOdW1iZXIuQ2hhcmFjdGVycykgJT4lIAogIGdyb3VwX2J5X2FsbCgpCmBgYAoKKioqCgojIyBMb29rIGF0IGRpZmZlcmVudCB2YXJpYWJsZXMgYW5kIGhvdyB0aGV5IGltcGFjdCBob3cgbXVjaCBwZW9wbGUgd3JpdGUgdG8gY29udmVyc2F0aW9uIGFuZCBhbm51YWwgcXVlc3Rpb25zLgoKR3JvdXAgb2YgKmFjYWRlbWlhKiA8PiBOdW1iZXIgb2YgY2hhcmFjdGVycwoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KZ2dwbG90bHkoCiAgZ2dwbG90KGVkZ2VEU192ZXJib3NpdHksIGFlcyhBY2FkZW1pYywgTnVtYmVyLkNoYXJhY3RlcnMpKSArIGdlb21fYm94cGxvdCgpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDQwMDAsIGJ5ID0gMjAwKSwgbGltaXRzID0gTkEpICsgCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPWMoMCw0MDAwKSkgKwogIHhsYWIoIkdyb3VwIikgKyB5bGFiKCJOdW1iZXIgb2YgY2hhcmFjdGVycyIpICsgCiAgZ2d0aXRsZSgiTnVtYmVyIG9mIGNoYXJhY3RlcnMgYnkgZ3JvdXAgKGJvdGggZ2VuZGVycykiKSArCiAgdGhlbWVfbWluaW1hbCgpICsgc2NhbGVfZmlsbF9wdG9sKCkKKSAlPiUgbGF5b3V0KHhheGlzID0gbGlzdCh0aWNrdGV4dCA9IGMoIk5vbl9BY2FkZW1pY2lhbnMiLCAiQWNhZGVtaWNpYW5zIiwgIk5BIikpKQpgYGAKCltIb3BlZnVsbHkgb25lIGRheSBwbG90bHkgUiB3aWxsIGZpeCBzdWJ0aXRsZSBpc3N1ZXNdKGh0dHBzOi8vZ2l0aHViLmNvbS9yb3BlbnNjaS9wbG90bHkvaXNzdWVzLzc5OSkKCkF2YXJhZ2UgbnVtYmVyIG9mIGNoYXJhY3RlcnMgYnkgYWNhZGVtaWNpYW5zIGFuZCBsYXRlciBub24tYWNhZGVtaWNpYW5zOgoKYGBge3J9CmVkZ2VEU192ZXJib3NpdHlfYWNhX3kgPC0gZWRnZURTX3ZlcmJvc2l0eSAlPiUgZmlsdGVyKEFjYWRlbWljID09ICJBY2FkZW1pY2lhbnMiKSAKbWVhbihlZGdlRFNfdmVyYm9zaXR5X2FjYV95JE51bWJlci5DaGFyYWN0ZXJzKSAKCmVkZ2VEU192ZXJib3NpdHlfYWNhX24gPC0gZWRnZURTX3ZlcmJvc2l0eSAlPiUgZmlsdGVyKEFjYWRlbWljID09ICJOb25fQWNhZGVtaWNpYW5zIikgCm1lYW4oZWRnZURTX3ZlcmJvc2l0eV9hY2FfbiROdW1iZXIuQ2hhcmFjdGVycykKYGBgCltTb3VyY2UgIzFdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS80NzAwMTM2KQoKKioqCgpEb2VzIHRoZSBudW1iZXIgb2YgY2hhcmFjdGVycyBpbiB0aGUgY29tbWVudHMgZGVwZW5kIGFueWhvdyBvbiBwZXJzb24ncyAqam9iIHRpdGxlKj8gV2VsbCwgb25seSBzbGlnaHRseS4gCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpnZ3Bsb3RseSgKICBnZ3Bsb3QoZWRnZURTX3ZlcmJvc2l0eSwgYWVzKEpvYl9UaXRsZV9TLCBOdW1iZXIuQ2hhcmFjdGVycykpICsgZ2VvbV9ib3hwbG90KCkgKyAKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwyMDAwMCwgYnkgPSAxMDAwKSwgbGltaXRzID0gYygwLDE5MDAwMCkpICsgCiAgICB4bGFiKCJKb2IgVGl0bGUiKSArIHlsYWIoIk51bWJlciBvZiBjaGFyYWN0ZXJzIikgKyAKICAgIGdndGl0bGUoIldoZW4gZ3JhZHVhdGUgc3R1ZGVudHMgd3JpdGUsIHRoZW4gaXQgaXMgYWx3YXlzIHF1aXRlIGEgbG90IiwgCiAgICAgICAgICAgIHN1YnRpdGxlID0gIm1heWJlIHRoZXJlIGFyZSBzb21lIGluIE5BIG9yIE90aGVyIGJpbnMiKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX3B0b2woKSArIGNvb3JkX2ZsaXAoeWxpbSA9YygwLDYwMDApKQopICU+JSBsYXlvdXQobWFyZ2luID0gbGlzdChsID0gMjAwKSkKYGBgCgoqKioKCkFsc28sIG9mIHRob3NlIGFjYWRlbWljIHBlb3BsZSwgKmRlcGFydG1lbnRzL2ZpZWxkcyogdGhleSBjb21lIGZyb20gYW5kIHdvcmsgaW4gLSBkb2VzIGl0IGhhdmUgYW55IGltcGFjdCBvbiBob3cgbXVjaCB0aGV5IHdyaXRlPwoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KZ2dwbG90bHkoCiAgZ2dwbG90KGVkZ2VEU192ZXJib3NpdHksIGFlcyhEZXBhcnRtZW50X1MsIE51bWJlci5DaGFyYWN0ZXJzKSkgKyBnZW9tX2JveHBsb3QoKSArCiAgICBjb29yZF9mbGlwKHlsaW0gPWMoMCw0NTAwMCkpICsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCw0NTAwMCwgYnkgPSA1MDAwKSwgbGltaXRzID0gYygwLDE5MDAwMCkpICsKICAgIHhsYWIoIkFjYWRlbWljIERlcGFydG1lbnQiKSArIHlsYWIoIk51bWJlciBvZiBjaGFyYWN0ZXJzIikgKyAKICAgIHRoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfcHRvbCgpIAopCmBgYAoKKioqCgoqRGlzY2lwbGluZSogYWxzbyBzZWVtcyB0byBoYXZlIGFuIGltcGFjdC4gVGhlIGRpZmZlcmVuY2UgYmV0d2VlbiAiUHJvZmVzc2lvbnMiIGFuZCAiT3RoZXIiICgiTkEiKSBpcyBhbHNvIHF1aXRlIHNpZ25pZmljYW50LgoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KZ2dwbG90bHkoCiAgZ2dwbG90KGVkZ2VEU192ZXJib3NpdHksIGFlcyhEaXNjaXBsaW5lLCBOdW1iZXIuQ2hhcmFjdGVycykpICsgCiAgICBnZW9tX2JveHBsb3QoKSArICNjb29yZF9mbGlwKCkgICsgCiAgICB4bGFiKCJBY2FkZW1pYyBEaXNjaXBsaW5lIikgKyB5bGFiKCJOdW1iZXIgb2YgY2hhcmFjdGVycyIpICsgCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEwMDAwMCwgYnkgPSAxMDAwKSwgbGltaXRzID0gTkEpICsgCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9YygwLDEwMDAwKSkgKyAgCiAgICBzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbiwgZnVuLmFyZ3MgPSBsaXN0KG5hLnJtID0gRiksIAogICAgICAgICAgICAgICAgIG5hLnJtID0gVCwgZ2VvbT0icG9pbnQiLCBzaXplPTIuNSwgY29sb3I9ImdyZWVuIikgKyAgCiAgICBnZ3RpdGxlKCJCb3ggUGxvdCBvZiBudW1iZXIgb2YgY2hhcmFjdGVycyBieSBhY2FkZW1pYyBkaXNjaXBsaW5lIiwgCiAgICAgICAgIHN1YnRpdGxlID0gIkdyZWVuIFBvaW50IHNob3dzIGFuIGF2ZXJhZ2UvbWVhbiIpICsKICAgIHRoZW1lX21pbmltYWwoKSArIHNjYWxlX2ZpbGxfcHRvbCgpICAKKQoKZWRnZURTX3ZlcmJvc2l0eV9kaXNjX2RpZmYgPC0gZWRnZURTX3ZlcmJvc2l0eSAlPiUgCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUgCiAgZHBseXI6OnNlbGVjdChEaXNjaXBsaW5lLCBOdW1iZXIuQ2hhcmFjdGVycykgJT4lIAogIGRwbHlyOjpncm91cF9ieShEaXNjaXBsaW5lKSAlPiUgCiAgZHBseXI6OnN1bW1hcml6ZShtaW5fTnVtYmVyLkNoYXJhY3RlcnMgPSBtaW4oTnVtYmVyLkNoYXJhY3RlcnMpLCAKICAgICAgICAgICAgI21pbkRpc2NpcGxpbmVOYW1lID0gRGlzY2lwbGluZVt3aGljaC5taW4oTnVtYmVyLkNoYXJhY3RlcnMpXSwgCiAgICAgICAgICAgIG1heF9OdW1iZXIuQ2hhcmFjdGVycyA9IG1heChOdW1iZXIuQ2hhcmFjdGVycyksIAogICAgICAgICAgICAjbWF4RGlzY2lwbGluZU5hbWUgPSBEaXNjaXBsaW5lW3doaWNoLm1heChOdW1iZXIuQ2hhcmFjdGVycyldLAogICAgICAgICAgICBtZWFuX051bWJlci5DaGFyYWN0ZXJzID0gcm91bmQobWVhbihOdW1iZXIuQ2hhcmFjdGVycywgbmEucm0gPSBUKSwyKQogICAgICAgICAgICApICU+JSAKICBkcGx5cjo6bXV0YXRlKGRpZmZlcmVuY2VfbWF4X21pbiA9IG1heF9OdW1iZXIuQ2hhcmFjdGVycy1taW5fTnVtYmVyLkNoYXJhY3RlcnMpCmBgYApbU291cmNlICMxXShodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzAxOTY1NjEpCgpgYGB7ciBlY2hvPUZBTFNFfQprYWJsZShlZGdlRFNfdmVyYm9zaXR5X2Rpc2NfZGlmZiwgImh0bWwiKSAlPiUgCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoImhvdmVyIiwgImNvbmRlbnNlZCIpLCBmdWxsX3dpZHRoID0gRikKYGBgCgoqKioKClRoZSAqU2hhbmdoYWkgUmFua2luZyogb2YgdGhlaXIgUGhEIEluc3RpdHV0aW9uIHZzLiBudW1iZXIgb2YgY2hhcmFjdGVycyB0aGV5IHdyaXRlLiBMaWtlCgotIDEgPSB1bml2ZXJzaXR5IHdhcyByYW5rZWQgYmV0d2VlbiAxIGFuZCA1MAoKLSAyID0gdW5pdmVyc2l0eSB3YXMgcmFua2VkIGJldHdlZW4gNTEgYW5kIDEwMAoKLSBldGMuCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpnZ3Bsb3RseSgKICBnZ3Bsb3QoZWRnZURTX3ZlcmJvc2l0eSwgYWVzKFBoRF9JbnN0aXR1dGlvbl9TUl9CaW4sIE51bWJlci5DaGFyYWN0ZXJzKSkgKyAKICAgIGdlb21fYm94cGxvdCgpICsKICAgIGNvb3JkX2NhcnRlc2lhbih5bGltID1jKDAsNzAwMCkpICsgCiAgICBnZ3RpdGxlKCJTaGFuZ2hhaSBSYW5raW5ncyBvZiB0aGVpciBQaEQgSW5zdGl0dXRpb24iKSsKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMDAwMCwgYnkgPSA1MDApLCBsaW1pdHMgPSBjKDAsMTkwMDAwKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsgc2NhbGVfZmlsbF9wdG9sKCkKKSAlPiUgbGF5b3V0KHhheGlzID0gbGlzdCh0aWNrdGV4dCA9IGMoIjEtNTAiLCAiNTEtMTAwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIjEwMS0xNTAiLCAiMTUxLTIwMCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICIyMDEtMzAwIiwgIjMwMS00MDAiLCAiNDAxLTUxMCIsICJOQSIpLCBzaG93Z3JpZCA9IEYpKQpgYGAKCioqKgoKQnkgKkFjYWRlbWljSGllcmFyY2h5U3RyaWN0KjoKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmdncGxvdGx5KAogIGdncGxvdChlZGdlRFNfdmVyYm9zaXR5LCBhZXMoQWNhZGVtaWNIaWVyYXJjaHlTdHJpY3QsIE51bWJlci5DaGFyYWN0ZXJzKSkgKyAKICBnZW9tX2JveHBsb3QoKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPWMoMCw2MDAwKSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwMDAsIGJ5ID0gNTAwKSwgbGltaXRzID0gYygwLDE5MDAwMCkpICsKICB0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX3B0b2woKQopICU+JSBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gIkFjYWRlbWljIEhpZXJhcmNoeSIsIAogICAgICAgICAgICAgdGlja3RleHQgPSBjKCJHcmFkdWF0ZSBTdHVkZW50IiwgIlBvc3Rkb2N0b3JhbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICJBc3Npc3RhbnQgUHJvZi4iLCAiQXNzb2NpYXRlIFByb2YuIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlByb2Zlc3NvciIsICJDaGFpcmVkIFByb2YuIiwgIk5BIiksIHNob3dncmlkID0gRikpCmBgYAoKKioqCgpNb3JlIHZlcmJvc2Ugd2hlbiB0aGV5IGhhdmUgUGhEPyBZZXMhCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpnZ3Bsb3RseSgKICBnZ3Bsb3QoZWRnZURTX3ZlcmJvc2l0eSwgYWVzKEhhdmVQaEQsIE51bWJlci5DaGFyYWN0ZXJzKSkgKyBnZW9tX2JveHBsb3QoKSArCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9YygwLDQwMDApKSArIAogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEwMDAwLCBieSA9IDI1MCksIGxpbWl0cyA9IGMoMCwxOTAwMDApKSArCiAgICB0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX3B0b2woKQopICU+JSBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gIkFyZSB0aGV5IERvY3RvciBvZiBQaGlsb3NvcGh5PyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t0ZXh0ID0gYygiRG9udCBoYXZlIFBoRCIsICJIYXZlIFBoRCIsICJOQSIpKSkKYGBgCgpIb3cgbXVjaCBwZW9wbGUgd2l0aC9vdXQgUGhEIHdyaXRlIG9uIGF2ZXJhZ2U/CgpgYGB7cn0KZWRnZURTX3ZlcmJvc2l0eV9ocGhkX3kgPC0gZWRnZURTX3ZlcmJvc2l0eSAlPiUgZmlsdGVyKEhhdmVQaEQgPT0gMSkKbWVhbihlZGdlRFNfdmVyYm9zaXR5X2hwaGRfeSROdW1iZXIuQ2hhcmFjdGVycykKCmVkZ2VEU192ZXJib3NpdHlfaHBoZF9uIDwtIGVkZ2VEU192ZXJib3NpdHkgJT4lIGZpbHRlcihIYXZlUGhEID09IDApIAptZWFuKGVkZ2VEU192ZXJib3NpdHlfaHBoZF9uJE51bWJlci5DaGFyYWN0ZXJzKQpgYGAKCioqKgoKQnkgKkdlbmRlcioKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmdncGxvdGx5KAogIGdncGxvdChlZGdlRFNfdmVyYm9zaXR5LCBhZXMoR2VuZGVyLCBOdW1iZXIuQ2hhcmFjdGVycykpICsgZ2VvbV9ib3hwbG90KCkgKwogICAgY29vcmRfY2FydGVzaWFuKHlsaW0gPWMoMCw1MDAwKSkgKyAKICAgIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMDAwMCwgYnkgPSA1MDApLCBsaW1pdHMgPSBjKDAsMTkwMDAwKSkgKwogICAgdGhlbWVfbWluaW1hbCgpICsgc2NhbGVfZmlsbF9wdG9sKCkKKSAlPiUgbGF5b3V0KHhheGlzID0gbGlzdCh0aXRsZSA9ICJHZW5kZXIiLCB0aWNrdGV4dCA9IGMoIk1hbGUiLCAiRmVtYWxlIiwgIk5BIikpKQpgYGAKCioqKgoKUm9sZSA/CgpgYGB7cixmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmdncGxvdGx5KAogIGdncGxvdChlZGdlRFNfdmVyYm9zaXR5LCBhZXMoUm9sZSwgTnVtYmVyLkNoYXJhY3RlcnMpKSArIGdlb21fYm94cGxvdCgpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9YygwLDUwMDApKSArIAogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMDAwMCwgYnkgPSA1MDApLCBsaW1pdHMgPSBjKDAsMTkwMDAwKSkKKSAlPiUgbGF5b3V0KHhheGlzID0gbGlzdCh0aXRsZSA9ICJXaG8gd2VyZSBkZWJhdGVycz8iLCB0aWNrdGV4dCA9IGMoIkF1dGhvciIsICJDb21tZW50YXRvciIpKSkKYGBgCgoqKioKClRoZSBtb3N0IGNvbW1lbnRzIGFyZSB3cml0dGVuIHdoZW4gdGhlIGRlYmF0ZSBzaXplIGlzIGJlbG93IDIwMCBwZW9wbGUuIAoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KZ2dwbG90KGVkZ2VEU192ZXJib3NpdHksIGFlcyhEZWJhdGVTaXplLCBOdW1iZXIuQ2hhcmFjdGVycykpICsKICAgIGNvb3JkX2NhcnRlc2lhbih5bGltID1jKDAsNzAwMCkpICsgCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwMDAsIGJ5ID0gNTAwKSwgbGltaXRzID0gYygwLDE5MDAwMCkpICsKICAgIGdlb21fYm94cGxvdChhZXMoZ3JvdXAgPSBjdXRfaW50ZXJ2YWwoRGViYXRlU2l6ZSwgMTApKSkKYGBgCgoqKioKQ3JlYXRlIGJpbnMgZm9yIGgtaW5kZXggYW5kIGkxMC1pbmRleCAoKipjaXRhdGlvbnMqKikKCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmVkZ2VEU192ZXJib3NpdHkkaGluZGV4X2JpbiA8LSBjdXQoZWRnZURTX3ZlcmJvc2l0eSRIX0luZGV4LCBicmVha3M9c2VxKDAsMTUwLCBieSA9IDE1KSwgbGFiZWxzPWMoIjAtMTUiLCIxNS0zMCIsIjMwLTQ1IiwgIjQ1LTYwIiwgIjYwLTc1IiwgIjc1LTkwIiwgIjkwLTEwNSIsICIxMDUtMTIwIiwgIjEyMC0xMzUiLCAiMTM1LTE1MCIpKQoKZ2dwbG90bHkoCiAgZ2dwbG90KGVkZ2VEU192ZXJib3NpdHksIGFlcyhoaW5kZXhfYmluLCBOdW1iZXIuQ2hhcmFjdGVycykpICsgCiAgICBnZW9tX2JveHBsb3QoKSArCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9YygwLDcwMDApKSArIAogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEwMDAwLCBieSA9IDUwMCksIGxpbWl0cyA9IGMoMCwxOTAwMDApKQopCmBgYAoKKioqCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQplZGdlRFNfdmVyYm9zaXR5JGkxMF9iaW4gPC0gY3V0KGVkZ2VEU192ZXJib3NpdHkkaTEwX0luZGV4LCBicmVha3M9c2VxKDAsNjAwLCBieSA9IDQwKSkKCmdncGxvdGx5KAogIGdncGxvdChlZGdlRFNfdmVyYm9zaXR5LCBhZXMoaTEwX2JpbiwgTnVtYmVyLkNoYXJhY3RlcnMpKSArIGdlb21fYm94cGxvdCgpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIGNvb3JkX2NhcnRlc2lhbih5bGltID1jKDAsMTMwMDApKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTUwMDAsIGJ5ID0gMTAwMCksIGxpbWl0cyA9IGMoMCwxOTAwMDApKQopCmBgYAoKCmBgYHtyfQpybShlZGdlRFNfdmVyYm9zaXR5X2FjYV9uLCBlZGdlRFNfdmVyYm9zaXR5X2FjYV95LCBkZl9hbm5vdGF0aW9uc0ZvckZhY2V0cywgZWRnZURTX3ZlcmJvc2l0eV9ocGhkX3ksIAogICBlZGdlRFNfdmVyYm9zaXR5X2Rpc2NfZGlmZiwgZWRnZURTX3ZlcmJvc2l0eV9ocGhkX24sIGVkZ2VEU192ZXJib3NpdHkpCmBgYAoKKioqCgojIyBDb21wYXJlIGhpZ2hlciBzdGF0dXMgcGFydGljaXBhbnRzIHdpdGggYWxsIHRoZSByZXN0LgoKIyMjIENvbXBhcmlzb24gIzE6IFRvcCAxMDAgaW4gQWNhZGVtaWEgd2l0aCBQaEQKCldoYXQgSSBjYWxsICJIaWdoIEZseWVycyIgYXJlIHNvbWVib2R5IHdobyBpcyBpbiBBY2FkZW1pYSB3aXRoIFBoRCAoZnJvbSBUT1AgMTAwIHVuaXZlcnNpdGllcyBhY2NvcmRpbmcgdG8gU2hhbmdoYWkgUmFua2luZyBhbmQgVVMgTmV3cyBhbmQgV29ybGQgUmVwb3J0ZWQgLSB1bmlvbikgYW5kIHdoZXJlIHRoZWlyIHVuaXZlcnNpdHkgd29ya3BsYWNlIAp3YXMgYWxzbyByYW5rZWQgaW4gVE9QIDEwMCAodW5pb24pLiAKCmBgYHtyfQpoaWdoX2ZseWVycyA8LSBlZGdlRFMgJT4lIAogIGZpbHRlcihBY2FkZW1pYyA9PSAiQWNhZGVtaWNpYW5zIiAmIEhhdmVQaEQgPT0gMSkgJT4lIAogIGZpbHRlcihQaERfSW5zdGl0dXRpb25fU1JfQmluICVpbiUgYygxLDIpIHwgUGhEX0luc3RpdHV0aW9uX1VTX0lSX0JpbiAlaW4lIGMoMSwyKSkgJT4lIAogIGZpbHRlcihXb3JrcGxhY2VfU1JfQmluICVpbiUgYygxLDIpIHwgV29ya3BsYWNlX1VTX0lSX0JpbiAlaW4lIGMoMSwyKSkgJT4lIAogIHNlbGVjdChZZWFyLCBOdW1iZXIuQ2hhcmFjdGVycykgJT4lIAogIGdyb3VwX2J5KFllYXIpICU+JSAKICBzdW1tYXJpc2UoTnVtYmVyLkNoYXJhY3RlcnMgPSBzdW0oTnVtYmVyLkNoYXJhY3RlcnMpKSAlPiUgCiAgbXV0YXRlKHR5cGUgPSAiaGlnaF9mbHllcnMiKQoKaGlnaF9mbHllcnNfb3BwbyA8LSBlZGdlRFMgJT4lIAogIGZpbHRlcighKEFjYWRlbWljID09ICJBY2FkZW1pY2lhbnMiICYgSGF2ZVBoRCA9PSAxKSkgJT4lIAogIGZpbHRlcighKFBoRF9JbnN0aXR1dGlvbl9TUl9CaW4gJWluJSBjKDEsMikgfCBQaERfSW5zdGl0dXRpb25fVVNfSVJfQmluICVpbiUgYygxLDIpKSkgJT4lIAogIGZpbHRlcighKFdvcmtwbGFjZV9TUl9CaW4gJWluJSBjKDEsMikgfCBXb3JrcGxhY2VfVVNfSVJfQmluICVpbiUgYygxLDIpKSkgJT4lIAogIHdyaXRlX2Nzdigifi9kb2N1bWVudHMvUi1naXRodWIvQ3Jvd2Rzb3VyY2luZ19EYXRhX0FuYWx5c2lzXzJfRURHRV9vcmcvaGlnaF9mbHllcnNfb3Bwby5jc3YiKSAlPiUgCiAgc2VsZWN0KFllYXIsIE51bWJlci5DaGFyYWN0ZXJzKSAlPiUgCiAgZ3JvdXBfYnkoWWVhcikgJT4lIAogIHN1bW1hcmlzZShOdW1iZXIuQ2hhcmFjdGVycyA9IHN1bShOdW1iZXIuQ2hhcmFjdGVycykpICU+JSAKICBtdXRhdGUodHlwZSA9ICJoaWdoX2ZseWVyc19vcHBvIikKICAKZGYgPC0gcmJpbmQoaGlnaF9mbHllcnMsaGlnaF9mbHllcnNfb3BwbyApCmBgYAoKKioqCgpBZnRlciBkYXRhIGFyZSBwcmVwYXJlZCwgcGxvdCB0aGVtIG5vdy4gCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQpnZ3Bsb3QoZGYsIGFlcyh4PVllYXIsIHkgPSBOdW1iZXIuQ2hhcmFjdGVycywgZmlsbCA9IGFzLmZhY3Rvcih0eXBlKSkpICsgCiAgZ2VvbV9iYXIocG9zaXRpb249ImRvZGdlIiwgc3RhdD0iaWRlbnRpdHkiKSArICMgZ2VvbV9saW5lKGFlcyhjb2xvciA9IGFzLmZhY3Rvcih0eXBlKSkpICsKICB0aGVtZV9taW5pbWFsKCkgKyBzY2FsZV9maWxsX3B0b2woKSArIAogIGxhYnMoZmlsbCA9ICJUeXBlIiwgY29sb3IgPSAiVHlwZSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gcHJldHR5KHVuaXF1ZShkZiRZZWFyKSwgbiA9IDE5KSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwMDAwMCwgYnkgPSA1MDAwMCksIGxhYmVscyA9IGNvbW1hKSArIAogIGdndGl0bGUoIkN1bW11bGF0aXZlIHN1bSBvZiBjaGFyYWN0ZXJzIHBlciB5ZWFyIGFuZCBncm91cCIsIAogICAgICAgICAgc3VidGl0bGUgPSAiRXhjZXB0IGZvciBhIGZldyB5ZWFycyB3aGVyZSBpdCBpcyBhbG1vc3QgZXF1YWwgb3IgZXZlbiBoaWdoZXIsIAogICAgICAgICAgaGlnaCBmbHllcnMgY29tbWVudCBtdWNoIG1vcmUgdGhhbiBub24taGlnaC1mbHllcnMuIikKYGBgCgoqKioKCiMgUiBTZXNzaW9uL0RldnRvb2xzCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAK