This report contains all analyses of Orbit fMRI behavioral data.

N = 28/34 –>
2 subjects did not complete the experiment due to anxiety/movement in the scanner and 4 subjects were excluded due to chance level behavior, defined as a mean absolute error of > 75 degrees (where chance = 90) in any condition (color, scene).

Mixture model functions are from: https://github.com/eddjberry/precision-mixture-model

Feature Errors

Response - Study angle across all subjects plotted as density histograms per feature.
Overlayed is the best fitting mixture model pdf (vonMises + uniform)

### All Color and Scene
### Fit mixture model to aggregate data (needs to be in radians):
Color <- JV10_fit(wrap(allData$ColResp/180*pi), wrap(allData$ColStudy/180*pi))
print(paste0("Color : % Correct = ", round(Color$B$Pt, digits = 4)))
[1] "Color : % Correct = 0.6496"
print(paste0("      : Precision = ", round(Color$B$K, digits = 4)))
[1] "      : Precision = 4.8539"
Scene <- JV10_fit(wrap(allData$SceneResp/180*pi), wrap(allData$SceStudy/180*pi))
print(paste0("Scene : % Correct = ", round(Scene$B$Pt, digits = 4)))
[1] "Scene : % Correct = 0.6313"
print(paste0("      : Precision = ", round(Scene$B$K, digits = 4)))
[1] "      : Precision = 23.7693"
### now get best fitting PDFs:
range = seq(from = -pi, to = pi, by = pi/180)
# 1. Get von Mises pdf based on aggregate precision
yCol = vonmisespdf(range,0,Color$B$K)
ySce = vonmisespdf(range,0,Scene$B$K)
# scale so area of distribution = proportion correct
yCol = yCol * (Color$B$Pt/(sum(yCol)))
ySce = ySce * (Scene$B$Pt/(sum(ySce)))
# 2. add guess rate (uniform component)
yCol = data.frame(yCol + (Color$B$Pu/length(range)))
ySce = data.frame(ySce + (Scene$B$Pu/length(range)))
colnames(yCol)<- c("prob")
yCol$error <- seq(from = -180, to = 180, by = 1)
colnames(ySce)<- c("prob")
ySce$error <- seq(from = -180, to = 180, by = 1)
# Threshold for memory 'success' (at least 50% chance that error fits von Mises), rounded to nearest multiple of 3 (my unique angles):
colT <-  max(abs(yCol$error[yCol$prob > (Color$B$Pu/length(range)*2)]))
colT <- 3*round(colT/3) 
sceT <-  max(abs(ySce$error[ySce$prob > (Scene$B$Pu/length(range))*2]))
sceT <- 3*round(sceT/3) 
print(paste("Threshold for color memory success at 50% <= ", colT, " degrees", sep = ""))
[1] "Threshold for color memory success at 50% <= 57 degrees"
print(paste("Threshold for scene memory success at 50% <= ", sceT, " degrees", sep = ""))
[1] "Threshold for scene memory success at 50% <= 30 degrees"
# add on Color and Scene accuracy columns to alldata based on model threshold:
allData$ColorCorrect[allData$ColAbsError <= colT] <- 1
allData$ColorCorrect[allData$ColAbsError > colT] <- 0
allData$SceneCorrect[allData$SceAbsError <= sceT] <- 1
allData$SceneCorrect[allData$SceAbsError > sceT] <- 0
# plot data with line at height of uniform distribution:
p1 <- ggplot(allData, aes(x = ColError)) +
    geom_histogram(bins = 61, color = 'white', fill = 'gray60', aes(y=..density..), 
                   position=position_dodge(1)) + 
    geom_line(data = yCol, aes(x = error, y = prob), color = 'coral2', size=1.5) +
    xlab("Error") + ylab("p(Error)") +
    scale_y_continuous(limits = c(0,0.020), expand = c(0,0), breaks = seq(0,0.020,by = 0.005)) + 
    scale_x_continuous(expand = c(0,0), breaks = seq(-180,180,by = 60)) + 
    ggtitle("Color Errors") +
    theme(plot.title = element_text(hjust = 0.5, size=28), axis.line = element_line(colour = "black"), 
          axis.text = element_text(size = 20), axis.title = element_text(size = 24),
          panel.background = element_blank(),
          legend.position="none", text = element_text(family="Helvetica"))  
ggsave('Color_Errors.jpg', plot = p1, dpi = 300, width = 6.5, height = 5)
p2 <- ggplot(allData, aes(x = SceError)) +
    geom_histogram(bins = 61, color = 'white', fill = 'gray60', aes(y=..density..),
                   position=position_dodge(1)) + 
    geom_line(data = ySce, aes(x = error, y = prob), color = 'dodgerblue2', size=1.5) +
    xlab("Error") + ylab("p(Error)") +
    scale_y_continuous(limits = c(0,0.032), expand = c(0,0), breaks = seq(0,0.032,by = 0.008)) + 
    scale_x_continuous(expand = c(0,0), breaks = seq(-180,180,by = 60)) + 
    ggtitle("Scene errors") +
    theme(plot.title = element_text(hjust = 0.5, size=28), axis.line = element_line(colour = "black"), 
          axis.text = element_text(size = 20), axis.title = element_text(size = 24),
          panel.background = element_blank(),
          legend.position="none", text = element_text(family="Helvetica"))     
ggsave('Scene_Errors.jpg', plot = p2, dpi = 300, width = 6.5, height = 5)
multiplot(p1,p2, cols = 2)

Subject Mixture Model by Color/Scene Feature

### Compute mixture model estimates by subject and feature
mixture <- data.frame(matrix(0, nrow = NSubjs*2, ncol = 4))
names(mixture) <- c("SubID","Feature","pT","k")
row <- 0
for (idx in 1:length(subjects)) {
    myData <- subset(allData, SubID == as.integer(subjects[idx]))
    row = row + 1
    mixture$SubID[row]   = myData$SubID[1]
    mixture$Feature[row] = 'Color'
    curModel <- JV10_fit(wrap(myData$ColResp/180*pi), wrap(myData$ColStudy/180*pi))
    mixture$pT[row] <- curModel$B$Pt
    mixture$k[row]  <- curModel$B$K
    row = row + 1
    mixture$SubID[row]   = myData$SubID[1]
    mixture$Feature[row] = 'Scene'
    curModel <- JV10_fit(wrap(myData$SceneResp/180*pi), wrap(myData$SceStudy/180*pi))
    mixture$pT[row] <- curModel$B$Pt
    mixture$k[row]  <- curModel$B$K
  }#end of loop through subjects    
mixture$SubID <- as.factor(mixture$SubID)
mixture$Feature <- as.factor(mixture$Feature)
mixture <- mixture %>% group_by(Feature) #group data by these factors
# Memory Success (proportion correct)
p1 <- ggplot(mixture, aes(x=Feature, y=pT, color=Feature, fill=Feature)) +
    stat_summary(fun.y = mean, geom="bar", alpha = 0.4, position = position_dodge(1)) +
    scale_fill_manual(values = c('coral2','dodgerblue2')) + 
    scale_color_manual(values = c('coral2','dodgerblue2')) +
    geom_dotplot(binaxis='y', stackdir='center', alpha = 0.8, position = position_dodge(1)) +
    stat_summary(fun.data = mean_se, geom = "errorbar", fun.args = list(mult = 1.96),
                 width = 0.4, color = "black", size = 0.6, position = position_dodge(1)) +
    ggtitle("Memory Success") +  scale_y_continuous(expand = c(0,0), limits=c(0,1)) + 
    theme(plot.title = element_text(hjust = 0.5, size=28), axis.line = element_line(colour = "black"), 
          axis.text = element_text(size = 22), axis.title = element_text(size = 22),
          panel.background = element_blank(),
          legend.position="none", text = element_text(family="Helvetica"))
