The main benefit of studying community assembly, and factors that impact it, is to further understand the connection of community diversity to ecosystem functionality, which is crucial in upkeeping ecosystems. With spatial distance shown to be a significant factor in community assembly processes, it is sensible to explore the waterbodies of the Lunz study site, which consists of various environments with different conditions, and includes three springs, seven creeks, four groundwater wells, a pond, a hyporheic spring, and three lakes. The connectivity is presumed to be hindered at the middle point of the catchment area, the Middle Lake.

1 Package loading

library(FEAST) # for source tracking
## Warning: replacing previous import 'dplyr::combine' by 'gridExtra::combine'
## when loading 'FEAST'
library(tidyverse)
library(vegan)
library(FSA) # for dunn post-hoc test
library(caret) 
library(broom)
library(patchwork) # for combining plots into 1
library(ggfortify)
library(pairwiseAdonis) # for permanova post-hoc

From every sample, DNA was extracted and used for 16S rRNA gene amplicon sequencing. Amplicon sequencing and bioinformatic processing of the raw sequence data for the inference of amplicon sequence variants (ASV) using DADA2 was done, as well as other processing of organelles and mitochondria.

2 Load data

# load metadata
metadata <- read.csv("~/faks/Ecology and Ecosystems/MEC-8 (Specific research project)/data/metadata_Lunz_revised.csv", 
                     row.names = 1)

# load asv table
asv_table <- read.csv("~/faks/Ecology and Ecosystems/MEC-8 (Specific research project)/data/asv_table.csv", row.names=1)

# identifier need to be identical between asv_table and metadata
identical(rownames(metadata), colnames(asv_table))
# if there is some that are different use setdiff(rownames(metadata), colnames(asv_table)) to see which

# data on sources/sinks
feast_metadata <- read.csv("~/faks/Ecology and Ecosystems/MEC-8 (Specific research project)/data/feast_metadata.csv", row.names=1)
# identifiers for sources have to be unique - source 1 needs to be Source1_1, Source1_2, ... )
# SampleID column need to be  rownames

3 FEAST

FEAST - the fast expectation-maximization was used, as a more computational efficient and shorter alternative to SourceTracker.

Prepare the data for FEAST.

# classes of datasets

# feast_metadata should be a data.frame
class(feast_metadata)

#asv should be matrix and each column an ineger in order to perform feast
feast_asv <- as.matrix(asv_table)                # matrix as a whole
    for(i in 1:ncol(feast_asv)){                 # each column as integer
                    feast_asv[, i] <- as.integer(feast_asv[, i])
}


# whole  table should be a matrix
class(feast_asv)

# individual column should be integer
class(feast_asv[, 1])



# final step - form needs to be as with vegan (sites rows, species columns)
feast_asv <- t(feast_asv)
feast_asv[1:10, 1:5]


#to remove from environment
rm(i) 

Perform FEAST. It exports the results and later on needs to be imported again.

The metadata table has three columns (i.e., ‘Env’, ‘SourceSink’, ‘id’). The first column is a description of the sampled environment (e.g., sample names), the second column indicates if this sample is a source or a sink (can take the value ‘Source’ or ‘Sink’). The third column is the Sink-Source id.

When using multiple sinks, only the rows with ‘SourceSink’ = Sink need an id (between 1 - number of sinks in the data), the sources’ ids are blank.

feast_output <- FEAST(C = feast_asv,              # transposed asv_table
                      metadata = feast_metadata,  # sink or source information
                      different_sources_flag = 0, # 0 if sources are not assigned to different sinks
                      EM_iterations = 1000,       # number of iterations
                      dir_path = "C:/Users/Angela Cukusic/Documents/faks/Ecology and Ecosystems/MEC-8 (Specific research project)/Results", 
                      outfile = "feast_results")  # prefix for saving output file

# COVERAGE should be included in the command if we want to indicate the rarefaction depth
#we got an output, import it now
feast_table <- read.table("C:/Users/Angela Cukusic/Documents/faks/Ecology and Ecosystems/MEC-8 (Specific research project)/Results/feast_results_source_contributions_matrix.txt", 
                          sep = "\t", row.names = 1)

3.1 Raw contribution to plottable data

To get an overview of the total contribution of each source (i.e. groups of samples) to the different sink we have to clean it.

# feast_output is of class "list"
# we want to make it a matrix

# 1. make a new vector with source types (and it is "character")
sources <- paste("source", c(1:8), sep = "")


# 2. make empty matrix with nrow = number of SINKS (5), 
# and ncol = number of possible sources (20+ samples are designated to 1-8 sources)
source_contributions <- matrix(NA,                        # empty
                               nrow = nrow(feast_table),  # 5 sinks
                               ncol = length(sources))    # n sources

# 3. fill matrix 
for(i in 1:length(sources)){    # for each source add contribution 
  source_contributions[, i] <- rowSums(feast_table[,      # sum up contributions for all 5 rows
                                      grepl(sources[i], colnames(feast_table))]) 
                                                          # of only the columns which have sourceX in name
}

# 4. we added contributions assigned to each of 8 sources, now add from unknown sources
source_contributions <- cbind(source_contributions, feast_table$Unknown)


# 5. check if all contributuons for individual sink amount to 1
rowSums(source_contributions) 


# 6. convert to data frame and bring back rownames and colnames
source_contributions <- as.data.frame(source_contributions)
colnames(source_contributions) <- c(sources, "unknown") # col
source_contributions <- source_contributions %>%        # row
  mutate(sample_id = rownames(feast_table), .before = 1) 


#  final clean up of environment
rm( sources, i)

3.2 Plot source contribution

source_contributions %>% 

  pivot_longer(cols = -sample_id, names_to = "sources", values_to = "contributions") %>% 
  mutate(sources = as.factor(sources))     %>% 
  
  
# find  relative abundances for each date in each water kind (well/pump/surf)
  group_by(sample_id) %>%
  mutate(rel_cont = contributions / sum(contributions) * 100) %>%
  ungroup() %>%
  
# plotting
  ggplot(aes(x = sample_id, y = rel_cont, fill = sources)) +
  geom_bar(stat = "identity") +
  
# labelling   
  geom_text(aes(label =  
                  # label if % is big enough
                  ifelse(rel_cont > 2, 
                  # if yes then  paste, if no then empty ""
                  paste0(round(rel_cont, 4) , "%"), "" )  ),
            # how to position it
            position = position_stack(vjust = 0.5), size = 4) +

# theme  
  theme(legend.position = "none",
        axis.ticks.y = element_blank(),
        axis.text.y = element_blank(),
        axis.title.y = element_blank()) +
  theme_classic() + 
  scale_fill_brewer(palette = "Set1") +
  labs(x= "Sinks", y="Relative contributions %", fill = "Sources") +
  scale_x_discrete(labels = c("Untersee \n(31m)", 
                              "Untersee \n(5m)", 
                              "Untersee - \nnear OSB inflow", 
                              "Untersee - \nat OSB \ninflow", 
                              "Sediment: \nUntersee - \nat OSB \ninflow")) 

From five sink samples identified in this study, four were water samples, and one a sediment sample. Each sink had a substantial portion of microbes of unknown origin.

Additional to that, another visible trend is water samples being traced back to Source 1 (surface waters), with non-existent or minimal portion of Source 2 related microbes (surface waters’ sediment and biofilm samples, see Fig.2.).

The sediment sink, on the other hand, showed no influence of Source 1 on its composition, but had a high Source 2 origin. Water sinks contained more ASVs not found in any of the sources than the sediment sink.

feast_table %>% 
  rownames_to_column("sample_id") %>% 
# find the two sinks in question  
  filter(sample_id %in% c("OSB_in_LUS_inflow_LUS_at_OSB_inflow",
                          "OSB_in_LUS_sed_LUS_sediment")) %>% 
  
# find the individual samples from source 6
  select( "sample_id",  contains("source6")) %>% 
# remove the last part of names, which says "source6"  
  rename_all(~str_remove(., ".{10}$")) %>% 
  
  pivot_longer(cols = -sample_id, names_to = "sources", values_to = "contributions") %>% 
  mutate(sources = as.factor(sources))     %>% 
  
  
# find  relative abundances for each date in each water kind (well/pump/surf)
  group_by(sample_id) %>%
  mutate(rel_cont = contributions / sum(contributions) * 100) %>%
  ungroup() %>%
  
# plotting
  
  ggplot(aes(x = sample_id, y = rel_cont, fill = sources)) +
  geom_bar(stat = "identity", color = "black") +
  
# labelling   
  geom_text(aes(label =  
                  # label if % is big enough
                  ifelse(rel_cont > 2, 
                  # if yes then  paste, if no then empty ""
                  paste0(round(rel_cont, 4) , "%"), "" )  ),
            # how to position it
            position = position_stack(vjust = 0.5), size = 4) +

# theme  
  theme(legend.position = "none",
        axis.ticks.y = element_blank(),
        axis.text.y = element_blank(),
        axis.title.y = element_blank()) +
  theme_classic() + 
  labs(x= "Sinks", y="Relative contributions %", fill = "Sources") +
  scale_x_discrete(labels = c("Untersee - \nat OSB \ninflow", 
                              "Sediment: \nUntersee - \nat OSB \ninflow")) +
  scale_fill_manual(values = c( "#006400", "#FFD700", "lightblue", "#FFD700",
                                "lightblue", "#006400", "lightblue" ))

Even though the two sinks at the inflow both had ~10% of Source 6 microbes (which was two locations - both sediment and water), it seems that more detailed look gives more insight that sample type is a better predictor of contribution than location is.

Result: water sink was more influenced by water samples communities, while sediment sink contained almost exclusively microbes from spring sediments and spring biofilms.

4 Sample type distribution

metadata_type <- metadata %>% 
                 rownames_to_column("sources") %>% 
                 select("sources", "type_III") %>% 
                 mutate(type_III = case_when(
                 # assign categories  
                   type_III %in% c("Creek", "Hyporheic",
                                   "Pond", "Lake", "Inflow") ~ "Surface", 
                            TRUE ~ type_III)) 




feast_table %>% 
  rownames_to_column("sink_id") %>% 
# rename the columns so that they can be connected to the metadata (type info)  
  rename_all(~str_remove(., ".{10}$")) %>% 
  pivot_longer(cols = - sink_id, names_to = "sources", values_to = "contributions") %>% 
# filter out contributions from unknow sources
  filter(sources != "Unknown") %>% 
# join with metadata
  left_join(., metadata_type, by = "sources") %>% 
  filter(type_III != "NA") %>% 
  filter( contributions < 0.05) %>% 
# plot
  ggplot(aes(x= type_III, y= contributions)) + 
  geom_boxplot(aes(fill = sink_id) ) +
  theme_linedraw() +
  scale_fill_manual(labels=c("Untersee (31m)", 
                             "Untersee (5m)",
                             "Untersee (near inflow)", 
                             "Untersee (at inflow)", 
                             "Sediment (at inflow)"), 
                    values=c("#acc7d9", "#8bb0ca","#5180a2","#3e647d","#d8b365")) +
  theme(legend.position=c(0.3,0.8), 
        legend.title = element_blank(), 
        legend.text = element_text(size = 14), 
        legend.background = element_rect(), 
        legend.box.background  =   element_rect(color = "gray")) +
  labs(y = "Contributions", x= "Sample type") + 
  scale_x_discrete(labels = c("Biofilm", "Ground water", "Sediment", 
                              "Soil", "Spring water", "Surface water") )

Surface waters contributed to all water sinks, but their effect on the sediment of the sink was minimal. Samples that did contribute to sediment sink are biofilm, sediment and soil source samples. Additional to contributing to the sediment sink, biofilm samples also had an impact on the community at the inflow of the Lower Lake. Springwater samples were the biggest contributor to the inflow, and had an impact on the microbial assembly of the Lower Lake at its 31-meter depth.

5 Spatial distribution

metadata_rank <- metadata %>% 
                 rownames_to_column("sources") %>% 
                 select("sources", "rank") %>% 
                 filter(rank != "sink")

feast_table %>% 
  rownames_to_column("sink_id") %>% 
# rename the columns so that they can be connected to the metadata (rank info)  
  rename_all(~str_remove(., ".{10}$")) %>% 
  pivot_longer(cols = - sink_id, names_to = "sources", values_to = "contributions") %>% 
# filter out contributions from unknow sources
  filter(sources != "Unknown") %>% 
# join with metadata
  left_join(., metadata_rank, by = "sources") %>% 
  filter(rank != "NA") %>% 
# plot
  ggplot(aes(x= rank, y= contributions)) + 
  geom_boxplot( fill = "violet") +
  facet_wrap(~sink_id, scales = "free_y",  labeller = 
               as_labeller( c("LUS_dp_31m_LUS_31m" = "Untersee (31m)",
                              "LUS_dp_5m_LUS_5m" = "Untersee (5m)",
                              "LUS_in_OSB_LUS_near_OSB_inflow" = "Untersee (near inflow)",
                              "OSB_in_LUS_inflow_LUS_at_OSB_inflow" = "Untersee (at inflow)",
                              "OSB_in_LUS_sed_LUS_sediment" = "Sediment (at inflow)" ))) +
  theme_linedraw() + 
  labs(y = "Contributions", x= "Ranked by spatial distance ")

We hypothesized that a substantial effect of passive dispersal of microorganisms on the composition of microbial communities in the lake sinks should result in significantly declining contributions of sources with increasing spatial distance to the main lake (i.e. distance ranks since data on exact spatial distances were not available).

Tackling this hypothesis, we did not find a significant correlation between spatial distance and sink contribution. None of the sinks followed the presumed trend of rank 1 having the highest sink contribution and rank 8 the lowest, nor was there a difference between the ranks before the connectivity barrier and after the barrier. The rank 6 is upstream of the Middle lake, which is the presumed barrier.

6 Pre-processing for community analysis

We need to account for the uneven sequencing depth.

# number of reads per sample
asv_table %>% colSums() %>% summary() 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    3710    3710    3710    3710    3710    3710

Considering all samples have the same number of reads the dataset has clearly already been rarefied by Lucas before giving it to me.

7 Alpha diversity

shannondiv <- vegan::diversity(t(asv_table))
# recalculating it as the effective number of species to be more comparable across studies.
ens <- exp(shannondiv) %>% as.data.frame() %>% rownames_to_column("sample_id") %>% 
  rename("diversity" = ".")

diversity_data <- specnumber(t(asv_table)) %>% as.data.frame() %>% rownames_to_column("sample_id") %>% 
  rename("richness" = ".") %>% inner_join(., ens, by ="sample_id" )

# we will plot diversity by source so make clean categorization here
feast_metadata %>% 
  # remove last two strings
  mutate(Env = str_remove(Env, ".{2}$")) %>% 
  # where SourceSink column is a source keep the value from the Env column
  mutate(Source_category = case_when(SourceSink == "Source" ~ Env,
  # otherwise keep the value from SourceSink column                                   
                                     TRUE ~ SourceSink) ) %>% 
  # some trouble with source 3
  mutate(Source_category = case_when(Source_category %in% c("source3", "source3_") ~ "source3",
                                     TRUE ~Source_category)) %>% 
  
  rownames_to_column("sample_id")  %>% 
  select("sample_id", "Source_category") %>% 
  mutate(Source_category = as.factor(Source_category)) %>% 
  # we now have clean category and can connect it to the diversity data
  inner_join(., diversity_data,   by = "sample_id") %>% 
  select(-sample_id) %>% 
  
  #pivot longer so we can facet
  pivot_longer(cols = -Source_category, names_to = "measure", values_to = "values") %>% 
  
  # plot
  ggplot( aes(x = Source_category, y = values)) +
  #stat_boxplot(geom ='errorbar') + 
  geom_boxplot(fill = "violet") +
  theme_linedraw()+
  coord_flip() + 
  facet_wrap(~measure, scales = "free",  labeller = 
               as_labeller( c("diversity" = "Shannon's diversity index", 
                              "richness" = "Richness") ) )+
  theme(legend.position = "none",
        axis.title=element_text(size=14,face="bold"),
        axis.text.y = element_text(size=10,face="bold"),
        strip.text = element_text(size = 14)) +
  labs( x = "Source category",
       y = NULL) +
  scale_x_discrete(labels = c("Sink",  "Source 1", "Source 2", "Source 3", "Source 4", 
                               "Source 5", "Source 6",  "Source 7",  "Source 8"))  

Richness of the sinks was the lowest compared to source richness. Sources 7, and 8, which have a direct inflow to the sinks, had the highest richness. Source 1, which makes a big contribution to sink communities had higher richness than the sinks it contributed to.

Sink evenness was lower than evenness of sources. Species distribution of the sink leans towards a few very dominant ASVs and many rare ones, indicating possible harder environmental conditions or bigger competitiveness in sink. Source 3, with its soil samples, had high evenness. Source 4 (groundwater) had slightly lower evenness and richness in comparison to other sources.

Test it:

# 1. the same data manipulation as above
feast_metadata %>% 
  mutate(Env = str_remove(Env, ".{2}$")) %>% 
  mutate(Source_category = case_when(SourceSink == "Source" ~ Env,                           
                                     TRUE ~ SourceSink) ) %>% 
  mutate(Source_category = case_when(Source_category %in% c("source3", "source3_") ~ "source3",
                                     TRUE ~Source_category)) %>% 
  
  rownames_to_column("sample_id")  %>% 
  select("sample_id", "Source_category") %>% 
  mutate(Source_category = as.factor(Source_category)) %>% 
  inner_join(., diversity_data,   by = "sample_id") %>% 
  select(-sample_id) -> data_for_alpha


