Introduction

We need to decide whether our “gates” methodology still makes sense when applied in the principal components (PC) coordinate system. In this experiment we compare runs filtered by output gates to runs filtered by PC gates to see how well they correspond.

Setup

library('dplyr', warn.conflicts = FALSE)
library('ggplot2')
library('ggthemes')
library('foreach')
library('hectorcal')

Evaluation of models that pass the gates in the PC space

Concentration-driven runs

Comparison of ESM and Hector PC ranges

For the concentration-driven runs most of the variation is carried in the first two PCs. The box marked out by the ESMs in this two-dimensional space gives a first approximation to our calibration region. How do models in this region perform relative to our old-style gates defined in the model output space?

Although PC1 and PC2 account for most of the variation in the hector results, there is still some variation in the other components, so we’ll take a look at different levels for PC 3 and 4 as well.

## We need the PC projections for the ensemble
hector_proj <- compute_pc(hector_conc_ensemble, c('historical','rcp26','rcp45','rcp60','rcp85'), 
                          'tas', 2006:2100, 1861:2005, retx=TRUE)$x
## ESM projections are stored as package data: cmip_conc_pcproj
## Tables of min, max, mean values by PC, for both sets
maxpc <- 10
esm_pc_stats <- group_by(cmip_conc_pcproj, PC) %>% 
    summarise(min=min(value), max=max(value), mean=mean(value), sd=sd(value)) %>%
    filter(PC <= maxpc)
stats_matrix <- apply(hector_proj[ , 1:maxpc], 2, function(x) {c(min(x), max(x), mean(x), sd(x))})
hector_pc_stats <- data.frame(PC=seq_along(stats_matrix[1,]), 
                              min=stats_matrix[1,],
                              max=stats_matrix[2,],
                              mean=stats_matrix[3,],
                              sd=stats_matrix[4,])
bind_cols(select(esm_pc_stats, PC, esm.min=min, esm.max=max, esm.mean=mean, esm.sd=sd),
          select(hector_pc_stats, hector.min=min, hector.max=max, hector.mean=mean, hector.sd=sd))

The first thing we can see from these statistics is that though the ESM statistics exclude a lot of the range covered by the Hector ensemble, the ensemble average passes all of the gates for the first 10 PCs, except for PC7, which marginally excludes zero. For PCs \(\geq\) 9, the coefficients of all of the hector ensemble members are all very close to zero, indicating that for this ensemble there is definitely no useful calibration to be done using those components because for any such test either the enitre parameter space will pass, or the entire space will fail.

We are now in a position to evaluate how the joint PC1-PC2 gate deprojects into the output plane. Here is a graphical depiction of the gate, with the positions of the ESMs labeled.

esm_pcplot(cmip_conc_pcproj) + geom_abline(slope=-0.6, intercept=-3, color='lightgrey', size=1.5, alpha=0.5)

One noticeable trend is that although these dimensions are uncorrelated in the Hector ensemble, the ESMs appear to cluster around a line with a slope of about \(-0.6\). The sample here is very small, so it’s not clear how seriously we should take this possible relationship. Is there no model around \((-7.5, -4)\) because that model is excluded by the ESMs’ calibration process, or because nobody happens to have written the model with that behavior? We are not in a position to answer that question right now, but it’s worth keeping in mind.

Evaluating the relationship between PCs and outputs

To get a sense of where the points in this plane fall in output space, we will define low, medium, and high levels for PC1 and PC2, defined by the min, mean, and max values, respectively, for the ESM projections. PC1 levels will be depicted by color in the plots, and PC2 levels will be depicted by line type. We will also define low, medium, and high levels for PC3 and PC4 using this time the min, mean, and max for the Hector ensemble, reflecting the fact that for now we are not planning to filter on those PCs. The PC3 and PC4 levels will be presented in facet plots. Finally, the results will be broken out by experiment, with each experiment presented as a separate family of plots.

idcols <- c('min','mean','max')
levels <- c('low','med','zhigh')
pc1lvls <- as.data.frame(esm_pc_stats)[1, idcols]
pc2lvls <- as.data.frame(esm_pc_stats)[2, idcols]
pc3lvls <- hector_pc_stats[3, idcols]
pc4lvls <- hector_pc_stats[4, idcols]
names(pc1lvls) <- names(pc2lvls) <- names(pc3lvls) <- names(pc4lvls) <- levels
### Create the tables for each combination of levels
climout <- 
    foreach(lpc1=levels, .combine=bind_rows) %do% {
        foreach(lpc2=levels, .combine=bind_rows) %do% {
            foreach(lpc3=levels, .combine=bind_rows) %do% {
                foreach(lpc4=levels, .combine=bind_rows) %do% {
                    coef <- c(pc1lvls[[lpc1]], pc2lvls[[lpc2]], pc3lvls[[lpc3]], pc4lvls[[lpc4]])
                    reconstruct_climate(coef, pc_conc, 4) %>%
                        mutate(PC1=lpc1, PC2=lpc2, PC3=lpc3, PC4=lpc4)
                }
            }
        }
    }
## Order the levels so that they are in order in the plots
#climout <- mutate(climout, 
#                  PC1 = ordered(PC1, labels=levels),
#                  PC2 = ordered(PC2, labels=levels),
#                  PC3 = ordered(PC3, labels=levels),
#                  PC4 = ordered(PC4, labels=levels))
## Get a data frame of gates for an experiment
get_gates <- function(expt, var, minyear=1861, maxyear=2100) {
    if(grepl('[Hh]istorical', expt)) {
        maxyear <- 2005
    }
    else {
        minyear <- 2006
    }
    
    exptdata <- filter(esm_comparison, experiment==expt, variable==var, 
                       year <= maxyear, year >= minyear)
    yrs <- c(min(exptdata$year),
             max(exptdata$year[exptdata$year <= median(exptdata$year)]),
             max(exptdata$year))
    filter(exptdata, year %in% yrs)
}
for(expt in unique(climout$experiment)) {
    print(
        ggplot(data=filter(climout, experiment==expt),
               aes(x=year, y=value, color=PC1, linetype=PC2)) +
            geom_line(size=0.75) +
            geom_errorbar(data=get_gates(expt, 'tas'), aes(x=year, ymin=mina, ymax=maxb), 
                          linetype=2, color='lightgrey', inherit.aes = FALSE, width=1) +
            facet_grid(PC3~PC4) + 
            ggtitle(paste('Experiment:', expt)) + ylab('Temperature') +
            theme_solarized_2(light=FALSE, base_size = 18) + 
            scale_color_solarized()
    )
}

Looking at the data this way makes it a lot more clear what each of the components is doing. For the future runs (the behavior for the historical runs is a bit different), PC1 shifts the temperature nearly uniformly up and down (look, for example, at the series of solid lines in the plots). Meanwhile, PC2 appears to control the average slope of the temperature curve over time (compare the sequence of lines in any single color).

PC3 (horizontal facets in the grid) appears to control the tendency of the temperature curve to bend downward in the late 21st century. Consider, for example, the RCP 2.6 experiment. With PC3 at the high level (right column), none of these scenarios show the peak and decline that we normally associate with RCP 2.6. PC3 also has a clear effect in the historical experiment, where it is clearly related to the strength of the aerosol effect.

The effect of PC4 (vertical facets) is a little hard to discern in the future runs. It looks to be a little duplicative of PC3, inducing some downward curvature late in the century. However, in the historical period PC4 is clearly influencing the behavior in the early part of the run. With PC4 low, scenarios tend to be below or at the low end of the 1933 gate. With PC4 medium, all scenarios go through the 1933 gate, irrespective of the other PC values, and with PC4 high, the scenarios tend to be high at the 1933 gate.

The conclusion from all of this is that notwithstanding the small fraction of the total variance accounted for by PC3 and PC4, if we want our PC methodology to correspond, at least roughly, to the output gate methodology, then we are going to have to constrain PC3 and PC4 using the ESM results.

If we constrain PC3 and PC4 with the ESM values and rerun the experiment, then we get the following.

pc1lvls_pc34 <- as.data.frame(esm_pc_stats)[1, idcols]
pc2lvls_pc34 <- as.data.frame(esm_pc_stats)[2, idcols]
pc3lvls_pc34 <- as.data.frame(esm_pc_stats)[3, idcols]
pc4lvls_pc34 <- as.data.frame(esm_pc_stats)[4, idcols]
names(pc1lvls_pc34) <- names(pc2lvls_pc34) <- 
    names(pc3lvls_pc34) <- names(pc4lvls_pc34) <- levels
### Create the tables for each combination of levels
climout_pc34 <- 
    foreach(lpc1=levels, .combine=bind_rows) %do% {
        foreach(lpc2=levels, .combine=bind_rows) %do% {
            foreach(lpc3=levels, .combine=bind_rows) %do% {
                foreach(lpc4=levels, .combine=bind_rows) %do% {
                    coef <- c(pc1lvls_pc34[[lpc1]], pc2lvls_pc34[[lpc2]], 
                              pc3lvls_pc34[[lpc3]], pc4lvls_pc34[[lpc4]])
                    reconstruct_climate(coef, pc_conc, 4) %>%
                        mutate(PC1=lpc1, PC2=lpc2, PC3=lpc3, PC4=lpc4)
                }
            }
        }
    }
for(expt in unique(climout_pc34$experiment)) {
    print(
        ggplot(data=filter(climout_pc34, experiment==expt),
               aes(x=year, y=value, color=PC1, linetype=PC2)) +
            geom_line(size=0.75) +
            geom_errorbar(data=get_gates(expt, 'tas'), aes(x=year, ymin=mina, ymax=maxb), 
                          linetype=2, color='lightgrey', inherit.aes = FALSE, width=1) +
            facet_grid(PC3~PC4) + 
            ggtitle(paste('Experiment:', expt)) + ylab('Temperature') +
            theme_solarized_2(light=FALSE, base_size = 18) + 
            scale_color_solarized()
    )
}

Not surprisingly, these constraints put most of the scenarios a lot closer to the output gates. We’re still missing sometimes, but at this point one starts to wonder, how firm are these gates. We don’t have that many ESMs, and so it’s not too hard to believe that scenarios a little outside of the gates are still reasonable. The only cases that are a little concerning are the RCP 8.5 scenarios for the (low/med, high, any, low) combinations. Some of those scenarios are \(1.5^{\circ}C\) below the lower edge of the 2100 gate, which seems a little much to me.

Note that for all of these scenarios, the projection onto PC5 is pegged at zero, which is within the ESM constraints, so constraining that parameter won’t affect anything in these plots. However, we might well wonder what happens to these results if PC5 is near the high or low end of its range. At the risk of inducing plot overload, here is the same set with PC5 low.

