Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Annual mortality, 1838-2020

path <- paste0(
  "https://www.ons.gov.uk/file?uri=/",
  "peoplepopulationandcommunity/",
  "birthsdeathsandmarriages/",
  "deaths/",
  "adhocs/",
  "12735annualdeathsandmortalityrates1938to2020provisional/"
)
file <- "2020annualprovisionaladhoc2.xls"
getFile(path,file)

These data are provided by the Office for National Statistics in response to a user request, reference 12735 [link]. Data are for England and Wales, combined. Total deaths and mortality rates are given from 1838; age-standardised mortality rates are given from 1942. Rates for 2020 were provisional at the time of publication. The data were originally published on 12 January 2021; an update was made on 8 March 2021 solely to correct some typographical errors in the supporting text, without affecting the data.

if (!file.exists(file)) {
  warning(paste("Couldn't find",file,"on disk"))
} else {
  message(paste("Reading",file,"from disk"))
  Annual <- read_excel(
    file,
    sheet="Table",
    col_types=c("text",
                "numeric",
                "numeric",
                "numeric",
                "numeric"
                ),
    col_names=c("date","deaths","population","raw","age standardised"),
    skip=15,
    na=":"
  )
  Annual$date <- dmy(paste("31 12",Annual$date))
  ggplot(melt(Annual,measure.vars = c('raw','age standardised'),variable.name = 'mortality'))+
    geom_step(aes(x=date,y=value,colour=mortality),direction="vh",na.rm=TRUE)+
    scale_x_date(date_labels="%Y")+
    scale_y_continuous("mortality /100,000",limits = c(0,NA))+
    labs(
      title = "Mortality by year of registration",
      subtitle = 'England and Wales',
      caption = acknowledgement
      )
}

Age-standardisation

knitr::kable(ESP2013[c('age','population')],caption = "European Standard Population 2013",padding = 1)
European Standard Population 2013
age population
<1 1000
1-4 4000
5-9 5500
10-14 5500
15-19 5500
20-24 6000
25-29 6000
30-34 6500
35-39 7000
40-44 7000
45-49 7000
50-54 7000
55-59 6500
60-64 6000
65-69 5500
70-74 5000
75-79 4000
80-84 2500
85-89 1500
90-94 800
95+ 200

Age-standardised mortality is standardised to the European Standard Population given by populations \(P_i\) (1000, 4000 etc.) for each of the age groups \(i\) (<1, 1-4 etc.) according to the following equation:

\[ a = \sum_i\frac{M_i}{N_i}P_i\] where the real number of people in age group \(i\) is \(N_i\) and the observed number of deaths in age group \(i\) is \(M_i\). The quantity \(M_i/N_i\) is the age-specific mortality for age group \(i\); when weighted by \(P_i\) and summed over \(i\) the result is the age-standardised mortality, \(a\) (as the \(P_i\) sum to 100,000, \(a\) is “per hundred thousand population”).

Except that it isn’t really “per hundred thousand population”, although it always seems to be expressed as such, by convention, because \(M_i\) is, implicitly, a rate - the number of people in age group \(i\) who die in a year. Where mortality is given at intervals other than a year this is, implicitly, a per annum rate. It’s a pity that the convention doesn’t make that clear. It would probably be better to describe, for example, an age-standardised mortality of 1000 as “1% p.a.” That’s what it means, although that seems not to be how it’s done.

If the population distribution matched the standard population, such that \(N_i/\sum_iN_i=P_i/\sum_iP_i\quad\forall i\), the age-standardised mortality would match the raw mortality:

\[r = \frac{\sum_iM_i\sum_iP_i}{\sum_iN_i}\] This is close to the current situation, because the current population of England and Wales is close to the 2013 European Standard Population. In contrast, if the population distribution were younger than the standard population the age-standardised mortality would exceed the actual mortality. This was the case in decades past; with advances in life expectancy and reductions in fertility the population has grown older having been younger before. This is why age-standardised mortality is useful as we can factor out the effect of an aging population on changes in mortality. Without it, mortality would appear to get worse, or not get better as fast as it really had, if advances in health care had led to increased life expectancy. This is most clearly visible in the data for the late 20th century: raw mortality was more or less constant even as the population aged - aging driven in part by advances in health care which led to reduced age-standardised mortality. It’s also visible in the 2010s: raw mortality increased slightly and that is explicable in terms of an aging population as is shown by the fact that age-standardised mortality was flat.

ONS also quote a “95% confidence interval” on age-standardised mortality, as a function of the total number of deaths, as follows:

\[ a = \left( 1 \pm \frac{1.96}{\sum_iM_i} \right)\sum_i\frac{M_i}{N_i}P_i \] This interval is not useful. It assumes that the only source of uncertainty is Poisson counting statistics on the total number of deaths. This is an underestimate because age-specific mortality is not a Poisson-distributed variable because death rates are inevitably not constant and perhaps also because counting intervals, being a variable number of days worked by registrars, etc., also vary, but the underestimate is probably not large. The resulting uncertainty estimates are very small, however - inevitably well under 1% - and do not capture the effect of uncertainty in the population estimates, \(N_i\). Mid-year estimates of population are used. The uncertainty in these estimates is unknown (to me, at least, and probably to everyone; besides, the population, by definition, varies across the year) but it is hard to believe that it is not at least a few percent and therefore much larger than the counting uncertainty. An uncertainty of so-many-percent in \(N_i\) propagates to the same percentage absolute uncertainty in age-specific mortality and contributes to the uncertainty in total mortality - both raw and age-standardised. It is almost certain that the uncertainty in both raw and age-standardised mortality is dominated by the unknown uncertainties in the total population and its age distribution. If you only trust population estimates to a few percent, you should also only trust mortality rate estimates to a few percent - and you should ignore the confidence intervals given by ONS because they are too small.

Age-standardised mortality by month, from January 2001

path <- paste0(
  "https://www.ons.gov.uk/file?uri=/",
  "peoplepopulationandcommunity/",
  "birthsdeathsandmarriages/",
  "deaths/",
  "datasets/",
  "monthlymortalityanalysisenglandandwales/",
  "september2021/"
  )
file <- "monthlymortalityanalysissep2021.xlsx"

getFile(path,file)

These data are provided on a monthly schedule by the Office for National Statistics [link]. They provide monthly mortality data from January 2001, by month of registration. Data are given separately for England and for Wales, for men and for women, and for different age groups. The total number of deaths are given as well as the age-standardised rate; here, I’m interested in the latter, in order to be able to make a comparison over time. The latest data are for September 2021 [link].

Monthly <- NULL
if (!file.exists(file)) {
  warning(paste("Couldn't find",file,"on disk"))
} else {
  message(paste("Reading",file,"from disk"))
  
  table <- c(
    paste("Table",c(rep(1,3),rep(2,3),rep(4,3),rep(5,3),rep(6,3),rep(7,3))),
    paste0("Table ",c(rep("8",12),rep("9",12)),
           rep(c(rep("a",4),rep("b",4),rep("c",4)),2))
    )
  country <- c(rep(c(rep("England",3),rep("Wales",3)),3),
               c(rep("England",12),rep("Wales",12)))
  age <- c(rep("all ages",6),rep("<75",6),rep("75+",6),
           rep(c("75-79","80-84","85-89","90+"),6))
  sex <- c(rep(c("men","women","both sexes"),6),
           rep(c(rep("men",4),rep("women",4),rep("both sexes",4)),2))
  cols <- list(
    c("text","numeric","numeric",rep("skip",15)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",15)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",15)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",15)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",15)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",15)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",21)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",15)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",18),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",21)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",15)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",18),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",21)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",15)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",18),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",21)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",15)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",18),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",21)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",15)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",18),"numeric","numeric",rep("skip",3)),
    
    c("text","numeric","numeric",rep("skip",21)),
    c("text",rep("skip",6),"numeric","numeric",rep("skip",15)),
    c("text",rep("skip",12),"numeric","numeric",rep("skip",9)),
    c("text",rep("skip",18),"numeric","numeric",rep("skip",3))
    )
  for (i in 1:length(table)) {
    df <- read_excel(
      file,
      sheet=table[i],
      col_types = cols[[i]],
      col_names=c("date","deaths","rate"),
      skip=5
      )
    df[["country"]] <- country[i]
    df[['sex']] <- sex[i]
    df[['age']] <-age[i]
    Monthly <- rbind(Monthly,df)
  }
  Monthly$date <- ceiling_date(dmy(paste("1",Monthly$date),quiet=T),"month")-1
}
Monthly<-na.omit(Monthly)
age <- "all ages"
sex <- "both sexes"
plotdata <- Monthly[Monthly[['sex']]==sex&Monthly[['age']]==age,]
ggplot(plotdata)+
  geom_step(aes(x=date,y=rate,colour=country),direction="vh")+
  #scale_colour_discrete(breaks=c('men','women','both sexes'),type=c('blue','deeppink','black'))+
  scale_x_date(limits=c(as.Date("2001-01-01"),NA),date_breaks="5 years",date_labels="%b %Y",date_minor_breaks="1 year")+
  scale_y_continuous("age-standardised mortality /100,000",limits = c(0,2500))+
  labs(
    title = "Age-standardised mortality by month of registration",
    subtitle = paste0(sex,', ',age),
    caption = acknowledgement
    )

