import from rio is actually slightly faster than data.table’s fread.
pacman::p_load("rio","tidyverse","stringr","ggthemes","RColorBrewer","viridis","data.table","kableExtra",
"knitr")
pacman::p_load("rio","tidyverse","stringr","ggthemes","RColorBrewer","viridis","data.table","kableExtra")
#CEMData<-import("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/CEM.csv")
system.time(CEMData<-import("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/CEM.csv")
)
Read 38.4% of 6430515 rows
Read 70.0% of 6430515 rows
Read 99.1% of 6430515 rows
Read 6430515 rows and 11 (of 11) columns from 0.316 GB file in 00:00:05
user system elapsed
3.715 0.439 5.278
#system.time(fread("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/CEM.csv"))
setwd("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA")
options(knitr.table.format="html")
#install.packages("kableExtra")
CEMData<-CEMData%>%dplyr::select(-V11 )
dim(CEMData)
[1] 6430515 10
CEMData%>%head()
CEMData%>%str()
'data.frame': 6430515 obs. of 10 variables:
$ VHCL_MODEL_YEAR : int 2011 2011 2011 2011 2011 2011 2011 2011 2011 2011 ...
$ VHCL_MODEL : chr "LDDM48" "LDDM48" "LDDM48" "LDDM48" ...
$ VHCL_FAMILY_CODE : chr "LD" "LD" "LD" "LD" ...
$ VIN : chr "2B3CL3CG4BH503092" "2B3CL3CG7BH531016" "2B3CL3CG7BH531016" "2B3CL3CG7BH531016" ...
$ DAY#DATE_VHCL_IN_SVC: int 24 7 7 7 7 3 17 17 17 17 ...
$ ODOMETER_TYPE : chr "M" "M" "M" "M" ...
$ CLAIM_TYPE : chr "N" "N" "N" "R" ...
$ DAYS_IN_SVC : int 833 1729 1729 1241 1241 1092 815 815 815 815 ...
$ ODOMETER___VHCL_RECD: int 36685 56148 56148 43320 43320 34003 30000 30000 30000 30000 ...
$ TRANSACTION_TYPE : chr "W" "S" "S" "S" ...
Extract the eigth character in VIN which is the engine code.This will be match with a vehicle idenfication code to determine the engine size.
CEMData$Engine_Size<-str_sub(CEMData$VIN, start = 8, end = 8)
We calculate miles per year by diviving the odometer vehicle recorded by the days in service and mltiply by the number of days in the year 365.25. Since we will be dividing by Days in Service,we have to filter out it’s values that are zero to avoid Inf or other non mathetically expressible computations.
CEMData<-CEMData%>%filter(DAYS_IN_SVC != 0)
CEMData$MILES_PER_YEAR<-(CEMData$ODOMETER___VHCL_RECD/CEMData$DAYS_IN_SVC)*365.25
# extract all numbers in miles per year
#MILES_P<-as.numeric(grep(pattern = "[0-9]", CEMData$MILES_PER_YEAR, value = TRUE))
#MILES_P
CEMData%>%dim()
[1] 6365749 12
CEMData%>%head()
95% Confidence Interval for the mean of miles per year is computed below.
con.iter=function(x){
x_error=(qnorm(0.975)*sd(x$MILES_PER_YEAR))/sqrt(dim(x)[1])
x_lower=x$MILES_PER_YEAR-x_error
x_upper=x$MILES_PER_YEAR+x_error
c=data.frame(LOWER_CI=x_lower,UPPER_CI=x_upper)
return(c)
}
#CEMData$MILES_ERROR=(qnorm(0.975)*sd(CEMData$MILES_PER_YEAR))/sqrt(dim(CEMData)[1])
#CEMData$LOWER_CONFIDENCE=CEMData$MILES_PER_YEAR-CEMData$MILES_ERROR
#CEMData$UPPER_CONFIDENCE=CEMData$MILES_PER_YEAR+CEMData$MILES_ERROR
#CEMData%>%head()
unique(CEMData$VHCL_MODEL)
[1] "LDDM48" "LDDP48" "LDEP48" "LDDE48" "LDDX48" "LDDS48" "LDES48" "LDDR48" "LDEM48" "LDEE48" "LADH22"
[12] "LADX22" "LADP22" "LADR22" "LADS22" "LDDT48" "LAEH22" "LADM22"
unique(CEMData$VHCL_MODEL_YEAR)
[1] 2011 2012 2013 2014 2015 2016 2017 2018
match engine displacement with engine code and also cylinders.The matching file is in vehicle identification number.
CEMData=CEMData %>%
mutate(EngineCylinder = case_when(.$Engine_Size == "G"~ "V6" ,
.$Engine_Size == "T"~ "V8",
.$Engine_Size == "J"~"V8",
.$Engine_Size == "9"~"8"))
CEMData=CEMData %>%
mutate(EngineDisplacement = case_when(.$Engine_Size == "G"~ "3.6L" ,
.$Engine_Size == "T"~ "5.7L",
.$Engine_Size == "J"~"6.4L",
.$Engine_Size == "9"~"6.2L"))
CEMData%>%head()
CEMData=CEMData %>%
mutate(Model_Name = case_when(.$VHCL_MODEL == "LADR22"~ "Challenger_SRT_Hellcat" ,
.$VHCL_MODEL == "LDDT48"~ "Charger_SRT_Hellcat",
.$VHCL_MODEL == "LADS22"~"Challenger_SRT392",
.$VHCL_MODEL == "LADX22"~"Challenger_RT_SCATPACK",
.$VHCL_MODEL == "LDDP48"~"Charger_RT",
.$VHCL_MODEL == "LDDS48"~"Charger_SXT",
.$VHCL_MODEL == "LDDR48"~"Charger_RT_SCATPACK",
.$VHCL_MODEL == "LDES48"~"Charger_SXT_AWD",
.$VHCL_MODEL == "LDEM48"~"Charger_SE_AWD",
.$VHCL_MODEL == "LDEE48"~"Charger_PoliceAWD",
.$VHCL_MODEL == "LDDX48"~"Charger_SRT_392",
.$VHCL_MODEL == "LDDE48"~"Charger_PoliceRWD",
.$VHCL_MODEL == "LDDM48"~"Charger_SE",
.$VHCL_MODEL == "LADH22"~"Challenger_SXT",
.$VHCL_MODEL == "LADP22"~"Challenger_RT",
.$VHCL_MODEL == "LCDH22"~"Challenger_SXT",
.$VHCL_MODEL == "LCDP22"~"Challenger_RT",
.$VHCL_MODEL == "LCDX22"~"Challenger_SRT392"))
rio::export(CEMData,"/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/CEMDataVIN.csv")
CEMData=rio::import("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/CEMDataVIN.csv")
Read 0.0% of 6365749 rows
Read 19.3% of 6365749 rows
Read 38.8% of 6365749 rows
Read 58.3% of 6365749 rows
Read 78.2% of 6365749 rows
Read 98.0% of 6365749 rows
Read 6365749 rows and 15 (of 15) columns from 0.523 GB file in 00:00:08
#=============================================================================================
# remove white spaces in column names
#=============================================================================================
# This aproach replaces the white spaces in the name with a period
#colnames(pred_dat)=make.names(names(pred_dat) ,unique= TRUE)
# This aproach replaces the white spaces in the name with a an underscore
names(CEMData)<-gsub("\\s", "_", names(CEMData))
names(CEMData)
[1] "VHCL_MODEL_YEAR" "VHCL_MODEL" "VHCL_FAMILY_CODE" "VIN"
[5] "DAY#DATE_VHCL_IN_SVC" "ODOMETER_TYPE" "CLAIM_TYPE" "DAYS_IN_SVC"
[9] "ODOMETER___VHCL_RECD" "TRANSACTION_TYPE" "Engine_Size" "MILES_PER_YEAR"
[13] "EngineCylinder" "EngineDisplacement" "Model_Name"
CEMData1<-CEMData%>%dplyr::select(VIN,VHCL_MODEL_YEAR,VHCL_MODEL,VHCL_FAMILY_CODE,DAYS_IN_SVC,ODOMETER___VHCL_RECD ,Engine_Size,MILES_PER_YEAR,Model_Name,EngineCylinder,EngineDisplacement)
CEMData1$MILES_PER_YEAR<-as.numeric(CEMData1$MILES_PER_YEAR)
CEMData1%>%head()
#models <- CEMData1 %>%
#split(.$VIN) %>%
#map(~dplyr::slice(.,which.max(ODOMETER___VHCL_RECD )))
#models<-models%>%bind_rows()
#models%>%dim()
#models%>%head()
#Alternatively
#CEMData1= CEMData1[1:100,]
#modelss <-CEMData1%>%
#split(.$VIN) %>%
# map(function(df) dplyr::slice(df,which.max(ODOMETER___VHCL_RECD )))%>%rbind_all()
#
#
#
# unique(CEMData1$VIN)%>%length()
#
#
# length(modelss)
#
#
# modelss%>%head()
#Alternatively
#do.call(rbind,modelss)
#bind_rows(modelss)
#rbind_all(modelss)
model3<- CEMData1%>%group_by(VIN)%>%dplyr::slice(which.max(ODOMETER___VHCL_RECD ))
model3%>%head()
model3%>%dim()
[1] 896858 11
#quantile(model3$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
model3<-model3%>%filter(MILES_PER_YEAR>0)
Split into LA and LD
LD<-model3%>%slice(VHCL_FAMILY_CODE=="LD")
LD%>%head()
unique(model3$Engine_Size)
[1] "G" "T" "J" "9"
LA<-model3%>%filter(VHCL_FAMILY_CODE=="LA")
LA%>%head()
LA=LA%>%arrange(MILES_PER_YEAR)
LD=LD%>%arrange(MILES_PER_YEAR)
Separate into Engine Sizes
LA
LA_ES_3.6<-LA%>%filter(EngineDisplacement=="3.6L")
LA_ES_5.7<-LA%>%filter(EngineDisplacement=="5.7L")
LA_ES_6.2<-LA%>%filter(EngineDisplacement=="6.2L")
LA_ES_6.4<-LA%>%filter(EngineDisplacement=="6.4L")
LA ENGINE SIZE 3.6 MILES PER YEAR
quantile(LA_ES_3.6$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
31.76087 13365.34070 31993.92341
LA ENGINE SIZE 5.7 MILES PER YEAR
quantile(LA_ES_5.7$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
32.82163 10818.09160 32284.44408
LA ENGINE SIZE 6.2 MILES PER YEAR
quantile(LA_ES_6.2$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
23.82065 3135.57839 21143.91667
LA ENGINE SIZE 6.4 MILES PER YEAR
quantile(LA_ES_6.4$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
40.58333 8035.50000 26499.26020
LA_ES_3.6%>%dim()
[1] 51996 11
LA_ES_5.7%>%dim()
[1] 33753 11
LA_ES_6.2%>%dim()
[1] 13821 11
LA_ES_6.4%>%dim()
[1] 23461 11
df=data.frame(Value=c(31.76087,13365.34070,31993.92341,32.82163,10818.09160,32284.44408,23.82065,3135.57839, 21143.91667,40.58333,8035.50000,26499.26020 ),percentile=c("5th","50th","95th","5th","50th","95th","5th","50th","95th","5th","50th","95th"),model=c("3.6L","3.6L","3.6L","5.7L","5.7L","5.7L","6.2L","6.2L","6.2L","6.4L","6.4L","6.4L"))
df
colourCount = length(unique(df$model))
getPalette = colorRampPalette(brewer.pal(9, "Set1"))
ggplot(df,aes(x=percentile,y=Value,fill=model))+geom_bar(stat="identity",position = position_dodge())+
geom_text(aes(label=round(Value),vjust=1.6),position = position_dodge(width = 1),color="black")+labs(y="Miles per Year",title="Customer Equivalent Mileage LA Vehicles")+theme_bw()+
#scale_fill_brewer(palette = "Paired")
#scale_fill_brewer(palette="Set1")
scale_fill_brewer(palette="Set2")
#scale_fill_manual(values = getPalette(colourCount))
#scale_fill_manual(values = colorRampPalette(brewer.pal(12, "Accent"))(colourCount))
ggsave("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/LA.pdf")
Saving 7.29 x 4.51 in image

NA
NA
NA
Separate into Engine Sizes
LD
LD_ES_3.6<-LD%>%filter(EngineDisplacement=="3.6L")
LD_ES_5.7<-LD%>%filter(EngineDisplacement=="5.7L")
LD_ES_6.2<-LD%>%filter(EngineDisplacement=="6.2L")
LD_ES_6.4<-LD%>%filter(EngineDisplacement=="6.4L")
LD_ES_3.6%>%dim()
[1] 352581 11
LD_ES_5.7%>%dim()
[1] 156846 11
LD_ES_6.2%>%dim()
[1] 4822 11
LD_ES_6.4%>%dim()
[1] 17734 11
LA ENGINE SIZE 3.6 CUMULATIVE PERCENTILE
LA_ES_3.6$CumPercentile<-1/length(LA_ES_3.6$MILES_PER_YEAR)
LA_ES_3.6$CumPercentile2<-cumsum(LA_ES_3.6$CumPercentile)
LA_ES_5.7$CumPercentile<-1/length(LA_ES_5.7$MILES_PER_YEAR)
LA_ES_5.7$CumPercentile2<-cumsum(LA_ES_5.7$CumPercentile)
LA_ES_6.2$CumPercentile<-1/length(LA_ES_6.2$MILES_PER_YEAR)
LA_ES_6.2$CumPercentile2<-cumsum(LA_ES_6.2$CumPercentile)
LA_ES_6.4$CumPercentile<-1/length(LA_ES_6.4$MILES_PER_YEAR)
LA_ES_6.4$CumPercentile2<-cumsum(LA_ES_6.4$CumPercentile)
LD ENGINE SIZE 3.6 CUMULATIVE PERCENTILE
LD_ES_3.6<-LD_ES_3.6%>%data.frame(con.iter(LD_ES_3.6))
#LD_ES_3.6$MILES_PER_YEAR2=(cumsum(LD_ES_3.6$MILES_PER_YEAR)/sum(LD_ES_3.6$MILES_PER_YEAR))
LD_ES_3.6%>%dim()
[1] 352581 13
LD_ES_3.6%>%head()
LD_ES_3.6%>%tail()
quantile(LD_ES_3.6$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
214.3859 17398.1423 37001.7474
LD_ES_3.6$CumPercentile<-1/length(LD_ES_3.6$MILES_PER_YEAR)
LD_ES_3.6$CumPercentile2<-cumsum(LD_ES_3.6$CumPercentile)
LD_ES_5.7$CumPercentile<-1/length(LD_ES_5.7$MILES_PER_YEAR)
LD_ES_5.7$CumPercentile2<-cumsum(LD_ES_5.7$CumPercentile)
LD_ES_6.2$CumPercentile<-1/length(LD_ES_6.2$MILES_PER_YEAR)
LD_ES_6.2$CumPercentile2<-cumsum(LD_ES_6.2$CumPercentile)
LD_ES_6.4$CumPercentile<-1/length(LD_ES_6.4$MILES_PER_YEAR)
LD_ES_6.4$CumPercentile2<-cumsum(LD_ES_6.4$CumPercentile)
LD_ES_6.4%>%tail()
LA CUMULATIVE PERCENTILE PLOT
ggplot()+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="3.6L"),data=LA_ES_3.6,size=1.5,linetype=6)+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="5.7L"),data=LA_ES_5.7,size=1.5,linetype=3)+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="6.2L"),data=LA_ES_6.2,size=1.5,linetype=4)+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="6.4L"),data=LA_ES_6.4,size=1.5,linetype=5)+
scale_y_continuous(labels = scales::percent)+scale_x_continuous(labels = scales::comma)+
coord_cartesian(xlim = c(0,50000))+labs(title="LA Vehicle Customer Equivalent Mileage",y="Percentile",x="CEM",color= "Engine Size")+
geom_hline(aes(yintercept =c(0.50)))+geom_hline(aes(yintercept =c(0.95)))+
theme_bw()
ggsave("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/CUMLA.pdf")
Saving 7.29 x 4.51 in image