### -2.76 is the low value for PC5 (from the table above)
climout_pc5lo <- 
    foreach(lpc1=levels, .combine=bind_rows) %do% {
        foreach(lpc2=levels, .combine=bind_rows) %do% {
            foreach(lpc3=levels, .combine=bind_rows) %do% {
                foreach(lpc4=levels, .combine=bind_rows) %do% {
                    coef <- c(pc1lvls_pc34[[lpc1]], pc2lvls_pc34[[lpc2]], 
                              pc3lvls_pc34[[lpc3]], pc4lvls_pc34[[lpc4]], -2.76)
                    reconstruct_climate(coef, pc_conc, 5) %>%
                        mutate(PC1=lpc1, PC2=lpc2, PC3=lpc3, PC4=lpc4)
                }
            }
        }
    }
for(expt in unique(climout_pc5lo$experiment)) {
    print(
        ggplot(data=filter(climout_pc5lo, experiment==expt),
               aes(x=year, y=value, color=PC1, linetype=PC2)) +
            geom_line(size=0.75) +
            geom_errorbar(data=get_gates(expt, 'tas'), aes(x=year, ymin=mina, ymax=maxb), 
                          linetype=2, color='lightgrey', inherit.aes = FALSE, width=1) +
            facet_grid(PC3~PC4) + 
            ggtitle(paste('Experiment:', expt)) + ylab('Temperature') +
            theme_solarized_2(light=FALSE, base_size = 18) + 
            scale_color_solarized()
    )
}

Some of these are way outside the gates; the RCP 2.6 scenarios, especially, are very high at the 2100 gate.

### 0.382 is the high value for PC5 (from the table above)
climout_pc5hi <- 
    foreach(lpc1=levels, .combine=bind_rows) %do% {
        foreach(lpc2=levels, .combine=bind_rows) %do% {
            foreach(lpc3=levels, .combine=bind_rows) %do% {
                foreach(lpc4=levels, .combine=bind_rows) %do% {
                    coef <- c(pc1lvls_pc34[[lpc1]], pc2lvls_pc34[[lpc2]], 
                              pc3lvls_pc34[[lpc3]], pc4lvls_pc34[[lpc4]], 0.382)
                    reconstruct_climate(coef, pc_conc, 5) %>%
                        mutate(PC1=lpc1, PC2=lpc2, PC3=lpc3, PC4=lpc4)
                }
            }
        }
    }
for(expt in unique(climout_pc5hi$experiment)) {
    print(
        ggplot(data=filter(climout_pc5hi, experiment==expt),
               aes(x=year, y=value, color=PC1, linetype=PC2)) +
            geom_line(size=0.75) +
            geom_errorbar(data=get_gates(expt, 'tas'), aes(x=year, ymin=mina, ymax=maxb), 
                          linetype=2, color='lightgrey', inherit.aes = FALSE, width=1) +
            facet_grid(PC3~PC4) + 
            ggtitle(paste('Experiment:', expt)) + ylab('Temperature') +
            theme_solarized_2(light=FALSE, base_size = 18) + 
            scale_color_solarized()
    )
}

These actually don’t look too bad. However, given the poor performance at the low end, it’s pretty clear that we will need to constrain PC5.

We could continue this line of analysis, but if we look at the range for PC6, the ESM maximum doesn’t constrain the ensemble at all because the ensemble maximum is actually lower than the ESM maximum. There is some constraint at the low end, but it’s a much weaker constraint than we see for PC5, so I’m pretty confident that constraining PC6 won’t make much difference. Note also that for PCs 8-10 the ESM range includes the entire ensemble range, so constraining these components definitely won’t have any effect. Therefore, we will probably end up running MCMC runs with constraints on PC1-5, 1-6, and 1-7, and we’ll compare the parameter distributions that we get from these to see if there is any significant difference.

Emissions-driven runs

Reliability of the small concentration-driven ESM sample

Here we go again. My main concern here is that with only three valid models to use in the calibration, the statistics for our calibration data may be not be very good. In particular we could be seeing gates that are way too narrow if the models that we happen to have available to us aren’t near the edges of the true distribution of model outcomes. We can get some idea of the extent to which this happens by comparing the temperature output gates in the historical and RCP 8.5 experiments for the concentration and emissions driven ESM runs.

bind_rows(
    get_gates('historical', 'tas'),
    get_gates('esmHistorical', 'tas'))
bind_rows(
    get_gates('rcp85', 'tas'),
    get_gates('esmrcp85', 'tas'))

It looks as if the gates for the emissions-driven runs are at their most restrictive when we’re close to the historical-future change over. The gates for the 1861 and 2100 don’t look much smaller than their concentration-driven counterparts. However, we would expect the emissions-driven runs to show a greater dispersion in outcomes than the concentration- driven runs, since they have more dimensions along which they can be different from one another. That we don’t see that additional dispersion indicates that our gates in the emission-driven runs probably are narrower than they should be.

I am thinking that when we go to do the calibration we will need to correct for this by widening the likelihood function. We can do this either by increasing the width of the gates, or by increasing the smoothing parameter. I haven’t yet decided which way is better, but I am leaning toward using the smoothing parameter, since it better expresses the idea that we have softened the edge of the gate because we don’t really know where that edge is. How do we know how much to soften the gates? Here we can take advantage of the better sampling of the concentration-driven model space. If we take the marginal variance of the temperature parameters as being relatively reliably determined by the concentration- driven MCMC, then we can adjust the softening in the emissions-driven MCMC until the marginal variances of the temperature parameters are reasonably close to the values from the concentration-driven MCMC.

Comparison of Hector and ESM PC ranges

## We need the PC projections for the ensemble
hector_emiss_proj <- compute_pc(hector_emiss_ensemble, c('esmHistorical','esmrcp85'), 
                                c('tas', 'co2'), 2006:2100, 1861:2005, retx=TRUE)$x
## Tables of min, max, mean values by PC, for both sets
maxpc <- 20
esm_emiss_pc_stats <- group_by(cmip_emiss_pcproj, PC) %>% 
    summarise(min=min(value), max=max(value), mean=mean(value), sd=sd(value)) %>%
    filter(PC <= maxpc)
stats_matrix <- apply(hector_emiss_proj[ , 1:maxpc], 2, function(x) {c(min(x), max(x), mean(x), sd(x))})
hector_emiss_pc_stats <- data.frame(PC=seq_along(stats_matrix[1,]), 
                                    min=stats_matrix[1,],
                                    max=stats_matrix[2,],
                                    mean=stats_matrix[3,],
                                    sd=stats_matrix[4,])
bind_cols(select(esm_emiss_pc_stats, PC, esm.min=min, esm.max=max, esm.mean=mean, esm.sd=sd),
          select(hector_emiss_pc_stats, hector.min=min, hector.max=max, hector.mean=mean, hector.sd=sd))

Between the variance fraction analysis, the results from the concentration-driven runs, and the table above it seems likely that we are going to need to constrain at least the first 4 PCs, so I’ve dispensed with the version of the plot where PC3 and PC4 are unconstrained.

pc1lvls_emiss <- as.data.frame(esm_emiss_pc_stats)[1, idcols]
pc2lvls_emiss <- as.data.frame(esm_emiss_pc_stats)[2, idcols]
pc3lvls_emiss <- as.data.frame(esm_emiss_pc_stats)[3, idcols]
pc4lvls_emiss <- as.data.frame(esm_emiss_pc_stats)[4, idcols]
names(pc1lvls_emiss) <- names(pc2lvls_emiss) <- 
    names(pc3lvls_emiss) <- names(pc4lvls_emiss) <- levels
### Create the tables for each combination of levels
climout_emiss <- 
    foreach(lpc1=levels, .combine=bind_rows) %do% {
        foreach(lpc2=levels, .combine=bind_rows) %do% {
            foreach(lpc3=levels, .combine=bind_rows) %do% {
                foreach(lpc4=levels, .combine=bind_rows) %do% {
                    coef <- c(pc1lvls_emiss[[lpc1]], pc2lvls_emiss[[lpc2]], 
                              pc3lvls_emiss[[lpc3]], pc4lvls_emiss[[lpc4]])
                    reconstruct_climate(coef, pc_emiss, 4) %>%
                        mutate(PC1=lpc1, PC2=lpc2, PC3=lpc3, PC4=lpc4)
                }
            }
        }
    }
for(expt in unique(climout_emiss$experiment)) {
    for(var in unique(climout_emiss$variable)) {
        if(var=='tas') {
            yl <- 'Temperature'
        }
        else {
            yl <- 'CO2 concentration'
        }
        print(
            ggplot(data=filter(climout_emiss, experiment==expt, variable==var),
                   aes(x=year, y=value, color=PC1, linetype=PC2)) +
                geom_line(size=0.75) +
                geom_errorbar(data=get_gates(expt, var), aes(x=year, ymin=mina, ymax=maxb), 
                              linetype=2, color='lightgrey', inherit.aes = FALSE, width=1) +
                facet_grid(PC3~PC4) + 
                ggtitle(paste('Experiment:', expt)) + ylab(yl) +
                theme_solarized_2(light=FALSE, base_size = 18) + 
                scale_color_solarized()
        )
    }
}

The effects of the various components are a little harder to tease out here, partly because we have two variables to look at now, and partly because we don’t have the lower emissions scenarios to work with. It does look like PC1 and PC2 are felt mainly in the temperature, while PC3 and PC4 seem to affect both variables.

With just these four components constrained, we are actually getting pretty good agreement with the output gates. Looking at the table of principal component stats suggests that the ESMs will provide substantial constraints up through PC7, but for the reasons discussed above, it’s not clear how seriously we should take this with only three ESMs in the sample. Notice that for PC8 the ESMs span a very narrow range of coefficients. This seems almost certain to be an artifact of the small sample size. Therefore, I’m thinking our experimental range for the number of PCs to constrain in the emissions-driven runs should be 5-7.

It would be nice if we could come up with an objective formula for deciding the number of PCs to constrain in calibration. The cumulative variance fraction for the PCA doesn’t seem like a very good guide. I was thinking of something related to the variance in the ESM projections, but that doesn’t look very promising either. For now, the best answer seems to be to look at the output performance relative to the ESMs (as we’ve done above), but that analysis gets murky as we go to higher dimensions.

Evaluation of models that pass the gates in output space

What we want to determine here is, does the analysis in the PCA space miss any models that we would have deemed good when we looked at them in the output space? Stay tuned.

