National Energy Board, Canada’s Energy Future 2016: Energy Supply and Demand Projections to 2040
National Energy Board, Canada’s Energy Future 2016: Energy Supply and Demand Projections to 2040
Electricity Generation.xlsx (Ontario table) -> NEB_generation.csv
Electricity Capacity.xlsx (Ontario table) -> NEB_capacity.csv
NEB Generation Projections (GWh)
NEB_generation <- transpose(read.csv("NEB_generation.csv", header = FALSE))
NEB_generation <- NEB_generation[-1,]
colnames(NEB_generation) <- c("Year","Hydro","Wind","Biomass_and_Geothermal","Solar","Uranium","Coal","Natural_Gas","Oil")
Start year is 2005
NEB_generation$Year <- NULL
NEB_generation$Hydro <- as.numeric(NEB_generation$Hydro)
NEB_generation$Wind <- as.numeric(NEB_generation$Wind)
NEB_generation$Biomass_and_Geothermal <- as.numeric(NEB_generation$Biomass_and_Geothermal)
NEB_generation$Solar <- as.numeric(NEB_generation$Solar)
NEB_generation$Uranium <- as.numeric(NEB_generation$Uranium)
NEB_generation$Coal <- as.numeric(NEB_generation$Coal)
NEB_generation$Natural_Gas <- as.numeric(NEB_generation$Natural_Gas)
NEB_generation$Oil <- as.numeric(NEB_generation$Oil)
NEB_generation$Total <- NEB_generation$Hydro+NEB_generation$Wind+NEB_generation$Biomass_and_Geothermal+NEB_generation$Solar+NEB_generation$Uranium+NEB_generation$Coal+NEB_generation$Natural_Gas+NEB_generation$Oil
NEB_generation.ts <- ts(NEB_generation, start = 2005, frequency = 1)
ggplot2::autoplot(NEB_generation.ts, ylab="GWh", main="Ontario Annual Electricity Generation Projections")
NEB Capacity Projections (MW)
NEB_capacity <- transpose(read.csv("NEB_capacity.csv", header = FALSE))
NEB_capacity <- NEB_capacity[-1,]
colnames(NEB_capacity) <- c("Year","Petroleum1","Petroleum2","Petroleum3","Coal", "Nuclear","Biomass_and_Geothermal","Solar","Wind","Hydro")
NEB_capacity$Year <- NULL
NEB_capacity$Petroleum <- as.numeric(NEB_capacity$Petroleum1) + as.numeric(NEB_capacity$Petroleum2) + as.numeric(NEB_capacity$Petroleum3)
NEB_capacity$Petroleum1 <- NULL
NEB_capacity$Petroleum2 <- NULL
NEB_capacity$Petroleum3 <- NULL
NEB_capacity$Coal <- as.numeric(NEB_capacity$Coal)
NEB_capacity$Nuclear <- as.numeric(NEB_capacity$Nuclear)
NEB_capacity$Biomass_and_Geothermal <- as.numeric(NEB_capacity$Biomass_and_Geothermal)
NEB_capacity$Solar <- as.numeric(NEB_capacity$Solar)
NEB_capacity$Wind <- as.numeric(NEB_capacity$Wind)
NEB_capacity$Hydro <- as.numeric(NEB_capacity$Hydro)
NEB_capacity$Total <- NEB_capacity$Petroleum+NEB_capacity$Coal+NEB_capacity$Nuclear+NEB_capacity$Biomass_and_Geothermal+NEB_capacity$Solar+NEB_capacity$Wind+NEB_capacity$Hydro
NEB_capacity.ts <- ts(NEB_capacity, start = 2005, frequency = 1)
ggplot2::autoplot(NEB_capacity.ts, ylab="MW", main="Ontario Annual Electricity Capacity Projections")
Monthly Electricity Supply and Disposition Survey (MELE), Ontario (MWh)
Statistics Canada, Monthly Electricity Supply and Disposition Survey (MELE)
Electric power generation, monthly generation by type of electricity. Table: 25-10-0015-01
MELE_generation <- read.csv("2510001501-noSymbol.csv")
MELE_generation$YEAR_MONTH <- NULL
MELE_generation.ts <- ts(MELE_generation, start = 2008, frequency = 12)
ggplot2::autoplot(MELE_generation.ts, ylab="MWh", main="Ontario Monthly Electricity Generation")
MELE_generation_total.ts <- ts(MELE_generation$Total, start = 2008, frequency = 12)
plot(MELE_generation_total.ts)
MELE_generation_total.ts.components <- decompose(MELE_generation_total.ts)
forecast::autoplot(MELE_generation_total.ts.components)
MELE_generation_total.ts.arima <- auto.arima(MELE_generation_total.ts)
MELE_generation_total.ts.arima
Series: MELE_generation_total.ts
ARIMA(1,1,1)(2,1,0)[12]
Coefficients:
ar1 ma1 sar1 sar2
0.6312 -0.9083 -0.6268 -0.3358
s.e. 0.1059 0.0604 0.0879 0.0850
sigma^2 estimated as 2.994e+11: log likelihood=-1786.41
AIC=3582.82 AICc=3583.34 BIC=3596.84
MELE_generation_total.ts.arima.forecast <- forecast(MELE_generation_total.ts.arima, level = c(95), h = 120)
forecast::autoplot(MELE_generation_total.ts.arima.forecast)
IESO
Independent Electricity System Operator (IESO), Data Directory
Hourly Generator Energy Output and Capability Report
Hourly Generator Energy Output and Capability Report
The Hourly Generator Energy Output and Capability Report presents the energy output and capability for generating facilities in the IESO-administered energy market with a maximum output capability of 20 MW or more.
http://reports.ieso.ca/docrefs/helpfile/GenOutputCapability_h4.pdf
Output is the actual energy production of the unit or facility. The hourly output is the facility’s five-minute outputs averaged over an hour.
Capability is the maximum potential output of the unit or facility under current conditions, which includes maximum unit derates and outages for that hour. In this report, Capability is provided for nuclear, hydro, gas, and biofuel generation (excluding wind and solar).
GOC-2010.xlsx - GOC-2019-Jan-April.xlsx -> IESO_output_2010.csv, IESO_capability_2010.csv - IESO_output_2019.csv, IESO_capability_2019.csv
observation for each hour, 2010 to April 2019
Robert J Hyman, Seasonal periods. forecast::msts
IESO_output_2010 <- fread("IESO_output_2010.csv")
IESO_output_2010$DATE <- NULL
IESO_output_2010$HOUR <- NULL
IESO_output_2010$TOTAL <- rowSums(IESO_output_2010, na.rm=TRUE)
IESO_output_2010 <- IESO_output_2010[,.(TOTAL)]
IESO_output_2011 <- fread("IESO_output_2011.csv")
IESO_output_2011$DATE <- NULL
IESO_output_2011$HOUR <- NULL
IESO_output_2011$TOTAL <- rowSums(IESO_output_2011, na.rm=TRUE)
IESO_output_2011 <- IESO_output_2011[,.(TOTAL)]
IESO_output_2012 <- fread("IESO_output_2012.csv")
IESO_output_2012$DATE <- NULL
IESO_output_2012$HOUR <- NULL
IESO_output_2012$TOTAL <- rowSums(IESO_output_2012, na.rm=TRUE)
IESO_output_2012 <- IESO_output_2012[,.(TOTAL)]
IESO_output_2012.ts <- msts(IESO_output_2012$TOTAL, seasonal.periods = c(24, 24*365.25), start=2012)
forecast::autoplot(IESO_output_2012.ts)
2012 Outliers
which(IESO_output_2012$TOTAL==0)
[1] 3947 7834
3947: DATE 13-Jun-12, HOUR 11
7834: DATE 22-Nov-12, HOUR 10
IESO_output_2012$TOTAL[3947]
[1] 0
IESO_output_2012$TOTAL[7834]
[1] 0
IESO_output_2012$TOTAL[3947] <- IESO_output_2012$TOTAL[3946]
IESO_output_2012$TOTAL[7834] <- IESO_output_2012$TOTAL[7833]
IESO_output_2012.ts <- msts(IESO_output_2012$TOTAL, seasonal.periods = c(24, 24*365.25), start=2012)
autoplot(IESO_output_2012.ts)
IESO_output_2013 <- fread("IESO_output_2013.csv")
IESO_output_2013$DATE <- NULL
IESO_output_2013$HOUR <- NULL
IESO_output_2013$TOTAL <- rowSums(IESO_output_2013, na.rm=TRUE)
IESO_output_2013 <- IESO_output_2013[,.(TOTAL)]
IESO_output_2014 <- fread("IESO_output_2014.csv")
IESO_output_2014$DATE <- NULL
IESO_output_2014$HOUR <- NULL
IESO_output_2014$TOTAL <- rowSums(IESO_output_2014, na.rm=TRUE)
IESO_output_2014 <- IESO_output_2014[,.(TOTAL)]
IESO_output_2015 <- fread("IESO_output_2015.csv")
IESO_output_2015 <- IESO_output_2015[,.(TOTAL)]
IESO_output_2016 <- fread("IESO_output_2016.csv")
IESO_output_2016 <- IESO_output_2016[,.(TOTAL)]
IESO_output_2016.ts <- msts(IESO_output_2015$TOTAL, seasonal.periods = c(24, 24*365.25), start=2016)
forecast::autoplot(IESO_output_2016.ts)
2016 Outliers
Autoregressive replacement of outlier values
for (t in which(IESO_output_2016$TOTAL<4000)){
IESO_output_2016$TOTAL[t] <- IESO_output_2016$TOTAL[t-1]
}
IESO_output_2017 <- fread("IESO_output_2017.csv")
IESO_output_2017 <- IESO_output_2017[,.(TOTAL)]
IESO_output_2018 <- fread("IESO_output_2018.csv")
IESO_output_2018 <- IESO_output_2018[,.(TOTAL)]
IESO_output_2019 <- fread("IESO_output_2019.csv")
IESO_output_2019$DATE <- NULL
IESO_output_2019$HOUR <- NULL
IESO_output_2019$TOTAL <- rowSums(IESO_output_2019, na.rm=TRUE)
IESO_output_2019 <- IESO_output_2019[,.(TOTAL)]
IESO_output_2010_to_2019 <- do.call("rbind",list(IESO_output_2010,IESO_output_2011,IESO_output_2012,
IESO_output_2013, IESO_output_2014, IESO_output_2015,
IESO_output_2016, IESO_output_2017, IESO_output_2018,
IESO_output_2019))
IESO_output_2010_to_2019.ts <- msts(IESO_output_2010_to_2019$TOTAL, seasonal.periods = c(24, 168, 8766), start=2010)
forecast::autoplot(IESO_output_2010_to_2019.ts)
IESO_output_2010_to_2019.ts.components <- mstl(IESO_output_2010_to_2019.ts)
forecast::autoplot(IESO_output_2010_to_2019.ts.components)
IESO_output_2010_to_2019.24.ts <- IESO_output_2010_to_2019.ts.components[, "Seasonal24"]
IESO_output_2010_to_2019.168.ts <- IESO_output_2010_to_2019.ts.components[, "Seasonal168"]
IESO_output_2010_to_2019.8766.ts <- IESO_output_2010_to_2019.ts.components[, "Seasonal8766"]
autoplot(subset(IESO_output_2010_to_2019.24.ts, end = 24*7*4))
autoplot(subset(IESO_output_2010_to_2019.168.ts, end = 24*7*4))
autoplot(subset(IESO_output_2010_to_2019.8766.ts, end = 24*7*52))
Realtime Constrained Totals Report (Ontario and Market Demand)
http://reports.ieso.ca/docrefs/helpfile/RealtimeConstTotals_h2.pdf
TOTAL ENERGY: Total energy dispatched into the IESO-controlled grid, calculated as Ontario generation plus imports
TOTAL LOSS: Total losses in the IESO-controlled grid, calculated by the load flow
TOTAL LOAD: Total system load, calculated as Total Energy - Total Loss
TOTAL DISP LOAD: Total MW withdrawn from the IESO-controlled grid by dispatchable load, where the value represents the system-wide amount of dispatchable load that was dispatched down. For example, if the load is bidding 100 MW and gets dispatched down to 90 MW, then the Total Disp Load quantity is 10 MW
ONTARIO DEMAND: Total Ontario electricity demand, calculated as:
Total Energy + Total Generation Without Offers - Total Exports + Total Off Market +/- Over/Under Generation
Hourly Demand Report
PUB_Demand_2002.csv - PUB_Demand_2019.csv (to July)
Demand_2010 <- fread("PUB_Demand_2010.csv")
Demand_2010 <- Demand_2010[,.(DEMAND = `Market Demand`)]
Demand_2011 <- fread("PUB_Demand_2011.csv")
Demand_2011 <- Demand_2011[,.(DEMAND = `Market Demand`)]
Demand_2012 <- fread("PUB_Demand_2012.csv")
Demand_2012 <- Demand_2012[,.(DEMAND = `Market Demand`)]
Demand_2013 <- fread("PUB_Demand_2013.csv")
Demand_2013 <- Demand_2013[,.(DEMAND = `Market Demand`)]
Demand_2014 <- fread("PUB_Demand_2014.csv")
Demand_2014 <- Demand_2014[,.(DEMAND = `Market Demand`)]
Demand_2015 <- fread("PUB_Demand_2015.csv")
Demand_2015 <- Demand_2015[,.(DEMAND = `Market Demand`)]
Demand_2016 <- fread("PUB_Demand_2016.csv")
Demand_2016 <- Demand_2016[,.(DEMAND = `Market Demand`)]
Demand_2017 <- fread("PUB_Demand_2017.csv")
Demand_2017 <- Demand_2017[,.(DEMAND = `Market Demand`)]
Demand_2018 <- fread("PUB_Demand_2018.csv")
Demand_2018 <- Demand_2018[,.(DEMAND = `Market Demand`)]
Demand_2019 <- fread("PUB_Demand_2019.csv")
Demand_2019 <- Demand_2019[,.(DEMAND = `Market Demand`)]
Demand_2010_to_2019 <- do.call("rbind",list(Demand_2010,Demand_2011,Demand_2012,
Demand_2013, Demand_2014, Demand_2015,
Demand_2016, Demand_2017, Demand_2018,
Demand_2019))
Demand_2010_to_2019.ts <- msts(Demand_2010_to_2019$DEMAND, seasonal.periods = c(24, 168, 8766), start=2010)
Demand_2010_to_2019.ts.components <- mstl(Demand_2010_to_2019.ts)
forecast::autoplot(Demand_2010_to_2019.ts.components)
attributes(Demand_2010_to_2019.ts.components)
$dim
[1] 83496 6
$dimnames
$dimnames[[1]]
NULL
$dimnames[[2]]
[1] "Data" "Trend" "Seasonal24" "Seasonal168" "Seasonal8766" "Remainder"
$tsp
[1] 2010.000 2019.525 8766.000
$class
[1] "mstl" "mts" "msts" "ts"
$seasonal.periods
[1] 24 168 8766
Demand_2010_to_2019.24.ts <- Demand_2010_to_2019.ts.components[, "Seasonal24"]
Demand_2010_to_2019.168.ts <- Demand_2010_to_2019.ts.components[, "Seasonal168"]
Demand_2010_to_2019.8766.ts <- Demand_2010_to_2019.ts.components[, "Seasonal8766"]
class(Demand_2010_to_2019.8766.ts)
[1] "msts" "ts"
autoplot(subset(Demand_2010_to_2019.Seasonal24.ts, end = 24*7*4))
Error in subset(Demand_2010_to_2019.Seasonal24.ts, end = 24 * 7 * 4) :
object 'Demand_2010_to_2019.Seasonal24.ts' not found
autoplot(subset(Demand_2010_to_2019.168.ts, end = 24*7*4))
autoplot(subset(Demand_2010_to_2019.8766.ts, end = 24*7*365))
Hourly Ontario Energy Price (HOEP)
Yearly Hourly HOEP OR Predispatch Report
PUB_PriceHOEPPredispOR_2002.csv - PUB_PriceHOEPPredispOR_2019.csv (to July)
HOEP_2010 <- fread("PUB_PriceHOEPPredispOR_2010.csv")
HOEP_2010 <- HOEP_2010[,.(HOEP)]
HOEP_2011 <- fread("PUB_PriceHOEPPredispOR_2011.csv")
HOEP_2011 <- HOEP_2011[,.(HOEP)]
HOEP_2012 <- fread("PUB_PriceHOEPPredispOR_2012.csv")
HOEP_2012 <- HOEP_2012[,.(HOEP)]
HOEP_2013 <- fread("PUB_PriceHOEPPredispOR_2013.csv")
HOEP_2013 <- HOEP_2013[,.(HOEP)]
HOEP_2014 <- fread("PUB_PriceHOEPPredispOR_2014.csv")
HOEP_2014 <- HOEP_2014[,.(HOEP)]
HOEP_2015 <- fread("PUB_PriceHOEPPredispOR_2015.csv")
HOEP_2015 <- HOEP_2015[,.(HOEP)]
HOEP_2016 <- fread("PUB_PriceHOEPPredispOR_2016.csv")
HOEP_2016 <- HOEP_2016[,.(HOEP)]
HOEP_2017 <- fread("PUB_PriceHOEPPredispOR_2017.csv")
HOEP_2017 <- HOEP_2017[,.(HOEP)]
HOEP_2018 <- fread("PUB_PriceHOEPPredispOR_2018.csv")
HOEP_2018 <- HOEP_2018[,.(HOEP)]
HOEP_2018.ts <- ts(HOEP_2018$HOEP, frequency = 24)
HOEP_2018.ts.components <- decompose(HOEP_2018.ts)
forecast::autoplot(HOEP_2018.ts.components)
autoplot(subset(HOEP_2018.ts.components$seasonal, end = 24*7*4))
HOEP_2019 <- fread("PUB_PriceHOEPPredispOR_2019.csv")
HOEP_2019 <- HOEP_2019[,.(HOEP)]
HOEP_2010_to_2019 <- do.call("rbind",list(HOEP_2010,HOEP_2011,HOEP_2012,
HOEP_2013, HOEP_2014, HOEP_2015,
HOEP_2016, HOEP_2017, HOEP_2018,
HOEP_2019))
HOEP_2010_to_2019.ts <- msts(HOEP_2010_to_2019$HOEP, seasonal.periods = c(24, 168, 8766), start=2010)
autoplot(HOEP_2010_to_2019.ts)
HOEP_2010_to_2019.ts.components <- mstl(HOEP_2010_to_2019.ts)
forecast::autoplot(HOEP_2010_to_2019.ts.components)
HOEP_2010_to_2019.24.ts <- HOEP_2010_to_2019.ts.components[, "Seasonal24"]
HOEP_2010_to_2019.168.ts <- HOEP_2010_to_2019.ts.components[, "Seasonal168"]
HOEP_2010_to_2019.8766.ts <- HOEP_2010_to_2019.ts.components[, "Seasonal8766"]
autoplot(subset(HOEP_2010_to_2019.24.ts, end = 24*7*4))
autoplot(subset(HOEP_2010_to_2019.168.ts, end = 24*7*4))
autoplot(subset(HOEP_2010_to_2019.8766.ts, end = 24*7*52))
autoplot(subset(HOEP_2010_to_2019.ts.components[,"Seasonal24"], end = 24*7*4))
LS0tDQp0aXRsZTogIk9udGFyaW8gRWxlY3RyaWNpdHkgR2VuZXJhdGlvbiwgRGVtYW5kLCBhbmQgUHJpY2UgVGltZXNlcmllcyINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIHRvYzogeWVzDQotLS0NCg0KIyBBdXRob3INCg0KKiBKb3JkYW4gQmVsbA0KKiBKdWx5IDIzLCAyMDE5DQoqIDxodHRwczovL2pvcmRhbmJlbGwyMzU3LmdpdGh1Yi5pby9JRVNPLm5iLmh0bWw+DQoNCmBgYHtyfQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0KbGlicmFyeShnZ2ZvcnRpZnkpICNhdXRvcGxvdA0KbGlicmFyeShmb3JlY2FzdCkgI2F1dG9wbG90LCBhdXRvLmFyaW1hDQpgYGANCg0KIyBOYXRpb25hbCBFbmVyZ3kgQm9hcmQsIENhbmFkYSdzIEVuZXJneSBGdXR1cmUgMjAxNjogRW5lcmd5IFN1cHBseSBhbmQgRGVtYW5kIFByb2plY3Rpb25zIHRvIDIwNDANCg0KTmF0aW9uYWwgRW5lcmd5IEJvYXJkLCBbQ2FuYWRh4oCZcyBFbmVyZ3kgRnV0dXJlIDIwMTY6IEVuZXJneSBTdXBwbHkgYW5kIERlbWFuZCBQcm9qZWN0aW9ucyB0byAyMDQwXShodHRwczovL2FwcHMubmViLW9uZS5nYy5jYS9mdHJwcG5kYzQvZGZsdC5hc3B4P0dvQ1RlbXBsYXRlQ3VsdHVyZT1lbi1DQSkNCg0KRWxlY3RyaWNpdHkgR2VuZXJhdGlvbi54bHN4IChPbnRhcmlvIHRhYmxlKSAtPiBORUJfZ2VuZXJhdGlvbi5jc3YNCg0KRWxlY3RyaWNpdHkgQ2FwYWNpdHkueGxzeCAoT250YXJpbyB0YWJsZSkgLT4gTkVCX2NhcGFjaXR5LmNzdg0KDQojIyBORUIgR2VuZXJhdGlvbiBQcm9qZWN0aW9ucyAoR1doKQ0KDQpgYGB7cn0NCk5FQl9nZW5lcmF0aW9uIDwtIHRyYW5zcG9zZShyZWFkLmNzdigiTkVCX2dlbmVyYXRpb24uY3N2IiwgaGVhZGVyID0gRkFMU0UpKQ0KDQpORUJfZ2VuZXJhdGlvbiA8LSBORUJfZ2VuZXJhdGlvblstMSxdDQoNCmNvbG5hbWVzKE5FQl9nZW5lcmF0aW9uKSA8LSBjKCJZZWFyIiwiSHlkcm8iLCJXaW5kIiwiQmlvbWFzc19hbmRfR2VvdGhlcm1hbCIsIlNvbGFyIiwiVXJhbml1bSIsIkNvYWwiLCJOYXR1cmFsX0dhcyIsIk9pbCIpDQpgYGANCg0KU3RhcnQgeWVhciBpcyAyMDA1DQoNCmBgYHtyfQ0KTkVCX2dlbmVyYXRpb24kWWVhciA8LSBOVUxMDQoNCk5FQl9nZW5lcmF0aW9uJEh5ZHJvIDwtIGFzLm51bWVyaWMoTkVCX2dlbmVyYXRpb24kSHlkcm8pDQoNCk5FQl9nZW5lcmF0aW9uJFdpbmQgPC0gYXMubnVtZXJpYyhORUJfZ2VuZXJhdGlvbiRXaW5kKQ0KDQpORUJfZ2VuZXJhdGlvbiRCaW9tYXNzX2FuZF9HZW90aGVybWFsIDwtIGFzLm51bWVyaWMoTkVCX2dlbmVyYXRpb24kQmlvbWFzc19hbmRfR2VvdGhlcm1hbCkNCg0KTkVCX2dlbmVyYXRpb24kU29sYXIgPC0gYXMubnVtZXJpYyhORUJfZ2VuZXJhdGlvbiRTb2xhcikNCg0KTkVCX2dlbmVyYXRpb24kVXJhbml1bSA8LSBhcy5udW1lcmljKE5FQl9nZW5lcmF0aW9uJFVyYW5pdW0pDQoNCk5FQl9nZW5lcmF0aW9uJENvYWwgPC0gYXMubnVtZXJpYyhORUJfZ2VuZXJhdGlvbiRDb2FsKQ0KDQpORUJfZ2VuZXJhdGlvbiROYXR1cmFsX0dhcyA8LSBhcy5udW1lcmljKE5FQl9nZW5lcmF0aW9uJE5hdHVyYWxfR2FzKQ0KDQpORUJfZ2VuZXJhdGlvbiRPaWwgPC0gYXMubnVtZXJpYyhORUJfZ2VuZXJhdGlvbiRPaWwpDQoNCk5FQl9nZW5lcmF0aW9uJFRvdGFsIDwtIE5FQl9nZW5lcmF0aW9uJEh5ZHJvK05FQl9nZW5lcmF0aW9uJFdpbmQrTkVCX2dlbmVyYXRpb24kQmlvbWFzc19hbmRfR2VvdGhlcm1hbCtORUJfZ2VuZXJhdGlvbiRTb2xhcitORUJfZ2VuZXJhdGlvbiRVcmFuaXVtK05FQl9nZW5lcmF0aW9uJENvYWwrTkVCX2dlbmVyYXRpb24kTmF0dXJhbF9HYXMrTkVCX2dlbmVyYXRpb24kT2lsDQpgYGANCg0KYGBge3J9DQpORUJfZ2VuZXJhdGlvbi50cyA8LSB0cyhORUJfZ2VuZXJhdGlvbiwgc3RhcnQgPSAyMDA1LCBmcmVxdWVuY3kgPSAxKQ0KDQpnZ3Bsb3QyOjphdXRvcGxvdChORUJfZ2VuZXJhdGlvbi50cywgeWxhYj0iR1doIiwgbWFpbj0iT250YXJpbyBBbm51YWwgRWxlY3RyaWNpdHkgR2VuZXJhdGlvbiBQcm9qZWN0aW9ucyIpDQpgYGANCg0KIyMgTkVCIENhcGFjaXR5IFByb2plY3Rpb25zIChNVykNCg0KYGBge3J9DQpORUJfY2FwYWNpdHkgPC0gdHJhbnNwb3NlKHJlYWQuY3N2KCJORUJfY2FwYWNpdHkuY3N2IiwgaGVhZGVyID0gRkFMU0UpKQ0KDQpORUJfY2FwYWNpdHkgPC0gTkVCX2NhcGFjaXR5Wy0xLF0NCg0KY29sbmFtZXMoTkVCX2NhcGFjaXR5KSA8LSBjKCJZZWFyIiwiUGV0cm9sZXVtMSIsIlBldHJvbGV1bTIiLCJQZXRyb2xldW0zIiwiQ29hbCIsICJOdWNsZWFyIiwiQmlvbWFzc19hbmRfR2VvdGhlcm1hbCIsIlNvbGFyIiwiV2luZCIsIkh5ZHJvIikNCg0KTkVCX2NhcGFjaXR5JFllYXIgPC0gTlVMTA0KDQpORUJfY2FwYWNpdHkkUGV0cm9sZXVtIDwtIGFzLm51bWVyaWMoTkVCX2NhcGFjaXR5JFBldHJvbGV1bTEpICsgYXMubnVtZXJpYyhORUJfY2FwYWNpdHkkUGV0cm9sZXVtMikgKyBhcy5udW1lcmljKE5FQl9jYXBhY2l0eSRQZXRyb2xldW0zKQ0KDQpORUJfY2FwYWNpdHkkUGV0cm9sZXVtMSA8LSBOVUxMDQoNCk5FQl9jYXBhY2l0eSRQZXRyb2xldW0yIDwtIE5VTEwNCg0KTkVCX2NhcGFjaXR5JFBldHJvbGV1bTMgPC0gTlVMTA0KDQpORUJfY2FwYWNpdHkkQ29hbCA8LSBhcy5udW1lcmljKE5FQl9jYXBhY2l0eSRDb2FsKQ0KDQpORUJfY2FwYWNpdHkkTnVjbGVhciA8LSBhcy5udW1lcmljKE5FQl9jYXBhY2l0eSROdWNsZWFyKQ0KDQpORUJfY2FwYWNpdHkkQmlvbWFzc19hbmRfR2VvdGhlcm1hbCA8LSBhcy5udW1lcmljKE5FQl9jYXBhY2l0eSRCaW9tYXNzX2FuZF9HZW90aGVybWFsKQ0KDQpORUJfY2FwYWNpdHkkU29sYXIgPC0gYXMubnVtZXJpYyhORUJfY2FwYWNpdHkkU29sYXIpDQoNCk5FQl9jYXBhY2l0eSRXaW5kIDwtIGFzLm51bWVyaWMoTkVCX2NhcGFjaXR5JFdpbmQpDQoNCk5FQl9jYXBhY2l0eSRIeWRybyA8LSBhcy5udW1lcmljKE5FQl9jYXBhY2l0eSRIeWRybykNCg0KTkVCX2NhcGFjaXR5JFRvdGFsIDwtIE5FQl9jYXBhY2l0eSRQZXRyb2xldW0rTkVCX2NhcGFjaXR5JENvYWwrTkVCX2NhcGFjaXR5JE51Y2xlYXIrTkVCX2NhcGFjaXR5JEJpb21hc3NfYW5kX0dlb3RoZXJtYWwrTkVCX2NhcGFjaXR5JFNvbGFyK05FQl9jYXBhY2l0eSRXaW5kK05FQl9jYXBhY2l0eSRIeWRybw0KYGBgDQoNCmBgYHtyfQ0KTkVCX2NhcGFjaXR5LnRzIDwtIHRzKE5FQl9jYXBhY2l0eSwgc3RhcnQgPSAyMDA1LCBmcmVxdWVuY3kgPSAxKQ0KDQpnZ3Bsb3QyOjphdXRvcGxvdChORUJfY2FwYWNpdHkudHMsIHlsYWI9Ik1XIiwgbWFpbj0iT250YXJpbyBBbm51YWwgRWxlY3RyaWNpdHkgQ2FwYWNpdHkgUHJvamVjdGlvbnMiKQ0KYGBgDQoNCiMgTW9udGhseSBFbGVjdHJpY2l0eSBTdXBwbHkgYW5kIERpc3Bvc2l0aW9uIFN1cnZleSAoTUVMRSksIE9udGFyaW8gKE1XaCkNCg0KU3RhdGlzdGljcyBDYW5hZGEsIE1vbnRobHkgRWxlY3RyaWNpdHkgU3VwcGx5IGFuZCBEaXNwb3NpdGlvbiBTdXJ2ZXkgKE1FTEUpDQoNCkVsZWN0cmljIHBvd2VyIGdlbmVyYXRpb24sIG1vbnRobHkgZ2VuZXJhdGlvbiBieSB0eXBlIG9mIGVsZWN0cmljaXR5LiBbVGFibGU6IDI1LTEwLTAwMTUtMDFdKGh0dHBzOi8vd3d3MTUwLnN0YXRjYW4uZ2MuY2EvdDEvdGJsMS9lbi9jdiFyZWNyZWF0ZS5hY3Rpb24/cGlkPTI1MTAwMDE1MDEmc2VsZWN0ZWROb2RlSWRzPTFENywzRDIsM0QzLDNENCwzRDUsM0Q2LDNENywzRDgsM0Q5LDNEMTAsM0QxMSZjaGVja2VkTGV2ZWxzPTFEMSwyRDEmcmVmUGVyaW9kcz0yMDA4MDEwMSwyMDE5MDMwMSZkaW1lbnNpb25MYXlvdXRzPWxheW91dDMsbGF5b3V0MyxsYXlvdXQyLGxheW91dDMmdmVjdG9yRGlzcGxheT1mYWxzZSkNCg0KYGBge3J9DQpNRUxFX2dlbmVyYXRpb24gPC0gcmVhZC5jc3YoIjI1MTAwMDE1MDEtbm9TeW1ib2wuY3N2IikNCmBgYA0KDQpgYGB7cn0NCk1FTEVfZ2VuZXJhdGlvbiRZRUFSX01PTlRIIDwtIE5VTEwNCg0KTUVMRV9nZW5lcmF0aW9uLnRzIDwtIHRzKE1FTEVfZ2VuZXJhdGlvbiwgc3RhcnQgPSAyMDA4LCBmcmVxdWVuY3kgPSAxMikNCg0KZ2dwbG90Mjo6YXV0b3Bsb3QoTUVMRV9nZW5lcmF0aW9uLnRzLCB5bGFiPSJNV2giLCBtYWluPSJPbnRhcmlvIE1vbnRobHkgRWxlY3RyaWNpdHkgR2VuZXJhdGlvbiIpDQpgYGANCg0KYGBge3J9DQpNRUxFX2dlbmVyYXRpb25fdG90YWwudHMgPC0gdHMoTUVMRV9nZW5lcmF0aW9uJFRvdGFsLCBzdGFydCA9IDIwMDgsIGZyZXF1ZW5jeSA9IDEyKQ0KDQpwbG90KE1FTEVfZ2VuZXJhdGlvbl90b3RhbC50cykNCmBgYA0KDQpgYGB7cn0NCk1FTEVfZ2VuZXJhdGlvbl90b3RhbC50cy5jb21wb25lbnRzIDwtIGRlY29tcG9zZShNRUxFX2dlbmVyYXRpb25fdG90YWwudHMpDQoNCmZvcmVjYXN0OjphdXRvcGxvdChNRUxFX2dlbmVyYXRpb25fdG90YWwudHMuY29tcG9uZW50cykNCmBgYA0KDQpgYGB7cn0NCk1FTEVfZ2VuZXJhdGlvbl90b3RhbC50cy5hcmltYSA8LSBhdXRvLmFyaW1hKE1FTEVfZ2VuZXJhdGlvbl90b3RhbC50cykNCg0KTUVMRV9nZW5lcmF0aW9uX3RvdGFsLnRzLmFyaW1hDQpgYGANCg0KYGBge3J9DQpNRUxFX2dlbmVyYXRpb25fdG90YWwudHMuYXJpbWEuZm9yZWNhc3QgPC0gZm9yZWNhc3QoTUVMRV9nZW5lcmF0aW9uX3RvdGFsLnRzLmFyaW1hLCBsZXZlbCA9IGMoOTUpLCBoID0gMTIwKQ0KDQpmb3JlY2FzdDo6YXV0b3Bsb3QoTUVMRV9nZW5lcmF0aW9uX3RvdGFsLnRzLmFyaW1hLmZvcmVjYXN0KQ0KYGBgDQoNCiMgSUVTTw0KDQpJbmRlcGVuZGVudCBFbGVjdHJpY2l0eSBTeXN0ZW0gT3BlcmF0b3IgKElFU08pLCBbRGF0YSBEaXJlY3RvcnldKGh0dHA6Ly9pZXNvLmNhL2VuL1Bvd2VyLURhdGEvRGF0YS1EaXJlY3RvcnkpDQoNCiMjIEhvdXJseSBHZW5lcmF0b3IgRW5lcmd5IE91dHB1dCBhbmQgQ2FwYWJpbGl0eSBSZXBvcnQNCg0KSG91cmx5IEdlbmVyYXRvciBFbmVyZ3kgT3V0cHV0IGFuZCBDYXBhYmlsaXR5IFJlcG9ydA0KDQo+IFRoZSBIb3VybHkgR2VuZXJhdG9yIEVuZXJneSBPdXRwdXQgYW5kIENhcGFiaWxpdHkgUmVwb3J0IHByZXNlbnRzIHRoZSBlbmVyZ3kgb3V0cHV0IGFuZCBjYXBhYmlsaXR5IGZvciBnZW5lcmF0aW5nIGZhY2lsaXRpZXMgaW4gdGhlIElFU08tYWRtaW5pc3RlcmVkIGVuZXJneSBtYXJrZXQgd2l0aCBhIG1heGltdW0gb3V0cHV0IGNhcGFiaWxpdHkgb2YgMjAgTVcgb3IgbW9yZS4NCg0KPGh0dHA6Ly9yZXBvcnRzLmllc28uY2EvZG9jcmVmcy9oZWxwZmlsZS9HZW5PdXRwdXRDYXBhYmlsaXR5X2g0LnBkZj4NCg0KPiAqKk91dHB1dCoqIGlzIHRoZSBhY3R1YWwgZW5lcmd5IHByb2R1Y3Rpb24gb2YgdGhlIHVuaXQgb3IgZmFjaWxpdHkuIFRoZSBob3VybHkgb3V0cHV0IGlzIHRoZSBmYWNpbGl0eeKAmXMgZml2ZS1taW51dGUNCm91dHB1dHMgYXZlcmFnZWQgb3ZlciBhbiBob3VyLiANCj4NCj4gKipDYXBhYmlsaXR5KiogaXMgdGhlIG1heGltdW0gcG90ZW50aWFsIG91dHB1dCBvZiB0aGUgdW5pdCBvciBmYWNpbGl0eSB1bmRlciBjdXJyZW50IGNvbmRpdGlvbnMsIHdoaWNoIGluY2x1ZGVzDQptYXhpbXVtIHVuaXQgZGVyYXRlcyBhbmQgb3V0YWdlcyBmb3IgdGhhdCBob3VyLiBJbiB0aGlzIHJlcG9ydCwgQ2FwYWJpbGl0eSBpcyBwcm92aWRlZCBmb3IgbnVjbGVhciwgaHlkcm8sIGdhcywNCmFuZCBiaW9mdWVsIGdlbmVyYXRpb24gKGV4Y2x1ZGluZyB3aW5kIGFuZCBzb2xhcikuIA0KDQpHT0MtMjAxMC54bHN4IC0gR09DLTIwMTktSmFuLUFwcmlsLnhsc3ggLT4gSUVTT19vdXRwdXRfMjAxMC5jc3YsIElFU09fY2FwYWJpbGl0eV8yMDEwLmNzdiAtDQpJRVNPX291dHB1dF8yMDE5LmNzdiwgSUVTT19jYXBhYmlsaXR5XzIwMTkuY3N2DQoNCm9ic2VydmF0aW9uIGZvciBlYWNoIGhvdXIsIDIwMTAgdG8gQXByaWwgMjAxOQ0KDQpSb2JlcnQgSiBIeW1hbiwgW1NlYXNvbmFsIHBlcmlvZHNdKGh0dHBzOi8vcm9iamh5bmRtYW4uY29tL2h5bmRzaWdodC9zZWFzb25hbC1wZXJpb2RzLykuDQpbZm9yZWNhc3Q6Om1zdHNdKGh0dHBzOi8vd3d3LnJkb2N1bWVudGF0aW9uLm9yZy9wYWNrYWdlcy9mb3JlY2FzdC92ZXJzaW9ucy84LjcvdG9waWNzL21zdHMpDQoNCmBgYHtyfQ0KSUVTT19vdXRwdXRfMjAxMCA8LSBmcmVhZCgiSUVTT19vdXRwdXRfMjAxMC5jc3YiKQ0KDQpJRVNPX291dHB1dF8yMDEwJERBVEUgPC0gTlVMTA0KDQpJRVNPX291dHB1dF8yMDEwJEhPVVIgPC0gTlVMTA0KDQpJRVNPX291dHB1dF8yMDEwJFRPVEFMIDwtIHJvd1N1bXMoSUVTT19vdXRwdXRfMjAxMCwgbmEucm09VFJVRSkNCg0KSUVTT19vdXRwdXRfMjAxMCA8LSBJRVNPX291dHB1dF8yMDEwWywuKFRPVEFMKV0NCmBgYA0KDQpgYGB7cn0NCklFU09fb3V0cHV0XzIwMTEgPC0gZnJlYWQoIklFU09fb3V0cHV0XzIwMTEuY3N2IikNCg0KSUVTT19vdXRwdXRfMjAxMSREQVRFIDwtIE5VTEwNCg0KSUVTT19vdXRwdXRfMjAxMSRIT1VSIDwtIE5VTEwNCg0KSUVTT19vdXRwdXRfMjAxMSRUT1RBTCA8LSByb3dTdW1zKElFU09fb3V0cHV0XzIwMTEsIG5hLnJtPVRSVUUpDQoNCklFU09fb3V0cHV0XzIwMTEgPC0gSUVTT19vdXRwdXRfMjAxMVssLihUT1RBTCldDQpgYGANCg0KYGBge3J9DQpJRVNPX291dHB1dF8yMDEyIDwtIGZyZWFkKCJJRVNPX291dHB1dF8yMDEyLmNzdiIpDQoNCklFU09fb3V0cHV0XzIwMTIkREFURSA8LSBOVUxMDQoNCklFU09fb3V0cHV0XzIwMTIkSE9VUiA8LSBOVUxMDQoNCklFU09fb3V0cHV0XzIwMTIkVE9UQUwgPC0gcm93U3VtcyhJRVNPX291dHB1dF8yMDEyLCBuYS5ybT1UUlVFKQ0KDQpJRVNPX291dHB1dF8yMDEyIDwtIElFU09fb3V0cHV0XzIwMTJbLC4oVE9UQUwpXQ0KDQpJRVNPX291dHB1dF8yMDEyLnRzIDwtIG1zdHMoSUVTT19vdXRwdXRfMjAxMiRUT1RBTCwgc2Vhc29uYWwucGVyaW9kcyA9IGMoMjQsIDI0KjM2NS4yNSksIHN0YXJ0PTIwMTIpDQpgYGANCg0KYGBge3J9DQpmb3JlY2FzdDo6YXV0b3Bsb3QoSUVTT19vdXRwdXRfMjAxMi50cykNCmBgYA0KDQojIyMgMjAxMiBPdXRsaWVycw0KDQpgYGB7cn0NCndoaWNoKElFU09fb3V0cHV0XzIwMTIkVE9UQUw9PTApDQpgYGANCg0KMzk0NzogREFURSAxMy1KdW4tMTIsIEhPVVIgMTENCg0KNzgzNDogREFURSAyMi1Ob3YtMTIsIEhPVVIgMTANCg0KYGBge3J9DQpJRVNPX291dHB1dF8yMDEyJFRPVEFMWzM5NDddDQpgYGANCg0KYGBge3J9DQpJRVNPX291dHB1dF8yMDEyJFRPVEFMWzc4MzRdDQpgYGANCg0KYGBge3J9DQpJRVNPX291dHB1dF8yMDEyJFRPVEFMWzM5NDddIDwtIElFU09fb3V0cHV0XzIwMTIkVE9UQUxbMzk0Nl0NCg0KSUVTT19vdXRwdXRfMjAxMiRUT1RBTFs3ODM0XSA8LSBJRVNPX291dHB1dF8yMDEyJFRPVEFMWzc4MzNdDQoNCklFU09fb3V0cHV0XzIwMTIudHMgPC0gbXN0cyhJRVNPX291dHB1dF8yMDEyJFRPVEFMLCBzZWFzb25hbC5wZXJpb2RzID0gYygyNCwgMjQqMzY1LjI1KSwgc3RhcnQ9MjAxMikNCg0KYXV0b3Bsb3QoSUVTT19vdXRwdXRfMjAxMi50cykNCmBgYA0KDQpgYGB7cn0NCklFU09fb3V0cHV0XzIwMTMgPC0gZnJlYWQoIklFU09fb3V0cHV0XzIwMTMuY3N2IikNCg0KSUVTT19vdXRwdXRfMjAxMyREQVRFIDwtIE5VTEwNCg0KSUVTT19vdXRwdXRfMjAxMyRIT1VSIDwtIE5VTEwNCg0KSUVTT19vdXRwdXRfMjAxMyRUT1RBTCA8LSByb3dTdW1zKElFU09fb3V0cHV0XzIwMTMsIG5hLnJtPVRSVUUpDQoNCklFU09fb3V0cHV0XzIwMTMgPC0gSUVTT19vdXRwdXRfMjAxM1ssLihUT1RBTCldDQpgYGANCg0KYGBge3J9DQpJRVNPX291dHB1dF8yMDE0IDwtIGZyZWFkKCJJRVNPX291dHB1dF8yMDE0LmNzdiIpDQoNCklFU09fb3V0cHV0XzIwMTQkREFURSA8LSBOVUxMDQoNCklFU09fb3V0cHV0XzIwMTQkSE9VUiA8LSBOVUxMDQoNCklFU09fb3V0cHV0XzIwMTQkVE9UQUwgPC0gcm93U3VtcyhJRVNPX291dHB1dF8yMDE0LCBuYS5ybT1UUlVFKQ0KDQpJRVNPX291dHB1dF8yMDE0IDwtIElFU09fb3V0cHV0XzIwMTRbLC4oVE9UQUwpXQ0KYGBgDQoNCmBgYHtyfQ0KSUVTT19vdXRwdXRfMjAxNSA8LSBmcmVhZCgiSUVTT19vdXRwdXRfMjAxNS5jc3YiKQ0KDQpJRVNPX291dHB1dF8yMDE1IDwtIElFU09fb3V0cHV0XzIwMTVbLC4oVE9UQUwpXQ0KYGBgDQoNCmBgYHtyfQ0KSUVTT19vdXRwdXRfMjAxNiA8LSBmcmVhZCgiSUVTT19vdXRwdXRfMjAxNi5jc3YiKQ0KDQpJRVNPX291dHB1dF8yMDE2IDwtIElFU09fb3V0cHV0XzIwMTZbLC4oVE9UQUwpXQ0KDQpJRVNPX291dHB1dF8yMDE2LnRzIDwtIG1zdHMoSUVTT19vdXRwdXRfMjAxNSRUT1RBTCwgc2Vhc29uYWwucGVyaW9kcyA9IGMoMjQsIDI0KjM2NS4yNSksIHN0YXJ0PTIwMTYpDQpgYGANCg0KYGBge3J9DQpmb3JlY2FzdDo6YXV0b3Bsb3QoSUVTT19vdXRwdXRfMjAxNi50cykNCmBgYA0KDQojIyMgMjAxNiBPdXRsaWVycw0KDQpBdXRvcmVncmVzc2l2ZSByZXBsYWNlbWVudCBvZiBvdXRsaWVyIHZhbHVlcw0KDQpgYGB7cn0NCmZvciAodCBpbiB3aGljaChJRVNPX291dHB1dF8yMDE2JFRPVEFMPDQwMDApKXsNCiAgSUVTT19vdXRwdXRfMjAxNiRUT1RBTFt0XSA8LSBJRVNPX291dHB1dF8yMDE2JFRPVEFMW3QtMV0gDQp9DQpgYGANCg0KYGBge3J9DQpJRVNPX291dHB1dF8yMDE3IDwtIGZyZWFkKCJJRVNPX291dHB1dF8yMDE3LmNzdiIpDQoNCklFU09fb3V0cHV0XzIwMTcgPC0gSUVTT19vdXRwdXRfMjAxN1ssLihUT1RBTCldDQpgYGANCg0KYGBge3J9DQpJRVNPX291dHB1dF8yMDE4IDwtIGZyZWFkKCJJRVNPX291dHB1dF8yMDE4LmNzdiIpDQoNCklFU09fb3V0cHV0XzIwMTggPC0gSUVTT19vdXRwdXRfMjAxOFssLihUT1RBTCldDQpgYGANCg0KYGBge3J9DQpJRVNPX291dHB1dF8yMDE5IDwtIGZyZWFkKCJJRVNPX291dHB1dF8yMDE5LmNzdiIpDQoNCklFU09fb3V0cHV0XzIwMTkkREFURSA8LSBOVUxMDQoNCklFU09fb3V0cHV0XzIwMTkkSE9VUiA8LSBOVUxMDQoNCklFU09fb3V0cHV0XzIwMTkkVE9UQUwgPC0gcm93U3VtcyhJRVNPX291dHB1dF8yMDE5LCBuYS5ybT1UUlVFKQ0KDQpJRVNPX291dHB1dF8yMDE5IDwtIElFU09fb3V0cHV0XzIwMTlbLC4oVE9UQUwpXQ0KYGBgDQoNCmBgYHtyfQ0KSUVTT19vdXRwdXRfMjAxMF90b18yMDE5IDwtIGRvLmNhbGwoInJiaW5kIixsaXN0KElFU09fb3V0cHV0XzIwMTAsSUVTT19vdXRwdXRfMjAxMSxJRVNPX291dHB1dF8yMDEyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIElFU09fb3V0cHV0XzIwMTMsIElFU09fb3V0cHV0XzIwMTQsIElFU09fb3V0cHV0XzIwMTUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSUVTT19vdXRwdXRfMjAxNiwgSUVTT19vdXRwdXRfMjAxNywgSUVTT19vdXRwdXRfMjAxOCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJRVNPX291dHB1dF8yMDE5KSkNCmBgYA0KDQpgYGB7cn0NCklFU09fb3V0cHV0XzIwMTBfdG9fMjAxOS50cyA8LSBtc3RzKElFU09fb3V0cHV0XzIwMTBfdG9fMjAxOSRUT1RBTCwgc2Vhc29uYWwucGVyaW9kcyA9IGMoMjQsIDE2OCwgODc2NiksIHN0YXJ0PTIwMTApDQpgYGANCg0KYGBge3J9DQpmb3JlY2FzdDo6YXV0b3Bsb3QoSUVTT19vdXRwdXRfMjAxMF90b18yMDE5LnRzKQ0KYGBgDQoNCmBgYHtyfQ0KSUVTT19vdXRwdXRfMjAxMF90b18yMDE5LnRzLmNvbXBvbmVudHMgPC0gbXN0bChJRVNPX291dHB1dF8yMDEwX3RvXzIwMTkudHMpDQoNCmZvcmVjYXN0OjphdXRvcGxvdChJRVNPX291dHB1dF8yMDEwX3RvXzIwMTkudHMuY29tcG9uZW50cykNCmBgYA0KDQpgYGB7cn0NCklFU09fb3V0cHV0XzIwMTBfdG9fMjAxOS4yNC50cyA8LSBJRVNPX291dHB1dF8yMDEwX3RvXzIwMTkudHMuY29tcG9uZW50c1ssICJTZWFzb25hbDI0Il0NCg0KSUVTT19vdXRwdXRfMjAxMF90b18yMDE5LjE2OC50cyA8LSBJRVNPX291dHB1dF8yMDEwX3RvXzIwMTkudHMuY29tcG9uZW50c1ssICJTZWFzb25hbDE2OCJdDQoNCklFU09fb3V0cHV0XzIwMTBfdG9fMjAxOS44NzY2LnRzIDwtIElFU09fb3V0cHV0XzIwMTBfdG9fMjAxOS50cy5jb21wb25lbnRzWywgIlNlYXNvbmFsODc2NiJdDQoNCmF1dG9wbG90KHN1YnNldChJRVNPX291dHB1dF8yMDEwX3RvXzIwMTkuMjQudHMsIGVuZCA9IDI0KjcqNCkpDQpgYGANCg0KYGBge3J9DQphdXRvcGxvdChzdWJzZXQoSUVTT19vdXRwdXRfMjAxMF90b18yMDE5LjE2OC50cywgZW5kID0gMjQqNyo0KSkNCmBgYA0KDQpgYGB7cn0NCmF1dG9wbG90KHN1YnNldChJRVNPX291dHB1dF8yMDEwX3RvXzIwMTkuODc2Ni50cywgZW5kID0gMjQqNyo1MikpDQpgYGANCg0KDQojIyBSZWFsdGltZSBDb25zdHJhaW5lZCBUb3RhbHMgUmVwb3J0IChPbnRhcmlvIGFuZCBNYXJrZXQgRGVtYW5kKQ0KDQo8aHR0cDovL3JlcG9ydHMuaWVzby5jYS9kb2NyZWZzL2hlbHBmaWxlL1JlYWx0aW1lQ29uc3RUb3RhbHNfaDIucGRmPg0KDQo+IFRPVEFMIEVORVJHWTogVG90YWwgZW5lcmd5IGRpc3BhdGNoZWQgaW50byB0aGUgSUVTTy1jb250cm9sbGVkIGdyaWQsIGNhbGN1bGF0ZWQgYXMgT250YXJpbw0KZ2VuZXJhdGlvbiBwbHVzIGltcG9ydHMNCj4NCj4gVE9UQUwgTE9TUzogVG90YWwgbG9zc2VzIGluIHRoZSBJRVNPLWNvbnRyb2xsZWQgZ3JpZCwgY2FsY3VsYXRlZCBieSB0aGUgbG9hZCBmbG93DQo+DQo+IFRPVEFMIExPQUQ6IFRvdGFsIHN5c3RlbSBsb2FkLCBjYWxjdWxhdGVkIGFzIFRvdGFsIEVuZXJneSAtIFRvdGFsIExvc3MNCj4NCj4gVE9UQUwgRElTUCBMT0FEOiBUb3RhbCBNVyB3aXRoZHJhd24gZnJvbSB0aGUgSUVTTy1jb250cm9sbGVkIGdyaWQgYnkgZGlzcGF0Y2hhYmxlIGxvYWQsIHdoZXJlDQp0aGUgdmFsdWUgcmVwcmVzZW50cyB0aGUgc3lzdGVtLXdpZGUgYW1vdW50IG9mIGRpc3BhdGNoYWJsZSBsb2FkIHRoYXQgd2FzDQpkaXNwYXRjaGVkIGRvd24uIEZvciBleGFtcGxlLCBpZiB0aGUgbG9hZCBpcyBiaWRkaW5nIDEwMCBNVyBhbmQgZ2V0cw0KZGlzcGF0Y2hlZCBkb3duIHRvIDkwIE1XLCB0aGVuIHRoZSBUb3RhbCBEaXNwIExvYWQgcXVhbnRpdHkgaXMgMTAgTVcNCj4NCj4gT05UQVJJTyBERU1BTkQ6IFRvdGFsIE9udGFyaW8gZWxlY3RyaWNpdHkgZGVtYW5kLCBjYWxjdWxhdGVkIGFzOiANCj4NCj4gVG90YWwgRW5lcmd5ICsgVG90YWwgR2VuZXJhdGlvbiBXaXRob3V0IE9mZmVycyAtIFRvdGFsIEV4cG9ydHMgKyBUb3RhbCBPZmYgTWFya2V0ICsvLSBPdmVyL1VuZGVyDQpHZW5lcmF0aW9uDQoNCltIb3VybHkgRGVtYW5kIFJlcG9ydF0oaHR0cDovL3JlcG9ydHMuaWVzby5jYS9wdWJsaWMvRGVtYW5kLykNCg0KUFVCX0RlbWFuZF8yMDAyLmNzdiAtIFBVQl9EZW1hbmRfMjAxOS5jc3YgKHRvIEp1bHkpDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTAgPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxMC5jc3YiKQ0KDQpEZW1hbmRfMjAxMCA8LSBEZW1hbmRfMjAxMFssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTEgPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxMS5jc3YiKQ0KDQpEZW1hbmRfMjAxMSA8LSBEZW1hbmRfMjAxMVssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTIgPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxMi5jc3YiKQ0KDQpEZW1hbmRfMjAxMiA8LSBEZW1hbmRfMjAxMlssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTMgPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxMy5jc3YiKQ0KDQpEZW1hbmRfMjAxMyA8LSBEZW1hbmRfMjAxM1ssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTQgPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxNC5jc3YiKQ0KDQpEZW1hbmRfMjAxNCA8LSBEZW1hbmRfMjAxNFssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTUgPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxNS5jc3YiKQ0KDQpEZW1hbmRfMjAxNSA8LSBEZW1hbmRfMjAxNVssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTYgPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxNi5jc3YiKQ0KDQpEZW1hbmRfMjAxNiA8LSBEZW1hbmRfMjAxNlssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTcgPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxNy5jc3YiKQ0KDQpEZW1hbmRfMjAxNyA8LSBEZW1hbmRfMjAxN1ssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTggPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxOC5jc3YiKQ0KDQpEZW1hbmRfMjAxOCA8LSBEZW1hbmRfMjAxOFssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTkgPC0gZnJlYWQoIlBVQl9EZW1hbmRfMjAxOS5jc3YiKQ0KDQpEZW1hbmRfMjAxOSA8LSBEZW1hbmRfMjAxOVssLihERU1BTkQgPSBgTWFya2V0IERlbWFuZGApXQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTBfdG9fMjAxOSA8LSBkby5jYWxsKCJyYmluZCIsbGlzdChEZW1hbmRfMjAxMCxEZW1hbmRfMjAxMSxEZW1hbmRfMjAxMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZW1hbmRfMjAxMywgRGVtYW5kXzIwMTQsIERlbWFuZF8yMDE1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERlbWFuZF8yMDE2LCBEZW1hbmRfMjAxNywgRGVtYW5kXzIwMTgsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRGVtYW5kXzIwMTkpKQ0KYGBgDQoNCmBgYHtyfQ0KRGVtYW5kXzIwMTBfdG9fMjAxOS50cyA8LSBtc3RzKERlbWFuZF8yMDEwX3RvXzIwMTkkREVNQU5ELCBzZWFzb25hbC5wZXJpb2RzID0gYygyNCwgMTY4LCA4NzY2KSwgc3RhcnQ9MjAxMCkNCmBgYA0KDQpgYGB7cn0NCkRlbWFuZF8yMDEwX3RvXzIwMTkudHMuY29tcG9uZW50cyA8LSBtc3RsKERlbWFuZF8yMDEwX3RvXzIwMTkudHMpDQoNCmZvcmVjYXN0OjphdXRvcGxvdChEZW1hbmRfMjAxMF90b18yMDE5LnRzLmNvbXBvbmVudHMpDQpgYGANCg0KYGBge3J9DQphdHRyaWJ1dGVzKERlbWFuZF8yMDEwX3RvXzIwMTkudHMuY29tcG9uZW50cykNCmBgYA0KDQpgYGB7cn0NCkRlbWFuZF8yMDEwX3RvXzIwMTkuMjQudHMgPC0gRGVtYW5kXzIwMTBfdG9fMjAxOS50cy5jb21wb25lbnRzWywgIlNlYXNvbmFsMjQiXQ0KDQpEZW1hbmRfMjAxMF90b18yMDE5LjE2OC50cyA8LSBEZW1hbmRfMjAxMF90b18yMDE5LnRzLmNvbXBvbmVudHNbLCAiU2Vhc29uYWwxNjgiXQ0KDQpEZW1hbmRfMjAxMF90b18yMDE5Ljg3NjYudHMgPC0gRGVtYW5kXzIwMTBfdG9fMjAxOS50cy5jb21wb25lbnRzWywgIlNlYXNvbmFsODc2NiJdDQoNCmNsYXNzKERlbWFuZF8yMDEwX3RvXzIwMTkuODc2Ni50cykNCmBgYA0KDQpgYGB7cn0NCmF1dG9wbG90KHN1YnNldChEZW1hbmRfMjAxMF90b18yMDE5LlNlYXNvbmFsMjQudHMsIGVuZCA9IDI0KjcqNCkpDQpgYGANCg0KYGBge3J9DQphdXRvcGxvdChzdWJzZXQoRGVtYW5kXzIwMTBfdG9fMjAxOS4xNjgudHMsIGVuZCA9IDI0KjcqNCkpDQpgYGANCg0KYGBge3J9DQphdXRvcGxvdChzdWJzZXQoRGVtYW5kXzIwMTBfdG9fMjAxOS44NzY2LnRzLCBlbmQgPSAyNCo3KjM2NSkpDQpgYGANCg0KDQoNCg0KIyMgSG91cmx5IE9udGFyaW8gRW5lcmd5IFByaWNlIChIT0VQKQ0KDQpbWWVhcmx5IEhvdXJseSBIT0VQIE9SIFByZWRpc3BhdGNoIFJlcG9ydA0KXShodHRwOi8vcmVwb3J0cy5pZXNvLmNhL3B1YmxpYy9QcmljZUhPRVBQcmVkaXNwT1IvKQ0KDQpQVUJfUHJpY2VIT0VQUHJlZGlzcE9SXzIwMDIuY3N2IC0gUFVCX1ByaWNlSE9FUFByZWRpc3BPUl8yMDE5LmNzdiAodG8gSnVseSkNCg0KYGBge3J9DQpIT0VQXzIwMTAgPC0gZnJlYWQoIlBVQl9QcmljZUhPRVBQcmVkaXNwT1JfMjAxMC5jc3YiKQ0KDQpIT0VQXzIwMTAgPC0gSE9FUF8yMDEwWywuKEhPRVApXQ0KYGBgDQoNCmBgYHtyfQ0KSE9FUF8yMDExIDwtIGZyZWFkKCJQVUJfUHJpY2VIT0VQUHJlZGlzcE9SXzIwMTEuY3N2IikNCg0KSE9FUF8yMDExIDwtIEhPRVBfMjAxMVssLihIT0VQKV0NCmBgYA0KDQpgYGB7cn0NCkhPRVBfMjAxMiA8LSBmcmVhZCgiUFVCX1ByaWNlSE9FUFByZWRpc3BPUl8yMDEyLmNzdiIpDQoNCkhPRVBfMjAxMiA8LSBIT0VQXzIwMTJbLC4oSE9FUCldDQpgYGANCg0KYGBge3J9DQpIT0VQXzIwMTMgPC0gZnJlYWQoIlBVQl9QcmljZUhPRVBQcmVkaXNwT1JfMjAxMy5jc3YiKQ0KDQpIT0VQXzIwMTMgPC0gSE9FUF8yMDEzWywuKEhPRVApXQ0KYGBgDQoNCmBgYHtyfQ0KSE9FUF8yMDE0IDwtIGZyZWFkKCJQVUJfUHJpY2VIT0VQUHJlZGlzcE9SXzIwMTQuY3N2IikNCg0KSE9FUF8yMDE0IDwtIEhPRVBfMjAxNFssLihIT0VQKV0NCmBgYA0KDQpgYGB7cn0NCkhPRVBfMjAxNSA8LSBmcmVhZCgiUFVCX1ByaWNlSE9FUFByZWRpc3BPUl8yMDE1LmNzdiIpDQoNCkhPRVBfMjAxNSA8LSBIT0VQXzIwMTVbLC4oSE9FUCldDQpgYGANCg0KYGBge3J9DQpIT0VQXzIwMTYgPC0gZnJlYWQoIlBVQl9QcmljZUhPRVBQcmVkaXNwT1JfMjAxNi5jc3YiKQ0KDQpIT0VQXzIwMTYgPC0gSE9FUF8yMDE2WywuKEhPRVApXQ0KYGBgDQoNCmBgYHtyfQ0KSE9FUF8yMDE3IDwtIGZyZWFkKCJQVUJfUHJpY2VIT0VQUHJlZGlzcE9SXzIwMTcuY3N2IikNCg0KSE9FUF8yMDE3IDwtIEhPRVBfMjAxN1ssLihIT0VQKV0NCmBgYA0KDQpgYGB7cn0NCkhPRVBfMjAxOCA8LSBmcmVhZCgiUFVCX1ByaWNlSE9FUFByZWRpc3BPUl8yMDE4LmNzdiIpDQoNCkhPRVBfMjAxOCA8LSBIT0VQXzIwMThbLC4oSE9FUCldDQpgYGANCg0KYGBge3J9DQpIT0VQXzIwMTgudHMgPC0gdHMoSE9FUF8yMDE4JEhPRVAsIGZyZXF1ZW5jeSA9IDI0KQ0KDQpIT0VQXzIwMTgudHMuY29tcG9uZW50cyA8LSBkZWNvbXBvc2UoSE9FUF8yMDE4LnRzKQ0KDQpmb3JlY2FzdDo6YXV0b3Bsb3QoSE9FUF8yMDE4LnRzLmNvbXBvbmVudHMpDQpgYGANCg0KYGBge3J9DQphdXRvcGxvdChzdWJzZXQoSE9FUF8yMDE4LnRzLmNvbXBvbmVudHMkc2Vhc29uYWwsIGVuZCA9IDI0KjcqNCkpDQpgYGANCg0KDQpgYGB7cn0NCkhPRVBfMjAxOSA8LSBmcmVhZCgiUFVCX1ByaWNlSE9FUFByZWRpc3BPUl8yMDE5LmNzdiIpDQoNCkhPRVBfMjAxOSA8LSBIT0VQXzIwMTlbLC4oSE9FUCldDQpgYGANCg0KYGBge3J9DQpIT0VQXzIwMTBfdG9fMjAxOSA8LSBkby5jYWxsKCJyYmluZCIsbGlzdChIT0VQXzIwMTAsSE9FUF8yMDExLEhPRVBfMjAxMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBIT0VQXzIwMTMsIEhPRVBfMjAxNCwgSE9FUF8yMDE1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhPRVBfMjAxNiwgSE9FUF8yMDE3LCBIT0VQXzIwMTgsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSE9FUF8yMDE5KSkNCmBgYA0KDQpgYGB7cn0NCkhPRVBfMjAxMF90b18yMDE5LnRzIDwtIG1zdHMoSE9FUF8yMDEwX3RvXzIwMTkkSE9FUCwgc2Vhc29uYWwucGVyaW9kcyA9IGMoMjQsIDE2OCwgODc2NiksIHN0YXJ0PTIwMTApDQpgYGANCg0KYGBge3J9DQphdXRvcGxvdChIT0VQXzIwMTBfdG9fMjAxOS50cykNCmBgYA0KDQpgYGB7cn0NCkhPRVBfMjAxMF90b18yMDE5LnRzLmNvbXBvbmVudHMgPC0gbXN0bChIT0VQXzIwMTBfdG9fMjAxOS50cykNCg0KZm9yZWNhc3Q6OmF1dG9wbG90KEhPRVBfMjAxMF90b18yMDE5LnRzLmNvbXBvbmVudHMpDQpgYGANCg0KYGBge3J9DQpIT0VQXzIwMTBfdG9fMjAxOS4yNC50cyA8LSBIT0VQXzIwMTBfdG9fMjAxOS50cy5jb21wb25lbnRzWywgIlNlYXNvbmFsMjQiXQ0KDQpIT0VQXzIwMTBfdG9fMjAxOS4xNjgudHMgPC0gSE9FUF8yMDEwX3RvXzIwMTkudHMuY29tcG9uZW50c1ssICJTZWFzb25hbDE2OCJdDQoNCkhPRVBfMjAxMF90b18yMDE5Ljg3NjYudHMgPC0gSE9FUF8yMDEwX3RvXzIwMTkudHMuY29tcG9uZW50c1ssICJTZWFzb25hbDg3NjYiXQ0KDQphdXRvcGxvdChzdWJzZXQoSE9FUF8yMDEwX3RvXzIwMTkuMjQudHMsIGVuZCA9IDI0KjcqNCkpDQpgYGANCg0KYGBge3J9DQphdXRvcGxvdChzdWJzZXQoSE9FUF8yMDEwX3RvXzIwMTkuMTY4LnRzLCBlbmQgPSAyNCo3KjQpKQ0KYGBgDQoNCmBgYHtyfQ0KYXV0b3Bsb3Qoc3Vic2V0KEhPRVBfMjAxMF90b18yMDE5Ljg3NjYudHMsIGVuZCA9IDI0KjcqNTIpKQ0KYGBgDQoNCg0KYGBge3J9DQphdXRvcGxvdChzdWJzZXQoSE9FUF8yMDEwX3RvXzIwMTkudHMuY29tcG9uZW50c1ssIlNlYXNvbmFsMjQiXSwgZW5kID0gMjQqNyo0KSkNCmBgYA0KDQojIFUuUy4gRW5lcmd5IEluZm9ybWF0aW9uIEFkbWluaXN0cmF0aW9uIChFSUEpOiBTdGF0ZSBvZiBOZXcgWW9yaw0KDQpbVS5TLiBFbmVyZ3kgSW5mb3JtYXRpb24gQWRtaW5pc3RyYXRpb24gKEVJQSldKGh0dHBzOi8vd3d3LmVpYS5nb3YvKQ0KDQpbQXZlcmFnZSByZXRhaWwgcHJpY2Ugb2YgZWxlY3RyaWNpdHkgOiBOZXcgWW9yayA6IGFsbCBzZWN0b3JzIDogbW9udGhseS4gQ2VudHMgcGVyIGtXaF0oaHR0cHM6Ly93d3cuZWlhLmdvdi9lbGVjdHJpY2l0eS9kYXRhL2Jyb3dzZXIvIy90b3BpYy83P2FnZz0wLDEmZ2VvPTAwMDImZW5kc2VjPXZnJmZyZXE9TSZzdGFydD0yMDAxMDEmZW5kPTIwMTkwNCZjdHlwZT1saW5lY2hhcnQmbHR5cGU9cGluJnJ0eXBlPXMmbWFwdHlwZT0wJnJzZT0wJnBpbj1FTEVDLlBSSUNFLk5ZLUFMTC5NfkVMRUMuUFJJQ0UuTlktUkVTLk1+RUxFQy5QUklDRS5OWS1DT00uTX5FTEVDLlBSSUNFLk5ZLUlORC5NfkVMRUMuUFJJQ0UuTlktVFJBLk1+RUxFQy5QUklDRS5OWS1PVEguTSkNCg0KYGBge3J9DQpFSUFfTlkgPC0gZnJlYWQoIkVJQV9OWS5jc3YiKQ0KYGBgDQoNCmBgYHtyfQ0KRUlBX05ZIDwtIEVJQV9OWVtucm93KEVJQV9OWSk6MSxdDQoNCkVJQV9OWSA8LSBFSUFfTllbLCAuKE1vbnRoLCBDZW50c19wZXJfa1doID0gQXZlcmFnZV9yZXRhaWxfcHJpY2VfZWxlY3RyaWNpdHlfbW9udGhseV9jZW50c19wZXJfa1doKV0NCg0KaGVhZChFSUFfTlkpDQpgYGANCg0KYGBge3J9DQpFSUFfTlkudHMgPC0gdHMoRUlBX05ZJENlbnRzX3Blcl9rV2gsIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IDIwMDEpDQoNCkVJQV9OWS50cy5jb21wb25lbnRzIDwtIGRlY29tcG9zZShFSUFfTlkudHMpDQoNCmZvcmVjYXN0OjphdXRvcGxvdChFSUFfTlkudHMuY29tcG9uZW50cykNCmBgYA0KDQo=