Metadados

Os metadados consistem em explicações sobre a estrutura de dados. Por exemplo, o significado dos códigos ou abreviações presentes em uma data tabela, do que se trata a informação presente nas linhas e nas colunas, o que uma dada função faz. Reportar precisamente o que cada arquivo contém é de extrema importância para garantir com que outras pessoas, ou mesmo o você do futuro saiba o que foi/está sendo feito no projeto científico.

Os metadados não servem apenas para reportar o significado das variáveis em tabelas, isso por si só já seria um motivo relevante para termos metadados, mas também para facilitar a integração de bases diferentes de dados. Imagine só ter que navegar manualmente nos metadados de estudos de diferentes grupos, com dados coletados com diferentes métodos, tabelas que adotam diferentes códigos, com distantas escalas espaciais e temporais. Até seria possível, mas talvez a taxa com que perdemos espécies e habitats seja mais rápida (e está sendo) que nossa capacidade de síntese de dados. Portanto, os metadados não servem apenas para o nosso interesse próprio de organização, mas ao utilizarmos os metadados estamos contribuindo para um avanço mais rápido do processo científico.

Dada tais importâncias citadas acima, os metadados ideais devem seguir um esquema onde podem ser lidos por humanos (human-readable) e por computadores (machine-readable). Desta forma, nesta seção vamos praticar a elaboração de metadados que seguem essa característica, e que o formato foi pensado para satisfazer as especificidades dos dados ecológicos. Para tanto vamos utilizar o pacote EML.

Leituras sugeridas

Para uma itrodução mais completa sobre os metadados sugiro este artigo. Para uma introdução da importância dos metadados para contruir conjuntos de dados integrados sugiro o artigo de Jones et al. (2006). Para um exemplo de base de dados online que se utiliza das potencialidades dos metadados sugiro visitar o KNB - Knowledge Network Biocomplexity.

Exemplos de metadados

Para um exemplo simples de como um metadado se parece veja aqui. Para um exemplo mais completo sugiro este arquivo. Esta introdução trazida pelo NEON (National Ecological Observatory) é muito interessante para compreender de maneira geral a importância de metadados para síntese e como eles podem ser obtidos facilmente com auxílio do pacote EML. O DataOne é uma plataforma de dados que também se utiliza dos arquivos XML para reportar as características gerais dos dados.

Metadados na prática - utilizando o pacote {EML}

Nesta seção iremos utilizar o conjunto de dados do artigo “Organic-matter loading determines regime shifts and alternative states in an aquatic ecosystem”. Optamos por usar este dado pois ele já apresenta um arquivo de metadados associado, assim podemos reconstruí-lo e verificar como fica. Além disso ele é o mesmo dado utilizado no tutorial original do pacote EML, sendo conveniente para fins didáticos. Ao final vamos praticar com um outro conjunto de dados. Lembrando que se você baixou o repositório do material desta disciplina, você conseguirá ler os dados sem problemas.

Instalação

Para instalar o pacote EML faça o seguinte:

install.packages("EML")

library(EML)

Vamos utilizar um conjunto de dados contidos no próprio pacote EML para facilitar a compreensão dos passos necessários para construir um EML completo

Construindo um EML - Harvard Forest Data

Construindo os Atributos

Os atributos são as descrições para as variáveis contidas na nossa tabela. Aquela aba contendo as informações das variáveis, pois então, esta seria os atributos da sua tabela de dados. Então, primeiro precisamos de uma tabela de atributos que define o significado geral de cada variável em nossa tabela de dados. Esta tabela pode ser gerada aqui no R direto, como no exemplo abaixo, mas pode ser importada a partir de uma tabela .csv. A tabela segue o formato a seguir:

attributes <-
tibble::tribble(
~attributeName, ~attributeDefinition,                                                 ~formatString, ~definition,        ~unit,   ~numberType,
  "run.num",    "which run number (=block). Range: 1 - 6. (integer)",                 NA,            "which run number", NA,       NA,
  "year",       "year, 2012",                                                         "YYYY",        NA,                 NA,       NA,
  "day",        "Julian day. Range: 170 - 209.",                                      "DDD",         NA,                 NA,       NA,
  "hour.min",   "hour and minute of observation. Range 1 - 2400 (integer)",           "hhmm",        NA,                 NA,       NA,
  "i.flag",     "is variable Real, Interpolated or Bad (character/factor)",           NA,            NA,                 NA,       NA,
  "variable",   "what variable being measured in what treatment (character/factor).", NA,            NA,                 NA,       NA,
  "value.i",    "value of measured variable for run.num on year/day/hour.min.",       NA,            NA,                 NA,       NA,
  "length",    "length of the species in meters (dummy example of numeric data)",     NA,            NA,                 "meter",  "real")

Dê uma olhada na tabela de atributos (pode ser feito usano a função View ou abrindo no Excel). A maioria dos dados seguem este formato geral.

A seguir precisamos descrever os atributos que apresentam níveis. Por exemplo o atributo chamado variable apresenta oito níveis. A estratégia seguida aqui foi criar vetores com os códigos usados para cada nível dos atributos e uma pequena explicação.

i.flag <- c(R = "real",
            I = "interpolated",
            B = "bad")
variable <- c(
  control  = "no prey added",
  low      = "0.125 mg prey added ml-1 d-1",
  med.low  = "0,25 mg prey added ml-1 d-1",
  med.high = "0.5 mg prey added ml-1 d-1",
  high     = "1.0 mg prey added ml-1 d-1",
  air.temp = "air temperature measured just above all plants (1 thermocouple)",
  water.temp = "water temperature measured within each pitcher",
  par       = "photosynthetic active radiation (PAR) measured just above all plants (1 sensor)"
)

value.i <- c(
  control  = "% dissolved oxygen",
  low      = "% dissolved oxygen",
  med.low  = "% dissolved oxygen",
  med.high = "% dissolved oxygen",
  high     = "% dissolved oxygen",
  air.temp = "degrees C",
  water.temp = "degrees C",
  par      = "micromoles m-1 s-1"
)

## Write these into the data.frame format
factors <- rbind(
data.frame(
  attributeName = "i.flag",
  code = names(i.flag),
  definition = unname(i.flag)
),
data.frame(
  attributeName = "variable",
  code = names(variable),
  definition = unname(variable)
),
data.frame(
  attributeName = "value.i",
  code = names(value.i),
  definition = unname(value.i)
)
)

Após especificadas as características das variáveis categóricas (as contínuas já estão especificadas na tabela geral de atributos attributes), usamos a função set_attributes para criar a lista de atributos geral dos dados, onde devemos especificar o tipo de atributo que estamos inserindo (se caracter, se data, se fator etc..)

attributeList <- set_attributes(attributes, factors, col_classes = c("character", "Date", "Date", "Date", "factor", "factor", "factor", "numeric"))

Construindo as características físicas do dado

Aqui vamos especificar as características físicas do próprio arquivo de dados que utilizamos, ou seja, o formato, o tipo de compressão do arquivo, o separador etc. Resumindo, aqui é especificado a característica do arquivo. Isso é feito facilmente com a função set_physical. Se estivermos utilizando um arquivo .csv a função já extrai automaticamente a maior parte das características relevantes do arquivo de dados.

physical <- set_physical(here::here("data", "hf205-01-TPexp1-EML-Exemple.csv"))

Juntando Atributos e Características físicas

Com o objeto de atributos e o objeto de características físicas temos o essencial para descrever o nosso conjunto de dados. Agora vamos juntar ambos com mais algumas informações em uma única lista e denominar isso como sendo o nosso dataTable

dataTable <- list(
                 entityName = "hf205-01-TPexp1.csv",
                 entityDescription = "tipping point experiment 1",
                 physical = physical,
                 attributeList = attributeList)

Características adicionais - extensão geográfica, métodos e outros

geographicDescription <- "Harvard Forest Greenhouse, Tom Swamp Tract (Harvard Forest)"


coverage <- 
  set_coverage(begin = '2012-06-01', end = '2013-12-31',
               sci_names = "Sarracenia purpurea",
               geographicDescription = geographicDescription,
               west = -122.44, east = -117.15, 
               north = 37.38, south = 30.00,
               altitudeMin = 160, altitudeMaximum = 330,
               altitudeUnits = "meter")

Para descrever os métodos em metadados

methods_file <- here::here("data", "hf205-methods.docx")
methods <- set_methods(methods_file)

Identificação dos indivíduos endereço e outras informações sobre contatos

R_person <- person("Aaron", "Ellison", ,"fakeaddress@email.com", "cre", 
                  c(ORCID = "0000-0003-4151-6081"))
