From 1dd61064ec89b6c5f142dbe0fd8b37f949caa174 Mon Sep 17 00:00:00 2001 From: Erik Leppo Date: Thu, 25 Jan 2024 12:16:04 -0500 Subject: [PATCH] v2.0.7.9025 * refactor: QC function to move QC columns, Issue #154 + Flag. and Comment.MOD cols next to measurement columns + Ignore Date, Time, and Date.Time --- DESCRIPTION | 4 +- NEWS | 16 +- NEWS.md | 10 +- NEWS.rmd | 7 + R/fun.QC.File.R | 194 ++++++++++++++- R/fun.QC.R | 228 ++++++++++++++++-- inst/extdata/ContDataQC_LibraryCreation.Rmd | 1 + .../ContDataQC_LibraryCreation.nb.html | 7 +- inst/shiny-examples/ContDataQC/ui.R | 2 +- 9 files changed, 446 insertions(+), 23 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 1bc2370..b215285 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: ContDataQC Title: Quality Control (QC) of Continous Monitoring Data -Version: 2.0.7.9024 +Version: 2.0.7.9025 Authors@R: c( person("Erik W", "Leppo", email="Erik.Leppo@tetratech.com",role=c("aut","cre")), person("Ann","Roseberry Lincoln", role="ctb"), @@ -42,5 +42,5 @@ Remotes: tsangyp/StreamThermal, jasonelaw/iha StagedInstall: no -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.0 Config/testthat/edition: 3 diff --git a/NEWS b/NEWS index 8335ef8..918ffdc 100644 --- a/NEWS +++ b/NEWS @@ -3,10 +3,24 @@ NEWS-ContDataQC - #> Last Update: 2023-09-22 16:14:21.634179 + #> Last Update: 2024-01-25 12:04:12.540163 # Version History +## v2.0.7.9025 + +2024-01-25 + +- refactor: QC function to move QC columns, Issue \#154 + - Flag. and Comment.MOD cols next to measurement columns + - Ignore Date, Time, and Date.Time + +## v2.0.7.9024 + +2023-09-28 + +- refactor: Use USEPA template + ## v2.0.7.9023 2023-09-18 diff --git a/NEWS.md b/NEWS.md index 4bbf1d3..918ffdc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,10 +3,18 @@ NEWS-ContDataQC - #> Last Update: 2023-09-28 11:06:45.427073 + #> Last Update: 2024-01-25 12:04:12.540163 # Version History +## v2.0.7.9025 + +2024-01-25 + +- refactor: QC function to move QC columns, Issue \#154 + - Flag. and Comment.MOD cols next to measurement columns + - Ignore Date, Time, and Date.Time + ## v2.0.7.9024 2023-09-28 diff --git a/NEWS.rmd b/NEWS.rmd index 4dbfc73..2c5ef12 100644 --- a/NEWS.rmd +++ b/NEWS.rmd @@ -21,6 +21,13 @@ cat(paste0("Last Update: ",Sys.time())) # Version History +## v2.0.7.9025 +2024-01-25 + +* refactor: QC function to move QC columns, Issue #154 + + Flag. and Comment.MOD cols next to measurement columns + + Ignore Date, Time, and Date.Time + ## v2.0.7.9024 2023-09-28 diff --git a/R/fun.QC.File.R b/R/fun.QC.File.R index df7cd8c..08f6c74 100644 --- a/R/fun.QC.File.R +++ b/R/fun.QC.File.R @@ -91,6 +91,7 @@ fun.QC.File <- function(fun.myFile , fun.CreateReport = TRUE , fun.AddDeployCol = FALSE ) {##FUN.fun.QC.START + boo_DEBUG <- FALSE # # # A. Data Prep #### # # Convert Data Type to proper case @@ -1188,7 +1189,198 @@ fun.QC.File <- function(fun.myFile # data.import[,paste(myName.Raw,j,sep=".")] <- data.import[,j] # # 6-9 #not here - # + + # B.5.1. Move "Comment.MOD" next to "Flag" ---- + # 2024-01-22 + boo_move_CM <- TRUE + if (boo_move_CM) { + # boo_DEBUG <- FALSE + + patt_flag_env <- ContData.env$myName.Flag + patt_flag <- paste0("^", patt_flag_env, ".") + patt_cm_env <- "Comment.MOD" + patt_cm <- paste0("^", patt_cm_env, ".") + patt_datetime <- c(ContData.env$myName.Date + , ContData.env$myName.Time + , ContData.env$myName.DateTime) + patt_flag_datetime <- paste(patt_flag_env, patt_datetime, sep = ".") + patt_cm_datetime <- paste(patt_cm_env, patt_datetime, sep = ".") + + ## Names, all + names_all <- names(data.import) + if (boo_DEBUG) { + names_all + }## IF ~ boo_DEBUG + + ## Names, Flag + names_flag <- names(data.import)[grepl(patt_flag, names(data.import))] + if (boo_DEBUG) { + names_flag + }## IF ~ boo_DEBUG + # Remove Discrete + patt_discrete <- "Discrete." + names_flag <- names_flag[!grepl(patt_discrete, names_flag)] + + ## Names, Comment.MOD + names_cm <- names(data.import)[grepl(patt_cm, names(data.import))] + # remove date time + names_cm <- names_cm[!names_cm %in% patt_cm_datetime] + if (boo_DEBUG) { + names_cm + }## IF ~ boo_DEBUG + + #ContData.env$myNames.QCTests <- c("Gross","Spike","RoC","Flat") + myNames.QCTests <- c("Gross","Spike","RoC","Flat") + patt_QCTests <- paste(myNames.QCTests, collapse = "|") + # ONLY QC Test flags + names_flag_qctests <- names_flag[grepl(patt_QCTests, names_flag)] + # Non QC Test flags + names_flag_overall <- names_flag[!grepl(patt_QCTests, names_flag)] + # Non Discrete + patt_discrete <- "Discrete." + names_flag_overall <- names_flag_overall[!grepl(patt_discrete, names_flag_overall)] + ## remove Date.Time + names_flag_overall <- names_flag_overall[!names_flag_overall %in% patt_flag_datetime] + + #IF len not > 0 then quit + + # Names, Measurements + names_flag_measurements <- sub(patt_flag, "", names_flag_overall) + names_cm_measurements <- sub(patt_cm, "", names_cm) + # remove Date.Time + names_flag_measurements <- names_flag_measurements[!names_flag_measurements %in% patt_datetime] + names_cm_measurements <- names_cm_measurements[!names_cm_measurements %in% patt_datetime] + + if (boo_DEBUG) { + names_flag_qctests + names_flag_overall + names_flag_measurements + names_cm_measurements + names_cm + }## IF ~ boo_DEBUG + + # names position + colnums_flag_qctests <- match(names_flag_qctests, names(data.import)) + colnums_flag_overall <- match(names_flag_overall, names(data.import)) + colnums_cm <- match(names_cm, names(data.import)) + colnums_remove <- sort(c(colnums_flag_overall, colnums_flag_qctests, colnums_cm)) + + colnums_orig <- seq_len(ncol(data.import)) + colnums_remove_all <- colnums_orig[-c(colnums_remove )] + + # measurements should be in the same order for flags and cm but not guaranteed! + + # at position of each names_flag_overall create new order + # p <- names_flag_measurements[1] # testing + + for (p in names_flag_measurements) { + + if (boo_DEBUG) { + print(p) + print(names_flag_overall) + print(colnums_flag_overall) + print(colnums_cm) + }## IF ~ boo_DEBUG + + # number for iterations + p_num <- match(p, names_flag_measurements) + if (boo_DEBUG) { + p_num + }## IF ~ boo_DEBUG + + # flag measure + p_flag_msr <- p + if (boo_DEBUG) { + print(p_flag_msr) + }## IF ~ boo_DEBUG + + # match flag measure with cm measure + p_flag_msr_match_cm_msr <- match(p_flag_msr, names_cm_measurements) + if (boo_DEBUG) { + print(p_flag_msr_match_cm_msr) + }## IF ~ boo_DEBUG + + # cm + p_cm <- names_cm[p_flag_msr_match_cm_msr] + if (boo_DEBUG) { + print(p_cm) + }## IF ~ boo_DEBUG + + # flag_overall + p_flag_overall <- names_flag_overall[grepl(p, names_flag_overall)] + if (boo_DEBUG) { + print(p_flag_overall) + }## IF ~ boo_DEBUG + + # flag_qctests + p_flag_qctests <- names_flag_qctests[grepl(p, names_flag_qctests)] + if (boo_DEBUG) { + print(p_flag_qctests) + }## IF ~ boo_DEBUG + + # Col Num, all + if (p_num == 1) { + colnums_mod <- colnums_remove_all + }## IF ~ p_num == 1 + if (boo_DEBUG) { + print(colnums_mod) + }## IF ~ boo_DEBUG + + # 0. find measurement colnum + # insert after it using append + # 1. Flag overall + # 2. Comment.MOD + # 3. Other flags + + # Col Num, p (measurement) + colnum_p_orig <- match(p, names_all) + if (boo_DEBUG) { + print(colnum_p_orig) + }## IF ~ boo_DEBUG + + # Col Num, p_flag_overall + colnum_p_flag_overall_orig <- match(p_flag_overall, names_all) + if (boo_DEBUG) { + print(colnum_p_flag_overall_orig) + }## IF ~ boo_DEBUG + + # Col Num, p_cm + colnum_p_cm_orig <- match(p_cm, names_all) + # MIGHT CHANGE, could be out of order + if (boo_DEBUG) { + print(colnum_p_cm_orig) + }## IF ~ boo_DEBUG + + # Col Num, p_flag_qctests + colnum_p_flag_qctests_orig <- match(p_flag_qctests, names_all) + # MIGHT CHANGE, could be out of order + if (boo_DEBUG) { + print(colnum_p_flag_qctests_orig) + }## IF ~ boo_DEBUG + + # Col Num, insert + colnum_p_insert <- c(colnum_p_flag_overall_orig + , colnum_p_cm_orig + , colnum_p_flag_qctests_orig) + + # new position in modified data frame + colnum_p_new <- match(colnum_p_orig, colnums_mod) + if (boo_DEBUG) { + print(colnum_p_new) + }## IF ~ boo_DEBUG + + # insert CM after Flag + colnums_mod <- append(colnums_mod + , values = colnum_p_insert + , after = colnum_p_new) + + }## FOR ~ p ~ names_flag_overall + + # resort data frame on new columns + data.import <- data.import[, colnums_mod] + + }## IF ~ boo_move_CM + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # save file then run QC Report in a separate Script #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/R/fun.QC.R b/R/fun.QC.R index 9eec655..e306ab0 100644 --- a/R/fun.QC.R +++ b/R/fun.QC.R @@ -1078,8 +1078,8 @@ fun.QC <- function(fun.myData.SiteID #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Names of columns for QC Calculations and Tests with Flags for each data column present # combine so can check for and remove later. - myNames.DataFields.Present.QCCalcs <- as.vector(t(outer(myNames.DataFields.Present,ContData.env$myNames.QCCalcs,paste,sep="."))) - myNames.Flags.QCTests <- paste("Flag.",as.vector(t(outer(ContData.env$myNames.QCTests,myNames.DataFields.Present,paste,sep="."))),sep="") + myNames.DataFields.Present.QCCalcs <- as.vector(t(outer(myNames.DataFields.Present,ContData.env$myNames.QCCalcs,paste,sep = "."))) + myNames.Flags.QCTests <- paste("Flag.",as.vector(t(outer(ContData.env$myNames.QCTests,myNames.DataFields.Present,paste,sep = "."))),sep = "") #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # not sure if need this little bit anymore #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1145,9 +1145,9 @@ fun.QC <- function(fun.myData.SiteID for (j in myNames.DataFields2Mod) {##FOR.j.START # # A. Add comment field and leave blank - data.import[, paste(myName.Comment.Mod, j, sep=".")] <- "" + data.import[, paste(myName.Comment.Mod, j, sep = ".")] <- "" # B. Add data.RAW and populate with original data - data.import[, paste(myName.Raw, j, sep=".")] <- data.import[, j] + data.import[, paste(myName.Raw, j, sep = ".")] <- data.import[, j] # }##FOR.j.END # @@ -1164,7 +1164,204 @@ fun.QC <- function(fun.myData.SiteID # data.import[,paste(myName.Raw,j,sep=".")] <- data.import[,j] # # 6-9 #not here - # + + # B.5.1. Move "Comment.MOD" and "Flag" ---- + ## Next to measurement (but not Date.Time) + # 2024-01-22 + boo_move_CM <- TRUE + if (boo_move_CM) { + + # boo_DEBUG <- FALSE + + patt_flag_env <- ContData.env$myName.Flag + patt_flag <- paste0("^", patt_flag_env, ".") + patt_cm_env <- "Comment.MOD" + patt_cm <- paste0("^", patt_cm_env, ".") + patt_datetime <- c(ContData.env$myName.Date + , ContData.env$myName.Time + , ContData.env$myName.DateTime) + patt_flag_datetime <- paste(patt_flag_env, patt_datetime, sep = ".") + patt_cm_datetime <- paste(patt_cm_env, patt_datetime, sep = ".") + + ## Names, all + names_all <- names(data.import) + if (boo_DEBUG) { + names_all + }## IF ~ boo_DEBUG + + ## Names, Flag + names_flag <- names(data.import)[grepl(patt_flag, names(data.import))] + if (boo_DEBUG) { + names_flag + }## IF ~ boo_DEBUG + # Remove Discrete + patt_discrete <- "Discrete." + names_flag <- names_flag[!grepl(patt_discrete, names_flag)] + + ## Names, Comment.MOD + names_cm <- names(data.import)[grepl(patt_cm, names(data.import))] + # remove date time + names_cm <- names_cm[!names_cm %in% patt_cm_datetime] + if (boo_DEBUG) { + names_cm + }## IF ~ boo_DEBUG + + #ContData.env$myNames.QCTests <- c("Gross","Spike","RoC","Flat") + myNames.QCTests <- c("Gross","Spike","RoC","Flat") + patt_QCTests <- paste(myNames.QCTests, collapse = "|") + # ONLY QC Test flags + names_flag_qctests <- names_flag[grepl(patt_QCTests, names_flag)] + # Non QC Test flags + names_flag_overall <- names_flag[!grepl(patt_QCTests, names_flag)] + # Non Discrete + patt_discrete <- "Discrete." + names_flag_overall <- names_flag_overall[!grepl(patt_discrete, names_flag_overall)] + ## remove Date.Time + names_flag_overall <- names_flag_overall[!names_flag_overall %in% patt_flag_datetime] + + #IF len not > 0 then quit + + # Names, Measurements + names_flag_measurements <- sub(patt_flag, "", names_flag_overall) + names_cm_measurements <- sub(patt_cm, "", names_cm) + # remove Date.Time + names_flag_measurements <- names_flag_measurements[!names_flag_measurements %in% patt_datetime] + names_cm_measurements <- names_cm_measurements[!names_cm_measurements %in% patt_datetime] + + if (boo_DEBUG) { + names_flag_qctests + names_flag_overall + names_flag_measurements + names_cm_measurements + names_cm + }## IF ~ boo_DEBUG + + # names position + colnums_flag_qctests <- match(names_flag_qctests, names(data.import)) + colnums_flag_overall <- match(names_flag_overall, names(data.import)) + colnums_cm <- match(names_cm, names(data.import)) + colnums_remove <- sort(c(colnums_flag_overall, colnums_flag_qctests, colnums_cm)) + + colnums_orig <- seq_len(ncol(data.import)) + colnums_remove_all <- colnums_orig[-c(colnums_remove )] + + # measurements should be in the same order for flags and cm but not guaranteed! + + # at position of each names_flag_overall create new order + # p <- names_flag_measurements[1] # testing + + for (p in names_flag_measurements) { + + if (boo_DEBUG) { + print(p) + print(names_flag_overall) + print(colnums_flag_overall) + print(colnums_cm) + }## IF ~ boo_DEBUG + + # number for iterations + p_num <- match(p, names_flag_measurements) + if (boo_DEBUG) { + p_num + }## IF ~ boo_DEBUG + + # flag measure + p_flag_msr <- p + if (boo_DEBUG) { + print(p_flag_msr) + }## IF ~ boo_DEBUG + + # match flag measure with cm measure + p_flag_msr_match_cm_msr <- match(p_flag_msr, names_cm_measurements) + if (boo_DEBUG) { + print(p_flag_msr_match_cm_msr) + }## IF ~ boo_DEBUG + + # cm + p_cm <- names_cm[p_flag_msr_match_cm_msr] + if (boo_DEBUG) { + print(p_cm) + }## IF ~ boo_DEBUG + + # flag_overall + p_flag_overall <- names_flag_overall[grepl(p, names_flag_overall)] + if (boo_DEBUG) { + print(p_flag_overall) + }## IF ~ boo_DEBUG + + # flag_qctests + p_flag_qctests <- names_flag_qctests[grepl(p, names_flag_qctests)] + if (boo_DEBUG) { + print(p_flag_qctests) + }## IF ~ boo_DEBUG + + # Col Num, all + if (p_num == 1) { + colnums_mod <- colnums_remove_all + }## IF ~ p_num == 1 + if (boo_DEBUG) { + print(colnums_mod) + }## IF ~ boo_DEBUG + + # 0. find measurement colnum + # insert after it using append + # 1. Flag overall + # 2. Comment.MOD + # 3. Other flags + + # Col Num, p (measurement) + colnum_p_orig <- match(p, names_all) + if (boo_DEBUG) { + print(colnum_p_orig) + }## IF ~ boo_DEBUG + + # Col Num, p_flag_overall + colnum_p_flag_overall_orig <- match(p_flag_overall, names_all) + if (boo_DEBUG) { + print(colnum_p_flag_overall_orig) + }## IF ~ boo_DEBUG + + # Col Num, p_cm + colnum_p_cm_orig <- match(p_cm, names_all) + # MIGHT CHANGE, could be out of order + if (boo_DEBUG) { + print(colnum_p_cm_orig) + }## IF ~ boo_DEBUG + + # Col Num, p_flag_qctests + colnum_p_flag_qctests_orig <- match(p_flag_qctests, names_all) + # MIGHT CHANGE, could be out of order + if (boo_DEBUG) { + print(colnum_p_flag_qctests_orig) + }## IF ~ boo_DEBUG + + # Col Num, insert + colnum_p_insert <- c(colnum_p_flag_overall_orig + , colnum_p_cm_orig + , colnum_p_flag_qctests_orig) + + # new position in modified data frame + colnum_p_new <- match(colnum_p_orig, colnums_mod) + if (boo_DEBUG) { + print(colnum_p_new) + }## IF ~ boo_DEBUG + + # insert CM after Flag + colnums_mod <- append(colnums_mod + , values = colnum_p_insert + , after = colnum_p_new) + + }## FOR ~ p ~ names_flag_overall + + # resort data frame on new columns + data.import <- data.import[, colnums_mod] + + }## IF ~ boo_move_CM + + + + + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # save file then run QC Report in a separate Script #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1182,16 +1379,16 @@ fun.QC <- function(fun.myData.SiteID ,strFile.DataType ,File.Date.Start ,File.Date.End - ,sep=ContData.env$myDelim) - ,"csv" - ,sep=".") + ,sep = ContData.env$myDelim) + , "csv" + , sep = ".") # 10.2. Save to File the data (overwrites any existing file). #print(paste("Saving output of file ",intCounter," of ",intCounter.Stop," files complete.",sep="")) #utils::flush.console() #write.csv(data.import,file=paste(myDir.data.export,"/",strFile.Out,sep=""),quote=FALSE,row.names=FALSE) utils::write.csv(data.import,file = file.path(myDir.data.export, strFile.Out) - ,quote=FALSE - ,row.names=FALSE) + ,quote = FALSE + ,row.names = FALSE) # # # B.11. Clean up # # B.11.1. Inform user of progress and update LOG @@ -1214,7 +1411,7 @@ fun.QC <- function(fun.myData.SiteID # insert QC Report so runs without user intervention #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # DEBUG, REPORT #### - if(boo_DEBUG==TRUE){##IF~boo_DEBUG~START + if (boo_DEBUG == TRUE) { fun.myData.SiteID <- strFile.SiteID fun.myData.Type <- strFile.DataType fun.myData.DateRange.Start <- fun.myData.DateRange.Start @@ -1228,7 +1425,7 @@ fun.QC <- function(fun.myData.SiteID # run with same import and export directory ### # B.10.3. Report #### - if (fun.CreateReport==TRUE){##IF.CreateReport.START + if (fun.CreateReport == TRUE) { fun.Report(strFile.SiteID , strFile.DataType , strFile.Date.Start @@ -1238,7 +1435,8 @@ fun.QC <- function(fun.myData.SiteID , strFile.Out.Prefix , fun.myReport.format , fun.myReport.Dir - ) }##IF.CreateReport.END + ) + }##IF.CreateReport.END #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1257,7 +1455,9 @@ fun.QC <- function(fun.myData.SiteID # # C. Return #### myTime.End <- Sys.time() - print(paste("Task COMPLETE; ",round(difftime(myTime.End,myTime.Start,units="mins"),2)," min.",sep="")) + print(paste("Task COMPLETE; " + , round(difftime(myTime.End,myTime.Start, units = "mins"), 2) + ," min.", sep = "")) utils::flush.console() # # return data table diff --git a/inst/extdata/ContDataQC_LibraryCreation.Rmd b/inst/extdata/ContDataQC_LibraryCreation.Rmd index 6d4c710..0c9312d 100644 --- a/inst/extdata/ContDataQC_LibraryCreation.Rmd +++ b/inst/extdata/ContDataQC_LibraryCreation.Rmd @@ -139,6 +139,7 @@ After creating the package reload it after restarting R within RStudio pkg <- "ContDataQC" library(pkg, character.only = TRUE) help(package=(pkg)) +shell.exec(tempdir()) # ?PeriodStats #?CompSiteCDF diff --git a/inst/extdata/ContDataQC_LibraryCreation.nb.html b/inst/extdata/ContDataQC_LibraryCreation.nb.html index 3ff9c24..84c1125 100644 --- a/inst/extdata/ContDataQC_LibraryCreation.nb.html +++ b/inst/extdata/ContDataQC_LibraryCreation.nb.html @@ -1750,7 +1750,7 @@

