Introduction

Here, we present an analysis of the needs assessment online survey results that were collected for the German Competence Center Cloud Technologies for Data Management and Processing (de.KCD). The aim of the needs assessment is to get an overview of cloud technologies that are deployed for the purpose of data management and analysis in the different scientific fields and by the scientific community as a whole. Besides that, gaps in existing training materials of participating research data initiatives should be identified to inform experts from partner institutions where a need for additional materials exists.

The survey can be accessed by using the following link: https://ec.europa.eu/eusurvey/runner/deKCD_needs_assessment_2024

The anonymized survey results are available in the following GitHub repository: https://github.com/deKCD/needs-assessment-evaluation

Table of contents

Analysis

The survey was carried out using the online survey platform EUSurvey. The survey results were exported in the proprietary .xlsx format and then converted to the .csv format to enable analysis with other software packages. Exploratory data analysis and plotting was conducted using the programming language R and the IDE RStudio, see R session info section for more detailed information.

# load libraries
library(tidyverse)
library(DT)
library(webshot)
library(gridExtra)
library(ggrepel)
library(ggplot2)
library(scales)
library(flextable)

# read in survey raw data
res <- read.csv("data/Content_Export_deKCD_needs_assessment_2024_2024-11-19.CSV", sep = ";", na.strings = c("", "NA"))
# add unique contribution ID to each entry
res$ID <- seq.int(nrow(res))

# separate results by topic and keep submission IDs for each subset
# General information
res_general <- select(res, c(59, 1:5))
# Provision of cloud services
res_CS_provision <- select(res, c(59, 6:14))
# Training content
res_training <- select(res, c(59, 15:23))
# Data processing
res_data <- select(res, c(59, 24:41))
# Infrastructure
res_infra <- select(res, c(59, 42:53))

General Information

The primary target group for the survey were people engaged in NFDI projects or other projects dedicated to provide data management and data analysis services for a scientific audience.

Scientific domain representation

To understand which scientific fields are covered by the survey results, we asked participants to which field their project can be assigned. The number of participants from each field is visualized in the following plot:

# Plot: Distribution of scientific fields among participants

# Select relevant column, count occurrences, and add n=0 for missing values
plot1_data = select(res_general, 5) %>%
  na.omit() %>%
  rename(ScientificField = 1) %>%
  count(ScientificField) %>%
  complete(ScientificField = c("Engineering sciences","Humanities and social sciences","Life sciences","Natural sciences","Interdisciplinary project"), fill = list(n = 0))

# Move "Interdisciplinary project" to end for plotting
plot1_data = plot1_data %>%
  bind_rows(slice(.,3)) %>%
  slice(-3)

# lock factor level order
#plot1_data$ScientificField <- factor(plot1_data$ScientificField, levels = plot1_data$ScientificField)

# Make bar plot
plot_1 <- ggplot(plot1_data, aes(x=reorder(ScientificField, -as.numeric(n)), y=as.numeric(n), fill=ScientificField)) +
  geom_bar(colour="black", stat="identity") +
  scale_y_continuous(expand = expansion(mult = c(0, .1))) +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal() +
  theme(axis.text.x = element_blank()) +
  labs(fill = "Scientific field", y = "Participants", x = "Scientific field")

plot_1

Figure 1: Distribution of scientific fields in which participants of the survey work primarily.

In total, 34 individuals took part in the survey. The majority of contributions came from the Life Science domain with a total of 19 participants. The second largest group were people engaged in interdisciplinary projects. Of the 6 people within this group, two are active in the NFDI project Base4NFDI, two are working in local data initiatives at universities, one was active in the NFDI4Earth consortium, and one was active in multiple NFDI consortia. The rest of the participants were split between projects in Engineering sciences (3), Humanities and Social sciences (2), and Natural sciences (1). One participant classified themselves as local contact person for RDM matters without specifying a scientific domain. This distribution of scientific fields represents a clear bias towards contributions from the Life sciences domain, which will be taken into consideration in the further evaluation of the survey results.

NFDI consortia representation

Since most of the participants indicated that they are active in more than one NFDI consortium, we were also interested to know which consortia are not represented by at least one participant of the survey. This information can be helpful when deciding which NFDI consortia should be contacted directly, if it is intended to improve the data basis of this survey in the future. All NFDI consortia which were not represented in the current survey results are listed in the following table.

# Table: not represented NFDI consortia

# read in table with all NFDI consortia + domains
consortia = read.csv("data/NFDI_consortia.CSV", sep = ";")

# extract NFDI consortia data from results
tab1_data = select(res_general, 3) %>%
  rename(consortium = 1) %>%
  # discard empty rows
  na.omit() %>%
  # split fields with multiple entries
  separate_longer_delim(consortium, delim = "; ") %>%
  # discard duplicates
  distinct()

# add new column indicating presence
tab1_data$represented = TRUE

# merge with consortia table, discard represented consortia
tab1_data = left_join(consortia, tab1_data, by = join_by(consortium)) %>%
  mutate(represented = replace_na(represented, FALSE)) %>%
  filter(represented == FALSE)

if (knitr::is_html_output()) {
  datatable(tab1_data)
} else {
  flextable(tab1_data, cwidth = c(2,3,1)) %>%
  set_header_labels(consortium = "NFDI Consortium", domain = "Scientific domain", represented = "Represented?") %>%
  theme_zebra()
}

Table 1: NFDI consortia that are not represented by at least one participant of the online survey.

Representation of further RDM initiatives and projects

Besides their involvement in NFDI projects, we also asked participants if they are active in other RDM initiatives and projects outside of the NFDI space. The following table shows an overview of the initiatives mentioned by participants.

#manually extract information from results (res_general) and generate table
Initiatives <- c("ELIXIR","de.NBI", "TRR projects", "local RDM initiatives", "EOSC", "RDA", "CLARIN ERIC", "QUADRIGA", "HMC")
n <- c(4, 4, 3, 3, 3, 1, 1, 1, 1)

tab2_data <- data.frame(Initiatives, n)

if (knitr::is_html_output()) {
  datatable(tab2_data)
} else {
  flextable(tab2_data, cwidth = c(3,1)) %>%
  set_header_labels(Initiatives = "Initiative/Project", n = "n") %>%
  theme_zebra()
}

Table 2: non-NFDI RDM projects represented by participants

Table of contents

Provision of cloud services

The first topic-specific question block of the survey was primarily addressing participants who already provide cloud services for their target audience or are in the process of developing such a solution. We asked them which services they provide, what their experiences with implementing those services were, and what challenges they faced. If participants indicated that they are not offering cloud services for their users, we were also interested in the reason for this decision. Lastly, participants were asked to indicate how well they think cloud services are accepted in their user base and what the possible reasons for low acceptance could be.

Characterization of provided cloud services

#summarise answers to first question
b2q1 = res_CS_provision %>%
  rename(answer = 2) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

# collect free text answers to second question
b2q2 = res_CS_provision %>%
  rename(answer = 3) %>%
  select(answer) %>%
  na.omit()

Out of 33 participants, 23 (70%) indicated that they are providing cloud services for their target audience already, while 2 participants stated that they are currently implementing such a cloud service. The cloud services that are provided by participants of the survey can be roughly classified into four main types: (i) cloud storage, (ii) resources for field-specific applications, (iii) generic compute resources and VM hosting, and (iv) research metadata services.

Cloud storage

Overall, the most frequently mentioned service that participants provide was cloud storage. Given examples ranged from commercial cloud storage solutions, over storage devices provided through self-hosted Infrastructure-as-a-Service (IaaS) solutions, to the application of established file-sharing protocols. The only commercial cloud storage service that was mentioned by participants is the Simple Storage Service (S3)1, which is part of Amazon Web Services (AWS)2. IaaS solutions that are hosted by some participants seem to be mostly based on the OpenStack cloud operating system3 and thus the OpenStack Object Storage (Swift) software4 was used to provide access to the storage backend in those cases.

Both, S3 and Swift, are object storage solutions which are particularly suited to handle large amounts of unstructured data in large files. Notably, block storage was also mentioned by two participants, presumably for specific applications that are based on structured data and benefit from shorter access times in contrast to object storage, especially for small files.

Another frequently mentioned cloud storage application use case is the provision of shared file systems, either within closed academic networks or on a global scale. The provision of local shared file systems was realized by using established file sharing protocols like the UNIX network protocol Network File System (NFS)5 or the equivalent protocol used by Windows operating systems: Server Message Block (SMB)6. In one record, a participant also mentioned the use case of making such shared file systems accessible from outside the closed academic network by using the non-profit service Globus share7, which was developed at the University of Chicago and can be accessed from around the world.

Cloud services for field-specific applications

Besides cloud storage, field-specific applications running in the cloud were the most frequently mentioned cloud services provided by participants of the survey. Naturally, this is also the most diverse category of services, since every specialized field has developed its own applications to solve specific problems within the field. Most of the specialized applications mentioned by participants were developed to provide execution environments for particular workflows and/or handle field-specific data types.

A good example for specialized execution environments is the provision of compute resources to execute automated text analysis algorithms. This is a use-case that was in the past primarily popular in the social sciences field, but the recent explosion of Natural Language Processing (NLP) applications, primarily driven by the adoption of deep neural network methods (deep learning)8, has demonstrated that many fields can benefit from this expertise9 10 11.

An example of field-specific applications, that is more focused on handling specific data types, is the provision of environments that are specialized to deal with image data. One of those applications, that originated in the light-microscopy domain, is the Open Microscopy Environment Remote Objects (OMERO) software platform12. The SaaS platform was developed based on the Open Microscopy Environment (OME) Data Model13 and the image translation library Bio-Formats14 and provides a data management platform for analysis and processing of complex image data. It has also been adapted to provide the basis of scientific image repositories and extensions are developed to handle other use cases besides image data, like analysis of human genome data15.

Another application that might be particularly interesting for scientific disciplines with a wet-lab component are Lab Information Management Systems (LIMS). LIMS are software solutions that allow research laboratories to manage samples, instruments, processes, and generated data within one integrated system. Electronic Lab Notebooks (ELN) fall, depending on the feature set they provide, under the same umbrella term, but are usually more focused on documenting the research process and serve as a replacement of traditional paper lab notebooks. Both, LIMS and ELNs, are regularly deployed as closed institutional solutions and as cloud services with broader access possibilities and interoperability with other services. Popular open source examples of ELNs that are also deployed within several NFDI projects are Chemotion16, a service particularly designed for the chemical sciences, and eLabFTW17, a more generic service which can be adapted to several research disciplines.

Participants of the survey were also involved in the Galaxy project, which provides freely accessible data analysis tools and pipelines for researchers that can be accessed through a graphical user interface in a web browser environment. The project was originally initiated within the field of genomics and aimed at making reproducible computational workflows available to researchers without in-depth skills in bioinformatics 18. Since then, the project has massively grown and is now providing computational resources world wide for a constantly growing user base that has expanded far beyond the field of genomics 19. The service has been constantly updated and now encompasses a sophisticated learning platform for users and a vast collection of software packages for data analysis in a variety of research fields. Besides Galaxy, the Cloud-based workflow manager (CloWM) was also brought up by survey participants as an alternative platform to execute reproducible analysis pipelines in the cloud. The service allows developers to convert their workflows into a web service for publication and execution by end users on a scalable compute cluster20.

Generic compute resources and research metadata services

Beside the aforementioned specialized applications, provision of generic compute resources was also frequently mentioned by participants of the survey. This is likely connected to the fact that many professionals addressed by the survey work in core facilities of universities and other academic institutions and part of their work is the provision and maintenance of computational resources for institution members and the scientific public. As already hinted at in a previous section, OpenStack and AWS seem to be the preferred platforms for this task among participants, and also the deployment of kubernets clusters was frequently mentioned by participants.

  • de.NBI
  • SimpleVM
  • Infrastructure-as-a-service (IaaS) - OpenStack instances, kubernetes clusters
  • JupyterHub
  • research metadata services

Challenging topics encountered by cloud service providers

# collect answers to third question
b2q3 = res_CS_provision %>%
  rename(answer = 4) %>%
  select(answer) %>%
  na.omit()

We asked participants of the survey, who are involved in providing cloud services for researchers, which topics they found to be particularly challenging when implementing and operating those services. The answers to this question were split between four superordinate subject areas: (i) technical challenges, (ii) legal challenges, (iii) user interaction, and (iv) maintenance and continued development. Topics for each subject area are summarized below and can serve as a first orientation when deciding which training material addressing cloud service providers would be relevant for this group in context of the cloud technology competence center.

Technical challenges:

  • appropriate service architecture design
    • trade offs between cost, complexity, data volume
  • implementation of identity management/user authentication
    • single sign on
  • scaling services to accomodate large user numbers
    • storage, RAM, compute power
  • containerization of tools and workflows
  • security of web services
  • federated operation of cloud services across multiple operation sites

Legal challenges:

  • handling sensitive data (e.g. medical research data)
  • certification of services
  • GDPR-compliant data privacy policies
  • legally binding terms of usage

User interaction:

  • providing user training, consultation, and support
  • cultivating user engagement to provide additional content
  • communication between service providers and users:
    • imparting technical possibilities and constraints to the end users
    • communicating needs of the end users to developers of the service

Maintenance and continued development:

  • strategies to promote user participation in continued development of services
  • education of (new) employees about cloud infrastructure and secure operation of cloud services
  • appropriate documentation and managing division of work to avoid unnecessary duplication of work (efficient usage of limited manpower)
  • resources to quickly and efficiently train lateral entry employees, new employees in general (tackling shortage of qualified workforce)
  • securing continued funding

Acceptance and relevance of cloud services

In the last question of the first question block we wanted to know how well cloud services are accepted among the potential user base in the perception of survey participants. We asked the participants to rate user acceptance on a scale between 0 and 10, where 0 meant users did not accept cloud services at all and 10 equaled full acceptance of cloud services in the user base. The results of the rating are summarized in the histogram below.

#get rating values for cloud acceptance
b2q4 = res_CS_provision %>%
  rename(val = 9) %>%
  select(ID, val) %>%
  na.omit()

#make a histogram for visualization of distribution
plot_2 <- ggplot(b2q4, aes(x=val)) +
  geom_histogram(binwidth = 1, color = "black", fill="#00A2F9") +
  geom_vline(aes(xintercept = median(val)), color = "red", linetype = "dashed", linewidth = 1) +
  scale_x_continuous(breaks = seq(0, 10, by = 1), limits = c(0,11)) +
  geom_text(x=1, y=10, label="n = 32", size = 5) +
  geom_text(x=1, y=9, label="median = 8", size = 5) +
  theme_minimal() +
  xlab("value") +
  ggtitle("Cloud service acceptance estimation of survey participants")

plot_2

Figure 2:

Overall the results imply that cloud services are generally well accepted with a median acceptance value of 8. Besides the clear peak around an acceptance value of 8, however, there was also a considerable number of participants that rated acceptance of cloud services with a value of 5 or less. We were interested to know if low acceptance values correlated with the scientific field in which they were used. Many of the already existing cloud services supporting research originate from the Life Science domain and have been actively used by the community since more than a decade in some cases. Users from the Life Science domain might therefore be accustomed to the tools and processes in contrast to other domains, potentially increasing acceptance. We therefore separated acceptance ratings of survey participants from the Life Science domain from the other results and generated two histograms, one with acceptance values from the Life Science domain and the other summarizing results from all other scientific disciplines.

#get scientific field answers and merge with acceptance value
scientific_field_data = select(res_general, ID, 5) %>%
  na.omit() %>%
  rename(ScientificField = 2)

plot2_data <- left_join(b2q4, scientific_field_data, by = "ID")

#subset data for Life Science and non Life science
plot2_data_LS <- filter(plot2_data, ScientificField == "Life sciences")
plot2_data_noLS <- filter(plot2_data, ScientificField != "Life sciences")

#plot both subsets next to each other
plot_2a <- ggplot(plot2_data_LS, aes(x=val)) +
  geom_histogram(binwidth = 1, color = "black", fill="#00A2F9") +
  geom_vline(aes(xintercept = median(val)), color = "red", linetype = "dashed", linewidth = 1) +
  scale_x_continuous(breaks = seq(0, 10, by = 1), limits = c(0,11)) +
  ylim(0, 8) +
  geom_text(x=1, y=7, label="n = 18", size = 5) +
  geom_text(x=1, y=5, label="median = 8", size = 5) +
  theme_minimal() +
  xlab("") +
  ggtitle("Cloud service acceptance estimation in Life Sciences")

plot_2b <- ggplot(plot2_data_noLS, aes(x=val)) +
  geom_histogram(binwidth = 1, color = "black", fill="#00A2F9") +
  geom_vline(aes(xintercept = median(val)), color = "red", linetype = "dashed", linewidth = 1) +
  scale_x_continuous(breaks = seq(0, 10, by = 1), limits = c(0,11)) +
  ylim(0, 8) +
  geom_text(x=1, y=7, label="n = 12", size = 5) +
  geom_text(x=1, y=5, label="median = 6.5", size = 5) +
  theme_minimal() +
  xlab("value") +
  ggtitle("Cloud service acceptance estimation outside Life Sciences")

grid.arrange(plot_2a, plot_2b, ncol = 1)

#calculate some statistics
n2a = nrow(plot2_data_LS)
median2a = median(plot2_data_LS$val)
n2b = nrow(plot2_data_noLS)
median2b = median(plot2_data_noLS$val)

# plot cloud service acceptance cloud providers vs non-cloud-providers
plot3_data = res_CS_provision %>%
  rename(val = 9, provider = 2) %>%
  select(ID, provider, val) %>%
  na.omit()

plot3_data_provider <- filter(plot3_data, provider == "Yes")
plot3_data_nonprovider <- filter(plot3_data, provider != "Yes")

plot_3a <- ggplot(plot3_data_provider, aes(x=val)) +
  geom_histogram(binwidth = 1, color = "black", fill="#00A2F9") +
  geom_vline(aes(xintercept = median(val)), color = "red", linetype = "dashed", linewidth = 1) +
  scale_x_continuous(breaks = seq(0, 10, by = 1), limits = c(0,11)) +
  ylim(0, 8) +
  theme_minimal() +
  xlab("") +
  ggtitle("Cloud service acceptance estimation of cloud service providers")

plot_3b <- ggplot(plot3_data_nonprovider, aes(x=val)) +
  geom_histogram(binwidth = 1, color = "black", fill="#00A2F9") +
  geom_vline(aes(xintercept = median(val)), color = "red", linetype = "dashed", linewidth = 1) +
  scale_x_continuous(breaks = seq(0, 10, by = 1), limits = c(0,11)) +
  ylim(0, 8) +
  theme_minimal() +
  xlab("value") +
  ggtitle("Cloud service acceptance estimation of participants not providing cloud services")

#grid.arrange(plot_3a, plot_3b, ncol = 1)

Figure 3:

The two plots show that median acceptance of cloud services drops notably when considering only contributions from outside the Life Science domain to a value of 6.5, compared to a median acceptance of 8 within Life Sciences. These results suggest that scientists from other disciplines are generally more hesitant to use cloud services in their research process.

#collect free text answer for reasoning why cloud services are not accepted
b2q5 <- res_CS_provision %>%
  rename(val = 9, answers = 10) %>%
  select(ID, val, answers) %>%
  filter(val <= 6) %>%
  na.omit()

#b2q5$answers

To better understand the potential reasons for low acceptance of cloud services within the research community, we asked participants for their opinion on this topic. The free-text answers to this question are summarized in the following bullet points:

Technical issues

  • low data transfer rates from local machines to the cloud, especially for large files (e.g. mass spectrometry)
  • tools developed by the community for data analysis on client machines are not well adapted to be deployed in a cloud environment

Practical issues

  • increased workload of transferring data from the machine where it was generated to the cloud environment for analysis
  • preference to execute analysis software on local machines
  • hesitance to change established routines for data analysis
  • cloud services do not provide enough advantages to justify changing processes in the eyes of users

Missing education and lack of trust in cloud technologies

  • users are afraid to loose sovereignty over their data when uploading it to a cloud platform
  • data analysis in a cloud environment is perceived as a “black box”, meaning users do not fully understand the workflow and are therefore hesitant to trust the results
  • lack of (technical) knowledge about cloud services
  • general lack of exposure to cloud environments and familiarity with using those services

Table of contents

Training content

The second question block of the survey included questions around the topic of training materials teaching the use and implementation of cloud services for the purpose of research data management and data analysis. We wanted to know which training content is already existing within the projects of survey participants, in which form it is provided, and which gaps exist that can be filled by the de.KCD project.

Provision of training content

Out of 34 survey participants, 20 (59%) indicated that they are providing training materials within their project already. When designing the training material, all participants who provided training content had PhD students and Post-docs as a target group in mind (see Figure 4). Besides that, employees at research institutions (16 out of 20) and students in general (15 out of 20) were the second most frequently mentioned target group. The least frequently mentioned target group were data stewards, who were considered by 8 out of 20 participants who provide training content within their project. One participant indicated that they are providing training content targeted at all academic levels.

## "Do you provide training content?"
# get summary of question 1
b3q1 = res_training %>%
  rename(answer = 2) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

#if (knitr::is_html_output()) {
#  datatable(b3q1)
#} else {
#  flextable(b3q1, cwidth = c(1,1)) %>%
#  set_header_labels(answer = "Answer", n = "n") %>%
#  theme_zebra()
#}

## Training content target group
# collect answers to 2nd question and split multi-choice columns by delimiter
b3q2 = res_training %>%
  rename(answer = 3) %>%
  select(answer) %>%
  na.omit() %>%
  separate_longer_delim(answer, delim = ";")

# remove leading and trailing whitespaces 
b3q2 <- as.data.frame(gsub("^\\s+|\\s+$", "", b3q2$answer))

# count occurences of answers
plot3_1_data = b3q2 %>%
  rename(answer = 1) %>%
  count(answer)

# make bar plot
plot3_1 <- ggplot(plot3_1_data, aes(x=reorder(answer, -as.numeric(n)), y=n, fill = reorder(answer, -as.numeric(n)))) +
  geom_bar(color = "black", stat = "identity") +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal() +
  theme(axis.text.x = element_blank()) +
  labs(fill = "Target group", y = "count", x = "Target group")

plot3_1

Figure 4: Target groups for training materials provided within the projects of survey participants.

Training materials can be provided in many different ways, so we were interested to know in which form the content is provided to the target audience. The results of this question are shown in Figure 5. Almost all participants (19 out of 20) who provide training content use online courses and workshops as a vehicle to deliver knowledge about their cloud services to their users. Besides that, slide decks (12 out of 20) and knowledge databases or wikis (11 out of 20) were popular choices as well. Only a minority provided training materials via a project homepage (8 out of 20) and educational video material was the least popular choice to deliver knowledge to the target group (5 out of 20).

## Type of training content
b3q3 = res_training %>%
  rename(answer = 5) %>%
  select(answer) %>%
  na.omit() %>%
  separate_longer_delim(answer, delim = ";")

# remove leading and trailing whitespaces 
b3q3 <- as.data.frame(gsub("^\\s+|\\s+$", "", b3q3$answer))

# count occurences of answers
plot3_2_data = b3q3 %>%
  rename(answer = 1) %>%
  count(answer)

# make bar plot
plot3_2 <- ggplot(plot3_2_data, aes(x=reorder(answer, -as.numeric(n)), y=n, fill = reorder(answer, -as.numeric(n)))) +
  geom_bar(color = "black", stat = "identity") +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal() +
  theme(axis.text.x = element_blank()) +
  labs(fill = "Type of training content", y = "count", x = "Type of training content")

plot3_2

Figure 5: Types of training content that are used within projects of survey participants to deliver knowledge to their target audience.

Besides the pre-defined types of training content shown above, participants also used other means to transfer knowledge to their target audience. Those include individual training sessions, documentation in git repositories, jupyter notebooks, and interactive self learning platforms.

# list "other"
plot3_2_other = res_training %>%
  rename(answer = 6) %>%
  select(answer) %>%
  na.omit()

#if (knitr::is_html_output()) {
#  datatable(plot3_2_other)
#} else {
#  flextable(plot3_2_other, cwidth = 3) %>%
#  set_header_labels(answer = "Other answers") %>%
#  theme_zebra()
#}

Subjects for which survey participants provide learning content:

## Training content subjects
b3q4 = res_training %>%
  rename(answer = 7) %>%
  select(answer) %>%
  na.omit()

#b3q4$answer

HPC training

  • Usage of HPC resources
    • how to create and access VMs
  • file transfer to VMs
  • use of cloud storage devices
    • object storage
    • cinder volumes
    • S3 storage

Cloud service training

  • Basic usage of the provided cloud services
  • How to run Large Language Models (LLM) in the cloud
  • SysAdmin, Audit, Network, and Security (SANS) training
  • cloud service deployment and optimization
  • overview and benefits of cloud solutions

Research data management training

  • Research Data Management (RDM) basics
    • FAIR data management
    • FAIR research software
  • citation of data
  • data access and processing with python
  • Use of catalogs in combination with data hosted in the cloud

Workflow/Analysis pipeline training

  • Basic training and materials for workflow developers
  • Usage of workflow management systems for data analysis
  • Field-specific analysis pipelines
    • Metagenome analyses in the cloud

Cloud services for training content and courses

Do participants use cloud-based services for conducting training?