NA
LD CUMULATIVE PERCENTILE PLOT
ggplot()+geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="3.6L"),data=LD_ES_3.6,size=1.5,linetype=1)+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="5.7L"),data=LD_ES_5.7,size=1.5,linetype=3)+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="6.2L"),data=LD_ES_6.2,size=1.5,linetype=4)+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="6.4L"),data=LD_ES_6.4,size=1.5,linetype=5)+
scale_y_continuous(labels = scales::percent)+scale_x_continuous(labels = scales::comma)+
coord_cartesian(xlim = c(0,50000))+labs(title="LD Vehicle Customer Equivalent Mileage",y="Percentile",x="CEM",color= "Engine Size")+
geom_hline(aes(yintercept =c(0.50)))+geom_hline(aes(yintercept =c(0.95)))+
theme_bw()
ggsave("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/CUMLD.pdf")
Saving 7.29 x 4.51 in image

NA
Cumulative Percentile Plots
#ggplot(LD_ES_3.6[1:1000,],aes(MILES_PER_YEAR))+geom_histogram()
#plot(LD_ES_3.6$MILES_PER_YEAR, cumsum(LD_ES_3.6$MILES_PER_YEAR)/sum(LD_ES_3.6$MILES_PER_YEAR))
duration = LD_ES_3.6$MILES_PER_YEAR
breaks = seq(0, length(LD_ES_3.6$MILES_PER_YEAR), by=10000)
duration.cut = cut(duration, breaks, right=FALSE)
duration.freq = table(duration.cut)
cumfreq0 = c(0, cumsum(duration.freq)/sum(duration.freq))
plot(breaks, cumfreq0, # plot the data
main="Old Faithful Eruptions", # main title
xlab="Duration minutes", # x−axis label
ylab="Cumulative eruptions") # y−axis label
lines(breaks, cumfreq0) # join the points

plotdf=data.frame(breaks,cumfreq0)
ggplot(plotdf,aes(breaks,cumfreq0))+geom_line()+scale_y_continuous(labels = scales::percent)+scale_x_continuous(labels = scales::scientific)

ggplot(LD_ES_3.6, aes(x=MILES_PER_YEAR)) + stat_ecdf()+
coord_cartesian(xlim = c(0,50000))
ggplot(LD_ES_3.6, aes(MILES_PER_YEAR,CumPercentile2)) +
geom_step() + xlab("MILES_PER_YEAR") + ylab("Percentile")

cumdata=function(x){
duration = x
breaks = seq(0, length(duration), by=1000)
duration.cut = cut(duration, breaks, right=FALSE)
duration.freq = table(duration.cut)
cumfreq0 = c(0, cumsum(duration.freq)/sum(duration.freq))
#cumfreq0=(cumsum(duration)/sum(duration))
plotdf=data.frame(breaks,cumfreq0)
return(plotdf)
}
# duration = LD_ES_3.6$MILES_PER_YEAR
# breaks = seq(0, length(duration), by=10000)
# duration.cut = cut(duration, breaks, right=FALSE)
# duration.freq = table(duration.cut)
# cumfreq0 = c(0, cumsum(duration.freq)/sum(duration.freq))
#
ggplot()+
geom_line(aes(breaks,cumfreq0,color="3.6L"),data=cumdata(LD_ES_3.6$MILES_PER_YEAR ),size=1.5,linetype=1)+
geom_line(aes(breaks,cumfreq0,color="5.7L"),data=cumdata(LD_ES_5.7$MILES_PER_YEAR ),size=1.5,linetype=3) +
geom_line(aes(breaks,cumfreq0,color="6.2L"),data=cumdata(LD_ES_6.2$MILES_PER_YEAR ),size=1.5,linetype=4) +
geom_line(aes(breaks,cumfreq0,color="6.4L"),data=cumdata(LD_ES_6.4$MILES_PER_YEAR ),size=1.5,linetype=5) +
scale_y_continuous(labels = scales::percent)+scale_x_continuous(labels = scales::comma)+
coord_cartesian(xlim = c(0,50000))+labs(title="LD Vehicle Customer Equivalent Mileage",y="Percentile",x="CEM",color= "Engine Size")+
geom_hline(aes(yintercept =c(0.5)))+geom_hline(aes(yintercept =c(0.95)))+
theme_bw()

# remove legend title
# theme(legend.title = element_blank()) +
#rename the color legend
#guides(color=guide_legend(title = "Engine Size"))
cumdata(LD_ES_3.6$MILES_PER_YEAR )
Error in data.frame(breaks, cumfreq0) :
arguments imply differing number of rows: 353, 352581
LD ENGINE SIZE 5.7 MILES PER YEAR
quantile(LD_ES_5.7$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
243.50 14995.75 37643.32
LD ENGINE SIZE 6.2 MILES PER YEAR
quantile(LD_ES_6.2$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
17.5601 5439.4126 27449.7852
LD ENGINE SIZE 6.4 MILES PER YEAR
quantile(LD_ES_6.4$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
46.44947 11659.98386 36570.14206
df1=data.frame(Value=c(214.3859,17398.1423,37001.7474,243.50,14995.75,37643.32,17.5601,5439.4126,27449.7852,
46.44947,11659.98386,36570.14206),percentile=c("5th","50th","95th","5th","50th","95th","5th","50th","95th","5th","50th","95th"),model=c("3.6L","3.6L","3.6L","5.7L","5.7L","5.7L","6.2L","6.2L","6.2L","6.4L","6.4L","6.4L"))
df1%>%head()
colourCount = length(unique(df$model))
getPalette = colorRampPalette(brewer.pal(9, "Set1"))
ggplot(df1,aes(x=percentile,y=Value,fill=model))+geom_bar(stat="identity",position = position_dodge())+
geom_text(aes(label=round(Value),vjust=1.6),position = position_dodge(width = 1),color="black")+labs(y="Miles per Year",title="Customer Equivalent Mileage LD Vehicles")+theme_bw()+
#scale_fill_brewer(palette = "Paired")
#scale_fill_brewer(palette="Set1")
scale_fill_brewer(palette="Set2")
ggsave("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/Ld.pdf")
Saving 7.29 x 4.51 in image

NA
df=df%>%add_column(Name="LA")
df1=df1%>%add_column(Name="LD")
df3=bind_rows(df,df1)%>%mutate(Name=as.factor(Name))
tail(df3)
ggplot(df3,aes(x=percentile,y=Value,fill=model))+geom_bar(stat="identity",position = position_dodge())+
geom_text(aes(label=round(Value),vjust=1.6),position = position_dodge(width = 1),color="black")+labs(y="Miles per Year",title="Customer Equivalent Mileage Vehicles")+theme_bw()+
#facet_wrap(~Name, scales = "free", space="free")
facet_grid(.~Name, scales="free", space="free")

#scale_fill_brewer(palette = "Paired")
scale_fill_brewer(palette="Set1")
<ggproto object: Class ScaleDiscrete, Scale, gg>
aesthetics: fill
axis_order: function
break_info: function
break_positions: function
breaks: waiver
call: call
clone: function
dimension: function
drop: TRUE
expand: waiver
get_breaks: function
get_breaks_minor: function
get_labels: function
get_limits: function
guide: legend
is_discrete: function
is_empty: function
labels: waiver
limits: NULL
make_sec_title: function
make_title: function
map: function
map_df: function
n.breaks.cache: NULL
na.translate: TRUE
na.value: NA
name: waiver
palette: function
palette.cache: NULL
position: left
range: <ggproto object: Class RangeDiscrete, Range, gg>
range: NULL
reset: function
train: function
super: <ggproto object: Class RangeDiscrete, Range, gg>
reset: function
scale_name: brewer
train: function
train_df: function
transform: function
transform_df: function
super: <ggproto object: Class ScaleDiscrete, Scale, gg>
#scale_fill_brewer(palette="Set2")
Dividing Engine Size 6.4L Into SCAT and SRT
LD ENGINE SIZE 6.4
#Alternatively
LD_ES_6.4SCAT<-LD_ES_6.4%>%dplyr::filter(str_detect(Model_Name, "SCAT"))
LD_ES_6.4SRT<-LD_ES_6.4%>%dplyr::filter(str_detect(Model_Name, "SRT"))
LD_ES_6.4SCAT%>%dim()
[1] 9148 13
LD_ES_6.4SRT%>%dim()
[1] 8586 13
LD ENGINE SIZE 6.4 SCAT PACK MILES PER YEAR
quantile(LD_ES_6.4SCAT$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
38.44737 11134.90714 31228.96802
LD ENGINE SIZE 6.4 SCAT PACK MILES PER YEAR
quantile(LD_ES_6.4SRT$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
70.24038 12188.83768 41873.23894
df=data.frame(Value=c(11134.90714,31228.96802,12188.83768,41873.23894 ),percentile=c("50th","95th","50th","95th"),model=c("SCAT","SCAT","SRT","SRT"))
df
ggplot(df,aes(x=percentile,y=Value,fill=model))+geom_bar(stat="identity",position = position_dodge())+
geom_text(aes(label=round(Value),vjust=1.6),position = position_dodge(width = 1),color="black")+labs(y="Miles per Year",title="Customer Equivalent Mileage 6.4 LD")+theme_bw() +
#viridis::scale_color_viridis()
#scale_fill_brewer(palette = "RdYlGn")
#scale_colour_brewer(palette = "YlOrRd")
#scale_fill_viridis_d(direction = -1)
#scale_fill_wsj()
#scale_fill_solarized()
#scale_color_manual(values = c("#999999","#56B4E9"))
#scale_color_manual(values = c("black","lightgrey"))
scale_fill_brewer(palette = "Paired")
ggsave("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/LD6.4.pdf")
Saving 7.29 x 4.51 in image

NA
LA ENGINE SIZE 6.4
LA_ES_6.4SCAT<-LA_ES_6.4%>%dplyr::filter(str_detect(Model_Name, "SCAT"))
LA_ES_6.4SCAT%>%dim()
[1] 17472 13
LA_ES_6.4SRT<-LA_ES_6.4%>%dplyr::filter(str_detect(Model_Name, "SRT"))
LA_ES_6.4SRT%>%dim()
[1] 5989 13
LA ENGINE SIZE 6.4 SCAT PACK MILES PER YEAR
quantile(LA_ES_6.4SCAT$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
40.58333 8194.74512 26755.36820
LA ENGINE SIZE 6.4 CUMULATIVE PERCENTILE PLOT
LA_ES_6.4SCAT$CumPercentile<-1/length(LA_ES_6.4SCAT$MILES_PER_YEAR)
LA_ES_6.4SCAT$CumPercentile2<-cumsum(LA_ES_6.4SCAT$CumPercentile)
LA_ES_6.4SRT$CumPercentile<-1/length(LA_ES_6.4SRT$MILES_PER_YEAR)
LA_ES_6.4SRT$CumPercentile2<-cumsum(LA_ES_6.4SRT$CumPercentile)
ggplot()+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="SCAT"),data=LA_ES_6.4SCAT,size=1.5,linetype=1)+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="SRT"),data=LA_ES_6.4SRT,size=1.5,linetype=3) +
scale_y_continuous(labels = scales::percent)+scale_x_continuous(labels = scales::comma)+
coord_cartesian(xlim = c(0,50000))+labs(title="LA 6.4 Vehicle Customer Equivalent Mileage",y="Percentile",x="CEM",color= "Engine Size")+
geom_hline(aes(yintercept =c(0.5)))+geom_hline(aes(yintercept =c(0.95)))+
theme_bw()
ggsave("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/CUMLA6.4.pdf")
Saving 7.29 x 4.51 in image

NA
LD ENGINE SIZE 6.4 CUMULATIVE PERCENTILE PLOT
LD_ES_6.4SCAT$CumPercentile<-1/length(LD_ES_6.4SCAT$MILES_PER_YEAR)
LD_ES_6.4SCAT$CumPercentile2<-cumsum(LD_ES_6.4SCAT$CumPercentile)
LD_ES_6.4SRT$CumPercentile<-1/length(LD_ES_6.4SRT$MILES_PER_YEAR)
LD_ES_6.4SRT$CumPercentile2<-cumsum(LD_ES_6.4SRT$CumPercentile)
ggplot()+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="SCAT"),data=LD_ES_6.4SCAT,size=1.5,linetype=1)+
geom_line(aes(MILES_PER_YEAR,CumPercentile2,color="SRT"),data=LD_ES_6.4SRT,size=1.5,linetype=3) +
scale_y_continuous(labels = scales::percent)+scale_x_continuous(labels = scales::comma)+
coord_cartesian(xlim = c(0,50000))+labs(title="LD 6.4 Vehicle Customer Equivalent Mileage",y="Percentile",x="CEM",color= "Engine Size")+
geom_hline(aes(yintercept =c(0.5)))+geom_hline(aes(yintercept =c(0.95)))+
theme_bw()
ggsave("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/CUMLD6.4.pdf")
Saving 7.29 x 4.51 in image

