1 Package loading

library(staRdom)      # PARAFAC
library(tidyverse)
library(broom)
library(readxl)
library(vegan) 
library("FactoMineR") # for PCA
library("factoextra") # for PCA
library(caret)
library(patchwork)

2 Fluorescence data

We should throughout all these steps be using the command: “eem_overview_plot(nameX…, spp = …, contour = TRUE)” to check between the steps the intermediate results, but since it is intensive, I do not do it for the markdown.

2.1 Data import

Indicate path to data and number of cores for parallel processing.

# path to aqualog .dat files
sample_dir <- ("C:/Users/Angela Cukusic/Documents/faks/Ecology and Ecosystems/MEC-4 (Intro to research - s prof)/Data/flo_data") 

# number of cores
cores <- detectCores(logical = FALSE)

# import data
eem_list <- eem_read(sample_dir,
                     import_function = "aqualog", 
                     recursive = TRUE)

2.2 Process and correct

Subtract blank from data (skip if already done in aqualog software, but in our machine that is not the case).

eem_list_blank_subtracted <- eem_extend2largest(eem_list,
                                                interpolation = 1, 
                                                extend = FALSE, 
                                                cores = cores)

eem_list_blank_subtracted <- eem_remove_blank (eem_list_blank_subtracted)

# 12 blanks averaged -> checks out since we did one full year of data

Normalize data to Raman Units relative to blank.

eem_list_rel_ru <- eem_raman_normalisation2(eem_list_blank_subtracted,
                                            blank = "blank")

At this point blanks are not needed anymore and can be removed from the sample list.

eem_list_rel_ru <- eem_extract(eem_list_rel_ru, 
                               c("nano", "miliq", 
                                 "milliq", "mq", "blank"), 
                               ignore_case = TRUE)
## Removed sample(s): blank_20210112 blank_20210202 blank_20210304 blank_20210406 blank_20210504 blank_20210608 blank_20210706 blank_20200729 blank_20200902 blank_20201006 blank_20201103 blank_20201209

Remove Raman and Rayleigh scatter; scatter width might need fine tuning to sufficiently mask scatter.

eem_list_scatter_removed_1 <- eem_rem_scat(eem_list_rel_ru, 
                                           remove_scatter = c(TRUE, TRUE, TRUE, TRUE),
                                           remove_scatter_width = c(20, 15, 25, 15))

# plot (go back and re-adjust scatter width if necessary)
# eem_overview_plot(eem_list_scatter_removed_1, spp = 7, contour = TRUE)

# or to plot each sample by one:
# ggeem(eem_list_scatter_removed_1, contour = TRUE, fill_max = 1, spp=7)

Interpolate missing values after removing scatter.

eem_list_interp_1 <-  eem_interp(eem_list_scatter_removed_1, 
                                 cores = cores, type = 1, 
                                 extend = FALSE)

# summary(eem_list_interp_1)

Smooth data for peak picking.

eem4peaks <- eem_smooth(eem_list_interp_1, n = 4, cores = cores)

2.3 Peak picking

After having the pre-processed data we calculate Coble peaks and fluorescence indices.

eem_indices_and_peaks <- as.data.frame(cbind(eem_biological_index(eem4peaks),
                                 hix = eem_humification_index(eem4peaks)[, 2],
                                 fi = eem_fluorescence_index(eem4peaks)[, 2],
                                 eem_coble_peaks(eem4peaks)[, -1]))

colnames(eem_indices_and_peaks) <- c(# keep the 1:4 colnames as they are
                                     colnames(eem_indices_and_peaks)[1:4],
                                     # add to b, t, a, m, c the prefix "coble_peak"
                                     paste("coble_peak", colnames(eem_indices_and_peaks)[5:9], 
                                           sep = "_"))

2.4 PARAFAC modelling

As before, apply spectral correction to remove scatter. But this time set the range even before starting, because we have too much scatter outside the 300-500 area: indicate range of EX and EM wavelengths to keep (everything above and below will be cut); values for ex and em might need some fine tuning.

# cut data outside of indicated range
eem_list_trimmed <- eem_list_rel_ru %>% 
                    eem_range(ex = c(260, Inf), 
                              em = c(300,560))

# remove scatter
eem_list_scatter_removed_2 <- eem_rem_scat(eem_list_trimmed, 
                                           remove_scatter = c(TRUE, TRUE, TRUE, TRUE),
                                           remove_scatter_width = c(20, 15, 25, 15))

# continuously go back and re-adjust ex if necessary, again I am saving the comp. power here
# eem_overview_plot(eem_list_scatter_removed_2, spp = 7, contour = TRUE)

Remove other remnant noise (in this example at EX 280-295 nm; again fine tune as needed). You can see the wobbly lines in the plot around this area so our goal is to remove that and interpolate the “straight” lines from the rest of the model.

# with these just set the scatter areas as NAs
eem_list_scatter_removed_2 <- eem_setNA(eem_list_scatter_removed_2, 
                                        ex = 285:300, 
                                        interpolate = FALSE)

# with this interpolate the areas for smooth modeling
eem_list_interp_2 <-  eem_interp(eem_list_scatter_removed_2, 
                                 cores = cores, type = 1, 
                                 extend = FALSE)

Still there is too much variation in emission values of some samples. It is most visible in October, which rather than being fixed should be thrown out alltogether.

# with this identify the order number of October samples which show great variation 
eem_list_scatter_removed_2 

# its 64 to 70

# identify in order to remove at emission wavelengths 319.645-330.957 nm which are the [13:20] emission interval

# make them NAs
eem_list_scatter_removed_2[64][[1]]$x[13:20, ] <- NA
eem_list_scatter_removed_2[65][[1]]$x[13:20, ] <- NA
eem_list_scatter_removed_2[66][[1]]$x[13:20, ] <- NA
eem_list_scatter_removed_2[67][[1]]$x[13:20, ] <- NA
eem_list_scatter_removed_2[68][[1]]$x[13:20, ] <- NA
eem_list_scatter_removed_2[69][[1]]$x[13:20, ] <- NA
eem_list_scatter_removed_2[70][[1]]$x[13:20, ] <- NA

#interpolate the NAs
eem_list_interp_2 <-  eem_interp(eem_list_scatter_removed_2, 
                                 cores = cores, type = 1, 
                                 extend = FALSE)

#eem_overview_plot(eem_list_interp_2, spp = 7, contour = TRUE)

2.4.1 Finding component number

Set parameters.

# 1. range of components to look for 

## minimum number of components 
dim_min <- 3
## maximum number of components
dim_max <- 7

# will produce models with 3, 4, 5, 6, or 7 components, respectively



# 2. number of random initialization from which the best model will be chosen
nstart <- 50
# maximum number of iterations
maxit <- 5000
# tolerance in parafac analysis (tolerated change in R2)
ctol <- 10^-6

Calculate models (using constraints of non-negative fluorescence).

pf_screen <- eem_parafac(eem_list_interp_2, 
                            # how many components in model
                         comps = seq(dim_min, dim_max),
                         normalise = FALSE, 
                            # we cannot have negative em/ex data
                         const = c("nonneg", "nonneg", "nonneg"), 
                         maxit = maxit, 
                         nstart = nstart, 
                         ctol = ctol, 
                         cores = cores)

# rescale data such that maximum of each component is 1. 
pf_screen <- lapply(pf_screen, eempf_rescaleBC, newscale = "Fmax")

Check fit, peaks, and spectra of model components:

eempf_compare(pf_screen, contour = TRUE)

## [[1]]

## 
## [[2]]

## 
## [[3]]

In this case, model 3 with 5 components appears to give the best results. Check for correlations between components in model 3 (there should be no strong correlations).

eempf_corplot(pf_screen[[3]]) # comps 1 and 2  seem highly correlated

2.4.2 Normalization

Component 1 and 2 seem highly correlated; re-run the models with normalized data.

# re-run
pf_screen_norm <- eem_parafac(eem_list_interp_2, 
                              comps = seq(dim_min, dim_max), 
                              # with this we normalize the data, as opposed to before
                              normalise = TRUE, 
                              const = c("nonneg", "nonneg", "nonneg"), 
                              maxit = maxit, 
                              nstart = nstart, 
                              ctol = ctol, 
                              cores = cores)

# rescale
pf_screen_norm <- lapply(pf_screen_norm, 
                         eempf_rescaleBC, 
                         newscale = "Fmax")


# check fit, peaks, and spectra
eempf_compare(pf_screen_norm, contour = TRUE)

## [[1]]

## 
## [[2]]

## 
## [[3]]

After normalization, model 3 and model 4 with 4 and 5 components, respectively, appear reasonable; check for correlations in both.

# model3
# eempf_corplot(pf_screen_norm[[4]]) 

# model2
eempf_corplot(pf_screen_norm[[3]]) 

2.4.3 Screen outlier samples

There is possibility that certain samples have too much leverage in the model and would be better for the model to remove them. Leverage ranges between 0 and 1 with very atypical wavelengths/samples having a leverage near 1.

Leverage should be roughly similar across wavelengths/samples. If points with high leverage are identified, those should be removed and the model should be re-calculated.

# calculate leverage
cpl <- eempf_leverage(pf_screen_norm[[3]])

# plot
eempf_leverage_plot(cpl, qlabel=0.1)

# (exclude <- eempf_leverage_ident(cpl,qlabel=0.1))

At excitation 330 nm there is a huge spike in models with 5+ components. Since it does not seem to be such a big problem with 4 components, we keep all.

None of the samples have leverage bigger than 0.3, so we will not remove any.

2.4.4 Check residuals

Residuals should be random across samples and should not show major peaks or troughs (small peaks along the diagonal are acceptable and may be ignored; mainly represent merely remnant scatter).

eempf_residuals_plot(pf_screen_norm[[3]], 
                     eem_list_interp_2, 
                     residuals_only = TRUE, 
                     spp = 7, 
                     cores = cores, 
                     contour = TRUE)

No need to further adapt the model, the residuals look random.

2.5 Final model

Now that we are sure that all outliers are removed from the model, and that residuals are acceptable for this model, we calculate a new model with increased accuracy.

If we want to get a more detailed comparisons we can this command (not included as output because of the time needed):

# decrease tolerance in R deviation
ctol <- 10^-8 
# increase number of random starts
nstart = 60 
# increase number of maximum interations
maxit = 10000 
# number of suitable components identified previously
comps = 5 



# calculate model with n components
pf_n_components_1 <- eem_parafac(eem_list_interp_2, 
                                 comps = comps, 
                                 normalise = TRUE, 
                                 const = c("nonneg", "nonneg", "nonneg"), 
                                 maxit = maxit, 
                                 nstart = nstart, 
                                 ctol = ctol, 
                                 output = "all", 
                                 cores = cores)

# re-scale
pf_n_components_1 <- lapply(pf_n_components_1, 
                            eempf_rescaleBC, 
                            newscale = "Fmax")

Check the model:

# check convergence and model performance
eempf_convergence(pf_n_components_1[[1]])

# plot
eempf_compare(pf_n_components_1, contour = TRUE)

# check leverage
eempf_leverage_plot(eempf_leverage(pf_n_components_1[[1]]))

# check correlations
eempf_corplot(pf_n_components_1[[1]], progress = FALSE)
#comp 2 and 3 too correlated?

Opt out for the model with 5 components and re-calculate a new rough model with more restarts and lower accuracy.

pf_n_components_2 <- eem_parafac(eem_list_interp_2, 
                                 comps = 5, 
                                 normalise = TRUE, 
                                 const = c("nonneg", "nonneg", "nonneg"), 
                                 maxit = maxit, 
                                 nstart = 100, 
                                 ctol = min(ctol*100,0.01), 
                                 cores = cores)

Use the resulting model as starting point to re-calculate the high-accuracy model (nstarts can be lower here).

pf_n_components_3 <- eem_parafac(eem_list_interp_2, 
                                 comps = 5, 
                                 normalise = TRUE, 
                                 const = c("nonneg", "nonneg", "nonneg"), 
                                 maxit = maxit, 
                                 nstart = 10, 
                                 ctol = ctol, 
                                 cores = cores, 
                                 Bstart = pf_n_components_2[[1]]$B, 
                                 Cstart = pf_n_components_2[[1]]$C)

pf_n_components_3 <- lapply(pf_n_components_3, 
                            eempf_rescaleBC, 
                            newscale = "Fmax")

Plot the resulting components:

eempf_comp_load_plot(pf_n_components_3[[1]], contour = TRUE)
## [[1]]

## 
## [[2]]

2.6 Split-half analysis