## cloud-based services for training
# summarize usage of cloud services to provide training content
b3q5 = res_training %>%
  rename(answer = 8) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

if (knitr::is_html_output()) {
  datatable(b3q5)
} else {
  flextable(b3q5, cwidth = c(2,1)) %>%
  set_header_labels(answer = "Answer", n = "n") %>%
  theme_zebra()
}

Which cloud services are used to conduct training?

# collect answers
b3q6 = res_training %>%
  rename(answer = 9) %>%
  select(answer) %>%
  na.omit()

#b3q6$answer
  • Jupyter Notebooks are most popular among participants
    • also in combination with JupyterHub for multi-user sessions
  • Virtual machines are also popular
    • often deployed via SimpleVM
  • Galaxy training infrastructure as-a-service
  • Github/Gitlab repositories
  • VSCode research environments
  • portal for R shiny applications for data processing and visualization
  • X2Go
  • Hobbyfarm

Potential for additional training content provided by de.KCD partners

## Most important topics participants would need training on:
b3q7 = res_training %>%
  rename(answer = 10) %>%
  select(answer) %>%
  na.omit()

#b3q7$answer

We asked the survey participants which, in their opinion, are the most important topics on which they or people in their project would need additional training materials. The free text answers to this question are summarized in the following bullet points.

Cloud infrastructure knowledge

  • Cloud infrastructure basics
  • Linux Sysadmin basics
  • General introduction and best practice examples for different software stacks
  • How to ensure resilience and stability of cloud services
  • Networking and routing
  • Security and accessibility of cloud infrastructure
  • How to develop and deploy cloud-based resources/applications in a scalable way
  • Training on higher-level frameworks
    • Kubernetes
    • Ansible
    • Terraform
  • Debugging of complex cloud systems
  • Concepts of volatile cloud resources

Research data management for applications in the cloud

  • Basics of data management
  • Structuring complex data sets/analysis pipelines
  • Navigating the complex system of metadata, also in combination with ontologies
  • How to make data tidy
  • Ensuring reproducibility
  • Usage of cloud infrastructure for FAIR RDM

Data analysis in the cloud

  • How to transfer data into cloud environments
    • focus on large data sets
  • Workflow development with nextflow
    • understanding the nextflow concept of dataflow programming (e.g. channels)
  • Implementing portable workflows
    • ensuring the ability to run and proper scaling with large compute clusters
  • Information about parallel processing to exploit parallel access to cloud-hosted data

Access to cloud resources

  • How to include cloud resources in tools like VSCode
  • How to access different resources, e.g. via REST APIs, with the goal to use them in local or cloud analysis pipelines
  • How to effectively stream data between cloud sites for the purpose of analyzing data sets that are stored elsewhere
    • in particular, solutions for image data is sought
    • methods to minimize amount of data that needs to be transferred

Other topics

  • Data security and data privacy
    • practical use cases and best practices
  • Basic concepts of shell programming
  • How to best provide software solutions to a wide and diverse user community
  • Advantages of using digital services

Table of contents

Data processing

Characterization of typical data in projects of participants

Main types of data in the project:

b4q1 = res_data %>%
  rename(answer = 2) %>%
  select(answer) %>%
  na.omit()

if (knitr::is_html_output()) {
  datatable(b4q1)
} else {
  flextable(b4q1, cwidth = 6) %>%
  set_header_labels(answer = "Answers") %>%
  theme_zebra()
}

Typical size of data files within the project:

x <- c("GBytes", "Hundreds of GBytes", "TBytes", "Hundreds of TBytes", "PBytes")

b4q2 = res_data %>%
  rename(answer = 3) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer) %>%
  mutate(answer = factor(answer, levels = x)) %>%
  arrange(answer)

# make bar plot
plot4_1 <- ggplot(b4q2, aes(x=answer, y=n, fill = answer)) +
  geom_bar(color = "black", stat = "identity") +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal() +
  theme(axis.text.x = element_blank()) +
  labs(fill = "Magnitude of data", y = "count", x = "Magnitude of data")

plot4_1

Figure 6:

Cloud solutions for data deposition and sharing

Do participants provide cloud solutions for data deposition and sharing?

# Do participants provide cloud solutions for data deposition and sharing?
b4q3 = res_data %>%
  rename(answer = 4) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

if (knitr::is_html_output()) {
  datatable(b4q3)
} else {
  flextable(b4q3, cwidth = c(2,1)) %>%
  set_header_labels(answer = "Answer", n = "n") %>%
  theme_zebra()
}
# Which services do they provide?
b4q4 = res_data %>%
  rename(answer = 5) %>%
  select(answer) %>%
  na.omit()

#b4q4$answer

Used data deposition services:

  • established field-specific data repositories
    • EBI
    • NCBI
    • EMBL
    • Genbank
    • DDJB
  • commercial cloud storage
    • AWS S3 storage based solutions
    • Dell EMC Isilon
  • self hosted open-source software solutions
    • ownCloud
    • Ceph storage
  • open-source platforms
    • Galaxy Europe
    • Gitlab
  • non-profit services
    • Globus share
  • self-developed storage solutions
    • MWN Cloud Storage (LRZ)
    • Data Science Storage (LRZ)
    • Gitlab-based DataHUBs (DataPLANT)

Standardized data formats

Are standardized formats used for data and metadata?

# Are standardized formats used for data and metadata?
b4q5 = res_data %>%
  rename(answer = 6) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

if (knitr::is_html_output()) {
  datatable(b4q5)
} else {
  flextable(b4q5, cwidth = c(1,1)) %>%
  set_header_labels(answer = "Answer", n = "n") %>%
  theme_zebra()
}

Which standardized data formats are used?

# Which standard formats are used?
b4q6 = res_data %>%
  rename(answer = 7) %>%
  select(answer) %>%
  na.omit()

if (knitr::is_html_output()) {
  datatable(b4q6)
} else {
  flextable(b4q6, cwidth = 6) %>%
  set_header_labels(answer = "Answers") %>%
  theme_zebra()
}

Handling sensitive personal data

Is sensitive data handled within the project?

# Is sensitive data handled within the project?
b4q7 = res_data %>%
  rename(answer = 8) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

if (knitr::is_html_output()) {
  datatable(b4q7)
} else {
  flextable(b4q7, cwidth = c(1,1)) %>%
  set_header_labels(answer = "Answer", n = "n") %>%
  theme_zebra()
}
# How is sensitive data protected?
b4q8 = res_data %>%
  rename(answer = 9) %>%
  select(answer) %>%
  na.omit()

#b4q8$answer

Measurements to protect sensitive data:

  • implementation of audited information security management systems
  • Technical and operational measurements (TOM) according to GDPR
  • dedicated teams and departments
  • isolation and separation of data processing environments
  • documentation of the whole process from patient over controller to processing through SOP documents

Machine-learning algorithms for data analysis

Is the use of AI algorithms relevant for the project?

# is the use of AI algorithms relevant for the project?
b4q9 = res_data %>%
  rename(answer = 10) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

if (knitr::is_html_output()) {
  datatable(b4q9)
} else {
  flextable(b4q9, cwidth = c(1,1)) %>%
  set_header_labels(answer = "Answer", n = "n") %>%
  theme_zebra()
}

Which algorithms are used and for which purpose?

# Which algorithms and for what purpose?
b4q10 = res_data %>%
  rename(answer = 11) %>%
  select(answer) %>%
  na.omit()

if (knitr::is_html_output()) {
  datatable(b4q10)
} else {
  flextable(b4q10, cwidth = 6) %>%
  set_header_labels(answer = "Answers") %>%
  theme_zebra()
}

Solutions for reproducible data analysis

Are solutions for reproducible analysis employed?

# Are solutions for reproducible analysis employed?
b4q11 = res_data %>%
  rename(answer = 12) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

if (knitr::is_html_output()) {
  datatable(b4q11)
} else {
  flextable(b4q11, cwidth = c(1,1)) %>%
  set_header_labels(answer = "Answer", n = "n") %>%
  theme_zebra()
}

Which services or solutions are used for reproducible data analysis?

# Which services/solutions are used?
b4q12 = res_data %>%
  rename(answer = 13) %>%
  select(answer) %>%
  na.omit()

if (knitr::is_html_output()) {
  datatable(b4q12)
} else {
  flextable(b4q12, cwidth = 6) %>%
  set_header_labels(answer = "Answers") %>%
  theme_zebra()
}

Are services for reproducible data analysis used or provided via the cloud?

# Are cloud solutions for reproducible analysis employed?
b4q13 = res_data %>%
  rename(answer = 14) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

if (knitr::is_html_output()) {
  datatable(b4q13)
} else {
  flextable(b4q13, cwidth = c(1,1)) %>%
  set_header_labels(answer = "Answer", n = "n") %>%
  theme_zebra()
}

Is reproducible data analysis via cloud of interested, in case it is not yet used?

# Would cloud solutions for reproducible data analysis be of interest, in case they are not used yet?
b4q14 = res_data %>%
  rename(answer = 15) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

if (knitr::is_html_output()) {
  datatable(b4q14)
} else {
  flextable(b4q14, cwidth = c(1,1)) %>%
  set_header_labels(answer = "Answer", n = "n") %>%
  theme_zebra()
}

Data management software

Is data management software used as part of the project?

# Are data management solutions employed?
b4q15 = res_data %>%
  rename(answer = 16) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

if (knitr::is_html_output()) {
  datatable(b4q15)
} else {
  flextable(b4q15, cwidth = c(1,1)) %>%
  set_header_labels(answer = "Answer", n = "n") %>%
  theme_zebra()
}

Which data management solutions are used?

# Which services/solutions are used?
b4q16 = res_data %>%
  rename(answer = 17) %>%
  select(answer) %>%
  na.omit()

if (knitr::is_html_output()) {
  datatable(b4q16)
} else {
  flextable(b4q16, cwidth = c(4)) %>%
  set_header_labels(answer = "Answer") %>%
  theme_zebra()
}

Table of contents

Infrastructure

Are cloud services hosted on own or external infrastructure?

# Where do participants host their cloud services?
b5q1 = res_infra %>%
  rename(answer = 2) %>%
  select(answer) %>%
  na.omit() %>%
  count(answer)

# make bar plot
plot5_1 <- ggplot(b5q1, aes(x=answer, y=n, fill = answer)) +
  geom_bar(color = "black", stat = "identity") +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal() +
  theme(axis.text.x = element_blank()) +
  labs(fill = "Hosting of cloud services", y = "count", x = "Hosting of cloud services")

plot5_1

Figure 7:

Which infrastructure is used for hosting cloud services?

# Which infrastructure is used exactly?
b5q2 = res_infra %>%
  rename(answer = 3) %>%
  select(answer) %>%
  na.omit()

#b5q2$answer

# manual summary of answers:
Infrastructure <- c("de.NBI cloud", "academic compute centres (OpenStack)", "academic compute centres (kubernetes)", "academic compute centres (undefined)", "commercial providers", "cloWM", "Galaxy EU", "VMware")
n <- c(13, 3, 2, 6, 2, 1, 1, 1)

tab5_1_data <- data.frame(Infrastructure, n)

if (knitr::is_html_output()) {
  datatable(tab5_1_data)
} else {
  flextable(tab5_1_data, cwidth = c(3, 1)) %>%
  theme_zebra()
}

Overview of the usage of selected technologies among participants:

## summary of employed technologies
# gpu resources
b5q3 = res_infra %>%
  rename(answer = 4) %>%
  select(answer) %>%
  count(answer) %>%
  mutate(perc = round(`n` / sum(`n`) * 100), 1) %>%
  mutate(csum = rev(cumsum(rev(perc))), 
         pos = perc/2 + lead(csum, 1),
         pos = if_else(is.na(pos), perc/2, pos))

plot5_2a <- ggplot(b5q3, aes(x = "", y = perc, fill = answer)) +
  geom_col(width = 1, color = "black") +
  coord_polar(theta = "y") +
  scale_fill_brewer(palette = "Set2", direction = -1) +
  geom_label_repel(data = b5q3,
                   aes(y = pos, label = paste0(perc, "%")),
                   size = 4.5, nudge_x = 1, show.legend = FALSE) +
  guides(fill = guide_legend(title = "Answer: ")) +
  theme_void() +
  labs(title = "GPU cloud computing resources")

# containerization software
b5q4 = res_infra %>%
  rename(answer = 5) %>%
  select(answer) %>%
  count(answer) %>%
  mutate(perc = round(`n` / sum(`n`) * 100), 1) %>%
  mutate(csum = rev(cumsum(rev(perc))), 
         pos = perc/2 + lead(csum, 1),
         pos = if_else(is.na(pos), perc/2, pos))

plot5_2b <- ggplot(b5q4, aes(x = "", y = perc, fill = answer)) +
  geom_col(width = 1, color = "black") +
  coord_polar(theta = "y") +
  scale_fill_brewer(palette = "Set2", direction = -1) +
  geom_label_repel(data = b5q4,
                   aes(y = pos, label = paste0(perc, "%")),
                   size = 4.5, nudge_x = 1, show.legend = FALSE) +
  guides(fill = guide_legend(title = "Answer: ")) +
  theme_void() +
  labs(title = "Containerization software")

# container orchestration software
b5q5 = res_infra %>%
  rename(answer = 8) %>%
  select(answer) %>%
  count(answer) %>%
  mutate(perc = round(`n` / sum(`n`) * 100), 1) %>%
  mutate(csum = rev(cumsum(rev(perc))), 
         pos = perc/2 + lead(csum, 1),
         pos = if_else(is.na(pos), perc/2, pos))

plot5_2c <- ggplot(b5q5, aes(x = "", y = perc, fill = answer)) +
  geom_col(width = 1, color = "black") +
  coord_polar(theta = "y") +
  scale_fill_brewer(palette = "Set2", direction = -1) +
  geom_label_repel(data = b5q5,
                   aes(y = pos, label = paste0(perc, "%")),
                   size = 4.5, nudge_x = 1, show.legend = FALSE) +
  guides(fill = guide_legend(title = "Answer: ")) +
  theme_void() +
  labs(title = "Container orchestration software")

# Workflow management systems
b5q6 = res_infra %>%
  rename(answer = 11) %>%
  select(answer) %>%
  count(answer) %>%
  mutate(perc = round(`n` / sum(`n`) * 100), 1) %>%
  mutate(csum = rev(cumsum(rev(perc))), 
         pos = perc/2 + lead(csum, 1),
         pos = if_else(is.na(pos), perc/2, pos))

plot5_2d <- ggplot(b5q6, aes(x = "", y = perc, fill = answer)) +
  geom_col(width = 1, color = "black") +
  coord_polar(theta = "y") +
  scale_fill_brewer(palette = "Set2", direction = -1) +
  geom_label_repel(data = b5q6,
                   aes(y = pos, label = paste0(perc, "%")),
                   size = 4.5, nudge_x = 1, show.legend = FALSE) +
  guides(fill = guide_legend(title = "Answer: ")) +
  theme_void() +
  labs(title = "Workflow management systems")

# make unified plot
grid.arrange(plot5_2a, plot5_2b, plot5_2c, plot5_2d, ncol=2)

Figure 8:

Employed containerization software:

# collect answers for containerization software
b5q7 = res_infra %>%
  rename(answer = 6) %>%
  select(answer)

# manual summary
Containerization_software <- c("docker", "Singularity", "docker-compose", "Apptainer", "Kubermatic", "CharlieCloud")
n <- c(24,7,3,2,1,1)

tab5_2_data <- data.frame(Containerization_software, n)

if (knitr::is_html_output()) {
  datatable(tab5_2_data)
} else {
  flextable(tab5_2_data, cwidth = c(2, 1)) %>%
  set_header_labels(Containerization_software = "Containerization software", n = "n") %>%
  theme_zebra()
}

Employed container orchestration software:

# collect answers for containerization software
b5q8 = res_infra %>%
  rename(answer = 9) %>%
  select(answer)

# manual summary
Container_orchestration_software <- c("Kubernetes","docker swarm","Kubermatic","Rancher","SLURM")
n <- c(8,2,1,1,1)

tab5_3_data <- data.frame(Container_orchestration_software, n)

if (knitr::is_html_output()) {
  datatable(tab5_3_data)
} else {
  flextable(tab5_3_data, cwidth = c(2, 1)) %>%
  set_header_labels(Container_orchestration_software = "Container orchestration software", n = "n") %>%
  theme_zebra()
}

Employed workflow management systems:

# collect answers for containerization software
b5q9 = res_infra %>%
  rename(answer = 12) %>%
  select(answer)

# manual summary
Workflow_management_systems <- c("nextflow","Galaxy","snakemake","Common workflow language (CWL)","UNICORE","P-Grade","WebLicht","targets (R)","Apache airflow")
n <- c(15,6,4,2,2,2,1,1,1)

tab5_4_data <- data.frame(Workflow_management_systems, n)

if (knitr::is_html_output()) {
  datatable(tab5_4_data)
} else {
  flextable(tab5_4_data, cwidth = c(2, 1)) %>%
  set_header_labels(Workflow_management_systems = "Workflow management system", n = "n") %>%
  theme_zebra()
}

Table of contents

Discussion

Table of contents

Supplementary Information

R Session Info

sessionInfo()
R version 4.4.1 (2024-06-14 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 26100)

Matrix products: default


locale:
[1] LC_COLLATE=German_Germany.utf8  LC_CTYPE=German_Germany.utf8   
[3] LC_MONETARY=German_Germany.utf8 LC_NUMERIC=C                   
[5] LC_TIME=German_Germany.utf8    

time zone: Europe/Berlin
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] flextable_0.9.7 scales_1.3.0    ggrepel_0.9.6   gridExtra_2.3  
 [5] webshot_0.5.5   DT_0.33         lubridate_1.9.3 forcats_1.0.0  
 [9] stringr_1.5.1   dplyr_1.1.4     purrr_1.0.2     readr_2.1.5    
[13] tidyr_1.3.1     tibble_3.2.1    ggplot2_3.5.1   tidyverse_2.0.0

loaded via a namespace (and not attached):
 [1] gtable_0.3.5            xfun_0.48               bslib_0.8.0            
 [4] htmlwidgets_1.6.4       tzdb_0.4.0              crosstalk_1.2.1        
 [7] vctrs_0.6.5             tools_4.4.1             generics_0.1.3         
[10] fansi_1.0.6             highr_0.11              pkgconfig_2.0.3        
[13] data.table_1.16.0       RColorBrewer_1.1-3      uuid_1.2-1             
[16] lifecycle_1.0.4         compiler_4.4.1          farver_2.1.2           
[19] textshaping_0.4.0       munsell_0.5.1           fontquiver_0.2.1       
[22] fontLiberation_0.1.0    sass_0.4.9              htmltools_0.5.8.1      
[25] yaml_2.3.10             pillar_1.9.0            jquerylib_0.1.4        
[28] openssl_2.2.2           cachem_1.1.0            fontBitstreamVera_0.1.1
[31] tidyselect_1.2.1        zip_2.3.2               digest_0.6.37          
[34] stringi_1.8.4           labeling_0.4.3          fastmap_1.2.0          
[37] grid_4.4.1              colorspace_2.1-1        cli_3.6.3              
[40] magrittr_2.0.3          utf8_1.2.4              withr_3.0.1            
[43] gdtools_0.4.1           timechange_0.3.0        rmarkdown_2.28         
[46] officer_0.6.7           askpass_1.2.1           ragg_1.3.3             
[49] hms_1.1.3               evaluate_1.0.0          knitr_1.48             
[52] rlang_1.1.4             Rcpp_1.0.13             glue_1.8.0             
[55] xml2_1.3.6              jsonlite_1.8.9          rstudioapi_0.16.0      
[58] R6_2.5.1                systemfonts_1.1.0      

Table of contents


  1. https://aws.amazon.com/s3↩︎

  2. https://aws.amazon.com↩︎

  3. https://docs.openstack.org/2024.2/↩︎

  4. https://docs.openstack.org/swift/latest/↩︎

  5. https://ubuntu.com/server/docs/network-file-system-nfs↩︎

  6. https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-smb↩︎

  7. https://www.globus.org/data-sharing; Ananthakrishnan R., Chard K., Foster I. and Tuecke S. (2015), Globus platform-as-a-service for collaborative science applications, Concurrency Computat.: Pract. Exper., 27, pages 290–305, https://doi.org/10.1002/cpe.3262↩︎

  8. Khurana, D., Koli, A., Khatter, K. et al. Natural language processing: state of the art, current trends and challenges. Multimed Tools Appl 82, 3713–3744 (2023). https://doi.org/10.1007/s11042-022-13428-4↩︎

  9. Turchin A, Florez Builes LF. Using Natural Language Processing to Measure and Improve Quality of Diabetes Care: A Systematic Review. Journal of Diabetes Science and Technology. 2021;15(3):553-560. https://doi.org/10.1177/19322968211000831↩︎

  10. Yuexiong Ding, Jie Ma, Xiaowei Luo. Applications of natural language processing in construction. Automation in Construction 136, 104169 (2022). https://doi.org/10.1016/j.autcon.2022.104169↩︎

  11. Dan Ofer, Nadav Brandes, Michal Linial. The language of proteins: NLP, machine learning & protein sequences. Computational and Structural Biotechnology Journal 19, 1750-1758 (2021). https://doi.org/10.1016/j.csbj.2021.03.022↩︎

  12. Allan, C., Burel, JM., Moore, J. et al. OMERO: flexible, model-driven data management for experimental biology. Nat Methods 9, 245–253 (2012). https://doi.org/10.1038/nmeth.1896↩︎

  13. Goldberg IG, Allan C, Burel JM, Creager D, Falconi A, Hochheiser H, Johnston J, Mellen J, Sorger PK, Swedlow JR. The Open Microscopy Environment (OME) Data Model and XML file: open tools for informatics and quantitative analysis in biological imaging. Genome Biol. 2005;6(5):R47. https://doi.org/10.1186/gb-2005-6-5-r47. Epub 2005 May 3. PMID: 15892875; PMCID: PMC1175959.↩︎

  14. Linkert M, Rueden CT, Allan C, Burel JM, Moore W, Patterson A, Loranger B, Moore J, Neves C, Macdonald D, Tarkowska A, Sticco C, Hill E, Rossner M, Eliceiri KW, Swedlow JR. Metadata matters: access to image data in the real world. J Cell Biol. 2010 May 31;189(5):777-82. https://doi.org/10.1083/jcb.201004104. PMID: 20513764; PMCID: PMC2878938.↩︎

  15. Allan, C., Burel, JM., Moore, J. et al. OMERO: flexible, model-driven data management for experimental biology. Nat Methods 9, 245–253 (2012). https://doi.org/10.1038/nmeth.1896↩︎

  16. Tremouilhac P, Nguyen A, Huang YC, Kotov S, Lütjohann DS, Hübsch F, Jung N, Bräse S. Chemotion ELN: an Open Source electronic lab notebook for chemists in academia. J Cheminform. 2017 Sep 25;9(1):54. https://doi.org/10.1186/s13321-017-0240-0. PMID: 29086216; PMCID: PMC5612905.↩︎

  17. CARPi N, Minges A, Piel M. eLabFTW: An open source laboratory notebook for research labs. Journal of Open Source Software, 2(12), 146 (2017). https://doi.org/10.21105/joss.00146↩︎

  18. Giardine B, Riemer C, Hardison RC, Burhans R, Elnitski L, Shah P, Zhang Y, Blankenberg D, Albert I, Taylor J, Miller W, Kent WJ, Nekrutenko A. Galaxy: a platform for interactive large-scale genome analysis. Genome Res. 2005 Oct;15(10):1451-5. https://doi.org/10.1101/gr.4086505. Epub 2005 Sep 16. PMID: 16169926; PMCID: PMC1240089.↩︎

  19. Galaxy Community. The Galaxy platform for accessible, reproducible, and collaborative data analyses: 2024 update. Nucleic Acids Res. 2024 Jul 5;52(W1):W83-W94. doi: 10.1093/nar/gkae410. PMID: 38769056; PMCID: PMC11223835.↩︎

  20. https://gitlab.ub.uni-bielefeld.de/cmg/clowm/clowm-backend↩︎

