This is the behavioral analysis to go along with the MemoHR fMRI project.

1 Load & process data

1.0.1 Options

subjects <- c('s04','s05','s06','s07','s08','s09','s10','s11',
              's13','s14','s16','s17','s18',
              's19','s20','s21','s22','s23','s25','s26','s27','s28') # subjects included in fMRI analysis
datadir <- '/Volumes/External/MemoHR/Data/Behavioral/'
outdir <- paste(datadir,'summary/',sep='')
readOriginal <- FALSE # read in original csv files; otherwise pull from existing behavior_unprocessedData.Rdata 
processData <- FALSE # recode variables etc; otherwise pull from existing behavior_processedData.Rdata 
writeFiles <- FALSE # save out clean datafile per subject 
dir.create(outdir)
'/Volumes/External/MemoHR/Data/Behavioral/summary' already exists

1.0.2 Read in original data

if (readOriginal) {
  encdata <- data.frame()
  recdata <- data.frame()
  for (sub in subjects) {
    sub.encdata <- read.csv(paste(datadir,sub,'/',sub,'_encoding.csv',sep=""))
    sub.recdata <- read.csv(paste(datadir,sub,'/',sub,'_recognition.csv',sep=""))
    
    sub.encdata$X <- NULL
    sub.recdata$X <- NULL
    encdata <- rbind(encdata,sub.encdata)
    recdata <- rbind(recdata,sub.recdata)
    save(encdata,recdata,outdir,subjects,file=paste(outdir,"behavior_unprocessedData.Rdata",sep=""))
  }
} else {
  load(paste(outdir,"behavior_unprocessedData.Rdata",sep=""))
}
table(encdata$participant) # number of rows per participant - should be 192 trials + 6 run onset rows (except s20, missing one run)

  4   5   6   7   8   9  10  11  13  14  16  17  18  19  20  21  22  23  25  26  27  28 
198 198 198 198 198 198 198 198 198 198 198 198 198 198 165 198 198 198 198 198 198 198 

1.0.3 Process data

if (processData) {
  # Recode run numbers and trial numbers (start from 1 not 0)
  encdata$runs.thisN <- encdata$runs.thisN + 1
  encdata$trials.thisN <- encdata$trials.thisN + 1
  recdata$trials.thisN <- recdata$trials.thisN + 1
  
  # Recode responses
  encdata$responses.enc <- encdata$response.keys
  encdata$responses.enc <- factor(encdata$responses.enc,levels=c("1","2","3","4"))
  recdata$responses.itemrec <- revalue(recdata$response_itemrec.keys,c("n"="new","b"="fam","v"="rem"))
  recdata$responses.itemrec <- factor(recdata$responses.itemrec,levels=c("new","fam","rem"))
  recdata$responses.sourcerec <- revalue(recdata$response_sourcerec.keys,c("v"="within SF?","b"="professional photo?"))
  recdata$responses.sourceconf <- revalue(recdata$response_sourceconf.keys,c("v"="sure","b"="unsure"))
  recdata$responses.sourceconf <- factor(recdata$responses.sourceconf,levels=c("sure","unsure"))
  # Score item memory responses
  oldmask <- which(recdata$TrialType=="Old")
  newmask <- which(recdata$TrialType=="New")
  Fresp <- which(recdata$responses.itemrec=="fam")
  Rresp <- which(recdata$responses.itemrec=="rem")
  Nresp <- which(recdata$responses.itemrec=="new")
  recdata$itemScore <- factor(NA,levels=c("Rec","Fam","Miss","R-FA","F-FA","CR"))
  recdata$itemScore[intersect(oldmask,Rresp)] <- "Rec"
  recdata$itemScore[intersect(oldmask,Fresp)] <- "Fam"
  recdata$itemScore[intersect(oldmask,Nresp)] <- "Miss"
  recdata$itemScore[intersect(newmask,Rresp)] <- "R-FA"
  recdata$itemScore[intersect(newmask,Fresp)] <- "F-FA"
  recdata$itemScore[intersect(newmask,Nresp)] <- "CR"
  table(recdata$participant,recdata$itemScore)
  
  # Score source memory responses
  encdata$ConLabel <- factor(encdata$ConLabel,levels=c("within SF?","professional photo?"))
  recdata$ConLabel <- factor(recdata$ConLabel,levels=c("within SF?","professional photo?"))
  recdata$responses.sourcerec <- factor(recdata$responses.sourcerec,levels=c("within SF?","professional photo?"))
  recdata$sourceScore <- factor(NA,levels=c("Correct","Incorrect"))
  recdata$sourceScore[recdata$ConLabel==recdata$responses.sourcerec & !is.na(recdata$responses.sourcerec)] <- "Correct"
  recdata$sourceScore[recdata$ConLabel!=recdata$responses.sourcerec & !is.na(recdata$responses.sourcerec) & recdata$TrialType=="Old"] <- "Incorrect"
  summary(recdata$sourceScore)
  recdata$sourceScore.sure <- factor(NA,levels=c("Correct","Incorrect"))
  recdata$sourceScore.sure[recdata$ConLabel==recdata$responses.sourcerec & !is.na(recdata$responses.sourcerec) & recdata$responses.sourceconf=="sure"] <- "Correct"
  recdata$sourceScore.sure[recdata$ConLabel!=recdata$responses.sourcerec & !is.na(recdata$responses.sourcerec) & recdata$TrialType=="Old"] <- "Incorrect"
  recdata$sourceScore.sure[recdata$ConLabel==recdata$responses.sourcerec & !is.na(recdata$responses.sourcerec) & recdata$responses.sourceconf=="unsure"] <- "Incorrect"
  summary(recdata$sourceScore.sure)
  table(interaction(recdata$ConLabel,recdata$participant),recdata$sourceScore)
  
  # Get rid of extra run onset rows in encoding
  encdata <- subset(encdata,!is.na(onsetTimeTrial))
  
  # Merge data
  alldata <- merge(encdata,recdata,by=c("participant","ID","EmotionType","TrialType",
                                     "Category","ConID","ImageFile","Category","condition",
                                     "ConList","ConLabel","CB"),all.x=TRUE,all.y=TRUE,suffixes=c('.E','.R'))
  alldata$EmotionType <- revalue(alldata$EmotionType,c("Negative"="Emo","Neutral"="Neu"))
  
  # Save cleaned up version
  outputdata <- alldata[,c("participant","ID","EmotionType","TrialType","Category","CB","ConLabel",
                        "runs.thisN","trials.thisN.E","onsetTimeCue","onsetTimeTrial","responses.enc","response.rt",
                        "trials.thisN.R","responses.itemrec","responses.sourcerec","responses.sourceconf",
                        "response_itemrec.rt","response_sourcerec.rt","response_sourceconf.rt","itemScore","sourceScore",
                        "sourceScore.sure")]
  
  save(outputdata,file=paste(outdir,"behavior_processedData.Rdata",sep=""))
} else {
  load(paste(outdir,"behavior_processedData.Rdata",sep=""))
}

1.0.4 Write clean datafiles

if (writeFiles) {
  for (sub in subjects) {
    # Write out a cleaned up csv of all of the data - used for generating model regressors later
    outputdata.cursub <- subset(outputdata,participant==as.numeric(substring(sub,2,3))) 
    dataFilename <- paste(datadir,sub,'/',sub,'_alldata.csv',sep="")
    write.csv(outputdata.cursub, file=dataFilename)
  }
}

2 Analyze memory data

2.1 Item recognition

2.1.1 Base response rates

# denominator
sumdata.itemrec <- filter(outputdata,!is.na(itemScore) & TrialType=="Old") %>%
  group_by(participant,EmotionType) %>%
  summarize(allFreq = length(EmotionType))
# numerator
curdata.itemrec <- filter(outputdata,!is.na(itemScore) & TrialType=="Old") %>%
  group_by(participant,EmotionType,itemScore) %>%
  summarize(respFreq = length(itemScore)) 
# rate
curdata.itemrec <- merge(curdata.itemrec,sumdata.itemrec,by=c("participant","EmotionType")) %>%
  mutate(respRate = respFreq/allFreq,
         x = interaction(EmotionType,itemScore))
# Plot mean+-SEM rates
meandata.itemrec <- filter(curdata.itemrec,!is.na(itemScore)) %>%
  group_by(itemScore,EmotionType) %>%
  summarize(meanval=mean(respRate),
            sdval=sd(respRate),
            sem=sdval/sqrt(length(respRate)),
            nsubj=length(respRate))
mybarplot(data=meandata.itemrec,xvar="EmotionType",fillvar="EmotionType",facets=c(".","itemScore"),errorbars=TRUE) + 
  ylab('Response Rate') + xlab('') + theme_minimal(24) # functions from memolabr

These are just the basic response rates. Now let’s estimate recollection and familiarity. We’ll correct for false alarms, and familiarity will be adjusted according to the independence assumption (i.e., familiarity reflects number of Fam responses corrected for the rate of Rec responses).

2.1.2 Corrected rates

2.1.2.1 Calculate corrected rates

# denominator
sumdata.itemrec.corr <- filter(outputdata,!is.na(itemScore)) %>%
  group_by(participant,EmotionType,TrialType) %>%
  summarize(allFreq = length(EmotionType))
# numerator
curdata.itemrec.corr <- filter(outputdata,!is.na(itemScore)) %>%
  group_by(participant,EmotionType,itemScore,TrialType) %>%
  summarize(respFreq = length(itemScore)) # trials of each type
# rates
curdata.itemrec.corr.allrates <- merge(curdata.itemrec.corr,sumdata.itemrec.corr,by=c("participant","EmotionType","TrialType")) %>%
  mutate(respRate = respFreq/allFreq) # calculate response rate
# Calculate rates - filling in zeroes for anyone with missing combination (e.g., no recollection FAs)
curdata.itemrec.corr.allrates.summary <- 
  group_by(curdata.itemrec.corr.allrates,participant,EmotionType) %>%
  mutate(tmp1=length(which(itemScore=="R-FA")),
         Rold=respRate[itemScore=="Rec"],
         Rnew=ifelse(tmp1>0,respRate[itemScore=="R-FA"],0),
         tmp2=length(which(itemScore=="F-FA")),
         Fold=respRate[itemScore=="Fam"],
         Fnew=ifelse(tmp2>0,respRate[itemScore=="F-FA"],0),
         tmp3=length(which(itemScore=="Miss")),
         missRate = ifelse(tmp3>0,respRate[itemScore=="Miss"],0),
         tmp4=length(which(itemScore=="CR")),
         CRrate = ifelse(tmp4>0,respRate[itemScore=="CR"],0)
  ) %>% 
  select(participant,EmotionType,Rold,Rnew,Fold,Fnew,missRate,CRrate) %>%
  unique() %>%
  as.data.frame()
# Calculate corrected rates - somewhat redundant with above for legacy reasons
curdata.itemrec.corr <- 
  group_by(curdata.itemrec.corr.allrates,participant,EmotionType) %>%
  mutate(tmp1=length(which(itemScore=="R-FA")),
         Rold=respRate[itemScore=="Rec"],
         Rnew=ifelse(tmp1>0,respRate[itemScore=="R-FA"],0),
         cRec=(Rold - Rnew)/(1 - Rnew),
         tmp2=length(which(itemScore=="F-FA")),
         Fold=respRate[itemScore=="Fam"],
         Fnew=ifelse(tmp2>0,respRate[itemScore=="F-FA"],0),
         cFam=(Fold/(1-Rold)) - (Fnew/(1-Rnew))
  ) %>% 
  select(participant,EmotionType,cRec,cFam) %>%
  unique() %>%
  gather("correctedRate","value",3:4) %>%
  as.data.frame()