# Precision summary
p2 <- ggplot(mixture, aes(x=Feature, y=k, color=Feature, fill=Feature)) +
    stat_summary(fun.y = mean, geom="bar", alpha = 0.4, position = position_dodge(1)) +
    scale_fill_manual(values = c('coral2','dodgerblue2')) +
    scale_color_manual(values = c('coral2','dodgerblue2')) +
    geom_dotplot(binaxis='y', stackdir='center', alpha = 0.8, position = position_dodge(1)) +
    stat_summary(fun.data = mean_se, geom = "errorbar", fun.args = list(mult = 1.96),
                 width = 0.4, color = "black", size = 0.6, position = position_dodge(1)) +
    ggtitle("Memory Precision") + scale_y_continuous(expand = c(0,0), limits=c(0,84)) + 
    theme(plot.title = element_text(hjust = 0.5, size=28), axis.line = element_line(colour = "black"), 
          axis.text = element_text(size = 22), axis.title = element_text(size = 22),
          panel.background = element_blank(),
          legend.position="none", text = element_text(family="Helvetica"))
multiplot(p1,p2, cols = 2)

pander(t.test(pT ~ Feature, data=mixture, paired = TRUE))

----------------------------------------------------------------------------------
 Test statistic   df   P value   Alternative hypothesis   mean of the differences 
---------------- ---- --------- ------------------------ -------------------------
     1.086        27    0.287          two.sided                  0.02864         
----------------------------------------------------------------------------------

Table: Paired t-test: `pT` by `Feature`
pander(t.test(k ~ Feature, data=mixture, paired = TRUE))

---------------------------------------------------------------
 Test statistic   df      P value       Alternative hypothesis 
---------------- ---- ---------------- ------------------------
     -6.484       27   5.98e-07 * * *         two.sided        
---------------------------------------------------------------

Table: Paired t-test: `k` by `Feature` (continued below)

 
-------------------------
 mean of the differences 
-------------------------
         -21.59          
-------------------------
# for saving data in csv:
pT <- subset(mixture, select = -c(k)) %>%
       spread(key = Feature, value = pT)
colnames(pT) <- c('SubID','ColorpT','ScenepT')
k <- subset(mixture, select = -c(pT)) %>%
       spread(key = Feature, value = k)
colnames(k) <- c('SubID','Colork','Scenek')
group_data <- merge.data.frame(pT,k,by='SubID') %>%
               sortFrame(SubID)

Emotion Memory

Proportion correct and proportion of high confidence correct emotion responses

### Emotion accuracy (proportion correct)
emotion <- allData %>% 
                group_by(SubID) %>% 
                 summarise(EmotionSuccess = mean(EmotionCorrect)) 
group_data <- merge.data.frame(group_data, emotion, by = 'SubID')
summary <- emotion %>%
             summarise(EmotionCorrect = mean(EmotionSuccess), SE = se(EmotionSuccess))
print(kable(summary))


| EmotionCorrect|        SE|
|--------------:|---------:|
|      0.7559524| 0.0201145|
### Proportion of corect repsonses that were high confidence
correctData <- subset(allData, EmotionCorrect == 1)
confidence <- correctData %>% 
                group_by(SubID) %>% 
                 summarise(EmotionConfidence = mean(EmotionConfidence))
group_data <- merge.data.frame(group_data, confidence, by = 'SubID')
summary <- confidence %>%
             summarise(EmotionConf = mean(EmotionConfidence), SE = se(EmotionConfidence))
print(kable(summary))


| EmotionConf|        SE|
|-----------:|---------:|
|   0.7227009| 0.0300857|

Memory Dependency

Retrieval Success

Uses the dependent vs independent approach from Horner & Burgess (2013/2014) to estimate dependency of correct retrieval for each feature pair

dependency <- data.frame(matrix(0, nrow = NSubjs*3, ncol = 3))
names(dependency) <- c("SubID","Pair","Difference")
row <- 0
for (idx in 1:length(subjects)) {
    myData <- subset(allData, SubID == as.integer(subjects[idx]))
   
    for (pair in 1:3) {
      if (pair == 1) {
        name = 'Emotion-Color'
        curAcc <- cbind(myData$EmotionCorrect,myData$ColorCorrect)
      } else if (pair == 2) {
        name = 'Emotion-Scene'
        curAcc <- cbind(myData$EmotionCorrect,myData$SceneCorrect)
      } else if (pair == 3) {
        name = 'Color-Scene'
        curAcc <- cbind(myData$ColorCorrect,myData$SceneCorrect)
      }
      
      row = row + 1
      dependency$SubID[row]   = myData$SubID[1]
      dependency$Pair[row]    = name
      data  = sum(!rowSums(curAcc) == 1)/nrow(curAcc) #actual dependency of the data (proportion of times both remembered or forgotten)
      sumAcc <- colMeans(curAcc)
      independent = (sumAcc[1]*sumAcc[2])+((1-sumAcc[1])*(1-sumAcc[2])) #dependency of data expected based on performance (assuming actually independent)
      dependency$Difference[row] = data - independent #degree to which features are more/less dependent in memory than expected by chance (based on performance)
     }
  }#end of loop through subjects    
dependency$Pair <- as.factor(dependency$Pair)
# data vs independent model by feature
success <- dependency %>% 
              group_by(SubID, Pair)
p1 <- ggplot(success, aes(x = Pair, y=Difference, fill=Pair)) +
    stat_summary(fun.y = mean, geom="bar", alpha = 0.5) +
    geom_dotplot(binaxis='y', stackdir='center', dotsize=1, alpha = 0.8) +
    stat_summary(fun.data = mean_se, geom = "errorbar", fun.args = list(mult = 1.96),
                 width = 0.4, color = "black", size = 0.6) +
    scale_fill_manual(values = c('#66bd63','coral2','dodgerblue2')) + 
    ylab("Dependency") + scale_y_continuous(limits = c(-0.12,0.24),
                                                    expand = c(0,0),
                                                    breaks = seq(-0.12,0.24,by = 0.06)) +
    ggtitle("Retrieval Success Dependence") + geom_hline(yintercept = 0) +
    scale_x_discrete(labels=c("Color\nScene","Color\nEmotion","Scene\nEmotion")) +
    theme(plot.title = element_text(hjust = 0.5, size=28), axis.line = element_line(colour = "black"), 
          axis.text.x = element_text(size = 22), axis.text.y = element_text(size = 20),
          axis.title = element_text(size = 24),
          panel.background = element_blank(),
          legend.position="none", text = element_text(family="Helvetica"))   
plot(p1)

ggsave('Correct_Dependency.jpg', plot = p1, dpi = 300, width = 6, height = 5)
#t-tests, greater than 0?
pander(t.test(success$Difference[success$Pair == 'Color-Scene'], mu=0))

----------------------------------------------------------------------------
 Test statistic   df       P value       Alternative hypothesis   mean of x 
---------------- ---- ----------------- ------------------------ -----------
     8.004        27   1.332e-08 * * *         two.sided           0.07779  
----------------------------------------------------------------------------

Table: One Sample t-test: `success$Difference[success$Pair == "Color-Scene"]`
pander(t.test(success$Difference[success$Pair == 'Emotion-Color'], mu=0))

----------------------------------------------------------------------------
 Test statistic   df       P value       Alternative hypothesis   mean of x 
---------------- ---- ----------------- ------------------------ -----------
     7.297        27   7.545e-08 * * *         two.sided           0.04664  
----------------------------------------------------------------------------

Table: One Sample t-test: `success$Difference[success$Pair == "Emotion-Color"]`
pander(t.test(success$Difference[success$Pair == 'Emotion-Scene'], mu=0))

----------------------------------------------------------------------------
 Test statistic   df       P value       Alternative hypothesis   mean of x 
---------------- ---- ----------------- ------------------------ -----------
     8.489        27   4.213e-09 * * *         two.sided           0.06567  
----------------------------------------------------------------------------

Table: One Sample t-test: `success$Difference[success$Pair == "Emotion-Scene"]`
# for saving data in csv:
success <- success %>%
               spread(key = Pair, value = Difference)
group_data <- merge.data.frame(group_data,success,by='SubID') %>%
                sortFrame(SubID)

Retrieval Precision

Computes the correlations between color and scene success (1 0) and precision (reversed ‘correct’ error).