LS0tCnRpdGxlOiAiRXhwZXJpbWVudCAyOiBSZWxhdGlvbnNoaXAgYmV0d2VlbiBQQyBnYXRlcyBhbmQgb3V0cHV0IGdhdGVzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyBJbnRyb2R1Y3Rpb24KCldlIG5lZWQgdG8gZGVjaWRlIHdoZXRoZXIgb3VyICJnYXRlcyIgbWV0aG9kb2xvZ3kgc3RpbGwgbWFrZXMgc2Vuc2Ugd2hlbiBhcHBsaWVkIGluIHRoZQpwcmluY2lwYWwgY29tcG9uZW50cyAoUEMpIGNvb3JkaW5hdGUgc3lzdGVtLiAgSW4gdGhpcyBleHBlcmltZW50IHdlIGNvbXBhcmUgcnVucyBmaWx0ZXJlZApieSBvdXRwdXQgZ2F0ZXMgdG8gcnVucyBmaWx0ZXJlZCBieSBQQyBnYXRlcyB0byBzZWUgaG93IHdlbGwgdGhleSBjb3JyZXNwb25kLiAgCgojIyBTZXR1cAoKYGBge3Igc2V0dXB9CmxpYnJhcnkoJ2RwbHlyJywgd2Fybi5jb25mbGljdHMgPSBGQUxTRSkKbGlicmFyeSgnZ2dwbG90MicpCmxpYnJhcnkoJ2dndGhlbWVzJykKbGlicmFyeSgnZm9yZWFjaCcpCmxpYnJhcnkoJ2hlY3RvcmNhbCcpCgpgYGAKCiMjIEV2YWx1YXRpb24gb2YgbW9kZWxzIHRoYXQgcGFzcyB0aGUgZ2F0ZXMgaW4gdGhlIFBDIHNwYWNlCgojIyMgQ29uY2VudHJhdGlvbi1kcml2ZW4gcnVucwoKIyMjIyBDb21wYXJpc29uIG9mIEVTTSBhbmQgSGVjdG9yIFBDIHJhbmdlcwpGb3IgdGhlIGNvbmNlbnRyYXRpb24tZHJpdmVuIHJ1bnMgbW9zdCBvZiB0aGUgdmFyaWF0aW9uIGlzIGNhcnJpZWQgaW4gdGhlIGZpcnN0IHR3byBQQ3MuClRoZSBib3ggbWFya2VkIG91dCBieSB0aGUgRVNNcyBpbiB0aGlzIHR3by1kaW1lbnNpb25hbCBzcGFjZSBnaXZlcyBhIGZpcnN0IGFwcHJveGltYXRpb24gCnRvIG91ciBjYWxpYnJhdGlvbiByZWdpb24uICBIb3cgZG8gbW9kZWxzIGluIHRoaXMgcmVnaW9uIHBlcmZvcm0gcmVsYXRpdmUgdG8gb3VyIG9sZC1zdHlsZQpnYXRlcyBkZWZpbmVkIGluIHRoZSBtb2RlbCBvdXRwdXQgc3BhY2U/CgpBbHRob3VnaCBQQzEgYW5kIFBDMiBhY2NvdW50IGZvciBfbW9zdF8gb2YgdGhlIHZhcmlhdGlvbiBpbiB0aGUgaGVjdG9yIHJlc3VsdHMsIHRoZXJlIGlzIApzdGlsbCBfc29tZV8gdmFyaWF0aW9uIGluIHRoZSBvdGhlciBjb21wb25lbnRzLCBzbyB3ZSdsbCB0YWtlIGEgbG9vayBhdCBkaWZmZXJlbnQgbGV2ZWxzIApmb3IgUEMgMyBhbmQgNCBhcyB3ZWxsLgoKYGBge3IgaGVjdG9ycHJvan0KIyMgV2UgbmVlZCB0aGUgUEMgcHJvamVjdGlvbnMgZm9yIHRoZSBlbnNlbWJsZQpoZWN0b3JfcHJvaiA8LSBjb21wdXRlX3BjKGhlY3Rvcl9jb25jX2Vuc2VtYmxlLCBjKCdoaXN0b3JpY2FsJywncmNwMjYnLCdyY3A0NScsJ3JjcDYwJywncmNwODUnKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgJ3RhcycsIDIwMDY6MjEwMCwgMTg2MToyMDA1LCByZXR4PVRSVUUpJHgKIyMgRVNNIHByb2plY3Rpb25zIGFyZSBzdG9yZWQgYXMgcGFja2FnZSBkYXRhOiBjbWlwX2NvbmNfcGNwcm9qCmBgYAoKYGBge3IgZ2V0Y29lZnN9CiMjIFRhYmxlcyBvZiBtaW4sIG1heCwgbWVhbiB2YWx1ZXMgYnkgUEMsIGZvciBib3RoIHNldHMKbWF4cGMgPC0gMTAKZXNtX3BjX3N0YXRzIDwtIGdyb3VwX2J5KGNtaXBfY29uY19wY3Byb2osIFBDKSAlPiUgCiAgICBzdW1tYXJpc2UobWluPW1pbih2YWx1ZSksIG1heD1tYXgodmFsdWUpLCBtZWFuPW1lYW4odmFsdWUpLCBzZD1zZCh2YWx1ZSkpICU+JQogICAgZmlsdGVyKFBDIDw9IG1heHBjKQpzdGF0c19tYXRyaXggPC0gYXBwbHkoaGVjdG9yX3Byb2pbICwgMTptYXhwY10sIDIsIGZ1bmN0aW9uKHgpIHtjKG1pbih4KSwgbWF4KHgpLCBtZWFuKHgpLCBzZCh4KSl9KQpoZWN0b3JfcGNfc3RhdHMgPC0gZGF0YS5mcmFtZShQQz1zZXFfYWxvbmcoc3RhdHNfbWF0cml4WzEsXSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW49c3RhdHNfbWF0cml4WzEsXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4PXN0YXRzX21hdHJpeFsyLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW49c3RhdHNfbWF0cml4WzMsXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Q9c3RhdHNfbWF0cml4WzQsXSkKYmluZF9jb2xzKHNlbGVjdChlc21fcGNfc3RhdHMsIFBDLCBlc20ubWluPW1pbiwgZXNtLm1heD1tYXgsIGVzbS5tZWFuPW1lYW4sIGVzbS5zZD1zZCksCiAgICAgICAgICBzZWxlY3QoaGVjdG9yX3BjX3N0YXRzLCBoZWN0b3IubWluPW1pbiwgaGVjdG9yLm1heD1tYXgsIGhlY3Rvci5tZWFuPW1lYW4sIGhlY3Rvci5zZD1zZCkpCmBgYApUaGUgZmlyc3QgdGhpbmcgd2UgY2FuIHNlZSBmcm9tIHRoZXNlIHN0YXRpc3RpY3MgaXMgdGhhdCB0aG91Z2ggdGhlIEVTTQpzdGF0aXN0aWNzIGV4Y2x1ZGUgYSBsb3Qgb2YgdGhlIHJhbmdlIGNvdmVyZWQgYnkgdGhlIEhlY3RvciBlbnNlbWJsZSwgdGhlCmVuc2VtYmxlIGF2ZXJhZ2UgcGFzc2VzIGFsbCBvZiB0aGUgZ2F0ZXMgZm9yIHRoZSBmaXJzdCAxMCBQQ3MsIGV4Y2VwdCBmb3IgUEM3LAp3aGljaCBtYXJnaW5hbGx5IGV4Y2x1ZGVzIHplcm8uICBGb3IgUENzICRcZ2VxJCA5LCB0aGUgY29lZmZpY2llbnRzIG9mIGFsbCBvZgp0aGUgaGVjdG9yIGVuc2VtYmxlIG1lbWJlcnMgYXJlIGFsbCB2ZXJ5IGNsb3NlIHRvIHplcm8sIGluZGljYXRpbmcgdGhhdCBmb3IgdGhpcwplbnNlbWJsZSB0aGVyZSBpcyBfZGVmaW5pdGVseV8gbm8gdXNlZnVsIGNhbGlicmF0aW9uIHRvIGJlIGRvbmUgdXNpbmcgdGhvc2UKY29tcG9uZW50cyBiZWNhdXNlIGZvciBhbnkgc3VjaCB0ZXN0IGVpdGhlciB0aGUgZW5pdHJlIHBhcmFtZXRlciBzcGFjZSB3aWxsCnBhc3MsIG9yIHRoZSBlbnRpcmUgc3BhY2Ugd2lsbCBmYWlsLgoKV2UgYXJlIG5vdyBpbiBhIHBvc2l0aW9uIHRvIGV2YWx1YXRlIGhvdyB0aGUgam9pbnQgUEMxLVBDMiBnYXRlIGRlcHJvamVjdHMgaW50bwp0aGUgb3V0cHV0IHBsYW5lLiAgSGVyZSBpcyBhIGdyYXBoaWNhbCBkZXBpY3Rpb24gb2YgdGhlIGdhdGUsIHdpdGggdGhlIHBvc2l0aW9ucwpvZiB0aGUgRVNNcyBsYWJlbGVkLgpgYGB7ciBwY3BsYW5lfQplc21fcGNwbG90KGNtaXBfY29uY19wY3Byb2opICsgZ2VvbV9hYmxpbmUoc2xvcGU9LTAuNiwgaW50ZXJjZXB0PS0zLCBjb2xvcj0nbGlnaHRncmV5Jywgc2l6ZT0xLjUsIGFscGhhPTAuNSkKYGBgCk9uZSBub3RpY2VhYmxlIHRyZW5kIGlzIHRoYXQgYWx0aG91Z2ggdGhlc2UgZGltZW5zaW9ucyBhcmUgdW5jb3JyZWxhdGVkIGluIHRoZSAKSGVjdG9yIGVuc2VtYmxlLCB0aGUgRVNNcyBhcHBlYXIgdG8gY2x1c3RlciBhcm91bmQgYSBsaW5lIHdpdGggYSBzbG9wZSBvZiBhYm91dAokLTAuNiQuICBUaGUgc2FtcGxlIGhlcmUgaXMgdmVyeSBzbWFsbCwgc28gaXQncyBub3QgY2xlYXIgaG93IHNlcmlvdXNseSB3ZQpzaG91bGQgdGFrZSB0aGlzIHBvc3NpYmxlIHJlbGF0aW9uc2hpcC4gIElzIHRoZXJlIG5vIG1vZGVsIGFyb3VuZCAkKC03LjUsIC00KSQKYmVjYXVzZSB0aGF0IG1vZGVsIGlzIGV4Y2x1ZGVkIGJ5IHRoZSBFU01zJyBjYWxpYnJhdGlvbiBwcm9jZXNzLCBvciBiZWNhdXNlIApub2JvZHkgaGFwcGVucyB0byBoYXZlIHdyaXR0ZW4gdGhlIG1vZGVsIHdpdGggdGhhdCBiZWhhdmlvcj8gIFdlIGFyZSBub3QgaW4gYQpwb3NpdGlvbiB0byBhbnN3ZXIgdGhhdCBxdWVzdGlvbiByaWdodCBub3csIGJ1dCBpdCdzIHdvcnRoIGtlZXBpbmcgaW4gbWluZC4KCiMjIyMgRXZhbHVhdGluZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gUENzIGFuZCBvdXRwdXRzClRvIGdldCBhIHNlbnNlIG9mIHdoZXJlIHRoZSBwb2ludHMgaW4gdGhpcyBwbGFuZSBmYWxsIGluIG91dHB1dCBzcGFjZSwgd2Ugd2lsbApkZWZpbmUgbG93LCBtZWRpdW0sIGFuZCBoaWdoIGxldmVscyBmb3IgUEMxIGFuZCBQQzIsIGRlZmluZWQgYnkgdGhlIG1pbiwgbWVhbiwKYW5kIG1heCB2YWx1ZXMsIHJlc3BlY3RpdmVseSwgZm9yIHRoZSBFU00gcHJvamVjdGlvbnMuICBQQzEgbGV2ZWxzIHdpbGwgYmUgZGVwaWN0ZWQKYnkgY29sb3IgaW4gdGhlIHBsb3RzLCBhbmQgUEMyIGxldmVscyB3aWxsIGJlIGRlcGljdGVkIGJ5IGxpbmUgdHlwZS4gIFdlIHdpbGwgCmFsc28gZGVmaW5lIGxvdywgbWVkaXVtLCBhbmQgaGlnaCBsZXZlbHMgZm9yIFBDMyBhbmQgUEM0IHVzaW5nIHRoaXMgdGltZSB0aGUKbWluLCBtZWFuLCBhbmQgbWF4IGZvciB0aGUgSGVjdG9yIGVuc2VtYmxlLCByZWZsZWN0aW5nIHRoZSBmYWN0IHRoYXQgZm9yIG5vdyB3ZQphcmUgX25vdF8gcGxhbm5pbmcgdG8gZmlsdGVyIG9uIHRob3NlIFBDcy4gIFRoZSBQQzMgYW5kIFBDNCBsZXZlbHMgd2lsbCBiZSAKcHJlc2VudGVkIGluIGZhY2V0IHBsb3RzLiAgRmluYWxseSwgdGhlIHJlc3VsdHMgd2lsbCBiZSBicm9rZW4gb3V0IGJ5IGV4cGVyaW1lbnQsCndpdGggZWFjaCBleHBlcmltZW50IHByZXNlbnRlZCBhcyBhIHNlcGFyYXRlIGZhbWlseSBvZiBwbG90cy4KCmBgYHtyIGdhdGVwbG90cywgZmlnLmhlaWdodD02LjUsIGZpZy53aWR0aD05fQppZGNvbHMgPC0gYygnbWluJywnbWVhbicsJ21heCcpCmxldmVscyA8LSBjKCdsb3cnLCdtZWQnLCd6aGlnaCcpCnBjMWx2bHMgPC0gYXMuZGF0YS5mcmFtZShlc21fcGNfc3RhdHMpWzEsIGlkY29sc10KcGMybHZscyA8LSBhcy5kYXRhLmZyYW1lKGVzbV9wY19zdGF0cylbMiwgaWRjb2xzXQpwYzNsdmxzIDwtIGhlY3Rvcl9wY19zdGF0c1szLCBpZGNvbHNdCnBjNGx2bHMgPC0gaGVjdG9yX3BjX3N0YXRzWzQsIGlkY29sc10KCm5hbWVzKHBjMWx2bHMpIDwtIG5hbWVzKHBjMmx2bHMpIDwtIG5hbWVzKHBjM2x2bHMpIDwtIG5hbWVzKHBjNGx2bHMpIDwtIGxldmVscwoKIyMjIENyZWF0ZSB0aGUgdGFibGVzIGZvciBlYWNoIGNvbWJpbmF0aW9uIG9mIGxldmVscwpjbGltb3V0IDwtIAogICAgZm9yZWFjaChscGMxPWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICBmb3JlYWNoKGxwYzI9bGV2ZWxzLCAuY29tYmluZT1iaW5kX3Jvd3MpICVkbyUgewogICAgICAgICAgICBmb3JlYWNoKGxwYzM9bGV2ZWxzLCAuY29tYmluZT1iaW5kX3Jvd3MpICVkbyUgewogICAgICAgICAgICAgICAgZm9yZWFjaChscGM0PWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICAgICAgICAgICAgICBjb2VmIDwtIGMocGMxbHZsc1tbbHBjMV1dLCBwYzJsdmxzW1tscGMyXV0sIHBjM2x2bHNbW2xwYzNdXSwgcGM0bHZsc1tbbHBjNF1dKQogICAgICAgICAgICAgICAgICAgIHJlY29uc3RydWN0X2NsaW1hdGUoY29lZiwgcGNfY29uYywgNCkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIG11dGF0ZShQQzE9bHBjMSwgUEMyPWxwYzIsIFBDMz1scGMzLCBQQzQ9bHBjNCkKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KCiMjIE9yZGVyIHRoZSBsZXZlbHMgc28gdGhhdCB0aGV5IGFyZSBpbiBvcmRlciBpbiB0aGUgcGxvdHMKI2NsaW1vdXQgPC0gbXV0YXRlKGNsaW1vdXQsIAojICAgICAgICAgICAgICAgICAgUEMxID0gb3JkZXJlZChQQzEsIGxhYmVscz1sZXZlbHMpLAojICAgICAgICAgICAgICAgICAgUEMyID0gb3JkZXJlZChQQzIsIGxhYmVscz1sZXZlbHMpLAojICAgICAgICAgICAgICAgICAgUEMzID0gb3JkZXJlZChQQzMsIGxhYmVscz1sZXZlbHMpLAojICAgICAgICAgICAgICAgICAgUEM0ID0gb3JkZXJlZChQQzQsIGxhYmVscz1sZXZlbHMpKQoKIyMgR2V0IGEgZGF0YSBmcmFtZSBvZiBnYXRlcyBmb3IgYW4gZXhwZXJpbWVudApnZXRfZ2F0ZXMgPC0gZnVuY3Rpb24oZXhwdCwgdmFyLCBtaW55ZWFyPTE4NjEsIG1heHllYXI9MjEwMCkgewogICAgaWYoZ3JlcGwoJ1tIaF1pc3RvcmljYWwnLCBleHB0KSkgewogICAgICAgIG1heHllYXIgPC0gMjAwNQogICAgfQogICAgZWxzZSB7CiAgICAgICAgbWlueWVhciA8LSAyMDA2CiAgICB9CiAgICAKICAgIGV4cHRkYXRhIDwtIGZpbHRlcihlc21fY29tcGFyaXNvbiwgZXhwZXJpbWVudD09ZXhwdCwgdmFyaWFibGU9PXZhciwgCiAgICAgICAgICAgICAgICAgICAgICAgeWVhciA8PSBtYXh5ZWFyLCB5ZWFyID49IG1pbnllYXIpCiAgICB5cnMgPC0gYyhtaW4oZXhwdGRhdGEkeWVhciksCiAgICAgICAgICAgICBtYXgoZXhwdGRhdGEkeWVhcltleHB0ZGF0YSR5ZWFyIDw9IG1lZGlhbihleHB0ZGF0YSR5ZWFyKV0pLAogICAgICAgICAgICAgbWF4KGV4cHRkYXRhJHllYXIpKQogICAgZmlsdGVyKGV4cHRkYXRhLCB5ZWFyICVpbiUgeXJzKQp9Cgpmb3IoZXhwdCBpbiB1bmlxdWUoY2xpbW91dCRleHBlcmltZW50KSkgewogICAgcHJpbnQoCiAgICAgICAgZ2dwbG90KGRhdGE9ZmlsdGVyKGNsaW1vdXQsIGV4cGVyaW1lbnQ9PWV4cHQpLAogICAgICAgICAgICAgICBhZXMoeD15ZWFyLCB5PXZhbHVlLCBjb2xvcj1QQzEsIGxpbmV0eXBlPVBDMikpICsKICAgICAgICAgICAgZ2VvbV9saW5lKHNpemU9MC43NSkgKwogICAgICAgICAgICBnZW9tX2Vycm9yYmFyKGRhdGE9Z2V0X2dhdGVzKGV4cHQsICd0YXMnKSwgYWVzKHg9eWVhciwgeW1pbj1taW5hLCB5bWF4PW1heGIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0yLCBjb2xvcj0nbGlnaHRncmV5JywgaW5oZXJpdC5hZXMgPSBGQUxTRSwgd2lkdGg9MSkgKwogICAgICAgICAgICBmYWNldF9ncmlkKFBDM35QQzQpICsgCiAgICAgICAgICAgIGdndGl0bGUocGFzdGUoJ0V4cGVyaW1lbnQ6JywgZXhwdCkpICsgeWxhYignVGVtcGVyYXR1cmUnKSArCiAgICAgICAgICAgIHRoZW1lX3NvbGFyaXplZF8yKGxpZ2h0PUZBTFNFLCBiYXNlX3NpemUgPSAxOCkgKyAKICAgICAgICAgICAgc2NhbGVfY29sb3Jfc29sYXJpemVkKCkKICAgICkKfQpgYGAKCkxvb2tpbmcgYXQgdGhlIGRhdGEgdGhpcyB3YXkgbWFrZXMgaXQgYSBsb3QgbW9yZSBjbGVhciB3aGF0IGVhY2ggb2YgdGhlCmNvbXBvbmVudHMgaXMgZG9pbmcuICBGb3IgdGhlIGZ1dHVyZSBydW5zICh0aGUgYmVoYXZpb3IgZm9yIHRoZSBoaXN0b3JpY2FsIHJ1bnMKaXMgYSBiaXQgZGlmZmVyZW50KSwgUEMxIHNoaWZ0cyB0aGUgdGVtcGVyYXR1cmUgbmVhcmx5IHVuaWZvcm1seSB1cCBhbmQgZG93bgoobG9vaywgZm9yIGV4YW1wbGUsIGF0IHRoZSBzZXJpZXMgb2Ygc29saWQgbGluZXMgaW4gdGhlIHBsb3RzKS4gIE1lYW53aGlsZSwgUEMyCmFwcGVhcnMgdG8gY29udHJvbCB0aGUgYXZlcmFnZSBzbG9wZSBvZiB0aGUgdGVtcGVyYXR1cmUgY3VydmUgb3ZlciB0aW1lIChjb21wYXJlCnRoZSBzZXF1ZW5jZSBvZiBsaW5lcyBpbiBhbnkgc2luZ2xlIGNvbG9yKS4KClBDMyAoaG9yaXpvbnRhbCBmYWNldHMgaW4gdGhlIGdyaWQpIGFwcGVhcnMgdG8gY29udHJvbCB0aGUgdGVuZGVuY3kgb2YgdGhlCnRlbXBlcmF0dXJlIGN1cnZlIHRvIGJlbmQgZG93bndhcmQgaW4gdGhlIGxhdGUgMjFzdCBjZW50dXJ5LiAgQ29uc2lkZXIsIGZvcgpleGFtcGxlLCB0aGUgUkNQIDIuNiBleHBlcmltZW50LiBXaXRoIFBDMyBhdCB0aGUgX2hpZ2hfIGxldmVsIChyaWdodCBjb2x1bW4pLApub25lIG9mIHRoZXNlIHNjZW5hcmlvcyBzaG93IHRoZSBwZWFrIGFuZCBkZWNsaW5lIHRoYXQgd2Ugbm9ybWFsbHkgYXNzb2NpYXRlIAp3aXRoIFJDUCAyLjYuICBQQzMgYWxzbyBoYXMgYSBjbGVhciBlZmZlY3QgaW4gdGhlIGhpc3RvcmljYWwgZXhwZXJpbWVudCwgd2hlcmUKaXQgaXMgY2xlYXJseSByZWxhdGVkIHRvIHRoZSBzdHJlbmd0aCBvZiB0aGUgYWVyb3NvbCBlZmZlY3QuICAKClRoZSBlZmZlY3Qgb2YgUEM0ICh2ZXJ0aWNhbCBmYWNldHMpIGlzIGEgbGl0dGxlIGhhcmQgdG8gZGlzY2VybiBpbiB0aGUgZnV0dXJlCnJ1bnMuICBJdCBsb29rcyB0byBiZSBhIGxpdHRsZSBkdXBsaWNhdGl2ZSBvZiBQQzMsIGluZHVjaW5nIHNvbWUgZG93bndhcmQKY3VydmF0dXJlIGxhdGUgaW4gdGhlIGNlbnR1cnkuIEhvd2V2ZXIsIGluIHRoZSBoaXN0b3JpY2FsIHBlcmlvZCBQQzQgaXMgY2xlYXJseQppbmZsdWVuY2luZyB0aGUgYmVoYXZpb3IgaW4gdGhlIGVhcmx5IHBhcnQgb2YgdGhlIHJ1bi4gIFdpdGggUEM0IF9sb3dfLApzY2VuYXJpb3MgdGVuZCB0byBiZSBiZWxvdyBvciBhdCB0aGUgbG93IGVuZCBvZiB0aGUgMTkzMyBnYXRlLiAgV2l0aCBQQzQKX21lZGl1bV8sIGFsbCBzY2VuYXJpb3MgZ28gdGhyb3VnaCB0aGUgMTkzMyBnYXRlLCBpcnJlc3BlY3RpdmUgb2YgdGhlIG90aGVyIFBDCnZhbHVlcywgYW5kIHdpdGggUEM0IF9oaWdoXywgdGhlIHNjZW5hcmlvcyB0ZW5kIHRvIGJlIGhpZ2ggYXQgdGhlIDE5MzMgZ2F0ZS4KClRoZSBjb25jbHVzaW9uIGZyb20gYWxsIG9mIHRoaXMgaXMgdGhhdCBub3R3aXRoc3RhbmRpbmcgdGhlIHNtYWxsIGZyYWN0aW9uIG9mCnRoZSB0b3RhbCB2YXJpYW5jZSBhY2NvdW50ZWQgZm9yIGJ5IFBDMyBhbmQgUEM0LCBpZiB3ZSB3YW50IG91ciBQQyBtZXRob2RvbG9neQp0byBjb3JyZXNwb25kLCBhdCBsZWFzdCByb3VnaGx5LCB0byB0aGUgb3V0cHV0IGdhdGUgbWV0aG9kb2xvZ3ksIHRoZW4gd2UgYXJlIGdvaW5nCnRvIGhhdmUgdG8gY29uc3RyYWluIFBDMyBhbmQgUEM0IHVzaW5nIHRoZSBFU00gcmVzdWx0cy4KCklmIHdlIGNvbnN0cmFpbiBQQzMgYW5kIFBDNCB3aXRoIHRoZSBFU00gdmFsdWVzIGFuZCByZXJ1biB0aGUgZXhwZXJpbWVudCwgdGhlbiB3ZQpnZXQgdGhlIGZvbGxvd2luZy4KYGBge3IgZ2F0ZXBsb3RzLnBjMzQsIGZpZy5oZWlnaHQ9Ny41LCBmaWcud2lkdGg9OX0KcGMxbHZsc19wYzM0IDwtIGFzLmRhdGEuZnJhbWUoZXNtX3BjX3N0YXRzKVsxLCBpZGNvbHNdCnBjMmx2bHNfcGMzNCA8LSBhcy5kYXRhLmZyYW1lKGVzbV9wY19zdGF0cylbMiwgaWRjb2xzXQpwYzNsdmxzX3BjMzQgPC0gYXMuZGF0YS5mcmFtZShlc21fcGNfc3RhdHMpWzMsIGlkY29sc10KcGM0bHZsc19wYzM0IDwtIGFzLmRhdGEuZnJhbWUoZXNtX3BjX3N0YXRzKVs0LCBpZGNvbHNdCgpuYW1lcyhwYzFsdmxzX3BjMzQpIDwtIG5hbWVzKHBjMmx2bHNfcGMzNCkgPC0gCiAgICBuYW1lcyhwYzNsdmxzX3BjMzQpIDwtIG5hbWVzKHBjNGx2bHNfcGMzNCkgPC0gbGV2ZWxzCgojIyMgQ3JlYXRlIHRoZSB0YWJsZXMgZm9yIGVhY2ggY29tYmluYXRpb24gb2YgbGV2ZWxzCmNsaW1vdXRfcGMzNCA8LSAKICAgIGZvcmVhY2gobHBjMT1sZXZlbHMsIC5jb21iaW5lPWJpbmRfcm93cykgJWRvJSB7CiAgICAgICAgZm9yZWFjaChscGMyPWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICAgICAgZm9yZWFjaChscGMzPWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICAgICAgICAgIGZvcmVhY2gobHBjND1sZXZlbHMsIC5jb21iaW5lPWJpbmRfcm93cykgJWRvJSB7CiAgICAgICAgICAgICAgICAgICAgY29lZiA8LSBjKHBjMWx2bHNfcGMzNFtbbHBjMV1dLCBwYzJsdmxzX3BjMzRbW2xwYzJdXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBjM2x2bHNfcGMzNFtbbHBjM11dLCBwYzRsdmxzX3BjMzRbW2xwYzRdXSkKICAgICAgICAgICAgICAgICAgICByZWNvbnN0cnVjdF9jbGltYXRlKGNvZWYsIHBjX2NvbmMsIDQpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoUEMxPWxwYzEsIFBDMj1scGMyLCBQQzM9bHBjMywgUEM0PWxwYzQpCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cgpmb3IoZXhwdCBpbiB1bmlxdWUoY2xpbW91dF9wYzM0JGV4cGVyaW1lbnQpKSB7CiAgICBwcmludCgKICAgICAgICBnZ3Bsb3QoZGF0YT1maWx0ZXIoY2xpbW91dF9wYzM0LCBleHBlcmltZW50PT1leHB0KSwKICAgICAgICAgICAgICAgYWVzKHg9eWVhciwgeT12YWx1ZSwgY29sb3I9UEMxLCBsaW5ldHlwZT1QQzIpKSArCiAgICAgICAgICAgIGdlb21fbGluZShzaXplPTAuNzUpICsKICAgICAgICAgICAgZ2VvbV9lcnJvcmJhcihkYXRhPWdldF9nYXRlcyhleHB0LCAndGFzJyksIGFlcyh4PXllYXIsIHltaW49bWluYSwgeW1heD1tYXhiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGU9MiwgY29sb3I9J2xpZ2h0Z3JleScsIGluaGVyaXQuYWVzID0gRkFMU0UsIHdpZHRoPTEpICsKICAgICAgICAgICAgZmFjZXRfZ3JpZChQQzN+UEM0KSArIAogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlKCdFeHBlcmltZW50OicsIGV4cHQpKSArIHlsYWIoJ1RlbXBlcmF0dXJlJykgKwogICAgICAgICAgICB0aGVtZV9zb2xhcml6ZWRfMihsaWdodD1GQUxTRSwgYmFzZV9zaXplID0gMTgpICsgCiAgICAgICAgICAgIHNjYWxlX2NvbG9yX3NvbGFyaXplZCgpCiAgICApCn0KCmBgYApOb3Qgc3VycHJpc2luZ2x5LCB0aGVzZSBjb25zdHJhaW50cyBwdXQgbW9zdCBvZiB0aGUgc2NlbmFyaW9zIGEgbG90IGNsb3NlciB0byB0aGUKb3V0cHV0IGdhdGVzLiAgV2UncmUgc3RpbGwgbWlzc2luZyBzb21ldGltZXMsIGJ1dCBhdCB0aGlzIHBvaW50IG9uZSBzdGFydHMgdG8gd29uZGVyLApob3cgZmlybSBhcmUgdGhlc2UgZ2F0ZXMuICBXZSBkb24ndCBoYXZlIF90aGF0XyBtYW55IEVTTXMsIGFuZCBzbyBpdCdzIG5vdCB0b28gaGFyZAp0byBiZWxpZXZlIHRoYXQgc2NlbmFyaW9zIGEgbGl0dGxlIG91dHNpZGUgb2YgdGhlIGdhdGVzIGFyZSBzdGlsbCByZWFzb25hYmxlLiAgVGhlCm9ubHkgY2FzZXMgdGhhdCBhcmUgYSBsaXR0bGUgY29uY2VybmluZyBhcmUgdGhlIFJDUCA4LjUgc2NlbmFyaW9zIGZvciB0aGUgCihfbG93Xy9fbWVkXywgX2hpZ2hfLCBfYW55XywgX2xvd18pIGNvbWJpbmF0aW9ucy4gIFNvbWUgb2YgdGhvc2Ugc2NlbmFyaW9zIGFyZSAKJDEuNV57XGNpcmN9QyQgYmVsb3cgdGhlIGxvd2VyIGVkZ2Ugb2YgdGhlIDIxMDAgZ2F0ZSwgd2hpY2ggc2VlbXMgYSBsaXR0bGUgbXVjaCB0byBtZS4KCk5vdGUgdGhhdCBmb3IgYWxsIG9mIHRoZXNlIHNjZW5hcmlvcywgdGhlIHByb2plY3Rpb24gb250byBQQzUgaXMgcGVnZ2VkIGF0IHplcm8sIHdoaWNoCmlzIHdpdGhpbiB0aGUgRVNNIGNvbnN0cmFpbnRzLCBzbyBjb25zdHJhaW5pbmcgdGhhdCBwYXJhbWV0ZXIgd29uJ3QgYWZmZWN0IGFueXRoaW5nIGluCnRoZXNlIHBsb3RzLiAgSG93ZXZlciwgd2UgbWlnaHQgd2VsbCB3b25kZXIgd2hhdCBoYXBwZW5zIHRvIHRoZXNlIHJlc3VsdHMgaWYgUEM1IGlzIG5lYXIKdGhlIGhpZ2ggb3IgbG93IGVuZCBvZiBpdHMgcmFuZ2UuICBBdCB0aGUgcmlzayBvZiBpbmR1Y2luZyBwbG90IG92ZXJsb2FkLCBoZXJlIGlzIHRoZSAKc2FtZSBzZXQgd2l0aCBQQzUgbG93LgoKYGBge3IgZ2F0ZXBsb3RzLnBjNWxvLCBmaWcuaGVpZ2h0PTcuNSwgZmlnLndpZHRoPTl9CiMjIyAtMi43NiBpcyB0aGUgbG93IHZhbHVlIGZvciBQQzUgKGZyb20gdGhlIHRhYmxlIGFib3ZlKQpjbGltb3V0X3BjNWxvIDwtIAogICAgZm9yZWFjaChscGMxPWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICBmb3JlYWNoKGxwYzI9bGV2ZWxzLCAuY29tYmluZT1iaW5kX3Jvd3MpICVkbyUgewogICAgICAgICAgICBmb3JlYWNoKGxwYzM9bGV2ZWxzLCAuY29tYmluZT1iaW5kX3Jvd3MpICVkbyUgewogICAgICAgICAgICAgICAgZm9yZWFjaChscGM0PWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICAgICAgICAgICAgICBjb2VmIDwtIGMocGMxbHZsc19wYzM0W1tscGMxXV0sIHBjMmx2bHNfcGMzNFtbbHBjMl1dLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGMzbHZsc19wYzM0W1tscGMzXV0sIHBjNGx2bHNfcGMzNFtbbHBjNF1dLCAtMi43NikKICAgICAgICAgICAgICAgICAgICByZWNvbnN0cnVjdF9jbGltYXRlKGNvZWYsIHBjX2NvbmMsIDUpICU+JQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoUEMxPWxwYzEsIFBDMj1scGMyLCBQQzM9bHBjMywgUEM0PWxwYzQpCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9Cgpmb3IoZXhwdCBpbiB1bmlxdWUoY2xpbW91dF9wYzVsbyRleHBlcmltZW50KSkgewogICAgcHJpbnQoCiAgICAgICAgZ2dwbG90KGRhdGE9ZmlsdGVyKGNsaW1vdXRfcGM1bG8sIGV4cGVyaW1lbnQ9PWV4cHQpLAogICAgICAgICAgICAgICBhZXMoeD15ZWFyLCB5PXZhbHVlLCBjb2xvcj1QQzEsIGxpbmV0eXBlPVBDMikpICsKICAgICAgICAgICAgZ2VvbV9saW5lKHNpemU9MC43NSkgKwogICAgICAgICAgICBnZW9tX2Vycm9yYmFyKGRhdGE9Z2V0X2dhdGVzKGV4cHQsICd0YXMnKSwgYWVzKHg9eWVhciwgeW1pbj1taW5hLCB5bWF4PW1heGIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0yLCBjb2xvcj0nbGlnaHRncmV5JywgaW5oZXJpdC5hZXMgPSBGQUxTRSwgd2lkdGg9MSkgKwogICAgICAgICAgICBmYWNldF9ncmlkKFBDM35QQzQpICsgCiAgICAgICAgICAgIGdndGl0bGUocGFzdGUoJ0V4cGVyaW1lbnQ6JywgZXhwdCkpICsgeWxhYignVGVtcGVyYXR1cmUnKSArCiAgICAgICAgICAgIHRoZW1lX3NvbGFyaXplZF8yKGxpZ2h0PUZBTFNFLCBiYXNlX3NpemUgPSAxOCkgKyAKICAgICAgICAgICAgc2NhbGVfY29sb3Jfc29sYXJpemVkKCkKICAgICkKfQoKYGBgClNvbWUgb2YgdGhlc2UgYXJlIHdheSBvdXRzaWRlIHRoZSBnYXRlczsgdGhlIFJDUCAyLjYgc2NlbmFyaW9zLCBlc3BlY2lhbGx5LCBhcmUgX3ZlcnlfIGhpZ2ggCmF0IHRoZSAyMTAwIGdhdGUuCgoKYGBge3IgZ2F0ZXBsb3RzLnBjNWhpLCBmaWcuaGVpZ2h0PTcuNSwgZmlnLndpZHRoPTl9CiMjIyAwLjM4MiBpcyB0aGUgaGlnaCB2YWx1ZSBmb3IgUEM1IChmcm9tIHRoZSB0YWJsZSBhYm92ZSkKY2xpbW91dF9wYzVoaSA8LSAKICAgIGZvcmVhY2gobHBjMT1sZXZlbHMsIC5jb21iaW5lPWJpbmRfcm93cykgJWRvJSB7CiAgICAgICAgZm9yZWFjaChscGMyPWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICAgICAgZm9yZWFjaChscGMzPWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICAgICAgICAgIGZvcmVhY2gobHBjND1sZXZlbHMsIC5jb21iaW5lPWJpbmRfcm93cykgJWRvJSB7CiAgICAgICAgICAgICAgICAgICAgY29lZiA8LSBjKHBjMWx2bHNfcGMzNFtbbHBjMV1dLCBwYzJsdmxzX3BjMzRbW2xwYzJdXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBjM2x2bHNfcGMzNFtbbHBjM11dLCBwYzRsdmxzX3BjMzRbW2xwYzRdXSwgMC4zODIpCiAgICAgICAgICAgICAgICAgICAgcmVjb25zdHJ1Y3RfY2xpbWF0ZShjb2VmLCBwY19jb25jLCA1KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKFBDMT1scGMxLCBQQzI9bHBjMiwgUEMzPWxwYzMsIFBDND1scGM0KQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKZm9yKGV4cHQgaW4gdW5pcXVlKGNsaW1vdXRfcGM1aGkkZXhwZXJpbWVudCkpIHsKICAgIHByaW50KAogICAgICAgIGdncGxvdChkYXRhPWZpbHRlcihjbGltb3V0X3BjNWhpLCBleHBlcmltZW50PT1leHB0KSwKICAgICAgICAgICAgICAgYWVzKHg9eWVhciwgeT12YWx1ZSwgY29sb3I9UEMxLCBsaW5ldHlwZT1QQzIpKSArCiAgICAgICAgICAgIGdlb21fbGluZShzaXplPTAuNzUpICsKICAgICAgICAgICAgZ2VvbV9lcnJvcmJhcihkYXRhPWdldF9nYXRlcyhleHB0LCAndGFzJyksIGFlcyh4PXllYXIsIHltaW49bWluYSwgeW1heD1tYXhiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGluZXR5cGU9MiwgY29sb3I9J2xpZ2h0Z3JleScsIGluaGVyaXQuYWVzID0gRkFMU0UsIHdpZHRoPTEpICsKICAgICAgICAgICAgZmFjZXRfZ3JpZChQQzN+UEM0KSArIAogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlKCdFeHBlcmltZW50OicsIGV4cHQpKSArIHlsYWIoJ1RlbXBlcmF0dXJlJykgKwogICAgICAgICAgICB0aGVtZV9zb2xhcml6ZWRfMihsaWdodD1GQUxTRSwgYmFzZV9zaXplID0gMTgpICsgCiAgICAgICAgICAgIHNjYWxlX2NvbG9yX3NvbGFyaXplZCgpCiAgICApCn0KCmBgYApUaGVzZSBhY3R1YWxseSBkb24ndCBsb29rIHRvbyBiYWQuICBIb3dldmVyLCBnaXZlbiB0aGUgcG9vciBwZXJmb3JtYW5jZSBhdCB0aGUgbG93IGVuZCwgaXQncwpwcmV0dHkgY2xlYXIgdGhhdCB3ZSB3aWxsIG5lZWQgdG8gY29uc3RyYWluIFBDNS4KCldlIGNvdWxkIGNvbnRpbnVlIHRoaXMgbGluZSBvZiBhbmFseXNpcywgYnV0IGlmIHdlIGxvb2sgYXQgdGhlIHJhbmdlIGZvciBQQzYsIHRoZSBFU00gbWF4aW11bQpkb2Vzbid0IGNvbnN0cmFpbiB0aGUgZW5zZW1ibGUgYXQgYWxsIGJlY2F1c2UgdGhlIGVuc2VtYmxlIG1heGltdW0gaXMgYWN0dWFsbHkgbG93ZXIgdGhhbiB0aGUKRVNNIG1heGltdW0uICBUaGVyZSBpcyBzb21lIGNvbnN0cmFpbnQgYXQgdGhlIGxvdyBlbmQsIGJ1dCBpdCdzIGEgbXVjaCB3ZWFrZXIgY29uc3RyYWludCB0aGFuCndlIHNlZSBmb3IgUEM1LCBzbyBJJ20gcHJldHR5IGNvbmZpZGVudCB0aGF0IGNvbnN0cmFpbmluZyBQQzYgd29uJ3QgbWFrZSBtdWNoIGRpZmZlcmVuY2UuICBOb3RlCmFsc28gdGhhdCBmb3IgUENzIDgtMTAgdGhlIEVTTSByYW5nZSBpbmNsdWRlcyB0aGUgZW50aXJlIGVuc2VtYmxlIHJhbmdlLCBzbyBjb25zdHJhaW5pbmcgdGhlc2UKY29tcG9uZW50cyBfZGVmaW5pdGVseV8gd29uJ3QgaGF2ZSBhbnkgZWZmZWN0LiAgVGhlcmVmb3JlLCB3ZSB3aWxsIHByb2JhYmx5IGVuZCB1cCBydW5uaW5nIApNQ01DIHJ1bnMgd2l0aCBjb25zdHJhaW50cyBvbiBQQzEtNSwgMS02LCBhbmQgMS03LCBhbmQgd2UnbGwgY29tcGFyZSB0aGUgcGFyYW1ldGVyIGRpc3RyaWJ1dGlvbnMKdGhhdCB3ZSBnZXQgZnJvbSB0aGVzZSB0byBzZWUgaWYgdGhlcmUgaXMgYW55IHNpZ25pZmljYW50IGRpZmZlcmVuY2UuCgojIyMgRW1pc3Npb25zLWRyaXZlbiBydW5zCgojIyMjIFJlbGlhYmlsaXR5IG9mIHRoZSBzbWFsbCBjb25jZW50cmF0aW9uLWRyaXZlbiBFU00gc2FtcGxlCkhlcmUgd2UgZ28gYWdhaW4uICBNeSBtYWluIGNvbmNlcm4gaGVyZSBpcyB0aGF0IHdpdGggb25seSB0aHJlZSB2YWxpZCBtb2RlbHMgdG8gdXNlIGluIHRoZSAKY2FsaWJyYXRpb24sIHRoZSBzdGF0aXN0aWNzIGZvciBvdXIgY2FsaWJyYXRpb24gZGF0YSBtYXkgYmUgbm90IGJlIHZlcnkgZ29vZC4gIEluIHBhcnRpY3VsYXIKd2UgY291bGQgYmUgc2VlaW5nIGdhdGVzIHRoYXQgYXJlIHdheSB0b28gbmFycm93IGlmIHRoZSBtb2RlbHMgdGhhdCB3ZSBoYXBwZW4gdG8gaGF2ZSBhdmFpbGFibGUKdG8gdXMgYXJlbid0IG5lYXIgdGhlIGVkZ2VzIG9mIHRoZSB0cnVlIGRpc3RyaWJ1dGlvbiBvZiBtb2RlbCBvdXRjb21lcy4gIFdlIGNhbiBnZXQgc29tZSBpZGVhCm9mIHRoZSBleHRlbnQgdG8gd2hpY2ggdGhpcyBoYXBwZW5zIGJ5IGNvbXBhcmluZyB0aGUgdGVtcGVyYXR1cmUgb3V0cHV0IGdhdGVzIGluIHRoZSBoaXN0b3JpY2FsIAphbmQgUkNQIDguNSBleHBlcmltZW50cyBmb3IgdGhlIGNvbmNlbnRyYXRpb24gYW5kIGVtaXNzaW9ucyBkcml2ZW4gRVNNIHJ1bnMuCmBgYHtyIGdhdGVjbXB9CmJpbmRfcm93cygKICAgIGdldF9nYXRlcygnaGlzdG9yaWNhbCcsICd0YXMnKSwKICAgIGdldF9nYXRlcygnZXNtSGlzdG9yaWNhbCcsICd0YXMnKSkKYmluZF9yb3dzKAogICAgZ2V0X2dhdGVzKCdyY3A4NScsICd0YXMnKSwKICAgIGdldF9nYXRlcygnZXNtcmNwODUnLCAndGFzJykpCmBgYApJdCBsb29rcyBhcyBpZiB0aGUgZ2F0ZXMgZm9yIHRoZSBlbWlzc2lvbnMtZHJpdmVuIHJ1bnMgYXJlIGF0IHRoZWlyIG1vc3QgcmVzdHJpY3RpdmUgd2hlbgp3ZSdyZSBjbG9zZSB0byB0aGUgaGlzdG9yaWNhbC1mdXR1cmUgY2hhbmdlIG92ZXIuICBUaGUgZ2F0ZXMgZm9yIHRoZSAxODYxIGFuZCAyMTAwIGRvbid0IApsb29rIG11Y2ggc21hbGxlciB0aGFuIHRoZWlyIGNvbmNlbnRyYXRpb24tZHJpdmVuIGNvdW50ZXJwYXJ0cy4gIEhvd2V2ZXIsIHdlIHdvdWxkIGV4cGVjdAp0aGUgZW1pc3Npb25zLWRyaXZlbiBydW5zIHRvIHNob3cgYSBfZ3JlYXRlcl8gZGlzcGVyc2lvbiBpbiBvdXRjb21lcyB0aGFuIHRoZSBjb25jZW50cmF0aW9uLQpkcml2ZW4gcnVucywgc2luY2UgdGhleSBoYXZlIG1vcmUgZGltZW5zaW9ucyBhbG9uZyB3aGljaCB0aGV5IGNhbiBiZSBkaWZmZXJlbnQgZnJvbSBvbmUgYW5vdGhlci4KVGhhdCB3ZSBkb24ndCBzZWUgdGhhdCBhZGRpdGlvbmFsIGRpc3BlcnNpb24gaW5kaWNhdGVzIHRoYXQgb3VyIGdhdGVzIGluIHRoZSBlbWlzc2lvbi1kcml2ZW4gCnJ1bnMgcHJvYmFibHkgYXJlIG5hcnJvd2VyIHRoYW4gdGhleSBzaG91bGQgYmUuCgpJIGFtIHRoaW5raW5nIHRoYXQgd2hlbiB3ZSBnbyB0byBkbyB0aGUgY2FsaWJyYXRpb24gd2Ugd2lsbCBuZWVkIHRvIGNvcnJlY3QgZm9yIHRoaXMgYnkKd2lkZW5pbmcgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24uICBXZSBjYW4gZG8gdGhpcyBlaXRoZXIgYnkgaW5jcmVhc2luZyB0aGUgd2lkdGggb2YgdGhlIApnYXRlcywgb3IgYnkgaW5jcmVhc2luZyB0aGUgc21vb3RoaW5nIHBhcmFtZXRlci4gIEkgaGF2ZW4ndCB5ZXQgZGVjaWRlZCB3aGljaCB3YXkgaXMgYmV0dGVyLApidXQgSSBhbSBsZWFuaW5nIHRvd2FyZCB1c2luZyB0aGUgc21vb3RoaW5nIHBhcmFtZXRlciwgc2luY2UgaXQgYmV0dGVyIGV4cHJlc3NlcyB0aGUgaWRlYQp0aGF0IHdlIGhhdmUgc29mdGVuZWQgdGhlIGVkZ2Ugb2YgdGhlIGdhdGUgYmVjYXVzZSB3ZSBkb24ndCByZWFsbHkga25vdyB3aGVyZSB0aGF0IGVkZ2UgCmlzLiAgSG93IGRvIHdlIGtub3cgaG93IG11Y2ggdG8gc29mdGVuIHRoZSBnYXRlcz8gIEhlcmUgd2UgY2FuIHRha2UgYWR2YW50YWdlIG9mIHRoZQpiZXR0ZXIgc2FtcGxpbmcgb2YgdGhlIGNvbmNlbnRyYXRpb24tZHJpdmVuIG1vZGVsIHNwYWNlLiAgSWYgd2UgdGFrZSB0aGUgbWFyZ2luYWwgdmFyaWFuY2UKb2YgdGhlIHRlbXBlcmF0dXJlIHBhcmFtZXRlcnMgYXMgYmVpbmcgcmVsYXRpdmVseSByZWxpYWJseSBkZXRlcm1pbmVkIGJ5IHRoZSBjb25jZW50cmF0aW9uLQpkcml2ZW4gTUNNQywgdGhlbiB3ZSBjYW4gYWRqdXN0IHRoZSBzb2Z0ZW5pbmcgaW4gdGhlIGVtaXNzaW9ucy1kcml2ZW4gTUNNQyB1bnRpbCB0aGUgCm1hcmdpbmFsIHZhcmlhbmNlcyBvZiB0aGUgdGVtcGVyYXR1cmUgcGFyYW1ldGVycyBhcmUgcmVhc29uYWJseSBjbG9zZSB0byB0aGUgdmFsdWVzIGZyb20gCnRoZSBjb25jZW50cmF0aW9uLWRyaXZlbiBNQ01DLgoKIyMjIyBDb21wYXJpc29uIG9mIEhlY3RvciBhbmQgRVNNIFBDIHJhbmdlcwoKYGBge3IgaGVjdG9ycHJvai5lc219CiMjIFdlIG5lZWQgdGhlIFBDIHByb2plY3Rpb25zIGZvciB0aGUgZW5zZW1ibGUKaGVjdG9yX2VtaXNzX3Byb2ogPC0gY29tcHV0ZV9wYyhoZWN0b3JfZW1pc3NfZW5zZW1ibGUsIGMoJ2VzbUhpc3RvcmljYWwnLCdlc21yY3A4NScpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCd0YXMnLCAnY28yJyksIDIwMDY6MjEwMCwgMTg2MToyMDA1LCByZXR4PVRSVUUpJHgKYGBgCgpgYGB7ciBnZXRjb2Vmcy5lc219CiMjIFRhYmxlcyBvZiBtaW4sIG1heCwgbWVhbiB2YWx1ZXMgYnkgUEMsIGZvciBib3RoIHNldHMKbWF4cGMgPC0gMjAKZXNtX2VtaXNzX3BjX3N0YXRzIDwtIGdyb3VwX2J5KGNtaXBfZW1pc3NfcGNwcm9qLCBQQykgJT4lIAogICAgc3VtbWFyaXNlKG1pbj1taW4odmFsdWUpLCBtYXg9bWF4KHZhbHVlKSwgbWVhbj1tZWFuKHZhbHVlKSwgc2Q9c2QodmFsdWUpKSAlPiUKICAgIGZpbHRlcihQQyA8PSBtYXhwYykKc3RhdHNfbWF0cml4IDwtIGFwcGx5KGhlY3Rvcl9lbWlzc19wcm9qWyAsIDE6bWF4cGNdLCAyLCBmdW5jdGlvbih4KSB7YyhtaW4oeCksIG1heCh4KSwgbWVhbih4KSwgc2QoeCkpfSkKaGVjdG9yX2VtaXNzX3BjX3N0YXRzIDwtIGRhdGEuZnJhbWUoUEM9c2VxX2Fsb25nKHN0YXRzX21hdHJpeFsxLF0pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWluPXN0YXRzX21hdHJpeFsxLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heD1zdGF0c19tYXRyaXhbMixdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuPXN0YXRzX21hdHJpeFszLF0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkPXN0YXRzX21hdHJpeFs0LF0pCmJpbmRfY29scyhzZWxlY3QoZXNtX2VtaXNzX3BjX3N0YXRzLCBQQywgZXNtLm1pbj1taW4sIGVzbS5tYXg9bWF4LCBlc20ubWVhbj1tZWFuLCBlc20uc2Q9c2QpLAogICAgICAgICAgc2VsZWN0KGhlY3Rvcl9lbWlzc19wY19zdGF0cywgaGVjdG9yLm1pbj1taW4sIGhlY3Rvci5tYXg9bWF4LCBoZWN0b3IubWVhbj1tZWFuLCBoZWN0b3Iuc2Q9c2QpKQpgYGAKCgpCZXR3ZWVuIHRoZSB2YXJpYW5jZSBmcmFjdGlvbiBhbmFseXNpcywgdGhlIHJlc3VsdHMgZnJvbSB0aGUgY29uY2VudHJhdGlvbi1kcml2ZW4gcnVucywgYW5kIHRoZSB0YWJsZSBhYm92ZQppdCBzZWVtcyBsaWtlbHkgdGhhdCB3ZSBhcmUgZ29pbmcgdG8gbmVlZCB0byBjb25zdHJhaW4gYXQgbGVhc3QgdGhlIGZpcnN0IDQgUENzLCBzbyBJJ3ZlIGRpc3BlbnNlZCB3aXRoIHRoZSB2ZXJzaW9uCm9mIHRoZSBwbG90IHdoZXJlIFBDMyBhbmQgUEM0IGFyZSB1bmNvbnN0cmFpbmVkLgpgYGB7ciBnYXRlcGxvdHMuZXNtLCBmaWcuaGVpZ2h0PTcuNSwgZmlnLndpZHRoPTEwfQpwYzFsdmxzX2VtaXNzIDwtIGFzLmRhdGEuZnJhbWUoZXNtX2VtaXNzX3BjX3N0YXRzKVsxLCBpZGNvbHNdCnBjMmx2bHNfZW1pc3MgPC0gYXMuZGF0YS5mcmFtZShlc21fZW1pc3NfcGNfc3RhdHMpWzIsIGlkY29sc10KcGMzbHZsc19lbWlzcyA8LSBhcy5kYXRhLmZyYW1lKGVzbV9lbWlzc19wY19zdGF0cylbMywgaWRjb2xzXQpwYzRsdmxzX2VtaXNzIDwtIGFzLmRhdGEuZnJhbWUoZXNtX2VtaXNzX3BjX3N0YXRzKVs0LCBpZGNvbHNdCgpuYW1lcyhwYzFsdmxzX2VtaXNzKSA8LSBuYW1lcyhwYzJsdmxzX2VtaXNzKSA8LSAKICAgIG5hbWVzKHBjM2x2bHNfZW1pc3MpIDwtIG5hbWVzKHBjNGx2bHNfZW1pc3MpIDwtIGxldmVscwoKIyMjIENyZWF0ZSB0aGUgdGFibGVzIGZvciBlYWNoIGNvbWJpbmF0aW9uIG9mIGxldmVscwpjbGltb3V0X2VtaXNzIDwtIAogICAgZm9yZWFjaChscGMxPWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICBmb3JlYWNoKGxwYzI9bGV2ZWxzLCAuY29tYmluZT1iaW5kX3Jvd3MpICVkbyUgewogICAgICAgICAgICBmb3JlYWNoKGxwYzM9bGV2ZWxzLCAuY29tYmluZT1iaW5kX3Jvd3MpICVkbyUgewogICAgICAgICAgICAgICAgZm9yZWFjaChscGM0PWxldmVscywgLmNvbWJpbmU9YmluZF9yb3dzKSAlZG8lIHsKICAgICAgICAgICAgICAgICAgICBjb2VmIDwtIGMocGMxbHZsc19lbWlzc1tbbHBjMV1dLCBwYzJsdmxzX2VtaXNzW1tscGMyXV0sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYzNsdmxzX2VtaXNzW1tscGMzXV0sIHBjNGx2bHNfZW1pc3NbW2xwYzRdXSkKICAgICAgICAgICAgICAgICAgICByZWNvbnN0cnVjdF9jbGltYXRlKGNvZWYsIHBjX2VtaXNzLCA0KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKFBDMT1scGMxLCBQQzI9bHBjMiwgUEMzPWxwYzMsIFBDND1scGM0KQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKCmZvcihleHB0IGluIHVuaXF1ZShjbGltb3V0X2VtaXNzJGV4cGVyaW1lbnQpKSB7CiAgICBmb3IodmFyIGluIHVuaXF1ZShjbGltb3V0X2VtaXNzJHZhcmlhYmxlKSkgewogICAgICAgIGlmKHZhcj09J3RhcycpIHsKICAgICAgICAgICAgeWwgPC0gJ1RlbXBlcmF0dXJlJwogICAgICAgIH0KICAgICAgICBlbHNlIHsKICAgICAgICAgICAgeWwgPC0gJ0NPMiBjb25jZW50cmF0aW9uJwogICAgICAgIH0KICAgICAgICBwcmludCgKICAgICAgICAgICAgZ2dwbG90KGRhdGE9ZmlsdGVyKGNsaW1vdXRfZW1pc3MsIGV4cGVyaW1lbnQ9PWV4cHQsIHZhcmlhYmxlPT12YXIpLAogICAgICAgICAgICAgICAgICAgYWVzKHg9eWVhciwgeT12YWx1ZSwgY29sb3I9UEMxLCBsaW5ldHlwZT1QQzIpKSArCiAgICAgICAgICAgICAgICBnZW9tX2xpbmUoc2l6ZT0wLjc1KSArCiAgICAgICAgICAgICAgICBnZW9tX2Vycm9yYmFyKGRhdGE9Z2V0X2dhdGVzKGV4cHQsIHZhciksIGFlcyh4PXllYXIsIHltaW49bWluYSwgeW1heD1tYXhiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPTIsIGNvbG9yPSdsaWdodGdyZXknLCBpbmhlcml0LmFlcyA9IEZBTFNFLCB3aWR0aD0xKSArCiAgICAgICAgICAgICAgICBmYWNldF9ncmlkKFBDM35QQzQpICsgCiAgICAgICAgICAgICAgICBnZ3RpdGxlKHBhc3RlKCdFeHBlcmltZW50OicsIGV4cHQpKSArIHlsYWIoeWwpICsKICAgICAgICAgICAgICAgIHRoZW1lX3NvbGFyaXplZF8yKGxpZ2h0PUZBTFNFLCBiYXNlX3NpemUgPSAxOCkgKyAKICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX3NvbGFyaXplZCgpCiAgICAgICAgKQogICAgfQp9CmBgYAoKVGhlIGVmZmVjdHMgb2YgdGhlIHZhcmlvdXMgY29tcG9uZW50cyBhcmUgYSBsaXR0bGUgaGFyZGVyIHRvIHRlYXNlIG91dCBoZXJlLCBwYXJ0bHkgYmVjYXVzZSB3ZQpoYXZlIHR3byB2YXJpYWJsZXMgdG8gbG9vayBhdCBub3csIGFuZCBwYXJ0bHkgYmVjYXVzZSB3ZSBkb24ndCBoYXZlIHRoZSBsb3dlciBlbWlzc2lvbnMgc2NlbmFyaW9zCnRvIHdvcmsgd2l0aC4gIEl0IGRvZXMgbG9vayBsaWtlIFBDMSBhbmQgUEMyIGFyZSBmZWx0IG1haW5seSBpbiB0aGUgdGVtcGVyYXR1cmUsIHdoaWxlIFBDMyBhbmQgUEM0CnNlZW0gdG8gYWZmZWN0IGJvdGggdmFyaWFibGVzLiAgCgpXaXRoIGp1c3QgdGhlc2UgZm91ciBjb21wb25lbnRzIGNvbnN0cmFpbmVkLCB3ZSBhcmUgYWN0dWFsbHkgZ2V0dGluZyBwcmV0dHkgZ29vZCBhZ3JlZW1lbnQgd2l0aCB0aGUKb3V0cHV0IGdhdGVzLiAgTG9va2luZyBhdCB0aGUgdGFibGUgb2YgcHJpbmNpcGFsIGNvbXBvbmVudCBzdGF0cyBzdWdnZXN0cyB0aGF0IHRoZSBFU01zIHdpbGwgcHJvdmlkZQpzdWJzdGFudGlhbCBjb25zdHJhaW50cyB1cCB0aHJvdWdoIFBDNywgYnV0IGZvciB0aGUgcmVhc29ucyBkaXNjdXNzZWQgYWJvdmUsIGl0J3Mgbm90IGNsZWFyIGhvdwpzZXJpb3VzbHkgd2Ugc2hvdWxkIHRha2UgdGhpcyB3aXRoIG9ubHkgdGhyZWUgRVNNcyBpbiB0aGUgc2FtcGxlLiAgTm90aWNlIHRoYXQgZm9yIFBDOCB0aGUgRVNNcwpzcGFuIGEgX3ZlcnlfIG5hcnJvdyByYW5nZSBvZiBjb2VmZmljaWVudHMuICBUaGlzIHNlZW1zIGFsbW9zdCBjZXJ0YWluIHRvIGJlIGFuIGFydGlmYWN0IG9mIHRoZSAKc21hbGwgc2FtcGxlIHNpemUuICBUaGVyZWZvcmUsIEknbSB0aGlua2luZyBvdXIgZXhwZXJpbWVudGFsIHJhbmdlIGZvciB0aGUgbnVtYmVyIG9mIFBDcyB0byBjb25zdHJhaW4KaW4gdGhlIGVtaXNzaW9ucy1kcml2ZW4gcnVucyBzaG91bGQgYmUgNS03LgoKSXQgd291bGQgYmUgbmljZSBpZiB3ZSBjb3VsZCBjb21lIHVwIHdpdGggYW4gb2JqZWN0aXZlIGZvcm11bGEgZm9yIGRlY2lkaW5nIHRoZSBudW1iZXIgb2YgUENzIHRvIApjb25zdHJhaW4gaW4gY2FsaWJyYXRpb24uICBUaGUgY3VtdWxhdGl2ZSB2YXJpYW5jZSBmcmFjdGlvbiBmb3IgdGhlIFBDQSBkb2Vzbid0IHNlZW0gbGlrZSBhIHZlcnkgCmdvb2QgZ3VpZGUuICBJIHdhcyB0aGlua2luZyBvZiBzb21ldGhpbmcgcmVsYXRlZCB0byB0aGUgdmFyaWFuY2UgaW4gdGhlIEVTTSBwcm9qZWN0aW9ucywgYnV0IHRoYXQKZG9lc24ndCBsb29rIHZlcnkgcHJvbWlzaW5nIGVpdGhlci4gIEZvciBub3csIHRoZSBiZXN0IGFuc3dlciBzZWVtcyB0byBiZSB0byBsb29rIGF0IHRoZSBvdXRwdXQgCnBlcmZvcm1hbmNlIHJlbGF0aXZlIHRvIHRoZSBFU01zIChhcyB3ZSd2ZSBkb25lIGFib3ZlKSwgYnV0IHRoYXQgYW5hbHlzaXMgZ2V0cyBtdXJreSBhcyB3ZSBnbyB0bwpoaWdoZXIgZGltZW5zaW9ucy4KCiMjIEV2YWx1YXRpb24gb2YgbW9kZWxzIHRoYXQgcGFzcyB0aGUgZ2F0ZXMgaW4gb3V0cHV0IHNwYWNlCgpXaGF0IHdlIHdhbnQgdG8gZGV0ZXJtaW5lIGhlcmUgaXMsIGRvZXMgdGhlIGFuYWx5c2lzIGluIHRoZSBQQ0Egc3BhY2UgX21pc3NfIGFueSBtb2RlbHMgdGhhdCB3ZQp3b3VsZCBoYXZlIGRlZW1lZCBnb29kIHdoZW4gd2UgbG9va2VkIGF0IHRoZW0gaW4gdGhlIG91dHB1dCBzcGFjZT8gIFN0YXkgdHVuZWQuCg==