ContDataQC

Library Creation

-

2023-09-08 14:58:25.121477

+

2024-01-24 15:09:45.110549

@@ -1914,11 +1914,12 @@

Create Package

RStudio (Ctrl + Shift + F10).

- +
# Restart R within RStudio:  Ctrl + Shift + F10
 pkg <- "ContDataQC"
 library(pkg, character.only = TRUE)
 help(package=(pkg))
+shell.exec(tempdir())
 #
 ?PeriodStats
 #?CompSiteCDF
@@ -2259,7 +2260,7 @@ 

Test Stats only

-
LS0tDQp0aXRsZTogIkNvbnREYXRhUUMiDQpzdWJ0aXRsZTogIkxpYnJhcnkgQ3JlYXRpb24iDQphdXRob3I6ICJFcmlrLkxlcHBvQHRldHJhdGVjaC5jb20iDQpkYXRlOiAiYHIgU3lzLnRpbWUoKWAiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6IG5vDQotLS0NCg0KSGVscGVyIGNvZGUgZm9yIGNyZWF0aW5nIGxpYnJhcnkuDQoNCkVyaWsuTGVwcG9AdGV0cmF0ZWNoLmNvbQ0KMjAxNy0wOS0yNg0KDQojIFBhY2thZ2UNCg0KUGFja2FnZSByZWxhdGVkIGNvZGUuDQoNCiMjIFZpZ25ldHRlDQoNCjEuIE5lZWQgdG8gcnVuIGNvZGUgYmVsb3cgdG8gYWRkIGRhdGEgdG8gInZpZ25ldHRlIiBkaXJlY3Rvcnkgc28gaXQgd2lsbCB3b3JrLg0KDQpgYGB7ciBWaWduZXR0ZV9EYXRhLCBldmFsPUZBTFNFfQ0KIyAxLiBjaGFuZ2Ugd2QgdG8gdmlnbmV0dGVzDQpzZXR3ZChmaWxlLnBhdGgoIkM6IiwiVXNlcnMiLCJFcmlrLkxlcHBvIiwiT25lRHJpdmUgLSBUZXRyYSBUZWNoLCBJbmMiDQogICAgICAgICAgICAgICAgLCJNeURvY3NfT25lRHJpdmUiLCJHaXRIdWIiLCJDb250RGF0YVFDIiwidmlnbmV0dGVzIikpDQojDQojIDIuIEFkZCBkYXRhIGZvciB2aWduZXR0ZSBleGFtcGxlcw0KIyBQYXJhbWV0ZXJzDQpTZWxlY3Rpb24uT3BlcmF0aW9uIDwtIGMoIkdldEdhZ2VEYXRhIiwiUUNSYXciLCAiQWdncmVnYXRlIiwgIlN1bW1hcnlTdGF0cyIpDQpTZWxlY3Rpb24uVHlwZSAgICAgIDwtIGMoIkFpciIsIldhdGVyIiwiQVciLCJHYWdlIiwiQVdHIiwiQUciLCJXRyIpDQpTZWxlY3Rpb24uU1VCIDwtIGMoIkRhdGExX1JBVyIsIkRhdGEyX1FDIiwiRGF0YTNfQWdncmVnYXRlZCIsIkRhdGE0X1N0YXRzIikNCm15RGlyLkJBU0UgPC0gZ2V0d2QoKQ0KIw0KIyBDcmVhdGUgZGF0YSBkaXJlY3Rvcmllcw0KbXlEaXIuY3JlYXRlIDwtIHBhc3RlMCgiLi8iLFNlbGVjdGlvbi5TVUJbMV0pDQogIGlmZWxzZShkaXIuZXhpc3RzKG15RGlyLmNyZWF0ZSk9PUZBTFNFLGRpci5jcmVhdGUobXlEaXIuY3JlYXRlKSwiRGlyZWN0b3J5IGFscmVhZHkgZXhpc3RzIikNCm15RGlyLmNyZWF0ZSA8LSBwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzJdKQ0KICBpZmVsc2UoZGlyLmV4aXN0cyhteURpci5jcmVhdGUpPT1GQUxTRSxkaXIuY3JlYXRlKG15RGlyLmNyZWF0ZSksIkRpcmVjdG9yeSBhbHJlYWR5IGV4aXN0cyIpDQpteURpci5jcmVhdGUgPC0gcGFzdGUwKCIuLyIsU2VsZWN0aW9uLlNVQlszXSkNCiAgaWZlbHNlKGRpci5leGlzdHMobXlEaXIuY3JlYXRlKT09RkFMU0UsZGlyLmNyZWF0ZShteURpci5jcmVhdGUpLCJEaXJlY3RvcnkgYWxyZWFkeSBleGlzdHMiKQ0KbXlEaXIuY3JlYXRlIDwtIHBhc3RlMCgiLi8iLFNlbGVjdGlvbi5TVUJbNF0pDQogIGlmZWxzZShkaXIuZXhpc3RzKG15RGlyLmNyZWF0ZSk9PUZBTFNFLGRpci5jcmVhdGUobXlEaXIuY3JlYXRlKSwiRGlyZWN0b3J5IGFscmVhZHkgZXhpc3RzIikNCiMNCiMgU2F2ZSBleGFtcGxlIGRhdGEgKGFzc3VtZXMgZGlyZWN0b3J5IC4vRGF0YTFfUkFXLyBleGlzdHMpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDJfQVdfMjAxMzA0MjZfMjAxMzA3MjUNCiAgd3JpdGUuY3N2KG15RGF0YSxwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzFdLCIvdGVzdDJfQVdfMjAxMzA0MjZfMjAxMzA3MjUuY3N2IikpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDJfQVdfMjAxMzA3MjVfMjAxMzEwMTUNCiAgd3JpdGUuY3N2KG15RGF0YSxwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzFdLCIvdGVzdDJfQVdfMjAxMzA3MjVfMjAxMzEwMTUuY3N2IikpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDJfQVdfMjAxNDA5MDFfMjAxNDA5MzANCiAgd3JpdGUuY3N2KG15RGF0YSxwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzFdLCIvdGVzdDJfQVdfMjAxNDA5MDFfMjAxNDA5MzAuY3N2IikpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDRfQVdfMjAxNjA0MThfMjAxNjA3MjYNCiAgd3JpdGUuY3N2KG15RGF0YSxwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzFdLCIvdGVzdDRfQVdfMjAxNjA0MThfMjAxNjA3MjYuY3N2IikpDQpteUZpbGUgPC0gImNvbmZpZy5UWi5DZW50cmFsLlIiDQogIGZpbGUuY29weShmaWxlLnBhdGgocGF0aC5wYWNrYWdlKCJDb250RGF0YVFDIiksImV4dGRhdGEiLG15RmlsZSkNCiAgICAgICAgICAgICxmaWxlLnBhdGgoZ2V0d2QoKSxTZWxlY3Rpb24uU1VCWzFdLG15RmlsZSkpDQpgYGANCg0KMi4gS25pdCB0aGUgdmlnbmV0dGUgaW4gdGhlIHZpZ25ldHRlIGZvbGRlciB0byBlbnN1cmUgYWxsIG9mIHRoZSBjb2RlIHdvcmtzIGFuZCANCmlzIHByb3Blcmx5IGRpc3BsYXllZC4gIFRoaXMgY2FuIHRha2UgMiB0byA1IG1pbi4NCg0KMy4gVXNlIHRoZSBjb2RlIGJlbG93IHRvICJidWlsZCIgdGhlIHZpZ25ldHRlIGFuZCB0aGVuIHVzZSBpdCBpbiB0aGUgcGtnLg0KDQpgYGB7ciBWaWduZXR0ZV9CdWlsZCwgZXZhbD1GQUxTRX0NCiMgZ2VuZXJhdGUgVmlnbmV0dGUNCmxpYnJhcnkoQ29udERhdGFRQykNCmxpYnJhcnkoZGV2dG9vbHMpDQpkZXZ0b29sczo6YnVpbGRfdmlnbmV0dGVzKCkNCg0KIyBjcmVhdGUgdmlnbmV0dGUgZm9sZGVyIGFuZCBkZWZhdWx0IGZpbGUNCiNkZXZ0b29sczo6dXNlX3ZpZ25ldHRlKCJDb250RGF0YVFDX1ZpZ25ldHRlIikNCmBgYA0KZGV2dG9vbHM6OmJ1aWxkKCkgbW9yZSB1c2VmdWwgYW5kIGJ1aWxkX3ZpZ25ldHRlcygpDQoNCiMjIENyZWF0ZSBQYWNrYWdlDQpVc2UgdGhlIGNvZGUgYmVsb3cgdG8gY3JlYXRlIHRoZSBwYWNrYWdlLiAgQXNzdW1lcyB5b3UgYXJlIGluIHRoZSBkZXZlbG9wbWVudCANCnBhY2thZ2UgZGlyZWN0b3J5DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBTZXQgd29ya2luZyBkaXJlY3RvcnkNCm15TGlicmFyeSA8LSAiQ29udERhdGFRQyINCmRpcl9iYXNlIDwtICJDOi9Vc2Vycy9FcmlrLkxlcHBvL09uZURyaXZlIC0gVGV0cmEgVGVjaCwgSW5jL015RG9jc19PbmVEcml2ZS9HaXRIdWIiDQpzZXR3ZChmaWxlLnBhdGgoZGlyX2Jhc2UsIG15TGlicmFyeSkpDQoNCg0KIyBSZW1vdmUgYWxsIGZpbGVzIGluICJSZXN1bHRzIiBmb2xkZXINCiMgVHJpZ2dlcmVkIGhlcmUgc28gY2FuIHJ1biBkaWZmZXJlbnQgZmlsZXMNCnBhdGhfc2hpbnkgPC0gZmlsZS5wYXRoKCJpbnN0IiwgInNoaW55LWV4YW1wbGVzIiwgIkNvbnREYXRhUUMiKQ0KcGF0aF9yZXN1bHRzIDwtIGZpbGUucGF0aChwYXRoX3NoaW55LCAiZGF0YSIpDQpmbl9yZXN1bHRzIDwtIGxpc3QuZmlsZXMocGF0aF9yZXN1bHRzDQogICAgICAgICAgICAgICAgICAgICAgICAgLCBmdWxsLm5hbWVzID0gVFJVRQ0KICAgICAgICAgICAgICAgICAgICAgICAgICwgaW5jbHVkZS5kaXJzID0gRkFMU0UNCiAgICAgICAgICAgICAgICAgICAgICAgICAsIHJlY3Vyc2l2ZSA9IFRSVUUpDQpmaWxlLnJlbW92ZShmbl9yZXN1bHRzKSAjIG9rIGlmIG5vIGZpbGVzDQojIENvcHkgZmlsZSB0byBlbnN1cmUgZGlyZWN0b3J5IG5vdCBlbXB0eQ0KZm5fY29weSAgICA8LSAicmVtb3ZlLnR4dCINCnBhdGhfZnJvbSAgPC0gZmlsZS5wYXRoKHBhdGhfc2hpbnksICJleHRlcm5hbCIsIGZuX2NvcHkpDQpwYXRoX3RvICAgIDwtIGZpbGUucGF0aChwYXRoX3NoaW55LCAiZGF0YSIsIGZuX2NvcHkpDQpmaWxlLmNvcHkocGF0aF9mcm9tLCBwYXRoX3RvKQ0KDQojIE5FV1MNCiMgUmVuZGVyIHRoZW4gQ29weSBORVdTIHNvIHBpY2tlZCB1cCBpbiBoZWxwDQpybWFya2Rvd246OnJlbmRlcigiTkVXUy5ybWQiLCAiYWxsIikNCmZpbGUuY29weSgiTkVXUy5tZCIsICJORVdTIiwgb3ZlcndyaXRlID0gVFJVRSkNCmZpbGUucmVtb3ZlKCJORVdTLmh0bWwiKQ0KI2ZpbGUucmVtb3ZlKCJORVdTLm1kIikgIyBrZWVwIGZvciBwa2dkb3duIENIQU5HRSBMT0cNCiMNCiMgTG9hZCBMaWJyYXJ5DQpsaWJyYXJ5KGRldnRvb2xzKQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMgQ3JlYXRlIFBhY2thZ2UNCiMgY3JlYXRlKG15TGlicmFyeSkNCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIERvY3VtZW50LCBJbnN0YWxsLCBhbmQgUmVsb2FkIExpYnJhcnkNCiMjIEdlbmVyYXRlIERvY3VtZW50YXRpb24NCmRldnRvb2xzOjpkb2N1bWVudCgpDQojIyBJbnN0YWxsIE5ldyBQYWNrYWdlIChsb2NhbGx5KQ0Kc2V0d2QoIi4uIikgIyByZXR1cm4gdG8gcm9vdCBkaXJlY3RvcnkgZmlyc3QNCmRldnRvb2xzOjppbnN0YWxsKG15TGlicmFyeQ0KICAgICAgICAgICAgICAgICAgLCBidWlsZF92aWduZXR0ZXMgPSBUUlVFDQogICAgICAgICAgICAgICAgICAsIHF1aWNrID0gRkFMU0UNCiAgICAgICAgICAgICAgICAgICwgcmVsb2FkID0gVFJVRSkNCg0KIyMgUmVsb2FkIGxpYnJhcnkNCmxpYnJhcnkobXlMaWJyYXJ5LGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCiMgY2hhbmdlIHdkIGJhY2sgdG8gcGFja2FnZQ0Kc2V0d2QoZmlsZS5wYXRoKGRpcl9iYXNlLCBteUxpYnJhcnkpKQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCmBgYA0KDQpBZnRlciBjcmVhdGluZyB0aGUgcGFja2FnZSByZWxvYWQgaXQgYWZ0ZXIgcmVzdGFydGluZyBSIHdpdGhpbiBSU3R1ZGlvIA0KKEN0cmwgKyBTaGlmdCArIEYxMCkuDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBSZXN0YXJ0IFIgd2l0aGluIFJTdHVkaW86ICBDdHJsICsgU2hpZnQgKyBGMTANCnBrZyA8LSAiQ29udERhdGFRQyINCmxpYnJhcnkocGtnLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQpoZWxwKHBhY2thZ2U9KHBrZykpDQojDQo/UGVyaW9kU3RhdHMNCiM/Q29tcFNpdGVDREYNCj8/Q29udERhdGFRQw0KP2Z1bi5FeHBvcnQuSUhBDQo/RXhwb3J0LlN0cmVhbVRoZXJtYWwgIA0KYGBgDQoNClBhY2thZ2Ugd2Vic2l0ZQ0KVXNlIHBrZ2Rvd24gdG8gY3JlYXRlIHNpdGUuDQoNCmh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tL3R2dGhlbWVzLTEtMS0wLWlzLW9uLWNyYW4tY3JlYXRpbmctYS1wa2dkb3duLXdlYnNpdGUtZ3Jhdml0eS1mYWxscy1wYWxldHRlLWFuZC1tb3JlLw0KDQpgYGB7ciBQa2dkb3duLCBldmFsPUZBTFNFfQ0KI2xpYnJhcnkocGtnZG93bikNCg0KdXNldGhpczo6dXNlX3BrZ2Rvd24oKQ0KcGtnZG93bjo6YnVpbGRfc2l0ZSgpDQoNCmBgYA0KDQojIGNvZGUgcGVyZm9tYW5jZQ0KdGltZSBlYWNoIHBhcnQgb2YgY29kZQ0KDQpgYGB7ciBwcm9mdmlzfQ0KIyBQYWNrYWdlcw0KbGlicmFyeShwcm9mdmlzKQ0KDQojIFJ1biBleGFtcGxlIGNvZGUNCiMjIFNldCB1cA0KIyBFeGFtcGxlcyBvZiBlYWNoIG9wZXJhdGlvbg0KDQojIDAwLiBTZXQgdXANCiMgUGFyYW1ldGVycw0KU2VsZWN0aW9uLk9wZXJhdGlvbiA8LSBjKCJHZXRHYWdlRGF0YSINCiAgICAgICAgICAgICAgICAgICAgICAgICAsICJRQ1JhdyINCiAgICAgICAgICAgICAgICAgICAgICAgICAsICJBZ2dyZWdhdGUiDQogICAgICAgICAgICAgICAgICAgICAgICAgLCAiU3VtbWFyeVN0YXRzIikNClNlbGVjdGlvbi5UeXBlICAgICAgPC0gYygiQWlyIiwiV2F0ZXIiLCJBVyIsIkdhZ2UiLCJBV0ciLCJBRyIsIldHIikNClNlbGVjdGlvbi5TVUIgPC0gYygiRGF0YTBfT3JpZ2luYWwiDQogICAgICAgICAgICAgICAgICAgLCAiRGF0YTFfUkFXIg0KICAgICAgICAgICAgICAgICAgICwgIkRhdGEyX1FDIg0KICAgICAgICAgICAgICAgICAgICwgIkRhdGEzX0FnZ3JlZ2F0ZWQiDQogICAgICAgICAgICAgICAgICAgLCAiRGF0YTRfU3RhdHMiKQ0KKG15RGlyLkJBU0UgPC0gdGVtcGRpcigpKSAjIGNyZWF0ZSBhbmQgcHJpbnQgdGVtcCBkaXJlY3RvcnkgZm9yIGV4YW1wbGUgZGF0YQ0KDQojIENyZWF0ZSBkYXRhIGRpcmVjdG9yaWVzDQpteURpci5jcmVhdGUgPC0gZmlsZS5wYXRoKG15RGlyLkJBU0UsIFNlbGVjdGlvbi5TVUJbMV0pDQogIGlmZWxzZShkaXIuZXhpc3RzKG15RGlyLmNyZWF0ZSkgPT0gRkFMU0UNCiAgICAgICAgICwgZGlyLmNyZWF0ZShteURpci5jcmVhdGUpDQogICAgICAgICAsICJEaXJlY3RvcnkgYWxyZWFkeSBleGlzdHMiKQ0KbXlEaXIuY3JlYXRlIDwtIGZpbGUucGF0aChteURpci5CQVNFLCBTZWxlY3Rpb24uU1VCWzJdKQ0KICBpZmVsc2UoZGlyLmV4aXN0cyhteURpci5jcmVhdGUpID09IEZBTFNFDQogICAgICAgICAsIGRpci5jcmVhdGUobXlEaXIuY3JlYXRlKQ0KICAgICAgICAgLCAiRGlyZWN0b3J5IGFscmVhZHkgZXhpc3RzIikNCm15RGlyLmNyZWF0ZSA8LSBmaWxlLnBhdGgobXlEaXIuQkFTRSwgU2VsZWN0aW9uLlNVQlszXSkNCiAgaWZlbHNlKGRpci5leGlzdHMobXlEaXIuY3JlYXRlKSA9PSBGQUxTRQ0KICAgICAgICAgLCBkaXIuY3JlYXRlKG15RGlyLmNyZWF0ZSkNCiAgICAgICAgICwgIkRpcmVjdG9yeSBhbHJlYWR5IGV4aXN0cyIpDQpteURpci5jcmVhdGUgPC0gZmlsZS5wYXRoKG15RGlyLkJBU0UsIFNlbGVjdGlvbi5TVUJbNF0pDQogIGlmZWxzZShkaXIuZXhpc3RzKG15RGlyLmNyZWF0ZSkgPT0gRkFMU0UNCiAgICAgICAgICwgZGlyLmNyZWF0ZShteURpci5jcmVhdGUpDQogICAgICAgICAsICJEaXJlY3RvcnkgYWxyZWFkeSBleGlzdHMiKQ0KbXlEaXIuY3JlYXRlIDwtIGZpbGUucGF0aChteURpci5CQVNFLCBTZWxlY3Rpb24uU1VCWzVdKQ0KICBpZmVsc2UoZGlyLmV4aXN0cyhteURpci5jcmVhdGUpID09IEZBTFNFDQogICAgICAgICAsIGRpci5jcmVhdGUobXlEaXIuY3JlYXRlKQ0KICAgICAgICAgLCAiRGlyZWN0b3J5IGFscmVhZHkgZXhpc3RzIikNCg0KIyBTYXZlIGV4YW1wbGUgZGF0YSAoYXNzdW1lcyBteURpci5CQVNFIGRpcmVjdG9yeSBleGlzdHMpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDJfQVdfMjAxMzA0MjZfMjAxMzA3MjUNCiAgd3JpdGUuY3N2KG15RGF0YSwgZmlsZS5wYXRoKG15RGlyLkJBU0UNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICwgU2VsZWN0aW9uLlNVQlsyXQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAidGVzdDJfQVdfMjAxMzA0MjZfMjAxMzA3MjUuY3N2IikpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDJfQVdfMjAxMzA3MjVfMjAxMzEwMTUNCiAgd3JpdGUuY3N2KG15RGF0YSwgZmlsZS5wYXRoKG15RGlyLkJBU0UNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICwgU2VsZWN0aW9uLlNVQlsyXQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAidGVzdDJfQVdfMjAxMzA3MjVfMjAxMzEwMTUuY3N2IikpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDJfQVdfMjAxNDA5MDFfMjAxNDA5MzANCiAgd3JpdGUuY3N2KG15RGF0YSwgZmlsZS5wYXRoKG15RGlyLkJBU0UNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICwgU2VsZWN0aW9uLlNVQlsyXQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAidGVzdDJfQVdfMjAxNDA5MDFfMjAxNDA5MzAuY3N2IikpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDRfQVdfMjAxNjA0MThfMjAxNjA3MjYNCiAgd3JpdGUuY3N2KG15RGF0YSwgZmlsZS5wYXRoKG15RGlyLkJBU0UNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICwgU2VsZWN0aW9uLlNVQlsyXQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCAidGVzdDRfQVdfMjAxNjA0MThfMjAxNjA3MjYuY3N2IikpDQpteUZpbGUgPC0gImNvbmZpZy5UWi5DZW50cmFsLlIiDQogIGZpbGUuY29weShmaWxlLnBhdGgocGF0aC5wYWNrYWdlKCJDb250RGF0YVFDIiksICJleHRkYXRhIiwgbXlGaWxlKQ0KICAgICAgICAgICAgLCBmaWxlLnBhdGgobXlEaXIuQkFTRSwgU2VsZWN0aW9uLlNVQlsyXSwgbXlGaWxlKSkNCiAgDQpteURhdGEuT3BlcmF0aW9uICAgICAgIDwtICJRQ1JhdyIgI1NlbGVjdGlvbi5PcGVyYXRpb25bMl0NCm15RGF0YS5TaXRlSUQgICAgICAgICAgPC0gInRlc3QyIg0KbXlEYXRhLlR5cGUgICAgICAgICAgICA8LSBTZWxlY3Rpb24uVHlwZVszXSAjIkFXIg0KbXlEYXRhLkRhdGVSYW5nZS5TdGFydCA8LSAiMjAxMy0wMS0wMSINCm15RGF0YS5EYXRlUmFuZ2UuRW5kICAgPC0gIjIwMTQtMTItMzEiDQpteURpci5pbXBvcnQgICAgICAgICAgIDwtIGZpbGUucGF0aChteURpci5CQVNFLCBTZWxlY3Rpb24uU1VCWzJdKSAjIkRhdGExX1JBVyINCm15RGlyLmV4cG9ydCAgICAgICAgICAgPC0gZmlsZS5wYXRoKG15RGlyLkJBU0UsIFNlbGVjdGlvbi5TVUJbM10pICMiRGF0YTJfUUMiDQpteVJlcG9ydC5mb3JtYXQgICAgICAgIDwtICJkb2N4Ig0KDQoNCiMgU2F2ZQ0KcCA8LSBwcm9mdmlzKHsNCiAgQ29udERhdGFRQyhteURhdGEuT3BlcmF0aW9uDQogICAgICAgICAgICwgbXlEYXRhLlNpdGVJRA0KICAgICAgICAgICAsIG15RGF0YS5UeXBlDQogICAgICAgICAgICwgbXlEYXRhLkRhdGVSYW5nZS5TdGFydA0KICAgICAgICAgICAsIG15RGF0YS5EYXRlUmFuZ2UuRW5kDQogICAgICAgICAgICwgbXlEaXIuaW1wb3J0DQogICAgICAgICAgICwgbXlEaXIuZXhwb3J0DQogICAgICAgICAgICwgZnVuLm15UmVwb3J0LmZvcm1hdCA9IG15UmVwb3J0LmZvcm1hdCkNCn0pDQoNCiMgU2F2ZSB0byBIVE1MDQpodG1sd2lkZ2V0czo6c2F2ZVdpZGdldChwLCBmaWxlLnBhdGgodGVtcGRpcigpLCAicHJvZmlsZS5odG1sIikpDQoNCiMgT3BlbiBpbiBicm93c2VyIGZyb20gUg0KYnJvd3NlVVJMKGZpbGUucGF0aCh0ZW1wZGlyKCksICJwcm9maWxlLmh0bWwiKSkNCg0KYGBgDQoNCg0KVGVzdGluZyBvZiBjb25maWd1cmF0aW9uIGFuZCBSTUQgZmlsZXMuDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KbGlicmFyeShDb250RGF0YVFDKQ0KIyBQYXJhbWV0ZXJzDQpTZWxlY3Rpb24uT3BlcmF0aW9uIDwtIGMoIkdldEdhZ2VEYXRhIiwiUUNSYXciLCAiQWdncmVnYXRlIiwgIlN1bW1hcnlTdGF0cyIpDQpTZWxlY3Rpb24uVHlwZSAgICAgIDwtIGMoIkFpciIsIldhdGVyIiwiQVciLCJHYWdlIiwiQVdHIiwiQUciLCJXRyIpDQpTZWxlY3Rpb24uU1VCIDwtIGMoIkRhdGExX1JBVyIsIkRhdGEyX1FDIiwiRGF0YTNfQWdncmVnYXRlZCIsIkRhdGE0X1N0YXRzIikNCm15RGlyLkJBU0UgPC0gZ2V0d2QoKQ0KIw0KIyBBZ2dyZWdhdGUgRGF0YQ0KbXlEYXRhLk9wZXJhdGlvbiA8LSAiQWdncmVnYXRlIiAjU2VsZWN0aW9uLk9wZXJhdGlvblszXQ0KbXlEYXRhLlNpdGVJRCAgICA8LSAidGVzdDIiDQpteURhdGEuVHlwZSAgICAgIDwtIFNlbGVjdGlvbi5UeXBlWzNdICMiQVciDQpteURhdGEuRGF0ZVJhbmdlLlN0YXJ0ICA8LSAiMjAxMy0wMS0wMSINCm15RGF0YS5EYXRlUmFuZ2UuRW5kICAgIDwtICIyMDE0LTEyLTMxIg0KbXlEaXIuaW1wb3J0IDwtIGZpbGUucGF0aChteURpci5CQVNFLFNlbGVjdGlvbi5TVUJbMl0pICMiRGF0YTJfUUMiDQpteURpci5leHBvcnQgPC0gZmlsZS5wYXRoKG15RGlyLkJBU0UsU2VsZWN0aW9uLlNVQlszXSkgIyJEYXRhM19BZ2dyZWdhdGVkIg0KbXlSZXBvcnQuZm9ybWF0IDwtICJkb2N4Ig0KIw0KIyBzZXQgY29uZmlnIGZpbGUgd2l0aCBSTUQgZGlyZWN0b3J5IGFzIGdldHdkKCkNCm15Q29uZmlnICAgICAgICAgICAgPC0gZmlsZS5wYXRoKGdldHdkKCksU2VsZWN0aW9uLlNVQlsyXSwiY29uZmlnLlJNRGRpci5SIikNCiMgcnVuIGZ1bmN0aW9uDQpDb250RGF0YVFDKG15RGF0YS5PcGVyYXRpb24sIG15RGF0YS5TaXRlSUQsIG15RGF0YS5UeXBlLCBteURhdGEuRGF0ZVJhbmdlLlN0YXJ0DQogICAgICAgICAgICwgbXlEYXRhLkRhdGVSYW5nZS5FbmQsIG15RGlyLmltcG9ydCwgbXlEaXIuZXhwb3J0DQogICAgICAgICAgICwgZnVuLm15UmVwb3J0LmZvcm1hdD1teVJlcG9ydC5mb3JtYXQsIGZ1bi5teUNvbmZpZyA9IG15Q29uZmlnKQ0KYGBgDQoNCg0KIyMgSW5jbHVkaW5nIERhdGENCkFsbCBkYXRhIHNob3VsZCBoYXZlIGFscmVhZHkgYmVlbiBjcmVhdGVkLg0KDQojIyBDaGVjaw0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgQ2hlY2sgZm9yIGVycm9ycyAob3IgcHJlc3MgQ21kICsgU2hpZnQgKyBFIGluIFJTdHVkaW8pDQojaHR0cDovL3ItcGtncy5oYWQuY28ubnovY2hlY2suaHRtbA0KZGV2dG9vbHM6OmNoZWNrKCkNCmBgYA0KDQpJZiB1c2UgUlN0dWRpbywgQnVpbGQgLSBDaGVjayBQYWNrYWdlLCB0aGUgb3V0cHV0IGlzIGVhc2llciB0byByZWFkLiANCg0KIyMgVGVzdA0KTmVlZCB0byB1c2UgdGVzdHRoYXQgYnV0IG5vdCB0byB0aGF0IHN0YWdlIHlldC4NCg0KUlN0dWRpbywgQnVpbGQgLSBUZXN0IFBhY2thZ2UuDQoNCiMgQ0ksIEJhZGdlcywgQ29kZSBDb3ZlcmFnZSwgZXRjDQoqIENvbnRpbnVvdXMgSW50ZWdyYXRpb24gd2l0aCBHaXRIdWIgQWN0aW9ucyAoVHJhdmlzQ0kgc2h1dCBkb3duIERlYyAyMDIwKQ0KKiBDb2RlIFF1YWxpdHkgKENvZGVGYWN0b3IpDQogICAgKyBDb2RlRmFjdG9yLmlvDQogICAgICAgIC0gR2l0SHViIGxvZ2luDQoqIENvZGUgQ292ZXJhZ2UgKHRlc3RpbmcpDQogICAgKyBDb2RlY292LmlvDQogICAgICAgIC0gR2l0SHViIGxvZ2luDQogICAgICAgIC0gQWZ0ZXIgc2V0IHVwIENJIHdpdGggR2l0SHViIEFjdGlvbnMNCiogUGFja2FnZSB3ZWJzaXRlIChwa2dkb3duIGFuZCBHaXRIdWIgQWN0aW9uKQ0KICAgICsgYnJhbmNoIGdoLXBhZ2VzLCBhdXRvIHVwZGF0ZXMgd2l0aCBlYWNoIGNvbW1pdA0KICAgICsgVXBkYXRlIGluIHNldHRpbmdzIHRoZSBsb2NhdGlvbg0KKiBCYWRnZXM7IE1haW50YWluZWQsIExpZmUgQ3ljbGUsIExpY2Vuc2UsIElzc3VlcywgZXRjDQogICAgKyBodHRwczovL2dpdGh1Yi5jb20vR3VhbmdjaHVhbmdZdS9iYWRnZXINCiAgICAgICAgLSBDb21tYW5kcyB0byBjcmVhdGUgYmFkZ2VzDQoNCmJhZGdlciBwYWNrYWdlIGNyZWF0ZXMgdGhlIHRleHQgZm9yIHBrZyByZWFkbWUgZmlsZS4NCiAgICAgICAgDQpBbHNvDQpodHRwczovL3NoaWVsZHMuaW8vICAgICAgICANCmh0dHBzOi8vZ2l0aHViLmNvbS9iYWRnZXMvc2hpZWxkcw0KQ2FuIG1ha2Ugc29tZSBiYWRnZXMgZHluYW1pYywgc3RhdGljIG9uZXMgYmVsb3cNCg0KIyBpc3N1ZXMNClshW0dpdEh1YiBpc3N1ZXNdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vZ2l0aHViL2lzc3Vlcy9sZXBwb3R0L01CU1N0b29scy5zdmcpXShodHRwczovL0dpdEh1Yi5jb20vbGVwcG90dC9NQlNTdG9vbHMvaXNzdWVzLykNCiMgcmVsZWFzZQ0KWyFbR2l0SHViIHJlbGVhc2VdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vZ2l0aHViL3JlbGVhc2UvbGVwcG90dC9NQlNTdG9vbHMuc3ZnKV0oaHR0cHM6Ly9HaXRIdWIuY29tL2xlcHBvdHQvTUJTU3Rvb2xzL3JlbGVhc2VzLykNCiMgZG93bmxvYWRzDQpbIVtHaXRodWIgYWxsIHJlbGVhc2VzXShodHRwczovL2ltZy5zaGllbGRzLmlvL2dpdGh1Yi9kb3dubG9hZHMvbGVwcG90dC9NQlNTdG9vbHMvdG90YWwuc3ZnKV0oaHR0cHM6Ly9HaXRIdWIuY29tL2xlcHBvdHQvTUJTU3Rvb2xzL3JlbGVhc2VzLykNCiAgICAgICAgDQpgYGB7cn0NCnBrZ19HSCA8LSAibGVwcG90dC9Db250RGF0YVFDIg0KcGtnX2xpYyA8LSAiTUlUIg0KDQojIEdpdEh1YiBBY3Rpb24sIENJDQp1c2V0aGlzOjp1c2VfZ2l0aHViX2FjdGlvbnMoKQ0KdXNldGhpczo6dXNlX2dpdGh1Yl9hY3Rpb25zX2JhZGdlKCkNCiMgYmFkZ2VyOjpiYWRnZV9naXRodWJfYWN0aW9ucyhwa2dfR0gpDQoNCiMgY29kZSBjb3ZlcmFnZQ0KdXNldGhpczo6dXNlX2dpdGh1Yl9hY3Rpb24oInRlc3QtY292ZXJhZ2UiKQ0KDQojIEdpdEh1YiBBY3Rpb24sIHBrZ2Rvd24NCnVzZXRoaXM6OnVzZV9naXRodWJfYWN0aW9uKCJwa2dkb3duIikNCg0KIyBCYWRnZXMNCiMgbGlmZWN5Y2xlDQpiYWRnZXI6OmJhZGdlX2xpZmVjeWNsZSgic3RhYmxlIiwgImdyZWVuIikgIyBzdGFibGUvZ3JlZW4sIG1hdHVyaW5nL2Rvcm1hbnQvYmx1ZQ0KIyBtYWludGFpbmVkDQojIGxpY2Vuc2UNCmJhZGdlcjo6YmFkZ2VfbGljZW5zZSgpDQojIGNvZGUgcXVhbGl0eQ0KYmFkZ2VyOjpiYWRnZV9jb2RlZmFjdG9yKHBrZ19HSCkNCiMgY29kZSB0ZXN0aW5nIGNvdmVyYWdlDQpiYWRnZXI6OmJhZGdlX2NvZGVjb3YocGtnX0dIKQ0KIyBjbWQgY2hlY2sNCmJhZGdlcjo6YmFkZ2VfZ2l0aHViX2FjdGlvbnMocGtnX0dIKQ0KDQoNCmBgYA0KDQoNCg0KIyBPdGhlciBTdHVmZg0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIFVwbG9hZCB0byBHaXRodWIgdmlhIEdpdEh1YiBEZXNrdG9wIHV0aWxpdHkNCiMgMC4gZG93bmxvYWQgZnJvbSB3ZWIgdmlhICJjbG9uZSBvciBkb3dubG9hZCIgdmlhICJPcGVuIGluIERlc2t0b3AiIChHaXRIdWIgRGVza3RvcCkgaWYgbm90IGFscmVhZHkgaW4gR2l0SHViIERlc2t0b3ANCiMgMS4gTWFrZSBjaGFuZ2VzIGluIGRvd25sb2FkL2Nsb25lIGZvbGRlci4gKGRvbmUgYWJvdmUpDQojIDMuIE9wZW4gR0ggRGVza3RvcCBjb21taXQgY2hhbmdlcyB0aGVuIHN5bmMuDQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KIyBpbnN0YWxsIGZyb20gR2l0SHViICh2aWEgZGV2dG9vbHMpDQpteUxpYnJhcnkgPC0gIkNvbnREYXRhUUMiDQpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIocGFzdGUwKCJsZXBwb3R0LyIsbXlMaWJyYXJ5KSkNCiMNCg0KDQoNCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIHJlbW92ZSBpbnN0YWxsZWQgcGFja2FnZXMgKGlmIG5lZWRlZCBmb3IgdHJvdWJsZXNob290aW5nKQ0Kc2VhcmNoKCkgIyBmaW5kDQojZGV0YWNoKDMpICMgcmVtb3ZlIGJ5IG51bWJlcg0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCg0KDQojIHRvIGJ1aWxkIHBhY2thZ2UNCiNodHRwczovL3RoZXBvbGl0aWNhbG1ldGhvZG9sb2dpc3QuY29tLzIwMTQvMDgvMTQvYnVpbGRpbmctYW5kLW1haW50YWluaW5nLXItcGFja2FnZXMtd2l0aC1kZXZ0b29scy1hbmQtcm94eWdlbjIvDQojIFRvIGJ1aWxkIHRoZSBwYWNrYWdlIGFzIGEgY29tcHJlc3NlZCBmaWxlIGluIHlvdXIgd29ya2luZyBkaXJlY3RvcnksIHJ1biBidWlsZChjdXJyZW50LmNvZGUsIHBhdGg9Z2V0d2QoKSkuDQoNCiMgdG8gc2F2ZSBpbnRlcm5hbCBkYXRhIGZvciBleGFtcGxlcw0KIyBleGFtcGxlDQojaHR0cDovL3ItcGtncy5oYWQuY28ubnovZGF0YS5odG1sI2RhdGEtc3lzZGF0YQ0KIyBoYXZlIHRvIGJlIGF0IHJvb3QgZGlyZWN0b3J5IChhYm92ZSBwYWNrYWdlKQ0KI2RldnRvb2xzOjp1c2VfZGF0YShOVi5wcmVkaWN0b3JzLE5WLmJ1Z3MscGtnPSJNTUljYWxjTlYiLGludGVybmFsPVRSVUUsb3ZlcndyaXRlPVRSVUUpDQojIyB2ZXJpZnkgd2l0aCBkYXRhKCkNCg0KIyBUbyBzYXZlIFJNRCBmaWxlcw0KIyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzMwMzc3MjEzL2hvdy10by1pbmNsdWRlLXJtYXJrZG93bi1maWxlLWluLXItcGFja2FnZQ0KIyAvcGtnL2luc3Qvcm1kLw0KIyBzeXN0ZW0uZmlsZSgicm1kL2ZpbGUuUm1kIiwgcGFja2FnZT0icGFja2FnZW5hbWUiKQ0KIw0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiNodHRwczovL2hpbGFyeXBhcmtlci5jb20vMjAxNC8wNC8yOS93cml0aW5nLWFuLXItcGFja2FnZS1mcm9tLXNjcmF0Y2gvDQojIENyZWF0ZSBQYWNrYWdlDQojIGNyZWF0ZShteUxpYnJhcnkpDQoNCmBgYA0KDQojIFRlc3QgU3RhdHMgb25seQ0KDQoNCmBgYHtyIFN0YXRzX0dhZ2UsIGV2YWw9RkFMU0V9DQojIFBhcmFtZXRlcnMNClNlbGVjdGlvbi5PcGVyYXRpb24gPC0gYygiR2V0R2FnZURhdGEiLCJRQ1JhdyIsICJBZ2dyZWdhdGUiLCAiU3VtbWFyeVN0YXRzIikNClNlbGVjdGlvbi5UeXBlICAgICAgPC0gYygiQWlyIiwiV2F0ZXIiLCJBVyIsIkdhZ2UiLCJBV0ciLCJBRyIsIldHIikNClNlbGVjdGlvbi5TVUIgPC0gYygiRGF0YTFfUkFXIiwiRGF0YTJfUUMiLCJEYXRhM19BZ2dyZWdhdGVkIiwiRGF0YTRfU3RhdHMiKQ0KbXlEaXIuQkFTRSA8LSBnZXR3ZCgpDQojDQojIFN1bW1hcnkgU3RhdHMsIEZpbGUNCiMjIEhhdmUgdG8gdXNlICJmaWxlIiB2ZXJzaW9uLiAgDQojIyBCYXNlIHZlcnNpb24gYnVpbGRzIGZpbGUgbmFtZSBhbmQgZXhwZWN0cyAiREFUQSIgcHJlZml4DQoNCiMgR2FnZSBGaWxlICsgT3RoZXIgRmlsZQ0KbXlEYXRhLk9wZXJhdGlvbiA8LSAiU3VtbWFyeVN0YXRzIiAjU2VsZWN0aW9uLk9wZXJhdGlvbls0XQ0KbXlGaWxlIDwtIGMoIkRhdGE0U3RhdHNfMDExODczMDBfR2FnZV8yMDEzMDEwMV8yMDE0MTIzMS5jc3YiDQogICAgICAgICAgICAsIkRhdGE0U3RhdHNfdGVzdDJfQXdfMjAxMzAxMDFfMjAxNDEyMzEuY3N2IikNCm15RGlyLmltcG9ydCA8LSBmaWxlLnBhdGgoIi4iLCJkYXRhLXJhdyIpDQpteURpci5leHBvcnQgPC0gZmlsZS5wYXRoKCIuIiwiRGF0YTRfU3RhdHMiKQ0KDQojTGVhdmUgb2ZmIG15UmVwb3J0LmZvcm1hdCBhbmQgZ2V0IGRlZmF1bHQgKGRvY3gpLg0KQ29udERhdGFRQyhteURhdGEuT3BlcmF0aW9uDQogICAgICAgICAgICwgZnVuLm15RGlyLmltcG9ydD1teURpci5pbXBvcnQNCiAgICAgICAgICAgLCBmdW4ubXlEaXIuZXhwb3J0PW15RGlyLmV4cG9ydA0KICAgICAgICAgICAsIGZ1bi5teUZpbGU9bXlGaWxlKQ0KDQoNCmBgYA0KDQpTaXRlSUQsIERhdGUsIFRpbWUsIERhdGUuVGltZSwgUGFyYW1ldGVycywgRmxhZy5QYXJhbWV0ZXJzDQoNCk9ubHkgb25lIGZsYWcgcGVyIHBhcmFtZXRlci4gIERvIG5vdCBuZWVkIGluZGl2aWR1YWwgdGVzdCBmbGFncy4NCg0KIkYiIChmYWlsKSBmbGFncyBhcmUgY2hhbmdlZCB0byBOQSBzbyB0aGV5IGFyZSBkcm9wcGVkIGZyb20gdGhlIHN0YXRpc3RpY3MgdGhhdCBjYWxjdWxhdGVkLg0KDQpNb2NrZWQgdXAgMiBmaWxlcy4NCg==
+
LS0tDQp0aXRsZTogIkNvbnREYXRhUUMiDQpzdWJ0aXRsZTogIkxpYnJhcnkgQ3JlYXRpb24iDQphdXRob3I6ICJFcmlrLkxlcHBvQHRldHJhdGVjaC5jb20iDQpkYXRlOiAiYHIgU3lzLnRpbWUoKWAiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgZGVwdGg6IDMNCiAgICB0b2NfZmxvYXQ6IG5vDQotLS0NCg0KSGVscGVyIGNvZGUgZm9yIGNyZWF0aW5nIGxpYnJhcnkuDQoNCkVyaWsuTGVwcG9AdGV0cmF0ZWNoLmNvbQ0KMjAxNy0wOS0yNg0KDQojIFBhY2thZ2UNCg0KUGFja2FnZSByZWxhdGVkIGNvZGUuDQoNCiMjIFZpZ25ldHRlDQoNCjEuIE5lZWQgdG8gcnVuIGNvZGUgYmVsb3cgdG8gYWRkIGRhdGEgdG8gInZpZ25ldHRlIiBkaXJlY3Rvcnkgc28gaXQgd2lsbCB3b3JrLg0KDQpgYGB7ciBWaWduZXR0ZV9EYXRhLCBldmFsPUZBTFNFfQ0KIyAxLiBjaGFuZ2Ugd2QgdG8gdmlnbmV0dGVzDQpzZXR3ZChmaWxlLnBhdGgoIkM6IiwiVXNlcnMiLCJFcmlrLkxlcHBvIiwiT25lRHJpdmUgLSBUZXRyYSBUZWNoLCBJbmMiDQogICAgICAgICAgICAgICAgLCJNeURvY3NfT25lRHJpdmUiLCJHaXRIdWIiLCJDb250RGF0YVFDIiwidmlnbmV0dGVzIikpDQojDQojIDIuIEFkZCBkYXRhIGZvciB2aWduZXR0ZSBleGFtcGxlcw0KIyBQYXJhbWV0ZXJzDQpTZWxlY3Rpb24uT3BlcmF0aW9uIDwtIGMoIkdldEdhZ2VEYXRhIiwiUUNSYXciLCAiQWdncmVnYXRlIiwgIlN1bW1hcnlTdGF0cyIpDQpTZWxlY3Rpb24uVHlwZSAgICAgIDwtIGMoIkFpciIsIldhdGVyIiwiQVciLCJHYWdlIiwiQVdHIiwiQUciLCJXRyIpDQpTZWxlY3Rpb24uU1VCIDwtIGMoIkRhdGExX1JBVyIsIkRhdGEyX1FDIiwiRGF0YTNfQWdncmVnYXRlZCIsIkRhdGE0X1N0YXRzIikNCm15RGlyLkJBU0UgPC0gZ2V0d2QoKQ0KIw0KIyBDcmVhdGUgZGF0YSBkaXJlY3Rvcmllcw0KbXlEaXIuY3JlYXRlIDwtIHBhc3RlMCgiLi8iLFNlbGVjdGlvbi5TVUJbMV0pDQogIGlmZWxzZShkaXIuZXhpc3RzKG15RGlyLmNyZWF0ZSk9PUZBTFNFLGRpci5jcmVhdGUobXlEaXIuY3JlYXRlKSwiRGlyZWN0b3J5IGFscmVhZHkgZXhpc3RzIikNCm15RGlyLmNyZWF0ZSA8LSBwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzJdKQ0KICBpZmVsc2UoZGlyLmV4aXN0cyhteURpci5jcmVhdGUpPT1GQUxTRSxkaXIuY3JlYXRlKG15RGlyLmNyZWF0ZSksIkRpcmVjdG9yeSBhbHJlYWR5IGV4aXN0cyIpDQpteURpci5jcmVhdGUgPC0gcGFzdGUwKCIuLyIsU2VsZWN0aW9uLlNVQlszXSkNCiAgaWZlbHNlKGRpci5leGlzdHMobXlEaXIuY3JlYXRlKT09RkFMU0UsZGlyLmNyZWF0ZShteURpci5jcmVhdGUpLCJEaXJlY3RvcnkgYWxyZWFkeSBleGlzdHMiKQ0KbXlEaXIuY3JlYXRlIDwtIHBhc3RlMCgiLi8iLFNlbGVjdGlvbi5TVUJbNF0pDQogIGlmZWxzZShkaXIuZXhpc3RzKG15RGlyLmNyZWF0ZSk9PUZBTFNFLGRpci5jcmVhdGUobXlEaXIuY3JlYXRlKSwiRGlyZWN0b3J5IGFscmVhZHkgZXhpc3RzIikNCiMNCiMgU2F2ZSBleGFtcGxlIGRhdGEgKGFzc3VtZXMgZGlyZWN0b3J5IC4vRGF0YTFfUkFXLyBleGlzdHMpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDJfQVdfMjAxMzA0MjZfMjAxMzA3MjUNCiAgd3JpdGUuY3N2KG15RGF0YSxwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzFdLCIvdGVzdDJfQVdfMjAxMzA0MjZfMjAxMzA3MjUuY3N2IikpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDJfQVdfMjAxMzA3MjVfMjAxMzEwMTUNCiAgd3JpdGUuY3N2KG15RGF0YSxwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzFdLCIvdGVzdDJfQVdfMjAxMzA3MjVfMjAxMzEwMTUuY3N2IikpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDJfQVdfMjAxNDA5MDFfMjAxNDA5MzANCiAgd3JpdGUuY3N2KG15RGF0YSxwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzFdLCIvdGVzdDJfQVdfMjAxNDA5MDFfMjAxNDA5MzAuY3N2IikpDQpteURhdGEgPC0gZGF0YV9yYXdfdGVzdDRfQVdfMjAxNjA0MThfMjAxNjA3MjYNCiAgd3JpdGUuY3N2KG15RGF0YSxwYXN0ZTAoIi4vIixTZWxlY3Rpb24uU1VCWzFdLCIvdGVzdDRfQVdfMjAxNjA0MThfMjAxNjA3MjYuY3N2IikpDQpteUZpbGUgPC0gImNvbmZpZy5UWi5DZW50cmFsLlIiDQogIGZpbGUuY29weShmaWxlLnBhdGgocGF0aC5wYWNrYWdlKCJDb250RGF0YVFDIiksImV4dGRhdGEiLG15RmlsZSkNCiAgICAgICAgICAgICxmaWxlLnBhdGgoZ2V0d2QoKSxTZWxlY3Rpb24uU1VCWzFdLG15RmlsZSkpDQpgYGANCg0KMi4gS25pdCB0aGUgdmlnbmV0dGUgaW4gdGhlIHZpZ25ldHRlIGZvbGRlciB0byBlbnN1cmUgYWxsIG9mIHRoZSBjb2RlIHdvcmtzIGFuZCANCmlzIHByb3Blcmx5IGRpc3BsYXllZC4gIFRoaXMgY2FuIHRha2UgMiB0byA1IG1pbi4NCg0KMy4gVXNlIHRoZSBjb2RlIGJlbG93IHRvICJidWlsZCIgdGhlIHZpZ25ldHRlIGFuZCB0aGVuIHVzZSBpdCBpbiB0aGUgcGtnLg0KDQpgYGB7ciBWaWduZXR0ZV9CdWlsZCwgZXZhbD1GQUxTRX0NCiMgZ2VuZXJhdGUgVmlnbmV0dGUNCmxpYnJhcnkoQ29udERhdGFRQykNCmxpYnJhcnkoZGV2dG9vbHMpDQpkZXZ0b29sczo6YnVpbGRfdmlnbmV0dGVzKCkNCg0KIyBjcmVhdGUgdmlnbmV0dGUgZm9sZGVyIGFuZCBkZWZhdWx0IGZpbGUNCiNkZXZ0b29sczo6dXNlX3ZpZ25ldHRlKCJDb250RGF0YVFDX1ZpZ25ldHRlIikNCmBgYA0KZGV2dG9vbHM6OmJ1aWxkKCkgbW9yZSB1c2VmdWwgYW5kIGJ1aWxkX3ZpZ25ldHRlcygpDQoNCiMjIENyZWF0ZSBQYWNrYWdlDQpVc2UgdGhlIGNvZGUgYmVsb3cgdG8gY3JlYXRlIHRoZSBwYWNrYWdlLiAgQXNzdW1lcyB5b3UgYXJlIGluIHRoZSBkZXZlbG9wbWVudCANCnBhY2thZ2UgZGlyZWN0b3J5DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBTZXQgd29ya2luZyBkaXJlY3RvcnkNCm15TGlicmFyeSA8LSAiQ29udERhdGFRQyINCmRpcl9iYXNlIDwtICJDOi9Vc2Vycy9FcmlrLkxlcHBvL09uZURyaXZlIC0gVGV0cmEgVGVjaCwgSW5jL015RG9jc19PbmVEcml2ZS9HaXRIdWIiDQpzZXR3ZChmaWxlLnBhdGgoZGlyX2Jhc2UsIG15TGlicmFyeSkpDQoNCg0KIyBSZW1vdmUgYWxsIGZpbGVzIGluICJSZXN1bHRzIiBmb2xkZXINCiMgVHJpZ2dlcmVkIGhlcmUgc28gY2FuIHJ1biBkaWZmZXJlbnQgZmlsZXMNCnBhdGhfc2hpbnkgPC0gZmlsZS5wYXRoKCJpbnN0IiwgInNoaW55LWV4YW1wbGVzIiwgIkNvbnREYXRhUUMiKQ0KcGF0aF9yZXN1bHRzIDwtIGZpbGUucGF0aChwYXRoX3NoaW55LCAiZGF0YSIpDQpmbl9yZXN1bHRzIDwtIGxpc3QuZmlsZXMocGF0aF9yZXN1bHRzDQogICAgICAgICAgICAgICAgICAgICAgICAgLCBmdWxsLm5hbWVzID0gVFJVRQ0KICAgICAgICAgICAgICAgICAgICAgICAgICwgaW5jbHVkZS5kaXJzID0gRkFMU0UNCiAgICAgICAgICAgICAgICAgICAgICAgICAsIHJlY3Vyc2l2ZSA9IFRSVUUpDQpmaWxlLnJlbW92ZShmbl9yZXN1bHRzKSAjIG9rIGlmIG5vIGZpbGVzDQojIENvcHkgZmlsZSB0byBlbnN1cmUgZGlyZWN0b3J5IG5vdCBlbXB0eQ0KZm5fY29weSAgICA8LSAicmVtb3ZlLnR4dCINCnBhdGhfZnJvbSAgPC0gZmlsZS5wYXRoKHBhdGhfc2hpbnksICJleHRlcm5hbCIsIGZuX2NvcHkpDQpwYXRoX3RvICAgIDwtIGZpbGUucGF0aChwYXRoX3NoaW55LCAiZGF0YSIsIGZuX2NvcHkpDQpmaWxlLmNvcHkocGF0aF9mcm9tLCBwYXRoX3RvKQ0KDQojIE5FV1MNCiMgUmVuZGVyIHRoZW4gQ29weSBORVdTIHNvIHBpY2tlZCB1cCBpbiBoZWxwDQpybWFya2Rvd246OnJlbmRlcigiTkVXUy5ybWQiLCAiYWxsIikNCmZpbGUuY29weSgiTkVXUy5tZCIsICJORVdTIiwgb3ZlcndyaXRlID0gVFJVRSkNCmZpbGUucmVtb3ZlKCJORVdTLmh0bWwiKQ0KI2ZpbGUucmVtb3ZlKCJORVdTLm1kIikgIyBrZWVwIGZvciBwa2dkb3duIENIQU5HRSBMT0cNCiMNCiMgTG9hZCBMaWJyYXJ5DQpsaWJyYXJ5KGRldnRvb2xzKQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMgQ3JlYXRlIFBhY2thZ2UNCiMgY3JlYXRlKG15TGlicmFyeSkNCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIERvY3VtZW50LCBJbnN0YWxsLCBhbmQgUmVsb2FkIExpYnJhcnkNCiMjIEdlbmVyYXRlIERvY3VtZW50YXRpb24NCmRldnRvb2xzOjpkb2N1bWVudCgpDQojIyBJbnN0YWxsIE5ldyBQYWNrYWdlIChsb2NhbGx5KQ0Kc2V0d2QoIi4uIikgIyByZXR1cm4gdG8gcm9vdCBkaXJlY3RvcnkgZmlyc3QNCmRldnRvb2xzOjppbnN0YWxsKG15TGlicmFyeQ0KICAgICAgICAgICAgICAgICAgLCBidWlsZF92aWduZXR0ZXMgPSBUUlVFDQogICAgICAgICAgICAgICAgICAsIHF1aWNrID0gRkFMU0UNCiAgICAgICAgICAgICAgICAgICwgcmVsb2FkID0gVFJVRSkNCg0KIyMgUmVsb2FkIGxpYnJhcnkNCmxpYnJhcnkobXlMaWJyYXJ5LGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCiMgY2hhbmdlIHdkIGJhY2sgdG8gcGFja2FnZQ0Kc2V0d2QoZmlsZS5wYXRoKGRpcl9iYXNlLCBteUxpYnJhcnkpKQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCmBgYA0KDQpBZnRlciBjcmVhdGluZyB0aGUgcGFja2FnZSByZWxvYWQgaXQgYWZ0ZXIgcmVzdGFydGluZyBSIHdpdGhpbiBSU3R1ZGlvIA0KKEN0cmwgKyBTaGlmdCArIEYxMCkuDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBSZXN0YXJ0IFIgd2l0aGluIFJTdHVkaW86ICBDdHJsICsgU2hpZnQgKyBGMTANCnBrZyA8LSAiQ29udERhdGFRQyINCmxpYnJhcnkocGtnLCBjaGFyYWN0ZXIub25seSA9IFRSVUUpDQpoZWxwKHBhY2thZ2U9KHBrZykpDQpzaGVsbC5leGVjKHRlbXBkaXIoKSkNCiMNCj9QZXJpb2RTdGF0cw0KIz9Db21wU2l0ZUNERg0KPz9Db250RGF0YVFDDQo/ZnVuLkV4cG9ydC5JSEENCj9FeHBvcnQuU3RyZWFtVGhlcm1hbCAgDQpgYGANCg0KUGFja2FnZSB3ZWJzaXRlDQpVc2UgcGtnZG93biB0byBjcmVhdGUgc2l0ZS4NCg0KaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vdHZ0aGVtZXMtMS0xLTAtaXMtb24tY3Jhbi1jcmVhdGluZy1hLXBrZ2Rvd24td2Vic2l0ZS1ncmF2aXR5LWZhbGxzLXBhbGV0dGUtYW5kLW1vcmUvDQoNCmBgYHtyIFBrZ2Rvd24sIGV2YWw9RkFMU0V9DQojbGlicmFyeShwa2dkb3duKQ0KDQp1c2V0aGlzOjp1c2VfcGtnZG93bigpDQpwa2dkb3duOjpidWlsZF9zaXRlKCkNCg0KYGBgDQoNCiMgY29kZSBwZXJmb21hbmNlDQp0aW1lIGVhY2ggcGFydCBvZiBjb2RlDQoNCmBgYHtyIHByb2Z2aXN9DQojIFBhY2thZ2VzDQpsaWJyYXJ5KHByb2Z2aXMpDQoNCiMgUnVuIGV4YW1wbGUgY29kZQ0KIyMgU2V0IHVwDQojIEV4YW1wbGVzIG9mIGVhY2ggb3BlcmF0aW9uDQoNCiMgMDAuIFNldCB1cA0KIyBQYXJhbWV0ZXJzDQpTZWxlY3Rpb24uT3BlcmF0aW9uIDwtIGMoIkdldEdhZ2VEYXRhIg0KICAgICAgICAgICAgICAgICAgICAgICAgICwgIlFDUmF3Ig0KICAgICAgICAgICAgICAgICAgICAgICAgICwgIkFnZ3JlZ2F0ZSINCiAgICAgICAgICAgICAgICAgICAgICAgICAsICJTdW1tYXJ5U3RhdHMiKQ0KU2VsZWN0aW9uLlR5cGUgICAgICA8LSBjKCJBaXIiLCJXYXRlciIsIkFXIiwiR2FnZSIsIkFXRyIsIkFHIiwiV0ciKQ0KU2VsZWN0aW9uLlNVQiA8LSBjKCJEYXRhMF9PcmlnaW5hbCINCiAgICAgICAgICAgICAgICAgICAsICJEYXRhMV9SQVciDQogICAgICAgICAgICAgICAgICAgLCAiRGF0YTJfUUMiDQogICAgICAgICAgICAgICAgICAgLCAiRGF0YTNfQWdncmVnYXRlZCINCiAgICAgICAgICAgICAgICAgICAsICJEYXRhNF9TdGF0cyIpDQoobXlEaXIuQkFTRSA8LSB0ZW1wZGlyKCkpICMgY3JlYXRlIGFuZCBwcmludCB0ZW1wIGRpcmVjdG9yeSBmb3IgZXhhbXBsZSBkYXRhDQoNCiMgQ3JlYXRlIGRhdGEgZGlyZWN0b3JpZXMNCm15RGlyLmNyZWF0ZSA8LSBmaWxlLnBhdGgobXlEaXIuQkFTRSwgU2VsZWN0aW9uLlNVQlsxXSkNCiAgaWZlbHNlKGRpci5leGlzdHMobXlEaXIuY3JlYXRlKSA9PSBGQUxTRQ0KICAgICAgICAgLCBkaXIuY3JlYXRlKG15RGlyLmNyZWF0ZSkNCiAgICAgICAgICwgIkRpcmVjdG9yeSBhbHJlYWR5IGV4aXN0cyIpDQpteURpci5jcmVhdGUgPC0gZmlsZS5wYXRoKG15RGlyLkJBU0UsIFNlbGVjdGlvbi5TVUJbMl0pDQogIGlmZWxzZShkaXIuZXhpc3RzKG15RGlyLmNyZWF0ZSkgPT0gRkFMU0UNCiAgICAgICAgICwgZGlyLmNyZWF0ZShteURpci5jcmVhdGUpDQogICAgICAgICAsICJEaXJlY3RvcnkgYWxyZWFkeSBleGlzdHMiKQ0KbXlEaXIuY3JlYXRlIDwtIGZpbGUucGF0aChteURpci5CQVNFLCBTZWxlY3Rpb24uU1VCWzNdKQ0KICBpZmVsc2UoZGlyLmV4aXN0cyhteURpci5jcmVhdGUpID09IEZBTFNFDQogICAgICAgICAsIGRpci5jcmVhdGUobXlEaXIuY3JlYXRlKQ0KICAgICAgICAgLCAiRGlyZWN0b3J5IGFscmVhZHkgZXhpc3RzIikNCm15RGlyLmNyZWF0ZSA8LSBmaWxlLnBhdGgobXlEaXIuQkFTRSwgU2VsZWN0aW9uLlNVQls0XSkNCiAgaWZlbHNlKGRpci5leGlzdHMobXlEaXIuY3JlYXRlKSA9PSBGQUxTRQ0KICAgICAgICAgLCBkaXIuY3JlYXRlKG15RGlyLmNyZWF0ZSkNCiAgICAgICAgICwgIkRpcmVjdG9yeSBhbHJlYWR5IGV4aXN0cyIpDQpteURpci5jcmVhdGUgPC0gZmlsZS5wYXRoKG15RGlyLkJBU0UsIFNlbGVjdGlvbi5TVUJbNV0pDQogIGlmZWxzZShkaXIuZXhpc3RzKG15RGlyLmNyZWF0ZSkgPT0gRkFMU0UNCiAgICAgICAgICwgZGlyLmNyZWF0ZShteURpci5jcmVhdGUpDQogICAgICAgICAsICJEaXJlY3RvcnkgYWxyZWFkeSBleGlzdHMiKQ0KDQojIFNhdmUgZXhhbXBsZSBkYXRhIChhc3N1bWVzIG15RGlyLkJBU0UgZGlyZWN0b3J5IGV4aXN0cykNCm15RGF0YSA8LSBkYXRhX3Jhd190ZXN0Ml9BV18yMDEzMDQyNl8yMDEzMDcyNQ0KICB3cml0ZS5jc3YobXlEYXRhLCBmaWxlLnBhdGgobXlEaXIuQkFTRQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCBTZWxlY3Rpb24uU1VCWzJdDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICJ0ZXN0Ml9BV18yMDEzMDQyNl8yMDEzMDcyNS5jc3YiKSkNCm15RGF0YSA8LSBkYXRhX3Jhd190ZXN0Ml9BV18yMDEzMDcyNV8yMDEzMTAxNQ0KICB3cml0ZS5jc3YobXlEYXRhLCBmaWxlLnBhdGgobXlEaXIuQkFTRQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCBTZWxlY3Rpb24uU1VCWzJdDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICJ0ZXN0Ml9BV18yMDEzMDcyNV8yMDEzMTAxNS5jc3YiKSkNCm15RGF0YSA8LSBkYXRhX3Jhd190ZXN0Ml9BV18yMDE0MDkwMV8yMDE0MDkzMA0KICB3cml0ZS5jc3YobXlEYXRhLCBmaWxlLnBhdGgobXlEaXIuQkFTRQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCBTZWxlY3Rpb24uU1VCWzJdDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICJ0ZXN0Ml9BV18yMDE0MDkwMV8yMDE0MDkzMC5jc3YiKSkNCm15RGF0YSA8LSBkYXRhX3Jhd190ZXN0NF9BV18yMDE2MDQxOF8yMDE2MDcyNg0KICB3cml0ZS5jc3YobXlEYXRhLCBmaWxlLnBhdGgobXlEaXIuQkFTRQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLCBTZWxlY3Rpb24uU1VCWzJdDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsICJ0ZXN0NF9BV18yMDE2MDQxOF8yMDE2MDcyNi5jc3YiKSkNCm15RmlsZSA8LSAiY29uZmlnLlRaLkNlbnRyYWwuUiINCiAgZmlsZS5jb3B5KGZpbGUucGF0aChwYXRoLnBhY2thZ2UoIkNvbnREYXRhUUMiKSwgImV4dGRhdGEiLCBteUZpbGUpDQogICAgICAgICAgICAsIGZpbGUucGF0aChteURpci5CQVNFLCBTZWxlY3Rpb24uU1VCWzJdLCBteUZpbGUpKQ0KICANCm15RGF0YS5PcGVyYXRpb24gICAgICAgPC0gIlFDUmF3IiAjU2VsZWN0aW9uLk9wZXJhdGlvblsyXQ0KbXlEYXRhLlNpdGVJRCAgICAgICAgICA8LSAidGVzdDIiDQpteURhdGEuVHlwZSAgICAgICAgICAgIDwtIFNlbGVjdGlvbi5UeXBlWzNdICMiQVciDQpteURhdGEuRGF0ZVJhbmdlLlN0YXJ0IDwtICIyMDEzLTAxLTAxIg0KbXlEYXRhLkRhdGVSYW5nZS5FbmQgICA8LSAiMjAxNC0xMi0zMSINCm15RGlyLmltcG9ydCAgICAgICAgICAgPC0gZmlsZS5wYXRoKG15RGlyLkJBU0UsIFNlbGVjdGlvbi5TVUJbMl0pICMiRGF0YTFfUkFXIg0KbXlEaXIuZXhwb3J0ICAgICAgICAgICA8LSBmaWxlLnBhdGgobXlEaXIuQkFTRSwgU2VsZWN0aW9uLlNVQlszXSkgIyJEYXRhMl9RQyINCm15UmVwb3J0LmZvcm1hdCAgICAgICAgPC0gImRvY3giDQoNCg0KIyBTYXZlDQpwIDwtIHByb2Z2aXMoew0KICBDb250RGF0YVFDKG15RGF0YS5PcGVyYXRpb24NCiAgICAgICAgICAgLCBteURhdGEuU2l0ZUlEDQogICAgICAgICAgICwgbXlEYXRhLlR5cGUNCiAgICAgICAgICAgLCBteURhdGEuRGF0ZVJhbmdlLlN0YXJ0DQogICAgICAgICAgICwgbXlEYXRhLkRhdGVSYW5nZS5FbmQNCiAgICAgICAgICAgLCBteURpci5pbXBvcnQNCiAgICAgICAgICAgLCBteURpci5leHBvcnQNCiAgICAgICAgICAgLCBmdW4ubXlSZXBvcnQuZm9ybWF0ID0gbXlSZXBvcnQuZm9ybWF0KQ0KfSkNCg0KIyBTYXZlIHRvIEhUTUwNCmh0bWx3aWRnZXRzOjpzYXZlV2lkZ2V0KHAsIGZpbGUucGF0aCh0ZW1wZGlyKCksICJwcm9maWxlLmh0bWwiKSkNCg0KIyBPcGVuIGluIGJyb3dzZXIgZnJvbSBSDQpicm93c2VVUkwoZmlsZS5wYXRoKHRlbXBkaXIoKSwgInByb2ZpbGUuaHRtbCIpKQ0KDQpgYGANCg0KDQpUZXN0aW5nIG9mIGNvbmZpZ3VyYXRpb24gYW5kIFJNRCBmaWxlcy4NCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpsaWJyYXJ5KENvbnREYXRhUUMpDQojIFBhcmFtZXRlcnMNClNlbGVjdGlvbi5PcGVyYXRpb24gPC0gYygiR2V0R2FnZURhdGEiLCJRQ1JhdyIsICJBZ2dyZWdhdGUiLCAiU3VtbWFyeVN0YXRzIikNClNlbGVjdGlvbi5UeXBlICAgICAgPC0gYygiQWlyIiwiV2F0ZXIiLCJBVyIsIkdhZ2UiLCJBV0ciLCJBRyIsIldHIikNClNlbGVjdGlvbi5TVUIgPC0gYygiRGF0YTFfUkFXIiwiRGF0YTJfUUMiLCJEYXRhM19BZ2dyZWdhdGVkIiwiRGF0YTRfU3RhdHMiKQ0KbXlEaXIuQkFTRSA8LSBnZXR3ZCgpDQojDQojIEFnZ3JlZ2F0ZSBEYXRhDQpteURhdGEuT3BlcmF0aW9uIDwtICJBZ2dyZWdhdGUiICNTZWxlY3Rpb24uT3BlcmF0aW9uWzNdDQpteURhdGEuU2l0ZUlEICAgIDwtICJ0ZXN0MiINCm15RGF0YS5UeXBlICAgICAgPC0gU2VsZWN0aW9uLlR5cGVbM10gIyJBVyINCm15RGF0YS5EYXRlUmFuZ2UuU3RhcnQgIDwtICIyMDEzLTAxLTAxIg0KbXlEYXRhLkRhdGVSYW5nZS5FbmQgICAgPC0gIjIwMTQtMTItMzEiDQpteURpci5pbXBvcnQgPC0gZmlsZS5wYXRoKG15RGlyLkJBU0UsU2VsZWN0aW9uLlNVQlsyXSkgIyJEYXRhMl9RQyINCm15RGlyLmV4cG9ydCA8LSBmaWxlLnBhdGgobXlEaXIuQkFTRSxTZWxlY3Rpb24uU1VCWzNdKSAjIkRhdGEzX0FnZ3JlZ2F0ZWQiDQpteVJlcG9ydC5mb3JtYXQgPC0gImRvY3giDQojDQojIHNldCBjb25maWcgZmlsZSB3aXRoIFJNRCBkaXJlY3RvcnkgYXMgZ2V0d2QoKQ0KbXlDb25maWcgICAgICAgICAgICA8LSBmaWxlLnBhdGgoZ2V0d2QoKSxTZWxlY3Rpb24uU1VCWzJdLCJjb25maWcuUk1EZGlyLlIiKQ0KIyBydW4gZnVuY3Rpb24NCkNvbnREYXRhUUMobXlEYXRhLk9wZXJhdGlvbiwgbXlEYXRhLlNpdGVJRCwgbXlEYXRhLlR5cGUsIG15RGF0YS5EYXRlUmFuZ2UuU3RhcnQNCiAgICAgICAgICAgLCBteURhdGEuRGF0ZVJhbmdlLkVuZCwgbXlEaXIuaW1wb3J0LCBteURpci5leHBvcnQNCiAgICAgICAgICAgLCBmdW4ubXlSZXBvcnQuZm9ybWF0PW15UmVwb3J0LmZvcm1hdCwgZnVuLm15Q29uZmlnID0gbXlDb25maWcpDQpgYGANCg0KDQojIyBJbmNsdWRpbmcgRGF0YQ0KQWxsIGRhdGEgc2hvdWxkIGhhdmUgYWxyZWFkeSBiZWVuIGNyZWF0ZWQuDQoNCiMjIENoZWNrDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBDaGVjayBmb3IgZXJyb3JzIChvciBwcmVzcyBDbWQgKyBTaGlmdCArIEUgaW4gUlN0dWRpbykNCiNodHRwOi8vci1wa2dzLmhhZC5jby5uei9jaGVjay5odG1sDQpkZXZ0b29sczo6Y2hlY2soKQ0KYGBgDQoNCklmIHVzZSBSU3R1ZGlvLCBCdWlsZCAtIENoZWNrIFBhY2thZ2UsIHRoZSBvdXRwdXQgaXMgZWFzaWVyIHRvIHJlYWQuIA0KDQojIyBUZXN0DQpOZWVkIHRvIHVzZSB0ZXN0dGhhdCBidXQgbm90IHRvIHRoYXQgc3RhZ2UgeWV0Lg0KDQpSU3R1ZGlvLCBCdWlsZCAtIFRlc3QgUGFja2FnZS4NCg0KIyBDSSwgQmFkZ2VzLCBDb2RlIENvdmVyYWdlLCBldGMNCiogQ29udGludW91cyBJbnRlZ3JhdGlvbiB3aXRoIEdpdEh1YiBBY3Rpb25zIChUcmF2aXNDSSBzaHV0IGRvd24gRGVjIDIwMjApDQoqIENvZGUgUXVhbGl0eSAoQ29kZUZhY3RvcikNCiAgICArIENvZGVGYWN0b3IuaW8NCiAgICAgICAgLSBHaXRIdWIgbG9naW4NCiogQ29kZSBDb3ZlcmFnZSAodGVzdGluZykNCiAgICArIENvZGVjb3YuaW8NCiAgICAgICAgLSBHaXRIdWIgbG9naW4NCiAgICAgICAgLSBBZnRlciBzZXQgdXAgQ0kgd2l0aCBHaXRIdWIgQWN0aW9ucw0KKiBQYWNrYWdlIHdlYnNpdGUgKHBrZ2Rvd24gYW5kIEdpdEh1YiBBY3Rpb24pDQogICAgKyBicmFuY2ggZ2gtcGFnZXMsIGF1dG8gdXBkYXRlcyB3aXRoIGVhY2ggY29tbWl0DQogICAgKyBVcGRhdGUgaW4gc2V0dGluZ3MgdGhlIGxvY2F0aW9uDQoqIEJhZGdlczsgTWFpbnRhaW5lZCwgTGlmZSBDeWNsZSwgTGljZW5zZSwgSXNzdWVzLCBldGMNCiAgICArIGh0dHBzOi8vZ2l0aHViLmNvbS9HdWFuZ2NodWFuZ1l1L2JhZGdlcg0KICAgICAgICAtIENvbW1hbmRzIHRvIGNyZWF0ZSBiYWRnZXMNCg0KYmFkZ2VyIHBhY2thZ2UgY3JlYXRlcyB0aGUgdGV4dCBmb3IgcGtnIHJlYWRtZSBmaWxlLg0KICAgICAgICANCkFsc28NCmh0dHBzOi8vc2hpZWxkcy5pby8gICAgICAgIA0KaHR0cHM6Ly9naXRodWIuY29tL2JhZGdlcy9zaGllbGRzDQpDYW4gbWFrZSBzb21lIGJhZGdlcyBkeW5hbWljLCBzdGF0aWMgb25lcyBiZWxvdw0KDQojIGlzc3Vlcw0KWyFbR2l0SHViIGlzc3Vlc10oaHR0cHM6Ly9pbWcuc2hpZWxkcy5pby9naXRodWIvaXNzdWVzL2xlcHBvdHQvTUJTU3Rvb2xzLnN2ZyldKGh0dHBzOi8vR2l0SHViLmNvbS9sZXBwb3R0L01CU1N0b29scy9pc3N1ZXMvKQ0KIyByZWxlYXNlDQpbIVtHaXRIdWIgcmVsZWFzZV0oaHR0cHM6Ly9pbWcuc2hpZWxkcy5pby9naXRodWIvcmVsZWFzZS9sZXBwb3R0L01CU1N0b29scy5zdmcpXShodHRwczovL0dpdEh1Yi5jb20vbGVwcG90dC9NQlNTdG9vbHMvcmVsZWFzZXMvKQ0KIyBkb3dubG9hZHMNClshW0dpdGh1YiBhbGwgcmVsZWFzZXNdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vZ2l0aHViL2Rvd25sb2Fkcy9sZXBwb3R0L01CU1N0b29scy90b3RhbC5zdmcpXShodHRwczovL0dpdEh1Yi5jb20vbGVwcG90dC9NQlNTdG9vbHMvcmVsZWFzZXMvKQ0KICAgICAgICANCmBgYHtyfQ0KcGtnX0dIIDwtICJsZXBwb3R0L0NvbnREYXRhUUMiDQpwa2dfbGljIDwtICJNSVQiDQoNCiMgR2l0SHViIEFjdGlvbiwgQ0kNCnVzZXRoaXM6OnVzZV9naXRodWJfYWN0aW9ucygpDQp1c2V0aGlzOjp1c2VfZ2l0aHViX2FjdGlvbnNfYmFkZ2UoKQ0KIyBiYWRnZXI6OmJhZGdlX2dpdGh1Yl9hY3Rpb25zKHBrZ19HSCkNCg0KIyBjb2RlIGNvdmVyYWdlDQp1c2V0aGlzOjp1c2VfZ2l0aHViX2FjdGlvbigidGVzdC1jb3ZlcmFnZSIpDQoNCiMgR2l0SHViIEFjdGlvbiwgcGtnZG93bg0KdXNldGhpczo6dXNlX2dpdGh1Yl9hY3Rpb24oInBrZ2Rvd24iKQ0KDQojIEJhZGdlcw0KIyBsaWZlY3ljbGUNCmJhZGdlcjo6YmFkZ2VfbGlmZWN5Y2xlKCJzdGFibGUiLCAiZ3JlZW4iKSAjIHN0YWJsZS9ncmVlbiwgbWF0dXJpbmcvZG9ybWFudC9ibHVlDQojIG1haW50YWluZWQNCiMgbGljZW5zZQ0KYmFkZ2VyOjpiYWRnZV9saWNlbnNlKCkNCiMgY29kZSBxdWFsaXR5DQpiYWRnZXI6OmJhZGdlX2NvZGVmYWN0b3IocGtnX0dIKQ0KIyBjb2RlIHRlc3RpbmcgY292ZXJhZ2UNCmJhZGdlcjo6YmFkZ2VfY29kZWNvdihwa2dfR0gpDQojIGNtZCBjaGVjaw0KYmFkZ2VyOjpiYWRnZV9naXRodWJfYWN0aW9ucyhwa2dfR0gpDQoNCg0KYGBgDQoNCg0KDQojIE90aGVyIFN0dWZmDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMgVXBsb2FkIHRvIEdpdGh1YiB2aWEgR2l0SHViIERlc2t0b3AgdXRpbGl0eQ0KIyAwLiBkb3dubG9hZCBmcm9tIHdlYiB2aWEgImNsb25lIG9yIGRvd25sb2FkIiB2aWEgIk9wZW4gaW4gRGVza3RvcCIgKEdpdEh1YiBEZXNrdG9wKSBpZiBub3QgYWxyZWFkeSBpbiBHaXRIdWIgRGVza3RvcA0KIyAxLiBNYWtlIGNoYW5nZXMgaW4gZG93bmxvYWQvY2xvbmUgZm9sZGVyLiAoZG9uZSBhYm92ZSkNCiMgMy4gT3BlbiBHSCBEZXNrdG9wIGNvbW1pdCBjaGFuZ2VzIHRoZW4gc3luYy4NCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIGluc3RhbGwgZnJvbSBHaXRIdWIgKHZpYSBkZXZ0b29scykNCm15TGlicmFyeSA8LSAiQ29udERhdGFRQyINCmRldnRvb2xzOjppbnN0YWxsX2dpdGh1YihwYXN0ZTAoImxlcHBvdHQvIixteUxpYnJhcnkpKQ0KIw0KDQoNCg0KI35+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCiMgcmVtb3ZlIGluc3RhbGxlZCBwYWNrYWdlcyAoaWYgbmVlZGVkIGZvciB0cm91Ymxlc2hvb3RpbmcpDQpzZWFyY2goKSAjIGZpbmQNCiNkZXRhY2goMykgIyByZW1vdmUgYnkgbnVtYmVyDQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KDQoNCiMgdG8gYnVpbGQgcGFja2FnZQ0KI2h0dHBzOi8vdGhlcG9saXRpY2FsbWV0aG9kb2xvZ2lzdC5jb20vMjAxNC8wOC8xNC9idWlsZGluZy1hbmQtbWFpbnRhaW5pbmctci1wYWNrYWdlcy13aXRoLWRldnRvb2xzLWFuZC1yb3h5Z2VuMi8NCiMgVG8gYnVpbGQgdGhlIHBhY2thZ2UgYXMgYSBjb21wcmVzc2VkIGZpbGUgaW4geW91ciB3b3JraW5nIGRpcmVjdG9yeSwgcnVuIGJ1aWxkKGN1cnJlbnQuY29kZSwgcGF0aD1nZXR3ZCgpKS4NCg0KIyB0byBzYXZlIGludGVybmFsIGRhdGEgZm9yIGV4YW1wbGVzDQojIGV4YW1wbGUNCiNodHRwOi8vci1wa2dzLmhhZC5jby5uei9kYXRhLmh0bWwjZGF0YS1zeXNkYXRhDQojIGhhdmUgdG8gYmUgYXQgcm9vdCBkaXJlY3RvcnkgKGFib3ZlIHBhY2thZ2UpDQojZGV2dG9vbHM6OnVzZV9kYXRhKE5WLnByZWRpY3RvcnMsTlYuYnVncyxwa2c9Ik1NSWNhbGNOViIsaW50ZXJuYWw9VFJVRSxvdmVyd3JpdGU9VFJVRSkNCiMjIHZlcmlmeSB3aXRoIGRhdGEoKQ0KDQojIFRvIHNhdmUgUk1EIGZpbGVzDQojIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzAzNzcyMTMvaG93LXRvLWluY2x1ZGUtcm1hcmtkb3duLWZpbGUtaW4tci1wYWNrYWdlDQojIC9wa2cvaW5zdC9ybWQvDQojIHN5c3RlbS5maWxlKCJybWQvZmlsZS5SbWQiLCBwYWNrYWdlPSJwYWNrYWdlbmFtZSIpDQojDQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KI2h0dHBzOi8vaGlsYXJ5cGFya2VyLmNvbS8yMDE0LzA0LzI5L3dyaXRpbmctYW4tci1wYWNrYWdlLWZyb20tc2NyYXRjaC8NCiMgQ3JlYXRlIFBhY2thZ2UNCiMgY3JlYXRlKG15TGlicmFyeSkNCg0KYGBgDQoNCiMgVGVzdCBTdGF0cyBvbmx5DQoNCg0KYGBge3IgU3RhdHNfR2FnZSwgZXZhbD1GQUxTRX0NCiMgUGFyYW1ldGVycw0KU2VsZWN0aW9uLk9wZXJhdGlvbiA8LSBjKCJHZXRHYWdlRGF0YSIsIlFDUmF3IiwgIkFnZ3JlZ2F0ZSIsICJTdW1tYXJ5U3RhdHMiKQ0KU2VsZWN0aW9uLlR5cGUgICAgICA8LSBjKCJBaXIiLCJXYXRlciIsIkFXIiwiR2FnZSIsIkFXRyIsIkFHIiwiV0ciKQ0KU2VsZWN0aW9uLlNVQiA8LSBjKCJEYXRhMV9SQVciLCJEYXRhMl9RQyIsIkRhdGEzX0FnZ3JlZ2F0ZWQiLCJEYXRhNF9TdGF0cyIpDQpteURpci5CQVNFIDwtIGdldHdkKCkNCiMNCiMgU3VtbWFyeSBTdGF0cywgRmlsZQ0KIyMgSGF2ZSB0byB1c2UgImZpbGUiIHZlcnNpb24uICANCiMjIEJhc2UgdmVyc2lvbiBidWlsZHMgZmlsZSBuYW1lIGFuZCBleHBlY3RzICJEQVRBIiBwcmVmaXgNCg0KIyBHYWdlIEZpbGUgKyBPdGhlciBGaWxlDQpteURhdGEuT3BlcmF0aW9uIDwtICJTdW1tYXJ5U3RhdHMiICNTZWxlY3Rpb24uT3BlcmF0aW9uWzRdDQpteUZpbGUgPC0gYygiRGF0YTRTdGF0c18wMTE4NzMwMF9HYWdlXzIwMTMwMTAxXzIwMTQxMjMxLmNzdiINCiAgICAgICAgICAgICwiRGF0YTRTdGF0c190ZXN0Ml9Bd18yMDEzMDEwMV8yMDE0MTIzMS5jc3YiKQ0KbXlEaXIuaW1wb3J0IDwtIGZpbGUucGF0aCgiLiIsImRhdGEtcmF3IikNCm15RGlyLmV4cG9ydCA8LSBmaWxlLnBhdGgoIi4iLCJEYXRhNF9TdGF0cyIpDQoNCiNMZWF2ZSBvZmYgbXlSZXBvcnQuZm9ybWF0IGFuZCBnZXQgZGVmYXVsdCAoZG9jeCkuDQpDb250RGF0YVFDKG15RGF0YS5PcGVyYXRpb24NCiAgICAgICAgICAgLCBmdW4ubXlEaXIuaW1wb3J0PW15RGlyLmltcG9ydA0KICAgICAgICAgICAsIGZ1bi5teURpci5leHBvcnQ9bXlEaXIuZXhwb3J0DQogICAgICAgICAgICwgZnVuLm15RmlsZT1teUZpbGUpDQoNCg0KYGBgDQoNClNpdGVJRCwgRGF0ZSwgVGltZSwgRGF0ZS5UaW1lLCBQYXJhbWV0ZXJzLCBGbGFnLlBhcmFtZXRlcnMNCg0KT25seSBvbmUgZmxhZyBwZXIgcGFyYW1ldGVyLiAgRG8gbm90IG5lZWQgaW5kaXZpZHVhbCB0ZXN0IGZsYWdzLg0KDQoiRiIgKGZhaWwpIGZsYWdzIGFyZSBjaGFuZ2VkIHRvIE5BIHNvIHRoZXkgYXJlIGRyb3BwZWQgZnJvbSB0aGUgc3RhdGlzdGljcyB0aGF0IGNhbGN1bGF0ZWQuDQoNCk1vY2tlZCB1cCAyIGZpbGVzLg0K
diff --git a/inst/shiny-examples/ContDataQC/ui.R b/inst/shiny-examples/ContDataQC/ui.R index 3c81502..17a2015 100644 --- a/inst/shiny-examples/ContDataQC/ui.R +++ b/inst/shiny-examples/ContDataQC/ui.R @@ -320,7 +320,7 @@ shinyUI( # IMPORTANT! For a navbar page, you will need to place the header and footer inside the navbar section (as shown below) - # you will then want to comment out lines 201-213 and lines 254-263 navbarPage( - title = h2("Continuous data QC, summary, and statistics - v2.0.7.9024"), + title = h2("Continuous data QC, summary, and statistics - v2.0.7.9025"), #theme= shinytheme("spacelab"), header = HTML( '