NA
quantile(LA_ES_6.4SRT$MILES_PER_YEAR,c(0.05,0.5,0.95),na.rm = TRUE)
5% 50% 95%
42.14423 7610.56147 25861.30654
LA ENGINE SIZE 6.4 SRT MILES PER YEAR
df=data.frame(Value=c( 8194.74512,26755.36820,7610.56147,25861.30654 ),percentile=c("50th","95th","50th","95th"),model=c("SCAT","SCAT","SRT","SRT"))
df
NA
NA
NA
ggplot(df,aes(x=percentile,y=Value,fill=model))+geom_bar(stat="identity",position = position_dodge())+
geom_text(aes(label=round(Value),vjust=1.6),position = position_dodge(width = 1),color="black")+labs(y="Miles per Year",title="Customer Equivalent Mileage 6.4 LA")+theme_bw() +
#viridis::scale_color_viridis()
#scale_fill_brewer(palette = "RdYlGn")
#scale_colour_brewer(palette = "YlOrRd")
#scale_fill_viridis_d(direction = -1)
#scale_fill_wsj()
#scale_fill_solarized()
#scale_color_manual(values = c("#999999","#56B4E9"))
#scale_color_manual(values = c("black","lightgrey"))
scale_fill_brewer(palette = "Paired")
ggsave("/Users/nanaakwasiabayieboateng/Documents/memphisclassesbooks/DataMiningscience/FCA/LA6.4.pdf")
Saving 7.29 x 4.51 in image

