1 Getting Started

1.1 Libraries Used in this Document

There are a number of useful libraries for manipulating and analyzing tree-ring data in R. In this document we will use the following tree-ring specific and general libraries.
    • burnr
    • dendroTools
    • DendroSync
    • dplR
    • ggplot2
    • TRADER
    • treeclim
    • graphics
    • utils

1.2 Installing and Loading Libraries

If you do not have one or many of these libraries installed you can add them by using the install.libraries(x) function where x is the name of the package you desire to install. Start by loading all of the libraries:

library(burnr)
library(dendroTools)
library(DendroSync)
library(dplR)
library(ggplot2)
library(TRADER)
library(treeclim)
library(utils)

All of these packages are cited in the README file available in the repository found at rNADEF Workbook

2 COFECHA in dplR

Using the script below, you will be able to read in raw ring width files for COFECHA-like analysis. To run your own data, change the fname to match the data in your data <- read.rwl(fname = ... , format = "auto") script. You can also examine summary statistics of your ring width file using the rwl.stats(x) function. Alternatively you can use the RWL file included in this project.

grow.rwl <- read.tucson(fname = "Yellowstone_PSME_format.txt")
There does not appear to be a header in the rwl file
There are 32 series
1       BTK05A       1741    2016   0.001
2       BTK05B       1727    2016   0.001
3       BTK6A        1649    2016   0.001
4       BTK6B        1618    2016   0.001
5       BTK06C       1680    2016   0.001
6       BTK07A       1614    2016   0.001
7       BTK07B       1640    2016   0.001
8       BTK08A       1840    2016   0.001
9       BTK8B        1437    2016   0.001
10      BTK09B       1681    2016   0.001
11      BTK09C       1493    1679   0.001
12      BTK10C       1691    2016   0.001
13      BTK11A       1618    2016   0.001
14      BTK11B       1692    2016   0.001
15      BTK12A       1551    2016   0.001
16      BTK12B       1551    1918   0.001
17      BTK13A       1637    2016   0.001
18      BTK13B       1637    1998   0.001
19      BTK13C       1652    2016   0.001
20      BTK14A       1719    2016   0.001
21      BTK14B       1716    2016   0.001
22      BTK15A       1599    2016   0.001
23      BTK 17A      1758    2016   0.001
24      BTK 17B      1769    2016   0.001
25      BTK19B       1503    2016   0.001
26      BTK19A       1473    2016   0.001
27      BTK20A       1665    2016   0.001
28      BTK20B       1685    2016   0.001
29      BTK 33A      1765    2016   0.001
30      BTK 33B      1751    2016   0.001
31      BTK 34A      1653    2016   0.001
32      BTK 34B      1655    2016   0.001
rwl.stats(grow.rwl)

