library(ggplot2)
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(tidyr)
library(magrittr)

Attaching package: ‘magrittr’

The following object is masked from ‘package:tidyr’:

    extract
library(anytime)
library(stringr)

# Define function for generating latin square given the # of items and # of conditions
latin.square <- function(n.items, n.conditions){
  # Define the height and width of the table in which the latin square will be stored
  ls_table <- matrix(nrow = n.items, ncol = n.conditions)
  # Make a vector to store the last cell's value
  last_cell <- vector(length = 0)
  # For each row associated w/ each item number, ...
  for (row in 1:n.items){
    # If "last" hasn't received a value yet, ...
    if(length(last_cell) == 0){
      # Then value the cells in the first row from 1 to n.conditions, and...
      ls_table[row,] <- 1:n.conditions
      # Assign the value of the last cell in the first row to "last".
      last_cell <- ls_table[row, n.conditions]
    } else{
      # If "last" has a value, assign to row the sequence from last value of last row, ending w/ n.conditions
      ls_table[row, 1:length(last_cell:n.conditions)] <- last_cell:n.conditions
      # If x is anything other than 1, ...
      if(last_cell != 1){
        # Then starting w/ the cell after the cell in row whose value matches n.conditions,
        # assign values to the remaining cells starting w/ 1 and going to the number before, ...
        ls_table[row,(length(last_cell:n.conditions)+1):n.conditions] <- 1:(n.conditions - length(last_cell:n.conditions))
        # and assign the value of the last cell in the first row to "last".
        last_cell <- ls_table[row, n.conditions]
      } else{
        # Otherwise (if last_cell is 1), just assign the value of the last cell in the first row to "last" (without )
        last_cell <- ls_table[row, n.conditions]
      }
    }
  }
  # Convert the matrix into a dataframe
  ls_table <- as.data.frame(ls_table)
  # Give the conditions letter labels (as column names)
  colnames(ls_table) <- letters[1:n.conditions]
  # Give the items numeric labels (as row names)
  row.names(ls_table) <- 1:n.items
  return(ls_table)
}
# Read in "results" file from IBEX (in csv format) for AJT controller
# Supply column names
read.csv("Results/results_2020-01-20(1).csv",
         header = FALSE,
         col.names = c("epoch_time",
                       "MD5",
                       "controller",
                       "IBEX_ID",
                       "element",
                       "type",
                       "item",
                       "question",
                       "rating",
                       "correct",
                       "rt")) -> ibex_import

# Replace %2C w/ commas and é w/ é
ibex_import[,"question"] %<>% str_replace("%2C", ",")
ibex_import[,"question"] %<>% str_replace("%0A", ";")
ibex_import[,"question"] %<>% str_replace("é", "é")

# Associate all sentences w/ IBEX_ID, remove duplicate rows
ibex_import %>%
  subset(controller == "AcceptabilityJudgment" & question != "NULL",
         select = c(IBEX_ID,
                    question)) %>%
  distinct() %>%
  arrange(IBEX_ID) -> ID_key

# Get ratings data
ibex_import %>%
  subset(controller == "AcceptabilityJudgment" & question == "NULL",
         select = c(epoch_time,
                    IBEX_ID,
                    type,
                    rating,
                    rt)) -> ratings_data_incl

# Add trial order information (trial order at this stage is still preserved in the order)
n <- length(unique(ratings_data_incl$epoch_time))
ratings_data_incl$trial <- rep(1:138, n)

# Get form data (intro and debrief)
ibex_import %>%
  subset(controller == "Form",
         select = c(epoch_time,
                    question,
                    rating)) %>%
  droplevels -> participant_data

# Change column names
colnames(participant_data) <- c("epoch_time", "question", "response")

# Change participant data to long format (one row per submission/subject)
participant_data %>%
  group_by(epoch_time) %>%
  summarize(prolific_id = str_sub(response[question == "prolificid"],
                                  -4, -1),
            age = response[question == "age"],
            native_eng = response[question == "languageEnglish"],
            other_langs = response[question == "otherLanguages"],
            ling_major = response[question == "linguistics"],
            consent = response[question == "consent"],
            what_about = response[question == "debrief1Response"],
            strategy = response[question == "debrief2Response"],
            patterns_noticed = response[question == "debrief3Response"],
            cp_vs_vt = response[question == "debrief4Response"],
            cp_vs_ee = response[question == "debrief5Response"],
            vt_vs_ee = response[question == "debrief6Response"],
            difficulty = response[question == "difficulty"],
            form_rts = sum(as.numeric(as.character(response[question == "_REACTION_TIME_"]))),
            seps = 500*(138-1)) -> participant_data

# Make epoch_time numeric (agnostic of which column it's in)
ratings_data_incl[,which(colnames(ratings_data_incl) == "epoch_time")] %>%
  as.character %>%
  as.numeric -> ratings_data_incl[,which(colnames(ratings_data_incl) == "epoch_time")]

# Import items, fillers, practice for both experiments
read.csv("Items/CSVs/exp6_items.csv") -> items
  items$frequency <- NULL
  items$context <- NULL
  items$sentence_w_gaps <- NULL
  items$comments <- NULL
read.csv("Items/CSVs/exp6_fillers.csv") -> fillers
read.csv("Items/CSVs/exp6_practice.csv") -> practice
read.csv("Items/CSVs/exp6_burn-in_items.csv") -> burn_in_items
  burn_in_items$frequency <- NULL
  burn_in_items$context <- NULL
  burn_in_items$sentence_w_gaps <- NULL
read.csv("Items/CSVs/exp6_burn-in_fillers.csv") -> burn_in_fillers
  burn_in_fillers$mean.z.rating. <- NULL
read.csv("Items/CSVs/exp6_attention.csv") -> attention_checks
  
# Associate conditions w/ their IBEX ID
merge(items,
      ID_key,
      by.x = "sentence",
      by.y = "question") -> items

merge(fillers,
      ID_key,
      by.x = "sentence",
      by.y = "question") -> fillers

merge(practice,
      ID_key,
      by.x = "sentence",
      by.y = "question") -> practice

merge(burn_in_items,
      ID_key,
      by.x = "sentence",
      by.y = "question") -> burn_in_items

merge(burn_in_fillers,
      ID_key,
      by.x = "sentence",
      by.y = "question") -> burn_in_fillers

merge(attention_checks,
      ID_key,
      by.x = "sentence",
      by.y = "question") -> attention_checks

# Generate latin square for experiment & convert to long format
lsq <- latin.square(n.items = 36, n.conditions = 6)
lsq <- cbind(item = as.numeric(row.names(lsq)), lsq)
lsq %>%
  gather(condition, list, a:f, factor_key = TRUE) -> lsq
lsq %>%
  arrange(item) -> lsq

# Add list number that conditions appeared in to exp items
items %>%
  merge(.,
        lsq,
        by = c("item", "condition")) -> items

# Create master list of items, fillers, and practice
## Make copies of dfs, and add/remove columns to make columns consistent
items -> items_m
  items_m$requested_rating <- NA
fillers -> fillers_m
  fillers_m$s_type <- NULL
  fillers_m$gramm_s_type <- NULL
  fillers_m$only <- NULL
  fillers_m$original_source <- NULL
  fillers_m$last_used <- NULL
  fillers_m$X <- NULL
  fillers_m$requested_rating <- NA
  fillers_m$condition <- NA
  fillers_m$length <- NA
  fillers_m$structure <- NA
  fillers_m$env <- NA
  fillers_m$list <- NA
  fillers_m$item <- NA
  fillers_m$verb <- NA