# 2. perform ANOVA/ kruskal-wallis

# 1. assumption of ANOVA: Normal distribution: 
# Each population to be compared should be normally distributed 
# (NOT THE ENTIRE DATASET).
shapiro.test (  data_for_alpha[which(data_for_alpha$Source_category == "source1"), "diversity"] ) # NOT ND
shapiro.test (  data_for_alpha[which(data_for_alpha$Source_category == "source2"), "diversity"] ) # ND
shapiro.test (  data_for_alpha[which(data_for_alpha$Source_category == "source3"), "diversity"] ) # ND
shapiro.test (  data_for_alpha[which(data_for_alpha$Source_category == "source4"), "diversity"] ) # NOT ND
shapiro.test (  data_for_alpha[which(data_for_alpha$Source_category == "source5"), "diversity"] ) # NOT ND
shapiro.test (  data_for_alpha[which(data_for_alpha$Source_category == "source6"), "diversity"] ) # ND
# source 7 is too small sample size to perform the test  
shapiro.test (  data_for_alpha[which(data_for_alpha$Source_category == "source8"), "diversity"] ) # ND
shapiro.test (  data_for_alpha[which(data_for_alpha$Source_category == "Sink"), "diversity"] ) # ND

# A: would be better to do a non-parametric test


## 2. assumption of ANOVA: Homogeneity of variance: 
## Variance in the populations compared should be the same/similar. 
bartlett.test ( diversity ~ Source_category, data= data_for_alpha )
# assumption met


# 3. test
kruskal.test (diversity ~ Source_category, data= data_for_alpha) 
# 4. post-hoc
FSA::dunnTest(diversity ~ Source_category, data= data_for_alpha)
## Dunn (1964) Kruskal-Wallis multiple comparison
##   p-values adjusted with the Holm method.

Even though one assumption is met (hom.var.) we should not use ANOVA - the assumption of homogeneity of variance is an extension of the assumption of normality. It would not be feasible to compare a skewed distribution in one group to a normal distribution in another group, even if they have comparable variances!

Kruskal-Wallis test confirms differences in shannon’s index. We do post-hoc diagnosing to see which groups are different with a Dunn test. The difference which is statistically sound is the diversity levels between the source 3 samples and the Sink, after adjusting the p-value.

Since source 3 consists of soil samples, it is not unexpected that it would have higher diversity.

8 Beta diversity

bc_diss <- vegdist(t(asv_table), method = "bray")
nmds <- metaMDS(bc_diss)


# make palette for plotting
pal = c("green4", "navy", "orange", "brown", "blue", "lightblue")


# lets plot an nmds where the color is sample type, shape is source sink
as.data.frame(nmds$points) %>% 
  cbind(data_for_alpha$Source_category, metadata_type$type_III) %>% 
  rename("source_cat" = "data_for_alpha$Source_category",
         "type" = "metadata_type$type_III") %>% 
  mutate(source_cat = case_when(source_cat == "Sink" ~ "sink",
                                TRUE ~ "source")) ->  data_for_nmds
  
# plot 
data_for_nmds %>%   
  ggplot(aes(x = MDS1, y = MDS2)) +
  geom_point(aes(fill = type, color = type, 
                 shape= source_cat), 
             size = 5, stroke=1, alpha = 0.6) +
# customizing the plot  
  scale_fill_manual(values =  pal) + 
  scale_color_manual(values = pal) +
  scale_shape_manual(values = c(21,23)) +
  
  theme_linedraw() +
  annotate(geom="text",x=-1.4, y=1.5, label="stress =", color="black") +   
  annotate(geom="text", x=-1.1, y=1.5, label=round(nmds$stress,4),
           color="black") +
  
  #stat_ellipse(aes(colour = type), linewidth = 0.3) + 
  #stat_ellipse(aes(fill = type), geom="polygon",level=0.95,alpha=0.04) +
  
  theme(legend.background = element_blank(),
        legend.box.background = element_rect(colour = "gray")) +
  labs(color = "Water \ntype", shape = "Source") +
  guides(fill = FALSE) +
  geom_vline(xintercept = c(0), color = "grey70", linetype = 2) +
  geom_hline(yintercept = c(0), color = "grey70", linetype = 2) -> plot_nmds

There was clear grouping of soil and sediment communities. Surface water, spring water and biofilm communities were more spread out, and more dissimilar to soil than to sediment communities.

Out of five sinks, four water and one sediment sink, the most similar to sediment source samples, in terms of community assembly, was the sediment sink. It is also closer to the soil sources, whereas water sinks communities showed little similarity to soil sources.

plot_nmds

8.1 Test community differences

# test differences in group centroid with adonis (anova version for multivariate statistics)
permanova <- adonis2(t(asv_table) ~ data_for_nmds$type, 
                    method = "bray" , permutations = 999)
permanova # 0.001
pair_res <- pairwiseAdonis::pairwise.adonis2(t(asv_table) ~ type, data = data_for_nmds)
# Spring_vs_Surface, GW_vs_Spring are only one not significantly distinct!!


# test dispersion as an assumption (variance test for multivariate statitics)
disp <- betadisper( vegdist(  t(asv_table), method = "bray" ), data_for_nmds$type) 
anova(disp)
TukeyHSD(disp) 
# Surface-GW have diff dispersions, does not interfere with centroid differences

There is signifiicant difference in communities of different sample type (***). Biofilm, sediment and soil are distinctly different from each other and from surface water, groundwater and spring. Surface water, groundwater and spring are not easily identifiable between themselves.

9 Environmental data

9.1 pca (environmenta variables of water communities)

df_pca <- metadata %>% 
  # we only have measurements for water, not for soil nor sediment 
  filter(type_I == "Water") %>% 
  select(where(is.numeric)) %>% 
  select(-c("filter", # dont need it
            "N_NO2", "P_PO4")) # NAs
 

# remove the highly correlated ones, like internalATP and totalATP
cor_matrix <- cor(df_pca)
highly_correlated <- caret::findCorrelation(cor_matrix, cutoff = 0.9)
df_pca <- df_pca[, -highly_correlated]

# now there is 22 observations and 10 environmental variables
# lets see if any env vars can be packed neatly in PCs
pca_env <- prcomp(df_pca, scale = TRUE)
biplot(pca_env)

# i believe it is beneficial to remove the sample PX_gw since it is a single outlier in almost every variable, and stresses the ordination
pca_env <- prcomp(df_pca[rownames(df_pca) != "PX_gw",], scale = TRUE)


# we need the column for coloring by type, get it from the original metadata
 metadata[rownames(df_pca) != "PX_gw", c(colnames(df_pca), "type_III", "type_I")] %>% 
   # remove the outlier sample, the columns that are highly correlated and soil/sed samples
  filter(type_I == "Water") -> data_for_pca

autoplot(pca_env, data =data_for_pca , 
         colour = 'type_III',
         size=5, loadings=TRUE, 
         loadings.colour="black", 
         loadings.label=TRUE, loadings.label.size=5, 
         loadings.label.colour="black" )+ 
  geom_vline(xintercept = c(0), color = "grey70", linetype = 2) +
  geom_hline(yintercept = c(0), color = "grey70", linetype = 2) +
  geom_point(shape= 21, color = "black", size = 5) + 
  theme_linedraw() +
  geom_vline(xintercept = c(0), color = "grey70", linetype = 2) +
  geom_hline(yintercept = c(0), color = "grey70", linetype = 2) +
  scale_color_brewer(palette = "Accent")+
  theme(legend.background = element_blank(),
        legend.box.background = element_rect(colour = "gray"))  -> pca_plot

pca_plot

The first three components have 1+ variance explanation. See more detailed what PC1, PC2 and PC3 (as combinations of environmental variables) consist of.

normal data: variance = (st.dev)^2 pca data: eigenvalue = (st.dev)^2 “eigenvalues represent the variance explained by each principal component” -> eigen ~ variance

# Extract the loadings from the PCA result and convert to tidy format 
loadings_df <-   tidy(pca_env, matrix = "rotation")


# PC1
# Create the ggplot2 object for plotting the loadings
loadings_df %>% filter(PC == "1") %>% 
  #x=reorder(class,-amount,sum)
ggplot( aes(x = reorder(column, -value), y = value, group = factor(column))) +
  geom_bar(stat = "identity", position = "dodge", 
           fill= "gray90", color = "gray20") +
  geom_text(aes(label = column), position = position_dodge(width = 0.9), 
            #vjust = "inward",  
            angle = 90 , hjust = "inward") +
  labs(x = "Variables of PC1", y = "Loadings") +
  theme_minimal() +
  theme(axis.text.x = element_blank(),
        legend.position = "none")  -> plot_pca1

# PC2 
loadings_df %>% filter(PC == "2") %>% 
  #x=reorder(class,-amount,sum)
ggplot( aes(x = reorder(column, -value), y = value, group = factor(column))) +
  geom_bar(stat = "identity", position = "dodge", 
           fill= "gray90", color = "gray20") +
  geom_text(aes(label = column), position = position_dodge(width = 0.9), 
            #vjust = "inward",  
            angle = 90 , hjust = "inward") +
  labs(x = "Variables of PC2", y = "Loadings") +
  theme_minimal() +
  theme(axis.text.x = element_blank(),
        legend.position = "none") -> plot_pca2

# PC3
loadings_df %>% filter(PC == "3") %>% 
  #x=reorder(class,-amount,sum)
ggplot( aes(x = reorder(column, -value), y = value, group = factor(column))) +
  geom_bar(stat = "identity", position = "dodge", 
           fill= "gray90", color = "gray20") +
  geom_text(aes(label = column), position = position_dodge(width = 0.9), 
            #vjust = "inward",  
            angle = 90 , hjust = "inward") +
  labs(x = "Variables of PC3", y = "Loadings") +
  theme_minimal() +
  theme(axis.text.x = element_blank(),
        legend.position = "none") -> plot_pca3

plot_pca1 + plot_pca2 + plot_pca3

Test pca dispersions.

# we can check the significance in difference between groups in both pca and nmds

euclidean_dist <- data_for_pca %>% select(-c("type_I" , "type_III")) %>% 
                  scale() %>% as.data.frame()  %>% 
                  dist(., method = "euclidean") 

disp_pca <- betadisper( euclidean_dist, data_for_pca$type_III )
anova(disp_pca) #no sign. differences 
## Analysis of Variance Table
## 
## Response: Distances
##           Df Sum Sq Mean Sq F value Pr(>F)
## Groups     6  22.11   3.685  1.7759 0.1762
## Residuals 14  29.05   2.075
disp_pca$distances %>% as.data.frame() %>% 
  rename("Distance" = ".") %>% 
  rownames_to_column("sample_id") %>% 
  cbind(data_for_pca) %>% 
# plot
  ggplot( aes(x = type_III, y = Distance)) +
  geom_boxplot( fill = "violet") +
  labs(x = NULL, y = "Environmental differences \nstandardized Euclidean distance") +
  theme_linedraw() +
  theme(axis.text.x = element_text(size = 10),
        axis.title.y = element_text(size = 10)) -> pca_disp

9.2 nmds (water communities)

asv_water <- asv_table [,rownames(df_pca)] %>% select(!"PX_gw")
bc_diss_water <- vegdist(t(asv_water), method = "bray")
nmds_water <- metaMDS(bc_diss_water)
as.data.frame(nmds_water$points) %>% 
  cbind(data_for_pca$type_III) %>% 
  rename("type" = "data_for_pca$type_III") %>% 
  
# plot 
  ggplot(aes(x = MDS1, y = MDS2)) +
  geom_point(aes(fill = type), shape = 21, 
             size = 5, color= "black" ) +
# customizing the plot  
  scale_fill_brewer(palette = "Accent") +
  theme_linedraw() +
  annotate(geom="text",x=-1.4, y=1.5, label="stress =", color="black") +   
  annotate(geom="text", x=-1.1, y=1.5, label=round(nmds_water$stress,4),
           color="black") +
  
  theme(legend.background = element_blank(),
        legend.box.background = element_rect(colour = "gray")) +
  labs(color = "Water \ntype", shape = "Source") +
  guides(fill = FALSE) +
  geom_vline(xintercept = c(0), color = "grey70", linetype = 2) +
  geom_hline(yintercept = c(0), color = "grey70", linetype = 2) -> nmds_plot_water
  


euclidean_dist <- data_for_pca %>% select(-c("type_I" , "type_III")) %>% 
                  scale() %>% as.data.frame()  %>% 
                  dist(., method = "euclidean") 

disp_nmds <- betadisper( bc_diss_water, data_for_pca$type_III )
anova(disp_nmds) # sign. differences 


disp_nmds$distances %>% as.data.frame() %>% 
  rename("Distance" = ".") %>% 
  rownames_to_column("sample_id") %>% 
  cbind(data_for_pca) %>% 
# plot
  ggplot( aes(x = type_III, y = Distance)) +
  geom_boxplot( fill = "violet") +
  labs(x = NULL, y = "Bray-curtis distance") +
  theme_linedraw() +
  theme(axis.text.x = element_text(size = 10),
        axis.title.y = element_text(size = 10)) -> nmds_water_disp


 nmds_plot_water  + pca_plot +
  nmds_water_disp + pca_disp 

## Analysis of Variance Table
## 
## Response: Distances
##           Df  Sum Sq  Mean Sq F value  Pr(>F)  
## Groups     6 0.48932 0.081554  3.0834 0.03869 *
## Residuals 14 0.37029 0.026449                  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Lake communities and groundwater communties seem to have relatively distinct microbial composition. The hyporheic, pond and inflow water consist only of one sample point, when we remove the soil and sediment samples for this analysis, so it is not possible to draw conclusions. But the rest of the samples have a similar relation for both the environmental variaton and the community variation - environmental homogeneity of the groundwater samples in visible in the low dispersion of the groundwater microbial communities. (check significance and put on plot later)

9.3 Constrained ordiantion

CAP ordination as an distance-based alternative to the RDA (which uses bray, as opposed to RDA’s euclidean). Hellinger transformation (square root of relative abundances) is used to account for compositionality of data.

data_for_pca %>% select(where(is.numeric)) %>% 
  scale() %>% as.data.frame() -> env.data

decostand(t(asv_water), method = "hellinger") -> sp.dat

# check
identical(rownames(env.data), colnames(asv_water)) #TRUE

# perform model
simpleRDA <- capscale(sp.dat ~  ., data=env.data ,
                 distance = "bray")

vif.cca(simpleRDA) # all variables lower than 10


# test

# test env paameters
anova.model3 <- anova(simpleRDA, step=1000, by = "term")
anova.model3
# sign: bix* , fi***, TCC***, Cond, O2**,  Temp*

# new model 
simpleRDA <- capscale(sp.dat ~  bix + fi + TCC + Cond + O2 + Temp, data=env.data ,
                 distance = "bray")
# test env paameters
anova.model3 <- anova(simpleRDA, step=1000, by = "term")

# test of all canonical axes
anova.model <- anova.cca(simpleRDA, by='axis', step=1000)  # CAP1,CAP2,CAP3 significant 

# test the whole model
anova.model2 <- anova.cca(simpleRDA, step=1000) # sign
RsquareAdj(simpleRDA)$adj.r.squared # explains 30%
## [1] TRUE
##      bix       fi      TCC     Cond       O2     Temp       pH    tot.N 
## 5.638966 3.408220 2.283686 2.525874 1.294785 1.745977 1.627837 4.961876 
##    N_NO3    tot.P 
## 6.261860 5.577410 
## Permutation test for capscale under reduced model
## Terms added sequentially (first to last)
## Permutation: free
## Number of permutations: 999
## 
## Model: capscale(formula = sp.dat ~ bix + fi + TCC + Cond + O2 + Temp + pH + tot.N + N_NO3 + tot.P, data = env.data, distance = "bray")
##          Df SumOfSqs      F Pr(>F)    
## bix       1  0.31946 1.7225  0.001 ***
## fi        1  0.84028 4.5307  0.001 ***
## TCC       1  0.66653 3.5939  0.001 ***
## Cond      1  0.31856 1.7177  0.039 *  
## O2        1  0.50456 2.7205  0.001 ***
## Temp      1  0.43066 2.3221  0.013 *  
## pH        1  0.30100 1.6230  0.075 .  
## tot.N     1  0.29959 1.6154  0.064 .  
## N_NO3     1  0.30315 1.6345  0.053 .  
## tot.P     1  0.24783 1.3363  0.133    
## Residual 10  1.85462                  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## [1] 0.2943814

We can say that bix and fix, as well as the temeprature, oxygen and conductivity have an impact on the microbial communities of Luny water bodies. Additionally, the number of TCC (microbial load) in the water body is also a significant indicator of the water community composition.

Plot the constrained ordination if we want to but it could be a bit redundadnt considering the individual ordinations of environmental variables and communitiies. On the other hand, the visual depiction implies need for more sample points, considering how sparse the ordination is.