You can plot this information to view the time series and/or skeleton plot of a series. To see the time series, use the function seg.plot(x). To view the skeleton plot of an individual series, use skel.plot(x[#]) where # is the series/core you would like to view.

seg.plot(grow.rwl)

skel.plot(grow.rwl[1])

You can also examine the radii (mm) for each series, common time interval, and mean sensitivity of the rwl. While there isn’t a direct function in dplR to calculate radii, you can use colSums() from base R to calculate the values. For the common interval and mean sensitivity you can use common.interval() and sens1() respectively.

colSums(grow.rwl, na.rm = TRUE, dims = 1)
 BTK05A  BTK05B   BTK6A   BTK6B  BTK06C  BTK07A  BTK07B  BTK08A   BTK8B 
125.448 130.678 236.437 288.138 160.378 147.127 141.698  35.854 226.280 
 BTK09B  BTK09C  BTK10C  BTK11A  BTK11B  BTK12A  BTK12B  BTK13A  BTK13B 
 56.100  68.566 128.930 232.076 248.110 110.557  90.246 222.705 168.850 
 BTK13C  BTK14A  BTK14B  BTK15A BTK 17A BTK 17B  BTK19B  BTK19A  BTK20A 
151.969 174.576 172.746 183.356 202.596 186.586 194.488 243.716 216.798 
 BTK20B BTK 33A BTK 33B BTK 34A BTK 34B 
221.785 250.081 281.806 225.388 221.292 
crn.common <- common.interval(grow.rwl, type=c("years"), make.plot=TRUE)

sens1(grow.rwl)
[1] 0.2660017

2.1 Crossdating

Using functions from dplR you can also obtain a COFECH-like output with the corr.rwl.seg() function. You can also examine an individual series with series.rwl.plot(). Please note that the options used in the examples below are specific to this project and might be different from your specific analysis.

corr.rwl.seg(rwl = grow.rwl, seg.length = 50, bin.floor = 100, n = NULL, prewhiten = TRUE, pcrit = 0.05, biweight = TRUE, method = c("spearman"), make.plot = TRUE, label.cex = 1, floor.plus1 = FALSE, master = NULL)

To examine an individual series you will need to be able to identify the specific series in the function.

series.rwl.plot(grow.rwl, series = "BTK05A", series.yrs = as.numeric(names(series)), seg.length = 50, bin.floor = 100, n = NULL, prewhiten = TRUE, biweight = TRUE, floor.plus1 = FALSE)

Using interseries.cor will allow you to calculate the interseries correlation between each series and the master for the ring width file.

interseries.cor(grow.rwl, n = NULL, prewhiten = TRUE, biweight = TRUE, method = "spearman")

To facilitate crossdating you can also use dplR to calculate marker rings with the pointer() function.

markers <- pointer(grow.rwl)
markers

2.2 Spaghetti Plot of Raw Ring Widths

Frequently you will see a plot of the ring widths of all series on the same graph. These spaghetti plots can be created using the spag.plot() function in dplR.

spag.plot(rwl = grow.rwl, zfac = 1, useRaster = FALSE, res = 300)

3 Arstan in dplR

3.1 Detrending

The standalone ARSTAN program allows you to develop site chronologies and interactively detrend or standardize a series. These options are also baked into dplR. To run interactive detrending you can use the i.detrend() function. Ihis allows you to explore curve fits for each tree ring series.

grow.rwi.int <- i.detrend(rwl = grow.rwl, nyrs = NULL, f = 0.5,pos.slope = FALSE) #allows you to see a variety of fits
Detrend series 1 of 32

Choose a detrending method for this series BTK05A.
Methods are: 
1: Spline
2: ModNegExp
3: Mean
4: Ar
5: Friedman
6: ModHugershoff
1
Detrend series 2 of 32


Choose a detrending method for this series BTK05B.
Methods are: 
1: Spline
2: ModNegExp
3: Mean
4: Ar
5: Friedman
6: ModHugershoff

You will need to select a detrending method for each series.

To view the spaghetti plot for the detrended series you can once again use the spag.plot() function similar to above except substituting the raw ring width data for the detrended data.

spag.plot(rwl = grow.rwi.int, zfac = 1, useRaster = FALSE, res = 300)

If you want to utilize a singular detrending method for all of your series, or you used interactive detrending to determine the best fit for your data, you can use the detrend() function instead of i.detrend(). In this function you will choose one of the following detrending options with method = : “Spline”, “ModNegExp”, “Mean”, “Ar”, “Friedman”, or “ModHugershoff”.

grow.rwi <- detrend(rwl = grow.rwl, method = c("Spline"), nyrs = NULL, f = 0.5, pos.slope = FALSE)
grow.rwi

To examine the statistics for the entire chronology you can use rwi.stats() or rwi.stats.running() to use running statistics in order to adjust the time periods. See ?rwi.stats.running for help on this function.

rwi.stats(grow.rwi)
rwi.stats.running(grow.rwi)

3.2 Generating Chronologies

The ARSTAN program generates a standardized chronology, an ARSTAN chronology, and a residual chronology. In dplR you can use the chron() function to build a mean value chronology from detrended ring widths produced from a detrend() function.

Standardized chronology:

grow.crn <- chron(x = grow.rwi, prefix = "BTK", biweight = TRUE, prewhiten = FALSE)
grow.crn

Standard and Residual chronologies:

grow.crn <- chron(x = grow.rwi, prefix = "BTK", biweight = TRUE, prewhiten = TRUE)
grow.crn

You can then plot the chronology using crn.plot() to view chronologies developed with chron().

crn.plot(crn = grow.crn, add.spline = TRUE, nyrs = NULL, f = 0.5, crn.line.col='grey50', spline.line.col='red', samp.depth.col='grey90', samp.depth.border.col='grey80', crn.lwd=1, spline.lwd=2.0, abline.pos=1, abline.col='black', abline.lty=1,abline.lwd=1, xlab="Time", ylab="RWI")

For daily and monthly dendroclimatological analysis in the dendroTools library you can save the developed chronologies as .csv files using the write.csv(x) function:

btk_std <- grow.crn[1] #subset only year (already as.numeric) and index columns
write.csv(btk_std, file = "BTK_std.csv")

To export the data use the following script: write.csv(btk_std, file = "BTK_std.csv")

3.3 Wavelet Transform

Wavelet Transform allows you to look at frequencies or temporal patterns in your crn for paleoclimatological analysis.

Years <- as.numeric(rownames(grow.crn))
rings <- grow.crn[, 1]
tubular <- morlet(y1 = rings, x1 = Years, p2 = 9, dj = 0.1,
                   siglvl = 0.99)
wavelet.plot(tubular, useRaster = NA)

4 Treeclim

The TreeClim package allows for the assessment of growth-climate relationships similar to the older DendroClim2002 software. To begin, you will need to load a chronology. You can use your own chronology or the chronology developed in the previous steps. With the script below, you can view a summary of the chronology you will be using for this analysis. Alternatively, you can change the name of the chronology to one you have generated.

#summary of the chronology
summary(grow.crn)
     BTKstd          samp.depth   
 Min.   :0.08791   Min.   : 1.00  
 1st Qu.:0.83354   1st Qu.: 6.00  
 Median :0.98508   Median :24.50  
 Mean   :0.98300   Mean   :19.36  
 3rd Qu.:1.13387   3rd Qu.:30.00  
 Max.   :1.99612   Max.   :31.00  

Next you will need to load climate data. There are a number of methods for adding climate data but this example has one as a csv file in the project.

climate <- read.csv("WY_yellowstone_climate.csv", header = TRUE)
names(climate)
 [1] "Year"  "Month" "PCP"   "TAVG"  "PDSI"  "PHDI"  "ZNDX" 
 [8] "PMDI"  "CDD"   "HDD"   "SP01"  "SP02"  "SP03"  "SP06" 
[15] "SP09"  "SP12"  "SP24"  "TMIN"  "TMAX" 
summary(climate)
      Year          Month            PCP             TAVG      
 Min.   :1900   Min.   : 1.00   Min.   :0.540   Min.   :21.90  
 1st Qu.:1929   1st Qu.: 3.75   1st Qu.:2.140   1st Qu.:38.06  
 Median :1958   Median : 6.50   Median :2.510   Median :52.86  
 Mean   :1958   Mean   : 6.50   Mean   :2.504   Mean   :52.22  
 3rd Qu.:1987   3rd Qu.: 9.25   3rd Qu.:2.880   3rd Qu.:66.75  
 Max.   :2016   Max.   :12.00   Max.   :4.440   Max.   :76.80  
      PDSI              PHDI              ZNDX        
 Min.   :-8.3900   Min.   :-8.3900   Min.   :-7.1300  
 1st Qu.:-1.5200   1st Qu.:-1.9800   1st Qu.:-1.1000  
 Median : 0.7400   Median : 1.1000   Median : 0.1050  
 Mean   : 0.3093   Mean   : 0.2772   Mean   : 0.0788  
 3rd Qu.: 2.3150   3rd Qu.: 2.4400   3rd Qu.: 1.2600  
 Max.   : 6.5100   Max.   : 6.5100   Max.   : 6.9000  
      PMDI              CDD             HDD        
 Min.   :-8.3900   Min.   :  1.0   Min.   :   3.0  
 1st Qu.:-1.5550   1st Qu.: 10.0   1st Qu.:  56.0  
 Median : 0.7050   Median : 41.0   Median : 309.5  
 Mean   : 0.2636   Mean   :101.1   Mean   : 384.7  
 3rd Qu.: 2.2625   3rd Qu.:184.2   3rd Qu.: 690.0  
 Max.   : 6.5100   Max.   :405.0   Max.   :1184.0  
      SP01                SP02                SP03          
 Min.   :-3.090000   Min.   :-3.090000   Min.   :-3.090000  
 1st Qu.:-0.660000   1st Qu.:-0.640000   1st Qu.:-0.630000  
 Median :-0.005000   Median : 0.030000   Median :-0.020000  
 Mean   : 0.004701   Mean   : 0.006125   Mean   : 0.006432  
 3rd Qu.: 0.680000   3rd Qu.: 0.610000   3rd Qu.: 0.652500  
 Max.   : 3.090000   Max.   : 3.090000   Max.   : 3.090000  
      SP06                SP09                SP12          
 Min.   :-3.090000   Min.   :-2.420000   Min.   :-2.390000  
 1st Qu.:-0.640000   1st Qu.:-0.670000   1st Qu.:-0.710000  
 Median : 0.020000   Median : 0.035000   Median : 0.080000  
 Mean   : 0.006147   Mean   : 0.007407   Mean   : 0.005705  
 3rd Qu.: 0.682500   3rd Qu.: 0.670000   3rd Qu.: 0.645000  
 Max.   : 2.960000   Max.   : 3.090000   Max.   : 2.820000  
      SP24                TMIN            TMAX      
 Min.   :-2.420000   Min.   :12.52   Min.   :31.26  
 1st Qu.:-0.650000   1st Qu.:27.11   1st Qu.:48.73  
 Median : 0.040000   Median :40.29   Median :65.40  
 Mean   : 0.006645   Mean   :40.25   Mean   :64.19  
 3rd Qu.: 0.680000   3rd Qu.:54.03   3rd Qu.:79.78  
 Max.   : 2.650000   Max.   :63.55   Max.   :90.84  
ym <- climate[,1:2] #pull year and month columns
var1 <- climate[3] #pull climate variables, 1 or 2 at a time to avoid N problems
clim <- data.frame(c(ym, var1)) #build climate data frame 
summary(clim)
      Year          Month            PCP       
 Min.   :1900   Min.   : 1.00   Min.   :0.540  
 1st Qu.:1929   1st Qu.: 3.75   1st Qu.:2.140  
 Median :1958   Median : 6.50   Median :2.510  
 Mean   :1958   Mean   : 6.50   Mean   :2.504  
 3rd Qu.:1987   3rd Qu.: 9.25   3rd Qu.:2.880  
 Max.   :2016   Max.   :12.00   Max.   :4.440  

4.1 Response Function Analysis

Modeled after Dendroclim2002 Can produce “static”, “moving”, or “evolving” using the dynamic = argument in the dcc script.

resp <- dcc(chrono = grow.crn, climate = clim, selection = -5:10, method = "response", dynamic = "evolving", win_size = 35, win_offset = 1, start_last = TRUE, timespan = NULL, var_names = NULL, ci = 0.05, boot = "std", sb = FALSE) #this is the main function in treeclim
Error in dcc(chrono = grow.crn, climate = clim, selection = -5:10, method = "response",  : 
  Overlapping time span of chrono and climate records is smaller than number of parameters! Consider adapting the number of parameters to a maximum of 35.

You can save the output using the following script: write.csv(coef, file = ("pcp_coef.csv"))

Additionally you can write the plot to a file:

tiff("resp_coef.tiff", width = 8, height = 4, units = 'in', res = 300)
plot.new()
plot(resp)
title(main = "Climate", xlab = "Month")
dev.off()

4.2 Split Calibration with 2 Climate Variables/Months

recon <- dcc(chrono = grow.crn, climate = clim, selection = 6:7, #use a selection with recon variable of interest - modifiers like .mean or .sum can be used to average across months
             method = "response", dynamic = "static", win_size = 35,
             win_offset = 1, start_last = TRUE, timespan = NULL, var_names =
             NULL, ci = 0.05, boot = "std", sb = FALSE)
Running for timespan 1900 - 2016...
recon_coef <- coef(recon)
plot(recon)

recon #show model results
Coefficients (significance flags correspond to p < 0.05):
              id varname month   coef significant ci_lower ci_upper
PCP.curr.jun   1     PCP   JUN  0.180       FALSE   -0.026    0.373
PCP.curr.jul   2     PCP   JUL  0.090       FALSE   -0.029    0.210
TAVG.curr.jun  3    TAVG   JUN -0.096       FALSE   -0.242    0.052
TAVG.curr.jul  4    TAVG   JUL -0.065       FALSE   -0.178    0.076
#this does the evaluation
skillz <- skills(object = recon, target = .mean(1:2), model = "ols", calibration = "50%", timespan = NULL)
plot(skillz)

skillz #show model results
Call:
skills(object = recon, target = .mean(1:2), model = "ols", calibration = "50%", 
    timespan = NULL)

Using climate target PCP.mean.curr.jan.curr.feb and calibration model with 50 percent (= 59 years) of data starting at recent end as calibration period:

         r     p-value  
0.09830632  0.19801980  

Coefficients:
intercept      slope  
2.0058845  0.1608999  

Verification statistics:
             RE               CE  prediction RMSE  
          0.030           -0.003            0.051  

Durbin-Watson Test: 1.756 (p = 0.1587905)

Model for whole period:

         r     p-value  
0.13144548  0.04950495  

Coefficients:
intercept      slope  
2.0115633  0.1801164  

4.3 Split Calibration with Single Variable

Is your model time stable and does it verify?

recon_dlm <- dlm(chrono = grow.crn, climate = clim, selection = 6, timespan = NULL, var_names = NULL,
    param_names = NULL, intercept = TRUE, scale = FALSE)
Running for timespan 1900 - 2016...
recon_coef <- coef(recon_dlm)
plot(recon_dlm)

recon_dlm #show model results

Call:
lm(formula = tree ~ ., data = design_df)

Coefficients:
  (Intercept)   PCP.curr.jun  TAVG.curr.jun  
      2.17262        0.11500       -0.02185  
#this does the evaluation
skillz <- skills(object = recon_dlm, target = 6, model = "ols", calibration = "50%", timespan = NULL)
plot(skillz)

skillz #show model results
Call:
skills(object = recon_dlm, target = 6, model = "ols", calibration = "50%", 
    timespan = NULL)

Using climate target PCP.curr.jun and calibration model with 50 percent (= 59 years) of data starting at recent end as calibration period:

        r    p-value  
0.0225227  0.4257426  

Coefficients:
 intercept       slope  
2.93700516  0.04379646  

Verification statistics:
             RE               CE  prediction RMSE  
          0.020           -0.005            0.080  

Durbin-Watson Test: 2.082 (p = 0.6025759)

Model for whole period:

         r     p-value  
0.27200435  0.00990099  

Coefficients:
intercept      slope  
2.4299891  0.5067075  

4.4 Seasonal Correlation Analysis

Orginal code developed by Dave Meko in Matlab

climate <- read.csv("WY_yellowstone_climate.csv", header = TRUE)
names(climate)
 [1] "Year"  "Month" "PCP"   "TAVG"  "PDSI"  "PHDI"  "ZNDX"  "PMDI" 
 [9] "CDD"   "HDD"   "SP01"  "SP02"  "SP03"  "SP06"  "SP09"  "SP12" 
[17] "SP24"  "TMIN"  "TMAX" 
summary(climate)
      Year          Month            PCP             TAVG      
 Min.   :1900   Min.   : 1.00   Min.   :0.540   Min.   :21.90  
 1st Qu.:1929   1st Qu.: 3.75   1st Qu.:2.140   1st Qu.:38.06  
 Median :1958   Median : 6.50   Median :2.510   Median :52.86  
 Mean   :1958   Mean   : 6.50   Mean   :2.504   Mean   :52.22  
 3rd Qu.:1987   3rd Qu.: 9.25   3rd Qu.:2.880   3rd Qu.:66.75  
 Max.   :2016   Max.   :12.00   Max.   :4.440   Max.   :76.80  
      PDSI              PHDI              ZNDX              PMDI        
 Min.   :-8.3900   Min.   :-8.3900   Min.   :-7.1300   Min.   :-8.3900  
 1st Qu.:-1.5200   1st Qu.:-1.9800   1st Qu.:-1.1000   1st Qu.:-1.5550  
 Median : 0.7400   Median : 1.1000   Median : 0.1050   Median : 0.7050  
 Mean   : 0.3093   Mean   : 0.2772   Mean   : 0.0788   Mean   : 0.2636  
 3rd Qu.: 2.3150   3rd Qu.: 2.4400   3rd Qu.: 1.2600   3rd Qu.: 2.2625  
 Max.   : 6.5100   Max.   : 6.5100   Max.   : 6.9000   Max.   : 6.5100  
      CDD             HDD              SP01                SP02          
 Min.   :  1.0   Min.   :   3.0   Min.   :-3.090000   Min.   :-3.090000  
 1st Qu.: 10.0   1st Qu.:  56.0   1st Qu.:-0.660000   1st Qu.:-0.640000  
 Median : 41.0   Median : 309.5   Median :-0.005000   Median : 0.030000  
 Mean   :101.1   Mean   : 384.7   Mean   : 0.004701   Mean   : 0.006125  
 3rd Qu.:184.2   3rd Qu.: 690.0   3rd Qu.: 0.680000   3rd Qu.: 0.610000  
 Max.   :405.0   Max.   :1184.0   Max.   : 3.090000   Max.   : 3.090000  
      SP03                SP06                SP09          
 Min.   :-3.090000   Min.   :-3.090000   Min.   :-2.420000  
 1st Qu.:-0.630000   1st Qu.:-0.640000   1st Qu.:-0.670000  
 Median :-0.020000   Median : 0.020000   Median : 0.035000  
 Mean   : 0.006432   Mean   : 0.006147   Mean   : 0.007407  
 3rd Qu.: 0.652500   3rd Qu.: 0.682500   3rd Qu.: 0.670000  
 Max.   : 3.090000   Max.   : 2.960000   Max.   : 3.090000  
      SP12                SP24                TMIN            TMAX      
 Min.   :-2.390000   Min.   :-2.420000   Min.   :12.52   Min.   :31.26  
 1st Qu.:-0.710000   1st Qu.:-0.650000   1st Qu.:27.11   1st Qu.:48.73  
 Median : 0.080000   Median : 0.040000   Median :40.29   Median :65.40  
 Mean   : 0.005705   Mean   : 0.006645   Mean   :40.25   Mean   :64.19  
 3rd Qu.: 0.645000   3rd Qu.: 0.680000   3rd Qu.:54.03   3rd Qu.:79.78  
 Max.   : 2.820000   Max.   : 2.650000   Max.   :63.55   Max.   :90.84  
ym <- climate[,1:2] #pull year and month columns
var1 <- climate[3:4] #pull climate variables, 1 or 2 at a time to avoid N problems
clim <- data.frame(c(ym, var1)) #build climate data frame 
summary(clim)
      Year          Month            PCP             TAVG      
 Min.   :1900   Min.   : 1.00   Min.   :0.540   Min.   :21.90  
 1st Qu.:1929   1st Qu.: 3.75   1st Qu.:2.140   1st Qu.:38.06  
 Median :1958   Median : 6.50   Median :2.510   Median :52.86  
 Mean   :1958   Mean   : 6.50   Mean   :2.504   Mean   :52.22  
 3rd Qu.:1987   3rd Qu.: 9.25   3rd Qu.:2.880   3rd Qu.:66.75  
 Max.   :2016   Max.   :12.00   Max.   :4.440   Max.   :76.80  
seas <- seascorr(grow.crn, climate, var_names = NULL, timespan = NULL, complete = 9,
         season_lengths = c(1, 3, 6), primary = 1, secondary = 2, ci = 0.05)#this is the main function
Running for timespan 1901 - 2016...
plot(seas)

seas
Results for a season length of 1 month:

Results for a season length of 3 months:

Results for a season length of 6 months:
NA

5 TRADER Code for Growth Release Detection

TRADER, Tree Ring Analysis of Disturbance Events in R, is a package for disturbance reconstruction from tree-ring data. Analyses include Absolute Increase (Fraver & White 2005), Growth Averaging (Nowacki & Abrams 1997), Boundary Line (Black & Abrams 2003), and Splechtna (Splechtna, Gratzer & Black 2005) which combines growth averaging and boundary line techniques.

To start you need to read in a rwl file to begin the analysis.

For this example the Growth Averaging, growthAveragingALL(), technique will be used with a the following paramenters: years averaged prior to release = 10 (m1), years averaged after release = 10, number of years between release events = 10, moderate relase = 0.25, major release = 0.50, with 5yrs of exceeding growth to be considered a release. Note, some of the analyses will create a large number of files to be created in your working directory/

This script was not run as part of the workbook to avoid a large number of files created in the GitHub repository

Similar to the script in a previous section, you can create a spaghetti plot of the data.

spag.plot(thedata, zfac = 1, useRaster = FALSE, res = 300)

thedata.raw.crn <- chron(thedata, prefix = "BTK", prewhiten=FALSE)
plot(thedata.raw.crn,abline.pos=NULL,ylab='mm',xlab='Year')

6 Basal Area Increment calculation in dplR

Using the bai.out function you can use the raw ring width file to calculate basal area increment.

grow.rwl <- read.rwl(fname = "wa091.rwl", format = "auto")
Attempting to automatically detect format.
Assuming a Tucson format file.
There appears to be a header in the rwl file
There are 44 series
1       TCT190A      1609    1987   0.01
2       TCT190B      1584    1987   0.01
3       TCT191A      1608    1987   0.01
4       TCT191B      1638    1987   0.01
5       TCT192A      1556    1987   0.01
6       TCT192B      1596    1987   0.01
7       TCT193A      1592    1986   0.01
8       TCT194A      1693    1986   0.01
9       TCT194B      1691    1987   0.01
10      TCT195A      1608    1987   0.01
11      TCT195B      1601    1987   0.01
12      TCT196A      1581    1987   0.01
13      TCT196B      1564    1987   0.01
14      TCT197A      1589    1987   0.01
15      TCT197B      1569    1987   0.01
16      TCT198A      1708    1987   0.01
17      TCT198B      1680    1987   0.01
18      TCT199A      1561    1987   0.01
19      TCT199B      1585    1987   0.01
20      TCT201A      1410    1986   0.01
21      TCT201B      1489    1986   0.01
22      TCT202A      1664    1987   0.01
23      TCT202B      1657    1987   0.01
24      TCT203A      1810    1987   0.01
25      TCT203B      1410    1987   0.01
26      TCT204A      1655    1987   0.01
27      TCT204B      1550    1987   0.01
28      TCT205A      1629    1987   0.01
29      TCT205B      1707    1986   0.01
30      TCT206B      1681    1982   0.01
31      TCT207A      1611    1987   0.01
32      TCT207B      1586    1987   0.01
33      TCT208A      1643    1987   0.01
34      TCT208B      1778    1987   0.01
35      TCT209A      1410    1987   0.01
36      TCT209B      1410    1987   0.01
37      TCT210A      1637    1987   0.01
38      TCT210B      1714    1987   0.01
39      TCT211A      1700    1987   0.01
40      TCT211B      1703    1987   0.01
41      TCT212A      1702    1987   0.01
42      TCT212B      1660    1987   0.01
43      TCT213A      1693    1987   0.01
44      TCT213B      1597    1987   0.01
basal <- bai.out(grow.rwl, diam = NULL)
basal_p <- print(basal)
spag.plot(basal[1], zfac = 1, useRaster = FALSE, res = 300)

Similar to before, you can export the data using write.csv(basal_p, "basal_bai.csv")

7 burnR

The burnR package creates composite fire history plots similar to the FHX2 and FHAES programs. It uses FHX formatted files. An example of a FHX file is included in the repository.

After loading the burnr library, you can use read_fhx() to load data already formatted into the FHX format.

Zion <- read_fhx('Zion.fhx')
Zion

Although each of the samples have an ID, we can add so site information in order to facet our plots. This will sort each of the samples into the appropriate category when facted with the plot_demograph function.

Sites <- read.csv('ZionSiteIDs.csv')
Sites
facetplot <- plot_demograph(Zion, facet_group = Sites$SiteID, facet_id = Sites$series, plot_legend = TRUE)
print(facetplot)

Another option available in plot_demograph is a to create a plot of all samples with a composite plot beneath the plot of individuals. In addition to the plot and composite, you can also add annotations to highlight common fire dates.

rugplot <- plot_demograph(Zion, composite_rug = TRUE, plot_legend = TRUE)
compositerug <- rugplot + 
  annotate('rect', xmin = 1721, xmax = 1723, ymin = 0, ymax = 21, alpha = 0.4) + 
  annotate('rect', xmin = 1734, xmax = 1736, ymin = 0, ymax = 21, alpha = 0.4) + 
  annotate('rect', xmin = 1748, xmax = 1750, ymin = 0, ymax = 21, alpha = 0.4) + 
  annotate('rect', xmin = 1777, xmax = 1779, ymin = 0, ymax = 21, alpha = 0.4) + 
  annotate('rect', xmin = 1793, xmax = 1795, ymin = 0, ymax = 21, alpha = 0.4) + 
  scale_x_continuous(limits=c(1450, 2005), breaks = seq(1450,2005,25)) + 
  theme(axis.text.x = element_text(angle = -90, hjust = 0, vjust = 0.2), 
        panel.grid.major = element_blank(), panel.grid.minor = element_blank())
print(compositerug)

8 dendroTools

Alright, let’s step up the game! Let’s try some climate response with daily climate data because trees don’t know what a month is. You can get daily climate data for the US from the PRISM Climate Group.

Load and format the data prior to analysis.

pcp_d <- read.csv("BTK_daily_pcp.csv", header = TRUE)
row.names(pcp_d) <- as.numeric(pcp_d$Year)
pcp_d <- pcp_d[,2:367] #subset only 1 to 366 days, not year column
crn_d <- read.csv("Btk_std.csv")
row.names(crn_d) <- as.numeric(crn_d$X) #set the years as row names
crn_d <- crn_d[2] #subset only growth index
head(crn_d) 

Take a look at the daily climate data

glimpse_daily_data(env_data = pcp_d, tidy_env_data = FALSE, na.color = "white")

Analyze growth vs climate with fixed window width. This is set in the script using the fixed_width = function.

fixed_width <- daily_response(response = crn_d, env_data = pcp_d,
               method = "cor", fixed_width = 60, row_names_subset = TRUE,
               remove_insignificant = TRUE, alpha = 0.05)
fixed_width$plot_extreme #creates a plot showing best correlated period

You can compare the response across two periods of analysis to assess time stability, or you can leave the subset to all the years.

btk_past <- daily_response(response = crn_d, env_data = pcp_d,
            method = "cor", lower_limit = 50, upper_limit = 70,
            row_names_subset = TRUE, previous_year = TRUE,
            remove_insignificant = TRUE, alpha = 0.05,
            plot_specific_window = 60, subset_years = c(1981, 1998))
btk_present <- daily_response(response = crn_d, env_data = pcp_d,
               method = "cor", lower_limit = 50, upper_limit = 70,
               row_names_subset = TRUE, previous_year = TRUE,
               remove_insignificant = TRUE, alpha = 0.05,
               plot_specific_window = 60, subset_years = c(1999, 2016))

Now you can plot the results.

btk_past$plot_heatmap

btk_present$plot_heatmap

btk_past$plot_specific #choose a specific window length to plot if you set this above

btk_present$plot_specific

8.1 Climate Response on the Principle Components

Load data

data(example_proxies_individual)
data(LJ_daily_temperatures)

Example PCA - just create a data frame with multiple crns

example_PCA <- daily_response(response = example_proxies_individual, 
                              env_data = LJ_daily_temperatures, method = "lm", 
                              lower_limit = 60, upper_limit = 70,
                              row_names_subset = TRUE, remove_insignificant =
                              TRUE, alpha = 0.01, PCA_transformation = TRUE,
                              components_selection = "manual", N_components = 2)

Summary output and plot for the PCA analysis.

summary(example_PCA$PCA_output)
Importance of components:
                          Comp.1    Comp.2    Comp.3     Comp.4     Comp.5
Standard deviation     1.8691406 1.5007125 1.1867201 0.87168877 0.79432916
Proportion of Variance 0.3493686 0.2252138 0.1408305 0.07598413 0.06309588
Cumulative Proportion  0.3493686 0.5745824 0.7154129 0.79139704 0.85449292
                           Comp.6     Comp.7     Comp.8     Comp.9
Standard deviation     0.68818504 0.61467322 0.57233447 0.49611738
Proportion of Variance 0.04735987 0.03778232 0.03275667 0.02461325
Cumulative Proportion  0.90185279 0.93963510 0.97239178 0.99700502
                           Comp.10
Standard deviation     0.173060035
Proportion of Variance 0.002994978
Cumulative Proportion  1.000000000
example_PCA$plot_heatmap

8.2 Quick common period reconstruction

Load the sample data.

data(data_TRW)
data(KRE_daily_temperatures)

Reconstruction

example_reconstruction_lin <- daily_response(response = data_TRW, 
                              env_data = KRE_daily_temperatures, method = "lm",
                              metric = "r.squared", lower_limit = 30,
                              upper_limit = 40, row_names_subset = TRUE,
                              temporal_stability_check = "progressive",
                              cross_validation_type = "randomized", k = 3)

Reconstruction Plots

example_reconstruction_lin$plot_extreme

example_reconstruction_lin$temporal_stability
example_reconstruction_lin$cross_validation
example_reconstruction_lin$transfer_function

linear_model <- lm(Optimized_return ~ TRW, data = example_reconstruction_lin$optimized_return)

reconstruction <- data.frame(predictions = predict(linear_model, newdata = data_TRW))

linear_model <- lm(Optimized_return ~ TRW, data = example_reconstruction_lin$optimized_return)

reconstruction <- data.frame(predictions = predict(linear_model, newdata = data_TRW))

plot(row.names(data_TRW), reconstruction$predictions, type = "l", xlab = "Year", ylab = "Mean temperature May 15 - Jun 27 [?C]")

8.3 Monthly Analysis

load data

flow_d <- read.csv("BighornXavier_r.csv", header = TRUE)
row.names(flow_d) <- as.numeric(flow_d$year)
flow_d <- flow_d[,2:13]#subset only 1 to 366 days, not year column

Run analysis with split period

flow_past <- monthly_response(response = crn_d, env_data = flow_d,
             method = "cor", row_names_subset = TRUE, previous_year = TRUE,
             remove_insignificant = TRUE, alpha = 0.05, subset_years = c(1935,
             1976), aggregate_function = 'mean')
flow_present <- monthly_response(response = data_MVA, env_data =
                LJ_monthly_temperatures, method = "cor", row_names_subset =
                TRUE, alpha = 0.05, previous_year = TRUE, remove_insignificant =
                TRUE, subset_years = c(1977, 2016), aggregate_function = 'mean')
flow_past$plot_heatmap

flow_present$plot_heatmap

flow_past$plot_extreme

flow_present$plot_extreme

8.4 Monthly analysis using a PCA of chronologies with crns

You still need to get crns in column format

flow_PCA <- monthly_response(response = example_proxies_individual,
            env_data = flow_d, method = "lm", row_names_subset = TRUE,
            remove_insignificant = TRUE, alpha = 0.01, PCA_transformation =
            TRUE, previous_year = TRUE, components_selection = "manual",
            N_components = 2)
summary(flow_PCA$PCA_output)
Importance of components:
                          Comp.1    Comp.2    Comp.3     Comp.4     Comp.5
Standard deviation     1.8658357 1.5006020 1.1926249 0.87691842 0.80005480
Proportion of Variance 0.3481343 0.2251806 0.1422354 0.07689859 0.06400877
Cumulative Proportion  0.3481343 0.5733149 0.7155503 0.79244893 0.85645770
                           Comp.6    Comp.7     Comp.8     Comp.9
Standard deviation     0.69546274 0.6144111 0.54823741 0.49391586
Proportion of Variance 0.04836684 0.0377501 0.03005643 0.02439529
Cumulative Proportion  0.90482454 0.9425746 0.97263107 0.99702636
                           Comp.10
Standard deviation     0.172442402
Proportion of Variance 0.002973638
Cumulative Proportion  1.000000000
flow_PCA$plot_heatmap

flow_PCA$plot_extreme

9 DendroSync

This package provides functions for the calculation and plotting of synchrony in tree growth from tree-ring width chronologies (TRW index).

Load Data

data(conifersIP) #note the format of the data if you choose to use this analysis
head(conifersIP)

Calculate synchrony for null.model (broad evaluation, mBE) and homoscedastic variant of unstructured model (or full, mUN) for conifersIP data, and heteroscedastic variant for 1970-1999 period.

Fit the homoscedastic set of varcov models (mBE, mNE, mCS, mUN) using taxonomic grouping criteria (i.e. Species)

ModHm <- dendro.varcov(TRW ~ Code, varTime = "Year", varGroup = "Species", 
                       data = conifersIP, homoscedastic = TRUE)
[1] "Please wait. I am fitting the models now :)"
summary(ModHm)# Class and length of list elements
    Length Class Mode
mBE 18     lme   list
mNE 18     lme   list
mCS 18     lme   list
mUN 18     lme   list

Examine synchrony for mBE and mUN models

sync(ModHm, modname = "mBE")
$Within_Group_Synchrony
  Modname a_all    SE
1     mBE 0.309 0.043

attr(,"class")
[1] "sync"
sync(ModHm, modname = "mUN")
$Within_Group_Synchrony
  Modname GroupName a_Group SE_Group
1     mUN      ABAL   0.280    0.041
2     mUN      PINI   0.469    0.050
3     mUN      PISY   0.318    0.044

$Between_Group_Synchrony
  Modname GroupName a_betw_Grp SE_betw_Grp
1     mUN ABAL/PINI      0.278       0.041
2     mUN ABAL/PISY      0.270       0.040
3     mUN PINI/PISY      0.298       0.042

attr(,"class")
[1] "sync"

Subset the data from 1970 to 1999.

conif.30 <- conifersIP[conifersIP$Year>1969 & conifersIP$Year<2000,]
summary(conif.30$Year)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   1970    1977    1984    1984    1991    1999 

Fit the heteroscedastic set of variance covariance mixed models (mBE, mHeNE, mHeCS, mHeUN) using taxonomic grouping criteria (ie. Species)

ModHt30 <- dendro.varcov(TRW ~ Code, varTime = "Year", varGroup = "Species", 
                         data = conif.30, homoscedastic = FALSE)
[1] "Please wait. I am fitting the models now :)"
sync(ModHt30, modname = "mBE")
$Within_Group_Synchrony
  Modname a_all    SE
1     mBE 0.319 0.058

attr(,"class")
[1] "sync"
sync(ModHt30, modname = "mHeUN")
$Within_Group_Synchrony
  Modname GroupName a_Group SE_Group
1   mHeUN      ABAL   0.505    0.066
2   mHeUN      PINI   0.414    0.064
3   mHeUN      PISY   0.297    0.055

$Between_Group_Synchrony
  Modname GroupName a_betw_Grp SE_betw_Grp
1   mHeUN ABAL/PINI      0.321       0.058
2   mHeUN ABAL/PISY      0.325       0.058
3   mHeUN PINI/PISY      0.259       0.051

attr(,"class")
[1] "sync"

This workbook was created as an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code. The resulting html is used to display the static contents via GitHub.

LS0tDQp0aXRsZTogInJOQURFRiBXb3JrYm9vayINCmF1dGhvcjogTm9ydGggQW1lcmljYW4gRGVuZHJvZWNvbG9naWNhbCBGaWVsZHdlZWsgPGJyPiA8aT48c21hbGw+U2NyaXB0IGJ5IFN0b2NrdG9uIE1heHdlbGwsIE5BREVGIENvLU9yZ2FuaXplcjsgR2l0aHViIGFuZCBXZWJzaXRlIGJ5IENocmlzIEdlbnRyeTsgYW5kIGRhdGEgZnJvbSBHcmFudCBIYXJsZXksIE5BREVGIENvLU9yZ2FuaXplciwgIFN0b2NrdG9uIE1heHdlbGwsIENocmlzIEdlbnRyeSwgYW5kIG1hbnkgb3RoZXJzPC9zbWFsbD48L2k+IDxicj4NCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICByb3dzLnByaW50OiAxMA0KICAgIHRoZW1lOiBjb3Ntbw0KICAgIGhpZ2hsaWdodDogYnJlZXplZGFyaw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQ0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KDQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogNDBweDsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGNvbG9yOiBEYXJrR3JlZW47DQogIHRleHQtYWxpZ246IExlZnQ7DQp9DQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBjb2xvcjogRGFya0dyZWVuOw0KICB0ZXh0LWFsaWduOiBMZWZ0Ow0KfQ0KPC9zdHlsZT4NCg0KPHN0eWxlPg0KICAuY29sMiB7DQogICAgY29sdW1uczogMiAyMDBweDsgICAgICAgICAvKiBudW1iZXIgb2YgY29sdW1ucyBhbmQgd2lkdGggaW4gcGl4ZWxzKi8NCiAgICAtd2Via2l0LWNvbHVtbnM6IDIgMjAwcHg7IC8qIGNocm9tZSwgc2FmYXJpICovDQogICAgLW1vei1jb2x1bW5zOiAyIDIwMHB4OyAgICAvKiBmaXJlZm94ICovDQogIH0NCiAgLmNvbDMgew0KICAgIGNvbHVtbnM6IDMgMTAwcHg7DQogICAgLXdlYmtpdC1jb2x1bW5zOiAzIDEwMHB4Ow0KICAgIC1tb3otY29sdW1uczogMyAxMDBweDsNCiAgfQ0KPC9zdHlsZT4NCg0KIyBHZXR0aW5nIFN0YXJ0ZWQNCiMjIExpYnJhcmllcyBVc2VkIGluIHRoaXMgRG9jdW1lbnQ8YnI+DQpUaGVyZSBhcmUgYSBudW1iZXIgb2YgdXNlZnVsIGxpYnJhcmllcyBmb3IgbWFuaXB1bGF0aW5nIGFuZCBhbmFseXppbmcgdHJlZS1yaW5nIGRhdGEgaW4gKipSKiouIEluIHRoaXMgZG9jdW1lbnQgd2Ugd2lsbCB1c2UgdGhlIGZvbGxvd2luZyB0cmVlLXJpbmcgc3BlY2lmaWMgYW5kIGdlbmVyYWwgbGlicmFyaWVzLjwvYnI+IA0KPGRpdiBjbGFzcz0iY29sMiI+DQo8dWw+DQorIGJ1cm5yDQorIGRlbmRyb1Rvb2xzDQorIERlbmRyb1N5bmMNCisgZHBsUg0KKyBnZ3Bsb3QyDQorIFRSQURFUg0KKyB0cmVlY2xpbQ0KKyBncmFwaGljcw0KKyB1dGlscw0KPC91bD48L2Rpdj4NCg0KIyMgSW5zdGFsbGluZyBhbmQgTG9hZGluZyBMaWJyYXJpZXM8YnI+DQpJZiB5b3UgZG8gbm90IGhhdmUgb25lIG9yIG1hbnkgb2YgdGhlc2UgbGlicmFyaWVzIGluc3RhbGxlZCB5b3UgY2FuIGFkZCB0aGVtIGJ5IHVzaW5nIHRoZSAgYGBgaW5zdGFsbC5saWJyYXJpZXMoeClgYGAgZnVuY3Rpb24gd2hlcmUgKngqIGlzIHRoZSBuYW1lIG9mIHRoZSBwYWNrYWdlIHlvdSBkZXNpcmUgdG8gaW5zdGFsbC4gU3RhcnQgYnkgbG9hZGluZyBhbGwgb2YgdGhlIGxpYnJhcmllczo8L2JyPg0KDQpgYGB7ciBsaWJyYXJpZXMsIG1lc3NhZ2U9RkFMU0UsIHBhZ2VkLnByaW50PUZBTFNFfQ0KbGlicmFyeShidXJucikNCmxpYnJhcnkoZGVuZHJvVG9vbHMpDQpsaWJyYXJ5KERlbmRyb1N5bmMpDQpsaWJyYXJ5KGRwbFIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KFRSQURFUikNCmxpYnJhcnkodHJlZWNsaW0pDQpsaWJyYXJ5KGdyYXBoaWNzKQ0KbGlicmFyeSh1dGlscykNCmBgYA0KDQpBbGwgb2YgdGhlc2UgcGFja2FnZXMgYXJlIGNpdGVkIGluIHRoZSBbUkVBRE1FXShodHRwczovL2dpdGh1Yi5jb20vY2hyaXNtZ2VudHJ5L3JOQURFRi9ibG9iL21hc3Rlci9SRUFETUUubWQpIGZpbGUgYXZhaWxhYmxlIGluIHRoZSByZXBvc2l0b3J5IGZvdW5kIGF0IFtyTkFERUYgV29ya2Jvb2tdKGh0dHBzOi8vZ2l0aHViLmNvbS9jaHJpc21nZW50cnkvck5BREVGKQ0KDQojIENPRkVDSEEgaW4gZHBsUg0KVXNpbmcgdGhlIHNjcmlwdCBiZWxvdywgeW91IHdpbGwgYmUgYWJsZSB0byByZWFkIGluIHJhdyByaW5nIHdpZHRoIGZpbGVzIGZvciAqQ09GRUNIQSotbGlrZSBhbmFseXNpcy4gVG8gcnVuIHlvdXIgb3duIGRhdGEsIGNoYW5nZSB0aGUgYGBgZm5hbWVgYGAgIHRvIG1hdGNoIHRoZSBkYXRhIGluIHlvdXIgYGBgZGF0YSA8LSByZWFkLnJ3bChmbmFtZSA9IC4uLiAsIGZvcm1hdCA9ICJhdXRvIilgYGAgc2NyaXB0LiBZb3UgY2FuIGFsc28gZXhhbWluZSBzdW1tYXJ5IHN0YXRpc3RpY3Mgb2YgeW91ciByaW5nIHdpZHRoIGZpbGUgdXNpbmcgdGhlIGBgYHJ3bC5zdGF0cyh4KWBgYCBmdW5jdGlvbi4gQWx0ZXJuYXRpdmVseSB5b3UgY2FuIHVzZSB0aGUgUldMIGZpbGUgaW5jbHVkZWQgaW4gdGhpcyBwcm9qZWN0Lg0KDQpgYGB7ciBJbXBvcnQgRGF0YSBhbmQgQW5hbHl6ZSwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ3Jvdy5yd2wgPC0gcmVhZC50dWNzb24oZm5hbWUgPSAiWWVsbG93c3RvbmVfUFNNRV9mb3JtYXQudHh0IikNCnJ3bC5zdGF0cyhncm93LnJ3bCkNCmBgYA0KDQpZb3UgY2FuIHBsb3QgdGhpcyBpbmZvcm1hdGlvbiB0byB2aWV3IHRoZSB0aW1lIHNlcmllcyBhbmQvb3Igc2tlbGV0b24gcGxvdCBvZiBhIHNlcmllcy4gVG8gc2VlIHRoZSB0aW1lIHNlcmllcywgdXNlIHRoZSBmdW5jdGlvbiBgYGBzZWcucGxvdCh4KWBgYC4gVG8gdmlldyB0aGUgc2tlbGV0b24gcGxvdCBvZiBhbiBpbmRpdmlkdWFsIHNlcmllcywgdXNlIGBgYHNrZWwucGxvdCh4WyNdKWBgYCB3aGVyZSAjIGlzIHRoZSBzZXJpZXMvY29yZSB5b3Ugd291bGQgbGlrZSB0byB2aWV3Lg0KDQpgYGB7ciBQbG90IFRpbWUgU2VyaWVzLCBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQ0Kc2VnLnBsb3QoZ3Jvdy5yd2wpDQpza2VsLnBsb3QoZ3Jvdy5yd2xbMV0pDQpgYGANCg0KWW91IGNhbiBhbHNvIGV4YW1pbmUgdGhlIHJhZGlpIChtbSkgZm9yIGVhY2ggc2VyaWVzLCBjb21tb24gdGltZSBpbnRlcnZhbCwgYW5kIG1lYW4gc2Vuc2l0aXZpdHkgb2YgdGhlIHJ3bC4gV2hpbGUgdGhlcmUgaXNuJ3QgYSBkaXJlY3QgZnVuY3Rpb24gaW4gKmRwbFIqIHRvIGNhbGN1bGF0ZSByYWRpaSwgeW91IGNhbiB1c2UgYGBgY29sU3VtcygpYGBgIGZyb20gYmFzZSBSIHRvIGNhbGN1bGF0ZSB0aGUgdmFsdWVzLiBGb3IgdGhlIGNvbW1vbiBpbnRlcnZhbCBhbmQgbWVhbiBzZW5zaXRpdml0eSB5b3UgY2FuIHVzZSBgYGBjb21tb24uaW50ZXJ2YWwoKWBgYCBhbmQgYGBgc2VuczEoKWBgYCByZXNwZWN0aXZlbHkuDQoNCmBgYHtyIFJhZGlpLUNvbUludC1NZWFuU2VuLCBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0NCmNvbFN1bXMoZ3Jvdy5yd2wsIG5hLnJtID0gVFJVRSwgZGltcyA9IDEpDQpjcm4uY29tbW9uIDwtIGNvbW1vbi5pbnRlcnZhbChncm93LnJ3bCwgdHlwZT1jKCJ5ZWFycyIpLCBtYWtlLnBsb3Q9VFJVRSkNCnNlbnMxKGdyb3cucndsKQ0KYGBgDQoNCiMjIENyb3NzZGF0aW5nDQoNClVzaW5nIGZ1bmN0aW9ucyBmcm9tICoqZHBsUioqIHlvdSBjYW4gYWxzbyBvYnRhaW4gYSAqQ09GRUNIKi1saWtlIG91dHB1dCB3aXRoIHRoZSBgYGBjb3JyLnJ3bC5zZWcoKWBgYCBmdW5jdGlvbi4gWW91IGNhbiBhbHNvIGV4YW1pbmUgYW4gaW5kaXZpZHVhbCBzZXJpZXMgd2l0aCBgYGBzZXJpZXMucndsLnBsb3QoKWBgYC4gUGxlYXNlIG5vdGUgdGhhdCB0aGUgb3B0aW9ucyB1c2VkIGluIHRoZSBleGFtcGxlcyBiZWxvdyBhcmUgc3BlY2lmaWMgdG8gdGhpcyBwcm9qZWN0IGFuZCBtaWdodCBiZSBkaWZmZXJlbnQgZnJvbSB5b3VyIHNwZWNpZmljIGFuYWx5c2lzLg0KDQpgYGB7ciBDcm9zc2RhdGluZywgZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJywgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmNvcnIucndsLnNlZyhyd2wgPSBncm93LnJ3bCwgc2VnLmxlbmd0aCA9IDUwLCBiaW4uZmxvb3IgPSAxMDAsIG4gPSBOVUxMLCBwcmV3aGl0ZW4gPSBUUlVFLCBwY3JpdCA9IDAuMDUsIGJpd2VpZ2h0ID0gVFJVRSwgbWV0aG9kID0gYygic3BlYXJtYW4iKSwgbWFrZS5wbG90ID0gVFJVRSwgbGFiZWwuY2V4ID0gMSwgZmxvb3IucGx1czEgPSBGQUxTRSwgbWFzdGVyID0gTlVMTCkNCmBgYA0KVG8gZXhhbWluZSBhbiBpbmRpdmlkdWFsIHNlcmllcyB5b3Ugd2lsbCBuZWVkIHRvIGJlIGFibGUgdG8gaWRlbnRpZnkgdGhlIHNwZWNpZmljIHNlcmllcyBpbiB0aGUgZnVuY3Rpb24uDQpgYGB7ciBTZXJpZXMgUGxvdCwgZWNobz1UUlVFLCByZXN1bHRzPSdoaWRlJywgZmlnLmtlZXA9J2FsbCcsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0NCnNlcmllcy5yd2wucGxvdChncm93LnJ3bCwgc2VyaWVzID0gIkJUSzA1QSIsIHNlcmllcy55cnMgPSBhcy5udW1lcmljKG5hbWVzKHNlcmllcykpLCBzZWcubGVuZ3RoID0gNTAsIGJpbi5mbG9vciA9IDEwMCwgbiA9IE5VTEwsIHByZXdoaXRlbiA9IFRSVUUsIGJpd2VpZ2h0ID0gVFJVRSwgZmxvb3IucGx1czEgPSBGQUxTRSkNCmBgYA0KDQpVc2luZyBgYGBpbnRlcnNlcmllcy5jb3JgYGAgd2lsbCBhbGxvdyB5b3UgdG8gY2FsY3VsYXRlIHRoZSBpbnRlcnNlcmllcyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGVhY2ggc2VyaWVzIGFuZCB0aGUgbWFzdGVyIGZvciB0aGUgcmluZyB3aWR0aCBmaWxlLg0KDQpgYGB7ciBJbnRlcnNlcmllcyBDb3JyZWxhdGlvbiwgZWNobz1UUlVFfQ0KaW50ZXJzZXJpZXMuY29yKGdyb3cucndsLCBuID0gTlVMTCwgcHJld2hpdGVuID0gVFJVRSwgYml3ZWlnaHQgPSBUUlVFLCBtZXRob2QgPSAic3BlYXJtYW4iKQ0KYGBgDQoNClRvIGZhY2lsaXRhdGUgY3Jvc3NkYXRpbmcgeW91IGNhbiBhbHNvIHVzZSAqZHBsUiogdG8gY2FsY3VsYXRlIG1hcmtlciByaW5ncyB3aXRoIHRoZSBgYGBwb2ludGVyKClgYGAgZnVuY3Rpb24uIA0KDQpgYGB7ciBNYXJrZXIgUmluZ3MsIGVjaG89VFJVRX0NCm1hcmtlcnMgPC0gcG9pbnRlcihncm93LnJ3bCkNCm1hcmtlcnMNCmBgYA0KDQoNCiMjIFNwYWdoZXR0aSBQbG90IG9mIFJhdyBSaW5nIFdpZHRocw0KDQpGcmVxdWVudGx5IHlvdSB3aWxsIHNlZSBhIHBsb3Qgb2YgdGhlIHJpbmcgd2lkdGhzIG9mIGFsbCBzZXJpZXMgb24gdGhlIHNhbWUgZ3JhcGguIFRoZXNlICpzcGFnaGV0dGkgcGxvdHMqIGNhbiBiZSBjcmVhdGVkIHVzaW5nIHRoZSBgYGBzcGFnLnBsb3QoKWBgYCBmdW5jdGlvbiBpbiAqKmRwbFIqKi4NCmBgYHtyIFNwYWcgUGxvdCwgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnNwYWcucGxvdChyd2wgPSBncm93LnJ3bCwgemZhYyA9IDEsIHVzZVJhc3RlciA9IEZBTFNFLCByZXMgPSAzMDApDQpgYGANCg0KIyBBcnN0YW4gaW4gZHBsUg0KIyMgRGV0cmVuZGluZw0KDQpUaGUgc3RhbmRhbG9uZSAqKkFSU1RBTioqIHByb2dyYW0gYWxsb3dzIHlvdSB0byBkZXZlbG9wIHNpdGUgY2hyb25vbG9naWVzIGFuZCBpbnRlcmFjdGl2ZWx5IGRldHJlbmQgb3Igc3RhbmRhcmRpemUgYSBzZXJpZXMuIFRoZXNlIG9wdGlvbnMgYXJlIGFsc28gYmFrZWQgaW50byAqKmRwbFIqKi4gVG8gcnVuIGludGVyYWN0aXZlIGRldHJlbmRpbmcgeW91IGNhbiB1c2UgdGhlIGBgYGkuZGV0cmVuZCgpYGBgIGZ1bmN0aW9uLiBJaGlzIGFsbG93cyB5b3UgdG8gZXhwbG9yZSBjdXJ2ZSBmaXRzIGZvciBlYWNoIHRyZWUgcmluZyBzZXJpZXMuDQpgYGB7ciBpRGV0cmVuZGluZywgaW5jbHVkZT1UUlVFLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpncm93LnJ3aS5pbnQgPC0gaS5kZXRyZW5kKHJ3bCA9IGdyb3cucndsLCBueXJzID0gTlVMTCwgZiA9IDAuNSxwb3Muc2xvcGUgPSBGQUxTRSkgI2FsbG93cyB5b3UgdG8gc2VlIGEgdmFyaWV0eSBvZiBmaXRzDQpgYGANCllvdSB3aWxsIG5lZWQgdG8gc2VsZWN0IGEgZGV0cmVuZGluZyBtZXRob2QgZm9yIGVhY2ggc2VyaWVzLg0KDQpUbyB2aWV3IHRoZSBzcGFnaGV0dGkgcGxvdCBmb3IgdGhlIGRldHJlbmRlZCBzZXJpZXMgeW91IGNhbiBvbmNlIGFnYWluIHVzZSB0aGUgYGBgc3BhZy5wbG90KClgYGAgZnVuY3Rpb24gc2ltaWxhciB0byBhYm92ZSBleGNlcHQgc3Vic3RpdHV0aW5nIHRoZSByYXcgcmluZyB3aWR0aCBkYXRhIGZvciB0aGUgZGV0cmVuZGVkIGRhdGEuDQpgYGB7ciBEZXRyZW5kIFNwYWcgUGxvdCwgZWNobz1UUlVFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnNwYWcucGxvdChyd2wgPSBncm93LnJ3aS5pbnQsIHpmYWMgPSAxLCB1c2VSYXN0ZXIgPSBGQUxTRSwgcmVzID0gMzAwKQ0KYGBgDQoNCklmIHlvdSB3YW50IHRvIHV0aWxpemUgYSBzaW5ndWxhciBkZXRyZW5kaW5nIG1ldGhvZCBmb3IgYWxsIG9mIHlvdXIgc2VyaWVzLCBvciB5b3UgdXNlZCBpbnRlcmFjdGl2ZSBkZXRyZW5kaW5nIHRvIGRldGVybWluZSB0aGUgYmVzdCBmaXQgZm9yIHlvdXIgZGF0YSwgeW91IGNhbiB1c2UgdGhlIGBgYGRldHJlbmQoKWBgYCBmdW5jdGlvbiBpbnN0ZWFkIG9mIGBgYGkuZGV0cmVuZCgpYGBgLiBJbiB0aGlzIGZ1bmN0aW9uIHlvdSB3aWxsIGNob29zZSBvbmUgb2YgdGhlIGZvbGxvd2luZyBkZXRyZW5kaW5nIG9wdGlvbnMgd2l0aCAqbWV0aG9kID0gKjogIlNwbGluZSIsICJNb2ROZWdFeHAiLCAiTWVhbiIsICJBciIsICJGcmllZG1hbiIsIG9yICJNb2RIdWdlcnNob2ZmIi4NCg0KYGBge3IgRGV0cmVuZGluZywgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ3Jvdy5yd2kgPC0gZGV0cmVuZChyd2wgPSBncm93LnJ3bCwgbWV0aG9kID0gYygiU3BsaW5lIiksIG55cnMgPSBOVUxMLCBmID0gMC41LCBwb3Muc2xvcGUgPSBGQUxTRSkNCmdyb3cucndpDQpgYGANCg0KVG8gZXhhbWluZSB0aGUgc3RhdGlzdGljcyBmb3IgdGhlIGVudGlyZSBjaHJvbm9sb2d5IHlvdSBjYW4gdXNlIGBgYHJ3aS5zdGF0cygpYGBgIG9yIGBgYHJ3aS5zdGF0cy5ydW5uaW5nKClgYGAgdG8gdXNlIHJ1bm5pbmcgc3RhdGlzdGljcyBpbiBvcmRlciB0byBhZGp1c3QgdGhlIHRpbWUgcGVyaW9kcy4gU2VlIGBgYD9yd2kuc3RhdHMucnVubmluZ2BgYCBmb3IgaGVscCBvbiB0aGlzIGZ1bmN0aW9uLg0KDQpgYGB7ciBTdGF0cywgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcndpLnN0YXRzKGdyb3cucndpKQ0KYGBgDQoNCmBgYHtyIFJ1blN0YXRzLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpyd2kuc3RhdHMucnVubmluZyhncm93LnJ3aSkNCmBgYA0KDQojIyBHZW5lcmF0aW5nIENocm9ub2xvZ2llcw0KDQpUaGUgQVJTVEFOIHByb2dyYW0gZ2VuZXJhdGVzIGEgc3RhbmRhcmRpemVkIGNocm9ub2xvZ3ksIGFuIEFSU1RBTiBjaHJvbm9sb2d5LCBhbmQgYSByZXNpZHVhbCBjaHJvbm9sb2d5LiBJbiAqZHBsUiogeW91IGNhbiB1c2UgdGhlIGBgYGNocm9uKClgYGAgZnVuY3Rpb24gdG8gYnVpbGQgYSBtZWFuIHZhbHVlIGNocm9ub2xvZ3kgZnJvbSBkZXRyZW5kZWQgcmluZyB3aWR0aHMgcHJvZHVjZWQgZnJvbSBhIGBgYGRldHJlbmQoKWBgYCBmdW5jdGlvbi4gDQoNClN0YW5kYXJkaXplZCBjaHJvbm9sb2d5Og0KYGBge3IgU3RhbmRhcmRpemVkLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpncm93LmNybiA8LSBjaHJvbih4ID0gZ3Jvdy5yd2ksIHByZWZpeCA9ICJCVEsiLCBiaXdlaWdodCA9IFRSVUUsIHByZXdoaXRlbiA9IEZBTFNFKQ0KZ3Jvdy5jcm4NCmBgYA0KDQpTdGFuZGFyZCBhbmQgUmVzaWR1YWwgY2hyb25vbG9naWVzOg0KYGBge3IgUmVzaWR1YWwsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmdyb3cuY3JuIDwtIGNocm9uKHggPSBncm93LnJ3aSwgcHJlZml4ID0gIkJUSyIsIGJpd2VpZ2h0ID0gVFJVRSwgcHJld2hpdGVuID0gVFJVRSkNCmdyb3cuY3JuDQpgYGANCg0KWW91IGNhbiB0aGVuIHBsb3QgdGhlIGNocm9ub2xvZ3kgdXNpbmcgYGBgY3JuLnBsb3QoKWBgYCB0byB2aWV3IGNocm9ub2xvZ2llcyBkZXZlbG9wZWQgd2l0aCBgYGBjaHJvbigpYGBgLg0KDQpgYGB7ciBDaHJvblBsb3QsIGVjaG89VFJVRSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KY3JuLnBsb3QoY3JuID0gZ3Jvdy5jcm4sIGFkZC5zcGxpbmUgPSBUUlVFLCBueXJzID0gTlVMTCwgZiA9IDAuNSwgY3JuLmxpbmUuY29sPSdncmV5NTAnLCBzcGxpbmUubGluZS5jb2w9J3JlZCcsIHNhbXAuZGVwdGguY29sPSdncmV5OTAnLCBzYW1wLmRlcHRoLmJvcmRlci5jb2w9J2dyZXk4MCcsIGNybi5sd2Q9MSwgc3BsaW5lLmx3ZD0yLjAsIGFibGluZS5wb3M9MSwgYWJsaW5lLmNvbD0nYmxhY2snLCBhYmxpbmUubHR5PTEsYWJsaW5lLmx3ZD0xLCB4bGFiPSJUaW1lIiwgeWxhYj0iUldJIikNCmBgYA0KDQpGb3IgZGFpbHkgYW5kIG1vbnRobHkgZGVuZHJvY2xpbWF0b2xvZ2ljYWwgYW5hbHlzaXMgaW4gdGhlICoqZGVuZHJvVG9vbHMqKiBsaWJyYXJ5IHlvdSBjYW4gc2F2ZSB0aGUgZGV2ZWxvcGVkIGNocm9ub2xvZ2llcyBhcyAqLmNzdiogZmlsZXMgdXNpbmcgdGhlIGBgYHdyaXRlLmNzdih4KWBgYCBmdW5jdGlvbjoNCg0KYGBge3IgRXhwb3J0IENSTiwgZWNobz1UUlVFfQ0KYnRrX3N0ZCA8LSBncm93LmNyblsxXSAjc3Vic2V0IG9ubHkgeWVhciAoYWxyZWFkeSBhcy5udW1lcmljKSBhbmQgaW5kZXggY29sdW1ucw0KYGBgDQpUbyBleHBvcnQgdGhlIGRhdGEgdXNlIHRoZSBmb2xsb3dpbmcgc2NyaXB0OiBgYGB3cml0ZS5jc3YoYnRrX3N0ZCwgZmlsZSA9ICJCVEtfc3RkLmNzdiIpYGBgDQoNCiMjIFdhdmVsZXQgVHJhbnNmb3JtDQpXYXZlbGV0IFRyYW5zZm9ybSBhbGxvd3MgeW91IHRvIGxvb2sgYXQgZnJlcXVlbmNpZXMgb3IgdGVtcG9yYWwgcGF0dGVybnMgaW4geW91ciAqY3JuKiBmb3IgcGFsZW9jbGltYXRvbG9naWNhbCBhbmFseXNpcy4NCg0KYGBge3IgV2F2ZWxldCwgZWNobz1UUlVFLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KWWVhcnMgPC0gYXMubnVtZXJpYyhyb3duYW1lcyhncm93LmNybikpDQpyaW5ncyA8LSBncm93LmNyblssIDFdDQp0dWJ1bGFyIDwtIG1vcmxldCh5MSA9IHJpbmdzLCB4MSA9IFllYXJzLCBwMiA9IDksIGRqID0gMC4xLA0KICAgICAgICAgICAgICAgICAgIHNpZ2x2bCA9IDAuOTkpDQp3YXZlbGV0LnBsb3QodHVidWxhciwgdXNlUmFzdGVyID0gTkEpDQpgYGANCg0KIyBUcmVlY2xpbQ0KDQpUaGUgKipUcmVlQ2xpbSoqIHBhY2thZ2UgYWxsb3dzIGZvciB0aGUgYXNzZXNzbWVudCBvZiBncm93dGgtY2xpbWF0ZSByZWxhdGlvbnNoaXBzIHNpbWlsYXIgdG8gdGhlIG9sZGVyICpEZW5kcm9DbGltMjAwMiogc29mdHdhcmUuIFRvIGJlZ2luLCB5b3Ugd2lsbCBuZWVkIHRvIGxvYWQgYSBjaHJvbm9sb2d5LiBZb3UgY2FuIHVzZSB5b3VyIG93biBjaHJvbm9sb2d5IG9yIHRoZSBjaHJvbm9sb2d5IGRldmVsb3BlZCBpbiB0aGUgcHJldmlvdXMgc3RlcHMuIFdpdGggdGhlIHNjcmlwdCBiZWxvdywgeW91IGNhbiB2aWV3IGEgc3VtbWFyeSBvZiB0aGUgY2hyb25vbG9neSB5b3Ugd2lsbCBiZSB1c2luZyBmb3IgdGhpcyBhbmFseXNpcy4gQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBjaGFuZ2UgdGhlIG5hbWUgb2YgdGhlIGNocm9ub2xvZ3kgdG8gb25lIHlvdSBoYXZlIGdlbmVyYXRlZC4NCmBgYHtyIENocm9uU3VtLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojc3VtbWFyeSBvZiB0aGUgY2hyb25vbG9neQ0Kc3VtbWFyeShncm93LmNybikNCmBgYA0KDQpOZXh0IHlvdSB3aWxsIG5lZWQgdG8gbG9hZCBjbGltYXRlIGRhdGEuIFRoZXJlIGFyZSBhIG51bWJlciBvZiBtZXRob2RzIGZvciBhZGRpbmcgY2xpbWF0ZSBkYXRhIGJ1dCB0aGlzIGV4YW1wbGUgaGFzIG9uZSBhcyBhIGNzdiBmaWxlIGluIHRoZSBwcm9qZWN0Lg0KDQpgYGB7ciBDbGltYXRlIERhdGEsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmNsaW1hdGUgPC0gcmVhZC5jc3YoIldZX3llbGxvd3N0b25lX2NsaW1hdGUuY3N2IiwgaGVhZGVyID0gVFJVRSkNCm5hbWVzKGNsaW1hdGUpDQpzdW1tYXJ5KGNsaW1hdGUpDQp5bSA8LSBjbGltYXRlWywxOjJdICNwdWxsIHllYXIgYW5kIG1vbnRoIGNvbHVtbnMNCnZhcjEgPC0gY2xpbWF0ZVszXSAjcHVsbCBjbGltYXRlIHZhcmlhYmxlcywgMSBvciAyIGF0IGEgdGltZSB0byBhdm9pZCBOIHByb2JsZW1zDQpjbGltIDwtIGRhdGEuZnJhbWUoYyh5bSwgdmFyMSkpICNidWlsZCBjbGltYXRlIGRhdGEgZnJhbWUgDQpzdW1tYXJ5KGNsaW0pDQpgYGANCg0KDQojIyBSZXNwb25zZSBGdW5jdGlvbiBBbmFseXNpcw0KKk1vZGVsZWQgYWZ0ZXIgRGVuZHJvY2xpbTIwMDIqIA0KKkNhbiBwcm9kdWNlICJzdGF0aWMiLCAibW92aW5nIiwgb3IgImV2b2x2aW5nIiB1c2luZyB0aGUgYGBgZHluYW1pYyA9IGBgYCBhcmd1bWVudCBpbiB0aGUgYGBgZGNjYGBgIHNjcmlwdC4qDQoNCmBgYHtyIFJlc3BvbnNlIEZ1bmN0aW9uLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpyZXNwIDwtIGRjYyhjaHJvbm8gPSBncm93LmNybiwgY2xpbWF0ZSA9IGNsaW0sIHNlbGVjdGlvbiA9IC01OjEwLCBtZXRob2QgPSAicmVzcG9uc2UiLCBkeW5hbWljID0gImV2b2x2aW5nIiwgd2luX3NpemUgPSAzNSwgd2luX29mZnNldCA9IDEsIHN0YXJ0X2xhc3QgPSBUUlVFLCB0aW1lc3BhbiA9IE5VTEwsIHZhcl9uYW1lcyA9IE5VTEwsIGNpID0gMC4wNSwgYm9vdCA9ICJzdGQiLCBzYiA9IEZBTFNFKSAjdGhpcyBpcyB0aGUgbWFpbiBmdW5jdGlvbiBpbiB0cmVlY2xpbQ0KY29lZiA8LSBjb2VmKHJlc3ApICNtb2RlbCBjb2VmZmljaWVudHMgDQpwbG90KHJlc3ApICNwbG90IHRoZSBtb2RlbCBjb2VmZmljaWVudHMNCnJlc3AgI3Nob3cgbW9kZWwgcmVzdWx0cyBpZiB5b3UnZCBsaWtlDQp0cmFjZXBsb3QocmVzcCwgdmFyaWFibGVzID0gYygiUENQLnByZXYuYXVnIiwgIlBDUC5jdXJyLmp1biIsICJQQ1AuY3Vyci5qdWwiKSwgZmFjZXQgPSBGQUxTRSkgI3Nob3dzIGNvcnJlbGF0aW9ucyBvdmVyIHRpbWUgaWYgbW92aW5nIG9yIGV2b2x1dGlvbmFyeSBzZWxlY3RlZA0KYGBgDQoNCllvdSBjYW4gc2F2ZSB0aGUgb3V0cHV0IHVzaW5nIHRoZSBmb2xsb3dpbmcgc2NyaXB0OiBgYGB3cml0ZS5jc3YoY29lZiwgZmlsZSA9ICgicGNwX2NvZWYuY3N2IikpYGBgDQoNCkFkZGl0aW9uYWxseSB5b3UgY2FuIHdyaXRlIHRoZSBwbG90IHRvIGEgZmlsZToNCmBgYA0KdGlmZigicmVzcF9jb2VmLnRpZmYiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDQsIHVuaXRzID0gJ2luJywgcmVzID0gMzAwKQ0KcGxvdC5uZXcoKQ0KcGxvdChyZXNwKQ0KdGl0bGUobWFpbiA9ICJDbGltYXRlIiwgeGxhYiA9ICJNb250aCIpDQpkZXYub2ZmKCkNCmBgYA0KIyMgU3BsaXQgQ2FsaWJyYXRpb24gd2l0aCAyIENsaW1hdGUgVmFyaWFibGVzL01vbnRocw0KYGBge3IgMiBWYXJpYWJsZSBFdmFsdWF0aW9uLCBlY2hvPVRSVUUsIGZpZy5rZWVwPSdhbGwnLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpyZWNvbiA8LSBkY2MoY2hyb25vID0gZ3Jvdy5jcm4sIGNsaW1hdGUgPSBjbGltLCBzZWxlY3Rpb24gPSA2OjcsICN1c2UgYSBzZWxlY3Rpb24gd2l0aCByZWNvbiB2YXJpYWJsZSBvZiBpbnRlcmVzdCAtIG1vZGlmaWVycyBsaWtlIC5tZWFuIG9yIC5zdW0gY2FuIGJlIHVzZWQgdG8gYXZlcmFnZSBhY3Jvc3MgbW9udGhzDQogICAgICAgICAgICAgbWV0aG9kID0gInJlc3BvbnNlIiwgZHluYW1pYyA9ICJzdGF0aWMiLCB3aW5fc2l6ZSA9IDM1LA0KICAgICAgICAgICAgIHdpbl9vZmZzZXQgPSAxLCBzdGFydF9sYXN0ID0gVFJVRSwgdGltZXNwYW4gPSBOVUxMLCB2YXJfbmFtZXMgPQ0KICAgICAgICAgICAgIE5VTEwsIGNpID0gMC4wNSwgYm9vdCA9ICJzdGQiLCBzYiA9IEZBTFNFKQ0KcmVjb25fY29lZiA8LSBjb2VmKHJlY29uKQ0KcGxvdChyZWNvbikNCnJlY29uICNzaG93IG1vZGVsIHJlc3VsdHMNCiN0aGlzIGRvZXMgdGhlIGV2YWx1YXRpb24NCnNraWxseiA8LSBza2lsbHMob2JqZWN0ID0gcmVjb24sIHRhcmdldCA9IC5tZWFuKDE6MiksIG1vZGVsID0gIm9scyIsIGNhbGlicmF0aW9uID0gIjUwJSIsIHRpbWVzcGFuID0gTlVMTCkNCnBsb3Qoc2tpbGx6KQ0Kc2tpbGx6ICNzaG93IG1vZGVsIHJlc3VsdHMNCmBgYA0KDQojIyBTcGxpdCBDYWxpYnJhdGlvbiB3aXRoIFNpbmdsZSBWYXJpYWJsZQ0KKklzIHlvdXIgbW9kZWwgdGltZSBzdGFibGUgYW5kIGRvZXMgaXQgdmVyaWZ5PyoNCmBgYHtyIDEgVmFyaWFibGUgRXZhbHVhdGlvbiwgZWNobz1UUlVFLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcmVjb25fZGxtIDwtIGRsbShjaHJvbm8gPSBncm93LmNybiwgY2xpbWF0ZSA9IGNsaW0sIHNlbGVjdGlvbiA9IDYsIHRpbWVzcGFuID0gTlVMTCwgdmFyX25hbWVzID0gTlVMTCwNCiAgICBwYXJhbV9uYW1lcyA9IE5VTEwsIGludGVyY2VwdCA9IFRSVUUsIHNjYWxlID0gRkFMU0UpDQpyZWNvbl9jb2VmIDwtIGNvZWYocmVjb25fZGxtKQ0KcGxvdChyZWNvbl9kbG0pDQpyZWNvbl9kbG0gI3Nob3cgbW9kZWwgcmVzdWx0cw0KI3RoaXMgZG9lcyB0aGUgZXZhbHVhdGlvbg0Kc2tpbGx6IDwtIHNraWxscyhvYmplY3QgPSByZWNvbl9kbG0sIHRhcmdldCA9IDYsIG1vZGVsID0gIm9scyIsIGNhbGlicmF0aW9uID0gIjUwJSIsIHRpbWVzcGFuID0gTlVMTCkNCnBsb3Qoc2tpbGx6KQ0Kc2tpbGx6ICNzaG93IG1vZGVsIHJlc3VsdHMNCmBgYA0KDQojIyBTZWFzb25hbCBDb3JyZWxhdGlvbiBBbmFseXNpcw0KKk9yZ2luYWwgY29kZSBkZXZlbG9wZWQgYnkgRGF2ZSBNZWtvIGluIE1hdGxhYioNCmBgYHtyIFNlYXNvbmFsIENvcnJlbGF0aW9uLCBlY2hvPVRSVUUsIGZpZy5rZWVwPSdhbGwnLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmNsaW1hdGUgPC0gcmVhZC5jc3YoIldZX3llbGxvd3N0b25lX2NsaW1hdGUuY3N2IiwgaGVhZGVyID0gVFJVRSkNCm5hbWVzKGNsaW1hdGUpDQpzdW1tYXJ5KGNsaW1hdGUpDQp5bSA8LSBjbGltYXRlWywxOjJdICNwdWxsIHllYXIgYW5kIG1vbnRoIGNvbHVtbnMNCnZhcjEgPC0gY2xpbWF0ZVszOjRdICNwdWxsIGNsaW1hdGUgdmFyaWFibGVzLCAxIG9yIDIgYXQgYSB0aW1lIHRvIGF2b2lkIE4gcHJvYmxlbXMNCmNsaW0gPC0gZGF0YS5mcmFtZShjKHltLCB2YXIxKSkgI2J1aWxkIGNsaW1hdGUgZGF0YSBmcmFtZSANCnN1bW1hcnkoY2xpbSkNCnNlYXMgPC0gc2Vhc2NvcnIoZ3Jvdy5jcm4sIGNsaW1hdGUsIHZhcl9uYW1lcyA9IE5VTEwsIHRpbWVzcGFuID0gTlVMTCwgY29tcGxldGUgPSA5LA0KICAgICAgICAgc2Vhc29uX2xlbmd0aHMgPSBjKDEsIDMsIDYpLCBwcmltYXJ5ID0gMSwgc2Vjb25kYXJ5ID0gMiwgY2kgPSAwLjA1KSN0aGlzIGlzIHRoZSBtYWluIGZ1bmN0aW9uDQpwbG90KHNlYXMpDQpzZWFzDQpgYGANCg0KIyBUUkFERVIgQ29kZSBmb3IgR3Jvd3RoIFJlbGVhc2UgRGV0ZWN0aW9uDQoNCioqVFJBREVSKiosIFRyZWUgUmluZyBBbmFseXNpcyBvZiBEaXN0dXJiYW5jZSBFdmVudHMgaW4gUiwgaXMgYSBwYWNrYWdlIGZvciBkaXN0dXJiYW5jZSByZWNvbnN0cnVjdGlvbiBmcm9tIHRyZWUtcmluZyBkYXRhLiBBbmFseXNlcyBpbmNsdWRlIEFic29sdXRlIEluY3JlYXNlIChGcmF2ZXIgJiBXaGl0ZSAyMDA1KSwgR3Jvd3RoIEF2ZXJhZ2luZyAoTm93YWNraSAmIEFicmFtcyAxOTk3KSwgQm91bmRhcnkgTGluZSAoQmxhY2sgJiBBYnJhbXMgMjAwMyksIGFuZCBTcGxlY2h0bmEgKFNwbGVjaHRuYSwgR3JhdHplciAmIEJsYWNrIDIwMDUpIHdoaWNoIGNvbWJpbmVzIGdyb3d0aCBhdmVyYWdpbmcgYW5kIGJvdW5kYXJ5IGxpbmUgdGVjaG5pcXVlcy4gDQoNClRvIHN0YXJ0IHlvdSBuZWVkIHRvIHJlYWQgaW4gYSByd2wgZmlsZSB0byBiZWdpbiB0aGUgYW5hbHlzaXMuDQoNCmBgYHtyIFRyYWRlciBEYXRhLCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0aGVkYXRhIDwtIHJlYWQudHVjc29uKCdZZWxsb3dzdG9uZV9QU01FX2Zvcm1hdC50eHQnKQ0KYGBgDQoNCkZvciB0aGlzIGV4YW1wbGUgdGhlICpHcm93dGggQXZlcmFnaW5nKiwgYGBgZ3Jvd3RoQXZlcmFnaW5nQUxMKClgYGAsIHRlY2huaXF1ZSB3aWxsIGJlIHVzZWQgd2l0aCBhIHRoZSBmb2xsb3dpbmcgcGFyYW1lbnRlcnM6IHllYXJzIGF2ZXJhZ2VkIHByaW9yIHRvIHJlbGVhc2UgPSAxMCAoKm0xKiksIHllYXJzIGF2ZXJhZ2VkIGFmdGVyIHJlbGVhc2UgPSAxMCwgbnVtYmVyIG9mIHllYXJzIGJldHdlZW4gcmVsZWFzZSBldmVudHMgPSAxMCwgbW9kZXJhdGUgcmVsYXNlID0gMC4yNSwgbWFqb3IgcmVsZWFzZSA9IDAuNTAsIHdpdGggNXlycyBvZiBleGNlZWRpbmcgZ3Jvd3RoIHRvIGJlIGNvbnNpZGVyZWQgYSByZWxlYXNlLiBOb3RlLCBzb21lIG9mIHRoZSBhbmFseXNlcyB3aWxsIGNyZWF0ZSBhIGxhcmdlIG51bWJlciBvZiBmaWxlcyB0byBiZSBjcmVhdGVkIGluIHlvdXIgd29ya2luZyBkaXJlY3RvcnkvDQoNCmBgYHtyIE5vd2Fja2lBYnJhbXMsIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmdyb3d0aEF2ZXJhZ2luZ0FMTCh0aGVkYXRhLCByZWxlYXNlcyA9IE5VTEwsIG0xID0gMTUsIG0yID0gMTUsYnVmZmVyID0gMTAsIGRyYXdpbmcgPSBUUlVFLCBjcml0ZXJpYSA9IDAuMjUsIGNyaXRlcmlhMiA9IDAuNTAscHJlZml4ID0gImdhIiwgZ2Z1biA9IG1lYW4sIGxlbmd0aCA9IDUsIHN0b3JlZGV2ID0ganBlZykNCmBgYA0KDQpgYGBUaGlzIHNjcmlwdCB3YXMgbm90IHJ1biBhcyBwYXJ0IG9mIHRoZSB3b3JrYm9vayB0byBhdm9pZCBhIGxhcmdlIG51bWJlciBvZiBmaWxlcyBjcmVhdGVkIGluIHRoZSBHaXRIdWIgcmVwb3NpdG9yeWBgYA0KDQpTaW1pbGFyIHRvIHRoZSBzY3JpcHQgaW4gYSBwcmV2aW91cyBzZWN0aW9uLCB5b3UgY2FuIGNyZWF0ZSBhIHNwYWdoZXR0aSBwbG90IG9mIHRoZSBkYXRhLg0KDQpgYGB7ciBUUkFERVIgU3BhZ1Bsb3QsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3BhZy5wbG90KHRoZWRhdGEsIHpmYWMgPSAxLCB1c2VSYXN0ZXIgPSBGQUxTRSwgcmVzID0gMzAwKQ0KdGhlZGF0YS5yYXcuY3JuIDwtIGNocm9uKHRoZWRhdGEsIHByZWZpeCA9ICJCVEsiLCBwcmV3aGl0ZW49RkFMU0UpDQpwbG90KHRoZWRhdGEucmF3LmNybixhYmxpbmUucG9zPU5VTEwseWxhYj0nbW0nLHhsYWI9J1llYXInKQ0KYGBgDQoNCiMgQmFzYWwgQXJlYSBJbmNyZW1lbnQgY2FsY3VsYXRpb24gaW4gKmRwbFIqDQoNClVzaW5nIHRoZSBgYGBiYWkub3V0YGBgIGZ1bmN0aW9uIHlvdSBjYW4gdXNlIHRoZSByYXcgcmluZyB3aWR0aCBmaWxlIHRvIGNhbGN1bGF0ZSBiYXNhbCBhcmVhIGluY3JlbWVudC4NCmBgYHtyIEJBSSwgZWNobz1UUlVFLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpncm93LnJ3bCA8LSByZWFkLnJ3bChmbmFtZSA9ICJ3YTA5MS5yd2wiLCBmb3JtYXQgPSAiYXV0byIpDQpiYXNhbCA8LSBiYWkub3V0KGdyb3cucndsLCBkaWFtID0gTlVMTCkNCmJhc2FsX3AgPC0gcHJpbnQoYmFzYWwpDQpzcGFnLnBsb3QoYmFzYWxbMV0sIHpmYWMgPSAxLCB1c2VSYXN0ZXIgPSBGQUxTRSwgcmVzID0gMzAwKQ0KYGBgDQoNClNpbWlsYXIgdG8gYmVmb3JlLCB5b3UgY2FuIGV4cG9ydCB0aGUgZGF0YSB1c2luZyANCmBgYHdyaXRlLmNzdihiYXNhbF9wLCAiYmFzYWxfYmFpLmNzdiIpYGBgDQoNCiMgYnVyblINCg0KVGhlICoqYnVyblIqKiBwYWNrYWdlIGNyZWF0ZXMgY29tcG9zaXRlIGZpcmUgaGlzdG9yeSBwbG90cyBzaW1pbGFyIHRvIHRoZSAqKkZIWDIqKiBhbmQgKipGSEFFUyoqIHByb2dyYW1zLiBJdCB1c2VzICpGSFgqIGZvcm1hdHRlZCBmaWxlcy4gQW4gZXhhbXBsZSBvZiBhIEZIWCBmaWxlIGlzIGluY2x1ZGVkIGluIHRoZSByZXBvc2l0b3J5Lg0KDQpBZnRlciBsb2FkaW5nIHRoZSBgYGBidXJucmBgYCBsaWJyYXJ5LCB5b3UgY2FuIHVzZSBgYGByZWFkX2ZoeCgpYGBgIHRvIGxvYWQgZGF0YSBhbHJlYWR5IGZvcm1hdHRlZCBpbnRvIHRoZSBGSFggZm9ybWF0Lg0KDQpgYGB7ciBMb2FkIEZIWCwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KWmlvbiA8LSByZWFkX2ZoeCgnWmlvbi5maHgnKQ0KWmlvbg0KYGBgDQoNCkFsdGhvdWdoIGVhY2ggb2YgdGhlIHNhbXBsZXMgaGF2ZSBhbiBJRCwgd2UgY2FuIGFkZCBzbyBzaXRlIGluZm9ybWF0aW9uIGluIG9yZGVyIHRvIGZhY2V0IG91ciBwbG90cy4gVGhpcyB3aWxsIHNvcnQgZWFjaCBvZiB0aGUgc2FtcGxlcyBpbnRvIHRoZSBhcHByb3ByaWF0ZSBjYXRlZ29yeSB3aGVuIGZhY3RlZCB3aXRoIHRoZSBgYGBwbG90X2RlbW9ncmFwaGBgYCBmdW5jdGlvbi4NCg0KYGBge3IgUGxvdCBGYWNldCBGSFgsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KU2l0ZXMgPC0gcmVhZC5jc3YoJ1ppb25TaXRlSURzLmNzdicpDQpTaXRlcw0KZmFjZXRwbG90IDwtIHBsb3RfZGVtb2dyYXBoKFppb24sIGZhY2V0X2dyb3VwID0gU2l0ZXMkU2l0ZUlELCBmYWNldF9pZCA9IFNpdGVzJHNlcmllcywgcGxvdF9sZWdlbmQgPSBUUlVFKQ0KcHJpbnQoZmFjZXRwbG90KQ0KYGBgDQoNCkFub3RoZXIgb3B0aW9uIGF2YWlsYWJsZSBpbiBgYGBwbG90X2RlbW9ncmFwaGBgYCBpcyBhIHRvIGNyZWF0ZSBhIHBsb3Qgb2YgYWxsIHNhbXBsZXMgd2l0aCBhIGNvbXBvc2l0ZSBwbG90IGJlbmVhdGggdGhlIHBsb3Qgb2YgaW5kaXZpZHVhbHMuIEluIGFkZGl0aW9uIHRvIHRoZSBwbG90IGFuZCBjb21wb3NpdGUsIHlvdSBjYW4gYWxzbyBhZGQgYW5ub3RhdGlvbnMgdG8gaGlnaGxpZ2h0IGNvbW1vbiBmaXJlIGRhdGVzLg0KDQpgYGB7ciBQbG90IENvbXAgRkhYLCBlY2hvPVRSVUUsIGZpZy5rZWVwPSdhbGwnLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnJ1Z3Bsb3QgPC0gcGxvdF9kZW1vZ3JhcGgoWmlvbiwgY29tcG9zaXRlX3J1ZyA9IFRSVUUsIHBsb3RfbGVnZW5kID0gVFJVRSkNCmNvbXBvc2l0ZXJ1ZyA8LSBydWdwbG90ICsgDQogIGFubm90YXRlKCdyZWN0JywgeG1pbiA9IDE3MjEsIHhtYXggPSAxNzIzLCB5bWluID0gMCwgeW1heCA9IDIxLCBhbHBoYSA9IDAuNCkgKyAgIGFubm90YXRlKCdyZWN0JywgeG1pbiA9IDE3MzQsIHhtYXggPSAxNzM2LCB5bWluID0gMCwgeW1heCA9IDIxLCBhbHBoYSA9IDAuNCkgKyAgIGFubm90YXRlKCdyZWN0JywgeG1pbiA9IDE3NDgsIHhtYXggPSAxNzUwLCB5bWluID0gMCwgeW1heCA9IDIxLCBhbHBoYSA9IDAuNCkgKyAgIGFubm90YXRlKCdyZWN0JywgeG1pbiA9IDE3NzcsIHhtYXggPSAxNzc5LCB5bWluID0gMCwgeW1heCA9IDIxLCBhbHBoYSA9IDAuNCkgKyAgIGFubm90YXRlKCdyZWN0JywgeG1pbiA9IDE3OTMsIHhtYXggPSAxNzk1LCB5bWluID0gMCwgeW1heCA9IDIxLCBhbHBoYSA9IDAuNCkgKyAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHM9YygxNDUwLCAyMDA1KSwgYnJlYWtzID0gc2VxKDE0NTAsMjAwNSwyNSkpICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gLTkwLCBoanVzdCA9IDAsIHZqdXN0ID0gMC4yKSwgDQogIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpDQpwcmludChjb21wb3NpdGVydWcpDQpgYGANCg0KIyBkZW5kcm9Ub29scw0KQWxyaWdodCwgbGV0J3Mgc3RlcCB1cCB0aGUgZ2FtZSEgTGV0J3MgdHJ5IHNvbWUgY2xpbWF0ZSByZXNwb25zZSB3aXRoIGRhaWx5IGNsaW1hdGUgZGF0YSBiZWNhdXNlIHRyZWVzIGRvbid0IGtub3cgd2hhdCBhIG1vbnRoIGlzLiAgWW91IGNhbiBnZXQgZGFpbHkgY2xpbWF0ZSBkYXRhIGZvciB0aGUgVVMgZnJvbSB0aGUgW1BSSVNNIENsaW1hdGUgR3JvdXBdKGh0dHA6Ly93d3cucHJpc20ub3JlZ29uc3RhdGUuZWR1LykuDQoNCkxvYWQgYW5kIGZvcm1hdCB0aGUgZGF0YSBwcmlvciB0byBhbmFseXNpcy4NCmBgYHtyIEZvcm1hdHRpbmcgUENQIERhdGEsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGNwX2QgPC0gcmVhZC5jc3YoIkJUS19kYWlseV9wY3AuY3N2IiwgaGVhZGVyID0gVFJVRSkNCnJvdy5uYW1lcyhwY3BfZCkgPC0gYXMubnVtZXJpYyhwY3BfZCRZZWFyKQ0KcGNwX2QgPC0gcGNwX2RbLDI6MzY3XSAjc3Vic2V0IG9ubHkgMSB0byAzNjYgZGF5cywgbm90IHllYXIgY29sdW1uDQpjcm5fZCA8LSByZWFkLmNzdigiQnRrX3N0ZC5jc3YiKQ0Kcm93Lm5hbWVzKGNybl9kKSA8LSBhcy5udW1lcmljKGNybl9kJFgpICNzZXQgdGhlIHllYXJzIGFzIHJvdyBuYW1lcw0KY3JuX2QgPC0gY3JuX2RbMl0gI3N1YnNldCBvbmx5IGdyb3d0aCBpbmRleA0KaGVhZChjcm5fZCkgDQpgYGANClRha2UgYSBsb29rIGF0IHRoZSBkYWlseSBjbGltYXRlIGRhdGENCmBgYHtyIEdsaW1wc2UsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ2xpbXBzZV9kYWlseV9kYXRhKGVudl9kYXRhID0gcGNwX2QsIHRpZHlfZW52X2RhdGEgPSBGQUxTRSwgbmEuY29sb3IgPSAid2hpdGUiKQ0KYGBgDQoNCkFuYWx5emUgZ3Jvd3RoIHZzIGNsaW1hdGUgd2l0aCBmaXhlZCB3aW5kb3cgd2lkdGguIFRoaXMgaXMgc2V0IGluIHRoZSBzY3JpcHQgdXNpbmcgdGhlIGBgYGZpeGVkX3dpZHRoID0gYGBgIGZ1bmN0aW9uLg0KYGBgDQpmaXhlZF93aWR0aCA8LSBkYWlseV9yZXNwb25zZShyZXNwb25zZSA9IGNybl9kLCBlbnZfZGF0YSA9IHBjcF9kLA0KICAgICAgICAgICAgICAgbWV0aG9kID0gImNvciIsIGZpeGVkX3dpZHRoID0gNjAsIHJvd19uYW1lc19zdWJzZXQgPSBUUlVFLA0KICAgICAgICAgICAgICAgcmVtb3ZlX2luc2lnbmlmaWNhbnQgPSBUUlVFLCBhbHBoYSA9IDAuMDUpDQpgYGAgICAgICAgICAgICAgICANCmBgYHtyIEZpeGVkIFdpZHRoLCBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9NiwgZmlnLmtlZXA9J2FsbCcsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0gICAgICAgICAgICAgICANCmZpeGVkX3dpZHRoJHBsb3RfZXh0cmVtZSAjY3JlYXRlcyBhIHBsb3Qgc2hvd2luZyBiZXN0IGNvcnJlbGF0ZWQgcGVyaW9kDQpgYGANCg0KWW91IGNhbiBjb21wYXJlIHRoZSByZXNwb25zZSBhY3Jvc3MgdHdvIHBlcmlvZHMgb2YgYW5hbHlzaXMgdG8gYXNzZXNzIHRpbWUgc3RhYmlsaXR5LCBvciB5b3UgY2FuIGxlYXZlIHRoZSBzdWJzZXQgdG8gYWxsIHRoZSB5ZWFycy4NCg0KYGBgDQpidGtfcGFzdCA8LSBkYWlseV9yZXNwb25zZShyZXNwb25zZSA9IGNybl9kLCBlbnZfZGF0YSA9IHBjcF9kLA0KICAgICAgICAgICAgbWV0aG9kID0gImNvciIsIGxvd2VyX2xpbWl0ID0gNTAsIHVwcGVyX2xpbWl0ID0gNzAsDQogICAgICAgICAgICByb3dfbmFtZXNfc3Vic2V0ID0gVFJVRSwgcHJldmlvdXNfeWVhciA9IFRSVUUsDQogICAgICAgICAgICByZW1vdmVfaW5zaWduaWZpY2FudCA9IFRSVUUsIGFscGhhID0gMC4wNSwNCiAgICAgICAgICAgIHBsb3Rfc3BlY2lmaWNfd2luZG93ID0gNjAsIHN1YnNldF95ZWFycyA9IGMoMTk4MSwgMTk5OCkpDQpgYGANCmBgYA0KYnRrX3ByZXNlbnQgPC0gZGFpbHlfcmVzcG9uc2UocmVzcG9uc2UgPSBjcm5fZCwgZW52X2RhdGEgPSBwY3BfZCwNCiAgICAgICAgICAgICAgIG1ldGhvZCA9ICJjb3IiLCBsb3dlcl9saW1pdCA9IDUwLCB1cHBlcl9saW1pdCA9IDcwLA0KICAgICAgICAgICAgICAgcm93X25hbWVzX3N1YnNldCA9IFRSVUUsIHByZXZpb3VzX3llYXIgPSBUUlVFLA0KICAgICAgICAgICAgICAgcmVtb3ZlX2luc2lnbmlmaWNhbnQgPSBUUlVFLCBhbHBoYSA9IDAuMDUsDQogICAgICAgICAgICAgICBwbG90X3NwZWNpZmljX3dpbmRvdyA9IDYwLCBzdWJzZXRfeWVhcnMgPSBjKDE5OTksIDIwMTYpKQ0KYGBgDQoNCk5vdyB5b3UgY2FuIHBsb3QgdGhlIHJlc3VsdHMuDQpgYGB7ciBCVEsgUGFzdCBQcmVzZW50IFBsb3RzLCBlY2hvPVRSVUUsIGZpZy5rZWVwPSdhbGwnLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmJ0a19wYXN0JHBsb3RfaGVhdG1hcA0KYnRrX3ByZXNlbnQkcGxvdF9oZWF0bWFwDQpidGtfcGFzdCRwbG90X3NwZWNpZmljICNjaG9vc2UgYSBzcGVjaWZpYyB3aW5kb3cgbGVuZ3RoIHRvIHBsb3QgaWYgeW91IHNldCB0aGlzIGFib3ZlDQpidGtfcHJlc2VudCRwbG90X3NwZWNpZmljDQpgYGANCiMjIENsaW1hdGUgUmVzcG9uc2Ugb24gdGhlIFByaW5jaXBsZSBDb21wb25lbnRzDQoNCkxvYWQgZGF0YQ0KYGBge3IgUENBIERBdGEsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGF0YShleGFtcGxlX3Byb3hpZXNfaW5kaXZpZHVhbCkNCmRhdGEoTEpfZGFpbHlfdGVtcGVyYXR1cmVzKQ0KYGBgDQoNCkV4YW1wbGUgUENBIC0ganVzdCBjcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggbXVsdGlwbGUgY3Jucw0KYGBgDQpleGFtcGxlX1BDQSA8LSBkYWlseV9yZXNwb25zZShyZXNwb25zZSA9IGV4YW1wbGVfcHJveGllc19pbmRpdmlkdWFsLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudl9kYXRhID0gTEpfZGFpbHlfdGVtcGVyYXR1cmVzLCBtZXRob2QgPSAibG0iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvd2VyX2xpbWl0ID0gNjAsIHVwcGVyX2xpbWl0ID0gNzAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dfbmFtZXNfc3Vic2V0ID0gVFJVRSwgcmVtb3ZlX2luc2lnbmlmaWNhbnQgPQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSwgYWxwaGEgPSAwLjAxLCBQQ0FfdHJhbnNmb3JtYXRpb24gPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcG9uZW50c19zZWxlY3Rpb24gPSAibWFudWFsIiwgTl9jb21wb25lbnRzID0gMikNCmBgYA0KU3VtbWFyeSBvdXRwdXQgYW5kIHBsb3QgZm9yIHRoZSBQQ0EgYW5hbHlzaXMuDQpgYGB7ciBQQ0EsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3VtbWFyeShleGFtcGxlX1BDQSRQQ0Ffb3V0cHV0KQ0KYGBgDQpgYGB7ciBQQ0EgSGVhdCBNYXAsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZXhhbXBsZV9QQ0EkcGxvdF9oZWF0bWFwDQpgYGANCg0KIyMgUXVpY2sgY29tbW9uIHBlcmlvZCByZWNvbnN0cnVjdGlvbg0KDQpMb2FkIHRoZSBzYW1wbGUgZGF0YS4NCmBgYHtyIENQIFJlY29uIERhdGEsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGF0YShkYXRhX1RSVykNCmRhdGEoS1JFX2RhaWx5X3RlbXBlcmF0dXJlcykNCmBgYA0KUmVjb25zdHJ1Y3Rpb24NCmBgYA0KZXhhbXBsZV9yZWNvbnN0cnVjdGlvbl9saW4gPC0gZGFpbHlfcmVzcG9uc2UocmVzcG9uc2UgPSBkYXRhX1RSVywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnZfZGF0YSA9IEtSRV9kYWlseV90ZW1wZXJhdHVyZXMsIG1ldGhvZCA9ICJsbSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRyaWMgPSAici5zcXVhcmVkIiwgbG93ZXJfbGltaXQgPSAzMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVwcGVyX2xpbWl0ID0gNDAsIHJvd19uYW1lc19zdWJzZXQgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGVtcG9yYWxfc3RhYmlsaXR5X2NoZWNrID0gInByb2dyZXNzaXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNyb3NzX3ZhbGlkYXRpb25fdHlwZSA9ICJyYW5kb21pemVkIiwgayA9IDMpDQpgYGANClJlY29uc3RydWN0aW9uIFBsb3RzDQpgYGB7ciBSZWNvbiBQbG90cywgZWNobz1UUlVFLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpleGFtcGxlX3JlY29uc3RydWN0aW9uX2xpbiRwbG90X2V4dHJlbWUNCmV4YW1wbGVfcmVjb25zdHJ1Y3Rpb25fbGluJHRlbXBvcmFsX3N0YWJpbGl0eQ0KZXhhbXBsZV9yZWNvbnN0cnVjdGlvbl9saW4kY3Jvc3NfdmFsaWRhdGlvbg0KZXhhbXBsZV9yZWNvbnN0cnVjdGlvbl9saW4kdHJhbnNmZXJfZnVuY3Rpb24NCmBgYA0KYGBge3IgUmVjb24gTW9kZWxzLCBlY2hvPVRSVUUsIGZpZy5rZWVwPSdhbGwnLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpbmVhcl9tb2RlbCA8LSBsbShPcHRpbWl6ZWRfcmV0dXJuIH4gVFJXLCBkYXRhID0gZXhhbXBsZV9yZWNvbnN0cnVjdGlvbl9saW4kb3B0aW1pemVkX3JldHVybikNCnJlY29uc3RydWN0aW9uIDwtIGRhdGEuZnJhbWUocHJlZGljdGlvbnMgPSBwcmVkaWN0KGxpbmVhcl9tb2RlbCwgbmV3ZGF0YSA9IGRhdGFfVFJXKSkNCmxpbmVhcl9tb2RlbCA8LSBsbShPcHRpbWl6ZWRfcmV0dXJuIH4gVFJXLCBkYXRhID0gZXhhbXBsZV9yZWNvbnN0cnVjdGlvbl9saW4kb3B0aW1pemVkX3JldHVybikNCnJlY29uc3RydWN0aW9uIDwtIGRhdGEuZnJhbWUocHJlZGljdGlvbnMgPSBwcmVkaWN0KGxpbmVhcl9tb2RlbCwgbmV3ZGF0YSA9IGRhdGFfVFJXKSkNCnBsb3Qocm93Lm5hbWVzKGRhdGFfVFJXKSwgcmVjb25zdHJ1Y3Rpb24kcHJlZGljdGlvbnMsIHR5cGUgPSAibCIsIHhsYWIgPSAiWWVhciIsIHlsYWIgPSAiTWVhbiB0ZW1wZXJhdHVyZSBNYXkgMTUgLSBKdW4gMjcgWz9DXSIpDQpgYGANCiMjIE1vbnRobHkgQW5hbHlzaXMNCmxvYWQgZGF0YQ0KYGBge3IgTW9udGhseSBBbmFseXNpcyBEYXRhLCBlY2hvPVRSVUUsIGZpZy5rZWVwPSdhbGwnLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmZsb3dfZCA8LSByZWFkLmNzdigiQmlnaG9yblhhdmllcl9yLmNzdiIsIGhlYWRlciA9IFRSVUUpDQpyb3cubmFtZXMoZmxvd19kKSA8LSBhcy5udW1lcmljKGZsb3dfZCR5ZWFyKQ0KZmxvd19kIDwtIGZsb3dfZFssMjoxM10jc3Vic2V0IG9ubHkgMSB0byAzNjYgZGF5cywgbm90IHllYXIgY29sdW1uDQpgYGANCg0KUnVuIGFuYWx5c2lzIHdpdGggc3BsaXQgcGVyaW9kDQpgYGANCmZsb3dfcGFzdCA8LSBtb250aGx5X3Jlc3BvbnNlKHJlc3BvbnNlID0gY3JuX2QsIGVudl9kYXRhID0gZmxvd19kLA0KICAgICAgICAgICAgIG1ldGhvZCA9ICJjb3IiLCByb3dfbmFtZXNfc3Vic2V0ID0gVFJVRSwgcHJldmlvdXNfeWVhciA9IFRSVUUsDQogICAgICAgICAgICAgcmVtb3ZlX2luc2lnbmlmaWNhbnQgPSBUUlVFLCBhbHBoYSA9IDAuMDUsIHN1YnNldF95ZWFycyA9IGMoMTkzNSwNCiAgICAgICAgICAgICAxOTc2KSwgYWdncmVnYXRlX2Z1bmN0aW9uID0gJ21lYW4nKQ0KYGBgDQpgYGANCmZsb3dfcHJlc2VudCA8LSBtb250aGx5X3Jlc3BvbnNlKHJlc3BvbnNlID0gZGF0YV9NVkEsIGVudl9kYXRhID0NCiAgICAgICAgICAgICAgICBMSl9tb250aGx5X3RlbXBlcmF0dXJlcywgbWV0aG9kID0gImNvciIsIHJvd19uYW1lc19zdWJzZXQgPQ0KICAgICAgICAgICAgICAgIFRSVUUsIGFscGhhID0gMC4wNSwgcHJldmlvdXNfeWVhciA9IFRSVUUsIHJlbW92ZV9pbnNpZ25pZmljYW50ID0NCiAgICAgICAgICAgICAgICBUUlVFLCBzdWJzZXRfeWVhcnMgPSBjKDE5NzcsIDIwMTYpLCBhZ2dyZWdhdGVfZnVuY3Rpb24gPSAnbWVhbicpDQpgYGANCmBgYHtyIEZsb3cgUGxvdHMsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZmxvd19wYXN0JHBsb3RfaGVhdG1hcA0KZmxvd19wcmVzZW50JHBsb3RfaGVhdG1hcA0KZmxvd19wYXN0JHBsb3RfZXh0cmVtZQ0KZmxvd19wcmVzZW50JHBsb3RfZXh0cmVtZQ0KYGBgDQojIyBNb250aGx5IGFuYWx5c2lzIHVzaW5nIGEgUENBIG9mIGNocm9ub2xvZ2llcyB3aXRoIGNybnMNCg0KWW91IHN0aWxsIG5lZWQgdG8gZ2V0IGNybnMgaW4gY29sdW1uIGZvcm1hdA0KYGBgDQpmbG93X1BDQSA8LSBtb250aGx5X3Jlc3BvbnNlKHJlc3BvbnNlID0gZXhhbXBsZV9wcm94aWVzX2luZGl2aWR1YWwsDQogICAgICAgICAgICBlbnZfZGF0YSA9IGZsb3dfZCwgbWV0aG9kID0gImxtIiwgcm93X25hbWVzX3N1YnNldCA9IFRSVUUsDQogICAgICAgICAgICByZW1vdmVfaW5zaWduaWZpY2FudCA9IFRSVUUsIGFscGhhID0gMC4wMSwgUENBX3RyYW5zZm9ybWF0aW9uID0NCiAgICAgICAgICAgIFRSVUUsIHByZXZpb3VzX3llYXIgPSBUUlVFLCBjb21wb25lbnRzX3NlbGVjdGlvbiA9ICJtYW51YWwiLA0KICAgICAgICAgICAgTl9jb21wb25lbnRzID0gMikNCmBgYA0KYGBge3IgTW9udGhseSBDUk4gUGxvdHMsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3VtbWFyeShmbG93X1BDQSRQQ0Ffb3V0cHV0KQ0KZmxvd19QQ0EkcGxvdF9oZWF0bWFwDQpmbG93X1BDQSRwbG90X2V4dHJlbWUNCmBgYA0KIyBEZW5kcm9TeW5jDQoNClRoaXMgcGFja2FnZSBwcm92aWRlcyBmdW5jdGlvbnMgZm9yIHRoZSBjYWxjdWxhdGlvbiBhbmQgcGxvdHRpbmcgb2Ygc3luY2hyb255IGluIHRyZWUgZ3Jvd3RoIGZyb20gdHJlZS1yaW5nIHdpZHRoIGNocm9ub2xvZ2llcyAoVFJXIGluZGV4KS4NCg0KTG9hZCBEYXRhDQpgYGB7ciBEZW5kcm9TeW5jIERhdGEsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGF0YShjb25pZmVyc0lQKSAjbm90ZSB0aGUgZm9ybWF0IG9mIHRoZSBkYXRhIGlmIHlvdSBjaG9vc2UgdG8gdXNlIHRoaXMgYW5hbHlzaXMNCmhlYWQoY29uaWZlcnNJUCkNCmBgYA0KDQpDYWxjdWxhdGUgc3luY2hyb255IGZvciBudWxsLm1vZGVsIChicm9hZCBldmFsdWF0aW9uLCBtQkUpIGFuZCBob21vc2NlZGFzdGljIHZhcmlhbnQgb2YgdW5zdHJ1Y3R1cmVkIG1vZGVsIChvciBmdWxsLCBtVU4pIGZvciBjb25pZmVyc0lQIGRhdGEsIGFuZCBoZXRlcm9zY2VkYXN0aWMgdmFyaWFudCBmb3IgMTk3MC0xOTk5IHBlcmlvZC4NCg0KRml0IHRoZSBob21vc2NlZGFzdGljIHNldCBvZiB2YXJjb3YgbW9kZWxzIChtQkUsIG1ORSwgbUNTLCBtVU4pIHVzaW5nIHRheG9ub21pYyBncm91cGluZyBjcml0ZXJpYSAoaS5lLiBTcGVjaWVzKQ0KYGBge3IgTW9kSE0sIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KTW9kSG0gPC0gZGVuZHJvLnZhcmNvdihUUlcgfiBDb2RlLCB2YXJUaW1lID0gIlllYXIiLCB2YXJHcm91cCA9ICJTcGVjaWVzIiwgDQogICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBjb25pZmVyc0lQLCBob21vc2NlZGFzdGljID0gVFJVRSkNCg0Kc3VtbWFyeShNb2RIbSkjIENsYXNzIGFuZCBsZW5ndGggb2YgbGlzdCBlbGVtZW50cw0KYGBgDQoNCkV4YW1pbmUgc3luY2hyb255IGZvciBtQkUgYW5kIG1VTiBtb2RlbHMNCmBgYHtyIE1vZGVsIFN5bmNocm9ueSwgZWNobz1UUlVFLCBmaWcua2VlcD0nYWxsJywgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpzeW5jKE1vZEhtLCBtb2RuYW1lID0gIm1CRSIpDQpzeW5jKE1vZEhtLCBtb2RuYW1lID0gIm1VTiIpDQpgYGANCg0KU3Vic2V0IHRoZSBkYXRhIGZyb20gMTk3MCB0byAxOTk5Lg0KYGBge3IgTW9kZWwgU3Vic2V0LCBlY2hvPVRSVUUsIGZpZy5rZWVwPSdhbGwnLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmNvbmlmLjMwIDwtIGNvbmlmZXJzSVBbY29uaWZlcnNJUCRZZWFyPjE5NjkgJiBjb25pZmVyc0lQJFllYXI8MjAwMCxdDQpzdW1tYXJ5KGNvbmlmLjMwJFllYXIpDQpgYGANCg0KRml0IHRoZSBoZXRlcm9zY2VkYXN0aWMgc2V0IG9mIHZhcmlhbmNlIGNvdmFyaWFuY2UgbWl4ZWQgbW9kZWxzIChtQkUsIG1IZU5FLCBtSGVDUywgbUhlVU4pIHVzaW5nIHRheG9ub21pYyBncm91cGluZyBjcml0ZXJpYSAoaWUuIFNwZWNpZXMpDQpgYGB7ciBNaXhlZCBNb2RlbHMsIGVjaG89VFJVRSwgZmlnLmtlZXA9J2FsbCcsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KTW9kSHQzMCA8LSBkZW5kcm8udmFyY292KFRSVyB+IENvZGUsIHZhclRpbWUgPSAiWWVhciIsIHZhckdyb3VwID0gIlNwZWNpZXMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhID0gY29uaWYuMzAsIGhvbW9zY2VkYXN0aWMgPSBGQUxTRSkNCmBgYA0KYGBge3IgTWl4ZWQgTW9kZWwgU3luY2hyb255LCBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpzeW5jKE1vZEh0MzAsIG1vZG5hbWUgPSAibUJFIikNCnN5bmMoTW9kSHQzMCwgbW9kbmFtZSA9ICJtSGVVTiIpDQpgYGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NClRoaXMgd29ya2Jvb2sgd2FzIGNyZWF0ZWQgYXMgYW4gW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pIE5vdGVib29rLiBXaGVuIHlvdSBleGVjdXRlIGNvZGUgd2l0aGluIHRoZSBub3RlYm9vaywgdGhlIHJlc3VsdHMgYXBwZWFyIGJlbmVhdGggdGhlIGNvZGUuIFRoZSByZXN1bHRpbmcgKmh0bWwqIGlzIHVzZWQgdG8gZGlzcGxheSB0aGUgc3RhdGljIGNvbnRlbnRzIHZpYSBHaXRIdWIuDQo=