burn_in_items -> burn_in_items_m
  burn_in_items_m$requested_rating <- NA
  burn_in_items_m$list <- NA
burn_in_fillers -> burn_in_fillers_m
  burn_in_fillers_m$orig_ID <- NULL
  burn_in_fillers_m$orig_sentence <- NULL
  burn_in_fillers_m$requested_rating <- NA
  burn_in_fillers_m$condition <- NA
  burn_in_fillers_m$length <- NA
  burn_in_fillers_m$structure <- NA
  burn_in_fillers_m$env <- NA
  burn_in_fillers_m$list <- NA
  burn_in_fillers_m$item <- NA
  burn_in_fillers_m$verb <- NA
practice -> practice_m
  colnames(practice_m)[3] <- "gramm"
  practice_m$requested_rating <- NA
  practice_m$condition <- NA
  practice_m$length <- NA
  practice_m$structure <- NA
  practice_m$env <- NA
  practice_m$list <- NA
  practice_m$item <- NA
  practice_m$verb <- NA
attention_checks -> attention_checks_m
  attention_checks_m$in_IBEX <- NULL
  attention_checks_m$condition <- NA
  attention_checks_m$length <- NA
  attention_checks_m$structure <- NA
  attention_checks_m$env <- NA
  attention_checks_m$list <- NA
  attention_checks_m$item <- NA
  attention_checks_m$gramm <- NA
  attention_checks_m$verb <- NA

# Combine items, fillers, practice items, burn-in items, burn-in fillers, and attention checks
master <- rbind(items_m, fillers_m, burn_in_items_m, burn_in_fillers_m, practice_m, attention_checks_m)

# Match master to ratings data
ratings_data_incl %>%
  merge(.,
        master,
        by = "IBEX_ID") -> ratings_data_incl

# Associate epoch_time w/ subject number and native speaker status
ratings_data_incl %>%
  merge(.,
        participant_data[,1:2],
        by = "epoch_time") -> ratings_data_incl

# Save ratings data as csv
write.csv(ratings_data_incl, file = "exp6_ratings.csv")

# Find the list each subject was given
ratings_data_incl %>%
  subset(type == "experimental",
         select = c(prolific_id,
                    list)) %>%
  droplevels %>%
  group_by(prolific_id) %>%
  summarize(one_list = length(unique(list)) == 1,
            list = if(one_list == TRUE){
              min(list)
              } else {
                NA
              }) -> list_key

# Join list_key w/ participant_data
participant_data %>%
  merge(.,
        list_key,
        by = "prolific_id") -> participant_data

# Add sentence RT sums to participant data
ratings_data_incl %>%
  group_by(prolific_id) %>%
  summarize(stc_rts = sum(rt)) -> participant_rts

# Add RTs to participant_data & sum it up
merge(participant_data,
      participant_rts,
      by = "prolific_id") -> participant_data

apply(participant_data, 1,
      function(x){
        sum(as.numeric(as.character(x["form_rts"])),
            as.numeric(as.character(x["seps"])),
            as.numeric(as.character(x["stc_rts"]))) -> time
        return(time)
      }) -> participant_data$tot_time_ms

participant_data$tot_time_s <- participant_data$tot_time_ms/1000
participant_data$tot_time_m <- participant_data$tot_time_s/60

# Remove excluded participants from participant_data (SEE EXCLUDED PARTICIPANTS IN LIST BELOW)
participant_data %>%
  subset(prolific_id %in% excluded) -> participant_data_rm

participant_data %>%
  subset(!(prolific_id %in% excluded)) -> participant_data

# Determine how balanced the lists are. For this experiment, there are 6 lists.
participant_data %>%
  group_by(list) %>%
  summarize(counter = first(list) - 1,
            n = n()) -> list_dist

1 Exclusion criteria

A participant will be excluded if any of the following conditions are met: 1. They fail at least one of the six attention checks. 2. The proportion of response times lower than one second is greater than or equal to 0.10. 3. Their mean ratings for fillers expected to be ungrammatical and fillers expected to be grammatical are either inverted or are too close. Too close is defined on normalized ratings, where a difference that is more than two standard deviations below the mean difference is too close.

1.1 Attention checks

ratings_data_incl %>%
  subset(type == "attention") %>%
  group_by(epoch_time,
           prolific_id) %>%
  summarize(first = rating[ID == "a01"],
            second = rating[ID == "a02"],
            third = rating[ID == "a03"],
            fourth = rating[ID == "a04"],
            fifth = rating[ID == "a05"],
            sixth = rating[ID == "a06"])

1.2 Response times

# Generate RT density plots for each participant
for (n in 1:length(unique(ratings_data_incl$prolific_id))) {
  participant <- unique(ratings_data_incl$prolific_id)[n]
  ratings_data_incl %>%
    subset(prolific_id == participant) %>%
    group_by(IBEX_ID) %>%
    summarize(rt_s = rt/1000) %>%
    ggplot(aes(x = rt_s)) +
    geom_density() +
    geom_vline(aes(xintercept = mean(rt_s))) +
    xlim(xmin = 0,
         xmax = 10) +
    labs(title = paste("Prolific ID", participant, "response times"),
         x = "Response time (seconds)",
         y = "Density") -> plot
  print(plot)
}


# Get RT stats
ratings_data_incl %>%
  group_by(epoch_time,
           prolific_id) %>%
  summarize(mean_rt = mean(rt),
            p_below_1000 = length(rt[rt < 1000])/length(rt),
            min_rt = min(rt),
            max_rt = max(rt),
            median_rt = median(rt),
            n = n(),
            sd = sd(rt),
            se = sd/sqrt(n)) -> rt_stats
print(rt_stats)

# Print participants for whom 25% or more of their RTs are less than a second.
rt_stats %>%
  subset(p_below_1000 >= 0.10,
         select = c(epoch_time, prolific_id))

1.3 Filler ratings

# Select filler & experimental sentences and transform ratings to z-scores (grouping by participant)
ratings_data_incl %>%
  subset(type == "experimental" | type == "filler") %>%
  group_by(prolific_id) %>%
  mutate(z_rating = scale(as.numeric(as.character(rating)))) %>%
  ungroup() %>%
  # Select only the fillers
  subset(type == "filler") %>%
  # Group by participant and grammaticality & summarize ratings
  group_by(prolific_id,
           gramm) %>%
  summarize(mean_z_rating = mean(z_rating)) -> filler_z_means
print(filler_z_means)

# Get difference in mean z_ratings per participant and join w/ filler_z_means
filler_z_means %>%
  group_by(prolific_id) %>%
  summarize(diff = mean_z_rating[gramm == "1"] - mean_z_rating[gramm == "0"]) %>%
  merge(filler_z_means, .) -> filler_z_means

# Show a list of participants whose difference is over two SDs away from the mean
#filler_z_means %>%
#  subset(diff < mean_diff-(2*sd_diff))

filler_z_means %>%
  ggplot(aes(x = reorder(prolific_id, diff),
             y = mean_z_rating,
             color = as.factor(gramm))) +
  geom_point() +
  labs(x = "Prolific ID (first 4)",
       y = "Mean z-score-transformed rating") +
  scale_color_discrete("Grammaticality") +
  theme(axis.text.x = element_text(angle = 45, vjust = 0.95, hjust = 0.95)) -> filler_ratings_plot
print(filler_ratings_plot)

1.4 Make list of excluded participants

