Diane, Jane, and Kimberly.
Everything before 15 - analysis is a syntax to match all children.
I know errors happen all the time. Therefore, these codes were made available here if someone wants to review or check the consistency.
In the e-mail that you found this link, I attached an excel file in which you’ll be able to check this file.

Please notice that this report refers to birth to three only
If you don’t want to check any code, please click here

1 load package

pacman::p_load(tidyverse, janitor)

2 Data handling

3 get all ASQ4 data

read_excel_allsheets <- function(filename) {
    sheets <- readxl::excel_sheets(filename) #get all sheet names
    x <- lapply(sheets, function(X) readxl::read_excel(filename, sheet = X))
    names(x) <- sheets #get names only
    x #return
}
#get the excel file
excel_list <- read_excel_allsheets("C:/Users/luisf/Dropbox/ASQ4_AEPS Data for Luis 2.2021/Luis Feb 2021/Final ALL ASQ4 for AEPS 2019_2020.xlsx")
#transform into vectors
list2env(setNames(excel_list, #list
                  paste0("ds_",janitor::make_clean_names(names(excel_list)))),  #fixing different names and other patterns
         envir=.GlobalEnv) #where?

4 Create a backup

backup_asq4_demo <- ds_asq4_demo 
backup_asq4_items <- ds_asq4_items

#remove all attributes

#ds_asq4_demo[] <- lapply(ds_asq4_demo, function(x) { attributes(x) <- NULL; x })
#backup_asq4_items[] <- lapply(backup_asq4_items, function(x) { attributes(x) <- NULL; x })

5 clean names

ds_asq4_demo <- clean_names(ds_asq4_demo)
ds_asq4_items <- clean_names(ds_asq4_items)

6 merge datasets

ds_asq <- left_join(ds_asq4_demo, ds_asq4_items, by = c("asq4_id"))

7 Compute totals

7.1 Change variable computational level

ds_asq <- ds_asq %>% 
  mutate_at(vars(c1:c6, gm1:gm6, fm1:fm6, ps1:ps6, p1:p6), ~as.numeric(.))

7.2 Compute totals for each ASQ-4 domain

ds_asq<-ds_asq %>% 
  mutate(com_sum = rowSums(select(.,c1:c6))) %>% 
  mutate(gm_sum = rowSums(select(.,gm1:gm6))) %>% 
  mutate(fm_sum = rowSums(select(.,fm1:fm6))) %>% 
  mutate(ps_sum = rowSums(select(.,ps1:ps6))) %>% 
  mutate(per_sum = rowSums(select(.,p1:p6)))

8 AEPS Demographics

aeps_1_demo <- readxl::read_excel("C:/Users/luisf/Dropbox/ASQ4_AEPS Data for Luis 2.2021/Luis Feb 2021/copy KM Cleaned AEPS 3.5.21/1.Cleaned AEPSBirthToThreeFormNoN 2 Grace 9.13.2019.xlsx", sheet = 2)
#fix names
aeps_1_demo <- clean_names(aeps_1_demo)
#remove empty columns and rows
aeps_1_demo <- remove_empty(aeps_1_demo, which = c("rows", "cols"), quiet = TRUE)
#remove useless rows
aeps_1_demo <- aeps_1_demo %>% filter(!is.na(childs_id))

#add new features to merge
aeps_1_demo <- aeps_1_demo %>% 
  mutate(aeps_file_number = 1) %>% #same as ds_asq
  mutate(spread_sheet = spread_sheet_id_1) %>% #same as full dataset!
  mutate(aeps_sprdsheet_id_number = spread_sheet_id_1) #same as ds_asq

9 1.AEPSBirthToThreeFormNoN 2 Grace 9.13.2019

10 First file 1 - Fine motor (1)

10.1 get data

aeps_1_fine <- readxl::read_excel("C:/Users/luisf/Dropbox/ASQ4_AEPS Data for Luis 2.2021/Luis Feb 2021/copy KM Cleaned AEPS 3.5.21/1.Cleaned AEPSBirthToThreeFormNoN 2 Grace 9.13.2019.xlsx", sheet = 3)
#clear excel attributes
aeps_1_fine[] <- lapply(aeps_1_fine, function(x) { attributes(x) <- NULL; x })
#fix names
aeps_1_fine <- clean_names(aeps_1_fine)
#remove empty columns and rows
aeps_1_fine <- remove_empty(aeps_1_fine, which = c("rows", "cols"), quiet = TRUE)
#create a skill
aeps_1_fine <- aeps_1_fine %>% 
  mutate(skill = .[[1]]) %>% #this is the first column )in this case -- fine motor (sub)domain
  select(1,skill, everything())
#With this new variable (skill), just keep if is a letter
aeps_1_fine <- aeps_1_fine %>% 
  mutate(skill = if_else(str_detect(skill, "[a-z]"), .[[1]],  NA_character_)) %>% #if skill is a letter, otherwise missing
  fill(skill)
#remove first line (it's almost all na)
aeps_1_fine <- aeps_1_fine %>% 
  filter(!str_detect(.[[1]], "[a-z]"))
#transform to numeric
aeps_1_fine <- aeps_1_fine %>% mutate(!! names(.)[1] := as.numeric(!! rlang::sym(names(.)[1]))) 
#aeps_1_fine[[1]] <- as.numeric(aeps_1_fine[[1]])

10.2 Tranform it to long format

spec <- tibble(`.name` = names(aeps_1_fine)) %>%
  slice(-c(1:2)) %>%
  mutate(`.value` = case_when(
           `.name` %>% str_detect("spread") ~ "spread_sheet",
           `.name` %>% str_detect("score")  ~ "score",
           `.name` %>% str_detect("confirm") ~ "confirm")
  )
# apply the spec
aeps_1_fine_long <- aeps_1_fine %>%
  pivot_longer_spec(spec)

10.3 Add domain

This chunk will get all domains and number skills. It will be useful to merge all ds in the future.

aeps_1_fine_long <- aeps_1_fine_long %>% 
  mutate(domain = names(.)[[1]]) %>% 
  rename(number_skill = names(.)[[1]]) %>% 
  select(domain, number_skill, everything())

11 First file 1 - Gross motor (2)

11.1 get data

aeps_1_gross <- readxl::read_excel("C:/Users/luisf/Dropbox/ASQ4_AEPS Data for Luis 2.2021/Luis Feb 2021/copy KM Cleaned AEPS 3.5.21/1.Cleaned AEPSBirthToThreeFormNoN 2 Grace 9.13.2019.xlsx", sheet = 4)
#clear excel attributes
aeps_1_gross[] <- lapply(aeps_1_gross, function(x) { attributes(x) <- NULL; x })
#fix names
aeps_1_gross <- clean_names(aeps_1_gross)
#remove empty columns and rows
aeps_1_gross <- remove_empty(aeps_1_gross, which = c("rows", "cols"), quiet = TRUE)
#create a skill
aeps_1_gross <- aeps_1_gross %>% 
  mutate(skill = .[[1]]) %>% #this is the first column )in this case -- fine motor (sub)domain
  select(1,skill, everything())
#With this new variable (skill), just keep if is a letter
aeps_1_gross <- aeps_1_gross %>% 
  mutate(skill = if_else(str_detect(skill, "[a-z]"), .[[1]],  NA_character_)) %>% #if skill is a letter, otherwise missing
  fill(skill)
#remove first line (it's almost all na)
aeps_1_gross <- aeps_1_gross %>% 
  filter(!str_detect(.[[1]], "[a-z]"))
#transform to numeric
aeps_1_gross <- aeps_1_gross %>% mutate(!! names(.)[1] := as.numeric(!! rlang::sym(names(.)[1]))) 
#aeps_1_gross[[1]] <- as.numeric(aeps_1_gross[[1]])

11.2 Tranform it to long format

spec <- tibble(`.name` = names(aeps_1_gross)) %>%
  slice(-c(1:2)) %>%
  mutate(`.value` = case_when(
    `.name` %>% str_detect("spread") ~ "spread_sheet",
    `.name` %>% str_detect("score")  ~ "score",
    `.name` %>% str_detect("confirm") ~ "confirm")
  )
# apply the spec
aeps_1_gross_long <- aeps_1_gross %>%
  pivot_longer_spec(spec)

11.3 Add domain

This chunk will get all domains and number skills. It will be useful to merge all ds in the future.

aeps_1_gross_long <- aeps_1_gross_long %>% 
  mutate(domain = names(.)[[1]]) %>% 
  rename(number_skill = names(.)[[1]]) %>% 
  select(domain, number_skill, everything())

12 First file 1 - Adaptive (3)

12.1 get data

aeps_1_adaptive <- readxl::read_excel("C:/Users/luisf/Dropbox/ASQ4_AEPS Data for Luis 2.2021/Luis Feb 2021/copy KM Cleaned AEPS 3.5.21/1.Cleaned AEPSBirthToThreeFormNoN 2 Grace 9.13.2019.xlsx", sheet = 5)
#clear excel attributes
aeps_1_adaptive[] <- lapply(aeps_1_adaptive, function(x) { attributes(x) <- NULL; x })
#fix names
aeps_1_adaptive <- clean_names(aeps_1_adaptive)
#remove empty columns and rows
aeps_1_adaptive <- remove_empty(aeps_1_adaptive, which = c("rows", "cols"), quiet = TRUE)
#create a skill
aeps_1_adaptive <- aeps_1_adaptive %>% 
  mutate(skill = .[[1]]) %>% #this is the first column )in this case -- fine motor (sub)domain
  select(1,skill, everything())
#With this new variable (skill), just keep if is a letter
aeps_1_adaptive <- aeps_1_adaptive %>% 
  mutate(skill = if_else(str_detect(skill, "[a-z]"), .[[1]],  NA_character_)) %>% #if skill is a letter, otherwise missing
  fill(skill)
#remove first line (it's almost all na)
aeps_1_adaptive <- aeps_1_adaptive %>% 
  filter(!str_detect(.[[1]], "[a-z]"))
