Exploring relationship between surprisal and SPRT

initial EDA

surps.RTs %>% 
  pivot_longer(starts_with("surp_"), names_to = "model", values_to = "surprisal", names_prefix = "surp_") %>%
  drop_na() %>% 
  ggplot(aes(x=surprisal,y=RT)) +
  # geom_density(aes(x=surprisal,y=1200+750*..density..)) + 
  geom_hex() + scale_fill_gradient(low="#DDDDDD",high="black") +
  # geom_point(alpha=.1,color="gray") + 
  geom_smooth() +
  xlab("surprisal") +
  facet_wrap(~model)+
  ggtitle("surprisal vs self-paced RT on naturalstories data")
`geom_smooth()` using method = 'gam' and formula 'y ~ s(x, bs = "cs")'

# with arithmetic statistics
surps.RTs.perword %>% 
  pivot_longer(starts_with("surp_"), names_to = "model", values_to = "surprisal", names_prefix = "surp_") %>%
  drop_na() %>% 
  ggplot(aes(x=surprisal,y=meanItemRT)) +
  # geom_density(data=surps.RTs %>% 
      # pivot_longer(starts_with("surp_"), names_to = "model", values_to = "surprisal", names_prefix = "surp_") %>%
      # drop_na(), 
    # aes(x=surprisal,y=-1250*..density..)) + 
  geom_errorbar(aes(ymin=meanItemRT-sdItemRT, ymax=meanItemRT+sdItemRT),alpha=.1, color="black") +
  geom_point(alpha=.1,color="blue") +
  xlab("surprisal") +
  facet_wrap(~model)+
  ggtitle("surprisal vs mean RT (blue) +-1sd (black) per item")


# with geometric statistics
# surps.RTs.perword %>% 
#   pivot_longer(starts_with("surp_"), names_to = "model", values_to = "surprisal", names_prefix = "surp_") %>%
#   drop_na() %>% 
#   ggplot(aes(x=surprisal,y=gmeanItemRT)) +
#   geom_density(aes(x=surprisal,y=1200+750*..density..)) + 
#   geom_errorbar(aes(ymin=gmeanItemRT/gsdItemRT, ymax=gmeanItemRT*gsdItemRT),alpha=.1, color="black") +
#   geom_point(alpha=.1,color="blue") +
#   xlab("surprisal") +
#   facet_wrap(~model)+
#   ggtitle("surprisal vs geometric mean RT (blue) * gsd^{+-1} (black) per item")

Almost all the data is at low surprisal. The variance increases a bit with higher surprisal.

surps.RTs %>%
pivot_longer(starts_with("surp_") &!contains("boyce"), 
             names_to = "model", values_to = "surprisal", names_prefix = "surp_") %>%
drop_na() %>% 
ggplot(aes(x=surprisal,y=RT)) +
stat_boxplot(aes(x=cut_width(surprisal,boundary=0, width=1)),notch=T,varwidth=F,position="identity",alpha=.75,
             outlier.color="gray", outlier.alpha = .5, outlier.size= .5,outlier.shape=20, color="blue"
             ) +
# stat_summary_bin(fun.data="mean_sdl", geom = "crossbar", binwidth = .5, alpha=0.2, fill="blue", size=.1)+
# stat_summary_bin(fun="median", binwidth = 1, alpha=0.2, size=.5, shape=3, color="red")+
xlab("surprisal (binned)") + theme(axis.text.x = element_text(angle=90, vjust=.5, hjust=1)) +
facet_wrap(~model,nrow=1) +
ggtitle("surprisal vs RT, binned by surprisal") 


surps.RTs %>% 
  pivot_longer(starts_with("surp_boyce"), 
               names_to = "model", values_to = "surprisal", names_prefix = "surp_") %>%
  drop_na() %>% 
  ggplot(aes(x=surprisal,y=RT)) +
  stat_boxplot(aes(x=cut_width(surprisal,boundary=0, width=1)),notch=T,varwidth=F,position="identity",alpha=.75,
               outlier.color="gray", outlier.alpha = .5, outlier.size= .5,outlier.shape=20, color="blue"
               ) +
  # stat_summary_bin(fun.data="mean_sdl", geom = "crossbar", binwidth = .5, alpha=0.2, fill="blue", size=.1)+
  # stat_summary_bin(fun="median", binwidth = 1, alpha=0.2, size=.5, shape=3, color="red")+
  xlab("surprisal (binned)") + theme(axis.text.x = element_text(angle=90, vjust=.5, hjust=1)) +
  facet_wrap(~model) +
  ggtitle("surprisal vs RT, binned by surprisal")

qiuck GAM Comparison

plot_compare_models_smooth<-function(data, what_to_predict, surp_threshold = 100, ...){
  data %>%
  pivot_longer(starts_with("surp_") & !ends_with("_c"), 
               names_to = "model", values_to = "surprisal", 
               names_prefix = "surp_") %>% 
    filter(!is.na(get(what_to_predict)),!is.na(surprisal)) %>% filter(surprisal<=surp_threshold) %>% 
  mutate(model=factor(model)) %>% 
  mutate(model=fct_relevel(model,"GPT2","GPT2-large","GPT-Neo","GPT-J","GPT3", after = 3)) %>% 
    ggplot(aes(color=model)) +
    geom_smooth(aes(x=surprisal,y=get(what_to_predict)), ...) +
    labs(x = "surprisal", y=what_to_predict) 
}

What to consider in choosing our basis?

  • cubic regression spline bs = 'cr' places knots by quantile (probably not what we want, since it will make things wiggly in the low-surprisal area where all the data are, artificially inflating edf, I think)
  • B-splines family (bs = 'bs', bs = 'ps', bs = 'ad') places knots evenly
  • thin plate bs = 'tp' places knots randomly max.knots (see smooth.construct.tp.smooth.spec)
#quick and dirty comparison
(
surps.RTs.perword %>% 
  plot_compare_models_smooth("meanItemRT", #surp_threshold = 30,
                             method = "gam", formula = y ~ s(x, bs = "tp")) + ggtitle("tp")
)+(
surps.RTs.perword %>% 
  plot_compare_models_smooth("meanItemRT", #surp_threshold = 30,
                             method = "gam", formula = y ~ s(x, bs = "cr")) + ggtitle("cr")
)+ plot_layout(guides = 'collect') + plot_annotation("SPRT vs surprisal GAMs quick model comparison")

Fitting gams

surps.RTs_lag_c <- surps.RTs %>% 
  inner_join(surps.RTs_lag_c.perword) %>% 
  mutate(Word_ID=as_factor(str_c(story_num, word_num_in_story, sep="_"))) %>% 
  relocate(Word_ID,word)
Joining, by = c("word_num_in_sentence", "sentence_num", "sentence", "word", "offset", "story_num", "surp_GPT2", "surp_GPT2-large", "surp_GPT-Neo", "surp_GPT-J", "surp_GPT3", "nth_occurence_in_story", "word_num_in_story", "nItem", "meanItemRT", "sdItemRT", "gmeanItemRT", "gsdItemRT", "word_human", "wordp_whole", "wordp_word", "wordp_1", "is_in_common_vocab", "wordlength", "Word", "surp_boyce_txl", "tokencount_boyce_txl", "surp_boyce_ngram", "tokencount_boyce_ngram", "surp_boyce_grnn", "tokencount_boyce_grnn", "freq", "length")

GAMs for SPRT

Fit a GAM for the GPT data

job::job({
  gam_gpt3_RT   <- fit_bam_SPRT(formula1, surps.RTs_lag_c, "GPT3")
  gam_gpt2_RT   <- fit_bam_SPRT(formula1, surps.RTs_lag_c, "GPT2")
  gam_gpt2l_RT  <- fit_bam_SPRT(formula1, surps.RTs_lag_c, "GPT2-large")
  gam_gptj_RT   <- fit_bam_SPRT(formula1, surps.RTs_lag_c, "GPT-J")
  gam_gptneo_RT <- fit_bam_SPRT(formula1, surps.RTs_lag_c, "GPT-Neo")
  
  write_rds(gam_gpt3_RT  , file="scratch/gam_gpt3_RT.rds")
  write_rds(gam_gpt2_RT  , file="scratch/gam_gpt2_RT.rds")
  write_rds(gam_gpt2l_RT , file="scratch/gam_gpt2l_RT.rds")
  write_rds(gam_gptj_RT  , file="scratch/gam_gptj_RT.rds")
  write_rds(gam_gptneo_RT, file="scratch/gam_gptneo_RT.rds")
}, 
title="fitting GAMs RT v GPT surprisals")

surprisal vs mazeRT

Aligning with AMAZE TASK from Boyce

# Data processing as in Boyce and Levy, in data_processing_mazeRTs.Rmd
maze_pre_error<-read_csv("natural-stories-surprisals/maze_data/maze_pre_error.csv")

(surps.RTs_lag_c.maze_pre_error %>% 
  plot_compare_models_smooth("mazeRT", #surp_threshold = 30,
                             method = "gam", formula = y ~ s(x, bs = "tp")) + ggtitle("thin plate")
)+(
surps.RTs_lag_c.maze_pre_error %>% 
  plot_compare_models_smooth("mazeRT",# surp_threshold = 30,
                             method = "gam", formula = y ~ s(x, bs = "cr")) + ggtitle("cubic regression")
) + plot_layout(guides = 'collect') + plot_annotation("Maze RT vs surprisal GAMs quick model comparison")

GAMS for mazeRT

# TODO: Morgan suggested adding randomeffects like this
job::job({  
  gam_gpt3_maze_withrandomeffects <- gam(
    rt ~
      s(surprisal, subject, bs="fs") + s(subject, bs='re') + s(word, bs='re') +
      s(surprisal, bs="cr", k=20) +
      te(freq, len, bs="cr") +
      s(prev_surp, bs="cr", k=20) +
      te(prev_freq, prev_len, bs="cr"),
    data=gpt3_maze,
    method="REML")
},
title = "gam_gpt3_maze_withrandomeffects")
plot.gam_surpRTmaze
plot.gam_surpRTmaze_boyce
draw_gam_both<-function(gam_model){
  print(gam.check(gam_model))
  draw(gam_model, seWithMean=T, shift=coef(gam_model)["(Intercept)"], select=c(1,3))
  }