country='England'
sex='both sexes'
for (age in list(c("all ages","<75","75+"),
                 c("all ages","<75","75-79","80-84","85-89","90+"))) {
  plotdata <- Monthly[Monthly[['country']]==country&
                      Monthly[['sex']]==sex&
                      Monthly[['age']]%in%age,]
  p<-ggplot(plotdata)+
    geom_step(aes(x=date,y=rate,colour=age),direction="vh")+
    scale_y_continuous("age-standardised mortality /100,000",limits = c(0,NA))+
    scale_colour_discrete(breaks=age)+
    scale_x_date(limits=c(as.Date("2001-01-01"),NA),
                 date_breaks="5 years",
                 date_labels="%b %Y",date_minor_breaks="1 year")+
    labs(
      title = "Age-standardised mortality by month of registration",
      subtitle = paste0(country,', ',sex),
      caption = acknowledgement
      )
  print(p)
}

country='England'
age='all ages'
plotdata <- Monthly[Monthly[['country']]==country&
                    Monthly[['age']]==age,]
ggplot(plotdata)+
  geom_step(aes(x=date,y=rate,colour=sex),direction="vh")+
  scale_colour_discrete()+
  scale_y_continuous("age-standardised mortality /100,000",limits = c(0,2500))+
  scale_x_date(limits=c(as.Date("2001-01-01"),NA),
                 date_breaks="5 years",
                 date_labels="%b %Y",date_minor_breaks="1 year")+
  labs(
    title = "Age-standardised mortality by month of registration",
    subtitle = paste0(country,', ',age),
    caption = acknowledgement
    )

Previous year’s mortality by month

Here, for each available month, the average mortality for the previous twelve months is shown.

plotdata <- Monthly[Monthly[['country']]=='England'&
                    Monthly[['sex']]=='both sexes'&
                    Monthly[['age']]=='all ages',]
N <- (length(plotdata[[1]])-11)
plotdata <- plotdata[1:N,]
for (i in 1:N) {
 plotdata[['rate']][i] <- mean(plotdata[['rate']][i:(i+11)])
}
ggplot(plotdata)+
  geom_step(aes(x=date,y=rate,colour=sex),direction="vh",na.rm=TRUE)+
  scale_x_date(limits=c(as.Date("2001-01-01"),NA),date_breaks="5 years",date_labels="%b %Y",date_minor_breaks="1 year")+
  scale_y_continuous("age-standardised mortality /100,000",limits = c(0,2500))+
  labs(
    title = "Previous year's mortality by month of registration",
    subtitle = paste0(country,', ',age),
    caption = acknowledgement
    )

Previous season’s mortality by month

Here, for each available month, the average mortality for the previous three months is shown.

plotdata <- Monthly[Monthly[['country']]=='England'&
                    Monthly[['sex']]=='both sexes'&
                    Monthly[['age']]=='all ages',]
N <- (length(plotdata[[1]])-2)
plotdata <- plotdata[1:N,]
for (i in 1:N) {
 plotdata[['rate']][i] <- mean(plotdata[['rate']][i:(i+2)])
}
ggplot(plotdata)+
  geom_step(aes(x=date,y=rate,colour=sex),direction="vh",na.rm=TRUE)+
  scale_x_date(limits=c(as.Date("2001-01-01"),NA),date_breaks="5 years",date_labels="%b %Y",date_minor_breaks="1 year")+
  scale_y_continuous("age-standardised mortality /100,000",limits = c(0,2500))+
  labs(
    title = "Previous season's mortality by month of registration",
    subtitle = paste0(country,', ',age),
    caption = acknowledgement
    )

Excess mortality by month

Excess mortality is often defined as the difference between the current mortality and a baseline given by the average of the last five years’ mortality (for monthly data, given by the average of the same month’s mortality over the five previous years). Here, for each available month, current, baseline and excess mortality are shown for the whole population in England. Data for men only and women only are similar and only clutter the graph.

country <- 'England'
sex <- 'both sexes'
age <- 'all ages'
plotdata <- Monthly[Monthly[['country']]==country&
                    Monthly[['sex']]==sex&
                    Monthly[['age']]==age,]
N <- (length(plotdata[[1]])-60)
plotdata <- data.frame(date=plotdata[['date']],
                 current=plotdata[['rate']],
                 baseline=NA,
                 excess=NA)

for (i in 1:N) {
 plotdata[i,'baseline'] <- mean(plotdata[i+seq(12,60,12),'current'])
}
plotdata['excess'] <- plotdata['current']-plotdata['baseline']
ggplot(melt(plotdata,measure.vars = c('current','baseline','excess'),variable.name = 'mortality'))+
  geom_step(aes(x=date,y=value,colour=mortality),direction="vh",na.rm=TRUE)+
  scale_x_date(limits=c(as.Date("2001-01-01"),NA),date_breaks="5 years",date_labels="%b %Y",date_minor_breaks="1 year")+
  scale_y_continuous("age-standardised mortality /100,000",limits = c(-500,2000))+
  labs(
    title = "Excess mortality by month of registration",
    subtitle = paste0(country,', ',sex,', ',age),
    caption = acknowledgement
    )

Excess mortality for a given month and over the preceding three and twelve months, inclusive, show seasonal and annual trends.

country <- 'England'
sex <- 'both sexes'
age <- 'all ages'
plotdata <- Monthly[Monthly[['country']]==country&
                    Monthly[['sex']]==sex&
                    Monthly[['age']]==age,]
N <- (length(plotdata[[1]])-60)
plotdata <- data.frame(date=plotdata[['date']],
                 current=plotdata[['rate']],
                 baseline=NA,
                 `given month`=NA,
                 `previous quarter`=NA,
                 `previous year`=NA,
                 `previous two years`=NA)

for (i in 1:N) {
 plotdata[i,'baseline'] <- mean(plotdata[i+seq(12,60,12),'current'])
}
plotdata['given month'] <- plotdata['current']-plotdata['baseline']
plotdata['previous quarter'] <- c(stats::filter((plotdata['given month']),rep(1/3,3),sides=1)[3:length(plotdata[[1]])],rep(NA,2))
plotdata['previous year'] <- c(stats::filter((plotdata['given month']),rep(1/12,12),sides=1)[12:length(plotdata[[1]])],rep(NA,11))
plotdata['previous two years'] <- c(stats::filter((plotdata['given month']),rep(1/24,24),sides=1)[24:length(plotdata[[1]])],rep(NA,23))
ggplot()+
  geom_step(aes(x=date,y=value,colour=`excess mortality`),data=melt(plotdata,measure.vars = c('given month','previous quarter','previous year','previous two years'),variable.name = 'excess mortality'),direction="vh",na.rm=TRUE)+
  scale_x_date(limits=c(as.Date("2006-01-01"),NA),date_breaks="5 years",date_labels="%b %Y",date_minor_breaks="1 year")+
  scale_y_continuous("age-standardised mortality /100,000",limits = c(-500,1000))+
  labs(
    title = "Excess mortality by month of registration",
    subtitle = paste0(country,', ',sex,', ',age),
    caption = acknowledgement
    )