Validate final model using split-half analysis (generates Tucker’s Congruence Coefficient; value should be close to one (and not smaller than ~0.9-0.85) for good consistent model).

# this is again way too intensive to knit in a pdf

#calculate split_half analysis
sh <- splithalf(eem_list_interp_2, 
                comps = 5, 
                normalise = TRUE, 
                rand = FALSE, 
                cores = cores, 
                nstart = nstart, 
                maxit = maxit, 
                ctol = ctol)

splithalf_plot(sh)
splithalf_tcc(sh)

2.7 Visualize components

Calculate “amount” of components per sample:

pf_missing_samples <- A_missing(eem_list_interp_1,
                                pf_n_components_3[[1]])
final_comp_table <- as.data.frame( eempf4analysis(pf_missing_samples, eem4peaks))


comp_table <- final_comp_table %>% 
  as.data.frame() %>% 
  dplyr::select("sample", "Comp.1", "Comp.2", 
                "Comp.3", "Comp.4", "Comp.5") %>% 
  
# add identifers for well_id and date  
  mutate( well_id = str_sub(sample, start = 1, end = 3),
          date = str_split(sample, "_", simplify = TRUE)[, 2],
          water_kind = case_when( # for pumped
                                  str_detect(sample, "p") ~ "pumped",
                                  # for well
                                  str_detect(sample, "w") ~ "well",
                                  # for surface
                                  TRUE ~ "surface") ) %>%              
 
   mutate(date = ymd(date))
  1. Absolute concentrations:
comp_table %>% 
  
# remove the well water  
  dplyr::filter(water_kind != "well") %>% 
  mutate(date = as.factor(date),
         water_kind = as.factor(water_kind)) %>% 
  dplyr::select(!c( "well_id", "sample")) %>% 
  pivot_longer(cols = -c(date, water_kind), 
               names_to = "comps", 
               values_to = "concs") %>% 
  mutate(comps = as.factor(comps))     %>% 
  
# find average from all three groundwater wells 
  group_by(date, comps, water_kind) %>% 
  summarise(concs = mean(concs)) %>% 
  ungroup() %>% 
  
# plot  
  ggplot(aes(x = date, y = concs, fill = comps)) +
  geom_bar(stat = "identity") +
  facet_wrap(~ water_kind, ncol = 1) + 
  geom_text(aes(label = paste0(round(concs, 4) )), 
            position = position_stack(vjust = 0.5), size = 2.5) +
  theme(legend.position = "none",
        axis.ticks.y = element_blank(),
        axis.text.y = element_blank(),
        axis.title.y = element_blank()) +
  theme_linedraw() + 
  scale_fill_brewer(palette = "Set2") +
  labs(x=NULL, y=NULL) +
  scale_x_discrete(labels = c("Aug", "Sep", "Oct", "Nov", "Dec",
                              "Jan", "Feb", "Mar", "Apr", "May", 
                              "Jun", "Jul")) -> plt2

plt2

  1. Relative concentrations:
comp_table %>% 
  mutate(date = as.factor(date),
         water_kind = as.factor(water_kind)) %>% 
  dplyr::select(!c( "well_id", "sample")) %>% 
  pivot_longer(cols = -c(date, water_kind), 
               names_to = "comps", 
               values_to = "concs") %>% 
  mutate(comps = as.factor(comps))     %>% 

# find average from all three groundwater wells 
  group_by(date, comps, water_kind) %>% 
  summarise(concs = mean(concs)) %>% 
  ungroup() %>% 

# find  relative abundances for each date in each water kind (well/pump/surf)
  group_by(date, water_kind) %>%
# relative concentrations are the value divided by the sum  
  mutate(rel_conc = concs / sum(concs) * 100) %>%
  ungroup() %>% 
  
# plot  
  ggplot(aes(x = date, y = rel_conc, fill = comps)) +
  geom_bar(stat = "identity") +
  facet_wrap(~ water_kind, ncol = 1) + 
  geom_text(aes(label = paste0(round(rel_conc, 4) , "%")), 
            position = position_stack(vjust = 0.5), size = 2.1) +
  theme(legend.position = "none",
        axis.ticks.y = element_blank(),
        axis.text.y = element_blank(),
        axis.title.y = element_blank()) +
  theme_linedraw() + 
  scale_fill_brewer(palette = "Set2") +
  labs(x=NULL, y=NULL) +
  scale_x_discrete(labels = c("Aug", "Sep", "Oct", "Nov", "Dec",
                              "Jan", "Feb", "Mar", "Apr", "May", 
                              "Jun", "Jul")) -> plt1

plt1

  1. Line plot of absolute abundances, per component:
comp_table %>% 
  dplyr::filter(water_kind != "well") %>% 
  mutate(date = as.factor(date),
         water_kind = as.factor(water_kind)) %>% 
  dplyr::select(!c( "well_id", "sample")) %>% 
  pivot_longer(cols = -c(date, water_kind), 
               names_to = "comps", values_to = "concs") %>% 
  mutate(comps = as.factor(comps)) %>% 

# find average from all three groundwater wells 
  group_by(date, comps, water_kind) %>% 
  summarise(concs = mean(concs)) %>% 
  ungroup() %>% 
  
# plot 
  ggplot(aes(x = date, y = concs, 
             color = water_kind, 
             group =water_kind)) +
  geom_point() +
  geom_line() +
  facet_wrap(~ comps) + 
  theme_linedraw() + 
  
  theme(legend.position = "none",
        axis.ticks.y = element_blank(),
        axis.text.y = element_blank(),
        axis.title.y = element_blank(),
        axis.text.x = element_text(angle = 90)) +
  
  scale_fill_brewer(palette = "Set2") +
  labs(x=NULL, y=NULL) +
  scale_x_discrete(labels = c("Aug", "Sep", "Oct", "Nov", "Dec",
                              "Jan", "Feb", "Mar", "Apr", "May", 
                              "Jun", "Jul")) -> plt3

plt3

2.8 Export component table

Get table with excitation/emission wavelengths for each component to identify by comparing to the already observed excitation/emission maxima.

comp_spectra <- eempf_export(pf_n_components_3[[1]])

From this table we look at which ex and em values for each component is at 1, for example Comp1 has the exctation maxima (1) at 260 nm.

3 Environmental data

# load environmental data
env_data <- read_excel("C:/Users/Angela Cukusic/Documents/faks/Ecology and Ecosystems/MEC-4 (Intro to research - s prof)/Data/lobau_data_combined.xlsx")
env_data1 <- env_data  %>% 
  # temperature and oxygen are in two different columns for gw and sw
  mutate(oxygen = coalesce( oxygen_mg_L , oxygen_above_bottom_mg_L),
         temp = coalesce( temp_C , temp_above_bottom_C) ) %>% 
  # remove unneccessary columns
  dplyr::select(!c("well_id", "date_mm_dd_yyyy", "sample_type", 
                              "atp_total_pM", "oxygen_below_gw_surface_mg_L", 
                              "temp_below_gw_surface_C", "delta_13ch4_permille",
                              "sd_delta_13ch4", "oxygen_mg_L" , 
                              "oxygen_above_bottom_mg_L",
                              "temp_C" , "temp_above_bottom_C")) %>% 
  left_join(comp_table, ., by= c("sample" = "sample_id")) %>% 
  # remove data on depth since it would remove all the surface water entries
  select(! matches("depth|table") ) %>% 
  # few months do not have measured parameters, remove those
  na.omit()

 rownames(env_data1) <- env_data1$sample 

Considering that the main focus of the analysis is the DOC, the approach to PCA is experimental - combining the environmental variables into principal components to use in the constrained analysis since the PC form prevents the collinearity.

# 1. Calculate the correlation matrix to first simplify the highly correlated ones
cor_matrix <- cor(env_data1[,-c(1:9)])

# Find highly correlated variables with a threshold of 0.8
highly_correlated <- findCorrelation(cor_matrix, cutoff = 0.8)

# Remove the highly correlated variables from the dataframe
df_pca <- env_data1[,-c(1:9)][, -highly_correlated]

# Perform PCA on the preprocessed dataframe (df_pca)
pca_env <- prcomp(df_pca, scale = TRUE)


biplot(pca_env)

# if there is one sample that is way different than all the rest which I would like to remove
#tidy(pca_env) %>% filter(PC == "1") %>% filter(value > 5) %>% select("row")

# but seems not


# 2. Look at which components it makes sense to keep for further analyisis
# usually those that contribute more than 1 eigenvalue

# Get the eigenvalues of components (the st.dev)
# summary(pca_env) -> the first 7 components have have more than 1 

normal data: variance = (st.dev)^2 pca data: eigenvalue = (st.dev)^2

“eigenvalues represent the variance explained by each principal component” -> eigen ~ variance

The first eight components explain more than 1 variance in data, but only the first three explain more than 1% of variance. Therefore, keep only PC1, PC2 and PC3 (as combinations of environmental variables) for further analysis.

3.1 Loadings

Now see what contributes to each of the three PCs and if some environmental variables can be removed.

# 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
p1 <- 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")

# DOC and minerals


# PC2 
p2 <- 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")


# PC3
p3 <- 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")

# PC3 consists 60%+ of co2, atp, P, N



p1 + p2 + p3

Seems that the variables not represented on the PC1 and PC2 are represented on PC3, we should still keep all three:

fviz_pca_biplot(pca_env, 
                # fill individuals by groups
                geom.ind = "point",
                pointshape = 21,
                pointsize = 2.5,
                fill.ind = env_data1$well_id,
                col.ind = "black",
                alpha.var ="contrib",
                col.var = "contrib",
                gradient.cols = "RdBu",
                repel = TRUE)+
        ggpubr::fill_palette("jco")      

3.2 Constrained analysis

# add component concentration in each sample
# i did not scale since they are more or less the same scale as loadings

tidy(pca_env) %>% 
  filter(PC %in% c("1", "2", "3", "4", "5", "6") )  %>% 
  pivot_wider(values_from = "value", names_from = "PC") %>% 
  rename("PC1" = "1", "PC2" = "2", "PC3" = "3", 
         "PC4" ="4", "PC5" = "5", "PC6" = "6") %>% 
  arrange(desc(row)) %>% 
  column_to_rownames("row")-> env.dat

env_data1[,1:6] %>% 
  #filter(sample != "D05p_20200729") %>% 
  arrange(desc(sample)) %>% 
  select(!"sample")-> sp.dat

identical(rownames(env.dat), rownames(sp.dat)) #TRUE
## [1] TRUE
simpleRDA <- capscale(sp.dat ~  ., data=env.dat ,
                 distance = "euclidean")

#summary(simpleRDA)
#64%% constrained 

3.3 Testing ordination

Test if any of these PCs impacts the composition of DOC components:

# test of all canonical axes
anova.model <- anova.cca(simpleRDA, by='axis', step=1000)  # cap1 is sign, cap2 also

# test the whole model
anova.model2 <- anova.cca(simpleRDA, step=1000) #is sign
RsquareAdj(simpleRDA)$adj.r.squared # and explains 60%
## [1] 0.6042249
# test env parameters
anova.model3 <- anova(simpleRDA, step=1000, by = "term")
# PC1, PC3, PC4 and PC5 sign


# new model

simpleRDA <- capscale(sp.dat ~  PC1 + PC3 + PC4 + PC5, 
                      data=env.dat ,
                      distance = "euclidean")

Only PC1 is significantly explaining the impact on the component composition, and explains 40% of variation. The PC1 is a combination of DOC (as expected), electric conductivity, oxygen, K, Na, co2. The nutrient availability does not seem to be impactfull for the DOC composition of the sample.

3.4 Plotting

# vectors
ccavectors <- as.matrix(scores(simpleRDA, display = "bp", scaling = "sites")*2.363299) %>%
  as.data.frame()

# site coordinates
env_data1[#which(rownames(env_data1) != "D05p_20200729")
  ,"well_id"] %>% 
  as.data.frame() %>% 
  rename("water_kind" = ".") %>% 
  arrange(desc(water_kind)) -> water

site_data <- scores(simpleRDA, display = "sites") %>% 
  as.data.frame() %>% 
  cbind(., water)
 
# add components
comp <- as.matrix(scores(simpleRDA, display = "species")*2.363299 )  %>% 
  as.data.frame()