dependency <- data.frame(matrix(0, nrow = NSubjs*3, ncol = 3))
names(dependency) <- c("SubID","Pair","Dependency")
row <- 0
for (idx in 1:length(subjects)) {
  for (pair in 1:3) {
    row = row + 1
    if (pair == 1) {
       myData <- subset(allData, SubID == subjects[idx] & ColorCorrect == 1 & SceneCorrect == 1)
       name = 'ColorP-SceneP'
       dependency$Dependency[row]  = fisherz(cor(180 - myData$ColAbsError,180 - myData$SceAbsError))
    } else if (pair == 2) {
       myData <- subset(allData, SubID == subjects[idx] & SceneCorrect == 1)
       name = 'ColorS-SceneP'
       dependency$Dependency[row]  = fisherz(cor(myData$ColorCorrect,180 - myData$SceAbsError))
    } else if (pair == 3) {
       myData <- subset(allData, SubID == subjects[idx] & ColorCorrect == 1)
       name = 'SceneS-ColorP'
       dependency$Dependency[row]  = fisherz(cor(myData$SceneCorrect,180 - myData$ColAbsError))
    }
    dependency$SubID[row] = myData$SubID[1]
    dependency$Pair[row]  = name
   }
  }#end of loop through subjects    
dependency$Pair <- as.factor(dependency$Pair)
# correlations by pair
precision <- dependency %>% 
              group_by(SubID, Pair)
p1 <- ggplot(precision, aes(x = Pair, y=Dependency, fill=Pair)) +
    stat_summary(fun.y = mean, geom="bar", alpha = 0.5) +
    geom_dotplot(binaxis='y', stackdir='center', dotsize=1, alpha = 0.8) +
    stat_summary(fun.data = mean_se, geom = "errorbar", fun.args = list(mult = 1.96),
                 width = 0.4, color = "black", size = 0.6) +
    scale_fill_manual(values = c('#66bd63','coral2','dodgerblue2')) + 
    ylab("Mean z") + scale_y_continuous(limits = c(-0.22,0.42), expand = c(0,0),
                                        breaks = seq(-0.4,0.4,by = 0.1)) +
    ggtitle("Retrieval Precision Dependence") + geom_hline(yintercept = 0) +
    scale_x_discrete(labels=c("Color.P\nScene.P","Color.S\nScene.P","Scene.S\nColor.P")) +
    theme(plot.title = element_text(hjust = 0.5, size=28), axis.line = element_line(colour = "black"), 
          axis.text.x = element_text(size = 22), axis.text.y = element_text(size = 20),
          axis.title = element_text(size = 24),
          panel.background = element_blank(),
          legend.position="none", text = element_text(family="Helvetica"))   
plot(p1)

ggsave('Precision_Dependency.jpg', plot = p1, dpi = 300, width = 6, height = 5)
#t-tests, greater than 0?
pander(t.test(precision$Dependency[precision$Pair == 'ColorP-SceneP'], mu=0))

--------------------------------------------------------------------
 Test statistic   df   P value   Alternative hypothesis   mean of x 
---------------- ---- --------- ------------------------ -----------
     0.3202       27   0.7513          two.sided          0.006954  
--------------------------------------------------------------------

Table: One Sample t-test: `precision$Dependency[precision$Pair == "ColorP-SceneP"]`
pander(t.test(precision$Dependency[precision$Pair == 'ColorS-SceneP'], mu=0))

--------------------------------------------------------------------
 Test statistic   df   P value   Alternative hypothesis   mean of x 
---------------- ---- --------- ------------------------ -----------
     1.844        27   0.07613         two.sided           0.04013  
--------------------------------------------------------------------

Table: One Sample t-test: `precision$Dependency[precision$Pair == "ColorS-SceneP"]`
pander(t.test(precision$Dependency[precision$Pair == 'SceneS-ColorP'], mu=0))

--------------------------------------------------------------------
 Test statistic   df   P value   Alternative hypothesis   mean of x 
---------------- ---- --------- ------------------------ -----------
     1.592        27   0.1231          two.sided           0.03718  
--------------------------------------------------------------------

Table: One Sample t-test: `precision$Dependency[precision$Pair == "SceneS-ColorP"]`
# for saving data in csv:
precision <- precision %>%
               spread(key = Pair, value = Dependency)
group_data <- merge.data.frame(group_data,precision,by='SubID') %>%
                sortFrame(SubID)