2.1.2.2 Plot & stats for item recognition

# Plot mean+-SEM
curdata.itemrec.corr$correctedRate <- factor(curdata.itemrec.corr$correctedRate,levels=c("cRec","cFam"))
meandata.itemrec.corr <- filter(curdata.itemrec.corr,!is.na(correctedRate)) %>%
  group_by(correctedRate,EmotionType) %>%
  summarize(meanval=mean(value),
            sdval=sd(value),
            sem = sdval/sqrt(length(value)),
            nsubj=length(value)) 
mybarplot(data=meandata.itemrec.corr,xvar="EmotionType",fillvar="EmotionType",facets=c(".","correctedRate"),errorbars=TRUE) +
  ylab('Corrected Rate') + xlab('') + theme_minimal(24) #+ scale_y_continuous(expand=c(0.01,0.01))

# Stats
## Recollection
ezANOVA(data=subset(curdata.itemrec.corr,correctedRate=="cRec"),dv=value,wid=participant,within=c(EmotionType),type=3)
Converting "participant" to factor for ANOVA.You have removed one or more levels from variable "EmotionType". Refactoring for ANOVA.
$ANOVA
## Familiarity
ezANOVA(data=subset(curdata.itemrec.corr,correctedRate=="cFam"),dv=value,wid=participant,within=c(EmotionType),type=3)
Converting "participant" to factor for ANOVA.You have removed one or more levels from variable "EmotionType". Refactoring for ANOVA.
$ANOVA
# Store corrected recognition scores
itemrecdata <- spread(curdata.itemrec.corr,correctedRate,value)
itemrecdata %>%
  group_by(participant) %>%
  summarize(cRec = cRec[EmotionType=="Emo"] - cRec[EmotionType=="Neu"],
            cFam = cFam[EmotionType=="Emo"] - cFam[EmotionType=="Neu"],
            EmotionType = 'EmovNeu') -> tmp
itemrecdata %>%
  select(participant,cRec,cFam,EmotionType) %>%
  rbind(tmp) -> itemrecdata
head(itemrecdata)

There is a significant enhancing effect of emotion on recollection estimates but not on familiarity estimates.

2.2 Source memory

2.2.1 Both levels of confidence - Stats for source memory

# denominator
outputdata %>%
  filter(!is.na(sourceScore) & TrialType=="Old" & itemScore!="Miss") %>%
  group_by(participant,EmotionType) %>%
  summarize(allFreq = length(EmotionType)) -> sumdata.src
# numerator
outputdata %>%
  filter(TrialType=="Old" & itemScore!="Miss") %>%
  group_by(participant,EmotionType,sourceScore) %>%
  summarize(respFreq = length(sourceScore)) -> curdata.src
# rates
curdata.src <- merge(curdata.src,sumdata.src,by=c("participant","EmotionType")) %>%
  mutate(respRate = respFreq/allFreq) %>%
  filter(sourceScore=="Correct")
# Plot mean+-SE
curdata.src %>%
  group_by(EmotionType) %>%
  summarize(meanval=mean(respRate),
            sdval=sd(respRate),
            sem = sdval/sqrt(length(respRate)),
            nsubj=length(respRate)) -> meandata.src
mybarplot(data=meandata.src,xvar="EmotionType",fillvar="EmotionType",errorbars=TRUE) +
  ylab('Source Accuracy') + geom_hline(aes(yintercept=.5), linetype="dashed") + theme_minimal(24)

# Stats
## Source Accuracy
ezANOVA(data=as.data.frame(curdata.src),dv=respRate,wid=participant,within=c(EmotionType),type=3)
Converting "participant" to factor for ANOVA.You have removed one or more levels from variable "EmotionType". Refactoring for ANOVA.
$ANOVA
## Source Accuracy corrected for chance rate (for testing intercept)
curdata.src$respRate.corr <- curdata.src$respRate - .5
ezANOVA(data=as.data.frame(curdata.src),dv=respRate.corr,wid=participant,within=c(EmotionType),type=3,detailed=TRUE)
Converting "participant" to factor for ANOVA.You have removed one or more levels from variable "EmotionType". Refactoring for ANOVA.
$ANOVA
# #### Store source recognition scores
curdata.src %>%
  group_by(participant) %>%
  summarize(sourceRate = respRate[EmotionType=="Emo"] - respRate[EmotionType=="Neu"],
            EmotionType = 'EmovNeu') -> tmp
curdata.src %>%
  mutate(sourceRate = respRate) %>%
  select(participant,sourceRate,EmotionType) %>%
  rbind(tmp) -> sourcerecdata
head(sourcerecdata)

There is no significant effect of emotion on source accuracy (collapsing high and low confidence). What if we now consider high-confidence responses only?

2.2.2 High-confidence source memory

# ### Plot source memory distribution: Rate
# denominator
outputdata %>%
  filter(!is.na(sourceScore.sure) & TrialType=="Old" & itemScore!="Miss") %>%
  group_by(participant,EmotionType) %>%
  summarize(allFreq = length(EmotionType)) -> sumdata.src.sure
# numerator
outputdata %>%
  filter(TrialType=="Old" & itemScore!="Miss") %>%
  group_by(participant,EmotionType,sourceScore.sure) %>%
  summarize(respFreq = length(sourceScore.sure)) -> curdata.src.sure
# rate
curdata.src.sure <- merge(curdata.src.sure,sumdata.src.sure,by=c("participant","EmotionType")) %>%
  mutate(respRate = respFreq/allFreq) %>%
  filter(sourceScore.sure=="Correct")
# Plot mean+-SEM
curdata.src.sure %>%
  group_by(EmotionType) %>%
  summarize(meanval=mean(respRate),
            sdval=sd(respRate),
            sem = sdval/sqrt(length(respRate)),
            nsubj=length(respRate)) -> meandata.src.sure
mybarplot(data=meandata.src.sure,xvar="EmotionType",fillvar="EmotionType",errorbars=TRUE) +
  ylab('Source Accuracy') + theme_minimal(24)

# Stats
## Source Accuracy - High confidence
ezANOVA(data=as.data.frame(curdata.src.sure),dv=respRate,wid=participant,within=c(EmotionType),type=3)
Converting "participant" to factor for ANOVA.You have removed one or more levels from variable "EmotionType". Refactoring for ANOVA.
$ANOVA
# #### Store source recognition scores
curdata.src.sure %>%
  group_by(participant) %>%
  summarize(sourceRate = respRate[EmotionType=="Emo"] - respRate[EmotionType=="Neu"],
            EmotionType = 'EmovNeu') -> tmp
curdata.src.sure %>%
  mutate(sourceRate = respRate) %>%
  select(participant,sourceRate,EmotionType) %>%
  rbind(tmp) -> sourcerecdata.sure.all

There appears to be an impairing effect of emotion on high-confidence source accuracy. However, this estimate is not corrected for bias to use the high-confidence rating. So let’s fix that.

2.2.3 High-confidence source memory correcting for high-conf incorrect

# Relabel only "sure" incorrect responses as incorrect; unsure marked unsure
outputdata$sourceScore.sure.new <- factor(NA,levels=c("Correct","Incorrect","Unsure"))
outputdata$sourceScore.sure.new[outputdata$ConLabel==outputdata$responses.sourcerec & !is.na(outputdata$responses.sourcerec) & outputdata$responses.sourceconf=="sure"  & outputdata$TrialType=="Old"] <- "Correct"
outputdata$sourceScore.sure.new[outputdata$ConLabel!=outputdata$responses.sourcerec & !is.na(outputdata$responses.sourcerec) & outputdata$responses.sourceconf=="sure" & outputdata$TrialType=="Old"] <- "Incorrect"
outputdata$sourceScore.sure.new[!is.na(outputdata$responses.sourcerec) & outputdata$responses.sourceconf=="unsure" & outputdata$TrialType=="Old"] <- "Unsure"
# denominator
outputdata %>%
  filter(!is.na(sourceScore.sure.new) & TrialType=="Old" & itemScore!="Miss") %>%
  group_by(participant,EmotionType) %>%
  summarize(allFreq = length(EmotionType)) -> sumdata.src.corr
# numerator
outputdata %>%
  filter(TrialType=="Old" & itemScore!="Miss") %>%
  group_by(participant,EmotionType,sourceScore.sure.new) %>%
  summarize(respFreq = length(sourceScore.sure.new)) -> curdata.src.corr
# rate
curdata.src.corr <- merge(curdata.src.corr,sumdata.src.corr,by=c("participant","EmotionType")) %>%
  mutate(respRate = respFreq/allFreq)
# the above was the same as before - now correct for rate of high-confidence incorrect source responses
curdata.src.corr <- curdata.src.corr %>%
  group_by(participant,EmotionType) %>%
  mutate(nFA = length(respRate[sourceScore.sure.new=="Incorrect"]),
         respRate = ifelse(nFA>0,
                           respRate[sourceScore.sure.new=="Correct"] - respRate[sourceScore.sure.new=="Incorrect"],
                           respRate[sourceScore.sure.new=="Correct"])) %>%
  filter(sourceScore.sure.new=="Correct") # corrected for incorrect sure responses (old items only)
# Plot mean+-SEM
curdata.src.corr %>% 
  group_by(EmotionType) %>%
  summarize(meanval=mean(respRate),
            sdval=sd(respRate),
            sem = sdval/sqrt(length(respRate)),
            nsubj=length(respRate)) -> meandata.src.corr
mybarplot(data=meandata.src.corr,xvar="EmotionType",fillvar="EmotionType",errorbars=TRUE) +
  ylab('Source Accuracy') + theme_minimal(24)

#' #### Stats
#' Source Accuracy
ezANOVA(data=as.data.frame(curdata.src.corr),dv=respRate,wid=participant,within=c(EmotionType),type=3)
Converting "participant" to factor for ANOVA.You have removed one or more levels from variable "EmotionType". Refactoring for ANOVA.
$ANOVA
NA

After correcting the high-confidence source accuracy rates, there is no significant effect of emotion.

3 Summarize data

3.1 Save scores

# Merge together all summary measures (itemrec, sourcerec, sourcerec-sure)
sourcerecdata <- merge(sourcerecdata,sourcerecdata.sure.all,by=c("participant","EmotionType"),suffixes=c("",".sure"))
summarydata <- merge(itemrecdata,sourcerecdata,by=c("participant","EmotionType"),suffixes=c(".item",".source"))
# use subject IDs instead of just numbers
snamefun <- function(s) {
  if (s<10) {sname <- paste0('s0',as.character(s))}
  else { sname <- paste0('s',as.character(s))}
  return(sname)
}
summarydata$subject <- sapply(summarydata$participant,snamefun)
head(summarydata)
write.csv(summarydata,file=paste0(outdir,'behavioral_summary_scores.csv'))

3.2 Table of behavioral data

# separate for easy indexing in markdown-formatted table (below)
summarydata %>%
  filter(EmotionType=="Emo")  -> emoScores
summarydata %>%
  filter(EmotionType=="Neu")  -> neuScores
curdata.itemrec.corr.allrates.summary %>%
  filter(EmotionType=="Emo") -> emoScores.rates
curdata.itemrec.corr.allrates.summary %>%
  filter(EmotionType=="Neu") -> neuScores.rates
formatMSD <- function(df) {
  meanval <- mean(df)
  sdval <- sd(df)
  sprintf("%0.2f (%0.2f)",meanval,sdval)
}

3.2.1 Paper Table 1