LS0tDQp0aXRsZTogJ2RlLktDRCBuZWVkcyBhc3Nlc3NtZW50IHN1cnZleSBldmFsdWF0aW9uJw0KYXV0aG9yOiAiQWxleGFuZGVyIEtpcmJpcyINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCg0Kb3V0cHV0Og0KICANCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgI3BkZl9kb2N1bWVudDoNCiAgICAjdG9jOiB0cnVlDQogIGh0bWxfbm90ZWJvb2s6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgdG9jOiB0cnVlDQogIA0Ka25pdDogKGZ1bmN0aW9uKGlucHV0RmlsZSwgLi4uKSB7DQogICAgcm1hcmtkb3duOjpyZW5kZXIoaW5wdXRGaWxlLCBvdXRwdXRfZm9ybWF0ID0gImFsbCIsIG91dHB1dF9kaXIgPSAiLi9yZXBvcnRzIikNCiAgICB9KQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KaWYgKCFrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkga25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG89RkFMU0UpDQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NCg0KSGVyZSwgd2UgcHJlc2VudCBhbiBhbmFseXNpcyBvZiB0aGUgbmVlZHMgYXNzZXNzbWVudCBvbmxpbmUgc3VydmV5IHJlc3VsdHMgdGhhdCB3ZXJlIGNvbGxlY3RlZCBmb3IgdGhlIEdlcm1hbiBDb21wZXRlbmNlIENlbnRlciBDbG91ZCBUZWNobm9sb2dpZXMgZm9yIERhdGEgTWFuYWdlbWVudCBhbmQgUHJvY2Vzc2luZyAoZGUuS0NEKS4gVGhlIGFpbSBvZiB0aGUgbmVlZHMgYXNzZXNzbWVudCBpcyB0byBnZXQgYW4gb3ZlcnZpZXcgb2YgY2xvdWQgdGVjaG5vbG9naWVzIHRoYXQgYXJlIGRlcGxveWVkIGZvciB0aGUgcHVycG9zZSBvZiBkYXRhIG1hbmFnZW1lbnQgYW5kIGFuYWx5c2lzIGluIHRoZSBkaWZmZXJlbnQgc2NpZW50aWZpYyBmaWVsZHMgYW5kIGJ5IHRoZSBzY2llbnRpZmljIGNvbW11bml0eSBhcyBhIHdob2xlLiBCZXNpZGVzIHRoYXQsIGdhcHMgaW4gZXhpc3RpbmcgdHJhaW5pbmcgbWF0ZXJpYWxzIG9mIHBhcnRpY2lwYXRpbmcgcmVzZWFyY2ggZGF0YSBpbml0aWF0aXZlcyBzaG91bGQgYmUgaWRlbnRpZmllZCB0byBpbmZvcm0gZXhwZXJ0cyBmcm9tIHBhcnRuZXIgaW5zdGl0dXRpb25zIHdoZXJlIGEgbmVlZCBmb3IgYWRkaXRpb25hbCBtYXRlcmlhbHMgZXhpc3RzLiANCg0KVGhlIHN1cnZleSBjYW4gYmUgYWNjZXNzZWQgYnkgdXNpbmcgdGhlIGZvbGxvd2luZyBsaW5rOiBodHRwczovL2VjLmV1cm9wYS5ldS9ldXN1cnZleS9ydW5uZXIvZGVLQ0RfbmVlZHNfYXNzZXNzbWVudF8yMDI0DQoNClRoZSBhbm9ueW1pemVkIHN1cnZleSByZXN1bHRzIGFyZSBhdmFpbGFibGUgaW4gdGhlIGZvbGxvd2luZyBHaXRIdWIgcmVwb3NpdG9yeTogaHR0cHM6Ly9naXRodWIuY29tL2RlS0NEL25lZWRzLWFzc2Vzc21lbnQtZXZhbHVhdGlvbg0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiByaWdodCI+DQoNCltUYWJsZSBvZiBjb250ZW50c10oI2hlYWRlcikNCg0KPC9kaXY+DQoNCiMgQW5hbHlzaXMNCg0KVGhlIHN1cnZleSB3YXMgY2FycmllZCBvdXQgdXNpbmcgdGhlIG9ubGluZSBzdXJ2ZXkgcGxhdGZvcm0gW0VVU3VydmV5XShodHRwczovL2VjLmV1cm9wYS5ldS9ldXN1cnZleS8pLiBUaGUgc3VydmV5IHJlc3VsdHMgd2VyZSBleHBvcnRlZCBpbiB0aGUgcHJvcHJpZXRhcnkgLnhsc3ggZm9ybWF0IGFuZCB0aGVuIGNvbnZlcnRlZCB0byB0aGUgLmNzdiBmb3JtYXQgdG8gZW5hYmxlIGFuYWx5c2lzIHdpdGggb3RoZXIgc29mdHdhcmUgcGFja2FnZXMuIEV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMgYW5kIHBsb3R0aW5nIHdhcyBjb25kdWN0ZWQgdXNpbmcgdGhlIHByb2dyYW1taW5nIGxhbmd1YWdlIFIgYW5kIHRoZSBJREUgUlN0dWRpbywgc2VlIFtSIHNlc3Npb24gaW5mbyBzZWN0aW9uXSgjci1zZXNzaW9uLWluZm8pIGZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLg0KDQpgYGB7ciwgcmVzdWx0cz0naGlkZSd9DQojIGxvYWQgbGlicmFyaWVzDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoRFQpDQpsaWJyYXJ5KHdlYnNob3QpDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCmxpYnJhcnkoZ2dyZXBlbCkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc2NhbGVzKQ0KbGlicmFyeShmbGV4dGFibGUpDQoNCiMgcmVhZCBpbiBzdXJ2ZXkgcmF3IGRhdGENCnJlcyA8LSByZWFkLmNzdigiZGF0YS9Db250ZW50X0V4cG9ydF9kZUtDRF9uZWVkc19hc3Nlc3NtZW50XzIwMjRfMjAyNC0xMS0xOS5DU1YiLCBzZXAgPSAiOyIsIG5hLnN0cmluZ3MgPSBjKCIiLCAiTkEiKSkNCiMgYWRkIHVuaXF1ZSBjb250cmlidXRpb24gSUQgdG8gZWFjaCBlbnRyeQ0KcmVzJElEIDwtIHNlcS5pbnQobnJvdyhyZXMpKQ0KDQojIHNlcGFyYXRlIHJlc3VsdHMgYnkgdG9waWMgYW5kIGtlZXAgc3VibWlzc2lvbiBJRHMgZm9yIGVhY2ggc3Vic2V0DQojIEdlbmVyYWwgaW5mb3JtYXRpb24NCnJlc19nZW5lcmFsIDwtIHNlbGVjdChyZXMsIGMoNTksIDE6NSkpDQojIFByb3Zpc2lvbiBvZiBjbG91ZCBzZXJ2aWNlcw0KcmVzX0NTX3Byb3Zpc2lvbiA8LSBzZWxlY3QocmVzLCBjKDU5LCA2OjE0KSkNCiMgVHJhaW5pbmcgY29udGVudA0KcmVzX3RyYWluaW5nIDwtIHNlbGVjdChyZXMsIGMoNTksIDE1OjIzKSkNCiMgRGF0YSBwcm9jZXNzaW5nDQpyZXNfZGF0YSA8LSBzZWxlY3QocmVzLCBjKDU5LCAyNDo0MSkpDQojIEluZnJhc3RydWN0dXJlDQpyZXNfaW5mcmEgPC0gc2VsZWN0KHJlcywgYyg1OSwgNDI6NTMpKQ0KYGBgDQoNCiMjIEdlbmVyYWwgSW5mb3JtYXRpb24NCg0KVGhlIHByaW1hcnkgdGFyZ2V0IGdyb3VwIGZvciB0aGUgc3VydmV5IHdlcmUgcGVvcGxlIGVuZ2FnZWQgaW4gTkZESSBwcm9qZWN0cyBvciBvdGhlciBwcm9qZWN0cyBkZWRpY2F0ZWQgdG8gcHJvdmlkZSBkYXRhIG1hbmFnZW1lbnQgYW5kIGRhdGEgYW5hbHlzaXMgc2VydmljZXMgZm9yIGEgc2NpZW50aWZpYyBhdWRpZW5jZS4NCg0KIyMjIFNjaWVudGlmaWMgZG9tYWluIHJlcHJlc2VudGF0aW9uDQoNClRvIHVuZGVyc3RhbmQgd2hpY2ggc2NpZW50aWZpYyBmaWVsZHMgYXJlIGNvdmVyZWQgYnkgdGhlIHN1cnZleSByZXN1bHRzLCB3ZSBhc2tlZCBwYXJ0aWNpcGFudHMgdG8gd2hpY2ggZmllbGQgdGhlaXIgcHJvamVjdCBjYW4gYmUgYXNzaWduZWQuIFRoZSBudW1iZXIgb2YgcGFydGljaXBhbnRzIGZyb20gZWFjaCBmaWVsZCBpcyB2aXN1YWxpemVkIGluIHRoZSBmb2xsb3dpbmcgcGxvdDoNCg0KYGBge3J9DQoNCg0KIyBQbG90OiBEaXN0cmlidXRpb24gb2Ygc2NpZW50aWZpYyBmaWVsZHMgYW1vbmcgcGFydGljaXBhbnRzDQoNCiMgU2VsZWN0IHJlbGV2YW50IGNvbHVtbiwgY291bnQgb2NjdXJyZW5jZXMsIGFuZCBhZGQgbj0wIGZvciBtaXNzaW5nIHZhbHVlcw0KcGxvdDFfZGF0YSA9IHNlbGVjdChyZXNfZ2VuZXJhbCwgNSkgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgcmVuYW1lKFNjaWVudGlmaWNGaWVsZCA9IDEpICU+JQ0KICBjb3VudChTY2llbnRpZmljRmllbGQpICU+JQ0KICBjb21wbGV0ZShTY2llbnRpZmljRmllbGQgPSBjKCJFbmdpbmVlcmluZyBzY2llbmNlcyIsIkh1bWFuaXRpZXMgYW5kIHNvY2lhbCBzY2llbmNlcyIsIkxpZmUgc2NpZW5jZXMiLCJOYXR1cmFsIHNjaWVuY2VzIiwiSW50ZXJkaXNjaXBsaW5hcnkgcHJvamVjdCIpLCBmaWxsID0gbGlzdChuID0gMCkpDQoNCiMgTW92ZSAiSW50ZXJkaXNjaXBsaW5hcnkgcHJvamVjdCIgdG8gZW5kIGZvciBwbG90dGluZw0KcGxvdDFfZGF0YSA9IHBsb3QxX2RhdGEgJT4lDQogIGJpbmRfcm93cyhzbGljZSguLDMpKSAlPiUNCiAgc2xpY2UoLTMpDQoNCiMgbG9jayBmYWN0b3IgbGV2ZWwgb3JkZXINCiNwbG90MV9kYXRhJFNjaWVudGlmaWNGaWVsZCA8LSBmYWN0b3IocGxvdDFfZGF0YSRTY2llbnRpZmljRmllbGQsIGxldmVscyA9IHBsb3QxX2RhdGEkU2NpZW50aWZpY0ZpZWxkKQ0KDQojIE1ha2UgYmFyIHBsb3QNCnBsb3RfMSA8LSBnZ3Bsb3QocGxvdDFfZGF0YSwgYWVzKHg9cmVvcmRlcihTY2llbnRpZmljRmllbGQsIC1hcy5udW1lcmljKG4pKSwgeT1hcy5udW1lcmljKG4pLCBmaWxsPVNjaWVudGlmaWNGaWVsZCkpICsNCiAgZ2VvbV9iYXIoY29sb3VyPSJibGFjayIsIHN0YXQ9ImlkZW50aXR5IikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIC4xKSkpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKGZpbGwgPSAiU2NpZW50aWZpYyBmaWVsZCIsIHkgPSAiUGFydGljaXBhbnRzIiwgeCA9ICJTY2llbnRpZmljIGZpZWxkIikNCg0KcGxvdF8xDQpgYGANCioqRmlndXJlIDE6KiogRGlzdHJpYnV0aW9uIG9mIHNjaWVudGlmaWMgZmllbGRzIGluIHdoaWNoIHBhcnRpY2lwYW50cyBvZiB0aGUgc3VydmV5IHdvcmsgcHJpbWFyaWx5Lg0KDQpJbiB0b3RhbCwgYHIgbnJvdyhyZXMpYCBpbmRpdmlkdWFscyB0b29rIHBhcnQgaW4gdGhlIHN1cnZleS4gVGhlIG1ham9yaXR5IG9mIGNvbnRyaWJ1dGlvbnMgY2FtZSBmcm9tIHRoZSBMaWZlIFNjaWVuY2UgZG9tYWluIHdpdGggYSB0b3RhbCBvZiAxOSBwYXJ0aWNpcGFudHMuIFRoZSBzZWNvbmQgbGFyZ2VzdCBncm91cCB3ZXJlIHBlb3BsZSBlbmdhZ2VkIGluIGludGVyZGlzY2lwbGluYXJ5IHByb2plY3RzLiBPZiB0aGUgNiBwZW9wbGUgd2l0aGluIHRoaXMgZ3JvdXAsIHR3byBhcmUgYWN0aXZlIGluIHRoZSBORkRJIHByb2plY3QgQmFzZTRORkRJLCB0d28gYXJlIHdvcmtpbmcgaW4gbG9jYWwgZGF0YSBpbml0aWF0aXZlcyBhdCB1bml2ZXJzaXRpZXMsIG9uZSB3YXMgYWN0aXZlIGluIHRoZSBORkRJNEVhcnRoIGNvbnNvcnRpdW0sIGFuZCBvbmUgd2FzIGFjdGl2ZSBpbiBtdWx0aXBsZSBORkRJIGNvbnNvcnRpYS4gVGhlIHJlc3Qgb2YgdGhlIHBhcnRpY2lwYW50cyB3ZXJlIHNwbGl0IGJldHdlZW4gcHJvamVjdHMgaW4gRW5naW5lZXJpbmcgc2NpZW5jZXMgKDMpLCBIdW1hbml0aWVzIGFuZCBTb2NpYWwgc2NpZW5jZXMgKDIpLCBhbmQgTmF0dXJhbCBzY2llbmNlcyAoMSkuIE9uZSBwYXJ0aWNpcGFudCBjbGFzc2lmaWVkIHRoZW1zZWx2ZXMgYXMgbG9jYWwgY29udGFjdCBwZXJzb24gZm9yIFJETSBtYXR0ZXJzIHdpdGhvdXQgc3BlY2lmeWluZyBhIHNjaWVudGlmaWMgZG9tYWluLiBUaGlzIGRpc3RyaWJ1dGlvbiBvZiBzY2llbnRpZmljIGZpZWxkcyByZXByZXNlbnRzIGEgY2xlYXIgYmlhcyB0b3dhcmRzIGNvbnRyaWJ1dGlvbnMgZnJvbSB0aGUgTGlmZSBzY2llbmNlcyBkb21haW4sIHdoaWNoIHdpbGwgYmUgdGFrZW4gaW50byBjb25zaWRlcmF0aW9uIGluIHRoZSBmdXJ0aGVyIGV2YWx1YXRpb24gb2YgdGhlIHN1cnZleSByZXN1bHRzLg0KDQojIyMgTkZESSBjb25zb3J0aWEgcmVwcmVzZW50YXRpb24NCg0KU2luY2UgbW9zdCBvZiB0aGUgcGFydGljaXBhbnRzIGluZGljYXRlZCB0aGF0IHRoZXkgYXJlIGFjdGl2ZSBpbiBtb3JlIHRoYW4gb25lIE5GREkgY29uc29ydGl1bSwgd2Ugd2VyZSBhbHNvIGludGVyZXN0ZWQgdG8ga25vdyB3aGljaCBjb25zb3J0aWEgYXJlIG5vdCByZXByZXNlbnRlZCBieSBhdCBsZWFzdCBvbmUgcGFydGljaXBhbnQgb2YgdGhlIHN1cnZleS4gVGhpcyBpbmZvcm1hdGlvbiBjYW4gYmUgaGVscGZ1bCB3aGVuIGRlY2lkaW5nIHdoaWNoIE5GREkgY29uc29ydGlhIHNob3VsZCBiZSBjb250YWN0ZWQgZGlyZWN0bHksIGlmIGl0IGlzIGludGVuZGVkIHRvIGltcHJvdmUgdGhlIGRhdGEgYmFzaXMgb2YgdGhpcyBzdXJ2ZXkgaW4gdGhlIGZ1dHVyZS4gQWxsIE5GREkgY29uc29ydGlhIHdoaWNoIHdlcmUgbm90IHJlcHJlc2VudGVkIGluIHRoZSBjdXJyZW50IHN1cnZleSByZXN1bHRzIGFyZSBsaXN0ZWQgaW4gdGhlIGZvbGxvd2luZyB0YWJsZS4NCg0KYGBge3J9DQojIFRhYmxlOiBub3QgcmVwcmVzZW50ZWQgTkZESSBjb25zb3J0aWENCg0KIyByZWFkIGluIHRhYmxlIHdpdGggYWxsIE5GREkgY29uc29ydGlhICsgZG9tYWlucw0KY29uc29ydGlhID0gcmVhZC5jc3YoImRhdGEvTkZESV9jb25zb3J0aWEuQ1NWIiwgc2VwID0gIjsiKQ0KDQojIGV4dHJhY3QgTkZESSBjb25zb3J0aWEgZGF0YSBmcm9tIHJlc3VsdHMNCnRhYjFfZGF0YSA9IHNlbGVjdChyZXNfZ2VuZXJhbCwgMykgJT4lDQogIHJlbmFtZShjb25zb3J0aXVtID0gMSkgJT4lDQogICMgZGlzY2FyZCBlbXB0eSByb3dzDQogIG5hLm9taXQoKSAlPiUNCiAgIyBzcGxpdCBmaWVsZHMgd2l0aCBtdWx0aXBsZSBlbnRyaWVzDQogIHNlcGFyYXRlX2xvbmdlcl9kZWxpbShjb25zb3J0aXVtLCBkZWxpbSA9ICI7ICIpICU+JQ0KICAjIGRpc2NhcmQgZHVwbGljYXRlcw0KICBkaXN0aW5jdCgpDQoNCiMgYWRkIG5ldyBjb2x1bW4gaW5kaWNhdGluZyBwcmVzZW5jZQ0KdGFiMV9kYXRhJHJlcHJlc2VudGVkID0gVFJVRQ0KDQojIG1lcmdlIHdpdGggY29uc29ydGlhIHRhYmxlLCBkaXNjYXJkIHJlcHJlc2VudGVkIGNvbnNvcnRpYQ0KdGFiMV9kYXRhID0gbGVmdF9qb2luKGNvbnNvcnRpYSwgdGFiMV9kYXRhLCBieSA9IGpvaW5fYnkoY29uc29ydGl1bSkpICU+JQ0KICBtdXRhdGUocmVwcmVzZW50ZWQgPSByZXBsYWNlX25hKHJlcHJlc2VudGVkLCBGQUxTRSkpICU+JQ0KICBmaWx0ZXIocmVwcmVzZW50ZWQgPT0gRkFMU0UpDQoNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkgew0KICBkYXRhdGFibGUodGFiMV9kYXRhKQ0KfSBlbHNlIHsNCiAgZmxleHRhYmxlKHRhYjFfZGF0YSwgY3dpZHRoID0gYygyLDMsMSkpICU+JQ0KICBzZXRfaGVhZGVyX2xhYmVscyhjb25zb3J0aXVtID0gIk5GREkgQ29uc29ydGl1bSIsIGRvbWFpbiA9ICJTY2llbnRpZmljIGRvbWFpbiIsIHJlcHJlc2VudGVkID0gIlJlcHJlc2VudGVkPyIpICU+JQ0KICB0aGVtZV96ZWJyYSgpDQp9DQoNCmBgYA0KKipUYWJsZSAxOioqIE5GREkgY29uc29ydGlhIHRoYXQgYXJlIG5vdCByZXByZXNlbnRlZCBieSBhdCBsZWFzdCBvbmUgcGFydGljaXBhbnQgb2YgdGhlIG9ubGluZSBzdXJ2ZXkuDQoNCiMjIyBSZXByZXNlbnRhdGlvbiBvZiBmdXJ0aGVyIFJETSBpbml0aWF0aXZlcyBhbmQgcHJvamVjdHMNCg0KQmVzaWRlcyB0aGVpciBpbnZvbHZlbWVudCBpbiBORkRJIHByb2plY3RzLCB3ZSBhbHNvIGFza2VkIHBhcnRpY2lwYW50cyBpZiB0aGV5IGFyZSBhY3RpdmUgaW4gb3RoZXIgUkRNIGluaXRpYXRpdmVzIGFuZCBwcm9qZWN0cyBvdXRzaWRlIG9mIHRoZSBORkRJIHNwYWNlLiBUaGUgZm9sbG93aW5nIHRhYmxlIHNob3dzIGFuIG92ZXJ2aWV3IG9mIHRoZSBpbml0aWF0aXZlcyBtZW50aW9uZWQgYnkgcGFydGljaXBhbnRzLg0KDQpgYGB7cn0NCiNtYW51YWxseSBleHRyYWN0IGluZm9ybWF0aW9uIGZyb20gcmVzdWx0cyAocmVzX2dlbmVyYWwpIGFuZCBnZW5lcmF0ZSB0YWJsZQ0KSW5pdGlhdGl2ZXMgPC0gYygiRUxJWElSIiwiZGUuTkJJIiwgIlRSUiBwcm9qZWN0cyIsICJsb2NhbCBSRE0gaW5pdGlhdGl2ZXMiLCAiRU9TQyIsICJSREEiLCAiQ0xBUklOIEVSSUMiLCAiUVVBRFJJR0EiLCAiSE1DIikNCm4gPC0gYyg0LCA0LCAzLCAzLCAzLCAxLCAxLCAxLCAxKQ0KDQp0YWIyX2RhdGEgPC0gZGF0YS5mcmFtZShJbml0aWF0aXZlcywgbikNCg0KaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogIGRhdGF0YWJsZSh0YWIyX2RhdGEpDQp9IGVsc2Ugew0KICBmbGV4dGFibGUodGFiMl9kYXRhLCBjd2lkdGggPSBjKDMsMSkpICU+JQ0KICBzZXRfaGVhZGVyX2xhYmVscyhJbml0aWF0aXZlcyA9ICJJbml0aWF0aXZlL1Byb2plY3QiLCBuID0gIm4iKSAlPiUNCiAgdGhlbWVfemVicmEoKQ0KfQ0KDQpgYGANCioqVGFibGUgMjoqKiBub24tTkZESSBSRE0gcHJvamVjdHMgcmVwcmVzZW50ZWQgYnkgcGFydGljaXBhbnRzDQoNCg0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiByaWdodCI+DQoNCltUYWJsZSBvZiBjb250ZW50c10oI2hlYWRlcikNCg0KPC9kaXY+DQojIyBQcm92aXNpb24gb2YgY2xvdWQgc2VydmljZXMNCg0KVGhlIGZpcnN0IHRvcGljLXNwZWNpZmljIHF1ZXN0aW9uIGJsb2NrIG9mIHRoZSBzdXJ2ZXkgd2FzIHByaW1hcmlseSBhZGRyZXNzaW5nIHBhcnRpY2lwYW50cyB3aG8gYWxyZWFkeSBwcm92aWRlIGNsb3VkIHNlcnZpY2VzIGZvciB0aGVpciB0YXJnZXQgYXVkaWVuY2Ugb3IgYXJlIGluIHRoZSBwcm9jZXNzIG9mIGRldmVsb3Bpbmcgc3VjaCBhIHNvbHV0aW9uLiBXZSBhc2tlZCB0aGVtIHdoaWNoIHNlcnZpY2VzIHRoZXkgcHJvdmlkZSwgd2hhdCB0aGVpciBleHBlcmllbmNlcyB3aXRoIGltcGxlbWVudGluZyB0aG9zZSBzZXJ2aWNlcyB3ZXJlLCBhbmQgd2hhdCBjaGFsbGVuZ2VzIHRoZXkgZmFjZWQuIElmIHBhcnRpY2lwYW50cyBpbmRpY2F0ZWQgdGhhdCB0aGV5IGFyZSBub3Qgb2ZmZXJpbmcgY2xvdWQgc2VydmljZXMgZm9yIHRoZWlyIHVzZXJzLCB3ZSB3ZXJlIGFsc28gaW50ZXJlc3RlZCBpbiB0aGUgcmVhc29uIGZvciB0aGlzIGRlY2lzaW9uLiBMYXN0bHksIHBhcnRpY2lwYW50cyB3ZXJlIGFza2VkIHRvIGluZGljYXRlIGhvdyB3ZWxsIHRoZXkgdGhpbmsgY2xvdWQgc2VydmljZXMgYXJlIGFjY2VwdGVkIGluIHRoZWlyIHVzZXIgYmFzZSBhbmQgd2hhdCB0aGUgcG9zc2libGUgcmVhc29ucyBmb3IgbG93IGFjY2VwdGFuY2UgY291bGQgYmUuDQoNCiMjIyBDaGFyYWN0ZXJpemF0aW9uIG9mIHByb3ZpZGVkIGNsb3VkIHNlcnZpY2VzDQoNCmBgYHtyfQ0KI3N1bW1hcmlzZSBhbnN3ZXJzIHRvIGZpcnN0IHF1ZXN0aW9uDQpiMnExID0gcmVzX0NTX3Byb3Zpc2lvbiAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDIpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBjb3VudChhbnN3ZXIpDQoNCiMgY29sbGVjdCBmcmVlIHRleHQgYW5zd2VycyB0byBzZWNvbmQgcXVlc3Rpb24NCmIycTIgPSByZXNfQ1NfcHJvdmlzaW9uICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMykgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkNCg0KYGBgDQoNCk91dCBvZiBgciBzdW0oYjJxMSRuKWAgcGFydGljaXBhbnRzLCBgciBiMnExJG5bYjJxMSRhbnN3ZXI9PSJZZXMiXWAgKGByIHJvdW5kKGIycTEkbltiMnExJGFuc3dlcj09IlllcyJdL3N1bShiMnExJG4pKjEwMCwgZGlnaXRzPTApYCUpIGluZGljYXRlZCB0aGF0IHRoZXkgYXJlIHByb3ZpZGluZyBjbG91ZCBzZXJ2aWNlcyBmb3IgdGhlaXIgdGFyZ2V0IGF1ZGllbmNlIGFscmVhZHksIHdoaWxlIGByIGIycTEkbltiMnExJGFuc3dlcj09InBsYW5uZWQgb3IgY3VycmVudGx5IGluIGRldmVsb3BtZW50Il1gIHBhcnRpY2lwYW50cyBzdGF0ZWQgdGhhdCB0aGV5IGFyZSBjdXJyZW50bHkgaW1wbGVtZW50aW5nIHN1Y2ggYSBjbG91ZCBzZXJ2aWNlLiBUaGUgY2xvdWQgc2VydmljZXMgdGhhdCBhcmUgcHJvdmlkZWQgYnkgcGFydGljaXBhbnRzIG9mIHRoZSBzdXJ2ZXkgY2FuIGJlIHJvdWdobHkgY2xhc3NpZmllZCBpbnRvIGZvdXIgbWFpbiB0eXBlczogKGkpICoqY2xvdWQgc3RvcmFnZSoqLCAoaWkpICoqcmVzb3VyY2VzIGZvciBmaWVsZC1zcGVjaWZpYyBhcHBsaWNhdGlvbnMqKiwgKGlpaSkgKipnZW5lcmljIGNvbXB1dGUgcmVzb3VyY2VzIGFuZCBWTSBob3N0aW5nKiosIGFuZCAoaXYpICoqcmVzZWFyY2ggbWV0YWRhdGEgc2VydmljZXMqKi4NCg0KIyMjIyBDbG91ZCBzdG9yYWdlDQoNCk92ZXJhbGwsIHRoZSBtb3N0IGZyZXF1ZW50bHkgbWVudGlvbmVkIHNlcnZpY2UgdGhhdCBwYXJ0aWNpcGFudHMgcHJvdmlkZSB3YXMgKipjbG91ZCBzdG9yYWdlKiouIEdpdmVuIGV4YW1wbGVzIHJhbmdlZCBmcm9tIGNvbW1lcmNpYWwgY2xvdWQgc3RvcmFnZSBzb2x1dGlvbnMsIG92ZXIgc3RvcmFnZSBkZXZpY2VzIHByb3ZpZGVkIHRocm91Z2ggc2VsZi1ob3N0ZWQgSW5mcmFzdHJ1Y3R1cmUtYXMtYS1TZXJ2aWNlIChJYWFTKSBzb2x1dGlvbnMsIHRvIHRoZSBhcHBsaWNhdGlvbiBvZiBlc3RhYmxpc2hlZCBmaWxlLXNoYXJpbmcgcHJvdG9jb2xzLiBUaGUgb25seSBjb21tZXJjaWFsIGNsb3VkIHN0b3JhZ2Ugc2VydmljZSB0aGF0IHdhcyBtZW50aW9uZWQgYnkgcGFydGljaXBhbnRzIGlzIHRoZSAqKlNpbXBsZSBTdG9yYWdlIFNlcnZpY2UgKFMzKSoqW15zM10sIHdoaWNoIGlzIHBhcnQgb2YgQW1hem9uIFdlYiBTZXJ2aWNlcyAoQVdTKVteYXdzXS4gSWFhUyBzb2x1dGlvbnMgdGhhdCBhcmUgaG9zdGVkIGJ5IHNvbWUgcGFydGljaXBhbnRzIHNlZW0gdG8gYmUgbW9zdGx5IGJhc2VkIG9uIHRoZSBPcGVuU3RhY2sgY2xvdWQgb3BlcmF0aW5nIHN5c3RlbVteb3BlbnN0YWNrXSBhbmQgdGh1cyB0aGUgKipPcGVuU3RhY2sgT2JqZWN0IFN0b3JhZ2UgKFN3aWZ0KSoqIHNvZnR3YXJlW15zd2lmdF0gd2FzIHVzZWQgdG8gcHJvdmlkZSBhY2Nlc3MgdG8gdGhlIHN0b3JhZ2UgYmFja2VuZCBpbiB0aG9zZSBjYXNlcy4gDQoNCkJvdGgsIFMzIGFuZCBTd2lmdCwgYXJlIG9iamVjdCBzdG9yYWdlIHNvbHV0aW9ucyB3aGljaCBhcmUgcGFydGljdWxhcmx5IHN1aXRlZCB0byBoYW5kbGUgbGFyZ2UgYW1vdW50cyBvZiB1bnN0cnVjdHVyZWQgZGF0YSBpbiBsYXJnZSBmaWxlcy4gTm90YWJseSwgKipibG9jayBzdG9yYWdlKiogd2FzIGFsc28gbWVudGlvbmVkIGJ5IHR3byBwYXJ0aWNpcGFudHMsIHByZXN1bWFibHkgZm9yIHNwZWNpZmljIGFwcGxpY2F0aW9ucyB0aGF0IGFyZSBiYXNlZCBvbiBzdHJ1Y3R1cmVkIGRhdGEgYW5kIGJlbmVmaXQgZnJvbSBzaG9ydGVyIGFjY2VzcyB0aW1lcyBpbiBjb250cmFzdCB0byBvYmplY3Qgc3RvcmFnZSwgZXNwZWNpYWxseSBmb3Igc21hbGwgZmlsZXMuDQoNCkFub3RoZXIgZnJlcXVlbnRseSBtZW50aW9uZWQgY2xvdWQgc3RvcmFnZSBhcHBsaWNhdGlvbiB1c2UgY2FzZSBpcyB0aGUgcHJvdmlzaW9uIG9mICoqc2hhcmVkIGZpbGUgc3lzdGVtcyoqLCBlaXRoZXIgd2l0aGluIGNsb3NlZCBhY2FkZW1pYyBuZXR3b3JrcyBvciBvbiBhIGdsb2JhbCBzY2FsZS4gVGhlIHByb3Zpc2lvbiBvZiBsb2NhbCBzaGFyZWQgZmlsZSBzeXN0ZW1zIHdhcyByZWFsaXplZCBieSB1c2luZyBlc3RhYmxpc2hlZCBmaWxlIHNoYXJpbmcgcHJvdG9jb2xzIGxpa2UgdGhlIFVOSVggbmV0d29yayBwcm90b2NvbCAqKk5ldHdvcmsgRmlsZSBTeXN0ZW0gKE5GUykqKltebmZzXSBvciB0aGUgZXF1aXZhbGVudCBwcm90b2NvbCB1c2VkIGJ5IFdpbmRvd3Mgb3BlcmF0aW5nIHN5c3RlbXM6ICoqU2VydmVyIE1lc3NhZ2UgQmxvY2sgKFNNQikqKltec21iXS4gSW4gb25lIHJlY29yZCwgYSBwYXJ0aWNpcGFudCBhbHNvIG1lbnRpb25lZCB0aGUgdXNlIGNhc2Ugb2YgbWFraW5nIHN1Y2ggc2hhcmVkIGZpbGUgc3lzdGVtcyBhY2Nlc3NpYmxlIGZyb20gb3V0c2lkZSB0aGUgY2xvc2VkIGFjYWRlbWljIG5ldHdvcmsgYnkgdXNpbmcgdGhlIG5vbi1wcm9maXQgc2VydmljZSAqKkdsb2J1cyBzaGFyZSoqW15nbG9idXNdLCB3aGljaCB3YXMgZGV2ZWxvcGVkIGF0IHRoZSBVbml2ZXJzaXR5IG9mIENoaWNhZ28gYW5kIGNhbiBiZSBhY2Nlc3NlZCBmcm9tIGFyb3VuZCB0aGUgd29ybGQuDQogDQpbXnMzXTogaHR0cHM6Ly9hd3MuYW1hem9uLmNvbS9zMw0KW15hd3NdOiBodHRwczovL2F3cy5hbWF6b24uY29tDQpbXm9wZW5zdGFja106IGh0dHBzOi8vZG9jcy5vcGVuc3RhY2sub3JnLzIwMjQuMi8NCltec3dpZnRdOiBodHRwczovL2RvY3Mub3BlbnN0YWNrLm9yZy9zd2lmdC9sYXRlc3QvDQpbXm5mc106IGh0dHBzOi8vdWJ1bnR1LmNvbS9zZXJ2ZXIvZG9jcy9uZXR3b3JrLWZpbGUtc3lzdGVtLW5mcw0KW15zbWJdOiBodHRwczovL2xlYXJuLm1pY3Jvc29mdC5jb20vZW4tdXMvb3BlbnNwZWNzL3dpbmRvd3NfcHJvdG9jb2xzL21zLXNtYg0KDQpbXmdsb2J1c106IA0KDQpodHRwczovL3d3dy5nbG9idXMub3JnL2RhdGEtc2hhcmluZzsNCkFuYW50aGFrcmlzaG5hbiBSLiwgQ2hhcmQgSy4sIEZvc3RlciBJLiBhbmQgVHVlY2tlIFMuICgyMDE1KSwgX0dsb2J1cyBwbGF0Zm9ybS1hcy1hLXNlcnZpY2UgZm9yIGNvbGxhYm9yYXRpdmUgc2NpZW5jZSBhcHBsaWNhdGlvbnNfLCBDb25jdXJyZW5jeSBDb21wdXRhdC46IFByYWN0LiBFeHBlci4sIDI3LCBwYWdlcyAyOTDigJMzMDUsIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDAyL2NwZS4zMjYyDQoNCiMjIyMgQ2xvdWQgc2VydmljZXMgZm9yIGZpZWxkLXNwZWNpZmljIGFwcGxpY2F0aW9ucw0KDQpCZXNpZGVzIGNsb3VkIHN0b3JhZ2UsIGZpZWxkLXNwZWNpZmljIGFwcGxpY2F0aW9ucyBydW5uaW5nIGluIHRoZSBjbG91ZCB3ZXJlIHRoZSBtb3N0IGZyZXF1ZW50bHkgbWVudGlvbmVkIGNsb3VkIHNlcnZpY2VzIHByb3ZpZGVkIGJ5IHBhcnRpY2lwYW50cyBvZiB0aGUgc3VydmV5LiBOYXR1cmFsbHksIHRoaXMgaXMgYWxzbyB0aGUgbW9zdCBkaXZlcnNlIGNhdGVnb3J5IG9mIHNlcnZpY2VzLCBzaW5jZSBldmVyeSBzcGVjaWFsaXplZCBmaWVsZCBoYXMgZGV2ZWxvcGVkIGl0cyBvd24gYXBwbGljYXRpb25zIHRvIHNvbHZlIHNwZWNpZmljIHByb2JsZW1zIHdpdGhpbiB0aGUgZmllbGQuIE1vc3Qgb2YgdGhlIHNwZWNpYWxpemVkIGFwcGxpY2F0aW9ucyBtZW50aW9uZWQgYnkgcGFydGljaXBhbnRzIHdlcmUgZGV2ZWxvcGVkIHRvIHByb3ZpZGUgKipleGVjdXRpb24gZW52aXJvbm1lbnRzKiogZm9yIHBhcnRpY3VsYXIgd29ya2Zsb3dzIGFuZC9vciBoYW5kbGUgKipmaWVsZC1zcGVjaWZpYyBkYXRhIHR5cGVzKiouDQoNCkEgZ29vZCBleGFtcGxlIGZvciBzcGVjaWFsaXplZCBleGVjdXRpb24gZW52aXJvbm1lbnRzIGlzIHRoZSBwcm92aXNpb24gb2YgY29tcHV0ZSByZXNvdXJjZXMgdG8gZXhlY3V0ZSAqKmF1dG9tYXRlZCB0ZXh0IGFuYWx5c2lzIGFsZ29yaXRobXMqKi4gVGhpcyBpcyBhIHVzZS1jYXNlIHRoYXQgd2FzIGluIHRoZSBwYXN0IHByaW1hcmlseSBwb3B1bGFyIGluIHRoZSBzb2NpYWwgc2NpZW5jZXMgZmllbGQsIGJ1dCB0aGUgcmVjZW50IGV4cGxvc2lvbiBvZiAqKk5hdHVyYWwgTGFuZ3VhZ2UgUHJvY2Vzc2luZyoqIChOTFApIGFwcGxpY2F0aW9ucywgcHJpbWFyaWx5IGRyaXZlbiBieSB0aGUgYWRvcHRpb24gb2YgZGVlcCBuZXVyYWwgbmV0d29yayBtZXRob2RzIChkZWVwIGxlYXJuaW5nKVtebmxwLXN0YXRlLW9mLXRoZS1hcnRdLCBoYXMgZGVtb25zdHJhdGVkIHRoYXQgbWFueSBmaWVsZHMgY2FuIGJlbmVmaXQgZnJvbSB0aGlzIGV4cGVydGlzZVtebmxwLWRpYWJldGVzLWNhcmVdIFtebmxwLWNvbnN0cnVjdGlvbl0gW15ubHAtcHJvdGVpbi1yZXNlYXJjaF0uDQoNCkFuIGV4YW1wbGUgb2YgZmllbGQtc3BlY2lmaWMgYXBwbGljYXRpb25zLCB0aGF0IGlzIG1vcmUgZm9jdXNlZCBvbiBoYW5kbGluZyBzcGVjaWZpYyBkYXRhIHR5cGVzLCBpcyB0aGUgcHJvdmlzaW9uIG9mIGVudmlyb25tZW50cyB0aGF0IGFyZSBzcGVjaWFsaXplZCB0byBkZWFsIHdpdGggKippbWFnZSBkYXRhKiouIE9uZSBvZiB0aG9zZSBhcHBsaWNhdGlvbnMsIHRoYXQgb3JpZ2luYXRlZCBpbiB0aGUgbGlnaHQtbWljcm9zY29weSBkb21haW4sIGlzIHRoZSBPcGVuIE1pY3Jvc2NvcHkgRW52aXJvbm1lbnQgUmVtb3RlIE9iamVjdHMgKCoqT01FUk8qKikgc29mdHdhcmUgcGxhdGZvcm1bXm9tZXJvXS4gVGhlICoqU2FhUyoqIHBsYXRmb3JtIHdhcyBkZXZlbG9wZWQgYmFzZWQgb24gdGhlIE9wZW4gTWljcm9zY29weSBFbnZpcm9ubWVudCAoT01FKSBEYXRhIE1vZGVsW15vbWVdIGFuZCB0aGUgaW1hZ2UgdHJhbnNsYXRpb24gbGlicmFyeSBCaW8tRm9ybWF0c1teYmlvLWZvcm1hdHNdIGFuZCBwcm92aWRlcyBhICoqZGF0YSBtYW5hZ2VtZW50IHBsYXRmb3JtKiogZm9yIGFuYWx5c2lzIGFuZCBwcm9jZXNzaW5nIG9mIGNvbXBsZXggaW1hZ2UgZGF0YS4gSXQgaGFzIGFsc28gYmVlbiBhZGFwdGVkIHRvIHByb3ZpZGUgdGhlIGJhc2lzIG9mICoqc2NpZW50aWZpYyBpbWFnZSByZXBvc2l0b3JpZXMqKiBhbmQgZXh0ZW5zaW9ucyBhcmUgZGV2ZWxvcGVkIHRvIGhhbmRsZSBvdGhlciB1c2UgY2FzZXMgYmVzaWRlcyBpbWFnZSBkYXRhLCBsaWtlIGFuYWx5c2lzIG9mIGh1bWFuIGdlbm9tZSBkYXRhW15vbWVyb10uDQoNCkFub3RoZXIgYXBwbGljYXRpb24gdGhhdCBtaWdodCBiZSBwYXJ0aWN1bGFybHkgaW50ZXJlc3RpbmcgZm9yIHNjaWVudGlmaWMgZGlzY2lwbGluZXMgd2l0aCBhIHdldC1sYWIgY29tcG9uZW50IGFyZSAqKkxhYiBJbmZvcm1hdGlvbiBNYW5hZ2VtZW50IFN5c3RlbXMqKiAoTElNUykuIExJTVMgYXJlIHNvZnR3YXJlIHNvbHV0aW9ucyB0aGF0IGFsbG93IHJlc2VhcmNoIGxhYm9yYXRvcmllcyB0byBtYW5hZ2Ugc2FtcGxlcywgaW5zdHJ1bWVudHMsIHByb2Nlc3NlcywgYW5kIGdlbmVyYXRlZCBkYXRhIHdpdGhpbiBvbmUgaW50ZWdyYXRlZCBzeXN0ZW0uICoqRWxlY3Ryb25pYyBMYWIgTm90ZWJvb2tzKiogKEVMTikgZmFsbCwgZGVwZW5kaW5nIG9uIHRoZSBmZWF0dXJlIHNldCB0aGV5IHByb3ZpZGUsIHVuZGVyIHRoZSBzYW1lIHVtYnJlbGxhIHRlcm0sIGJ1dCBhcmUgdXN1YWxseSBtb3JlIGZvY3VzZWQgb24gZG9jdW1lbnRpbmcgdGhlIHJlc2VhcmNoIHByb2Nlc3MgYW5kIHNlcnZlIGFzIGEgcmVwbGFjZW1lbnQgb2YgdHJhZGl0aW9uYWwgcGFwZXIgbGFiIG5vdGVib29rcy4gQm90aCwgTElNUyBhbmQgRUxOcywgYXJlIHJlZ3VsYXJseSBkZXBsb3llZCBhcyBjbG9zZWQgaW5zdGl0dXRpb25hbCBzb2x1dGlvbnMgYW5kIGFzIGNsb3VkIHNlcnZpY2VzIHdpdGggYnJvYWRlciBhY2Nlc3MgcG9zc2liaWxpdGllcyBhbmQgaW50ZXJvcGVyYWJpbGl0eSB3aXRoIG90aGVyIHNlcnZpY2VzLiBQb3B1bGFyIG9wZW4gc291cmNlIGV4YW1wbGVzIG9mIEVMTnMgdGhhdCBhcmUgYWxzbyBkZXBsb3llZCB3aXRoaW4gc2V2ZXJhbCBORkRJIHByb2plY3RzIGFyZSBDaGVtb3Rpb25bXmNoZW1vdGlvbl0sIGEgc2VydmljZSBwYXJ0aWN1bGFybHkgZGVzaWduZWQgZm9yIHRoZSBjaGVtaWNhbCBzY2llbmNlcywgYW5kIGVMYWJGVFdbXmVsYWJmdHddLCBhIG1vcmUgZ2VuZXJpYyBzZXJ2aWNlIHdoaWNoIGNhbiBiZSBhZGFwdGVkIHRvIHNldmVyYWwgcmVzZWFyY2ggZGlzY2lwbGluZXMuDQoNClBhcnRpY2lwYW50cyBvZiB0aGUgc3VydmV5IHdlcmUgYWxzbyBpbnZvbHZlZCBpbiB0aGUgKipHYWxheHkqKiBwcm9qZWN0LCB3aGljaCBwcm92aWRlcyBmcmVlbHkgYWNjZXNzaWJsZSBkYXRhIGFuYWx5c2lzIHRvb2xzIGFuZCBwaXBlbGluZXMgZm9yIHJlc2VhcmNoZXJzIHRoYXQgY2FuIGJlIGFjY2Vzc2VkIHRocm91Z2ggYSBncmFwaGljYWwgdXNlciBpbnRlcmZhY2UgaW4gYSB3ZWIgYnJvd3NlciBlbnZpcm9ubWVudC4gVGhlIHByb2plY3Qgd2FzIG9yaWdpbmFsbHkgaW5pdGlhdGVkIHdpdGhpbiB0aGUgZmllbGQgb2YgZ2Vub21pY3MgYW5kIGFpbWVkIGF0IG1ha2luZyByZXByb2R1Y2libGUgY29tcHV0YXRpb25hbCB3b3JrZmxvd3MgYXZhaWxhYmxlIHRvIHJlc2VhcmNoZXJzIHdpdGhvdXQgaW4tZGVwdGggc2tpbGxzIGluIGJpb2luZm9ybWF0aWNzIFteZ2FsYXh5XS4gU2luY2UgdGhlbiwgdGhlIHByb2plY3QgaGFzIG1hc3NpdmVseSBncm93biBhbmQgaXMgbm93IHByb3ZpZGluZyBjb21wdXRhdGlvbmFsIHJlc291cmNlcyB3b3JsZCB3aWRlIGZvciBhIGNvbnN0YW50bHkgZ3Jvd2luZyB1c2VyIGJhc2UgdGhhdCBoYXMgZXhwYW5kZWQgZmFyIGJleW9uZCB0aGUgZmllbGQgb2YgZ2Vub21pY3MgW15nYWxheHktMjAyNC11cGRhdGVdLiBUaGUgc2VydmljZSBoYXMgYmVlbiBjb25zdGFudGx5IHVwZGF0ZWQgYW5kIG5vdyBlbmNvbXBhc3NlcyBhIHNvcGhpc3RpY2F0ZWQgbGVhcm5pbmcgcGxhdGZvcm0gZm9yIHVzZXJzIGFuZCBhIHZhc3QgY29sbGVjdGlvbiBvZiBzb2Z0d2FyZSBwYWNrYWdlcyBmb3IgZGF0YSBhbmFseXNpcyBpbiBhIHZhcmlldHkgb2YgcmVzZWFyY2ggZmllbGRzLiBCZXNpZGVzIEdhbGF4eSwgdGhlICoqQ2xvdWQtYmFzZWQgd29ya2Zsb3cgbWFuYWdlcioqIChDbG9XTSkgd2FzIGFsc28gYnJvdWdodCB1cCBieSBzdXJ2ZXkgcGFydGljaXBhbnRzIGFzIGFuIGFsdGVybmF0aXZlIHBsYXRmb3JtIHRvIGV4ZWN1dGUgcmVwcm9kdWNpYmxlIGFuYWx5c2lzIHBpcGVsaW5lcyBpbiB0aGUgY2xvdWQuIFRoZSBzZXJ2aWNlIGFsbG93cyBkZXZlbG9wZXJzIHRvIGNvbnZlcnQgdGhlaXIgd29ya2Zsb3dzIGludG8gYSB3ZWIgc2VydmljZSBmb3IgcHVibGljYXRpb24gYW5kIGV4ZWN1dGlvbiBieSBlbmQgdXNlcnMgb24gYSBzY2FsYWJsZSBjb21wdXRlIGNsdXN0ZXJbXmNsb3dtXS4NCg0KW15ubHAtc3RhdGUtb2YtdGhlLWFydF06DQoNCktodXJhbmEsIEQuLCBLb2xpLCBBLiwgS2hhdHRlciwgSy4gZXQgYWwuIF9OYXR1cmFsIGxhbmd1YWdlIHByb2Nlc3Npbmc6IHN0YXRlIG9mIHRoZSBhcnQsIGN1cnJlbnQgdHJlbmRzIGFuZCBjaGFsbGVuZ2VzXy4gTXVsdGltZWQgVG9vbHMgQXBwbCA4MiwgMzcxM+KAkzM3NDQgKDIwMjMpLiBodHRwczovL2RvaS5vcmcvMTAuMTAwNy9zMTEwNDItMDIyLTEzNDI4LTQNCg0KW15ubHAtZGlhYmV0ZXMtY2FyZV06DQoNClR1cmNoaW4gQSwgRmxvcmV6IEJ1aWxlcyBMRi4gX1VzaW5nIE5hdHVyYWwgTGFuZ3VhZ2UgUHJvY2Vzc2luZyB0byBNZWFzdXJlIGFuZCBJbXByb3ZlIFF1YWxpdHkgb2YgRGlhYmV0ZXMgQ2FyZTogQSBTeXN0ZW1hdGljIFJldmlld18uIEpvdXJuYWwgb2YgRGlhYmV0ZXMgU2NpZW5jZSBhbmQgVGVjaG5vbG9neS4gMjAyMTsxNSgzKTo1NTMtNTYwLiBodHRwczovL2RvaS5vcmcvMTAuMTE3Ny8xOTMyMjk2ODIxMTAwMDgzMQ0KDQpbXm5scC1jb25zdHJ1Y3Rpb25dOg0KDQpZdWV4aW9uZyBEaW5nLCBKaWUgTWEsIFhpYW93ZWkgTHVvLiBfQXBwbGljYXRpb25zIG9mIG5hdHVyYWwgbGFuZ3VhZ2UgcHJvY2Vzc2luZyBpbiBjb25zdHJ1Y3Rpb25fLiBBdXRvbWF0aW9uIGluIENvbnN0cnVjdGlvbiAxMzYsIDEwNDE2OSAoMjAyMikuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDE2L2ouYXV0Y29uLjIwMjIuMTA0MTY5DQoNCltebmxwLXByb3RlaW4tcmVzZWFyY2hdOg0KDQpEYW4gT2ZlciwgTmFkYXYgQnJhbmRlcywgTWljaGFsIExpbmlhbC4gX1RoZSBsYW5ndWFnZSBvZiBwcm90ZWluczogTkxQLCBtYWNoaW5lIGxlYXJuaW5nICYgcHJvdGVpbiBzZXF1ZW5jZXNfLiBDb21wdXRhdGlvbmFsIGFuZCBTdHJ1Y3R1cmFsIEJpb3RlY2hub2xvZ3kgSm91cm5hbCAxOSwgMTc1MC0xNzU4ICgyMDIxKS4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5jc2JqLjIwMjEuMDMuMDIyDQoNClteb21lcm9dOg0KDQpBbGxhbiwgQy4sIEJ1cmVsLCBKTS4sIE1vb3JlLCBKLiBldCBhbC4gX09NRVJPOiBmbGV4aWJsZSwgbW9kZWwtZHJpdmVuIGRhdGEgbWFuYWdlbWVudCBmb3IgZXhwZXJpbWVudGFsIGJpb2xvZ3lfLiBOYXQgTWV0aG9kcyA5LCAyNDXigJMyNTMgKDIwMTIpLiBodHRwczovL2RvaS5vcmcvMTAuMTAzOC9ubWV0aC4xODk2DQoNClteb21lXToNCg0KR29sZGJlcmcgSUcsIEFsbGFuIEMsIEJ1cmVsIEpNLCBDcmVhZ2VyIEQsIEZhbGNvbmkgQSwgSG9jaGhlaXNlciBILCBKb2huc3RvbiBKLCBNZWxsZW4gSiwgU29yZ2VyIFBLLCBTd2VkbG93IEpSLiBfVGhlIE9wZW4gTWljcm9zY29weSBFbnZpcm9ubWVudCAoT01FKSBEYXRhIE1vZGVsIGFuZCBYTUwgZmlsZTogb3BlbiB0b29scyBmb3IgaW5mb3JtYXRpY3MgYW5kIHF1YW50aXRhdGl2ZSBhbmFseXNpcyBpbiBiaW9sb2dpY2FsIGltYWdpbmdfLiBHZW5vbWUgQmlvbC4gMjAwNTs2KDUpOlI0Ny4gaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvZ2ItMjAwNS02LTUtcjQ3LiBFcHViIDIwMDUgTWF5IDMuIFBNSUQ6IDE1ODkyODc1OyBQTUNJRDogUE1DMTE3NTk1OS4NCg0KW15iaW8tZm9ybWF0c106DQoNCkxpbmtlcnQgTSwgUnVlZGVuIENULCBBbGxhbiBDLCBCdXJlbCBKTSwgTW9vcmUgVywgUGF0dGVyc29uIEEsIExvcmFuZ2VyIEIsIE1vb3JlIEosIE5ldmVzIEMsIE1hY2RvbmFsZCBELCBUYXJrb3dza2EgQSwgU3RpY2NvIEMsIEhpbGwgRSwgUm9zc25lciBNLCBFbGljZWlyaSBLVywgU3dlZGxvdyBKUi4gX01ldGFkYXRhIG1hdHRlcnM6IGFjY2VzcyB0byBpbWFnZSBkYXRhIGluIHRoZSByZWFsIHdvcmxkXy4gSiBDZWxsIEJpb2wuIDIwMTAgTWF5IDMxOzE4OSg1KTo3NzctODIuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDgzL2pjYi4yMDEwMDQxMDQuIFBNSUQ6IDIwNTEzNzY0OyBQTUNJRDogUE1DMjg3ODkzOC4NCg0KW15jaGVtb3Rpb25dOg0KDQpUcmVtb3VpbGhhYyBQLCBOZ3V5ZW4gQSwgSHVhbmcgWUMsIEtvdG92IFMsIEzDvHRqb2hhbm4gRFMsIEjDvGJzY2ggRiwgSnVuZyBOLCBCcsOkc2UgUy4gX0NoZW1vdGlvbiBFTE46IGFuIE9wZW4gU291cmNlIGVsZWN0cm9uaWMgbGFiIG5vdGVib29rIGZvciBjaGVtaXN0cyBpbiBhY2FkZW1pYV8uIEogQ2hlbWluZm9ybS4gMjAxNyBTZXAgMjU7OSgxKTo1NC4gaHR0cHM6Ly9kb2kub3JnLzEwLjExODYvczEzMzIxLTAxNy0wMjQwLTAuIFBNSUQ6IDI5MDg2MjE2OyBQTUNJRDogUE1DNTYxMjkwNS4NCg0KW15lbGFiZnR3XToNCg0KQ0FSUGkgTiwgTWluZ2VzIEEsIFBpZWwgTS4gX2VMYWJGVFc6IEFuIG9wZW4gc291cmNlIGxhYm9yYXRvcnkgbm90ZWJvb2sgZm9yIHJlc2VhcmNoIGxhYnNfLiBKb3VybmFsIG9mIE9wZW4gU291cmNlIFNvZnR3YXJlLCAyKDEyKSwgMTQ2ICgyMDE3KS4gaHR0cHM6Ly9kb2kub3JnLzEwLjIxMTA1L2pvc3MuMDAxNDYNCg0KW15nYWxheHktMjAyNC11cGRhdGVdOg0KDQpHYWxheHkgQ29tbXVuaXR5LiBfVGhlIEdhbGF4eSBwbGF0Zm9ybSBmb3IgYWNjZXNzaWJsZSwgcmVwcm9kdWNpYmxlLCBhbmQgY29sbGFib3JhdGl2ZSBkYXRhIGFuYWx5c2VzOiAyMDI0IHVwZGF0ZV8uIE51Y2xlaWMgQWNpZHMgUmVzLiAyMDI0IEp1bCA1OzUyKFcxKTpXODMtVzk0LiBkb2k6IDEwLjEwOTMvbmFyL2drYWU0MTAuIFBNSUQ6IDM4NzY5MDU2OyBQTUNJRDogUE1DMTEyMjM4MzUuDQoNClteZ2FsYXh5XToNCg0KR2lhcmRpbmUgQiwgUmllbWVyIEMsIEhhcmRpc29uIFJDLCBCdXJoYW5zIFIsIEVsbml0c2tpIEwsIFNoYWggUCwgWmhhbmcgWSwgQmxhbmtlbmJlcmcgRCwgQWxiZXJ0IEksIFRheWxvciBKLCBNaWxsZXIgVywgS2VudCBXSiwgTmVrcnV0ZW5rbyBBLiBfR2FsYXh5OiBhIHBsYXRmb3JtIGZvciBpbnRlcmFjdGl2ZSBsYXJnZS1zY2FsZSBnZW5vbWUgYW5hbHlzaXNfLiBHZW5vbWUgUmVzLiAyMDA1IE9jdDsxNSgxMCk6MTQ1MS01LiBodHRwczovL2RvaS5vcmcvMTAuMTEwMS9nci40MDg2NTA1LiBFcHViIDIwMDUgU2VwIDE2LiBQTUlEOiAxNjE2OTkyNjsgUE1DSUQ6IFBNQzEyNDAwODkuDQoNClteY2xvd21dOg0KDQpodHRwczovL2dpdGxhYi51Yi51bmktYmllbGVmZWxkLmRlL2NtZy9jbG93bS9jbG93bS1iYWNrZW5kDQoNCiMjIyMgR2VuZXJpYyBjb21wdXRlIHJlc291cmNlcyBhbmQgcmVzZWFyY2ggbWV0YWRhdGEgc2VydmljZXMNCg0KQmVzaWRlIHRoZSBhZm9yZW1lbnRpb25lZCBzcGVjaWFsaXplZCBhcHBsaWNhdGlvbnMsIHByb3Zpc2lvbiBvZiAqKmdlbmVyaWMgY29tcHV0ZSByZXNvdXJjZXMqKiB3YXMgYWxzbyBmcmVxdWVudGx5IG1lbnRpb25lZCBieSBwYXJ0aWNpcGFudHMgb2YgdGhlIHN1cnZleS4gVGhpcyBpcyBsaWtlbHkgY29ubmVjdGVkIHRvIHRoZSBmYWN0IHRoYXQgbWFueSBwcm9mZXNzaW9uYWxzIGFkZHJlc3NlZCBieSB0aGUgc3VydmV5IHdvcmsgaW4gY29yZSBmYWNpbGl0aWVzIG9mIHVuaXZlcnNpdGllcyBhbmQgb3RoZXIgYWNhZGVtaWMgaW5zdGl0dXRpb25zIGFuZCBwYXJ0IG9mIHRoZWlyIHdvcmsgaXMgdGhlIHByb3Zpc2lvbiBhbmQgbWFpbnRlbmFuY2Ugb2YgY29tcHV0YXRpb25hbCByZXNvdXJjZXMgZm9yIGluc3RpdHV0aW9uIG1lbWJlcnMgYW5kIHRoZSBzY2llbnRpZmljIHB1YmxpYy4gQXMgYWxyZWFkeSBoaW50ZWQgYXQgaW4gW2EgcHJldmlvdXMgc2VjdGlvbl0oI2Nsb3VkLXN0b3JhZ2UpLCAqKk9wZW5TdGFjayoqIGFuZCAqKkFXUyoqIHNlZW0gdG8gYmUgdGhlIHByZWZlcnJlZCBwbGF0Zm9ybXMgZm9yIHRoaXMgdGFzayBhbW9uZyBwYXJ0aWNpcGFudHMsIGFuZCBhbHNvIHRoZSBkZXBsb3ltZW50IG9mICoqa3ViZXJuZXRzIGNsdXN0ZXJzKiogd2FzIGZyZXF1ZW50bHkgbWVudGlvbmVkIGJ5IHBhcnRpY2lwYW50cy4NCg0KLSBkZS5OQkkNCi0gU2ltcGxlVk0NCi0gSW5mcmFzdHJ1Y3R1cmUtYXMtYS1zZXJ2aWNlIChJYWFTKSAtIE9wZW5TdGFjayBpbnN0YW5jZXMsIGt1YmVybmV0ZXMgY2x1c3RlcnMNCi0gSnVweXRlckh1Yg0KLSByZXNlYXJjaCBtZXRhZGF0YSBzZXJ2aWNlcw0KDQoNCiMjIyBDaGFsbGVuZ2luZyB0b3BpY3MgZW5jb3VudGVyZWQgYnkgY2xvdWQgc2VydmljZSBwcm92aWRlcnMNCg0KYGBge3J9DQojIGNvbGxlY3QgYW5zd2VycyB0byB0aGlyZCBxdWVzdGlvbg0KYjJxMyA9IHJlc19DU19wcm92aXNpb24gJT4lDQogIHJlbmFtZShhbnN3ZXIgPSA0KSAlPiUNCiAgc2VsZWN0KGFuc3dlcikgJT4lDQogIG5hLm9taXQoKQ0KYGBgDQoNCldlIGFza2VkIHBhcnRpY2lwYW50cyBvZiB0aGUgc3VydmV5LCB3aG8gYXJlIGludm9sdmVkIGluIHByb3ZpZGluZyBjbG91ZCBzZXJ2aWNlcyBmb3IgcmVzZWFyY2hlcnMsIHdoaWNoIHRvcGljcyB0aGV5IGZvdW5kIHRvIGJlIHBhcnRpY3VsYXJseSBjaGFsbGVuZ2luZyB3aGVuIGltcGxlbWVudGluZyBhbmQgb3BlcmF0aW5nIHRob3NlIHNlcnZpY2VzLiBUaGUgYW5zd2VycyB0byB0aGlzIHF1ZXN0aW9uIHdlcmUgc3BsaXQgYmV0d2VlbiBmb3VyIHN1cGVyb3JkaW5hdGUgc3ViamVjdCBhcmVhczogKGkpICoqdGVjaG5pY2FsIGNoYWxsZW5nZXMqKiwgKGlpKSAqKmxlZ2FsIGNoYWxsZW5nZXMqKiwgKGlpaSkgKip1c2VyIGludGVyYWN0aW9uKiosIGFuZCAoaXYpICoqbWFpbnRlbmFuY2UgYW5kIGNvbnRpbnVlZCBkZXZlbG9wbWVudCoqLiBUb3BpY3MgZm9yIGVhY2ggc3ViamVjdCBhcmVhIGFyZSBzdW1tYXJpemVkIGJlbG93IGFuZCBjYW4gc2VydmUgYXMgYSBmaXJzdCBvcmllbnRhdGlvbiB3aGVuIGRlY2lkaW5nIHdoaWNoIHRyYWluaW5nIG1hdGVyaWFsIGFkZHJlc3NpbmcgY2xvdWQgc2VydmljZSBwcm92aWRlcnMgd291bGQgYmUgcmVsZXZhbnQgZm9yIHRoaXMgZ3JvdXAgaW4gY29udGV4dCBvZiB0aGUgY2xvdWQgdGVjaG5vbG9neSBjb21wZXRlbmNlIGNlbnRlci4NCg0KDQpUZWNobmljYWwgY2hhbGxlbmdlczoNCg0KLSBhcHByb3ByaWF0ZSBzZXJ2aWNlIGFyY2hpdGVjdHVyZSBkZXNpZ24NCiAgLSB0cmFkZSBvZmZzIGJldHdlZW4gY29zdCwgY29tcGxleGl0eSwgZGF0YSB2b2x1bWUNCi0gaW1wbGVtZW50YXRpb24gb2YgaWRlbnRpdHkgbWFuYWdlbWVudC91c2VyIGF1dGhlbnRpY2F0aW9uDQogIC0gc2luZ2xlIHNpZ24gb24NCi0gc2NhbGluZyBzZXJ2aWNlcyB0byBhY2NvbW9kYXRlIGxhcmdlIHVzZXIgbnVtYmVycw0KICAtIHN0b3JhZ2UsIFJBTSwgY29tcHV0ZSBwb3dlcg0KLSBjb250YWluZXJpemF0aW9uIG9mIHRvb2xzIGFuZCB3b3JrZmxvd3MNCi0gc2VjdXJpdHkgb2Ygd2ViIHNlcnZpY2VzDQotIGZlZGVyYXRlZCBvcGVyYXRpb24gb2YgY2xvdWQgc2VydmljZXMgYWNyb3NzIG11bHRpcGxlIG9wZXJhdGlvbiBzaXRlcw0KDQpMZWdhbCBjaGFsbGVuZ2VzOg0KDQotIGhhbmRsaW5nIHNlbnNpdGl2ZSBkYXRhIChlLmcuIG1lZGljYWwgcmVzZWFyY2ggZGF0YSkNCi0gY2VydGlmaWNhdGlvbiBvZiBzZXJ2aWNlcw0KLSBHRFBSLWNvbXBsaWFudCBkYXRhIHByaXZhY3kgcG9saWNpZXMNCi0gbGVnYWxseSBiaW5kaW5nIHRlcm1zIG9mIHVzYWdlDQoNClVzZXIgaW50ZXJhY3Rpb246DQoNCi0gcHJvdmlkaW5nIHVzZXIgdHJhaW5pbmcsIGNvbnN1bHRhdGlvbiwgYW5kIHN1cHBvcnQNCi0gY3VsdGl2YXRpbmcgdXNlciBlbmdhZ2VtZW50IHRvIHByb3ZpZGUgYWRkaXRpb25hbCBjb250ZW50DQotIGNvbW11bmljYXRpb24gYmV0d2VlbiBzZXJ2aWNlIHByb3ZpZGVycyBhbmQgdXNlcnM6DQogIC0gaW1wYXJ0aW5nIHRlY2huaWNhbCBwb3NzaWJpbGl0aWVzIGFuZCBjb25zdHJhaW50cyB0byB0aGUgZW5kIHVzZXJzDQogIC0gY29tbXVuaWNhdGluZyBuZWVkcyBvZiB0aGUgZW5kIHVzZXJzIHRvIGRldmVsb3BlcnMgb2YgdGhlIHNlcnZpY2UNCg0KTWFpbnRlbmFuY2UgYW5kIGNvbnRpbnVlZCBkZXZlbG9wbWVudDoNCg0KLSBzdHJhdGVnaWVzIHRvIHByb21vdGUgdXNlciBwYXJ0aWNpcGF0aW9uIGluIGNvbnRpbnVlZCBkZXZlbG9wbWVudCBvZiBzZXJ2aWNlcw0KLSBlZHVjYXRpb24gb2YgKG5ldykgZW1wbG95ZWVzIGFib3V0IGNsb3VkIGluZnJhc3RydWN0dXJlIGFuZCBzZWN1cmUgb3BlcmF0aW9uIG9mIGNsb3VkIHNlcnZpY2VzDQotIGFwcHJvcHJpYXRlIGRvY3VtZW50YXRpb24gYW5kIG1hbmFnaW5nIGRpdmlzaW9uIG9mIHdvcmsgdG8gYXZvaWQgdW5uZWNlc3NhcnkgZHVwbGljYXRpb24gb2Ygd29yayAoZWZmaWNpZW50IHVzYWdlIG9mIGxpbWl0ZWQgbWFucG93ZXIpDQotIHJlc291cmNlcyB0byBxdWlja2x5IGFuZCBlZmZpY2llbnRseSB0cmFpbiBsYXRlcmFsIGVudHJ5IGVtcGxveWVlcywgbmV3IGVtcGxveWVlcyBpbiBnZW5lcmFsICh0YWNrbGluZyBzaG9ydGFnZSBvZiBxdWFsaWZpZWQgd29ya2ZvcmNlKQ0KLSBzZWN1cmluZyBjb250aW51ZWQgZnVuZGluZw0KDQojIyMgQWNjZXB0YW5jZSBhbmQgcmVsZXZhbmNlIG9mIGNsb3VkIHNlcnZpY2VzDQoNCkluIHRoZSBsYXN0IHF1ZXN0aW9uIG9mIHRoZSBmaXJzdCBxdWVzdGlvbiBibG9jayB3ZSB3YW50ZWQgdG8ga25vdyBob3cgd2VsbCBjbG91ZCBzZXJ2aWNlcyBhcmUgYWNjZXB0ZWQgYW1vbmcgdGhlIHBvdGVudGlhbCB1c2VyIGJhc2UgaW4gdGhlIHBlcmNlcHRpb24gb2Ygc3VydmV5IHBhcnRpY2lwYW50cy4gV2UgYXNrZWQgdGhlIHBhcnRpY2lwYW50cyB0byByYXRlIHVzZXIgYWNjZXB0YW5jZSBvbiBhIHNjYWxlIGJldHdlZW4gMCBhbmQgMTAsIHdoZXJlIDAgbWVhbnQgdXNlcnMgZGlkIG5vdCBhY2NlcHQgY2xvdWQgc2VydmljZXMgYXQgYWxsIGFuZCAxMCBlcXVhbGVkIGZ1bGwgYWNjZXB0YW5jZSBvZiBjbG91ZCBzZXJ2aWNlcyBpbiB0aGUgdXNlciBiYXNlLiBUaGUgcmVzdWx0cyBvZiB0aGUgcmF0aW5nIGFyZSBzdW1tYXJpemVkIGluIHRoZSBoaXN0b2dyYW0gYmVsb3cuDQoNCmBgYHtyfQ0KI2dldCByYXRpbmcgdmFsdWVzIGZvciBjbG91ZCBhY2NlcHRhbmNlDQpiMnE0ID0gcmVzX0NTX3Byb3Zpc2lvbiAlPiUNCiAgcmVuYW1lKHZhbCA9IDkpICU+JQ0KICBzZWxlY3QoSUQsIHZhbCkgJT4lDQogIG5hLm9taXQoKQ0KDQojbWFrZSBhIGhpc3RvZ3JhbSBmb3IgdmlzdWFsaXphdGlvbiBvZiBkaXN0cmlidXRpb24NCnBsb3RfMiA8LSBnZ3Bsb3QoYjJxNCwgYWVzKHg9dmFsKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGNvbG9yID0gImJsYWNrIiwgZmlsbD0iIzAwQTJGOSIpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lZGlhbih2YWwpKSwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEwLCBieSA9IDEpLCBsaW1pdHMgPSBjKDAsMTEpKSArDQogIGdlb21fdGV4dCh4PTEsIHk9MTAsIGxhYmVsPSJuID0gMzIiLCBzaXplID0gNSkgKw0KICBnZW9tX3RleHQoeD0xLCB5PTksIGxhYmVsPSJtZWRpYW4gPSA4Iiwgc2l6ZSA9IDUpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgeGxhYigidmFsdWUiKSArDQogIGdndGl0bGUoIkNsb3VkIHNlcnZpY2UgYWNjZXB0YW5jZSBlc3RpbWF0aW9uIG9mIHN1cnZleSBwYXJ0aWNpcGFudHMiKQ0KDQpwbG90XzINCmBgYA0KKipGaWd1cmUgMjoqKg0KDQpPdmVyYWxsIHRoZSByZXN1bHRzIGltcGx5IHRoYXQgY2xvdWQgc2VydmljZXMgYXJlIGdlbmVyYWxseSB3ZWxsIGFjY2VwdGVkIHdpdGggYSBtZWRpYW4gYWNjZXB0YW5jZSB2YWx1ZSBvZiA4LiBCZXNpZGVzIHRoZSBjbGVhciBwZWFrIGFyb3VuZCBhbiBhY2NlcHRhbmNlIHZhbHVlIG9mIDgsIGhvd2V2ZXIsIHRoZXJlIHdhcyBhbHNvIGEgY29uc2lkZXJhYmxlIG51bWJlciBvZiBwYXJ0aWNpcGFudHMgdGhhdCByYXRlZCBhY2NlcHRhbmNlIG9mIGNsb3VkIHNlcnZpY2VzIHdpdGggYSB2YWx1ZSBvZiA1IG9yIGxlc3MuIFdlIHdlcmUgaW50ZXJlc3RlZCB0byBrbm93IGlmIGxvdyBhY2NlcHRhbmNlIHZhbHVlcyBjb3JyZWxhdGVkIHdpdGggdGhlIHNjaWVudGlmaWMgZmllbGQgaW4gd2hpY2ggdGhleSB3ZXJlIHVzZWQuIE1hbnkgb2YgdGhlIGFscmVhZHkgZXhpc3RpbmcgY2xvdWQgc2VydmljZXMgc3VwcG9ydGluZyByZXNlYXJjaCBvcmlnaW5hdGUgZnJvbSB0aGUgTGlmZSBTY2llbmNlIGRvbWFpbiBhbmQgaGF2ZSBiZWVuIGFjdGl2ZWx5IHVzZWQgYnkgdGhlIGNvbW11bml0eSBzaW5jZSBtb3JlIHRoYW4gYSBkZWNhZGUgaW4gc29tZSBjYXNlcy4gVXNlcnMgZnJvbSB0aGUgTGlmZSBTY2llbmNlIGRvbWFpbiBtaWdodCB0aGVyZWZvcmUgYmUgYWNjdXN0b21lZCB0byB0aGUgdG9vbHMgYW5kIHByb2Nlc3NlcyBpbiBjb250cmFzdCB0byBvdGhlciBkb21haW5zLCBwb3RlbnRpYWxseSBpbmNyZWFzaW5nIGFjY2VwdGFuY2UuIFdlIHRoZXJlZm9yZSBzZXBhcmF0ZWQgYWNjZXB0YW5jZSByYXRpbmdzIG9mIHN1cnZleSBwYXJ0aWNpcGFudHMgZnJvbSB0aGUgTGlmZSBTY2llbmNlIGRvbWFpbiBmcm9tIHRoZSBvdGhlciByZXN1bHRzIGFuZCBnZW5lcmF0ZWQgdHdvIGhpc3RvZ3JhbXMsIG9uZSB3aXRoIGFjY2VwdGFuY2UgdmFsdWVzIGZyb20gdGhlIExpZmUgU2NpZW5jZSBkb21haW4gYW5kIHRoZSBvdGhlciBzdW1tYXJpemluZyByZXN1bHRzIGZyb20gYWxsIG90aGVyIHNjaWVudGlmaWMgZGlzY2lwbGluZXMuDQoNCmBgYHtyfQ0KI2dldCBzY2llbnRpZmljIGZpZWxkIGFuc3dlcnMgYW5kIG1lcmdlIHdpdGggYWNjZXB0YW5jZSB2YWx1ZQ0Kc2NpZW50aWZpY19maWVsZF9kYXRhID0gc2VsZWN0KHJlc19nZW5lcmFsLCBJRCwgNSkgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgcmVuYW1lKFNjaWVudGlmaWNGaWVsZCA9IDIpDQoNCnBsb3QyX2RhdGEgPC0gbGVmdF9qb2luKGIycTQsIHNjaWVudGlmaWNfZmllbGRfZGF0YSwgYnkgPSAiSUQiKQ0KDQojc3Vic2V0IGRhdGEgZm9yIExpZmUgU2NpZW5jZSBhbmQgbm9uIExpZmUgc2NpZW5jZQ0KcGxvdDJfZGF0YV9MUyA8LSBmaWx0ZXIocGxvdDJfZGF0YSwgU2NpZW50aWZpY0ZpZWxkID09ICJMaWZlIHNjaWVuY2VzIikNCnBsb3QyX2RhdGFfbm9MUyA8LSBmaWx0ZXIocGxvdDJfZGF0YSwgU2NpZW50aWZpY0ZpZWxkICE9ICJMaWZlIHNjaWVuY2VzIikNCg0KI3Bsb3QgYm90aCBzdWJzZXRzIG5leHQgdG8gZWFjaCBvdGhlcg0KcGxvdF8yYSA8LSBnZ3Bsb3QocGxvdDJfZGF0YV9MUywgYWVzKHg9dmFsKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGNvbG9yID0gImJsYWNrIiwgZmlsbD0iIzAwQTJGOSIpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lZGlhbih2YWwpKSwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEwLCBieSA9IDEpLCBsaW1pdHMgPSBjKDAsMTEpKSArDQogIHlsaW0oMCwgOCkgKw0KICBnZW9tX3RleHQoeD0xLCB5PTcsIGxhYmVsPSJuID0gMTgiLCBzaXplID0gNSkgKw0KICBnZW9tX3RleHQoeD0xLCB5PTUsIGxhYmVsPSJtZWRpYW4gPSA4Iiwgc2l6ZSA9IDUpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgeGxhYigiIikgKw0KICBnZ3RpdGxlKCJDbG91ZCBzZXJ2aWNlIGFjY2VwdGFuY2UgZXN0aW1hdGlvbiBpbiBMaWZlIFNjaWVuY2VzIikNCg0KcGxvdF8yYiA8LSBnZ3Bsb3QocGxvdDJfZGF0YV9ub0xTLCBhZXMoeD12YWwpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgY29sb3IgPSAiYmxhY2siLCBmaWxsPSIjMDBBMkY5IikgKw0KICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gbWVkaWFuKHZhbCkpLCBjb2xvciA9ICJyZWQiLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBsaW5ld2lkdGggPSAxKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMTAsIGJ5ID0gMSksIGxpbWl0cyA9IGMoMCwxMSkpICsNCiAgeWxpbSgwLCA4KSArDQogIGdlb21fdGV4dCh4PTEsIHk9NywgbGFiZWw9Im4gPSAxMiIsIHNpemUgPSA1KSArDQogIGdlb21fdGV4dCh4PTEsIHk9NSwgbGFiZWw9Im1lZGlhbiA9IDYuNSIsIHNpemUgPSA1KSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHhsYWIoInZhbHVlIikgKw0KICBnZ3RpdGxlKCJDbG91ZCBzZXJ2aWNlIGFjY2VwdGFuY2UgZXN0aW1hdGlvbiBvdXRzaWRlIExpZmUgU2NpZW5jZXMiKQ0KDQpncmlkLmFycmFuZ2UocGxvdF8yYSwgcGxvdF8yYiwgbmNvbCA9IDEpDQoNCiNjYWxjdWxhdGUgc29tZSBzdGF0aXN0aWNzDQpuMmEgPSBucm93KHBsb3QyX2RhdGFfTFMpDQptZWRpYW4yYSA9IG1lZGlhbihwbG90Ml9kYXRhX0xTJHZhbCkNCm4yYiA9IG5yb3cocGxvdDJfZGF0YV9ub0xTKQ0KbWVkaWFuMmIgPSBtZWRpYW4ocGxvdDJfZGF0YV9ub0xTJHZhbCkNCg0KIyBwbG90IGNsb3VkIHNlcnZpY2UgYWNjZXB0YW5jZSBjbG91ZCBwcm92aWRlcnMgdnMgbm9uLWNsb3VkLXByb3ZpZGVycw0KcGxvdDNfZGF0YSA9IHJlc19DU19wcm92aXNpb24gJT4lDQogIHJlbmFtZSh2YWwgPSA5LCBwcm92aWRlciA9IDIpICU+JQ0KICBzZWxlY3QoSUQsIHByb3ZpZGVyLCB2YWwpICU+JQ0KICBuYS5vbWl0KCkNCg0KcGxvdDNfZGF0YV9wcm92aWRlciA8LSBmaWx0ZXIocGxvdDNfZGF0YSwgcHJvdmlkZXIgPT0gIlllcyIpDQpwbG90M19kYXRhX25vbnByb3ZpZGVyIDwtIGZpbHRlcihwbG90M19kYXRhLCBwcm92aWRlciAhPSAiWWVzIikNCg0KcGxvdF8zYSA8LSBnZ3Bsb3QocGxvdDNfZGF0YV9wcm92aWRlciwgYWVzKHg9dmFsKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGNvbG9yID0gImJsYWNrIiwgZmlsbD0iIzAwQTJGOSIpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lZGlhbih2YWwpKSwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEwLCBieSA9IDEpLCBsaW1pdHMgPSBjKDAsMTEpKSArDQogIHlsaW0oMCwgOCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB4bGFiKCIiKSArDQogIGdndGl0bGUoIkNsb3VkIHNlcnZpY2UgYWNjZXB0YW5jZSBlc3RpbWF0aW9uIG9mIGNsb3VkIHNlcnZpY2UgcHJvdmlkZXJzIikNCg0KcGxvdF8zYiA8LSBnZ3Bsb3QocGxvdDNfZGF0YV9ub25wcm92aWRlciwgYWVzKHg9dmFsKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGNvbG9yID0gImJsYWNrIiwgZmlsbD0iIzAwQTJGOSIpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lZGlhbih2YWwpKSwgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIiwgbGluZXdpZHRoID0gMSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEwLCBieSA9IDEpLCBsaW1pdHMgPSBjKDAsMTEpKSArDQogIHlsaW0oMCwgOCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB4bGFiKCJ2YWx1ZSIpICsNCiAgZ2d0aXRsZSgiQ2xvdWQgc2VydmljZSBhY2NlcHRhbmNlIGVzdGltYXRpb24gb2YgcGFydGljaXBhbnRzIG5vdCBwcm92aWRpbmcgY2xvdWQgc2VydmljZXMiKQ0KDQojZ3JpZC5hcnJhbmdlKHBsb3RfM2EsIHBsb3RfM2IsIG5jb2wgPSAxKQ0KDQpgYGANCioqRmlndXJlIDM6KioNCg0KVGhlIHR3byBwbG90cyBzaG93IHRoYXQgbWVkaWFuIGFjY2VwdGFuY2Ugb2YgY2xvdWQgc2VydmljZXMgZHJvcHMgbm90YWJseSB3aGVuIGNvbnNpZGVyaW5nIG9ubHkgY29udHJpYnV0aW9ucyBmcm9tIG91dHNpZGUgdGhlIExpZmUgU2NpZW5jZSBkb21haW4gdG8gYSB2YWx1ZSBvZiA2LjUsIGNvbXBhcmVkIHRvIGEgbWVkaWFuIGFjY2VwdGFuY2Ugb2YgOCB3aXRoaW4gTGlmZSBTY2llbmNlcy4gVGhlc2UgcmVzdWx0cyBzdWdnZXN0IHRoYXQgc2NpZW50aXN0cyBmcm9tIG90aGVyIGRpc2NpcGxpbmVzIGFyZSBnZW5lcmFsbHkgbW9yZSBoZXNpdGFudCB0byB1c2UgY2xvdWQgc2VydmljZXMgaW4gdGhlaXIgcmVzZWFyY2ggcHJvY2Vzcy4gDQoNCmBgYHtyfQ0KI2NvbGxlY3QgZnJlZSB0ZXh0IGFuc3dlciBmb3IgcmVhc29uaW5nIHdoeSBjbG91ZCBzZXJ2aWNlcyBhcmUgbm90IGFjY2VwdGVkDQpiMnE1IDwtIHJlc19DU19wcm92aXNpb24gJT4lDQogIHJlbmFtZSh2YWwgPSA5LCBhbnN3ZXJzID0gMTApICU+JQ0KICBzZWxlY3QoSUQsIHZhbCwgYW5zd2VycykgJT4lDQogIGZpbHRlcih2YWwgPD0gNikgJT4lDQogIG5hLm9taXQoKQ0KDQojYjJxNSRhbnN3ZXJzDQpgYGANCg0KVG8gYmV0dGVyIHVuZGVyc3RhbmQgdGhlIHBvdGVudGlhbCByZWFzb25zIGZvciBsb3cgYWNjZXB0YW5jZSBvZiBjbG91ZCBzZXJ2aWNlcyB3aXRoaW4gdGhlIHJlc2VhcmNoIGNvbW11bml0eSwgd2UgYXNrZWQgcGFydGljaXBhbnRzIGZvciB0aGVpciBvcGluaW9uIG9uIHRoaXMgdG9waWMuIFRoZSBmcmVlLXRleHQgYW5zd2VycyB0byB0aGlzIHF1ZXN0aW9uIGFyZSBzdW1tYXJpemVkIGluIHRoZSBmb2xsb3dpbmcgYnVsbGV0IHBvaW50czoNCg0KVGVjaG5pY2FsIGlzc3Vlcw0KDQotIGxvdyBkYXRhIHRyYW5zZmVyIHJhdGVzIGZyb20gbG9jYWwgbWFjaGluZXMgdG8gdGhlIGNsb3VkLCBlc3BlY2lhbGx5IGZvciBsYXJnZSBmaWxlcyAoZS5nLiBtYXNzIHNwZWN0cm9tZXRyeSkNCi0gdG9vbHMgZGV2ZWxvcGVkIGJ5IHRoZSBjb21tdW5pdHkgZm9yIGRhdGEgYW5hbHlzaXMgb24gY2xpZW50IG1hY2hpbmVzIGFyZSBub3Qgd2VsbCBhZGFwdGVkIHRvIGJlIGRlcGxveWVkIGluIGEgY2xvdWQgZW52aXJvbm1lbnQNCg0KUHJhY3RpY2FsIGlzc3Vlcw0KDQotIGluY3JlYXNlZCB3b3JrbG9hZCBvZiB0cmFuc2ZlcnJpbmcgZGF0YSBmcm9tIHRoZSBtYWNoaW5lIHdoZXJlIGl0IHdhcyBnZW5lcmF0ZWQgdG8gdGhlIGNsb3VkIGVudmlyb25tZW50IGZvciBhbmFseXNpcw0KLSBwcmVmZXJlbmNlIHRvIGV4ZWN1dGUgYW5hbHlzaXMgc29mdHdhcmUgb24gbG9jYWwgbWFjaGluZXMNCi0gaGVzaXRhbmNlIHRvIGNoYW5nZSBlc3RhYmxpc2hlZCByb3V0aW5lcyBmb3IgZGF0YSBhbmFseXNpcw0KLSBjbG91ZCBzZXJ2aWNlcyBkbyBub3QgcHJvdmlkZSBlbm91Z2ggYWR2YW50YWdlcyB0byBqdXN0aWZ5IGNoYW5naW5nIHByb2Nlc3NlcyBpbiB0aGUgZXllcyBvZiB1c2Vycw0KDQpNaXNzaW5nIGVkdWNhdGlvbiBhbmQgbGFjayBvZiB0cnVzdCBpbiBjbG91ZCB0ZWNobm9sb2dpZXMNCg0KLSB1c2VycyBhcmUgYWZyYWlkIHRvIGxvb3NlIHNvdmVyZWlnbnR5IG92ZXIgdGhlaXIgZGF0YSB3aGVuIHVwbG9hZGluZyBpdCB0byBhIGNsb3VkIHBsYXRmb3JtDQotIGRhdGEgYW5hbHlzaXMgaW4gYSBjbG91ZCBlbnZpcm9ubWVudCBpcyBwZXJjZWl2ZWQgYXMgYSAiYmxhY2sgYm94IiwgbWVhbmluZyB1c2VycyBkbyBub3QgZnVsbHkgdW5kZXJzdGFuZCB0aGUgd29ya2Zsb3cgYW5kIGFyZSB0aGVyZWZvcmUgaGVzaXRhbnQgdG8gdHJ1c3QgdGhlIHJlc3VsdHMNCi0gbGFjayBvZiAodGVjaG5pY2FsKSBrbm93bGVkZ2UgYWJvdXQgY2xvdWQgc2VydmljZXMNCi0gZ2VuZXJhbCBsYWNrIG9mIGV4cG9zdXJlIHRvIGNsb3VkIGVudmlyb25tZW50cyBhbmQgZmFtaWxpYXJpdHkgd2l0aCB1c2luZyB0aG9zZSBzZXJ2aWNlcw0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiByaWdodCI+DQoNCltUYWJsZSBvZiBjb250ZW50c10oI2hlYWRlcikNCg0KPC9kaXY+DQojIyBUcmFpbmluZyBjb250ZW50DQoNClRoZSBzZWNvbmQgcXVlc3Rpb24gYmxvY2sgb2YgdGhlIHN1cnZleSBpbmNsdWRlZCBxdWVzdGlvbnMgYXJvdW5kIHRoZSB0b3BpYyBvZiB0cmFpbmluZyBtYXRlcmlhbHMgdGVhY2hpbmcgdGhlIHVzZSBhbmQgaW1wbGVtZW50YXRpb24gb2YgY2xvdWQgc2VydmljZXMgZm9yIHRoZSBwdXJwb3NlIG9mIHJlc2VhcmNoIGRhdGEgbWFuYWdlbWVudCBhbmQgZGF0YSBhbmFseXNpcy4gV2Ugd2FudGVkIHRvIGtub3cgd2hpY2ggdHJhaW5pbmcgY29udGVudCBpcyBhbHJlYWR5IGV4aXN0aW5nIHdpdGhpbiB0aGUgcHJvamVjdHMgb2Ygc3VydmV5IHBhcnRpY2lwYW50cywgaW4gd2hpY2ggZm9ybSBpdCBpcyBwcm92aWRlZCwgYW5kIHdoaWNoIGdhcHMgZXhpc3QgdGhhdCBjYW4gYmUgZmlsbGVkIGJ5IHRoZSBkZS5LQ0QgcHJvamVjdC4NCg0KIyMjIFByb3Zpc2lvbiBvZiB0cmFpbmluZyBjb250ZW50DQoNCk91dCBvZiAzNCBzdXJ2ZXkgcGFydGljaXBhbnRzLCAyMCAoNTklKSBpbmRpY2F0ZWQgdGhhdCB0aGV5IGFyZSBwcm92aWRpbmcgdHJhaW5pbmcgbWF0ZXJpYWxzIHdpdGhpbiB0aGVpciBwcm9qZWN0IGFscmVhZHkuIFdoZW4gZGVzaWduaW5nIHRoZSB0cmFpbmluZyBtYXRlcmlhbCwgYWxsIHBhcnRpY2lwYW50cyB3aG8gcHJvdmlkZWQgdHJhaW5pbmcgY29udGVudCBoYWQgUGhEIHN0dWRlbnRzIGFuZCBQb3N0LWRvY3MgYXMgYSB0YXJnZXQgZ3JvdXAgaW4gbWluZCAoc2VlIEZpZ3VyZSA0KS4gQmVzaWRlcyB0aGF0LCBlbXBsb3llZXMgYXQgcmVzZWFyY2ggaW5zdGl0dXRpb25zICgxNiBvdXQgb2YgMjApIGFuZCBzdHVkZW50cyBpbiBnZW5lcmFsICgxNSBvdXQgb2YgMjApIHdlcmUgdGhlIHNlY29uZCBtb3N0IGZyZXF1ZW50bHkgbWVudGlvbmVkIHRhcmdldCBncm91cC4gVGhlIGxlYXN0IGZyZXF1ZW50bHkgbWVudGlvbmVkIHRhcmdldCBncm91cCB3ZXJlIGRhdGEgc3Rld2FyZHMsIHdobyB3ZXJlIGNvbnNpZGVyZWQgYnkgOCBvdXQgb2YgMjAgcGFydGljaXBhbnRzIHdobyBwcm92aWRlIHRyYWluaW5nIGNvbnRlbnQgd2l0aGluIHRoZWlyIHByb2plY3QuIE9uZSBwYXJ0aWNpcGFudCBpbmRpY2F0ZWQgdGhhdCB0aGV5IGFyZSBwcm92aWRpbmcgdHJhaW5pbmcgY29udGVudCB0YXJnZXRlZCBhdCBhbGwgYWNhZGVtaWMgbGV2ZWxzLg0KDQpgYGB7cn0NCiMjICJEbyB5b3UgcHJvdmlkZSB0cmFpbmluZyBjb250ZW50PyINCiMgZ2V0IHN1bW1hcnkgb2YgcXVlc3Rpb24gMQ0KYjNxMSA9IHJlc190cmFpbmluZyAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDIpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBjb3VudChhbnN3ZXIpDQoNCiNpZiAoa25pdHI6OmlzX2h0bWxfb3V0cHV0KCkpIHsNCiMgIGRhdGF0YWJsZShiM3ExKQ0KI30gZWxzZSB7DQojICBmbGV4dGFibGUoYjNxMSwgY3dpZHRoID0gYygxLDEpKSAlPiUNCiMgIHNldF9oZWFkZXJfbGFiZWxzKGFuc3dlciA9ICJBbnN3ZXIiLCBuID0gIm4iKSAlPiUNCiMgIHRoZW1lX3plYnJhKCkNCiN9DQoNCiMjIFRyYWluaW5nIGNvbnRlbnQgdGFyZ2V0IGdyb3VwDQojIGNvbGxlY3QgYW5zd2VycyB0byAybmQgcXVlc3Rpb24gYW5kIHNwbGl0IG11bHRpLWNob2ljZSBjb2x1bW5zIGJ5IGRlbGltaXRlcg0KYjNxMiA9IHJlc190cmFpbmluZyAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDMpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBzZXBhcmF0ZV9sb25nZXJfZGVsaW0oYW5zd2VyLCBkZWxpbSA9ICI7IikNCg0KIyByZW1vdmUgbGVhZGluZyBhbmQgdHJhaWxpbmcgd2hpdGVzcGFjZXMgDQpiM3EyIDwtIGFzLmRhdGEuZnJhbWUoZ3N1YigiXlxccyt8XFxzKyQiLCAiIiwgYjNxMiRhbnN3ZXIpKQ0KDQojIGNvdW50IG9jY3VyZW5jZXMgb2YgYW5zd2Vycw0KcGxvdDNfMV9kYXRhID0gYjNxMiAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDEpICU+JQ0KICBjb3VudChhbnN3ZXIpDQoNCiMgbWFrZSBiYXIgcGxvdA0KcGxvdDNfMSA8LSBnZ3Bsb3QocGxvdDNfMV9kYXRhLCBhZXMoeD1yZW9yZGVyKGFuc3dlciwgLWFzLm51bWVyaWMobikpLCB5PW4sIGZpbGwgPSByZW9yZGVyKGFuc3dlciwgLWFzLm51bWVyaWMobikpKSkgKw0KICBnZW9tX2Jhcihjb2xvciA9ICJibGFjayIsIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgbGFicyhmaWxsID0gIlRhcmdldCBncm91cCIsIHkgPSAiY291bnQiLCB4ID0gIlRhcmdldCBncm91cCIpDQoNCnBsb3QzXzENCmBgYA0KKipGaWd1cmUgNDoqKiBUYXJnZXQgZ3JvdXBzIGZvciB0cmFpbmluZyBtYXRlcmlhbHMgcHJvdmlkZWQgd2l0aGluIHRoZSBwcm9qZWN0cyBvZiBzdXJ2ZXkgcGFydGljaXBhbnRzLg0KDQpUcmFpbmluZyBtYXRlcmlhbHMgY2FuIGJlIHByb3ZpZGVkIGluIG1hbnkgZGlmZmVyZW50IHdheXMsIHNvIHdlIHdlcmUgaW50ZXJlc3RlZCB0byBrbm93IGluIHdoaWNoIGZvcm0gdGhlIGNvbnRlbnQgaXMgcHJvdmlkZWQgdG8gdGhlIHRhcmdldCBhdWRpZW5jZS4gVGhlIHJlc3VsdHMgb2YgdGhpcyBxdWVzdGlvbiBhcmUgc2hvd24gaW4gRmlndXJlIDUuIEFsbW9zdCBhbGwgcGFydGljaXBhbnRzICgxOSBvdXQgb2YgMjApIHdobyBwcm92aWRlIHRyYWluaW5nIGNvbnRlbnQgdXNlIG9ubGluZSBjb3Vyc2VzIGFuZCB3b3Jrc2hvcHMgYXMgYSB2ZWhpY2xlIHRvIGRlbGl2ZXIga25vd2xlZGdlIGFib3V0IHRoZWlyIGNsb3VkIHNlcnZpY2VzIHRvIHRoZWlyIHVzZXJzLiBCZXNpZGVzIHRoYXQsIHNsaWRlIGRlY2tzICgxMiBvdXQgb2YgMjApIGFuZCBrbm93bGVkZ2UgZGF0YWJhc2VzIG9yIHdpa2lzICgxMSBvdXQgb2YgMjApIHdlcmUgcG9wdWxhciBjaG9pY2VzIGFzIHdlbGwuIE9ubHkgYSBtaW5vcml0eSBwcm92aWRlZCB0cmFpbmluZyBtYXRlcmlhbHMgdmlhIGEgcHJvamVjdCBob21lcGFnZSAoOCBvdXQgb2YgMjApIGFuZCBlZHVjYXRpb25hbCB2aWRlbyBtYXRlcmlhbCB3YXMgdGhlIGxlYXN0IHBvcHVsYXIgY2hvaWNlIHRvIGRlbGl2ZXIga25vd2xlZGdlIHRvIHRoZSB0YXJnZXQgZ3JvdXAgKDUgb3V0IG9mIDIwKS4NCg0KYGBge3J9DQojIyBUeXBlIG9mIHRyYWluaW5nIGNvbnRlbnQNCmIzcTMgPSByZXNfdHJhaW5pbmcgJT4lDQogIHJlbmFtZShhbnN3ZXIgPSA1KSAlPiUNCiAgc2VsZWN0KGFuc3dlcikgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgc2VwYXJhdGVfbG9uZ2VyX2RlbGltKGFuc3dlciwgZGVsaW0gPSAiOyIpDQoNCiMgcmVtb3ZlIGxlYWRpbmcgYW5kIHRyYWlsaW5nIHdoaXRlc3BhY2VzIA0KYjNxMyA8LSBhcy5kYXRhLmZyYW1lKGdzdWIoIl5cXHMrfFxccyskIiwgIiIsIGIzcTMkYW5zd2VyKSkNCg0KIyBjb3VudCBvY2N1cmVuY2VzIG9mIGFuc3dlcnMNCnBsb3QzXzJfZGF0YSA9IGIzcTMgJT4lDQogIHJlbmFtZShhbnN3ZXIgPSAxKSAlPiUNCiAgY291bnQoYW5zd2VyKQ0KDQojIG1ha2UgYmFyIHBsb3QNCnBsb3QzXzIgPC0gZ2dwbG90KHBsb3QzXzJfZGF0YSwgYWVzKHg9cmVvcmRlcihhbnN3ZXIsIC1hcy5udW1lcmljKG4pKSwgeT1uLCBmaWxsID0gcmVvcmRlcihhbnN3ZXIsIC1hcy5udW1lcmljKG4pKSkpICsNCiAgZ2VvbV9iYXIoY29sb3IgPSAiYmxhY2siLCBzdGF0ID0gImlkZW50aXR5IikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoZmlsbCA9ICJUeXBlIG9mIHRyYWluaW5nIGNvbnRlbnQiLCB5ID0gImNvdW50IiwgeCA9ICJUeXBlIG9mIHRyYWluaW5nIGNvbnRlbnQiKQ0KDQpwbG90M18yDQpgYGANCioqRmlndXJlIDU6KiogVHlwZXMgb2YgdHJhaW5pbmcgY29udGVudCB0aGF0IGFyZSB1c2VkIHdpdGhpbiBwcm9qZWN0cyBvZiBzdXJ2ZXkgcGFydGljaXBhbnRzIHRvIGRlbGl2ZXIga25vd2xlZGdlIHRvIHRoZWlyIHRhcmdldCBhdWRpZW5jZS4NCg0KQmVzaWRlcyB0aGUgcHJlLWRlZmluZWQgdHlwZXMgb2YgdHJhaW5pbmcgY29udGVudCBzaG93biBhYm92ZSwgcGFydGljaXBhbnRzIGFsc28gdXNlZCBvdGhlciBtZWFucyB0byB0cmFuc2ZlciBrbm93bGVkZ2UgdG8gdGhlaXIgdGFyZ2V0IGF1ZGllbmNlLiBUaG9zZSBpbmNsdWRlIGluZGl2aWR1YWwgdHJhaW5pbmcgc2Vzc2lvbnMsIGRvY3VtZW50YXRpb24gaW4gZ2l0IHJlcG9zaXRvcmllcywganVweXRlciBub3RlYm9va3MsIGFuZCBpbnRlcmFjdGl2ZSBzZWxmIGxlYXJuaW5nIHBsYXRmb3Jtcy4NCg0KYGBge3J9DQojIGxpc3QgIm90aGVyIg0KcGxvdDNfMl9vdGhlciA9IHJlc190cmFpbmluZyAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDYpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpDQoNCiNpZiAoa25pdHI6OmlzX2h0bWxfb3V0cHV0KCkpIHsNCiMgIGRhdGF0YWJsZShwbG90M18yX290aGVyKQ0KI30gZWxzZSB7DQojICBmbGV4dGFibGUocGxvdDNfMl9vdGhlciwgY3dpZHRoID0gMykgJT4lDQojICBzZXRfaGVhZGVyX2xhYmVscyhhbnN3ZXIgPSAiT3RoZXIgYW5zd2VycyIpICU+JQ0KIyAgdGhlbWVfemVicmEoKQ0KI30NCmBgYA0KDQoNClN1YmplY3RzIGZvciB3aGljaCBzdXJ2ZXkgcGFydGljaXBhbnRzIHByb3ZpZGUgbGVhcm5pbmcgY29udGVudDoNCg0KYGBge3J9DQojIyBUcmFpbmluZyBjb250ZW50IHN1YmplY3RzDQpiM3E0ID0gcmVzX3RyYWluaW5nICU+JQ0KICByZW5hbWUoYW5zd2VyID0gNykgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkNCg0KI2IzcTQkYW5zd2VyDQpgYGANCg0KSFBDIHRyYWluaW5nDQoNCi0gVXNhZ2Ugb2YgSFBDIHJlc291cmNlcw0KICAtIGhvdyB0byBjcmVhdGUgYW5kIGFjY2VzcyBWTXMNCi0gZmlsZSB0cmFuc2ZlciB0byBWTXMNCi0gdXNlIG9mIGNsb3VkIHN0b3JhZ2UgZGV2aWNlcw0KICAtIG9iamVjdCBzdG9yYWdlDQogIC0gY2luZGVyIHZvbHVtZXMNCiAgLSBTMyBzdG9yYWdlDQoNCkNsb3VkIHNlcnZpY2UgdHJhaW5pbmcNCg0KLSBCYXNpYyB1c2FnZSBvZiB0aGUgcHJvdmlkZWQgY2xvdWQgc2VydmljZXMNCi0gSG93IHRvIHJ1biBMYXJnZSBMYW5ndWFnZSBNb2RlbHMgKExMTSkgaW4gdGhlIGNsb3VkDQotIFN5c0FkbWluLCBBdWRpdCwgTmV0d29yaywgYW5kIFNlY3VyaXR5IChTQU5TKSB0cmFpbmluZw0KLSBjbG91ZCBzZXJ2aWNlIGRlcGxveW1lbnQgYW5kIG9wdGltaXphdGlvbg0KLSBvdmVydmlldyBhbmQgYmVuZWZpdHMgb2YgY2xvdWQgc29sdXRpb25zIA0KDQpSZXNlYXJjaCBkYXRhIG1hbmFnZW1lbnQgdHJhaW5pbmcNCg0KLSBSZXNlYXJjaCBEYXRhIE1hbmFnZW1lbnQgKFJETSkgYmFzaWNzDQogIC0gRkFJUiBkYXRhIG1hbmFnZW1lbnQNCiAgLSBGQUlSIHJlc2VhcmNoIHNvZnR3YXJlDQotIGNpdGF0aW9uIG9mIGRhdGENCi0gZGF0YSBhY2Nlc3MgYW5kIHByb2Nlc3Npbmcgd2l0aCBweXRob24NCi0gVXNlIG9mIGNhdGFsb2dzIGluIGNvbWJpbmF0aW9uIHdpdGggZGF0YSBob3N0ZWQgaW4gdGhlIGNsb3VkDQoNCldvcmtmbG93L0FuYWx5c2lzIHBpcGVsaW5lIHRyYWluaW5nDQoNCi0gQmFzaWMgdHJhaW5pbmcgYW5kIG1hdGVyaWFscyBmb3Igd29ya2Zsb3cgZGV2ZWxvcGVycw0KLSBVc2FnZSBvZiB3b3JrZmxvdyBtYW5hZ2VtZW50IHN5c3RlbXMgZm9yIGRhdGEgYW5hbHlzaXMNCi0gRmllbGQtc3BlY2lmaWMgYW5hbHlzaXMgcGlwZWxpbmVzDQogIC0gTWV0YWdlbm9tZSBhbmFseXNlcyBpbiB0aGUgY2xvdWQNCg0KDQojIyMgQ2xvdWQgc2VydmljZXMgZm9yIHRyYWluaW5nIGNvbnRlbnQgYW5kIGNvdXJzZXMNCg0KRG8gcGFydGljaXBhbnRzIHVzZSBjbG91ZC1iYXNlZCBzZXJ2aWNlcyBmb3IgY29uZHVjdGluZyB0cmFpbmluZz8NCg0KYGBge3J9DQojIyBjbG91ZC1iYXNlZCBzZXJ2aWNlcyBmb3IgdHJhaW5pbmcNCiMgc3VtbWFyaXplIHVzYWdlIG9mIGNsb3VkIHNlcnZpY2VzIHRvIHByb3ZpZGUgdHJhaW5pbmcgY29udGVudA0KYjNxNSA9IHJlc190cmFpbmluZyAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDgpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBjb3VudChhbnN3ZXIpDQoNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkgew0KICBkYXRhdGFibGUoYjNxNSkNCn0gZWxzZSB7DQogIGZsZXh0YWJsZShiM3E1LCBjd2lkdGggPSBjKDIsMSkpICU+JQ0KICBzZXRfaGVhZGVyX2xhYmVscyhhbnN3ZXIgPSAiQW5zd2VyIiwgbiA9ICJuIikgJT4lDQogIHRoZW1lX3plYnJhKCkNCn0NCmBgYA0KDQpXaGljaCBjbG91ZCBzZXJ2aWNlcyBhcmUgdXNlZCB0byBjb25kdWN0IHRyYWluaW5nPw0KDQpgYGB7cn0NCiMgY29sbGVjdCBhbnN3ZXJzDQpiM3E2ID0gcmVzX3RyYWluaW5nICU+JQ0KICByZW5hbWUoYW5zd2VyID0gOSkgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkNCg0KI2IzcTYkYW5zd2VyDQpgYGANCg0KLSBKdXB5dGVyIE5vdGVib29rcyBhcmUgbW9zdCBwb3B1bGFyIGFtb25nIHBhcnRpY2lwYW50cw0KICAtIGFsc28gaW4gY29tYmluYXRpb24gd2l0aCBKdXB5dGVySHViIGZvciBtdWx0aS11c2VyIHNlc3Npb25zDQotIFZpcnR1YWwgbWFjaGluZXMgYXJlIGFsc28gcG9wdWxhcg0KICAtIG9mdGVuIGRlcGxveWVkIHZpYSBTaW1wbGVWTQ0KLSBHYWxheHkgdHJhaW5pbmcgaW5mcmFzdHJ1Y3R1cmUgYXMtYS1zZXJ2aWNlDQotIEdpdGh1Yi9HaXRsYWIgcmVwb3NpdG9yaWVzDQotIFZTQ29kZSByZXNlYXJjaCBlbnZpcm9ubWVudHMNCi0gcG9ydGFsIGZvciBSIHNoaW55IGFwcGxpY2F0aW9ucyBmb3IgZGF0YSBwcm9jZXNzaW5nIGFuZCB2aXN1YWxpemF0aW9uDQotIFgyR28NCi0gSG9iYnlmYXJtDQoNCiMjIyBQb3RlbnRpYWwgZm9yIGFkZGl0aW9uYWwgdHJhaW5pbmcgY29udGVudCBwcm92aWRlZCBieSBkZS5LQ0QgcGFydG5lcnMNCg0KYGBge3J9DQojIyBNb3N0IGltcG9ydGFudCB0b3BpY3MgcGFydGljaXBhbnRzIHdvdWxkIG5lZWQgdHJhaW5pbmcgb246DQpiM3E3ID0gcmVzX3RyYWluaW5nICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMTApICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpDQoNCiNiM3E3JGFuc3dlcg0KYGBgDQoNCldlIGFza2VkIHRoZSBzdXJ2ZXkgcGFydGljaXBhbnRzIHdoaWNoLCBpbiB0aGVpciBvcGluaW9uLCBhcmUgdGhlIG1vc3QgaW1wb3J0YW50IHRvcGljcyBvbiB3aGljaCB0aGV5IG9yIHBlb3BsZSBpbiB0aGVpciBwcm9qZWN0IHdvdWxkIG5lZWQgYWRkaXRpb25hbCB0cmFpbmluZyBtYXRlcmlhbHMuIFRoZSBmcmVlIHRleHQgYW5zd2VycyB0byB0aGlzIHF1ZXN0aW9uIGFyZSBzdW1tYXJpemVkIGluIHRoZSBmb2xsb3dpbmcgYnVsbGV0IHBvaW50cy4NCg0KQ2xvdWQgaW5mcmFzdHJ1Y3R1cmUga25vd2xlZGdlDQoNCi0gQ2xvdWQgaW5mcmFzdHJ1Y3R1cmUgYmFzaWNzDQotIExpbnV4IFN5c2FkbWluIGJhc2ljcw0KLSBHZW5lcmFsIGludHJvZHVjdGlvbiBhbmQgYmVzdCBwcmFjdGljZSBleGFtcGxlcyBmb3IgZGlmZmVyZW50IHNvZnR3YXJlIHN0YWNrcw0KLSBIb3cgdG8gZW5zdXJlIHJlc2lsaWVuY2UgYW5kIHN0YWJpbGl0eSBvZiBjbG91ZCBzZXJ2aWNlcw0KLSBOZXR3b3JraW5nIGFuZCByb3V0aW5nDQotIFNlY3VyaXR5IGFuZCBhY2Nlc3NpYmlsaXR5IG9mIGNsb3VkIGluZnJhc3RydWN0dXJlDQotIEhvdyB0byBkZXZlbG9wIGFuZCBkZXBsb3kgY2xvdWQtYmFzZWQgcmVzb3VyY2VzL2FwcGxpY2F0aW9ucyBpbiBhIHNjYWxhYmxlIHdheQ0KLSBUcmFpbmluZyBvbiBoaWdoZXItbGV2ZWwgZnJhbWV3b3Jrcw0KICAtIEt1YmVybmV0ZXMNCiAgLSBBbnNpYmxlDQogIC0gVGVycmFmb3JtDQotIERlYnVnZ2luZyBvZiBjb21wbGV4IGNsb3VkIHN5c3RlbXMNCi0gQ29uY2VwdHMgb2Ygdm9sYXRpbGUgY2xvdWQgcmVzb3VyY2VzDQoNCg0KUmVzZWFyY2ggZGF0YSBtYW5hZ2VtZW50IGZvciBhcHBsaWNhdGlvbnMgaW4gdGhlIGNsb3VkDQoNCi0gQmFzaWNzIG9mIGRhdGEgbWFuYWdlbWVudA0KLSBTdHJ1Y3R1cmluZyBjb21wbGV4IGRhdGEgc2V0cy9hbmFseXNpcyBwaXBlbGluZXMNCi0gTmF2aWdhdGluZyB0aGUgY29tcGxleCBzeXN0ZW0gb2YgbWV0YWRhdGEsIGFsc28gaW4gY29tYmluYXRpb24gd2l0aCBvbnRvbG9naWVzDQotIEhvdyB0byBtYWtlIGRhdGEgdGlkeQ0KLSBFbnN1cmluZyByZXByb2R1Y2liaWxpdHkNCi0gVXNhZ2Ugb2YgY2xvdWQgaW5mcmFzdHJ1Y3R1cmUgZm9yIEZBSVIgUkRNDQoNCg0KRGF0YSBhbmFseXNpcyBpbiB0aGUgY2xvdWQNCg0KLSBIb3cgdG8gdHJhbnNmZXIgZGF0YSBpbnRvIGNsb3VkIGVudmlyb25tZW50cw0KICAtIGZvY3VzIG9uIGxhcmdlIGRhdGEgc2V0cw0KLSBXb3JrZmxvdyBkZXZlbG9wbWVudCB3aXRoIG5leHRmbG93DQogIC0gdW5kZXJzdGFuZGluZyB0aGUgbmV4dGZsb3cgY29uY2VwdCBvZiBkYXRhZmxvdyBwcm9ncmFtbWluZyAoZS5nLiBjaGFubmVscykNCi0gSW1wbGVtZW50aW5nIHBvcnRhYmxlIHdvcmtmbG93cw0KICAtIGVuc3VyaW5nIHRoZSBhYmlsaXR5IHRvIHJ1biBhbmQgcHJvcGVyIHNjYWxpbmcgd2l0aCBsYXJnZSBjb21wdXRlIGNsdXN0ZXJzDQotIEluZm9ybWF0aW9uIGFib3V0IHBhcmFsbGVsIHByb2Nlc3NpbmcgdG8gZXhwbG9pdCBwYXJhbGxlbCBhY2Nlc3MgdG8gY2xvdWQtaG9zdGVkIGRhdGENCg0KDQpBY2Nlc3MgdG8gY2xvdWQgcmVzb3VyY2VzDQoNCi0gSG93IHRvIGluY2x1ZGUgY2xvdWQgcmVzb3VyY2VzIGluIHRvb2xzIGxpa2UgVlNDb2RlDQotIEhvdyB0byBhY2Nlc3MgZGlmZmVyZW50IHJlc291cmNlcywgZS5nLiB2aWEgUkVTVCBBUElzLCB3aXRoIHRoZSBnb2FsIHRvIHVzZSB0aGVtIGluIGxvY2FsIG9yIGNsb3VkIGFuYWx5c2lzIHBpcGVsaW5lcw0KLSBIb3cgdG8gZWZmZWN0aXZlbHkgc3RyZWFtIGRhdGEgYmV0d2VlbiBjbG91ZCBzaXRlcyBmb3IgdGhlIHB1cnBvc2Ugb2YgYW5hbHl6aW5nIGRhdGEgc2V0cyB0aGF0IGFyZSBzdG9yZWQgZWxzZXdoZXJlDQogIC0gaW4gcGFydGljdWxhciwgc29sdXRpb25zIGZvciBpbWFnZSBkYXRhIGlzIHNvdWdodA0KICAtIG1ldGhvZHMgdG8gbWluaW1pemUgYW1vdW50IG9mIGRhdGEgdGhhdCBuZWVkcyB0byBiZSB0cmFuc2ZlcnJlZA0KDQoNCk90aGVyIHRvcGljcw0KDQotIERhdGEgc2VjdXJpdHkgYW5kIGRhdGEgcHJpdmFjeQ0KICAtIHByYWN0aWNhbCB1c2UgY2FzZXMgYW5kIGJlc3QgcHJhY3RpY2VzDQotIEJhc2ljIGNvbmNlcHRzIG9mIHNoZWxsIHByb2dyYW1taW5nDQotIEhvdyB0byBiZXN0IHByb3ZpZGUgc29mdHdhcmUgc29sdXRpb25zIHRvIGEgd2lkZSBhbmQgZGl2ZXJzZSB1c2VyIGNvbW11bml0eQ0KLSBBZHZhbnRhZ2VzIG9mIHVzaW5nIGRpZ2l0YWwgc2VydmljZXMNCg0KDQoNCg0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiByaWdodCI+DQoNCltUYWJsZSBvZiBjb250ZW50c10oI2hlYWRlcikNCg0KPC9kaXY+DQojIyBEYXRhIHByb2Nlc3NpbmcNCg0KIyMjIENoYXJhY3Rlcml6YXRpb24gb2YgdHlwaWNhbCBkYXRhIGluIHByb2plY3RzIG9mIHBhcnRpY2lwYW50cw0KDQpNYWluIHR5cGVzIG9mIGRhdGEgaW4gdGhlIHByb2plY3Q6DQoNCmBgYHtyfQ0KYjRxMSA9IHJlc19kYXRhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMikgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkNCg0KaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogIGRhdGF0YWJsZShiNHExKQ0KfSBlbHNlIHsNCiAgZmxleHRhYmxlKGI0cTEsIGN3aWR0aCA9IDYpICU+JQ0KICBzZXRfaGVhZGVyX2xhYmVscyhhbnN3ZXIgPSAiQW5zd2VycyIpICU+JQ0KICB0aGVtZV96ZWJyYSgpDQp9DQpgYGANCg0KVHlwaWNhbCBzaXplIG9mIGRhdGEgZmlsZXMgd2l0aGluIHRoZSBwcm9qZWN0Og0KDQpgYGB7cn0NCnggPC0gYygiR0J5dGVzIiwgIkh1bmRyZWRzIG9mIEdCeXRlcyIsICJUQnl0ZXMiLCAiSHVuZHJlZHMgb2YgVEJ5dGVzIiwgIlBCeXRlcyIpDQoNCmI0cTIgPSByZXNfZGF0YSAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDMpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBjb3VudChhbnN3ZXIpICU+JQ0KICBtdXRhdGUoYW5zd2VyID0gZmFjdG9yKGFuc3dlciwgbGV2ZWxzID0geCkpICU+JQ0KICBhcnJhbmdlKGFuc3dlcikNCg0KIyBtYWtlIGJhciBwbG90DQpwbG90NF8xIDwtIGdncGxvdChiNHEyLCBhZXMoeD1hbnN3ZXIsIHk9biwgZmlsbCA9IGFuc3dlcikpICsNCiAgZ2VvbV9iYXIoY29sb3IgPSAiYmxhY2siLCBzdGF0ID0gImlkZW50aXR5IikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoZmlsbCA9ICJNYWduaXR1ZGUgb2YgZGF0YSIsIHkgPSAiY291bnQiLCB4ID0gIk1hZ25pdHVkZSBvZiBkYXRhIikNCg0KcGxvdDRfMQ0KYGBgDQoqKkZpZ3VyZSA2OioqDQoNCiMjIyBDbG91ZCBzb2x1dGlvbnMgZm9yIGRhdGEgZGVwb3NpdGlvbiBhbmQgc2hhcmluZw0KDQpEbyBwYXJ0aWNpcGFudHMgcHJvdmlkZSBjbG91ZCBzb2x1dGlvbnMgZm9yIGRhdGEgZGVwb3NpdGlvbiBhbmQgc2hhcmluZz8NCg0KYGBge3J9DQojIERvIHBhcnRpY2lwYW50cyBwcm92aWRlIGNsb3VkIHNvbHV0aW9ucyBmb3IgZGF0YSBkZXBvc2l0aW9uIGFuZCBzaGFyaW5nPw0KYjRxMyA9IHJlc19kYXRhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gNCkgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIGNvdW50KGFuc3dlcikNCg0KaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogIGRhdGF0YWJsZShiNHEzKQ0KfSBlbHNlIHsNCiAgZmxleHRhYmxlKGI0cTMsIGN3aWR0aCA9IGMoMiwxKSkgJT4lDQogIHNldF9oZWFkZXJfbGFiZWxzKGFuc3dlciA9ICJBbnN3ZXIiLCBuID0gIm4iKSAlPiUNCiAgdGhlbWVfemVicmEoKQ0KfQ0KDQojIFdoaWNoIHNlcnZpY2VzIGRvIHRoZXkgcHJvdmlkZT8NCmI0cTQgPSByZXNfZGF0YSAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDUpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpDQoNCiNiNHE0JGFuc3dlcg0KYGBgDQoNClVzZWQgZGF0YSBkZXBvc2l0aW9uIHNlcnZpY2VzOg0KDQotIGVzdGFibGlzaGVkIGZpZWxkLXNwZWNpZmljIGRhdGEgcmVwb3NpdG9yaWVzDQogIC0gRUJJDQogIC0gTkNCSQ0KICAtIEVNQkwNCiAgLSBHZW5iYW5rDQogIC0gRERKQg0KLSBjb21tZXJjaWFsIGNsb3VkIHN0b3JhZ2UNCiAgLSBBV1MgUzMgc3RvcmFnZSBiYXNlZCBzb2x1dGlvbnMNCiAgLSBEZWxsIEVNQyBJc2lsb24NCi0gc2VsZiBob3N0ZWQgb3Blbi1zb3VyY2Ugc29mdHdhcmUgc29sdXRpb25zDQogIC0gb3duQ2xvdWQNCiAgLSBDZXBoIHN0b3JhZ2UNCi0gb3Blbi1zb3VyY2UgcGxhdGZvcm1zDQogIC0gR2FsYXh5IEV1cm9wZQ0KICAtIEdpdGxhYg0KLSBub24tcHJvZml0IHNlcnZpY2VzDQogIC0gR2xvYnVzIHNoYXJlDQotIHNlbGYtZGV2ZWxvcGVkIHN0b3JhZ2Ugc29sdXRpb25zDQogIC0gTVdOIENsb3VkIFN0b3JhZ2UgKExSWikNCiAgLSBEYXRhIFNjaWVuY2UgU3RvcmFnZSAoTFJaKQ0KICAtIEdpdGxhYi1iYXNlZCBEYXRhSFVCcyAoRGF0YVBMQU5UKQ0KDQojIyMgU3RhbmRhcmRpemVkIGRhdGEgZm9ybWF0cw0KDQpBcmUgc3RhbmRhcmRpemVkIGZvcm1hdHMgdXNlZCBmb3IgZGF0YSBhbmQgbWV0YWRhdGE/DQoNCmBgYHtyfQ0KIyBBcmUgc3RhbmRhcmRpemVkIGZvcm1hdHMgdXNlZCBmb3IgZGF0YSBhbmQgbWV0YWRhdGE/DQpiNHE1ID0gcmVzX2RhdGEgJT4lDQogIHJlbmFtZShhbnN3ZXIgPSA2KSAlPiUNCiAgc2VsZWN0KGFuc3dlcikgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgY291bnQoYW5zd2VyKQ0KDQppZiAoa25pdHI6OmlzX2h0bWxfb3V0cHV0KCkpIHsNCiAgZGF0YXRhYmxlKGI0cTUpDQp9IGVsc2Ugew0KICBmbGV4dGFibGUoYjRxNSwgY3dpZHRoID0gYygxLDEpKSAlPiUNCiAgc2V0X2hlYWRlcl9sYWJlbHMoYW5zd2VyID0gIkFuc3dlciIsIG4gPSAibiIpICU+JQ0KICB0aGVtZV96ZWJyYSgpDQp9DQpgYGANCg0KV2hpY2ggc3RhbmRhcmRpemVkIGRhdGEgZm9ybWF0cyBhcmUgdXNlZD8NCg0KYGBge3J9DQojIFdoaWNoIHN0YW5kYXJkIGZvcm1hdHMgYXJlIHVzZWQ/DQpiNHE2ID0gcmVzX2RhdGEgJT4lDQogIHJlbmFtZShhbnN3ZXIgPSA3KSAlPiUNCiAgc2VsZWN0KGFuc3dlcikgJT4lDQogIG5hLm9taXQoKQ0KDQppZiAoa25pdHI6OmlzX2h0bWxfb3V0cHV0KCkpIHsNCiAgZGF0YXRhYmxlKGI0cTYpDQp9IGVsc2Ugew0KICBmbGV4dGFibGUoYjRxNiwgY3dpZHRoID0gNikgJT4lDQogIHNldF9oZWFkZXJfbGFiZWxzKGFuc3dlciA9ICJBbnN3ZXJzIikgJT4lDQogIHRoZW1lX3plYnJhKCkNCn0NCmBgYA0KDQojIyMgSGFuZGxpbmcgc2Vuc2l0aXZlIHBlcnNvbmFsIGRhdGENCg0KSXMgc2Vuc2l0aXZlIGRhdGEgaGFuZGxlZCB3aXRoaW4gdGhlIHByb2plY3Q/DQoNCmBgYHtyfQ0KIyBJcyBzZW5zaXRpdmUgZGF0YSBoYW5kbGVkIHdpdGhpbiB0aGUgcHJvamVjdD8NCmI0cTcgPSByZXNfZGF0YSAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDgpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBjb3VudChhbnN3ZXIpDQoNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkgew0KICBkYXRhdGFibGUoYjRxNykNCn0gZWxzZSB7DQogIGZsZXh0YWJsZShiNHE3LCBjd2lkdGggPSBjKDEsMSkpICU+JQ0KICBzZXRfaGVhZGVyX2xhYmVscyhhbnN3ZXIgPSAiQW5zd2VyIiwgbiA9ICJuIikgJT4lDQogIHRoZW1lX3plYnJhKCkNCn0NCg0KIyBIb3cgaXMgc2Vuc2l0aXZlIGRhdGEgcHJvdGVjdGVkPw0KYjRxOCA9IHJlc19kYXRhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gOSkgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkNCg0KI2I0cTgkYW5zd2VyDQpgYGANCk1lYXN1cmVtZW50cyB0byBwcm90ZWN0IHNlbnNpdGl2ZSBkYXRhOg0KDQotIGltcGxlbWVudGF0aW9uIG9mIGF1ZGl0ZWQgaW5mb3JtYXRpb24gc2VjdXJpdHkgbWFuYWdlbWVudCBzeXN0ZW1zDQotIFRlY2huaWNhbCBhbmQgb3BlcmF0aW9uYWwgbWVhc3VyZW1lbnRzIChUT00pIGFjY29yZGluZyB0byBHRFBSDQotIGRlZGljYXRlZCB0ZWFtcyBhbmQgZGVwYXJ0bWVudHMNCi0gaXNvbGF0aW9uIGFuZCBzZXBhcmF0aW9uIG9mIGRhdGEgcHJvY2Vzc2luZyBlbnZpcm9ubWVudHMNCi0gZG9jdW1lbnRhdGlvbiBvZiB0aGUgd2hvbGUgcHJvY2VzcyBmcm9tIHBhdGllbnQgb3ZlciBjb250cm9sbGVyIHRvIHByb2Nlc3NpbmcgdGhyb3VnaCBTT1AgZG9jdW1lbnRzDQoNCiMjIyBNYWNoaW5lLWxlYXJuaW5nIGFsZ29yaXRobXMgZm9yIGRhdGEgYW5hbHlzaXMNCg0KSXMgdGhlIHVzZSBvZiBBSSBhbGdvcml0aG1zIHJlbGV2YW50IGZvciB0aGUgcHJvamVjdD8NCg0KYGBge3J9DQojIGlzIHRoZSB1c2Ugb2YgQUkgYWxnb3JpdGhtcyByZWxldmFudCBmb3IgdGhlIHByb2plY3Q/DQpiNHE5ID0gcmVzX2RhdGEgJT4lDQogIHJlbmFtZShhbnN3ZXIgPSAxMCkgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIGNvdW50KGFuc3dlcikNCg0KaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogIGRhdGF0YWJsZShiNHE5KQ0KfSBlbHNlIHsNCiAgZmxleHRhYmxlKGI0cTksIGN3aWR0aCA9IGMoMSwxKSkgJT4lDQogIHNldF9oZWFkZXJfbGFiZWxzKGFuc3dlciA9ICJBbnN3ZXIiLCBuID0gIm4iKSAlPiUNCiAgdGhlbWVfemVicmEoKQ0KfQ0KYGBgDQoNCldoaWNoIGFsZ29yaXRobXMgYXJlIHVzZWQgYW5kIGZvciB3aGljaCBwdXJwb3NlPw0KDQpgYGB7cn0NCiMgV2hpY2ggYWxnb3JpdGhtcyBhbmQgZm9yIHdoYXQgcHVycG9zZT8NCmI0cTEwID0gcmVzX2RhdGEgJT4lDQogIHJlbmFtZShhbnN3ZXIgPSAxMSkgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkNCg0KaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogIGRhdGF0YWJsZShiNHExMCkNCn0gZWxzZSB7DQogIGZsZXh0YWJsZShiNHExMCwgY3dpZHRoID0gNikgJT4lDQogIHNldF9oZWFkZXJfbGFiZWxzKGFuc3dlciA9ICJBbnN3ZXJzIikgJT4lDQogIHRoZW1lX3plYnJhKCkNCn0NCmBgYA0KDQojIyMgU29sdXRpb25zIGZvciByZXByb2R1Y2libGUgZGF0YSBhbmFseXNpcw0KDQpBcmUgc29sdXRpb25zIGZvciByZXByb2R1Y2libGUgYW5hbHlzaXMgZW1wbG95ZWQ/DQoNCmBgYHtyfQ0KIyBBcmUgc29sdXRpb25zIGZvciByZXByb2R1Y2libGUgYW5hbHlzaXMgZW1wbG95ZWQ/DQpiNHExMSA9IHJlc19kYXRhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMTIpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBjb3VudChhbnN3ZXIpDQoNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkgew0KICBkYXRhdGFibGUoYjRxMTEpDQp9IGVsc2Ugew0KICBmbGV4dGFibGUoYjRxMTEsIGN3aWR0aCA9IGMoMSwxKSkgJT4lDQogIHNldF9oZWFkZXJfbGFiZWxzKGFuc3dlciA9ICJBbnN3ZXIiLCBuID0gIm4iKSAlPiUNCiAgdGhlbWVfemVicmEoKQ0KfQ0KYGBgDQoNCldoaWNoIHNlcnZpY2VzIG9yIHNvbHV0aW9ucyBhcmUgdXNlZCBmb3IgcmVwcm9kdWNpYmxlIGRhdGEgYW5hbHlzaXM/DQoNCmBgYHtyfQ0KIyBXaGljaCBzZXJ2aWNlcy9zb2x1dGlvbnMgYXJlIHVzZWQ/DQpiNHExMiA9IHJlc19kYXRhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMTMpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpDQoNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkgew0KICBkYXRhdGFibGUoYjRxMTIpDQp9IGVsc2Ugew0KICBmbGV4dGFibGUoYjRxMTIsIGN3aWR0aCA9IDYpICU+JQ0KICBzZXRfaGVhZGVyX2xhYmVscyhhbnN3ZXIgPSAiQW5zd2VycyIpICU+JQ0KICB0aGVtZV96ZWJyYSgpDQp9DQpgYGANCg0KQXJlIHNlcnZpY2VzIGZvciByZXByb2R1Y2libGUgZGF0YSBhbmFseXNpcyB1c2VkIG9yIHByb3ZpZGVkIHZpYSB0aGUgY2xvdWQ/DQoNCmBgYHtyfQ0KIyBBcmUgY2xvdWQgc29sdXRpb25zIGZvciByZXByb2R1Y2libGUgYW5hbHlzaXMgZW1wbG95ZWQ/DQpiNHExMyA9IHJlc19kYXRhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMTQpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgbmEub21pdCgpICU+JQ0KICBjb3VudChhbnN3ZXIpDQoNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkgew0KICBkYXRhdGFibGUoYjRxMTMpDQp9IGVsc2Ugew0KICBmbGV4dGFibGUoYjRxMTMsIGN3aWR0aCA9IGMoMSwxKSkgJT4lDQogIHNldF9oZWFkZXJfbGFiZWxzKGFuc3dlciA9ICJBbnN3ZXIiLCBuID0gIm4iKSAlPiUNCiAgdGhlbWVfemVicmEoKQ0KfQ0KYGBgDQoNCklzIHJlcHJvZHVjaWJsZSBkYXRhIGFuYWx5c2lzIHZpYSBjbG91ZCBvZiBpbnRlcmVzdGVkLCBpbiBjYXNlIGl0IGlzIG5vdCB5ZXQgdXNlZD8NCg0KYGBge3J9DQojIFdvdWxkIGNsb3VkIHNvbHV0aW9ucyBmb3IgcmVwcm9kdWNpYmxlIGRhdGEgYW5hbHlzaXMgYmUgb2YgaW50ZXJlc3QsIGluIGNhc2UgdGhleSBhcmUgbm90IHVzZWQgeWV0Pw0KYjRxMTQgPSByZXNfZGF0YSAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDE1KSAlPiUNCiAgc2VsZWN0KGFuc3dlcikgJT4lDQogIG5hLm9taXQoKSAlPiUNCiAgY291bnQoYW5zd2VyKQ0KDQppZiAoa25pdHI6OmlzX2h0bWxfb3V0cHV0KCkpIHsNCiAgZGF0YXRhYmxlKGI0cTE0KQ0KfSBlbHNlIHsNCiAgZmxleHRhYmxlKGI0cTE0LCBjd2lkdGggPSBjKDEsMSkpICU+JQ0KICBzZXRfaGVhZGVyX2xhYmVscyhhbnN3ZXIgPSAiQW5zd2VyIiwgbiA9ICJuIikgJT4lDQogIHRoZW1lX3plYnJhKCkNCn0NCmBgYA0KDQojIyMgRGF0YSBtYW5hZ2VtZW50IHNvZnR3YXJlDQoNCklzIGRhdGEgbWFuYWdlbWVudCBzb2Z0d2FyZSB1c2VkIGFzIHBhcnQgb2YgdGhlIHByb2plY3Q/DQoNCmBgYHtyfQ0KIyBBcmUgZGF0YSBtYW5hZ2VtZW50IHNvbHV0aW9ucyBlbXBsb3llZD8NCmI0cTE1ID0gcmVzX2RhdGEgJT4lDQogIHJlbmFtZShhbnN3ZXIgPSAxNikgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIGNvdW50KGFuc3dlcikNCg0KaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogIGRhdGF0YWJsZShiNHExNSkNCn0gZWxzZSB7DQogIGZsZXh0YWJsZShiNHExNSwgY3dpZHRoID0gYygxLDEpKSAlPiUNCiAgc2V0X2hlYWRlcl9sYWJlbHMoYW5zd2VyID0gIkFuc3dlciIsIG4gPSAibiIpICU+JQ0KICB0aGVtZV96ZWJyYSgpDQp9DQpgYGANCg0KV2hpY2ggZGF0YSBtYW5hZ2VtZW50IHNvbHV0aW9ucyBhcmUgdXNlZD8NCg0KYGBge3J9DQojIFdoaWNoIHNlcnZpY2VzL3NvbHV0aW9ucyBhcmUgdXNlZD8NCmI0cTE2ID0gcmVzX2RhdGEgJT4lDQogIHJlbmFtZShhbnN3ZXIgPSAxNykgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkNCg0KaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogIGRhdGF0YWJsZShiNHExNikNCn0gZWxzZSB7DQogIGZsZXh0YWJsZShiNHExNiwgY3dpZHRoID0gYyg0KSkgJT4lDQogIHNldF9oZWFkZXJfbGFiZWxzKGFuc3dlciA9ICJBbnN3ZXIiKSAlPiUNCiAgdGhlbWVfemVicmEoKQ0KfQ0KYGBgDQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246IHJpZ2h0Ij4NCg0KW1RhYmxlIG9mIGNvbnRlbnRzXSgjaGVhZGVyKQ0KDQo8L2Rpdj4NCiMjIEluZnJhc3RydWN0dXJlDQoNCkFyZSBjbG91ZCBzZXJ2aWNlcyBob3N0ZWQgb24gb3duIG9yIGV4dGVybmFsIGluZnJhc3RydWN0dXJlPw0KDQpgYGB7cn0NCiMgV2hlcmUgZG8gcGFydGljaXBhbnRzIGhvc3QgdGhlaXIgY2xvdWQgc2VydmljZXM/DQpiNXExID0gcmVzX2luZnJhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMikgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkgJT4lDQogIGNvdW50KGFuc3dlcikNCg0KIyBtYWtlIGJhciBwbG90DQpwbG90NV8xIDwtIGdncGxvdChiNXExLCBhZXMoeD1hbnN3ZXIsIHk9biwgZmlsbCA9IGFuc3dlcikpICsNCiAgZ2VvbV9iYXIoY29sb3IgPSAiYmxhY2siLCBzdGF0ID0gImlkZW50aXR5IikgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoZmlsbCA9ICJIb3N0aW5nIG9mIGNsb3VkIHNlcnZpY2VzIiwgeSA9ICJjb3VudCIsIHggPSAiSG9zdGluZyBvZiBjbG91ZCBzZXJ2aWNlcyIpDQoNCnBsb3Q1XzENCg0KYGBgDQoqKkZpZ3VyZSA3OioqDQoNCldoaWNoIGluZnJhc3RydWN0dXJlIGlzIHVzZWQgZm9yIGhvc3RpbmcgY2xvdWQgc2VydmljZXM/DQoNCmBgYHtyfQ0KIyBXaGljaCBpbmZyYXN0cnVjdHVyZSBpcyB1c2VkIGV4YWN0bHk/DQpiNXEyID0gcmVzX2luZnJhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMykgJT4lDQogIHNlbGVjdChhbnN3ZXIpICU+JQ0KICBuYS5vbWl0KCkNCg0KI2I1cTIkYW5zd2VyDQoNCiMgbWFudWFsIHN1bW1hcnkgb2YgYW5zd2VyczoNCkluZnJhc3RydWN0dXJlIDwtIGMoImRlLk5CSSBjbG91ZCIsICJhY2FkZW1pYyBjb21wdXRlIGNlbnRyZXMgKE9wZW5TdGFjaykiLCAiYWNhZGVtaWMgY29tcHV0ZSBjZW50cmVzIChrdWJlcm5ldGVzKSIsICJhY2FkZW1pYyBjb21wdXRlIGNlbnRyZXMgKHVuZGVmaW5lZCkiLCAiY29tbWVyY2lhbCBwcm92aWRlcnMiLCAiY2xvV00iLCAiR2FsYXh5IEVVIiwgIlZNd2FyZSIpDQpuIDwtIGMoMTMsIDMsIDIsIDYsIDIsIDEsIDEsIDEpDQoNCnRhYjVfMV9kYXRhIDwtIGRhdGEuZnJhbWUoSW5mcmFzdHJ1Y3R1cmUsIG4pDQoNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkgew0KICBkYXRhdGFibGUodGFiNV8xX2RhdGEpDQp9IGVsc2Ugew0KICBmbGV4dGFibGUodGFiNV8xX2RhdGEsIGN3aWR0aCA9IGMoMywgMSkpICU+JQ0KICB0aGVtZV96ZWJyYSgpDQp9DQpgYGANCg0KT3ZlcnZpZXcgb2YgdGhlIHVzYWdlIG9mIHNlbGVjdGVkIHRlY2hub2xvZ2llcyBhbW9uZyBwYXJ0aWNpcGFudHM6DQoNCmBgYHtyfQ0KIyMgc3VtbWFyeSBvZiBlbXBsb3llZCB0ZWNobm9sb2dpZXMNCiMgZ3B1IHJlc291cmNlcw0KYjVxMyA9IHJlc19pbmZyYSAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDQpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgY291bnQoYW5zd2VyKSAlPiUNCiAgbXV0YXRlKHBlcmMgPSByb3VuZChgbmAgLyBzdW0oYG5gKSAqIDEwMCksIDEpICU+JQ0KICBtdXRhdGUoY3N1bSA9IHJldihjdW1zdW0ocmV2KHBlcmMpKSksIA0KICAgICAgICAgcG9zID0gcGVyYy8yICsgbGVhZChjc3VtLCAxKSwNCiAgICAgICAgIHBvcyA9IGlmX2Vsc2UoaXMubmEocG9zKSwgcGVyYy8yLCBwb3MpKQ0KDQpwbG90NV8yYSA8LSBnZ3Bsb3QoYjVxMywgYWVzKHggPSAiIiwgeSA9IHBlcmMsIGZpbGwgPSBhbnN3ZXIpKSArDQogIGdlb21fY29sKHdpZHRoID0gMSwgY29sb3IgPSAiYmxhY2siKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIGRpcmVjdGlvbiA9IC0xKSArDQogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IGI1cTMsDQogICAgICAgICAgICAgICAgICAgYWVzKHkgPSBwb3MsIGxhYmVsID0gcGFzdGUwKHBlcmMsICIlIikpLA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSA0LjUsIG51ZGdlX3ggPSAxLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkFuc3dlcjogIikpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgbGFicyh0aXRsZSA9ICJHUFUgY2xvdWQgY29tcHV0aW5nIHJlc291cmNlcyIpDQoNCiMgY29udGFpbmVyaXphdGlvbiBzb2Z0d2FyZQ0KYjVxNCA9IHJlc19pbmZyYSAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDUpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgY291bnQoYW5zd2VyKSAlPiUNCiAgbXV0YXRlKHBlcmMgPSByb3VuZChgbmAgLyBzdW0oYG5gKSAqIDEwMCksIDEpICU+JQ0KICBtdXRhdGUoY3N1bSA9IHJldihjdW1zdW0ocmV2KHBlcmMpKSksIA0KICAgICAgICAgcG9zID0gcGVyYy8yICsgbGVhZChjc3VtLCAxKSwNCiAgICAgICAgIHBvcyA9IGlmX2Vsc2UoaXMubmEocG9zKSwgcGVyYy8yLCBwb3MpKQ0KDQpwbG90NV8yYiA8LSBnZ3Bsb3QoYjVxNCwgYWVzKHggPSAiIiwgeSA9IHBlcmMsIGZpbGwgPSBhbnN3ZXIpKSArDQogIGdlb21fY29sKHdpZHRoID0gMSwgY29sb3IgPSAiYmxhY2siKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIGRpcmVjdGlvbiA9IC0xKSArDQogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IGI1cTQsDQogICAgICAgICAgICAgICAgICAgYWVzKHkgPSBwb3MsIGxhYmVsID0gcGFzdGUwKHBlcmMsICIlIikpLA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSA0LjUsIG51ZGdlX3ggPSAxLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkFuc3dlcjogIikpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgbGFicyh0aXRsZSA9ICJDb250YWluZXJpemF0aW9uIHNvZnR3YXJlIikNCg0KIyBjb250YWluZXIgb3JjaGVzdHJhdGlvbiBzb2Z0d2FyZQ0KYjVxNSA9IHJlc19pbmZyYSAlPiUNCiAgcmVuYW1lKGFuc3dlciA9IDgpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgY291bnQoYW5zd2VyKSAlPiUNCiAgbXV0YXRlKHBlcmMgPSByb3VuZChgbmAgLyBzdW0oYG5gKSAqIDEwMCksIDEpICU+JQ0KICBtdXRhdGUoY3N1bSA9IHJldihjdW1zdW0ocmV2KHBlcmMpKSksIA0KICAgICAgICAgcG9zID0gcGVyYy8yICsgbGVhZChjc3VtLCAxKSwNCiAgICAgICAgIHBvcyA9IGlmX2Vsc2UoaXMubmEocG9zKSwgcGVyYy8yLCBwb3MpKQ0KDQpwbG90NV8yYyA8LSBnZ3Bsb3QoYjVxNSwgYWVzKHggPSAiIiwgeSA9IHBlcmMsIGZpbGwgPSBhbnN3ZXIpKSArDQogIGdlb21fY29sKHdpZHRoID0gMSwgY29sb3IgPSAiYmxhY2siKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIGRpcmVjdGlvbiA9IC0xKSArDQogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IGI1cTUsDQogICAgICAgICAgICAgICAgICAgYWVzKHkgPSBwb3MsIGxhYmVsID0gcGFzdGUwKHBlcmMsICIlIikpLA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSA0LjUsIG51ZGdlX3ggPSAxLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkFuc3dlcjogIikpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgbGFicyh0aXRsZSA9ICJDb250YWluZXIgb3JjaGVzdHJhdGlvbiBzb2Z0d2FyZSIpDQoNCiMgV29ya2Zsb3cgbWFuYWdlbWVudCBzeXN0ZW1zDQpiNXE2ID0gcmVzX2luZnJhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMTEpICU+JQ0KICBzZWxlY3QoYW5zd2VyKSAlPiUNCiAgY291bnQoYW5zd2VyKSAlPiUNCiAgbXV0YXRlKHBlcmMgPSByb3VuZChgbmAgLyBzdW0oYG5gKSAqIDEwMCksIDEpICU+JQ0KICBtdXRhdGUoY3N1bSA9IHJldihjdW1zdW0ocmV2KHBlcmMpKSksIA0KICAgICAgICAgcG9zID0gcGVyYy8yICsgbGVhZChjc3VtLCAxKSwNCiAgICAgICAgIHBvcyA9IGlmX2Vsc2UoaXMubmEocG9zKSwgcGVyYy8yLCBwb3MpKQ0KDQpwbG90NV8yZCA8LSBnZ3Bsb3QoYjVxNiwgYWVzKHggPSAiIiwgeSA9IHBlcmMsIGZpbGwgPSBhbnN3ZXIpKSArDQogIGdlb21fY29sKHdpZHRoID0gMSwgY29sb3IgPSAiYmxhY2siKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIsIGRpcmVjdGlvbiA9IC0xKSArDQogIGdlb21fbGFiZWxfcmVwZWwoZGF0YSA9IGI1cTYsDQogICAgICAgICAgICAgICAgICAgYWVzKHkgPSBwb3MsIGxhYmVsID0gcGFzdGUwKHBlcmMsICIlIikpLA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSA0LjUsIG51ZGdlX3ggPSAxLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkFuc3dlcjogIikpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgbGFicyh0aXRsZSA9ICJXb3JrZmxvdyBtYW5hZ2VtZW50IHN5c3RlbXMiKQ0KDQojIG1ha2UgdW5pZmllZCBwbG90DQpncmlkLmFycmFuZ2UocGxvdDVfMmEsIHBsb3Q1XzJiLCBwbG90NV8yYywgcGxvdDVfMmQsIG5jb2w9MikNCmBgYA0KKipGaWd1cmUgODoqKg0KDQpFbXBsb3llZCBjb250YWluZXJpemF0aW9uIHNvZnR3YXJlOg0KDQpgYGB7cn0NCiMgY29sbGVjdCBhbnN3ZXJzIGZvciBjb250YWluZXJpemF0aW9uIHNvZnR3YXJlDQpiNXE3ID0gcmVzX2luZnJhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gNikgJT4lDQogIHNlbGVjdChhbnN3ZXIpDQoNCiMgbWFudWFsIHN1bW1hcnkNCkNvbnRhaW5lcml6YXRpb25fc29mdHdhcmUgPC0gYygiZG9ja2VyIiwgIlNpbmd1bGFyaXR5IiwgImRvY2tlci1jb21wb3NlIiwgIkFwcHRhaW5lciIsICJLdWJlcm1hdGljIiwgIkNoYXJsaWVDbG91ZCIpDQpuIDwtIGMoMjQsNywzLDIsMSwxKQ0KDQp0YWI1XzJfZGF0YSA8LSBkYXRhLmZyYW1lKENvbnRhaW5lcml6YXRpb25fc29mdHdhcmUsIG4pDQoNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkgew0KICBkYXRhdGFibGUodGFiNV8yX2RhdGEpDQp9IGVsc2Ugew0KICBmbGV4dGFibGUodGFiNV8yX2RhdGEsIGN3aWR0aCA9IGMoMiwgMSkpICU+JQ0KICBzZXRfaGVhZGVyX2xhYmVscyhDb250YWluZXJpemF0aW9uX3NvZnR3YXJlID0gIkNvbnRhaW5lcml6YXRpb24gc29mdHdhcmUiLCBuID0gIm4iKSAlPiUNCiAgdGhlbWVfemVicmEoKQ0KfQ0KYGBgDQoNCkVtcGxveWVkIGNvbnRhaW5lciBvcmNoZXN0cmF0aW9uIHNvZnR3YXJlOg0KDQpgYGB7cn0NCiMgY29sbGVjdCBhbnN3ZXJzIGZvciBjb250YWluZXJpemF0aW9uIHNvZnR3YXJlDQpiNXE4ID0gcmVzX2luZnJhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gOSkgJT4lDQogIHNlbGVjdChhbnN3ZXIpDQoNCiMgbWFudWFsIHN1bW1hcnkNCkNvbnRhaW5lcl9vcmNoZXN0cmF0aW9uX3NvZnR3YXJlIDwtIGMoIkt1YmVybmV0ZXMiLCJkb2NrZXIgc3dhcm0iLCJLdWJlcm1hdGljIiwiUmFuY2hlciIsIlNMVVJNIikNCm4gPC0gYyg4LDIsMSwxLDEpDQoNCnRhYjVfM19kYXRhIDwtIGRhdGEuZnJhbWUoQ29udGFpbmVyX29yY2hlc3RyYXRpb25fc29mdHdhcmUsIG4pDQoNCmlmIChrbml0cjo6aXNfaHRtbF9vdXRwdXQoKSkgew0KICBkYXRhdGFibGUodGFiNV8zX2RhdGEpDQp9IGVsc2Ugew0KICBmbGV4dGFibGUodGFiNV8zX2RhdGEsIGN3aWR0aCA9IGMoMiwgMSkpICU+JQ0KICBzZXRfaGVhZGVyX2xhYmVscyhDb250YWluZXJfb3JjaGVzdHJhdGlvbl9zb2Z0d2FyZSA9ICJDb250YWluZXIgb3JjaGVzdHJhdGlvbiBzb2Z0d2FyZSIsIG4gPSAibiIpICU+JQ0KICB0aGVtZV96ZWJyYSgpDQp9DQpgYGANCg0KRW1wbG95ZWQgd29ya2Zsb3cgbWFuYWdlbWVudCBzeXN0ZW1zOg0KDQpgYGB7cn0NCiMgY29sbGVjdCBhbnN3ZXJzIGZvciBjb250YWluZXJpemF0aW9uIHNvZnR3YXJlDQpiNXE5ID0gcmVzX2luZnJhICU+JQ0KICByZW5hbWUoYW5zd2VyID0gMTIpICU+JQ0KICBzZWxlY3QoYW5zd2VyKQ0KDQojIG1hbnVhbCBzdW1tYXJ5DQpXb3JrZmxvd19tYW5hZ2VtZW50X3N5c3RlbXMgPC0gYygibmV4dGZsb3ciLCJHYWxheHkiLCJzbmFrZW1ha2UiLCJDb21tb24gd29ya2Zsb3cgbGFuZ3VhZ2UgKENXTCkiLCJVTklDT1JFIiwiUC1HcmFkZSIsIldlYkxpY2h0IiwidGFyZ2V0cyAoUikiLCJBcGFjaGUgYWlyZmxvdyIpDQpuIDwtIGMoMTUsNiw0LDIsMiwyLDEsMSwxKQ0KDQp0YWI1XzRfZGF0YSA8LSBkYXRhLmZyYW1lKFdvcmtmbG93X21hbmFnZW1lbnRfc3lzdGVtcywgbikNCg0KaWYgKGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7DQogIGRhdGF0YWJsZSh0YWI1XzRfZGF0YSkNCn0gZWxzZSB7DQogIGZsZXh0YWJsZSh0YWI1XzRfZGF0YSwgY3dpZHRoID0gYygyLCAxKSkgJT4lDQogIHNldF9oZWFkZXJfbGFiZWxzKFdvcmtmbG93X21hbmFnZW1lbnRfc3lzdGVtcyA9ICJXb3JrZmxvdyBtYW5hZ2VtZW50IHN5c3RlbSIsIG4gPSAibiIpICU+JQ0KICB0aGVtZV96ZWJyYSgpDQp9DQpgYGANCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjogcmlnaHQiPg0KDQpbVGFibGUgb2YgY29udGVudHNdKCNoZWFkZXIpDQoNCjwvZGl2Pg0KIyBEaXNjdXNzaW9uDQoNCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjogcmlnaHQiPg0KDQpbVGFibGUgb2YgY29udGVudHNdKCNoZWFkZXIpDQoNCjwvZGl2Pg0KDQojIFN1cHBsZW1lbnRhcnkgSW5mb3JtYXRpb24NCg0KIyMgUiBTZXNzaW9uIEluZm8NCg0KYGBge3J9DQpzZXNzaW9uSW5mbygpDQpgYGANCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjogcmlnaHQiPg0KDQpbVGFibGUgb2YgY29udGVudHNdKCNoZWFkZXIpDQoNCjwvZGl2Pg0KDQojIExpbmtzIGFuZCByZWZlcmVuY2Vz