excluded <- NULL
excluded <- c(excluded, "134d") # Failed one attention check
excluded <- c(excluded, "d6ad") # Mean gramm and ungramm filler ratings too close; most RTs below 2.5s
excluded <- c(excluded, "d797") # Mean gramm and ungramm filler ratings too close
LS0tCnRpdGxlOiAiUkMgc3ViZXh0cmFjdGlvbiBpbiBFbmdsaXNoOiBTZXQtdXAgbm90ZWJvb2sgZm9yIEV4cGVyaW1lbnQgNiAiCmF1dGhvcjogIkpha2UgVy4gVmluY2VudCAoJiMxMDY7JiMxMTk7JiMxMTg7JiMxMDU7JiMxMTA7JiM5OTsmIzEwMTtuJiM2NDsmIzExNztjJiMxMTU7Yy5lJiMxMDA7dSkiCm91dHB1dDoKICBodG1sX25vdGVib29rOiAKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0aGVtZTogZmxhdGx5CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNzczogc3R5bGUuY3NzCiAgICB0b2M6IHRydWUKICBwZGZfZG9jdW1lbnQ6IAogICAga2VlcF90ZXg6IHllcwpiaWJsaW9ncmFwaHk6IH4vRG9jdW1lbnRzL2xpYnJhcnkuYmliCi0tLQpgYGB7ciBzZXQtdXB9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShtYWdyaXR0cikKbGlicmFyeShhbnl0aW1lKQpsaWJyYXJ5KHN0cmluZ3IpCgojIERlZmluZSBmdW5jdGlvbiBmb3IgZ2VuZXJhdGluZyBsYXRpbiBzcXVhcmUgZ2l2ZW4gdGhlICMgb2YgaXRlbXMgYW5kICMgb2YgY29uZGl0aW9ucwpsYXRpbi5zcXVhcmUgPC0gZnVuY3Rpb24obi5pdGVtcywgbi5jb25kaXRpb25zKXsKICAjIERlZmluZSB0aGUgaGVpZ2h0IGFuZCB3aWR0aCBvZiB0aGUgdGFibGUgaW4gd2hpY2ggdGhlIGxhdGluIHNxdWFyZSB3aWxsIGJlIHN0b3JlZAogIGxzX3RhYmxlIDwtIG1hdHJpeChucm93ID0gbi5pdGVtcywgbmNvbCA9IG4uY29uZGl0aW9ucykKICAjIE1ha2UgYSB2ZWN0b3IgdG8gc3RvcmUgdGhlIGxhc3QgY2VsbCdzIHZhbHVlCiAgbGFzdF9jZWxsIDwtIHZlY3RvcihsZW5ndGggPSAwKQogICMgRm9yIGVhY2ggcm93IGFzc29jaWF0ZWQgdy8gZWFjaCBpdGVtIG51bWJlciwgLi4uCiAgZm9yIChyb3cgaW4gMTpuLml0ZW1zKXsKICAgICMgSWYgImxhc3QiIGhhc24ndCByZWNlaXZlZCBhIHZhbHVlIHlldCwgLi4uCiAgICBpZihsZW5ndGgobGFzdF9jZWxsKSA9PSAwKXsKICAgICAgIyBUaGVuIHZhbHVlIHRoZSBjZWxscyBpbiB0aGUgZmlyc3Qgcm93IGZyb20gMSB0byBuLmNvbmRpdGlvbnMsIGFuZC4uLgogICAgICBsc190YWJsZVtyb3csXSA8LSAxOm4uY29uZGl0aW9ucwogICAgICAjIEFzc2lnbiB0aGUgdmFsdWUgb2YgdGhlIGxhc3QgY2VsbCBpbiB0aGUgZmlyc3Qgcm93IHRvICJsYXN0Ii4KICAgICAgbGFzdF9jZWxsIDwtIGxzX3RhYmxlW3Jvdywgbi5jb25kaXRpb25zXQogICAgfSBlbHNlewogICAgICAjIElmICJsYXN0IiBoYXMgYSB2YWx1ZSwgYXNzaWduIHRvIHJvdyB0aGUgc2VxdWVuY2UgZnJvbSBsYXN0IHZhbHVlIG9mIGxhc3Qgcm93LCBlbmRpbmcgdy8gbi5jb25kaXRpb25zCiAgICAgIGxzX3RhYmxlW3JvdywgMTpsZW5ndGgobGFzdF9jZWxsOm4uY29uZGl0aW9ucyldIDwtIGxhc3RfY2VsbDpuLmNvbmRpdGlvbnMKICAgICAgIyBJZiB4IGlzIGFueXRoaW5nIG90aGVyIHRoYW4gMSwgLi4uCiAgICAgIGlmKGxhc3RfY2VsbCAhPSAxKXsKICAgICAgICAjIFRoZW4gc3RhcnRpbmcgdy8gdGhlIGNlbGwgYWZ0ZXIgdGhlIGNlbGwgaW4gcm93IHdob3NlIHZhbHVlIG1hdGNoZXMgbi5jb25kaXRpb25zLAogICAgICAgICMgYXNzaWduIHZhbHVlcyB0byB0aGUgcmVtYWluaW5nIGNlbGxzIHN0YXJ0aW5nIHcvIDEgYW5kIGdvaW5nIHRvIHRoZSBudW1iZXIgYmVmb3JlLCAuLi4KICAgICAgICBsc190YWJsZVtyb3csKGxlbmd0aChsYXN0X2NlbGw6bi5jb25kaXRpb25zKSsxKTpuLmNvbmRpdGlvbnNdIDwtIDE6KG4uY29uZGl0aW9ucyAtIGxlbmd0aChsYXN0X2NlbGw6bi5jb25kaXRpb25zKSkKICAgICAgICAjIGFuZCBhc3NpZ24gdGhlIHZhbHVlIG9mIHRoZSBsYXN0IGNlbGwgaW4gdGhlIGZpcnN0IHJvdyB0byAibGFzdCIuCiAgICAgICAgbGFzdF9jZWxsIDwtIGxzX3RhYmxlW3Jvdywgbi5jb25kaXRpb25zXQogICAgICB9IGVsc2V7CiAgICAgICAgIyBPdGhlcndpc2UgKGlmIGxhc3RfY2VsbCBpcyAxKSwganVzdCBhc3NpZ24gdGhlIHZhbHVlIG9mIHRoZSBsYXN0IGNlbGwgaW4gdGhlIGZpcnN0IHJvdyB0byAibGFzdCIgKHdpdGhvdXQgKQogICAgICAgIGxhc3RfY2VsbCA8LSBsc190YWJsZVtyb3csIG4uY29uZGl0aW9uc10KICAgICAgfQogICAgfQogIH0KICAjIENvbnZlcnQgdGhlIG1hdHJpeCBpbnRvIGEgZGF0YWZyYW1lCiAgbHNfdGFibGUgPC0gYXMuZGF0YS5mcmFtZShsc190YWJsZSkKICAjIEdpdmUgdGhlIGNvbmRpdGlvbnMgbGV0dGVyIGxhYmVscyAoYXMgY29sdW1uIG5hbWVzKQogIGNvbG5hbWVzKGxzX3RhYmxlKSA8LSBsZXR0ZXJzWzE6bi5jb25kaXRpb25zXQogICMgR2l2ZSB0aGUgaXRlbXMgbnVtZXJpYyBsYWJlbHMgKGFzIHJvdyBuYW1lcykKICByb3cubmFtZXMobHNfdGFibGUpIDwtIDE6bi5pdGVtcwogIHJldHVybihsc190YWJsZSkKfQpgYGAKCmBgYHtyIGltcG9ydF9kYXRhfQojIFJlYWQgaW4gInJlc3VsdHMiIGZpbGUgZnJvbSBJQkVYIChpbiBjc3YgZm9ybWF0KSBmb3IgQUpUIGNvbnRyb2xsZXIKIyBTdXBwbHkgY29sdW1uIG5hbWVzCnJlYWQuY3N2KCJSZXN1bHRzL3Jlc3VsdHNfMjAyMC0wMS0yMCgxKS5jc3YiLAogICAgICAgICBoZWFkZXIgPSBGQUxTRSwKICAgICAgICAgY29sLm5hbWVzID0gYygiZXBvY2hfdGltZSIsCiAgICAgICAgICAgICAgICAgICAgICAgIk1ENSIsCiAgICAgICAgICAgICAgICAgICAgICAgImNvbnRyb2xsZXIiLAogICAgICAgICAgICAgICAgICAgICAgICJJQkVYX0lEIiwKICAgICAgICAgICAgICAgICAgICAgICAiZWxlbWVudCIsCiAgICAgICAgICAgICAgICAgICAgICAgInR5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICJpdGVtIiwKICAgICAgICAgICAgICAgICAgICAgICAicXVlc3Rpb24iLAogICAgICAgICAgICAgICAgICAgICAgICJyYXRpbmciLAogICAgICAgICAgICAgICAgICAgICAgICJjb3JyZWN0IiwKICAgICAgICAgICAgICAgICAgICAgICAicnQiKSkgLT4gaWJleF9pbXBvcnQKCiMgUmVwbGFjZSAlMkMgdy8gY29tbWFzIGFuZCDDg8KpIHcvIMOpCmliZXhfaW1wb3J0WywicXVlc3Rpb24iXSAlPD4lIHN0cl9yZXBsYWNlKCIlMkMiLCAiLCIpCmliZXhfaW1wb3J0WywicXVlc3Rpb24iXSAlPD4lIHN0cl9yZXBsYWNlKCIlMEEiLCAiOyIpCmliZXhfaW1wb3J0WywicXVlc3Rpb24iXSAlPD4lIHN0cl9yZXBsYWNlKCLDg8KpIiwgIsOpIikKCiMgQXNzb2NpYXRlIGFsbCBzZW50ZW5jZXMgdy8gSUJFWF9JRCwgcmVtb3ZlIGR1cGxpY2F0ZSByb3dzCmliZXhfaW1wb3J0ICU+JQogIHN1YnNldChjb250cm9sbGVyID09ICJBY2NlcHRhYmlsaXR5SnVkZ21lbnQiICYgcXVlc3Rpb24gIT0gIk5VTEwiLAogICAgICAgICBzZWxlY3QgPSBjKElCRVhfSUQsCiAgICAgICAgICAgICAgICAgICAgcXVlc3Rpb24pKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIGFycmFuZ2UoSUJFWF9JRCkgLT4gSURfa2V5CgojIEdldCByYXRpbmdzIGRhdGEKaWJleF9pbXBvcnQgJT4lCiAgc3Vic2V0KGNvbnRyb2xsZXIgPT0gIkFjY2VwdGFiaWxpdHlKdWRnbWVudCIgJiBxdWVzdGlvbiA9PSAiTlVMTCIsCiAgICAgICAgIHNlbGVjdCA9IGMoZXBvY2hfdGltZSwKICAgICAgICAgICAgICAgICAgICBJQkVYX0lELAogICAgICAgICAgICAgICAgICAgIHR5cGUsCiAgICAgICAgICAgICAgICAgICAgcmF0aW5nLAogICAgICAgICAgICAgICAgICAgIHJ0KSkgLT4gcmF0aW5nc19kYXRhX2luY2wKCiMgQWRkIHRyaWFsIG9yZGVyIGluZm9ybWF0aW9uICh0cmlhbCBvcmRlciBhdCB0aGlzIHN0YWdlIGlzIHN0aWxsIHByZXNlcnZlZCBpbiB0aGUgb3JkZXIpCm4gPC0gbGVuZ3RoKHVuaXF1ZShyYXRpbmdzX2RhdGFfaW5jbCRlcG9jaF90aW1lKSkKcmF0aW5nc19kYXRhX2luY2wkdHJpYWwgPC0gcmVwKDE6MTM4LCBuKQoKIyBHZXQgZm9ybSBkYXRhIChpbnRybyBhbmQgZGVicmllZikKaWJleF9pbXBvcnQgJT4lCiAgc3Vic2V0KGNvbnRyb2xsZXIgPT0gIkZvcm0iLAogICAgICAgICBzZWxlY3QgPSBjKGVwb2NoX3RpbWUsCiAgICAgICAgICAgICAgICAgICAgcXVlc3Rpb24sCiAgICAgICAgICAgICAgICAgICAgcmF0aW5nKSkgJT4lCiAgZHJvcGxldmVscyAtPiBwYXJ0aWNpcGFudF9kYXRhCgojIENoYW5nZSBjb2x1bW4gbmFtZXMKY29sbmFtZXMocGFydGljaXBhbnRfZGF0YSkgPC0gYygiZXBvY2hfdGltZSIsICJxdWVzdGlvbiIsICJyZXNwb25zZSIpCgojIENoYW5nZSBwYXJ0aWNpcGFudCBkYXRhIHRvIGxvbmcgZm9ybWF0IChvbmUgcm93IHBlciBzdWJtaXNzaW9uL3N1YmplY3QpCnBhcnRpY2lwYW50X2RhdGEgJT4lCiAgZ3JvdXBfYnkoZXBvY2hfdGltZSkgJT4lCiAgc3VtbWFyaXplKHByb2xpZmljX2lkID0gc3RyX3N1YihyZXNwb25zZVtxdWVzdGlvbiA9PSAicHJvbGlmaWNpZCJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLTQsIC0xKSwKICAgICAgICAgICAgYWdlID0gcmVzcG9uc2VbcXVlc3Rpb24gPT0gImFnZSJdLAogICAgICAgICAgICBuYXRpdmVfZW5nID0gcmVzcG9uc2VbcXVlc3Rpb24gPT0gImxhbmd1YWdlRW5nbGlzaCJdLAogICAgICAgICAgICBvdGhlcl9sYW5ncyA9IHJlc3BvbnNlW3F1ZXN0aW9uID09ICJvdGhlckxhbmd1YWdlcyJdLAogICAgICAgICAgICBsaW5nX21ham9yID0gcmVzcG9uc2VbcXVlc3Rpb24gPT0gImxpbmd1aXN0aWNzIl0sCiAgICAgICAgICAgIGNvbnNlbnQgPSByZXNwb25zZVtxdWVzdGlvbiA9PSAiY29uc2VudCJdLAogICAgICAgICAgICB3aGF0X2Fib3V0ID0gcmVzcG9uc2VbcXVlc3Rpb24gPT0gImRlYnJpZWYxUmVzcG9uc2UiXSwKICAgICAgICAgICAgc3RyYXRlZ3kgPSByZXNwb25zZVtxdWVzdGlvbiA9PSAiZGVicmllZjJSZXNwb25zZSJdLAogICAgICAgICAgICBwYXR0ZXJuc19ub3RpY2VkID0gcmVzcG9uc2VbcXVlc3Rpb24gPT0gImRlYnJpZWYzUmVzcG9uc2UiXSwKICAgICAgICAgICAgY3BfdnNfdnQgPSByZXNwb25zZVtxdWVzdGlvbiA9PSAiZGVicmllZjRSZXNwb25zZSJdLAogICAgICAgICAgICBjcF92c19lZSA9IHJlc3BvbnNlW3F1ZXN0aW9uID09ICJkZWJyaWVmNVJlc3BvbnNlIl0sCiAgICAgICAgICAgIHZ0X3ZzX2VlID0gcmVzcG9uc2VbcXVlc3Rpb24gPT0gImRlYnJpZWY2UmVzcG9uc2UiXSwKICAgICAgICAgICAgZGlmZmljdWx0eSA9IHJlc3BvbnNlW3F1ZXN0aW9uID09ICJkaWZmaWN1bHR5Il0sCiAgICAgICAgICAgIGZvcm1fcnRzID0gc3VtKGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHJlc3BvbnNlW3F1ZXN0aW9uID09ICJfUkVBQ1RJT05fVElNRV8iXSkpKSwKICAgICAgICAgICAgc2VwcyA9IDUwMCooMTM4LTEpKSAtPiBwYXJ0aWNpcGFudF9kYXRhCgojIE1ha2UgZXBvY2hfdGltZSBudW1lcmljIChhZ25vc3RpYyBvZiB3aGljaCBjb2x1bW4gaXQncyBpbikKcmF0aW5nc19kYXRhX2luY2xbLHdoaWNoKGNvbG5hbWVzKHJhdGluZ3NfZGF0YV9pbmNsKSA9PSAiZXBvY2hfdGltZSIpXSAlPiUKICBhcy5jaGFyYWN0ZXIgJT4lCiAgYXMubnVtZXJpYyAtPiByYXRpbmdzX2RhdGFfaW5jbFssd2hpY2goY29sbmFtZXMocmF0aW5nc19kYXRhX2luY2wpID09ICJlcG9jaF90aW1lIildCgojIEltcG9ydCBpdGVtcywgZmlsbGVycywgcHJhY3RpY2UgZm9yIGJvdGggZXhwZXJpbWVudHMKcmVhZC5jc3YoIkl0ZW1zL0NTVnMvZXhwNl9pdGVtcy5jc3YiKSAtPiBpdGVtcwogIGl0ZW1zJGZyZXF1ZW5jeSA8LSBOVUxMCiAgaXRlbXMkY29udGV4dCA8LSBOVUxMCiAgaXRlbXMkc2VudGVuY2Vfd19nYXBzIDwtIE5VTEwKICBpdGVtcyRjb21tZW50cyA8LSBOVUxMCnJlYWQuY3N2KCJJdGVtcy9DU1ZzL2V4cDZfZmlsbGVycy5jc3YiKSAtPiBmaWxsZXJzCnJlYWQuY3N2KCJJdGVtcy9DU1ZzL2V4cDZfcHJhY3RpY2UuY3N2IikgLT4gcHJhY3RpY2UKcmVhZC5jc3YoIkl0ZW1zL0NTVnMvZXhwNl9idXJuLWluX2l0ZW1zLmNzdiIpIC0+IGJ1cm5faW5faXRlbXMKICBidXJuX2luX2l0ZW1zJGZyZXF1ZW5jeSA8LSBOVUxMCiAgYnVybl9pbl9pdGVtcyRjb250ZXh0IDwtIE5VTEwKICBidXJuX2luX2l0ZW1zJHNlbnRlbmNlX3dfZ2FwcyA8LSBOVUxMCnJlYWQuY3N2KCJJdGVtcy9DU1ZzL2V4cDZfYnVybi1pbl9maWxsZXJzLmNzdiIpIC0+IGJ1cm5faW5fZmlsbGVycwogIGJ1cm5faW5fZmlsbGVycyRtZWFuLnoucmF0aW5nLiA8LSBOVUxMCnJlYWQuY3N2KCJJdGVtcy9DU1ZzL2V4cDZfYXR0ZW50aW9uLmNzdiIpIC0+IGF0dGVudGlvbl9jaGVja3MKICAKIyBBc3NvY2lhdGUgY29uZGl0aW9ucyB3LyB0aGVpciBJQkVYIElECm1lcmdlKGl0ZW1zLAogICAgICBJRF9rZXksCiAgICAgIGJ5LnggPSAic2VudGVuY2UiLAogICAgICBieS55ID0gInF1ZXN0aW9uIikgLT4gaXRlbXMKCm1lcmdlKGZpbGxlcnMsCiAgICAgIElEX2tleSwKICAgICAgYnkueCA9ICJzZW50ZW5jZSIsCiAgICAgIGJ5LnkgPSAicXVlc3Rpb24iKSAtPiBmaWxsZXJzCgptZXJnZShwcmFjdGljZSwKICAgICAgSURfa2V5LAogICAgICBieS54ID0gInNlbnRlbmNlIiwKICAgICAgYnkueSA9ICJxdWVzdGlvbiIpIC0+IHByYWN0aWNlCgptZXJnZShidXJuX2luX2l0ZW1zLAogICAgICBJRF9rZXksCiAgICAgIGJ5LnggPSAic2VudGVuY2UiLAogICAgICBieS55ID0gInF1ZXN0aW9uIikgLT4gYnVybl9pbl9pdGVtcwoKbWVyZ2UoYnVybl9pbl9maWxsZXJzLAogICAgICBJRF9rZXksCiAgICAgIGJ5LnggPSAic2VudGVuY2UiLAogICAgICBieS55ID0gInF1ZXN0aW9uIikgLT4gYnVybl9pbl9maWxsZXJzCgptZXJnZShhdHRlbnRpb25fY2hlY2tzLAogICAgICBJRF9rZXksCiAgICAgIGJ5LnggPSAic2VudGVuY2UiLAogICAgICBieS55ID0gInF1ZXN0aW9uIikgLT4gYXR0ZW50aW9uX2NoZWNrcwoKIyBHZW5lcmF0ZSBsYXRpbiBzcXVhcmUgZm9yIGV4cGVyaW1lbnQgJiBjb252ZXJ0IHRvIGxvbmcgZm9ybWF0CmxzcSA8LSBsYXRpbi5zcXVhcmUobi5pdGVtcyA9IDM2LCBuLmNvbmRpdGlvbnMgPSA2KQpsc3EgPC0gY2JpbmQoaXRlbSA9IGFzLm51bWVyaWMocm93Lm5hbWVzKGxzcSkpLCBsc3EpCmxzcSAlPiUKICBnYXRoZXIoY29uZGl0aW9uLCBsaXN0LCBhOmYsIGZhY3Rvcl9rZXkgPSBUUlVFKSAtPiBsc3EKbHNxICU+JQogIGFycmFuZ2UoaXRlbSkgLT4gbHNxCgojIEFkZCBsaXN0IG51bWJlciB0aGF0IGNvbmRpdGlvbnMgYXBwZWFyZWQgaW4gdG8gZXhwIGl0ZW1zCml0ZW1zICU+JQogIG1lcmdlKC4sCiAgICAgICAgbHNxLAogICAgICAgIGJ5ID0gYygiaXRlbSIsICJjb25kaXRpb24iKSkgLT4gaXRlbXMKCiMgQ3JlYXRlIG1hc3RlciBsaXN0IG9mIGl0ZW1zLCBmaWxsZXJzLCBhbmQgcHJhY3RpY2UKIyMgTWFrZSBjb3BpZXMgb2YgZGZzLCBhbmQgYWRkL3JlbW92ZSBjb2x1bW5zIHRvIG1ha2UgY29sdW1ucyBjb25zaXN0ZW50Cml0ZW1zIC0+IGl0ZW1zX20KICBpdGVtc19tJHJlcXVlc3RlZF9yYXRpbmcgPC0gTkEKZmlsbGVycyAtPiBmaWxsZXJzX20KICBmaWxsZXJzX20kc190eXBlIDwtIE5VTEwKICBmaWxsZXJzX20kZ3JhbW1fc190eXBlIDwtIE5VTEwKICBmaWxsZXJzX20kb25seSA8LSBOVUxMCiAgZmlsbGVyc19tJG9yaWdpbmFsX3NvdXJjZSA8LSBOVUxMCiAgZmlsbGVyc19tJGxhc3RfdXNlZCA8LSBOVUxMCiAgZmlsbGVyc19tJFggPC0gTlVMTAogIGZpbGxlcnNfbSRyZXF1ZXN0ZWRfcmF0aW5nIDwtIE5BCiAgZmlsbGVyc19tJGNvbmRpdGlvbiA8LSBOQQogIGZpbGxlcnNfbSRsZW5ndGggPC0gTkEKICBmaWxsZXJzX20kc3RydWN0dXJlIDwtIE5BCiAgZmlsbGVyc19tJGVudiA8LSBOQQogIGZpbGxlcnNfbSRsaXN0IDwtIE5BCiAgZmlsbGVyc19tJGl0ZW0gPC0gTkEKICBmaWxsZXJzX20kdmVyYiA8LSBOQQpidXJuX2luX2l0ZW1zIC0+IGJ1cm5faW5faXRlbXNfbQogIGJ1cm5faW5faXRlbXNfbSRyZXF1ZXN0ZWRfcmF0aW5nIDwtIE5BCiAgYnVybl9pbl9pdGVtc19tJGxpc3QgPC0gTkEKYnVybl9pbl9maWxsZXJzIC0+IGJ1cm5faW5fZmlsbGVyc19tCiAgYnVybl9pbl9maWxsZXJzX20kb3JpZ19JRCA8LSBOVUxMCiAgYnVybl9pbl9maWxsZXJzX20kb3JpZ19zZW50ZW5jZSA8LSBOVUxMCiAgYnVybl9pbl9maWxsZXJzX20kcmVxdWVzdGVkX3JhdGluZyA8LSBOQQogIGJ1cm5faW5fZmlsbGVyc19tJGNvbmRpdGlvbiA8LSBOQQogIGJ1cm5faW5fZmlsbGVyc19tJGxlbmd0aCA8LSBOQQogIGJ1cm5faW5fZmlsbGVyc19tJHN0cnVjdHVyZSA8LSBOQQogIGJ1cm5faW5fZmlsbGVyc19tJGVudiA8LSBOQQogIGJ1cm5faW5fZmlsbGVyc19tJGxpc3QgPC0gTkEKICBidXJuX2luX2ZpbGxlcnNfbSRpdGVtIDwtIE5BCiAgYnVybl9pbl9maWxsZXJzX20kdmVyYiA8LSBOQQpwcmFjdGljZSAtPiBwcmFjdGljZV9tCiAgY29sbmFtZXMocHJhY3RpY2VfbSlbM10gPC0gImdyYW1tIgogIHByYWN0aWNlX20kcmVxdWVzdGVkX3JhdGluZyA8LSBOQQogIHByYWN0aWNlX20kY29uZGl0aW9uIDwtIE5BCiAgcHJhY3RpY2VfbSRsZW5ndGggPC0gTkEKICBwcmFjdGljZV9tJHN0cnVjdHVyZSA8LSBOQQogIHByYWN0aWNlX20kZW52IDwtIE5BCiAgcHJhY3RpY2VfbSRsaXN0IDwtIE5BCiAgcHJhY3RpY2VfbSRpdGVtIDwtIE5BCiAgcHJhY3RpY2VfbSR2ZXJiIDwtIE5BCmF0dGVudGlvbl9jaGVja3MgLT4gYXR0ZW50aW9uX2NoZWNrc19tCiAgYXR0ZW50aW9uX2NoZWNrc19tJGluX0lCRVggPC0gTlVMTAogIGF0dGVudGlvbl9jaGVja3NfbSRjb25kaXRpb24gPC0gTkEKICBhdHRlbnRpb25fY2hlY2tzX20kbGVuZ3RoIDwtIE5BCiAgYXR0ZW50aW9uX2NoZWNrc19tJHN0cnVjdHVyZSA8LSBOQQogIGF0dGVudGlvbl9jaGVja3NfbSRlbnYgPC0gTkEKICBhdHRlbnRpb25fY2hlY2tzX20kbGlzdCA8LSBOQQogIGF0dGVudGlvbl9jaGVja3NfbSRpdGVtIDwtIE5BCiAgYXR0ZW50aW9uX2NoZWNrc19tJGdyYW1tIDwtIE5BCiAgYXR0ZW50aW9uX2NoZWNrc19tJHZlcmIgPC0gTkEKCiMgQ29tYmluZSBpdGVtcywgZmlsbGVycywgcHJhY3RpY2UgaXRlbXMsIGJ1cm4taW4gaXRlbXMsIGJ1cm4taW4gZmlsbGVycywgYW5kIGF0dGVudGlvbiBjaGVja3MKbWFzdGVyIDwtIHJiaW5kKGl0ZW1zX20sIGZpbGxlcnNfbSwgYnVybl9pbl9pdGVtc19tLCBidXJuX2luX2ZpbGxlcnNfbSwgcHJhY3RpY2VfbSwgYXR0ZW50aW9uX2NoZWNrc19tKQoKIyBNYXRjaCBtYXN0ZXIgdG8gcmF0aW5ncyBkYXRhCnJhdGluZ3NfZGF0YV9pbmNsICU+JQogIG1lcmdlKC4sCiAgICAgICAgbWFzdGVyLAogICAgICAgIGJ5ID0gIklCRVhfSUQiKSAtPiByYXRpbmdzX2RhdGFfaW5jbAoKIyBBc3NvY2lhdGUgZXBvY2hfdGltZSB3LyBzdWJqZWN0IG51bWJlciBhbmQgbmF0aXZlIHNwZWFrZXIgc3RhdHVzCnJhdGluZ3NfZGF0YV9pbmNsICU+JQogIG1lcmdlKC4sCiAgICAgICAgcGFydGljaXBhbnRfZGF0YVssMToyXSwKICAgICAgICBieSA9ICJlcG9jaF90aW1lIikgLT4gcmF0aW5nc19kYXRhX2luY2wKCiMgU2F2ZSByYXRpbmdzIGRhdGEgYXMgY3N2CndyaXRlLmNzdihyYXRpbmdzX2RhdGFfaW5jbCwgZmlsZSA9ICJleHA2X3JhdGluZ3MuY3N2IikKCiMgRmluZCB0aGUgbGlzdCBlYWNoIHN1YmplY3Qgd2FzIGdpdmVuCnJhdGluZ3NfZGF0YV9pbmNsICU+JQogIHN1YnNldCh0eXBlID09ICJleHBlcmltZW50YWwiLAogICAgICAgICBzZWxlY3QgPSBjKHByb2xpZmljX2lkLAogICAgICAgICAgICAgICAgICAgIGxpc3QpKSAlPiUKICBkcm9wbGV2ZWxzICU+JQogIGdyb3VwX2J5KHByb2xpZmljX2lkKSAlPiUKICBzdW1tYXJpemUob25lX2xpc3QgPSBsZW5ndGgodW5pcXVlKGxpc3QpKSA9PSAxLAogICAgICAgICAgICBsaXN0ID0gaWYob25lX2xpc3QgPT0gVFJVRSl7CiAgICAgICAgICAgICAgbWluKGxpc3QpCiAgICAgICAgICAgICAgfSBlbHNlIHsKICAgICAgICAgICAgICAgIE5BCiAgICAgICAgICAgICAgfSkgLT4gbGlzdF9rZXkKCiMgSm9pbiBsaXN0X2tleSB3LyBwYXJ0aWNpcGFudF9kYXRhCnBhcnRpY2lwYW50X2RhdGEgJT4lCiAgbWVyZ2UoLiwKICAgICAgICBsaXN0X2tleSwKICAgICAgICBieSA9ICJwcm9saWZpY19pZCIpIC0+IHBhcnRpY2lwYW50X2RhdGEKCiMgQWRkIHNlbnRlbmNlIFJUIHN1bXMgdG8gcGFydGljaXBhbnQgZGF0YQpyYXRpbmdzX2RhdGFfaW5jbCAlPiUKICBncm91cF9ieShwcm9saWZpY19pZCkgJT4lCiAgc3VtbWFyaXplKHN0Y19ydHMgPSBzdW0ocnQpKSAtPiBwYXJ0aWNpcGFudF9ydHMKCiMgQWRkIFJUcyB0byBwYXJ0aWNpcGFudF9kYXRhICYgc3VtIGl0IHVwCm1lcmdlKHBhcnRpY2lwYW50X2RhdGEsCiAgICAgIHBhcnRpY2lwYW50X3J0cywKICAgICAgYnkgPSAicHJvbGlmaWNfaWQiKSAtPiBwYXJ0aWNpcGFudF9kYXRhCgphcHBseShwYXJ0aWNpcGFudF9kYXRhLCAxLAogICAgICBmdW5jdGlvbih4KXsKICAgICAgICBzdW0oYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeFsiZm9ybV9ydHMiXSkpLAogICAgICAgICAgICBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcih4WyJzZXBzIl0pKSwKICAgICAgICAgICAgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeFsic3RjX3J0cyJdKSkpIC0+IHRpbWUKICAgICAgICByZXR1cm4odGltZSkKICAgICAgfSkgLT4gcGFydGljaXBhbnRfZGF0YSR0b3RfdGltZV9tcwoKcGFydGljaXBhbnRfZGF0YSR0b3RfdGltZV9zIDwtIHBhcnRpY2lwYW50X2RhdGEkdG90X3RpbWVfbXMvMTAwMApwYXJ0aWNpcGFudF9kYXRhJHRvdF90aW1lX20gPC0gcGFydGljaXBhbnRfZGF0YSR0b3RfdGltZV9zLzYwCgojIFJlbW92ZSBleGNsdWRlZCBwYXJ0aWNpcGFudHMgZnJvbSBwYXJ0aWNpcGFudF9kYXRhIChTRUUgRVhDTFVERUQgUEFSVElDSVBBTlRTIElOIExJU1QgQkVMT1cpCnBhcnRpY2lwYW50X2RhdGEgJT4lCiAgc3Vic2V0KHByb2xpZmljX2lkICVpbiUgZXhjbHVkZWQpIC0+IHBhcnRpY2lwYW50X2RhdGFfcm0KCnBhcnRpY2lwYW50X2RhdGEgJT4lCiAgc3Vic2V0KCEocHJvbGlmaWNfaWQgJWluJSBleGNsdWRlZCkpICU+JQogIGRyb3BsZXZlbHMgLT4gcGFydGljaXBhbnRfZGF0YQoKIyBEZXRlcm1pbmUgaG93IGJhbGFuY2VkIHRoZSBsaXN0cyBhcmUuIEZvciB0aGlzIGV4cGVyaW1lbnQsIHRoZXJlIGFyZSA2IGxpc3RzLgpwYXJ0aWNpcGFudF9kYXRhICU+JQogIGdyb3VwX2J5KGxpc3QpICU+JQogIHN1bW1hcml6ZShjb3VudGVyID0gZmlyc3QobGlzdCkgLSAxLAogICAgICAgICAgICBuID0gbigpKSAtPiBsaXN0X2Rpc3QKYGBgCgojIEV4Y2x1c2lvbiBjcml0ZXJpYQoKQSBwYXJ0aWNpcGFudCB3aWxsIGJlIGV4Y2x1ZGVkIGlmIGFueSBvZiB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnMgYXJlIG1ldDoKMS4gVGhleSBmYWlsIGF0IGxlYXN0IG9uZSBvZiB0aGUgc2l4IGF0dGVudGlvbiBjaGVja3MuCjIuIFRoZSBwcm9wb3J0aW9uIG9mIHJlc3BvbnNlIHRpbWVzIGxvd2VyIHRoYW4gb25lIHNlY29uZCBpcyBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gMC4xMC4KMy4gVGhlaXIgbWVhbiByYXRpbmdzIGZvciBmaWxsZXJzIGV4cGVjdGVkIHRvIGJlIHVuZ3JhbW1hdGljYWwgYW5kIGZpbGxlcnMgZXhwZWN0ZWQgdG8gYmUgZ3JhbW1hdGljYWwgYXJlIGVpdGhlciBpbnZlcnRlZCBvciBhcmUgdG9vIGNsb3NlLiAqVG9vIGNsb3NlKiBpcyBkZWZpbmVkIG9uIG5vcm1hbGl6ZWQgcmF0aW5ncywgd2hlcmUgYSBkaWZmZXJlbmNlIHRoYXQgaXMgbW9yZSB0aGFuIHR3byBzdGFuZGFyZCBkZXZpYXRpb25zIGJlbG93IHRoZSBtZWFuIGRpZmZlcmVuY2UgaXMgdG9vIGNsb3NlLgoKCiMjIEF0dGVudGlvbiBjaGVja3MKCmBgYHtyIGF0dGVudGlvbl9jaGVja3N9CnJhdGluZ3NfZGF0YV9pbmNsICU+JQogIHN1YnNldCh0eXBlID09ICJhdHRlbnRpb24iKSAlPiUKICBncm91cF9ieShlcG9jaF90aW1lLAogICAgICAgICAgIHByb2xpZmljX2lkKSAlPiUKICBzdW1tYXJpemUoZmlyc3QgPSByYXRpbmdbSUQgPT0gImEwMSJdLAogICAgICAgICAgICBzZWNvbmQgPSByYXRpbmdbSUQgPT0gImEwMiJdLAogICAgICAgICAgICB0aGlyZCA9IHJhdGluZ1tJRCA9PSAiYTAzIl0sCiAgICAgICAgICAgIGZvdXJ0aCA9IHJhdGluZ1tJRCA9PSAiYTA0Il0sCiAgICAgICAgICAgIGZpZnRoID0gcmF0aW5nW0lEID09ICJhMDUiXSwKICAgICAgICAgICAgc2l4dGggPSByYXRpbmdbSUQgPT0gImEwNiJdKQpgYGAKCiMjIFJlc3BvbnNlIHRpbWVzCmBgYHtyIHJ0X3Bsb3RzfQojIEdlbmVyYXRlIFJUIGRlbnNpdHkgcGxvdHMgZm9yIGVhY2ggcGFydGljaXBhbnQKZm9yIChuIGluIDE6bGVuZ3RoKHVuaXF1ZShyYXRpbmdzX2RhdGFfaW5jbCRwcm9saWZpY19pZCkpKSB7CiAgcGFydGljaXBhbnQgPC0gdW5pcXVlKHJhdGluZ3NfZGF0YV9pbmNsJHByb2xpZmljX2lkKVtuXQogIHJhdGluZ3NfZGF0YV9pbmNsICU+JQogICAgc3Vic2V0KHByb2xpZmljX2lkID09IHBhcnRpY2lwYW50KSAlPiUKICAgIGdyb3VwX2J5KElCRVhfSUQpICU+JQogICAgc3VtbWFyaXplKHJ0X3MgPSBydC8xMDAwKSAlPiUKICAgIGdncGxvdChhZXMoeCA9IHJ0X3MpKSArCiAgICBnZW9tX2RlbnNpdHkoKSArCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVhbihydF9zKSkpICsKICAgIHhsaW0oeG1pbiA9IDAsCiAgICAgICAgIHhtYXggPSAxMCkgKwogICAgbGFicyh0aXRsZSA9IHBhc3RlKCJQcm9saWZpYyBJRCIsIHBhcnRpY2lwYW50LCAicmVzcG9uc2UgdGltZXMiKSwKICAgICAgICAgeCA9ICJSZXNwb25zZSB0aW1lIChzZWNvbmRzKSIsCiAgICAgICAgIHkgPSAiRGVuc2l0eSIpIC0+IHBsb3QKICBwcmludChwbG90KQp9CgojIEdldCBSVCBzdGF0cwpyYXRpbmdzX2RhdGFfaW5jbCAlPiUKICBncm91cF9ieShlcG9jaF90aW1lLAogICAgICAgICAgIHByb2xpZmljX2lkKSAlPiUKICBzdW1tYXJpemUobWVhbl9ydCA9IG1lYW4ocnQpLAogICAgICAgICAgICBwX2JlbG93XzEwMDAgPSBsZW5ndGgocnRbcnQgPCAxMDAwXSkvbGVuZ3RoKHJ0KSwKICAgICAgICAgICAgbWluX3J0ID0gbWluKHJ0KSwKICAgICAgICAgICAgbWF4X3J0ID0gbWF4KHJ0KSwKICAgICAgICAgICAgbWVkaWFuX3J0ID0gbWVkaWFuKHJ0KSwKICAgICAgICAgICAgbiA9IG4oKSwKICAgICAgICAgICAgc2QgPSBzZChydCksCiAgICAgICAgICAgIHNlID0gc2Qvc3FydChuKSkgLT4gcnRfc3RhdHMKcHJpbnQocnRfc3RhdHMpCgojIFByaW50IHBhcnRpY2lwYW50cyBmb3Igd2hvbSAyNSUgb3IgbW9yZSBvZiB0aGVpciBSVHMgYXJlIGxlc3MgdGhhbiBhIHNlY29uZC4KcnRfc3RhdHMgJT4lCiAgc3Vic2V0KHBfYmVsb3dfMTAwMCA+PSAwLjEwLAogICAgICAgICBzZWxlY3QgPSBjKGVwb2NoX3RpbWUsIHByb2xpZmljX2lkKSkKYGBgCgojIyBGaWxsZXIgcmF0aW5ncwpgYGB7ciBmaWxsZXJfcmF0aW5nc30KIyBTZWxlY3QgZmlsbGVyICYgZXhwZXJpbWVudGFsIHNlbnRlbmNlcyBhbmQgdHJhbnNmb3JtIHJhdGluZ3MgdG8gei1zY29yZXMgKGdyb3VwaW5nIGJ5IHBhcnRpY2lwYW50KQpyYXRpbmdzX2RhdGFfaW5jbCAlPiUKICBzdWJzZXQodHlwZSA9PSAiZXhwZXJpbWVudGFsIiB8IHR5cGUgPT0gImZpbGxlciIpICU+JQogIGdyb3VwX2J5KHByb2xpZmljX2lkKSAlPiUKICBtdXRhdGUoel9yYXRpbmcgPSBzY2FsZShhcy5udW1lcmljKGFzLmNoYXJhY3RlcihyYXRpbmcpKSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICAjIFNlbGVjdCBvbmx5IHRoZSBmaWxsZXJzCiAgc3Vic2V0KHR5cGUgPT0gImZpbGxlciIpICU+JQogICMgR3JvdXAgYnkgcGFydGljaXBhbnQgYW5kIGdyYW1tYXRpY2FsaXR5ICYgc3VtbWFyaXplIHJhdGluZ3MKICBncm91cF9ieShwcm9saWZpY19pZCwKICAgICAgICAgICBncmFtbSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fel9yYXRpbmcgPSBtZWFuKHpfcmF0aW5nKSkgLT4gZmlsbGVyX3pfbWVhbnMKcHJpbnQoZmlsbGVyX3pfbWVhbnMpCgojIEdldCBkaWZmZXJlbmNlIGluIG1lYW4gel9yYXRpbmdzIHBlciBwYXJ0aWNpcGFudCBhbmQgam9pbiB3LyBmaWxsZXJfel9tZWFucwpmaWxsZXJfel9tZWFucyAlPiUKICBncm91cF9ieShwcm9saWZpY19pZCkgJT4lCiAgc3VtbWFyaXplKGRpZmYgPSBtZWFuX3pfcmF0aW5nW2dyYW1tID09ICIxIl0gLSBtZWFuX3pfcmF0aW5nW2dyYW1tID09ICIwIl0pICU+JQogIG1lcmdlKGZpbGxlcl96X21lYW5zLCAuKSAtPiBmaWxsZXJfel9tZWFucwoKIyBTaG93IGEgbGlzdCBvZiBwYXJ0aWNpcGFudHMgd2hvc2UgZGlmZmVyZW5jZSBpcyBvdmVyIHR3byBTRHMgYXdheSBmcm9tIHRoZSBtZWFuCiNmaWxsZXJfel9tZWFucyAlPiUKIyAgc3Vic2V0KGRpZmYgPCBtZWFuX2RpZmYtKDIqc2RfZGlmZikpCgpmaWxsZXJfel9tZWFucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKHByb2xpZmljX2lkLCBkaWZmKSwKICAgICAgICAgICAgIHkgPSBtZWFuX3pfcmF0aW5nLAogICAgICAgICAgICAgY29sb3IgPSBhcy5mYWN0b3IoZ3JhbW0pKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4ID0gIlByb2xpZmljIElEIChmaXJzdCA0KSIsCiAgICAgICB5ID0gIk1lYW4gei1zY29yZS10cmFuc2Zvcm1lZCByYXRpbmciKSArCiAgc2NhbGVfY29sb3JfZGlzY3JldGUoIkdyYW1tYXRpY2FsaXR5IikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC45NSwgaGp1c3QgPSAwLjk1KSkgLT4gZmlsbGVyX3JhdGluZ3NfcGxvdApwcmludChmaWxsZXJfcmF0aW5nc19wbG90KQpgYGAKCiMjIE1ha2UgbGlzdCBvZiBleGNsdWRlZCBwYXJ0aWNpcGFudHMKCmBgYHtyIGV4Y2x1ZGVkX3BhcnRpY2lwYW50c30KZXhjbHVkZWQgPC0gTlVMTApleGNsdWRlZCA8LSBjKGV4Y2x1ZGVkLCAiMTM0ZCIpICMgRmFpbGVkIG9uZSBhdHRlbnRpb24gY2hlY2sKZXhjbHVkZWQgPC0gYyhleGNsdWRlZCwgImQ2YWQiKSAjIE1lYW4gZ3JhbW0gYW5kIHVuZ3JhbW0gZmlsbGVyIHJhdGluZ3MgdG9vIGNsb3NlOyBtb3N0IFJUcyBiZWxvdyAyLjVzCmV4Y2x1ZGVkIDwtIGMoZXhjbHVkZWQsICJkNzk3IikgIyBNZWFuIGdyYW1tIGFuZCB1bmdyYW1tIGZpbGxlciByYXRpbmdzIHRvbyBjbG9zZQpgYGA=