Condition Remember rate Familiar rate New Rate Recollection estimate Familiarity estimate Source accuracy Source accuracy - high confidence
Emotion - old 0.60 (0.16) 0.26 (0.10) 0.14 (0.10) 0.60 (0.15) 0.53 (0.19) 0.67 (0.06) 0.36 (0.14)
Neutral - old 0.53 (0.18) 0.33 (0.13) 0.14 (0.10) 0.51 (0.18) 0.53 (0.15) 0.68 (0.08) 0.40 (0.13)
Emotion - new 0.02 (0.04) 0.14 (0.16) 0.85 (0.20) - - - -
Neutral - new 0.04 (0.04) 0.17 (0.13) 0.79 (0.15) - - - -

3.3 Paper Figure 2 - Behavioral data plot

plotcolors1 <- c('#e9a3c9','#a1d76a','#e9a3c9','#a1d76a','#e9a3c9','#a1d76a')
plotcolors2 <- c('#d01c8b','#4dac26')
# Reformat dataframe for easier plotting
summarydata %>%
  filter(EmotionType=="Emo" | EmotionType=="Neu") %>%
  gather(measure,value,-participant,-EmotionType,-subject) -> summarydata.long
summarydata.long$measure <- factor(summarydata.long$measure,levels=c("cRec","cFam","sourceRate","sourceRate.sure"))
summarydata.long.rec <- filter(summarydata.long,measure=="cRec" | measure=="cFam" | measure=="sourceRate" )
summarydata.long.src <- filter(summarydata.long,measure=="sourceRate" | measure=="sourceRate.sure")
# Plot all behavioral measures
summarydata.long.rec %>%
  group_by(measure,EmotionType) %>%
  summarize(meanval=mean(value),
            sem=sd(value)/sqrt(length(value))) %>%
  ggplot(aes(x=EmotionType,y=meanval)) + 
  geom_bar(stat="identity",color="gray40",fill=plotcolors1) + theme_minimal(18) +
  facet_grid(.~measure) +
  geom_dotplot(data=summarydata.long.rec,aes(x=EmotionType,y=value,fill=EmotionType), binaxis = "y", stackdir = "center", binwidth=.02) +
  geom_errorbar(aes(x=EmotionType,ymin=meanval-sem,ymax=meanval+sem,width=.2)) +
  scale_fill_manual(values=plotcolors2) + ylab("Mean corrected rate") + xlab("")