LS0tDQojIEFuYWx5c2lzIG9mIGFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IGRhdGEgZnJvbSB0aGUgT2ZmaWNlIGZvcg0KIyBOYXRpb25hbCBTdGF0aXN0aWNzDQojIENvcHlyaWdodCAoQykgMjAyMSAgU2ltb24gUGxhdHQNCg0KIyBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeQ0KIyBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieQ0KIyB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBlaXRoZXIgdmVyc2lvbiAzIG9mIHRoZSBMaWNlbnNlLCBvcg0KIyAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLg0KIw0KIyBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwNCiMgYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2YNCiMgTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZQ0KIyBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLg0KIw0KIyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZQ0KIyBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbS4gIElmIG5vdCwgc2VlIDxodHRwczovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uDQoNCnRpdGxlOiAiQW5hbHlzaXMgb2YgYWdlLXN0YW5kYXJkaXNlZCBtb3J0YWxpdHkgZGF0YSBmcm9tIHRoZSBPZmZpY2UgZm9yIE5hdGlvbmFsIFN0YXRpc3RpY3MiDQphdXRob3I6ICJTaW1vbiBQbGF0dCINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVlICVCICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KYGBgez1odG1sfQ0KPGEgcmVsPSJsaWNlbnNlIiBocmVmPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS80LjAvIj48aW1nIGFsdD0iQ3JlYXRpdmUgQ29tbW9ucyBMaWNlbnNlIiBzdHlsZT0iYm9yZGVyLXdpZHRoOjAiIHNyYz0iaHR0cHM6Ly9pLmNyZWF0aXZlY29tbW9ucy5vcmcvbC9ieS1zYS80LjAvODh4MzEucG5nIiAvPjwvYT48YnIgLz5UaGlzIHdvcmsgaXMgbGljZW5zZWQgdW5kZXIgYSA8YSByZWw9ImxpY2Vuc2UiIGhyZWY9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzQuMC8iPkNyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlPC9hPi4NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCg0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocmVzaGFwZTIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KdGhlbWVfc2V0KHRoZW1lX2J3KCkpDQoNCnJlYWRVcmwgPC0gZnVuY3Rpb24ocGF0aCxmaWxlbmFtZSkgew0KICB3YXJuIDwtIGVyciA8LSBOVUxMDQogIHN0YXR1cyA8LSB3aXRoQ2FsbGluZ0hhbmRsZXJzKA0KICAgIHRyeUNhdGNoKA0KICAgICAgew0KICAgICAgICB0bXAgPC0gdGVtcGZpbGUoKQ0KICAgICAgICBkb3dubG9hZC5maWxlKA0KICAgICAgICAgIHBhc3RlMChwYXRoLGZpbGVuYW1lKSwNCiAgICAgICAgICB0bXAsIA0KICAgICAgICAgIHF1aWV0PVQsIA0KICAgICAgICAgIG1vZGU9IndiIg0KICAgICAgICAgICkNCiAgICAgIH0sDQogICAgICBlcnJvciA9IGZ1bmN0aW9uKGUpIHsNCiAgICAgICAgZXJyIDw8LSBjb25kaXRpb25NZXNzYWdlKGUpDQogICAgICAgIDENCiAgICAgICAgfQ0KICAgICAgKSwNCiAgICB3YXJuaW5nID0gZnVuY3Rpb24odykgew0KICAgICAgd2FybiA8PC0gYXBwZW5kKHdhcm4sIGNvbmRpdGlvbk1lc3NhZ2UodykpDQogICAgICBpbnZva2VSZXN0YXJ0KCJtdWZmbGVXYXJuaW5nIikNCiAgICAgIDENCiAgICAgIH0NCiAgICApDQogIGlmIChzdGF0dXM9PTApIHsNCiAgICBzdGF0dXMgPC0gIWZpbGUucmVuYW1lKHRtcCxmaWxlbmFtZSkNCiAgfQ0KICByZXR1cm4obGlzdChzdWNjZXNzPSFhcy5sb2dpY2FsKHN0YXR1cyksd2FybmluZz13YXJuLGVycm9yPWVycikpDQp9DQoNCmdldEZpbGUgPC0gZnVuY3Rpb24ocGF0aCxmaWxlKSB7DQogIG1kNWZpbGUgPC0gcGFzdGUwKGZpbGUsJy5tZDUnKQ0KICBpZiAoIWZpbGUuZXhpc3RzKGZpbGUpIHx8IA0KICAgICAgIShmaWxlLmV4aXN0cyhtZDVmaWxlKSAmJiANCiAgICAgICAgcmVhZExpbmVzKG1kNWZpbGUsMSk9PXRvb2xzOjptZDVzdW0oZmlsZSkpKSB7DQogICAgZG93bmxvYWQgPC0gcmVhZFVybChwYXRoLGZpbGUpDQogICAgaWYgKGRvd25sb2FkJHN1Y2Nlc3MpIHsNCiAgICAgIHdyaXRlTGluZXModG9vbHM6Om1kNXN1bShmaWxlKSxtZDVmaWxlKQ0KICAgICAgbWVzc2FnZShwYXN0ZSgiR290IGRhdGEgZnJvbSIscGFzdGUwKHBhdGgsZmlsZSkpKQ0KICAgIH0NCiAgfQ0KfQ0KDQpFU1AyMDEzIDwtIGRhdGEuZnJhbWUoDQogIGFnZT1jKA0KICAgICI8MSIsDQogICAgIjEtNCIsDQogICAgIjUtOSIsDQogICAgIjEwLTE0IiwNCiAgICAiMTUtMTkiLA0KICAgICIyMC0yNCIsDQogICAgIjI1LTI5IiwNCiAgICAiMzAtMzQiLA0KICAgICIzNS0zOSIsDQogICAgIjQwLTQ0IiwNCiAgICAiNDUtNDkiLA0KICAgICI1MC01NCIsDQogICAgIjU1LTU5IiwNCiAgICAiNjAtNjQiLA0KICAgICI2NS02OSIsDQogICAgIjcwLTc0IiwNCiAgICAiNzUtNzkiLA0KICAgICI4MC04NCIsDQogICAgIjg1LTg5IiwNCiAgICAiOTAtOTQiLA0KICAgICI5NSsiDQogICAgKSwNCiAgYnJlYWtzPWMoMCwxLDUsMTAsMTUsMjAsMjUsMzAsMzUsNDAsNDUsNTAsNTUsNjAsNjUsNzAsNzUsODAsODUsOTAsOTUpLA0KICBwb3B1bGF0aW9uPWMoDQogICAgMTAwMCwNCiAgICA0MDAwLA0KICAgIDU1MDAsDQogICAgNTUwMCwNCiAgICA1NTAwLA0KICAgIDYwMDAsDQogICAgNjAwMCwNCiAgICA2NTAwLA0KICAgIDcwMDAsDQogICAgNzAwMCwNCiAgICA3MDAwLA0KICAgIDcwMDAsDQogICAgNjUwMCwNCiAgICA2MDAwLA0KICAgIDU1MDAsDQogICAgNTAwMCwNCiAgICA0MDAwLA0KICAgIDI1MDAsDQogICAgMTUwMCwNCiAgICA4MDAsDQogICAgMjAwDQogICAgKQ0KICApDQoNCmFja25vd2xlZGdlbWVudCA8LSAnU291cmNlOiBPTlMgbGljZW5zZWQgdW5kZXIgdGhlIE9wZW4gR292ZXJubWVudCBMaWNlbmNlLiDCqSBTLiBQLiBQbGF0dCAyMDIxIENDIEJZLVNBIDQuMCcNCg0KYGBgDQoNCiMjIEFubnVhbCBtb3J0YWxpdHksIDE4MzgtMjAyMA0KDQpgYGB7ciBnZXQtYW5udWFsLW1vcnRhbGl0eS1kYXRhLG1lc3NhZ2U9RkFMU0V9DQpwYXRoIDwtIHBhc3RlMCgNCiAgImh0dHBzOi8vd3d3Lm9ucy5nb3YudWsvZmlsZT91cmk9LyIsDQogICJwZW9wbGVwb3B1bGF0aW9uYW5kY29tbXVuaXR5LyIsDQogICJiaXJ0aHNkZWF0aHNhbmRtYXJyaWFnZXMvIiwNCiAgImRlYXRocy8iLA0KICAiYWRob2NzLyIsDQogICIxMjczNWFubnVhbGRlYXRoc2FuZG1vcnRhbGl0eXJhdGVzMTkzOHRvMjAyMHByb3Zpc2lvbmFsLyINCikNCmZpbGUgPC0gIjIwMjBhbm51YWxwcm92aXNpb25hbGFkaG9jMi54bHMiDQpnZXRGaWxlKHBhdGgsZmlsZSkNCmBgYA0KDQpUaGVzZSBkYXRhIGFyZSBwcm92aWRlZCBieSB0aGUgT2ZmaWNlIGZvciBOYXRpb25hbCBTdGF0aXN0aWNzIGluIHJlc3BvbnNlIHRvIGEgdXNlciByZXF1ZXN0LCByZWZlcmVuY2UgMTI3MzUgW1tsaW5rXShgciAiaHR0cHM6Ly93d3cub25zLmdvdi51ay9wZW9wbGVwb3B1bGF0aW9uYW5kY29tbXVuaXR5L2JpcnRoc2RlYXRoc2FuZG1hcnJpYWdlcy9kZWF0aHMvYWRob2NzLzEyNzM1YW5udWFsZGVhdGhzYW5kbW9ydGFsaXR5cmF0ZXMxOTM4dG8yMDIwcHJvdmlzaW9uYWwiYCldLg0KRGF0YSBhcmUgZm9yIEVuZ2xhbmQgYW5kIFdhbGVzLCBjb21iaW5lZC4NClRvdGFsIGRlYXRocyBhbmQgbW9ydGFsaXR5IHJhdGVzIGFyZSBnaXZlbiBmcm9tIDE4Mzg7IGFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IHJhdGVzIGFyZSBnaXZlbiBmcm9tIDE5NDIuDQpSYXRlcyBmb3IgMjAyMCB3ZXJlIHByb3Zpc2lvbmFsIGF0IHRoZSB0aW1lIG9mIHB1YmxpY2F0aW9uLg0KVGhlIGRhdGEgd2VyZSBvcmlnaW5hbGx5IHB1Ymxpc2hlZCBvbiAxMiBKYW51YXJ5IDIwMjE7IGFuIHVwZGF0ZSB3YXMgbWFkZSBvbiA4IE1hcmNoIDIwMjEgc29sZWx5IHRvIGNvcnJlY3Qgc29tZSB0eXBvZ3JhcGhpY2FsIGVycm9ycyBpbiB0aGUgc3VwcG9ydGluZyB0ZXh0LCB3aXRob3V0IGFmZmVjdGluZyB0aGUgZGF0YS4NCg0KYGBge3IgcGxvdC1hbm51YWwtbW9ydGFsaXR5LWRhdGEsIG1lc3NhZ2U9RkFMU0V9DQppZiAoIWZpbGUuZXhpc3RzKGZpbGUpKSB7DQogIHdhcm5pbmcocGFzdGUoIkNvdWxkbid0IGZpbmQiLGZpbGUsIm9uIGRpc2siKSkNCn0gZWxzZSB7DQogIG1lc3NhZ2UocGFzdGUoIlJlYWRpbmciLGZpbGUsImZyb20gZGlzayIpKQ0KICBBbm51YWwgPC0gcmVhZF9leGNlbCgNCiAgICBmaWxlLA0KICAgIHNoZWV0PSJUYWJsZSIsDQogICAgY29sX3R5cGVzPWMoInRleHQiLA0KICAgICAgICAgICAgICAgICJudW1lcmljIiwNCiAgICAgICAgICAgICAgICAibnVtZXJpYyIsDQogICAgICAgICAgICAgICAgIm51bWVyaWMiLA0KICAgICAgICAgICAgICAgICJudW1lcmljIg0KICAgICAgICAgICAgICAgICksDQogICAgY29sX25hbWVzPWMoImRhdGUiLCJkZWF0aHMiLCJwb3B1bGF0aW9uIiwicmF3IiwiYWdlIHN0YW5kYXJkaXNlZCIpLA0KICAgIHNraXA9MTUsDQogICAgbmE9IjoiDQogICkNCiAgQW5udWFsJGRhdGUgPC0gZG15KHBhc3RlKCIzMSAxMiIsQW5udWFsJGRhdGUpKQ0KICBnZ3Bsb3QobWVsdChBbm51YWwsbWVhc3VyZS52YXJzID0gYygncmF3JywnYWdlIHN0YW5kYXJkaXNlZCcpLHZhcmlhYmxlLm5hbWUgPSAnbW9ydGFsaXR5JykpKw0KICAgIGdlb21fc3RlcChhZXMoeD1kYXRlLHk9dmFsdWUsY29sb3VyPW1vcnRhbGl0eSksZGlyZWN0aW9uPSJ2aCIsbmEucm09VFJVRSkrDQogICAgc2NhbGVfeF9kYXRlKGRhdGVfbGFiZWxzPSIlWSIpKw0KICAgIHNjYWxlX3lfY29udGludW91cygibW9ydGFsaXR5IC8xMDAsMDAwIixsaW1pdHMgPSBjKDAsTkEpKSsNCiAgICBsYWJzKA0KICAgICAgdGl0bGUgPSAiTW9ydGFsaXR5IGJ5IHllYXIgb2YgcmVnaXN0cmF0aW9uIiwNCiAgICAgIHN1YnRpdGxlID0gJ0VuZ2xhbmQgYW5kIFdhbGVzJywNCiAgICAgIGNhcHRpb24gPSBhY2tub3dsZWRnZW1lbnQNCiAgICAgICkNCn0NCmBgYA0KDQojIyMgQWdlLXN0YW5kYXJkaXNhdGlvbg0KDQpgYGB7ciBFU1AyMDEzLHJlc3VsdHM9J2FzaXMnfQ0Ka25pdHI6OmthYmxlKEVTUDIwMTNbYygnYWdlJywncG9wdWxhdGlvbicpXSxjYXB0aW9uID0gIkV1cm9wZWFuIFN0YW5kYXJkIFBvcHVsYXRpb24gMjAxMyIscGFkZGluZyA9IDEpDQpgYGANCkFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IGlzIHN0YW5kYXJkaXNlZCB0byB0aGUgRXVyb3BlYW4gU3RhbmRhcmQgUG9wdWxhdGlvbiBnaXZlbiBieSBwb3B1bGF0aW9ucyAkUF9pJCAoYHIgRVNQMjAxMyRwb3B1bGF0aW9uWzE6Ml1gIGV0Yy4pIGZvciBlYWNoIG9mIHRoZSBhZ2UgZ3JvdXBzICRpJCAoYHIgRVNQMjAxMyRhZ2VbMToyXWAgZXRjLikgYWNjb3JkaW5nIHRvIHRoZSBmb2xsb3dpbmcgZXF1YXRpb246DQoNCiQkIGEgPSBcc3VtX2lcZnJhY3tNX2l9e05faX1QX2kkJA0Kd2hlcmUgdGhlIHJlYWwgbnVtYmVyIG9mIHBlb3BsZSBpbiBhZ2UgZ3JvdXAgJGkkIGlzICROX2kkIGFuZCB0aGUgb2JzZXJ2ZWQgbnVtYmVyIG9mIGRlYXRocyBpbiBhZ2UgZ3JvdXAgJGkkIGlzICRNX2kkLg0KVGhlIHF1YW50aXR5ICRNX2kvTl9pJCBpcyB0aGUgX2FnZS1zcGVjaWZpY18gbW9ydGFsaXR5IGZvciBhZ2UgZ3JvdXAgJGkkOyB3aGVuIHdlaWdodGVkIGJ5ICRQX2kkIGFuZCBzdW1tZWQgb3ZlciAkaSQgdGhlIHJlc3VsdCBpcyB0aGUgX2FnZS1zdGFuZGFyZGlzZWRfIG1vcnRhbGl0eSwgJGEkIChhcyB0aGUgJFBfaSQgc3VtIHRvIGByIGZvcm1hdChzdW0oRVNQMjAxM1sncG9wdWxhdGlvbiddKSxzY2llbnRpZmljPUYsYmlnLm1hcms9JywnKWAsICRhJCBpcyAicGVyIGh1bmRyZWQgdGhvdXNhbmQgcG9wdWxhdGlvbiIpLg0KDQpFeGNlcHQgdGhhdCBpdCBpc24ndCByZWFsbHkgInBlciBodW5kcmVkIHRob3VzYW5kIHBvcHVsYXRpb24iLCBhbHRob3VnaCBpdCBhbHdheXMgc2VlbXMgdG8gYmUgZXhwcmVzc2VkIGFzIHN1Y2gsIGJ5IGNvbnZlbnRpb24sIGJlY2F1c2UgJE1faSQgaXMsIGltcGxpY2l0bHksIGEgcmF0ZSAtIHRoZSBudW1iZXIgb2YgcGVvcGxlIGluIGFnZSBncm91cCAkaSQgd2hvIGRpZSBfaW4gYSB5ZWFyXy4NCldoZXJlIG1vcnRhbGl0eSBpcyBnaXZlbiBhdCBpbnRlcnZhbHMgb3RoZXIgdGhhbiBhIHllYXIgdGhpcyBpcywgaW1wbGljaXRseSwgYSBwZXIgYW5udW0gcmF0ZS4NCkl0J3MgYSBwaXR5IHRoYXQgdGhlIGNvbnZlbnRpb24gZG9lc24ndCBtYWtlIHRoYXQgY2xlYXIuDQpJdCB3b3VsZCBwcm9iYWJseSBiZSBiZXR0ZXIgdG8gZGVzY3JpYmUsIGZvciBleGFtcGxlLCBhbiBhZ2Utc3RhbmRhcmRpc2VkIG1vcnRhbGl0eSBvZiAxMDAwIGFzICIxJSBwLmEuIg0KVGhhdCdzIHdoYXQgaXQgbWVhbnMsIGFsdGhvdWdoIHRoYXQgc2VlbXMgbm90IHRvIGJlIGhvdyBpdCdzIGRvbmUuDQoNCklmIHRoZSBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbiBtYXRjaGVkIHRoZSBzdGFuZGFyZCBwb3B1bGF0aW9uLCBzdWNoIHRoYXQgJE5faS9cc3VtX2lOX2k9UF9pL1xzdW1faVBfaVxxdWFkXGZvcmFsbCBpJCwgdGhlIGFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IHdvdWxkIG1hdGNoIHRoZSByYXcgbW9ydGFsaXR5Og0KDQokJHIgPSBcZnJhY3tcc3VtX2lNX2lcc3VtX2lQX2l9e1xzdW1faU5faX0kJA0KVGhpcyBpcyBjbG9zZSB0byB0aGUgY3VycmVudCBzaXR1YXRpb24sIGJlY2F1c2UgdGhlIGN1cnJlbnQgcG9wdWxhdGlvbiBvZiBFbmdsYW5kIGFuZCBXYWxlcyBpcyBjbG9zZSB0byB0aGUgMjAxMyBFdXJvcGVhbiBTdGFuZGFyZCBQb3B1bGF0aW9uLg0KSW4gY29udHJhc3QsIGlmIHRoZSBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbiB3ZXJlIHlvdW5nZXIgdGhhbiB0aGUgc3RhbmRhcmQgcG9wdWxhdGlvbiB0aGUgYWdlLXN0YW5kYXJkaXNlZCBtb3J0YWxpdHkgd291bGQgZXhjZWVkIHRoZSBhY3R1YWwgbW9ydGFsaXR5Lg0KVGhpcyB3YXMgdGhlIGNhc2UgaW4gZGVjYWRlcyBwYXN0OyB3aXRoIGFkdmFuY2VzIGluIGxpZmUgZXhwZWN0YW5jeSBhbmQgcmVkdWN0aW9ucyBpbiBmZXJ0aWxpdHkgdGhlIHBvcHVsYXRpb24gaGFzIGdyb3duIG9sZGVyIGhhdmluZyBiZWVuIHlvdW5nZXIgYmVmb3JlLg0KVGhpcyBpcyB3aHkgYWdlLXN0YW5kYXJkaXNlZCBtb3J0YWxpdHkgaXMgdXNlZnVsIGFzIHdlIGNhbiBmYWN0b3Igb3V0IHRoZSBlZmZlY3Qgb2YgYW4gYWdpbmcgcG9wdWxhdGlvbiBvbiBjaGFuZ2VzIGluIG1vcnRhbGl0eS4NCldpdGhvdXQgaXQsIG1vcnRhbGl0eSB3b3VsZCBhcHBlYXIgdG8gZ2V0IHdvcnNlLCBvciBub3QgZ2V0IGJldHRlciBhcyBmYXN0IGFzIGl0IHJlYWxseSBoYWQsIGlmIGFkdmFuY2VzIGluIGhlYWx0aCBjYXJlIGhhZCBsZWQgdG8gaW5jcmVhc2VkIGxpZmUgZXhwZWN0YW5jeS4NClRoaXMgaXMgbW9zdCBjbGVhcmx5IHZpc2libGUgaW4gdGhlIGRhdGEgZm9yIHRoZSBsYXRlIDIwdGggY2VudHVyeTogcmF3IG1vcnRhbGl0eSB3YXMgbW9yZSBvciBsZXNzIGNvbnN0YW50IGV2ZW4gYXMgdGhlIHBvcHVsYXRpb24gYWdlZCAtIGFnaW5nIGRyaXZlbiBpbiBwYXJ0IGJ5IGFkdmFuY2VzIGluIGhlYWx0aCBjYXJlIHdoaWNoIGxlZCB0byByZWR1Y2VkIGFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5Lg0KSXQncyBhbHNvIHZpc2libGUgaW4gdGhlIDIwMTBzOiByYXcgbW9ydGFsaXR5IGluY3JlYXNlZCBzbGlnaHRseSBhbmQgdGhhdCBpcyBleHBsaWNhYmxlIGluIHRlcm1zIG9mIGFuIGFnaW5nIHBvcHVsYXRpb24gYXMgaXMgc2hvd24gYnkgdGhlIGZhY3QgdGhhdCBhZ2Utc3RhbmRhcmRpc2VkIG1vcnRhbGl0eSB3YXMgZmxhdC4gDQoNCk9OUyBhbHNvIHF1b3RlIGEgIjk1JSBjb25maWRlbmNlIGludGVydmFsIiBvbiBhZ2Utc3RhbmRhcmRpc2VkIG1vcnRhbGl0eSwgYXMgYSBmdW5jdGlvbiBvZiB0aGUgdG90YWwgbnVtYmVyIG9mIGRlYXRocywgYXMgZm9sbG93czoNCg0KJCQgYSA9IFxsZWZ0KCAxIFxwbSBcZnJhY3sxLjk2fXtcc3VtX2lNX2l9IFxyaWdodClcc3VtX2lcZnJhY3tNX2l9e05faX1QX2kgJCQNClRoaXMgaW50ZXJ2YWwgaXMgbm90IHVzZWZ1bC4gDQpJdCBhc3N1bWVzIHRoYXQgdGhlIG9ubHkgc291cmNlIG9mIHVuY2VydGFpbnR5IGlzIFBvaXNzb24gY291bnRpbmcgc3RhdGlzdGljcyBvbiB0aGUgdG90YWwgbnVtYmVyIG9mIGRlYXRocy4NClRoaXMgaXMgYW4gdW5kZXJlc3RpbWF0ZSBiZWNhdXNlIGFnZS1zcGVjaWZpYyBtb3J0YWxpdHkgaXMgbm90IGEgUG9pc3Nvbi1kaXN0cmlidXRlZCB2YXJpYWJsZSBiZWNhdXNlIGRlYXRoIHJhdGVzIGFyZSBpbmV2aXRhYmx5IG5vdCBjb25zdGFudCBhbmQgcGVyaGFwcyBhbHNvIGJlY2F1c2UgY291bnRpbmcgaW50ZXJ2YWxzLCBiZWluZyBhIHZhcmlhYmxlIG51bWJlciBvZiBkYXlzIHdvcmtlZCBieSByZWdpc3RyYXJzLCBldGMuLCBhbHNvIHZhcnksIGJ1dCB0aGUgdW5kZXJlc3RpbWF0ZSBpcyBwcm9iYWJseSBub3QgbGFyZ2UuDQpUaGUgcmVzdWx0aW5nIHVuY2VydGFpbnR5IGVzdGltYXRlcyBhcmUgdmVyeSBzbWFsbCwgaG93ZXZlciAtIGluZXZpdGFibHkgd2VsbCB1bmRlciAxJSAtIGFuZCBkbyBub3QgY2FwdHVyZSB0aGUgZWZmZWN0IG9mIHVuY2VydGFpbnR5IGluIHRoZSBwb3B1bGF0aW9uIGVzdGltYXRlcywgJE5faSQuDQpNaWQteWVhciBlc3RpbWF0ZXMgb2YgcG9wdWxhdGlvbiBhcmUgdXNlZC4NClRoZSB1bmNlcnRhaW50eSBpbiB0aGVzZSBlc3RpbWF0ZXMgaXMgdW5rbm93biAodG8gbWUsIGF0IGxlYXN0LCBhbmQgcHJvYmFibHkgdG8gZXZlcnlvbmU7IGJlc2lkZXMsIHRoZSBwb3B1bGF0aW9uLCBieSBkZWZpbml0aW9uLCB2YXJpZXMgYWNyb3NzIHRoZSB5ZWFyKSBidXQgaXQgaXMgaGFyZCB0byBiZWxpZXZlIHRoYXQgaXQgaXMgbm90IGF0IGxlYXN0IGEgZmV3IHBlcmNlbnQgYW5kIHRoZXJlZm9yZSBtdWNoIGxhcmdlciB0aGFuIHRoZSBjb3VudGluZyB1bmNlcnRhaW50eS4NCkFuIHVuY2VydGFpbnR5IG9mIHNvLW1hbnktcGVyY2VudCBpbiAkTl9pJCBwcm9wYWdhdGVzIHRvIHRoZSBzYW1lIHBlcmNlbnRhZ2UgYWJzb2x1dGUgdW5jZXJ0YWludHkgaW4gYWdlLXNwZWNpZmljIG1vcnRhbGl0eSBhbmQgY29udHJpYnV0ZXMgdG8gdGhlIHVuY2VydGFpbnR5IGluIHRvdGFsIG1vcnRhbGl0eSAtIGJvdGggcmF3IGFuZCBhZ2Utc3RhbmRhcmRpc2VkLg0KSXQgaXMgYWxtb3N0IGNlcnRhaW4gdGhhdCB0aGUgdW5jZXJ0YWludHkgaW4gYm90aCByYXcgYW5kIGFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IGlzIGRvbWluYXRlZCBieSB0aGUgdW5rbm93biB1bmNlcnRhaW50aWVzIGluIHRoZSB0b3RhbCBwb3B1bGF0aW9uIGFuZCBpdHMgYWdlIGRpc3RyaWJ1dGlvbi4NCklmIHlvdSBvbmx5IHRydXN0IHBvcHVsYXRpb24gZXN0aW1hdGVzIHRvIGEgZmV3IHBlcmNlbnQsIHlvdSBzaG91bGQgYWxzbyBvbmx5IHRydXN0IG1vcnRhbGl0eSByYXRlIGVzdGltYXRlcyB0byBhIGZldyBwZXJjZW50IC0gYW5kIHlvdSBzaG91bGQgaWdub3JlIHRoZSBjb25maWRlbmNlIGludGVydmFscyBnaXZlbiBieSBPTlMgYmVjYXVzZSB0aGV5IGFyZSB0b28gc21hbGwuDQoNCiMjIEFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IGJ5IG1vbnRoLCBmcm9tIEphbnVhcnkgMjAwMQ0KYGBge3IgZ2V0LW1vbnRobHktbW9ydGFsaXR5LWRhdGEsbWVzc2FnZT1GQUxTRX0NCnBhdGggPC0gcGFzdGUwKA0KICAiaHR0cHM6Ly93d3cub25zLmdvdi51ay9maWxlP3VyaT0vIiwNCiAgInBlb3BsZXBvcHVsYXRpb25hbmRjb21tdW5pdHkvIiwNCiAgImJpcnRoc2RlYXRoc2FuZG1hcnJpYWdlcy8iLA0KICAiZGVhdGhzLyIsDQogICJkYXRhc2V0cy8iLA0KICAibW9udGhseW1vcnRhbGl0eWFuYWx5c2lzZW5nbGFuZGFuZHdhbGVzLyIsDQogICJzZXB0ZW1iZXIyMDIxLyINCiAgKQ0KZmlsZSA8LSAibW9udGhseW1vcnRhbGl0eWFuYWx5c2lzc2VwMjAyMS54bHN4Ig0KDQpnZXRGaWxlKHBhdGgsZmlsZSkNCmBgYA0KDQpUaGVzZSBkYXRhIGFyZSBwcm92aWRlZCBvbiBhIG1vbnRobHkgc2NoZWR1bGUgYnkgdGhlIE9mZmljZSBmb3IgTmF0aW9uYWwgU3RhdGlzdGljcyBbW2xpbmtdKGByICJodHRwczovL3d3dy5vbnMuZ292LnVrL3Blb3BsZXBvcHVsYXRpb25hbmRjb21tdW5pdHkvYmlydGhzZGVhdGhzYW5kbWFycmlhZ2VzL2RlYXRocy9kYXRhc2V0cy9tb250aGx5bW9ydGFsaXR5YW5hbHlzaXNlbmdsYW5kYW5kd2FsZXMiYCldLg0KVGhleSBwcm92aWRlIG1vbnRobHkgbW9ydGFsaXR5IGRhdGEgZnJvbSBKYW51YXJ5IDIwMDEsIGJ5IG1vbnRoIG9mIHJlZ2lzdHJhdGlvbi4NCkRhdGEgYXJlIGdpdmVuIHNlcGFyYXRlbHkgZm9yIEVuZ2xhbmQgYW5kIGZvciBXYWxlcywgZm9yIG1lbiBhbmQgZm9yIHdvbWVuLCBhbmQgZm9yIGRpZmZlcmVudCBhZ2UgZ3JvdXBzLg0KVGhlIHRvdGFsIG51bWJlciBvZiBkZWF0aHMgYXJlIGdpdmVuIGFzIHdlbGwgYXMgdGhlIGFnZS1zdGFuZGFyZGlzZWQgcmF0ZTsNCmhlcmUsIEknbSBpbnRlcmVzdGVkIGluIHRoZSBsYXR0ZXIsIGluIG9yZGVyIHRvIGJlIGFibGUgdG8gbWFrZSBhIGNvbXBhcmlzb24gb3ZlciB0aW1lLg0KVGhlIGxhdGVzdCBkYXRhIGFyZSBmb3IgU2VwdGVtYmVyIDIwMjEgW1tsaW5rXShgciBwYXN0ZTAocGF0aCxmaWxlKWApXS4NCg0KYGBge3IgcmVhZC1tb250aGx5LWRhdGEsbWVzc2FnZT1GQUxTRX0NCk1vbnRobHkgPC0gTlVMTA0KaWYgKCFmaWxlLmV4aXN0cyhmaWxlKSkgew0KICB3YXJuaW5nKHBhc3RlKCJDb3VsZG4ndCBmaW5kIixmaWxlLCJvbiBkaXNrIikpDQp9IGVsc2Ugew0KICBtZXNzYWdlKHBhc3RlKCJSZWFkaW5nIixmaWxlLCJmcm9tIGRpc2siKSkNCiAgDQogIHRhYmxlIDwtIGMoDQogICAgcGFzdGUoIlRhYmxlIixjKHJlcCgxLDMpLHJlcCgyLDMpLHJlcCg0LDMpLHJlcCg1LDMpLHJlcCg2LDMpLHJlcCg3LDMpKSksDQogICAgcGFzdGUwKCJUYWJsZSAiLGMocmVwKCI4IiwxMikscmVwKCI5IiwxMikpLA0KICAgICAgICAgICByZXAoYyhyZXAoImEiLDQpLHJlcCgiYiIsNCkscmVwKCJjIiw0KSksMikpDQogICAgKQ0KICBjb3VudHJ5IDwtIGMocmVwKGMocmVwKCJFbmdsYW5kIiwzKSxyZXAoIldhbGVzIiwzKSksMyksDQogICAgICAgICAgICAgICBjKHJlcCgiRW5nbGFuZCIsMTIpLHJlcCgiV2FsZXMiLDEyKSkpDQogIGFnZSA8LSBjKHJlcCgiYWxsIGFnZXMiLDYpLHJlcCgiPDc1Iiw2KSxyZXAoIjc1KyIsNiksDQogICAgICAgICAgIHJlcChjKCI3NS03OSIsIjgwLTg0IiwiODUtODkiLCI5MCsiKSw2KSkNCiAgc2V4IDwtIGMocmVwKGMoIm1lbiIsIndvbWVuIiwiYm90aCBzZXhlcyIpLDYpLA0KICAgICAgICAgICByZXAoYyhyZXAoIm1lbiIsNCkscmVwKCJ3b21lbiIsNCkscmVwKCJib3RoIHNleGVzIiw0KSksMikpDQogIGNvbHMgPC0gbGlzdCgNCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMTUpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxMiksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMTUpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxMiksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMTUpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxMiksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMTUpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxMiksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMTUpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxMiksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMTUpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxMiksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMjEpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiwxNSkpLA0KICAgIGMoInRleHQiLHJlcCgic2tpcCIsMTIpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxOCksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMjEpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiwxNSkpLA0KICAgIGMoInRleHQiLHJlcCgic2tpcCIsMTIpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxOCksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMjEpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiwxNSkpLA0KICAgIGMoInRleHQiLHJlcCgic2tpcCIsMTIpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxOCksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMjEpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiwxNSkpLA0KICAgIGMoInRleHQiLHJlcCgic2tpcCIsMTIpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxOCksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMjEpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiwxNSkpLA0KICAgIGMoInRleHQiLHJlcCgic2tpcCIsMTIpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxOCksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKSwNCiAgICANCiAgICBjKCJ0ZXh0IiwibnVtZXJpYyIsIm51bWVyaWMiLHJlcCgic2tpcCIsMjEpKSwNCiAgICBjKCJ0ZXh0IixyZXAoInNraXAiLDYpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiwxNSkpLA0KICAgIGMoInRleHQiLHJlcCgic2tpcCIsMTIpLCJudW1lcmljIiwibnVtZXJpYyIscmVwKCJza2lwIiw5KSksDQogICAgYygidGV4dCIscmVwKCJza2lwIiwxOCksIm51bWVyaWMiLCJudW1lcmljIixyZXAoInNraXAiLDMpKQ0KICAgICkNCiAgZm9yIChpIGluIDE6bGVuZ3RoKHRhYmxlKSkgew0KICAgIGRmIDwtIHJlYWRfZXhjZWwoDQogICAgICBmaWxlLA0KICAgICAgc2hlZXQ9dGFibGVbaV0sDQogICAgICBjb2xfdHlwZXMgPSBjb2xzW1tpXV0sDQogICAgICBjb2xfbmFtZXM9YygiZGF0ZSIsImRlYXRocyIsInJhdGUiKSwNCiAgICAgIHNraXA9NQ0KICAgICAgKQ0KICAgIGRmW1siY291bnRyeSJdXSA8LSBjb3VudHJ5W2ldDQogICAgZGZbWydzZXgnXV0gPC0gc2V4W2ldDQogICAgZGZbWydhZ2UnXV0gPC1hZ2VbaV0NCiAgICBNb250aGx5IDwtIHJiaW5kKE1vbnRobHksZGYpDQogIH0NCiAgTW9udGhseSRkYXRlIDwtIGNlaWxpbmdfZGF0ZShkbXkocGFzdGUoIjEiLE1vbnRobHkkZGF0ZSkscXVpZXQ9VCksIm1vbnRoIiktMQ0KfQ0KTW9udGhseTwtbmEub21pdChNb250aGx5KQ0KYGBgDQoNCmBgYHtyIHBsb3QtbW9udGhseS1kYXRhLWJ5LWNvdW50cnksbWVzc2FnZT1GQUxTRX0NCmFnZSA8LSAiYWxsIGFnZXMiDQpzZXggPC0gImJvdGggc2V4ZXMiDQpwbG90ZGF0YSA8LSBNb250aGx5W01vbnRobHlbWydzZXgnXV09PXNleCZNb250aGx5W1snYWdlJ11dPT1hZ2UsXQ0KZ2dwbG90KHBsb3RkYXRhKSsNCiAgZ2VvbV9zdGVwKGFlcyh4PWRhdGUseT1yYXRlLGNvbG91cj1jb3VudHJ5KSxkaXJlY3Rpb249InZoIikrDQogICNzY2FsZV9jb2xvdXJfZGlzY3JldGUoYnJlYWtzPWMoJ21lbicsJ3dvbWVuJywnYm90aCBzZXhlcycpLHR5cGU9YygnYmx1ZScsJ2RlZXBwaW5rJywnYmxhY2snKSkrDQogIHNjYWxlX3hfZGF0ZShsaW1pdHM9Yyhhcy5EYXRlKCIyMDAxLTAxLTAxIiksTkEpLGRhdGVfYnJlYWtzPSI1IHllYXJzIixkYXRlX2xhYmVscz0iJWIgJVkiLGRhdGVfbWlub3JfYnJlYWtzPSIxIHllYXIiKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJhZ2Utc3RhbmRhcmRpc2VkIG1vcnRhbGl0eSAvMTAwLDAwMCIsbGltaXRzID0gYygwLDI1MDApKSsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJBZ2Utc3RhbmRhcmRpc2VkIG1vcnRhbGl0eSBieSBtb250aCBvZiByZWdpc3RyYXRpb24iLA0KICAgIHN1YnRpdGxlID0gcGFzdGUwKHNleCwnLCAnLGFnZSksDQogICAgY2FwdGlvbiA9IGFja25vd2xlZGdlbWVudA0KICAgICkNCmBgYA0KDQpgYGB7ciBwbG90LW1vbnRobHktZGF0YS1ieS1hZ2UsbWVzc2FnZT1GQUxTRX0NCmNvdW50cnk9J0VuZ2xhbmQnDQpzZXg9J2JvdGggc2V4ZXMnDQpmb3IgKGFnZSBpbiBsaXN0KGMoImFsbCBhZ2VzIiwiPDc1IiwiNzUrIiksDQogICAgICAgICAgICAgICAgIGMoImFsbCBhZ2VzIiwiPDc1IiwiNzUtNzkiLCI4MC04NCIsIjg1LTg5IiwiOTArIikpKSB7DQogIHBsb3RkYXRhIDwtIE1vbnRobHlbTW9udGhseVtbJ2NvdW50cnknXV09PWNvdW50cnkmDQogICAgICAgICAgICAgICAgICAgICAgTW9udGhseVtbJ3NleCddXT09c2V4Jg0KICAgICAgICAgICAgICAgICAgICAgIE1vbnRobHlbWydhZ2UnXV0laW4lYWdlLF0NCiAgcDwtZ2dwbG90KHBsb3RkYXRhKSsNCiAgICBnZW9tX3N0ZXAoYWVzKHg9ZGF0ZSx5PXJhdGUsY29sb3VyPWFnZSksZGlyZWN0aW9uPSJ2aCIpKw0KICAgIHNjYWxlX3lfY29udGludW91cygiYWdlLXN0YW5kYXJkaXNlZCBtb3J0YWxpdHkgLzEwMCwwMDAiLGxpbWl0cyA9IGMoMCxOQSkpKw0KICAgIHNjYWxlX2NvbG91cl9kaXNjcmV0ZShicmVha3M9YWdlKSsNCiAgICBzY2FsZV94X2RhdGUobGltaXRzPWMoYXMuRGF0ZSgiMjAwMS0wMS0wMSIpLE5BKSwNCiAgICAgICAgICAgICAgICAgZGF0ZV9icmVha3M9IjUgeWVhcnMiLA0KICAgICAgICAgICAgICAgICBkYXRlX2xhYmVscz0iJWIgJVkiLGRhdGVfbWlub3JfYnJlYWtzPSIxIHllYXIiKSsNCiAgICBsYWJzKA0KICAgICAgdGl0bGUgPSAiQWdlLXN0YW5kYXJkaXNlZCBtb3J0YWxpdHkgYnkgbW9udGggb2YgcmVnaXN0cmF0aW9uIiwNCiAgICAgIHN1YnRpdGxlID0gcGFzdGUwKGNvdW50cnksJywgJyxzZXgpLA0KICAgICAgY2FwdGlvbiA9IGFja25vd2xlZGdlbWVudA0KICAgICAgKQ0KICBwcmludChwKQ0KfQ0KYGBgDQoNCmBgYHtyIHBsb3QtbW9udGhseS1kYXRhLWJ5LXNleCxtZXNzYWdlPUZBTFNFfQ0KY291bnRyeT0nRW5nbGFuZCcNCmFnZT0nYWxsIGFnZXMnDQpwbG90ZGF0YSA8LSBNb250aGx5W01vbnRobHlbWydjb3VudHJ5J11dPT1jb3VudHJ5Jg0KICAgICAgICAgICAgICAgICAgICBNb250aGx5W1snYWdlJ11dPT1hZ2UsXQ0KZ2dwbG90KHBsb3RkYXRhKSsNCiAgZ2VvbV9zdGVwKGFlcyh4PWRhdGUseT1yYXRlLGNvbG91cj1zZXgpLGRpcmVjdGlvbj0idmgiKSsNCiAgc2NhbGVfY29sb3VyX2Rpc2NyZXRlKCkrDQogIHNjYWxlX3lfY29udGludW91cygiYWdlLXN0YW5kYXJkaXNlZCBtb3J0YWxpdHkgLzEwMCwwMDAiLGxpbWl0cyA9IGMoMCwyNTAwKSkrDQogIHNjYWxlX3hfZGF0ZShsaW1pdHM9Yyhhcy5EYXRlKCIyMDAxLTAxLTAxIiksTkEpLA0KICAgICAgICAgICAgICAgICBkYXRlX2JyZWFrcz0iNSB5ZWFycyIsDQogICAgICAgICAgICAgICAgIGRhdGVfbGFiZWxzPSIlYiAlWSIsZGF0ZV9taW5vcl9icmVha3M9IjEgeWVhciIpKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IGJ5IG1vbnRoIG9mIHJlZ2lzdHJhdGlvbiIsDQogICAgc3VidGl0bGUgPSBwYXN0ZTAoY291bnRyeSwnLCAnLGFnZSksDQogICAgY2FwdGlvbiA9IGFja25vd2xlZGdlbWVudA0KICAgICkNCmBgYA0KDQojIyBQcmV2aW91cyB5ZWFyJ3MgbW9ydGFsaXR5IGJ5IG1vbnRoDQoNCkhlcmUsIGZvciBlYWNoIGF2YWlsYWJsZSBtb250aCwgdGhlIGF2ZXJhZ2UgbW9ydGFsaXR5IGZvciB0aGUgcHJldmlvdXMgdHdlbHZlIG1vbnRocyBpcyBzaG93bi4NCg0KYGBge3IgcGxvdC1wcmV2aW91cy15ZWFyLW1vcnRhbGl0eX0NCnBsb3RkYXRhIDwtIE1vbnRobHlbTW9udGhseVtbJ2NvdW50cnknXV09PSdFbmdsYW5kJyYNCiAgICAgICAgICAgICAgICAgICAgTW9udGhseVtbJ3NleCddXT09J2JvdGggc2V4ZXMnJg0KICAgICAgICAgICAgICAgICAgICBNb250aGx5W1snYWdlJ11dPT0nYWxsIGFnZXMnLF0NCk4gPC0gKGxlbmd0aChwbG90ZGF0YVtbMV1dKS0xMSkNCnBsb3RkYXRhIDwtIHBsb3RkYXRhWzE6TixdDQpmb3IgKGkgaW4gMTpOKSB7DQogcGxvdGRhdGFbWydyYXRlJ11dW2ldIDwtIG1lYW4ocGxvdGRhdGFbWydyYXRlJ11dW2k6KGkrMTEpXSkNCn0NCmdncGxvdChwbG90ZGF0YSkrDQogIGdlb21fc3RlcChhZXMoeD1kYXRlLHk9cmF0ZSxjb2xvdXI9c2V4KSxkaXJlY3Rpb249InZoIixuYS5ybT1UUlVFKSsNCiAgc2NhbGVfeF9kYXRlKGxpbWl0cz1jKGFzLkRhdGUoIjIwMDEtMDEtMDEiKSxOQSksZGF0ZV9icmVha3M9IjUgeWVhcnMiLGRhdGVfbGFiZWxzPSIlYiAlWSIsZGF0ZV9taW5vcl9icmVha3M9IjEgeWVhciIpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoImFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IC8xMDAsMDAwIixsaW1pdHMgPSBjKDAsMjUwMCkpKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlByZXZpb3VzIHllYXIncyBtb3J0YWxpdHkgYnkgbW9udGggb2YgcmVnaXN0cmF0aW9uIiwNCiAgICBzdWJ0aXRsZSA9IHBhc3RlMChjb3VudHJ5LCcsICcsYWdlKSwNCiAgICBjYXB0aW9uID0gYWNrbm93bGVkZ2VtZW50DQogICAgKQ0KYGBgDQoNCiMjIFByZXZpb3VzIHNlYXNvbidzIG1vcnRhbGl0eSBieSBtb250aA0KDQpIZXJlLCBmb3IgZWFjaCBhdmFpbGFibGUgbW9udGgsIHRoZSBhdmVyYWdlIG1vcnRhbGl0eSBmb3IgdGhlIHByZXZpb3VzIHRocmVlIG1vbnRocyBpcyBzaG93bi4NCg0KYGBge3IgcGxvdC1wcmV2aW91cy1zZWFzb24tbW9ydGFsaXR5fQ0KcGxvdGRhdGEgPC0gTW9udGhseVtNb250aGx5W1snY291bnRyeSddXT09J0VuZ2xhbmQnJg0KICAgICAgICAgICAgICAgICAgICBNb250aGx5W1snc2V4J11dPT0nYm90aCBzZXhlcycmDQogICAgICAgICAgICAgICAgICAgIE1vbnRobHlbWydhZ2UnXV09PSdhbGwgYWdlcycsXQ0KTiA8LSAobGVuZ3RoKHBsb3RkYXRhW1sxXV0pLTIpDQpwbG90ZGF0YSA8LSBwbG90ZGF0YVsxOk4sXQ0KZm9yIChpIGluIDE6Tikgew0KIHBsb3RkYXRhW1sncmF0ZSddXVtpXSA8LSBtZWFuKHBsb3RkYXRhW1sncmF0ZSddXVtpOihpKzIpXSkNCn0NCmdncGxvdChwbG90ZGF0YSkrDQogIGdlb21fc3RlcChhZXMoeD1kYXRlLHk9cmF0ZSxjb2xvdXI9c2V4KSxkaXJlY3Rpb249InZoIixuYS5ybT1UUlVFKSsNCiAgc2NhbGVfeF9kYXRlKGxpbWl0cz1jKGFzLkRhdGUoIjIwMDEtMDEtMDEiKSxOQSksZGF0ZV9icmVha3M9IjUgeWVhcnMiLGRhdGVfbGFiZWxzPSIlYiAlWSIsZGF0ZV9taW5vcl9icmVha3M9IjEgeWVhciIpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoImFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IC8xMDAsMDAwIixsaW1pdHMgPSBjKDAsMjUwMCkpKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlByZXZpb3VzIHNlYXNvbidzIG1vcnRhbGl0eSBieSBtb250aCBvZiByZWdpc3RyYXRpb24iLA0KICAgIHN1YnRpdGxlID0gcGFzdGUwKGNvdW50cnksJywgJyxhZ2UpLA0KICAgIGNhcHRpb24gPSBhY2tub3dsZWRnZW1lbnQNCiAgICApDQpgYGANCg0KIyMgRXhjZXNzIG1vcnRhbGl0eSBieSBtb250aA0KDQpFeGNlc3MgbW9ydGFsaXR5IGlzIG9mdGVuIGRlZmluZWQgYXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgY3VycmVudCBtb3J0YWxpdHkgYW5kIGEgYmFzZWxpbmUgZ2l2ZW4gYnkgdGhlIGF2ZXJhZ2Ugb2YgdGhlIGxhc3QgZml2ZSB5ZWFycycgbW9ydGFsaXR5IChmb3IgbW9udGhseSBkYXRhLCBnaXZlbiBieSB0aGUgYXZlcmFnZSBvZiB0aGUgc2FtZSBtb250aCdzIG1vcnRhbGl0eSBvdmVyIHRoZSBmaXZlIHByZXZpb3VzIHllYXJzKS4NCkhlcmUsIGZvciBlYWNoIGF2YWlsYWJsZSBtb250aCwgY3VycmVudCwgYmFzZWxpbmUgYW5kIGV4Y2VzcyBtb3J0YWxpdHkgYXJlIHNob3duIGZvciB0aGUgd2hvbGUgcG9wdWxhdGlvbiBpbiBFbmdsYW5kLg0KRGF0YSBmb3IgbWVuIG9ubHkgYW5kIHdvbWVuIG9ubHkgYXJlIHNpbWlsYXIgYW5kIG9ubHkgY2x1dHRlciB0aGUgZ3JhcGguDQoNCmBgYHtyIHBsb3QtZXhjZXNzLW1vcnRhbGl0eX0NCmNvdW50cnkgPC0gJ0VuZ2xhbmQnDQpzZXggPC0gJ2JvdGggc2V4ZXMnDQphZ2UgPC0gJ2FsbCBhZ2VzJw0KcGxvdGRhdGEgPC0gTW9udGhseVtNb250aGx5W1snY291bnRyeSddXT09Y291bnRyeSYNCiAgICAgICAgICAgICAgICAgICAgTW9udGhseVtbJ3NleCddXT09c2V4Jg0KICAgICAgICAgICAgICAgICAgICBNb250aGx5W1snYWdlJ11dPT1hZ2UsXQ0KTiA8LSAobGVuZ3RoKHBsb3RkYXRhW1sxXV0pLTYwKQ0KcGxvdGRhdGEgPC0gZGF0YS5mcmFtZShkYXRlPXBsb3RkYXRhW1snZGF0ZSddXSwNCiAgICAgICAgICAgICAgICAgY3VycmVudD1wbG90ZGF0YVtbJ3JhdGUnXV0sDQogICAgICAgICAgICAgICAgIGJhc2VsaW5lPU5BLA0KICAgICAgICAgICAgICAgICBleGNlc3M9TkEpDQoNCmZvciAoaSBpbiAxOk4pIHsNCiBwbG90ZGF0YVtpLCdiYXNlbGluZSddIDwtIG1lYW4ocGxvdGRhdGFbaStzZXEoMTIsNjAsMTIpLCdjdXJyZW50J10pDQp9DQpwbG90ZGF0YVsnZXhjZXNzJ10gPC0gcGxvdGRhdGFbJ2N1cnJlbnQnXS1wbG90ZGF0YVsnYmFzZWxpbmUnXQ0KZ2dwbG90KG1lbHQocGxvdGRhdGEsbWVhc3VyZS52YXJzID0gYygnY3VycmVudCcsJ2Jhc2VsaW5lJywnZXhjZXNzJyksdmFyaWFibGUubmFtZSA9ICdtb3J0YWxpdHknKSkrDQogIGdlb21fc3RlcChhZXMoeD1kYXRlLHk9dmFsdWUsY29sb3VyPW1vcnRhbGl0eSksZGlyZWN0aW9uPSJ2aCIsbmEucm09VFJVRSkrDQogIHNjYWxlX3hfZGF0ZShsaW1pdHM9Yyhhcy5EYXRlKCIyMDAxLTAxLTAxIiksTkEpLGRhdGVfYnJlYWtzPSI1IHllYXJzIixkYXRlX2xhYmVscz0iJWIgJVkiLGRhdGVfbWlub3JfYnJlYWtzPSIxIHllYXIiKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJhZ2Utc3RhbmRhcmRpc2VkIG1vcnRhbGl0eSAvMTAwLDAwMCIsbGltaXRzID0gYygtNTAwLDIwMDApKSsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJFeGNlc3MgbW9ydGFsaXR5IGJ5IG1vbnRoIG9mIHJlZ2lzdHJhdGlvbiIsDQogICAgc3VidGl0bGUgPSBwYXN0ZTAoY291bnRyeSwnLCAnLHNleCwnLCAnLGFnZSksDQogICAgY2FwdGlvbiA9IGFja25vd2xlZGdlbWVudA0KICAgICkNCmBgYA0KDQpFeGNlc3MgbW9ydGFsaXR5IGZvciBhIGdpdmVuIG1vbnRoIGFuZCBvdmVyIHRoZSBwcmVjZWRpbmcgdGhyZWUgYW5kIHR3ZWx2ZSBtb250aHMsIGluY2x1c2l2ZSwgc2hvdyBzZWFzb25hbCBhbmQgYW5udWFsIHRyZW5kcy4NCg0KYGBge3IgcGxvdC1leGNlc3MtbW9ydGFsaXR5LWZpbHRlcmVkfQ0KY291bnRyeSA8LSAnRW5nbGFuZCcNCnNleCA8LSAnYm90aCBzZXhlcycNCmFnZSA8LSAnYWxsIGFnZXMnDQpwbG90ZGF0YSA8LSBNb250aGx5W01vbnRobHlbWydjb3VudHJ5J11dPT1jb3VudHJ5Jg0KICAgICAgICAgICAgICAgICAgICBNb250aGx5W1snc2V4J11dPT1zZXgmDQogICAgICAgICAgICAgICAgICAgIE1vbnRobHlbWydhZ2UnXV09PWFnZSxdDQpOIDwtIChsZW5ndGgocGxvdGRhdGFbWzFdXSktNjApDQpwbG90ZGF0YSA8LSBkYXRhLmZyYW1lKGRhdGU9cGxvdGRhdGFbWydkYXRlJ11dLA0KICAgICAgICAgICAgICAgICBjdXJyZW50PXBsb3RkYXRhW1sncmF0ZSddXSwNCiAgICAgICAgICAgICAgICAgYmFzZWxpbmU9TkEsDQogICAgICAgICAgICAgICAgIGBnaXZlbiBtb250aGA9TkEsDQogICAgICAgICAgICAgICAgIGBwcmV2aW91cyBxdWFydGVyYD1OQSwNCiAgICAgICAgICAgICAgICAgYHByZXZpb3VzIHllYXJgPU5BLA0KICAgICAgICAgICAgICAgICBgcHJldmlvdXMgdHdvIHllYXJzYD1OQSkNCg0KZm9yIChpIGluIDE6Tikgew0KIHBsb3RkYXRhW2ksJ2Jhc2VsaW5lJ10gPC0gbWVhbihwbG90ZGF0YVtpK3NlcSgxMiw2MCwxMiksJ2N1cnJlbnQnXSkNCn0NCnBsb3RkYXRhWydnaXZlbiBtb250aCddIDwtIHBsb3RkYXRhWydjdXJyZW50J10tcGxvdGRhdGFbJ2Jhc2VsaW5lJ10NCnBsb3RkYXRhWydwcmV2aW91cyBxdWFydGVyJ10gPC0gYyhzdGF0czo6ZmlsdGVyKChwbG90ZGF0YVsnZ2l2ZW4gbW9udGgnXSkscmVwKDEvMywzKSxzaWRlcz0xKVszOmxlbmd0aChwbG90ZGF0YVtbMV1dKV0scmVwKE5BLDIpKQ0KcGxvdGRhdGFbJ3ByZXZpb3VzIHllYXInXSA8LSBjKHN0YXRzOjpmaWx0ZXIoKHBsb3RkYXRhWydnaXZlbiBtb250aCddKSxyZXAoMS8xMiwxMiksc2lkZXM9MSlbMTI6bGVuZ3RoKHBsb3RkYXRhW1sxXV0pXSxyZXAoTkEsMTEpKQ0KcGxvdGRhdGFbJ3ByZXZpb3VzIHR3byB5ZWFycyddIDwtIGMoc3RhdHM6OmZpbHRlcigocGxvdGRhdGFbJ2dpdmVuIG1vbnRoJ10pLHJlcCgxLzI0LDI0KSxzaWRlcz0xKVsyNDpsZW5ndGgocGxvdGRhdGFbWzFdXSldLHJlcChOQSwyMykpDQpnZ3Bsb3QoKSsNCiAgZ2VvbV9zdGVwKGFlcyh4PWRhdGUseT12YWx1ZSxjb2xvdXI9YGV4Y2VzcyBtb3J0YWxpdHlgKSxkYXRhPW1lbHQocGxvdGRhdGEsbWVhc3VyZS52YXJzID0gYygnZ2l2ZW4gbW9udGgnLCdwcmV2aW91cyBxdWFydGVyJywncHJldmlvdXMgeWVhcicsJ3ByZXZpb3VzIHR3byB5ZWFycycpLHZhcmlhYmxlLm5hbWUgPSAnZXhjZXNzIG1vcnRhbGl0eScpLGRpcmVjdGlvbj0idmgiLG5hLnJtPVRSVUUpKw0KICBzY2FsZV94X2RhdGUobGltaXRzPWMoYXMuRGF0ZSgiMjAwNi0wMS0wMSIpLE5BKSxkYXRlX2JyZWFrcz0iNSB5ZWFycyIsZGF0ZV9sYWJlbHM9IiViICVZIixkYXRlX21pbm9yX2JyZWFrcz0iMSB5ZWFyIikrDQogIHNjYWxlX3lfY29udGludW91cygiYWdlLXN0YW5kYXJkaXNlZCBtb3J0YWxpdHkgLzEwMCwwMDAiLGxpbWl0cyA9IGMoLTUwMCwxMDAwKSkrDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRXhjZXNzIG1vcnRhbGl0eSBieSBtb250aCBvZiByZWdpc3RyYXRpb24iLA0KICAgIHN1YnRpdGxlID0gcGFzdGUwKGNvdW50cnksJywgJyxzZXgsJywgJyxhZ2UpLA0KICAgIGNhcHRpb24gPSBhY2tub3dsZWRnZW1lbnQNCiAgICApDQpgYGANCg==