#transform to numeric
aeps_1_adaptive <- aeps_1_adaptive %>% mutate(!! names(.)[1] := as.numeric(!! rlang::sym(names(.)[1]))) 
#aeps_1_adaptive[[1]] <- as.numeric(aeps_1_adaptive[[1]])

12.2 Tranform it to long format

spec <- tibble(`.name` = names(aeps_1_adaptive)) %>%
  slice(-c(1:2)) %>%
  mutate(`.value` = case_when(
    `.name` %>% str_detect("spread") ~ "spread_sheet",
    `.name` %>% str_detect("score")  ~ "score",
    `.name` %>% str_detect("confirm") ~ "confirm")
  )
# apply the spec
aeps_1_adaptive_long <- aeps_1_adaptive %>%
  pivot_longer_spec(spec)

12.3 Add domain

This chunk will get all domains and number skills. It will be useful to merge all ds in the future.

aeps_1_adaptive_long <- aeps_1_adaptive_long %>% 
  mutate(domain = names(.)[[1]]) %>% 
  rename(number_skill = names(.)[[1]]) %>% 
  select(domain, number_skill, everything())

13 Merge AEPS spreadsheets datasets

Just checking if we have 22 children in each dataset

aeps_1_fine_long %>% count(spread_sheet)
aeps_1_gross_long %>% count(spread_sheet)
aeps_1_adaptive_long %>% count(spread_sheet)

I’ll use bind_rows to put each dataset on top of the another. First, fine long with gross long

ds_aeps_birth_three <- bind_rows(
  aeps_1_fine_long,
  aeps_1_gross_long)

Now, this resultant ds with adaptive

ds_aeps_birth_three <- bind_rows(
  ds_aeps_birth_three,
  aeps_1_adaptive_long)

14 Merge AEPS with AEPS demographics

I’ll get aeps_1_demo to add to this partially full dataset the child’ ID

ds_aeps_birth_three <- left_join(ds_aeps_birth_three, aeps_1_demo)

First, i’ll add two key variables present in the ASQ-4 dataset to guarantee the merging will be correct

ds_aeps_birth_three <- ds_aeps_birth_three %>% 
  mutate(aeps_file_number = 1) %>% 
  mutate(aeps_sprdsheet_id_number = spread_sheet) %>% 
  rename(asq4_id = childs_id) %>% 
  mutate(asq4_id = as.numeric(asq4_id)) #in ASQ4 dataset, this variable is numeric

Create a full dataset with ASQ-4 and AEPS

ds_birth_three_aeps_asq <- left_join(
  ds_aeps_birth_three,
  ds_asq,
  by = "asq4_id"
)

14.1 Manual check

ds_birth_three_aeps_asq %>% 
  filter(spread_sheet == "15") %>% View()

14.2 Save as excel

It seems everything worked! (Saturday, 13 March, 2021)
Ask Kimberly

15 Analyses - birth to three

Diane, Jane, and Kimberly. From this line on, I will:
(1) Present a plot and a table with the ASQ-4 summative results
(2) Present a plot and a table with the AEPS summative results (I read elsewhere and it seems that AEPS items need to be summed as well)
(3) Run all correlation analyses between the ASQ-4 summative scores and the AEPS summative scores

You’ll notice that the correlation results are too low. I’m wondering if something was under the radar in my code or if I’m missing some point.
I have sent an e-mail in which I present an excel file to make some points clearer.

15.1 ASQ-4 analysis

15.1.1 Plot

The graph below describes the distribution of all ASQ4 results.

15.1.2 Summary table

The table below reports the ASQ-4 results. I did not group the results by age interval.

com_sum (N=22) fm_sum (N=22) gm_sum (N=22) per_sum (N=22) ps_sum (N=22) Total (N=110) p value
value 0.328
   Mean (SD) 51.250 (10.683) 46.818 (12.492) 52.045 (9.084) 46.818 (9.580) 48.636 (10.821) 49.114 (10.631)
   Range 15.000 - 60.000 15.000 - 60.000 35.000 - 60.000 20.000 - 60.000 20.000 - 60.000 15.000 - 60.000
ds_birth_three_aeps_asq %>%
  select(asq4_id, everything()) %>% #just for checking
  distinct(asq4_id, .keep_all = T) %>% #use only one information (we have 22 children here)
  select(ends_with("_sum")) %>% 
  janitor::remove_empty(c("cols")) %>% #remove empty columns
  pivot_longer(everything(.)) %>% 
  arsenal::tableby(name ~ value, .) %>% 
  summary()

15.2 AEPS domains and skills

The following results will present the AEPS findings.

15.2.1 Descriptive table

The following table will present the descriptives of each participant and activitiy

How to interpret these results?
ASQ4id = 500 (it’s a child in the dataset) He or She has 18 results in domain adaptative and skill = Feeding.
If you access the excel file, it will be these same values.

15.2.2 Plot total scores