LS0tCnRpdGxlOiAiTWVtb0hSIGZNUkkgQmVoYXZpb3JhbCBEYXRhIgphdXRob3I6ICJNYXVyZWVuIFJpdGNoZXkiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgZmlnX2hlaWdodDogMwogICAgZmlnX3dpZHRoOiA1CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdGhlbWU6IHNwYWNlbGFiCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogIGh0bWxfZG9jdW1lbnQ6CiAgICBmaWdfaGVpZ2h0OiAzCiAgICBmaWdfd2lkdGg6IDUKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKVGhpcyBpcyB0aGUgYmVoYXZpb3JhbCBhbmFseXNpcyB0byBnbyBhbG9uZyB3aXRoIHRoZSBNZW1vSFIgZk1SSSBwcm9qZWN0LgoKYGBge3IgaW5pdGlhbGl6ZSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeSgncGx5cicpCmxpYnJhcnkoJ2V6JykKbGlicmFyeSgnZ2dwbG90MicpCmxpYnJhcnkoJ2RwbHlyJykKbGlicmFyeSgndGlkeXInKQpsaWJyYXJ5KCdtZW1vbGFicicpCmBgYAoKIyBMb2FkICYgcHJvY2VzcyBkYXRhCiMjIyBPcHRpb25zCmBgYHtyIGxvYWREYXRhfQpzdWJqZWN0cyA8LSBjKCdzMDQnLCdzMDUnLCdzMDYnLCdzMDcnLCdzMDgnLCdzMDknLCdzMTAnLCdzMTEnLAogICAgICAgICAgICAgICdzMTMnLCdzMTQnLCdzMTYnLCdzMTcnLCdzMTgnLAogICAgICAgICAgICAgICdzMTknLCdzMjAnLCdzMjEnLCdzMjInLCdzMjMnLCdzMjUnLCdzMjYnLCdzMjcnLCdzMjgnKSAjIHN1YmplY3RzIGluY2x1ZGVkIGluIGZNUkkgYW5hbHlzaXMKZGF0YWRpciA8LSAnL1ZvbHVtZXMvRXh0ZXJuYWwvTWVtb0hSL0RhdGEvQmVoYXZpb3JhbC8nCm91dGRpciA8LSBwYXN0ZShkYXRhZGlyLCdzdW1tYXJ5Lycsc2VwPScnKQpyZWFkT3JpZ2luYWwgPC0gRkFMU0UgIyByZWFkIGluIG9yaWdpbmFsIGNzdiBmaWxlczsgb3RoZXJ3aXNlIHB1bGwgZnJvbSBleGlzdGluZyBiZWhhdmlvcl91bnByb2Nlc3NlZERhdGEuUmRhdGEgCnByb2Nlc3NEYXRhIDwtIEZBTFNFICMgcmVjb2RlIHZhcmlhYmxlcyBldGM7IG90aGVyd2lzZSBwdWxsIGZyb20gZXhpc3RpbmcgYmVoYXZpb3JfcHJvY2Vzc2VkRGF0YS5SZGF0YSAKd3JpdGVGaWxlcyA8LSBGQUxTRSAjIHNhdmUgb3V0IGNsZWFuIGRhdGFmaWxlIHBlciBzdWJqZWN0IAoKZGlyLmNyZWF0ZShvdXRkaXIpCgpgYGAKCiMjIyBSZWFkIGluIG9yaWdpbmFsIGRhdGEKYGBge3J9CmlmIChyZWFkT3JpZ2luYWwpIHsKICBlbmNkYXRhIDwtIGRhdGEuZnJhbWUoKQogIHJlY2RhdGEgPC0gZGF0YS5mcmFtZSgpCiAgZm9yIChzdWIgaW4gc3ViamVjdHMpIHsKICAgIHN1Yi5lbmNkYXRhIDwtIHJlYWQuY3N2KHBhc3RlKGRhdGFkaXIsc3ViLCcvJyxzdWIsJ19lbmNvZGluZy5jc3YnLHNlcD0iIikpCiAgICBzdWIucmVjZGF0YSA8LSByZWFkLmNzdihwYXN0ZShkYXRhZGlyLHN1YiwnLycsc3ViLCdfcmVjb2duaXRpb24uY3N2JyxzZXA9IiIpKQogICAgCiAgICBzdWIuZW5jZGF0YSRYIDwtIE5VTEwKICAgIHN1Yi5yZWNkYXRhJFggPC0gTlVMTAogICAgZW5jZGF0YSA8LSByYmluZChlbmNkYXRhLHN1Yi5lbmNkYXRhKQogICAgcmVjZGF0YSA8LSByYmluZChyZWNkYXRhLHN1Yi5yZWNkYXRhKQogICAgc2F2ZShlbmNkYXRhLHJlY2RhdGEsb3V0ZGlyLHN1YmplY3RzLGZpbGU9cGFzdGUob3V0ZGlyLCJiZWhhdmlvcl91bnByb2Nlc3NlZERhdGEuUmRhdGEiLHNlcD0iIikpCiAgfQp9IGVsc2UgewogIGxvYWQocGFzdGUob3V0ZGlyLCJiZWhhdmlvcl91bnByb2Nlc3NlZERhdGEuUmRhdGEiLHNlcD0iIikpCn0KdGFibGUoZW5jZGF0YSRwYXJ0aWNpcGFudCkgIyBudW1iZXIgb2Ygcm93cyBwZXIgcGFydGljaXBhbnQgLSBzaG91bGQgYmUgMTkyIHRyaWFscyArIDYgcnVuIG9uc2V0IHJvd3MgKGV4Y2VwdCBzMjAsIG1pc3Npbmcgb25lIHJ1bikKYGBgCgojIyMgUHJvY2VzcyBkYXRhCmBgYHtyIHByb2Nlc3NEYXRhfQppZiAocHJvY2Vzc0RhdGEpIHsKICAjIFJlY29kZSBydW4gbnVtYmVycyBhbmQgdHJpYWwgbnVtYmVycyAoc3RhcnQgZnJvbSAxIG5vdCAwKQogIGVuY2RhdGEkcnVucy50aGlzTiA8LSBlbmNkYXRhJHJ1bnMudGhpc04gKyAxCiAgZW5jZGF0YSR0cmlhbHMudGhpc04gPC0gZW5jZGF0YSR0cmlhbHMudGhpc04gKyAxCiAgcmVjZGF0YSR0cmlhbHMudGhpc04gPC0gcmVjZGF0YSR0cmlhbHMudGhpc04gKyAxCiAgCiAgIyBSZWNvZGUgcmVzcG9uc2VzCiAgZW5jZGF0YSRyZXNwb25zZXMuZW5jIDwtIGVuY2RhdGEkcmVzcG9uc2Uua2V5cwogIGVuY2RhdGEkcmVzcG9uc2VzLmVuYyA8LSBmYWN0b3IoZW5jZGF0YSRyZXNwb25zZXMuZW5jLGxldmVscz1jKCIxIiwiMiIsIjMiLCI0IikpCiAgcmVjZGF0YSRyZXNwb25zZXMuaXRlbXJlYyA8LSByZXZhbHVlKHJlY2RhdGEkcmVzcG9uc2VfaXRlbXJlYy5rZXlzLGMoIm4iPSJuZXciLCJiIj0iZmFtIiwidiI9InJlbSIpKQogIHJlY2RhdGEkcmVzcG9uc2VzLml0ZW1yZWMgPC0gZmFjdG9yKHJlY2RhdGEkcmVzcG9uc2VzLml0ZW1yZWMsbGV2ZWxzPWMoIm5ldyIsImZhbSIsInJlbSIpKQogIHJlY2RhdGEkcmVzcG9uc2VzLnNvdXJjZXJlYyA8LSByZXZhbHVlKHJlY2RhdGEkcmVzcG9uc2Vfc291cmNlcmVjLmtleXMsYygidiI9IndpdGhpbiBTRj8iLCJiIj0icHJvZmVzc2lvbmFsIHBob3RvPyIpKQogIHJlY2RhdGEkcmVzcG9uc2VzLnNvdXJjZWNvbmYgPC0gcmV2YWx1ZShyZWNkYXRhJHJlc3BvbnNlX3NvdXJjZWNvbmYua2V5cyxjKCJ2Ij0ic3VyZSIsImIiPSJ1bnN1cmUiKSkKICByZWNkYXRhJHJlc3BvbnNlcy5zb3VyY2Vjb25mIDwtIGZhY3RvcihyZWNkYXRhJHJlc3BvbnNlcy5zb3VyY2Vjb25mLGxldmVscz1jKCJzdXJlIiwidW5zdXJlIikpCgogICMgU2NvcmUgaXRlbSBtZW1vcnkgcmVzcG9uc2VzCiAgb2xkbWFzayA8LSB3aGljaChyZWNkYXRhJFRyaWFsVHlwZT09Ik9sZCIpCiAgbmV3bWFzayA8LSB3aGljaChyZWNkYXRhJFRyaWFsVHlwZT09Ik5ldyIpCiAgRnJlc3AgPC0gd2hpY2gocmVjZGF0YSRyZXNwb25zZXMuaXRlbXJlYz09ImZhbSIpCiAgUnJlc3AgPC0gd2hpY2gocmVjZGF0YSRyZXNwb25zZXMuaXRlbXJlYz09InJlbSIpCiAgTnJlc3AgPC0gd2hpY2gocmVjZGF0YSRyZXNwb25zZXMuaXRlbXJlYz09Im5ldyIpCiAgcmVjZGF0YSRpdGVtU2NvcmUgPC0gZmFjdG9yKE5BLGxldmVscz1jKCJSZWMiLCJGYW0iLCJNaXNzIiwiUi1GQSIsIkYtRkEiLCJDUiIpKQogIHJlY2RhdGEkaXRlbVNjb3JlW2ludGVyc2VjdChvbGRtYXNrLFJyZXNwKV0gPC0gIlJlYyIKICByZWNkYXRhJGl0ZW1TY29yZVtpbnRlcnNlY3Qob2xkbWFzayxGcmVzcCldIDwtICJGYW0iCiAgcmVjZGF0YSRpdGVtU2NvcmVbaW50ZXJzZWN0KG9sZG1hc2ssTnJlc3ApXSA8LSAiTWlzcyIKICByZWNkYXRhJGl0ZW1TY29yZVtpbnRlcnNlY3QobmV3bWFzayxScmVzcCldIDwtICJSLUZBIgogIHJlY2RhdGEkaXRlbVNjb3JlW2ludGVyc2VjdChuZXdtYXNrLEZyZXNwKV0gPC0gIkYtRkEiCiAgcmVjZGF0YSRpdGVtU2NvcmVbaW50ZXJzZWN0KG5ld21hc2ssTnJlc3ApXSA8LSAiQ1IiCiAgdGFibGUocmVjZGF0YSRwYXJ0aWNpcGFudCxyZWNkYXRhJGl0ZW1TY29yZSkKICAKICAjIFNjb3JlIHNvdXJjZSBtZW1vcnkgcmVzcG9uc2VzCiAgZW5jZGF0YSRDb25MYWJlbCA8LSBmYWN0b3IoZW5jZGF0YSRDb25MYWJlbCxsZXZlbHM9Yygid2l0aGluIFNGPyIsInByb2Zlc3Npb25hbCBwaG90bz8iKSkKICByZWNkYXRhJENvbkxhYmVsIDwtIGZhY3RvcihyZWNkYXRhJENvbkxhYmVsLGxldmVscz1jKCJ3aXRoaW4gU0Y/IiwicHJvZmVzc2lvbmFsIHBob3RvPyIpKQogIHJlY2RhdGEkcmVzcG9uc2VzLnNvdXJjZXJlYyA8LSBmYWN0b3IocmVjZGF0YSRyZXNwb25zZXMuc291cmNlcmVjLGxldmVscz1jKCJ3aXRoaW4gU0Y/IiwicHJvZmVzc2lvbmFsIHBob3RvPyIpKQogIHJlY2RhdGEkc291cmNlU2NvcmUgPC0gZmFjdG9yKE5BLGxldmVscz1jKCJDb3JyZWN0IiwiSW5jb3JyZWN0IikpCiAgcmVjZGF0YSRzb3VyY2VTY29yZVtyZWNkYXRhJENvbkxhYmVsPT1yZWNkYXRhJHJlc3BvbnNlcy5zb3VyY2VyZWMgJiAhaXMubmEocmVjZGF0YSRyZXNwb25zZXMuc291cmNlcmVjKV0gPC0gIkNvcnJlY3QiCiAgcmVjZGF0YSRzb3VyY2VTY29yZVtyZWNkYXRhJENvbkxhYmVsIT1yZWNkYXRhJHJlc3BvbnNlcy5zb3VyY2VyZWMgJiAhaXMubmEocmVjZGF0YSRyZXNwb25zZXMuc291cmNlcmVjKSAmIHJlY2RhdGEkVHJpYWxUeXBlPT0iT2xkIl0gPC0gIkluY29ycmVjdCIKICBzdW1tYXJ5KHJlY2RhdGEkc291cmNlU2NvcmUpCiAgcmVjZGF0YSRzb3VyY2VTY29yZS5zdXJlIDwtIGZhY3RvcihOQSxsZXZlbHM9YygiQ29ycmVjdCIsIkluY29ycmVjdCIpKQogIHJlY2RhdGEkc291cmNlU2NvcmUuc3VyZVtyZWNkYXRhJENvbkxhYmVsPT1yZWNkYXRhJHJlc3BvbnNlcy5zb3VyY2VyZWMgJiAhaXMubmEocmVjZGF0YSRyZXNwb25zZXMuc291cmNlcmVjKSAmIHJlY2RhdGEkcmVzcG9uc2VzLnNvdXJjZWNvbmY9PSJzdXJlIl0gPC0gIkNvcnJlY3QiCiAgcmVjZGF0YSRzb3VyY2VTY29yZS5zdXJlW3JlY2RhdGEkQ29uTGFiZWwhPXJlY2RhdGEkcmVzcG9uc2VzLnNvdXJjZXJlYyAmICFpcy5uYShyZWNkYXRhJHJlc3BvbnNlcy5zb3VyY2VyZWMpICYgcmVjZGF0YSRUcmlhbFR5cGU9PSJPbGQiXSA8LSAiSW5jb3JyZWN0IgogIHJlY2RhdGEkc291cmNlU2NvcmUuc3VyZVtyZWNkYXRhJENvbkxhYmVsPT1yZWNkYXRhJHJlc3BvbnNlcy5zb3VyY2VyZWMgJiAhaXMubmEocmVjZGF0YSRyZXNwb25zZXMuc291cmNlcmVjKSAmIHJlY2RhdGEkcmVzcG9uc2VzLnNvdXJjZWNvbmY9PSJ1bnN1cmUiXSA8LSAiSW5jb3JyZWN0IgogIHN1bW1hcnkocmVjZGF0YSRzb3VyY2VTY29yZS5zdXJlKQogIHRhYmxlKGludGVyYWN0aW9uKHJlY2RhdGEkQ29uTGFiZWwscmVjZGF0YSRwYXJ0aWNpcGFudCkscmVjZGF0YSRzb3VyY2VTY29yZSkKICAKICAjIEdldCByaWQgb2YgZXh0cmEgcnVuIG9uc2V0IHJvd3MgaW4gZW5jb2RpbmcKICBlbmNkYXRhIDwtIHN1YnNldChlbmNkYXRhLCFpcy5uYShvbnNldFRpbWVUcmlhbCkpCiAgCiAgIyBNZXJnZSBkYXRhCiAgYWxsZGF0YSA8LSBtZXJnZShlbmNkYXRhLHJlY2RhdGEsYnk9YygicGFydGljaXBhbnQiLCJJRCIsIkVtb3Rpb25UeXBlIiwiVHJpYWxUeXBlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDYXRlZ29yeSIsIkNvbklEIiwiSW1hZ2VGaWxlIiwiQ2F0ZWdvcnkiLCJjb25kaXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNvbkxpc3QiLCJDb25MYWJlbCIsIkNCIiksYWxsLng9VFJVRSxhbGwueT1UUlVFLHN1ZmZpeGVzPWMoJy5FJywnLlInKSkKICBhbGxkYXRhJEVtb3Rpb25UeXBlIDwtIHJldmFsdWUoYWxsZGF0YSRFbW90aW9uVHlwZSxjKCJOZWdhdGl2ZSI9IkVtbyIsIk5ldXRyYWwiPSJOZXUiKSkKICAKICAjIFNhdmUgY2xlYW5lZCB1cCB2ZXJzaW9uCiAgb3V0cHV0ZGF0YSA8LSBhbGxkYXRhWyxjKCJwYXJ0aWNpcGFudCIsIklEIiwiRW1vdGlvblR5cGUiLCJUcmlhbFR5cGUiLCJDYXRlZ29yeSIsIkNCIiwiQ29uTGFiZWwiLAogICAgICAgICAgICAgICAgICAgICAgICAicnVucy50aGlzTiIsInRyaWFscy50aGlzTi5FIiwib25zZXRUaW1lQ3VlIiwib25zZXRUaW1lVHJpYWwiLCJyZXNwb25zZXMuZW5jIiwicmVzcG9uc2UucnQiLAogICAgICAgICAgICAgICAgICAgICAgICAidHJpYWxzLnRoaXNOLlIiLCJyZXNwb25zZXMuaXRlbXJlYyIsInJlc3BvbnNlcy5zb3VyY2VyZWMiLCJyZXNwb25zZXMuc291cmNlY29uZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICJyZXNwb25zZV9pdGVtcmVjLnJ0IiwicmVzcG9uc2Vfc291cmNlcmVjLnJ0IiwicmVzcG9uc2Vfc291cmNlY29uZi5ydCIsIml0ZW1TY29yZSIsInNvdXJjZVNjb3JlIiwKICAgICAgICAgICAgICAgICAgICAgICAgInNvdXJjZVNjb3JlLnN1cmUiKV0KICAKICBzYXZlKG91dHB1dGRhdGEsZmlsZT1wYXN0ZShvdXRkaXIsImJlaGF2aW9yX3Byb2Nlc3NlZERhdGEuUmRhdGEiLHNlcD0iIikpCn0gZWxzZSB7CiAgbG9hZChwYXN0ZShvdXRkaXIsImJlaGF2aW9yX3Byb2Nlc3NlZERhdGEuUmRhdGEiLHNlcD0iIikpCn0KCmBgYAoKIyMjIFdyaXRlIGNsZWFuIGRhdGFmaWxlcwpgYGAge3Igd3JpdGVDbGVhbn0KCmlmICh3cml0ZUZpbGVzKSB7CiAgZm9yIChzdWIgaW4gc3ViamVjdHMpIHsKICAgICMgV3JpdGUgb3V0IGEgY2xlYW5lZCB1cCBjc3Ygb2YgYWxsIG9mIHRoZSBkYXRhIC0gdXNlZCBmb3IgZ2VuZXJhdGluZyBtb2RlbCByZWdyZXNzb3JzIGxhdGVyCiAgICBvdXRwdXRkYXRhLmN1cnN1YiA8LSBzdWJzZXQob3V0cHV0ZGF0YSxwYXJ0aWNpcGFudD09YXMubnVtZXJpYyhzdWJzdHJpbmcoc3ViLDIsMykpKSAKICAgIGRhdGFGaWxlbmFtZSA8LSBwYXN0ZShkYXRhZGlyLHN1YiwnLycsc3ViLCdfYWxsZGF0YS5jc3YnLHNlcD0iIikKICAgIHdyaXRlLmNzdihvdXRwdXRkYXRhLmN1cnN1YiwgZmlsZT1kYXRhRmlsZW5hbWUpCiAgfQp9CgpgYGAKCgojIEFuYWx5emUgbWVtb3J5IGRhdGEKIyMgSXRlbSByZWNvZ25pdGlvbgojIyMgQmFzZSByZXNwb25zZSByYXRlcwoKYGBge3IgaXRlbVJlY29nQW5hbHlzaXN9CgojIGRlbm9taW5hdG9yCnN1bWRhdGEuaXRlbXJlYyA8LSBmaWx0ZXIob3V0cHV0ZGF0YSwhaXMubmEoaXRlbVNjb3JlKSAmIFRyaWFsVHlwZT09Ik9sZCIpICU+JQogIGdyb3VwX2J5KHBhcnRpY2lwYW50LEVtb3Rpb25UeXBlKSAlPiUKICBzdW1tYXJpemUoYWxsRnJlcSA9IGxlbmd0aChFbW90aW9uVHlwZSkpCiMgbnVtZXJhdG9yCmN1cmRhdGEuaXRlbXJlYyA8LSBmaWx0ZXIob3V0cHV0ZGF0YSwhaXMubmEoaXRlbVNjb3JlKSAmIFRyaWFsVHlwZT09Ik9sZCIpICU+JQogIGdyb3VwX2J5KHBhcnRpY2lwYW50LEVtb3Rpb25UeXBlLGl0ZW1TY29yZSkgJT4lCiAgc3VtbWFyaXplKHJlc3BGcmVxID0gbGVuZ3RoKGl0ZW1TY29yZSkpIAojIHJhdGUKY3VyZGF0YS5pdGVtcmVjIDwtIG1lcmdlKGN1cmRhdGEuaXRlbXJlYyxzdW1kYXRhLml0ZW1yZWMsYnk9YygicGFydGljaXBhbnQiLCJFbW90aW9uVHlwZSIpKSAlPiUKICBtdXRhdGUocmVzcFJhdGUgPSByZXNwRnJlcS9hbGxGcmVxLAogICAgICAgICB4ID0gaW50ZXJhY3Rpb24oRW1vdGlvblR5cGUsaXRlbVNjb3JlKSkKCiMgUGxvdCBtZWFuKy1TRU0gcmF0ZXMKbWVhbmRhdGEuaXRlbXJlYyA8LSBmaWx0ZXIoY3VyZGF0YS5pdGVtcmVjLCFpcy5uYShpdGVtU2NvcmUpKSAlPiUKICBncm91cF9ieShpdGVtU2NvcmUsRW1vdGlvblR5cGUpICU+JQogIHN1bW1hcml6ZShtZWFudmFsPW1lYW4ocmVzcFJhdGUpLAogICAgICAgICAgICBzZHZhbD1zZChyZXNwUmF0ZSksCiAgICAgICAgICAgIHNlbT1zZHZhbC9zcXJ0KGxlbmd0aChyZXNwUmF0ZSkpLAogICAgICAgICAgICBuc3Viaj1sZW5ndGgocmVzcFJhdGUpKQpteWJhcnBsb3QoZGF0YT1tZWFuZGF0YS5pdGVtcmVjLHh2YXI9IkVtb3Rpb25UeXBlIixmaWxsdmFyPSJFbW90aW9uVHlwZSIsZmFjZXRzPWMoIi4iLCJpdGVtU2NvcmUiKSxlcnJvcmJhcnM9VFJVRSkgKyAKICB5bGFiKCdSZXNwb25zZSBSYXRlJykgKyB4bGFiKCcnKSArIHRoZW1lX21pbmltYWwoMjQpICMgZnVuY3Rpb25zIGZyb20gbWVtb2xhYnIKCmBgYAoKVGhlc2UgYXJlIGp1c3QgdGhlIGJhc2ljIHJlc3BvbnNlIHJhdGVzLiBOb3cgbGV0J3MgZXN0aW1hdGUgcmVjb2xsZWN0aW9uIGFuZCBmYW1pbGlhcml0eS4gV2UnbGwgY29ycmVjdCBmb3IgZmFsc2UgYWxhcm1zLCBhbmQgZmFtaWxpYXJpdHkgd2lsbCBiZSBhZGp1c3RlZCBhY2NvcmRpbmcgdG8gdGhlIGluZGVwZW5kZW5jZSBhc3N1bXB0aW9uIChpLmUuLCBmYW1pbGlhcml0eSByZWZsZWN0cyBudW1iZXIgb2YgRmFtIHJlc3BvbnNlcyBjb3JyZWN0ZWQgZm9yIHRoZSByYXRlIG9mIFJlYyByZXNwb25zZXMpLgoKIyMjIENvcnJlY3RlZCByYXRlcyAKIyMjIyBDYWxjdWxhdGUgY29ycmVjdGVkIHJhdGVzCgpgYGAge3IgaXRlbVJlY29nQW5hbHlzaXMtY29ycmVjdGVkfQoKIyBkZW5vbWluYXRvcgpzdW1kYXRhLml0ZW1yZWMuY29yciA8LSBmaWx0ZXIob3V0cHV0ZGF0YSwhaXMubmEoaXRlbVNjb3JlKSkgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQsRW1vdGlvblR5cGUsVHJpYWxUeXBlKSAlPiUKICBzdW1tYXJpemUoYWxsRnJlcSA9IGxlbmd0aChFbW90aW9uVHlwZSkpCiMgbnVtZXJhdG9yCmN1cmRhdGEuaXRlbXJlYy5jb3JyIDwtIGZpbHRlcihvdXRwdXRkYXRhLCFpcy5uYShpdGVtU2NvcmUpKSAlPiUKICBncm91cF9ieShwYXJ0aWNpcGFudCxFbW90aW9uVHlwZSxpdGVtU2NvcmUsVHJpYWxUeXBlKSAlPiUKICBzdW1tYXJpemUocmVzcEZyZXEgPSBsZW5ndGgoaXRlbVNjb3JlKSkgIyB0cmlhbHMgb2YgZWFjaCB0eXBlCiMgcmF0ZXMKY3VyZGF0YS5pdGVtcmVjLmNvcnIuYWxscmF0ZXMgPC0gbWVyZ2UoY3VyZGF0YS5pdGVtcmVjLmNvcnIsc3VtZGF0YS5pdGVtcmVjLmNvcnIsYnk9YygicGFydGljaXBhbnQiLCJFbW90aW9uVHlwZSIsIlRyaWFsVHlwZSIpKSAlPiUKICBtdXRhdGUocmVzcFJhdGUgPSByZXNwRnJlcS9hbGxGcmVxKSAjIGNhbGN1bGF0ZSByZXNwb25zZSByYXRlCgojIENhbGN1bGF0ZSByYXRlcyAtIGZpbGxpbmcgaW4gemVyb2VzIGZvciBhbnlvbmUgd2l0aCBtaXNzaW5nIGNvbWJpbmF0aW9uIChlLmcuLCBubyByZWNvbGxlY3Rpb24gRkFzKQpjdXJkYXRhLml0ZW1yZWMuY29yci5hbGxyYXRlcy5zdW1tYXJ5IDwtIAogIGdyb3VwX2J5KGN1cmRhdGEuaXRlbXJlYy5jb3JyLmFsbHJhdGVzLHBhcnRpY2lwYW50LEVtb3Rpb25UeXBlKSAlPiUKICBtdXRhdGUodG1wMT1sZW5ndGgod2hpY2goaXRlbVNjb3JlPT0iUi1GQSIpKSwKICAgICAgICAgUm9sZD1yZXNwUmF0ZVtpdGVtU2NvcmU9PSJSZWMiXSwKICAgICAgICAgUm5ldz1pZmVsc2UodG1wMT4wLHJlc3BSYXRlW2l0ZW1TY29yZT09IlItRkEiXSwwKSwKICAgICAgICAgdG1wMj1sZW5ndGgod2hpY2goaXRlbVNjb3JlPT0iRi1GQSIpKSwKICAgICAgICAgRm9sZD1yZXNwUmF0ZVtpdGVtU2NvcmU9PSJGYW0iXSwKICAgICAgICAgRm5ldz1pZmVsc2UodG1wMj4wLHJlc3BSYXRlW2l0ZW1TY29yZT09IkYtRkEiXSwwKSwKICAgICAgICAgdG1wMz1sZW5ndGgod2hpY2goaXRlbVNjb3JlPT0iTWlzcyIpKSwKICAgICAgICAgbWlzc1JhdGUgPSBpZmVsc2UodG1wMz4wLHJlc3BSYXRlW2l0ZW1TY29yZT09Ik1pc3MiXSwwKSwKICAgICAgICAgdG1wND1sZW5ndGgod2hpY2goaXRlbVNjb3JlPT0iQ1IiKSksCiAgICAgICAgIENScmF0ZSA9IGlmZWxzZSh0bXA0PjAscmVzcFJhdGVbaXRlbVNjb3JlPT0iQ1IiXSwwKQogICkgJT4lIAogIHNlbGVjdChwYXJ0aWNpcGFudCxFbW90aW9uVHlwZSxSb2xkLFJuZXcsRm9sZCxGbmV3LG1pc3NSYXRlLENScmF0ZSkgJT4lCiAgdW5pcXVlKCkgJT4lCiAgYXMuZGF0YS5mcmFtZSgpCgojIENhbGN1bGF0ZSBjb3JyZWN0ZWQgcmF0ZXMgLSBzb21ld2hhdCByZWR1bmRhbnQgd2l0aCBhYm92ZSBmb3IgbGVnYWN5IHJlYXNvbnMKY3VyZGF0YS5pdGVtcmVjLmNvcnIgPC0gCiAgZ3JvdXBfYnkoY3VyZGF0YS5pdGVtcmVjLmNvcnIuYWxscmF0ZXMscGFydGljaXBhbnQsRW1vdGlvblR5cGUpICU+JQogIG11dGF0ZSh0bXAxPWxlbmd0aCh3aGljaChpdGVtU2NvcmU9PSJSLUZBIikpLAogICAgICAgICBSb2xkPXJlc3BSYXRlW2l0ZW1TY29yZT09IlJlYyJdLAogICAgICAgICBSbmV3PWlmZWxzZSh0bXAxPjAscmVzcFJhdGVbaXRlbVNjb3JlPT0iUi1GQSJdLDApLAogICAgICAgICBjUmVjPShSb2xkIC0gUm5ldykvKDEgLSBSbmV3KSwKICAgICAgICAgdG1wMj1sZW5ndGgod2hpY2goaXRlbVNjb3JlPT0iRi1GQSIpKSwKICAgICAgICAgRm9sZD1yZXNwUmF0ZVtpdGVtU2NvcmU9PSJGYW0iXSwKICAgICAgICAgRm5ldz1pZmVsc2UodG1wMj4wLHJlc3BSYXRlW2l0ZW1TY29yZT09IkYtRkEiXSwwKSwKICAgICAgICAgY0ZhbT0oRm9sZC8oMS1Sb2xkKSkgLSAoRm5ldy8oMS1SbmV3KSkKICApICU+JSAKICBzZWxlY3QocGFydGljaXBhbnQsRW1vdGlvblR5cGUsY1JlYyxjRmFtKSAlPiUKICB1bmlxdWUoKSAlPiUKICBnYXRoZXIoImNvcnJlY3RlZFJhdGUiLCJ2YWx1ZSIsMzo0KSAlPiUKICBhcy5kYXRhLmZyYW1lKCkKYGBgCgojIyMjIFBsb3QgJiBzdGF0cyBmb3IgaXRlbSByZWNvZ25pdGlvbgpgYGAge3IgaXRlbVJlY29nLVBsb3RTdGF0c30KCiMgUGxvdCBtZWFuKy1TRU0KY3VyZGF0YS5pdGVtcmVjLmNvcnIkY29ycmVjdGVkUmF0ZSA8LSBmYWN0b3IoY3VyZGF0YS5pdGVtcmVjLmNvcnIkY29ycmVjdGVkUmF0ZSxsZXZlbHM9YygiY1JlYyIsImNGYW0iKSkKbWVhbmRhdGEuaXRlbXJlYy5jb3JyIDwtIGZpbHRlcihjdXJkYXRhLml0ZW1yZWMuY29yciwhaXMubmEoY29ycmVjdGVkUmF0ZSkpICU+JQogIGdyb3VwX2J5KGNvcnJlY3RlZFJhdGUsRW1vdGlvblR5cGUpICU+JQogIHN1bW1hcml6ZShtZWFudmFsPW1lYW4odmFsdWUpLAogICAgICAgICAgICBzZHZhbD1zZCh2YWx1ZSksCiAgICAgICAgICAgIHNlbSA9IHNkdmFsL3NxcnQobGVuZ3RoKHZhbHVlKSksCiAgICAgICAgICAgIG5zdWJqPWxlbmd0aCh2YWx1ZSkpIApteWJhcnBsb3QoZGF0YT1tZWFuZGF0YS5pdGVtcmVjLmNvcnIseHZhcj0iRW1vdGlvblR5cGUiLGZpbGx2YXI9IkVtb3Rpb25UeXBlIixmYWNldHM9YygiLiIsImNvcnJlY3RlZFJhdGUiKSxlcnJvcmJhcnM9VFJVRSkgKwogIHlsYWIoJ0NvcnJlY3RlZCBSYXRlJykgKyB4bGFiKCcnKSArIHRoZW1lX21pbmltYWwoMjQpICMrIHNjYWxlX3lfY29udGludW91cyhleHBhbmQ9YygwLjAxLDAuMDEpKQoKIyBTdGF0cwojIyBSZWNvbGxlY3Rpb24KZXpBTk9WQShkYXRhPXN1YnNldChjdXJkYXRhLml0ZW1yZWMuY29ycixjb3JyZWN0ZWRSYXRlPT0iY1JlYyIpLGR2PXZhbHVlLHdpZD1wYXJ0aWNpcGFudCx3aXRoaW49YyhFbW90aW9uVHlwZSksdHlwZT0zKQoKIyMgRmFtaWxpYXJpdHkKZXpBTk9WQShkYXRhPXN1YnNldChjdXJkYXRhLml0ZW1yZWMuY29ycixjb3JyZWN0ZWRSYXRlPT0iY0ZhbSIpLGR2PXZhbHVlLHdpZD1wYXJ0aWNpcGFudCx3aXRoaW49YyhFbW90aW9uVHlwZSksdHlwZT0zKQoKCiMgU3RvcmUgY29ycmVjdGVkIHJlY29nbml0aW9uIHNjb3JlcwppdGVtcmVjZGF0YSA8LSBzcHJlYWQoY3VyZGF0YS5pdGVtcmVjLmNvcnIsY29ycmVjdGVkUmF0ZSx2YWx1ZSkKaXRlbXJlY2RhdGEgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQpICU+JQogIHN1bW1hcml6ZShjUmVjID0gY1JlY1tFbW90aW9uVHlwZT09IkVtbyJdIC0gY1JlY1tFbW90aW9uVHlwZT09Ik5ldSJdLAogICAgICAgICAgICBjRmFtID0gY0ZhbVtFbW90aW9uVHlwZT09IkVtbyJdIC0gY0ZhbVtFbW90aW9uVHlwZT09Ik5ldSJdLAogICAgICAgICAgICBFbW90aW9uVHlwZSA9ICdFbW92TmV1JykgLT4gdG1wCml0ZW1yZWNkYXRhICU+JQogIHNlbGVjdChwYXJ0aWNpcGFudCxjUmVjLGNGYW0sRW1vdGlvblR5cGUpICU+JQogIHJiaW5kKHRtcCkgLT4gaXRlbXJlY2RhdGEKaGVhZChpdGVtcmVjZGF0YSkKYGBgCgpUaGVyZSBpcyBhIHNpZ25pZmljYW50IGVuaGFuY2luZyBlZmZlY3Qgb2YgZW1vdGlvbiBvbiByZWNvbGxlY3Rpb24gZXN0aW1hdGVzIGJ1dCBub3Qgb24gZmFtaWxpYXJpdHkgZXN0aW1hdGVzLgoKIyMgU291cmNlIG1lbW9yeQojIyMgQm90aCBsZXZlbHMgb2YgY29uZmlkZW5jZSAtIFN0YXRzIGZvciBzb3VyY2UgbWVtb3J5CgpgYGB7ciBzb3VyY2VSZWNvZ0FuYWx5c2lzfQoKIyBkZW5vbWluYXRvcgpvdXRwdXRkYXRhICU+JQogIGZpbHRlcighaXMubmEoc291cmNlU2NvcmUpICYgVHJpYWxUeXBlPT0iT2xkIiAmIGl0ZW1TY29yZSE9Ik1pc3MiKSAlPiUKICBncm91cF9ieShwYXJ0aWNpcGFudCxFbW90aW9uVHlwZSkgJT4lCiAgc3VtbWFyaXplKGFsbEZyZXEgPSBsZW5ndGgoRW1vdGlvblR5cGUpKSAtPiBzdW1kYXRhLnNyYwojIG51bWVyYXRvcgpvdXRwdXRkYXRhICU+JQogIGZpbHRlcihUcmlhbFR5cGU9PSJPbGQiICYgaXRlbVNjb3JlIT0iTWlzcyIpICU+JQogIGdyb3VwX2J5KHBhcnRpY2lwYW50LEVtb3Rpb25UeXBlLHNvdXJjZVNjb3JlKSAlPiUKICBzdW1tYXJpemUocmVzcEZyZXEgPSBsZW5ndGgoc291cmNlU2NvcmUpKSAtPiBjdXJkYXRhLnNyYwojIHJhdGVzCmN1cmRhdGEuc3JjIDwtIG1lcmdlKGN1cmRhdGEuc3JjLHN1bWRhdGEuc3JjLGJ5PWMoInBhcnRpY2lwYW50IiwiRW1vdGlvblR5cGUiKSkgJT4lCiAgbXV0YXRlKHJlc3BSYXRlID0gcmVzcEZyZXEvYWxsRnJlcSkgJT4lCiAgZmlsdGVyKHNvdXJjZVNjb3JlPT0iQ29ycmVjdCIpCgojIFBsb3QgbWVhbistU0UKY3VyZGF0YS5zcmMgJT4lCiAgZ3JvdXBfYnkoRW1vdGlvblR5cGUpICU+JQogIHN1bW1hcml6ZShtZWFudmFsPW1lYW4ocmVzcFJhdGUpLAogICAgICAgICAgICBzZHZhbD1zZChyZXNwUmF0ZSksCiAgICAgICAgICAgIHNlbSA9IHNkdmFsL3NxcnQobGVuZ3RoKHJlc3BSYXRlKSksCiAgICAgICAgICAgIG5zdWJqPWxlbmd0aChyZXNwUmF0ZSkpIC0+IG1lYW5kYXRhLnNyYwpteWJhcnBsb3QoZGF0YT1tZWFuZGF0YS5zcmMseHZhcj0iRW1vdGlvblR5cGUiLGZpbGx2YXI9IkVtb3Rpb25UeXBlIixlcnJvcmJhcnM9VFJVRSkgKwogIHlsYWIoJ1NvdXJjZSBBY2N1cmFjeScpICsgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0uNSksIGxpbmV0eXBlPSJkYXNoZWQiKSArIHRoZW1lX21pbmltYWwoMjQpCgojIFN0YXRzCiMjIFNvdXJjZSBBY2N1cmFjeQplekFOT1ZBKGRhdGE9YXMuZGF0YS5mcmFtZShjdXJkYXRhLnNyYyksZHY9cmVzcFJhdGUsd2lkPXBhcnRpY2lwYW50LHdpdGhpbj1jKEVtb3Rpb25UeXBlKSx0eXBlPTMpCiMjIFNvdXJjZSBBY2N1cmFjeSBjb3JyZWN0ZWQgZm9yIGNoYW5jZSByYXRlIChmb3IgdGVzdGluZyBpbnRlcmNlcHQpCmN1cmRhdGEuc3JjJHJlc3BSYXRlLmNvcnIgPC0gY3VyZGF0YS5zcmMkcmVzcFJhdGUgLSAuNQplekFOT1ZBKGRhdGE9YXMuZGF0YS5mcmFtZShjdXJkYXRhLnNyYyksZHY9cmVzcFJhdGUuY29ycix3aWQ9cGFydGljaXBhbnQsd2l0aGluPWMoRW1vdGlvblR5cGUpLHR5cGU9MyxkZXRhaWxlZD1UUlVFKQoKIyAjIyMjIFN0b3JlIHNvdXJjZSByZWNvZ25pdGlvbiBzY29yZXMKY3VyZGF0YS5zcmMgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQpICU+JQogIHN1bW1hcml6ZShzb3VyY2VSYXRlID0gcmVzcFJhdGVbRW1vdGlvblR5cGU9PSJFbW8iXSAtIHJlc3BSYXRlW0Vtb3Rpb25UeXBlPT0iTmV1Il0sCiAgICAgICAgICAgIEVtb3Rpb25UeXBlID0gJ0Vtb3ZOZXUnKSAtPiB0bXAKY3VyZGF0YS5zcmMgJT4lCiAgbXV0YXRlKHNvdXJjZVJhdGUgPSByZXNwUmF0ZSkgJT4lCiAgc2VsZWN0KHBhcnRpY2lwYW50LHNvdXJjZVJhdGUsRW1vdGlvblR5cGUpICU+JQogIHJiaW5kKHRtcCkgLT4gc291cmNlcmVjZGF0YQpoZWFkKHNvdXJjZXJlY2RhdGEpCmBgYApUaGVyZSBpcyBubyBzaWduaWZpY2FudCBlZmZlY3Qgb2YgZW1vdGlvbiBvbiBzb3VyY2UgYWNjdXJhY3kgKGNvbGxhcHNpbmcgaGlnaCBhbmQgbG93IGNvbmZpZGVuY2UpLiBXaGF0IGlmIHdlIG5vdyBjb25zaWRlciBoaWdoLWNvbmZpZGVuY2UgcmVzcG9uc2VzIG9ubHk/CgojIyMgSGlnaC1jb25maWRlbmNlIHNvdXJjZSBtZW1vcnkKCmBgYHtyIHNvdXJjZVJlY29nQW5hbHlzaXMtc3VyZX0KCiMgIyMjIFBsb3Qgc291cmNlIG1lbW9yeSBkaXN0cmlidXRpb246IFJhdGUKCiMgZGVub21pbmF0b3IKb3V0cHV0ZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKHNvdXJjZVNjb3JlLnN1cmUpICYgVHJpYWxUeXBlPT0iT2xkIiAmIGl0ZW1TY29yZSE9Ik1pc3MiKSAlPiUKICBncm91cF9ieShwYXJ0aWNpcGFudCxFbW90aW9uVHlwZSkgJT4lCiAgc3VtbWFyaXplKGFsbEZyZXEgPSBsZW5ndGgoRW1vdGlvblR5cGUpKSAtPiBzdW1kYXRhLnNyYy5zdXJlCiMgbnVtZXJhdG9yCm91dHB1dGRhdGEgJT4lCiAgZmlsdGVyKFRyaWFsVHlwZT09Ik9sZCIgJiBpdGVtU2NvcmUhPSJNaXNzIikgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQsRW1vdGlvblR5cGUsc291cmNlU2NvcmUuc3VyZSkgJT4lCiAgc3VtbWFyaXplKHJlc3BGcmVxID0gbGVuZ3RoKHNvdXJjZVNjb3JlLnN1cmUpKSAtPiBjdXJkYXRhLnNyYy5zdXJlCiMgcmF0ZQpjdXJkYXRhLnNyYy5zdXJlIDwtIG1lcmdlKGN1cmRhdGEuc3JjLnN1cmUsc3VtZGF0YS5zcmMuc3VyZSxieT1jKCJwYXJ0aWNpcGFudCIsIkVtb3Rpb25UeXBlIikpICU+JQogIG11dGF0ZShyZXNwUmF0ZSA9IHJlc3BGcmVxL2FsbEZyZXEpICU+JQogIGZpbHRlcihzb3VyY2VTY29yZS5zdXJlPT0iQ29ycmVjdCIpCgojIFBsb3QgbWVhbistU0VNCmN1cmRhdGEuc3JjLnN1cmUgJT4lCiAgZ3JvdXBfYnkoRW1vdGlvblR5cGUpICU+JQogIHN1bW1hcml6ZShtZWFudmFsPW1lYW4ocmVzcFJhdGUpLAogICAgICAgICAgICBzZHZhbD1zZChyZXNwUmF0ZSksCiAgICAgICAgICAgIHNlbSA9IHNkdmFsL3NxcnQobGVuZ3RoKHJlc3BSYXRlKSksCiAgICAgICAgICAgIG5zdWJqPWxlbmd0aChyZXNwUmF0ZSkpIC0+IG1lYW5kYXRhLnNyYy5zdXJlCm15YmFycGxvdChkYXRhPW1lYW5kYXRhLnNyYy5zdXJlLHh2YXI9IkVtb3Rpb25UeXBlIixmaWxsdmFyPSJFbW90aW9uVHlwZSIsZXJyb3JiYXJzPVRSVUUpICsKICB5bGFiKCdTb3VyY2UgQWNjdXJhY3knKSArIHRoZW1lX21pbmltYWwoMjQpCgojIFN0YXRzCiMjIFNvdXJjZSBBY2N1cmFjeSAtIEhpZ2ggY29uZmlkZW5jZQplekFOT1ZBKGRhdGE9YXMuZGF0YS5mcmFtZShjdXJkYXRhLnNyYy5zdXJlKSxkdj1yZXNwUmF0ZSx3aWQ9cGFydGljaXBhbnQsd2l0aGluPWMoRW1vdGlvblR5cGUpLHR5cGU9MykKCiMgIyMjIyBTdG9yZSBzb3VyY2UgcmVjb2duaXRpb24gc2NvcmVzCmN1cmRhdGEuc3JjLnN1cmUgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQpICU+JQogIHN1bW1hcml6ZShzb3VyY2VSYXRlID0gcmVzcFJhdGVbRW1vdGlvblR5cGU9PSJFbW8iXSAtIHJlc3BSYXRlW0Vtb3Rpb25UeXBlPT0iTmV1Il0sCiAgICAgICAgICAgIEVtb3Rpb25UeXBlID0gJ0Vtb3ZOZXUnKSAtPiB0bXAKY3VyZGF0YS5zcmMuc3VyZSAlPiUKICBtdXRhdGUoc291cmNlUmF0ZSA9IHJlc3BSYXRlKSAlPiUKICBzZWxlY3QocGFydGljaXBhbnQsc291cmNlUmF0ZSxFbW90aW9uVHlwZSkgJT4lCiAgcmJpbmQodG1wKSAtPiBzb3VyY2VyZWNkYXRhLnN1cmUuYWxsCgpgYGAKClRoZXJlIGFwcGVhcnMgdG8gYmUgYW4gaW1wYWlyaW5nIGVmZmVjdCBvZiBlbW90aW9uIG9uIGhpZ2gtY29uZmlkZW5jZSBzb3VyY2UgYWNjdXJhY3kuIEhvd2V2ZXIsIHRoaXMgZXN0aW1hdGUgaXMgbm90IGNvcnJlY3RlZCBmb3IgYmlhcyB0byB1c2UgdGhlIGhpZ2gtY29uZmlkZW5jZSByYXRpbmcuIFNvIGxldCdzIGZpeCB0aGF0LgoKIyMjIEhpZ2gtY29uZmlkZW5jZSBzb3VyY2UgbWVtb3J5IGNvcnJlY3RpbmcgZm9yIGhpZ2gtY29uZiBpbmNvcnJlY3QKCmBgYHtyIHNvdXJjZUNvbmYtYWx0fQoKIyBSZWxhYmVsIG9ubHkgInN1cmUiIGluY29ycmVjdCByZXNwb25zZXMgYXMgaW5jb3JyZWN0OyB1bnN1cmUgbWFya2VkIHVuc3VyZQpvdXRwdXRkYXRhJHNvdXJjZVNjb3JlLnN1cmUubmV3IDwtIGZhY3RvcihOQSxsZXZlbHM9YygiQ29ycmVjdCIsIkluY29ycmVjdCIsIlVuc3VyZSIpKQpvdXRwdXRkYXRhJHNvdXJjZVNjb3JlLnN1cmUubmV3W291dHB1dGRhdGEkQ29uTGFiZWw9PW91dHB1dGRhdGEkcmVzcG9uc2VzLnNvdXJjZXJlYyAmICFpcy5uYShvdXRwdXRkYXRhJHJlc3BvbnNlcy5zb3VyY2VyZWMpICYgb3V0cHV0ZGF0YSRyZXNwb25zZXMuc291cmNlY29uZj09InN1cmUiICAmIG91dHB1dGRhdGEkVHJpYWxUeXBlPT0iT2xkIl0gPC0gIkNvcnJlY3QiCm91dHB1dGRhdGEkc291cmNlU2NvcmUuc3VyZS5uZXdbb3V0cHV0ZGF0YSRDb25MYWJlbCE9b3V0cHV0ZGF0YSRyZXNwb25zZXMuc291cmNlcmVjICYgIWlzLm5hKG91dHB1dGRhdGEkcmVzcG9uc2VzLnNvdXJjZXJlYykgJiBvdXRwdXRkYXRhJHJlc3BvbnNlcy5zb3VyY2Vjb25mPT0ic3VyZSIgJiBvdXRwdXRkYXRhJFRyaWFsVHlwZT09Ik9sZCJdIDwtICJJbmNvcnJlY3QiCm91dHB1dGRhdGEkc291cmNlU2NvcmUuc3VyZS5uZXdbIWlzLm5hKG91dHB1dGRhdGEkcmVzcG9uc2VzLnNvdXJjZXJlYykgJiBvdXRwdXRkYXRhJHJlc3BvbnNlcy5zb3VyY2Vjb25mPT0idW5zdXJlIiAmIG91dHB1dGRhdGEkVHJpYWxUeXBlPT0iT2xkIl0gPC0gIlVuc3VyZSIKCiMgZGVub21pbmF0b3IKb3V0cHV0ZGF0YSAlPiUKICBmaWx0ZXIoIWlzLm5hKHNvdXJjZVNjb3JlLnN1cmUubmV3KSAmIFRyaWFsVHlwZT09Ik9sZCIgJiBpdGVtU2NvcmUhPSJNaXNzIikgJT4lCiAgZ3JvdXBfYnkocGFydGljaXBhbnQsRW1vdGlvblR5cGUpICU+JQogIHN1bW1hcml6ZShhbGxGcmVxID0gbGVuZ3RoKEVtb3Rpb25UeXBlKSkgLT4gc3VtZGF0YS5zcmMuY29ycgojIG51bWVyYXRvcgpvdXRwdXRkYXRhICU+JQogIGZpbHRlcihUcmlhbFR5cGU9PSJPbGQiICYgaXRlbVNjb3JlIT0iTWlzcyIpICU+JQogIGdyb3VwX2J5KHBhcnRpY2lwYW50LEVtb3Rpb25UeXBlLHNvdXJjZVNjb3JlLnN1cmUubmV3KSAlPiUKICBzdW1tYXJpemUocmVzcEZyZXEgPSBsZW5ndGgoc291cmNlU2NvcmUuc3VyZS5uZXcpKSAtPiBjdXJkYXRhLnNyYy5jb3JyCiMgcmF0ZQpjdXJkYXRhLnNyYy5jb3JyIDwtIG1lcmdlKGN1cmRhdGEuc3JjLmNvcnIsc3VtZGF0YS5zcmMuY29ycixieT1jKCJwYXJ0aWNpcGFudCIsIkVtb3Rpb25UeXBlIikpICU+JQogIG11dGF0ZShyZXNwUmF0ZSA9IHJlc3BGcmVxL2FsbEZyZXEpCgojIHRoZSBhYm92ZSB3YXMgdGhlIHNhbWUgYXMgYmVmb3JlIC0gbm93IGNvcnJlY3QgZm9yIHJhdGUgb2YgaGlnaC1jb25maWRlbmNlIGluY29ycmVjdCBzb3VyY2UgcmVzcG9uc2VzCmN1cmRhdGEuc3JjLmNvcnIgPC0gY3VyZGF0YS5zcmMuY29yciAlPiUKICBncm91cF9ieShwYXJ0aWNpcGFudCxFbW90aW9uVHlwZSkgJT4lCiAgbXV0YXRlKG5GQSA9IGxlbmd0aChyZXNwUmF0ZVtzb3VyY2VTY29yZS5zdXJlLm5ldz09IkluY29ycmVjdCJdKSwKICAgICAgICAgcmVzcFJhdGUgPSBpZmVsc2UobkZBPjAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BSYXRlW3NvdXJjZVNjb3JlLnN1cmUubmV3PT0iQ29ycmVjdCJdIC0gcmVzcFJhdGVbc291cmNlU2NvcmUuc3VyZS5uZXc9PSJJbmNvcnJlY3QiXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzcFJhdGVbc291cmNlU2NvcmUuc3VyZS5uZXc9PSJDb3JyZWN0Il0pKSAlPiUKICBmaWx0ZXIoc291cmNlU2NvcmUuc3VyZS5uZXc9PSJDb3JyZWN0IikgIyBjb3JyZWN0ZWQgZm9yIGluY29ycmVjdCBzdXJlIHJlc3BvbnNlcyAob2xkIGl0ZW1zIG9ubHkpCgojIFBsb3QgbWVhbistU0VNCmN1cmRhdGEuc3JjLmNvcnIgJT4lIAogIGdyb3VwX2J5KEVtb3Rpb25UeXBlKSAlPiUKICBzdW1tYXJpemUobWVhbnZhbD1tZWFuKHJlc3BSYXRlKSwKICAgICAgICAgICAgc2R2YWw9c2QocmVzcFJhdGUpLAogICAgICAgICAgICBzZW0gPSBzZHZhbC9zcXJ0KGxlbmd0aChyZXNwUmF0ZSkpLAogICAgICAgICAgICBuc3Viaj1sZW5ndGgocmVzcFJhdGUpKSAtPiBtZWFuZGF0YS5zcmMuY29ycgpteWJhcnBsb3QoZGF0YT1tZWFuZGF0YS5zcmMuY29ycix4dmFyPSJFbW90aW9uVHlwZSIsZmlsbHZhcj0iRW1vdGlvblR5cGUiLGVycm9yYmFycz1UUlVFKSArCiAgeWxhYignU291cmNlIEFjY3VyYWN5JykgKyB0aGVtZV9taW5pbWFsKDI0KQoKIycgIyMjIyBTdGF0cwojJyBTb3VyY2UgQWNjdXJhY3kKZXpBTk9WQShkYXRhPWFzLmRhdGEuZnJhbWUoY3VyZGF0YS5zcmMuY29yciksZHY9cmVzcFJhdGUsd2lkPXBhcnRpY2lwYW50LHdpdGhpbj1jKEVtb3Rpb25UeXBlKSx0eXBlPTMpCgpgYGAKCkFmdGVyIGNvcnJlY3RpbmcgdGhlIGhpZ2gtY29uZmlkZW5jZSBzb3VyY2UgYWNjdXJhY3kgcmF0ZXMsIHRoZXJlIGlzIG5vIHNpZ25pZmljYW50IGVmZmVjdCBvZiBlbW90aW9uLgoKIyBTdW1tYXJpemUgZGF0YQojIyBTYXZlIHNjb3JlcwoKYGBge3Igc2F2ZVNjb3Jlc30KIyBNZXJnZSB0b2dldGhlciBhbGwgc3VtbWFyeSBtZWFzdXJlcyAoaXRlbXJlYywgc291cmNlcmVjLCBzb3VyY2VyZWMtc3VyZSkKc291cmNlcmVjZGF0YSA8LSBtZXJnZShzb3VyY2VyZWNkYXRhLHNvdXJjZXJlY2RhdGEuc3VyZS5hbGwsYnk9YygicGFydGljaXBhbnQiLCJFbW90aW9uVHlwZSIpLHN1ZmZpeGVzPWMoIiIsIi5zdXJlIikpCnN1bW1hcnlkYXRhIDwtIG1lcmdlKGl0ZW1yZWNkYXRhLHNvdXJjZXJlY2RhdGEsYnk9YygicGFydGljaXBhbnQiLCJFbW90aW9uVHlwZSIpLHN1ZmZpeGVzPWMoIi5pdGVtIiwiLnNvdXJjZSIpKQoKIyB1c2Ugc3ViamVjdCBJRHMgaW5zdGVhZCBvZiBqdXN0IG51bWJlcnMKc25hbWVmdW4gPC0gZnVuY3Rpb24ocykgewogIGlmIChzPDEwKSB7c25hbWUgPC0gcGFzdGUwKCdzMCcsYXMuY2hhcmFjdGVyKHMpKX0KICBlbHNlIHsgc25hbWUgPC0gcGFzdGUwKCdzJyxhcy5jaGFyYWN0ZXIocykpfQogIHJldHVybihzbmFtZSkKfQpzdW1tYXJ5ZGF0YSRzdWJqZWN0IDwtIHNhcHBseShzdW1tYXJ5ZGF0YSRwYXJ0aWNpcGFudCxzbmFtZWZ1bikKCmhlYWQoc3VtbWFyeWRhdGEpCndyaXRlLmNzdihzdW1tYXJ5ZGF0YSxmaWxlPXBhc3RlMChvdXRkaXIsJ2JlaGF2aW9yYWxfc3VtbWFyeV9zY29yZXMuY3N2JykpCmBgYAoKIyMgVGFibGUgb2YgYmVoYXZpb3JhbCBkYXRhCmBgYHtyIHRhYmxlRm9yUGFwZXJ9CgojIHNlcGFyYXRlIGZvciBlYXN5IGluZGV4aW5nIGluIG1hcmtkb3duLWZvcm1hdHRlZCB0YWJsZSAoYmVsb3cpCnN1bW1hcnlkYXRhICU+JQogIGZpbHRlcihFbW90aW9uVHlwZT09IkVtbyIpICAtPiBlbW9TY29yZXMKc3VtbWFyeWRhdGEgJT4lCiAgZmlsdGVyKEVtb3Rpb25UeXBlPT0iTmV1IikgIC0+IG5ldVNjb3JlcwoKY3VyZGF0YS5pdGVtcmVjLmNvcnIuYWxscmF0ZXMuc3VtbWFyeSAlPiUKICBmaWx0ZXIoRW1vdGlvblR5cGU9PSJFbW8iKSAtPiBlbW9TY29yZXMucmF0ZXMKY3VyZGF0YS5pdGVtcmVjLmNvcnIuYWxscmF0ZXMuc3VtbWFyeSAlPiUKICBmaWx0ZXIoRW1vdGlvblR5cGU9PSJOZXUiKSAtPiBuZXVTY29yZXMucmF0ZXMKCmZvcm1hdE1TRCA8LSBmdW5jdGlvbihkZikgewogIG1lYW52YWwgPC0gbWVhbihkZikKICBzZHZhbCA8LSBzZChkZikKICBzcHJpbnRmKCIlMC4yZiAoJTAuMmYpIixtZWFudmFsLHNkdmFsKQp9CgpgYGAKIyMjIFBhcGVyIFRhYmxlIDEKCnwgQ29uZGl0aW9uIHwgUmVtZW1iZXIgcmF0ZSB8IEZhbWlsaWFyIHJhdGUgfCBOZXcgUmF0ZSB8IFJlY29sbGVjdGlvbiBlc3RpbWF0ZSB8IEZhbWlsaWFyaXR5IGVzdGltYXRlIHwgU291cmNlIGFjY3VyYWN5IHwgU291cmNlIGFjY3VyYWN5IC0gaGlnaCBjb25maWRlbmNlIHwKfCAtLS0tLS0tLS0tLS0tIHw6LS0tLS0tLS0tLS0tLTp8IC0tLS0tOnwgLS0tLS06fCAtLS0tLTp8IC0tLS0tOnwgLS0tLS06fCAtLS0tLTp8CnwgRW1vdGlvbiAtIG9sZCB8IGByIGZvcm1hdE1TRChlbW9TY29yZXMucmF0ZXMkUm9sZClgIHwgYHIgZm9ybWF0TVNEKGVtb1Njb3Jlcy5yYXRlcyRGb2xkKWAgfCBgciBmb3JtYXRNU0QoZW1vU2NvcmVzLnJhdGVzJG1pc3NSYXRlKWAgfCBgciBmb3JtYXRNU0QoZW1vU2NvcmVzJGNSZWMpYCB8IGByIGZvcm1hdE1TRChlbW9TY29yZXMkY0ZhbSlgIHwgYHIgZm9ybWF0TVNEKGVtb1Njb3JlcyRzb3VyY2VSYXRlKWAgfCBgciBmb3JtYXRNU0QoZW1vU2NvcmVzJHNvdXJjZVJhdGUuc3VyZSlgIHwKfCBOZXV0cmFsIC0gb2xkIHwgYHIgZm9ybWF0TVNEKG5ldVNjb3Jlcy5yYXRlcyRSb2xkKWAgfCBgciBmb3JtYXRNU0QobmV1U2NvcmVzLnJhdGVzJEZvbGQpYCB8IGByIGZvcm1hdE1TRChuZXVTY29yZXMucmF0ZXMkbWlzc1JhdGUpYCB8IGByIGZvcm1hdE1TRChuZXVTY29yZXMkY1JlYylgIHwgYHIgZm9ybWF0TVNEKG5ldVNjb3JlcyRjRmFtKWAgfCBgciBmb3JtYXRNU0QobmV1U2NvcmVzJHNvdXJjZVJhdGUpYCB8IGByIGZvcm1hdE1TRChuZXVTY29yZXMkc291cmNlUmF0ZS5zdXJlKWAgfAp8IEVtb3Rpb24gLSBuZXcgfCBgciBmb3JtYXRNU0QoZW1vU2NvcmVzLnJhdGVzJFJuZXcpYCB8IGByIGZvcm1hdE1TRChlbW9TY29yZXMucmF0ZXMkRm5ldylgIHwgYHIgZm9ybWF0TVNEKGVtb1Njb3Jlcy5yYXRlcyRDUnJhdGUpYCB8IC0gfCAtIHwgLSB8IC0gfAp8IE5ldXRyYWwgLSBuZXcgfCBgciBmb3JtYXRNU0QobmV1U2NvcmVzLnJhdGVzJFJuZXcpYCB8IGByIGZvcm1hdE1TRChuZXVTY29yZXMucmF0ZXMkRm5ldylgIHwgYHIgZm9ybWF0TVNEKG5ldVNjb3Jlcy5yYXRlcyRDUnJhdGUpYCB8IC0gfCAtIHwgLSB8IC0gfAoKCiMjIFBhcGVyIEZpZ3VyZSAyIC0gQmVoYXZpb3JhbCBkYXRhIHBsb3QKYGBge3IgcGxvdEZvclBhcGVyLCBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD01fQoKcGxvdGNvbG9yczEgPC0gYygnI2U5YTNjOScsJyNhMWQ3NmEnLCcjZTlhM2M5JywnI2ExZDc2YScsJyNlOWEzYzknLCcjYTFkNzZhJykKcGxvdGNvbG9yczIgPC0gYygnI2QwMWM4YicsJyM0ZGFjMjYnKQoKCiMgUmVmb3JtYXQgZGF0YWZyYW1lIGZvciBlYXNpZXIgcGxvdHRpbmcKc3VtbWFyeWRhdGEgJT4lCiAgZmlsdGVyKEVtb3Rpb25UeXBlPT0iRW1vIiB8IEVtb3Rpb25UeXBlPT0iTmV1IikgJT4lCiAgZ2F0aGVyKG1lYXN1cmUsdmFsdWUsLXBhcnRpY2lwYW50LC1FbW90aW9uVHlwZSwtc3ViamVjdCkgLT4gc3VtbWFyeWRhdGEubG9uZwpzdW1tYXJ5ZGF0YS5sb25nJG1lYXN1cmUgPC0gZmFjdG9yKHN1bW1hcnlkYXRhLmxvbmckbWVhc3VyZSxsZXZlbHM9YygiY1JlYyIsImNGYW0iLCJzb3VyY2VSYXRlIiwic291cmNlUmF0ZS5zdXJlIikpCgpzdW1tYXJ5ZGF0YS5sb25nLnJlYyA8LSBmaWx0ZXIoc3VtbWFyeWRhdGEubG9uZyxtZWFzdXJlPT0iY1JlYyIgfCBtZWFzdXJlPT0iY0ZhbSIgfCBtZWFzdXJlPT0ic291cmNlUmF0ZSIgKQpzdW1tYXJ5ZGF0YS5sb25nLnNyYyA8LSBmaWx0ZXIoc3VtbWFyeWRhdGEubG9uZyxtZWFzdXJlPT0ic291cmNlUmF0ZSIgfCBtZWFzdXJlPT0ic291cmNlUmF0ZS5zdXJlIikKCiMgUGxvdCBhbGwgYmVoYXZpb3JhbCBtZWFzdXJlcwpzdW1tYXJ5ZGF0YS5sb25nLnJlYyAlPiUKICBncm91cF9ieShtZWFzdXJlLEVtb3Rpb25UeXBlKSAlPiUKICBzdW1tYXJpemUobWVhbnZhbD1tZWFuKHZhbHVlKSwKICAgICAgICAgICAgc2VtPXNkKHZhbHVlKS9zcXJ0KGxlbmd0aCh2YWx1ZSkpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9RW1vdGlvblR5cGUseT1tZWFudmFsKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsY29sb3I9ImdyYXk0MCIsZmlsbD1wbG90Y29sb3JzMSkgKyB0aGVtZV9taW5pbWFsKDE4KSArCiAgZmFjZXRfZ3JpZCgufm1lYXN1cmUpICsKICBnZW9tX2RvdHBsb3QoZGF0YT1zdW1tYXJ5ZGF0YS5sb25nLnJlYyxhZXMoeD1FbW90aW9uVHlwZSx5PXZhbHVlLGZpbGw9RW1vdGlvblR5cGUpLCBiaW5heGlzID0gInkiLCBzdGFja2RpciA9ICJjZW50ZXIiLCBiaW53aWR0aD0uMDIpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh4PUVtb3Rpb25UeXBlLHltaW49bWVhbnZhbC1zZW0seW1heD1tZWFudmFsK3NlbSx3aWR0aD0uMikpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGxvdGNvbG9yczIpICsgeWxhYigiTWVhbiBjb3JyZWN0ZWQgcmF0ZSIpICsgeGxhYigiIikKCmBgYAoK