# plotting
plot_cca <- 
  site_data %>% 
  ggplot( aes(x = CAP1, y = CAP2)) +
  geom_point(aes( color= water_kind), size = 3) +
  geom_point(color = "black", shape = 21, size = 3) +  
  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.1, y = CAP2*1.5, 
                                   label = rownames(ccavectors)),
                                   size=6 ) +
  
  geom_text(data = comp, aes(x = CAP1, y=CAP2, 
                             label = rownames(comp))) + 
  theme_bw() +
  labs(x = "CAP1 [44.58 %]", y="CAP2 [1.55 %]") +
  stat_ellipse(aes(color=water_kind), size = 1, alpha = 0.5) + 
  
  labs( color = "Water \nkind", fill = "water kind") +
  
     theme(legend.background = element_blank(),
           legend.box.background = element_rect(colour = "gray")) +
  scale_color_manual(values=c("#acc7d9","#5180a2",
                              "#3e647d","#d8b365"))

plot_cca

Conclusion: component 4 is mostly related to the surface water, while component 1, 2 and 3 are closely related to PC1 defined environmenal variables, namely minerals. This fits the results of component distribution by well id. The PCA approach does provide fitting results but is not an improvement to an actual constraint with raw environmental variables.

LS0tDQp0aXRsZTogIklkZW50aWZ5aW5nIHRoZSBET0MgY29tcG9zaXRpb24gb2YgZ3JvdW5kd2F0ZXIgd2l0aCBQQVJBRkFDIG1vZGVsbGluZyIgDQphdXRob3I6ICAiQW5nZWxhIEN1a3VzaWMiDQpkYXRlOiBKdW5lIDIwLCAyMDIzDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlICAgICAgICAgICAgICAgIyBUYWJsZSBvZiBjb250ZW50cw0KICAgIHRvY19mbG9hdDogdHJ1ZSAgICAgICAgICMgS2VlcCB0aGUgdGFibGUgb2YgY29udGVudHMgZmxvYXRpbmcgb24gdGhlIHBhZ2UNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAgICAjIEVuYWJsZSBjb2RlIGRvd25sb2FkIGJ1dHRvbg0KICAgIGNvZGVfY29weTogdHJ1ZSAgICAgICAgICMgRW5hYmxlIGNvZGUgY29weSBidXR0b24NCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUgICAjIE51bWJlcmluZyB0aGUgc2VjdGlvbnMNCiAgICB0aGVtZTogY2VydWxlYW4gICAgICAgICAgICMgQ2hvb3NlIGEgQm9vdHN0cmFwIHRoZW1lIChjaGVjayBhdmFpbGFibGUgdGhlbWVzKQ0KICAgIGhpZ2hsaWdodDogdGFuZ28gICAgICAgICMgU3ludGF4IGhpZ2hsaWdodGluZyBzdHlsZSAocGljayBhIHN0eWxlIGZyb20gYXZhaWxhYmxlIHRoZW1lcykNCg0KLS0tDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIEZvciB3aWR0aCBvZiBjb2RlIGNodW5rcyBhbmQgc2Nyb2xsIGJhciANCm9wdGlvbnMod2lkdGg9MjUwKQ0KDQprbml0cjo6b3B0c19jaHVuayRzZXQoZXZhbCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgIGVjaG8gPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICBjYWNoZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZSA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbGxhcHNlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGVuZ2luZSA9ICJSIiwgDQogICAgICAgICAgICAgICAgICAgICAgIyBDaHVua3Mgd2lsbCBhbHdheXMgaGF2ZSBSIGNvZGUsIHVubGVzcyBub3RlZA0KICAgICAgICAgICAgICAgICAgICAgIGVycm9yID0gVFJVRSkNCg0KYGBgDQoNCg0KIyBQYWNrYWdlIGxvYWRpbmcNCmBgYHtyLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoc3RhUmRvbSkgICAgICAjIFBBUkFGQUMNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShicm9vbSkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeSh2ZWdhbikgDQpsaWJyYXJ5KCJGYWN0b01pbmVSIikgIyBmb3IgUENBDQpsaWJyYXJ5KCJmYWN0b2V4dHJhIikgIyBmb3IgUENBDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShwYXRjaHdvcmspDQpgYGANCg0KDQojIEZsdW9yZXNjZW5jZSBkYXRhDQoNCg0KV2Ugc2hvdWxkIHRocm91Z2hvdXQgYWxsIHRoZXNlIHN0ZXBzIGJlIHVzaW5nIHRoZSBjb21tYW5kOiANCiJlZW1fb3ZlcnZpZXdfcGxvdChuYW1lWC4uLiwgc3BwID0gLi4uLCBjb250b3VyID0gVFJVRSkiDQp0byBjaGVjayBiZXR3ZWVuIHRoZSBzdGVwcyB0aGUgaW50ZXJtZWRpYXRlIHJlc3VsdHMsIGJ1dCBzaW5jZSBpdCBpcyBpbnRlbnNpdmUsDQpJIGRvIG5vdCBkbyBpdCBmb3IgdGhlIG1hcmtkb3duLg0KDQoNCiMjIERhdGEgaW1wb3J0DQpJbmRpY2F0ZSBwYXRoIHRvIGRhdGEgYW5kIG51bWJlciBvZiBjb3JlcyBmb3IgcGFyYWxsZWwgcHJvY2Vzc2luZy4NCmBgYHtyIGRhdGEtbG9hZGluZ30NCiMgcGF0aCB0byBhcXVhbG9nIC5kYXQgZmlsZXMNCnNhbXBsZV9kaXIgPC0gKCJDOi9Vc2Vycy9BbmdlbGEgQ3VrdXNpYy9Eb2N1bWVudHMvZmFrcy9FY29sb2d5IGFuZCBFY29zeXN0ZW1zL01FQy00IChJbnRybyB0byByZXNlYXJjaCAtIHMgcHJvZikvRGF0YS9mbG9fZGF0YSIpIA0KDQojIG51bWJlciBvZiBjb3Jlcw0KY29yZXMgPC0gZGV0ZWN0Q29yZXMobG9naWNhbCA9IEZBTFNFKQ0KDQojIGltcG9ydCBkYXRhDQplZW1fbGlzdCA8LSBlZW1fcmVhZChzYW1wbGVfZGlyLA0KICAgICAgICAgICAgICAgICAgICAgaW1wb3J0X2Z1bmN0aW9uID0gImFxdWFsb2ciLCANCiAgICAgICAgICAgICAgICAgICAgIHJlY3Vyc2l2ZSA9IFRSVUUpDQoNCmBgYA0KDQoNCiMjIFByb2Nlc3MgYW5kIGNvcnJlY3QNCg0KU3VidHJhY3QgYmxhbmsgZnJvbSBkYXRhIChza2lwIGlmIGFscmVhZHkgZG9uZSBpbiBhcXVhbG9nIHNvZnR3YXJlLCANCmJ1dCBpbiBvdXIgbWFjaGluZSB0aGF0IGlzIG5vdCB0aGUgY2FzZSkuDQoNCmBgYHtyIGJsYW5rLXJlbW92ZX0NCmVlbV9saXN0X2JsYW5rX3N1YnRyYWN0ZWQgPC0gZWVtX2V4dGVuZDJsYXJnZXN0KGVlbV9saXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJwb2xhdGlvbiA9IDEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXh0ZW5kID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSBjb3JlcykNCg0KZWVtX2xpc3RfYmxhbmtfc3VidHJhY3RlZCA8LSBlZW1fcmVtb3ZlX2JsYW5rIChlZW1fbGlzdF9ibGFua19zdWJ0cmFjdGVkKQ0KDQojIDEyIGJsYW5rcyBhdmVyYWdlZCAtPiBjaGVja3Mgb3V0IHNpbmNlIHdlIGRpZCBvbmUgZnVsbCB5ZWFyIG9mIGRhdGENCmBgYA0KDQpOb3JtYWxpemUgZGF0YSB0byBSYW1hbiBVbml0cyByZWxhdGl2ZSB0byBibGFuay4NCmBgYHtyIHJhbWFuLWNvcnJlY3Rpb24sIHJlc3VsdHM9J2hpZGUnfQ0KDQplZW1fbGlzdF9yZWxfcnUgPC0gZWVtX3JhbWFuX25vcm1hbGlzYXRpb24yKGVlbV9saXN0X2JsYW5rX3N1YnRyYWN0ZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJsYW5rID0gImJsYW5rIikNCg0KYGBgDQoNCkF0IHRoaXMgcG9pbnQgYmxhbmtzIGFyZSBub3QgbmVlZGVkIGFueW1vcmUgYW5kIGNhbiBiZSByZW1vdmVkIGZyb20gdGhlIHNhbXBsZSBsaXN0Lg0KDQpgYGB7ciB9DQplZW1fbGlzdF9yZWxfcnUgPC0gZWVtX2V4dHJhY3QoZWVtX2xpc3RfcmVsX3J1LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJuYW5vIiwgIm1pbGlxIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWlsbGlxIiwgIm1xIiwgImJsYW5rIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZV9jYXNlID0gVFJVRSkNCmBgYA0KDQoNCg0KUmVtb3ZlIFJhbWFuIGFuZCBSYXlsZWlnaCBzY2F0dGVyOyAgc2NhdHRlciB3aWR0aCBtaWdodCBuZWVkIGZpbmUgdHVuaW5nIHRvIHN1ZmZpY2llbnRseSBtYXNrIHNjYXR0ZXIuDQoNCmBgYHtyIH0NCmVlbV9saXN0X3NjYXR0ZXJfcmVtb3ZlZF8xIDwtIGVlbV9yZW1fc2NhdChlZW1fbGlzdF9yZWxfcnUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZV9zY2F0dGVyID0gYyhUUlVFLCBUUlVFLCBUUlVFLCBUUlVFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW1vdmVfc2NhdHRlcl93aWR0aCA9IGMoMjAsIDE1LCAyNSwgMTUpKQ0KDQojIHBsb3QgKGdvIGJhY2sgYW5kIHJlLWFkanVzdCBzY2F0dGVyIHdpZHRoIGlmIG5lY2Vzc2FyeSkNCiMgZWVtX292ZXJ2aWV3X3Bsb3QoZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzEsIHNwcCA9IDcsIGNvbnRvdXIgPSBUUlVFKQ0KDQojIG9yIHRvIHBsb3QgZWFjaCBzYW1wbGUgYnkgb25lOg0KIyBnZ2VlbShlZW1fbGlzdF9zY2F0dGVyX3JlbW92ZWRfMSwgY29udG91ciA9IFRSVUUsIGZpbGxfbWF4ID0gMSwgc3BwPTcpDQpgYGANCg0KSW50ZXJwb2xhdGUgbWlzc2luZyB2YWx1ZXMgYWZ0ZXIgcmVtb3Zpbmcgc2NhdHRlci4NCmBgYHtyIH0NCmVlbV9saXN0X2ludGVycF8xIDwtICBlZW1faW50ZXJwKGVlbV9saXN0X3NjYXR0ZXJfcmVtb3ZlZF8xLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gY29yZXMsIHR5cGUgPSAxLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dGVuZCA9IEZBTFNFKQ0KDQojIHN1bW1hcnkoZWVtX2xpc3RfaW50ZXJwXzEpDQpgYGANCg0KU21vb3RoIGRhdGEgZm9yIHBlYWsgcGlja2luZy4NCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdob2xkJ30NCmVlbTRwZWFrcyA8LSBlZW1fc21vb3RoKGVlbV9saXN0X2ludGVycF8xLCBuID0gNCwgY29yZXMgPSBjb3JlcykNCmBgYA0KDQoNCiMjIFBlYWsgcGlja2luZw0KDQpBZnRlciBoYXZpbmcgdGhlIHByZS1wcm9jZXNzZWQgZGF0YSB3ZSBjYWxjdWxhdGUgQ29ibGUgcGVha3MgYW5kIGZsdW9yZXNjZW5jZSBpbmRpY2VzLg0KDQpgYGB7cn0NCmVlbV9pbmRpY2VzX2FuZF9wZWFrcyA8LSBhcy5kYXRhLmZyYW1lKGNiaW5kKGVlbV9iaW9sb2dpY2FsX2luZGV4KGVlbTRwZWFrcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoaXggPSBlZW1faHVtaWZpY2F0aW9uX2luZGV4KGVlbTRwZWFrcylbLCAyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpID0gZWVtX2ZsdW9yZXNjZW5jZV9pbmRleChlZW00cGVha3MpWywgMl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZW1fY29ibGVfcGVha3MoZWVtNHBlYWtzKVssIC0xXSkpDQoNCmNvbG5hbWVzKGVlbV9pbmRpY2VzX2FuZF9wZWFrcykgPC0gYygjIGtlZXAgdGhlIDE6NCBjb2xuYW1lcyBhcyB0aGV5IGFyZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG5hbWVzKGVlbV9pbmRpY2VzX2FuZF9wZWFrcylbMTo0XSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGFkZCB0byBiLCB0LCBhLCBtLCBjIHRoZSBwcmVmaXggImNvYmxlX3BlYWsiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoImNvYmxlX3BlYWsiLCBjb2xuYW1lcyhlZW1faW5kaWNlc19hbmRfcGVha3MpWzU6OV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICJfIikpDQoNCg0KDQpgYGANCg0KDQojIyBQQVJBRkFDIG1vZGVsbGluZw0KDQpBcyBiZWZvcmUsIGFwcGx5IHNwZWN0cmFsIGNvcnJlY3Rpb24gdG8gcmVtb3ZlIHNjYXR0ZXIuIEJ1dCB0aGlzIHRpbWUgc2V0IHRoZSByYW5nZSBldmVuIGJlZm9yZSBzdGFydGluZywgYmVjYXVzZSB3ZSBoYXZlIHRvbyBtdWNoIHNjYXR0ZXIgb3V0c2lkZSB0aGUgMzAwLTUwMCBhcmVhOiBpbmRpY2F0ZSByYW5nZSBvZiBFWCBhbmQgRU0gd2F2ZWxlbmd0aHMgdG8ga2VlcCAoZXZlcnl0aGluZyBhYm92ZSBhbmQgYmVsb3cgd2lsbCBiZSBjdXQpOyB2YWx1ZXMgZm9yIGV4IGFuZCBlbSBtaWdodCBuZWVkIHNvbWUgZmluZSB0dW5pbmcuDQoNCmBgYHtyIHRyaW0tZGF0YX0NCg0KIyBjdXQgZGF0YSBvdXRzaWRlIG9mIGluZGljYXRlZCByYW5nZQ0KZWVtX2xpc3RfdHJpbW1lZCA8LSBlZW1fbGlzdF9yZWxfcnUgJT4lIA0KICAgICAgICAgICAgICAgICAgICBlZW1fcmFuZ2UoZXggPSBjKDI2MCwgSW5mKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbSA9IGMoMzAwLDU2MCkpDQoNCiMgcmVtb3ZlIHNjYXR0ZXINCmVlbV9saXN0X3NjYXR0ZXJfcmVtb3ZlZF8yIDwtIGVlbV9yZW1fc2NhdChlZW1fbGlzdF90cmltbWVkLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW1vdmVfc2NhdHRlciA9IGMoVFJVRSwgVFJVRSwgVFJVRSwgVFJVRSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlX3NjYXR0ZXJfd2lkdGggPSBjKDIwLCAxNSwgMjUsIDE1KSkNCg0KIyBjb250aW51b3VzbHkgZ28gYmFjayBhbmQgcmUtYWRqdXN0IGV4IGlmIG5lY2Vzc2FyeSwgYWdhaW4gSSBhbSBzYXZpbmcgdGhlIGNvbXAuIHBvd2VyIGhlcmUNCiMgZWVtX292ZXJ2aWV3X3Bsb3QoZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzIsIHNwcCA9IDcsIGNvbnRvdXIgPSBUUlVFKQ0KDQpgYGANCg0KUmVtb3ZlICBvdGhlciByZW1uYW50IG5vaXNlIChpbiB0aGlzIGV4YW1wbGUgYXQgRVggMjgwLTI5NSBubTsgYWdhaW4gZmluZSB0dW5lIGFzIG5lZWRlZCkuDQpZb3UgY2FuIHNlZSB0aGUgd29iYmx5IGxpbmVzIGluIHRoZSBwbG90IGFyb3VuZCB0aGlzIGFyZWEgc28gb3VyIGdvYWwgaXMgdG8gcmVtb3ZlIHRoYXQgYW5kIGludGVycG9sYXRlIHRoZSAic3RyYWlnaHQiIGxpbmVzIGZyb20gdGhlIHJlc3Qgb2YgdGhlIG1vZGVsLg0KDQpgYGB7ciBzZXQtTkFzfQ0KDQojIHdpdGggdGhlc2UganVzdCBzZXQgdGhlIHNjYXR0ZXIgYXJlYXMgYXMgTkFzDQplZW1fbGlzdF9zY2F0dGVyX3JlbW92ZWRfMiA8LSBlZW1fc2V0TkEoZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4ID0gMjg1OjMwMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJwb2xhdGUgPSBGQUxTRSkNCg0KIyB3aXRoIHRoaXMgaW50ZXJwb2xhdGUgdGhlIGFyZWFzIGZvciBzbW9vdGggbW9kZWxpbmcNCmVlbV9saXN0X2ludGVycF8yIDwtICBlZW1faW50ZXJwKGVlbV9saXN0X3NjYXR0ZXJfcmVtb3ZlZF8yLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gY29yZXMsIHR5cGUgPSAxLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dGVuZCA9IEZBTFNFKQ0KDQpgYGANCg0KU3RpbGwgdGhlcmUgaXMgdG9vIG11Y2ggdmFyaWF0aW9uIGluIGVtaXNzaW9uIHZhbHVlcyBvZiBzb21lIHNhbXBsZXMuIEl0IGlzIG1vc3QgdmlzaWJsZSBpbiBPY3RvYmVyLCB3aGljaCByYXRoZXIgdGhhbiBiZWluZyBmaXhlZCBzaG91bGQgYmUgdGhyb3duIG91dCBhbGx0b2dldGhlci4NCmBgYHtyLCByZXN1bHRzPSdoaWRlJ30NCg0KDQojIHdpdGggdGhpcyBpZGVudGlmeSB0aGUgb3JkZXIgbnVtYmVyIG9mIE9jdG9iZXIgc2FtcGxlcyB3aGljaCBzaG93IGdyZWF0IHZhcmlhdGlvbiANCmVlbV9saXN0X3NjYXR0ZXJfcmVtb3ZlZF8yIA0KDQojIGl0cyA2NCB0byA3MA0KDQojIGlkZW50aWZ5IGluIG9yZGVyIHRvIHJlbW92ZSBhdCBlbWlzc2lvbiB3YXZlbGVuZ3RocyAzMTkuNjQ1LTMzMC45NTcgbm0gd2hpY2ggYXJlIHRoZSBbMTM6MjBdIGVtaXNzaW9uIGludGVydmFsDQoNCiMgbWFrZSB0aGVtIE5Bcw0KZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzJbNjRdW1sxXV0keFsxMzoyMCwgXSA8LSBOQQ0KZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzJbNjVdW1sxXV0keFsxMzoyMCwgXSA8LSBOQQ0KZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzJbNjZdW1sxXV0keFsxMzoyMCwgXSA8LSBOQQ0KZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzJbNjddW1sxXV0keFsxMzoyMCwgXSA8LSBOQQ0KZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzJbNjhdW1sxXV0keFsxMzoyMCwgXSA8LSBOQQ0KZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzJbNjldW1sxXV0keFsxMzoyMCwgXSA8LSBOQQ0KZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzJbNzBdW1sxXV0keFsxMzoyMCwgXSA8LSBOQQ0KDQojaW50ZXJwb2xhdGUgdGhlIE5Bcw0KZWVtX2xpc3RfaW50ZXJwXzIgPC0gIGVlbV9pbnRlcnAoZWVtX2xpc3Rfc2NhdHRlcl9yZW1vdmVkXzIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSBjb3JlcywgdHlwZSA9IDEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXh0ZW5kID0gRkFMU0UpDQoNCiNlZW1fb3ZlcnZpZXdfcGxvdChlZW1fbGlzdF9pbnRlcnBfMiwgc3BwID0gNywgY29udG91ciA9IFRSVUUpDQpgYGANCg0KDQojIyMgRmluZGluZyBjb21wb25lbnQgbnVtYmVyDQoNClNldCBwYXJhbWV0ZXJzLg0KYGBge3IgfQ0KIyAxLiByYW5nZSBvZiBjb21wb25lbnRzIHRvIGxvb2sgZm9yIA0KDQojIyBtaW5pbXVtIG51bWJlciBvZiBjb21wb25lbnRzIA0KZGltX21pbiA8LSAzDQojIyBtYXhpbXVtIG51bWJlciBvZiBjb21wb25lbnRzDQpkaW1fbWF4IDwtIDcNCg0KIyB3aWxsIHByb2R1Y2UgbW9kZWxzIHdpdGggMywgNCwgNSwgNiwgb3IgNyBjb21wb25lbnRzLCByZXNwZWN0aXZlbHkNCg0KDQoNCiMgMi4gbnVtYmVyIG9mIHJhbmRvbSBpbml0aWFsaXphdGlvbiBmcm9tIHdoaWNoIHRoZSBiZXN0IG1vZGVsIHdpbGwgYmUgY2hvc2VuDQpuc3RhcnQgPC0gNTANCiMgbWF4aW11bSBudW1iZXIgb2YgaXRlcmF0aW9ucw0KbWF4aXQgPC0gNTAwMA0KIyB0b2xlcmFuY2UgaW4gcGFyYWZhYyBhbmFseXNpcyAodG9sZXJhdGVkIGNoYW5nZSBpbiBSMikNCmN0b2wgPC0gMTBeLTYNCmBgYA0KDQoNCg0KQ2FsY3VsYXRlIG1vZGVscyAodXNpbmcgY29uc3RyYWludHMgb2Ygbm9uLW5lZ2F0aXZlIGZsdW9yZXNjZW5jZSkuDQpgYGB7ciB9DQpwZl9zY3JlZW4gPC0gZWVtX3BhcmFmYWMoZWVtX2xpc3RfaW50ZXJwXzIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaG93IG1hbnkgY29tcG9uZW50cyBpbiBtb2RlbA0KICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBzID0gc2VxKGRpbV9taW4sIGRpbV9tYXgpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGlzZSA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHdlIGNhbm5vdCBoYXZlIG5lZ2F0aXZlIGVtL2V4IGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCA9IGMoIm5vbm5lZyIsICJub25uZWciLCAibm9ubmVnIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIG1heGl0ID0gbWF4aXQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIG5zdGFydCA9IG5zdGFydCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgY3RvbCA9IGN0b2wsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmVzID0gY29yZXMpDQoNCiMgcmVzY2FsZSBkYXRhIHN1Y2ggdGhhdCBtYXhpbXVtIG9mIGVhY2ggY29tcG9uZW50IGlzIDEuIA0KcGZfc2NyZWVuIDwtIGxhcHBseShwZl9zY3JlZW4sIGVlbXBmX3Jlc2NhbGVCQywgbmV3c2NhbGUgPSAiRm1heCIpDQpgYGANCg0KDQoNCkNoZWNrIGZpdCwgcGVha3MsIGFuZCBzcGVjdHJhIG9mIG1vZGVsIGNvbXBvbmVudHM6DQpgYGB7ciBjb21wYXJlLW1vZGVsLWZpdH0NCmVlbXBmX2NvbXBhcmUocGZfc2NyZWVuLCBjb250b3VyID0gVFJVRSkNCmBgYA0KDQoNCkluIHRoaXMgY2FzZSwgbW9kZWwgMyB3aXRoIDUgY29tcG9uZW50cyBhcHBlYXJzIHRvIGdpdmUgdGhlIGJlc3QgcmVzdWx0cy4gQ2hlY2sgZm9yIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGNvbXBvbmVudHMgaW4gbW9kZWwgMyAodGhlcmUgc2hvdWxkIGJlIG5vIHN0cm9uZyBjb3JyZWxhdGlvbnMpLg0KYGBge3IgfQ0KDQplZW1wZl9jb3JwbG90KHBmX3NjcmVlbltbM11dKSAjIGNvbXBzIDEgYW5kIDIgIHNlZW0gaGlnaGx5IGNvcnJlbGF0ZWQNCmBgYA0KDQojIyMgTm9ybWFsaXphdGlvbg0KQ29tcG9uZW50IDEgYW5kIDIgc2VlbSBoaWdobHkgY29ycmVsYXRlZDsgcmUtcnVuIHRoZSBtb2RlbHMgd2l0aCBub3JtYWxpemVkIGRhdGEuDQpgYGB7ciB9DQojIHJlLXJ1bg0KcGZfc2NyZWVuX25vcm0gPC0gZWVtX3BhcmFmYWMoZWVtX2xpc3RfaW50ZXJwXzIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcHMgPSBzZXEoZGltX21pbiwgZGltX21heCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB3aXRoIHRoaXMgd2Ugbm9ybWFsaXplIHRoZSBkYXRhLCBhcyBvcHBvc2VkIHRvIGJlZm9yZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXNlID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCA9IGMoIm5vbm5lZyIsICJub25uZWciLCAibm9ubmVnIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4aXQgPSBtYXhpdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc3RhcnQgPSBuc3RhcnQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3RvbCA9IGN0b2wsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSBjb3JlcykNCg0KIyByZXNjYWxlDQpwZl9zY3JlZW5fbm9ybSA8LSBsYXBwbHkocGZfc2NyZWVuX25vcm0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgIGVlbXBmX3Jlc2NhbGVCQywgDQogICAgICAgICAgICAgICAgICAgICAgICAgbmV3c2NhbGUgPSAiRm1heCIpDQoNCg0KIyBjaGVjayBmaXQsIHBlYWtzLCBhbmQgc3BlY3RyYQ0KZWVtcGZfY29tcGFyZShwZl9zY3JlZW5fbm9ybSwgY29udG91ciA9IFRSVUUpDQpgYGANCg0KQWZ0ZXIgbm9ybWFsaXphdGlvbiwgbW9kZWwgMyBhbmQgbW9kZWwgNCB3aXRoIDQgYW5kIDUgY29tcG9uZW50cywgcmVzcGVjdGl2ZWx5LCBhcHBlYXIgcmVhc29uYWJsZTsgY2hlY2sgZm9yIGNvcnJlbGF0aW9ucyBpbiBib3RoLg0KDQpgYGB7ciB9DQoNCiMgbW9kZWwzDQojIGVlbXBmX2NvcnBsb3QocGZfc2NyZWVuX25vcm1bWzRdXSkgDQoNCiMgbW9kZWwyDQplZW1wZl9jb3JwbG90KHBmX3NjcmVlbl9ub3JtW1szXV0pIA0KDQpgYGANCg0KIyMjIFNjcmVlbiBvdXRsaWVyIHNhbXBsZXMgDQpUaGVyZSBpcyBwb3NzaWJpbGl0eSB0aGF0IGNlcnRhaW4gc2FtcGxlcyBoYXZlIHRvbyBtdWNoIGxldmVyYWdlIGluIHRoZSBtb2RlbCBhbmQgd291bGQgYmUgYmV0dGVyIGZvciB0aGUgbW9kZWwgdG8gcmVtb3ZlIHRoZW0uDQpMZXZlcmFnZSByYW5nZXMgYmV0d2VlbiAwIGFuZCAxIHdpdGggdmVyeSBhdHlwaWNhbCB3YXZlbGVuZ3Rocy9zYW1wbGVzIGhhdmluZyBhIGxldmVyYWdlIG5lYXIgMS4NCg0KTGV2ZXJhZ2Ugc2hvdWxkIGJlIHJvdWdobHkgc2ltaWxhciBhY3Jvc3Mgd2F2ZWxlbmd0aHMvc2FtcGxlcy4gDQpJZiBwb2ludHMgd2l0aCBoaWdoIGxldmVyYWdlIGFyZSBpZGVudGlmaWVkLCB0aG9zZSBzaG91bGQgYmUgcmVtb3ZlZCBhbmQgdGhlIG1vZGVsIHNob3VsZCBiZSByZS1jYWxjdWxhdGVkLg0KDQpgYGB7cn0NCiMgY2FsY3VsYXRlIGxldmVyYWdlDQpjcGwgPC0gZWVtcGZfbGV2ZXJhZ2UocGZfc2NyZWVuX25vcm1bWzNdXSkNCg0KIyBwbG90DQplZW1wZl9sZXZlcmFnZV9wbG90KGNwbCwgcWxhYmVsPTAuMSkNCg0KIyAoZXhjbHVkZSA8LSBlZW1wZl9sZXZlcmFnZV9pZGVudChjcGwscWxhYmVsPTAuMSkpDQpgYGANCg0KQXQgZXhjaXRhdGlvbiAzMzAgbm0gdGhlcmUgaXMgYSBodWdlIHNwaWtlIGluIG1vZGVscyB3aXRoIDUrIGNvbXBvbmVudHMuIFNpbmNlIGl0IGRvZXMgbm90IHNlZW0gdG8gYmUgc3VjaCBhIGJpZyBwcm9ibGVtIHdpdGggNCBjb21wb25lbnRzLCB3ZSBrZWVwIGFsbC4NCg0KTm9uZSBvZiB0aGUgc2FtcGxlcyBoYXZlIGxldmVyYWdlIGJpZ2dlciB0aGFuIDAuMywgc28gd2Ugd2lsbCBub3QgcmVtb3ZlIGFueS4gIA0KDQoNCiMjIyBDaGVjayByZXNpZHVhbHMNCg0KUmVzaWR1YWxzIHNob3VsZCBiZSByYW5kb20gYWNyb3NzIHNhbXBsZXMgYW5kIHNob3VsZCBub3Qgc2hvdyBtYWpvciBwZWFrcyBvciB0cm91Z2hzIChzbWFsbCBwZWFrcyBhbG9uZyB0aGUgZGlhZ29uYWwgYXJlIGFjY2VwdGFibGUgYW5kIG1heSBiZSBpZ25vcmVkOyBtYWlubHkgcmVwcmVzZW50IG1lcmVseSByZW1uYW50IHNjYXR0ZXIpLg0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0NCmVlbXBmX3Jlc2lkdWFsc19wbG90KHBmX3NjcmVlbl9ub3JtW1szXV0sIA0KICAgICAgICAgICAgICAgICAgICAgZWVtX2xpc3RfaW50ZXJwXzIsIA0KICAgICAgICAgICAgICAgICAgICAgcmVzaWR1YWxzX29ubHkgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgIHNwcCA9IDcsIA0KICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSBjb3JlcywgDQogICAgICAgICAgICAgICAgICAgICBjb250b3VyID0gVFJVRSkNCmBgYA0KDQoNCk5vIG5lZWQgdG8gZnVydGhlciBhZGFwdCB0aGUgbW9kZWwsIHRoZSByZXNpZHVhbHMgbG9vayByYW5kb20uDQoNCg0KDQojIyBGaW5hbCBtb2RlbCANCg0KTm93IHRoYXQgd2UgYXJlIHN1cmUgdGhhdCBhbGwgb3V0bGllcnMgYXJlIHJlbW92ZWQgZnJvbSB0aGUgbW9kZWwsIGFuZCB0aGF0IHJlc2lkdWFscyBhcmUgYWNjZXB0YWJsZSBmb3IgdGhpcyBtb2RlbCwgd2UgY2FsY3VsYXRlIGEgbmV3IG1vZGVsIHdpdGggaW5jcmVhc2VkIGFjY3VyYWN5LiANCg0KDQpJZiB3ZSB3YW50IHRvIGdldCBhIG1vcmUgZGV0YWlsZWQgY29tcGFyaXNvbnMgd2UgY2FuIHRoaXMgY29tbWFuZCAobm90IGluY2x1ZGVkIGFzIG91dHB1dCBiZWNhdXNlIG9mIHRoZSB0aW1lIG5lZWRlZCk6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KIyBkZWNyZWFzZSB0b2xlcmFuY2UgaW4gUiBkZXZpYXRpb24NCmN0b2wgPC0gMTBeLTggDQojIGluY3JlYXNlIG51bWJlciBvZiByYW5kb20gc3RhcnRzDQpuc3RhcnQgPSA2MCANCiMgaW5jcmVhc2UgbnVtYmVyIG9mIG1heGltdW0gaW50ZXJhdGlvbnMNCm1heGl0ID0gMTAwMDAgDQojIG51bWJlciBvZiBzdWl0YWJsZSBjb21wb25lbnRzIGlkZW50aWZpZWQgcHJldmlvdXNseQ0KY29tcHMgPSA1IA0KDQoNCg0KIyBjYWxjdWxhdGUgbW9kZWwgd2l0aCBuIGNvbXBvbmVudHMNCnBmX25fY29tcG9uZW50c18xIDwtIGVlbV9wYXJhZmFjKGVlbV9saXN0X2ludGVycF8yLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBzID0gY29tcHMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXNlID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCA9IGMoIm5vbm5lZyIsICJub25uZWciLCAibm9ubmVnIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4aXQgPSBtYXhpdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc3RhcnQgPSBuc3RhcnQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3RvbCA9IGN0b2wsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0ID0gImFsbCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSBjb3JlcykNCg0KIyByZS1zY2FsZQ0KcGZfbl9jb21wb25lbnRzXzEgPC0gbGFwcGx5KHBmX25fY29tcG9uZW50c18xLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZW1wZl9yZXNjYWxlQkMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld3NjYWxlID0gIkZtYXgiKQ0KDQpgYGANCg0KDQpDaGVjayB0aGUgbW9kZWw6DQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KDQojIGNoZWNrIGNvbnZlcmdlbmNlIGFuZCBtb2RlbCBwZXJmb3JtYW5jZQ0KZWVtcGZfY29udmVyZ2VuY2UocGZfbl9jb21wb25lbnRzXzFbWzFdXSkNCg0KIyBwbG90DQplZW1wZl9jb21wYXJlKHBmX25fY29tcG9uZW50c18xLCBjb250b3VyID0gVFJVRSkNCg0KIyBjaGVjayBsZXZlcmFnZQ0KZWVtcGZfbGV2ZXJhZ2VfcGxvdChlZW1wZl9sZXZlcmFnZShwZl9uX2NvbXBvbmVudHNfMVtbMV1dKSkNCg0KIyBjaGVjayBjb3JyZWxhdGlvbnMNCmVlbXBmX2NvcnBsb3QocGZfbl9jb21wb25lbnRzXzFbWzFdXSwgcHJvZ3Jlc3MgPSBGQUxTRSkNCiNjb21wIDIgYW5kIDMgdG9vIGNvcnJlbGF0ZWQ/DQpgYGANCg0KDQpPcHQgb3V0IGZvciB0aGUgbW9kZWwgd2l0aCA1IGNvbXBvbmVudHMgYW5kIHJlLWNhbGN1bGF0ZSBhIG5ldyByb3VnaCBtb2RlbCB3aXRoIG1vcmUgcmVzdGFydHMgYW5kIGxvd2VyIGFjY3VyYWN5Lg0KYGBge3J9DQpwZl9uX2NvbXBvbmVudHNfMiA8LSBlZW1fcGFyYWZhYyhlZW1fbGlzdF9pbnRlcnBfMiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wcyA9IDUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXNlID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCA9IGMoIm5vbm5lZyIsICJub25uZWciLCAibm9ubmVnIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4aXQgPSBtYXhpdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuc3RhcnQgPSAxMDAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3RvbCA9IG1pbihjdG9sKjEwMCwwLjAxKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlcyA9IGNvcmVzKQ0KDQpgYGANCg0KDQpVc2UgdGhlIHJlc3VsdGluZyBtb2RlbCBhcyBzdGFydGluZyBwb2ludCB0byByZS1jYWxjdWxhdGUgdGhlIGhpZ2gtYWNjdXJhY3kgbW9kZWwgKG5zdGFydHMgY2FuIGJlIGxvd2VyIGhlcmUpLg0KDQoNCmBgYHtyfQ0KcGZfbl9jb21wb25lbnRzXzMgPC0gZWVtX3BhcmFmYWMoZWVtX2xpc3RfaW50ZXJwXzIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcHMgPSA1LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbGlzZSA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgPSBjKCJub25uZWciLCAibm9ubmVnIiwgIm5vbm5lZyIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heGl0ID0gbWF4aXQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnN0YXJ0ID0gMTAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3RvbCA9IGN0b2wsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZXMgPSBjb3JlcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCc3RhcnQgPSBwZl9uX2NvbXBvbmVudHNfMltbMV1dJEIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ3N0YXJ0ID0gcGZfbl9jb21wb25lbnRzXzJbWzFdXSRDKQ0KDQpwZl9uX2NvbXBvbmVudHNfMyA8LSBsYXBwbHkocGZfbl9jb21wb25lbnRzXzMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVlbXBmX3Jlc2NhbGVCQywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3c2NhbGUgPSAiRm1heCIpDQoNCmBgYA0KDQoNClBsb3QgdGhlIHJlc3VsdGluZyBjb21wb25lbnRzOg0KYGBge3J9DQplZW1wZl9jb21wX2xvYWRfcGxvdChwZl9uX2NvbXBvbmVudHNfM1tbMV1dLCBjb250b3VyID0gVFJVRSkNCmBgYA0KDQoNCiMjIFNwbGl0LWhhbGYgYW5hbHlzaXMNClZhbGlkYXRlIGZpbmFsIG1vZGVsIHVzaW5nIHNwbGl0LWhhbGYgYW5hbHlzaXMgKGdlbmVyYXRlcyBUdWNrZXLigJlzIENvbmdydWVuY2UgQ29lZmZpY2llbnQ7IHZhbHVlIHNob3VsZCBiZSBjbG9zZSB0byBvbmUgKGFuZCBub3Qgc21hbGxlciB0aGFuIH4wLjktMC44NSkgZm9yIGdvb2QgY29uc2lzdGVudCBtb2RlbCkuDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMgdGhpcyBpcyBhZ2FpbiB3YXkgdG9vIGludGVuc2l2ZSB0byBrbml0IGluIGEgcGRmDQoNCiNjYWxjdWxhdGUgc3BsaXRfaGFsZiBhbmFseXNpcw0Kc2ggPC0gc3BsaXRoYWxmKGVlbV9saXN0X2ludGVycF8yLCANCiAgICAgICAgICAgICAgICBjb21wcyA9IDUsIA0KICAgICAgICAgICAgICAgIG5vcm1hbGlzZSA9IFRSVUUsIA0KICAgICAgICAgICAgICAgIHJhbmQgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgY29yZXMgPSBjb3JlcywgDQogICAgICAgICAgICAgICAgbnN0YXJ0ID0gbnN0YXJ0LCANCiAgICAgICAgICAgICAgICBtYXhpdCA9IG1heGl0LCANCiAgICAgICAgICAgICAgICBjdG9sID0gY3RvbCkNCg0Kc3BsaXRoYWxmX3Bsb3Qoc2gpDQpzcGxpdGhhbGZfdGNjKHNoKQ0KYGBgDQoNCg0KIyMgVmlzdWFsaXplIGNvbXBvbmVudHMNCg0KQ2FsY3VsYXRlICJhbW91bnQiIG9mIGNvbXBvbmVudHMgcGVyIHNhbXBsZToNCmBgYHtyLH0NCnBmX21pc3Npbmdfc2FtcGxlcyA8LSBBX21pc3NpbmcoZWVtX2xpc3RfaW50ZXJwXzEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBmX25fY29tcG9uZW50c18zW1sxXV0pDQpmaW5hbF9jb21wX3RhYmxlIDwtIGFzLmRhdGEuZnJhbWUoIGVlbXBmNGFuYWx5c2lzKHBmX21pc3Npbmdfc2FtcGxlcywgZWVtNHBlYWtzKSkNCg0KDQpjb21wX3RhYmxlIDwtIGZpbmFsX2NvbXBfdGFibGUgJT4lIA0KICBhcy5kYXRhLmZyYW1lKCkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KCJzYW1wbGUiLCAiQ29tcC4xIiwgIkNvbXAuMiIsIA0KICAgICAgICAgICAgICAgICJDb21wLjMiLCAiQ29tcC40IiwgIkNvbXAuNSIpICU+JSANCiAgDQojIGFkZCBpZGVudGlmZXJzIGZvciB3ZWxsX2lkIGFuZCBkYXRlICANCiAgbXV0YXRlKCB3ZWxsX2lkID0gc3RyX3N1YihzYW1wbGUsIHN0YXJ0ID0gMSwgZW5kID0gMyksDQogICAgICAgICAgZGF0ZSA9IHN0cl9zcGxpdChzYW1wbGUsICJfIiwgc2ltcGxpZnkgPSBUUlVFKVssIDJdLA0KICAgICAgICAgIHdhdGVyX2tpbmQgPSBjYXNlX3doZW4oICMgZm9yIHB1bXBlZA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3Qoc2FtcGxlLCAicCIpIH4gInB1bXBlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBmb3Igd2VsbA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3Qoc2FtcGxlLCAidyIpIH4gIndlbGwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZm9yIHN1cmZhY2UNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gInN1cmZhY2UiKSApICU+JSAgICAgICAgICAgICAgDQogDQogICBtdXRhdGUoZGF0ZSA9IHltZChkYXRlKSkNCg0KDQoNCmBgYA0KDQoNCmEpIEFic29sdXRlIGNvbmNlbnRyYXRpb25zOg0KYGBge3J9DQpjb21wX3RhYmxlICU+JSANCiAgDQojIHJlbW92ZSB0aGUgd2VsbCB3YXRlciAgDQogIGRwbHlyOjpmaWx0ZXIod2F0ZXJfa2luZCAhPSAid2VsbCIpICU+JSANCiAgbXV0YXRlKGRhdGUgPSBhcy5mYWN0b3IoZGF0ZSksDQogICAgICAgICB3YXRlcl9raW5kID0gYXMuZmFjdG9yKHdhdGVyX2tpbmQpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoIWMoICJ3ZWxsX2lkIiwgInNhbXBsZSIpKSAlPiUgDQogIHBpdm90X2xvbmdlcihjb2xzID0gLWMoZGF0ZSwgd2F0ZXJfa2luZCksIA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiY29tcHMiLCANCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJjb25jcyIpICU+JSANCiAgbXV0YXRlKGNvbXBzID0gYXMuZmFjdG9yKGNvbXBzKSkgICAgICU+JSANCiAgDQojIGZpbmQgYXZlcmFnZSBmcm9tIGFsbCB0aHJlZSBncm91bmR3YXRlciB3ZWxscyANCiAgZ3JvdXBfYnkoZGF0ZSwgY29tcHMsIHdhdGVyX2tpbmQpICU+JSANCiAgc3VtbWFyaXNlKGNvbmNzID0gbWVhbihjb25jcykpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgDQojIHBsb3QgIA0KICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gY29uY3MsIGZpbGwgPSBjb21wcykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgZmFjZXRfd3JhcCh+IHdhdGVyX2tpbmQsIG5jb2wgPSAxKSArIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKGNvbmNzLCA0KSApKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwgc2l6ZSA9IDIuNSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICB0aGVtZV9saW5lZHJhdygpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsNCiAgbGFicyh4PU5VTEwsIHk9TlVMTCkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IGMoIkF1ZyIsICJTZXAiLCAiT2N0IiwgIk5vdiIsICJEZWMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkphbiIsICJGZWIiLCAiTWFyIiwgIkFwciIsICJNYXkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJKdW4iLCAiSnVsIikpIC0+IHBsdDINCg0KcGx0Mg0KYGBgDQoNCmIpIFJlbGF0aXZlIGNvbmNlbnRyYXRpb25zOg0KYGBge3J9DQoNCg0KY29tcF90YWJsZSAlPiUgDQogIG11dGF0ZShkYXRlID0gYXMuZmFjdG9yKGRhdGUpLA0KICAgICAgICAgd2F0ZXJfa2luZCA9IGFzLmZhY3Rvcih3YXRlcl9raW5kKSkgJT4lIA0KICBkcGx5cjo6c2VsZWN0KCFjKCAid2VsbF9pZCIsICJzYW1wbGUiKSkgJT4lIA0KICBwaXZvdF9sb25nZXIoY29scyA9IC1jKGRhdGUsIHdhdGVyX2tpbmQpLCANCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gImNvbXBzIiwgDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiY29uY3MiKSAlPiUgDQogIG11dGF0ZShjb21wcyA9IGFzLmZhY3Rvcihjb21wcykpICAgICAlPiUgDQoNCiMgZmluZCBhdmVyYWdlIGZyb20gYWxsIHRocmVlIGdyb3VuZHdhdGVyIHdlbGxzIA0KICBncm91cF9ieShkYXRlLCBjb21wcywgd2F0ZXJfa2luZCkgJT4lIA0KICBzdW1tYXJpc2UoY29uY3MgPSBtZWFuKGNvbmNzKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KDQojIGZpbmQgIHJlbGF0aXZlIGFidW5kYW5jZXMgZm9yIGVhY2ggZGF0ZSBpbiBlYWNoIHdhdGVyIGtpbmQgKHdlbGwvcHVtcC9zdXJmKQ0KICBncm91cF9ieShkYXRlLCB3YXRlcl9raW5kKSAlPiUNCiMgcmVsYXRpdmUgY29uY2VudHJhdGlvbnMgYXJlIHRoZSB2YWx1ZSBkaXZpZGVkIGJ5IHRoZSBzdW0gIA0KICBtdXRhdGUocmVsX2NvbmMgPSBjb25jcyAvIHN1bShjb25jcykgKiAxMDApICU+JQ0KICB1bmdyb3VwKCkgJT4lIA0KICANCiMgcGxvdCAgDQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSByZWxfY29uYywgZmlsbCA9IGNvbXBzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBmYWNldF93cmFwKH4gd2F0ZXJfa2luZCwgbmNvbCA9IDEpICsgDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAocm91bmQocmVsX2NvbmMsIDQpICwgIiUiKSksIA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksIHNpemUgPSAyLjEpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgdGhlbWVfbGluZWRyYXcoKSArIA0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArDQogIGxhYnMoeD1OVUxMLCB5PU5VTEwpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBjKCJBdWciLCAiU2VwIiwgIk9jdCIsICJOb3YiLCAiRGVjIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJKYW4iLCAiRmViIiwgIk1hciIsICJBcHIiLCAiTWF5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSnVuIiwgIkp1bCIpKSAtPiBwbHQxDQoNCnBsdDENCg0KYGBgDQoNCmMpIExpbmUgcGxvdCBvZiBhYnNvbHV0ZSBhYnVuZGFuY2VzLCBwZXIgY29tcG9uZW50OiANCmBgYHtyfQ0KDQpjb21wX3RhYmxlICU+JSANCiAgZHBseXI6OmZpbHRlcih3YXRlcl9raW5kICE9ICJ3ZWxsIikgJT4lIA0KICBtdXRhdGUoZGF0ZSA9IGFzLmZhY3RvcihkYXRlKSwNCiAgICAgICAgIHdhdGVyX2tpbmQgPSBhcy5mYWN0b3Iod2F0ZXJfa2luZCkpICU+JSANCiAgZHBseXI6OnNlbGVjdCghYyggIndlbGxfaWQiLCAic2FtcGxlIikpICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtYyhkYXRlLCB3YXRlcl9raW5kKSwgDQogICAgICAgICAgICAgICBuYW1lc190byA9ICJjb21wcyIsIHZhbHVlc190byA9ICJjb25jcyIpICU+JSANCiAgbXV0YXRlKGNvbXBzID0gYXMuZmFjdG9yKGNvbXBzKSkgJT4lIA0KDQojIGZpbmQgYXZlcmFnZSBmcm9tIGFsbCB0aHJlZSBncm91bmR3YXRlciB3ZWxscyANCiAgZ3JvdXBfYnkoZGF0ZSwgY29tcHMsIHdhdGVyX2tpbmQpICU+JSANCiAgc3VtbWFyaXNlKGNvbmNzID0gbWVhbihjb25jcykpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgDQojIHBsb3QgDQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBjb25jcywgDQogICAgICAgICAgICAgY29sb3IgPSB3YXRlcl9raW5kLCANCiAgICAgICAgICAgICBncm91cCA9d2F0ZXJfa2luZCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBmYWNldF93cmFwKH4gY29tcHMpICsgDQogIHRoZW1lX2xpbmVkcmF3KCkgKyANCiAgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKw0KICANCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKw0KICBsYWJzKHg9TlVMTCwgeT1OVUxMKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiQXVnIiwgIlNlcCIsICJPY3QiLCAiTm92IiwgIkRlYyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSmFuIiwgIkZlYiIsICJNYXIiLCAiQXByIiwgIk1heSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkp1biIsICJKdWwiKSkgLT4gcGx0Mw0KDQpwbHQzDQpgYGANCg0KDQoNCiMjIEV4cG9ydCBjb21wb25lbnQgdGFibGUNCkdldCB0YWJsZSB3aXRoIGV4Y2l0YXRpb24vZW1pc3Npb24gd2F2ZWxlbmd0aHMgZm9yIGVhY2ggY29tcG9uZW50IHRvIGlkZW50aWZ5IGJ5IGNvbXBhcmluZyB0byB0aGUgYWxyZWFkeSBvYnNlcnZlZCBleGNpdGF0aW9uL2VtaXNzaW9uIG1heGltYS4NCg0KYGBge3J9DQpjb21wX3NwZWN0cmEgPC0gZWVtcGZfZXhwb3J0KHBmX25fY29tcG9uZW50c18zW1sxXV0pDQoNCmBgYA0KDQpGcm9tIHRoaXMgdGFibGUgd2UgbG9vayBhdCB3aGljaCBleCBhbmQgZW0gdmFsdWVzIGZvciBlYWNoIGNvbXBvbmVudCBpcyBhdCAxLCBmb3IgZXhhbXBsZSBDb21wMSBoYXMgdGhlIGV4Y3RhdGlvbiBtYXhpbWEgKDEpIGF0IDI2MCBubS4gDQoNCg0KDQoNCiMgRW52aXJvbm1lbnRhbCBkYXRhDQoNCmBgYHtyfQ0KDQojIGxvYWQgZW52aXJvbm1lbnRhbCBkYXRhDQplbnZfZGF0YSA8LSByZWFkX2V4Y2VsKCJDOi9Vc2Vycy9BbmdlbGEgQ3VrdXNpYy9Eb2N1bWVudHMvZmFrcy9FY29sb2d5IGFuZCBFY29zeXN0ZW1zL01FQy00IChJbnRybyB0byByZXNlYXJjaCAtIHMgcHJvZikvRGF0YS9sb2JhdV9kYXRhX2NvbWJpbmVkLnhsc3giKQ0KZW52X2RhdGExIDwtIGVudl9kYXRhICAlPiUgDQogICMgdGVtcGVyYXR1cmUgYW5kIG94eWdlbiBhcmUgaW4gdHdvIGRpZmZlcmVudCBjb2x1bW5zIGZvciBndyBhbmQgc3cNCiAgbXV0YXRlKG94eWdlbiA9IGNvYWxlc2NlKCBveHlnZW5fbWdfTCAsIG94eWdlbl9hYm92ZV9ib3R0b21fbWdfTCksDQogICAgICAgICB0ZW1wID0gY29hbGVzY2UoIHRlbXBfQyAsIHRlbXBfYWJvdmVfYm90dG9tX0MpICkgJT4lIA0KICAjIHJlbW92ZSB1bm5lY2Nlc3NhcnkgY29sdW1ucw0KICBkcGx5cjo6c2VsZWN0KCFjKCJ3ZWxsX2lkIiwgImRhdGVfbW1fZGRfeXl5eSIsICJzYW1wbGVfdHlwZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImF0cF90b3RhbF9wTSIsICJveHlnZW5fYmVsb3dfZ3dfc3VyZmFjZV9tZ19MIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGVtcF9iZWxvd19nd19zdXJmYWNlX0MiLCAiZGVsdGFfMTNjaDRfcGVybWlsbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNkX2RlbHRhXzEzY2g0IiwgIm94eWdlbl9tZ19MIiAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm94eWdlbl9hYm92ZV9ib3R0b21fbWdfTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGVtcF9DIiAsICJ0ZW1wX2Fib3ZlX2JvdHRvbV9DIikpICU+JSANCiAgbGVmdF9qb2luKGNvbXBfdGFibGUsIC4sIGJ5PSBjKCJzYW1wbGUiID0gInNhbXBsZV9pZCIpKSAlPiUgDQogICMgcmVtb3ZlIGRhdGEgb24gZGVwdGggc2luY2UgaXQgd291bGQgcmVtb3ZlIGFsbCB0aGUgc3VyZmFjZSB3YXRlciBlbnRyaWVzDQogIHNlbGVjdCghIG1hdGNoZXMoImRlcHRofHRhYmxlIikgKSAlPiUgDQogICMgZmV3IG1vbnRocyBkbyBub3QgaGF2ZSBtZWFzdXJlZCBwYXJhbWV0ZXJzLCByZW1vdmUgdGhvc2UNCiAgbmEub21pdCgpDQoNCiByb3duYW1lcyhlbnZfZGF0YTEpIDwtIGVudl9kYXRhMSRzYW1wbGUgDQoNCg0KYGBgDQoNCkNvbnNpZGVyaW5nIHRoYXQgdGhlIG1haW4gZm9jdXMgb2YgdGhlIGFuYWx5c2lzIGlzIHRoZSBET0MsIHRoZSBhcHByb2FjaCB0byBQQ0EgaXMgZXhwZXJpbWVudGFsIC0gY29tYmluaW5nIHRoZSBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcyBpbnRvIHByaW5jaXBhbCBjb21wb25lbnRzIHRvIHVzZSBpbiB0aGUgY29uc3RyYWluZWQgYW5hbHlzaXMgc2luY2UgdGhlIFBDIGZvcm0gcHJldmVudHMgdGhlIGNvbGxpbmVhcml0eS4NCg0KDQpgYGB7cn0NCg0KDQojIDEuIENhbGN1bGF0ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4IHRvIGZpcnN0IHNpbXBsaWZ5IHRoZSBoaWdobHkgY29ycmVsYXRlZCBvbmVzDQpjb3JfbWF0cml4IDwtIGNvcihlbnZfZGF0YTFbLC1jKDE6OSldKQ0KDQojIEZpbmQgaGlnaGx5IGNvcnJlbGF0ZWQgdmFyaWFibGVzIHdpdGggYSB0aHJlc2hvbGQgb2YgMC44DQpoaWdobHlfY29ycmVsYXRlZCA8LSBmaW5kQ29ycmVsYXRpb24oY29yX21hdHJpeCwgY3V0b2ZmID0gMC44KQ0KDQojIFJlbW92ZSB0aGUgaGlnaGx5IGNvcnJlbGF0ZWQgdmFyaWFibGVzIGZyb20gdGhlIGRhdGFmcmFtZQ0KZGZfcGNhIDwtIGVudl9kYXRhMVssLWMoMTo5KV1bLCAtaGlnaGx5X2NvcnJlbGF0ZWRdDQoNCiMgUGVyZm9ybSBQQ0Egb24gdGhlIHByZXByb2Nlc3NlZCBkYXRhZnJhbWUgKGRmX3BjYSkNCnBjYV9lbnYgPC0gcHJjb21wKGRmX3BjYSwgc2NhbGUgPSBUUlVFKQ0KDQoNCmJpcGxvdChwY2FfZW52KQ0KIyBpZiB0aGVyZSBpcyBvbmUgc2FtcGxlIHRoYXQgaXMgd2F5IGRpZmZlcmVudCB0aGFuIGFsbCB0aGUgcmVzdCB3aGljaCBJIHdvdWxkIGxpa2UgdG8gcmVtb3ZlDQojdGlkeShwY2FfZW52KSAlPiUgZmlsdGVyKFBDID09ICIxIikgJT4lIGZpbHRlcih2YWx1ZSA+IDUpICU+JSBzZWxlY3QoInJvdyIpDQoNCiMgYnV0IHNlZW1zIG5vdA0KDQoNCiMgMi4gTG9vayBhdCB3aGljaCBjb21wb25lbnRzIGl0IG1ha2VzIHNlbnNlIHRvIGtlZXAgZm9yIGZ1cnRoZXIgYW5hbHlpc2lzDQojIHVzdWFsbHkgdGhvc2UgdGhhdCBjb250cmlidXRlIG1vcmUgdGhhbiAxIGVpZ2VudmFsdWUNCg0KIyBHZXQgdGhlIGVpZ2VudmFsdWVzIG9mIGNvbXBvbmVudHMgKHRoZSBzdC5kZXYpDQojIHN1bW1hcnkocGNhX2VudikgLT4gdGhlIGZpcnN0IDcgY29tcG9uZW50cyBoYXZlIGhhdmUgbW9yZSB0aGFuIDEgDQpgYGANCg0KDQoNCm5vcm1hbCBkYXRhOiB2YXJpYW5jZSA9IChzdC5kZXYpXjINCnBjYSBkYXRhOiAgZWlnZW52YWx1ZSA9IChzdC5kZXYpXjINCg0KImVpZ2VudmFsdWVzIHJlcHJlc2VudCB0aGUgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IGVhY2ggcHJpbmNpcGFsIGNvbXBvbmVudCIgLT4gZWlnZW4gfiB2YXJpYW5jZQ0KDQpUaGUgZmlyc3QgZWlnaHQgY29tcG9uZW50cyBleHBsYWluIG1vcmUgdGhhbiAxIHZhcmlhbmNlIGluIGRhdGEsIGJ1dCBvbmx5IHRoZSBmaXJzdCB0aHJlZSBleHBsYWluIG1vcmUgdGhhbiAxJSBvZiB2YXJpYW5jZS4gVGhlcmVmb3JlLCBrZWVwIG9ubHkgUEMxLCBQQzIgYW5kIFBDMyAoYXMgY29tYmluYXRpb25zIG9mIGVudmlyb25tZW50YWwgdmFyaWFibGVzKSBmb3IgZnVydGhlciBhbmFseXNpcy4NCg0KIyMgTG9hZGluZ3MNCg0KTm93IHNlZSB3aGF0IGNvbnRyaWJ1dGVzIHRvIGVhY2ggb2YgdGhlIHRocmVlIFBDcyBhbmQgaWYgc29tZSBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcyBjYW4gYmUgcmVtb3ZlZC4NCmBgYHtyfQ0KDQojIEV4dHJhY3QgdGhlIGxvYWRpbmdzIGZyb20gdGhlIFBDQSByZXN1bHQgYW5kIGNvbnZlcnQgdG8gdGlkeSBmb3JtYXQNCmxvYWRpbmdzX2RmIDwtICAgdGlkeShwY2FfZW52LCBtYXRyaXggPSAicm90YXRpb24iKQ0KDQoNCg0KIyBQQzENCiMgQ3JlYXRlIHRoZSBnZ3Bsb3QyIG9iamVjdCBmb3IgcGxvdHRpbmcgdGhlIGxvYWRpbmdzDQpwMSA8LSBsb2FkaW5nc19kZiAlPiUgZmlsdGVyKFBDID09ICIxIikgJT4lIA0KICAjeD1yZW9yZGVyKGNsYXNzLC1hbW91bnQsc3VtKQ0KZ2dwbG90KCBhZXMoeCA9IHJlb3JkZXIoY29sdW1uLCAtdmFsdWUpLCB5ID0gdmFsdWUsIGdyb3VwID0gZmFjdG9yKGNvbHVtbikpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIA0KICAgICAgICAgICBmaWxsPSAiZ3JheTkwIiwgY29sb3IgPSAiZ3JheTIwIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY29sdW1uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIA0KICAgICAgICAgICAgI3ZqdXN0ID0gImlud2FyZCIsICANCiAgICAgICAgICAgIGFuZ2xlID0gOTAgLCBoanVzdCA9ICJpbndhcmQiKSArDQogIGxhYnMoeCA9ICJWYXJpYWJsZXMgb2YgUEMxIiwgeSA9ICJMb2FkaW5ncyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KIyBET0MgYW5kIG1pbmVyYWxzDQoNCg0KIyBQQzIgDQpwMiA8LSBsb2FkaW5nc19kZiAlPiUgZmlsdGVyKFBDID09ICIyIikgJT4lIA0KICAjeD1yZW9yZGVyKGNsYXNzLC1hbW91bnQsc3VtKQ0KZ2dwbG90KCBhZXMoeCA9IHJlb3JkZXIoY29sdW1uLCAtdmFsdWUpLCB5ID0gdmFsdWUsIGdyb3VwID0gZmFjdG9yKGNvbHVtbikpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIsIA0KICAgICAgICAgICBmaWxsPSAiZ3JheTkwIiwgY29sb3IgPSAiZ3JheTIwIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gY29sdW1uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIA0KICAgICAgICAgICAgI3ZqdXN0ID0gImlud2FyZCIsICANCiAgICAgICAgICAgIGFuZ2xlID0gOTAgLCBoanVzdCA9ICJpbndhcmQiKSArDQogIGxhYnMoeCA9ICJWYXJpYWJsZXMgb2YgUEMyIiwgeSA9ICJMb2FkaW5ncyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KDQojIFBDMw0KcDMgPC0gbG9hZGluZ3NfZGYgJT4lIGZpbHRlcihQQyA9PSAiMyIpICU+JSANCiAgI3g9cmVvcmRlcihjbGFzcywtYW1vdW50LHN1bSkNCmdncGxvdCggYWVzKHggPSByZW9yZGVyKGNvbHVtbiwgLXZhbHVlKSwgeSA9IHZhbHVlLCBncm91cCA9IGZhY3Rvcihjb2x1bW4pKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCANCiAgICAgICAgICAgZmlsbD0gImdyYXk5MCIsIGNvbG9yID0gImdyYXkyMCIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGNvbHVtbiksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpLCANCiAgICAgICAgICAgICN2anVzdCA9ICJpbndhcmQiLCAgDQogICAgICAgICAgICBhbmdsZSA9IDkwICwgaGp1c3QgPSAiaW53YXJkIikgKw0KICBsYWJzKHggPSAiVmFyaWFibGVzIG9mIFBDMyIsIHkgPSAiTG9hZGluZ3MiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCiMgUEMzIGNvbnNpc3RzIDYwJSsgb2YgY28yLCBhdHAsIFAsIE4NCg0KDQoNCnAxICsgcDIgKyBwMw0KYGBgDQoNCg0KDQpTZWVtcyB0aGF0IHRoZSB2YXJpYWJsZXMgbm90IHJlcHJlc2VudGVkIG9uIHRoZSBQQzEgYW5kIFBDMiBhcmUgcmVwcmVzZW50ZWQgb24gUEMzLCB3ZSBzaG91bGQgc3RpbGwga2VlcCBhbGwgdGhyZWU6DQoNCmBgYHtyfQ0KDQpmdml6X3BjYV9iaXBsb3QocGNhX2VudiwgDQogICAgICAgICAgICAgICAgIyBmaWxsIGluZGl2aWR1YWxzIGJ5IGdyb3Vwcw0KICAgICAgICAgICAgICAgIGdlb20uaW5kID0gInBvaW50IiwNCiAgICAgICAgICAgICAgICBwb2ludHNoYXBlID0gMjEsDQogICAgICAgICAgICAgICAgcG9pbnRzaXplID0gMi41LA0KICAgICAgICAgICAgICAgIGZpbGwuaW5kID0gZW52X2RhdGExJHdlbGxfaWQsDQogICAgICAgICAgICAgICAgY29sLmluZCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgYWxwaGEudmFyID0iY29udHJpYiIsDQogICAgICAgICAgICAgICAgY29sLnZhciA9ICJjb250cmliIiwNCiAgICAgICAgICAgICAgICBncmFkaWVudC5jb2xzID0gIlJkQnUiLA0KICAgICAgICAgICAgICAgIHJlcGVsID0gVFJVRSkrDQogICAgICAgIGdncHVicjo6ZmlsbF9wYWxldHRlKCJqY28iKSAgICAgIA0KYGBgDQoNCg0KDQojIyBDb25zdHJhaW5lZCBhbmFseXNpcyANCmBgYHtyfQ0KIyBhZGQgY29tcG9uZW50IGNvbmNlbnRyYXRpb24gaW4gZWFjaCBzYW1wbGUNCiMgaSBkaWQgbm90IHNjYWxlIHNpbmNlIHRoZXkgYXJlIG1vcmUgb3IgbGVzcyB0aGUgc2FtZSBzY2FsZSBhcyBsb2FkaW5ncw0KDQp0aWR5KHBjYV9lbnYpICU+JSANCiAgZmlsdGVyKFBDICVpbiUgYygiMSIsICIyIiwgIjMiLCAiNCIsICI1IiwgIjYiKSApICAlPiUgDQogIHBpdm90X3dpZGVyKHZhbHVlc19mcm9tID0gInZhbHVlIiwgbmFtZXNfZnJvbSA9ICJQQyIpICU+JSANCiAgcmVuYW1lKCJQQzEiID0gIjEiLCAiUEMyIiA9ICIyIiwgIlBDMyIgPSAiMyIsIA0KICAgICAgICAgIlBDNCIgPSI0IiwgIlBDNSIgPSAiNSIsICJQQzYiID0gIjYiKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhyb3cpKSAlPiUgDQogIGNvbHVtbl90b19yb3duYW1lcygicm93IiktPiBlbnYuZGF0DQoNCmVudl9kYXRhMVssMTo2XSAlPiUgDQogICNmaWx0ZXIoc2FtcGxlICE9ICJEMDVwXzIwMjAwNzI5IikgJT4lIA0KICBhcnJhbmdlKGRlc2Moc2FtcGxlKSkgJT4lIA0KICBzZWxlY3QoISJzYW1wbGUiKS0+IHNwLmRhdA0KDQppZGVudGljYWwocm93bmFtZXMoZW52LmRhdCksIHJvd25hbWVzKHNwLmRhdCkpICNUUlVFDQoNCg0KDQoNCnNpbXBsZVJEQSA8LSBjYXBzY2FsZShzcC5kYXQgfiAgLiwgZGF0YT1lbnYuZGF0ICwNCiAgICAgICAgICAgICAgICAgZGlzdGFuY2UgPSAiZXVjbGlkZWFuIikNCg0KI3N1bW1hcnkoc2ltcGxlUkRBKQ0KIzY0JSUgY29uc3RyYWluZWQgDQoNCg0KDQpgYGANCg0KIyMgVGVzdGluZyBvcmRpbmF0aW9uDQoNClRlc3QgaWYgYW55IG9mIHRoZXNlIFBDcyBpbXBhY3RzIHRoZSBjb21wb3NpdGlvbiBvZiBET0MgY29tcG9uZW50czogDQpgYGB7cn0NCiMgdGVzdCBvZiBhbGwgY2Fub25pY2FsIGF4ZXMNCmFub3ZhLm1vZGVsIDwtIGFub3ZhLmNjYShzaW1wbGVSREEsIGJ5PSdheGlzJywgc3RlcD0xMDAwKSAgIyBjYXAxIGlzIHNpZ24sIGNhcDIgYWxzbw0KDQojIHRlc3QgdGhlIHdob2xlIG1vZGVsDQphbm92YS5tb2RlbDIgPC0gYW5vdmEuY2NhKHNpbXBsZVJEQSwgc3RlcD0xMDAwKSAjaXMgc2lnbg0KUnNxdWFyZUFkaihzaW1wbGVSREEpJGFkai5yLnNxdWFyZWQgIyBhbmQgZXhwbGFpbnMgNjAlDQoNCg0KIyB0ZXN0IGVudiBwYXJhbWV0ZXJzDQphbm92YS5tb2RlbDMgPC0gYW5vdmEoc2ltcGxlUkRBLCBzdGVwPTEwMDAsIGJ5ID0gInRlcm0iKQ0KIyBQQzEsIFBDMywgUEM0IGFuZCBQQzUgc2lnbg0KDQoNCiMgbmV3IG1vZGVsDQoNCnNpbXBsZVJEQSA8LSBjYXBzY2FsZShzcC5kYXQgfiAgUEMxICsgUEMzICsgUEM0ICsgUEM1LCANCiAgICAgICAgICAgICAgICAgICAgICBkYXRhPWVudi5kYXQgLA0KICAgICAgICAgICAgICAgICAgICAgIGRpc3RhbmNlID0gImV1Y2xpZGVhbiIpDQpgYGANCg0KT25seSBQQzEgaXMgc2lnbmlmaWNhbnRseSBleHBsYWluaW5nIHRoZSBpbXBhY3Qgb24gdGhlIGNvbXBvbmVudCBjb21wb3NpdGlvbiwgYW5kIGV4cGxhaW5zIDQwJSBvZiB2YXJpYXRpb24uIFRoZSBQQzEgaXMgYSBjb21iaW5hdGlvbiBvZiBET0MgKGFzIGV4cGVjdGVkKSwgZWxlY3RyaWMgY29uZHVjdGl2aXR5LCBveHlnZW4sIEssIE5hLCBjbzIuIFRoZSBudXRyaWVudCBhdmFpbGFiaWxpdHkgZG9lcyBub3Qgc2VlbSB0byBiZSBpbXBhY3RmdWxsIGZvciB0aGUgIERPQyBjb21wb3NpdGlvbiBvZiB0aGUgc2FtcGxlLg0KDQojIyBQbG90dGluZw0KYGBge3J9DQoNCiMgdmVjdG9ycw0KY2NhdmVjdG9ycyA8LSBhcy5tYXRyaXgoc2NvcmVzKHNpbXBsZVJEQSwgZGlzcGxheSA9ICJicCIsIHNjYWxpbmcgPSAic2l0ZXMiKSoyLjM2MzI5OSkgJT4lDQogIGFzLmRhdGEuZnJhbWUoKQ0KDQojIHNpdGUgY29vcmRpbmF0ZXMNCmVudl9kYXRhMVsjd2hpY2gocm93bmFtZXMoZW52X2RhdGExKSAhPSAiRDA1cF8yMDIwMDcyOSIpDQogICwid2VsbF9pZCJdICU+JSANCiAgYXMuZGF0YS5mcmFtZSgpICU+JSANCiAgcmVuYW1lKCJ3YXRlcl9raW5kIiA9ICIuIikgJT4lIA0KICBhcnJhbmdlKGRlc2Mod2F0ZXJfa2luZCkpIC0+IHdhdGVyDQoNCnNpdGVfZGF0YSA8LSBzY29yZXMoc2ltcGxlUkRBLCBkaXNwbGF5ID0gInNpdGVzIikgJT4lIA0KICBhcy5kYXRhLmZyYW1lKCkgJT4lIA0KICBjYmluZCguLCB3YXRlcikNCiANCiMgYWRkIGNvbXBvbmVudHMNCmNvbXAgPC0gYXMubWF0cml4KHNjb3JlcyhzaW1wbGVSREEsIGRpc3BsYXkgPSAic3BlY2llcyIpKjIuMzYzMjk5ICkgICU+JSANCiAgYXMuZGF0YS5mcmFtZSgpDQoNCiMgcGxvdHRpbmcNCnBsb3RfY2NhIDwtIA0KICBzaXRlX2RhdGEgJT4lIA0KICBnZ3Bsb3QoIGFlcyh4ID0gQ0FQMSwgeSA9IENBUDIpKSArDQogIGdlb21fcG9pbnQoYWVzKCBjb2xvcj0gd2F0ZXJfa2luZCksIHNpemUgPSAzKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiYmxhY2siLCBzaGFwZSA9IDIxLCBzaXplID0gMykgKyAgDQogIGdlb21fc2VnbWVudChkYXRhID0gY2NhdmVjdG9ycywgDQogICAgICAgICAgICAgICBhZXMoeCA9IDAsIHkgPSAwLCANCiAgICAgICAgICAgICAgICAgICB4ZW5kID0gQ0FQMSwgeWVuZCA9IENBUDIpLCANCiAgICAgICAgICAgICAgIHNpemUgPSAxLjIsDQogICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC41LCAiY20iKSkpICsNCiAgDQogICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDApLCBjb2xvciA9ICJncmV5NzAiLCBsaW5ldHlwZSA9IDIpICsNCiAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGMoMCksIGNvbG9yID0gImdyZXk3MCIsIGxpbmV0eXBlID0gMikgKw0KICANCiAgZ2VvbV90ZXh0KGRhdGEgPSBjY2F2ZWN0b3JzLCBhZXMoeCA9IENBUDEqMS4xLCB5ID0gQ0FQMioxLjUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHJvd25hbWVzKGNjYXZlY3RvcnMpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT02ICkgKw0KICANCiAgZ2VvbV90ZXh0KGRhdGEgPSBjb21wLCBhZXMoeCA9IENBUDEsIHk9Q0FQMiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcm93bmFtZXMoY29tcCkpKSArIA0KICB0aGVtZV9idygpICsNCiAgbGFicyh4ID0gIkNBUDEgWzQ0LjU4ICVdIiwgeT0iQ0FQMiBbMS41NSAlXSIpICsNCiAgc3RhdF9lbGxpcHNlKGFlcyhjb2xvcj13YXRlcl9raW5kKSwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArIA0KICANCiAgbGFicyggY29sb3IgPSAiV2F0ZXIgXG5raW5kIiwgZmlsbCA9ICJ3YXRlciBraW5kIikgKw0KICANCiAgICAgdGhlbWUobGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgIGxlZ2VuZC5ib3guYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JheSIpKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiI2FjYzdkOSIsIiM1MTgwYTIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiMzZTY0N2QiLCIjZDhiMzY1IikpDQoNCnBsb3RfY2NhDQoNCg0KYGBgDQoNCg0KDQpDb25jbHVzaW9uOiBjb21wb25lbnQgNCBpcyBtb3N0bHkgcmVsYXRlZCB0byB0aGUgc3VyZmFjZSB3YXRlciwgd2hpbGUgY29tcG9uZW50IDEsIDIgYW5kIDMgYXJlIGNsb3NlbHkgcmVsYXRlZCB0byBQQzEgZGVmaW5lZCBlbnZpcm9ubWVuYWwgdmFyaWFibGVzLCBuYW1lbHkgbWluZXJhbHMuIFRoaXMgZml0cyB0aGUgcmVzdWx0cyBvZiBjb21wb25lbnQgZGlzdHJpYnV0aW9uIGJ5IHdlbGwgaWQuIFRoZSBQQ0EgYXBwcm9hY2ggZG9lcyBwcm92aWRlIGZpdHRpbmcgcmVzdWx0cyBidXQgaXMgbm90IGFuIGltcHJvdmVtZW50IHRvIGFuIGFjdHVhbCBjb25zdHJhaW50IHdpdGggcmF3IGVudmlyb25tZW50YWwgdmFyaWFibGVzLg0K