NA
Confidence Interval for Percentiles
We can find confidence intervals for the percentiles by generating a large bootstrap samples and calculating the confidence intervals from the bootstrap samples.
con.iter.percetile=function(x,p,R){
library(boot)
ci=boot.ci(boot(x,function(x,i) quantile(x[i],probs =p ), R))
return(ci)
}
#Alternatively
con.iter.percetile2<-function(x,p){
return(sort(x)[qbinom(c(.025,.975), length(x), p)])
}
#equivalently
con.iter.percetile3<-function(x,p){
bootmed = apply(matrix(sample(x, rep=TRUE, 1000*length(x)), nrow=1000), 1, quantile,probs=c(p))
return(quantile(bootmed, c(.025, 0.975)))
}
Confidence Interval for LA Engine Sizes
# LA_ES_3.6$MILES_PER_YEAR
# 5% 50% 95%
# 31.76087 13365.34070 31993.923_41
a=matrix(con.iter.percetile2(LA_ES_3.6$MILES_PER_YEAR,0.05),nrow = 1)%>%
rbind(con.iter.percetile2(LA_ES_3.6$MILES_PER_YEAR,0.5))%>%
rbind(con.iter.percetile2(LA_ES_3.6$MILES_PER_YEAR,0.95))
b=matrix(con.iter.percetile2(LA_ES_5.7$MILES_PER_YEAR,0.05),nrow = 1)%>%
rbind(con.iter.percetile2(LA_ES_5.7$MILES_PER_YEAR,0.5))%>%
rbind(con.iter.percetile2(LA_ES_5.7$MILES_PER_YEAR,0.95))
c=matrix(con.iter.percetile2(LA_ES_6.2$MILES_PER_YEAR,0.05),nrow = 1)%>%
rbind(con.iter.percetile2(LA_ES_6.2$MILES_PER_YEAR,0.5))%>%
rbind(con.iter.percetile2(LA_ES_6.2$MILES_PER_YEAR,0.95))
d=matrix(con.iter.percetile2(LA_ES_6.4$MILES_PER_YEAR,0.05),nrow = 1)%>%
rbind(con.iter.percetile2(LA_ES_6.4$MILES_PER_YEAR,0.5))%>%
rbind(con.iter.percetile2(LA_ES_6.4$MILES_PER_YEAR,0.95))
Name_LA=as.factor(rep(c(3.6,5.7,6.2,6.4),c(3,3,3,3)))
Percentile=as.factor(rep(c("5th","50th","95th"),4))
Value=c(31.76087,13365.34070,31993.92341,32.82163,10818.09160,32284.44408,23.82065,3135.57839, 21143.91667,40.58333,8035.50000,26499.26020 )
LA_CI=data.frame(Engine_Size=Name_LA,Value=round(Value,1),round(do.call(rbind,list(a,b,c,d)),1),Percentile)%>%rename(Lower=X1,Upper=X2)
LA_CI%>%kable(.,format="html",caption = "Confidence Interval for LA Engine Sizes")%>%kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"))
Confidence Interval for LA Engine Sizes
|
Engine_Size
|
Value
|
Lower
|
Upper
|
Percentile
|
|
3.6
|
31.8
|
31.0
|
33.0
|
5th
|
|
3.6
|
13365.3
|
13259.8
|
13467.5
|
50th
|
|
3.6
|
31993.9
|
31709.3
|
32300.5
|
95th
|
|
5.7
|
32.8
|
31.8
|
33.5
|
5th
|
|
5.7
|
10818.1
|
10644.5
|
10935.5
|
50th
|
|
5.7
|
32284.4
|
31865.5
|
32685.7
|
95th
|
|
6.2
|
23.8
|
22.2
|
24.9
|
5th
|
|
6.2
|
3135.6
|
3006.4
|
3276.4
|
50th
|
|
6.2
|
21143.9
|
20404.8
|
21768.9
|
95th
|
|
6.4
|
40.6
|
39.3
|
42.5
|
5th
|
|
6.4
|
8035.5
|
7906.5
|
8153.1
|
50th
|
|
6.4
|
26499.3
|
26023.8
|
26986.4
|
95th
|
LA_CI
Confidence Interval for LD Engine Sizes
#option(max.print=100)
a=matrix(con.iter.percetile2(LD_ES_3.6$MILES_PER_YEAR,0.05),nrow = 1)%>%
rbind(con.iter.percetile2(LD_ES_3.6$MILES_PER_YEAR,0.5))%>%
rbind(con.iter.percetile2(LD_ES_3.6$MILES_PER_YEAR,0.95))
b=matrix(con.iter.percetile2(LD_ES_5.7$MILES_PER_YEAR,0.05),nrow = 1)%>%
rbind(con.iter.percetile2(LD_ES_5.7$MILES_PER_YEAR,0.5))%>%
rbind(con.iter.percetile2(LD_ES_5.7$MILES_PER_YEAR,0.95))
c=matrix(con.iter.percetile2(LD_ES_6.2$MILES_PER_YEAR,0.05),nrow = 1)%>%
rbind(con.iter.percetile2(LD_ES_6.2$MILES_PER_YEAR,0.5))%>%
rbind(con.iter.percetile2(LD_ES_6.2$MILES_PER_YEAR,0.95))
d=matrix(con.iter.percetile2(LD_ES_6.4$MILES_PER_YEAR,0.05),nrow = 1)%>%
rbind(con.iter.percetile2(LD_ES_6.4$MILES_PER_YEAR,0.5))%>%
rbind(con.iter.percetile2(LD_ES_6.4$MILES_PER_YEAR,0.95))
Name_LD=as.factor(rep(c(3.6,5.7,6.2,6.4),c(3,3,3,3)))
Percentile=as.factor(rep(c("5th","50th","95th"),4))
Value=c(214.3859,17398.1423,37001.7474,243.50,14995.75,37643.32,17.5601,5439.4126,27449.7852,
46.44947,11659.98386,36570.14206)
LD_CI=data.frame(Engine_Size=Name_LA,Value=round(Value,1),round(do.call(rbind,list(a,b,c,d)),1),Percentile)%>%rename(Lower=X1,Upper=X2)
LD_CI
kable(LD_CI, "html")%>%
kable_styling("striped", full_width = T) %>%
column_spec(1:5, bold = T) %>%
row_spec(1:12, bold = T, color = "white", background = "#D7261E")
|
Engine_Size
|
Value
|
Lower
|
Upper
|
Percentile
|
|
3.6
|
214.4
|
199.2
|
226.1
|
5th
|
|
3.6
|
17398.1
|
17366.9
|
17430.5
|
50th
|
|
3.6
|
37001.7
|
36853.5
|
37145.1
|
95th
|
|
5.7
|
243.5
|
222.3
|
269.4
|
5th
|
|
5.7
|
14995.8
|
14944.3
|
15047.1
|
50th
|
|
5.7
|
37643.3
|
37389.7
|
37915.4
|
95th
|
|
6.2
|
17.6
|
16.6
|
18.7
|
5th
|
|
6.2
|
5439.4
|
4938.2
|
5766.4
|
50th
|
|
6.2
|
27449.8
|
26027.7
|
29078.5
|
95th
|
|
6.4
|
46.4
|
44.0
|
49.8
|
5th
|
|
6.4
|
11660.0
|
11480.0
|
11813.0
|
50th
|
|
6.4
|
36570.1
|
35828.3
|
37528.1
|
95th
|
LD_CI%>%kable(.,format="html",caption = "Confidence Interval for LD Engine Sizes")%>%kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"))
Confidence Interval for LD Engine Sizes
|
Engine_Size
|
Value
|
Lower
|
Upper
|
Percentile
|
|
3.6
|
214.4
|
199.2
|
226.1
|
5th
|
|
3.6
|
17398.1
|
17366.9
|
17430.5
|
50th
|
|
3.6
|
37001.7
|
36853.5
|
37145.1
|
95th
|
|
5.7
|
243.5
|
222.3
|
269.4
|
5th
|
|
5.7
|
14995.8
|
14944.3
|
15047.1
|
50th
|
|
5.7
|
37643.3
|
37389.7
|
37915.4
|
95th
|
|
6.2
|
17.6
|
16.6
|
18.7
|
5th
|
|
6.2
|
5439.4
|
4938.2
|
5766.4
|
50th
|
|
6.2
|
27449.8
|
26027.7
|
29078.5
|
95th
|
|
6.4
|
46.4
|
44.0
|
49.8
|
5th
|
|
6.4
|
11660.0
|
11480.0
|
11813.0
|
50th
|
|
6.4
|
36570.1
|
35828.3
|
37528.1
|
95th
|
LS0tCnRpdGxlOiAiQ3VzdG9tZXIgRXF1aXZhbGVudCBNaWxlYWdlIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBOYW5hIEJvYXRlbmcKZGZfcHJpbnQ6IHBhZ2VkClRpbWU6ICdgciBTeXMudGltZSgpYCcKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUIgJWQsICVZJylgIgotLS0KCgppbXBvcnQgZnJvbSByaW8gaXMgYWN0dWFsbHkgc2xpZ2h0bHkgZmFzdGVyIHRoYW4gZGF0YS50YWJsZSdzIGZyZWFkLgoKCmBgYHtyfQpwYWNtYW46OnBfbG9hZCgicmlvIiwidGlkeXZlcnNlIiwic3RyaW5nciIsImdndGhlbWVzIiwiUkNvbG9yQnJld2VyIiwidmlyaWRpcyIsImRhdGEudGFibGUiLCJrYWJsZUV4dHJhIiwKICAgICAgICAgICAgICAgImtuaXRyIikKCmBgYAoKCgoKYGBge3J9CgojQ0VNRGF0YTwtaW1wb3J0KCIvVXNlcnMvbmFuYWFrd2FzaWFiYXlpZWJvYXRlbmcvRG9jdW1lbnRzL21lbXBoaXNjbGFzc2VzYm9va3MvRGF0YU1pbmluZ3NjaWVuY2UvRkNBL0NFTS5jc3YiKQoKc3lzdGVtLnRpbWUoQ0VNRGF0YTwtaW1wb3J0KCIvVXNlcnMvbmFuYWFrd2FzaWFiYXlpZWJvYXRlbmcvRG9jdW1lbnRzL21lbXBoaXNjbGFzc2VzYm9va3MvRGF0YU1pbmluZ3NjaWVuY2UvRkNBL0NFTS5jc3YiKQopCgoKI3N5c3RlbS50aW1lKGZyZWFkKCIvVXNlcnMvbmFuYWFrd2FzaWFiYXlpZWJvYXRlbmcvRG9jdW1lbnRzL21lbXBoaXNjbGFzc2VzYm9va3MvRGF0YU1pbmluZ3NjaWVuY2UvRkNBL0NFTS5jc3YiKSkKCgoKYGBgCgoKYGBge3J9CgpzZXR3ZCgiL1VzZXJzL25hbmFha3dhc2lhYmF5aWVib2F0ZW5nL0RvY3VtZW50cy9tZW1waGlzY2xhc3Nlc2Jvb2tzL0RhdGFNaW5pbmdzY2llbmNlL0ZDQSIpCgpvcHRpb25zKGtuaXRyLnRhYmxlLmZvcm1hdD0iaHRtbCIpCgojaW5zdGFsbC5wYWNrYWdlcygia2FibGVFeHRyYSIpCgpgYGAKCgoKCmBgYHtyfQoKQ0VNRGF0YTwtQ0VNRGF0YSU+JWRwbHlyOjpzZWxlY3QoLVYxMSApCgpkaW0oQ0VNRGF0YSkKCkNFTURhdGElPiVoZWFkKCkKCgpDRU1EYXRhJT4lc3RyKCkKCmBgYAoKCkV4dHJhY3QgdGhlIGVpZ3RoIGNoYXJhY3RlciBpbiBWSU4gd2hpY2ggaXMgdGhlIGVuZ2luZSBjb2RlLlRoaXMgd2lsbCBiZSBtYXRjaCB3aXRoIGEgdmVoaWNsZSBpZGVuZmljYXRpb24gY29kZSB0byBkZXRlcm1pbmUgdGhlIGVuZ2luZSBzaXplLgoKYGBge3J9CkNFTURhdGEkRW5naW5lX1NpemU8LXN0cl9zdWIoQ0VNRGF0YSRWSU4sIHN0YXJ0ID0gOCwgZW5kID0gOCkKCmBgYAoKV2UgY2FsY3VsYXRlIG1pbGVzIHBlciB5ZWFyIGJ5IGRpdml2aW5nIHRoZSBvZG9tZXRlciB2ZWhpY2xlIHJlY29yZGVkIGJ5IHRoZSBkYXlzIGluIHNlcnZpY2UgYW5kIG1sdGlwbHkgYnkgdGhlIG51bWJlciBvZiBkYXlzIGluIHRoZSB5ZWFyIDM2NS4yNS4gU2luY2Ugd2Ugd2lsbCBiZSBkaXZpZGluZyBieSBEYXlzIGluIFNlcnZpY2Usd2UgaGF2ZSB0byBmaWx0ZXIgb3V0IGl0J3MgdmFsdWVzIHRoYXQgYXJlIHplcm8gdG8gYXZvaWQgSW5mIG9yIG90aGVyIG5vbiBtYXRoZXRpY2FsbHkgZXhwcmVzc2libGUgIGNvbXB1dGF0aW9ucy4KCmBgYHtyfQoKQ0VNRGF0YTwtQ0VNRGF0YSU+JWZpbHRlcihEQVlTX0lOX1NWQyAhPSAwKQoKCkNFTURhdGEkTUlMRVNfUEVSX1lFQVI8LShDRU1EYXRhJE9ET01FVEVSX19fVkhDTF9SRUNEL0NFTURhdGEkREFZU19JTl9TVkMpKjM2NS4yNQoKCiMgZXh0cmFjdCBhbGwgbnVtYmVycyBpbiBtaWxlcyBwZXIgeWVhcgojTUlMRVNfUDwtYXMubnVtZXJpYyhncmVwKHBhdHRlcm4gPSAiWzAtOV0iLCBDRU1EYXRhJE1JTEVTX1BFUl9ZRUFSLCB2YWx1ZSA9IFRSVUUpKQojTUlMRVNfUAoKCgpDRU1EYXRhJT4lZGltKCkKCgpDRU1EYXRhJT4laGVhZCgpCgpgYGAKCgo5NSUgQ29uZmlkZW5jZSBJbnRlcnZhbCBmb3IgdGhlIG1lYW4gb2YgbWlsZXMgcGVyIHllYXIgaXMgY29tcHV0ZWQgYmVsb3cuCgoKYGBge3J9Cgpjb24uaXRlcj1mdW5jdGlvbih4KXsKCnhfZXJyb3I9KHFub3JtKDAuOTc1KSpzZCh4JE1JTEVTX1BFUl9ZRUFSKSkvc3FydChkaW0oeClbMV0pIAoKeF9sb3dlcj14JE1JTEVTX1BFUl9ZRUFSLXhfZXJyb3IKICAgIAp4X3VwcGVyPXgkTUlMRVNfUEVSX1lFQVIreF9lcnJvciAKCmM9ZGF0YS5mcmFtZShMT1dFUl9DST14X2xvd2VyLFVQUEVSX0NJPXhfdXBwZXIpCgpyZXR1cm4oYykKICAKfQoKCgoKCgojQ0VNRGF0YSRNSUxFU19FUlJPUj0ocW5vcm0oMC45NzUpKnNkKENFTURhdGEkTUlMRVNfUEVSX1lFQVIpKS9zcXJ0KGRpbShDRU1EYXRhKVsxXSkKCiNDRU1EYXRhJExPV0VSX0NPTkZJREVOQ0U9Q0VNRGF0YSRNSUxFU19QRVJfWUVBUi1DRU1EYXRhJE1JTEVTX0VSUk9SCgojQ0VNRGF0YSRVUFBFUl9DT05GSURFTkNFPUNFTURhdGEkTUlMRVNfUEVSX1lFQVIrQ0VNRGF0YSRNSUxFU19FUlJPUgogICAgCiNDRU1EYXRhJT4laGVhZCgpCgoKCmBgYAoKCgoKCgoKYGBge3J9CnVuaXF1ZShDRU1EYXRhJFZIQ0xfTU9ERUwpCgp1bmlxdWUoQ0VNRGF0YSRWSENMX01PREVMX1lFQVIpCgpgYGAKCgojIyMjIG1hdGNoIGVuZ2luZSBkaXNwbGFjZW1lbnQgd2l0aCBlbmdpbmUgY29kZSBhbmQgYWxzbyBjeWxpbmRlcnMuVGhlIG1hdGNoaW5nIGZpbGUgaXMgaW4gdmVoaWNsZSBpZGVudGlmaWNhdGlvbiBudW1iZXIuCgpgYGB7cn0KCiAgCiAgQ0VNRGF0YT1DRU1EYXRhICU+JSAgCiAgbXV0YXRlKEVuZ2luZUN5bGluZGVyID0gY2FzZV93aGVuKC4kRW5naW5lX1NpemUgPT0gIkcifiAiVjYiICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJEVuZ2luZV9TaXplID09ICJUIn4gICJWOCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLiRFbmdpbmVfU2l6ZSA9PSAiSiJ+IlY4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJEVuZ2luZV9TaXplID09ICI5In4iOCIpKQoKCgpDRU1EYXRhPUNFTURhdGEgJT4lICAKICBtdXRhdGUoRW5naW5lRGlzcGxhY2VtZW50ID0gY2FzZV93aGVuKC4kRW5naW5lX1NpemUgPT0gIkcifiAiMy42TCIgLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kRW5naW5lX1NpemUgPT0gIlQifiAgIjUuN0wiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kRW5naW5lX1NpemUgPT0gIkoifiI2LjRMIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJEVuZ2luZV9TaXplID09ICI5In4iNi4yTCIpKQoKCkNFTURhdGElPiVoZWFkKCkKCmBgYAoKCgoKYGBge3J9CkNFTURhdGE9Q0VNRGF0YSAlPiUgIAogIG11dGF0ZShNb2RlbF9OYW1lID0gY2FzZV93aGVuKC4kVkhDTF9NT0RFTCA9PSAiTEFEUjIyIn4gIkNoYWxsZW5nZXJfU1JUX0hlbGxjYXQiICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJFZIQ0xfTU9ERUwgPT0gIkxERFQ0OCJ+ICAiQ2hhcmdlcl9TUlRfSGVsbGNhdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLiRWSENMX01PREVMID09ICJMQURTMjIifiJDaGFsbGVuZ2VyX1NSVDM5MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLiRWSENMX01PREVMID09ICJMQURYMjIifiJDaGFsbGVuZ2VyX1JUX1NDQVRQQUNLIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJFZIQ0xfTU9ERUwgPT0gIkxERFA0OCJ+IkNoYXJnZXJfUlQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kVkhDTF9NT0RFTCA9PSAiTEREUzQ4In4iQ2hhcmdlcl9TWFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kVkhDTF9NT0RFTCA9PSAiTEREUjQ4In4iQ2hhcmdlcl9SVF9TQ0FUUEFDSyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLiRWSENMX01PREVMID09ICJMREVTNDgifiJDaGFyZ2VyX1NYVF9BV0QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kVkhDTF9NT0RFTCA9PSAiTERFTTQ4In4iQ2hhcmdlcl9TRV9BV0QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kVkhDTF9NT0RFTCA9PSAiTERFRTQ4In4iQ2hhcmdlcl9Qb2xpY2VBV0QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kVkhDTF9NT0RFTCA9PSAiTEREWDQ4In4iQ2hhcmdlcl9TUlRfMzkyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJFZIQ0xfTU9ERUwgPT0gIkxEREU0OCJ+IkNoYXJnZXJfUG9saWNlUldEIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJFZIQ0xfTU9ERUwgPT0gIkxERE00OCJ+IkNoYXJnZXJfU0UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kVkhDTF9NT0RFTCA9PSAiTEFESDIyIn4iQ2hhbGxlbmdlcl9TWFQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4kVkhDTF9NT0RFTCA9PSAiTEFEUDIyIn4iQ2hhbGxlbmdlcl9SVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLiRWSENMX01PREVMID09ICJMQ0RIMjIifiJDaGFsbGVuZ2VyX1NYVCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLiRWSENMX01PREVMID09ICJMQ0RQMjIifiJDaGFsbGVuZ2VyX1JUIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuJFZIQ0xfTU9ERUwgPT0gIkxDRFgyMiJ+IkNoYWxsZW5nZXJfU1JUMzkyIikpCgoKQ0VNRGF0YSU+JWhlYWQoKQoKCmBgYAoKCgoKYGBge3J9CnJpbzo6ZXhwb3J0KENFTURhdGEsIi9Vc2Vycy9uYW5hYWt3YXNpYWJheWllYm9hdGVuZy9Eb2N1bWVudHMvbWVtcGhpc2NsYXNzZXNib29rcy9EYXRhTWluaW5nc2NpZW5jZS9GQ0EvQ0VNRGF0YVZJTi5jc3YiKQoKCmBgYAoKCgoKYGBge3J9CgpDRU1EYXRhPXJpbzo6aW1wb3J0KCIvVXNlcnMvbmFuYWFrd2FzaWFiYXlpZWJvYXRlbmcvRG9jdW1lbnRzL21lbXBoaXNjbGFzc2VzYm9va3MvRGF0YU1pbmluZ3NjaWVuY2UvRkNBL0NFTURhdGFWSU4uY3N2IikKCmBgYAoKCgoKYGBge3J9CiM9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyByZW1vdmUgd2hpdGUgc3BhY2VzIGluIGNvbHVtbiBuYW1lcwojPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIFRoaXMgYXByb2FjaCByZXBsYWNlcyB0aGUgd2hpdGUgc3BhY2VzIGluIHRoZSBuYW1lIHdpdGggYSBwZXJpb2QKCiNjb2xuYW1lcyhwcmVkX2RhdCk9bWFrZS5uYW1lcyhuYW1lcyhwcmVkX2RhdCkgLHVuaXF1ZT0gVFJVRSkKCiMgVGhpcyBhcHJvYWNoIHJlcGxhY2VzIHRoZSB3aGl0ZSBzcGFjZXMgaW4gdGhlIG5hbWUgd2l0aCBhIGFuIHVuZGVyc2NvcmUKCm5hbWVzKENFTURhdGEpPC1nc3ViKCJcXHMiLCAiXyIsIG5hbWVzKENFTURhdGEpKQoKYGBgCgoKCgpgYGB7cn0KCm5hbWVzKENFTURhdGEpCgoKQ0VNRGF0YTE8LUNFTURhdGElPiVkcGx5cjo6c2VsZWN0KFZJTixWSENMX01PREVMX1lFQVIsVkhDTF9NT0RFTCxWSENMX0ZBTUlMWV9DT0RFLERBWVNfSU5fU1ZDLE9ET01FVEVSX19fVkhDTF9SRUNEICxFbmdpbmVfU2l6ZSxNSUxFU19QRVJfWUVBUixNb2RlbF9OYW1lLEVuZ2luZUN5bGluZGVyLEVuZ2luZURpc3BsYWNlbWVudCkKCgoKQ0VNRGF0YTEkTUlMRVNfUEVSX1lFQVI8LWFzLm51bWVyaWMoQ0VNRGF0YTEkTUlMRVNfUEVSX1lFQVIpCgpDRU1EYXRhMSU+JWhlYWQoKQpgYGAKCgoKYGBge3J9CiNtb2RlbHMgPC0gQ0VNRGF0YTEgJT4lCiNzcGxpdCguJFZJTikgJT4lCiNtYXAofmRwbHlyOjpzbGljZSguLHdoaWNoLm1heChPRE9NRVRFUl9fX1ZIQ0xfUkVDRCApKSkKCmBgYAoKCgoKCmBgYHtyfQoKI21vZGVsczwtbW9kZWxzJT4lYmluZF9yb3dzKCkKCgoKCiNtb2RlbHMlPiVkaW0oKQoKCiNtb2RlbHMlPiVoZWFkKCkKCmBgYAoKCgoKCgoKCgoKCgoKYGBge3J9CgojQWx0ZXJuYXRpdmVseQoKI0NFTURhdGExPSBDRU1EYXRhMVsxOjEwMCxdCgojbW9kZWxzcyA8LUNFTURhdGExJT4lCiNzcGxpdCguJFZJTikgJT4lCiMgbWFwKGZ1bmN0aW9uKGRmKSBkcGx5cjo6c2xpY2UoZGYsd2hpY2gubWF4KE9ET01FVEVSX19fVkhDTF9SRUNEICkpKSU+JXJiaW5kX2FsbCgpCiMgCiMgCiMgCiMgdW5pcXVlKENFTURhdGExJFZJTiklPiVsZW5ndGgoKQojIAojIAojIGxlbmd0aChtb2RlbHNzKQojIAojIAojIG1vZGVsc3MlPiVoZWFkKCkgCgoKI0FsdGVybmF0aXZlbHkKCiNkby5jYWxsKHJiaW5kLG1vZGVsc3MpCgoKI2JpbmRfcm93cyhtb2RlbHNzKQoKI3JiaW5kX2FsbChtb2RlbHNzKQoKCmBgYAoKCgpgYGB7cn0KCgptb2RlbDM8LSBDRU1EYXRhMSU+JWdyb3VwX2J5KFZJTiklPiVkcGx5cjo6c2xpY2Uod2hpY2gubWF4KE9ET01FVEVSX19fVkhDTF9SRUNEICkpCgptb2RlbDMlPiVoZWFkKCkKCgptb2RlbDMlPiVkaW0oKQoKI3F1YW50aWxlKG1vZGVsMyRNSUxFU19QRVJfWUVBUixjKDAuMDUsMC41LDAuOTUpLG5hLnJtID0gVFJVRSkKCgoKYGBgCgoKYGBge3J9Cm1vZGVsMzwtbW9kZWwzJT4lZmlsdGVyKE1JTEVTX1BFUl9ZRUFSPjApCmBgYAoKCgoKIyMjIyBTcGxpdCBpbnRvIExBIGFuZCBMRAoKCmBgYHtyfQoKTEQ8LW1vZGVsMyU+JXNsaWNlKFZIQ0xfRkFNSUxZX0NPREU9PSJMRCIpCgpMRCU+JWhlYWQoKQoKCmBgYAoKCgoKYGBge3J9CnVuaXF1ZShtb2RlbDMkRW5naW5lX1NpemUpCmBgYAoKCmBgYHtyfQpMQTwtbW9kZWwzJT4lZmlsdGVyKFZIQ0xfRkFNSUxZX0NPREU9PSJMQSIpCgpMQSU+JWhlYWQoKQoKYGBgCgoKYGBge3J9CkxBPUxBJT4lYXJyYW5nZShNSUxFU19QRVJfWUVBUikKTEQ9TEQlPiVhcnJhbmdlKE1JTEVTX1BFUl9ZRUFSKQpgYGAKCgoKCgojIyMjIFNlcGFyYXRlIGludG8gRW5naW5lIFNpemVzCgojIyMjIyAgIExBCgpgYGB7cn0KCgoKCkxBX0VTXzMuNjwtTEElPiVmaWx0ZXIoRW5naW5lRGlzcGxhY2VtZW50PT0iMy42TCIpCgpMQV9FU181Ljc8LUxBJT4lZmlsdGVyKEVuZ2luZURpc3BsYWNlbWVudD09IjUuN0wiKQoKCkxBX0VTXzYuMjwtTEElPiVmaWx0ZXIoRW5naW5lRGlzcGxhY2VtZW50PT0iNi4yTCIpCgoKTEFfRVNfNi40PC1MQSU+JWZpbHRlcihFbmdpbmVEaXNwbGFjZW1lbnQ9PSI2LjRMIikKCgoKYGBgCgoKCiMjIyMjICBMQSBFTkdJTkUgU0laRSAzLjYgTUlMRVMgUEVSIFlFQVIKCmBgYHtyfQoKcXVhbnRpbGUoTEFfRVNfMy42JE1JTEVTX1BFUl9ZRUFSLGMoMC4wNSwwLjUsMC45NSksbmEucm0gPSBUUlVFKQoKCmBgYAoKCiMjIyMjICBMQSBFTkdJTkUgU0laRSA1LjcgTUlMRVMgUEVSIFlFQVIKCmBgYHtyfQoKcXVhbnRpbGUoTEFfRVNfNS43JE1JTEVTX1BFUl9ZRUFSLGMoMC4wNSwwLjUsMC45NSksbmEucm0gPSBUUlVFKQoKCmBgYAoKCiMjIyMjICBMQSBFTkdJTkUgU0laRSA2LjIgTUlMRVMgUEVSIFlFQVIKCmBgYHtyfQpxdWFudGlsZShMQV9FU182LjIkTUlMRVNfUEVSX1lFQVIsYygwLjA1LDAuNSwwLjk1KSxuYS5ybSA9IFRSVUUpCgpgYGAKCgojIyMjIyAgTEEgRU5HSU5FIFNJWkUgNi40IE1JTEVTIFBFUiBZRUFSCgpgYGB7cn0KcXVhbnRpbGUoTEFfRVNfNi40JE1JTEVTX1BFUl9ZRUFSLGMoMC4wNSwwLjUsMC45NSksbmEucm0gPSBUUlVFKQpgYGAKCgoKYGBge3J9CkxBX0VTXzMuNiU+JWRpbSgpCgpMQV9FU181LjclPiVkaW0oKQoKTEFfRVNfNi4yJT4lZGltKCkKCkxBX0VTXzYuNCU+JWRpbSgpCmBgYAoKCgpgYGB7cn0KCgoKCmRmPWRhdGEuZnJhbWUoVmFsdWU9YygzMS43NjA4NywxMzM2NS4zNDA3MCwzMTk5My45MjM0MSwzMi44MjE2MywxMDgxOC4wOTE2MCwzMjI4NC40NDQwOCwyMy44MjA2NSwzMTM1LjU3ODM5LCAyMTE0My45MTY2Nyw0MC41ODMzMyw4MDM1LjUwMDAwLDI2NDk5LjI2MDIwICApLHBlcmNlbnRpbGU9YygiNXRoIiwiNTB0aCIsIjk1dGgiLCI1dGgiLCI1MHRoIiwiOTV0aCIsIjV0aCIsIjUwdGgiLCI5NXRoIiwiNXRoIiwiNTB0aCIsIjk1dGgiKSxtb2RlbD1jKCIzLjZMIiwiMy42TCIsIjMuNkwiLCI1LjdMIiwiNS43TCIsIjUuN0wiLCI2LjJMIiwiNi4yTCIsIjYuMkwiLCI2LjRMIiwiNi40TCIsIjYuNEwiKSkKICAgICAgICAgICAgICAKIGRmIApjb2xvdXJDb3VudCA9IGxlbmd0aCh1bmlxdWUoZGYkbW9kZWwpKQpnZXRQYWxldHRlID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJTZXQxIikpIAogCiBnZ3Bsb3QoZGYsYWVzKHg9cGVyY2VudGlsZSx5PVZhbHVlLGZpbGw9bW9kZWwpKStnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKSsKICAKICBnZW9tX3RleHQoYWVzKGxhYmVsPXJvdW5kKFZhbHVlKSx2anVzdD0xLjYpLHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSxjb2xvcj0iYmxhY2siKStsYWJzKHk9Ik1pbGVzIHBlciBZZWFyIix0aXRsZT0iQ3VzdG9tZXIgRXF1aXZhbGVudCBNaWxlYWdlICBMQSBWZWhpY2xlcyIpK3RoZW1lX2J3KCkrIAogICAKICAgCiNzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIpCiNzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTZXQxIikKc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU2V0MiIpCiNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBnZXRQYWxldHRlKGNvbG91ckNvdW50KSkKI3NjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCgxMiwgIkFjY2VudCIpKShjb2xvdXJDb3VudCkpCgogCmdnc2F2ZSgiL1VzZXJzL25hbmFha3dhc2lhYmF5aWVib2F0ZW5nL0RvY3VtZW50cy9tZW1waGlzY2xhc3Nlc2Jvb2tzL0RhdGFNaW5pbmdzY2llbmNlL0ZDQS9MQS5wZGYiKQogCiAKICAKYGBgCgoKCgojIyMjIFNlcGFyYXRlIGludG8gRW5naW5lIFNpemVzCgojIyMjIyAgIExECgpgYGB7cn0KTERfRVNfMy42PC1MRCU+JWZpbHRlcihFbmdpbmVEaXNwbGFjZW1lbnQ9PSIzLjZMIikKCkxEX0VTXzUuNzwtTEQlPiVmaWx0ZXIoRW5naW5lRGlzcGxhY2VtZW50PT0iNS43TCIpCgoKTERfRVNfNi4yPC1MRCU+JWZpbHRlcihFbmdpbmVEaXNwbGFjZW1lbnQ9PSI2LjJMIikKCgpMRF9FU182LjQ8LUxEJT4lZmlsdGVyKEVuZ2luZURpc3BsYWNlbWVudD09IjYuNEwiKQoKCkxEX0VTXzMuNiU+JWRpbSgpCgpMRF9FU181LjclPiVkaW0oKQoKTERfRVNfNi4yJT4lZGltKCkKCkxEX0VTXzYuNCU+JWRpbSgpCgpgYGAKCgoKIyMjIyMgIExBIEVOR0lORSBTSVpFIDMuNiAgQ1VNVUxBVElWRSBQRVJDRU5USUxFCgpgYGB7cn0KCkxBX0VTXzMuNiRDdW1QZXJjZW50aWxlPC0xL2xlbmd0aChMQV9FU18zLjYkTUlMRVNfUEVSX1lFQVIpCgpMQV9FU18zLjYkQ3VtUGVyY2VudGlsZTI8LWN1bXN1bShMQV9FU18zLjYkQ3VtUGVyY2VudGlsZSkKCgoKCkxBX0VTXzUuNyRDdW1QZXJjZW50aWxlPC0xL2xlbmd0aChMQV9FU181LjckTUlMRVNfUEVSX1lFQVIpCgoKTEFfRVNfNS43JEN1bVBlcmNlbnRpbGUyPC1jdW1zdW0oTEFfRVNfNS43JEN1bVBlcmNlbnRpbGUpCgoKCgpMQV9FU182LjIkQ3VtUGVyY2VudGlsZTwtMS9sZW5ndGgoTEFfRVNfNi4yJE1JTEVTX1BFUl9ZRUFSKQoKCkxBX0VTXzYuMiRDdW1QZXJjZW50aWxlMjwtY3Vtc3VtKExBX0VTXzYuMiRDdW1QZXJjZW50aWxlKQoKCgpMQV9FU182LjQkQ3VtUGVyY2VudGlsZTwtMS9sZW5ndGgoTEFfRVNfNi40JE1JTEVTX1BFUl9ZRUFSKQoKCkxBX0VTXzYuNCRDdW1QZXJjZW50aWxlMjwtY3Vtc3VtKExBX0VTXzYuNCRDdW1QZXJjZW50aWxlKQpgYGAKCgoKCiMjIyMjICBMRCBFTkdJTkUgU0laRSAzLjYgIENVTVVMQVRJVkUgUEVSQ0VOVElMRSAKCmBgYHtyfQoKCgpMRF9FU18zLjY8LUxEX0VTXzMuNiU+JWRhdGEuZnJhbWUoY29uLml0ZXIoTERfRVNfMy42KSkKCgoKCgoKCiNMRF9FU18zLjYkTUlMRVNfUEVSX1lFQVIyPShjdW1zdW0oTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSKS9zdW0oTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSKSkKCkxEX0VTXzMuNiU+JWRpbSgpCgpMRF9FU18zLjYlPiVoZWFkKCkKCkxEX0VTXzMuNiU+JXRhaWwoKQoKCgoKCgoKcXVhbnRpbGUoTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSLGMoMC4wNSwwLjUsMC45NSksbmEucm0gPSBUUlVFKQoKCgoKCgoKTERfRVNfMy42JEN1bVBlcmNlbnRpbGU8LTEvbGVuZ3RoKExEX0VTXzMuNiRNSUxFU19QRVJfWUVBUikKCkxEX0VTXzMuNiRDdW1QZXJjZW50aWxlMjwtY3Vtc3VtKExEX0VTXzMuNiRDdW1QZXJjZW50aWxlKQoKCgoKTERfRVNfNS43JEN1bVBlcmNlbnRpbGU8LTEvbGVuZ3RoKExEX0VTXzUuNyRNSUxFU19QRVJfWUVBUikKCgpMRF9FU181LjckQ3VtUGVyY2VudGlsZTI8LWN1bXN1bShMRF9FU181LjckQ3VtUGVyY2VudGlsZSkKCgoKCkxEX0VTXzYuMiRDdW1QZXJjZW50aWxlPC0xL2xlbmd0aChMRF9FU182LjIkTUlMRVNfUEVSX1lFQVIpCgoKTERfRVNfNi4yJEN1bVBlcmNlbnRpbGUyPC1jdW1zdW0oTERfRVNfNi4yJEN1bVBlcmNlbnRpbGUpCgoKCkxEX0VTXzYuNCRDdW1QZXJjZW50aWxlPC0xL2xlbmd0aChMRF9FU182LjQkTUlMRVNfUEVSX1lFQVIpCgoKTERfRVNfNi40JEN1bVBlcmNlbnRpbGUyPC1jdW1zdW0oTERfRVNfNi40JEN1bVBlcmNlbnRpbGUpCgoKYGBgCgoKCgoKYGBge3J9CkxEX0VTXzYuNCU+JXRhaWwoKQpgYGAKCgojIyMjIExBIENVTVVMQVRJVkUgUEVSQ0VOVElMRSBQTE9UIAoKYGBge3J9CmdncGxvdCgpKwogIGdlb21fbGluZShhZXMoTUlMRVNfUEVSX1lFQVIsQ3VtUGVyY2VudGlsZTIsY29sb3I9IjMuNkwiKSxkYXRhPUxBX0VTXzMuNixzaXplPTEuNSxsaW5ldHlwZT02KSsKICBnZW9tX2xpbmUoYWVzKE1JTEVTX1BFUl9ZRUFSLEN1bVBlcmNlbnRpbGUyLGNvbG9yPSI1LjdMIiksZGF0YT1MQV9FU181Ljcsc2l6ZT0xLjUsbGluZXR5cGU9MykrCiAgIGdlb21fbGluZShhZXMoTUlMRVNfUEVSX1lFQVIsQ3VtUGVyY2VudGlsZTIsY29sb3I9IjYuMkwiKSxkYXRhPUxBX0VTXzYuMixzaXplPTEuNSxsaW5ldHlwZT00KSsKICAgZ2VvbV9saW5lKGFlcyhNSUxFU19QRVJfWUVBUixDdW1QZXJjZW50aWxlMixjb2xvcj0iNi40TCIpLGRhdGE9TEFfRVNfNi40LHNpemU9MS41LGxpbmV0eXBlPTUpKwogICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KStzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkrCiAgCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsNTAwMDApKStsYWJzKHRpdGxlPSJMQSBWZWhpY2xlIEN1c3RvbWVyIEVxdWl2YWxlbnQgTWlsZWFnZSIseT0iUGVyY2VudGlsZSIseD0iQ0VNIixjb2xvcj0gIkVuZ2luZSBTaXplIikrCiAgCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9YygwLjUwKSkpK2dlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPWMoMC45NSkpKSsKICB0aGVtZV9idygpIAogIAogICBnZ3NhdmUoIi9Vc2Vycy9uYW5hYWt3YXNpYWJheWllYm9hdGVuZy9Eb2N1bWVudHMvbWVtcGhpc2NsYXNzZXNib29rcy9EYXRhTWluaW5nc2NpZW5jZS9GQ0EvQ1VNTEEucGRmIikKIApgYGAKCgoKCgoKCiMjIyMgTEQgQ1VNVUxBVElWRSBQRVJDRU5USUxFIFBMT1QgCgpgYGB7cn0KCgpnZ3Bsb3QoKStnZW9tX2xpbmUoYWVzKE1JTEVTX1BFUl9ZRUFSLEN1bVBlcmNlbnRpbGUyLGNvbG9yPSIzLjZMIiksZGF0YT1MRF9FU18zLjYsc2l6ZT0xLjUsbGluZXR5cGU9MSkrCiAgZ2VvbV9saW5lKGFlcyhNSUxFU19QRVJfWUVBUixDdW1QZXJjZW50aWxlMixjb2xvcj0iNS43TCIpLGRhdGE9TERfRVNfNS43LHNpemU9MS41LGxpbmV0eXBlPTMpKwogICBnZW9tX2xpbmUoYWVzKE1JTEVTX1BFUl9ZRUFSLEN1bVBlcmNlbnRpbGUyLGNvbG9yPSI2LjJMIiksZGF0YT1MRF9FU182LjIsc2l6ZT0xLjUsbGluZXR5cGU9NCkrCiAgIGdlb21fbGluZShhZXMoTUlMRVNfUEVSX1lFQVIsQ3VtUGVyY2VudGlsZTIsY29sb3I9IjYuNEwiKSxkYXRhPUxEX0VTXzYuNCxzaXplPTEuNSxsaW5ldHlwZT01KSsKICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkrc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpKwogIAogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDUwMDAwKSkrbGFicyh0aXRsZT0iTEQgVmVoaWNsZSBDdXN0b21lciBFcXVpdmFsZW50IE1pbGVhZ2UiLHk9IlBlcmNlbnRpbGUiLHg9IkNFTSIsY29sb3I9ICJFbmdpbmUgU2l6ZSIpKwogIAogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPWMoMC41MCkpKStnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID1jKDAuOTUpKSkrCiAgdGhlbWVfYncoKSAKICAKICBnZ3NhdmUoIi9Vc2Vycy9uYW5hYWt3YXNpYWJheWllYm9hdGVuZy9Eb2N1bWVudHMvbWVtcGhpc2NsYXNzZXNib29rcy9EYXRhTWluaW5nc2NpZW5jZS9GQ0EvQ1VNTEQucGRmIikKIAoKYGBgCgoKIyMjIyMgQ3VtdWxhdGl2ZSBQZXJjZW50aWxlIFBsb3RzCgpgYGB7cn0KI2dncGxvdChMRF9FU18zLjZbMToxMDAwLF0sYWVzKE1JTEVTX1BFUl9ZRUFSKSkrZ2VvbV9oaXN0b2dyYW0oKQoKI3Bsb3QoTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSLCBjdW1zdW0oTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSKS9zdW0oTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSKSkKCmR1cmF0aW9uID0gTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSIApicmVha3MgPSBzZXEoMCwgbGVuZ3RoKExEX0VTXzMuNiRNSUxFU19QRVJfWUVBUiksIGJ5PTEwMDAwKSAKZHVyYXRpb24uY3V0ID0gY3V0KGR1cmF0aW9uLCBicmVha3MsIHJpZ2h0PUZBTFNFKSAKZHVyYXRpb24uZnJlcSA9IHRhYmxlKGR1cmF0aW9uLmN1dCkKY3VtZnJlcTAgPSBjKDAsIGN1bXN1bShkdXJhdGlvbi5mcmVxKS9zdW0oZHVyYXRpb24uZnJlcSkpIApwbG90KGJyZWFrcywgY3VtZnJlcTAsICAgICAgICAgICAgIyBwbG90IHRoZSBkYXRhIAptYWluPSJPbGQgRmFpdGhmdWwgRXJ1cHRpb25zIiwgICMgbWFpbiB0aXRsZSAKeGxhYj0iRHVyYXRpb24gbWludXRlcyIsICAgICAgICAjIHjiiJJheGlzIGxhYmVsIAp5bGFiPSJDdW11bGF0aXZlIGVydXB0aW9ucyIpICAgIyB54oiSYXhpcyBsYWJlbCAKbGluZXMoYnJlYWtzLCBjdW1mcmVxMCkgICAgICAgICAgICMgam9pbiB0aGUgcG9pbnRzCgpwbG90ZGY9ZGF0YS5mcmFtZShicmVha3MsY3VtZnJlcTApCgpnZ3Bsb3QocGxvdGRmLGFlcyhicmVha3MsY3VtZnJlcTApKStnZW9tX2xpbmUoKStzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KStzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpzY2llbnRpZmljKQpgYGAKCgpgYGB7cn0KI2dncGxvdChMRF9FU18zLjYsIGFlcyh4PU1JTEVTX1BFUl9ZRUFSKSkgKyBzdGF0X2VjZGYoKSsKIyAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsNTAwMDApKQpgYGAKCgpgYGB7cn0KZ2dwbG90KExEX0VTXzMuNiwgYWVzKE1JTEVTX1BFUl9ZRUFSLEN1bVBlcmNlbnRpbGUyKSkgKyAgCiBnZW9tX3N0ZXAoKSArIHhsYWIoIk1JTEVTX1BFUl9ZRUFSIikgKyB5bGFiKCJQZXJjZW50aWxlIikKYGBgCgoKCmBgYHtyfQoKY3VtZGF0YT1mdW5jdGlvbih4KXsKICAKZHVyYXRpb24gPSB4IApicmVha3MgPSBzZXEoMCwgbGVuZ3RoKGR1cmF0aW9uKSwgYnk9MTAwMCkgCmR1cmF0aW9uLmN1dCA9IGN1dChkdXJhdGlvbiwgYnJlYWtzLCByaWdodD1GQUxTRSkgCmR1cmF0aW9uLmZyZXEgPSB0YWJsZShkdXJhdGlvbi5jdXQpCmN1bWZyZXEwID0gYygwLCBjdW1zdW0oZHVyYXRpb24uZnJlcSkvc3VtKGR1cmF0aW9uLmZyZXEpKSAKCiNjdW1mcmVxMD0oY3Vtc3VtKGR1cmF0aW9uKS9zdW0oZHVyYXRpb24pKQogCnBsb3RkZj1kYXRhLmZyYW1lKGJyZWFrcyxjdW1mcmVxMCkgCgpyZXR1cm4ocGxvdGRmKQogIAogIAp9CgoKIyBkdXJhdGlvbiA9IExEX0VTXzMuNiRNSUxFU19QRVJfWUVBUiAKIyBicmVha3MgPSBzZXEoMCwgbGVuZ3RoKGR1cmF0aW9uKSwgYnk9MTAwMDApIAojIGR1cmF0aW9uLmN1dCA9IGN1dChkdXJhdGlvbiwgYnJlYWtzLCByaWdodD1GQUxTRSkgCiMgZHVyYXRpb24uZnJlcSA9IHRhYmxlKGR1cmF0aW9uLmN1dCkKIyBjdW1mcmVxMCA9IGMoMCwgY3Vtc3VtKGR1cmF0aW9uLmZyZXEpL3N1bShkdXJhdGlvbi5mcmVxKSkgCiMgICAgICAgICAKCgpnZ3Bsb3QoKSsKICAKZ2VvbV9saW5lKGFlcyhicmVha3MsY3VtZnJlcTAsY29sb3I9IjMuNkwiKSxkYXRhPWN1bWRhdGEoTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSICksc2l6ZT0xLjUsbGluZXR5cGU9MSkrCiAgCmdlb21fbGluZShhZXMoYnJlYWtzLGN1bWZyZXEwLGNvbG9yPSI1LjdMIiksZGF0YT1jdW1kYXRhKExEX0VTXzUuNyRNSUxFU19QRVJfWUVBUiApLHNpemU9MS41LGxpbmV0eXBlPTMpICsgCiAgCiAgCmdlb21fbGluZShhZXMoYnJlYWtzLGN1bWZyZXEwLGNvbG9yPSI2LjJMIiksZGF0YT1jdW1kYXRhKExEX0VTXzYuMiRNSUxFU19QRVJfWUVBUiApLHNpemU9MS41LGxpbmV0eXBlPTQpICsgIAogIAoKZ2VvbV9saW5lKGFlcyhicmVha3MsY3VtZnJlcTAsY29sb3I9IjYuNEwiKSxkYXRhPWN1bWRhdGEoTERfRVNfNi40JE1JTEVTX1BFUl9ZRUFSICksc2l6ZT0xLjUsbGluZXR5cGU9NSkgKyAgIAogIAogIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpK3NjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSsKICAKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCw1MDAwMCkpK2xhYnModGl0bGU9IkxEIFZlaGljbGUgQ3VzdG9tZXIgRXF1aXZhbGVudCBNaWxlYWdlIix5PSJQZXJjZW50aWxlIix4PSJDRU0iLGNvbG9yPSAiRW5naW5lIFNpemUiKSsKICAKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID1jKDAuNSkpKStnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID1jKDAuOTUpKSkrCiAgdGhlbWVfYncoKSAKCiMgcmVtb3ZlIGxlZ2VuZCB0aXRsZQogIAogICMgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCgojcmVuYW1lIHRoZSBjb2xvciBsZWdlbmQKCiNndWlkZXMoY29sb3I9Z3VpZGVfbGVnZW5kKHRpdGxlID0gIkVuZ2luZSBTaXplIikpCiAgCgpgYGAKCgoKCgpgYGB7cn0KY3VtZGF0YShMRF9FU18zLjYkTUlMRVNfUEVSX1lFQVIgKQpgYGAKCgoKCgoKCgoKCiMjIyMjICBMRCBFTkdJTkUgU0laRSA1LjcgTUlMRVMgUEVSIFlFQVIKCmBgYHtyfQoKcXVhbnRpbGUoTERfRVNfNS43JE1JTEVTX1BFUl9ZRUFSLGMoMC4wNSwwLjUsMC45NSksbmEucm0gPSBUUlVFKQoKYGBgCgoKIyMjIyMgIExEIEVOR0lORSBTSVpFIDYuMiBNSUxFUyBQRVIgWUVBUgoKYGBge3J9CnF1YW50aWxlKExEX0VTXzYuMiRNSUxFU19QRVJfWUVBUixjKDAuMDUsMC41LDAuOTUpLG5hLnJtID0gVFJVRSkKCmBgYAoKIyMjIyMgIExEIEVOR0lORSBTSVpFIDYuNCBNSUxFUyBQRVIgWUVBUgoKYGBge3J9CnF1YW50aWxlKExEX0VTXzYuNCRNSUxFU19QRVJfWUVBUixjKDAuMDUsMC41LDAuOTUpLG5hLnJtID0gVFJVRSkKYGBgCgoKCgoKYGBge3J9CmRmMT1kYXRhLmZyYW1lKFZhbHVlPWMoMjE0LjM4NTksMTczOTguMTQyMywzNzAwMS43NDc0LDI0My41MCwxNDk5NS43NSwzNzY0My4zMiwxNy41NjAxLDU0MzkuNDEyNiwyNzQ0OS43ODUyLAogICAgICAgICAgICAgICAgICAgICAgIDQ2LjQ0OTQ3LDExNjU5Ljk4Mzg2LDM2NTcwLjE0MjA2KSxwZXJjZW50aWxlPWMoIjV0aCIsIjUwdGgiLCI5NXRoIiwiNXRoIiwiNTB0aCIsIjk1dGgiLCI1dGgiLCI1MHRoIiwiOTV0aCIsIjV0aCIsIjUwdGgiLCI5NXRoIiksbW9kZWw9YygiMy42TCIsIjMuNkwiLCIzLjZMIiwiNS43TCIsIjUuN0wiLCI1LjdMIiwiNi4yTCIsIjYuMkwiLCI2LjJMIiwiNi40TCIsIjYuNEwiLCI2LjRMIikpCiAgICAgICAgICAgICAgCmRmMSU+JWhlYWQoKSAKY29sb3VyQ291bnQgPSBsZW5ndGgodW5pcXVlKGRmJG1vZGVsKSkKZ2V0UGFsZXR0ZSA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiU2V0MSIpKSAKIAogZ2dwbG90KGRmMSxhZXMoeD1wZXJjZW50aWxlLHk9VmFsdWUsZmlsbD1tb2RlbCkpK2dlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iixwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpKwogIAogIGdlb21fdGV4dChhZXMobGFiZWw9cm91bmQoVmFsdWUpLHZqdXN0PTEuNikscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLGNvbG9yPSJibGFjayIpK2xhYnMoeT0iTWlsZXMgcGVyIFllYXIiLHRpdGxlPSJDdXN0b21lciBFcXVpdmFsZW50IE1pbGVhZ2UgIExEIFZlaGljbGVzIikrdGhlbWVfYncoKSsgCiAgIAogICAKI3NjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiUGFpcmVkIikKI3NjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlNldDEiKQpzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTZXQyIikKIAogCiBnZ3NhdmUoIi9Vc2Vycy9uYW5hYWt3YXNpYWJheWllYm9hdGVuZy9Eb2N1bWVudHMvbWVtcGhpc2NsYXNzZXNib29rcy9EYXRhTWluaW5nc2NpZW5jZS9GQ0EvTGQucGRmIikKIApgYGAKCgoKCgoKYGBge3J9CmRmPWRmJT4lYWRkX2NvbHVtbihOYW1lPSJMQSIpCmRmMT1kZjElPiVhZGRfY29sdW1uKE5hbWU9IkxEIikKCmRmMz1iaW5kX3Jvd3MoZGYsZGYxKSU+JW11dGF0ZShOYW1lPWFzLmZhY3RvcihOYW1lKSkKCnRhaWwoZGYzKQoKYGBgCgoKCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KCgogZ2dwbG90KGRmMyxhZXMoeD1wZXJjZW50aWxlLHk9VmFsdWUsZmlsbD1tb2RlbCkpK2dlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iixwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpKwogIAogIGdlb21fdGV4dChhZXMobGFiZWw9cm91bmQoVmFsdWUpLHZqdXN0PTEuNikscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLGNvbG9yPSJibGFjayIpK2xhYnMoeT0iTWlsZXMgcGVyIFllYXIiLHRpdGxlPSJDdXN0b21lciBFcXVpdmFsZW50IE1pbGVhZ2UgICBWZWhpY2xlcyIpK3RoZW1lX2J3KCkrIAogICAKI2ZhY2V0X3dyYXAofk5hbWUsIHNjYWxlcyA9ICJmcmVlIiwgc3BhY2U9ImZyZWUiKSAgCiBmYWNldF9ncmlkKC5+TmFtZSwgc2NhbGVzPSJmcmVlIiwgc3BhY2U9ImZyZWUiKSAgCiNzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIpCnNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGU9IlNldDEiKQojc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iU2V0MiIpCgpgYGAKCgoKIyMjIyBEaXZpZGluZyBFbmdpbmUgU2l6ZSA2LjRMICBJbnRvIFNDQVQgYW5kIFNSVAoKIyMjIyMgIExEIEVOR0lORSBTSVpFIDYuNAoKYGBge3J9CgoKCiNBbHRlcm5hdGl2ZWx5CgpMRF9FU182LjRTQ0FUPC1MRF9FU182LjQlPiVkcGx5cjo6ZmlsdGVyKHN0cl9kZXRlY3QoTW9kZWxfTmFtZSwgIlNDQVQiKSkKCgoKCkxEX0VTXzYuNFNSVDwtTERfRVNfNi40JT4lZHBseXI6OmZpbHRlcihzdHJfZGV0ZWN0KE1vZGVsX05hbWUsICJTUlQiKSkKCiAgCgpMRF9FU182LjRTQ0FUJT4lZGltKCkKTERfRVNfNi40U1JUJT4lZGltKCkKCgoKCgpgYGAKCiMjIyMjIExEIEVOR0lORSBTSVpFIDYuNCAgU0NBVCBQQUNLIE1JTEVTIFBFUiBZRUFSCgpgYGB7cn0KcXVhbnRpbGUoTERfRVNfNi40U0NBVCRNSUxFU19QRVJfWUVBUixjKDAuMDUsMC41LDAuOTUpLG5hLnJtID0gVFJVRSkKYGBgCgojIyMjIyBMRCBFTkdJTkUgU0laRSA2LjQgIFNDQVQgUEFDSyBNSUxFUyBQRVIgWUVBUgoKYGBge3J9CnF1YW50aWxlKExEX0VTXzYuNFNSVCRNSUxFU19QRVJfWUVBUixjKDAuMDUsMC41LDAuOTUpLG5hLnJtID0gVFJVRSkKYGBgCgoKCgoKCgoKYGBge3J9CmRmPWRhdGEuZnJhbWUoVmFsdWU9YygxMTEzNC45MDcxNCwzMTIyOC45NjgwMiwxMjE4OC44Mzc2OCw0MTg3My4yMzg5NCAgKSxwZXJjZW50aWxlPWMoIjUwdGgiLCI5NXRoIiwiNTB0aCIsIjk1dGgiKSxtb2RlbD1jKCJTQ0FUIiwiU0NBVCIsIlNSVCIsIlNSVCIpKQogICAgICAgICAgICAgIAogZGYgCiAKIAogZ2dwbG90KGRmLGFlcyh4PXBlcmNlbnRpbGUseT1WYWx1ZSxmaWxsPW1vZGVsKSkrZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSkrCiAgCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1yb3VuZChWYWx1ZSksdmp1c3Q9MS42KSxwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksY29sb3I9ImJsYWNrIikrbGFicyh5PSJNaWxlcyBwZXIgWWVhciIsdGl0bGU9IkN1c3RvbWVyIEVxdWl2YWxlbnQgTWlsZWFnZSA2LjQgTEQiKSt0aGVtZV9idygpICsKICAKI3ZpcmlkaXM6OnNjYWxlX2NvbG9yX3ZpcmlkaXMoKQoKI3NjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiUmRZbEduIikKI3NjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJZbE9yUmQiKQojc2NhbGVfZmlsbF92aXJpZGlzX2QoZGlyZWN0aW9uID0gLTEpCiNzY2FsZV9maWxsX3dzaigpCiNzY2FsZV9maWxsX3NvbGFyaXplZCgpICAKICAKI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTk5OTk5IiwiIzU2QjRFOSIpKQogIAojc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwibGlnaHRncmV5IikpCgpzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIpCiAKIGdnc2F2ZSgiL1VzZXJzL25hbmFha3dhc2lhYmF5aWVib2F0ZW5nL0RvY3VtZW50cy9tZW1waGlzY2xhc3Nlc2Jvb2tzL0RhdGFNaW5pbmdzY2llbmNlL0ZDQS9MRDYuNC5wZGYiKQogCmBgYAoKCgoKCgoKCiMjIyMgTEEgRU5HSU5FIFNJWkUgNi40CgpgYGB7cn0KCkxBX0VTXzYuNFNDQVQ8LUxBX0VTXzYuNCU+JWRwbHlyOjpmaWx0ZXIoc3RyX2RldGVjdChNb2RlbF9OYW1lLCAiU0NBVCIpKQoKTEFfRVNfNi40U0NBVCU+JWRpbSgpCgoKTEFfRVNfNi40U1JUPC1MQV9FU182LjQlPiVkcGx5cjo6ZmlsdGVyKHN0cl9kZXRlY3QoTW9kZWxfTmFtZSwgIlNSVCIpKQpMQV9FU182LjRTUlQlPiVkaW0oKQoKCgoKCmBgYAoKCgoKCgojIyMjIyBMQSBFTkdJTkUgU0laRSA2LjQgIFNDQVQgUEFDSyBNSUxFUyBQRVIgWUVBUgoKYGBge3J9CnF1YW50aWxlKExBX0VTXzYuNFNDQVQkTUlMRVNfUEVSX1lFQVIsYygwLjA1LDAuNSwwLjk1KSxuYS5ybSA9IFRSVUUpCmBgYAoKCgojIyMjIyBMQSBFTkdJTkUgU0laRSA2LjQgIENVTVVMQVRJVkUgUEVSQ0VOVElMRSBQTE9UCgoKYGBge3J9CkxBX0VTXzYuNFNDQVQkQ3VtUGVyY2VudGlsZTwtMS9sZW5ndGgoTEFfRVNfNi40U0NBVCRNSUxFU19QRVJfWUVBUikKCgpMQV9FU182LjRTQ0FUJEN1bVBlcmNlbnRpbGUyPC1jdW1zdW0oTEFfRVNfNi40U0NBVCRDdW1QZXJjZW50aWxlKQoKCkxBX0VTXzYuNFNSVCRDdW1QZXJjZW50aWxlPC0xL2xlbmd0aChMQV9FU182LjRTUlQkTUlMRVNfUEVSX1lFQVIpCgoKTEFfRVNfNi40U1JUJEN1bVBlcmNlbnRpbGUyPC1jdW1zdW0oTEFfRVNfNi40U1JUJEN1bVBlcmNlbnRpbGUpCgoKCmdncGxvdCgpKwogIApnZW9tX2xpbmUoYWVzKE1JTEVTX1BFUl9ZRUFSLEN1bVBlcmNlbnRpbGUyLGNvbG9yPSJTQ0FUIiksZGF0YT1MQV9FU182LjRTQ0FULHNpemU9MS41LGxpbmV0eXBlPTEpKwogIApnZW9tX2xpbmUoYWVzKE1JTEVTX1BFUl9ZRUFSLEN1bVBlcmNlbnRpbGUyLGNvbG9yPSJTUlQiKSxkYXRhPUxBX0VTXzYuNFNSVCxzaXplPTEuNSxsaW5ldHlwZT0zKSArIAogIAogIAoKICAKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KStzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkrCiAgCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsNTAwMDApKStsYWJzKHRpdGxlPSJMQSA2LjQgVmVoaWNsZSBDdXN0b21lciBFcXVpdmFsZW50IE1pbGVhZ2UiLHk9IlBlcmNlbnRpbGUiLHg9IkNFTSIsY29sb3I9ICJFbmdpbmUgU2l6ZSIpKwogIAogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPWMoMC41KSkpK2dlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPWMoMC45NSkpKSsKICB0aGVtZV9idygpIApnZ3NhdmUoIi9Vc2Vycy9uYW5hYWt3YXNpYWJheWllYm9hdGVuZy9Eb2N1bWVudHMvbWVtcGhpc2NsYXNzZXNib29rcy9EYXRhTWluaW5nc2NpZW5jZS9GQ0EvQ1VNTEE2LjQucGRmIikKIAoKYGBgCgoKCgojIyMjIyBMRCBFTkdJTkUgU0laRSA2LjQgIENVTVVMQVRJVkUgUEVSQ0VOVElMRSBQTE9UCgoKCmBgYHtyfQpMRF9FU182LjRTQ0FUJEN1bVBlcmNlbnRpbGU8LTEvbGVuZ3RoKExEX0VTXzYuNFNDQVQkTUlMRVNfUEVSX1lFQVIpCgoKTERfRVNfNi40U0NBVCRDdW1QZXJjZW50aWxlMjwtY3Vtc3VtKExEX0VTXzYuNFNDQVQkQ3VtUGVyY2VudGlsZSkKCgpMRF9FU182LjRTUlQkQ3VtUGVyY2VudGlsZTwtMS9sZW5ndGgoTERfRVNfNi40U1JUJE1JTEVTX1BFUl9ZRUFSKQoKCkxEX0VTXzYuNFNSVCRDdW1QZXJjZW50aWxlMjwtY3Vtc3VtKExEX0VTXzYuNFNSVCRDdW1QZXJjZW50aWxlKQoKCgpnZ3Bsb3QoKSsKICAKZ2VvbV9saW5lKGFlcyhNSUxFU19QRVJfWUVBUixDdW1QZXJjZW50aWxlMixjb2xvcj0iU0NBVCIpLGRhdGE9TERfRVNfNi40U0NBVCxzaXplPTEuNSxsaW5ldHlwZT0xKSsKICAKZ2VvbV9saW5lKGFlcyhNSUxFU19QRVJfWUVBUixDdW1QZXJjZW50aWxlMixjb2xvcj0iU1JUIiksZGF0YT1MRF9FU182LjRTUlQsc2l6ZT0xLjUsbGluZXR5cGU9MykgKyAKICAKICAKCiAgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkrc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpKwogIAogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDUwMDAwKSkrbGFicyh0aXRsZT0iTEQgNi40IFZlaGljbGUgQ3VzdG9tZXIgRXF1aXZhbGVudCBNaWxlYWdlIix5PSJQZXJjZW50aWxlIix4PSJDRU0iLGNvbG9yPSAiRW5naW5lIFNpemUiKSsKICAKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID1jKDAuNSkpKStnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID1jKDAuOTUpKSkrCiAgdGhlbWVfYncoKSAKCiBnZ3NhdmUoIi9Vc2Vycy9uYW5hYWt3YXNpYWJheWllYm9hdGVuZy9Eb2N1bWVudHMvbWVtcGhpc2NsYXNzZXNib29rcy9EYXRhTWluaW5nc2NpZW5jZS9GQ0EvQ1VNTEQ2LjQucGRmIikKIApgYGAKCgoKCgoKCmBgYHtyfQoKcXVhbnRpbGUoTEFfRVNfNi40U1JUJE1JTEVTX1BFUl9ZRUFSLGMoMC4wNSwwLjUsMC45NSksbmEucm0gPSBUUlVFKQoKCmBgYAoKIyMjIyMgTEEgRU5HSU5FIFNJWkUgNi40ICBTUlQgTUlMRVMgUEVSIFlFQVIKCgoKCmBgYHtyfQpkZj1kYXRhLmZyYW1lKFZhbHVlPWMoICA4MTk0Ljc0NTEyLDI2NzU1LjM2ODIwLDc2MTAuNTYxNDcsMjU4NjEuMzA2NTQgICApLHBlcmNlbnRpbGU9YygiNTB0aCIsIjk1dGgiLCI1MHRoIiwiOTV0aCIpLG1vZGVsPWMoIlNDQVQiLCJTQ0FUIiwiU1JUIiwiU1JUIikpCiAgICAgICAgICAgICAgCiBkZiAKIAogCiAKCmBgYAoKYGBge3J9CgpnZ3Bsb3QoZGYsYWVzKHg9cGVyY2VudGlsZSx5PVZhbHVlLGZpbGw9bW9kZWwpKStnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIscG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpKSsKICAKICBnZW9tX3RleHQoYWVzKGxhYmVsPXJvdW5kKFZhbHVlKSx2anVzdD0xLjYpLHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSxjb2xvcj0iYmxhY2siKStsYWJzKHk9Ik1pbGVzIHBlciBZZWFyIix0aXRsZT0iQ3VzdG9tZXIgRXF1aXZhbGVudCBNaWxlYWdlIDYuNCBMQSIpK3RoZW1lX2J3KCkgKwogIAojdmlyaWRpczo6c2NhbGVfY29sb3JfdmlyaWRpcygpCgojc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJSZFlsR24iKQojc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIllsT3JSZCIpCiNzY2FsZV9maWxsX3ZpcmlkaXNfZChkaXJlY3Rpb24gPSAtMSkKI3NjYWxlX2ZpbGxfd3NqKCkKI3NjYWxlX2ZpbGxfc29sYXJpemVkKCkgIAogIAojc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiM5OTk5OTkiLCIjNTZCNEU5IikpCiAgCiNzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCJsaWdodGdyZXkiKSkKCnNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiUGFpcmVkIikKCgoKIGdnc2F2ZSgiL1VzZXJzL25hbmFha3dhc2lhYmF5aWVib2F0ZW5nL0RvY3VtZW50cy9tZW1waGlzY2xhc3Nlc2Jvb2tzL0RhdGFNaW5pbmdzY2llbmNlL0ZDQS9MQTYuNC5wZGYiKQogCmBgYAoKCiMjIyMgQ29uZmlkZW5jZSBJbnRlcnZhbCBmb3IgUGVyY2VudGlsZXMKV2UgY2FuIGZpbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMgZm9yIHRoZSBwZXJjZW50aWxlcyBieSBnZW5lcmF0aW5nICBhIGxhcmdlIGJvb3RzdHJhcCBzYW1wbGVzIGFuZCBjYWxjdWxhdGluZyB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbHMgZnJvbSB0aGUgYm9vdHN0cmFwIHNhbXBsZXMuCmBgYHtyfQoKY29uLml0ZXIucGVyY2V0aWxlPWZ1bmN0aW9uKHgscCxSKXsKCmxpYnJhcnkoYm9vdCkKCmNpPWJvb3QuY2koYm9vdCh4LGZ1bmN0aW9uKHgsaSkgcXVhbnRpbGUoeFtpXSxwcm9icyA9cCApLCBSKSkKCnJldHVybihjaSkKCn0KCgoKCgojQWx0ZXJuYXRpdmVseQoKCmNvbi5pdGVyLnBlcmNldGlsZTI8LWZ1bmN0aW9uKHgscCl7CiAgCnJldHVybihzb3J0KHgpW3FiaW5vbShjKC4wMjUsLjk3NSksIGxlbmd0aCh4KSwgcCldKSAgCiAgCn0KCgoKCiNlcXVpdmFsZW50bHkKCmNvbi5pdGVyLnBlcmNldGlsZTM8LWZ1bmN0aW9uKHgscCl7CiAgCmJvb3RtZWQgPSBhcHBseShtYXRyaXgoc2FtcGxlKHgsIHJlcD1UUlVFLCAxMDAwKmxlbmd0aCh4KSksIG5yb3c9MTAwMCksIDEsIHF1YW50aWxlLHByb2JzPWMocCkpCgpyZXR1cm4ocXVhbnRpbGUoYm9vdG1lZCwgYyguMDI1LCAwLjk3NSkpKQogIAp9CgoKCmBgYAoKCgojIyMjIyBDb25maWRlbmNlIEludGVydmFsIGZvciBMQSBFbmdpbmUgU2l6ZXMKCmBgYHtyLHJlc3VsdHM9ImFzaXMiLCAgcm93cy5wcmludD0xMDAsY29sLnByaW50PTIwfQojIExBX0VTXzMuNiRNSUxFU19QRVJfWUVBUgojICAgIDUlICAgICAgICAgNTAlICAgICAgICAgOTUlIAojICAgMzEuNzYwODcgMTMzNjUuMzQwNzAgMzE5OTMuOTIzXzQxIAoKYT1tYXRyaXgoY29uLml0ZXIucGVyY2V0aWxlMihMQV9FU18zLjYkTUlMRVNfUEVSX1lFQVIsMC4wNSksbnJvdyA9IDEpJT4lIApyYmluZChjb24uaXRlci5wZXJjZXRpbGUyKExBX0VTXzMuNiRNSUxFU19QRVJfWUVBUiwwLjUpKSU+JQpyYmluZChjb24uaXRlci5wZXJjZXRpbGUyKExBX0VTXzMuNiRNSUxFU19QRVJfWUVBUiwwLjk1KSkKCgoKYj1tYXRyaXgoY29uLml0ZXIucGVyY2V0aWxlMihMQV9FU181LjckTUlMRVNfUEVSX1lFQVIsMC4wNSksbnJvdyA9IDEpJT4lIApyYmluZChjb24uaXRlci5wZXJjZXRpbGUyKExBX0VTXzUuNyRNSUxFU19QRVJfWUVBUiwwLjUpKSU+JQpyYmluZChjb24uaXRlci5wZXJjZXRpbGUyKExBX0VTXzUuNyRNSUxFU19QRVJfWUVBUiwwLjk1KSkKCmM9bWF0cml4KGNvbi5pdGVyLnBlcmNldGlsZTIoTEFfRVNfNi4yJE1JTEVTX1BFUl9ZRUFSLDAuMDUpLG5yb3cgPSAxKSU+JSAKcmJpbmQoY29uLml0ZXIucGVyY2V0aWxlMihMQV9FU182LjIkTUlMRVNfUEVSX1lFQVIsMC41KSklPiUKcmJpbmQoY29uLml0ZXIucGVyY2V0aWxlMihMQV9FU182LjIkTUlMRVNfUEVSX1lFQVIsMC45NSkpCgpkPW1hdHJpeChjb24uaXRlci5wZXJjZXRpbGUyKExBX0VTXzYuNCRNSUxFU19QRVJfWUVBUiwwLjA1KSxucm93ID0gMSklPiUgCnJiaW5kKGNvbi5pdGVyLnBlcmNldGlsZTIoTEFfRVNfNi40JE1JTEVTX1BFUl9ZRUFSLDAuNSkpJT4lCnJiaW5kKGNvbi5pdGVyLnBlcmNldGlsZTIoTEFfRVNfNi40JE1JTEVTX1BFUl9ZRUFSLDAuOTUpKQoKCgoKCk5hbWVfTEE9YXMuZmFjdG9yKHJlcChjKDMuNiw1LjcsNi4yLDYuNCksYygzLDMsMywzKSkpCgpQZXJjZW50aWxlPWFzLmZhY3RvcihyZXAoYygiNXRoIiwiNTB0aCIsIjk1dGgiKSw0KSkKCgoKClZhbHVlPWMoMzEuNzYwODcsMTMzNjUuMzQwNzAsMzE5OTMuOTIzNDEsMzIuODIxNjMsMTA4MTguMDkxNjAsMzIyODQuNDQ0MDgsMjMuODIwNjUsMzEzNS41NzgzOSwgMjExNDMuOTE2NjcsNDAuNTgzMzMsODAzNS41MDAwMCwyNjQ5OS4yNjAyMCAgKQoKTEFfQ0k9ZGF0YS5mcmFtZShFbmdpbmVfU2l6ZT1OYW1lX0xBLFZhbHVlPXJvdW5kKFZhbHVlLDEpLHJvdW5kKGRvLmNhbGwocmJpbmQsbGlzdChhLGIsYyxkKSksMSksUGVyY2VudGlsZSklPiVyZW5hbWUoTG93ZXI9WDEsVXBwZXI9WDIpCgpMQV9DSSU+JWthYmxlKC4sZm9ybWF0PSJodG1sIixjYXB0aW9uID0gIkNvbmZpZGVuY2UgSW50ZXJ2YWwgZm9yIExBIEVuZ2luZSBTaXplcyIpJT4la2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSkKCkxBX0NJCmBgYAoKCgoKIyMjIyMgQ29uZmlkZW5jZSBJbnRlcnZhbCBmb3IgTEQgRW5naW5lIFNpemVzCgpgYGB7ciByb3dzLnByaW50PTEwMCxjb2wucHJpbnQ9MjB9Cgojb3B0aW9uKG1heC5wcmludD0xMDApCgphPW1hdHJpeChjb24uaXRlci5wZXJjZXRpbGUyKExEX0VTXzMuNiRNSUxFU19QRVJfWUVBUiwwLjA1KSxucm93ID0gMSklPiUgCnJiaW5kKGNvbi5pdGVyLnBlcmNldGlsZTIoTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSLDAuNSkpJT4lCnJiaW5kKGNvbi5pdGVyLnBlcmNldGlsZTIoTERfRVNfMy42JE1JTEVTX1BFUl9ZRUFSLDAuOTUpKQoKCgpiPW1hdHJpeChjb24uaXRlci5wZXJjZXRpbGUyKExEX0VTXzUuNyRNSUxFU19QRVJfWUVBUiwwLjA1KSxucm93ID0gMSklPiUgCnJiaW5kKGNvbi5pdGVyLnBlcmNldGlsZTIoTERfRVNfNS43JE1JTEVTX1BFUl9ZRUFSLDAuNSkpJT4lCnJiaW5kKGNvbi5pdGVyLnBlcmNldGlsZTIoTERfRVNfNS43JE1JTEVTX1BFUl9ZRUFSLDAuOTUpKQoKYz1tYXRyaXgoY29uLml0ZXIucGVyY2V0aWxlMihMRF9FU182LjIkTUlMRVNfUEVSX1lFQVIsMC4wNSksbnJvdyA9IDEpJT4lIApyYmluZChjb24uaXRlci5wZXJjZXRpbGUyKExEX0VTXzYuMiRNSUxFU19QRVJfWUVBUiwwLjUpKSU+JQpyYmluZChjb24uaXRlci5wZXJjZXRpbGUyKExEX0VTXzYuMiRNSUxFU19QRVJfWUVBUiwwLjk1KSkKCmQ9bWF0cml4KGNvbi5pdGVyLnBlcmNldGlsZTIoTERfRVNfNi40JE1JTEVTX1BFUl9ZRUFSLDAuMDUpLG5yb3cgPSAxKSU+JSAKcmJpbmQoY29uLml0ZXIucGVyY2V0aWxlMihMRF9FU182LjQkTUlMRVNfUEVSX1lFQVIsMC41KSklPiUKcmJpbmQoY29uLml0ZXIucGVyY2V0aWxlMihMRF9FU182LjQkTUlMRVNfUEVSX1lFQVIsMC45NSkpCgoKCgoKTmFtZV9MRD1hcy5mYWN0b3IocmVwKGMoMy42LDUuNyw2LjIsNi40KSxjKDMsMywzLDMpKSkKClBlcmNlbnRpbGU9YXMuZmFjdG9yKHJlcChjKCI1dGgiLCI1MHRoIiwiOTV0aCIpLDQpKQoKCgoKClZhbHVlPWMoMjE0LjM4NTksMTczOTguMTQyMywzNzAwMS43NDc0LDI0My41MCwxNDk5NS43NSwzNzY0My4zMiwxNy41NjAxLDU0MzkuNDEyNiwyNzQ0OS43ODUyLAogICAgICAgICAgICAgICAgICAgICAgIDQ2LjQ0OTQ3LDExNjU5Ljk4Mzg2LDM2NTcwLjE0MjA2KQpMRF9DST1kYXRhLmZyYW1lKEVuZ2luZV9TaXplPU5hbWVfTEEsVmFsdWU9cm91bmQoVmFsdWUsMSkscm91bmQoZG8uY2FsbChyYmluZCxsaXN0KGEsYixjLGQpKSwxKSxQZXJjZW50aWxlKSU+JXJlbmFtZShMb3dlcj1YMSxVcHBlcj1YMikKCkxEX0NJCgoKa2FibGUoTERfQ0ksICJodG1sIiklPiUKa2FibGVfc3R5bGluZygic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBUKSAlPiUKICBjb2x1bW5fc3BlYygxOjUsIGJvbGQgPSBUKSAlPiUKICByb3dfc3BlYygxOjEyLCBib2xkID0gVCwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiNENzI2MUUiKQoKCgpMRF9DSSU+JWthYmxlKC4sZm9ybWF0PSJodG1sIixjYXB0aW9uID0gIkNvbmZpZGVuY2UgSW50ZXJ2YWwgZm9yIExEIEVuZ2luZSBTaXplcyIpJT4la2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSkKCmBgYAoK