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