Rpubs link for this study: http://rpubs.com/The_Analyst/431304
Required packages
library(readr)
library(magrittr)
library(dplyr)
library(tidyr)
library(readxl)
library(lubridate)
library(stringr)
library(ggplot2)
library(mlr)
Executive Summary
- In this report, we are trying to analyse the housing prices and crime statistics for the key regional areas of Melbourne answering questions like which region has the highest property price or which region has the lowest number of reported crime incidents.
- Two data sets have been used for this purpose.
- The First one is the Melbourne Housing Data which contains the prices of properties sold, along with the type of property, its suburb, region etc. I have restricted my analysis to three bedroom landed houses sold in 2017 and within 100km from CBD. Also the rows where prices are not available have been removed as the housing prices are skewed and imputing them with mean or median might influence the whole result. Region names have been factorised and other necessary data transformation like changing the class of Date variable has been done. Post this the median price and distance have been calculated.
- The crime statistics data has been imported and its variable names have been updated.This was followed by converting variables into suitable data types and labelling the factors. The data for year 2017 has been filtered and checked for possible missing values.
- Post sanitation, the crime statistics data has been joined to the housing data, using suburb as the grouping variable. Missing values were identified and handled.Obvious error and inconsistency was checked.
- As the next logical step, we have used a boxplot to look into the outliers for Price and Crime. In this case the suburbs whose property price or crime rate are significantly higher than that of other suburbs in the same region.
I have not eliminated the outliers as they are not false alarms but a real depiction of the high property price or crime stats of a particular suburb.
- Going further, I have applied mathematical functions to transform the median price and distance, to achieve normality , post which we have used the mlr package to come with a model to predict the median price of a property using other variables. We have used the generalised linear model and achieved a performance statistics or mean absolute error below 0.1.
- This dataset can be used in future for further statistical analysis.
Data collection
Melbourne housing data is taken from the kaggle data set hyperlink,Melbourne Housing Market and Melbourne Crime Statistics has been sourced from hyperlink,Melbourne Crime Statistics
Data_Dictionary :
The followig variables are required:
Melbourne Housing Data:
- Suburb: Suburbs
- Rooms: Number of rooms
- Price: Price in Australian dollars
- Type: br - bedroom(s); h - house,cottage,villa, semi,terrace; u - unit, duplex; t - townhouse; dev site - development site; o res - other residential.
- Date: Date sold
- Distance: Distance from CBD in Kilometres
- Regionname: General Region (West, North West, North, North east …etc)
Crime Statistics data:
- Year ending June: Year of crime
- Postcode: Self explanatory
- Suburb/Town Name: Suburb
- Offence Division: offence category
- Incidents Recorded:Number of incidents
Crime_Inc_PostCode <- read_excel("Data_tables_Criminal_Incidents_Visualisation_year_ending_June_2018.xlsx", sheet = "Table 07" )
head(Crime_Inc_PostCode)
Melb <- read_csv("MELBOURNE_HOUSE_PRICES_LESS.csv") #Read the Housing data set
Parsed with column specification:
cols(
Suburb = col_character(),
Address = col_character(),
Rooms = col_integer(),
Type = col_character(),
Price = col_integer(),
Method = col_character(),
SellerG = col_character(),
Date = col_character(),
Postcode = col_integer(),
Regionname = col_character(),
Propertycount = col_integer(),
Distance = col_double(),
CouncilArea = col_character()
)
head(Melb)
Structure and manipulations of Melbourne Housing data set
- Check for NAs. Out of 60672 rows there are 13,836 items where the Price is missing. We will ignore those cases and only look at the rows where we have the price listed.
- For this assignment we are only looking at the price in 2017 for the landed houses (‘h’) with 3 bedrooms and within 100kms (from Melbourne Central).
- Check the class of variables.
- Factorise the region names.
- Change the type of date variable from numeric to date.
- Transform the suburb into upper case to match with the other data set at time of join.
sum(is.na(Melb$Price)) #check for NA
[1] 13836
Melb_drop_na <- drop_na(Melb,Price) #handling NA's
Melb_filtered_data_2017 <- Melb_drop_na %>% filter( Type == 'h' & Rooms == 3 & Distance <100 & Date >= '2017-01-01') #apply the filtering criteria on the dataset
sapply(Melb_filtered_data_2017, class)
Suburb Address Rooms Type Price
"character" "character" "integer" "character" "integer"
Method SellerG Date Postcode Regionname
"character" "character" "character" "integer" "character"
Propertycount Distance CouncilArea
"integer" "numeric" "character"
#factorise the Region Names
Melb_filtered_data_2017$Regionname <- as.factor(Melb_filtered_data_2017$Regionname)
levels(Melb_filtered_data_2017$Regionname)
[1] "Eastern Metropolitan" "Eastern Victoria"
[3] "Northern Metropolitan" "Northern Victoria"
[5] "South-Eastern Metropolitan" "Southern Metropolitan"
[7] "Western Metropolitan" "Western Victoria"
Melb_filtered_data_2017$Date<- dmy(Melb_filtered_data_2017$Date) #date transformation
#to check the month in the date
Melb_filtered_data_2017$Date %>% month(label = TRUE, abbr = FALSE) %>% head(10)
[1] February February February February February February February February
[9] February February
12 Levels: January < February < March < April < May < June < ... < December
#transform the Suburb variable to upper case
Melb_filtered_data_2017$Suburb <- toupper(Melb_filtered_data_2017$Suburb )
Structure and manipulations of Melbourne Crime data set
- Rename the column name to ease readability.
- Check the datatype of variables.
- Factorise the Offence type and Suburbs.
- Filter the 2017 crime statistics data for the purpose of this study.
- Check for NA’s in the final dataset.
names(Crime_Inc_PostCode) #check the names of dataset
[1] "Year ending June" "Postcode" "Suburb/Town Name"
[4] "Offence Division" "Offence Subdivision" "Offence Subgroup"
[7] "Incidents Recorded"
#rename the columns to make increase readablity
Crime_Inc_PostCode <- rename(Crime_Inc_PostCode,
Year = `Year ending June`,
Suburb = `Suburb/Town Name`,
Offence = `Offence Division`,
No_of_Incident = `Incidents Recorded`)
sapply(Crime_Inc_PostCode,class) #check datatypes
Year Postcode Suburb
"numeric" "numeric" "character"
Offence Offence Subdivision Offence Subgroup
"character" "character" "character"
No_of_Incident
"numeric"
#factorise the offence variable
Crime_Inc_PostCode$Offence <- factor(Crime_Inc_PostCode$Offence, levels = c("A Crimes against the person","B Property and deception offences","C Drug offences","D Public order and security offences","E Justice procedures offences","F Other offences"),
labels = c("Crime against person","Property offences","Drug offences","Public order and security","Justice Procedures","Others"))
Crime_Inc_PostCode$Suburb <- as.factor(Crime_Inc_PostCode$Suburb)
#filter the data for 2017 crime statistics
Crime_Inc_PostCode_2017 <- Crime_Inc_PostCode %>% filter(Year %in% "2017")
sum(is.na(Crime_Inc_PostCode_2017)) #check for NA's
[1] 0
Summarise the data and create new variables.
- Use mutate to create two new variables median_price and median_distance for the Melbourne housing data set.
- Group by Suburbs and use summarise to create Total_Incidents by Suburbs.
# Summarise the data and create new columns fro median price and distance.
Melb_working_set_2017 <- Melb_filtered_data_2017 %>% group_by(Postcode,Suburb) %>%
mutate(median_price = median(Price),
median_distance = median(Distance)
) %>% distinct(Postcode,median_price,median_distance,count,Regionname)
Trying to compute distinct() for variables not found in the data:
- `count`
This is an error, but only a warning is raised for compatibility reasons.
The following variables will be used:
- Postcode
- median_price
- median_distance
- Regionname
Melb_working_set_2017 %>% head(5)
#Summarise the Crime Data to find No of Incidents per Suburb
Suburbs_Crime_2017 <- Crime_Inc_PostCode_2017 %>% group_by(Suburb) %>% summarise(
Total_Incidents = sum(No_of_Incident)
)
Suburbs_Crime_2017 %>% head(5)
Join the data sets
- Join the Melbourne housing data with the crime statistics data to make a unified data set with Suburb name, postcode, regiona name, median price, median distance and total number of crime incidents.
#Join the Data sets
# On the Melbourne Housing Data , Join the Number of Criminal Incidents , per Suburb
Ready_to_work_data <- left_join(Melb_working_set_2017, Suburbs_Crime_2017, by="Suburb")
Column `Suburb` joining character vector and factor, coercing into character vector
Ready_to_work_data %>% head(5)
Scanning final data set for inconsistency
- Check for NA’s in the final data set.
- Eliminate the Suburb where we do not have information about the number of incidents committed.
- Create rule to check for obvious error or inconsistency.
#Investigatge if there is any NA's in this data set as result of Join
sum(is.na(Ready_to_work_data))
[1] 1
Ready_to_work_data[!complete.cases(Ready_to_work_data),] #inspect NA rows
#Eliminate this suburb as we dont have info about the total number of Incidents
Ready_to_work_data <- Ready_to_work_data[complete.cases(Ready_to_work_data),]
#create a rule to check if the values are non negative
Rule <- editset(c("median_price >= 0", "median_distance >= 0","Total_Incidents>=0"))
Rule
Edit set:
num1 : 0 <= median_price
num2 : 0 <= median_distance
num3 : 0 <= Total_Incidents
#apply rule on the Final data set
rules_violated <- violatedEdits(Rule,Ready_to_work_data)
summary(rules_violated) #visualise if any rules is violated
No violations detected, 0 checks evaluated to NA
NULL
Ready_to_work_data %>% head(5)
Identify the suburb with higher crime incidents (outliers)
- Group the suburbs by regions and plot the crime incident for each region.
- The outlier represents those “Suburbs” where the observed number of crime incidents departs significantly from the number of incidents in other suburbs on the same region. In other words it depicts the Suburbs with higher crime rate in that region.
- Melbourne suburb with 16826 number of incidents in marked to show the Suburb which has the highest number of crime incidents recorded across all regions.
outliers_crime = boxplot(Ready_to_work_data$Total_Incidents ~ Ready_to_work_data$Regionname,plot=FALSE)$out
#Make a new column for labelling the outliers : Suburb/Region with highest number of crime incidents. Use Paste to concatenate strings.
Ready_to_work_data$label_crime <- ifelse((Ready_to_work_data$Total_Incidents %in% outliers_crime & Ready_to_work_data$Total_Incidents>15000),
paste(Ready_to_work_data$Suburb,"\n",
Ready_to_work_data$Total_Incidents),"")
#Make a boxplot
ggplot(aes(y=Total_Incidents,x=Regionname,fill=Regionname),data = Ready_to_work_data)+geom_boxplot()+
#theme_grey(base_size = 10) +
theme(legend.position = "bottom")+
scale_x_discrete(labels=c("E.Metro","E.Vic","N.Metro",
"N.Vic","S-E.Metro","S.Metro","W.Metro", "W.Vic")) + geom_text(aes(label=label_crime))+
ggtitle("Melbourne Crime Incidents by Region") +
xlab("Region Names") + ylab("No of Crime Incidents") +
theme(
plot.title = element_text(colour = "Black",size = 14, face = "bold", hjust = 0.5 )
)

Excluding outlier
- Once we see that the suburb Melbourne has the maximum number of Crime Incidents in 2017, lets exclude it and view the boxplot again.Now we can clearly see the median i.e number of crimes in a region is highest for Western Victoria.( this is done only for visualisation)
- Still there are many outliers in the data, but as per this study, they represent the suburbs with higher crimes compared to that region and should not be excluded at any point.
Data_without_Melb_Suburb <- Ready_to_work_data %>% filter(!Suburb %in% "MELBOURNE")
ggplot(aes(y=Total_Incidents,x=Regionname,fill=Regionname),data = Data_without_Melb_Suburb)+geom_boxplot()+
# theme_grey(base_size = 10)+
theme(legend.position = "bottom")+
scale_x_discrete(labels=c("E.Metro","E.Vic","N.Metro",
"N.Vic","S-E.Metro","S.Metro","W.Metro", "W.Vic")) +
ggtitle("Melbourne Crime Incidents by Region") +
xlab("Region Names") + ylab("No of Crime Incidents") +
theme(
plot.title = element_text(colour = "Black",size = 14, face = "bold", hjust = 0.5 )
)

Multivariate outlier detection:
- Explore the relation between property price and crime incidents.
- Use a scatter plot for number of Crime Incidents against property price.
- There are few outliers in this plot which suggest the suburbs with an unusually high property price and crime rate compared to other suburbs.
- These outliers shouldnt be removed or imputed as they represent important facts.
qplot(data=Ready_to_work_data, x=median_price, y=Total_Incidents) +geom_text(aes(label=ifelse((Total_Incidents>5*IQR(Total_Incidents)|median_price>4*IQR(median_price)),paste(Suburb,"\n"),"")), hjust=1.1) +
ggtitle("Melbourne: Number of crime incidents against property prices") +
ylab("No of Crime Incidents") + xlab("median property price") +
theme(
plot.title = element_text(colour = "Black",size = 14, face = "bold", hjust = 0.5 )
) # 5*IQR / 4*IQR - random values just for labelling most extreme points.

- Looking at the plot above Toorak doesn’t appear to be the suburb with best value for money as there are other suburbs which are cheaper and with lower crime rate, however there might be other factors involved which is beyond the scope of this report.
Machine Learning model to predict the price using distance
Steps:
- Step 1: Define the task as regression analysis with Price as target variable.
- Step 2: We will use the classic regression as our algorithm
- Step 3: Fitting the model
- Divide the data into train and test set.
- Train the learner on the training set.
- Step 4 : Make pricing predictions using the trained model to predict the price in the test set.
- Step 5: Evaluating the learner: We calculate the mean square error and mean absolute error to see the performance metric of our learner.
# Task
ML_dataset_task <- makeRegrTask(data = ML_dataset,target = "median_price")
#Learner algorithm - classic regression
lrnr = makeLearner("regr.glm")
#definine the train and test sets
n=nrow(ML_dataset)
training_set = sample(n, size = 2/3*n)
testing_set = setdiff(1:n, training_set)
# make a model of the data and train the learner on the task using the training set
pricing_model = mlr::train(learner = lrnr, task = ML_dataset_task, subset = training_set)
pricing_model
Model for learner.id=regr.glm; learner.class=regr.glm
Trained on: task.id = ML_dataset; obs = 218; features = 1
Hyperparameters: family=gaussian,model=FALSE
#predict the price
pred_price = predict(pricing_model, task = ML_dataset_task, subset = testing_set)
#evaluate the learner
performance(pred_price,measures = list(mse,mae))
mse mae
0.01667724 0.10352674
Findings:
As the absolute error is small, the model performed well against the given set of data. The model can be applied on additional data sets to evaluate its performance. Further an F test can be done for overall model significance.
Further steps:
The data can be used to find a correlation between the housing prices and distance (from Melbourne Central). Also if the relationship changes travelling the same distance but in different metropolitan regions. Further, Crime statistics for the suburb can be looked to explore a correlation, if any between the housing price and crime in that suburb.
LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXN0ZXIgMiwgMjAxOCIKYXV0aG9yOiAiQWhtYWQgSGFzbmFpbiBzMzcxMjUzOCIKc3VidGl0bGU6IEFzc2lnbm1lbnQgMwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KClJwdWJzIGxpbmsgZm9yIHRoaXMgc3R1ZHk6IGh0dHA6Ly9ycHVicy5jb20vVGhlX0FuYWx5c3QvNDMxMzA0IAoKCiMjIFJlcXVpcmVkIHBhY2thZ2VzIAoKYGBge3J9CgpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KG1hZ3JpdHRyKSAKbGlicmFyeShkcGx5cikKbGlicmFyeSh0aWR5cikKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkobHVicmlkYXRlKSAKbGlicmFyeShzdHJpbmdyKSAKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KG1scikKYGBgCgojIyBFeGVjdXRpdmUgU3VtbWFyeSAKCiogSW4gdGhpcyByZXBvcnQsIHdlIGFyZSB0cnlpbmcgdG8gYW5hbHlzZSB0aGUgaG91c2luZyBwcmljZXMgYW5kIGNyaW1lIHN0YXRpc3RpY3MgZm9yIHRoZSBrZXkgcmVnaW9uYWwgYXJlYXMgb2YgTWVsYm91cm5lIGFuc3dlcmluZyBxdWVzdGlvbnMgbGlrZSB3aGljaCByZWdpb24gaGFzIHRoZSBoaWdoZXN0IHByb3BlcnR5IHByaWNlIG9yIHdoaWNoIHJlZ2lvbiBoYXMgdGhlIGxvd2VzdCBudW1iZXIgb2YgcmVwb3J0ZWQgY3JpbWUgaW5jaWRlbnRzLgoqIFR3byBkYXRhIHNldHMgaGF2ZSBiZWVuIHVzZWQgZm9yIHRoaXMgcHVycG9zZS4KKiBUaGUgRmlyc3Qgb25lIGlzIHRoZSBNZWxib3VybmUgSG91c2luZyBEYXRhIHdoaWNoIGNvbnRhaW5zIHRoZSBwcmljZXMgb2YgcHJvcGVydGllcyBzb2xkLCBhbG9uZyB3aXRoIHRoZSB0eXBlIG9mIHByb3BlcnR5LCBpdHMgc3VidXJiLCByZWdpb24gZXRjLiBJIGhhdmUgcmVzdHJpY3RlZCBteSBhbmFseXNpcyB0byB0aHJlZSBiZWRyb29tIGxhbmRlZCBob3VzZXMgc29sZCBpbiAyMDE3IGFuZCB3aXRoaW4gMTAwa20gZnJvbSBDQkQuIEFsc28gdGhlIHJvd3Mgd2hlcmUgcHJpY2VzIGFyZSBub3QgYXZhaWxhYmxlIGhhdmUgYmVlbiByZW1vdmVkIGFzIHRoZSBob3VzaW5nIHByaWNlcyBhcmUgc2tld2VkIGFuZCBpbXB1dGluZyB0aGVtIHdpdGggbWVhbiBvciBtZWRpYW4gbWlnaHQgaW5mbHVlbmNlIHRoZSB3aG9sZSByZXN1bHQuIFJlZ2lvbiBuYW1lcyBoYXZlIGJlZW4gZmFjdG9yaXNlZCBhbmQgb3RoZXIgbmVjZXNzYXJ5IGRhdGEgdHJhbnNmb3JtYXRpb24gbGlrZSBjaGFuZ2luZyB0aGUgY2xhc3Mgb2YgRGF0ZSB2YXJpYWJsZSBoYXMgYmVlbiBkb25lLiBQb3N0IHRoaXMgdGhlIG1lZGlhbiBwcmljZSBhbmQgZGlzdGFuY2UgaGF2ZSBiZWVuIGNhbGN1bGF0ZWQuIAoqIFRoZSBjcmltZSBzdGF0aXN0aWNzIGRhdGEgaGFzIGJlZW4gaW1wb3J0ZWQgIGFuZCBpdHMgdmFyaWFibGUgbmFtZXMgaGF2ZSBiZWVuIHVwZGF0ZWQuVGhpcyB3YXMgZm9sbG93ZWQgYnkgY29udmVydGluZyB2YXJpYWJsZXMgaW50byBzdWl0YWJsZSBkYXRhIHR5cGVzIGFuZCBsYWJlbGxpbmcgdGhlIGZhY3RvcnMuIFRoZSBkYXRhIGZvciB5ZWFyIDIwMTcgaGFzIGJlZW4gZmlsdGVyZWQgYW5kIGNoZWNrZWQgZm9yIHBvc3NpYmxlIG1pc3NpbmcgdmFsdWVzLiAKKiBQb3N0IHNhbml0YXRpb24sIHRoZSBjcmltZSBzdGF0aXN0aWNzIGRhdGEgaGFzIGJlZW4gam9pbmVkIHRvIHRoZSBob3VzaW5nIGRhdGEsIHVzaW5nIHN1YnVyYiBhcyB0aGUgZ3JvdXBpbmcgdmFyaWFibGUuIE1pc3NpbmcgdmFsdWVzIHdlcmUgaWRlbnRpZmllZCBhbmQgaGFuZGxlZC5PYnZpb3VzIGVycm9yIGFuZCBpbmNvbnNpc3RlbmN5IHdhcyBjaGVja2VkLiAKKiBBcyB0aGUgbmV4dCBsb2dpY2FsIHN0ZXAsIHdlIGhhdmUgdXNlZCBhIGJveHBsb3QgdG8gbG9vayBpbnRvIHRoZSBvdXRsaWVycyBmb3IgUHJpY2UgYW5kIENyaW1lLiBJbiB0aGlzIGNhc2UgdGhlIHN1YnVyYnMgd2hvc2UgcHJvcGVydHkgcHJpY2Ugb3IgY3JpbWUgcmF0ZSBhcmUgc2lnbmlmaWNhbnRseSBoaWdoZXIgdGhhbiB0aGF0IG9mIG90aGVyIHN1YnVyYnMgaW4gdGhlIHNhbWUgcmVnaW9uLiAgCkkgaGF2ZSBub3QgZWxpbWluYXRlZCB0aGUgb3V0bGllcnMgYXMgdGhleSBhcmUgbm90IGZhbHNlIGFsYXJtcyBidXQgYSByZWFsIGRlcGljdGlvbiBvZiB0aGUgaGlnaCBwcm9wZXJ0eSBwcmljZSBvciBjcmltZSBzdGF0cyBvZiBhIHBhcnRpY3VsYXIgc3VidXJiLiAKKiBHb2luZyBmdXJ0aGVyLCBJIGhhdmUgYXBwbGllZCBtYXRoZW1hdGljYWwgZnVuY3Rpb25zIHRvIHRyYW5zZm9ybSB0aGUgbWVkaWFuIHByaWNlIGFuZCBkaXN0YW5jZSwgdG8gYWNoaWV2ZSBub3JtYWxpdHkgLCBwb3N0IHdoaWNoIHdlIGhhdmUgdXNlZCB0aGUgbWxyIHBhY2thZ2UgdG8gY29tZSB3aXRoIGEgbW9kZWwgdG8gcHJlZGljdCB0aGUgbWVkaWFuIHByaWNlIG9mIGEgcHJvcGVydHkgdXNpbmcgb3RoZXIgdmFyaWFibGVzLiBXZSBoYXZlIHVzZWQgdGhlIGdlbmVyYWxpc2VkIGxpbmVhciBtb2RlbCBhbmQgYWNoaWV2ZWQgYSBwZXJmb3JtYW5jZSBzdGF0aXN0aWNzIG9yIG1lYW4gYWJzb2x1dGUgZXJyb3IgYmVsb3cgMC4xLiAKKiBUaGlzIGRhdGFzZXQgY2FuIGJlIHVzZWQgaW4gZnV0dXJlIGZvciBmdXJ0aGVyIHN0YXRpc3RpY2FsIGFuYWx5c2lzLiAKCiMjIERhdGEgY29sbGVjdGlvbiAKCk1lbGJvdXJuZSBob3VzaW5nIGRhdGEgaXMgdGFrZW4gZnJvbSB0aGUga2FnZ2xlIGRhdGEgc2V0IGh5cGVybGluayxbTWVsYm91cm5lIEhvdXNpbmcgTWFya2V0XShodHRwczovL3d3dy5rYWdnbGUuY29tL2FudGhvbnlwaW5vL21lbGJvdXJuZS1ob3VzaW5nLW1hcmtldC9ob21lKSBhbmQgTWVsYm91cm5lIENyaW1lIFN0YXRpc3RpY3MgaGFzIGJlZW4gc291cmNlZCBmcm9tIGh5cGVybGluayxbTWVsYm91cm5lIENyaW1lIFN0YXRpc3RpY3NdKGh0dHBzOi8vd3d3LmNyaW1lc3RhdGlzdGljcy52aWMuZ292LmF1KSAgIAoKIyMjIyMgRGF0YV9EaWN0aW9uYXJ5IDoKVGhlIGZvbGxvd2lnIHZhcmlhYmxlcyBhcmUgcmVxdWlyZWQ6CgojIyMjIyMgTWVsYm91cm5lIEhvdXNpbmcgRGF0YToKKiBTdWJ1cmI6IFN1YnVyYnMgCiogUm9vbXM6IE51bWJlciBvZiByb29tcwoqIFByaWNlOiBQcmljZSBpbiBBdXN0cmFsaWFuIGRvbGxhcnMKKiBUeXBlOiBiciAtIGJlZHJvb20ocyk7IGggLSBob3VzZSxjb3R0YWdlLHZpbGxhLCBzZW1pLHRlcnJhY2U7IHUgLSB1bml0LCBkdXBsZXg7IHQgLSB0b3duaG91c2U7IGRldiBzaXRlIC0gZGV2ZWxvcG1lbnQgc2l0ZTsgbyByZXMgLSBvdGhlciByZXNpZGVudGlhbC4KKiBEYXRlOiBEYXRlIHNvbGQKKiBEaXN0YW5jZTogRGlzdGFuY2UgZnJvbSBDQkQgaW4gS2lsb21ldHJlcwoqIFJlZ2lvbm5hbWU6IEdlbmVyYWwgUmVnaW9uIChXZXN0LCBOb3J0aCBXZXN0LCBOb3J0aCwgTm9ydGggZWFzdCAuLi5ldGMpCgojIyMjIyMgQ3JpbWUgU3RhdGlzdGljcyBkYXRhOiAKKiBZZWFyIGVuZGluZyBKdW5lOiBZZWFyIG9mIGNyaW1lIAoqIFBvc3Rjb2RlOiBTZWxmIGV4cGxhbmF0b3J5CiogU3VidXJiL1Rvd24gTmFtZTogU3VidXJiCiogT2ZmZW5jZSBEaXZpc2lvbjogb2ZmZW5jZSBjYXRlZ29yeQoqIEluY2lkZW50cyBSZWNvcmRlZDpOdW1iZXIgb2YgaW5jaWRlbnRzIAoKCgpgYGB7cn0KCkNyaW1lX0luY19Qb3N0Q29kZSA8LSByZWFkX2V4Y2VsKCJEYXRhX3RhYmxlc19DcmltaW5hbF9JbmNpZGVudHNfVmlzdWFsaXNhdGlvbl95ZWFyX2VuZGluZ19KdW5lXzIwMTgueGxzeCIsIHNoZWV0ID0gIlRhYmxlIDA3IiApCmhlYWQoQ3JpbWVfSW5jX1Bvc3RDb2RlKQoKTWVsYiA8LSByZWFkX2NzdigiTUVMQk9VUk5FX0hPVVNFX1BSSUNFU19MRVNTLmNzdiIpICNSZWFkIHRoZSBIb3VzaW5nIGRhdGEgc2V0CmhlYWQoTWVsYikKCgpgYGAKCgojIyBTdHJ1Y3R1cmUgYW5kIG1hbmlwdWxhdGlvbnMgb2YgTWVsYm91cm5lIEhvdXNpbmcgZGF0YSBzZXQKCiogQ2hlY2sgZm9yIE5Bcy4gCk91dCBvZiA2MDY3MiByb3dzIHRoZXJlIGFyZSAxMyw4MzYgaXRlbXMgd2hlcmUgdGhlIFByaWNlIGlzIG1pc3NpbmcuCldlIHdpbGwgIGlnbm9yZSB0aG9zZSBjYXNlcyBhbmQgb25seSBsb29rIGF0IHRoZSByb3dzIHdoZXJlIHdlIGhhdmUgdGhlIHByaWNlIGxpc3RlZC4KKiBGb3IgdGhpcyBhc3NpZ25tZW50IHdlIGFyZSBvbmx5IGxvb2tpbmcgYXQgdGhlIHByaWNlIGluIDIwMTcgZm9yIHRoZSBsYW5kZWQgaG91c2VzICgnaCcpIHdpdGggMyBiZWRyb29tcyBhbmQgd2l0aGluIDEwMGttcyAoZnJvbSBNZWxib3VybmUgQ2VudHJhbCkuCiogQ2hlY2sgdGhlIGNsYXNzIG9mIHZhcmlhYmxlcy4gCiogRmFjdG9yaXNlIHRoZSByZWdpb24gbmFtZXMuICAKKiBDaGFuZ2UgdGhlIHR5cGUgb2YgZGF0ZSB2YXJpYWJsZSBmcm9tIG51bWVyaWMgdG8gZGF0ZS4gIAoqIFRyYW5zZm9ybSB0aGUgc3VidXJiIGludG8gdXBwZXIgY2FzZSB0byBtYXRjaCB3aXRoIHRoZSBvdGhlciBkYXRhIHNldCBhdCB0aW1lIG9mIGpvaW4uIAoKCmBgYHtyfQoKc3VtKGlzLm5hKE1lbGIkUHJpY2UpKSAjY2hlY2sgZm9yIE5BCgpNZWxiX2Ryb3BfbmEgPC0gZHJvcF9uYShNZWxiLFByaWNlKSAjaGFuZGxpbmcgTkEncwpNZWxiX2ZpbHRlcmVkX2RhdGFfMjAxNyA8LSBNZWxiX2Ryb3BfbmEgJT4lIGZpbHRlciggVHlwZSA9PSAnaCcgJiBSb29tcyA9PSAzICYgRGlzdGFuY2UgPDEwMCAmIERhdGUgPj0gJzIwMTctMDEtMDEnKSAjYXBwbHkgdGhlIGZpbHRlcmluZyBjcml0ZXJpYSBvbiB0aGUgZGF0YXNldAoKCnNhcHBseShNZWxiX2ZpbHRlcmVkX2RhdGFfMjAxNywgY2xhc3MpCgojZmFjdG9yaXNlIHRoZSBSZWdpb24gTmFtZXMgCk1lbGJfZmlsdGVyZWRfZGF0YV8yMDE3JFJlZ2lvbm5hbWUgPC0gYXMuZmFjdG9yKE1lbGJfZmlsdGVyZWRfZGF0YV8yMDE3JFJlZ2lvbm5hbWUpCmxldmVscyhNZWxiX2ZpbHRlcmVkX2RhdGFfMjAxNyRSZWdpb25uYW1lKQoKTWVsYl9maWx0ZXJlZF9kYXRhXzIwMTckRGF0ZTwtIGRteShNZWxiX2ZpbHRlcmVkX2RhdGFfMjAxNyREYXRlKSAjZGF0ZSB0cmFuc2Zvcm1hdGlvbiAKCiN0byBjaGVjayB0aGUgbW9udGggaW4gdGhlIGRhdGUgCk1lbGJfZmlsdGVyZWRfZGF0YV8yMDE3JERhdGUgJT4lIG1vbnRoKGxhYmVsID0gVFJVRSwgYWJiciA9IEZBTFNFKSAlPiUgaGVhZCgxMCkKCiN0cmFuc2Zvcm0gdGhlIFN1YnVyYiB2YXJpYWJsZSB0byB1cHBlciBjYXNlCk1lbGJfZmlsdGVyZWRfZGF0YV8yMDE3JFN1YnVyYiA8LSB0b3VwcGVyKE1lbGJfZmlsdGVyZWRfZGF0YV8yMDE3JFN1YnVyYiApIAoKYGBgCgojIyBTdHJ1Y3R1cmUgYW5kIG1hbmlwdWxhdGlvbnMgb2YgTWVsYm91cm5lIENyaW1lIGRhdGEgc2V0CgoKKiBSZW5hbWUgdGhlIGNvbHVtbiBuYW1lIHRvIGVhc2UgcmVhZGFiaWxpdHkuIAoqIENoZWNrIHRoZSBkYXRhdHlwZSBvZiB2YXJpYWJsZXMuCiogRmFjdG9yaXNlIHRoZSBPZmZlbmNlIHR5cGUgIGFuZCBTdWJ1cmJzLiAKKiBGaWx0ZXIgdGhlIDIwMTcgY3JpbWUgc3RhdGlzdGljcyBkYXRhIGZvciB0aGUgcHVycG9zZSBvZiB0aGlzIHN0dWR5LiAKKiBDaGVjayBmb3IgTkEncyBpbiB0aGUgZmluYWwgZGF0YXNldC4gCgpgYGB7cn0KCm5hbWVzKENyaW1lX0luY19Qb3N0Q29kZSkgI2NoZWNrIHRoZSBuYW1lcyBvZiAgZGF0YXNldAoKI3JlbmFtZSB0aGUgY29sdW1ucyB0byBtYWtlIGluY3JlYXNlIHJlYWRhYmxpdHkKQ3JpbWVfSW5jX1Bvc3RDb2RlIDwtIHJlbmFtZShDcmltZV9JbmNfUG9zdENvZGUsCiAgICAgICAgICAgICAgICAgICAgICAgWWVhciA9IGBZZWFyIGVuZGluZyBKdW5lYCwKICAgICAgICAgICAgICAgICAgICAgICBTdWJ1cmIgPSBgU3VidXJiL1Rvd24gTmFtZWAsCiAgICAgICAgICAgICAgICAgICAgICAgT2ZmZW5jZSA9IGBPZmZlbmNlIERpdmlzaW9uYCwKICAgICAgICAgICAgICAgICAgICAgICBOb19vZl9JbmNpZGVudCA9IGBJbmNpZGVudHMgUmVjb3JkZWRgKQpzYXBwbHkoQ3JpbWVfSW5jX1Bvc3RDb2RlLGNsYXNzKSAjY2hlY2sgZGF0YXR5cGVzIAoKI2ZhY3RvcmlzZSB0aGUgb2ZmZW5jZSB2YXJpYWJsZSAKQ3JpbWVfSW5jX1Bvc3RDb2RlJE9mZmVuY2UgPC0gZmFjdG9yKENyaW1lX0luY19Qb3N0Q29kZSRPZmZlbmNlLCBsZXZlbHMgPSBjKCJBIENyaW1lcyBhZ2FpbnN0IHRoZSBwZXJzb24iLCJCIFByb3BlcnR5IGFuZCBkZWNlcHRpb24gb2ZmZW5jZXMiLCJDIERydWcgb2ZmZW5jZXMiLCJEIFB1YmxpYyBvcmRlciBhbmQgc2VjdXJpdHkgb2ZmZW5jZXMiLCJFIEp1c3RpY2UgcHJvY2VkdXJlcyBvZmZlbmNlcyIsIkYgT3RoZXIgb2ZmZW5jZXMiKSwKICAgICAgIGxhYmVscyA9IGMoIkNyaW1lIGFnYWluc3QgcGVyc29uIiwiUHJvcGVydHkgb2ZmZW5jZXMiLCJEcnVnIG9mZmVuY2VzIiwiUHVibGljIG9yZGVyIGFuZCBzZWN1cml0eSIsIkp1c3RpY2UgUHJvY2VkdXJlcyIsIk90aGVycyIpKQoKCkNyaW1lX0luY19Qb3N0Q29kZSRTdWJ1cmIgPC0gYXMuZmFjdG9yKENyaW1lX0luY19Qb3N0Q29kZSRTdWJ1cmIpCgoKI2ZpbHRlciB0aGUgZGF0YSBmb3IgMjAxNyBjcmltZSBzdGF0aXN0aWNzIApDcmltZV9JbmNfUG9zdENvZGVfMjAxNyA8LSBDcmltZV9JbmNfUG9zdENvZGUgJT4lIGZpbHRlcihZZWFyICVpbiUgIjIwMTciKQoKc3VtKGlzLm5hKENyaW1lX0luY19Qb3N0Q29kZV8yMDE3KSkgI2NoZWNrIGZvciBOQSdzCgpgYGAKCgojIyBTdW1tYXJpc2UgdGhlIGRhdGEgYW5kIGNyZWF0ZSBuZXcgdmFyaWFibGVzLiAKCiogVXNlIG11dGF0ZSB0byBjcmVhdGUgdHdvIG5ldyB2YXJpYWJsZXMgbWVkaWFuX3ByaWNlIGFuZCBtZWRpYW5fZGlzdGFuY2UgZm9yIHRoZSBNZWxib3VybmUgaG91c2luZyBkYXRhIHNldC4KKiBHcm91cCBieSBTdWJ1cmJzIGFuZCB1c2Ugc3VtbWFyaXNlIHRvIGNyZWF0ZSBUb3RhbF9JbmNpZGVudHMgYnkgU3VidXJicy4gCgpgYGB7cn0KCiMgU3VtbWFyaXNlIHRoZSBkYXRhIGFuZCBjcmVhdGUgbmV3IGNvbHVtbnMgZnJvIG1lZGlhbiBwcmljZSBhbmQgZGlzdGFuY2UuIAoKTWVsYl93b3JraW5nX3NldF8yMDE3IDwtIE1lbGJfZmlsdGVyZWRfZGF0YV8yMDE3ICU+JSAgZ3JvdXBfYnkoUG9zdGNvZGUsU3VidXJiKSAlPiUgCiAgbXV0YXRlKG1lZGlhbl9wcmljZSA9IG1lZGlhbihQcmljZSksCiAgICAgICAgIG1lZGlhbl9kaXN0YW5jZSA9IG1lZGlhbihEaXN0YW5jZSkKICAgICAgICAgKSAlPiUgZGlzdGluY3QoUG9zdGNvZGUsbWVkaWFuX3ByaWNlLG1lZGlhbl9kaXN0YW5jZSxjb3VudCxSZWdpb25uYW1lKQoKTWVsYl93b3JraW5nX3NldF8yMDE3ICU+JSBoZWFkKDUpCgojU3VtbWFyaXNlIHRoZSBDcmltZSBEYXRhIHRvIGZpbmQgTm8gb2YgSW5jaWRlbnRzIHBlciBTdWJ1cmIKU3VidXJic19DcmltZV8yMDE3IDwtIENyaW1lX0luY19Qb3N0Q29kZV8yMDE3ICU+JSBncm91cF9ieShTdWJ1cmIpICU+JSBzdW1tYXJpc2UoCiAgVG90YWxfSW5jaWRlbnRzID0gc3VtKE5vX29mX0luY2lkZW50KQopCgpTdWJ1cmJzX0NyaW1lXzIwMTcgJT4lIGhlYWQoNSkKCmBgYAoKIyMgSm9pbiB0aGUgZGF0YSBzZXRzCgoqIEpvaW4gdGhlIE1lbGJvdXJuZSBob3VzaW5nIGRhdGEgd2l0aCB0aGUgY3JpbWUgc3RhdGlzdGljcyBkYXRhIHRvIG1ha2UgYSB1bmlmaWVkIGRhdGEgc2V0IHdpdGggU3VidXJiIG5hbWUsIHBvc3Rjb2RlLCByZWdpb25hIG5hbWUsIG1lZGlhbiBwcmljZSwgbWVkaWFuIGRpc3RhbmNlIGFuZCAgdG90YWwgbnVtYmVyIG9mIGNyaW1lIGluY2lkZW50cy4gIAoKYGBge3J9CgojSm9pbiB0aGUgRGF0YSBzZXRzCgojIE9uIHRoZSBNZWxib3VybmUgSG91c2luZyBEYXRhICwgSm9pbiB0aGUgTnVtYmVyIG9mIENyaW1pbmFsIEluY2lkZW50cyAsIHBlciBTdWJ1cmIKClJlYWR5X3RvX3dvcmtfZGF0YSA8LSBsZWZ0X2pvaW4oTWVsYl93b3JraW5nX3NldF8yMDE3LCBTdWJ1cmJzX0NyaW1lXzIwMTcsIGJ5PSJTdWJ1cmIiKSAKClJlYWR5X3RvX3dvcmtfZGF0YSAlPiUgaGVhZCg1KQpgYGAKCgojIwlTY2FubmluZyBmaW5hbCBkYXRhIHNldCBmb3IgaW5jb25zaXN0ZW5jeSAgCgoqIENoZWNrIGZvciBOQSdzIGluIHRoZSBmaW5hbCBkYXRhIHNldC4gCiogRWxpbWluYXRlIHRoZSBTdWJ1cmIgd2hlcmUgd2UgZG8gbm90IGhhdmUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIG51bWJlciBvZiBpbmNpZGVudHMgY29tbWl0dGVkLiAKKiBDcmVhdGUgcnVsZSB0byBjaGVjayBmb3Igb2J2aW91cyBlcnJvciBvciBpbmNvbnNpc3RlbmN5LgoKYGBge3J9CgojSW52ZXN0aWdhdGdlIGlmIHRoZXJlIGlzIGFueSBOQSdzIGluIHRoaXMgZGF0YSBzZXQgYXMgcmVzdWx0IG9mIEpvaW4Kc3VtKGlzLm5hKFJlYWR5X3RvX3dvcmtfZGF0YSkpCgpSZWFkeV90b193b3JrX2RhdGFbIWNvbXBsZXRlLmNhc2VzKFJlYWR5X3RvX3dvcmtfZGF0YSksXSAjaW5zcGVjdCBOQSByb3dzCgojRWxpbWluYXRlIHRoaXMgc3VidXJiIGFzIHdlIGRvbnQgaGF2ZSBpbmZvIGFib3V0IHRoZSB0b3RhbCBudW1iZXIgb2YgSW5jaWRlbnRzClJlYWR5X3RvX3dvcmtfZGF0YSA8LSBSZWFkeV90b193b3JrX2RhdGFbY29tcGxldGUuY2FzZXMoUmVhZHlfdG9fd29ya19kYXRhKSxdCgoKI2NyZWF0ZSBhIHJ1bGUgdG8gY2hlY2sgaWYgdGhlIHZhbHVlcyBhcmUgbm9uIG5lZ2F0aXZlClJ1bGUgPC0gZWRpdHNldChjKCJtZWRpYW5fcHJpY2UgPj0gMCIsICJtZWRpYW5fZGlzdGFuY2UgPj0gMCIsIlRvdGFsX0luY2lkZW50cz49MCIpKQpSdWxlCiNhcHBseSBydWxlIG9uIHRoZSBGaW5hbCBkYXRhIHNldCAKcnVsZXNfdmlvbGF0ZWQgPC0gdmlvbGF0ZWRFZGl0cyhSdWxlLFJlYWR5X3RvX3dvcmtfZGF0YSkKCnN1bW1hcnkocnVsZXNfdmlvbGF0ZWQpICN2aXN1YWxpc2UgaWYgYW55IHJ1bGVzIGlzIHZpb2xhdGVkCgpSZWFkeV90b193b3JrX2RhdGEgJT4lIGhlYWQoNSkKCmBgYAoKIyMgSWRlbnRpZnkgdGhlIHN1YnVyYiB3aXRoIGhpZ2hlciBwcmljZSBtZWRpYW4gKG91dGxpZXJzKQoKKiBHcm91cCB0aGUgZGF0YSBieSBzdWJ1cmJzIGFuZCBwbG90IHRoZSBtZWRpYW5fcHJpY2UgYWdhaW5zdCB0aGUgcmVnaW9uLgoqIEZpbmQgdGhlIFN1YnVyYiB3aXRoIHRoZSBoaWdoZXN0IHByb3BlcnR5IHByaWNlLiAKKiBXZSBjYW4gc2VlIHRoYXQgU291dGggTWV0cm9wb2xpdGFuIFJlZ2lvbiBhcHBlYXJzIHRvIGJlIHRoZSBjb3N0bGllc3QgcmVnaW9uIHdpdGggbWVkaWFuIHByb3BlcnR5IHByaWNlIGFyb3VuZCAxLjUgbWlsbGlvbnMgYW5kIFRvb3JhayBiZWluZyB0aGUgU3VidXJiIHdpdGggaGlnaGVzdCBwcmljZSB3aXRoIG92ZXIgMyBtaWxsaW9uIEF1ICQuIAoKCmBgYHtyIGZpZy5oZWlnaHQgPSAwOCwgZmlnLndpZHRoID0gNX0Kb3V0bGllcnNfcHJpY2UgPSBib3hwbG90KFJlYWR5X3RvX3dvcmtfZGF0YSRtZWRpYW5fcHJpY2UgfiBSZWFkeV90b193b3JrX2RhdGEkUmVnaW9ubmFtZSxwbG90PUZBTFNFKSRvdXQKCiNNYWtlIGEgbmV3IGNvbHVtbiBmb3IgbGFiZWxsaW5nIHRoZSBvdXRsaWVycyA6IFN1YnVyYi9SZWdpb24gd2l0aCBoaWdoZXN0IG51bWJlciBvZiBjcmltZSBpbmNpZGVudHMKUmVhZHlfdG9fd29ya19kYXRhJGxhYmVsX3ByaWNlIDwtIGlmZWxzZSgoUmVhZHlfdG9fd29ya19kYXRhJG1lZGlhbl9wcmljZSAlaW4lIG91dGxpZXJzX3ByaWNlICYgUmVhZHlfdG9fd29ya19kYXRhJG1lZGlhbl9wcmljZT4zMDAwMDAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUoUmVhZHlfdG9fd29ya19kYXRhJFN1YnVyYiwiXG4iLApSZWFkeV90b193b3JrX2RhdGEkbWVkaWFuX3ByaWNlKSwiIikKCgpnZ3Bsb3QoYWVzKHk9bWVkaWFuX3ByaWNlLHg9UmVnaW9ubmFtZSxmaWxsPVJlZ2lvbm5hbWUpLGRhdGEgPSBSZWFkeV90b193b3JrX2RhdGEpK2dlb21fYm94cGxvdCgpKyBnZW9tX3RleHQoYWVzKGxhYmVsPWxhYmVsX3ByaWNlKSkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpK3NjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIkUuTWV0cm8iLCJFLlZpYyIsIk4uTWV0cm8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOLlZpYyIsIlMtRS5NZXRybyIsIlMuTWV0cm8iLCJXLk1ldHJvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVy5WaWMiKSkgKyAgCiAgZ2d0aXRsZSgiTWVsYm91cm5lIFByb3BlcnR5IFByaWNlICBieSBSZWdpb24iKSArIAogIHhsYWIoIlJlZ2lvbiBOYW1lcyIpICsgeWxhYigiTWVkaWFuX1ByaWNlIikgKwogIHRoZW1lKAogICAgCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJCbGFjayIsc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSApCiAgKQoKCmBgYAoKCiMjCUlkZW50aWZ5IHRoZSBzdWJ1cmIgd2l0aCBoaWdoZXIgY3JpbWUgaW5jaWRlbnRzIChvdXRsaWVycykKCiogR3JvdXAgdGhlIHN1YnVyYnMgYnkgcmVnaW9ucyBhbmQgcGxvdCB0aGUgY3JpbWUgaW5jaWRlbnQgZm9yIGVhY2ggcmVnaW9uLiAKKiBUaGUgb3V0bGllciByZXByZXNlbnRzIHRob3NlICJTdWJ1cmJzIiB3aGVyZSB0aGUgb2JzZXJ2ZWQgbnVtYmVyIG9mIGNyaW1lIGluY2lkZW50cyBkZXBhcnRzIHNpZ25pZmljYW50bHkgZnJvbSB0aGUgbnVtYmVyIG9mIGluY2lkZW50cyBpbiBvdGhlciBzdWJ1cmJzIG9uIHRoZSBzYW1lIHJlZ2lvbi4gSW4gb3RoZXIgd29yZHMgaXQgZGVwaWN0cyB0aGUgU3VidXJicyB3aXRoIGhpZ2hlciBjcmltZSByYXRlIGluIHRoYXQgcmVnaW9uLiAKKiBNZWxib3VybmUgc3VidXJiIHdpdGggMTY4MjYgbnVtYmVyIG9mIGluY2lkZW50cyBpbiBtYXJrZWQgdG8gc2hvdyB0aGUgU3VidXJiIHdoaWNoIGhhcyB0aGUgaGlnaGVzdCBudW1iZXIgb2YgY3JpbWUgaW5jaWRlbnRzIHJlY29yZGVkIGFjcm9zcyBhbGwgcmVnaW9ucy4gCgoKYGBge3IgZmlnLmhlaWdodCA9IDA4LCBmaWcud2lkdGggPSA1fQoKb3V0bGllcnNfY3JpbWUgPSBib3hwbG90KFJlYWR5X3RvX3dvcmtfZGF0YSRUb3RhbF9JbmNpZGVudHMgfiBSZWFkeV90b193b3JrX2RhdGEkUmVnaW9ubmFtZSxwbG90PUZBTFNFKSRvdXQKCiNNYWtlIGEgbmV3IGNvbHVtbiBmb3IgbGFiZWxsaW5nIHRoZSBvdXRsaWVycyA6IFN1YnVyYi9SZWdpb24gd2l0aCBoaWdoZXN0IG51bWJlciBvZiBjcmltZSBpbmNpZGVudHMuIFVzZSBQYXN0ZSB0byBjb25jYXRlbmF0ZSBzdHJpbmdzLiAKUmVhZHlfdG9fd29ya19kYXRhJGxhYmVsX2NyaW1lIDwtIGlmZWxzZSgoUmVhZHlfdG9fd29ya19kYXRhJFRvdGFsX0luY2lkZW50cyAlaW4lIG91dGxpZXJzX2NyaW1lICYgUmVhZHlfdG9fd29ya19kYXRhJFRvdGFsX0luY2lkZW50cz4xNTAwMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKFJlYWR5X3RvX3dvcmtfZGF0YSRTdWJ1cmIsIlxuIiwKUmVhZHlfdG9fd29ya19kYXRhJFRvdGFsX0luY2lkZW50cyksIiIpCgoKI01ha2UgYSBib3hwbG90IApnZ3Bsb3QoYWVzKHk9VG90YWxfSW5jaWRlbnRzLHg9UmVnaW9ubmFtZSxmaWxsPVJlZ2lvbm5hbWUpLGRhdGEgPSBSZWFkeV90b193b3JrX2RhdGEpK2dlb21fYm94cGxvdCgpKwogICN0aGVtZV9ncmV5KGJhc2Vfc2l6ZSA9IDEwKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPWMoIkUuTWV0cm8iLCJFLlZpYyIsIk4uTWV0cm8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOLlZpYyIsIlMtRS5NZXRybyIsIlMuTWV0cm8iLCJXLk1ldHJvIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXLlZpYyIpKSArIGdlb21fdGV4dChhZXMobGFiZWw9bGFiZWxfY3JpbWUpKSsKICBnZ3RpdGxlKCJNZWxib3VybmUgQ3JpbWUgSW5jaWRlbnRzIGJ5IFJlZ2lvbiIpICsgCiAgeGxhYigiUmVnaW9uIE5hbWVzIikgKyB5bGFiKCJObyBvZiBDcmltZSBJbmNpZGVudHMiKSArCiAgdGhlbWUoCiAgICAKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIkJsYWNrIixzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41ICkKICApCgoKCmBgYAoKCiMjCUV4Y2x1ZGluZyBvdXRsaWVyCgoqIE9uY2Ugd2Ugc2VlIHRoYXQgdGhlIHN1YnVyYiBNZWxib3VybmUgaGFzIHRoZSBtYXhpbXVtIG51bWJlciBvZiBDcmltZSBJbmNpZGVudHMgaW4gMjAxNywgbGV0cyBleGNsdWRlIGl0IGFuZCB2aWV3IHRoZSBib3hwbG90IGFnYWluLk5vdyB3ZSBjYW4gY2xlYXJseSBzZWUgdGhlIG1lZGlhbiBpLmUgbnVtYmVyIG9mIGNyaW1lcyBpbiBhIHJlZ2lvbiBpcyBoaWdoZXN0IGZvciBXZXN0ZXJuIFZpY3RvcmlhLiggdGhpcyBpcyBkb25lIG9ubHkgZm9yIHZpc3VhbGlzYXRpb24pCiogU3RpbGwgdGhlcmUgYXJlIG1hbnkgb3V0bGllcnMgaW4gdGhlIGRhdGEsIGJ1dCBhcyBwZXIgdGhpcyBzdHVkeSwgdGhleSByZXByZXNlbnQgdGhlIHN1YnVyYnMgd2l0aCBoaWdoZXIgY3JpbWVzIGNvbXBhcmVkIHRvIHRoYXQgcmVnaW9uIGFuZCBzaG91bGQgbm90IGJlIGV4Y2x1ZGVkIGF0IGFueSBwb2ludC4gCgoKYGBge3IgZmlnLmhlaWdodCA9IDA2LCBmaWcud2lkdGggPSA1fQoKRGF0YV93aXRob3V0X01lbGJfU3VidXJiIDwtIFJlYWR5X3RvX3dvcmtfZGF0YSAlPiUgZmlsdGVyKCFTdWJ1cmIgJWluJSAiTUVMQk9VUk5FIikKCmdncGxvdChhZXMoeT1Ub3RhbF9JbmNpZGVudHMseD1SZWdpb25uYW1lLGZpbGw9UmVnaW9ubmFtZSksZGF0YSA9IERhdGFfd2l0aG91dF9NZWxiX1N1YnVyYikrZ2VvbV9ib3hwbG90KCkrCiAgIyB0aGVtZV9ncmV5KGJhc2Vfc2l6ZSA9IDEwKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikrCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9YygiRS5NZXRybyIsIkUuVmljIiwiTi5NZXRybyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk4uVmljIiwiUy1FLk1ldHJvIiwiUy5NZXRybyIsIlcuTWV0cm8iLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlcuVmljIikpICsKICBnZ3RpdGxlKCJNZWxib3VybmUgQ3JpbWUgSW5jaWRlbnRzIGJ5IFJlZ2lvbiIpICsgCiAgeGxhYigiUmVnaW9uIE5hbWVzIikgKyB5bGFiKCJObyBvZiBDcmltZSBJbmNpZGVudHMiKSArCiAgdGhlbWUoCiAgICAKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gIkJsYWNrIixzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41ICkKICApCmBgYAoKIyMJTXVsdGl2YXJpYXRlIG91dGxpZXIgZGV0ZWN0aW9uOgoKKiBFeHBsb3JlIHRoZSByZWxhdGlvbiBiZXR3ZWVuIHByb3BlcnR5IHByaWNlIGFuZCBjcmltZSBpbmNpZGVudHMuIAoqIFVzZSBhIHNjYXR0ZXIgcGxvdCBmb3IgbnVtYmVyIG9mIENyaW1lIEluY2lkZW50cyBhZ2FpbnN0IHByb3BlcnR5IHByaWNlLgoqIFRoZXJlIGFyZSBmZXcgb3V0bGllcnMgaW4gdGhpcyBwbG90IHdoaWNoIHN1Z2dlc3QgdGhlIHN1YnVyYnMgd2l0aCBhbiB1bnVzdWFsbHkgaGlnaCBwcm9wZXJ0eSBwcmljZSBhbmQgY3JpbWUgcmF0ZSBjb21wYXJlZCB0byBvdGhlciBzdWJ1cmJzLiAKKiBUaGVzZSBvdXRsaWVycyBzaG91bGRudCBiZSByZW1vdmVkIG9yIGltcHV0ZWQgYXMgdGhleSByZXByZXNlbnQgaW1wb3J0YW50IGZhY3RzLiAgCgoKYGBge3IgZmlnLmhlaWdodCA9IDA2LCBmaWcud2lkdGggPSAxMX0KCiAgIHFwbG90KGRhdGE9UmVhZHlfdG9fd29ya19kYXRhLCB4PW1lZGlhbl9wcmljZSwgeT1Ub3RhbF9JbmNpZGVudHMpICtnZW9tX3RleHQoYWVzKGxhYmVsPWlmZWxzZSgoVG90YWxfSW5jaWRlbnRzPjUqSVFSKFRvdGFsX0luY2lkZW50cyl8bWVkaWFuX3ByaWNlPjQqSVFSKG1lZGlhbl9wcmljZSkpLHBhc3RlKFN1YnVyYiwiXG4iKSwiIikpLCBoanVzdD0xLjEpICsgCiAgZ2d0aXRsZSgiTWVsYm91cm5lOiAgTnVtYmVyIG9mIGNyaW1lIGluY2lkZW50cyBhZ2FpbnN0IHByb3BlcnR5IHByaWNlcyIpICsgCiAgeWxhYigiTm8gb2YgQ3JpbWUgSW5jaWRlbnRzIikgKyB4bGFiKCJtZWRpYW4gcHJvcGVydHkgcHJpY2UiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJCbGFjayIsc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSApCiAgKSAjIDUqSVFSIC8gNCpJUVIgLSByYW5kb20gdmFsdWVzIGp1c3QgZm9yIGxhYmVsbGluZyBtb3N0IGV4dHJlbWUgcG9pbnRzLiAKYGBgCgoqIExvb2tpbmcgYXQgdGhlIHBsb3QgYWJvdmUgVG9vcmFrIGRvZXNuJ3QgYXBwZWFyIHRvIGJlIHRoZSBzdWJ1cmIgd2l0aCBiZXN0IHZhbHVlIGZvciBtb25leSBhcyB0aGVyZSBhcmUgb3RoZXIgc3VidXJicyB3aGljaCBhcmUgY2hlYXBlciBhbmQgd2l0aCBsb3dlciBjcmltZSByYXRlLCBob3dldmVyIHRoZXJlIG1pZ2h0IGJlIG90aGVyIGZhY3RvcnMgaW52b2x2ZWQgd2hpY2ggaXMgYmV5b25kIHRoZSBzY29wZSBvZiB0aGlzIHJlcG9ydC4gCgojIyBEYXRhIFRyYW5zZm9ybWF0aW9uIGZvciBmdXJ0aGVyIHByb2Nlc3NpbmcKCkZ1cnRoZXIgSSB3YW50ZWQgIHRvIGV4cGxvcmUgaWYgdGhlcmUgaXMgYW55IGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHByaWNlIGFuZCBkaXN0YW5jZSAoZnJvbSB0aGUgY2VudHJhbCkuCgoxLiBDcmVhdGUgYSBuZXcgY29weSBvZiB0aGUgZGF0YSBzZXQgd2l0aCBvbmx5IG1lZGlhbl9kaXN0YW5jZSBhbmQgbWVkaWFuX3ByaWNlLgoyLiBDaGVjayBmb3IgdGhlIGRpc3RyYnV0aW9uIG9mIHRoZSBkYXRhLiAKMy4gQXBwbHkgc3VpdGFibGUgbWF0aGVtYXRpY2FsIG9wZXJhdGlvbnMgdG8gdHJhbnNmb3JtIHRoZSBkYXRhIGFzIGNsb3NlIHRvIG5vcm1hbCBhcyBwb3NzaWJsZS4gSW4gdGhpcyBjYXNlIHNxcnQgYW5kIGxvZ2FyaXRobWljIGZ1Y3Rpb25zIGdhdmUgdGhlIGRpc3RyaWJ1aW9ucyBjbG9zZXIgdG8gbm9ybWFsaXR5LiAKNC4gVHJhbnNmb3JtIHRoZSBkYXRhIGZyYW1lIGNvcHkgYWNjb3JkaW5nbHkuICAKCmBgYHtyfQoKI2NyZWF0ZSBhIG5ldyBjb3B5IG9mIGRhdGEgZm9yIHRoaXMgdGFzayAKCk1MX2RhdGFzZXQgPC0gTWVsYl9maWx0ZXJlZF9kYXRhXzIwMTcgJT4lIGdyb3VwX2J5KFN1YnVyYikgJT4lIHN1bW1hcmlzZSggbWVkaWFuX2Rpc3RhbmNlID1tZWRpYW4oRGlzdGFuY2UpLAptZWRpYW5fcHJpY2U9IG1lZGlhbihQcmljZSkpICU+JSBzZWxlY3QobWVkaWFuX2Rpc3RhbmNlLG1lZGlhbl9wcmljZSkKCk1MX2RhdGFzZXQgPC0gYXMuZGF0YS5mcmFtZShNTF9kYXRhc2V0KSAjQ292ZXJ0IHRoZSB0aWJibGUgaW50byBhIGRmCgpoaXN0KE1MX2RhdGFzZXQkbWVkaWFuX2Rpc3RhbmNlKSAjcmlnaHQgc2tld2VkCmhpc3QoTUxfZGF0YXNldCRtZWRpYW5fcHJpY2UpICNyaWdodCBza2V3ZWQKCiNhcHBseSB0cmFuc2Zvcm1hdGlvbiB0byBhY2hpZXZlIG5vcm1hbGl0eQpoaXN0KHNxcnQoTUxfZGF0YXNldCRtZWRpYW5fZGlzdGFuY2UpKQpoaXN0KGxvZzEwKE1MX2RhdGFzZXQkbWVkaWFuX3ByaWNlKSkKCiMgdHJhbnNmb3JtIHRoZSBkYXRhIGZyYW1lIGFjY29yZGluZ2x5IAoKZm9yIChpIGluIGxlbmd0aChNTF9kYXRhc2V0KSkgewogIAogIE1MX2RhdGFzZXQkbWVkaWFuX2Rpc3RhbmNlIDwtIHNxcnQoTUxfZGF0YXNldCRtZWRpYW5fZGlzdGFuY2UpCiAgTUxfZGF0YXNldCRtZWRpYW5fcHJpY2UgPC0gbG9nMTAoTUxfZGF0YXNldCRtZWRpYW5fcHJpY2UpCiAgCn0KCmBgYAoKIyMgTWFjaGluZSBMZWFybmluZyBtb2RlbCB0byBwcmVkaWN0IHRoZSBwcmljZSB1c2luZyBkaXN0YW5jZQoKIyMjIyMgU3RlcHM6IAoKCiogU3RlcCAxOiBEZWZpbmUgdGhlIHRhc2sgYXMgcmVncmVzc2lvbiBhbmFseXNpcyB3aXRoIFByaWNlIGFzIHRhcmdldCB2YXJpYWJsZS4KKiBTdGVwIDI6IFdlIHdpbGwgdXNlIHRoZSBjbGFzc2ljIHJlZ3Jlc3Npb24gYXMgb3VyIGFsZ29yaXRobSAKKiBTdGVwIDM6IEZpdHRpbmcgdGhlIG1vZGVsCiAgICAgKyBEaXZpZGUgdGhlIGRhdGEgaW50byB0cmFpbiBhbmQgdGVzdCBzZXQuCiAgICAgKyBUcmFpbiB0aGUgbGVhcm5lciBvbiB0aGUgdHJhaW5pbmcgc2V0LiAKKiBTdGVwIDQgOiBNYWtlIHByaWNpbmcgcHJlZGljdGlvbnMgdXNpbmcgdGhlIHRyYWluZWQgbW9kZWwgdG8gcHJlZGljdCB0aGUgcHJpY2UgaW4gdGhlIHRlc3Qgc2V0LiAKKiBTdGVwIDU6IEV2YWx1YXRpbmcgdGhlIGxlYXJuZXI6IApXZSBjYWxjdWxhdGUgdGhlIG1lYW4gc3F1YXJlIGVycm9yIGFuZCBtZWFuIGFic29sdXRlIGVycm9yIHRvIHNlZSB0aGUgcGVyZm9ybWFuY2UgbWV0cmljIG9mIG91ciBsZWFybmVyLgoKYGBge3J9CgojIFRhc2sKTUxfZGF0YXNldF90YXNrIDwtIG1ha2VSZWdyVGFzayhkYXRhID0gTUxfZGF0YXNldCx0YXJnZXQgPSAibWVkaWFuX3ByaWNlIikKCiNMZWFybmVyIGFsZ29yaXRobSAtIGNsYXNzaWMgcmVncmVzc2lvbiAKbHJuciA9IG1ha2VMZWFybmVyKCJyZWdyLmdsbSIpCgojZGVmaW5pbmUgdGhlIHRyYWluIGFuZCB0ZXN0IHNldHMKbj1ucm93KE1MX2RhdGFzZXQpCnRyYWluaW5nX3NldCA9IHNhbXBsZShuLCBzaXplID0gMi8zKm4pCnRlc3Rpbmdfc2V0ID0gc2V0ZGlmZigxOm4sIHRyYWluaW5nX3NldCkKCiMgbWFrZSBhIG1vZGVsIG9mIHRoZSBkYXRhIGFuZCB0cmFpbiB0aGUgbGVhcm5lciBvbiB0aGUgdGFzayB1c2luZyB0aGUgdHJhaW5pbmcgc2V0CnByaWNpbmdfbW9kZWwgPSBtbHI6OnRyYWluKGxlYXJuZXIgPSBscm5yLCB0YXNrID0gTUxfZGF0YXNldF90YXNrLCBzdWJzZXQgPSB0cmFpbmluZ19zZXQpCnByaWNpbmdfbW9kZWwKCiNwcmVkaWN0IHRoZSBwcmljZSAKCnByZWRfcHJpY2UgPSBwcmVkaWN0KHByaWNpbmdfbW9kZWwsIHRhc2sgPSBNTF9kYXRhc2V0X3Rhc2ssIHN1YnNldCA9IHRlc3Rpbmdfc2V0KQoKI2V2YWx1YXRlIHRoZSBsZWFybmVyIAoKcGVyZm9ybWFuY2UocHJlZF9wcmljZSxtZWFzdXJlcyA9IGxpc3QobXNlLG1hZSkpCgpgYGAKCioqRmluZGluZ3M6KioKCkFzIHRoZSBhYnNvbHV0ZSBlcnJvciBpcyBzbWFsbCwgdGhlIG1vZGVsIHBlcmZvcm1lZCB3ZWxsIGFnYWluc3QgdGhlIGdpdmVuIHNldCBvZiBkYXRhLiBUaGUgbW9kZWwgY2FuICBiZSBhcHBsaWVkIG9uIGFkZGl0aW9uYWwgZGF0YSBzZXRzIHRvIGV2YWx1YXRlIGl0cyBwZXJmb3JtYW5jZS4gRnVydGhlciBhbiBGIHRlc3QgY2FuIGJlIGRvbmUgZm9yIG92ZXJhbGwgbW9kZWwgc2lnbmlmaWNhbmNlLiAgCgoqKkZ1cnRoZXIgc3RlcHM6KioKClRoZSBkYXRhIGNhbiBiZSB1c2VkIHRvIGZpbmQgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBob3VzaW5nIHByaWNlcyBhbmQgZGlzdGFuY2UgKGZyb20gTWVsYm91cm5lIENlbnRyYWwpLiBBbHNvIGlmIHRoZSByZWxhdGlvbnNoaXAgY2hhbmdlcyB0cmF2ZWxsaW5nIHRoZSBzYW1lIGRpc3RhbmNlIGJ1dCBpbiBkaWZmZXJlbnQgbWV0cm9wb2xpdGFuIHJlZ2lvbnMuCkZ1cnRoZXIsIENyaW1lIHN0YXRpc3RpY3MgZm9yIHRoZSBzdWJ1cmIgY2FuIGJlIGxvb2tlZCB0byBleHBsb3JlIGEgY29ycmVsYXRpb24sIGlmIGFueSBiZXR3ZWVuIHRoZSBob3VzaW5nIHByaWNlIGFuZCBjcmltZSBpbiB0aGF0IHN1YnVyYi4gCgo8YnI+Cjxicj4=