If I understood everything right (I’ve consulted https://pt.slideshare.net/BrookesPubCo/aeps-intro-webinar-slideshare),
each participant needs to have a score reflecting his/her ability.
Therefore, I summed up the scores obtained in each skill of each domain (e.g.: Reach, Grab, and Release from Fine motor).

ds_birth_three_aeps_asq %>% 
  group_by(asq4_id,domain, skill) %>%  #grop for having each score for each participant
  summarise(raw_score = sum(score)) %>% #create the summative score
  select(asq4_id,domain, skill, raw_score) %>% #select before pivoting
      pivot_longer(-c(asq4_id, raw_score, skill),
                   values_to = "domain") %>% 
  select(-name) %>% 
  ggplot(., aes(x = domain, y = raw_score, fill = skill)) +
  #geom_col(position = position_dodge2(preserve = "single")) +
  geom_bar(stat = "summary", position = "dodge", width = 0.8) +
  theme_bw()
`summarise()` has grouped output by 'asq4_id', 'domain'. You can override using the `.groups` argument.

15.2.3 Summary total scores

The following table presents the same information presented above. However, I imagine you’ll be able to check if everything is correct.

ds_birth_three_aeps_asq %>% 
  group_by(asq4_id,domain, skill) %>%  #grop for having each score for each participant
  summarise(raw_score = sum(score)) %>% #create the summative score
  select(asq4_id,domain, skill, raw_score) %>% #select before pivoting
      pivot_longer(-c(asq4_id, raw_score, skill),
                   values_to = "domain") %>% 
  select(-name) %>% 
  group_by(domain, skill) %>% 
  summarise(mean(raw_score), sd(raw_score), n()) %>% 
  mutate_if(is.numeric,round,2)

summarise() has grouped output by ‘asq4_id’, ‘domain’. You can override using the .groups argument. summarise() has grouped output by ‘domain’. You can override using the .groups argument. mutate_if() ignored the following grouping variables: Column domain

How to interpret these results?
Example:
when considering all children in domain (fine motor), and skill (A. Reach, Grab, Release), the mean result is 34.82
I double checked the excel file and this result is correct

15.3 Correlations AEPS ASQ-4

The following tables will present the correlation between each ASQ-4 domain and its AEPS parallel.
I’m using the summative score of the ASQ-4 and also the summative score of AEPS. Diane, please let me know if that’s the way to achieve the AEPS results.

Please don’t consider the three following chunks. They are programming syntaxes.

15.3.1 Create a summative score (Ask Diane)

cor_ds_1 <- ds_birth_three_aeps_asq %>% 
  group_by(asq4_id,domain, skill) %>%  #grop for having each score for each participant
  summarise(raw_score = sum(score))
`summarise()` has grouped output by 'asq4_id', 'domain'. You can override using the `.groups` argument.

15.3.2 Create a dataframe to gather all data

15.3.3 Merge these data and remove useless vectors

cor_ds <- left_join(cor_ds_1,cor_ds_2)
Joining, by = "asq4_id"

15.4 ASQ Fine motor vs AEPS Fine motor

library(corrr) #correlation 

Correlation between ASQ Fine motor and AEPS Fine motor I’m using the same child!

How to interpret these results?
The correlation between the ASQ-4 fine motor and AEPS fine motor (skill: Reach and Grab) is -0.22 (makes no sense to me)
The correlation between the ASQ-4 fine motor and AEPS fine motor (skill: Functional use) is -0.05 (makes no sense to me)

I have attached an excel file in which I mannually ran these correlations and the results match

15.5 ASQ gross motor AEPS gross motor

Correlation between ASQ Gross motor and AEPS Gross motor I’m using the data from same children.

How to interpret these results?
The correlation between the ASQ-4 gross motor and AEPS gross motor (skill: A. Movement and Locomotion) is -0.17 (makes no sense to me)
The correlation between the ASQ-4 gross motor and AEPS gross motor (skill: B. Balance in Sitting) is -0.06 (makes no sense to me)
The correlation between the ASQ-4 gross motor and AEPS gross motor (skill: C. Balance & Mobility) is 0.03 (makes no sense to me)
The correlation between the ASQ-4 gross motor and AEPS gross motor (skill: D. Play Skills) is 0.04 (makes no sense to me)

15.6 ASQ Personal-Social AEPS adaptive

**Jane: Just to refresh my memory. In the dataset, PS means problem-solving and P means Personal and Social, right?
Correlation between ASQ Personal-Social and AEPS Adaptive I’m using the data from same children.

How to interpret these results?
The correlation between the ASQ-4 Personal and Social and AEPS Adaptive (skill: A. Feeding) is 0.34 (makes sense!!)
The correlation between the ASQ-4 Personal and Social and AEPS Adaptive (skill: B. Personal Hygiene) is 0.27 (makes sense!!)
The correlation between the ASQ-4 Personal and Social and AEPS Adaptive (skill: C. Undressing) is 0.30 (makes sense!!)

end of report

LS0tDQp0aXRsZTogIkRpYW5lIC0gQUVQUyAmIEFTUS00Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiB1bml0ZWQNCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7ciBnbG9iYWwgb3B0aW9ucywgaW5jbHVkZSA9IEZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlcyA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gImhpZGUiKQ0KYGBgDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXN1Y2Nlc3MiPg0KKipEaWFuZSwgSmFuZSwgYW5kIEtpbWJlcmx5LiAqKiAgIA0KRXZlcnl0aGluZyBiZWZvcmUgYDE1IC0gYW5hbHlzaXNgIGlzIGEgc3ludGF4IHRvIG1hdGNoIGFsbCBjaGlsZHJlbi4gICANCkkga25vdyBlcnJvcnMgaGFwcGVuIGFsbCB0aGUgdGltZS4gVGhlcmVmb3JlLCB0aGVzZSBjb2RlcyB3ZXJlIG1hZGUgYXZhaWxhYmxlIGhlcmUgaWYgc29tZW9uZSB3YW50cyB0byByZXZpZXcgb3IgY2hlY2sgdGhlIGNvbnNpc3RlbmN5LiAgIA0KSW4gdGhlIGUtbWFpbCB0aGF0IHlvdSBmb3VuZCB0aGlzIGxpbmssIEkgYXR0YWNoZWQgYW4gZXhjZWwgZmlsZSBpbiB3aGljaCB5b3UnbGwgYmUgYWJsZSB0byBjaGVjayB0aGlzIGZpbGUuICAgDQoNCioqUGxlYXNlIG5vdGljZSB0aGF0IHRoaXMgcmVwb3J0IHJlZmVycyB0byBiaXJ0aCB0byB0aHJlZSBvbmx5KiogICAgIA0KKipJZiB5b3UgZG9uJ3Qgd2FudCB0byBjaGVjayBhbnkgY29kZSwgcGxlYXNlIGNsaWNrIFtoZXJlXSgjYW5hbHlzZXMpKioNCjwvZGl2Pg0KDQoNCiMgbG9hZCBwYWNrYWdlDQpgYGB7cn0NCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwgamFuaXRvcikNCmBgYA0KDQojIERhdGEgaGFuZGxpbmcNCg0KIyBnZXQgYWxsIEFTUTQgZGF0YQ0KDQpgYGB7cn0NCnJlYWRfZXhjZWxfYWxsc2hlZXRzIDwtIGZ1bmN0aW9uKGZpbGVuYW1lKSB7DQogICAgc2hlZXRzIDwtIHJlYWR4bDo6ZXhjZWxfc2hlZXRzKGZpbGVuYW1lKSAjZ2V0IGFsbCBzaGVldCBuYW1lcw0KICAgIHggPC0gbGFwcGx5KHNoZWV0cywgZnVuY3Rpb24oWCkgcmVhZHhsOjpyZWFkX2V4Y2VsKGZpbGVuYW1lLCBzaGVldCA9IFgpKQ0KICAgIG5hbWVzKHgpIDwtIHNoZWV0cyAjZ2V0IG5hbWVzIG9ubHkNCiAgICB4ICNyZXR1cm4NCn0NCiNnZXQgdGhlIGV4Y2VsIGZpbGUNCmV4Y2VsX2xpc3QgPC0gcmVhZF9leGNlbF9hbGxzaGVldHMoIkM6L1VzZXJzL2x1aXNmL0Ryb3Bib3gvQVNRNF9BRVBTIERhdGEgZm9yIEx1aXMgMi4yMDIxL0x1aXMgRmViIDIwMjEvRmluYWwgQUxMIEFTUTQgZm9yIEFFUFMgMjAxOV8yMDIwLnhsc3giKQ0KI3RyYW5zZm9ybSBpbnRvIHZlY3RvcnMNCmxpc3QyZW52KHNldE5hbWVzKGV4Y2VsX2xpc3QsICNsaXN0DQogICAgICAgICAgICAgICAgICBwYXN0ZTAoImRzXyIsamFuaXRvcjo6bWFrZV9jbGVhbl9uYW1lcyhuYW1lcyhleGNlbF9saXN0KSkpKSwgICNmaXhpbmcgZGlmZmVyZW50IG5hbWVzIGFuZCBvdGhlciBwYXR0ZXJucw0KICAgICAgICAgZW52aXI9Lkdsb2JhbEVudikgI3doZXJlPw0KYGBgDQoNCiMgQ3JlYXRlIGEgYmFja3VwDQoNCmBgYHtyfQ0KYmFja3VwX2FzcTRfZGVtbyA8LSBkc19hc3E0X2RlbW8gDQpiYWNrdXBfYXNxNF9pdGVtcyA8LSBkc19hc3E0X2l0ZW1zDQpgYGANCg0KDQojcmVtb3ZlIGFsbCBhdHRyaWJ1dGVzIA0KDQpgYGB7cn0NCiNkc19hc3E0X2RlbW9bXSA8LSBsYXBwbHkoZHNfYXNxNF9kZW1vLCBmdW5jdGlvbih4KSB7IGF0dHJpYnV0ZXMoeCkgPC0gTlVMTDsgeCB9KQ0KI2JhY2t1cF9hc3E0X2l0ZW1zW10gPC0gbGFwcGx5KGJhY2t1cF9hc3E0X2l0ZW1zLCBmdW5jdGlvbih4KSB7IGF0dHJpYnV0ZXMoeCkgPC0gTlVMTDsgeCB9KQ0KYGBgDQoNCiMgY2xlYW4gbmFtZXMgDQoNCmBgYHtyfQ0KZHNfYXNxNF9kZW1vIDwtIGNsZWFuX25hbWVzKGRzX2FzcTRfZGVtbykNCmRzX2FzcTRfaXRlbXMgPC0gY2xlYW5fbmFtZXMoZHNfYXNxNF9pdGVtcykNCmBgYA0KDQojIG1lcmdlIGRhdGFzZXRzIA0KDQpgYGB7cn0NCmRzX2FzcSA8LSBsZWZ0X2pvaW4oZHNfYXNxNF9kZW1vLCBkc19hc3E0X2l0ZW1zLCBieSA9IGMoImFzcTRfaWQiKSkNCmBgYA0KDQojIENvbXB1dGUgdG90YWxzDQoNCiMjIENoYW5nZSB2YXJpYWJsZSBjb21wdXRhdGlvbmFsIGxldmVsIA0KDQpgYGB7cn0NCmRzX2FzcSA8LSBkc19hc3EgJT4lIA0KICBtdXRhdGVfYXQodmFycyhjMTpjNiwgZ20xOmdtNiwgZm0xOmZtNiwgcHMxOnBzNiwgcDE6cDYpLCB+YXMubnVtZXJpYyguKSkNCmBgYA0KDQojIyBDb21wdXRlIHRvdGFscyBmb3IgZWFjaCBBU1EtNCBkb21haW4NCmBgYHtyfQ0KZHNfYXNxPC1kc19hc3EgJT4lIA0KICBtdXRhdGUoY29tX3N1bSA9IHJvd1N1bXMoc2VsZWN0KC4sYzE6YzYpKSkgJT4lIA0KICBtdXRhdGUoZ21fc3VtID0gcm93U3VtcyhzZWxlY3QoLixnbTE6Z202KSkpICU+JSANCiAgbXV0YXRlKGZtX3N1bSA9IHJvd1N1bXMoc2VsZWN0KC4sZm0xOmZtNikpKSAlPiUgDQogIG11dGF0ZShwc19zdW0gPSByb3dTdW1zKHNlbGVjdCguLHBzMTpwczYpKSkgJT4lIA0KICBtdXRhdGUocGVyX3N1bSA9IHJvd1N1bXMoc2VsZWN0KC4scDE6cDYpKSkNCmBgYA0KDQoNCiMgQUVQUyBEZW1vZ3JhcGhpY3MNCg0KYGBge3J9DQphZXBzXzFfZGVtbyA8LSByZWFkeGw6OnJlYWRfZXhjZWwoIkM6L1VzZXJzL2x1aXNmL0Ryb3Bib3gvQVNRNF9BRVBTIERhdGEgZm9yIEx1aXMgMi4yMDIxL0x1aXMgRmViIDIwMjEvY29weSBLTSBDbGVhbmVkIEFFUFMgMy41LjIxLzEuQ2xlYW5lZCBBRVBTQmlydGhUb1RocmVlRm9ybU5vTiAyIEdyYWNlIDkuMTMuMjAxOS54bHN4Iiwgc2hlZXQgPSAyKQ0KYGBgDQoNCmBgYHtyfQ0KI2ZpeCBuYW1lcw0KYWVwc18xX2RlbW8gPC0gY2xlYW5fbmFtZXMoYWVwc18xX2RlbW8pDQojcmVtb3ZlIGVtcHR5IGNvbHVtbnMgYW5kIHJvd3MNCmFlcHNfMV9kZW1vIDwtIHJlbW92ZV9lbXB0eShhZXBzXzFfZGVtbywgd2hpY2ggPSBjKCJyb3dzIiwgImNvbHMiKSwgcXVpZXQgPSBUUlVFKQ0KI3JlbW92ZSB1c2VsZXNzIHJvd3MNCmFlcHNfMV9kZW1vIDwtIGFlcHNfMV9kZW1vICU+JSBmaWx0ZXIoIWlzLm5hKGNoaWxkc19pZCkpDQoNCiNhZGQgbmV3IGZlYXR1cmVzIHRvIG1lcmdlDQphZXBzXzFfZGVtbyA8LSBhZXBzXzFfZGVtbyAlPiUgDQogIG11dGF0ZShhZXBzX2ZpbGVfbnVtYmVyID0gMSkgJT4lICNzYW1lIGFzIGRzX2FzcQ0KICBtdXRhdGUoc3ByZWFkX3NoZWV0ID0gc3ByZWFkX3NoZWV0X2lkXzEpICU+JSAjc2FtZSBhcyBmdWxsIGRhdGFzZXQhDQogIG11dGF0ZShhZXBzX3NwcmRzaGVldF9pZF9udW1iZXIgPSBzcHJlYWRfc2hlZXRfaWRfMSkgI3NhbWUgYXMgZHNfYXNxDQpgYGANCg0KDQoNCiMgMS5BRVBTQmlydGhUb1RocmVlRm9ybU5vTiAyIEdyYWNlIDkuMTMuMjAxOQ0KDQojIEZpcnN0IGZpbGUgMSAtIEZpbmUgbW90b3IgKDEpDQoNCiMjIGdldCBkYXRhDQoNCmBgYHtyfQ0KYWVwc18xX2ZpbmUgPC0gcmVhZHhsOjpyZWFkX2V4Y2VsKCJDOi9Vc2Vycy9sdWlzZi9Ecm9wYm94L0FTUTRfQUVQUyBEYXRhIGZvciBMdWlzIDIuMjAyMS9MdWlzIEZlYiAyMDIxL2NvcHkgS00gQ2xlYW5lZCBBRVBTIDMuNS4yMS8xLkNsZWFuZWQgQUVQU0JpcnRoVG9UaHJlZUZvcm1Ob04gMiBHcmFjZSA5LjEzLjIwMTkueGxzeCIsIHNoZWV0ID0gMykNCmBgYA0KYGBge3J9DQojY2xlYXIgZXhjZWwgYXR0cmlidXRlcw0KYWVwc18xX2ZpbmVbXSA8LSBsYXBwbHkoYWVwc18xX2ZpbmUsIGZ1bmN0aW9uKHgpIHsgYXR0cmlidXRlcyh4KSA8LSBOVUxMOyB4IH0pDQojZml4IG5hbWVzDQphZXBzXzFfZmluZSA8LSBjbGVhbl9uYW1lcyhhZXBzXzFfZmluZSkNCiNyZW1vdmUgZW1wdHkgY29sdW1ucyBhbmQgcm93cw0KYWVwc18xX2ZpbmUgPC0gcmVtb3ZlX2VtcHR5KGFlcHNfMV9maW5lLCB3aGljaCA9IGMoInJvd3MiLCAiY29scyIpLCBxdWlldCA9IFRSVUUpDQojY3JlYXRlIGEgc2tpbGwNCmFlcHNfMV9maW5lIDwtIGFlcHNfMV9maW5lICU+JSANCiAgbXV0YXRlKHNraWxsID0gLltbMV1dKSAlPiUgI3RoaXMgaXMgdGhlIGZpcnN0IGNvbHVtbiApaW4gdGhpcyBjYXNlIC0tIGZpbmUgbW90b3IgKHN1Yilkb21haW4NCiAgc2VsZWN0KDEsc2tpbGwsIGV2ZXJ5dGhpbmcoKSkNCiNXaXRoIHRoaXMgbmV3IHZhcmlhYmxlIChza2lsbCksIGp1c3Qga2VlcCBpZiBpcyBhIGxldHRlcg0KYWVwc18xX2ZpbmUgPC0gYWVwc18xX2ZpbmUgJT4lIA0KICBtdXRhdGUoc2tpbGwgPSBpZl9lbHNlKHN0cl9kZXRlY3Qoc2tpbGwsICJbYS16XSIpLCAuW1sxXV0sICBOQV9jaGFyYWN0ZXJfKSkgJT4lICNpZiBza2lsbCBpcyBhIGxldHRlciwgb3RoZXJ3aXNlIG1pc3NpbmcNCiAgZmlsbChza2lsbCkNCiNyZW1vdmUgZmlyc3QgbGluZSAoaXQncyBhbG1vc3QgYWxsIG5hKQ0KYWVwc18xX2ZpbmUgPC0gYWVwc18xX2ZpbmUgJT4lIA0KICBmaWx0ZXIoIXN0cl9kZXRlY3QoLltbMV1dLCAiW2Etel0iKSkNCiN0cmFuc2Zvcm0gdG8gbnVtZXJpYw0KYWVwc18xX2ZpbmUgPC0gYWVwc18xX2ZpbmUgJT4lIG11dGF0ZSghISBuYW1lcyguKVsxXSA6PSBhcy5udW1lcmljKCEhIHJsYW5nOjpzeW0obmFtZXMoLilbMV0pKSkgDQojYWVwc18xX2ZpbmVbWzFdXSA8LSBhcy5udW1lcmljKGFlcHNfMV9maW5lW1sxXV0pDQpgYGANCg0KDQojIyBUcmFuZm9ybSBpdCB0byBsb25nIGZvcm1hdA0KDQpgYGB7cn0NCnNwZWMgPC0gdGliYmxlKGAubmFtZWAgPSBuYW1lcyhhZXBzXzFfZmluZSkpICU+JQ0KICBzbGljZSgtYygxOjIpKSAlPiUNCiAgbXV0YXRlKGAudmFsdWVgID0gY2FzZV93aGVuKA0KICAgICAgICAgICBgLm5hbWVgICU+JSBzdHJfZGV0ZWN0KCJzcHJlYWQiKSB+ICJzcHJlYWRfc2hlZXQiLA0KICAgICAgICAgICBgLm5hbWVgICU+JSBzdHJfZGV0ZWN0KCJzY29yZSIpICB+ICJzY29yZSIsDQogICAgICAgICAgIGAubmFtZWAgJT4lIHN0cl9kZXRlY3QoImNvbmZpcm0iKSB+ICJjb25maXJtIikNCiAgKQ0KIyBhcHBseSB0aGUgc3BlYw0KYWVwc18xX2ZpbmVfbG9uZyA8LSBhZXBzXzFfZmluZSAlPiUNCiAgcGl2b3RfbG9uZ2VyX3NwZWMoc3BlYykNCmBgYA0KDQojIyBBZGQgZG9tYWluDQoNClRoaXMgY2h1bmsgd2lsbCBnZXQgYWxsIGRvbWFpbnMgYW5kIG51bWJlciBza2lsbHMuIEl0IHdpbGwgYmUgdXNlZnVsIHRvIG1lcmdlIGFsbCBkcyBpbiB0aGUgZnV0dXJlLiAgDQoNCmBgYHtyfQ0KYWVwc18xX2ZpbmVfbG9uZyA8LSBhZXBzXzFfZmluZV9sb25nICU+JSANCiAgbXV0YXRlKGRvbWFpbiA9IG5hbWVzKC4pW1sxXV0pICU+JSANCiAgcmVuYW1lKG51bWJlcl9za2lsbCA9IG5hbWVzKC4pW1sxXV0pICU+JSANCiAgc2VsZWN0KGRvbWFpbiwgbnVtYmVyX3NraWxsLCBldmVyeXRoaW5nKCkpDQpgYGANCg0KDQojIEZpcnN0IGZpbGUgMSAtIEdyb3NzIG1vdG9yICgyKQ0KDQojIyBnZXQgZGF0YQ0KDQpgYGB7cn0NCmFlcHNfMV9ncm9zcyA8LSByZWFkeGw6OnJlYWRfZXhjZWwoIkM6L1VzZXJzL2x1aXNmL0Ryb3Bib3gvQVNRNF9BRVBTIERhdGEgZm9yIEx1aXMgMi4yMDIxL0x1aXMgRmViIDIwMjEvY29weSBLTSBDbGVhbmVkIEFFUFMgMy41LjIxLzEuQ2xlYW5lZCBBRVBTQmlydGhUb1RocmVlRm9ybU5vTiAyIEdyYWNlIDkuMTMuMjAxOS54bHN4Iiwgc2hlZXQgPSA0KQ0KYGBgDQpgYGB7cn0NCiNjbGVhciBleGNlbCBhdHRyaWJ1dGVzDQphZXBzXzFfZ3Jvc3NbXSA8LSBsYXBwbHkoYWVwc18xX2dyb3NzLCBmdW5jdGlvbih4KSB7IGF0dHJpYnV0ZXMoeCkgPC0gTlVMTDsgeCB9KQ0KI2ZpeCBuYW1lcw0KYWVwc18xX2dyb3NzIDwtIGNsZWFuX25hbWVzKGFlcHNfMV9ncm9zcykNCiNyZW1vdmUgZW1wdHkgY29sdW1ucyBhbmQgcm93cw0KYWVwc18xX2dyb3NzIDwtIHJlbW92ZV9lbXB0eShhZXBzXzFfZ3Jvc3MsIHdoaWNoID0gYygicm93cyIsICJjb2xzIiksIHF1aWV0ID0gVFJVRSkNCiNjcmVhdGUgYSBza2lsbA0KYWVwc18xX2dyb3NzIDwtIGFlcHNfMV9ncm9zcyAlPiUgDQogIG11dGF0ZShza2lsbCA9IC5bWzFdXSkgJT4lICN0aGlzIGlzIHRoZSBmaXJzdCBjb2x1bW4gKWluIHRoaXMgY2FzZSAtLSBmaW5lIG1vdG9yIChzdWIpZG9tYWluDQogIHNlbGVjdCgxLHNraWxsLCBldmVyeXRoaW5nKCkpDQojV2l0aCB0aGlzIG5ldyB2YXJpYWJsZSAoc2tpbGwpLCBqdXN0IGtlZXAgaWYgaXMgYSBsZXR0ZXINCmFlcHNfMV9ncm9zcyA8LSBhZXBzXzFfZ3Jvc3MgJT4lIA0KICBtdXRhdGUoc2tpbGwgPSBpZl9lbHNlKHN0cl9kZXRlY3Qoc2tpbGwsICJbYS16XSIpLCAuW1sxXV0sICBOQV9jaGFyYWN0ZXJfKSkgJT4lICNpZiBza2lsbCBpcyBhIGxldHRlciwgb3RoZXJ3aXNlIG1pc3NpbmcNCiAgZmlsbChza2lsbCkNCiNyZW1vdmUgZmlyc3QgbGluZSAoaXQncyBhbG1vc3QgYWxsIG5hKQ0KYWVwc18xX2dyb3NzIDwtIGFlcHNfMV9ncm9zcyAlPiUgDQogIGZpbHRlcighc3RyX2RldGVjdCguW1sxXV0sICJbYS16XSIpKQ0KI3RyYW5zZm9ybSB0byBudW1lcmljDQphZXBzXzFfZ3Jvc3MgPC0gYWVwc18xX2dyb3NzICU+JSBtdXRhdGUoISEgbmFtZXMoLilbMV0gOj0gYXMubnVtZXJpYyghISBybGFuZzo6c3ltKG5hbWVzKC4pWzFdKSkpIA0KI2FlcHNfMV9ncm9zc1tbMV1dIDwtIGFzLm51bWVyaWMoYWVwc18xX2dyb3NzW1sxXV0pDQpgYGANCg0KDQojIyBUcmFuZm9ybSBpdCB0byBsb25nIGZvcm1hdA0KDQpgYGB7cn0NCnNwZWMgPC0gdGliYmxlKGAubmFtZWAgPSBuYW1lcyhhZXBzXzFfZ3Jvc3MpKSAlPiUNCiAgc2xpY2UoLWMoMToyKSkgJT4lDQogIG11dGF0ZShgLnZhbHVlYCA9IGNhc2Vfd2hlbigNCiAgICBgLm5hbWVgICU+JSBzdHJfZGV0ZWN0KCJzcHJlYWQiKSB+ICJzcHJlYWRfc2hlZXQiLA0KICAgIGAubmFtZWAgJT4lIHN0cl9kZXRlY3QoInNjb3JlIikgIH4gInNjb3JlIiwNCiAgICBgLm5hbWVgICU+JSBzdHJfZGV0ZWN0KCJjb25maXJtIikgfiAiY29uZmlybSIpDQogICkNCiMgYXBwbHkgdGhlIHNwZWMNCmFlcHNfMV9ncm9zc19sb25nIDwtIGFlcHNfMV9ncm9zcyAlPiUNCiAgcGl2b3RfbG9uZ2VyX3NwZWMoc3BlYykNCmBgYA0KDQojIyBBZGQgZG9tYWluDQoNClRoaXMgY2h1bmsgd2lsbCBnZXQgYWxsIGRvbWFpbnMgYW5kIG51bWJlciBza2lsbHMuIEl0IHdpbGwgYmUgdXNlZnVsIHRvIG1lcmdlIGFsbCBkcyBpbiB0aGUgZnV0dXJlLiAgDQoNCmBgYHtyfQ0KYWVwc18xX2dyb3NzX2xvbmcgPC0gYWVwc18xX2dyb3NzX2xvbmcgJT4lIA0KICBtdXRhdGUoZG9tYWluID0gbmFtZXMoLilbWzFdXSkgJT4lIA0KICByZW5hbWUobnVtYmVyX3NraWxsID0gbmFtZXMoLilbWzFdXSkgJT4lIA0KICBzZWxlY3QoZG9tYWluLCBudW1iZXJfc2tpbGwsIGV2ZXJ5dGhpbmcoKSkNCmBgYA0KDQoNCg0KIyBGaXJzdCBmaWxlIDEgLSBBZGFwdGl2ZSAoMykNCg0KIyMgZ2V0IGRhdGENCg0KYGBge3J9DQphZXBzXzFfYWRhcHRpdmUgPC0gcmVhZHhsOjpyZWFkX2V4Y2VsKCJDOi9Vc2Vycy9sdWlzZi9Ecm9wYm94L0FTUTRfQUVQUyBEYXRhIGZvciBMdWlzIDIuMjAyMS9MdWlzIEZlYiAyMDIxL2NvcHkgS00gQ2xlYW5lZCBBRVBTIDMuNS4yMS8xLkNsZWFuZWQgQUVQU0JpcnRoVG9UaHJlZUZvcm1Ob04gMiBHcmFjZSA5LjEzLjIwMTkueGxzeCIsIHNoZWV0ID0gNSkNCmBgYA0KDQpgYGB7cn0NCiNjbGVhciBleGNlbCBhdHRyaWJ1dGVzDQphZXBzXzFfYWRhcHRpdmVbXSA8LSBsYXBwbHkoYWVwc18xX2FkYXB0aXZlLCBmdW5jdGlvbih4KSB7IGF0dHJpYnV0ZXMoeCkgPC0gTlVMTDsgeCB9KQ0KI2ZpeCBuYW1lcw0KYWVwc18xX2FkYXB0aXZlIDwtIGNsZWFuX25hbWVzKGFlcHNfMV9hZGFwdGl2ZSkNCiNyZW1vdmUgZW1wdHkgY29sdW1ucyBhbmQgcm93cw0KYWVwc18xX2FkYXB0aXZlIDwtIHJlbW92ZV9lbXB0eShhZXBzXzFfYWRhcHRpdmUsIHdoaWNoID0gYygicm93cyIsICJjb2xzIiksIHF1aWV0ID0gVFJVRSkNCiNjcmVhdGUgYSBza2lsbA0KYWVwc18xX2FkYXB0aXZlIDwtIGFlcHNfMV9hZGFwdGl2ZSAlPiUgDQogIG11dGF0ZShza2lsbCA9IC5bWzFdXSkgJT4lICN0aGlzIGlzIHRoZSBmaXJzdCBjb2x1bW4gKWluIHRoaXMgY2FzZSAtLSBmaW5lIG1vdG9yIChzdWIpZG9tYWluDQogIHNlbGVjdCgxLHNraWxsLCBldmVyeXRoaW5nKCkpDQojV2l0aCB0aGlzIG5ldyB2YXJpYWJsZSAoc2tpbGwpLCBqdXN0IGtlZXAgaWYgaXMgYSBsZXR0ZXINCmFlcHNfMV9hZGFwdGl2ZSA8LSBhZXBzXzFfYWRhcHRpdmUgJT4lIA0KICBtdXRhdGUoc2tpbGwgPSBpZl9lbHNlKHN0cl9kZXRlY3Qoc2tpbGwsICJbYS16XSIpLCAuW1sxXV0sICBOQV9jaGFyYWN0ZXJfKSkgJT4lICNpZiBza2lsbCBpcyBhIGxldHRlciwgb3RoZXJ3aXNlIG1pc3NpbmcNCiAgZmlsbChza2lsbCkNCiNyZW1vdmUgZmlyc3QgbGluZSAoaXQncyBhbG1vc3QgYWxsIG5hKQ0KYWVwc18xX2FkYXB0aXZlIDwtIGFlcHNfMV9hZGFwdGl2ZSAlPiUgDQogIGZpbHRlcighc3RyX2RldGVjdCguW1sxXV0sICJbYS16XSIpKQ0KI3RyYW5zZm9ybSB0byBudW1lcmljDQphZXBzXzFfYWRhcHRpdmUgPC0gYWVwc18xX2FkYXB0aXZlICU+JSBtdXRhdGUoISEgbmFtZXMoLilbMV0gOj0gYXMubnVtZXJpYyghISBybGFuZzo6c3ltKG5hbWVzKC4pWzFdKSkpIA0KI2FlcHNfMV9hZGFwdGl2ZVtbMV1dIDwtIGFzLm51bWVyaWMoYWVwc18xX2FkYXB0aXZlW1sxXV0pDQpgYGANCg0KDQojIyBUcmFuZm9ybSBpdCB0byBsb25nIGZvcm1hdA0KDQpgYGB7cn0NCnNwZWMgPC0gdGliYmxlKGAubmFtZWAgPSBuYW1lcyhhZXBzXzFfYWRhcHRpdmUpKSAlPiUNCiAgc2xpY2UoLWMoMToyKSkgJT4lDQogIG11dGF0ZShgLnZhbHVlYCA9IGNhc2Vfd2hlbigNCiAgICBgLm5hbWVgICU+JSBzdHJfZGV0ZWN0KCJzcHJlYWQiKSB+ICJzcHJlYWRfc2hlZXQiLA0KICAgIGAubmFtZWAgJT4lIHN0cl9kZXRlY3QoInNjb3JlIikgIH4gInNjb3JlIiwNCiAgICBgLm5hbWVgICU+JSBzdHJfZGV0ZWN0KCJjb25maXJtIikgfiAiY29uZmlybSIpDQogICkNCiMgYXBwbHkgdGhlIHNwZWMNCmFlcHNfMV9hZGFwdGl2ZV9sb25nIDwtIGFlcHNfMV9hZGFwdGl2ZSAlPiUNCiAgcGl2b3RfbG9uZ2VyX3NwZWMoc3BlYykNCmBgYA0KDQojIyBBZGQgZG9tYWluDQoNClRoaXMgY2h1bmsgd2lsbCBnZXQgYWxsIGRvbWFpbnMgYW5kIG51bWJlciBza2lsbHMuIEl0IHdpbGwgYmUgdXNlZnVsIHRvIG1lcmdlIGFsbCBkcyBpbiB0aGUgZnV0dXJlLiAgDQoNCmBgYHtyfQ0KYWVwc18xX2FkYXB0aXZlX2xvbmcgPC0gYWVwc18xX2FkYXB0aXZlX2xvbmcgJT4lIA0KICBtdXRhdGUoZG9tYWluID0gbmFtZXMoLilbWzFdXSkgJT4lIA0KICByZW5hbWUobnVtYmVyX3NraWxsID0gbmFtZXMoLilbWzFdXSkgJT4lIA0KICBzZWxlY3QoZG9tYWluLCBudW1iZXJfc2tpbGwsIGV2ZXJ5dGhpbmcoKSkNCmBgYA0KDQoNCiMgTWVyZ2UgQUVQUyBzcHJlYWRzaGVldHMgZGF0YXNldHMNCg0KSnVzdCBjaGVja2luZyBpZiB3ZSBoYXZlIDIyIGNoaWxkcmVuIGluIGVhY2ggZGF0YXNldCAgDQpgYGB7cn0NCmFlcHNfMV9maW5lX2xvbmcgJT4lIGNvdW50KHNwcmVhZF9zaGVldCkNCmFlcHNfMV9ncm9zc19sb25nICU+JSBjb3VudChzcHJlYWRfc2hlZXQpDQphZXBzXzFfYWRhcHRpdmVfbG9uZyAlPiUgY291bnQoc3ByZWFkX3NoZWV0KQ0KYGBgDQoNCkknbGwgdXNlIGBiaW5kX3Jvd3NgIHRvIHB1dCBlYWNoIGRhdGFzZXQgb24gdG9wIG9mIHRoZSBhbm90aGVyLiANCkZpcnN0LCBmaW5lIGxvbmcgd2l0aCBncm9zcyBsb25nDQoNCg0KYGBge3J9DQpkc19hZXBzX2JpcnRoX3RocmVlIDwtIGJpbmRfcm93cygNCiAgYWVwc18xX2ZpbmVfbG9uZywNCiAgYWVwc18xX2dyb3NzX2xvbmcpDQpgYGANCg0KTm93LCB0aGlzIHJlc3VsdGFudCBkcyB3aXRoIGFkYXB0aXZlDQoNCmBgYHtyfQ0KZHNfYWVwc19iaXJ0aF90aHJlZSA8LSBiaW5kX3Jvd3MoDQogIGRzX2FlcHNfYmlydGhfdGhyZWUsDQogIGFlcHNfMV9hZGFwdGl2ZV9sb25nKQ0KYGBgDQoNCg0KIyBNZXJnZSBBRVBTIHdpdGggQUVQUyBkZW1vZ3JhcGhpY3MNCg0KSSdsbCBnZXQgYGFlcHNfMV9kZW1vYCB0byBhZGQgdG8gdGhpcyBwYXJ0aWFsbHkgZnVsbCBkYXRhc2V0IHRoZSBjaGlsZCcgSUQNCg0KYGBge3J9DQpkc19hZXBzX2JpcnRoX3RocmVlIDwtIGxlZnRfam9pbihkc19hZXBzX2JpcnRoX3RocmVlLCBhZXBzXzFfZGVtbykNCmBgYA0KDQpGaXJzdCwgaSdsbCBhZGQgdHdvIGtleSB2YXJpYWJsZXMgcHJlc2VudCBpbiB0aGUgQVNRLTQgZGF0YXNldCB0byBndWFyYW50ZWUgdGhlIG1lcmdpbmcgd2lsbCBiZSBjb3JyZWN0DQoNCmBgYHtyfQ0KZHNfYWVwc19iaXJ0aF90aHJlZSA8LSBkc19hZXBzX2JpcnRoX3RocmVlICU+JSANCiAgbXV0YXRlKGFlcHNfZmlsZV9udW1iZXIgPSAxKSAlPiUgDQogIG11dGF0ZShhZXBzX3NwcmRzaGVldF9pZF9udW1iZXIgPSBzcHJlYWRfc2hlZXQpICU+JSANCiAgcmVuYW1lKGFzcTRfaWQgPSBjaGlsZHNfaWQpICU+JSANCiAgbXV0YXRlKGFzcTRfaWQgPSBhcy5udW1lcmljKGFzcTRfaWQpKSAjaW4gQVNRNCBkYXRhc2V0LCB0aGlzIHZhcmlhYmxlIGlzIG51bWVyaWMNCmBgYA0KDQoNCkNyZWF0ZSBhIGZ1bGwgZGF0YXNldCB3aXRoIEFTUS00IGFuZCBBRVBTDQoNCmBgYHtyfQ0KZHNfYmlydGhfdGhyZWVfYWVwc19hc3EgPC0gbGVmdF9qb2luKA0KICBkc19hZXBzX2JpcnRoX3RocmVlLA0KICBkc19hc3EsDQogIGJ5ID0gImFzcTRfaWQiDQopDQpgYGANCg0KDQojIyBNYW51YWwgY2hlY2sNCg0KYGBge3J9DQpkc19iaXJ0aF90aHJlZV9hZXBzX2FzcSAlPiUgDQogIGZpbHRlcihzcHJlYWRfc2hlZXQgPT0gIjE1IikgJT4lIFZpZXcoKQ0KYGBgDQoNCg0KIyMgU2F2ZSBhcyBleGNlbA0KDQpgYGB7cn0NCndyaXRlLmNzdihkc19iaXJ0aF90aHJlZV9hZXBzX2FzcSwgZmlsZSA9ICJkc19iaXJ0aF90aHJlZV9hZXBzX2FzcS5jc3YiLCByb3cubmFtZXMgPSBGKQ0KYGBgDQoNCg0KPiBJdCBzZWVtcyBldmVyeXRoaW5nIHdvcmtlZCEgKFNhdHVyZGF5LCAxMyBNYXJjaCwgMjAyMSkgIA0KQXNrIEtpbWJlcmx5DQoNCiMgQW5hbHlzZXMgLSBiaXJ0aCB0byB0aHJlZSB7I2FuYWx5c2VzfQ0KDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LXN1Y2Nlc3MiPg0KRGlhbmUsIEphbmUsIGFuZCBLaW1iZXJseS4gDQpGcm9tIHRoaXMgbGluZSBvbiwgSSB3aWxsOiAgICANCioqKDEpKiogUHJlc2VudCBhIHBsb3QgYW5kIGEgdGFibGUgd2l0aCB0aGUgQVNRLTQgc3VtbWF0aXZlIHJlc3VsdHMgICANCioqKDIpKiogUHJlc2VudCBhIHBsb3QgYW5kIGEgdGFibGUgd2l0aCB0aGUgIEFFUFMgc3VtbWF0aXZlIHJlc3VsdHMgKEkgcmVhZCBlbHNld2hlcmUgYW5kIGl0IHNlZW1zIHRoYXQgQUVQUyBpdGVtcyBuZWVkIHRvIGJlIHN1bW1lZCBhcyB3ZWxsKSAgIA0KKiooMykqKiBSdW4gYWxsIGNvcnJlbGF0aW9uIGFuYWx5c2VzIGJldHdlZW4gdGhlIEFTUS00IHN1bW1hdGl2ZSBzY29yZXMgYW5kIHRoZSBBRVBTIHN1bW1hdGl2ZSBzY29yZXMgICANCg0KWW91J2xsIG5vdGljZSB0aGF0IHRoZSBjb3JyZWxhdGlvbiByZXN1bHRzIGFyZSB0b28gbG93LiBJJ20gd29uZGVyaW5nIGlmIHNvbWV0aGluZyB3YXMgdW5kZXIgdGhlIHJhZGFyIGluIG15IGNvZGUgb3IgaWYgSSdtIG1pc3Npbmcgc29tZSBwb2ludC4gIA0KSSBoYXZlIHNlbnQgYW4gZS1tYWlsIGluIHdoaWNoIEkgcHJlc2VudCBhbiBleGNlbCBmaWxlIHRvIG1ha2Ugc29tZSBwb2ludHMgY2xlYXJlci4NCjwvZGl2Pg0KDQoNCiMjIEFTUS00IGFuYWx5c2lzDQoNCiMjIyBQbG90IA0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NClRoZSBncmFwaCBiZWxvdyBkZXNjcmliZXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhbGwgQVNRNCByZXN1bHRzLg0KPC9kaXY+DQoNCmBgYHtyfQ0KZHNfYmlydGhfdGhyZWVfYWVwc19hc3EgJT4lDQogIHNlbGVjdChhc3E0X2lkLCBldmVyeXRoaW5nKCkpICU+JSAjanVzdCBmb3IgY2hlY2tpbmcNCiAgZGlzdGluY3QoYXNxNF9pZCwgLmtlZXBfYWxsID0gVCkgJT4lICN1c2Ugb25seSBvbmUgaW5mb3JtYXRpb24gKHdlIGhhdmUgMjIgY2hpbGRyZW4gaGVyZSkNCiAgc2VsZWN0KGVuZHNfd2l0aCgiX3N1bSIpKSAlPiUgDQogIGphbml0b3I6OnJlbW92ZV9lbXB0eSgiY29scyIpICU+JSAjcmVtb3ZlIGVtcHR5IGNvbHVtbnMNCiAgcGl2b3RfbG9uZ2VyKGV2ZXJ5dGhpbmcoLikpICU+JSANCiAgZ2dwbG90KC4sIGFlcyhuYW1lLCB2YWx1ZSkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICB0aGVtZV9idygpDQpgYGANCiMjIyBTdW1tYXJ5IHRhYmxlICANCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQpUaGUgdGFibGUgYmVsb3cgcmVwb3J0cyB0aGUgQVNRLTQgcmVzdWx0cy4gSSBkaWQgbm90IGdyb3VwIHRoZSByZXN1bHRzIGJ5IGFnZSBpbnRlcnZhbC4gICAgICANCjwvZGl2Pg0KDQpgYGB7ciwgcmVzdWx0cyA9ICJhc2lzIn0NCmRzX2JpcnRoX3RocmVlX2FlcHNfYXNxICU+JQ0KICBzZWxlY3QoYXNxNF9pZCwgZXZlcnl0aGluZygpKSAlPiUgI2p1c3QgZm9yIGNoZWNraW5nDQogIGRpc3RpbmN0KGFzcTRfaWQsIC5rZWVwX2FsbCA9IFQpICU+JSAjdXNlIG9ubHkgb25lIGluZm9ybWF0aW9uICh3ZSBoYXZlIDIyIGNoaWxkcmVuIGhlcmUpDQogIHNlbGVjdChlbmRzX3dpdGgoIl9zdW0iKSkgJT4lIA0KICBqYW5pdG9yOjpyZW1vdmVfZW1wdHkoYygiY29scyIpKSAlPiUgI3JlbW92ZSBlbXB0eSBjb2x1bW5zDQogIHBpdm90X2xvbmdlcihldmVyeXRoaW5nKC4pKSAlPiUgDQogIGFyc2VuYWw6OnRhYmxlYnkobmFtZSB+IHZhbHVlLCAuKSAlPiUgDQogIHN1bW1hcnkoKQ0KYGBgDQoNCg0KDQojIyBBRVBTIGRvbWFpbnMgYW5kIHNraWxscw0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NClRoZSBmb2xsb3dpbmcgcmVzdWx0cyB3aWxsIHByZXNlbnQgdGhlIEFFUFMgZmluZGluZ3MuICAgDQo8L2Rpdj4NCg0KIyMjIERlc2NyaXB0aXZlIHRhYmxlICANCg0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NClRoZSBmb2xsb3dpbmcgdGFibGUgd2lsbCBwcmVzZW50IHRoZSBkZXNjcmlwdGl2ZXMgb2YgZWFjaCBwYXJ0aWNpcGFudCBhbmQgYWN0aXZpdGl5IA0KPC9kaXY+DQoNCg0KYGBge3J9DQpkc19iaXJ0aF90aHJlZV9hZXBzX2FzcSAlPiUgDQogIHNlbGVjdChhc3E0X2lkLCBldmVyeXRoaW5nKCkpICU+JSANCiAgZ3JvdXBfYnkoYXNxNF9pZCkgJT4lIA0KICBhcnJhbmdlKGFzcTRfaWQpICU+JSANCiAgY291bnQoZG9tYWluLCBza2lsbCkNCmBgYA0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCkhvdyB0byBpbnRlcnByZXQgdGhlc2UgcmVzdWx0cz8gICAgICANCkFTUTRpZCA9IDUwMCAoaXQncyBhIGNoaWxkIGluIHRoZSBkYXRhc2V0KQ0KSGUgb3IgU2hlIGhhcyAxOCByZXN1bHRzIGluIGRvbWFpbiBgYWRhcHRhdGl2ZWAgYW5kIHNraWxsID0gYEZlZWRpbmdgLiAgIA0KSWYgeW91IGFjY2VzcyB0aGUgZXhjZWwgZmlsZSwgaXQgd2lsbCBiZSB0aGVzZSBzYW1lIHZhbHVlcy4gIA0KPC9kaXY+DQoNCg0KDQojIyMgUGxvdCB0b3RhbCBzY29yZXMgIA0KDQo8ZGl2IGNsYXNzPSJhbGVydCBhbGVydC1pbmZvIj4NCklmIEkgdW5kZXJzdG9vZCBldmVyeXRoaW5nIHJpZ2h0IChJJ3ZlIGNvbnN1bHRlZCBodHRwczovL3B0LnNsaWRlc2hhcmUubmV0L0Jyb29rZXNQdWJDby9hZXBzLWludHJvLXdlYmluYXItc2xpZGVzaGFyZSksICAgIA0KZWFjaCBwYXJ0aWNpcGFudCBuZWVkcyB0byBoYXZlIGEgc2NvcmUgcmVmbGVjdGluZyBoaXMvaGVyIGFiaWxpdHkuICAgIA0KVGhlcmVmb3JlLCBJIHN1bW1lZCB1cCB0aGUgc2NvcmVzIG9idGFpbmVkIGluIGVhY2ggc2tpbGwgb2YgZWFjaCBkb21haW4gKGUuZy46IFJlYWNoLCBHcmFiLCBhbmQgUmVsZWFzZSBmcm9tIEZpbmUgbW90b3IpLiANCjwvZGl2Pg0KDQoNCmBgYHtyfQ0KZHNfYmlydGhfdGhyZWVfYWVwc19hc3EgJT4lIA0KICBncm91cF9ieShhc3E0X2lkLGRvbWFpbiwgc2tpbGwpICU+JSAgI2dyb3AgZm9yIGhhdmluZyBlYWNoIHNjb3JlIGZvciBlYWNoIHBhcnRpY2lwYW50DQogIHN1bW1hcmlzZShyYXdfc2NvcmUgPSBzdW0oc2NvcmUpKSAlPiUgI2NyZWF0ZSB0aGUgc3VtbWF0aXZlIHNjb3JlDQogIHNlbGVjdChhc3E0X2lkLGRvbWFpbiwgc2tpbGwsIHJhd19zY29yZSkgJT4lICNzZWxlY3QgYmVmb3JlIHBpdm90aW5nDQogICAgICBwaXZvdF9sb25nZXIoLWMoYXNxNF9pZCwgcmF3X3Njb3JlLCBza2lsbCksDQogICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImRvbWFpbiIpICU+JSANCiAgc2VsZWN0KC1uYW1lKSAlPiUgDQogIGdncGxvdCguLCBhZXMoeCA9IGRvbWFpbiwgeSA9IHJhd19zY29yZSwgZmlsbCA9IHNraWxsKSkgKw0KICAjZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZTIocHJlc2VydmUgPSAic2luZ2xlIikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJzdW1tYXJ5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCB3aWR0aCA9IDAuOCkgKw0KICB0aGVtZV9idygpDQogIA0KYGBgDQoNCiMjIyBTdW1tYXJ5IHRvdGFsIHNjb3JlcyANCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQpUaGUgZm9sbG93aW5nIHRhYmxlIHByZXNlbnRzIHRoZSBzYW1lIGluZm9ybWF0aW9uIHByZXNlbnRlZCBhYm92ZS4gSG93ZXZlciwgSSBpbWFnaW5lIHlvdSdsbCBiZSBhYmxlIHRvIGNoZWNrIGlmIGV2ZXJ5dGhpbmcgaXMgY29ycmVjdC4gICANCjwvZGl2Pg0KDQpgYGB7ciwgcmVzdWx0cyA9ICJhc2lzIn0NCmRzX2JpcnRoX3RocmVlX2FlcHNfYXNxICU+JSANCiAgZ3JvdXBfYnkoYXNxNF9pZCxkb21haW4sIHNraWxsKSAlPiUgICNncm9wIGZvciBoYXZpbmcgZWFjaCBzY29yZSBmb3IgZWFjaCBwYXJ0aWNpcGFudA0KICBzdW1tYXJpc2UocmF3X3Njb3JlID0gc3VtKHNjb3JlKSkgJT4lICNjcmVhdGUgdGhlIHN1bW1hdGl2ZSBzY29yZQ0KICBzZWxlY3QoYXNxNF9pZCxkb21haW4sIHNraWxsLCByYXdfc2NvcmUpICU+JSAjc2VsZWN0IGJlZm9yZSBwaXZvdGluZw0KICAgICAgcGl2b3RfbG9uZ2VyKC1jKGFzcTRfaWQsIHJhd19zY29yZSwgc2tpbGwpLA0KICAgICAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJkb21haW4iKSAlPiUgDQogIHNlbGVjdCgtbmFtZSkgJT4lIA0KICBncm91cF9ieShkb21haW4sIHNraWxsKSAlPiUgDQogIHN1bW1hcmlzZShtZWFuKHJhd19zY29yZSksIHNkKHJhd19zY29yZSksIG4oKSkgJT4lIA0KICBtdXRhdGVfaWYoaXMubnVtZXJpYyxyb3VuZCwyKQ0KYGBgDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQpIb3cgdG8gaW50ZXJwcmV0IHRoZXNlIHJlc3VsdHM/ICAgICAgDQpFeGFtcGxlOiAgIA0Kd2hlbiBjb25zaWRlcmluZyAqKmFsbCBjaGlsZHJlbioqIGluIGRvbWFpbiAoZmluZSBtb3RvciksIGFuZCBza2lsbCAoQS4gUmVhY2gsIEdyYWIsIFJlbGVhc2UpLCB0aGUgbWVhbiByZXN1bHQgaXMgMzQuODIgICANCkkgZG91YmxlIGNoZWNrZWQgdGhlIGV4Y2VsIGZpbGUgYW5kIHRoaXMgcmVzdWx0IGlzIGNvcnJlY3QgICANCjwvZGl2Pg0KDQoNCg0KIyMgQ29ycmVsYXRpb25zIEFFUFMgQVNRLTQgDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPg0KVGhlIGZvbGxvd2luZyB0YWJsZXMgd2lsbCBwcmVzZW50IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGVhY2ggQVNRLTQgZG9tYWluIGFuZCBpdHMgQUVQUyBwYXJhbGxlbC4gICANCkknbSB1c2luZyB0aGUgc3VtbWF0aXZlIHNjb3JlIG9mIHRoZSBBU1EtNCBhbmQgYWxzbyB0aGUgc3VtbWF0aXZlIHNjb3JlIG9mIEFFUFMuICBEaWFuZSwgcGxlYXNlIGxldCBtZSBrbm93IGlmIHRoYXQncyB0aGUgd2F5IHRvIGFjaGlldmUgdGhlIEFFUFMgcmVzdWx0cy4gICANCjwvZGl2Pg0KDQo+IFBsZWFzZSBkb24ndCBjb25zaWRlciB0aGUgdGhyZWUgZm9sbG93aW5nIGNodW5rcy4gVGhleSBhcmUgcHJvZ3JhbW1pbmcgc3ludGF4ZXMuICANCg0KIyMjIENyZWF0ZSBhIHN1bW1hdGl2ZSBzY29yZSAoQXNrIERpYW5lKQ0KDQpgYGB7cn0NCmNvcl9kc18xIDwtIGRzX2JpcnRoX3RocmVlX2FlcHNfYXNxICU+JSANCiAgZ3JvdXBfYnkoYXNxNF9pZCxkb21haW4sIHNraWxsKSAlPiUgICNncm9wIGZvciBoYXZpbmcgZWFjaCBzY29yZSBmb3IgZWFjaCBwYXJ0aWNpcGFudA0KICBzdW1tYXJpc2UocmF3X3Njb3JlID0gc3VtKHNjb3JlKSkNCmBgYA0KDQojIyMgQ3JlYXRlIGEgZGF0YWZyYW1lIHRvIGdhdGhlciBhbGwgZGF0YSANCg0KYGBge3J9DQpjb3JfZHNfMiA8LSBkc19iaXJ0aF90aHJlZV9hZXBzX2FzcSAlPiUNCiAgc2VsZWN0KGFzcTRfaWQsIGV2ZXJ5dGhpbmcoKSkgJT4lICNqdXN0IGZvciBjaGVja2luZw0KICBkaXN0aW5jdChhc3E0X2lkLCAua2VlcF9hbGwgPSBUKSAlPiUgI3VzZSBvbmx5IG9uZSBpbmZvcm1hdGlvbiAod2UgaGF2ZSAyMiBjaGlsZHJlbiBoZXJlKQ0KICBzZWxlY3QoYXNxNF9pZCxlbmRzX3dpdGgoIl9zdW0iKSkgJT4lIA0KICBqYW5pdG9yOjpyZW1vdmVfZW1wdHkoImNvbHMiKSAlPiUgI3JlbW92ZSBlbXB0eSBjb2x1bW5zDQogIHBpdm90X2xvbmdlcigtYXNxNF9pZCwgbmFtZXNfdG8gPSAiYXNxNCIpIA0KYGBgDQoNCg0KIyMjIE1lcmdlIHRoZXNlIGRhdGEgYW5kIHJlbW92ZSB1c2VsZXNzIHZlY3RvcnMgIA0KYGBge3J9DQpjb3JfZHMgPC0gbGVmdF9qb2luKGNvcl9kc18xLGNvcl9kc18yKQ0Kcm0oY29yX2RzXzEsIGNvcl9kc18yKQ0KYGBgDQoNCg0KIyMgQVNRIEZpbmUgbW90b3IgdnMgQUVQUyBGaW5lIG1vdG9yDQoNCmBgYHtyfQ0KbGlicmFyeShjb3JycikgI2NvcnJlbGF0aW9uIA0KYGBgDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPg0KQ29ycmVsYXRpb24gYmV0d2VlbiAqQVNRIEZpbmUgbW90b3IqIGFuZCAqQUVQUyBGaW5lIG1vdG9yKg0KSSdtIHVzaW5nIHRoZSBzYW1lIGNoaWxkISANCjwvZGl2Pg0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlID0gRkFMU0UgIH0NCmNvcl9kcyAlPiUgDQogIGZpbHRlcihhc3E0ID09ICJmbV9zdW0iLCBkb21haW4gPT0gImZpbmVfbW90b3IiKSU+JQ0KICBncm91cF9ieShza2lsbCkgJT4lIA0KICBzZWxlY3QocmF3X3Njb3JlLCB2YWx1ZSkgJT4lIA0KICBuZXN0KCkgJT4lIA0KICBtdXRhdGUoZGF0YSA9IG1hcChkYXRhLCBwdXJycjo6Y29tcG9zZShzdHJldGNoLCBjb3JyZWxhdGUpKSkgJT4lIA0KICB1bm5lc3QoY29scyA9IC1za2lsbCkgJT4lIA0KICBuYS5vbWl0ICAlPiUgDQogIGRpc3RpbmN0KHNraWxsLCAua2VlcF9hbGwgPSBUKQ0KYGBgDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQpIb3cgdG8gaW50ZXJwcmV0IHRoZXNlIHJlc3VsdHM/ICAgICAgDQpUaGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgQVNRLTQgZmluZSBtb3RvciBhbmQgQUVQUyBmaW5lIG1vdG9yIChza2lsbDogUmVhY2ggYW5kIEdyYWIpIGlzIC0wLjIyIChtYWtlcyBubyBzZW5zZSB0byBtZSkgICANClRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBBU1EtNCBmaW5lIG1vdG9yIGFuZCBBRVBTIGZpbmUgbW90b3IgKHNraWxsOiBGdW5jdGlvbmFsIHVzZSkgaXMgLTAuMDUgKG1ha2VzIG5vIHNlbnNlIHRvIG1lKSAgIA0KDQoqKkkgaGF2ZSBhdHRhY2hlZCBhbiBleGNlbCBmaWxlIGluIHdoaWNoIEkgbWFubnVhbGx5IHJhbiB0aGVzZSBjb3JyZWxhdGlvbnMgYW5kIHRoZSByZXN1bHRzIG1hdGNoKioNCjwvZGl2Pg0KDQojIyBBU1EgZ3Jvc3MgbW90b3IgQUVQUyBncm9zcyBtb3Rvcg0KDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWluZm8iPg0KQ29ycmVsYXRpb24gYmV0d2VlbiAqQVNRIEdyb3NzIG1vdG9yKiBhbmQgKkFFUFMgR3Jvc3MgbW90b3IqDQpJJ20gdXNpbmcgdGhlIGRhdGEgZnJvbSBzYW1lIGNoaWxkcmVuLiAgICANCjwvZGl2Pg0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlID0gRkFMU0UgIH0NCmNvcl9kcyAlPiUgDQogIGZpbHRlcihhc3E0ID09ICJnbV9zdW0iLCBkb21haW4gPT0gImdyb3NzX21vdG9yIikgJT4lDQogIGdyb3VwX2J5KHNraWxsKSAlPiUgDQogIHNlbGVjdChyYXdfc2NvcmUsIHZhbHVlKSAlPiUgDQogIG5lc3QoKSAlPiUgDQogIG11dGF0ZShkYXRhID0gbWFwKGRhdGEsIHB1cnJyOjpjb21wb3NlKHN0cmV0Y2gsIGNvcnJlbGF0ZSkpKSAlPiUgDQogIHVubmVzdChjb2xzID0gLXNraWxsKSAlPiUgDQogIG5hLm9taXQgICU+JSANCiAgZGlzdGluY3Qoc2tpbGwsIC5rZWVwX2FsbCA9IFQpDQpgYGANCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtZGFuZ2VyIj4NCkhvdyB0byBpbnRlcnByZXQgdGhlc2UgcmVzdWx0cz8gICAgICANClRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBBU1EtNCBncm9zcyBtb3RvciBhbmQgQUVQUyBncm9zcyBtb3RvciAoc2tpbGw6IEEuIE1vdmVtZW50IGFuZCBMb2NvbW90aW9uKSBpcyAtMC4xNyAobWFrZXMgbm8gc2Vuc2UgdG8gbWUpICAgICANClRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBBU1EtNCBncm9zcyBtb3RvciBhbmQgQUVQUyBncm9zcyBtb3RvciAoc2tpbGw6IEIuIEJhbGFuY2UgaW4gU2l0dGluZykgaXMgLTAuMDYgKG1ha2VzIG5vIHNlbnNlIHRvIG1lKSAgICAgDQpUaGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgQVNRLTQgZ3Jvc3MgbW90b3IgYW5kIEFFUFMgZ3Jvc3MgbW90b3IgKHNraWxsOiBDLiBCYWxhbmNlICYgTW9iaWxpdHkpIGlzIDAuMDMgKG1ha2VzIG5vIHNlbnNlIHRvIG1lKSAgICAgIA0KVGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIEFTUS00IGdyb3NzIG1vdG9yIGFuZCBBRVBTIGdyb3NzIG1vdG9yIChza2lsbDogRC4gUGxheSBTa2lsbHMpIGlzIDAuMDQgKG1ha2VzIG5vIHNlbnNlIHRvIG1lKSANCjwvZGl2Pg0KDQojIyBBU1EgUGVyc29uYWwtU29jaWFsIEFFUFMgYWRhcHRpdmUNCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtaW5mbyI+DQoqKkphbmU6IEp1c3QgdG8gcmVmcmVzaCBteSBtZW1vcnkuIEluIHRoZSBkYXRhc2V0LCBQUyBtZWFucyBwcm9ibGVtLXNvbHZpbmcgYW5kIFAgbWVhbnMgUGVyc29uYWwgYW5kIFNvY2lhbCwgcmlnaHQ/ICAgDQpDb3JyZWxhdGlvbiBiZXR3ZWVuICpBU1EgUGVyc29uYWwtU29jaWFsKiBhbmQgKkFFUFMgQWRhcHRpdmUqDQpJJ20gdXNpbmcgdGhlIGRhdGEgZnJvbSBzYW1lIGNoaWxkcmVuLiAgICANCjwvZGl2Pg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZSA9IEZBTFNFICB9DQpjb3JfZHMgJT4lIA0KICBmaWx0ZXIoYXNxNCA9PSAicGVyX3N1bSIsIGRvbWFpbiA9PSAiYWRhcHRpdmVfYXJlYSIpICU+JQ0KICBncm91cF9ieShza2lsbCkgJT4lIA0KICBzZWxlY3QocmF3X3Njb3JlLCB2YWx1ZSkgJT4lIA0KICBuZXN0KCkgJT4lIA0KICBtdXRhdGUoZGF0YSA9IG1hcChkYXRhLCBwdXJycjo6Y29tcG9zZShzdHJldGNoLCBjb3JyZWxhdGUpKSkgJT4lIA0KICB1bm5lc3QoY29scyA9IC1za2lsbCkgJT4lIA0KICBuYS5vbWl0ICAlPiUgDQogIGRpc3RpbmN0KHNraWxsLCAua2VlcF9hbGwgPSBUKQ0KYGBgDQoNCjxkaXYgY2xhc3M9ImFsZXJ0IGFsZXJ0LWRhbmdlciI+DQpIb3cgdG8gaW50ZXJwcmV0IHRoZXNlIHJlc3VsdHM/ICAgICAgDQpUaGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgQVNRLTQgUGVyc29uYWwgYW5kIFNvY2lhbCBhbmQgQUVQUyBBZGFwdGl2ZSAoc2tpbGw6IEEuIEZlZWRpbmcpIGlzIDAuMzQgKG1ha2VzIHNlbnNlISEpICAgICANClRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBBU1EtNCBQZXJzb25hbCBhbmQgU29jaWFsIGFuZCBBRVBTIEFkYXB0aXZlIChza2lsbDogQi4gUGVyc29uYWwgSHlnaWVuZSkgaXMgMC4yNyAobWFrZXMgc2Vuc2UhISkgICAgIA0KVGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIEFTUS00IFBlcnNvbmFsIGFuZCBTb2NpYWwgYW5kIEFFUFMgQWRhcHRpdmUgKHNraWxsOiBDLiBVbmRyZXNzaW5nKSBpcyAwLjMwIChtYWtlcyBzZW5zZSEhKSAgICAgDQo8L2Rpdj4gICANCg0KZW5kIG9mIHJlcG9ydA==