# vectors
ccavectors <- as.matrix(scores(simpleRDA, display = "bp", scaling = "sites")*3.32) %>% 
  t() %>% as.data.frame() %>% 
  rename("bix*" = "bix",
         "Temp*" = "Temp",
         "O2**" = "O2",
         "fi***" = "fi",
         "TCC***" = "TCC") %>%
  t() %>% as.data.frame()

#bix* , fi***, TCC***, Cond, O2**,  Temp*


# site coordinates
site_data <- scores(simpleRDA, display = "sites") %>% 
  as.data.frame() %>% 
  cbind(., data_for_pca$type_III) %>% 
  rename("type" = "data_for_pca$type_III")

# plotting
plot_cca <- 
  site_data %>% 
  ggplot( aes(x = CAP1, y = CAP2)) +
  geom_point(aes(fill = type), shape = 21, 
             size = 5, color= "black" )+  
  geom_segment(data = ccavectors, aes(x = 0, y = 0, xend = CAP1, yend = CAP2), 
               size = 1.2, arrow = arrow(length = unit(0.5, "cm"))) +
   geom_vline(xintercept = c(0), color = "grey70", linetype = 2) +
   geom_hline(yintercept = c(0), color = "grey70", linetype = 2) +
  geom_text(data = ccavectors, aes(x = CAP1*1.2, y = CAP2*1.1, 
                                   label = rownames(ccavectors)),
                                   size=6 ) +
  theme_linedraw() +
  scale_fill_brewer(palette = "Accent") +
     theme(legend.background = element_blank(),
           legend.box.background = element_rect(colour = "gray")) 

plot_cca

There is certain indication that microbial community assembly of Lunz lakes water samples and near water bodies is not impacted by the environmental variables which were measured in this study. However, the sample type provided a clearer impact on community assembly. Samples of type sediment, soil and surface water showed community similarity within the type category. To determine whether sample type is merely a proxy for ecological conditions, environmental variables for samples other than water samples need to be measured, which was not the case in this study.

Contribution of sources to sinks was not impacted by spatial distance, and the artificial lake provided no physical barrier. Contribution by sample type provided more accurate insight than contribution by “Source” category, which was an arbitrary category determined as a mix of sample type and distance from the sink.

This was shown with Source 6 contribution, consisting of spring sediment and water. Sample type analysis showed that spring sediment of Source 6 contributed to sink sediments, and Source 6 water samples contributed to water sinks.

In summary, this study provides a starting point in community assembly research of microbial fauna of Lunz lakes catchment, and gives indication that future studies should be focused on environmental conditions of each microenvironment, and their ties to microbial assembly, since categorising samples by distance or similarity does not give clear results.