aaron <- as_emld(R_person)
others <- c(as.person("Benjamin Baiser"), as.person("Jennifer Sirota"))
associatedParty <- as_emld(others)
associatedParty[[1]]$role <- "Researcher"
associatedParty[[2]]$role <- "Researcher"

HF_address <- list(
                  deliveryPoint = "324 North Main Street",
                  city = "Petersham",
                  administrativeArea = "MA",
                  postalCode = "01366",
                  country = "USA")

publisher <- list(
                 organizationName = "Harvard Forest",
                 address = HF_address)


contact <- 
  list(
    individualName = aaron$individualName,
    electronicMailAddress = aaron$electronicMailAddress,
    address = HF_address,
    organizationName = "Harvard Forest",
    phone = "000-000-0000")

criando keywords para os dados

keywordSet <- list(
    list(
        keywordThesaurus = "LTER controlled vocabulary",
        keyword = list("bacteria",
                    "carnivorous plants",
                    "genetics",
                    "thresholds")
        ),
    list(
        keywordThesaurus = "LTER core area",
        keyword =  list("populations", "inorganic nutrients", "disturbance")
        ),
    list(
        keywordThesaurus = "HFR default",
        keyword = list("Harvard Forest", "HFR", "LTER", "USA")
        ))

Outras informações relevantes como abstract etc

pubDate <- "2012" 

title <- "Thresholds and Tipping Points in a Sarracenia 
Microecosystem at Harvard Forest since 2012"

abstract <- "The primary goal of this project is to determine
  experimentally the amount of lead time required to prevent a state
change. To achieve this goal, we will (1) experimentally induce state
changes in a natural aquatic ecosystem - the Sarracenia microecosystem;
(2) use proteomic analysis to identify potential indicators of states
and state changes; and (3) test whether we can forestall state changes
by experimentally intervening in the system. This work uses state-of-the
art molecular tools to identify early warning indicators in the field
of aerobic to anaerobic state changes driven by nutrient enrichment
in an aquatic ecosystem. The study tests two general hypotheses: (1)
proteomic biomarkers can function as reliable indicators of impending
state changes and may give early warning before increasing variances
and statistical flickering of monitored variables; and (2) well-timed
intervention based on proteomic biomarkers can avert future state changes
in ecological systems."  

intellectualRights <- "This dataset is released to the public and may be freely
  downloaded. Please keep the designated Contact person informed of any
plans to use the dataset. Consultation or collaboration with the original
investigators is strongly encouraged. Publications and data products
that make use of the dataset must include proper acknowledgement. For
more information on LTER Network data access and use policies, please
see: http://www.lternet.edu/data/netpolicy.html."

Criando o arquivo XML

Agora que todas as informações foram criadas (atributos, dados físicos do arquivo, coverage, dados de contato), precisamos juntar todas elas em uma única lista.

dataset <- list(
               title = title,
               creator = aaron,
               pubDate = pubDate,
               intellectualRights = intellectualRights,
               abstract = abstract,
               associatedParty = associatedParty,
               keywordSet = keywordSet,
               coverage = coverage,
               contact = contact,
               methods = methods,
               dataTable = dataTable)

Antes de criar o arquivo XML é importante criar um uuid para o arquivo, que nada mais é que um identificador que qualquer um pode criar, como demonstrado a seguir. Para mais informações sobre o que é um uuid ver esta explicação no Wikipedia

eml <- list(
           packageId = uuid::UUIDgenerate(),
           system = "uuid", # type of identifier
           dataset = dataset)

Finalmente criando o arquivo XML e validando.

write_eml(eml, here::here("data", "eml_tutorialHF205.xml"))
eml_validate(here::here("data", "eml_tutorialHF205.xml"))

Metadados para dados de biodiversidade

Se você ainda não passou pela seção de metadados usando o pacote EML, volte um pouco, por favor. Lá apresento uma introdução geral sobre metadados em XML e como montá-los usando o pacote EML no R. Aqui abordarei especificamente como montar arquivos com metadados para dados de biodiversidade (ocorrência, lista de espécies, pontos etc).

Leituras sugeridas

Esta seção é baseada no documento produzido pelo Living Norway Project, que também oferece uma introdução muito interessante sobre Darwin Core e metadados para biodiversidade.

Exemplos de metadados de biodiversidade

O melhor exemplo de esturutura digital que utiliza metadados de biodiversidade construídos desta maneira que mostrarei é o GBIF.

Metadados na prática - utilizando o pacote {LivingNorwayR}

Instalação e dados

Primeiro vamos instalar o pacote

devtools::install_github("https://github.com/LivingNorway/LivingNorwayR")
library(LivingNorwayR)

Aqui os dados que serão utilizados no exemplo. Estes são os mesmos dados utilizados no tuturial do Living Norway R. Para mais detalhes visite a página deles.

Vamos utilizar um conjunto de dados que fizemos o download e está dentro da nossa pasta do curso para criar nosso arquivo Darwin Core.

# Lendo o arquivo core
TOVEEventTableDF <- read.table(here::here("data", "TOVEData", "event.txt"), sep = "\t", header = TRUE)
head(TOVEEventTableDF)

Obtendo os arquivos extendidos, neste caso o arquivo de ocorrência de espécies. Podemos ver que se trata de um simples data frame onde os nomes das colunas seguem os códigos do Darwin Core

TOVEOccTable <- read.table(here::here("data", "TOVEData", "occurrence.txt"), sep = "\t", header = TRUE)
head(TOVEOccTable)

Construindo um XML baseado em Darwin Core

Agora que temos nossos dados podemos construir um arquivo do tipo Darwin Core

Construindo o metadado para a tabela de eventos core

Primeiro precisamos definir o que será a tabela core e o que serão as suas extensões, que por sua vez podem ser mapeadas a partir de atributos comuns presentes em ambas as tabelas (neste caso o ID).

# 1. Inicializando automaticamente - só funciona caso os nomes já estejam de acordo com o Darwin Core
newTOVEEventTable <- initializeGBIFEvent(TOVEEventTableDF, "id", nameAutoMap = TRUE)

# 2. Iniciando manualmente - podemos usar o nome dos atributos que correspondem a cada categoria do Darwin Core. 
    # podemos usar o nome ou o número da coluna
newTOVEEventTable <- initializeGBIFEvent(TOVEEventTableDF, "id",
  type = "type",
  modified = "modified",
  datasetName = "datasetName",
  ownerInstitutionCode = "ownerInstitutionCode",
  informationWithheld = "informationWithheld",
  dataGeneralizations = "dataGeneralizations",
  eventID = "eventID",
  samplingProtocol = "samplingProtocol",
  sampleSizeValue = "sampleSizeValue",
  sampleSizeUnit = "sampleSizeUnit",
  samplingEffort = "samplingEffort",
  eventDate = "eventDate",
  eventTime = "eventTime",
  year = "year",
  month = "month",
  day = "day",
  locationID = "locationID",
  country = "country",
  countryCode = "countryCode",
  stateProvince = "stateProvince",
  municipality = "municipality",
  locality = "locality",
  minimumElevationInMeters = "minimumElevationInMeters",
  maximumElevationInMeters = "maximumElevationInMeters",
  decimalLatitude = "decimalLatitude",
  decimalLongitude = "decimalLongitude",
  geodeticDatum = "geodeticDatum",
  coordinateUncertaintyInMeters = "coordinateUncertaintyInMeters")

# Podemos checar se o mapeamento dos termos se deu corretamente
newTOVEEventTable$getTermMapping()

Construindo os metadados para as extensões da tabela core

Neste caso a tabela a extensão que temos da tabela chave é a tabela de ocorrência de espécies. Vamos mapear ela da mesma forma que fizemos para a tabela core

# Função para inicialização da tabela
newTOVEOccTable <- initializeGBIFOccurrence(TOVEOccTable, "id", nameAutoMap = TRUE)

# Checando quais eventos foram mapeados na tabela, o que aparece com NA não foi mapeado, ou porque não existe ou porque tem o nome incorreto
newTOVEOccTable$getTermMapping()

Construindo o EML