LS0tCnRpdGxlOiAic3VycHJpc2FsIGFuZCByZWFkaW5nIHRpbWUgb24gTmF0dXJhbCBTdG9yaWVzIgphdXRob3I6ICJKYWNvYiBMb3VpcyBIb292ZXIiCmRhdGU6ICJGYWxsIDIwMjEiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogIHR1ZnRlOjp0dWZ0ZV9odG1sOiBkZWZhdWx0CmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCmBgYHtyICJzZXR1cCIsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gIn4vTWNHaWxsL3Byb2plY3RzL0VWQUwyLXByb2Nlc3Npbmctc3VycHJpc2FsLyIpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShkb2NzdHJpbmcpCiMgbGlicmFyeShyZWFkcikKbGlicmFyeShicm1zKQpsaWJyYXJ5KGxtZTQpCmxpYnJhcnkocnN0YW4pCiMgbGlicmFyeSh0aWR5YmF5ZXMpCiMgbGlicmFyeShrbml0cikKbGlicmFyeShtZ2N2KQpsaWJyYXJ5KGdyYXRpYSkKIyBsaWJyYXJ5KG1nY1ZpeikKIyBsaWJyYXJ5KHRpZHltdikKIyBsaWJyYXJ5KHJzYW1wbGUpIAojIGxpYnJhcnkoY293cGxvdCkKIyBsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShjdXJsKQp0aGVtZV9zZXQodGhlbWVfYncoKSkKcnN0YW5fb3B0aW9ucyhhdXRvX3dyaXRlID0gVFJVRSkKb3B0aW9ucyhtYy5jb3JlcyA9IHBhcmFsbGVsOjpkZXRlY3RDb3JlcygpKQpgYGAKCgpgYGB7ciwgaW5jbHVkZT1GfQojIExvYWQgZGF0YSBmcm9tIGRhdGFfcHJvY2Vzc2luZ19zdXJwcy5SVHMuUm1kCgpzdXJwcy5SVHMucGVyd29yZDwtcmVhZF9jc3YoIm5hdHVyYWwtc3Rvcmllcy1zdXJwcmlzYWxzL3N1cnByaXNhbHNfYW5kX1JUc19kYXRhL3N1cnBzLlJUcy5wZXJ3b3JkLmNzdiIpCnN1cnBzLlJUczwtcmVhZF9jc3YoICAgICAgICAibmF0dXJhbC1zdG9yaWVzLXN1cnByaXNhbHMvc3VycHJpc2Fsc19hbmRfUlRzX2RhdGEvc3VycHMuUlRzLmNzdiIgICAgICAgICkKCiMgTm90ZSwgYWxsIG1vZGVscyBpbiBvbmUgZGF0YXNldC4geW91IGNhbiBnZXQganVzdCBzdXJwcyBmcm9tIG9uZSBtb2RlbCB3aXRoICBzb21ldGhpbmdsaWtlCiMgc3VycHMuUlRzICU+JSBzZWxlY3QoIChjb250YWlucygiR1BUMiIpJiFjb250YWlucygiLWxhcmdlIikpLCFzdGFydHNfd2l0aCgic3VycCIpKQpgYGAKCgojIEV4cGxvcmluZyByZWxhdGlvbnNoaXAgYmV0d2VlbiBzdXJwcmlzYWwgYW5kIFNQUlQKCiMjIGluaXRpYWwgRURBCgpgYGB7cn0Kc3VycHMuUlRzICU+JSAKICBwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoInN1cnBfIiksIG5hbWVzX3RvID0gIm1vZGVsIiwgdmFsdWVzX3RvID0gInN1cnByaXNhbCIsIG5hbWVzX3ByZWZpeCA9ICJzdXJwXyIpICU+JQogIGRyb3BfbmEoKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXN1cnByaXNhbCx5PVJUKSkgKwogICMgZ2VvbV9kZW5zaXR5KGFlcyh4PXN1cnByaXNhbCx5PTEyMDArNzUwKi4uZGVuc2l0eS4uKSkgKyAKICBnZW9tX2hleCgpICsgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9IiNEREREREQiLGhpZ2g9ImJsYWNrIikgKwogICMgZ2VvbV9wb2ludChhbHBoYT0uMSxjb2xvcj0iZ3JheSIpICsgCiAgZ2VvbV9zbW9vdGgoKSArCiAgeGxhYigic3VycHJpc2FsIikgKwogIGZhY2V0X3dyYXAofm1vZGVsKSsKICBnZ3RpdGxlKCJzdXJwcmlzYWwgdnMgc2VsZi1wYWNlZCBSVCBvbiBuYXR1cmFsc3RvcmllcyBkYXRhIikKYGBgCgoKCgpgYGB7cn0KIyB3aXRoIGFyaXRobWV0aWMgc3RhdGlzdGljcwpzdXJwcy5SVHMucGVyd29yZCAlPiUgCiAgcGl2b3RfbG9uZ2VyKHN0YXJ0c193aXRoKCJzdXJwXyIpLCBuYW1lc190byA9ICJtb2RlbCIsIHZhbHVlc190byA9ICJzdXJwcmlzYWwiLCBuYW1lc19wcmVmaXggPSAic3VycF8iKSAlPiUKICBkcm9wX25hKCkgJT4lIAogIGdncGxvdChhZXMoeD1zdXJwcmlzYWwseT1tZWFuSXRlbVJUKSkgKwogICMgZ2VvbV9kZW5zaXR5KGRhdGE9c3VycHMuUlRzICU+JSAKICAgICAgIyBwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoInN1cnBfIiksIG5hbWVzX3RvID0gIm1vZGVsIiwgdmFsdWVzX3RvID0gInN1cnByaXNhbCIsIG5hbWVzX3ByZWZpeCA9ICJzdXJwXyIpICU+JQogICAgICAjIGRyb3BfbmEoKSwgCiAgICAjIGFlcyh4PXN1cnByaXNhbCx5PS0xMjUwKi4uZGVuc2l0eS4uKSkgKyAKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW5JdGVtUlQtc2RJdGVtUlQsIHltYXg9bWVhbkl0ZW1SVCtzZEl0ZW1SVCksYWxwaGE9LjEsIGNvbG9yPSJibGFjayIpICsKICBnZW9tX3BvaW50KGFscGhhPS4xLGNvbG9yPSJibHVlIikgKwogIHhsYWIoInN1cnByaXNhbCIpICsKICBmYWNldF93cmFwKH5tb2RlbCkrCiAgZ2d0aXRsZSgic3VycHJpc2FsIHZzIG1lYW4gUlQgKGJsdWUpICstMXNkIChibGFjaykgcGVyIGl0ZW0iKQoKIyB3aXRoIGdlb21ldHJpYyBzdGF0aXN0aWNzCiMgc3VycHMuUlRzLnBlcndvcmQgJT4lIAojICAgcGl2b3RfbG9uZ2VyKHN0YXJ0c193aXRoKCJzdXJwXyIpLCBuYW1lc190byA9ICJtb2RlbCIsIHZhbHVlc190byA9ICJzdXJwcmlzYWwiLCBuYW1lc19wcmVmaXggPSAic3VycF8iKSAlPiUKIyAgIGRyb3BfbmEoKSAlPiUgCiMgICBnZ3Bsb3QoYWVzKHg9c3VycHJpc2FsLHk9Z21lYW5JdGVtUlQpKSArCiMgICBnZW9tX2RlbnNpdHkoYWVzKHg9c3VycHJpc2FsLHk9MTIwMCs3NTAqLi5kZW5zaXR5Li4pKSArIAojICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1nbWVhbkl0ZW1SVC9nc2RJdGVtUlQsIHltYXg9Z21lYW5JdGVtUlQqZ3NkSXRlbVJUKSxhbHBoYT0uMSwgY29sb3I9ImJsYWNrIikgKwojICAgZ2VvbV9wb2ludChhbHBoYT0uMSxjb2xvcj0iYmx1ZSIpICsKIyAgIHhsYWIoInN1cnByaXNhbCIpICsKIyAgIGZhY2V0X3dyYXAofm1vZGVsKSsKIyAgIGdndGl0bGUoInN1cnByaXNhbCB2cyBnZW9tZXRyaWMgbWVhbiBSVCAoYmx1ZSkgKiBnc2ReeystMX0gKGJsYWNrKSBwZXIgaXRlbSIpCmBgYAoKQWxtb3N0IGFsbCB0aGUgZGF0YSBpcyBhdCBsb3cgc3VycHJpc2FsLiBUaGUgdmFyaWFuY2UgaW5jcmVhc2VzIGEgYml0IHdpdGggaGlnaGVyIHN1cnByaXNhbC4KCmBgYHtyfQpzdXJwcy5SVHMgJT4lIAogIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgic3VycF8iKSAmICFlbmRzX3dpdGgoIl9jIiksIG5hbWVzX3RvID0gIm1vZGVsIiwgdmFsdWVzX3RvID0gInN1cnByaXNhbCIsIG5hbWVzX3ByZWZpeCA9ICJzdXJwXyIpICU+JQogIGRyb3BfbmEoKSAlPiUgCiAgZ3JvdXBfYnkoc3VycHJpc2FsYmluPWN1dF93aWR0aChzdXJwcmlzYWwsIGJvdW5kYXJ5ID0gMCwgd2lkdGggPSAxKSwgbW9kZWwpICU+JSAKICBzdW1tYXJpc2Uobj1uKCksIG5fd29yZHM9bGVuZ3RoKHVuaXF1ZSh3b3JkKSksIGJpbm5lZF9zdXJwcmlzYWxfbWluPW1pbihzdXJwcmlzYWwpLCB2YXI9dmFyKFJUKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIAogIGZpbHRlcihuX3dvcmRzPjEpICU+JSAjIHJlbW92ZSBwb2ludHMgd2hpY2ggY29tZSBmcm9tIGp1c3Qgb25lIHdvcmQgaW4gdGhlIGNvcnB1cwogIGdncGxvdChhZXMoeD1iaW5uZWRfc3VycHJpc2FsX21pbix5PXZhcixjb2xvcj1sb2cobikpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIGZvcm11bGE9eX54LCBjb2xvcj0icmVkIiwgbGluZXR5cGU9InNvbGlkIiwgc2l6ZT0uMjUsIGFscGhhPS4yNSkgKwogIGZhY2V0X3dyYXAofm1vZGVsLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeD0iYmlubmVkIHN1cnByaXNhbCIsIHk9InZhcmlhbmNlIGluIFJUIikgKwogIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93PSIjREREREREIiwgaGlnaD0iYmxhY2siKSArCiAgZ2d0aXRsZSgidmFyaWFuY2UgaW4gUlQgdnMgYmlubmVkIHN1cnByaXNhbCIpCgpgYGAKCgpgYGB7cn0Kc3VycHMuUlRzICU+JQpwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoInN1cnBfIikgJiFjb250YWlucygiYm95Y2UiKSwgCiAgICAgICAgICAgICBuYW1lc190byA9ICJtb2RlbCIsIHZhbHVlc190byA9ICJzdXJwcmlzYWwiLCBuYW1lc19wcmVmaXggPSAic3VycF8iKSAlPiUKZHJvcF9uYSgpICU+JSAKZ2dwbG90KGFlcyh4PXN1cnByaXNhbCx5PVJUKSkgKwpzdGF0X2JveHBsb3QoYWVzKHg9Y3V0X3dpZHRoKHN1cnByaXNhbCxib3VuZGFyeT0wLCB3aWR0aD0xKSksbm90Y2g9VCx2YXJ3aWR0aD1GLHBvc2l0aW9uPSJpZGVudGl0eSIsYWxwaGE9Ljc1LAogICAgICAgICAgICAgb3V0bGllci5jb2xvcj0iZ3JheSIsIG91dGxpZXIuYWxwaGEgPSAuNSwgb3V0bGllci5zaXplPSAuNSxvdXRsaWVyLnNoYXBlPTIwLCBjb2xvcj0iYmx1ZSIKICAgICAgICAgICAgICkgKwojIHN0YXRfc3VtbWFyeV9iaW4oZnVuLmRhdGE9Im1lYW5fc2RsIiwgZ2VvbSA9ICJjcm9zc2JhciIsIGJpbndpZHRoID0gLjUsIGFscGhhPTAuMiwgZmlsbD0iYmx1ZSIsIHNpemU9LjEpKwojIHN0YXRfc3VtbWFyeV9iaW4oZnVuPSJtZWRpYW4iLCBiaW53aWR0aCA9IDEsIGFscGhhPTAuMiwgc2l6ZT0uNSwgc2hhcGU9MywgY29sb3I9InJlZCIpKwp4bGFiKCJzdXJwcmlzYWwgKGJpbm5lZCkiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCB2anVzdD0uNSwgaGp1c3Q9MSkpICsKZmFjZXRfd3JhcCh+bW9kZWwsbnJvdz0xKSArCmdndGl0bGUoInN1cnByaXNhbCB2cyBSVCwgYmlubmVkIGJ5IHN1cnByaXNhbCIpIAoKc3VycHMuUlRzICU+JSAKICBwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoInN1cnBfYm95Y2UiKSwgCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIm1vZGVsIiwgdmFsdWVzX3RvID0gInN1cnByaXNhbCIsIG5hbWVzX3ByZWZpeCA9ICJzdXJwXyIpICU+JQogIGRyb3BfbmEoKSAlPiUgCiAgZ2dwbG90KGFlcyh4PXN1cnByaXNhbCx5PVJUKSkgKwogIHN0YXRfYm94cGxvdChhZXMoeD1jdXRfd2lkdGgoc3VycHJpc2FsLGJvdW5kYXJ5PTAsIHdpZHRoPTEpKSxub3RjaD1ULHZhcndpZHRoPUYscG9zaXRpb249ImlkZW50aXR5IixhbHBoYT0uNzUsCiAgICAgICAgICAgICAgIG91dGxpZXIuY29sb3I9ImdyYXkiLCBvdXRsaWVyLmFscGhhID0gLjUsIG91dGxpZXIuc2l6ZT0gLjUsb3V0bGllci5zaGFwZT0yMCwgY29sb3I9ImJsdWUiCiAgICAgICAgICAgICAgICkgKwogICMgc3RhdF9zdW1tYXJ5X2JpbihmdW4uZGF0YT0ibWVhbl9zZGwiLCBnZW9tID0gImNyb3NzYmFyIiwgYmlud2lkdGggPSAuNSwgYWxwaGE9MC4yLCBmaWxsPSJibHVlIiwgc2l6ZT0uMSkrCiAgIyBzdGF0X3N1bW1hcnlfYmluKGZ1bj0ibWVkaWFuIiwgYmlud2lkdGggPSAxLCBhbHBoYT0wLjIsIHNpemU9LjUsIHNoYXBlPTMsIGNvbG9yPSJyZWQiKSsKICB4bGFiKCJzdXJwcmlzYWwgKGJpbm5lZCkiKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCB2anVzdD0uNSwgaGp1c3Q9MSkpICsKICBmYWNldF93cmFwKH5tb2RlbCkgKwogIGdndGl0bGUoInN1cnByaXNhbCB2cyBSVCwgYmlubmVkIGJ5IHN1cnByaXNhbCIpCmBgYAoKCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CgojIEZpdHRpbmcgcHJlbGltaW5hcnkgR0FNcyB0byB0aGUgZGF0YSBkb2Vzbid0IG1ha2UgbXVjaCBkaWZmZXJlbmNlIGlmIHRoZXkncmUgZml0IHRvIGFsbCAKIyBSVCBkYXRhcG9pbnRzIG9yIHRvIHRoZSBtZWFucyBwZXIgc3VycHJpc2FsIHZhbHVlCiMgc3VycHMuUlRzLnBlcndvcmQgJT4lCiMgICBwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoInN1cnBfIiksIG5hbWVzX3RvID0gIm1vZGVsIiwgdmFsdWVzX3RvID0gInN1cnByaXNhbCIsIG5hbWVzX3ByZWZpeCA9ICJzdXJwXyIpICU+JQojICAgZHJvcF9uYSgpICU+JQojICAgICBnZ3Bsb3QoKSArCiMgICAgIGdlb21fbGluZShhZXMoeD1zdXJwcmlzYWwsIHk9bWVhbkl0ZW1SVCksCiMgICAgICAgICAgICAgICBzdGF0PSJzbW9vdGgiLCBtZXRob2QgPSAiZ2FtIiwgZm9ybXVsYSA9IHkgfiBzKHgsIGJzID0gImNzIiksIGNvbG9yPSJyZWQiLGFscGhhPTAuMykgKwojICAgICBnZW9tX2xpbmUoZGF0YT1ncHRzLlJUcyAlPiUgCiMgICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgic3VycF8iKSwgbmFtZXNfdG8gPSAibW9kZWwiLCB2YWx1ZXNfdG8gPSAic3VycHJpc2FsIiwgbmFtZXNfcHJlZml4ID0gInN1cnBfIikgJT4lCiMgICAgICAgICAgICAgICAgIGRyb3BfbmEoKSwKIyAgICAgICAgICAgICAgIGFlcyh4PXN1cnByaXNhbCx5PVJUKSwKIyAgICAgICAgICAgICAgIHN0YXQ9InNtb290aCIsIG1ldGhvZCA9ICJnYW0iLCBmb3JtdWxhID0geSB+IHMoeCwgYnMgPSAiY3MiKSwgY29sb3I9ImJsdWUiLCBhbHBoYT0wLjMpICsKIyAgICAgeGxhYigic3VycHJpc2FsIikgKwojICAgICBmYWNldF93cmFwKH5mYWN0b3IobW9kZWwsbGV2ZWxzID0gYygiR1BUMiIsIkdQVDItbGFyZ2UiLCJHUFQtTmVvIiwiR1BULUoiLCJHUFQzIikpKQoKIyBzdXJwcy5SVHMucGVyd29yZCAlPiUKIyAgIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgic3VycF8iKSwgbmFtZXNfdG8gPSAibW9kZWwiLCB2YWx1ZXNfdG8gPSAic3VycHJpc2FsIiwgbmFtZXNfcHJlZml4ID0gInN1cnBfIikgJT4lCiMgICBkcm9wX25hKCkgJT4lCiMgICAgIGdncGxvdCgpICsKIyAgICAgZ2VvbV9zbW9vdGgoYWVzKHg9c3VycHJpc2FsLCB5PW1lYW5JdGVtUlQpICxtZXRob2QgPSAiZ2FtIiwgY29sb3I9InJlZCIpICsKIyAgICAgeGxhYigic3VycHJpc2FsIikgKwojICAgICBmYWNldF93cmFwKH5mYWN0b3IobW9kZWwsbGV2ZWxzID0gYygiR1BUMiIsIkdQVDItbGFyZ2UiLCJHUFQtTmVvIiwiR1BULUoiLCJHUFQzIikpKQojIAojIHN1cnBzLlJUcyAlPiUgCiMgICBwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoInN1cnBfIiksIG5hbWVzX3RvID0gIm1vZGVsIiwgdmFsdWVzX3RvID0gInN1cnByaXNhbCIsIG5hbWVzX3ByZWZpeCA9ICJzdXJwXyIpICU+JQojICAgICBmaWx0ZXIoIWlzLm5hKG1lYW5JdGVtUlQpLCFpcy5uYShzdXJwcmlzYWwpKSAlPiUKIyAgICAgZ2dwbG90KCkgKwojICAgICBnZW9tX3Ntb290aChhZXMoeD1zdXJwcmlzYWwseT1SVCksIG1ldGhvZCA9ICJnYW0iLCBmb3JtdWxhID0geSB+IHMoeCwgYnMgPSAiY3MiKSkgKwojICAgICB4bGFiKCJzdXJwcmlzYWwiKSArCiMgICAgIGZhY2V0X3dyYXAofmZhY3Rvcihtb2RlbCxsZXZlbHMgPSBjKCJHUFQyIiwiR1BUMi1sYXJnZSIsIkdQVC1OZW8iLCJHUFQtSiIsIkdQVDMiKSkpCmBgYAoKIyMgcWl1Y2sgR0FNIENvbXBhcmlzb24KCmBgYHtyfQpwbG90X2NvbXBhcmVfbW9kZWxzX3Ntb290aDwtZnVuY3Rpb24oZGF0YSwgd2hhdF90b19wcmVkaWN0LCBzdXJwX3RocmVzaG9sZCA9IDEwMCwgLi4uKXsKICBkYXRhICU+JQogIHBpdm90X2xvbmdlcihzdGFydHNfd2l0aCgic3VycF8iKSAmICFlbmRzX3dpdGgoIl9jIiksIAogICAgICAgICAgICAgICBuYW1lc190byA9ICJtb2RlbCIsIHZhbHVlc190byA9ICJzdXJwcmlzYWwiLCAKICAgICAgICAgICAgICAgbmFtZXNfcHJlZml4ID0gInN1cnBfIikgJT4lIAogICAgZmlsdGVyKCFpcy5uYShnZXQod2hhdF90b19wcmVkaWN0KSksIWlzLm5hKHN1cnByaXNhbCkpICU+JSBmaWx0ZXIoc3VycHJpc2FsPD1zdXJwX3RocmVzaG9sZCkgJT4lIAogIG11dGF0ZShtb2RlbD1mYWN0b3IobW9kZWwpKSAlPiUgCiAgbXV0YXRlKG1vZGVsPWZjdF9yZWxldmVsKG1vZGVsLCJHUFQyIiwiR1BUMi1sYXJnZSIsIkdQVC1OZW8iLCJHUFQtSiIsIkdQVDMiLCBhZnRlciA9IDMpKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKGNvbG9yPW1vZGVsKSkgKwogICAgZ2VvbV9zbW9vdGgoYWVzKHg9c3VycHJpc2FsLHk9Z2V0KHdoYXRfdG9fcHJlZGljdCkpLCAuLi4pICsKICAgIGxhYnMoeCA9ICJzdXJwcmlzYWwiLCB5PXdoYXRfdG9fcHJlZGljdCkgCn0KYGBgCgpXaGF0IHRvIGNvbnNpZGVyIGluIGNob29zaW5nIG91ciBiYXNpcz8KCi0gY3ViaWMgcmVncmVzc2lvbiBzcGxpbmUgYGJzID0gJ2NyJ2AgcGxhY2VzIGtub3RzIGJ5IHF1YW50aWxlIChwcm9iYWJseSAqKm5vdCoqIHdoYXQgd2Ugd2FudCwgc2luY2UgaXQgd2lsbCBtYWtlIHRoaW5ncyB3aWdnbHkgaW4gdGhlIGxvdy1zdXJwcmlzYWwgYXJlYSB3aGVyZSBhbGwgdGhlIGRhdGEgYXJlLCBhcnRpZmljaWFsbHkgaW5mbGF0aW5nIGVkZiwgSSB0aGluaykKLSBCLXNwbGluZXMgZmFtaWx5IChgYnMgPSAnYnMnYCwgYGJzID0gJ3BzJ2AsIGBicyA9ICdhZCdgKSBwbGFjZXMga25vdHMgZXZlbmx5Ci0gdGhpbiBwbGF0ZSBgYnMgPSAndHAnYCBwbGFjZXMga25vdHMgcmFuZG9tbHkgYG1heC5rbm90c2AgKHNlZSBgc21vb3RoLmNvbnN0cnVjdC50cC5zbW9vdGguc3BlY2ApCgpgYGB7cn0KI3F1aWNrIGFuZCBkaXJ0eSBjb21wYXJpc29uCigKc3VycHMuUlRzLnBlcndvcmQgJT4lIAogIHBsb3RfY29tcGFyZV9tb2RlbHNfc21vb3RoKCJtZWFuSXRlbVJUIiwgI3N1cnBfdGhyZXNob2xkID0gMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImdhbSIsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJ0cCIpKSArIGdndGl0bGUoInRwIikKKSsoCnN1cnBzLlJUcy5wZXJ3b3JkICU+JSAKICBwbG90X2NvbXBhcmVfbW9kZWxzX3Ntb290aCgibWVhbkl0ZW1SVCIsICNzdXJwX3RocmVzaG9sZCA9IDMwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJnYW0iLCBmb3JtdWxhID0geSB+IHMoeCwgYnMgPSAiY3IiKSkgKyBnZ3RpdGxlKCJjciIpCikrIHBsb3RfbGF5b3V0KGd1aWRlcyA9ICdjb2xsZWN0JykgKyBwbG90X2Fubm90YXRpb24oIlNQUlQgdnMgc3VycHJpc2FsIEdBTXMgcXVpY2sgbW9kZWwgY29tcGFyaXNvbiIpCmBgYAojIEZpdHRpbmcgZ2FtcwoKYGBge3J9CiMgcmVtb3ZlIGFsbCBOQXMgYW5kIHRoZW4gCiMgLSBhZGQgY2VudHJlZCB2ZXJzaW9ucyBvZiBwcmVkaWN0b3JzLCB3aXRoIHN1ZmZpeCAiX2MiCiMgLSBhZGQgaW4gcHJlZGljdG9ycyBmb3IgcGFzdCB3b3JkLCB3aXRoIHByZWZpeCAicHJldl8iCiMgdXNpbmcgZHBseXIncyBtdXRhdGUoYWNyb3NzKCkpLCB3aGljaCBpcyBhcyBuZXcgdmVyc2lvbiBvZiBtdXRhdGVfYXQoKQpzdXJwcy5SVHNfbGFnX2MucGVyd29yZCA8LSBzdXJwcy5SVHMucGVyd29yZCAlPiUgCiAgZHJvcF9uYShjb250YWlucygic3VycF8iKSxtZWFuSXRlbVJULGZyZXEsbGVuZ3RoKSAlPiUgCiAgbXV0YXRlKGFjcm9zcygKICAgIGMoY29udGFpbnMoInN1cnBfIiksZnJlcSxsZW5ndGgpLAogICAgLmZucz1saXN0KCJjIj1mdW5jdGlvbih4KXt4IC0gbWVhbih4LCBuYS5ybT1UKX0pLAogICAgLm5hbWVzPSJ7LmNvbH1fey5mbn0iKSkgJT4lIAogIG11dGF0ZShhY3Jvc3MoCiAgICBjKGNvbnRhaW5zKCJzdXJwXyIpLGZyZXEsZnJlcV9jLGxlbmd0aCxsZW5ndGhfYyksCiAgICAuZm5zPWxpc3QoInByZXYiPWxhZyksIAogICAgLm5hbWVzPSJ7LmZufV97LmNvbH0iKSkKCgpzdXJwcy5SVHNfbGFnX2MgPC0gc3VycHMuUlRzICU+JSAKICBpbm5lcl9qb2luKHN1cnBzLlJUc19sYWdfYy5wZXJ3b3JkKSAlPiUgCiAgbXV0YXRlKFdvcmRfSUQ9YXNfZmFjdG9yKHN0cl9jKHN0b3J5X251bSwgd29yZF9udW1faW5fc3RvcnksIHNlcD0iXyIpKSkgJT4lIAogIHJlbG9jYXRlKFdvcmRfSUQsd29yZCkKYGBgCgoKCiMjIEdBTXMgZm9yIFNQUlQKCkZpdCBhIEdBTSBmb3IgdGhlIEdQVCBkYXRhCgpgYGB7ciBnYW1fR1BUcywgcmVzdWx0cyA9ICJoaWRlIn0KIyBCb3ljZSBhbmQgTGV2eSdzIGZvcm11bGEKZm9ybXVsYTEgPC0gcmVzcG9uc2UgfgogIHMoc3VycHJpc2FsLCBicz0iY3IiLCBrPTIwKSArIHRlKGZyZXEsIGxlbmd0aCwgYnM9ImNyIikgKwogIHMocHJldl9zdXJwcmlzYWwsIGJzPSJjciIsIGs9MjApICsgdGUocHJldl9mcmVxLCBwcmV2X2xlbmd0aCwgYnM9ImNyIikKCiMgV2l0aCBkZWZhdWx0cyAoYnM9J3RwJywgaz0xMCkgLi4uIHNob3VsZCBub3QgY2hhbmdlIHRoaW5ncyBtdWNoLCBidXQgaXQgZG9lcyBoYXZlIGV2ZW5seSBzcGFjZWQga25vdHMgd2hpY2ggbWF5IGJlIGJldHRlci4KZm9ybXVsYTEuZGVmYXVsdCA8LSByZXNwb25zZSB+CiAgcyhzdXJwcmlzYWwpICsgdGUoZnJlcSwgbGVuZ3RoKSArCiAgcyhwcmV2X3N1cnByaXNhbCkgKyB0ZShwcmV2X2ZyZXEsIHByZXZfbGVuZ3RoKQoKcHJlcGFyZV9kYXRhX0dBTV9TUCA8LSBmdW5jdGlvbihzdXJwcy5TUFJUc19kZiwgbW9kZWxuYW1lLCBzdXJwX2NvbG5hbWUsIHByZXZfc3VycF9jb2xuYW1lKSB7CiAgc3VycHMuU1BSVHNfZGYgJT4lCiAgICBzZWxlY3QoUlQsIFdvcmtlcklkLCBXb3JkX0lELAogICAgICAgICAgIHN1cnByaXNhbD1hbGxfb2Yoc3VycF9jb2xuYW1lKSwgcHJldl9zdXJwcmlzYWw9YWxsX29mKHByZXZfc3VycF9jb2xuYW1lKSwKICAgICAgICAgICBmcmVxPWZyZXFfYywgbGVuZ3RoPWxlbmd0aF9jLCBwcmV2X2ZyZXE9cHJldl9mcmVxX2MsIHByZXZfbGVuZ3RoPXByZXZfbGVuZ3RoX2MpICU+JQogICAgbXV0YXRlKG1vZGVsPW1vZGVsbmFtZSwgCiAgICAgICAgICAgc3ViamVjdD1mYWN0b3IoV29ya2VySWQpLCAKICAgICAgICAgICByZXNwb25zZT1SVCkKfQoKZml0X2JhbV9TUFJUIDwtIGZ1bmN0aW9uKGZvcm11bGEsIGRhdGEsIG1vZGVsbmFtZSl7CiAgIycgZml0IGEgR0FNIG9mIFNQUlQgYXMgYSBmdW5jdGlvbiBvZiBzdXJwcmlzYWwKICAjJyBAcGFyYW0gZm9ybXVsYSBtY2d2IGZvcm11bGEKICAjJyBAcGFyYW0gbW9kZWxuYW1lIG5hbWUgb2YgbW9kZWwgZm9yIHN1cnByaXNhbAogIHN1cnBfY29sbmFtZSA8LSBwYXN0ZTAoInN1cnBfIiwgbW9kZWxuYW1lKQogIHByZXZfc3VycF9jb2xuYW1lIDwtIHBhc3RlMCgicHJldl9zdXJwXyIsIG1vZGVsbmFtZSkKICBkYXRhX3ByZXBhcmVkIDwtIGRhdGEgJT4lCiAgICBzZWxlY3QocmVzcG9uc2U9UlQsIFdvcmtlcklkLCBXb3JkX0lELAogICAgICAgICAgIHN1cnByaXNhbD1hbGxfb2Yoc3VycF9jb2xuYW1lKSwgcHJldl9zdXJwcmlzYWw9YWxsX29mKHByZXZfc3VycF9jb2xuYW1lKSwKICAgICAgICAgICBmcmVxPWZyZXFfYywgbGVuZ3RoPWxlbmd0aF9jLCBwcmV2X2ZyZXE9cHJldl9mcmVxX2MsIHByZXZfbGVuZ3RoPXByZXZfbGVuZ3RoX2MpICU+JQogICAgbXV0YXRlKG1vZGVsPW1vZGVsbmFtZSwgCiAgICAgICAgICAgc3ViamVjdD1mYWN0b3IoV29ya2VySWQpKQogIGJhbShmb3JtdWxhLCBtZXRob2Q9IlJFTUwiLCBkYXRhPWRhdGFfcHJlcGFyZWQpCn0KCgpqb2I6OmpvYih7CiAgZ2FtX2dwdDNfUlQgICA8LSBmaXRfYmFtX1NQUlQoZm9ybXVsYTEsIHN1cnBzLlJUc19sYWdfYywgIkdQVDMiKQogIGdhbV9ncHQyX1JUICAgPC0gZml0X2JhbV9TUFJUKGZvcm11bGExLCBzdXJwcy5SVHNfbGFnX2MsICJHUFQyIikKICBnYW1fZ3B0MmxfUlQgIDwtIGZpdF9iYW1fU1BSVChmb3JtdWxhMSwgc3VycHMuUlRzX2xhZ19jLCAiR1BUMi1sYXJnZSIpCiAgZ2FtX2dwdGpfUlQgICA8LSBmaXRfYmFtX1NQUlQoZm9ybXVsYTEsIHN1cnBzLlJUc19sYWdfYywgIkdQVC1KIikKICBnYW1fZ3B0bmVvX1JUIDwtIGZpdF9iYW1fU1BSVChmb3JtdWxhMSwgc3VycHMuUlRzX2xhZ19jLCAiR1BULU5lbyIpCiAgCiAgd3JpdGVfcmRzKGdhbV9ncHQzX1JUICAsIGZpbGU9InNjcmF0Y2gvZ2FtX2dwdDNfUlQucmRzIikKICB3cml0ZV9yZHMoZ2FtX2dwdDJfUlQgICwgZmlsZT0ic2NyYXRjaC9nYW1fZ3B0Ml9SVC5yZHMiKQogIHdyaXRlX3JkcyhnYW1fZ3B0MmxfUlQgLCBmaWxlPSJzY3JhdGNoL2dhbV9ncHQybF9SVC5yZHMiKQogIHdyaXRlX3JkcyhnYW1fZ3B0al9SVCAgLCBmaWxlPSJzY3JhdGNoL2dhbV9ncHRqX1JULnJkcyIpCiAgd3JpdGVfcmRzKGdhbV9ncHRuZW9fUlQsIGZpbGU9InNjcmF0Y2gvZ2FtX2dwdG5lb19SVC5yZHMiKQp9LCAKdGl0bGU9ImZpdHRpbmcgR0FNcyBSVCB2IEdQVCBzdXJwcmlzYWxzIikKCgpnYW1fZ3B0M19SVCAgIDwtcmVhZF9yZHMoInNjcmF0Y2gvZ2FtX2dwdDNfUlQucmRzIikKZ2FtX2dwdDJfUlQgICA8LXJlYWRfcmRzKCJzY3JhdGNoL2dhbV9ncHQyX1JULnJkcyIpCmdhbV9ncHQybF9SVCAgPC1yZWFkX3Jkcygic2NyYXRjaC9nYW1fZ3B0MmxfUlQucmRzIikKZ2FtX2dwdGpfUlQgICA8LXJlYWRfcmRzKCJzY3JhdGNoL2dhbV9ncHRqX1JULnJkcyIpCmdhbV9ncHRuZW9fUlQgPC1yZWFkX3Jkcygic2NyYXRjaC9nYW1fZ3B0bmVvX1JULnJkcyIpCmBgYAoKYGBge3IsIHJlc3VsdHMgPSAiaGlkZSJ9CmdldF9nYW1fcHJlZGljdGlvbnMucHJldl9hbmRfY3VyciA8LSBmdW5jdGlvbihnYW1fbW9kZWwsIHN1cnBfbW9kZWxfbmFtZSwgc2VyaWVzX2xlbmd0aD0xMDApIHsKICBjdXJyIDwtIHRpZHltdjo6Z2V0X2dhbV9wcmVkaWN0aW9ucyhtb2RlbD1nYW1fbW9kZWwsIHNlcmllcz1zdXJwcmlzYWwsIHNlcmllc19sZW5ndGg9c2VyaWVzX2xlbmd0aCkgJT4lCiAgICBzZWxlY3Qoc3VycHJpc2FsLCByZXNwb25zZSwgQ0lfdXBwZXIsIENJX2xvd2VyKSAlPiUgCiAgICB1bmlxdWUoKSAlPiUgCiAgICBtdXRhdGUobW9kZWw9c3VycF9tb2RlbF9uYW1lLCBzPSJDdXJyZW50IikKICAKICBwcmV2IDwtIHRpZHltdjo6Z2V0X2dhbV9wcmVkaWN0aW9ucyhtb2RlbD1nYW1fbW9kZWwsIHNlcmllcz1wcmV2X3N1cnByaXNhbCwgc2VyaWVzX2xlbmd0aD1zZXJpZXNfbGVuZ3RoKSAlPiUKICAgc2VsZWN0KHN1cnByaXNhbD1wcmV2X3N1cnByaXNhbCwgcmVzcG9uc2UsIENJX3VwcGVyLCBDSV9sb3dlcikgJT4lCiAgIHVuaXF1ZSgpICU+JQogICBtdXRhdGUobW9kZWw9c3VycF9tb2RlbF9uYW1lLCBzPSJQcmV2aW91cyIpCiAgCiAgYm90aCA8LSBjdXJyICU+JSB1bmlvbihwcmV2KQp9CgphbGxfZ2FtX3N1cnBSVF9wcmVkaWN0aW9ucyA8LSBnZXRfZ2FtX3ByZWRpY3Rpb25zLnByZXZfYW5kX2N1cnIoZ2FtX2dwdDNfUlQsICJHUFQzIikgJT4lIAogIHVuaW9uKGdldF9nYW1fcHJlZGljdGlvbnMucHJldl9hbmRfY3VycihnYW1fZ3B0Ml9SVCwgIkdQVDIiKSkgJT4lCiAgdW5pb24oZ2V0X2dhbV9wcmVkaWN0aW9ucy5wcmV2X2FuZF9jdXJyKGdhbV9ncHQybF9SVCwgIkdQVDItbGFyZ2UiKSkgJT4lCiAgdW5pb24oZ2V0X2dhbV9wcmVkaWN0aW9ucy5wcmV2X2FuZF9jdXJyKGdhbV9ncHRqX1JULCAiR1BULUoiKSkgJT4lIAogIHVuaW9uKGdldF9nYW1fcHJlZGljdGlvbnMucHJldl9hbmRfY3VycihnYW1fZ3B0bmVvX1JULCAiR1BULU5lbyIpKQogIApwbG90LmdhbV9zdXJwUlQgPC0gCiAgZ2dwbG90KGFsbF9nYW1fc3VycFJUX3ByZWRpY3Rpb25zLCAKICAgICAgICAgYWVzKHg9c3VycHJpc2FsLCB5PXJlc3BvbnNlLCB5bWluPUNJX2xvd2VyLCB5bWF4PUNJX3VwcGVyKSkrCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcmliYm9uKGFscGhhPS4zLGZpbGw9ImJsdWUiKSsKICAjIGdlb21fZGVuc2l0eShkYXRhPXN1cnBzLlJUc19sYWdfYy5wZXJ3b3JkLCBhZXMoeD1zdXJwLCB5PTEwMDAqLi5kZW5zaXR5Li4pLCBmaWxsPSJncmF5IiwgaW5oZXJpdC5hZXMgPSBGKSsKICBmYWNldF9ncmlkKHN+bW9kZWwpICsKICAjIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMzMwLDU4MCksIHhsaW09YygwLDE1KSkrCiAgbGFicyh4PSJTdXJwcmlzYWwiLCB5PSJSZWFkaW5nIFRpbWUgKG1zKSIpICsKICBnZ3RpdGxlKCJHQU0gZml0cyBmb3IgUlR2c3VycF9mb3JtdWxhMSIpCgpwbG90LmdhbV9zdXJwUlQKCiMgZ3B0ZGVuczIgPC0gZ2dwbG90KHN1cnBzLlJUc19sYWdfYy5wZXJ3b3JkLCBhZXMoeD1zdXJwX0dQVDMpKSsKIyAgIGdlb21fZGVuc2l0eShmaWxsPSJncmF5IiwpKwojICAgbGFicyh4PSJTdXJwcmlzYWwiLCB5PSIiKSsKIyAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCAKIyAgICAgICAgIHN0cmlwLnRleHQ9ZWxlbWVudF9ibGFuaygpLCAKIyAgICAgICAgIGF4aXMudGlja3MueSA9ZWxlbWVudF9ibGFuaygpLCAKIyAgICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksIAojICAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMCwgMCwgMCksICJjbSIpKQojIGdwdGJvdCA8LSBwbG90X2dyaWQoTkEsIGdwdGRlbnMyLCBOQSwgbnJvdz0xLCByZWxfd2lkdGhzID0gYyguMDc1LCAxLCAuMDM1KSkKIyBwPC1wbG90X2dyaWQocGxvdC5nYW1fc3VycFJULCBncHRib3QsIG5yb3c9MiwgcmVsX2hlaWdodHMgPSBjKDEsIC4zKSkKCgpgYGAKCiMgc3VycHJpc2FsIHZzIG1hemVSVAoKIyMgQWxpZ25pbmcgd2l0aCBBTUFaRSBUQVNLIGZyb20gQm95Y2UKCmBgYHtyLCByZXN1bHRzID0gImhpZGUifQojIGdldCBzdXJwcmlzYWwgKGFuZCBSVCkgZGF0YXNldAojIHN1cnBzLlJUc19sYWdfYy5wZXJ3b3JkIAojIGZyb20gYWJvdmUKCiMgam9pbmRhdGFfbWF6ZV93aXRoX3N1cnBzIDwtIGZ1bmN0aW9uKG1hemVfdGFza19kYXRhLCBzdXJwc19kYXRhKSB7CiMgICBtYXplX3Rhc2tfZGF0YSAlPiUgcmVuYW1lKG1hemVSVD1ydCkgJT4lIAojICAgICBpbm5lcl9qb2luKHN1cnBzX2RhdGEsIGJ5PWMoIndvcmRfbnVtX2luX3NlbnRlbmNlIiwgIndvcmQiLCAic2VudGVuY2UiKSkgJT4lCiMgICAgIGZpbHRlcih3b3JkX251bV9pbl9zZW50ZW5jZT4xKSAlPiUgCiMgICAgIHNlbGVjdChtYXplUlQsIHN1YmplY3QsIHdvcmRfbnVtX2luX3N0b3J5LCBzdG9yeV9udW0sIHdvcmQsCiMgICAgICAgICAgICBmcmVxLGxlbmd0aCwgbWVhbkl0ZW1SVCwgc2RJdGVtUlQsCiMgICAgICAgICAgICBjb250YWlucygic3VycF8iKSB8IHN0YXJ0c193aXRoKCJwcmV2IikgfCBlbmRzX3dpdGgoIl9jIiksCiMgICAgICAgICAgICApICU+JSAKIyAgICAgbXV0YXRlKFdvcmRfSUQ9YXNfZmFjdG9yKHN0cl9jKHN0b3J5X251bSwgd29yZF9udW1faW5fc3RvcnksIHNlcD0iXyIpKSkgJT4lIHJlbG9jYXRlKFdvcmRfSUQsIHdvcmQpCiMgICAgICMgc2VsZWN0KC13b3JkX251bV9pbl9zdG9yeSwgLXN0b3J5X251bSkgJT4lIHdyaXRlX3Jkcygic2NyYXRjaC9wcm9jZXNzZWRfYW1hemUvcHJlX2Vycm9yLnJkcyIpCiMgfQpqb2luZGF0YV9tYXplX3dpdGhfc3VycHMgPC0gZnVuY3Rpb24obWF6ZV90YXNrX2RhdGEsIHN1cnBzX2RhdGEpIHsKICBtYXplX3Rhc2tfZGF0YSAlPiUgcmVuYW1lKG1hemVSVD1ydCx3b3JkX2h1bWFuPXdvcmQpICU+JSAKICAgIGZ1bGxfam9pbihzdXJwc19kYXRhLCBieT1jKCJ3b3JkX251bV9pbl9zZW50ZW5jZSIsICJ3b3JkX2h1bWFuIiwgInNlbnRlbmNlIikpICU+JQogICAgZmlsdGVyKHdvcmRfbnVtX2luX3NlbnRlbmNlPjEpICU+JSAKICAgIHNlbGVjdChtYXplUlQsIHN1YmplY3QsIHdvcmRfbnVtX2luX3N0b3J5LCBzdG9yeV9udW0sIHdvcmQsCiAgICAgICAgICAgZnJlcSxsZW5ndGgsIG1lYW5JdGVtUlQsIHNkSXRlbVJULAogICAgICAgICAgIGNvbnRhaW5zKCJzdXJwXyIpIHwgc3RhcnRzX3dpdGgoInByZXYiKSB8IGVuZHNfd2l0aCgiX2MiKSwKICAgICAgICAgICApICU+JSAKICAgIG11dGF0ZShXb3JkX0lEPWFzX2ZhY3RvcihzdHJfYyhzdG9yeV9udW0sIHdvcmRfbnVtX2luX3N0b3J5LCBzZXA9Il8iKSkpICU+JSByZWxvY2F0ZShXb3JkX0lELCB3b3JkKQogICAgIyBzZWxlY3QoLXdvcmRfbnVtX2luX3N0b3J5LCAtc3RvcnlfbnVtKSAlPiUgd3JpdGVfcmRzKCJzY3JhdGNoL3Byb2Nlc3NlZF9hbWF6ZS9wcmVfZXJyb3IucmRzIikKfQpgYGAKCgpgYGB7ciByZXN1bHRzPSdoaWRlJ30KIyBEYXRhIHByb2Nlc3NpbmcgYXMgaW4gQm95Y2UgYW5kIExldnksIGluIGRhdGFfcHJvY2Vzc2luZ19tYXplUlRzLlJtZAptYXplX3ByZV9lcnJvcjwtcmVhZF9jc3YoIm5hdHVyYWwtc3Rvcmllcy1zdXJwcmlzYWxzL21hemVfZGF0YS9tYXplX3ByZV9lcnJvci5jc3YiKQoKCiMgcHJlX2Vycm9yCnN1cnBzLm1hemVSVHNfbGFnX2MgPC0gam9pbmRhdGFfbWF6ZV93aXRoX3N1cnBzKG1hemVfcHJlX2Vycm9yLCBzdXJwcy5SVHNfbGFnX2MucGVyd29yZCkgCndyaXRlX2NzdihzdXJwcy5tYXplUlRzX2xhZ19jLCJuYXR1cmFsLXN0b3JpZXMtc3VycHJpc2Fscy9zdXJwcmlzYWxzX2FuZF9SVHNfZGF0YS9zdXJwcy5tYXplUlRzX2xhZ19jLmNzdiIpCgojICMgcG9zdF9lcnJvciAoc2VlIGRhdGFfcHJvY2Vzc2luZ19tYXplUlRzLlJtZCkKIyBzdXJwcy5SVHNfbGFnX2MubWF6ZV9wb3N0X2Vycm9yIDwtIGpvaW5kYXRhX21hemVfd2l0aF9zdXJwcyhtYXplX3JlYWR5LCBzdXJwcy5SVHNfbGFnX2MucGVyd29yZCkKIyAKIyAjIHBvc3Rfb25seSAgKHNlZSBkYXRhX3Byb2Nlc3NpbmdfbWF6ZVJUcy5SbWQpCiMgc3VycHMuUlRzX2xhZ19jLm1hemVfcG9zdF9vbmx5IDwtIGpvaW5kYXRhX21hemVfd2l0aF9zdXJwcyhtYXplX3Bvc3Rfb25seSwgc3VycHMuUlRzX2xhZ19jLnBlcndvcmQpCgpgYGAKCmBgYHtyfQpzdXJwcy5tYXplUlRzX2xhZ19jICU+JSAKICBwaXZvdF9sb25nZXIoc3RhcnRzX3dpdGgoInN1cnBfIikgJiAhZW5kc193aXRoKCJfYyIpLCBuYW1lc190byA9ICJtb2RlbCIsIHZhbHVlc190byA9ICJzdXJwcmlzYWwiLCBuYW1lc19wcmVmaXggPSAic3VycF8iKSAlPiUKICBkcm9wX25hKCkgJT4lIAogIGdyb3VwX2J5KHN1cnByaXNhbGJpbj1jdXRfd2lkdGgoc3VycHJpc2FsLCBib3VuZGFyeSA9IDAsIHdpZHRoID0gMSksIG1vZGVsKSAlPiUgCiAgc3VtbWFyaXNlKG49bigpLCBuX1dvcmRfSURzPWxlbmd0aCh1bmlxdWUoV29yZF9JRCkpLCBiaW5uZWRfc3VycHJpc2FsX21pbj1taW4oc3VycHJpc2FsKSwgdmFyPXZhcihtYXplUlQpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgCiAgZmlsdGVyKG5fV29yZF9JRHM+MSkgJT4lICAjIHJlbW92ZSBwb2ludHMgd2hpY2ggY29tZSBmcm9tIGp1c3Qgb25lIHdvcmQgaW4gdGhlIGNvcnB1cwogIGdncGxvdChhZXMoeD1iaW5uZWRfc3VycHJpc2FsX21pbix5PXZhcixjb2xvcj1sb2cobikpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIGZvcm11bGE9eX54LCBjb2xvcj0icmVkIiwgbGluZXR5cGU9InNvbGlkIiwgc2l6ZT0uMjUsIGFscGhhPS4yNSkgKwogIGZhY2V0X3dyYXAofm1vZGVsLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeD0iYmlubmVkIHN1cnByaXNhbCIsIHk9InZhcmlhbmNlIGluIG1hemVSVCIpICsKICBzY2FsZV9jb2xvcl9jb250aW51b3VzKGxvdz0iI0RERERERCIsIGhpZ2g9ImJsYWNrIikgKwogIGdndGl0bGUoInZhcmlhbmNlIGluIG1hemVSVCB2cyBiaW5uZWQgc3VycHJpc2FsIikKYGBgCgoKCmBgYHtyfQooc3VycHMuUlRzX2xhZ19jLm1hemVfcHJlX2Vycm9yICU+JSAKICBwbG90X2NvbXBhcmVfbW9kZWxzX3Ntb290aCgibWF6ZVJUIiwgI3N1cnBfdGhyZXNob2xkID0gMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImdhbSIsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJ0cCIpKSArIGdndGl0bGUoInRoaW4gcGxhdGUiKQopKygKc3VycHMuUlRzX2xhZ19jLm1hemVfcHJlX2Vycm9yICU+JSAKICBwbG90X2NvbXBhcmVfbW9kZWxzX3Ntb290aCgibWF6ZVJUIiwjIHN1cnBfdGhyZXNob2xkID0gMzAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImdhbSIsIGZvcm11bGEgPSB5IH4gcyh4LCBicyA9ICJjciIpKSArIGdndGl0bGUoImN1YmljIHJlZ3Jlc3Npb24iKQopICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gJ2NvbGxlY3QnKSArIHBsb3RfYW5ub3RhdGlvbigiTWF6ZSBSVCB2cyBzdXJwcmlzYWwgR0FNcyBxdWljayBtb2RlbCBjb21wYXJpc29uIikKYGBgCgoKIyMgR0FNUyBmb3IgbWF6ZVJUCgpgYGB7ciBnYW1fdGliYmxlc19wZXJtb2RlbCxyZXN1bHRzID0gImhpZGUifQoKCnByZXBhcmVfZGF0YV9HQU1fbWF6ZVJUIDwtIGZ1bmN0aW9uKHN1cnBzLm1hemVSVHNfZGYsIG1vZGVsbmFtZSwgc3VycF9jb2xuYW1lLCBwcmV2X3N1cnBfY29sbmFtZSkgewogIHN1cnBzLm1hemVSVHNfZGYgJT4lCiAgICBzZWxlY3QobWF6ZVJULCBzdWJqZWN0LCBXb3JkX0lELAogICAgICAgICAgIHN1cnByaXNhbD1hbGxfb2Yoc3VycF9jb2xuYW1lKSwgcHJldl9zdXJwcmlzYWw9YWxsX29mKHByZXZfc3VycF9jb2xuYW1lKSwKICAgICAgICAgICBmcmVxPWZyZXFfYywgbGVuZ3RoPWxlbmd0aF9jLCBwcmV2X2ZyZXE9cHJldl9mcmVxX2MsIHByZXZfbGVuZ3RoPXByZXZfbGVuZ3RoX2MpICU+JQogICAgbXV0YXRlKG1vZGVsPW1vZGVsbmFtZSwgc3ViamVjdD1mYWN0b3Ioc3ViamVjdCkpCn0KCgpCbmdyYW1fbWF6ZSAgPC0gcHJlcGFyZV9kYXRhX0dBTV9tYXplUlQoc3VycHMuUlRzX2xhZ19jLm1hemVfcHJlX2Vycm9yLCAiYm95Y2Vfc3VycF9uZ3JhbSIsICJwcmV2X2JveWNlX3N1cnBfbmdyYW0iLCAiQl81LWdyYW0iKQpCZ3Jubl9tYXplICAgPC0gcHJlcGFyZV9kYXRhX0dBTV9tYXplUlQoc3VycHMuUlRzX2xhZ19jLm1hemVfcHJlX2Vycm9yLCAiYm95Y2Vfc3VycF9ncm5uIiwgInByZXZfYm95Y2Vfc3VycF9ncm5uIiwgICAiQl9HUk5OIiAgKQpCdHhsX21hemUgICAgPC0gcHJlcGFyZV9kYXRhX0dBTV9tYXplUlQoc3VycHMuUlRzX2xhZ19jLm1hemVfcHJlX2Vycm9yLCAiYm95Y2Vfc3VycF90eGwiLCAicHJldl9ib3ljZV9zdXJwX3R4bCIsICAgICAiQl9UWEwiICAgKQoKZ3B0Ml9tYXplICAgIDwtIHByZXBhcmVfZGF0YV9HQU1fbWF6ZVJUKHN1cnBzLlJUc19sYWdfYy5tYXplX3ByZV9lcnJvciwgInN1cnBfR1BUMiIsICJwcmV2X3N1cnBfR1BUMiIsICJHUFQyIikKZ3B0MmxfbWF6ZSAgIDwtIHByZXBhcmVfZGF0YV9HQU1fbWF6ZVJUKHN1cnBzLlJUc19sYWdfYy5tYXplX3ByZV9lcnJvciwgInN1cnBfR1BUMi1sYXJnZSIsICJwcmV2X3N1cnBfR1BUMi1sYXJnZSIsICJHUFQyLWxhcmdlIikKZ3B0al9tYXplICAgIDwtIHByZXBhcmVfZGF0YV9HQU1fbWF6ZVJUKHN1cnBzLlJUc19sYWdfYy5tYXplX3ByZV9lcnJvciwgInN1cnBfR1BULUoiLCAicHJldl9zdXJwX0dQVC1KIiwgIkdQVC1KIikKZ3B0bmVvX21hemUgIDwtIHByZXBhcmVfZGF0YV9HQU1fbWF6ZVJUKHN1cnBzLlJUc19sYWdfYy5tYXplX3ByZV9lcnJvciwgInN1cnBfR1BULU5lbyIsICJwcmV2X3N1cnBfR1BULU5lbyIsICJHUFQtTmVvIikKZ3B0M19tYXplICAgIDwtIHByZXBhcmVfZGF0YV9HQU1fbWF6ZVJUKHN1cnBzLlJUc19sYWdfYy5tYXplX3ByZV9lcnJvciwgInN1cnBfR1BUMyIsICJwcmV2X3N1cnBfR1BUMyIsICJHUFQzIikKCgphbGxfbWF6ZSA8LSAKICBCbmdyYW1fbWF6ZSAlPiUKICB1bmlvbihCZ3Jubl9tYXplKSAlPiUgCiAgdW5pb24oQnR4bF9tYXplKSAlPiUgCiAgdW5pb24oZ3B0Ml9tYXplKSAlPiUgIAogIHVuaW9uKGdwdDJsX21hemUpICU+JQogIHVuaW9uKGdwdGpfbWF6ZSkgJT4lICAKICB1bmlvbihncHRuZW9fbWF6ZSkgJT4lCiAgdW5pb24oZ3B0M19tYXplKSAlPiUgCiAgc2VsZWN0KHN1cnByaXNhbCxwcmV2X3N1cnByaXNhbCxtb2RlbCkgJT4lIAogIHBpdm90X2xvbmdlcihjb2xzID0gYHN1cnByaXNhbGA6YHByZXZfc3VycHJpc2FsYCwgbmFtZXNfdG8gPSAic3VycHJpc2FsX29yX3ByZXZfc3VycHJpc2FsIikgJT4lIAogIG11dGF0ZShzPWlmZWxzZShzdXJwcmlzYWxfb3JfcHJldl9zdXJwcmlzYWw9PSJzdXJwcmlzYWwiLCAiQ3VycmVudCIsICJQcmV2aW91cyIpKQpgYGAKCmBgYHtyIGdhbXMsIHJlc3VsdHMgPSAiaGlkZSIsIGluY2x1ZGU9Rn0KbWF6ZVJUdnN1cnBfZm9ybXVsYTEgPC0gbWF6ZVJUIH4KICBzKHN1cnByaXNhbCwgYnM9ImNyIiwgaz0yMCkgKyB0ZShmcmVxLCBsZW5ndGgsIGJzPSJjciIpICsKICBzKHByZXZfc3VycHJpc2FsLCBicz0iY3IiLCBrPTIwKSArIHRlKHByZXZfZnJlcSwgcHJldl9sZW5ndGgsIGJzPSJjciIpCgojIGpvYjo6am9iKHsKIyAgIGdhbV9CbmdyYW1fbWF6ZSA8LSBiYW0obWF6ZVJUdnN1cnBfZm9ybXVsYTEsIG1ldGhvZD0iUkVNTCIsIGRhdGE9Qm5ncmFtX21hemUpCiMgICB9LCB0aXRsZSA9ICJnYW1fbmdyYW1fbWF6ZSIpCiMgam9iOjpqb2IoewojICAgZ2FtX0Jncm5uX21hemUgPC0gYmFtKG1hemVSVHZzdXJwX2Zvcm11bGExLCBtZXRob2Q9IlJFTUwiLCBkYXRhPUJncm5uX21hemUpCiMgICB9LCB0aXRsZSA9ICJnYW1fZ3Jubl9tYXplIikKIyBqb2I6OmpvYih7CiMgICBnYW1fQnR4bF9tYXplIDwtIGJhbShtYXplUlR2c3VycF9mb3JtdWxhMSwgbWV0aG9kPSJSRU1MIiwgZGF0YT1CdHhsX21hemUpCiMgICB9LCB0aXRsZSA9ICJnYW1fdHhsX21hemUiKQojIAojIGpvYjo6am9iKHsKIyAgIGdhbV9ncHQyX21hemUgPC0gYmFtKG1hemVSVHZzdXJwX2Zvcm11bGExLCBtZXRob2Q9IlJFTUwiLCBkYXRhPWdwdDJfbWF6ZSkKIyAgIH0sIHRpdGxlID0gImdhbV9HUFQyX21hemUiKQojIGpvYjo6am9iKHsKIyAgIGdhbV9ncHQybF9tYXplIDwtIGJhbShtYXplUlR2c3VycF9mb3JtdWxhMSwgbWV0aG9kPSJSRU1MIiwgZGF0YT1ncHQybF9tYXplKQojICAgfSwgdGl0bGUgPSAiZ2FtX0dQVDItbGFyZ2VfbWF6ZSIpCiMgam9iOjpqb2IoewojICAgZ2FtX2dwdGpfbWF6ZSA8LSBiYW0obWF6ZVJUdnN1cnBfZm9ybXVsYTEsIG1ldGhvZD0iUkVNTCIsIGRhdGE9Z3B0al9tYXplKQojICAgfSwgdGl0bGUgPSAiZ2FtX0dQVDItSl9tYXplIikKIyBqb2I6OmpvYih7CiMgICBnYW1fZ3B0bmVvX21hemUgPC0gYmFtKG1hemVSVHZzdXJwX2Zvcm11bGExLCBtZXRob2Q9IlJFTUwiLCBkYXRhPWdwdG5lb19tYXplKQojICAgfSwgdGl0bGUgPSAiZ2FtX0dQVDItTmVvX21hemUiKQojIGpvYjo6am9iKHsKIyAgIGdhbV9ncHQzX21hemUgPC0gYmFtKG1hemVSVHZzdXJwX2Zvcm11bGExLCBtZXRob2Q9IlJFTUwiLCBkYXRhPWdwdDNfbWF6ZSkKIyAgIH0sIHRpdGxlID0gImdhbV9HUFQzX21hemUiKQoKIyAKIyB3cml0ZV9yZHMoZ2FtX0JuZ3JhbV9tYXplLCBmaWxlPSJzY3JhdGNoL2dhbV9CbmdyYW1fbWF6ZS5yZHMiKQojIHdyaXRlX3JkcyhnYW1fQmdybm5fbWF6ZSwgZmlsZT0ic2NyYXRjaC9nYW1fQmdybm5fbWF6ZS5yZHMiKQojIHdyaXRlX3JkcyhnYW1fQnR4bF9tYXplLCBmaWxlPSJzY3JhdGNoL2dhbV9CdHhsX21hemUucmRzIikKIyB3cml0ZV9yZHMoZ2FtX2dwdDJfbWF6ZSwgZmlsZT0ic2NyYXRjaC9nYW1fZ3B0Ml9tYXplLnJkcyIpCiMgd3JpdGVfcmRzKGdhbV9ncHQybF9tYXplLCBmaWxlPSJzY3JhdGNoL2dhbV9ncHQybF9tYXplLnJkcyIpCiMgd3JpdGVfcmRzKGdhbV9ncHRqX21hemUsIGZpbGU9InNjcmF0Y2gvZ2FtX2dwdGpfbWF6ZS5yZHMiKQojIHdyaXRlX3JkcyhnYW1fZ3B0bmVvX21hemUsIGZpbGU9InNjcmF0Y2gvZ2FtX2dwdG5lb19tYXplLnJkcyIpCiMgd3JpdGVfcmRzKGdhbV9ncHQzX21hemUsIGZpbGU9InNjcmF0Y2gvZ2FtX2dwdDNfbWF6ZS5yZHMiKQojIApnYW1fQm5ncmFtX21hemUgPC0gcmVhZF9yZHMoInNjcmF0Y2gvZ2FtX0JuZ3JhbV9tYXplLnJkcyIpCmdhbV9CZ3Jubl9tYXplICA8LSByZWFkX3Jkcygic2NyYXRjaC9nYW1fQmdybm5fbWF6ZS5yZHMiKQpnYW1fQnR4bF9tYXplICAgPC0gcmVhZF9yZHMoInNjcmF0Y2gvZ2FtX0J0eGxfbWF6ZS5yZHMiKQpnYW1fZ3B0Ml9tYXplICAgPC0gcmVhZF9yZHMoInNjcmF0Y2gvZ2FtX2dwdDJfbWF6ZS5yZHMiKQpnYW1fZ3B0MmxfbWF6ZSAgPC0gcmVhZF9yZHMoInNjcmF0Y2gvZ2FtX2dwdDJsX21hemUucmRzIikKZ2FtX2dwdGpfbWF6ZSAgIDwtIHJlYWRfcmRzKCJzY3JhdGNoL2dhbV9ncHRqX21hemUucmRzIikKZ2FtX2dwdG5lb19tYXplIDwtIHJlYWRfcmRzKCJzY3JhdGNoL2dhbV9ncHRuZW9fbWF6ZS5yZHMiKQpnYW1fZ3B0M19tYXplICAgPC0gcmVhZF9yZHMoInNjcmF0Y2gvZ2FtX2dwdDNfbWF6ZS5yZHMiKQoKYGBgCgoKYGBgCiMgVE9ETzogTW9yZ2FuIHN1Z2dlc3RlZCBhZGRpbmcgcmFuZG9tZWZmZWN0cyBsaWtlIHRoaXMKam9iOjpqb2IoeyAgCiAgZ2FtX2dwdDNfbWF6ZV93aXRocmFuZG9tZWZmZWN0cyA8LSBnYW0oCiAgICBydCB+CiAgICAgIHMoc3VycHJpc2FsLCBzdWJqZWN0LCBicz0iZnMiKSArIHMoc3ViamVjdCwgYnM9J3JlJykgKyBzKHdvcmQsIGJzPSdyZScpICsKICAgICAgcyhzdXJwcmlzYWwsIGJzPSJjciIsIGs9MjApICsKICAgICAgdGUoZnJlcSwgbGVuLCBicz0iY3IiKSArCiAgICAgIHMocHJldl9zdXJwLCBicz0iY3IiLCBrPTIwKSArCiAgICAgIHRlKHByZXZfZnJlcSwgcHJldl9sZW4sIGJzPSJjciIpLAogICAgZGF0YT1ncHQzX21hemUsCiAgICBtZXRob2Q9IlJFTUwiKQp9LAp0aXRsZSA9ICJnYW1fZ3B0M19tYXplX3dpdGhyYW5kb21lZmZlY3RzIikKYGBgCmBgYHtyLCBpbmNsdWRlPUZ9CgoKYWxsX2dhbV9zdXJwUlRtYXplX3ByZWRpY3Rpb25zIDwtIAogIGdldF9nYW1fcHJlZGljdGlvbnMucHJldl9hbmRfY3VycigibWF6ZVJUIixnYW1fQm5ncmFtX21hemUsICJCXzUtZ3JhbSIpICU+JSAKICB1bmlvbihnZXRfZ2FtX3ByZWRpY3Rpb25zLnByZXZfYW5kX2N1cnIoIm1hemVSVCIsZ2FtX0Jncm5uX21hemUsICJCX0dSTk4iKSkgJT4lIAogIHVuaW9uKGdldF9nYW1fcHJlZGljdGlvbnMucHJldl9hbmRfY3VycigibWF6ZVJUIixnYW1fQnR4bF9tYXplLCAiQl9UWEwiKSkgJT4lIAogIHVuaW9uKGdldF9nYW1fcHJlZGljdGlvbnMucHJldl9hbmRfY3VycigibWF6ZVJUIixnYW1fZ3B0M19tYXplLCAiR1BUMyIpKSAlPiUgCiAgdW5pb24oZ2V0X2dhbV9wcmVkaWN0aW9ucy5wcmV2X2FuZF9jdXJyKCJtYXplUlQiLGdhbV9ncHQyX21hemUsICJHUFQyIikpICU+JQogIHVuaW9uKGdldF9nYW1fcHJlZGljdGlvbnMucHJldl9hbmRfY3VycigibWF6ZVJUIixnYW1fZ3B0MmxfbWF6ZSwgIkdQVDItbGFyZ2UiKSkgJT4lCiAgdW5pb24oZ2V0X2dhbV9wcmVkaWN0aW9ucy5wcmV2X2FuZF9jdXJyKCJtYXplUlQiLGdhbV9ncHRqX21hemUsICJHUFQtSiIpKSAlPiUgCiAgdW5pb24oZ2V0X2dhbV9wcmVkaWN0aW9ucy5wcmV2X2FuZF9jdXJyKCJtYXplUlQiLGdhbV9ncHRuZW9fbWF6ZSwgIkdQVC1OZW8iKSkKICAKcGxvdC5nYW1fc3VycFJUbWF6ZSA8LSAKICBnZ3Bsb3QoYWxsX2dhbV9zdXJwUlRtYXplX3ByZWRpY3Rpb25zICU+JSBmaWx0ZXIoIXN0cl9kZXRlY3QobW9kZWwsICJeQl8iKSksIAogICAgICAgICBhZXMoeD1zdXJwcmlzYWwsIHk9bWF6ZVJULCB5bWluPUNJX2xvd2VyLCB5bWF4PUNJX3VwcGVyKSkrCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcmliYm9uKGFscGhhPS4zLGZpbGw9ImJsdWUiKSsKICAjIGdlb21fZGVuc2l0eShkYXRhPXN1cnBzLlJUc19sYWdfYy5wZXJ3b3JkLCBhZXMoeD1zdXJwLCB5PTEwMDAqLi5kZW5zaXR5Li4pLCBmaWxsPSJncmF5IiwgaW5oZXJpdC5hZXMgPSBGKSsKICBmYWNldF9ncmlkKHN+bW9kZWwpICsKICAjIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMzMwLDU4MCksIHhsaW09YygwLDE1KSkrCiAgbGFicyh4PSJTdXJwcmlzYWwiLCB5PSJNYXplIFJlYWN0aW9uIFRpbWUgKG1zKSIpICsKICBnZ3RpdGxlKCJHQU0gZml0cyBmb3IgbWF6ZVJUdnN1cnBfZm9ybXVsYTEiKQoKI3JlcGxpY2F0aW5nIGJveWNlCnBsb3QuZ2FtX3N1cnBSVG1hemVfYm95Y2UgPC0gCiAgZ2dwbG90KGFsbF9nYW1fc3VycFJUbWF6ZV9wcmVkaWN0aW9ucyAlPiUgZmlsdGVyKHN0cl9kZXRlY3QobW9kZWwsICJeQl8iKSksIAogICAgICAgICBhZXMoeD1zdXJwcmlzYWwsIHk9bWF6ZVJULCB5bWluPUNJX2xvd2VyLCB5bWF4PUNJX3VwcGVyKSkrCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcmliYm9uKGFscGhhPS4zLGZpbGw9ImJsdWUiKSsKICAjIGdlb21fZGVuc2l0eShkYXRhPXN1cnBzLlJUc19sYWdfYy5wZXJ3b3JkLCBhZXMoeD1zdXJwLCB5PTEwMDAqLi5kZW5zaXR5Li4pLCBmaWxsPSJncmF5IiwgaW5oZXJpdC5hZXMgPSBGKSsKICBmYWNldF9ncmlkKHN+bW9kZWwpICsKICAjIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMzMwLDU4MCksIHhsaW09YygwLDE1KSkrCiAgbGFicyh4PSJTdXJwcmlzYWwiLCB5PSJNYXplIFJlYWN0aW9uIFRpbWUgKG1zKSIpICsKICBnZ3RpdGxlKCJHQU0gZml0cyBmb3IgbWF6ZVJUdnN1cnBfZm9ybXVsYTEgKHJlcGxpY2F0aW5nIEJveWNlKSIpCgoKIyBkZW5zMiA8LSAgIGdncGxvdChhbGxfbWF6ZSwgYWVzKHg9dmFsdWUpKSsKIyAgIGdlb21fZGVuc2l0eShmaWxsPSJncmF5IiwpKwojICAgZmFjZXRfZ3JpZCgufm1vZGVsKSsKIyAgIGxhYnMoeD0iU3VycHJpc2FsIChiaXRzKSIsIHk9IiIpKwojICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIHN0cmlwLnRleHQ9ZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwgMCwgMCwgMCksICJjbSIpKQojIAojIGJvdCA8LSBwbG90X2dyaWQoTkEsIGRlbnMyLCBOQSwgbnJvdz0xLCByZWxfd2lkdGhzID0gYyguMDc1LCAxLCAuMDM1KSkKIyAKIyBwbG90X2dyaWQocGxvdC5nYW1fc3VycFJUbWF6ZSwgYm90LCBucm93PTIsIHJlbF9oZWlnaHRzID0gYygxLCAuMykpCgpgYGAKCmBgYHtyfQpwbG90LmdhbV9zdXJwUlRtYXplCmBgYAoKYGBge3J9CnBsb3QuZ2FtX3N1cnBSVG1hemVfYm95Y2UKYGBgCgoKYGBge3J9CmRyYXdfZ2FtX2JvdGg8LWZ1bmN0aW9uKGdhbV9tb2RlbCl7CiAgcHJpbnQoZ2FtLmNoZWNrKGdhbV9tb2RlbCkpCiAgZHJhdyhnYW1fbW9kZWwsIHNlV2l0aE1lYW49VCwgc2hpZnQ9Y29lZihnYW1fbW9kZWwpWyIoSW50ZXJjZXB0KSJdLCBzZWxlY3Q9YygxLDMpKQogIH0KYGBgCg==