LS0tDQp0aXRsZTogIk1pY3JvYmlhbCBjb21tdW5pdHkgYXNzZW1ibHkgYW5hbHlzaXMgb2YgTHVueiBsYWtlcyBhbmQgdGhlIHN1cnJvdW5kaW5nIHdhdGVyYm9kaWVzIiANCmF1dGhvcjogICJBbmdlbGEgQ3VrdXNpYyINCmRhdGU6IEp1bHkgMjksIDIwMjMNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUgICAgICAgICAgICAgICAjIFRhYmxlIG9mIGNvbnRlbnRzDQogICAgdG9jX2Zsb2F0OiB0cnVlICAgICAgICAgIyBLZWVwIHRoZSB0YWJsZSBvZiBjb250ZW50cyBmbG9hdGluZyBvbiB0aGUgcGFnZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgICAgICMgRW5hYmxlIGNvZGUgZG93bmxvYWQgYnV0dG9uDQogICAgY29kZV9jb3B5OiB0cnVlICAgICAgICAgIyBFbmFibGUgY29kZSBjb3B5IGJ1dHRvbg0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZSAgICMgTnVtYmVyaW5nIHRoZSBzZWN0aW9ucw0KICAgIHRoZW1lOiBjZXJ1bGVhbiAgICAgICAgICAgIyBDaG9vc2UgYSBCb290c3RyYXAgdGhlbWUgKGNoZWNrIGF2YWlsYWJsZSB0aGVtZXMpDQogICAgaGlnaGxpZ2h0OiB0YW5nbyAgICAgICAgIyBTeW50YXggaGlnaGxpZ2h0aW5nIHN0eWxlIChwaWNrIGEgc3R5bGUgZnJvbSBhdmFpbGFibGUgdGhlbWVzKQ0KDQotLS0NCg0KVGhlIG1haW4gYmVuZWZpdCBvZiBzdHVkeWluZyBjb21tdW5pdHkgYXNzZW1ibHksIGFuZCBmYWN0b3JzIHRoYXQgaW1wYWN0IGl0LCBpcyB0byBmdXJ0aGVyIHVuZGVyc3RhbmQgdGhlIGNvbm5lY3Rpb24gb2YgY29tbXVuaXR5IGRpdmVyc2l0eSB0byBlY29zeXN0ZW0gZnVuY3Rpb25hbGl0eSwgd2hpY2ggaXMgY3J1Y2lhbCBpbiB1cGtlZXBpbmcgZWNvc3lzdGVtcy4gV2l0aCBzcGF0aWFsIGRpc3RhbmNlIHNob3duIHRvIGJlIGEgc2lnbmlmaWNhbnQgZmFjdG9yIGluIGNvbW11bml0eSBhc3NlbWJseSBwcm9jZXNzZXMsIGl0IGlzIHNlbnNpYmxlIHRvIGV4cGxvcmUgdGhlIHdhdGVyYm9kaWVzIG9mIHRoZSBMdW56IHN0dWR5IHNpdGUsIHdoaWNoIGNvbnNpc3RzIG9mIHZhcmlvdXMNCmVudmlyb25tZW50cyB3aXRoIGRpZmZlcmVudCBjb25kaXRpb25zLCBhbmQgaW5jbHVkZXMgdGhyZWUgc3ByaW5ncywgc2V2ZW4gY3JlZWtzLCBmb3VyIGdyb3VuZHdhdGVyIHdlbGxzLCBhIHBvbmQsIGEgaHlwb3JoZWljIHNwcmluZywgYW5kIHRocmVlIGxha2VzLiBUaGUgY29ubmVjdGl2aXR5IGlzIHByZXN1bWVkIHRvIGJlIGhpbmRlcmVkIGF0IHRoZSBtaWRkbGUgcG9pbnQgb2YgdGhlIGNhdGNobWVudCBhcmVhLCB0aGUgTWlkZGxlIExha2UuDQoNCiMgUGFja2FnZSBsb2FkaW5nDQpgYGB7ciwgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KEZFQVNUKSAjIGZvciBzb3VyY2UgdHJhY2tpbmcNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh2ZWdhbikNCmxpYnJhcnkoRlNBKSAjIGZvciBkdW5uIHBvc3QtaG9jIHRlc3QNCmxpYnJhcnkoY2FyZXQpIA0KbGlicmFyeShicm9vbSkNCmxpYnJhcnkocGF0Y2h3b3JrKSAjIGZvciBjb21iaW5pbmcgcGxvdHMgaW50byAxDQpsaWJyYXJ5KGdnZm9ydGlmeSkNCmxpYnJhcnkocGFpcndpc2VBZG9uaXMpICMgZm9yIHBlcm1hbm92YSBwb3N0LWhvYw0KYGBgDQoNCkZyb20gZXZlcnkgc2FtcGxlLCBETkEgd2FzIGV4dHJhY3RlZCBhbmQgdXNlZCBmb3IgMTZTIHJSTkEgZ2VuZSBhbXBsaWNvbiBzZXF1ZW5jaW5nLiBBbXBsaWNvbiBzZXF1ZW5jaW5nIGFuZCBiaW9pbmZvcm1hdGljIHByb2Nlc3Npbmcgb2YgdGhlIHJhdyBzZXF1ZW5jZSBkYXRhIGZvciB0aGUgaW5mZXJlbmNlIG9mIGFtcGxpY29uIHNlcXVlbmNlIHZhcmlhbnRzIChBU1YpIHVzaW5nIERBREEyIHdhcyBkb25lLCBhcyB3ZWxsIGFzIG90aGVyIHByb2Nlc3Npbmcgb2Ygb3JnYW5lbGxlcyBhbmQgbWl0b2Nob25kcmlhLg0KDQojIExvYWQgZGF0YQ0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KDQoNCiMgbG9hZCBtZXRhZGF0YQ0KbWV0YWRhdGEgPC0gcmVhZC5jc3YoIn4vZmFrcy9FY29sb2d5IGFuZCBFY29zeXN0ZW1zL01FQy04IChTcGVjaWZpYyByZXNlYXJjaCBwcm9qZWN0KS9kYXRhL21ldGFkYXRhX0x1bnpfcmV2aXNlZC5jc3YiLCANCiAgICAgICAgICAgICAgICAgICAgIHJvdy5uYW1lcyA9IDEpDQoNCiMgbG9hZCBhc3YgdGFibGUNCmFzdl90YWJsZSA8LSByZWFkLmNzdigifi9mYWtzL0Vjb2xvZ3kgYW5kIEVjb3N5c3RlbXMvTUVDLTggKFNwZWNpZmljIHJlc2VhcmNoIHByb2plY3QpL2RhdGEvYXN2X3RhYmxlLmNzdiIsIHJvdy5uYW1lcz0xKQ0KDQojIGlkZW50aWZpZXIgbmVlZCB0byBiZSBpZGVudGljYWwgYmV0d2VlbiBhc3ZfdGFibGUgYW5kIG1ldGFkYXRhDQppZGVudGljYWwocm93bmFtZXMobWV0YWRhdGEpLCBjb2xuYW1lcyhhc3ZfdGFibGUpKQ0KIyBpZiB0aGVyZSBpcyBzb21lIHRoYXQgYXJlIGRpZmZlcmVudCB1c2Ugc2V0ZGlmZihyb3duYW1lcyhtZXRhZGF0YSksIGNvbG5hbWVzKGFzdl90YWJsZSkpIHRvIHNlZSB3aGljaA0KDQojIGRhdGEgb24gc291cmNlcy9zaW5rcw0KZmVhc3RfbWV0YWRhdGEgPC0gcmVhZC5jc3YoIn4vZmFrcy9FY29sb2d5IGFuZCBFY29zeXN0ZW1zL01FQy04IChTcGVjaWZpYyByZXNlYXJjaCBwcm9qZWN0KS9kYXRhL2ZlYXN0X21ldGFkYXRhLmNzdiIsIHJvdy5uYW1lcz0xKQ0KIyBpZGVudGlmaWVycyBmb3Igc291cmNlcyBoYXZlIHRvIGJlIHVuaXF1ZSAtIHNvdXJjZSAxIG5lZWRzIHRvIGJlIFNvdXJjZTFfMSwgU291cmNlMV8yLCAuLi4gKQ0KIyBTYW1wbGVJRCBjb2x1bW4gbmVlZCB0byBiZSAgcm93bmFtZXMNCg0KYGBgDQoNCiMgRkVBU1QNCg0KRkVBU1QgLSB0aGUgZmFzdCBleHBlY3RhdGlvbi1tYXhpbWl6YXRpb24gd2FzIHVzZWQsIGFzIGEgbW9yZSBjb21wdXRhdGlvbmFsIGVmZmljaWVudCBhbmQgc2hvcnRlciBhbHRlcm5hdGl2ZSB0byBTb3VyY2VUcmFja2VyLg0KDQoNClByZXBhcmUgdGhlIGRhdGEgZm9yIEZFQVNULg0KYGBge3IsIGV2YWw9RkFMU0V9DQojIGNsYXNzZXMgb2YgZGF0YXNldHMNCg0KIyBmZWFzdF9tZXRhZGF0YSBzaG91bGQgYmUgYSBkYXRhLmZyYW1lDQpjbGFzcyhmZWFzdF9tZXRhZGF0YSkNCg0KI2FzdiBzaG91bGQgYmUgbWF0cml4IGFuZCBlYWNoIGNvbHVtbiBhbiBpbmVnZXIgaW4gb3JkZXIgdG8gcGVyZm9ybSBmZWFzdA0KZmVhc3RfYXN2IDwtIGFzLm1hdHJpeChhc3ZfdGFibGUpICAgICAgICAgICAgICAgICMgbWF0cml4IGFzIGEgd2hvbGUNCiAgICBmb3IoaSBpbiAxOm5jb2woZmVhc3RfYXN2KSl7ICAgICAgICAgICAgICAgICAjIGVhY2ggY29sdW1uIGFzIGludGVnZXINCiAgICAgICAgICAgICAgICAgICAgZmVhc3RfYXN2WywgaV0gPC0gYXMuaW50ZWdlcihmZWFzdF9hc3ZbLCBpXSkNCn0NCg0KDQojIHdob2xlICB0YWJsZSBzaG91bGQgYmUgYSBtYXRyaXgNCmNsYXNzKGZlYXN0X2FzdikNCg0KIyBpbmRpdmlkdWFsIGNvbHVtbiBzaG91bGQgYmUgaW50ZWdlcg0KY2xhc3MoZmVhc3RfYXN2WywgMV0pDQoNCg0KDQojIGZpbmFsIHN0ZXAgLSBmb3JtIG5lZWRzIHRvIGJlIGFzIHdpdGggdmVnYW4gKHNpdGVzIHJvd3MsIHNwZWNpZXMgY29sdW1ucykNCmZlYXN0X2FzdiA8LSB0KGZlYXN0X2FzdikNCmZlYXN0X2FzdlsxOjEwLCAxOjVdDQoNCg0KI3RvIHJlbW92ZSBmcm9tIGVudmlyb25tZW50DQpybShpKSANCg0KDQpgYGANCg0KDQpQZXJmb3JtIEZFQVNULiBJdCBleHBvcnRzIHRoZSByZXN1bHRzIGFuZCBsYXRlciBvbiBuZWVkcyB0byBiZSBpbXBvcnRlZCBhZ2Fpbi4NCg0KVGhlIG1ldGFkYXRhIHRhYmxlIGhhcyB0aHJlZSBjb2x1bW5zIChpLmUuLCAnRW52JywgJ1NvdXJjZVNpbmsnLCAnaWQnKS4gDQpUaGUgZmlyc3QgY29sdW1uIGlzIGEgZGVzY3JpcHRpb24gb2YgdGhlIHNhbXBsZWQgZW52aXJvbm1lbnQgKGUuZy4sIHNhbXBsZSBuYW1lcyksIA0KdGhlIHNlY29uZCBjb2x1bW4gaW5kaWNhdGVzIGlmIHRoaXMgc2FtcGxlIGlzIGEgc291cmNlIG9yIGEgc2luayAoY2FuIHRha2UgdGhlIHZhbHVlICdTb3VyY2UnIG9yICdTaW5rJykuIA0KVGhlIHRoaXJkIGNvbHVtbiBpcyB0aGUgU2luay1Tb3VyY2UgaWQuIA0KDQpXaGVuIHVzaW5nIG11bHRpcGxlIHNpbmtzLCBvbmx5IHRoZSByb3dzIHdpdGggJ1NvdXJjZVNpbmsnID0gU2luayBuZWVkIGFuIGlkIA0KKGJldHdlZW4gMSAtIG51bWJlciBvZiBzaW5rcyBpbiB0aGUgZGF0YSksIHRoZSBzb3VyY2Vz4oCZIGlkcyBhcmUgYmxhbmsuIA0KDQoNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpmZWFzdF9vdXRwdXQgPC0gRkVBU1QoQyA9IGZlYXN0X2FzdiwgICAgICAgICAgICAgICMgdHJhbnNwb3NlZCBhc3ZfdGFibGUNCiAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YSA9IGZlYXN0X21ldGFkYXRhLCAgIyBzaW5rIG9yIHNvdXJjZSBpbmZvcm1hdGlvbg0KICAgICAgICAgICAgICAgICAgICAgIGRpZmZlcmVudF9zb3VyY2VzX2ZsYWcgPSAwLCAjIDAgaWYgc291cmNlcyBhcmUgbm90IGFzc2lnbmVkIHRvIGRpZmZlcmVudCBzaW5rcw0KICAgICAgICAgICAgICAgICAgICAgIEVNX2l0ZXJhdGlvbnMgPSAxMDAwLCAgICAgICAjIG51bWJlciBvZiBpdGVyYXRpb25zDQogICAgICAgICAgICAgICAgICAgICAgZGlyX3BhdGggPSAiQzovVXNlcnMvQW5nZWxhIEN1a3VzaWMvRG9jdW1lbnRzL2Zha3MvRWNvbG9neSBhbmQgRWNvc3lzdGVtcy9NRUMtOCAoU3BlY2lmaWMgcmVzZWFyY2ggcHJvamVjdCkvUmVzdWx0cyIsIA0KICAgICAgICAgICAgICAgICAgICAgIG91dGZpbGUgPSAiZmVhc3RfcmVzdWx0cyIpICAjIHByZWZpeCBmb3Igc2F2aW5nIG91dHB1dCBmaWxlDQoNCiMgQ09WRVJBR0Ugc2hvdWxkIGJlIGluY2x1ZGVkIGluIHRoZSBjb21tYW5kIGlmIHdlIHdhbnQgdG8gaW5kaWNhdGUgdGhlIHJhcmVmYWN0aW9uIGRlcHRoDQoNCg0KYGBgDQoNCmBgYHtyfQ0KI3dlIGdvdCBhbiBvdXRwdXQsIGltcG9ydCBpdCBub3cNCmZlYXN0X3RhYmxlIDwtIHJlYWQudGFibGUoIkM6L1VzZXJzL0FuZ2VsYSBDdWt1c2ljL0RvY3VtZW50cy9mYWtzL0Vjb2xvZ3kgYW5kIEVjb3N5c3RlbXMvTUVDLTggKFNwZWNpZmljIHJlc2VhcmNoIHByb2plY3QpL1Jlc3VsdHMvZmVhc3RfcmVzdWx0c19zb3VyY2VfY29udHJpYnV0aW9uc19tYXRyaXgudHh0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJcdCIsIHJvdy5uYW1lcyA9IDEpDQoNCmBgYA0KDQoNCg0KIyMgUmF3IGNvbnRyaWJ1dGlvbiB0byBwbG90dGFibGUgZGF0YQ0KVG8gZ2V0IGFuIG92ZXJ2aWV3IG9mIHRoZSB0b3RhbCBjb250cmlidXRpb24gb2YgZWFjaCBzb3VyY2UgKGkuZS4gZ3JvdXBzIG9mIHNhbXBsZXMpIHRvIHRoZSBkaWZmZXJlbnQgc2luayB3ZSBoYXZlIHRvIGNsZWFuIGl0Lg0KDQpgYGB7ciwgcmVzdWx0cz0naGlkZSd9DQojIGZlYXN0X291dHB1dCBpcyBvZiBjbGFzcyAibGlzdCINCiMgd2Ugd2FudCB0byBtYWtlIGl0IGEgbWF0cml4DQoNCiMgMS4gbWFrZSBhIG5ldyB2ZWN0b3Igd2l0aCBzb3VyY2UgdHlwZXMgKGFuZCBpdCBpcyAiY2hhcmFjdGVyIikNCnNvdXJjZXMgPC0gcGFzdGUoInNvdXJjZSIsIGMoMTo4KSwgc2VwID0gIiIpDQoNCg0KIyAyLiBtYWtlIGVtcHR5IG1hdHJpeCB3aXRoIG5yb3cgPSBudW1iZXIgb2YgU0lOS1MgKDUpLCANCiMgYW5kIG5jb2wgPSBudW1iZXIgb2YgcG9zc2libGUgc291cmNlcyAoMjArIHNhbXBsZXMgYXJlIGRlc2lnbmF0ZWQgdG8gMS04IHNvdXJjZXMpDQpzb3VyY2VfY29udHJpYnV0aW9ucyA8LSBtYXRyaXgoTkEsICAgICAgICAgICAgICAgICAgICAgICAgIyBlbXB0eQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3cgPSBucm93KGZlYXN0X3RhYmxlKSwgICMgNSBzaW5rcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSBsZW5ndGgoc291cmNlcykpICAgICMgbiBzb3VyY2VzDQoNCiMgMy4gZmlsbCBtYXRyaXggDQpmb3IoaSBpbiAxOmxlbmd0aChzb3VyY2VzKSl7ICAgICMgZm9yIGVhY2ggc291cmNlIGFkZCBjb250cmlidXRpb24gDQogIHNvdXJjZV9jb250cmlidXRpb25zWywgaV0gPC0gcm93U3VtcyhmZWFzdF90YWJsZVssICAgICAgIyBzdW0gdXAgY29udHJpYnV0aW9ucyBmb3IgYWxsIDUgcm93cw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmVwbChzb3VyY2VzW2ldLCBjb2xuYW1lcyhmZWFzdF90YWJsZSkpXSkgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBvZiBvbmx5IHRoZSBjb2x1bW5zIHdoaWNoIGhhdmUgc291cmNlWCBpbiBuYW1lDQp9DQoNCiMgNC4gd2UgYWRkZWQgY29udHJpYnV0aW9ucyBhc3NpZ25lZCB0byBlYWNoIG9mIDggc291cmNlcywgbm93IGFkZCBmcm9tIHVua25vd24gc291cmNlcw0Kc291cmNlX2NvbnRyaWJ1dGlvbnMgPC0gY2JpbmQoc291cmNlX2NvbnRyaWJ1dGlvbnMsIGZlYXN0X3RhYmxlJFVua25vd24pDQoNCg0KIyA1LiBjaGVjayBpZiBhbGwgY29udHJpYnV0dW9ucyBmb3IgaW5kaXZpZHVhbCBzaW5rIGFtb3VudCB0byAxDQpyb3dTdW1zKHNvdXJjZV9jb250cmlidXRpb25zKSANCg0KDQojIDYuIGNvbnZlcnQgdG8gZGF0YSBmcmFtZSBhbmQgYnJpbmcgYmFjayByb3duYW1lcyBhbmQgY29sbmFtZXMNCnNvdXJjZV9jb250cmlidXRpb25zIDwtIGFzLmRhdGEuZnJhbWUoc291cmNlX2NvbnRyaWJ1dGlvbnMpDQpjb2xuYW1lcyhzb3VyY2VfY29udHJpYnV0aW9ucykgPC0gYyhzb3VyY2VzLCAidW5rbm93biIpICMgY29sDQpzb3VyY2VfY29udHJpYnV0aW9ucyA8LSBzb3VyY2VfY29udHJpYnV0aW9ucyAlPiUgICAgICAgICMgcm93DQogIG11dGF0ZShzYW1wbGVfaWQgPSByb3duYW1lcyhmZWFzdF90YWJsZSksIC5iZWZvcmUgPSAxKSANCg0KDQojICBmaW5hbCBjbGVhbiB1cCBvZiBlbnZpcm9ubWVudA0Kcm0oIHNvdXJjZXMsIGkpDQoNCmBgYA0KDQojIyBQbG90IHNvdXJjZSBjb250cmlidXRpb24NCg0KYGBge3J9DQpzb3VyY2VfY29udHJpYnV0aW9ucyAlPiUgDQoNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtc2FtcGxlX2lkLCBuYW1lc190byA9ICJzb3VyY2VzIiwgdmFsdWVzX3RvID0gImNvbnRyaWJ1dGlvbnMiKSAlPiUgDQogIG11dGF0ZShzb3VyY2VzID0gYXMuZmFjdG9yKHNvdXJjZXMpKSAgICAgJT4lIA0KICANCiAgDQojIGZpbmQgIHJlbGF0aXZlIGFidW5kYW5jZXMgZm9yIGVhY2ggZGF0ZSBpbiBlYWNoIHdhdGVyIGtpbmQgKHdlbGwvcHVtcC9zdXJmKQ0KICBncm91cF9ieShzYW1wbGVfaWQpICU+JQ0KICBtdXRhdGUocmVsX2NvbnQgPSBjb250cmlidXRpb25zIC8gc3VtKGNvbnRyaWJ1dGlvbnMpICogMTAwKSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICANCiMgcGxvdHRpbmcNCiAgZ2dwbG90KGFlcyh4ID0gc2FtcGxlX2lkLCB5ID0gcmVsX2NvbnQsIGZpbGwgPSBzb3VyY2VzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICANCiMgbGFiZWxsaW5nICAgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSAgDQogICAgICAgICAgICAgICAgICAjIGxhYmVsIGlmICUgaXMgYmlnIGVub3VnaA0KICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlbF9jb250ID4gMiwgDQogICAgICAgICAgICAgICAgICAjIGlmIHllcyB0aGVuICBwYXN0ZSwgaWYgbm8gdGhlbiBlbXB0eSAiIg0KICAgICAgICAgICAgICAgICAgcGFzdGUwKHJvdW5kKHJlbF9jb250LCA0KSAsICIlIiksICIiICkgICksDQogICAgICAgICAgICAjIGhvdyB0byBwb3NpdGlvbiBpdA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksIHNpemUgPSA0KSArDQoNCiMgdGhlbWUgIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICB0aGVtZV9jbGFzc2ljKCkgKyANCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikgKw0KICBsYWJzKHg9ICJTaW5rcyIsIHk9IlJlbGF0aXZlIGNvbnRyaWJ1dGlvbnMgJSIsIGZpbGwgPSAiU291cmNlcyIpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBjKCJVbnRlcnNlZSBcbigzMW0pIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVW50ZXJzZWUgXG4oNW0pIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVW50ZXJzZWUgLSBcbm5lYXIgT1NCIGluZmxvdyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVudGVyc2VlIC0gXG5hdCBPU0IgXG5pbmZsb3ciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWRpbWVudDogXG5VbnRlcnNlZSAtIFxuYXQgT1NCIFxuaW5mbG93IikpIA0KDQoNCmBgYA0KDQpGcm9tIGZpdmUgc2luayBzYW1wbGVzIGlkZW50aWZpZWQgaW4gdGhpcyBzdHVkeSwgZm91ciB3ZXJlIHdhdGVyIHNhbXBsZXMsIGFuZCBvbmUgYSBzZWRpbWVudCBzYW1wbGUuIEVhY2ggc2luayBoYWQgYSBzdWJzdGFudGlhbCBwb3J0aW9uIG9mIG1pY3JvYmVzIG9mIHVua25vd24gb3JpZ2luLg0KDQpBZGRpdGlvbmFsIHRvIHRoYXQsIGFub3RoZXIgdmlzaWJsZSB0cmVuZCBpcyB3YXRlciBzYW1wbGVzIGJlaW5nIHRyYWNlZCBiYWNrIHRvIFNvdXJjZSAxIChzdXJmYWNlIHdhdGVycyksIHdpdGggbm9uLWV4aXN0ZW50IG9yIG1pbmltYWwgcG9ydGlvbiBvZiBTb3VyY2UgMiByZWxhdGVkIG1pY3JvYmVzIChzdXJmYWNlIHdhdGVycycgc2VkaW1lbnQgYW5kIGJpb2ZpbG0gc2FtcGxlcywgc2VlIEZpZy4yLikuIA0KDQpUaGUgc2VkaW1lbnQgc2luaywgb24gdGhlIG90aGVyIGhhbmQsIHNob3dlZCBubyBpbmZsdWVuY2Ugb2YgU291cmNlIDEgb24gaXRzIGNvbXBvc2l0aW9uLCBidXQgaGFkIGEgaGlnaCBTb3VyY2UgMiBvcmlnaW4uDQpXYXRlciBzaW5rcyBjb250YWluZWQgbW9yZSBBU1ZzIG5vdCBmb3VuZCBpbiBhbnkgb2YgdGhlIHNvdXJjZXMgdGhhbiB0aGUgc2VkaW1lbnQgc2luay4gDQoNCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCmZlYXN0X3RhYmxlICU+JSANCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGVfaWQiKSAlPiUgDQojIGZpbmQgdGhlIHR3byBzaW5rcyBpbiBxdWVzdGlvbiAgDQogIGZpbHRlcihzYW1wbGVfaWQgJWluJSBjKCJPU0JfaW5fTFVTX2luZmxvd19MVVNfYXRfT1NCX2luZmxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPU0JfaW5fTFVTX3NlZF9MVVNfc2VkaW1lbnQiKSkgJT4lIA0KICANCiMgZmluZCB0aGUgaW5kaXZpZHVhbCBzYW1wbGVzIGZyb20gc291cmNlIDYNCiAgc2VsZWN0KCAic2FtcGxlX2lkIiwgIGNvbnRhaW5zKCJzb3VyY2U2IikpICU+JSANCiMgcmVtb3ZlIHRoZSBsYXN0IHBhcnQgb2YgbmFtZXMsIHdoaWNoIHNheXMgInNvdXJjZTYiICANCiAgcmVuYW1lX2FsbCh+c3RyX3JlbW92ZSguLCAiLnsxMH0kIikpICU+JSANCiAgDQogIHBpdm90X2xvbmdlcihjb2xzID0gLXNhbXBsZV9pZCwgbmFtZXNfdG8gPSAic291cmNlcyIsIHZhbHVlc190byA9ICJjb250cmlidXRpb25zIikgJT4lIA0KICBtdXRhdGUoc291cmNlcyA9IGFzLmZhY3Rvcihzb3VyY2VzKSkgICAgICU+JSANCiAgDQogIA0KIyBmaW5kICByZWxhdGl2ZSBhYnVuZGFuY2VzIGZvciBlYWNoIGRhdGUgaW4gZWFjaCB3YXRlciBraW5kICh3ZWxsL3B1bXAvc3VyZikNCiAgZ3JvdXBfYnkoc2FtcGxlX2lkKSAlPiUNCiAgbXV0YXRlKHJlbF9jb250ID0gY29udHJpYnV0aW9ucyAvIHN1bShjb250cmlidXRpb25zKSAqIDEwMCkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgDQojIHBsb3R0aW5nDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBzYW1wbGVfaWQsIHkgPSByZWxfY29udCwgZmlsbCA9IHNvdXJjZXMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIpICsNCiAgDQojIGxhYmVsbGluZyAgIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gIA0KICAgICAgICAgICAgICAgICAgIyBsYWJlbCBpZiAlIGlzIGJpZyBlbm91Z2gNCiAgICAgICAgICAgICAgICAgIGlmZWxzZShyZWxfY29udCA+IDIsIA0KICAgICAgICAgICAgICAgICAgIyBpZiB5ZXMgdGhlbiAgcGFzdGUsIGlmIG5vIHRoZW4gZW1wdHkgIiINCiAgICAgICAgICAgICAgICAgIHBhc3RlMChyb3VuZChyZWxfY29udCwgNCkgLCAiJSIpLCAiIiApICApLA0KICAgICAgICAgICAgIyBob3cgdG8gcG9zaXRpb24gaXQNCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLCBzaXplID0gNCkgKw0KDQojIHRoZW1lICANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgdGhlbWVfY2xhc3NpYygpICsgDQogIGxhYnMoeD0gIlNpbmtzIiwgeT0iUmVsYXRpdmUgY29udHJpYnV0aW9ucyAlIiwgZmlsbCA9ICJTb3VyY2VzIikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIlVudGVyc2VlIC0gXG5hdCBPU0IgXG5pbmZsb3ciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTZWRpbWVudDogXG5VbnRlcnNlZSAtIFxuYXQgT1NCIFxuaW5mbG93IikpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyggIiMwMDY0MDAiLCAiI0ZGRDcwMCIsICJsaWdodGJsdWUiLCAiI0ZGRDcwMCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJsaWdodGJsdWUiLCAiIzAwNjQwMCIsICJsaWdodGJsdWUiICkpDQpgYGANCg0KDQpFdmVuIHRob3VnaCB0aGUgdHdvIHNpbmtzIGF0IHRoZSBpbmZsb3cgYm90aCBoYWQgfjEwJSBvZiBTb3VyY2UgNiBtaWNyb2JlcyAod2hpY2ggd2FzIHR3byBsb2NhdGlvbnMgLSBib3RoIHNlZGltZW50IGFuZCB3YXRlciksIGl0IHNlZW1zIHRoYXQgbW9yZSBkZXRhaWxlZCBsb29rIGdpdmVzIG1vcmUgaW5zaWdodCB0aGF0IHNhbXBsZSB0eXBlIGlzIGEgYmV0dGVyIHByZWRpY3RvciBvZiBjb250cmlidXRpb24gdGhhbiBsb2NhdGlvbiBpcy4NCg0KUmVzdWx0OiB3YXRlciBzaW5rIHdhcyBtb3JlIGluZmx1ZW5jZWQgYnkgd2F0ZXIgc2FtcGxlcyBjb21tdW5pdGllcywgd2hpbGUgc2VkaW1lbnQgc2luayBjb250YWluZWQgYWxtb3N0IGV4Y2x1c2l2ZWx5IG1pY3JvYmVzIGZyb20gc3ByaW5nIHNlZGltZW50cyBhbmQgc3ByaW5nIGJpb2ZpbG1zLg0KDQoNCg0KIyBTYW1wbGUgdHlwZSBkaXN0cmlidXRpb24NCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdob2xkJ30NCg0KbWV0YWRhdGFfdHlwZSA8LSBtZXRhZGF0YSAlPiUgDQogICAgICAgICAgICAgICAgIHJvd25hbWVzX3RvX2NvbHVtbigic291cmNlcyIpICU+JSANCiAgICAgICAgICAgICAgICAgc2VsZWN0KCJzb3VyY2VzIiwgInR5cGVfSUlJIikgJT4lIA0KICAgICAgICAgICAgICAgICBtdXRhdGUodHlwZV9JSUkgPSBjYXNlX3doZW4oDQogICAgICAgICAgICAgICAgICMgYXNzaWduIGNhdGVnb3JpZXMgIA0KICAgICAgICAgICAgICAgICAgIHR5cGVfSUlJICVpbiUgYygiQ3JlZWsiLCAiSHlwb3JoZWljIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBvbmQiLCAiTGFrZSIsICJJbmZsb3ciKSB+ICJTdXJmYWNlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IHR5cGVfSUlJKSkgDQoNCg0KDQoNCmZlYXN0X3RhYmxlICU+JSANCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzaW5rX2lkIikgJT4lIA0KIyByZW5hbWUgdGhlIGNvbHVtbnMgc28gdGhhdCB0aGV5IGNhbiBiZSBjb25uZWN0ZWQgdG8gdGhlIG1ldGFkYXRhICh0eXBlIGluZm8pICANCiAgcmVuYW1lX2FsbCh+c3RyX3JlbW92ZSguLCAiLnsxMH0kIikpICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtIHNpbmtfaWQsIG5hbWVzX3RvID0gInNvdXJjZXMiLCB2YWx1ZXNfdG8gPSAiY29udHJpYnV0aW9ucyIpICU+JSANCiMgZmlsdGVyIG91dCBjb250cmlidXRpb25zIGZyb20gdW5rbm93IHNvdXJjZXMNCiAgZmlsdGVyKHNvdXJjZXMgIT0gIlVua25vd24iKSAlPiUgDQojIGpvaW4gd2l0aCBtZXRhZGF0YQ0KICBsZWZ0X2pvaW4oLiwgbWV0YWRhdGFfdHlwZSwgYnkgPSAic291cmNlcyIpICU+JSANCiAgZmlsdGVyKHR5cGVfSUlJICE9ICJOQSIpICU+JSANCiAgZmlsdGVyKCBjb250cmlidXRpb25zIDwgMC4wNSkgJT4lIA0KIyBwbG90DQogIGdncGxvdChhZXMoeD0gdHlwZV9JSUksIHk9IGNvbnRyaWJ1dGlvbnMpKSArIA0KICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBzaW5rX2lkKSApICsNCiAgdGhlbWVfbGluZWRyYXcoKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKGxhYmVscz1jKCJVbnRlcnNlZSAoMzFtKSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVW50ZXJzZWUgKDVtKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVbnRlcnNlZSAobmVhciBpbmZsb3cpIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVbnRlcnNlZSAoYXQgaW5mbG93KSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU2VkaW1lbnQgKGF0IGluZmxvdykiKSwgDQogICAgICAgICAgICAgICAgICAgIHZhbHVlcz1jKCIjYWNjN2Q5IiwgIiM4YmIwY2EiLCIjNTE4MGEyIiwiIzNlNjQ3ZCIsIiNkOGIzNjUiKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249YygwLjMsMC44KSwgDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIA0KICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdCgpLCANCiAgICAgICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kICA9ICAgZWxlbWVudF9yZWN0KGNvbG9yID0gImdyYXkiKSkgKw0KICBsYWJzKHkgPSAiQ29udHJpYnV0aW9ucyIsIHg9ICJTYW1wbGUgdHlwZSIpICsgDQogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiQmlvZmlsbSIsICJHcm91bmQgd2F0ZXIiLCAiU2VkaW1lbnQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTb2lsIiwgIlNwcmluZyB3YXRlciIsICJTdXJmYWNlIHdhdGVyIikgKQ0KICANCiAgDQoNCmBgYA0KDQoNClN1cmZhY2Ugd2F0ZXJzIGNvbnRyaWJ1dGVkIHRvIGFsbCB3YXRlciBzaW5rcywgYnV0IHRoZWlyIGVmZmVjdCBvbiB0aGUgc2VkaW1lbnQgb2YgdGhlIHNpbmsgd2FzIG1pbmltYWwuIA0KU2FtcGxlcyB0aGF0IGRpZCBjb250cmlidXRlIHRvIHNlZGltZW50IHNpbmsgYXJlICBiaW9maWxtLCBzZWRpbWVudCBhbmQgc29pbCBzb3VyY2Ugc2FtcGxlcy4gDQpBZGRpdGlvbmFsIHRvIGNvbnRyaWJ1dGluZyB0byB0aGUgc2VkaW1lbnQgc2luaywgYmlvZmlsbSBzYW1wbGVzIGFsc28gaGFkIGFuIGltcGFjdCBvbiB0aGUgY29tbXVuaXR5IGF0IHRoZSBpbmZsb3cgb2YgdGhlIExvd2VyIExha2UuDQpTcHJpbmd3YXRlciBzYW1wbGVzIHdlcmUgdGhlIGJpZ2dlc3QgY29udHJpYnV0b3IgdG8gdGhlIGluZmxvdywgYW5kIGhhZCBhbiBpbXBhY3Qgb24gdGhlDQptaWNyb2JpYWwgYXNzZW1ibHkgb2YgdGhlIExvd2VyIExha2UgYXQgaXRzIDMxLW1ldGVyIGRlcHRoLg0KDQoNCg0KIyBTcGF0aWFsIGRpc3RyaWJ1dGlvbg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naG9sZCd9DQptZXRhZGF0YV9yYW5rIDwtIG1ldGFkYXRhICU+JSANCiAgICAgICAgICAgICAgICAgcm93bmFtZXNfdG9fY29sdW1uKCJzb3VyY2VzIikgJT4lIA0KICAgICAgICAgICAgICAgICBzZWxlY3QoInNvdXJjZXMiLCAicmFuayIpICU+JSANCiAgICAgICAgICAgICAgICAgZmlsdGVyKHJhbmsgIT0gInNpbmsiKQ0KDQpmZWFzdF90YWJsZSAlPiUgDQogIHJvd25hbWVzX3RvX2NvbHVtbigic2lua19pZCIpICU+JSANCiMgcmVuYW1lIHRoZSBjb2x1bW5zIHNvIHRoYXQgdGhleSBjYW4gYmUgY29ubmVjdGVkIHRvIHRoZSBtZXRhZGF0YSAocmFuayBpbmZvKSAgDQogIHJlbmFtZV9hbGwofnN0cl9yZW1vdmUoLiwgIi57MTB9JCIpKSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gLSBzaW5rX2lkLCBuYW1lc190byA9ICJzb3VyY2VzIiwgdmFsdWVzX3RvID0gImNvbnRyaWJ1dGlvbnMiKSAlPiUgDQojIGZpbHRlciBvdXQgY29udHJpYnV0aW9ucyBmcm9tIHVua25vdyBzb3VyY2VzDQogIGZpbHRlcihzb3VyY2VzICE9ICJVbmtub3duIikgJT4lIA0KIyBqb2luIHdpdGggbWV0YWRhdGENCiAgbGVmdF9qb2luKC4sIG1ldGFkYXRhX3JhbmssIGJ5ID0gInNvdXJjZXMiKSAlPiUgDQogIGZpbHRlcihyYW5rICE9ICJOQSIpICU+JSANCiMgcGxvdA0KICBnZ3Bsb3QoYWVzKHg9IHJhbmssIHk9IGNvbnRyaWJ1dGlvbnMpKSArIA0KICBnZW9tX2JveHBsb3QoIGZpbGwgPSAidmlvbGV0IikgKw0KICBmYWNldF93cmFwKH5zaW5rX2lkLCBzY2FsZXMgPSAiZnJlZV95IiwgIGxhYmVsbGVyID0gDQogICAgICAgICAgICAgICBhc19sYWJlbGxlciggYygiTFVTX2RwXzMxbV9MVVNfMzFtIiA9ICJVbnRlcnNlZSAoMzFtKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTFVTX2RwXzVtX0xVU181bSIgPSAiVW50ZXJzZWUgKDVtKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTFVTX2luX09TQl9MVVNfbmVhcl9PU0JfaW5mbG93IiA9ICJVbnRlcnNlZSAobmVhciBpbmZsb3cpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPU0JfaW5fTFVTX2luZmxvd19MVVNfYXRfT1NCX2luZmxvdyIgPSAiVW50ZXJzZWUgKGF0IGluZmxvdykiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9TQl9pbl9MVVNfc2VkX0xVU19zZWRpbWVudCIgPSAiU2VkaW1lbnQgKGF0IGluZmxvdykiICkpKSArDQogIHRoZW1lX2xpbmVkcmF3KCkgKyANCiAgbGFicyh5ID0gIkNvbnRyaWJ1dGlvbnMiLCB4PSAiUmFua2VkIGJ5IHNwYXRpYWwgZGlzdGFuY2UgIikNCg0KICANCmBgYA0KDQpXZSBoeXBvdGhlc2l6ZWQgdGhhdCBhIHN1YnN0YW50aWFsIGVmZmVjdCBvZiBwYXNzaXZlIGRpc3BlcnNhbCBvZiBtaWNyb29yZ2FuaXNtcyBvbiB0aGUgY29tcG9zaXRpb24gb2YgbWljcm9iaWFsIGNvbW11bml0aWVzIGluIHRoZSBsYWtlIHNpbmtzIHNob3VsZCByZXN1bHQgaW4gc2lnbmlmaWNhbnRseSBkZWNsaW5pbmcgY29udHJpYnV0aW9ucyBvZiBzb3VyY2VzIHdpdGggaW5jcmVhc2luZyBzcGF0aWFsIGRpc3RhbmNlIHRvIHRoZSBtYWluIGxha2UgKGkuZS4gZGlzdGFuY2UgcmFua3Mgc2luY2UgZGF0YSBvbiBleGFjdCBzcGF0aWFsIGRpc3RhbmNlcyB3ZXJlIG5vdCBhdmFpbGFibGUpLiANCg0KVGFja2xpbmcgdGhpcyBoeXBvdGhlc2lzLCB3ZSBkaWQgbm90IGZpbmQgYSBzaWduaWZpY2FudCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHNwYXRpYWwgZGlzdGFuY2UgYW5kIHNpbmsgY29udHJpYnV0aW9uLiBOb25lIG9mIHRoZSBzaW5rcyBmb2xsb3dlZCB0aGUgcHJlc3VtZWQgdHJlbmQgb2YgcmFuayAxIGhhdmluZyB0aGUgaGlnaGVzdCBzaW5rIGNvbnRyaWJ1dGlvbiBhbmQgcmFuayA4IHRoZSBsb3dlc3QsIG5vciB3YXMgdGhlcmUgYSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHJhbmtzIGJlZm9yZSB0aGUgY29ubmVjdGl2aXR5IGJhcnJpZXIgYW5kIGFmdGVyIHRoZSBiYXJyaWVyLiANClRoZSByYW5rIDYgaXMgdXBzdHJlYW0gb2YgdGhlIE1pZGRsZSBsYWtlLCB3aGljaCBpcyB0aGUgcHJlc3VtZWQgYmFycmllci4gDQoNCg0KDQojIFByZS1wcm9jZXNzaW5nIGZvciBjb21tdW5pdHkgYW5hbHlzaXMNCg0KV2UgbmVlZCB0byBhY2NvdW50IGZvciB0aGUgdW5ldmVuIHNlcXVlbmNpbmcgZGVwdGguDQpgYGB7cn0NCiMgbnVtYmVyIG9mIHJlYWRzIHBlciBzYW1wbGUNCmFzdl90YWJsZSAlPiUgY29sU3VtcygpICU+JSBzdW1tYXJ5KCkgDQoNCmBgYA0KDQpDb25zaWRlcmluZyBhbGwgc2FtcGxlcyBoYXZlIHRoZSBzYW1lIG51bWJlciBvZiByZWFkcyB0aGUgZGF0YXNldCBoYXMgY2xlYXJseSBhbHJlYWR5IGJlZW4gcmFyZWZpZWQgYnkgTHVjYXMgYmVmb3JlIGdpdmluZyBpdCB0byBtZS4NCg0KDQoNCg0KIyBBbHBoYSBkaXZlcnNpdHkNCmBgYHtyfQ0KDQpzaGFubm9uZGl2IDwtIHZlZ2FuOjpkaXZlcnNpdHkodChhc3ZfdGFibGUpKQ0KIyByZWNhbGN1bGF0aW5nIGl0IGFzIHRoZSBlZmZlY3RpdmUgbnVtYmVyIG9mIHNwZWNpZXMgdG8gYmUgbW9yZSBjb21wYXJhYmxlIGFjcm9zcyBzdHVkaWVzLg0KZW5zIDwtIGV4cChzaGFubm9uZGl2KSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSByb3duYW1lc190b19jb2x1bW4oInNhbXBsZV9pZCIpICU+JSANCiAgcmVuYW1lKCJkaXZlcnNpdHkiID0gIi4iKQ0KDQpkaXZlcnNpdHlfZGF0YSA8LSBzcGVjbnVtYmVyKHQoYXN2X3RhYmxlKSkgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGVfaWQiKSAlPiUgDQogIHJlbmFtZSgicmljaG5lc3MiID0gIi4iKSAlPiUgaW5uZXJfam9pbiguLCBlbnMsIGJ5ID0ic2FtcGxlX2lkIiApDQoNCiMgd2Ugd2lsbCBwbG90IGRpdmVyc2l0eSBieSBzb3VyY2Ugc28gbWFrZSBjbGVhbiBjYXRlZ29yaXphdGlvbiBoZXJlDQpmZWFzdF9tZXRhZGF0YSAlPiUgDQogICMgcmVtb3ZlIGxhc3QgdHdvIHN0cmluZ3MNCiAgbXV0YXRlKEVudiA9IHN0cl9yZW1vdmUoRW52LCAiLnsyfSQiKSkgJT4lIA0KICAjIHdoZXJlIFNvdXJjZVNpbmsgY29sdW1uIGlzIGEgc291cmNlIGtlZXAgdGhlIHZhbHVlIGZyb20gdGhlIEVudiBjb2x1bW4NCiAgbXV0YXRlKFNvdXJjZV9jYXRlZ29yeSA9IGNhc2Vfd2hlbihTb3VyY2VTaW5rID09ICJTb3VyY2UiIH4gRW52LA0KICAjIG90aGVyd2lzZSBrZWVwIHRoZSB2YWx1ZSBmcm9tIFNvdXJjZVNpbmsgY29sdW1uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gU291cmNlU2luaykgKSAlPiUgDQogICMgc29tZSB0cm91YmxlIHdpdGggc291cmNlIDMNCiAgbXV0YXRlKFNvdXJjZV9jYXRlZ29yeSA9IGNhc2Vfd2hlbihTb3VyY2VfY2F0ZWdvcnkgJWluJSBjKCJzb3VyY2UzIiwgInNvdXJjZTNfIikgfiAic291cmNlMyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+U291cmNlX2NhdGVnb3J5KSkgJT4lIA0KICANCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGVfaWQiKSAgJT4lIA0KICBzZWxlY3QoInNhbXBsZV9pZCIsICJTb3VyY2VfY2F0ZWdvcnkiKSAlPiUgDQogIG11dGF0ZShTb3VyY2VfY2F0ZWdvcnkgPSBhcy5mYWN0b3IoU291cmNlX2NhdGVnb3J5KSkgJT4lIA0KICAjIHdlIG5vdyBoYXZlIGNsZWFuIGNhdGVnb3J5IGFuZCBjYW4gY29ubmVjdCBpdCB0byB0aGUgZGl2ZXJzaXR5IGRhdGENCiAgaW5uZXJfam9pbiguLCBkaXZlcnNpdHlfZGF0YSwgICBieSA9ICJzYW1wbGVfaWQiKSAlPiUgDQogIHNlbGVjdCgtc2FtcGxlX2lkKSAlPiUgDQogIA0KICAjcGl2b3QgbG9uZ2VyIHNvIHdlIGNhbiBmYWNldA0KICBwaXZvdF9sb25nZXIoY29scyA9IC1Tb3VyY2VfY2F0ZWdvcnksIG5hbWVzX3RvID0gIm1lYXN1cmUiLCB2YWx1ZXNfdG8gPSAidmFsdWVzIikgJT4lIA0KICANCiAgIyBwbG90DQogIGdncGxvdCggYWVzKHggPSBTb3VyY2VfY2F0ZWdvcnksIHkgPSB2YWx1ZXMpKSArDQogICNzdGF0X2JveHBsb3QoZ2VvbSA9J2Vycm9yYmFyJykgKyANCiAgZ2VvbV9ib3hwbG90KGZpbGwgPSAidmlvbGV0IikgKw0KICB0aGVtZV9saW5lZHJhdygpKw0KICBjb29yZF9mbGlwKCkgKyANCiAgZmFjZXRfd3JhcCh+bWVhc3VyZSwgc2NhbGVzID0gImZyZWUiLCAgbGFiZWxsZXIgPSANCiAgICAgICAgICAgICAgIGFzX2xhYmVsbGVyKCBjKCJkaXZlcnNpdHkiID0gIlNoYW5ub24ncyBkaXZlcnNpdHkgaW5kZXgiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJyaWNobmVzcyIgPSAiUmljaG5lc3MiKSApICkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xNCxmYWNlPSJib2xkIiksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemU9MTAsZmFjZT0iYm9sZCIpLA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpICsNCiAgbGFicyggeCA9ICJTb3VyY2UgY2F0ZWdvcnkiLA0KICAgICAgIHkgPSBOVUxMKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiU2luayIsICAiU291cmNlIDEiLCAiU291cmNlIDIiLCAiU291cmNlIDMiLCAiU291cmNlIDQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU291cmNlIDUiLCAiU291cmNlIDYiLCAgIlNvdXJjZSA3IiwgICJTb3VyY2UgOCIpKSAgDQoNCg0KDQpgYGANCg0KUmljaG5lc3Mgb2YgdGhlIHNpbmtzIHdhcyB0aGUgbG93ZXN0IGNvbXBhcmVkIHRvIHNvdXJjZSByaWNobmVzcy4gU291cmNlcyA3LCBhbmQgOCwNCndoaWNoIGhhdmUgYSBkaXJlY3QgaW5mbG93IHRvIHRoZSBzaW5rcywgaGFkIHRoZSBoaWdoZXN0IHJpY2huZXNzLiBTb3VyY2UgMSwgd2hpY2ggbWFrZXMgYSBiaWcNCmNvbnRyaWJ1dGlvbiB0byBzaW5rIGNvbW11bml0aWVzIGhhZCBoaWdoZXIgcmljaG5lc3MgdGhhbiB0aGUgc2lua3MgaXQNCmNvbnRyaWJ1dGVkIHRvLg0KDQpTaW5rIGV2ZW5uZXNzIHdhcyBsb3dlciB0aGFuIGV2ZW5uZXNzIG9mIHNvdXJjZXMuIFNwZWNpZXMgZGlzdHJpYnV0aW9uIG9mIHRoZSBzaW5rIGxlYW5zIHRvd2FyZHMgYQ0KZmV3IHZlcnkgZG9taW5hbnQgQVNWcyBhbmQgbWFueSByYXJlIG9uZXMsIGluZGljYXRpbmcgcG9zc2libGUgaGFyZGVyIGVudmlyb25tZW50YWwgY29uZGl0aW9ucyBvciBiaWdnZXINCmNvbXBldGl0aXZlbmVzcyBpbiBzaW5rLiBTb3VyY2UgMywgd2l0aCBpdHMgc29pbCBzYW1wbGVzLCBoYWQgaGlnaCBldmVubmVzcy4gU291cmNlIDQgKGdyb3VuZHdhdGVyKSBoYWQgc2xpZ2h0bHkgbG93ZXINCmV2ZW5uZXNzIGFuZCByaWNobmVzcyBpbiBjb21wYXJpc29uIHRvIG90aGVyIHNvdXJjZXMuDQoNClRlc3QgaXQ6DQpgYGB7ciwgcmVzdWx0cz0naGlkZSd9DQojIDEuIHRoZSBzYW1lIGRhdGEgbWFuaXB1bGF0aW9uIGFzIGFib3ZlDQpmZWFzdF9tZXRhZGF0YSAlPiUgDQogIG11dGF0ZShFbnYgPSBzdHJfcmVtb3ZlKEVudiwgIi57Mn0kIikpICU+JSANCiAgbXV0YXRlKFNvdXJjZV9jYXRlZ29yeSA9IGNhc2Vfd2hlbihTb3VyY2VTaW5rID09ICJTb3VyY2UiIH4gRW52LCAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBTb3VyY2VTaW5rKSApICU+JSANCiAgbXV0YXRlKFNvdXJjZV9jYXRlZ29yeSA9IGNhc2Vfd2hlbihTb3VyY2VfY2F0ZWdvcnkgJWluJSBjKCJzb3VyY2UzIiwgInNvdXJjZTNfIikgfiAic291cmNlMyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+U291cmNlX2NhdGVnb3J5KSkgJT4lIA0KICANCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGVfaWQiKSAgJT4lIA0KICBzZWxlY3QoInNhbXBsZV9pZCIsICJTb3VyY2VfY2F0ZWdvcnkiKSAlPiUgDQogIG11dGF0ZShTb3VyY2VfY2F0ZWdvcnkgPSBhcy5mYWN0b3IoU291cmNlX2NhdGVnb3J5KSkgJT4lIA0KICBpbm5lcl9qb2luKC4sIGRpdmVyc2l0eV9kYXRhLCAgIGJ5ID0gInNhbXBsZV9pZCIpICU+JSANCiAgc2VsZWN0KC1zYW1wbGVfaWQpIC0+IGRhdGFfZm9yX2FscGhhDQoNCg0KIyAyLiBwZXJmb3JtIEFOT1ZBLyBrcnVza2FsLXdhbGxpcw0KDQojIDEuIGFzc3VtcHRpb24gb2YgQU5PVkE6IE5vcm1hbCBkaXN0cmlidXRpb246IA0KIyBFYWNoIHBvcHVsYXRpb24gdG8gYmUgY29tcGFyZWQgc2hvdWxkIGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIA0KIyAoTk9UIFRIRSBFTlRJUkUgREFUQVNFVCkuDQpzaGFwaXJvLnRlc3QgKCAgZGF0YV9mb3JfYWxwaGFbd2hpY2goZGF0YV9mb3JfYWxwaGEkU291cmNlX2NhdGVnb3J5ID09ICJzb3VyY2UxIiksICJkaXZlcnNpdHkiXSApICMgTk9UIE5EDQpzaGFwaXJvLnRlc3QgKCAgZGF0YV9mb3JfYWxwaGFbd2hpY2goZGF0YV9mb3JfYWxwaGEkU291cmNlX2NhdGVnb3J5ID09ICJzb3VyY2UyIiksICJkaXZlcnNpdHkiXSApICMgTkQNCnNoYXBpcm8udGVzdCAoICBkYXRhX2Zvcl9hbHBoYVt3aGljaChkYXRhX2Zvcl9hbHBoYSRTb3VyY2VfY2F0ZWdvcnkgPT0gInNvdXJjZTMiKSwgImRpdmVyc2l0eSJdICkgIyBORA0Kc2hhcGlyby50ZXN0ICggIGRhdGFfZm9yX2FscGhhW3doaWNoKGRhdGFfZm9yX2FscGhhJFNvdXJjZV9jYXRlZ29yeSA9PSAic291cmNlNCIpLCAiZGl2ZXJzaXR5Il0gKSAjIE5PVCBORA0Kc2hhcGlyby50ZXN0ICggIGRhdGFfZm9yX2FscGhhW3doaWNoKGRhdGFfZm9yX2FscGhhJFNvdXJjZV9jYXRlZ29yeSA9PSAic291cmNlNSIpLCAiZGl2ZXJzaXR5Il0gKSAjIE5PVCBORA0Kc2hhcGlyby50ZXN0ICggIGRhdGFfZm9yX2FscGhhW3doaWNoKGRhdGFfZm9yX2FscGhhJFNvdXJjZV9jYXRlZ29yeSA9PSAic291cmNlNiIpLCAiZGl2ZXJzaXR5Il0gKSAjIE5EDQojIHNvdXJjZSA3IGlzIHRvbyBzbWFsbCBzYW1wbGUgc2l6ZSB0byBwZXJmb3JtIHRoZSB0ZXN0ICANCnNoYXBpcm8udGVzdCAoICBkYXRhX2Zvcl9hbHBoYVt3aGljaChkYXRhX2Zvcl9hbHBoYSRTb3VyY2VfY2F0ZWdvcnkgPT0gInNvdXJjZTgiKSwgImRpdmVyc2l0eSJdICkgIyBORA0Kc2hhcGlyby50ZXN0ICggIGRhdGFfZm9yX2FscGhhW3doaWNoKGRhdGFfZm9yX2FscGhhJFNvdXJjZV9jYXRlZ29yeSA9PSAiU2luayIpLCAiZGl2ZXJzaXR5Il0gKSAjIE5EDQoNCiMgQTogd291bGQgYmUgYmV0dGVyIHRvIGRvIGEgbm9uLXBhcmFtZXRyaWMgdGVzdA0KDQoNCiMjIDIuIGFzc3VtcHRpb24gb2YgQU5PVkE6IEhvbW9nZW5laXR5IG9mIHZhcmlhbmNlOiANCiMjIFZhcmlhbmNlIGluIHRoZSBwb3B1bGF0aW9ucyBjb21wYXJlZCBzaG91bGQgYmUgdGhlIHNhbWUvc2ltaWxhci4gDQpiYXJ0bGV0dC50ZXN0ICggZGl2ZXJzaXR5IH4gU291cmNlX2NhdGVnb3J5LCBkYXRhPSBkYXRhX2Zvcl9hbHBoYSApDQojIGFzc3VtcHRpb24gbWV0DQoNCg0KIyAzLiB0ZXN0DQprcnVza2FsLnRlc3QgKGRpdmVyc2l0eSB+IFNvdXJjZV9jYXRlZ29yeSwgZGF0YT0gZGF0YV9mb3JfYWxwaGEpIA0KIyA0LiBwb3N0LWhvYw0KRlNBOjpkdW5uVGVzdChkaXZlcnNpdHkgfiBTb3VyY2VfY2F0ZWdvcnksIGRhdGE9IGRhdGFfZm9yX2FscGhhKQ0KYGBgDQoNCkV2ZW4gdGhvdWdoIG9uZSBhc3N1bXB0aW9uIGlzIG1ldCAoaG9tLnZhci4pIHdlIHNob3VsZCBub3QgdXNlIEFOT1ZBIC0gdGhlIGFzc3VtcHRpb24gb2YgaG9tb2dlbmVpdHkgb2YgdmFyaWFuY2UgaXMgYW4gZXh0ZW5zaW9uIG9mIHRoZSBhc3N1bXB0aW9uIG9mIG5vcm1hbGl0eS4gSXQgd291bGQgbm90IGJlIGZlYXNpYmxlIHRvIGNvbXBhcmUgYSBza2V3ZWQgZGlzdHJpYnV0aW9uIGluIG9uZSBncm91cCB0byBhIG5vcm1hbCBkaXN0cmlidXRpb24gaW4gYW5vdGhlciBncm91cCwgZXZlbiBpZiB0aGV5IGhhdmUgY29tcGFyYWJsZSB2YXJpYW5jZXMhDQoNCktydXNrYWwtV2FsbGlzIHRlc3QgY29uZmlybXMgZGlmZmVyZW5jZXMgaW4gc2hhbm5vbidzIGluZGV4LiBXZSBkbyBwb3N0LWhvYyBkaWFnbm9zaW5nIHRvIHNlZSB3aGljaCBncm91cHMgYXJlIGRpZmZlcmVudCB3aXRoIGEgRHVubiB0ZXN0LiBUaGUgZGlmZmVyZW5jZSB3aGljaCBpcyBzdGF0aXN0aWNhbGx5IHNvdW5kIGlzIHRoZSBkaXZlcnNpdHkgbGV2ZWxzIGJldHdlZW4gdGhlIHNvdXJjZSAzIHNhbXBsZXMgYW5kIHRoZSBTaW5rLCBhZnRlciBhZGp1c3RpbmcgdGhlIHAtdmFsdWUuDQoNClNpbmNlIHNvdXJjZSAzIGNvbnNpc3RzIG9mIHNvaWwgc2FtcGxlcywgaXQgaXMgbm90IHVuZXhwZWN0ZWQgdGhhdCBpdCB3b3VsZCBoYXZlIGhpZ2hlciBkaXZlcnNpdHkuDQoNCg0KIyBCZXRhIGRpdmVyc2l0eQ0KYGBge3IsIHJlc3VsdHM9J2hpZGUnLCB3YXJuaW5nPUZBTFNFfQ0KYmNfZGlzcyA8LSB2ZWdkaXN0KHQoYXN2X3RhYmxlKSwgbWV0aG9kID0gImJyYXkiKQ0Kbm1kcyA8LSBtZXRhTURTKGJjX2Rpc3MpDQoNCg0KIyBtYWtlIHBhbGV0dGUgZm9yIHBsb3R0aW5nDQpwYWwgPSBjKCJncmVlbjQiLCAibmF2eSIsICJvcmFuZ2UiLCAiYnJvd24iLCAiYmx1ZSIsICJsaWdodGJsdWUiKQ0KDQoNCiMgbGV0cyBwbG90IGFuIG5tZHMgd2hlcmUgdGhlIGNvbG9yIGlzIHNhbXBsZSB0eXBlLCBzaGFwZSBpcyBzb3VyY2Ugc2luaw0KYXMuZGF0YS5mcmFtZShubWRzJHBvaW50cykgJT4lIA0KICBjYmluZChkYXRhX2Zvcl9hbHBoYSRTb3VyY2VfY2F0ZWdvcnksIG1ldGFkYXRhX3R5cGUkdHlwZV9JSUkpICU+JSANCiAgcmVuYW1lKCJzb3VyY2VfY2F0IiA9ICJkYXRhX2Zvcl9hbHBoYSRTb3VyY2VfY2F0ZWdvcnkiLA0KICAgICAgICAgInR5cGUiID0gIm1ldGFkYXRhX3R5cGUkdHlwZV9JSUkiKSAlPiUgDQogIG11dGF0ZShzb3VyY2VfY2F0ID0gY2FzZV93aGVuKHNvdXJjZV9jYXQgPT0gIlNpbmsiIH4gInNpbmsiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gInNvdXJjZSIpKSAtPiAgZGF0YV9mb3Jfbm1kcw0KICANCiMgcGxvdCANCmRhdGFfZm9yX25tZHMgJT4lICAgDQogIGdncGxvdChhZXMoeCA9IE1EUzEsIHkgPSBNRFMyKSkgKw0KICBnZW9tX3BvaW50KGFlcyhmaWxsID0gdHlwZSwgY29sb3IgPSB0eXBlLCANCiAgICAgICAgICAgICAgICAgc2hhcGU9IHNvdXJjZV9jYXQpLCANCiAgICAgICAgICAgICBzaXplID0gNSwgc3Ryb2tlPTEsIGFscGhhID0gMC42KSArDQojIGN1c3RvbWl6aW5nIHRoZSBwbG90ICANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gIHBhbCkgKyANCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbCkgKw0KICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygyMSwyMykpICsNCiAgDQogIHRoZW1lX2xpbmVkcmF3KCkgKw0KICBhbm5vdGF0ZShnZW9tPSJ0ZXh0Iix4PS0xLjQsIHk9MS41LCBsYWJlbD0ic3RyZXNzID0iLCBjb2xvcj0iYmxhY2siKSArICAgDQogIGFubm90YXRlKGdlb209InRleHQiLCB4PS0xLjEsIHk9MS41LCBsYWJlbD1yb3VuZChubWRzJHN0cmVzcyw0KSwNCiAgICAgICAgICAgY29sb3I9ImJsYWNrIikgKw0KICANCiAgI3N0YXRfZWxsaXBzZShhZXMoY29sb3VyID0gdHlwZSksIGxpbmV3aWR0aCA9IDAuMykgKyANCiAgI3N0YXRfZWxsaXBzZShhZXMoZmlsbCA9IHR5cGUpLCBnZW9tPSJwb2x5Z29uIixsZXZlbD0wLjk1LGFscGhhPTAuMDQpICsNCiAgDQogIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXkiKSkgKw0KICBsYWJzKGNvbG9yID0gIldhdGVyIFxudHlwZSIsIHNoYXBlID0gIlNvdXJjZSIpICsNCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDApLCBjb2xvciA9ICJncmV5NzAiLCBsaW5ldHlwZSA9IDIpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygwKSwgY29sb3IgPSAiZ3JleTcwIiwgbGluZXR5cGUgPSAyKSAtPiBwbG90X25tZHMNCiAgDQoNCg0KDQpgYGANCg0KVGhlcmUgd2FzIGNsZWFyIGdyb3VwaW5nIG9mIHNvaWwgYW5kIHNlZGltZW50IGNvbW11bml0aWVzLiANClN1cmZhY2Ugd2F0ZXIsIHNwcmluZyB3YXRlciBhbmQgYmlvZmlsbSBjb21tdW5pdGllcyB3ZXJlIG1vcmUgc3ByZWFkIG91dCwgYW5kIG1vcmUgZGlzc2ltaWxhciB0byBzb2lsIHRoYW4gdG8gc2VkaW1lbnQNCmNvbW11bml0aWVzLg0KDQpPdXQgb2YgZml2ZSBzaW5rcywgZm91ciB3YXRlciBhbmQgb25lIHNlZGltZW50IHNpbmssIHRoZSBtb3N0IHNpbWlsYXIgdG8gc2VkaW1lbnQgc291cmNlIHNhbXBsZXMsIGluIHRlcm1zIG9mIGNvbW11bml0eSBhc3NlbWJseSwgd2FzIHRoZSBzZWRpbWVudCBzaW5rLiBJdCBpcyBhbHNvIGNsb3NlciB0byB0aGUgc29pbCBzb3VyY2VzLCB3aGVyZWFzIHdhdGVyIHNpbmtzIGNvbW11bml0aWVzIHNob3dlZCBsaXR0bGUgc2ltaWxhcml0eSB0byBzb2lsIHNvdXJjZXMuDQoNCmBgYHtyfQ0KcGxvdF9ubWRzDQpgYGANCg0KIyMgVGVzdCBjb21tdW5pdHkgZGlmZmVyZW5jZXMNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0NCiMgdGVzdCBkaWZmZXJlbmNlcyBpbiBncm91cCBjZW50cm9pZCB3aXRoIGFkb25pcyAoYW5vdmEgdmVyc2lvbiBmb3IgbXVsdGl2YXJpYXRlIHN0YXRpc3RpY3MpDQpwZXJtYW5vdmEgPC0gYWRvbmlzMih0KGFzdl90YWJsZSkgfiBkYXRhX2Zvcl9ubWRzJHR5cGUsIA0KICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiYnJheSIgLCBwZXJtdXRhdGlvbnMgPSA5OTkpDQpwZXJtYW5vdmEgIyAwLjAwMQ0KcGFpcl9yZXMgPC0gcGFpcndpc2VBZG9uaXM6OnBhaXJ3aXNlLmFkb25pczIodChhc3ZfdGFibGUpIH4gdHlwZSwgZGF0YSA9IGRhdGFfZm9yX25tZHMpDQojIFNwcmluZ192c19TdXJmYWNlLCBHV192c19TcHJpbmcgYXJlIG9ubHkgb25lIG5vdCBzaWduaWZpY2FudGx5IGRpc3RpbmN0ISENCg0KDQojIHRlc3QgZGlzcGVyc2lvbiBhcyBhbiBhc3N1bXB0aW9uICh2YXJpYW5jZSB0ZXN0IGZvciBtdWx0aXZhcmlhdGUgc3RhdGl0aWNzKQ0KZGlzcCA8LSBiZXRhZGlzcGVyKCB2ZWdkaXN0KCAgdChhc3ZfdGFibGUpLCBtZXRob2QgPSAiYnJheSIgKSwgZGF0YV9mb3Jfbm1kcyR0eXBlKSANCmFub3ZhKGRpc3ApDQpUdWtleUhTRChkaXNwKSANCiMgU3VyZmFjZS1HVyBoYXZlIGRpZmYgZGlzcGVyc2lvbnMsIGRvZXMgbm90IGludGVyZmVyZSB3aXRoIGNlbnRyb2lkIGRpZmZlcmVuY2VzDQoNCiANCmBgYA0KDQoNClRoZXJlIGlzIHNpZ25pZmlpY2FudCBkaWZmZXJlbmNlIGluIGNvbW11bml0aWVzIG9mIGRpZmZlcmVudCBzYW1wbGUgdHlwZSAoKioqKS4NCkJpb2ZpbG0sIHNlZGltZW50IGFuZCBzb2lsIGFyZSBkaXN0aW5jdGx5IGRpZmZlcmVudCBmcm9tIGVhY2ggb3RoZXIgYW5kIGZyb20gc3VyZmFjZSB3YXRlciwgZ3JvdW5kd2F0ZXIgYW5kIHNwcmluZy4NClN1cmZhY2Ugd2F0ZXIsIGdyb3VuZHdhdGVyIGFuZCBzcHJpbmcgYXJlIG5vdCBlYXNpbHkgaWRlbnRpZmlhYmxlIGJldHdlZW4gdGhlbXNlbHZlcy4NCg0KDQojIEVudmlyb25tZW50YWwgZGF0YQ0KDQojIyBwY2EgKGVudmlyb25tZW50YSB2YXJpYWJsZXMgb2Ygd2F0ZXIgY29tbXVuaXRpZXMpDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCmRmX3BjYSA8LSBtZXRhZGF0YSAlPiUgDQogICMgd2Ugb25seSBoYXZlIG1lYXN1cmVtZW50cyBmb3Igd2F0ZXIsIG5vdCBmb3Igc29pbCBub3Igc2VkaW1lbnQgDQogIGZpbHRlcih0eXBlX0kgPT0gIldhdGVyIikgJT4lIA0KICBzZWxlY3Qod2hlcmUoaXMubnVtZXJpYykpICU+JSANCiAgc2VsZWN0KC1jKCJmaWx0ZXIiLCAjIGRvbnQgbmVlZCBpdA0KICAgICAgICAgICAgIk5fTk8yIiwgIlBfUE80IikpICMgTkFzDQogDQoNCiMgcmVtb3ZlIHRoZSBoaWdobHkgY29ycmVsYXRlZCBvbmVzLCBsaWtlIGludGVybmFsQVRQIGFuZCB0b3RhbEFUUA0KY29yX21hdHJpeCA8LSBjb3IoZGZfcGNhKQ0KaGlnaGx5X2NvcnJlbGF0ZWQgPC0gY2FyZXQ6OmZpbmRDb3JyZWxhdGlvbihjb3JfbWF0cml4LCBjdXRvZmYgPSAwLjkpDQpkZl9wY2EgPC0gZGZfcGNhWywgLWhpZ2hseV9jb3JyZWxhdGVkXQ0KDQojIG5vdyB0aGVyZSBpcyAyMiBvYnNlcnZhdGlvbnMgYW5kIDEwIGVudmlyb25tZW50YWwgdmFyaWFibGVzDQojIGxldHMgc2VlIGlmIGFueSBlbnYgdmFycyBjYW4gYmUgcGFja2VkIG5lYXRseSBpbiBQQ3MNCnBjYV9lbnYgPC0gcHJjb21wKGRmX3BjYSwgc2NhbGUgPSBUUlVFKQ0KYmlwbG90KHBjYV9lbnYpDQoNCiMgaSBiZWxpZXZlIGl0IGlzIGJlbmVmaWNpYWwgdG8gcmVtb3ZlIHRoZSBzYW1wbGUgUFhfZ3cgc2luY2UgaXQgaXMgYSBzaW5nbGUgb3V0bGllciBpbiBhbG1vc3QgZXZlcnkgdmFyaWFibGUsIGFuZCBzdHJlc3NlcyB0aGUgb3JkaW5hdGlvbg0KcGNhX2VudiA8LSBwcmNvbXAoZGZfcGNhW3Jvd25hbWVzKGRmX3BjYSkgIT0gIlBYX2d3IixdLCBzY2FsZSA9IFRSVUUpDQoNCg0KIyB3ZSBuZWVkIHRoZSBjb2x1bW4gZm9yIGNvbG9yaW5nIGJ5IHR5cGUsIGdldCBpdCBmcm9tIHRoZSBvcmlnaW5hbCBtZXRhZGF0YQ0KIG1ldGFkYXRhW3Jvd25hbWVzKGRmX3BjYSkgIT0gIlBYX2d3IiwgYyhjb2xuYW1lcyhkZl9wY2EpLCAidHlwZV9JSUkiLCAidHlwZV9JIildICU+JSANCiAgICMgcmVtb3ZlIHRoZSBvdXRsaWVyIHNhbXBsZSwgdGhlIGNvbHVtbnMgdGhhdCBhcmUgaGlnaGx5IGNvcnJlbGF0ZWQgYW5kIHNvaWwvc2VkIHNhbXBsZXMNCiAgZmlsdGVyKHR5cGVfSSA9PSAiV2F0ZXIiKSAtPiBkYXRhX2Zvcl9wY2ENCg0KYXV0b3Bsb3QocGNhX2VudiwgZGF0YSA9ZGF0YV9mb3JfcGNhICwgDQogICAgICAgICBjb2xvdXIgPSAndHlwZV9JSUknLA0KICAgICAgICAgc2l6ZT01LCBsb2FkaW5ncz1UUlVFLCANCiAgICAgICAgIGxvYWRpbmdzLmNvbG91cj0iYmxhY2siLCANCiAgICAgICAgIGxvYWRpbmdzLmxhYmVsPVRSVUUsIGxvYWRpbmdzLmxhYmVsLnNpemU9NSwgDQogICAgICAgICBsb2FkaW5ncy5sYWJlbC5jb2xvdXI9ImJsYWNrIiApKyANCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygwKSwgY29sb3IgPSAiZ3JleTcwIiwgbGluZXR5cGUgPSAyKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGMoMCksIGNvbG9yID0gImdyZXk3MCIsIGxpbmV0eXBlID0gMikgKw0KICBnZW9tX3BvaW50KHNoYXBlPSAyMSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNSkgKyANCiAgdGhlbWVfbGluZWRyYXcoKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMCksIGNvbG9yID0gImdyZXk3MCIsIGxpbmV0eXBlID0gMikgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKDApLCBjb2xvciA9ICJncmV5NzAiLCBsaW5ldHlwZSA9IDIpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiQWNjZW50IikrDQogIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXkiKSkgIC0+IHBjYV9wbG90DQoNCnBjYV9wbG90DQpgYGANCg0KDQoNCg0KDQpUaGUgZmlyc3QgdGhyZWUgY29tcG9uZW50cyBoYXZlIDErIHZhcmlhbmNlIGV4cGxhbmF0aW9uLiBTZWUgbW9yZSBkZXRhaWxlZCB3aGF0IFBDMSwgUEMyIGFuZCBQQzMgKGFzIGNvbWJpbmF0aW9ucyBvZiBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcykgY29uc2lzdCBvZi4NCg0KDQpub3JtYWwgZGF0YTogdmFyaWFuY2UgPSAoc3QuZGV2KV4yIHBjYSBkYXRhOiBlaWdlbnZhbHVlID0gKHN0LmRldileMg0K4oCcZWlnZW52YWx1ZXMgcmVwcmVzZW50IHRoZSB2YXJpYW5jZSBleHBsYWluZWQgYnkgZWFjaCBwcmluY2lwYWwgY29tcG9uZW504oCdIC0+IGVpZ2VuIH4gdmFyaWFuY2UNCg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naG9sZCd9DQoNCiMgRXh0cmFjdCB0aGUgbG9hZGluZ3MgZnJvbSB0aGUgUENBIHJlc3VsdCBhbmQgY29udmVydCB0byB0aWR5IGZvcm1hdCANCmxvYWRpbmdzX2RmIDwtICAgdGlkeShwY2FfZW52LCBtYXRyaXggPSAicm90YXRpb24iKQ0KDQoNCiMgUEMxDQojIENyZWF0ZSB0aGUgZ2dwbG90MiBvYmplY3QgZm9yIHBsb3R0aW5nIHRoZSBsb2FkaW5ncw0KbG9hZGluZ3NfZGYgJT4lIGZpbHRlcihQQyA9PSAiMSIpICU+JSANCiAgI3g9cmVvcmRlcihjbGFzcywtYW1vdW50LHN1bSkNCmdncGxvdCggYWVzKHggPSByZW9yZGVyKGNvbHVtbiwgLXZhbHVlKSwgeSA9IHZhbHVlLCBncm91cCA9IGZhY3Rvcihjb2x1bW4pKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCANCiAgICAgICAgICAgZmlsbD0gImdyYXk5MCIsIGNvbG9yID0gImdyYXkyMCIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGNvbHVtbiksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpLCANCiAgICAgICAgICAgICN2anVzdCA9ICJpbndhcmQiLCAgDQogICAgICAgICAgICBhbmdsZSA9IDkwICwgaGp1c3QgPSAiaW53YXJkIikgKw0KICBsYWJzKHggPSAiVmFyaWFibGVzIG9mIFBDMSIsIHkgPSAiTG9hZGluZ3MiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICAtPiBwbG90X3BjYTENCg0KIyBQQzIgDQpsb2FkaW5nc19kZiAlPiUgZmlsdGVyKFBDID09ICIyIikgJT4lIA0KICAjeD1yZW9yZGVyKGNsYXNzLC1hbW91bnQsc3VtKQ0KZ2dwbG90KCBhZXMoeCA9IHJlb3JkZXIoY29sdW1uLCAtdmFsdWUpLCB5ID0gdmFsdWUsIGdyb3VwID0gZmFjdG9yKGNvbHVtbikpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIA0KICAgICAgICAgICBmaWxsPSAiZ3JheTkwIiwgY29sb3IgPSAiZ3JheTIwIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY29sdW1uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIA0KICAgICAgICAgICAgI3ZqdXN0ID0gImlud2FyZCIsICANCiAgICAgICAgICAgIGFuZ2xlID0gOTAgLCBoanVzdCA9ICJpbndhcmQiKSArDQogIGxhYnMoeCA9ICJWYXJpYWJsZXMgb2YgUEMyIiwgeSA9ICJMb2FkaW5ncyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgLT4gcGxvdF9wY2EyDQoNCiMgUEMzDQpsb2FkaW5nc19kZiAlPiUgZmlsdGVyKFBDID09ICIzIikgJT4lIA0KICAjeD1yZW9yZGVyKGNsYXNzLC1hbW91bnQsc3VtKQ0KZ2dwbG90KCBhZXMoeCA9IHJlb3JkZXIoY29sdW1uLCAtdmFsdWUpLCB5ID0gdmFsdWUsIGdyb3VwID0gZmFjdG9yKGNvbHVtbikpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIA0KICAgICAgICAgICBmaWxsPSAiZ3JheTkwIiwgY29sb3IgPSAiZ3JheTIwIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY29sdW1uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIA0KICAgICAgICAgICAgI3ZqdXN0ID0gImlud2FyZCIsICANCiAgICAgICAgICAgIGFuZ2xlID0gOTAgLCBoanVzdCA9ICJpbndhcmQiKSArDQogIGxhYnMoeCA9ICJWYXJpYWJsZXMgb2YgUEMzIiwgeSA9ICJMb2FkaW5ncyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgLT4gcGxvdF9wY2EzDQoNCnBsb3RfcGNhMSArIHBsb3RfcGNhMiArIHBsb3RfcGNhMw0KYGBgDQoNCg0KVGVzdCBwY2EgZGlzcGVyc2lvbnMuDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCiMgd2UgY2FuIGNoZWNrIHRoZSBzaWduaWZpY2FuY2UgaW4gZGlmZmVyZW5jZSBiZXR3ZWVuIGdyb3VwcyBpbiBib3RoIHBjYSBhbmQgbm1kcw0KDQpldWNsaWRlYW5fZGlzdCA8LSBkYXRhX2Zvcl9wY2EgJT4lIHNlbGVjdCgtYygidHlwZV9JIiAsICJ0eXBlX0lJSSIpKSAlPiUgDQogICAgICAgICAgICAgICAgICBzY2FsZSgpICU+JSBhcy5kYXRhLmZyYW1lKCkgICU+JSANCiAgICAgICAgICAgICAgICAgIGRpc3QoLiwgbWV0aG9kID0gImV1Y2xpZGVhbiIpIA0KDQpkaXNwX3BjYSA8LSBiZXRhZGlzcGVyKCBldWNsaWRlYW5fZGlzdCwgZGF0YV9mb3JfcGNhJHR5cGVfSUlJICkNCmFub3ZhKGRpc3BfcGNhKSAjbm8gc2lnbi4gZGlmZmVyZW5jZXMgDQoNCg0KZGlzcF9wY2EkZGlzdGFuY2VzICU+JSBhcy5kYXRhLmZyYW1lKCkgJT4lIA0KICByZW5hbWUoIkRpc3RhbmNlIiA9ICIuIikgJT4lIA0KICByb3duYW1lc190b19jb2x1bW4oInNhbXBsZV9pZCIpICU+JSANCiAgY2JpbmQoZGF0YV9mb3JfcGNhKSAlPiUgDQojIHBsb3QNCiAgZ2dwbG90KCBhZXMoeCA9IHR5cGVfSUlJLCB5ID0gRGlzdGFuY2UpKSArDQogIGdlb21fYm94cGxvdCggZmlsbCA9ICJ2aW9sZXQiKSArDQogIGxhYnMoeCA9IE5VTEwsIHkgPSAiRW52aXJvbm1lbnRhbCBkaWZmZXJlbmNlcyBcbnN0YW5kYXJkaXplZCBFdWNsaWRlYW4gZGlzdGFuY2UiKSArDQogIHRoZW1lX2xpbmVkcmF3KCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSkgLT4gcGNhX2Rpc3ANCg0KYGBgDQoNCiMjIG5tZHMgKHdhdGVyIGNvbW11bml0aWVzKQ0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KDQphc3Zfd2F0ZXIgPC0gYXN2X3RhYmxlIFsscm93bmFtZXMoZGZfcGNhKV0gJT4lIHNlbGVjdCghIlBYX2d3IikNCmJjX2Rpc3Nfd2F0ZXIgPC0gdmVnZGlzdCh0KGFzdl93YXRlciksIG1ldGhvZCA9ICJicmF5IikNCm5tZHNfd2F0ZXIgPC0gbWV0YU1EUyhiY19kaXNzX3dhdGVyKQ0KDQoNCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naG9sZCd9DQoNCmFzLmRhdGEuZnJhbWUobm1kc193YXRlciRwb2ludHMpICU+JSANCiAgY2JpbmQoZGF0YV9mb3JfcGNhJHR5cGVfSUlJKSAlPiUgDQogIHJlbmFtZSgidHlwZSIgPSAiZGF0YV9mb3JfcGNhJHR5cGVfSUlJIikgJT4lIA0KICANCiMgcGxvdCANCiAgZ2dwbG90KGFlcyh4ID0gTURTMSwgeSA9IE1EUzIpKSArDQogIGdlb21fcG9pbnQoYWVzKGZpbGwgPSB0eXBlKSwgc2hhcGUgPSAyMSwgDQogICAgICAgICAgICAgc2l6ZSA9IDUsIGNvbG9yPSAiYmxhY2siICkgKw0KIyBjdXN0b21pemluZyB0aGUgcGxvdCAgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiQWNjZW50IikgKw0KICB0aGVtZV9saW5lZHJhdygpICsNCiAgYW5ub3RhdGUoZ2VvbT0idGV4dCIseD0tMS40LCB5PTEuNSwgbGFiZWw9InN0cmVzcyA9IiwgY29sb3I9ImJsYWNrIikgKyAgIA0KICBhbm5vdGF0ZShnZW9tPSJ0ZXh0IiwgeD0tMS4xLCB5PTEuNSwgbGFiZWw9cm91bmQobm1kc193YXRlciRzdHJlc3MsNCksDQogICAgICAgICAgIGNvbG9yPSJibGFjayIpICsNCiAgDQogIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXkiKSkgKw0KICBsYWJzKGNvbG9yID0gIldhdGVyIFxudHlwZSIsIHNoYXBlID0gIlNvdXJjZSIpICsNCiAgZ3VpZGVzKGZpbGwgPSBGQUxTRSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDApLCBjb2xvciA9ICJncmV5NzAiLCBsaW5ldHlwZSA9IDIpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gYygwKSwgY29sb3IgPSAiZ3JleTcwIiwgbGluZXR5cGUgPSAyKSAtPiBubWRzX3Bsb3Rfd2F0ZXINCiAgDQoNCg0KZXVjbGlkZWFuX2Rpc3QgPC0gZGF0YV9mb3JfcGNhICU+JSBzZWxlY3QoLWMoInR5cGVfSSIgLCAidHlwZV9JSUkiKSkgJT4lIA0KICAgICAgICAgICAgICAgICAgc2NhbGUoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICAlPiUgDQogICAgICAgICAgICAgICAgICBkaXN0KC4sIG1ldGhvZCA9ICJldWNsaWRlYW4iKSANCg0KZGlzcF9ubWRzIDwtIGJldGFkaXNwZXIoIGJjX2Rpc3Nfd2F0ZXIsIGRhdGFfZm9yX3BjYSR0eXBlX0lJSSApDQphbm92YShkaXNwX25tZHMpICMgc2lnbi4gZGlmZmVyZW5jZXMgDQoNCg0KZGlzcF9ubWRzJGRpc3RhbmNlcyAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSANCiAgcmVuYW1lKCJEaXN0YW5jZSIgPSAiLiIpICU+JSANCiAgcm93bmFtZXNfdG9fY29sdW1uKCJzYW1wbGVfaWQiKSAlPiUgDQogIGNiaW5kKGRhdGFfZm9yX3BjYSkgJT4lIA0KIyBwbG90DQogIGdncGxvdCggYWVzKHggPSB0eXBlX0lJSSwgeSA9IERpc3RhbmNlKSkgKw0KICBnZW9tX2JveHBsb3QoIGZpbGwgPSAidmlvbGV0IikgKw0KICBsYWJzKHggPSBOVUxMLCB5ID0gIkJyYXktY3VydGlzIGRpc3RhbmNlIikgKw0KICB0aGVtZV9saW5lZHJhdygpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpIC0+IG5tZHNfd2F0ZXJfZGlzcA0KDQoNCiBubWRzX3Bsb3Rfd2F0ZXIgICsgcGNhX3Bsb3QgKw0KICBubWRzX3dhdGVyX2Rpc3AgKyBwY2FfZGlzcCANCmBgYA0KDQoNCkxha2UgY29tbXVuaXRpZXMgYW5kIGdyb3VuZHdhdGVyIGNvbW11bnRpZXMgc2VlbSB0byBoYXZlIHJlbGF0aXZlbHkgZGlzdGluY3QgbWljcm9iaWFsIGNvbXBvc2l0aW9uLg0KVGhlIGh5cG9yaGVpYywgcG9uZCBhbmQgaW5mbG93IHdhdGVyIGNvbnNpc3Qgb25seSBvZiBvbmUgc2FtcGxlIHBvaW50LCB3aGVuIHdlIHJlbW92ZSB0aGUgc29pbCBhbmQgc2VkaW1lbnQgc2FtcGxlcyBmb3IgdGhpcyBhbmFseXNpcywgc28gaXQgaXMgbm90IHBvc3NpYmxlIHRvIGRyYXcgY29uY2x1c2lvbnMuIEJ1dCB0aGUgcmVzdCBvZiB0aGUgc2FtcGxlcyBoYXZlIGEgc2ltaWxhciByZWxhdGlvbiBmb3IgYm90aCB0aGUgZW52aXJvbm1lbnRhbCB2YXJpYXRvbiBhbmQgdGhlIGNvbW11bml0eSB2YXJpYXRpb24gLSBlbnZpcm9ubWVudGFsIGhvbW9nZW5laXR5IG9mIHRoZSBncm91bmR3YXRlciBzYW1wbGVzIGluIHZpc2libGUgaW4gdGhlIGxvdyBkaXNwZXJzaW9uIG9mIHRoZSBncm91bmR3YXRlciBtaWNyb2JpYWwgY29tbXVuaXRpZXMuIChjaGVjayBzaWduaWZpY2FuY2UgYW5kIHB1dCBvbiBwbG90IGxhdGVyKSANCg0KIyMgQ29uc3RyYWluZWQgb3JkaWFudGlvbg0KDQpDQVAgb3JkaW5hdGlvbiBhcyBhbiBkaXN0YW5jZS1iYXNlZCBhbHRlcm5hdGl2ZSB0byB0aGUgUkRBICh3aGljaCB1c2VzIGJyYXksIGFzIG9wcG9zZWQgdG8gUkRBJ3MgZXVjbGlkZWFuKS4NCkhlbGxpbmdlciB0cmFuc2Zvcm1hdGlvbiAoc3F1YXJlIHJvb3Qgb2YgcmVsYXRpdmUgYWJ1bmRhbmNlcykgaXMgdXNlZCB0byBhY2NvdW50IGZvciBjb21wb3NpdGlvbmFsaXR5IG9mIGRhdGEuIA0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hvbGQnfQ0KDQpkYXRhX2Zvcl9wY2EgJT4lIHNlbGVjdCh3aGVyZShpcy5udW1lcmljKSkgJT4lIA0KICBzY2FsZSgpICU+JSBhcy5kYXRhLmZyYW1lKCkgLT4gZW52LmRhdGENCg0KZGVjb3N0YW5kKHQoYXN2X3dhdGVyKSwgbWV0aG9kID0gImhlbGxpbmdlciIpIC0+IHNwLmRhdA0KDQojIGNoZWNrDQppZGVudGljYWwocm93bmFtZXMoZW52LmRhdGEpLCBjb2xuYW1lcyhhc3Zfd2F0ZXIpKSAjVFJVRQ0KDQojIHBlcmZvcm0gbW9kZWwNCnNpbXBsZVJEQSA8LSBjYXBzY2FsZShzcC5kYXQgfiAgLiwgZGF0YT1lbnYuZGF0YSAsDQogICAgICAgICAgICAgICAgIGRpc3RhbmNlID0gImJyYXkiKQ0KDQp2aWYuY2NhKHNpbXBsZVJEQSkgIyBhbGwgdmFyaWFibGVzIGxvd2VyIHRoYW4gMTANCg0KDQojIHRlc3QNCg0KIyB0ZXN0IGVudiBwYWFtZXRlcnMNCmFub3ZhLm1vZGVsMyA8LSBhbm92YShzaW1wbGVSREEsIHN0ZXA9MTAwMCwgYnkgPSAidGVybSIpDQphbm92YS5tb2RlbDMNCiMgc2lnbjogYml4KiAsIGZpKioqLCBUQ0MqKiosIENvbmQsIE8yKiosICBUZW1wKg0KDQojIG5ldyBtb2RlbCANCnNpbXBsZVJEQSA8LSBjYXBzY2FsZShzcC5kYXQgfiAgYml4ICsgZmkgKyBUQ0MgKyBDb25kICsgTzIgKyBUZW1wLCBkYXRhPWVudi5kYXRhICwNCiAgICAgICAgICAgICAgICAgZGlzdGFuY2UgPSAiYnJheSIpDQojIHRlc3QgZW52IHBhYW1ldGVycw0KYW5vdmEubW9kZWwzIDwtIGFub3ZhKHNpbXBsZVJEQSwgc3RlcD0xMDAwLCBieSA9ICJ0ZXJtIikNCg0KIyB0ZXN0IG9mIGFsbCBjYW5vbmljYWwgYXhlcw0KYW5vdmEubW9kZWwgPC0gYW5vdmEuY2NhKHNpbXBsZVJEQSwgYnk9J2F4aXMnLCBzdGVwPTEwMDApICAjIENBUDEsQ0FQMixDQVAzIHNpZ25pZmljYW50IA0KDQojIHRlc3QgdGhlIHdob2xlIG1vZGVsDQphbm92YS5tb2RlbDIgPC0gYW5vdmEuY2NhKHNpbXBsZVJEQSwgc3RlcD0xMDAwKSAjIHNpZ24NClJzcXVhcmVBZGooc2ltcGxlUkRBKSRhZGouci5zcXVhcmVkICMgZXhwbGFpbnMgMzAlDQoNCmBgYA0KDQpXZSBjYW4gc2F5IHRoYXQgYml4IGFuZCBmaXgsIGFzIHdlbGwgYXMgdGhlIHRlbWVwcmF0dXJlLCBveHlnZW4gYW5kIGNvbmR1Y3Rpdml0eSBoYXZlIGFuIGltcGFjdCBvbiB0aGUgbWljcm9iaWFsIGNvbW11bml0aWVzIG9mIEx1bnkgd2F0ZXIgYm9kaWVzLiBBZGRpdGlvbmFsbHksIHRoZSBudW1iZXIgb2YgVENDIChtaWNyb2JpYWwgbG9hZCkgaW4gdGhlIHdhdGVyIGJvZHkgaXMgYWxzbyBhIHNpZ25pZmljYW50IGluZGljYXRvciBvZiB0aGUgd2F0ZXIgY29tbXVuaXR5IGNvbXBvc2l0aW9uLg0KDQoNCg0KUGxvdCB0aGUgY29uc3RyYWluZWQgb3JkaW5hdGlvbiBpZiB3ZSB3YW50IHRvIGJ1dCBpdCBjb3VsZCBiZSBhIGJpdCByZWR1bmRhZG50IGNvbnNpZGVyaW5nIHRoZSBpbmRpdmlkdWFsIG9yZGluYXRpb25zIG9mIGVudmlyb25tZW50YWwgdmFyaWFibGVzIGFuZCBjb21tdW5pdGlpZXMuIE9uIHRoZSBvdGhlciBoYW5kLCB0aGUgdmlzdWFsIGRlcGljdGlvbiBpbXBsaWVzIG5lZWQgZm9yIG1vcmUgc2FtcGxlIHBvaW50cywgY29uc2lkZXJpbmcgaG93IHNwYXJzZSB0aGUgb3JkaW5hdGlvbiBpcy4NCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdob2xkJ30NCiMgdmVjdG9ycw0KY2NhdmVjdG9ycyA8LSBhcy5tYXRyaXgoc2NvcmVzKHNpbXBsZVJEQSwgZGlzcGxheSA9ICJicCIsIHNjYWxpbmcgPSAic2l0ZXMiKSozLjMyKSAlPiUgDQogIHQoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSANCiAgcmVuYW1lKCJiaXgqIiA9ICJiaXgiLA0KICAgICAgICAgIlRlbXAqIiA9ICJUZW1wIiwNCiAgICAgICAgICJPMioqIiA9ICJPMiIsDQogICAgICAgICAiZmkqKioiID0gImZpIiwNCiAgICAgICAgICJUQ0MqKioiID0gIlRDQyIpICU+JQ0KICB0KCkgJT4lIGFzLmRhdGEuZnJhbWUoKQ0KDQojYml4KiAsIGZpKioqLCBUQ0MqKiosIENvbmQsIE8yKiosICBUZW1wKg0KDQoNCiMgc2l0ZSBjb29yZGluYXRlcw0Kc2l0ZV9kYXRhIDwtIHNjb3JlcyhzaW1wbGVSREEsIGRpc3BsYXkgPSAic2l0ZXMiKSAlPiUgDQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgDQogIGNiaW5kKC4sIGRhdGFfZm9yX3BjYSR0eXBlX0lJSSkgJT4lIA0KICByZW5hbWUoInR5cGUiID0gImRhdGFfZm9yX3BjYSR0eXBlX0lJSSIpDQoNCiMgcGxvdHRpbmcNCnBsb3RfY2NhIDwtIA0KICBzaXRlX2RhdGEgJT4lIA0KICBnZ3Bsb3QoIGFlcyh4ID0gQ0FQMSwgeSA9IENBUDIpKSArDQogIGdlb21fcG9pbnQoYWVzKGZpbGwgPSB0eXBlKSwgc2hhcGUgPSAyMSwgDQogICAgICAgICAgICAgc2l6ZSA9IDUsIGNvbG9yPSAiYmxhY2siICkrICANCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBjY2F2ZWN0b3JzLCBhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gQ0FQMSwgeWVuZCA9IENBUDIpLCANCiAgICAgICAgICAgICAgIHNpemUgPSAxLjIsIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjUsICJjbSIpKSkgKw0KICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygwKSwgY29sb3IgPSAiZ3JleTcwIiwgbGluZXR5cGUgPSAyKSArDQogICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBjKDApLCBjb2xvciA9ICJncmV5NzAiLCBsaW5ldHlwZSA9IDIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBjY2F2ZWN0b3JzLCBhZXMoeCA9IENBUDEqMS4yLCB5ID0gQ0FQMioxLjEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHJvd25hbWVzKGNjYXZlY3RvcnMpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT02ICkgKw0KICB0aGVtZV9saW5lZHJhdygpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJBY2NlbnQiKSArDQogICAgIHRoZW1lKGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyYXkiKSkgDQoNCnBsb3RfY2NhDQpgYGANCg0KVGhlcmUgaXMgY2VydGFpbiBpbmRpY2F0aW9uIHRoYXQgbWljcm9iaWFsIGNvbW11bml0eSBhc3NlbWJseSBvZiBMdW56IGxha2VzIHdhdGVyIHNhbXBsZXMgYW5kIG5lYXIgd2F0ZXIgYm9kaWVzIGlzIG5vdCBpbXBhY3RlZCBieSB0aGUgZW52aXJvbm1lbnRhbCB2YXJpYWJsZXMgd2hpY2ggd2VyZSBtZWFzdXJlZCBpbiB0aGlzIHN0dWR5LiBIb3dldmVyLCB0aGUgc2FtcGxlIHR5cGUgcHJvdmlkZWQgYSBjbGVhcmVyIGltcGFjdCBvbiBjb21tdW5pdHkNCmFzc2VtYmx5LiBTYW1wbGVzIG9mIHR5cGUgc2VkaW1lbnQsIHNvaWwgYW5kIHN1cmZhY2Ugd2F0ZXIgc2hvd2VkIGNvbW11bml0eSBzaW1pbGFyaXR5IHdpdGhpbiB0aGUgdHlwZSBjYXRlZ29yeS4gVG8gZGV0ZXJtaW5lIHdoZXRoZXIgc2FtcGxlIHR5cGUgaXMgbWVyZWx5IGEgcHJveHkgZm9yIGVjb2xvZ2ljYWwgY29uZGl0aW9ucywgZW52aXJvbm1lbnRhbCB2YXJpYWJsZXMgZm9yIHNhbXBsZXMgb3RoZXIgdGhhbiB3YXRlciBzYW1wbGVzIG5lZWQgdG8gYmUgbWVhc3VyZWQsIHdoaWNoIHdhcyBub3QgdGhlIGNhc2UgaW4gdGhpcyBzdHVkeS4gDQoNCkNvbnRyaWJ1dGlvbiBvZiBzb3VyY2VzIHRvIHNpbmtzIHdhcyBub3QgaW1wYWN0ZWQgYnkgc3BhdGlhbCBkaXN0YW5jZSwgYW5kIHRoZSBhcnRpZmljaWFsIGxha2UgcHJvdmlkZWQgbm8gcGh5c2ljYWwgYmFycmllci4gDQpDb250cmlidXRpb24gYnkgc2FtcGxlIHR5cGUgcHJvdmlkZWQgbW9yZSBhY2N1cmF0ZSBpbnNpZ2h0IHRoYW4gY29udHJpYnV0aW9uIGJ5IOKAnFNvdXJjZeKAnSBjYXRlZ29yeSwgd2hpY2ggd2FzIGFuIGFyYml0cmFyeSBjYXRlZ29yeSBkZXRlcm1pbmVkIGFzIGEgbWl4IG9mIHNhbXBsZSB0eXBlIGFuZCBkaXN0YW5jZSBmcm9tIHRoZSBzaW5rLiANCg0KVGhpcyB3YXMgc2hvd24gd2l0aCBTb3VyY2UgNiBjb250cmlidXRpb24sIGNvbnNpc3Rpbmcgb2Ygc3ByaW5nIHNlZGltZW50IGFuZCB3YXRlci4gU2FtcGxlIHR5cGUgYW5hbHlzaXMgc2hvd2VkIHRoYXQgc3ByaW5nIHNlZGltZW50IG9mIFNvdXJjZSA2IGNvbnRyaWJ1dGVkIHRvIHNpbmsgc2VkaW1lbnRzLCBhbmQgU291cmNlIDYgd2F0ZXIgc2FtcGxlcyBjb250cmlidXRlZCB0byB3YXRlciBzaW5rcy4NCg0KSW4gc3VtbWFyeSwgdGhpcyBzdHVkeSBwcm92aWRlcyBhIHN0YXJ0aW5nIHBvaW50IGluIGNvbW11bml0eSBhc3NlbWJseSByZXNlYXJjaCBvZiBtaWNyb2JpYWwgZmF1bmEgb2YgTHVueiBsYWtlcyBjYXRjaG1lbnQsIGFuZCBnaXZlcyBpbmRpY2F0aW9uIHRoYXQgZnV0dXJlIHN0dWRpZXMgc2hvdWxkIGJlIGZvY3VzZWQgb24gZW52aXJvbm1lbnRhbCBjb25kaXRpb25zIG9mIGVhY2ggbWljcm9lbnZpcm9ubWVudCwgYW5kIHRoZWlyIHRpZXMgdG8gbWljcm9iaWFsDQphc3NlbWJseSwgc2luY2UgY2F0ZWdvcmlzaW5nIHNhbXBsZXMgYnkgZGlzdGFuY2Ugb3Igc2ltaWxhcml0eSBkb2VzIG5vdCBnaXZlIGNsZWFyIHJlc3VsdHMuDQo=