write.csv(group_data, "Behavioral_data.csv", row.names=FALSE)
LS0tCnRpdGxlOiAiT3JiaXQgZk1SSSBCZWhhdmlvcmFsIERhdGEiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIGZvbnRzaXplOiA2cHQKLS0tCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJvZHl7IC8qIE5vcm1hbCAgKi8KICAgICAgZm9udC1zaXplOiAxNHB4fQp0ZCB7ICAvKiBUYWJsZSAgKi8KICBmb250LXNpemU6IDEycHh9CmgxLnRpdGxlIHsKICBmb250LXNpemU6IDMwcHh9CmgxIHsgLyogSGVhZGVyIDEgKi8KICBmb250LXNpemU6IDI0cHh9CmgyIHsgLyogSGVhZGVyIDIgKi8KICAgIGZvbnQtc2l6ZTogMjBweH0KY29kZS5yeyAvKiBDb2RlIGJsb2NrICovCiAgICBmb250LXNpemU6IDEycHh9Cjwvc3R5bGU+CgoKVGhpcyByZXBvcnQgY29udGFpbnMgYWxsIGFuYWx5c2VzIG9mIE9yYml0IGZNUkkgKmJlaGF2aW9yYWwqIGRhdGEuICAKCk4gPSAyOC8zNCAtLT4gIAoyIHN1YmplY3RzIGRpZCBub3QgY29tcGxldGUgdGhlIGV4cGVyaW1lbnQgZHVlIHRvIGFueGlldHkvbW92ZW1lbnQgaW4gdGhlIHNjYW5uZXIgYW5kIDQgc3ViamVjdHMgd2VyZSBleGNsdWRlZCBkdWUgdG8gY2hhbmNlIGxldmVsIGJlaGF2aW9yLCBkZWZpbmVkIGFzIGEgbWVhbiBhYnNvbHV0ZSBlcnJvciBvZiA+IDc1IGRlZ3JlZXMgKHdoZXJlIGNoYW5jZSA9IDkwKSBpbiBhbnkgY29uZGl0aW9uIChjb2xvciwgc2NlbmUpLiAgCgpNaXh0dXJlIG1vZGVsIGZ1bmN0aW9ucyBhcmUgZnJvbTogaHR0cHM6Ly9naXRodWIuY29tL2VkZGpiZXJyeS9wcmVjaXNpb24tbWl4dHVyZS1tb2RlbCAgCgoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CgojIyMjIGxvYWQgaW4gYWxsIG5lY2Vzc2FyeSBwYWNrYWdlczoKbGlicmFyeSgnZ2dwbG90MicpCmxpYnJhcnkoJ3RpZHlyJykKbGlicmFyeSgnZHBseXInKQpsaWJyYXJ5KCdleicpCmxpYnJhcnkoJ2xzcicpCmxpYnJhcnkoJ3BzeWNoJykKbGlicmFyeSgna25pdHInKQpsaWJyYXJ5KCdwYW5kZXInKQoKdGFza1ZlciA8LSAnZk1SSS1iZWhhdmlvcicKIyMjIGRlZmluZSBjb21wdXRlciBwYXRoCiNteUNvbXAgPC0gJy9Vc2Vycy9tZW1vbGFiL0dvb2dsZSBEcml2ZS8nCm15Q29tcCA8LSAnL1VzZXJzL3Jvc2Vjb29wZXIvRG9jdW1lbnRzLycKCiMjIyBkZWZpbmUgYWxsIGZ1bmN0aW9uczoKc291cmNlKHBhc3RlKG15Q29tcCwnV29yay9NZXRob2RzL215RnVuY3Rpb25zL0dlbmVyYWwvbXVsdGlwbG90LlInLHNlcCA9ICIiKSkgCnNvdXJjZShwYXN0ZShteUNvbXAsJ1dvcmsvTWV0aG9kcy9teUZ1bmN0aW9ucy9CYXlzUHJlY2lzaW9uL21peHR1cmVfbW9kZWxfZnVuY3Rpb25zLlInLHNlcCA9ICIiKSkgCgpzZSA8LSBmdW5jdGlvbih4KSBzcXJ0KHZhcih4KS9sZW5ndGgoeCkpICAjZnVuY3Rpb24gdG8gY2FsY3VsYXRlIFNFCmNpIDwtIGZ1bmN0aW9uKHgpIChzcXJ0KHZhcih4KS9sZW5ndGgoeCkpKSoxLjk2ICAjZnVuY3Rpb24gdG8gY2FsY3VsYXRlIDk1JSBjb25maWRlbmNlIGludGVydmFsCnpzY29yZSA8LSBmdW5jdGlvbih4LGRhdGEpICh4IC0gbWVhbihkYXRhKSkvc2QoZGF0YSkgICNhbGxvd3MgdmFsdWVzIHRvIGJlIHogc2NvcmVkIHJlbGF0aXZlIHRvIGl0c2VsZiAoeCA9IGRhdGEpIG9yIGEgZGlmZmVyZW50IHZhcmlhYmxlICh4ICE9IGRhdGEpCgoKIyMjIGxvYWQgaW4gYWxsIGJlaGF2aW9yYWwgZGF0YToKbXlGaWxlIDwtIHBhc3RlKG15Q29tcCwnV29yay9Cb3N0b24vT1JCSVQvYW5hbHlzaXMvJyx0YXNrVmVyLCcvQWxsRGF0YV8nLHRhc2tWZXIsJy5jc3YnLHNlcCA9ICIiKQphbGxEYXRhIDwtIGRhdGEuZnJhbWUocmVhZC5jc3YobXlGaWxlLCBoZWFkZXIgPSBUUlVFKSkKCiMgYWRkIGNvbHVtbiBmb3IgZW1vdGlvbiBjb25maWRlbmNlIGxldmVsOgphbGxEYXRhJEVtb3Rpb25NZW1vcnlbYWxsRGF0YSRFbW90aW9uQ29ycmVjdCA9PSAxICYgYWxsRGF0YSRFbW90aW9uQ29uZmlkZW5jZSA9PSAxXSA8LSAxCmFsbERhdGEkRW1vdGlvbk1lbW9yeVthbGxEYXRhJEVtb3Rpb25Db3JyZWN0ID09IDEgJiBhbGxEYXRhJEVtb3Rpb25Db25maWRlbmNlID09IDBdIDwtIDAuNQphbGxEYXRhJEVtb3Rpb25NZW1vcnlbYWxsRGF0YSRFbW90aW9uQ29ycmVjdCA9PSAwXSA8LSAwCgpzdWJqZWN0cyA8LSB1bmlxdWUoYWxsRGF0YSRTdWJJRCkKTlN1YmpzID0gbGVuZ3RoKHN1YmplY3RzKQoKYGBgCgojIEZlYXR1cmUgRXJyb3JzClJlc3BvbnNlIC0gU3R1ZHkgYW5nbGUgYWNyb3NzIGFsbCBzdWJqZWN0cyBwbG90dGVkIGFzIGRlbnNpdHkgaGlzdG9ncmFtcyBwZXIgZmVhdHVyZS4gIApPdmVybGF5ZWQgaXMgdGhlIGJlc3QgZml0dGluZyBtaXh0dXJlIG1vZGVsIHBkZiAodm9uTWlzZXMgKyB1bmlmb3JtKSAgCmBgYHtyLCBmaWcud2lkdGg9NixmaWcuaGVpZ2h0PTIuNX0KCiMjIyBBbGwgQ29sb3IgYW5kIFNjZW5lCiMjIyBGaXQgbWl4dHVyZSBtb2RlbCB0byBhZ2dyZWdhdGUgZGF0YSAobmVlZHMgdG8gYmUgaW4gcmFkaWFucyk6CkNvbG9yIDwtIEpWMTBfZml0KHdyYXAoYWxsRGF0YSRDb2xSZXNwLzE4MCpwaSksIHdyYXAoYWxsRGF0YSRDb2xTdHVkeS8xODAqcGkpKQpwcmludChwYXN0ZTAoIkNvbG9yIDogJSBDb3JyZWN0ID0gIiwgcm91bmQoQ29sb3IkQiRQdCwgZGlnaXRzID0gNCkpKQpwcmludChwYXN0ZTAoIiAgICAgIDogUHJlY2lzaW9uID0gIiwgcm91bmQoQ29sb3IkQiRLLCBkaWdpdHMgPSA0KSkpCgpTY2VuZSA8LSBKVjEwX2ZpdCh3cmFwKGFsbERhdGEkU2NlbmVSZXNwLzE4MCpwaSksIHdyYXAoYWxsRGF0YSRTY2VTdHVkeS8xODAqcGkpKQpwcmludChwYXN0ZTAoIlNjZW5lIDogJSBDb3JyZWN0ID0gIiwgcm91bmQoU2NlbmUkQiRQdCwgZGlnaXRzID0gNCkpKQpwcmludChwYXN0ZTAoIiAgICAgIDogUHJlY2lzaW9uID0gIiwgcm91bmQoU2NlbmUkQiRLLCBkaWdpdHMgPSA0KSkpCgojIyMgbm93IGdldCBiZXN0IGZpdHRpbmcgUERGczoKcmFuZ2UgPSBzZXEoZnJvbSA9IC1waSwgdG8gPSBwaSwgYnkgPSBwaS8xODApCiMgMS4gR2V0IHZvbiBNaXNlcyBwZGYgYmFzZWQgb24gYWdncmVnYXRlIHByZWNpc2lvbgp5Q29sID0gdm9ubWlzZXNwZGYocmFuZ2UsMCxDb2xvciRCJEspCnlTY2UgPSB2b25taXNlc3BkZihyYW5nZSwwLFNjZW5lJEIkSykKIyBzY2FsZSBzbyBhcmVhIG9mIGRpc3RyaWJ1dGlvbiA9IHByb3BvcnRpb24gY29ycmVjdAp5Q29sID0geUNvbCAqIChDb2xvciRCJFB0LyhzdW0oeUNvbCkpKQp5U2NlID0geVNjZSAqIChTY2VuZSRCJFB0LyhzdW0oeVNjZSkpKQojIDIuIGFkZCBndWVzcyByYXRlICh1bmlmb3JtIGNvbXBvbmVudCkKeUNvbCA9IGRhdGEuZnJhbWUoeUNvbCArIChDb2xvciRCJFB1L2xlbmd0aChyYW5nZSkpKQp5U2NlID0gZGF0YS5mcmFtZSh5U2NlICsgKFNjZW5lJEIkUHUvbGVuZ3RoKHJhbmdlKSkpCgpjb2xuYW1lcyh5Q29sKTwtIGMoInByb2IiKQp5Q29sJGVycm9yIDwtIHNlcShmcm9tID0gLTE4MCwgdG8gPSAxODAsIGJ5ID0gMSkKY29sbmFtZXMoeVNjZSk8LSBjKCJwcm9iIikKeVNjZSRlcnJvciA8LSBzZXEoZnJvbSA9IC0xODAsIHRvID0gMTgwLCBieSA9IDEpCgoKIyBUaHJlc2hvbGQgZm9yIG1lbW9yeSAnc3VjY2VzcycgKGF0IGxlYXN0IDUwJSBjaGFuY2UgdGhhdCBlcnJvciBmaXRzIHZvbiBNaXNlcyksIHJvdW5kZWQgdG8gbmVhcmVzdCBtdWx0aXBsZSBvZiAzIChteSB1bmlxdWUgYW5nbGVzKToKY29sVCA8LSAgbWF4KGFicyh5Q29sJGVycm9yW3lDb2wkcHJvYiA+IChDb2xvciRCJFB1L2xlbmd0aChyYW5nZSkqMildKSkKY29sVCA8LSAzKnJvdW5kKGNvbFQvMykgCnNjZVQgPC0gIG1heChhYnMoeVNjZSRlcnJvclt5U2NlJHByb2IgPiAoU2NlbmUkQiRQdS9sZW5ndGgocmFuZ2UpKSoyXSkpCnNjZVQgPC0gMypyb3VuZChzY2VULzMpIApwcmludChwYXN0ZSgiVGhyZXNob2xkIGZvciBjb2xvciBtZW1vcnkgc3VjY2VzcyBhdCA1MCUgPD0gIiwgY29sVCwgIiBkZWdyZWVzIiwgc2VwID0gIiIpKQpwcmludChwYXN0ZSgiVGhyZXNob2xkIGZvciBzY2VuZSBtZW1vcnkgc3VjY2VzcyBhdCA1MCUgPD0gIiwgc2NlVCwgIiBkZWdyZWVzIiwgc2VwID0gIiIpKQoKIyBhZGQgb24gQ29sb3IgYW5kIFNjZW5lIGFjY3VyYWN5IGNvbHVtbnMgdG8gYWxsZGF0YSBiYXNlZCBvbiBtb2RlbCB0aHJlc2hvbGQ6CmFsbERhdGEkQ29sb3JDb3JyZWN0W2FsbERhdGEkQ29sQWJzRXJyb3IgPD0gY29sVF0gPC0gMQphbGxEYXRhJENvbG9yQ29ycmVjdFthbGxEYXRhJENvbEFic0Vycm9yID4gY29sVF0gPC0gMAphbGxEYXRhJFNjZW5lQ29ycmVjdFthbGxEYXRhJFNjZUFic0Vycm9yIDw9IHNjZVRdIDwtIDEKYWxsRGF0YSRTY2VuZUNvcnJlY3RbYWxsRGF0YSRTY2VBYnNFcnJvciA+IHNjZVRdIDwtIDAKCiMgcGxvdCBkYXRhIHdpdGggbGluZSBhdCBoZWlnaHQgb2YgdW5pZm9ybSBkaXN0cmlidXRpb246CnAxIDwtIGdncGxvdChhbGxEYXRhLCBhZXMoeCA9IENvbEVycm9yKSkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDYxLCBjb2xvciA9ICd3aGl0ZScsIGZpbGwgPSAnZ3JheTYwJywgYWVzKHk9Li5kZW5zaXR5Li4pLCAKICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKDEpKSArIAogICAgZ2VvbV9saW5lKGRhdGEgPSB5Q29sLCBhZXMoeCA9IGVycm9yLCB5ID0gcHJvYiksIGNvbG9yID0gJ2NvcmFsMicsIHNpemU9MS41KSArCiAgICB4bGFiKCJFcnJvciIpICsgeWxhYigicChFcnJvcikiKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDAuMDIwKSwgZXhwYW5kID0gYygwLDApLCBicmVha3MgPSBzZXEoMCwwLjAyMCxieSA9IDAuMDA1KSkgKyAKICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGJyZWFrcyA9IHNlcSgtMTgwLDE4MCxieSA9IDYwKSkgKyAKICAgIGdndGl0bGUoIkNvbG9yIEVycm9ycyIpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemU9MjgpLCBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksIAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI0KSwKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLCB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseT0iSGVsdmV0aWNhIikpICAKCmdnc2F2ZSgnQ29sb3JfRXJyb3JzLmpwZycsIHBsb3QgPSBwMSwgZHBpID0gMzAwLCB3aWR0aCA9IDYuNSwgaGVpZ2h0ID0gNSkKCnAyIDwtIGdncGxvdChhbGxEYXRhLCBhZXMoeCA9IFNjZUVycm9yKSkgKwogICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDYxLCBjb2xvciA9ICd3aGl0ZScsIGZpbGwgPSAnZ3JheTYwJywgYWVzKHk9Li5kZW5zaXR5Li4pLAogICAgICAgICAgICAgICAgICAgcG9zaXRpb249cG9zaXRpb25fZG9kZ2UoMSkpICsgCiAgICBnZW9tX2xpbmUoZGF0YSA9IHlTY2UsIGFlcyh4ID0gZXJyb3IsIHkgPSBwcm9iKSwgY29sb3IgPSAnZG9kZ2VyYmx1ZTInLCBzaXplPTEuNSkgKwogICAgeGxhYigiRXJyb3IiKSArIHlsYWIoInAoRXJyb3IpIikgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwwLjAzMiksIGV4cGFuZCA9IGMoMCwwKSwgYnJlYWtzID0gc2VxKDAsMC4wMzIsYnkgPSAwLjAwOCkpICsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBicmVha3MgPSBzZXEoLTE4MCwxODAsYnkgPSA2MCkpICsgCiAgICBnZ3RpdGxlKCJTY2VuZSBlcnJvcnMiKSArCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplPTI4KSwgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpLCAKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLCBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNCksCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIiwgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHk9IkhlbHZldGljYSIpKSAgICAgCgpnZ3NhdmUoJ1NjZW5lX0Vycm9ycy5qcGcnLCBwbG90ID0gcDIsIGRwaSA9IDMwMCwgd2lkdGggPSA2LjUsIGhlaWdodCA9IDUpCgptdWx0aXBsb3QocDEscDIsIGNvbHMgPSAyKQoKYGBgCgojIFN1YmplY3QgTWl4dHVyZSBNb2RlbCBieSBDb2xvci9TY2VuZSBGZWF0dXJlCmBgYHtyLCBmaWcud2lkdGg9NSxmaWcuaGVpZ2h0PTN9CgojIyMgQ29tcHV0ZSBtaXh0dXJlIG1vZGVsIGVzdGltYXRlcyBieSBzdWJqZWN0IGFuZCBmZWF0dXJlCm1peHR1cmUgPC0gZGF0YS5mcmFtZShtYXRyaXgoMCwgbnJvdyA9IE5TdWJqcyoyLCBuY29sID0gNCkpCm5hbWVzKG1peHR1cmUpIDwtIGMoIlN1YklEIiwiRmVhdHVyZSIsInBUIiwiayIpCgpyb3cgPC0gMApmb3IgKGlkeCBpbiAxOmxlbmd0aChzdWJqZWN0cykpIHsKICAgIG15RGF0YSA8LSBzdWJzZXQoYWxsRGF0YSwgU3ViSUQgPT0gYXMuaW50ZWdlcihzdWJqZWN0c1tpZHhdKSkKCiAgICByb3cgPSByb3cgKyAxCiAgICBtaXh0dXJlJFN1YklEW3Jvd10gICA9IG15RGF0YSRTdWJJRFsxXQogICAgbWl4dHVyZSRGZWF0dXJlW3Jvd10gPSAnQ29sb3InCiAgICBjdXJNb2RlbCA8LSBKVjEwX2ZpdCh3cmFwKG15RGF0YSRDb2xSZXNwLzE4MCpwaSksIHdyYXAobXlEYXRhJENvbFN0dWR5LzE4MCpwaSkpCiAgICBtaXh0dXJlJHBUW3Jvd10gPC0gY3VyTW9kZWwkQiRQdAogICAgbWl4dHVyZSRrW3Jvd10gIDwtIGN1ck1vZGVsJEIkSwoKICAgIHJvdyA9IHJvdyArIDEKICAgIG1peHR1cmUkU3ViSURbcm93XSAgID0gbXlEYXRhJFN1YklEWzFdCiAgICBtaXh0dXJlJEZlYXR1cmVbcm93XSA9ICdTY2VuZScKICAgIGN1ck1vZGVsIDwtIEpWMTBfZml0KHdyYXAobXlEYXRhJFNjZW5lUmVzcC8xODAqcGkpLCB3cmFwKG15RGF0YSRTY2VTdHVkeS8xODAqcGkpKQogICAgbWl4dHVyZSRwVFtyb3ddIDwtIGN1ck1vZGVsJEIkUHQKICAgIG1peHR1cmUka1tyb3ddICA8LSBjdXJNb2RlbCRCJEsKICB9I2VuZCBvZiBsb29wIHRocm91Z2ggc3ViamVjdHMgICAgCgptaXh0dXJlJFN1YklEIDwtIGFzLmZhY3RvcihtaXh0dXJlJFN1YklEKQptaXh0dXJlJEZlYXR1cmUgPC0gYXMuZmFjdG9yKG1peHR1cmUkRmVhdHVyZSkKbWl4dHVyZSA8LSBtaXh0dXJlICU+JSBncm91cF9ieShGZWF0dXJlKSAjZ3JvdXAgZGF0YSBieSB0aGVzZSBmYWN0b3JzCgoKIyBNZW1vcnkgU3VjY2VzcyAocHJvcG9ydGlvbiBjb3JyZWN0KQpwMSA8LSBnZ3Bsb3QobWl4dHVyZSwgYWVzKHg9RmVhdHVyZSwgeT1wVCwgY29sb3I9RmVhdHVyZSwgZmlsbD1GZWF0dXJlKSkgKwogICAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbT0iYmFyIiwgYWxwaGEgPSAwLjQsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMSkpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJ2NvcmFsMicsJ2RvZGdlcmJsdWUyJykpICsgCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygnY29yYWwyJywnZG9kZ2VyYmx1ZTInKSkgKwogICAgZ2VvbV9kb3RwbG90KGJpbmF4aXM9J3knLCBzdGFja2Rpcj0nY2VudGVyJywgYWxwaGEgPSAwLjgsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMSkpICsKICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsIGdlb20gPSAiZXJyb3JiYXIiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEuOTYpLAogICAgICAgICAgICAgICAgIHdpZHRoID0gMC40LCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjYsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMSkpICsKICAgIGdndGl0bGUoIk1lbW9yeSBTdWNjZXNzIikgKyAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzPWMoMCwxKSkgKyAKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemU9MjgpLCBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiksIAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMiksIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIyKSwKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLCB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseT0iSGVsdmV0aWNhIikpCgojIFByZWNpc2lvbiBzdW1tYXJ5CnAyIDwtIGdncGxvdChtaXh0dXJlLCBhZXMoeD1GZWF0dXJlLCB5PWssIGNvbG9yPUZlYXR1cmUsIGZpbGw9RmVhdHVyZSkpICsKICAgIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGdlb209ImJhciIsIGFscGhhID0gMC40LCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDEpKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCdjb3JhbDInLCdkb2RnZXJibHVlMicpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygnY29yYWwyJywnZG9kZ2VyYmx1ZTInKSkgKwogICAgZ2VvbV9kb3RwbG90KGJpbmF4aXM9J3knLCBzdGFja2Rpcj0nY2VudGVyJywgYWxwaGEgPSAwLjgsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMSkpICsKICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsIGdlb20gPSAiZXJyb3JiYXIiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEuOTYpLAogICAgICAgICAgICAgICAgIHdpZHRoID0gMC40LCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjYsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMSkpICsKICAgIGdndGl0bGUoIk1lbW9yeSBQcmVjaXNpb24iKSArIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cz1jKDAsODQpKSArIAogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZT0yOCksIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSwgCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIyKSwgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjIpLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5PSJIZWx2ZXRpY2EiKSkKCm11bHRpcGxvdChwMSxwMiwgY29scyA9IDIpCgpwYW5kZXIodC50ZXN0KHBUIH4gRmVhdHVyZSwgZGF0YT1taXh0dXJlLCBwYWlyZWQgPSBUUlVFKSkKcGFuZGVyKHQudGVzdChrIH4gRmVhdHVyZSwgZGF0YT1taXh0dXJlLCBwYWlyZWQgPSBUUlVFKSkKCiMgZm9yIHNhdmluZyBkYXRhIGluIGNzdjoKcFQgPC0gc3Vic2V0KG1peHR1cmUsIHNlbGVjdCA9IC1jKGspKSAlPiUKICAgICAgIHNwcmVhZChrZXkgPSBGZWF0dXJlLCB2YWx1ZSA9IHBUKQpjb2xuYW1lcyhwVCkgPC0gYygnU3ViSUQnLCdDb2xvcnBUJywnU2NlbmVwVCcpCmsgPC0gc3Vic2V0KG1peHR1cmUsIHNlbGVjdCA9IC1jKHBUKSkgJT4lCiAgICAgICBzcHJlYWQoa2V5ID0gRmVhdHVyZSwgdmFsdWUgPSBrKQpjb2xuYW1lcyhrKSA8LSBjKCdTdWJJRCcsJ0NvbG9yaycsJ1NjZW5laycpCgpncm91cF9kYXRhIDwtIG1lcmdlLmRhdGEuZnJhbWUocFQsayxieT0nU3ViSUQnKSAlPiUKICAgICAgICAgICAgICAgc29ydEZyYW1lKFN1YklEKQoKYGBgCgojIyBFbW90aW9uIE1lbW9yeQpQcm9wb3J0aW9uIGNvcnJlY3QgYW5kIHByb3BvcnRpb24gb2YgaGlnaCBjb25maWRlbmNlIGNvcnJlY3QgZW1vdGlvbiByZXNwb25zZXMgIApgYGB7ciwgZmlnLndpZHRoPTMsZmlnLmhlaWdodD0xLjh9CgojIyMgRW1vdGlvbiBhY2N1cmFjeSAocHJvcG9ydGlvbiBjb3JyZWN0KQplbW90aW9uIDwtIGFsbERhdGEgJT4lIAogICAgICAgICAgICAgICAgZ3JvdXBfYnkoU3ViSUQpICU+JSAKICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoRW1vdGlvblN1Y2Nlc3MgPSBtZWFuKEVtb3Rpb25Db3JyZWN0KSkgCmdyb3VwX2RhdGEgPC0gbWVyZ2UuZGF0YS5mcmFtZShncm91cF9kYXRhLCBlbW90aW9uLCBieSA9ICdTdWJJRCcpCgpzdW1tYXJ5IDwtIGVtb3Rpb24gJT4lCiAgICAgICAgICAgICBzdW1tYXJpc2UoRW1vdGlvbkNvcnJlY3QgPSBtZWFuKEVtb3Rpb25TdWNjZXNzKSwgU0UgPSBzZShFbW90aW9uU3VjY2VzcykpCnByaW50KGthYmxlKHN1bW1hcnkpKQoKIyMjIFByb3BvcnRpb24gb2YgY29yZWN0IHJlcHNvbnNlcyB0aGF0IHdlcmUgaGlnaCBjb25maWRlbmNlCmNvcnJlY3REYXRhIDwtIHN1YnNldChhbGxEYXRhLCBFbW90aW9uQ29ycmVjdCA9PSAxKQpjb25maWRlbmNlIDwtIGNvcnJlY3REYXRhICU+JSAKICAgICAgICAgICAgICAgIGdyb3VwX2J5KFN1YklEKSAlPiUgCiAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKEVtb3Rpb25Db25maWRlbmNlID0gbWVhbihFbW90aW9uQ29uZmlkZW5jZSkpCmdyb3VwX2RhdGEgPC0gbWVyZ2UuZGF0YS5mcmFtZShncm91cF9kYXRhLCBjb25maWRlbmNlLCBieSA9ICdTdWJJRCcpCgpzdW1tYXJ5IDwtIGNvbmZpZGVuY2UgJT4lCiAgICAgICAgICAgICBzdW1tYXJpc2UoRW1vdGlvbkNvbmYgPSBtZWFuKEVtb3Rpb25Db25maWRlbmNlKSwgU0UgPSBzZShFbW90aW9uQ29uZmlkZW5jZSkpCnByaW50KGthYmxlKHN1bW1hcnkpKQoKYGBgCgojIE1lbW9yeSBEZXBlbmRlbmN5CiMjIFJldHJpZXZhbCBTdWNjZXNzClVzZXMgdGhlIGRlcGVuZGVudCB2cyBpbmRlcGVuZGVudCBhcHByb2FjaCBmcm9tIEhvcm5lciAmIEJ1cmdlc3MgKDIwMTMvMjAxNCkgdG8gZXN0aW1hdGUgZGVwZW5kZW5jeSBvZiBjb3JyZWN0IHJldHJpZXZhbCBmb3IgZWFjaCBmZWF0dXJlIHBhaXIgIApgYGB7ciwgZmlnLndpZHRoPTQsZmlnLmhlaWdodD0zfQoKZGVwZW5kZW5jeSA8LSBkYXRhLmZyYW1lKG1hdHJpeCgwLCBucm93ID0gTlN1YmpzKjMsIG5jb2wgPSAzKSkKbmFtZXMoZGVwZW5kZW5jeSkgPC0gYygiU3ViSUQiLCJQYWlyIiwiRGlmZmVyZW5jZSIpCgpyb3cgPC0gMApmb3IgKGlkeCBpbiAxOmxlbmd0aChzdWJqZWN0cykpIHsKICAgIG15RGF0YSA8LSBzdWJzZXQoYWxsRGF0YSwgU3ViSUQgPT0gYXMuaW50ZWdlcihzdWJqZWN0c1tpZHhdKSkKICAgCiAgICBmb3IgKHBhaXIgaW4gMTozKSB7CiAgICAgIGlmIChwYWlyID09IDEpIHsKICAgICAgICBuYW1lID0gJ0Vtb3Rpb24tQ29sb3InCiAgICAgICAgY3VyQWNjIDwtIGNiaW5kKG15RGF0YSRFbW90aW9uQ29ycmVjdCxteURhdGEkQ29sb3JDb3JyZWN0KQogICAgICB9IGVsc2UgaWYgKHBhaXIgPT0gMikgewogICAgICAgIG5hbWUgPSAnRW1vdGlvbi1TY2VuZScKICAgICAgICBjdXJBY2MgPC0gY2JpbmQobXlEYXRhJEVtb3Rpb25Db3JyZWN0LG15RGF0YSRTY2VuZUNvcnJlY3QpCiAgICAgIH0gZWxzZSBpZiAocGFpciA9PSAzKSB7CiAgICAgICAgbmFtZSA9ICdDb2xvci1TY2VuZScKICAgICAgICBjdXJBY2MgPC0gY2JpbmQobXlEYXRhJENvbG9yQ29ycmVjdCxteURhdGEkU2NlbmVDb3JyZWN0KQogICAgICB9CiAgICAgIAogICAgICByb3cgPSByb3cgKyAxCiAgICAgIGRlcGVuZGVuY3kkU3ViSURbcm93XSAgID0gbXlEYXRhJFN1YklEWzFdCiAgICAgIGRlcGVuZGVuY3kkUGFpcltyb3ddICAgID0gbmFtZQogICAgICBkYXRhICA9IHN1bSghcm93U3VtcyhjdXJBY2MpID09IDEpL25yb3coY3VyQWNjKSAjYWN0dWFsIGRlcGVuZGVuY3kgb2YgdGhlIGRhdGEgKHByb3BvcnRpb24gb2YgdGltZXMgYm90aCByZW1lbWJlcmVkIG9yIGZvcmdvdHRlbikKICAgICAgc3VtQWNjIDwtIGNvbE1lYW5zKGN1ckFjYykKICAgICAgaW5kZXBlbmRlbnQgPSAoc3VtQWNjWzFdKnN1bUFjY1syXSkrKCgxLXN1bUFjY1sxXSkqKDEtc3VtQWNjWzJdKSkgI2RlcGVuZGVuY3kgb2YgZGF0YSBleHBlY3RlZCBiYXNlZCBvbiBwZXJmb3JtYW5jZSAoYXNzdW1pbmcgYWN0dWFsbHkgaW5kZXBlbmRlbnQpCiAgICAgIGRlcGVuZGVuY3kkRGlmZmVyZW5jZVtyb3ddID0gZGF0YSAtIGluZGVwZW5kZW50ICNkZWdyZWUgdG8gd2hpY2ggZmVhdHVyZXMgYXJlIG1vcmUvbGVzcyBkZXBlbmRlbnQgaW4gbWVtb3J5IHRoYW4gZXhwZWN0ZWQgYnkgY2hhbmNlIChiYXNlZCBvbiBwZXJmb3JtYW5jZSkKICAgICB9CiAgfSNlbmQgb2YgbG9vcCB0aHJvdWdoIHN1YmplY3RzICAgIAoKZGVwZW5kZW5jeSRQYWlyIDwtIGFzLmZhY3RvcihkZXBlbmRlbmN5JFBhaXIpCgojIGRhdGEgdnMgaW5kZXBlbmRlbnQgbW9kZWwgYnkgZmVhdHVyZQpzdWNjZXNzIDwtIGRlcGVuZGVuY3kgJT4lIAogICAgICAgICAgICAgIGdyb3VwX2J5KFN1YklELCBQYWlyKQoKcDEgPC0gZ2dwbG90KHN1Y2Nlc3MsIGFlcyh4ID0gUGFpciwgeT1EaWZmZXJlbmNlLCBmaWxsPVBhaXIpKSArCiAgICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBnZW9tPSJiYXIiLCBhbHBoYSA9IDAuNSkgKwogICAgZ2VvbV9kb3RwbG90KGJpbmF4aXM9J3knLCBzdGFja2Rpcj0nY2VudGVyJywgZG90c2l6ZT0xLCBhbHBoYSA9IDAuOCkgKwogICAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgZ2VvbSA9ICJlcnJvcmJhciIsIGZ1bi5hcmdzID0gbGlzdChtdWx0ID0gMS45NiksCiAgICAgICAgICAgICAgICAgd2lkdGggPSAwLjQsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuNikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygnIzY2YmQ2MycsJ2NvcmFsMicsJ2RvZGdlcmJsdWUyJykpICsgCiAgICB5bGFiKCJEZXBlbmRlbmN5IikgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4xMiwwLjI0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4cGFuZCA9IGMoMCwwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgtMC4xMiwwLjI0LGJ5ID0gMC4wNikpICsKICAgIGdndGl0bGUoIlJldHJpZXZhbCBTdWNjZXNzIERlcGVuZGVuY2UiKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsKICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIkNvbG9yXG5TY2VuZSIsIkNvbG9yXG5FbW90aW9uIiwiU2NlbmVcbkVtb3Rpb24iKSkgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZT0yOCksIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSwgCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjIpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjQpLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5PSJIZWx2ZXRpY2EiKSkgICAKCnBsb3QocDEpCmdnc2F2ZSgnQ29ycmVjdF9EZXBlbmRlbmN5LmpwZycsIHBsb3QgPSBwMSwgZHBpID0gMzAwLCB3aWR0aCA9IDYsIGhlaWdodCA9IDUpCgojdC10ZXN0cywgZ3JlYXRlciB0aGFuIDA/CnBhbmRlcih0LnRlc3Qoc3VjY2VzcyREaWZmZXJlbmNlW3N1Y2Nlc3MkUGFpciA9PSAnQ29sb3ItU2NlbmUnXSwgbXU9MCkpCnBhbmRlcih0LnRlc3Qoc3VjY2VzcyREaWZmZXJlbmNlW3N1Y2Nlc3MkUGFpciA9PSAnRW1vdGlvbi1Db2xvciddLCBtdT0wKSkKcGFuZGVyKHQudGVzdChzdWNjZXNzJERpZmZlcmVuY2Vbc3VjY2VzcyRQYWlyID09ICdFbW90aW9uLVNjZW5lJ10sIG11PTApKQoKIyBmb3Igc2F2aW5nIGRhdGEgaW4gY3N2OgpzdWNjZXNzIDwtIHN1Y2Nlc3MgJT4lCiAgICAgICAgICAgICAgIHNwcmVhZChrZXkgPSBQYWlyLCB2YWx1ZSA9IERpZmZlcmVuY2UpCmdyb3VwX2RhdGEgPC0gbWVyZ2UuZGF0YS5mcmFtZShncm91cF9kYXRhLHN1Y2Nlc3MsYnk9J1N1YklEJykgJT4lCiAgICAgICAgICAgICAgICBzb3J0RnJhbWUoU3ViSUQpCgpgYGAKCiMjIyBSZXRyaWV2YWwgUHJlY2lzaW9uCkNvbXB1dGVzIHRoZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiBjb2xvciBhbmQgc2NlbmUgc3VjY2VzcyAoMSAwKSBhbmQgcHJlY2lzaW9uIChyZXZlcnNlZCAnY29ycmVjdCcgZXJyb3IpLiAgCmBgYHtyLCBmaWcud2lkdGg9NCxmaWcuaGVpZ2h0PTN9CgpkZXBlbmRlbmN5IDwtIGRhdGEuZnJhbWUobWF0cml4KDAsIG5yb3cgPSBOU3VianMqMywgbmNvbCA9IDMpKQpuYW1lcyhkZXBlbmRlbmN5KSA8LSBjKCJTdWJJRCIsIlBhaXIiLCJEZXBlbmRlbmN5IikKCnJvdyA8LSAwCmZvciAoaWR4IGluIDE6bGVuZ3RoKHN1YmplY3RzKSkgewoKICBmb3IgKHBhaXIgaW4gMTozKSB7CiAgICByb3cgPSByb3cgKyAxCiAgICBpZiAocGFpciA9PSAxKSB7CiAgICAgICBteURhdGEgPC0gc3Vic2V0KGFsbERhdGEsIFN1YklEID09IHN1YmplY3RzW2lkeF0gJiBDb2xvckNvcnJlY3QgPT0gMSAmIFNjZW5lQ29ycmVjdCA9PSAxKQogICAgICAgbmFtZSA9ICdDb2xvclAtU2NlbmVQJwogICAgICAgZGVwZW5kZW5jeSREZXBlbmRlbmN5W3Jvd10gID0gZmlzaGVyeihjb3IoMTgwIC0gbXlEYXRhJENvbEFic0Vycm9yLDE4MCAtIG15RGF0YSRTY2VBYnNFcnJvcikpCiAgICB9IGVsc2UgaWYgKHBhaXIgPT0gMikgewogICAgICAgbXlEYXRhIDwtIHN1YnNldChhbGxEYXRhLCBTdWJJRCA9PSBzdWJqZWN0c1tpZHhdICYgU2NlbmVDb3JyZWN0ID09IDEpCiAgICAgICBuYW1lID0gJ0NvbG9yUy1TY2VuZVAnCiAgICAgICBkZXBlbmRlbmN5JERlcGVuZGVuY3lbcm93XSAgPSBmaXNoZXJ6KGNvcihteURhdGEkQ29sb3JDb3JyZWN0LDE4MCAtIG15RGF0YSRTY2VBYnNFcnJvcikpCiAgICB9IGVsc2UgaWYgKHBhaXIgPT0gMykgewogICAgICAgbXlEYXRhIDwtIHN1YnNldChhbGxEYXRhLCBTdWJJRCA9PSBzdWJqZWN0c1tpZHhdICYgQ29sb3JDb3JyZWN0ID09IDEpCiAgICAgICBuYW1lID0gJ1NjZW5lUy1Db2xvclAnCiAgICAgICBkZXBlbmRlbmN5JERlcGVuZGVuY3lbcm93XSAgPSBmaXNoZXJ6KGNvcihteURhdGEkU2NlbmVDb3JyZWN0LDE4MCAtIG15RGF0YSRDb2xBYnNFcnJvcikpCiAgICB9CiAgICBkZXBlbmRlbmN5JFN1YklEW3Jvd10gPSBteURhdGEkU3ViSURbMV0KICAgIGRlcGVuZGVuY3kkUGFpcltyb3ddICA9IG5hbWUKICAgfQogIH0jZW5kIG9mIGxvb3AgdGhyb3VnaCBzdWJqZWN0cyAgICAKCmRlcGVuZGVuY3kkUGFpciA8LSBhcy5mYWN0b3IoZGVwZW5kZW5jeSRQYWlyKQoKIyBjb3JyZWxhdGlvbnMgYnkgcGFpcgpwcmVjaXNpb24gPC0gZGVwZW5kZW5jeSAlPiUgCiAgICAgICAgICAgICAgZ3JvdXBfYnkoU3ViSUQsIFBhaXIpCgpwMSA8LSBnZ3Bsb3QocHJlY2lzaW9uLCBhZXMoeCA9IFBhaXIsIHk9RGVwZW5kZW5jeSwgZmlsbD1QYWlyKSkgKwogICAgc3RhdF9zdW1tYXJ5KGZ1bi55ID0gbWVhbiwgZ2VvbT0iYmFyIiwgYWxwaGEgPSAwLjUpICsKICAgIGdlb21fZG90cGxvdChiaW5heGlzPSd5Jywgc3RhY2tkaXI9J2NlbnRlcicsIGRvdHNpemU9MSwgYWxwaGEgPSAwLjgpICsKICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsIGdlb20gPSAiZXJyb3JiYXIiLCBmdW4uYXJncyA9IGxpc3QobXVsdCA9IDEuOTYpLAogICAgICAgICAgICAgICAgIHdpZHRoID0gMC40LCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjYpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoJyM2NmJkNjMnLCdjb3JhbDInLCdkb2RnZXJibHVlMicpKSArIAogICAgeWxhYigiTWVhbiB6IikgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMC4yMiwwLjQyKSwgZXhwYW5kID0gYygwLDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKC0wLjQsMC40LGJ5ID0gMC4xKSkgKwogICAgZ2d0aXRsZSgiUmV0cmlldmFsIFByZWNpc2lvbiBEZXBlbmRlbmNlIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArCiAgICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscz1jKCJDb2xvci5QXG5TY2VuZS5QIiwiQ29sb3IuU1xuU2NlbmUuUCIsIlNjZW5lLlNcbkNvbG9yLlAiKSkgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZT0yOCksIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSwgCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjIpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjQpLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIHRleHQgPSBlbGVtZW50X3RleHQoZmFtaWx5PSJIZWx2ZXRpY2EiKSkgICAKCnBsb3QocDEpCmdnc2F2ZSgnUHJlY2lzaW9uX0RlcGVuZGVuY3kuanBnJywgcGxvdCA9IHAxLCBkcGkgPSAzMDAsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNSkKCiN0LXRlc3RzLCBncmVhdGVyIHRoYW4gMD8KcGFuZGVyKHQudGVzdChwcmVjaXNpb24kRGVwZW5kZW5jeVtwcmVjaXNpb24kUGFpciA9PSAnQ29sb3JQLVNjZW5lUCddLCBtdT0wKSkKcGFuZGVyKHQudGVzdChwcmVjaXNpb24kRGVwZW5kZW5jeVtwcmVjaXNpb24kUGFpciA9PSAnQ29sb3JTLVNjZW5lUCddLCBtdT0wKSkKcGFuZGVyKHQudGVzdChwcmVjaXNpb24kRGVwZW5kZW5jeVtwcmVjaXNpb24kUGFpciA9PSAnU2NlbmVTLUNvbG9yUCddLCBtdT0wKSkKCiMgZm9yIHNhdmluZyBkYXRhIGluIGNzdjoKcHJlY2lzaW9uIDwtIHByZWNpc2lvbiAlPiUKICAgICAgICAgICAgICAgc3ByZWFkKGtleSA9IFBhaXIsIHZhbHVlID0gRGVwZW5kZW5jeSkKZ3JvdXBfZGF0YSA8LSBtZXJnZS5kYXRhLmZyYW1lKGdyb3VwX2RhdGEscHJlY2lzaW9uLGJ5PSdTdWJJRCcpICU+JQogICAgICAgICAgICAgICAgc29ydEZyYW1lKFN1YklEKQoKYGBgCgpgYGB7cn0Kd3JpdGUuY3N2KGdyb3VwX2RhdGEsICJCZWhhdmlvcmFsX2RhdGEuY3N2Iiwgcm93Lm5hbWVzPUZBTFNFKQpgYGA=