O último elemento que precisamos para construir nossos metadados para os arquivos de biodiversidade que estamos utilizando é o arquivo EML, que vocês já conhecem. O EML pode ser criado de várias formas. Vimos anteriormente como criar um EML usando o pacote {EML}. O pacote {LivingNorwayR} oferece uma maneira simples de criar um arquivo XML usando um arquivo .Rmd, ou seja, usando o Rmarkdown. Vamos entender os detalhes de um arquivo do tipo Rmd mais adiante, por hora precisamos apenas saber que ele é um arquivo que permite mesclar textos e códigos, além de possibilitar criar tags para seções (Como os títulos num documento Word). Essas tags são utilizadas pelas funções do LivingNorwayR para criar o arquivo XML. Vale notar que isso é mais limitante que criar um XML usando o EML, mas para questões didáticas vamos usar um arquivo .Rmd pronto, que está na pasta de dados deste diretório.

createdTOVEMetadata <- initializeDwCMetadata(fileLocation = here::here("data", "TOVEData", "LNWorkshopExample_Metadata.rmd"), fileType = "rmarkdown")

# Exportando o EML
createdTOVEMetadata$exportToEML(file.path(here::here("data", "TOVEData"), "newMetadata.xml"))

Este novo metadado precisa ser lido para o R e assim podemos juntá-lo com os outros arquivos

newTOVEMetadata <- initializeDwCMetadata(file.path(here::here("data", "TOVEData"), "newMetadata.xml"),
  fileType = "eml" # This line is not required if the file has the ".xml" file extension
)

Juntando todos os arquivos

Agora temos os arquivos necessários para juntar em um único arquivo zipado que pode ser guardado localmente ou submetido em alguma plataforma de dados, por exemplo, GBIF, como ilustrado abaixo

Para juntar todos os arquivos criados precisamos usar a seguinte função

# criando um único arquivo com todos os objetos criados anteriormente
newTOVEArchive <- initializeDwCArchive(newTOVEEventTable, list(newTOVEOccTable), newTOVEMetadata)

Para salvar o objeto .zip, que agora é nosso Darwin Core Archive, podemos fazer o seguinte

newTOVEArchive$exportAsDwCArchive(file.path(here::here("data", "NEWTOVEData"), "newDwCArchive.zip"))

Explorando o Darwin Core Archive

Uma vez criado o arquivo no formato Darwin Core Archive podemos fazer o caminho inverso e obter as tabelas a partir do arquivo que criamos.

Para tanto podemos usar as funções do pacote LivingNorwayR para ler o arquivo zip e extrair as tabelas, incluindo os metadados.

localDataLoc2 <- file.path(here::here("data", "NEWTOVEData"), "newDwCArchive.zip") 
NEWTOVEArchive <- initializeDwCArchive(localDataLoc2, "UTF-8")

Podemos agora explorar os dados dentro do arquivo Darwin Core criado nos passos anteriores. Ou seja, podemos retomar os dados e importar para dentro do R para fazer, por exemplo, novas análises

# obtendo o dado
NEWTOVEEventTable <- NEWTOVEArchive$getCoreTable()
class(NEWTOVEEventTable)

# Podemos exportar como um dataframe
NEWTOVEEventTableDF <- NEWTOVEEventTable$exportAsDataFrame()

# obtendo dados da tabela extendida
NEWTOVEEventTableDF <- NEWTOVEEventTable$exportAsDataFrame()
# exportando como dataframe
head(NEWTOVEEventTableDF)

Atividade

Para fixar os conceitos apresentados sobre metadados, vamos treinar um pouco mais utilizando um outro conjunto de dados.

Produza um arquivo .xml utilizando os dados iris do pacote {ggplot}. Algumas informações nós não temos, por exemplo, a cobertura de coleta, ano de coleta etc. Mas para fins de prática vamos inventar essas informações no momento de fazer o metadado.

Para acessar os dados:

library(ggplot2)
data("iris")
LS0tCnRpdGxlOiAnTWV0YWRhZG9zIGNvbSBFTUwnCmF1dGhvcjogIkdhYnJpZWwgTmFrYW11cmEiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiBodG1sX2RvY3VtZW50Ci0tLQoKYGBge3IgZWNobz1GQUxTRSwgaW5jbHVkZT1UUlVFfQprbGlwcHk6OmtsaXBweSgpCmBgYAoKIyBNZXRhZGFkb3MKCk9zIG1ldGFkYWRvcyBjb25zaXN0ZW0gZW0gZXhwbGljYcOnw7VlcyBzb2JyZSBhIGVzdHJ1dHVyYSBkZSBkYWRvcy4gUG9yIGV4ZW1wbG8sIG8gc2lnbmlmaWNhZG8gZG9zIGPDs2RpZ29zIG91IGFicmV2aWHDp8O1ZXMgcHJlc2VudGVzIGVtIHVtYSBkYXRhIHRhYmVsYSwgZG8gcXVlIHNlIHRyYXRhIGEgaW5mb3JtYcOnw6NvIHByZXNlbnRlIG5hcyBsaW5oYXMgZSBuYXMgY29sdW5hcywgbyBxdWUgdW1hIGRhZGEgZnVuw6fDo28gZmF6LiBSZXBvcnRhciBwcmVjaXNhbWVudGUgbyBxdWUgY2FkYSBhcnF1aXZvIGNvbnTDqW0gw6kgZGUgZXh0cmVtYSBpbXBvcnTDom5jaWEgcGFyYSBnYXJhbnRpciBjb20gcXVlIG91dHJhcyBwZXNzb2FzLCBvdSBtZXNtbyBvIHZvY8OqIGRvIGZ1dHVybyBzYWliYSBvIHF1ZSBmb2kvZXN0w6Egc2VuZG8gZmVpdG8gbm8gcHJvamV0byBjaWVudMOtZmljby4KCk9zIG1ldGFkYWRvcyBuw6NvIHNlcnZlbSBhcGVuYXMgcGFyYSByZXBvcnRhciBvIHNpZ25pZmljYWRvIGRhcyB2YXJpw6F2ZWlzIGVtIHRhYmVsYXMsIGlzc28gcG9yIHNpIHPDsyBqw6Egc2VyaWEgdW0gbW90aXZvIHJlbGV2YW50ZSBwYXJhIHRlcm1vcyBtZXRhZGFkb3MsIG1hcyB0YW1iw6ltIHBhcmEgZmFjaWxpdGFyIGEgaW50ZWdyYcOnw6NvIGRlIGJhc2VzIGRpZmVyZW50ZXMgZGUgZGFkb3MuIEltYWdpbmUgc8OzIHRlciBxdWUgbmF2ZWdhciBtYW51YWxtZW50ZSBub3MgbWV0YWRhZG9zIGRlIGVzdHVkb3MgZGUgZGlmZXJlbnRlcyBncnVwb3MsIGNvbSBkYWRvcyBjb2xldGFkb3MgY29tIGRpZmVyZW50ZXMgbcOpdG9kb3MsIHRhYmVsYXMgcXVlIGFkb3RhbSBkaWZlcmVudGVzIGPDs2RpZ29zLCBjb20gZGlzdGFudGFzIGVzY2FsYXMgZXNwYWNpYWlzIGUgdGVtcG9yYWlzLiBBdMOpIHNlcmlhIHBvc3PDrXZlbCwgbWFzIHRhbHZleiBhIHRheGEgY29tIHF1ZSBwZXJkZW1vcyBlc3DDqWNpZXMgZSBoYWJpdGF0cyBzZWphIG1haXMgcsOhcGlkYSAoZSBlc3TDoSBzZW5kbykgcXVlIG5vc3NhIGNhcGFjaWRhZGUgZGUgc8OtbnRlc2UgZGUgZGFkb3MuIFBvcnRhbnRvLCBvcyBtZXRhZGFkb3MgbsOjbyBzZXJ2ZW0gYXBlbmFzIHBhcmEgbyBub3NzbyBpbnRlcmVzc2UgcHLDs3ByaW8gZGUgb3JnYW5pemHDp8OjbywgbWFzIGFvIHV0aWxpemFybW9zIG9zIG1ldGFkYWRvcyBlc3RhbW9zIGNvbnRyaWJ1aW5kbyBwYXJhIHVtIGF2YW7Dp28gbWFpcyByw6FwaWRvIGRvIHByb2Nlc3NvIGNpZW50w61maWNvLgoKRGFkYSB0YWlzIGltcG9ydMOibmNpYXMgY2l0YWRhcyBhY2ltYSwgb3MgbWV0YWRhZG9zIGlkZWFpcyBkZXZlbSBzZWd1aXIgdW0gZXNxdWVtYSBvbmRlIHBvZGVtIHNlciBsaWRvcyBwb3IgaHVtYW5vcyAoaHVtYW4tcmVhZGFibGUpIGUgcG9yIGNvbXB1dGFkb3JlcyAobWFjaGluZS1yZWFkYWJsZSkuIERlc3RhIGZvcm1hLCBuZXN0YSBzZcOnw6NvIHZhbW9zIHByYXRpY2FyIGEgZWxhYm9yYcOnw6NvIGRlIG1ldGFkYWRvcyBxdWUgc2VndWVtIGVzc2EgY2FyYWN0ZXLDrXN0aWNhLCBlIHF1ZSBvIGZvcm1hdG8gZm9pIHBlbnNhZG8gcGFyYSBzYXRpc2ZhemVyIGFzIGVzcGVjaWZpY2lkYWRlcyBkb3MgZGFkb3MgZWNvbMOzZ2ljb3MuIFBhcmEgdGFudG8gdmFtb3MgdXRpbGl6YXIgbyBwYWNvdGUgRU1MLiAKCiMjIExlaXR1cmFzIHN1Z2VyaWRhcwoKUGFyYSB1bWEgaXRyb2R1w6fDo28gbWFpcyBjb21wbGV0YSBzb2JyZSBvcyBtZXRhZGFkb3Mgc3VnaXJvIFtlc3RlXShodHRwczovL3NiY2x0ZXIubXNpLnVjc2IuZWR1L2V4dGVybmFsL0VNTC9FTUxfZG9jdW1lbnRzL2VtbF9tZXRhZGF0YV9ndWlkZS5odG1sKSBhcnRpZ28uIFBhcmEgdW1hIGludHJvZHXDp8OjbyBkYSBpbXBvcnTDom5jaWEgZG9zIG1ldGFkYWRvcyBwYXJhIGNvbnRydWlyIGNvbmp1bnRvcyBkZSBkYWRvcyBpbnRlZ3JhZG9zIHN1Z2lybyBvIGFydGlnbyBkZSBbSm9uZXMgZXQgYWwuICgyMDA2KV0oaHR0cHM6Ly93d3cuYW5udWFscmV2aWV3cy5vcmcvZG9pLzEwLjExNDYvYW5udXJldi5lY29sc3lzLjM3LjA5MTMwNS4xMTAwMzEpLiBQYXJhIHVtIGV4ZW1wbG8gZGUgYmFzZSBkZSBkYWRvcyBvbmxpbmUgcXVlIHNlIHV0aWxpemEgZGFzIHBvdGVuY2lhbGlkYWRlcyBkb3MgbWV0YWRhZG9zIHN1Z2lybyB2aXNpdGFyIG8gW0tOQiAtIEtub3dsZWRnZSBOZXR3b3JrIEJpb2NvbXBsZXhpdHldKGh0dHBzOi8va25iLmVjb2luZm9ybWF0aWNzLm9yZy9hYm91dCkuCgojIyBFeGVtcGxvcyBkZSBtZXRhZGFkb3MgCgpQYXJhIHVtIGV4ZW1wbG8gc2ltcGxlcyBkZSBjb21vIHVtIG1ldGFkYWRvIHNlIHBhcmVjZSB2ZWphIFthcXVpXShodHRwczovL2dpdGh1Yi5jb20vcm9wZW5zY2kvRU1ML2Jsb2IvbWFzdGVyL2luc3QvZXhhbXBsZXMvZXhhbXBsZS1lbWwtMi4xLjEueG1sKS4gUGFyYSB1bSBleGVtcGxvIG1haXMgY29tcGxldG8gc3VnaXJvIFtlc3RlIGFycXVpdm9dKGh0dHBzOi8vZ2l0aHViLmNvbS9yb3BlbnNjaS9FTUwvYmxvYi9tYXN0ZXIvaW5zdC9leGFtcGxlcy9oZjIwNS54bWwpLgpFc3RhIFtpbnRyb2R1w6fDo29dKGh0dHBzOi8vd3d3Lm5lb25zY2llbmNlLm9yZy9yZXNvdXJjZXMvbGVhcm5pbmctaHViL3R1dG9yaWFscy9kYy1tZXRhZGF0YS1pbXBvcnRhbmNlLWVtbC1yKSB0cmF6aWRhIHBlbG8gTkVPTiAoTmF0aW9uYWwgRWNvbG9naWNhbCBPYnNlcnZhdG9yeSkgw6kgbXVpdG8gaW50ZXJlc3NhbnRlIHBhcmEgY29tcHJlZW5kZXIgZGUgbWFuZWlyYSBnZXJhbCBhIGltcG9ydMOibmNpYSBkZSBtZXRhZGFkb3MgcGFyYSBzw61udGVzZSBlIGNvbW8gZWxlcyBwb2RlbSBzZXIgb2J0aWRvcyBmYWNpbG1lbnRlIGNvbSBhdXjDrWxpbyBkbyBwYWNvdGUgRU1MLiBPIFtEYXRhT25lXShodHRwczovL3d3dy5kYXRhb25lLm9yZy8pIMOpIHVtYSBwbGF0YWZvcm1hIGRlIGRhZG9zIHF1ZSB0YW1iw6ltIHNlIHV0aWxpemEgZG9zIGFycXVpdm9zIFhNTCBwYXJhIHJlcG9ydGFyIGFzIGNhcmFjdGVyw61zdGljYXMgZ2VyYWlzIGRvcyBkYWRvcy4KCiMgTWV0YWRhZG9zIG5hIHByw6F0aWNhIC0gdXRpbGl6YW5kbyBvIHBhY290ZSBge0VNTH1gCgpOZXN0YSBzZcOnw6NvIGlyZW1vcyB1dGlsaXphciBvIGNvbmp1bnRvIGRlIGRhZG9zIGRvIGFydGlnbyBbIk9yZ2FuaWMtbWF0dGVyIGxvYWRpbmcgZGV0ZXJtaW5lcyByZWdpbWUgc2hpZnRzIGFuZCBhbHRlcm5hdGl2ZSBzdGF0ZXMgaW4gYW4gYXF1YXRpYyBlY29zeXN0ZW0iXShodHRwczovL3d3dy5wbmFzLm9yZy9kb2kvMTAuMTA3My9wbmFzLjEyMjEwMzcxMTApLiBPcHRhbW9zIHBvciB1c2FyIGVzdGUgZGFkbyBwb2lzIGVsZSBqw6EgYXByZXNlbnRhIHVtIGFycXVpdm8gZGUgbWV0YWRhZG9zIGFzc29jaWFkbywgYXNzaW0gcG9kZW1vcyByZWNvbnN0cnXDrS1sbyBlIHZlcmlmaWNhciBjb21vIGZpY2EuIEFsw6ltIGRpc3NvIGVsZSDDqSBvIG1lc21vIGRhZG8gdXRpbGl6YWRvIG5vIHR1dG9yaWFsIG9yaWdpbmFsIGRvIHBhY290ZSBFTUwsIHNlbmRvIGNvbnZlbmllbnRlIHBhcmEgZmlucyBkaWTDoXRpY29zLiBBbyBmaW5hbCB2YW1vcyBwcmF0aWNhciBjb20gdW0gb3V0cm8gY29uanVudG8gZGUgZGFkb3MuIExlbWJyYW5kbyBxdWUgc2Ugdm9jw6ogYmFpeG91IG8gcmVwb3NpdMOzcmlvIGRvIG1hdGVyaWFsIGRlc3RhIGRpc2NpcGxpbmEsIHZvY8OqIGNvbnNlZ3VpcsOhIGxlciBvcyBkYWRvcyBzZW0gcHJvYmxlbWFzLgoKCiMjIEluc3RhbGHDp8OjbwoKUGFyYSBpbnN0YWxhciBvIHBhY290ZSBFTUwgZmHDp2EgbyBzZWd1aW50ZToKCmBgYHtyIGVjaG89VFJVRSxldmFsPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJFTUwiKQoKbGlicmFyeShFTUwpCmBgYAoKVmFtb3MgdXRpbGl6YXIgdW0gY29uanVudG8gZGUgZGFkb3MgY29udGlkb3Mgbm8gcHLDs3ByaW8gcGFjb3RlIEVNTCBwYXJhIGZhY2lsaXRhciBhIGNvbXByZWVuc8OjbyBkb3MgcGFzc29zIG5lY2Vzc8OhcmlvcyBwYXJhIGNvbnN0cnVpciB1bSBFTUwgY29tcGxldG8KCiMjIENvbnN0cnVpbmRvIHVtIEVNTCAtIEhhcnZhcmQgRm9yZXN0IERhdGEgCgojIyMgQ29uc3RydWluZG8gb3MgQXRyaWJ1dG9zCgpPcyBhdHJpYnV0b3Mgc8OjbyBhcyBkZXNjcmnDp8O1ZXMgcGFyYSBhcyB2YXJpw6F2ZWlzIGNvbnRpZGFzIG5hIG5vc3NhIHRhYmVsYS4gQXF1ZWxhIGFiYSBjb250ZW5kbyBhcyBpbmZvcm1hw6fDtWVzIGRhcyB2YXJpw6F2ZWlzLCBwb2lzIGVudMOjbywgZXN0YSBzZXJpYSBvcyBhdHJpYnV0b3MgZGEgc3VhIHRhYmVsYSBkZSBkYWRvcy4gRW50w6NvLCBwcmltZWlybyBwcmVjaXNhbW9zIGRlIHVtYSB0YWJlbGEgZGUgYXRyaWJ1dG9zIHF1ZSBkZWZpbmUgbyBzaWduaWZpY2FkbyBnZXJhbCBkZSBjYWRhIHZhcmnDoXZlbCBlbSBub3NzYSB0YWJlbGEgZGUgZGFkb3MuIEVzdGEgdGFiZWxhIHBvZGUgc2VyIGdlcmFkYSBhcXVpIG5vIFIgZGlyZXRvLCBjb21vIG5vIGV4ZW1wbG8gYWJhaXhvLCBtYXMgcG9kZSBzZXIgaW1wb3J0YWRhIGEgcGFydGlyIGRlIHVtYSB0YWJlbGEgYC5jc3ZgLiBBIHRhYmVsYSBzZWd1ZSBvIGZvcm1hdG8gYSBzZWd1aXI6CgpgYGB7cn0KYXR0cmlidXRlcyA8LQp0aWJibGU6OnRyaWJibGUoCn5hdHRyaWJ1dGVOYW1lLCB+YXR0cmlidXRlRGVmaW5pdGlvbiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfmZvcm1hdFN0cmluZywgfmRlZmluaXRpb24sICAgICAgICB+dW5pdCwgICB+bnVtYmVyVHlwZSwKICAicnVuLm51bSIsICAgICJ3aGljaCBydW4gbnVtYmVyICg9YmxvY2spLiBSYW5nZTogMSAtIDYuIChpbnRlZ2VyKSIsICAgICAgICAgICAgICAgICBOQSwgICAgICAgICAgICAid2hpY2ggcnVuIG51bWJlciIsIE5BLCAgICAgICBOQSwKICAieWVhciIsICAgICAgICJ5ZWFyLCAyMDEyIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiWVlZWSIsICAgICAgICBOQSwgICAgICAgICAgICAgICAgIE5BLCAgICAgICBOQSwKICAiZGF5IiwgICAgICAgICJKdWxpYW4gZGF5LiBSYW5nZTogMTcwIC0gMjA5LiIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiREREIiwgICAgICAgICBOQSwgICAgICAgICAgICAgICAgIE5BLCAgICAgICBOQSwKICAiaG91ci5taW4iLCAgICJob3VyIGFuZCBtaW51dGUgb2Ygb2JzZXJ2YXRpb24uIFJhbmdlIDEgLSAyNDAwIChpbnRlZ2VyKSIsICAgICAgICAgICAiaGhtbSIsICAgICAgICBOQSwgICAgICAgICAgICAgICAgIE5BLCAgICAgICBOQSwKICAiaS5mbGFnIiwgICAgICJpcyB2YXJpYWJsZSBSZWFsLCBJbnRlcnBvbGF0ZWQgb3IgQmFkIChjaGFyYWN0ZXIvZmFjdG9yKSIsICAgICAgICAgICBOQSwgICAgICAgICAgICBOQSwgICAgICAgICAgICAgICAgIE5BLCAgICAgICBOQSwKICAidmFyaWFibGUiLCAgICJ3aGF0IHZhcmlhYmxlIGJlaW5nIG1lYXN1cmVkIGluIHdoYXQgdHJlYXRtZW50IChjaGFyYWN0ZXIvZmFjdG9yKS4iLCBOQSwgICAgICAgICAgICBOQSwgICAgICAgICAgICAgICAgIE5BLCAgICAgICBOQSwKICAidmFsdWUuaSIsICAgICJ2YWx1ZSBvZiBtZWFzdXJlZCB2YXJpYWJsZSBmb3IgcnVuLm51bSBvbiB5ZWFyL2RheS9ob3VyLm1pbi4iLCAgICAgICBOQSwgICAgICAgICAgICBOQSwgICAgICAgICAgICAgICAgIE5BLCAgICAgICBOQSwKICAibGVuZ3RoIiwgICAgImxlbmd0aCBvZiB0aGUgc3BlY2llcyBpbiBtZXRlcnMgKGR1bW15IGV4YW1wbGUgb2YgbnVtZXJpYyBkYXRhKSIsICAgICBOQSwgICAgICAgICAgICBOQSwgICAgICAgICAgICAgICAgICJtZXRlciIsICAicmVhbCIpCmBgYAoKRMOqIHVtYSBvbGhhZGEgbmEgdGFiZWxhIGRlIGF0cmlidXRvcyAocG9kZSBzZXIgZmVpdG8gdXNhbm8gYSBmdW7Dp8OjbyBgVmlld2Agb3UgYWJyaW5kbyBubyBFeGNlbCkuIEEgbWFpb3JpYSBkb3MgZGFkb3Mgc2VndWVtIGVzdGUgZm9ybWF0byBnZXJhbC4KCkEgc2VndWlyIHByZWNpc2Ftb3MgZGVzY3JldmVyIG9zIGF0cmlidXRvcyBxdWUgYXByZXNlbnRhbSBuw612ZWlzLiBQb3IgZXhlbXBsbyBvIGF0cmlidXRvIGNoYW1hZG8gYHZhcmlhYmxlYCBhcHJlc2VudGEgb2l0byBuw612ZWlzLiBBIGVzdHJhdMOpZ2lhIHNlZ3VpZGEgYXF1aSBmb2kgY3JpYXIgdmV0b3JlcyBjb20gb3MgY8OzZGlnb3MgdXNhZG9zIHBhcmEgY2FkYSBuw612ZWwgZG9zIGF0cmlidXRvcyBlIHVtYSBwZXF1ZW5hIGV4cGxpY2HDp8Ojby4KCmBgYHtyIGVjaG89VFJVRSxldmFsPUZBTFNFfQppLmZsYWcgPC0gYyhSID0gInJlYWwiLAogICAgICAgICAgICBJID0gImludGVycG9sYXRlZCIsCiAgICAgICAgICAgIEIgPSAiYmFkIikKdmFyaWFibGUgPC0gYygKICBjb250cm9sICA9ICJubyBwcmV5IGFkZGVkIiwKICBsb3cgICAgICA9ICIwLjEyNSBtZyBwcmV5IGFkZGVkIG1sLTEgZC0xIiwKICBtZWQubG93ICA9ICIwLDI1IG1nIHByZXkgYWRkZWQgbWwtMSBkLTEiLAogIG1lZC5oaWdoID0gIjAuNSBtZyBwcmV5IGFkZGVkIG1sLTEgZC0xIiwKICBoaWdoICAgICA9ICIxLjAgbWcgcHJleSBhZGRlZCBtbC0xIGQtMSIsCiAgYWlyLnRlbXAgPSAiYWlyIHRlbXBlcmF0dXJlIG1lYXN1cmVkIGp1c3QgYWJvdmUgYWxsIHBsYW50cyAoMSB0aGVybW9jb3VwbGUpIiwKICB3YXRlci50ZW1wID0gIndhdGVyIHRlbXBlcmF0dXJlIG1lYXN1cmVkIHdpdGhpbiBlYWNoIHBpdGNoZXIiLAogIHBhciAgICAgICA9ICJwaG90b3N5bnRoZXRpYyBhY3RpdmUgcmFkaWF0aW9uIChQQVIpIG1lYXN1cmVkIGp1c3QgYWJvdmUgYWxsIHBsYW50cyAoMSBzZW5zb3IpIgopCgp2YWx1ZS5pIDwtIGMoCiAgY29udHJvbCAgPSAiJSBkaXNzb2x2ZWQgb3h5Z2VuIiwKICBsb3cgICAgICA9ICIlIGRpc3NvbHZlZCBveHlnZW4iLAogIG1lZC5sb3cgID0gIiUgZGlzc29sdmVkIG94eWdlbiIsCiAgbWVkLmhpZ2ggPSAiJSBkaXNzb2x2ZWQgb3h5Z2VuIiwKICBoaWdoICAgICA9ICIlIGRpc3NvbHZlZCBveHlnZW4iLAogIGFpci50ZW1wID0gImRlZ3JlZXMgQyIsCiAgd2F0ZXIudGVtcCA9ICJkZWdyZWVzIEMiLAogIHBhciAgICAgID0gIm1pY3JvbW9sZXMgbS0xIHMtMSIKKQoKIyMgV3JpdGUgdGhlc2UgaW50byB0aGUgZGF0YS5mcmFtZSBmb3JtYXQKZmFjdG9ycyA8LSByYmluZCgKZGF0YS5mcmFtZSgKICBhdHRyaWJ1dGVOYW1lID0gImkuZmxhZyIsCiAgY29kZSA9IG5hbWVzKGkuZmxhZyksCiAgZGVmaW5pdGlvbiA9IHVubmFtZShpLmZsYWcpCiksCmRhdGEuZnJhbWUoCiAgYXR0cmlidXRlTmFtZSA9ICJ2YXJpYWJsZSIsCiAgY29kZSA9IG5hbWVzKHZhcmlhYmxlKSwKICBkZWZpbml0aW9uID0gdW5uYW1lKHZhcmlhYmxlKQopLApkYXRhLmZyYW1lKAogIGF0dHJpYnV0ZU5hbWUgPSAidmFsdWUuaSIsCiAgY29kZSA9IG5hbWVzKHZhbHVlLmkpLAogIGRlZmluaXRpb24gPSB1bm5hbWUodmFsdWUuaSkKKQopCmBgYAoKQXDDs3MgZXNwZWNpZmljYWRhcyBhcyBjYXJhY3RlcsOtc3RpY2FzIGRhcyB2YXJpw6F2ZWlzIGNhdGVnw7NyaWNhcyAoYXMgY29udMOtbnVhcyBqw6EgZXN0w6NvIGVzcGVjaWZpY2FkYXMgbmEgdGFiZWxhIGdlcmFsIGRlIGF0cmlidXRvcyBgYXR0cmlidXRlc2ApLCB1c2Ftb3MgYSBmdW7Dp8OjbyBgc2V0X2F0dHJpYnV0ZXNgIHBhcmEgY3JpYXIgYSBsaXN0YSBkZSBhdHJpYnV0b3MgZ2VyYWwgZG9zIGRhZG9zLCBvbmRlIGRldmVtb3MgZXNwZWNpZmljYXIgbyB0aXBvIGRlIGF0cmlidXRvIHF1ZSBlc3RhbW9zIGluc2VyaW5kbyAoc2UgY2FyYWN0ZXIsIHNlIGRhdGEsIHNlIGZhdG9yIGV0Yy4uKQoKYGBge3IgZWNobz1UUlVFLGV2YWw9RkFMU0V9CmF0dHJpYnV0ZUxpc3QgPC0gc2V0X2F0dHJpYnV0ZXMoYXR0cmlidXRlcywgZmFjdG9ycywgY29sX2NsYXNzZXMgPSBjKCJjaGFyYWN0ZXIiLCAiRGF0ZSIsICJEYXRlIiwgIkRhdGUiLCAiZmFjdG9yIiwgImZhY3RvciIsICJmYWN0b3IiLCAibnVtZXJpYyIpKQpgYGAKCiMjIyBDb25zdHJ1aW5kbyBhcyBjYXJhY3RlcsOtc3RpY2FzIGbDrXNpY2FzIGRvIGRhZG8KCkFxdWkgdmFtb3MgZXNwZWNpZmljYXIgYXMgY2FyYWN0ZXLDrXN0aWNhcyBmw61zaWNhcyBkbyBwcsOzcHJpbyBhcnF1aXZvIGRlIGRhZG9zIHF1ZSB1dGlsaXphbW9zLCBvdSBzZWphLCBvIGZvcm1hdG8sIG8gdGlwbyBkZSBjb21wcmVzc8OjbyBkbyBhcnF1aXZvLCBvIHNlcGFyYWRvciBldGMuIFJlc3VtaW5kbywgYXF1aSDDqSBlc3BlY2lmaWNhZG8gYSAqKmNhcmFjdGVyw61zdGljYSBkbyBhcnF1aXZvKiouIElzc28gw6kgZmVpdG8gZmFjaWxtZW50ZSBjb20gYSBmdW7Dp8OjbyBgc2V0X3BoeXNpY2FsYC4gU2UgZXN0aXZlcm1vcyB1dGlsaXphbmRvIHVtIGFycXVpdm8gLmNzdiBhIGZ1bsOnw6NvIGrDoSBleHRyYWkgYXV0b21hdGljYW1lbnRlIGEgbWFpb3IgcGFydGUgZGFzIGNhcmFjdGVyw61zdGljYXMgcmVsZXZhbnRlcyBkbyBhcnF1aXZvIGRlIGRhZG9zLgoKYGBge3IgZWNobz1UUlVFLGV2YWw9RkFMU0V9CnBoeXNpY2FsIDwtIHNldF9waHlzaWNhbChoZXJlOjpoZXJlKCJkYXRhIiwgImhmMjA1LTAxLVRQZXhwMS1FTUwtRXhlbXBsZS5jc3YiKSkKYGBgCgojIyMgSnVudGFuZG8gQXRyaWJ1dG9zIGUgQ2FyYWN0ZXLDrXN0aWNhcyBmw61zaWNhcwoKQ29tIG8gb2JqZXRvIGRlIGF0cmlidXRvcyBlIG8gb2JqZXRvIGRlIGNhcmFjdGVyw61zdGljYXMgZsOtc2ljYXMgdGVtb3MgbyBlc3NlbmNpYWwgcGFyYSBkZXNjcmV2ZXIgbyBub3NzbyBjb25qdW50byBkZSBkYWRvcy4gQWdvcmEgdmFtb3MganVudGFyIGFtYm9zIGNvbSBtYWlzIGFsZ3VtYXMgaW5mb3JtYcOnw7VlcyBlbSB1bWEgw7puaWNhIGxpc3RhIGUgZGVub21pbmFyIGlzc28gY29tbyBzZW5kbyBvIG5vc3NvIGBkYXRhVGFibGVgCgpgYGB7ciBlY2hvPVRSVUUsZXZhbD1GQUxTRX0KCmRhdGFUYWJsZSA8LSBsaXN0KAogICAgICAgICAgICAgICAgIGVudGl0eU5hbWUgPSAiaGYyMDUtMDEtVFBleHAxLmNzdiIsCiAgICAgICAgICAgICAgICAgZW50aXR5RGVzY3JpcHRpb24gPSAidGlwcGluZyBwb2ludCBleHBlcmltZW50IDEiLAogICAgICAgICAgICAgICAgIHBoeXNpY2FsID0gcGh5c2ljYWwsCiAgICAgICAgICAgICAgICAgYXR0cmlidXRlTGlzdCA9IGF0dHJpYnV0ZUxpc3QpCmBgYAoKIyMjIENhcmFjdGVyw61zdGljYXMgYWRpY2lvbmFpcyAtIGV4dGVuc8OjbyBnZW9ncsOhZmljYSwgbcOpdG9kb3MgZSBvdXRyb3MKCgpgYGB7ciBlY2hvPVRSVUUsZXZhbD1GQUxTRX0KZ2VvZ3JhcGhpY0Rlc2NyaXB0aW9uIDwtICJIYXJ2YXJkIEZvcmVzdCBHcmVlbmhvdXNlLCBUb20gU3dhbXAgVHJhY3QgKEhhcnZhcmQgRm9yZXN0KSIKCgpjb3ZlcmFnZSA8LSAKICBzZXRfY292ZXJhZ2UoYmVnaW4gPSAnMjAxMi0wNi0wMScsIGVuZCA9ICcyMDEzLTEyLTMxJywKICAgICAgICAgICAgICAgc2NpX25hbWVzID0gIlNhcnJhY2VuaWEgcHVycHVyZWEiLAogICAgICAgICAgICAgICBnZW9ncmFwaGljRGVzY3JpcHRpb24gPSBnZW9ncmFwaGljRGVzY3JpcHRpb24sCiAgICAgICAgICAgICAgIHdlc3QgPSAtMTIyLjQ0LCBlYXN0ID0gLTExNy4xNSwgCiAgICAgICAgICAgICAgIG5vcnRoID0gMzcuMzgsIHNvdXRoID0gMzAuMDAsCiAgICAgICAgICAgICAgIGFsdGl0dWRlTWluID0gMTYwLCBhbHRpdHVkZU1heGltdW0gPSAzMzAsCiAgICAgICAgICAgICAgIGFsdGl0dWRlVW5pdHMgPSAibWV0ZXIiKQoKCmBgYAoKClBhcmEgZGVzY3JldmVyIG9zIG3DqXRvZG9zIGVtIG1ldGFkYWRvcwoKYGBge3IgZWNobz1UUlVFLGV2YWw9RkFMU0V9CgptZXRob2RzX2ZpbGUgPC0gaGVyZTo6aGVyZSgiZGF0YSIsICJoZjIwNS1tZXRob2RzLmRvY3giKQptZXRob2RzIDwtIHNldF9tZXRob2RzKG1ldGhvZHNfZmlsZSkKYGBgCgpJZGVudGlmaWNhw6fDo28gZG9zIGluZGl2w61kdW9zIGVuZGVyZcOnbyBlIG91dHJhcyBpbmZvcm1hw6fDtWVzIHNvYnJlIGNvbnRhdG9zCgpgYGB7ciBlY2hvPVRSVUUsZXZhbD1GQUxTRX0KUl9wZXJzb24gPC0gcGVyc29uKCJBYXJvbiIsICJFbGxpc29uIiwgLCJmYWtlYWRkcmVzc0BlbWFpbC5jb20iLCAiY3JlIiwgCiAgICAgICAgICAgICAgICAgIGMoT1JDSUQgPSAiMDAwMC0wMDAzLTQxNTEtNjA4MSIpKQphYXJvbiA8LSBhc19lbWxkKFJfcGVyc29uKQpvdGhlcnMgPC0gYyhhcy5wZXJzb24oIkJlbmphbWluIEJhaXNlciIpLCBhcy5wZXJzb24oIkplbm5pZmVyIFNpcm90YSIpKQphc3NvY2lhdGVkUGFydHkgPC0gYXNfZW1sZChvdGhlcnMpCmFzc29jaWF0ZWRQYXJ0eVtbMV1dJHJvbGUgPC0gIlJlc2VhcmNoZXIiCmFzc29jaWF0ZWRQYXJ0eVtbMl1dJHJvbGUgPC0gIlJlc2VhcmNoZXIiCgpIRl9hZGRyZXNzIDwtIGxpc3QoCiAgICAgICAgICAgICAgICAgIGRlbGl2ZXJ5UG9pbnQgPSAiMzI0IE5vcnRoIE1haW4gU3RyZWV0IiwKICAgICAgICAgICAgICAgICAgY2l0eSA9ICJQZXRlcnNoYW0iLAogICAgICAgICAgICAgICAgICBhZG1pbmlzdHJhdGl2ZUFyZWEgPSAiTUEiLAogICAgICAgICAgICAgICAgICBwb3N0YWxDb2RlID0gIjAxMzY2IiwKICAgICAgICAgICAgICAgICAgY291bnRyeSA9ICJVU0EiKQoKcHVibGlzaGVyIDwtIGxpc3QoCiAgICAgICAgICAgICAgICAgb3JnYW5pemF0aW9uTmFtZSA9ICJIYXJ2YXJkIEZvcmVzdCIsCiAgICAgICAgICAgICAgICAgYWRkcmVzcyA9IEhGX2FkZHJlc3MpCgoKY29udGFjdCA8LSAKICBsaXN0KAogICAgaW5kaXZpZHVhbE5hbWUgPSBhYXJvbiRpbmRpdmlkdWFsTmFtZSwKICAgIGVsZWN0cm9uaWNNYWlsQWRkcmVzcyA9IGFhcm9uJGVsZWN0cm9uaWNNYWlsQWRkcmVzcywKICAgIGFkZHJlc3MgPSBIRl9hZGRyZXNzLAogICAgb3JnYW5pemF0aW9uTmFtZSA9ICJIYXJ2YXJkIEZvcmVzdCIsCiAgICBwaG9uZSA9ICIwMDAtMDAwLTAwMDAiKQpgYGAKCgpjcmlhbmRvIGtleXdvcmRzIHBhcmEgb3MgZGFkb3MKCmBgYHtyIGVjaG89VFJVRSxldmFsPUZBTFNFfQprZXl3b3JkU2V0IDwtIGxpc3QoCiAgICBsaXN0KAogICAgICAgIGtleXdvcmRUaGVzYXVydXMgPSAiTFRFUiBjb250cm9sbGVkIHZvY2FidWxhcnkiLAogICAgICAgIGtleXdvcmQgPSBsaXN0KCJiYWN0ZXJpYSIsCiAgICAgICAgICAgICAgICAgICAgImNhcm5pdm9yb3VzIHBsYW50cyIsCiAgICAgICAgICAgICAgICAgICAgImdlbmV0aWNzIiwKICAgICAgICAgICAgICAgICAgICAidGhyZXNob2xkcyIpCiAgICAgICAgKSwKICAgIGxpc3QoCiAgICAgICAga2V5d29yZFRoZXNhdXJ1cyA9ICJMVEVSIGNvcmUgYXJlYSIsCiAgICAgICAga2V5d29yZCA9ICBsaXN0KCJwb3B1bGF0aW9ucyIsICJpbm9yZ2FuaWMgbnV0cmllbnRzIiwgImRpc3R1cmJhbmNlIikKICAgICAgICApLAogICAgbGlzdCgKICAgICAgICBrZXl3b3JkVGhlc2F1cnVzID0gIkhGUiBkZWZhdWx0IiwKICAgICAgICBrZXl3b3JkID0gbGlzdCgiSGFydmFyZCBGb3Jlc3QiLCAiSEZSIiwgIkxURVIiLCAiVVNBIikKICAgICAgICApKQpgYGAKT3V0cmFzIGluZm9ybWHDp8O1ZXMgcmVsZXZhbnRlcyBjb21vIGFic3RyYWN0IGV0YwoKYGBge3IgZWNobz1UUlVFLGV2YWw9RkFMU0V9CnB1YkRhdGUgPC0gIjIwMTIiIAoKdGl0bGUgPC0gIlRocmVzaG9sZHMgYW5kIFRpcHBpbmcgUG9pbnRzIGluIGEgU2FycmFjZW5pYSAKTWljcm9lY29zeXN0ZW0gYXQgSGFydmFyZCBGb3Jlc3Qgc2luY2UgMjAxMiIKCmFic3RyYWN0IDwtICJUaGUgcHJpbWFyeSBnb2FsIG9mIHRoaXMgcHJvamVjdCBpcyB0byBkZXRlcm1pbmUKICBleHBlcmltZW50YWxseSB0aGUgYW1vdW50IG9mIGxlYWQgdGltZSByZXF1aXJlZCB0byBwcmV2ZW50IGEgc3RhdGUKY2hhbmdlLiBUbyBhY2hpZXZlIHRoaXMgZ29hbCwgd2Ugd2lsbCAoMSkgZXhwZXJpbWVudGFsbHkgaW5kdWNlIHN0YXRlCmNoYW5nZXMgaW4gYSBuYXR1cmFsIGFxdWF0aWMgZWNvc3lzdGVtIC0gdGhlIFNhcnJhY2VuaWEgbWljcm9lY29zeXN0ZW07CigyKSB1c2UgcHJvdGVvbWljIGFuYWx5c2lzIHRvIGlkZW50aWZ5IHBvdGVudGlhbCBpbmRpY2F0b3JzIG9mIHN0YXRlcwphbmQgc3RhdGUgY2hhbmdlczsgYW5kICgzKSB0ZXN0IHdoZXRoZXIgd2UgY2FuIGZvcmVzdGFsbCBzdGF0ZSBjaGFuZ2VzCmJ5IGV4cGVyaW1lbnRhbGx5IGludGVydmVuaW5nIGluIHRoZSBzeXN0ZW0uIFRoaXMgd29yayB1c2VzIHN0YXRlLW9mLXRoZQphcnQgbW9sZWN1bGFyIHRvb2xzIHRvIGlkZW50aWZ5IGVhcmx5IHdhcm5pbmcgaW5kaWNhdG9ycyBpbiB0aGUgZmllbGQKb2YgYWVyb2JpYyB0byBhbmFlcm9iaWMgc3RhdGUgY2hhbmdlcyBkcml2ZW4gYnkgbnV0cmllbnQgZW5yaWNobWVudAppbiBhbiBhcXVhdGljIGVjb3N5c3RlbS4gVGhlIHN0dWR5IHRlc3RzIHR3byBnZW5lcmFsIGh5cG90aGVzZXM6ICgxKQpwcm90ZW9taWMgYmlvbWFya2VycyBjYW4gZnVuY3Rpb24gYXMgcmVsaWFibGUgaW5kaWNhdG9ycyBvZiBpbXBlbmRpbmcKc3RhdGUgY2hhbmdlcyBhbmQgbWF5IGdpdmUgZWFybHkgd2FybmluZyBiZWZvcmUgaW5jcmVhc2luZyB2YXJpYW5jZXMKYW5kIHN0YXRpc3RpY2FsIGZsaWNrZXJpbmcgb2YgbW9uaXRvcmVkIHZhcmlhYmxlczsgYW5kICgyKSB3ZWxsLXRpbWVkCmludGVydmVudGlvbiBiYXNlZCBvbiBwcm90ZW9taWMgYmlvbWFya2VycyBjYW4gYXZlcnQgZnV0dXJlIHN0YXRlIGNoYW5nZXMKaW4gZWNvbG9naWNhbCBzeXN0ZW1zLiIgIAoKaW50ZWxsZWN0dWFsUmlnaHRzIDwtICJUaGlzIGRhdGFzZXQgaXMgcmVsZWFzZWQgdG8gdGhlIHB1YmxpYyBhbmQgbWF5IGJlIGZyZWVseQogIGRvd25sb2FkZWQuIFBsZWFzZSBrZWVwIHRoZSBkZXNpZ25hdGVkIENvbnRhY3QgcGVyc29uIGluZm9ybWVkIG9mIGFueQpwbGFucyB0byB1c2UgdGhlIGRhdGFzZXQuIENvbnN1bHRhdGlvbiBvciBjb2xsYWJvcmF0aW9uIHdpdGggdGhlIG9yaWdpbmFsCmludmVzdGlnYXRvcnMgaXMgc3Ryb25nbHkgZW5jb3VyYWdlZC4gUHVibGljYXRpb25zIGFuZCBkYXRhIHByb2R1Y3RzCnRoYXQgbWFrZSB1c2Ugb2YgdGhlIGRhdGFzZXQgbXVzdCBpbmNsdWRlIHByb3BlciBhY2tub3dsZWRnZW1lbnQuIEZvcgptb3JlIGluZm9ybWF0aW9uIG9uIExURVIgTmV0d29yayBkYXRhIGFjY2VzcyBhbmQgdXNlIHBvbGljaWVzLCBwbGVhc2UKc2VlOiBodHRwOi8vd3d3Lmx0ZXJuZXQuZWR1L2RhdGEvbmV0cG9saWN5Lmh0bWwuIgpgYGAKCiMjIyBDcmlhbmRvIG8gYXJxdWl2byBYTUwKCkFnb3JhIHF1ZSB0b2RhcyBhcyBpbmZvcm1hw6fDtWVzIGZvcmFtIGNyaWFkYXMgKGF0cmlidXRvcywgZGFkb3MgZsOtc2ljb3MgZG8gYXJxdWl2bywgY292ZXJhZ2UsIGRhZG9zIGRlIGNvbnRhdG8pLCBwcmVjaXNhbW9zIGp1bnRhciB0b2RhcyBlbGFzIGVtIHVtYSDDum5pY2EgbGlzdGEuCgpgYGB7ciBlY2hvPVRSVUUsZXZhbD1GQUxTRX0KZGF0YXNldCA8LSBsaXN0KAogICAgICAgICAgICAgICB0aXRsZSA9IHRpdGxlLAogICAgICAgICAgICAgICBjcmVhdG9yID0gYWFyb24sCiAgICAgICAgICAgICAgIHB1YkRhdGUgPSBwdWJEYXRlLAogICAgICAgICAgICAgICBpbnRlbGxlY3R1YWxSaWdodHMgPSBpbnRlbGxlY3R1YWxSaWdodHMsCiAgICAgICAgICAgICAgIGFic3RyYWN0ID0gYWJzdHJhY3QsCiAgICAgICAgICAgICAgIGFzc29jaWF0ZWRQYXJ0eSA9IGFzc29jaWF0ZWRQYXJ0eSwKICAgICAgICAgICAgICAga2V5d29yZFNldCA9IGtleXdvcmRTZXQsCiAgICAgICAgICAgICAgIGNvdmVyYWdlID0gY292ZXJhZ2UsCiAgICAgICAgICAgICAgIGNvbnRhY3QgPSBjb250YWN0LAogICAgICAgICAgICAgICBtZXRob2RzID0gbWV0aG9kcywKICAgICAgICAgICAgICAgZGF0YVRhYmxlID0gZGF0YVRhYmxlKQpgYGAKCkFudGVzIGRlIGNyaWFyIG8gYXJxdWl2byBYTUwgw6kgaW1wb3J0YW50ZSBjcmlhciB1bSB1dWlkIHBhcmEgbyBhcnF1aXZvLCBxdWUgbmFkYSBtYWlzIMOpIHF1ZSB1bSBpZGVudGlmaWNhZG9yIHF1ZSBxdWFscXVlciB1bSBwb2RlIGNyaWFyLCBjb21vIGRlbW9uc3RyYWRvIGEgc2VndWlyLiBQYXJhIG1haXMgaW5mb3JtYcOnw7VlcyBzb2JyZSBvIHF1ZSDDqSB1bSB1dWlkIHZlciBbZXN0YSBleHBsaWNhw6fDo28gbm8gV2lraXBlZGlhXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Vbml2ZXJzYWxseV91bmlxdWVfaWRlbnRpZmllcikKCmBgYHtyIGVjaG89VFJVRSxldmFsPUZBTFNFfQplbWwgPC0gbGlzdCgKICAgICAgICAgICBwYWNrYWdlSWQgPSB1dWlkOjpVVUlEZ2VuZXJhdGUoKSwKICAgICAgICAgICBzeXN0ZW0gPSAidXVpZCIsICMgdHlwZSBvZiBpZGVudGlmaWVyCiAgICAgICAgICAgZGF0YXNldCA9IGRhdGFzZXQpCmBgYAoKRmluYWxtZW50ZSBjcmlhbmRvIG8gYXJxdWl2byBYTUwgZSB2YWxpZGFuZG8uCgpgYGB7ciBlY2hvPVRSVUUsZXZhbD1GQUxTRX0Kd3JpdGVfZW1sKGVtbCwgaGVyZTo6aGVyZSgiZGF0YSIsICJlbWxfdHV0b3JpYWxIRjIwNS54bWwiKSkKZW1sX3ZhbGlkYXRlKGhlcmU6OmhlcmUoImRhdGEiLCAiZW1sX3R1dG9yaWFsSEYyMDUueG1sIikpCmBgYAoKCjwhLS0gYXF1aSBhIHNlw6fDo28gZGUgbWV0YWRhdGEgcGFyYSBkYWRvcyBkZSBiaW9kaXZlcnNpZGFkZSB1c2FuZG8gRHdDb3JlIC0tPgoKYGBge3IgY2hpbGQ9IkRhcndpbi1jb3JlLUxOUC5SbWQiLGV2YWw9VFJVRX0KYGBgCgoKIyBBdGl2aWRhZGUKClBhcmEgZml4YXIgb3MgY29uY2VpdG9zIGFwcmVzZW50YWRvcyBzb2JyZSBtZXRhZGFkb3MsIHZhbW9zIHRyZWluYXIgdW0gcG91Y28gbWFpcyB1dGlsaXphbmRvIHVtIG91dHJvIGNvbmp1bnRvIGRlIGRhZG9zLiAKClByb2R1emEgdW0gYXJxdWl2byBgLnhtbGAgdXRpbGl6YW5kbyBvcyBkYWRvcyBgaXJpc2AgZG8gcGFjb3RlIGB7Z2dwbG90fWAuIEFsZ3VtYXMgaW5mb3JtYcOnw7VlcyBuw7NzIG7Do28gdGVtb3MsIHBvciBleGVtcGxvLCBhIGNvYmVydHVyYSBkZSBjb2xldGEsIGFubyBkZSBjb2xldGEgZXRjLiBNYXMgcGFyYSBmaW5zIGRlIHByw6F0aWNhIHZhbW9zIGludmVudGFyIGVzc2FzIGluZm9ybWHDp8O1ZXMgbm8gbW9tZW50byBkZSBmYXplciBvIG1ldGFkYWRvLgoKUGFyYSBhY2Vzc2FyIG9zIGRhZG9zOgoKYGBge3IgZWNobz1UUlVFLGV2YWw9RkFMU0V9CmxpYnJhcnkoZ2dwbG90MikKZGF0YSgiaXJpcyIpCmBgYAoKCgoK