In this project I will investigate the Crime Data from the City of Cambridge from 2009 to 2016
First, I’ll install the packages I might need for this analysis.
library(readr)
library(stringr)
library(ggplot2)
library(dplyr)
library(purrr)
library(tidyr)
library(magrittr)
getwd()
[1] "C:/Users/Ana/Desktop/Data Analytics"
Importing data:
setwd("C:/Users/Ana/Desktop/Data Analytics/CSV Files")
The working directory was changed to C:/Users/Ana/Desktop/Data Analytics/CSV Files inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
raw_data <- read_csv("crime_data_csv.csv")
Parsed with column specification:
cols(
`File Number` = [31mcol_character()[39m,
`Date of Report` = [31mcol_character()[39m,
`Crime Date Time` = [31mcol_character()[39m,
Crime = [31mcol_character()[39m,
`Reporting Area` = [32mcol_double()[39m,
Neighborhood = [31mcol_character()[39m,
Location = [31mcol_character()[39m
)
#column_names <- colnames(raw_data)
#print(column_names)
Here is the first 10 rows of the raw data:
head(raw_data, 10)
The data has 7 columns:
- File number - a reference number for the crime
- Date of report - when the report was made
- Crime Date Time - The date and time of the crime
- Reporting Area - Subset of Neighborhood
- Neighbourhood - Neighborhood within Cambridge
- Location - specific location where crime took place
Next, find out:
- How many rows of raw data are there?
- How many different categories of crimes are there?
- How many reporting areas are there?
- How many neighbourhoods are there?
count(raw_data[,1])
crime_types <- unique(raw_data$Crime)
no_of_reporting_areas <- unique(raw_data$`Reporting Area`)
neighborhoods <- unique(raw_data$Neighborhood)
print(as.data.frame(neighborhoods))
length(crime_types)
[1] 54
length(no_of_reporting_areas)
[1] 118
length(neighborhoods)
[1] 14
So there are 54 different types of crime, 118 different reporting areas, and 13 different neighborhoods (note, not 14 as one is an NA entry).
Here are some things I will investigate with this data:
- What are the most commonly occurring crimes in Cambridge?
- What neighbourhoods have the highest crime rate?
- Are the most common types of crime the same across all areas?
- Is there any seasonal variation with crime types?
- Is there any time variation with crime types? i.e. do certain crimes happen at certain times of the day?
- How have crimes changed over the years?
What is the best way to present all of this data?
- Bar chart (x = crime type, y = no. of occurrances)
- Bar chart (x = neighborhood, y = no. of crimes)
- Bar chart of the number of incidents of each crime and split the incidents into colours representing each neighborhood.
- Line graph (x = month, y = number of incidents of each type of crime. Plot different crime types in each colour)
- Line graph (x = time of day (in hours), y = number of incidents of each type of crime.)
- Line graph (x = year, y = totals of each crime (plot different crimes in different colours))
I’m not going to do any analysis on ‘date of report’ as this is just sometime around the date of crime so I shall remove this column from the data set.
Next I will clean the data and check for any missing values. The ‘Crime Date Time’ column needs to be rearranged. It would be good to split this column up. Sometimes a range of dates and times are inputted into this column. Here are the first 10 entries in the existing Crime Date Time column:
data_clean <- raw_data %>%
select(-'Date of Report')
date_time_v <- raw_data$`Crime Date Time`
head(date_time_v, 10)
[1] "01/01/2009 00:39" "01/01/2009 01:34"
[3] "01/01/2009 02:20 - 02:35" "01/01/2009 02:20 - 02:45"
[5] "01/01/2009 02:15 - 02:35" "01/01/2009 02:45"
[7] "01/01/2009 02:37" "01/01/2009 10:30 - 10:42"
[9] "01/01/2009 10:35 - 10:47" "12/31/2008 10:00 - 01/01/2009 10:00"
Here are the new columns: Date Start, Time Start, Date End, Time End.
col_names <- c("crime_st_date", "crime_st_time", "crime_end_date", "crime_end_time")
info_splitted <- as.data.frame(str_split(date_time_v, " ", simplify = TRUE))
info_splitted <- info_splitted %>%
select(-V3) %>%
mutate(V5 = if_else(V5 == "", V4, V5)) %>%
mutate(V4 = if_else(V5 == V4, "", V4))
colnames(info_splitted) <- col_names
print(head(info_splitted, 10))
NA
Now I want to add these columns back to the main dataframe. I can also now remove the original Crime Date Time column. Here’s the dataframe as it currently stands:
crime_data <- cbind(data_clean, info_splitted)
crime_data <- crime_data %>%
select(-`Crime Date Time`)
print(head(crime_data, 10))
Next I should check for any missing data.
logic_na <- as.logical(rowSums(is.na(crime_data)))
#print(head(logic_na, 10))
na_rows <- crime_data[logic_na,]
#na_rows
length(na_rows[,1])
[1] 85
There are 85 rows which contain NA values. Next I want to quickly see if there are certain columns which contain most of the NA values. To do this I can sum the number of NA values for each column. I can also plot a visual aid to show the number of NA values in each column.
no_nas <- as.data.frame(colSums(is.na(na_rows)))
colnames(no_nas) <- "No. of NA Values"
no_nas
The table shows that it is mostly data in the Location column that is missing. Here is a visual aid to illustrate this.
library(purrr)
df_na <- map_df(na_rows, function(x) as.numeric(is.na(x)))
df_na_heat <- df_na %>%
pivot_longer(cols = everything(),
names_to = "x") %>%
group_by(x) %>%
mutate(y = row_number())
plot_na_matrix <- function(df_na) {
# Preparing the dataframe for heatmaps
df_heat <- df_na %>%
pivot_longer(cols = everything(),
names_to = "x") %>%
group_by(x) %>%
mutate(y = row_number())
# Ensuring the order of columns is kept as it is
df_heat <- df_heat %>%
ungroup() %>%
mutate(x = factor(x,levels = colnames(df_na)))
# Plotting data
g <- ggplot(data = df_heat, aes(x=x, y=y, fill=value)) +
geom_tile() +
theme(legend.position = "none",
axis.title.y=element_blank(),
axis.text.y =element_blank(),
axis.ticks.y=element_blank(),
axis.title.x=element_blank(),
axis.text.x = element_text(angle = 90, hjust = 1))
# Returning the plot
g
}
plot_na_matrix(df_na)

As we could already see before, most of the missing values are in the Location column. There are also 2 missing values in the ‘Reporting Area’ and ‘Neighborhood’ columns but for both these instances there IS an entry in the Location column.
There isn’t any way of finding the exact location data from the rest of the data. There is probably a way of getting the Reporting Area and Neighborhood from the Location data however 2 out of 56000+ rows of data is not significant so the best thing to do is to probably remove the rows of data which don’t have the Reporting Area and Neighborhood. There’s also an entry for “admin error” under Crime so I am going to disregard these rows.
#length(crime_data[,1]) # See how many rows there were before
crime_data <- crime_data %>%
drop_na(`Reporting Area`) %>%
filter(Crime != "Admin Error")
#length(crime_data[,1]) # See how many rows there are after dropping the NA values from 'Reporting Area' and removing entries for "Admin Error" in the Crime column
Now I have cleaned the data and removed the rows containing NA values, I can start to analyse the data.
Q1: what is the overall crime profile of Cambridge?
crime_data_grouped <- crime_data %>%
group_by(Crime) %>%
summarise(no_of_incidents = n()) %>%
arrange(desc(no_of_incidents))
crime_data_grouped
ggplot(data = crime_data_grouped,
aes(x = Crime, y = no_of_incidents, fill = 'blue')) +
theme(axis.text.x = element_text(angle=60, hjust=1)) +
scale_x_discrete(limits=crime_data_grouped$Crime) +
geom_bar(stat='identity')+
labs(title = "No. of Incidents (all years) vs Crime Type", x = "Crime Type", y = "No. of Incidents") +
theme(panel.background = element_rect(fill = "white"))

Q2:Which Neighborhoods have the highest crime rate?
neighborhood_data_grouped <- crime_data %>%
group_by(Neighborhood) %>%
summarise(no_of_incidents = n()) %>%
arrange(desc(no_of_incidents))
neighborhood_data_grouped
ggplot(data = neighborhood_data_grouped,
aes(x = Neighborhood, y = no_of_incidents, fill = Neighborhood)) +
theme(axis.text.x = element_text(angle=60, hjust=1)) +
scale_x_discrete(limits=neighborhood_data_grouped$Neighborhood) +
geom_bar(stat='identity') +
labs(title = "Crime Rate vs Neighborhood", x = "Neighborhood", y = "No. of Incidents (all crimes)") +
theme(panel.background = element_rect(fill = "white"))

I should really find out the population of each of these neighborhoods as that would give a better idea of the crime rate.
Q3: Are the most common types of crime the same across all areas?
I will create a bar chart of the number of incidents of each crime and split the incidents into colours representing each neighborhood.
nc_data_grouped <- crime_data %>%
group_by(Neighborhood, Crime) %>%
summarise(no_of_incidents = n())
#nc_data_grouped
ggplot(data = nc_data_grouped,
aes(x = Crime, y = no_of_incidents, fill = Neighborhood)) +
theme(axis.text.x = element_text(angle=60, hjust=1)) +
geom_bar(stat='identity') +
labs(title = "No. of Crime incidents per Crime Type", x = "Crime Type", y = "No. of Incidents") +
theme(panel.background = element_rect(fill = "white"))

From this plot, it looks like most crimes occur across all the neighborhoods. i.e. there is no crime which is more one colour than another. There’s probably some more in depth analysis possible, but for now, we’ll just consider that the crime profiles are pretty similar across the different neighborhoods.
Q4: Is there any seasonal variation with Crime types?
For this, it would be good to plot a line graph with the months on the x-axis and the total number of crimes in each month on the y-axis. However, the crime_st_date data needs to be manipulated to extract the month. Use regex to extract the month in digits and add a column for ‘crime_month’
Here’s the dataframe again with the new column ‘crime_month’ added:
#head(crime_data, 20)
pattern = "\\b(.+)\\/.+\\/"
month <- str_match(crime_data$crime_st_date, pattern)[,2]
#head(month)
crime_data <- crime_data %>%
mutate(crime_month = month) %>%
mutate(crime_month = str_pad(crime_month, 2, side = "left", pad = "0"))
#print(unique(crime_data$crime_month)) # checking what months I get - it should be 01 - 12
head(crime_data,10)
Now I have a column with the months. I now want to plot the frequency of each type of crime for each month and then plot line graphs to see if there’s any seasonal variation.
#head(crime_data, 20)
total_seasonal_data <- crime_data %>%
group_by(crime_month) %>%
summarise(monthly_total = n()) %>%
mutate(crime_month = as.integer(crime_month)) #%>%
#mutate(crime_month = month.abb[crime_month])
ggplot(data = total_seasonal_data,
aes(x = crime_month, y = monthly_total, fill = "blue")) +
theme(axis.text.x = element_text(angle=60, hjust=1)) +
geom_bar(stat = 'identity') +
labs(title = "All Crime Rate Vs Month", x = "Month", y = "No. of Crimes") +
theme(panel.background = element_rect(fill = "white")) +
scale_x_discrete(limits = month.abb)

seasonal_data <- crime_data %>%
group_by(Crime, crime_month) %>%
summarise(monthly_totals = n()) %>%
mutate(crime_month = as.integer(crime_month))
ggplot(data = seasonal_data,
aes(x = crime_month, y = monthly_totals, color = Crime)) +
geom_line() +
labs(title = "Crime Rate Vs Month", x = "Month", y = "No. of Crimes") +
theme(panel.background = element_rect(fill = "white")) +
scale_x_discrete(limits=month.abb) +
theme(axis.text.x = element_text(angle=90, hjust=1))

NA
NA
NA
The bar graph showing all crimes over the course of the year shows clearly that the number of crimes increases across the summer months and decreases in the winter months, with a small increase in crimes in January.
It would be really interesting to see whether this overall trend is driven by specific crimes or whether all crimes follow this general trend.
However, when I plotted all the crimes separately on a line graph then there were too many lines to work out what was going on. I think it would be best to plot them all on separate graphs, but there’s a lot. I can tell that some of the crimes show significant variation in incidence across the year.
I think it would be good to plot only the graphs that are interesting i.e. there is some significant variation in incidence level accross the year. To do this, I will look at the variation of the data within each crime.
The next table shows the Crime and the corresponding standard deviation of the monthly incidents of each crime.
sd_seasonal_data <- crime_data %>%
group_by(Crime, crime_month) %>%
summarise(monthly_totals = n()) %>%
group_by(Crime) %>%
summarise(st_dev = sd(monthly_totals)) %>%
arrange(desc(st_dev))
head(sd_seasonal_data, 20)
This confirms what I could see from the data. Next, I am going to plot graphs of crimes which show signficant variation in incidence level across the year. I’ll plot the 10 crimes with the greatest standard deviation.
high_sd_crimes <- sd_seasonal_data$Crime[1:10]
#length(sd_seasonal_data$Crime)
#high_sd_crimes
high_sd_seasonal_data <- subset(seasonal_data, Crime %in% high_sd_crimes)
ggplot(data = high_sd_seasonal_data,
aes(x = crime_month, y = monthly_totals)) +
facet_wrap(~Crime, nrow = 2) +
geom_line() +
labs(title = "Top 10 Most Season-Dependant Crimes: Crime Rate Vs Month", x = "Month", y = "No. of Crimes") +
theme(panel.background = element_rect(fill = "white")) +
scale_x_discrete(limits=month.abb) +
theme(axis.text.x = element_text(angle=90, hjust=1))

In summary - there is seasonal variation with total numbers of crimes committed. This overall variation is caused by a number of crimes which have a distict summer preference, most notably, larceny of bicycle. This particular crime sways the overall data so much because there are a lot of incidents of this crime. Interestingly, Domestic Disputes seem to occur more in the early summer, peaking in June. I don’t know why this is. Hit and Runs seem to peak in January and February. Would be interesting to find out why but don’t think this data will tell us that!
There are 53 crime types in total. Let’s also see which have the lowest standard deviation.
print(low_sd_crimes <- sd_seasonal_data$Crime[44:53])
[1] "Prostitution" "Liquor Possession/Sale" "Annoying & Accosting" "Peeping & Spying"
[5] "Kidnapping" "Sex Offender Violation" "Extortion/Blackmail" "Homicide"
[9] "Stalking" "Gambling"
These crimes seem to occur throughout the year with very little variation between months.
Q5: Is there any time variation with crime type?
For this, I need to create a new column with the time grouped in hours. I can just take the first 2 digits from the crime_st_time column.I’m going to call this new column ‘crime_hour’
pattern <- "(\\d+):"
crime_data_hours_1 <- crime_data %>%
mutate(crime_hour = str_match(crime_st_time, pattern)[,2]) %>%
mutate(crime_hour = str_pad(crime_hour, 2, side = "left", pad = "0"))
crime_data_hours <- crime_data_hours_1 %>%
group_by(Crime, crime_hour) %>%
summarise(no_crimes_per_hour = n()) %>%
mutate(crime_hour = as.integer(crime_hour)) %>%
filter(crime_hour != is.na(crime_hour))
#print(unique(crime_data_hours$crime_hour))
head(crime_data_hours, 20)
all_crime_data_hours <- crime_data_hours %>%
group_by(crime_hour) %>%
summarise(total_crimes_per_hour = sum(no_crimes_per_hour)) %>%
filter(crime_hour != is.na(crime_hour))
ggplot(data = all_crime_data_hours,
aes(x = crime_hour, y = total_crimes_per_hour)) +
geom_line() +
labs(title = "Crime Rate Vs Time in 24 hours", x = "Time (hours)", y = "No. of Crimes") +
#theme(panel.background = element_rect(fill = "white")) +
scale_x_continuous(breaks=c(0:23))

ggplot(data = crime_data_hours,
aes(x = crime_hour, y = no_crimes_per_hour)) +
facet_wrap(~Crime, nrow = 5) +
geom_line() +
labs(title = "Crime Rate Vs Time in 24 hours", x = "Time (hours)", y = "No. of Crimes") +
#theme(panel.background = element_rect(fill = "white"))+
scale_x_continuous(breaks=c(0,4,8,12,16,20))

NA
NA
The plot of overall crimes seems to show that the peak time for crimes (of any sort) to be committed is 6pm. The least likely time for a crime (any sort) to be committed is 4am-5am. There is also another peak crime time which is midday. This seems unusual and may be worth further investigation. Could it be that if no time is entered, the default is midday? Or is it that midday day is usually popular with criminals? Maybe looking at the individual crimes will shed more light on this.
From the individual crime plots - once again, some crimes appear to have no or very little relation to time of day, however with some others it is quite marked.
Again, calculate the standard deviation of each crime and plot the crimes which show the most variation (top 10).
crime_data_hours_sd <- crime_data_hours %>%
group_by(Crime) %>%
summarise(st_dev = sd(no_crimes_per_hour)) %>%
arrange(desc(st_dev))
crime_data_hours_sd
crime_data_hrs_sd_top10 <- crime_data_hours_sd$Crime[1:10]
#crime_data_hrs_sd_top10
top10_sd_time_data <- subset(crime_data_hours, Crime %in% crime_data_hrs_sd_top10)
ggplot(data = top10_sd_time_data,
aes(x = crime_hour, y = no_crimes_per_hour)) +
facet_wrap(~Crime, nrow = 2) +
geom_line() +
labs(title = "Top 10 most Time-Dependant Crimes: Crime Rate Vs Time in 24 hours", x = "Time", y = "No. of Crimes") +
theme(panel.background = element_rect(fill = "white")) +
scale_x_continuous(breaks=c(0, 4, 8, 12, 16, 20))

NA
NA
You can see from these plots that certain crimes are more likely to happen at certain times of the day. Domestic disputes are most likely to occur in the evening, peaking at 8pm. Car theft is most likely to happen in the evening as well, highest between 6pm and 8pm. Shoplifting unsurprising occurs during most shop opening hours and peaks between 3pm and 6pm. The graph for forgery is interesting. There seems to be a very large peak at midday. It seems unlikely that criminals have a preference for carrying out forgery at midday. This -could- be due to the fact that forgery is reported after the actual crime is commited and people generally don’t know when it was committed and therefore the time is recorded as default midday. Some qualitative analysis/questionnaires would perhaps be able to answer this question. Quite a few of the other crimes have peaks at midday as well.
One way of potentially discovering why is to look back at the original data for time. Time data is given in HH:MM. i.e 12:35, 15:15. If there is a default setting for midday, that would mean that many of the crimes would be entered as 12:00 instead of, say 12:10, 12:40
Try this: for each hour, count the total number of entires and also count the number of entires which are of the format HH:00.
pattern = ":00"
crime_data_midday <- crime_data_hours_1 %>%
mutate(logic_midday = str_detect(crime_st_time, pattern)) %>%
group_by(crime_hour, logic_midday) %>%
summarise(no_1200 = n()) %>%
pivot_wider(names_from = logic_midday, values_from = no_1200) %>%
mutate(percent_00 = `TRUE`/`FALSE`*100) %>%
arrange(desc = -percent_00)
crime_data_midday
Interestingly the highest proportion of entires for exactly on the hours is for 00:00 i.e. midnight. Next is 12:00 and then 08:00.
Even though 95% of entries for 00:00-01:00 are recorded as 00:00 exactly, from looking at the graphs, there doesn’t seem to be an unusual peak. This could suggest that people record crimes at exactly midnight but they largely do occur around midnight.
For the midday entries, 78% are recorded as exactly midday, but there seems to be a peak purely for this hour on the graphs.
This does support the theory that these entries could be due to default time settings but I’d need to do some qual research to check.
Q6: How have crimes changed over the years? For this, I want to see if any crimes have any particular trend across the years that this data has been collected. The data covers the years 2009 - 2016. First, I’ll plot the total crime trend across the years, then I’ll look at individual crimes, and again plot those crimes with the biggest variability in data across the years.
#head(crime_data)
pattern = "/\\d+/(\\d+)\\b"
dates <- crime_data$crime_st_date
#head(str_match(dates, pattern))
year_crime_data_1 <- crime_data %>%
mutate(crime_year = str_match(crime_st_date, pattern)[,2]) %>%
mutate(crime_year = str_sub(crime_year, -2, -1))
year_crime_data <- year_crime_data_1 %>%
group_by(crime_year) %>%
summarise(crimes_per_year = n())
#print(unique(year_crime_data$crime_year))
correct_years <- c("09", "10", "11", "12", "13", "14", "15", "16")
year_crime_data <- subset(year_crime_data, crime_year %in% correct_years)
head(year_crime_data,50)
#print(sum(year_crime_data$crimes_per_year))
year_crime_data <- year_crime_data %>%
mutate(crime_year = str_pad(crime_year, 3, side = "left", pad = "0")) %>%
mutate(crime_year = str_pad(crime_year, 4, side = "left", pad = "2"))
ggplot(data = year_crime_data,
aes(x = as.numeric(crime_year), y = crimes_per_year)) +
geom_line() +
labs(title = "Crimes Committed Per Year in Cambridge", x = "Year", y = "No. of Crimes") +
theme(panel.background = element_rect(fill = "white")) +
scale_x_continuous(breaks=c(2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016))

(Note: From grouping by year and counting the number of crimes that occur in each year, I can see that there are a few ‘rogue’ years in there… I was expecting to see 2009-2016 but sometimes the years are entered as 2009 and sometimes as 09. I can sort this by subsetting the string for only the last two digits. However the other problem is that there are years that I didn’t expect like 1999 and 01. However the number of entries for these years is very small so I’ve removed these entries from the data. I still have 55127 data entries.)
From the plot of crimes over time in years, it looks like crime has overall decreased, with a dip in 2013. However the big dip for 2016 is probably unrealistic and suggests the data grab was taken part way through the year. I can check to see if the data for 2016 contains all months.
check_2016 <- subset(year_crime_data_1, crime_year %in% correct_years)
check_2016 <- check_2016 %>%
select(crime_year, crime_month) %>%
filter(crime_year == 16) %>%
group_by(crime_month) %>%
summarise(no_per_month = n())
colnames(check_2016) <- c("Month in 2016", "No. Crimes per Month")
check_2016
NA
This shows what was expected - the months only go up to 09 i.e. September. So we’d expect the number of crimes to be ~75% of the other years.
Seeing as this is going to mess up the overall trends, I am going to exclude the year 2016 from the analysis.
The next table shows the Crime and the corresponding standard deviation of the yearly incidents of each crime.
#year_crime_data_1
crimes_by_year <- year_crime_data_1 %>%
mutate(crime_year = str_pad(crime_year, 3, side = "left", pad = "0")) %>%
mutate(crime_year = str_pad(crime_year, 4, side = "left", pad = "2")) %>%
mutate(crime_year = as.numeric(crime_year)) %>%
filter(crime_year == 2009:2015) %>%
group_by(Crime, crime_year) %>%
summarise(no_per_year = n())
longer object length is not a multiple of shorter object length
#crimes_by_year
top10_sd_year_data <- crimes_by_year %>%
group_by(Crime) %>%
summarise(st_dev = sd(no_per_year)) %>%
arrange(desc(st_dev))
top10 <- top10_sd_year_data$Crime[1:10]
top_10_df <- top10_sd_year_data[1:10,]
top_10_df
crimes_by_year <- subset(crimes_by_year, Crime %in% top10)
#crimes_by_year
ggplot(data = crimes_by_year,
aes(x = crime_year, y = no_per_year)) +
facet_wrap(~Crime, nrow = 2) +
geom_line() +
labs(title = "Crimes Committed Per Year in Cambridge", x = "Year", y = "No. of Crimes") +
theme(panel.background = element_rect(fill = "white"))

NA
NA
Although these graphs show that some of the crimes are quite variable year to year, most of them don’t show an obvious downward or upward trend. The only one worth noting here is Larceny from MV which seems to be decreasing each year.
And here ends my analysis of Cambridge, MA Crime Data!
LS0tDQp0aXRsZTogIkludmVzdGlnYXRpbmcgQ2FtYnJpZGdlIENyaW1lIERhdGEiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCkluIHRoaXMgcHJvamVjdCBJIHdpbGwgaW52ZXN0aWdhdGUgdGhlIENyaW1lIERhdGEgZnJvbSB0aGUgQ2l0eSBvZiBDYW1icmlkZ2UgZnJvbSAyMDA5IHRvIDIwMTYNCg0KRmlyc3QsIEknbGwgaW5zdGFsbCB0aGUgcGFja2FnZXMgSSBtaWdodCBuZWVkIGZvciB0aGlzIGFuYWx5c2lzLg0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwdXJycikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KDQpnZXR3ZCgpDQoNCmBgYA0KDQpJbXBvcnRpbmcgZGF0YToNCmBgYHtyfQ0Kc2V0d2QoIkM6L1VzZXJzL0FuYS9EZXNrdG9wL0RhdGEgQW5hbHl0aWNzL0NTViBGaWxlcyIpDQpyYXdfZGF0YSA8LSByZWFkX2NzdigiY3JpbWVfZGF0YV9jc3YuY3N2IikNCg0KI2NvbHVtbl9uYW1lcyA8LSBjb2xuYW1lcyhyYXdfZGF0YSkNCiNwcmludChjb2x1bW5fbmFtZXMpDQpgYGANCg0KSGVyZSBpcyB0aGUgZmlyc3QgMTAgcm93cyBvZiB0aGUgcmF3IGRhdGE6DQogIA0KYGBge3J9DQpoZWFkKHJhd19kYXRhLCAxMCkNCmBgYA0KVGhlIGRhdGEgaGFzIDcgY29sdW1uczogDQoNCiAgLSBGaWxlIG51bWJlciAtIGEgcmVmZXJlbmNlIG51bWJlciBmb3IgdGhlIGNyaW1lDQogIC0gRGF0ZSBvZiByZXBvcnQgLSB3aGVuIHRoZSByZXBvcnQgd2FzIG1hZGUNCiAgLSBDcmltZSBEYXRlIFRpbWUgLSBUaGUgZGF0ZSBhbmQgdGltZSBvZiB0aGUgY3JpbWUNCiAgLSBSZXBvcnRpbmcgQXJlYSAtIFN1YnNldCBvZiBOZWlnaGJvcmhvb2QNCiAgLSBOZWlnaGJvdXJob29kIC0gTmVpZ2hib3Job29kIHdpdGhpbiBDYW1icmlkZ2UgDQogIC0gTG9jYXRpb24gLSBzcGVjaWZpYyBsb2NhdGlvbiB3aGVyZSBjcmltZSB0b29rIHBsYWNlDQoNCk5leHQsIGZpbmQgb3V0Og0KDQogIC0gSG93IG1hbnkgcm93cyBvZiByYXcgZGF0YSBhcmUgdGhlcmU/DQogIC0gSG93IG1hbnkgZGlmZmVyZW50IGNhdGVnb3JpZXMgb2YgY3JpbWVzIGFyZSB0aGVyZT8NCiAgLSBIb3cgbWFueSByZXBvcnRpbmcgYXJlYXMgYXJlIHRoZXJlPw0KICAtIEhvdyBtYW55IG5laWdoYm91cmhvb2RzIGFyZSB0aGVyZT8NCg0KYGBge3J9DQpjb3VudChyYXdfZGF0YVssMV0pDQoNCmNyaW1lX3R5cGVzIDwtIHVuaXF1ZShyYXdfZGF0YSRDcmltZSkNCm5vX29mX3JlcG9ydGluZ19hcmVhcyA8LSB1bmlxdWUocmF3X2RhdGEkYFJlcG9ydGluZyBBcmVhYCkNCm5laWdoYm9yaG9vZHMgPC0gdW5pcXVlKHJhd19kYXRhJE5laWdoYm9yaG9vZCkNCg0KcHJpbnQoYXMuZGF0YS5mcmFtZShuZWlnaGJvcmhvb2RzKSkNCg0KbGVuZ3RoKGNyaW1lX3R5cGVzKQ0KbGVuZ3RoKG5vX29mX3JlcG9ydGluZ19hcmVhcykNCmxlbmd0aChuZWlnaGJvcmhvb2RzKQ0KYGBgDQpTbyB0aGVyZSBhcmUgNTQgZGlmZmVyZW50IHR5cGVzIG9mIGNyaW1lLCAxMTggZGlmZmVyZW50IHJlcG9ydGluZyBhcmVhcywgYW5kIDEzIGRpZmZlcmVudCBuZWlnaGJvcmhvb2RzIChub3RlLCBub3QgMTQgYXMgb25lIGlzIGFuIE5BIGVudHJ5KS4gDQoNCkhlcmUgYXJlIHNvbWUgdGhpbmdzIEkgd2lsbCBpbnZlc3RpZ2F0ZSB3aXRoIHRoaXMgZGF0YToNCg0KMS4gV2hhdCBhcmUgdGhlIG1vc3QgY29tbW9ubHkgb2NjdXJyaW5nIGNyaW1lcyBpbiBDYW1icmlkZ2U/DQoyLiBXaGF0IG5laWdoYm91cmhvb2RzIGhhdmUgdGhlIGhpZ2hlc3QgY3JpbWUgcmF0ZT8NCjMuIEFyZSB0aGUgbW9zdCBjb21tb24gdHlwZXMgb2YgY3JpbWUgdGhlIHNhbWUgYWNyb3NzIGFsbCBhcmVhcz8NCjQuIElzIHRoZXJlIGFueSBzZWFzb25hbCB2YXJpYXRpb24gd2l0aCBjcmltZSB0eXBlcz8NCjUuIElzIHRoZXJlIGFueSB0aW1lIHZhcmlhdGlvbiB3aXRoIGNyaW1lIHR5cGVzPyBpLmUuIGRvIGNlcnRhaW4gY3JpbWVzIGhhcHBlbiBhdCBjZXJ0YWluIHRpbWVzIG9mIHRoZSBkYXk/DQo2LiBIb3cgaGF2ZSBjcmltZXMgY2hhbmdlZCBvdmVyIHRoZSB5ZWFycz8gDQoNCldoYXQgaXMgdGhlIGJlc3Qgd2F5IHRvIHByZXNlbnQgYWxsIG9mIHRoaXMgZGF0YT8gDQoNCjEuIEJhciBjaGFydCAoeCA9IGNyaW1lIHR5cGUsIHkgPSBuby4gb2Ygb2NjdXJyYW5jZXMpDQoyLiBCYXIgY2hhcnQgKHggPSBuZWlnaGJvcmhvb2QsIHkgPSBuby4gb2YgY3JpbWVzKQ0KMy4gQmFyIGNoYXJ0IG9mIHRoZSBudW1iZXIgb2YgaW5jaWRlbnRzIG9mIGVhY2ggY3JpbWUgYW5kIHNwbGl0IHRoZSBpbmNpZGVudHMgaW50byBjb2xvdXJzIHJlcHJlc2VudGluZyBlYWNoIG5laWdoYm9yaG9vZC4NCjQuIExpbmUgZ3JhcGggKHggPSBtb250aCwgeSA9IG51bWJlciBvZiBpbmNpZGVudHMgb2YgZWFjaCB0eXBlIG9mIGNyaW1lLiBQbG90IGRpZmZlcmVudCBjcmltZSB0eXBlcyBpbiBlYWNoIGNvbG91cikNCjUuIExpbmUgZ3JhcGggKHggPSB0aW1lIG9mIGRheSAoaW4gaG91cnMpLCB5ID0gbnVtYmVyIG9mIGluY2lkZW50cyBvZiBlYWNoIHR5cGUgb2YgY3JpbWUuKQ0KNi4gTGluZSBncmFwaCAoeCA9IHllYXIsIHkgPSB0b3RhbHMgb2YgZWFjaCBjcmltZSAocGxvdCBkaWZmZXJlbnQgY3JpbWVzIGluIGRpZmZlcmVudCBjb2xvdXJzKSkNCg0KSSdtIG5vdCBnb2luZyB0byBkbyBhbnkgYW5hbHlzaXMgb24gJ2RhdGUgb2YgcmVwb3J0JyBhcyB0aGlzIGlzIGp1c3Qgc29tZXRpbWUgYXJvdW5kIHRoZSBkYXRlIG9mIGNyaW1lIHNvIEkgc2hhbGwgcmVtb3ZlIHRoaXMgY29sdW1uIGZyb20gdGhlIGRhdGEgc2V0Lg0KDQpOZXh0IEkgd2lsbCBjbGVhbiB0aGUgZGF0YSBhbmQgY2hlY2sgZm9yIGFueSBtaXNzaW5nIHZhbHVlcy4gVGhlICdDcmltZSBEYXRlIFRpbWUnIGNvbHVtbiBuZWVkcyB0byBiZSByZWFycmFuZ2VkLiBJdCB3b3VsZCBiZSBnb29kIHRvIHNwbGl0IHRoaXMgY29sdW1uIHVwLiBTb21ldGltZXMgYSByYW5nZSBvZiBkYXRlcyBhbmQgdGltZXMgYXJlIGlucHV0dGVkIGludG8gdGhpcyBjb2x1bW4uIEhlcmUgYXJlIHRoZSBmaXJzdCAxMCBlbnRyaWVzIGluIHRoZSBleGlzdGluZyBgQ3JpbWUgRGF0ZSBUaW1lYCBjb2x1bW46DQoNCmBgYHtyfQ0KZGF0YV9jbGVhbiA8LSByYXdfZGF0YSAlPiUNCiAgc2VsZWN0KC0nRGF0ZSBvZiBSZXBvcnQnKSANCg0KZGF0ZV90aW1lX3YgPC0gcmF3X2RhdGEkYENyaW1lIERhdGUgVGltZWANCmhlYWQoZGF0ZV90aW1lX3YsIDEwKQ0KDQpgYGANCg0KDQpIZXJlIGFyZSB0aGUgbmV3IGNvbHVtbnM6IERhdGUgU3RhcnQsIFRpbWUgU3RhcnQsIERhdGUgRW5kLCBUaW1lIEVuZC4NCg0KYGBge3J9DQpjb2xfbmFtZXMgPC0gYygiY3JpbWVfc3RfZGF0ZSIsICJjcmltZV9zdF90aW1lIiwgImNyaW1lX2VuZF9kYXRlIiwgImNyaW1lX2VuZF90aW1lIikNCg0KaW5mb19zcGxpdHRlZCA8LSBhcy5kYXRhLmZyYW1lKHN0cl9zcGxpdChkYXRlX3RpbWVfdiwgIiAiLCBzaW1wbGlmeSA9IFRSVUUpKQ0KDQppbmZvX3NwbGl0dGVkIDwtIGluZm9fc3BsaXR0ZWQgJT4lDQogIHNlbGVjdCgtVjMpICU+JQ0KICBtdXRhdGUoVjUgPSBpZl9lbHNlKFY1ID09ICIiLCBWNCwgVjUpKSAlPiUNCiAgbXV0YXRlKFY0ID0gaWZfZWxzZShWNSA9PSBWNCwgIiIsIFY0KSkgDQoNCmNvbG5hbWVzKGluZm9fc3BsaXR0ZWQpIDwtIGNvbF9uYW1lcw0KDQpwcmludChoZWFkKGluZm9fc3BsaXR0ZWQsIDEwKSkNCg0KYGBgDQpOb3cgSSB3YW50IHRvIGFkZCB0aGVzZSBjb2x1bW5zIGJhY2sgdG8gdGhlIG1haW4gZGF0YWZyYW1lLiBJIGNhbiBhbHNvIG5vdyByZW1vdmUgdGhlIG9yaWdpbmFsIGBDcmltZSBEYXRlIFRpbWVgIGNvbHVtbi4gSGVyZSdzIHRoZSBkYXRhZnJhbWUgYXMgaXQgY3VycmVudGx5IHN0YW5kczoNCg0KYGBge3J9DQpjcmltZV9kYXRhIDwtIGNiaW5kKGRhdGFfY2xlYW4sIGluZm9fc3BsaXR0ZWQpDQoNCmNyaW1lX2RhdGEgPC0gY3JpbWVfZGF0YSAlPiUNCiAgICBzZWxlY3QoLWBDcmltZSBEYXRlIFRpbWVgKQ0KDQpwcmludChoZWFkKGNyaW1lX2RhdGEsIDEwKSkNCmBgYA0KTmV4dCBJIHNob3VsZCBjaGVjayBmb3IgYW55IG1pc3NpbmcgZGF0YS4NCmBgYHtyfQ0KbG9naWNfbmEgPC0gYXMubG9naWNhbChyb3dTdW1zKGlzLm5hKGNyaW1lX2RhdGEpKSkNCg0KI3ByaW50KGhlYWQobG9naWNfbmEsIDEwKSkNCg0KbmFfcm93cyA8LSBjcmltZV9kYXRhW2xvZ2ljX25hLF0NCg0KI25hX3Jvd3MNCg0KbGVuZ3RoKG5hX3Jvd3NbLDFdKQ0KYGBgDQoNClRoZXJlIGFyZSA4NSByb3dzIHdoaWNoIGNvbnRhaW4gTkEgdmFsdWVzLiBOZXh0IEkgd2FudCB0byBxdWlja2x5IHNlZSBpZiB0aGVyZSBhcmUgY2VydGFpbiBjb2x1bW5zIHdoaWNoIGNvbnRhaW4gbW9zdCBvZiB0aGUgTkEgdmFsdWVzLiBUbyBkbyB0aGlzIEkgY2FuIHN1bSB0aGUgbnVtYmVyIG9mIE5BIHZhbHVlcyBmb3IgZWFjaCBjb2x1bW4uIEkgY2FuIGFsc28gcGxvdCBhIHZpc3VhbCBhaWQgdG8gc2hvdyB0aGUgbnVtYmVyIG9mIE5BIHZhbHVlcyBpbiBlYWNoIGNvbHVtbi4gDQpgYGB7cn0NCg0Kbm9fbmFzIDwtIGFzLmRhdGEuZnJhbWUoY29sU3Vtcyhpcy5uYShuYV9yb3dzKSkpDQpjb2xuYW1lcyhub19uYXMpIDwtICJOby4gb2YgTkEgVmFsdWVzIg0Kbm9fbmFzDQpgYGANClRoZSB0YWJsZSBzaG93cyB0aGF0IGl0IGlzIG1vc3RseSBkYXRhIGluIHRoZSBMb2NhdGlvbiBjb2x1bW4gdGhhdCBpcyBtaXNzaW5nLiBIZXJlIGlzIGEgdmlzdWFsIGFpZCB0byBpbGx1c3RyYXRlIHRoaXMuDQpgYGB7cn0NCmxpYnJhcnkocHVycnIpDQoNCmRmX25hIDwtIG1hcF9kZihuYV9yb3dzLCBmdW5jdGlvbih4KSBhcy5udW1lcmljKGlzLm5hKHgpKSkNCiBkZl9uYV9oZWF0IDwtIGRmX25hICU+JQ0KICAgIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgICAgICBuYW1lc190byA9ICJ4IikgJT4lDQogICAgZ3JvdXBfYnkoeCkgJT4lDQogICAgbXV0YXRlKHkgPSByb3dfbnVtYmVyKCkpDQoNCnBsb3RfbmFfbWF0cml4IDwtIGZ1bmN0aW9uKGRmX25hKSB7DQogICAgICMgUHJlcGFyaW5nIHRoZSBkYXRhZnJhbWUgZm9yIGhlYXRtYXBzIA0KICAgIGRmX2hlYXQgPC0gZGZfbmEgJT4lDQogICAgICAgIHBpdm90X2xvbmdlcihjb2xzID0gZXZlcnl0aGluZygpLA0KICAgICAgICAgICBuYW1lc190byA9ICJ4IikgJT4lDQogICAgICAgIGdyb3VwX2J5KHgpICU+JQ0KICAgICAgICBtdXRhdGUoeSA9IHJvd19udW1iZXIoKSkNCiAgICAgIyBFbnN1cmluZyB0aGUgb3JkZXIgb2YgY29sdW1ucyBpcyBrZXB0IGFzIGl0IGlzDQogICAgZGZfaGVhdCA8LSBkZl9oZWF0ICU+JQ0KICAgICAgICB1bmdyb3VwKCkgJT4lDQogICAgICAgIG11dGF0ZSh4ID0gZmFjdG9yKHgsbGV2ZWxzID0gY29sbmFtZXMoZGZfbmEpKSkNCiAgICAgIyBQbG90dGluZyBkYXRhDQogICAgZyA8LSBnZ3Bsb3QoZGF0YSA9IGRmX2hlYXQsIGFlcyh4PXgsIHk9eSwgZmlsbD12YWx1ZSkpICsgDQogICAgICAgIGdlb21fdGlsZSgpICsgDQogICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgYXhpcy50aWNrcy55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkNCiAgICAgIyBSZXR1cm5pbmcgdGhlIHBsb3QNCiAgICBnDQogfSANCiANCnBsb3RfbmFfbWF0cml4KGRmX25hKQ0KYGBgDQpBcyB3ZSBjb3VsZCBhbHJlYWR5IHNlZSBiZWZvcmUsIG1vc3Qgb2YgdGhlIG1pc3NpbmcgdmFsdWVzIGFyZSBpbiB0aGUgTG9jYXRpb24gY29sdW1uLiBUaGVyZSBhcmUgYWxzbyAyIG1pc3NpbmcgdmFsdWVzIGluIHRoZSAnUmVwb3J0aW5nIEFyZWEnIGFuZCAnTmVpZ2hib3Job29kJyBjb2x1bW5zIGJ1dCBmb3IgYm90aCB0aGVzZSBpbnN0YW5jZXMgdGhlcmUgSVMgYW4gZW50cnkgaW4gdGhlIExvY2F0aW9uIGNvbHVtbi4gDQoNClRoZXJlIGlzbid0IGFueSB3YXkgb2YgZmluZGluZyB0aGUgZXhhY3QgbG9jYXRpb24gZGF0YSBmcm9tIHRoZSByZXN0IG9mIHRoZSBkYXRhLiBUaGVyZSBpcyBwcm9iYWJseSBhIHdheSBvZiBnZXR0aW5nIHRoZSBSZXBvcnRpbmcgQXJlYSBhbmQgTmVpZ2hib3Job29kIGZyb20gdGhlIExvY2F0aW9uIGRhdGEgaG93ZXZlciAyIG91dCBvZiA1NjAwMCsgcm93cyBvZiBkYXRhIGlzIG5vdCBzaWduaWZpY2FudCBzbyB0aGUgYmVzdCB0aGluZyB0byBkbyBpcyB0byBwcm9iYWJseSByZW1vdmUgdGhlIHJvd3Mgb2YgZGF0YSB3aGljaCBkb24ndCBoYXZlIHRoZSBSZXBvcnRpbmcgQXJlYSBhbmQgTmVpZ2hib3Job29kLg0KVGhlcmUncyBhbHNvIGFuIGVudHJ5IGZvciAiYWRtaW4gZXJyb3IiIHVuZGVyIENyaW1lIHNvIEkgYW0gZ29pbmcgdG8gZGlzcmVnYXJkIHRoZXNlIHJvd3MuDQpgYGB7cn0NCiNsZW5ndGgoY3JpbWVfZGF0YVssMV0pICMgU2VlIGhvdyBtYW55IHJvd3MgdGhlcmUgd2VyZSBiZWZvcmUNCg0KY3JpbWVfZGF0YSA8LSBjcmltZV9kYXRhICU+JQ0KICBkcm9wX25hKGBSZXBvcnRpbmcgQXJlYWApICU+JQ0KICBmaWx0ZXIoQ3JpbWUgIT0gIkFkbWluIEVycm9yIikNCg0KI2xlbmd0aChjcmltZV9kYXRhWywxXSkgIyBTZWUgaG93IG1hbnkgcm93cyB0aGVyZSBhcmUgYWZ0ZXIgZHJvcHBpbmcgdGhlIE5BIHZhbHVlcyBmcm9tICdSZXBvcnRpbmcgQXJlYScgYW5kIHJlbW92aW5nIGVudHJpZXMgZm9yICJBZG1pbiBFcnJvciIgaW4gdGhlIENyaW1lIGNvbHVtbg0KDQpgYGANCk5vdyBJIGhhdmUgY2xlYW5lZCB0aGUgZGF0YSBhbmQgcmVtb3ZlZCB0aGUgcm93cyBjb250YWluaW5nIE5BIHZhbHVlcywgSSBjYW4gc3RhcnQgdG8gYW5hbHlzZSB0aGUgZGF0YS4NCg0KUTE6IHdoYXQgaXMgdGhlIG92ZXJhbGwgY3JpbWUgcHJvZmlsZSBvZiBDYW1icmlkZ2U/DQpgYGB7cn0NCmNyaW1lX2RhdGFfZ3JvdXBlZCA8LSBjcmltZV9kYXRhICU+JQ0KICBncm91cF9ieShDcmltZSkgJT4lDQogIHN1bW1hcmlzZShub19vZl9pbmNpZGVudHMgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2Mobm9fb2ZfaW5jaWRlbnRzKSkNCg0KY3JpbWVfZGF0YV9ncm91cGVkDQoNCmdncGxvdChkYXRhID0gY3JpbWVfZGF0YV9ncm91cGVkLA0KICBhZXMoeCA9IENyaW1lLCB5ID0gbm9fb2ZfaW5jaWRlbnRzLCBmaWxsID0gJ2JsdWUnKSkgKyANCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NjAsIGhqdXN0PTEpKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzPWNyaW1lX2RhdGFfZ3JvdXBlZCRDcmltZSkgKw0KICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpKw0KICBsYWJzKHRpdGxlID0gIk5vLiBvZiBJbmNpZGVudHMgKGFsbCB5ZWFycykgdnMgQ3JpbWUgVHlwZSIsIHggPSAiQ3JpbWUgVHlwZSIsIHkgPSAiTm8uIG9mIEluY2lkZW50cyIpICsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikpDQpgYGANClEyOldoaWNoIE5laWdoYm9yaG9vZHMgaGF2ZSB0aGUgaGlnaGVzdCBjcmltZSByYXRlPw0KDQpgYGB7cn0NCm5laWdoYm9yaG9vZF9kYXRhX2dyb3VwZWQgPC0gY3JpbWVfZGF0YSAlPiUNCiAgZ3JvdXBfYnkoTmVpZ2hib3Job29kKSAlPiUNCiAgc3VtbWFyaXNlKG5vX29mX2luY2lkZW50cyA9IG4oKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhub19vZl9pbmNpZGVudHMpKQ0KDQpuZWlnaGJvcmhvb2RfZGF0YV9ncm91cGVkDQoNCmdncGxvdChkYXRhID0gbmVpZ2hib3Job29kX2RhdGFfZ3JvdXBlZCwNCiAgYWVzKHggPSBOZWlnaGJvcmhvb2QsIHkgPSBub19vZl9pbmNpZGVudHMsIGZpbGwgPSBOZWlnaGJvcmhvb2QpKSArIA0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02MCwgaGp1c3Q9MSkpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHM9bmVpZ2hib3Job29kX2RhdGFfZ3JvdXBlZCROZWlnaGJvcmhvb2QpICsNCiAgZ2VvbV9iYXIoc3RhdD0naWRlbnRpdHknKSArDQogIGxhYnModGl0bGUgPSAiQ3JpbWUgUmF0ZSB2cyBOZWlnaGJvcmhvb2QiLCB4ID0gIk5laWdoYm9yaG9vZCIsIHkgPSAiTm8uIG9mIEluY2lkZW50cyAoYWxsIGNyaW1lcykiKSArDQogIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKQ0KYGBgDQpJIHNob3VsZCByZWFsbHkgZmluZCBvdXQgdGhlIHBvcHVsYXRpb24gb2YgZWFjaCBvZiB0aGVzZSBuZWlnaGJvcmhvb2RzIGFzIHRoYXQgd291bGQgZ2l2ZSBhIGJldHRlciBpZGVhIG9mIHRoZSBjcmltZSByYXRlLiANCg0KUTM6IEFyZSB0aGUgbW9zdCBjb21tb24gdHlwZXMgb2YgY3JpbWUgdGhlIHNhbWUgYWNyb3NzIGFsbCBhcmVhcz8gDQoNCkkgd2lsbCBjcmVhdGUgYSBiYXIgY2hhcnQgb2YgdGhlIG51bWJlciBvZiBpbmNpZGVudHMgb2YgZWFjaCBjcmltZSBhbmQgc3BsaXQgdGhlIGluY2lkZW50cyBpbnRvIGNvbG91cnMgcmVwcmVzZW50aW5nIGVhY2ggbmVpZ2hib3Job29kLg0KDQpgYGB7cn0NCm5jX2RhdGFfZ3JvdXBlZCA8LSBjcmltZV9kYXRhICU+JQ0KICBncm91cF9ieShOZWlnaGJvcmhvb2QsIENyaW1lKSAlPiUNCiAgc3VtbWFyaXNlKG5vX29mX2luY2lkZW50cyA9IG4oKSkNCg0KI25jX2RhdGFfZ3JvdXBlZA0KDQpnZ3Bsb3QoZGF0YSA9IG5jX2RhdGFfZ3JvdXBlZCwNCiAgYWVzKHggPSBDcmltZSwgeSA9IG5vX29mX2luY2lkZW50cywgZmlsbCA9IE5laWdoYm9yaG9vZCkpICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTYwLCBoanVzdD0xKSkgKw0KICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsNCiAgbGFicyh0aXRsZSA9ICJOby4gb2YgQ3JpbWUgaW5jaWRlbnRzIHBlciBDcmltZSBUeXBlIiwgeCA9ICJDcmltZSBUeXBlIiwgeSA9ICJOby4gb2YgSW5jaWRlbnRzIikgKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkNCmBgYA0KRnJvbSB0aGlzIHBsb3QsIGl0IGxvb2tzIGxpa2UgbW9zdCBjcmltZXMgb2NjdXIgYWNyb3NzIGFsbCB0aGUgbmVpZ2hib3Job29kcy4gaS5lLiB0aGVyZSBpcyBubyBjcmltZSB3aGljaCBpcyBtb3JlIG9uZSBjb2xvdXIgdGhhbiBhbm90aGVyLiBUaGVyZSdzIHByb2JhYmx5IHNvbWUgbW9yZSBpbiBkZXB0aCBhbmFseXNpcyBwb3NzaWJsZSwgYnV0IGZvciBub3csIHdlJ2xsIGp1c3QgY29uc2lkZXIgdGhhdCB0aGUgY3JpbWUgcHJvZmlsZXMgYXJlIHByZXR0eSBzaW1pbGFyIGFjcm9zcyB0aGUgZGlmZmVyZW50IG5laWdoYm9yaG9vZHMuICANCg0KUTQ6IElzIHRoZXJlIGFueSBzZWFzb25hbCB2YXJpYXRpb24gd2l0aCBDcmltZSB0eXBlcz8NCg0KRm9yIHRoaXMsIGl0IHdvdWxkIGJlIGdvb2QgdG8gcGxvdCBhIGxpbmUgZ3JhcGggd2l0aCB0aGUgbW9udGhzIG9uIHRoZSB4LWF4aXMgYW5kIHRoZSB0b3RhbCBudW1iZXIgb2YgY3JpbWVzIGluIGVhY2ggbW9udGggb24gdGhlIHktYXhpcy4gSG93ZXZlciwgdGhlIGNyaW1lX3N0X2RhdGUgZGF0YSBuZWVkcyB0byBiZSBtYW5pcHVsYXRlZCB0byBleHRyYWN0IHRoZSBtb250aC4gDQpVc2UgcmVnZXggdG8gZXh0cmFjdCB0aGUgbW9udGggaW4gZGlnaXRzIGFuZCBhZGQgYSBjb2x1bW4gZm9yICdjcmltZV9tb250aCcNCg0KSGVyZSdzIHRoZSBkYXRhZnJhbWUgYWdhaW4gd2l0aCB0aGUgbmV3IGNvbHVtbiAnY3JpbWVfbW9udGgnIGFkZGVkOg0KDQpgYGB7cn0NCiNoZWFkKGNyaW1lX2RhdGEsIDIwKQ0KDQpwYXR0ZXJuID0gIlxcYiguKylcXC8uK1xcLyINCm1vbnRoIDwtIHN0cl9tYXRjaChjcmltZV9kYXRhJGNyaW1lX3N0X2RhdGUsIHBhdHRlcm4pWywyXQ0KI2hlYWQobW9udGgpDQoNCmNyaW1lX2RhdGEgPC0gY3JpbWVfZGF0YSAlPiUNCiAgbXV0YXRlKGNyaW1lX21vbnRoID0gbW9udGgpICU+JQ0KICBtdXRhdGUoY3JpbWVfbW9udGggPSBzdHJfcGFkKGNyaW1lX21vbnRoLCAyLCBzaWRlID0gImxlZnQiLCBwYWQgPSAiMCIpKQ0KDQojcHJpbnQodW5pcXVlKGNyaW1lX2RhdGEkY3JpbWVfbW9udGgpKSAjIGNoZWNraW5nIHdoYXQgbW9udGhzIEkgZ2V0IC0gaXQgc2hvdWxkIGJlIDAxIC0gMTINCg0KaGVhZChjcmltZV9kYXRhLDEwKQ0KYGBgDQpOb3cgSSBoYXZlIGEgY29sdW1uIHdpdGggdGhlIG1vbnRocy4gSSBub3cgd2FudCB0byBwbG90IHRoZSBmcmVxdWVuY3kgb2YgZWFjaCB0eXBlIG9mIGNyaW1lIGZvciBlYWNoIG1vbnRoIGFuZCB0aGVuIHBsb3QgbGluZSBncmFwaHMgdG8gc2VlIGlmIHRoZXJlJ3MgYW55IHNlYXNvbmFsIHZhcmlhdGlvbi4NCmBgYHtyfQ0KI2hlYWQoY3JpbWVfZGF0YSwgMjApDQoNCg0KdG90YWxfc2Vhc29uYWxfZGF0YSA8LSBjcmltZV9kYXRhICU+JQ0KICBncm91cF9ieShjcmltZV9tb250aCkgJT4lDQogIHN1bW1hcmlzZShtb250aGx5X3RvdGFsID0gbigpKSAlPiUNCiAgbXV0YXRlKGNyaW1lX21vbnRoID0gYXMuaW50ZWdlcihjcmltZV9tb250aCkpICMlPiUNCiAgI211dGF0ZShjcmltZV9tb250aCA9IG1vbnRoLmFiYltjcmltZV9tb250aF0pDQoNCmdncGxvdChkYXRhID0gdG90YWxfc2Vhc29uYWxfZGF0YSwNCiAgICAgICBhZXMoeCA9IGNyaW1lX21vbnRoLCB5ID0gbW9udGhseV90b3RhbCwgZmlsbCA9ICJibHVlIikpICsNCiAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT02MCwgaGp1c3Q9MSkpICsNCiAgICAgICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKw0KICAgICAgIGxhYnModGl0bGUgPSAiQWxsIENyaW1lIFJhdGUgVnMgTW9udGgiLCB4ID0gIk1vbnRoIiwgeSA9ICJOby4gb2YgQ3JpbWVzIikgKw0KICAgICAgIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKSArIA0KICAgICAgIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gbW9udGguYWJiKQ0KDQpzZWFzb25hbF9kYXRhIDwtIGNyaW1lX2RhdGEgJT4lDQogIGdyb3VwX2J5KENyaW1lLCBjcmltZV9tb250aCkgJT4lDQogIHN1bW1hcmlzZShtb250aGx5X3RvdGFscyA9IG4oKSkgJT4lDQogIG11dGF0ZShjcmltZV9tb250aCA9IGFzLmludGVnZXIoY3JpbWVfbW9udGgpKSANCg0KZ2dwbG90KGRhdGEgPSBzZWFzb25hbF9kYXRhLA0KICBhZXMoeCA9IGNyaW1lX21vbnRoLCB5ID0gbW9udGhseV90b3RhbHMsIGNvbG9yID0gQ3JpbWUpKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh0aXRsZSA9ICJDcmltZSBSYXRlIFZzIE1vbnRoIiwgeCA9ICJNb250aCIsIHkgPSAiTm8uIG9mIENyaW1lcyIpICsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHM9bW9udGguYWJiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTkwLCBoanVzdD0xKSkgDQoNCg0KDQpgYGANClRoZSBiYXIgZ3JhcGggc2hvd2luZyBhbGwgY3JpbWVzIG92ZXIgdGhlIGNvdXJzZSBvZiB0aGUgeWVhciBzaG93cyBjbGVhcmx5IHRoYXQgdGhlIG51bWJlciBvZiBjcmltZXMgaW5jcmVhc2VzIGFjcm9zcyB0aGUgc3VtbWVyIG1vbnRocyBhbmQgZGVjcmVhc2VzIGluIHRoZSB3aW50ZXIgbW9udGhzLCB3aXRoIGEgc21hbGwgaW5jcmVhc2UgaW4gY3JpbWVzIGluIEphbnVhcnkuIA0KDQpJdCB3b3VsZCBiZSByZWFsbHkgaW50ZXJlc3RpbmcgdG8gc2VlIHdoZXRoZXIgdGhpcyBvdmVyYWxsIHRyZW5kIGlzIGRyaXZlbiBieSBzcGVjaWZpYyBjcmltZXMgb3Igd2hldGhlciBhbGwgY3JpbWVzIGZvbGxvdyB0aGlzIGdlbmVyYWwgdHJlbmQuIA0KDQpIb3dldmVyLCB3aGVuIEkgcGxvdHRlZCBhbGwgdGhlIGNyaW1lcyBzZXBhcmF0ZWx5IG9uIGEgbGluZSBncmFwaCB0aGVuIHRoZXJlIHdlcmUgdG9vIG1hbnkgbGluZXMgdG8gd29yayBvdXQgd2hhdCB3YXMgZ29pbmcgb24uIEkgdGhpbmsgaXQgd291bGQgYmUgYmVzdCB0byBwbG90IHRoZW0gYWxsIG9uIHNlcGFyYXRlIGdyYXBocywgYnV0IHRoZXJlJ3MgYSBsb3QuIEkgY2FuIHRlbGwgdGhhdCBzb21lIG9mIHRoZSBjcmltZXMgc2hvdyBzaWduaWZpY2FudCB2YXJpYXRpb24gaW4gaW5jaWRlbmNlIGFjcm9zcyB0aGUgeWVhci4gDQoNCkkgdGhpbmsgaXQgd291bGQgYmUgZ29vZCB0byBwbG90IG9ubHkgdGhlIGdyYXBocyB0aGF0IGFyZSBpbnRlcmVzdGluZyBpLmUuIHRoZXJlIGlzIHNvbWUgc2lnbmlmaWNhbnQgdmFyaWF0aW9uIGluIGluY2lkZW5jZSBsZXZlbCBhY2Nyb3NzIHRoZSB5ZWFyLiBUbyBkbyB0aGlzLCBJIHdpbGwgbG9vayBhdCB0aGUgdmFyaWF0aW9uIG9mIHRoZSBkYXRhIHdpdGhpbiBlYWNoIGNyaW1lLiANCg0KVGhlIG5leHQgdGFibGUgc2hvd3MgdGhlIENyaW1lIGFuZCB0aGUgY29ycmVzcG9uZGluZyBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIG1vbnRobHkgaW5jaWRlbnRzIG9mIGVhY2ggY3JpbWUuDQpgYGB7cn0NCnNkX3NlYXNvbmFsX2RhdGEgPC0gY3JpbWVfZGF0YSAlPiUNCiAgZ3JvdXBfYnkoQ3JpbWUsIGNyaW1lX21vbnRoKSAlPiUNCiAgc3VtbWFyaXNlKG1vbnRobHlfdG90YWxzID0gbigpKSAlPiUNCiAgZ3JvdXBfYnkoQ3JpbWUpICU+JQ0KICBzdW1tYXJpc2Uoc3RfZGV2ID0gc2QobW9udGhseV90b3RhbHMpKSAlPiUNCiAgYXJyYW5nZShkZXNjKHN0X2RldikpDQoNCmhlYWQoc2Rfc2Vhc29uYWxfZGF0YSwgMjApDQpgYGANClRoaXMgY29uZmlybXMgd2hhdCBJIGNvdWxkIHNlZSBmcm9tIHRoZSBkYXRhLiBOZXh0LCBJIGFtIGdvaW5nIHRvIHBsb3QgZ3JhcGhzIG9mIGNyaW1lcyB3aGljaCBzaG93IHNpZ25maWNhbnQgdmFyaWF0aW9uIGluIGluY2lkZW5jZSBsZXZlbCBhY3Jvc3MgdGhlIHllYXIuIEknbGwgcGxvdCB0aGUgMTAgY3JpbWVzIHdpdGggdGhlIGdyZWF0ZXN0IHN0YW5kYXJkIGRldmlhdGlvbi4gDQoNCmBgYHtyfQ0KaGlnaF9zZF9jcmltZXMgPC0gc2Rfc2Vhc29uYWxfZGF0YSRDcmltZVsxOjEwXQ0KDQojbGVuZ3RoKHNkX3NlYXNvbmFsX2RhdGEkQ3JpbWUpDQoNCiNoaWdoX3NkX2NyaW1lcw0KDQpoaWdoX3NkX3NlYXNvbmFsX2RhdGEgPC0gc3Vic2V0KHNlYXNvbmFsX2RhdGEsIENyaW1lICVpbiUgaGlnaF9zZF9jcmltZXMpDQoNCmdncGxvdChkYXRhID0gaGlnaF9zZF9zZWFzb25hbF9kYXRhLA0KICBhZXMoeCA9IGNyaW1lX21vbnRoLCB5ID0gbW9udGhseV90b3RhbHMpKSArDQogIGZhY2V0X3dyYXAofkNyaW1lLCBucm93ID0gMikgKw0KICBnZW9tX2xpbmUoKSArDQogIGxhYnModGl0bGUgPSAiVG9wIDEwIE1vc3QgU2Vhc29uLURlcGVuZGFudCBDcmltZXM6IENyaW1lIFJhdGUgVnMgTW9udGgiLCB4ID0gIk1vbnRoIiwgeSA9ICJOby4gb2YgQ3JpbWVzIikgKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cz1tb250aC5hYmIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9OTAsIGhqdXN0PTEpKSANCmBgYA0KSW4gc3VtbWFyeSAtIHRoZXJlIGlzIHNlYXNvbmFsIHZhcmlhdGlvbiB3aXRoIHRvdGFsIG51bWJlcnMgb2YgY3JpbWVzIGNvbW1pdHRlZC4gVGhpcyBvdmVyYWxsIHZhcmlhdGlvbiBpcyBjYXVzZWQgYnkgYSBudW1iZXIgb2YgY3JpbWVzIHdoaWNoIGhhdmUgYSBkaXN0aWN0IHN1bW1lciBwcmVmZXJlbmNlLCBtb3N0IG5vdGFibHksIGxhcmNlbnkgb2YgYmljeWNsZS4gVGhpcyBwYXJ0aWN1bGFyIGNyaW1lIHN3YXlzIHRoZSBvdmVyYWxsIGRhdGEgc28gbXVjaCBiZWNhdXNlIHRoZXJlIGFyZSBhIGxvdCBvZiBpbmNpZGVudHMgb2YgdGhpcyBjcmltZS4gSW50ZXJlc3RpbmdseSwgRG9tZXN0aWMgRGlzcHV0ZXMgc2VlbSB0byBvY2N1ciBtb3JlIGluIHRoZSBlYXJseSBzdW1tZXIsIHBlYWtpbmcgaW4gSnVuZS4gSSBkb24ndCBrbm93IHdoeSB0aGlzIGlzLiBIaXQgYW5kIFJ1bnMgc2VlbSB0byBwZWFrIGluIEphbnVhcnkgYW5kIEZlYnJ1YXJ5LiBXb3VsZCBiZSBpbnRlcmVzdGluZyB0byBmaW5kIG91dCB3aHkgYnV0IGRvbid0IHRoaW5rIHRoaXMgZGF0YSB3aWxsIHRlbGwgdXMgdGhhdCEgDQoNClRoZXJlIGFyZSA1MyBjcmltZSB0eXBlcyBpbiB0b3RhbC4gTGV0J3MgYWxzbyBzZWUgd2hpY2ggaGF2ZSB0aGUgbG93ZXN0IHN0YW5kYXJkIGRldmlhdGlvbi4NCg0KYGBge3J9DQpwcmludChsb3dfc2RfY3JpbWVzIDwtIHNkX3NlYXNvbmFsX2RhdGEkQ3JpbWVbNDQ6NTNdKQ0KYGBgDQpUaGVzZSBjcmltZXMgc2VlbSB0byBvY2N1ciB0aHJvdWdob3V0IHRoZSB5ZWFyIHdpdGggdmVyeSBsaXR0bGUgdmFyaWF0aW9uIGJldHdlZW4gbW9udGhzLg0KDQpRNTogSXMgdGhlcmUgYW55IHRpbWUgdmFyaWF0aW9uIHdpdGggY3JpbWUgdHlwZT8NCg0KRm9yIHRoaXMsIEkgbmVlZCB0byBjcmVhdGUgYSBuZXcgY29sdW1uIHdpdGggdGhlIHRpbWUgZ3JvdXBlZCBpbiBob3Vycy4gSSBjYW4ganVzdCB0YWtlIHRoZSBmaXJzdCAyIGRpZ2l0cyBmcm9tIHRoZSBjcmltZV9zdF90aW1lIGNvbHVtbi5JJ20gZ29pbmcgdG8gY2FsbCB0aGlzIG5ldyBjb2x1bW4gJ2NyaW1lX2hvdXInDQoNCg0KYGBge3J9DQpwYXR0ZXJuIDwtICIoXFxkKyk6Ig0KDQpjcmltZV9kYXRhX2hvdXJzXzEgPC0gY3JpbWVfZGF0YSAlPiUNCiAgbXV0YXRlKGNyaW1lX2hvdXIgPSBzdHJfbWF0Y2goY3JpbWVfc3RfdGltZSwgcGF0dGVybilbLDJdKSAlPiUNCiAgbXV0YXRlKGNyaW1lX2hvdXIgPSBzdHJfcGFkKGNyaW1lX2hvdXIsIDIsIHNpZGUgPSAibGVmdCIsIHBhZCA9ICIwIikpIA0KDQpjcmltZV9kYXRhX2hvdXJzIDwtIGNyaW1lX2RhdGFfaG91cnNfMSAlPiUNCiAgZ3JvdXBfYnkoQ3JpbWUsIGNyaW1lX2hvdXIpICU+JQ0KICBzdW1tYXJpc2Uobm9fY3JpbWVzX3Blcl9ob3VyID0gbigpKSAlPiUNCiAgbXV0YXRlKGNyaW1lX2hvdXIgPSBhcy5pbnRlZ2VyKGNyaW1lX2hvdXIpKSAlPiUNCiAgZmlsdGVyKGNyaW1lX2hvdXIgIT0gaXMubmEoY3JpbWVfaG91cikpDQoNCiNwcmludCh1bmlxdWUoY3JpbWVfZGF0YV9ob3VycyRjcmltZV9ob3VyKSkNCg0KaGVhZChjcmltZV9kYXRhX2hvdXJzLCAyMCkNCg0KYWxsX2NyaW1lX2RhdGFfaG91cnMgPC0gY3JpbWVfZGF0YV9ob3VycyAlPiUNCiAgZ3JvdXBfYnkoY3JpbWVfaG91cikgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9jcmltZXNfcGVyX2hvdXIgPSBzdW0obm9fY3JpbWVzX3Blcl9ob3VyKSkgJT4lDQogIGZpbHRlcihjcmltZV9ob3VyICE9IGlzLm5hKGNyaW1lX2hvdXIpKQ0KDQpnZ3Bsb3QoZGF0YSA9IGFsbF9jcmltZV9kYXRhX2hvdXJzLA0KICAgICAgIGFlcyh4ID0gY3JpbWVfaG91ciwgeSA9IHRvdGFsX2NyaW1lc19wZXJfaG91cikpICsNCiAgICAgIGdlb21fbGluZSgpICsNCiAgbGFicyh0aXRsZSA9ICJDcmltZSBSYXRlIFZzIFRpbWUgaW4gMjQgaG91cnMiLCB4ID0gIlRpbWUgKGhvdXJzKSIsIHkgPSAiTm8uIG9mIENyaW1lcyIpICsNCiAgI3RoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygwOjIzKSkNCg0KZ2dwbG90KGRhdGEgPSBjcmltZV9kYXRhX2hvdXJzLA0KICAgICAgIGFlcyh4ID0gY3JpbWVfaG91ciwgeSA9IG5vX2NyaW1lc19wZXJfaG91cikpICsNCiAgICAgIGZhY2V0X3dyYXAofkNyaW1lLCBucm93ID0gNSkgKw0KICAgICAgZ2VvbV9saW5lKCkgKw0KICAgICAgbGFicyh0aXRsZSA9ICJDcmltZSBSYXRlIFZzIFRpbWUgaW4gMjQgaG91cnMiLCB4ID0gIlRpbWUgKGhvdXJzKSIsIHkgPSAiTm8uIG9mIENyaW1lcyIpICsNCiAgICAgICN0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkrDQogICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCw0LDgsMTIsMTYsMjApKQ0KDQoNCmBgYA0KVGhlIHBsb3Qgb2Ygb3ZlcmFsbCBjcmltZXMgc2VlbXMgdG8gc2hvdyB0aGF0IHRoZSBwZWFrIHRpbWUgZm9yIGNyaW1lcyAob2YgYW55IHNvcnQpIHRvIGJlIGNvbW1pdHRlZCBpcyA2cG0uIFRoZSBsZWFzdCBsaWtlbHkgdGltZSBmb3IgYSBjcmltZSAoYW55IHNvcnQpIHRvIGJlIGNvbW1pdHRlZCBpcyA0YW0tNWFtLiBUaGVyZSBpcyBhbHNvIGFub3RoZXIgcGVhayBjcmltZSB0aW1lIHdoaWNoIGlzIG1pZGRheS4gVGhpcyBzZWVtcyB1bnVzdWFsIGFuZCBtYXkgYmUgd29ydGggZnVydGhlciBpbnZlc3RpZ2F0aW9uLiBDb3VsZCBpdCBiZSB0aGF0IGlmIG5vIHRpbWUgaXMgZW50ZXJlZCwgdGhlIGRlZmF1bHQgaXMgbWlkZGF5PyBPciBpcyBpdCB0aGF0IG1pZGRheSBkYXkgaXMgdXN1YWxseSBwb3B1bGFyIHdpdGggY3JpbWluYWxzPyBNYXliZSBsb29raW5nIGF0IHRoZSBpbmRpdmlkdWFsIGNyaW1lcyB3aWxsIHNoZWQgbW9yZSBsaWdodCBvbiB0aGlzLiANCg0KRnJvbSB0aGUgaW5kaXZpZHVhbCBjcmltZSBwbG90cyAtIG9uY2UgYWdhaW4sIHNvbWUgY3JpbWVzIGFwcGVhciB0byBoYXZlIG5vIG9yIHZlcnkgbGl0dGxlIHJlbGF0aW9uIHRvIHRpbWUgb2YgZGF5LCBob3dldmVyIHdpdGggc29tZSBvdGhlcnMgaXQgaXMgcXVpdGUgbWFya2VkLg0KDQpBZ2FpbiwgY2FsY3VsYXRlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgZWFjaCBjcmltZSBhbmQgcGxvdCB0aGUgY3JpbWVzIHdoaWNoIHNob3cgdGhlIG1vc3QgdmFyaWF0aW9uICh0b3AgMTApLg0KDQpgYGB7cn0NCmNyaW1lX2RhdGFfaG91cnNfc2QgPC0gY3JpbWVfZGF0YV9ob3VycyAlPiUNCiAgZ3JvdXBfYnkoQ3JpbWUpICU+JQ0KICBzdW1tYXJpc2Uoc3RfZGV2ID0gc2Qobm9fY3JpbWVzX3Blcl9ob3VyKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhzdF9kZXYpKQ0KDQpjcmltZV9kYXRhX2hvdXJzX3NkDQoNCmNyaW1lX2RhdGFfaHJzX3NkX3RvcDEwIDwtIGNyaW1lX2RhdGFfaG91cnNfc2QkQ3JpbWVbMToxMF0NCg0KI2NyaW1lX2RhdGFfaHJzX3NkX3RvcDEwDQoNCnRvcDEwX3NkX3RpbWVfZGF0YSA8LSBzdWJzZXQoY3JpbWVfZGF0YV9ob3VycywgQ3JpbWUgJWluJSBjcmltZV9kYXRhX2hyc19zZF90b3AxMCkNCg0KZ2dwbG90KGRhdGEgPSB0b3AxMF9zZF90aW1lX2RhdGEsDQogIGFlcyh4ID0gY3JpbWVfaG91ciwgeSA9IG5vX2NyaW1lc19wZXJfaG91cikpICsNCiAgZmFjZXRfd3JhcCh+Q3JpbWUsIG5yb3cgPSAyKSArDQogIGdlb21fbGluZSgpICsNCiAgbGFicyh0aXRsZSA9ICJUb3AgMTAgbW9zdCBUaW1lLURlcGVuZGFudCBDcmltZXM6IENyaW1lIFJhdGUgVnMgVGltZSBpbiAyNCBob3VycyIsIHggPSAiVGltZSIsIHkgPSAiTm8uIG9mIENyaW1lcyIpICsNCiAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikpICsNCiAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygwLCA0LCA4LCAxMiwgMTYsIDIwKSkNCg0KDQpgYGANCllvdSBjYW4gc2VlIGZyb20gdGhlc2UgcGxvdHMgdGhhdCBjZXJ0YWluIGNyaW1lcyBhcmUgbW9yZSBsaWtlbHkgdG8gaGFwcGVuIGF0IGNlcnRhaW4gdGltZXMgb2YgdGhlIGRheS4gRG9tZXN0aWMgZGlzcHV0ZXMgYXJlIG1vc3QgbGlrZWx5IHRvIG9jY3VyIGluIHRoZSBldmVuaW5nLCBwZWFraW5nIGF0IDhwbS4gQ2FyIHRoZWZ0IGlzIG1vc3QgbGlrZWx5IHRvIGhhcHBlbiBpbiB0aGUgZXZlbmluZyBhcyB3ZWxsLCBoaWdoZXN0IGJldHdlZW4gNnBtIGFuZCA4cG0uIFNob3BsaWZ0aW5nIHVuc3VycHJpc2luZyBvY2N1cnMgZHVyaW5nIG1vc3Qgc2hvcCBvcGVuaW5nIGhvdXJzIGFuZCBwZWFrcyBiZXR3ZWVuIDNwbSBhbmQgNnBtLiBUaGUgZ3JhcGggZm9yIGZvcmdlcnkgaXMgaW50ZXJlc3RpbmcuIFRoZXJlIHNlZW1zIHRvIGJlIGEgdmVyeSBsYXJnZSBwZWFrIGF0IG1pZGRheS4gSXQgc2VlbXMgdW5saWtlbHkgdGhhdCBjcmltaW5hbHMgaGF2ZSBhIHByZWZlcmVuY2UgZm9yIGNhcnJ5aW5nIG91dCBmb3JnZXJ5IGF0IG1pZGRheS4gVGhpcyAtY291bGQtIGJlIGR1ZSB0byB0aGUgZmFjdCB0aGF0IGZvcmdlcnkgaXMgcmVwb3J0ZWQgYWZ0ZXIgdGhlIGFjdHVhbCBjcmltZSBpcyBjb21taXRlZCBhbmQgcGVvcGxlIGdlbmVyYWxseSBkb24ndCBrbm93IHdoZW4gaXQgd2FzIGNvbW1pdHRlZCBhbmQgdGhlcmVmb3JlIHRoZSB0aW1lIGlzIHJlY29yZGVkIGFzIGRlZmF1bHQgbWlkZGF5LiBTb21lIHF1YWxpdGF0aXZlIGFuYWx5c2lzL3F1ZXN0aW9ubmFpcmVzIHdvdWxkIHBlcmhhcHMgYmUgYWJsZSB0byBhbnN3ZXIgdGhpcyBxdWVzdGlvbi4gUXVpdGUgYSBmZXcgb2YgdGhlIG90aGVyIGNyaW1lcyBoYXZlIHBlYWtzIGF0IG1pZGRheSBhcyB3ZWxsLiANCg0KT25lIHdheSBvZiBwb3RlbnRpYWxseSBkaXNjb3ZlcmluZyB3aHkgaXMgdG8gbG9vayBiYWNrIGF0IHRoZSBvcmlnaW5hbCBkYXRhIGZvciB0aW1lLiBUaW1lIGRhdGEgaXMgZ2l2ZW4gaW4gSEg6TU0uIGkuZSAxMjozNSwgMTU6MTUuIElmIHRoZXJlIGlzIGEgZGVmYXVsdCBzZXR0aW5nIGZvciBtaWRkYXksIHRoYXQgd291bGQgbWVhbiB0aGF0IG1hbnkgb2YgdGhlIGNyaW1lcyB3b3VsZCBiZSBlbnRlcmVkIGFzIDEyOjAwIGluc3RlYWQgb2YsIHNheSAxMjoxMCwgMTI6NDAgDQoNClRyeSB0aGlzOiBmb3IgZWFjaCBob3VyLCBjb3VudCB0aGUgdG90YWwgbnVtYmVyIG9mIGVudGlyZXMgYW5kIGFsc28gY291bnQgdGhlIG51bWJlciBvZiBlbnRpcmVzIHdoaWNoIGFyZSBvZiB0aGUgZm9ybWF0IEhIOjAwLg0KYGBge3J9DQpwYXR0ZXJuID0gIjowMCINCg0KY3JpbWVfZGF0YV9taWRkYXkgPC0gY3JpbWVfZGF0YV9ob3Vyc18xICU+JQ0KICBtdXRhdGUobG9naWNfbWlkZGF5ID0gc3RyX2RldGVjdChjcmltZV9zdF90aW1lLCBwYXR0ZXJuKSkgJT4lDQogIGdyb3VwX2J5KGNyaW1lX2hvdXIsIGxvZ2ljX21pZGRheSkgJT4lDQogIHN1bW1hcmlzZShub18xMjAwID0gbigpKSAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGxvZ2ljX21pZGRheSwgdmFsdWVzX2Zyb20gPSBub18xMjAwKSAlPiUNCiAgbXV0YXRlKHBlcmNlbnRfMDAgPSBgVFJVRWAvYEZBTFNFYCoxMDApICU+JQ0KICBhcnJhbmdlKGRlc2MgPSAtcGVyY2VudF8wMCkNCg0KY3JpbWVfZGF0YV9taWRkYXkNCmBgYA0KSW50ZXJlc3RpbmdseSB0aGUgaGlnaGVzdCBwcm9wb3J0aW9uIG9mIGVudGlyZXMgZm9yIGV4YWN0bHkgb24gdGhlIGhvdXJzIGlzIGZvciAwMDowMCBpLmUuIG1pZG5pZ2h0LiBOZXh0IGlzIDEyOjAwIGFuZCB0aGVuIDA4OjAwLg0KDQpFdmVuIHRob3VnaCA5NSUgb2YgZW50cmllcyBmb3IgMDA6MDAtMDE6MDAgYXJlIHJlY29yZGVkIGFzIDAwOjAwIGV4YWN0bHksIGZyb20gbG9va2luZyBhdCB0aGUgZ3JhcGhzLCB0aGVyZSBkb2Vzbid0IHNlZW0gdG8gYmUgYW4gdW51c3VhbCBwZWFrLiBUaGlzIGNvdWxkIHN1Z2dlc3QgdGhhdCBwZW9wbGUgcmVjb3JkIGNyaW1lcyBhdCBleGFjdGx5IG1pZG5pZ2h0IGJ1dCB0aGV5IGxhcmdlbHkgZG8gb2NjdXIgYXJvdW5kIG1pZG5pZ2h0LiANCg0KRm9yIHRoZSBtaWRkYXkgZW50cmllcywgNzglIGFyZSByZWNvcmRlZCBhcyBleGFjdGx5IG1pZGRheSwgYnV0IHRoZXJlIHNlZW1zIHRvIGJlIGEgcGVhayBwdXJlbHkgZm9yIHRoaXMgaG91ciBvbiB0aGUgZ3JhcGhzLg0KDQpUaGlzIGRvZXMgc3VwcG9ydCB0aGUgdGhlb3J5IHRoYXQgdGhlc2UgZW50cmllcyBjb3VsZCBiZSBkdWUgdG8gZGVmYXVsdCB0aW1lIHNldHRpbmdzIGJ1dCBJJ2QgbmVlZCB0byBkbyBzb21lIHF1YWwgcmVzZWFyY2ggdG8gY2hlY2suIA0KDQpRNjogSG93IGhhdmUgY3JpbWVzIGNoYW5nZWQgb3ZlciB0aGUgeWVhcnM/IA0KRm9yIHRoaXMsIEkgd2FudCB0byBzZWUgaWYgYW55IGNyaW1lcyBoYXZlIGFueSBwYXJ0aWN1bGFyIHRyZW5kIGFjcm9zcyB0aGUgeWVhcnMgdGhhdCB0aGlzIGRhdGEgaGFzIGJlZW4gY29sbGVjdGVkLiBUaGUgZGF0YSBjb3ZlcnMgdGhlIHllYXJzIDIwMDkgLSAyMDE2LiBGaXJzdCwgSSdsbCBwbG90IHRoZSB0b3RhbCBjcmltZSB0cmVuZCBhY3Jvc3MgdGhlIHllYXJzLCB0aGVuIEknbGwgbG9vayBhdCBpbmRpdmlkdWFsIGNyaW1lcywgYW5kIGFnYWluIHBsb3QgdGhvc2UgY3JpbWVzIHdpdGggdGhlIGJpZ2dlc3QgdmFyaWFiaWxpdHkgaW4gZGF0YSBhY3Jvc3MgdGhlIHllYXJzLiANCg0KYGBge3J9DQojaGVhZChjcmltZV9kYXRhKQ0KDQpwYXR0ZXJuID0gIi9cXGQrLyhcXGQrKVxcYiINCg0KZGF0ZXMgPC0gY3JpbWVfZGF0YSRjcmltZV9zdF9kYXRlDQoNCiNoZWFkKHN0cl9tYXRjaChkYXRlcywgcGF0dGVybikpDQoNCnllYXJfY3JpbWVfZGF0YV8xIDwtIGNyaW1lX2RhdGEgJT4lDQogIG11dGF0ZShjcmltZV95ZWFyID0gc3RyX21hdGNoKGNyaW1lX3N0X2RhdGUsIHBhdHRlcm4pWywyXSkgJT4lDQogIG11dGF0ZShjcmltZV95ZWFyID0gc3RyX3N1YihjcmltZV95ZWFyLCAtMiwgLTEpKSANCg0KeWVhcl9jcmltZV9kYXRhIDwtIHllYXJfY3JpbWVfZGF0YV8xICU+JQ0KICBncm91cF9ieShjcmltZV95ZWFyKSAlPiUNCiAgc3VtbWFyaXNlKGNyaW1lc19wZXJfeWVhciA9IG4oKSkgDQoNCiNwcmludCh1bmlxdWUoeWVhcl9jcmltZV9kYXRhJGNyaW1lX3llYXIpKQ0KY29ycmVjdF95ZWFycyA8LSBjKCIwOSIsICIxMCIsICIxMSIsICIxMiIsICIxMyIsICIxNCIsICIxNSIsICIxNiIpDQoNCnllYXJfY3JpbWVfZGF0YSA8LSBzdWJzZXQoeWVhcl9jcmltZV9kYXRhLCBjcmltZV95ZWFyICVpbiUgY29ycmVjdF95ZWFycykNCg0KaGVhZCh5ZWFyX2NyaW1lX2RhdGEsNTApDQoNCiNwcmludChzdW0oeWVhcl9jcmltZV9kYXRhJGNyaW1lc19wZXJfeWVhcikpDQoNCnllYXJfY3JpbWVfZGF0YSA8LSB5ZWFyX2NyaW1lX2RhdGEgJT4lDQogIG11dGF0ZShjcmltZV95ZWFyID0gc3RyX3BhZChjcmltZV95ZWFyLCAzLCBzaWRlID0gImxlZnQiLCBwYWQgPSAiMCIpKSAlPiUNCiAgbXV0YXRlKGNyaW1lX3llYXIgPSBzdHJfcGFkKGNyaW1lX3llYXIsIDQsIHNpZGUgPSAibGVmdCIsIHBhZCA9ICIyIikpIA0KDQpnZ3Bsb3QoZGF0YSA9IHllYXJfY3JpbWVfZGF0YSwNCiAgICAgICBhZXMoeCA9IGFzLm51bWVyaWMoY3JpbWVfeWVhciksIHkgPSBjcmltZXNfcGVyX3llYXIpKSArDQogICAgICAgZ2VvbV9saW5lKCkgKw0KICAgICAgIGxhYnModGl0bGUgPSAiQ3JpbWVzIENvbW1pdHRlZCBQZXIgWWVhciBpbiBDYW1icmlkZ2UiLCB4ID0gIlllYXIiLCB5ID0gIk5vLiBvZiBDcmltZXMiKSArDQogICAgICAgdGhlbWUocGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIikpICsNCiAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygyMDA5LCAyMDEwLCAyMDExLCAyMDEyLCAyMDEzLCAyMDE0LCAyMDE1LCAyMDE2KSkNCg0KYGBgDQooTm90ZTogRnJvbSBncm91cGluZyBieSB5ZWFyIGFuZCBjb3VudGluZyB0aGUgbnVtYmVyIG9mIGNyaW1lcyB0aGF0IG9jY3VyIGluIGVhY2ggeWVhciwgSSBjYW4gc2VlIHRoYXQgdGhlcmUgYXJlIGEgZmV3ICdyb2d1ZScgeWVhcnMgaW4gdGhlcmUuLi4gSSB3YXMgZXhwZWN0aW5nIHRvIHNlZSAyMDA5LTIwMTYgYnV0IHNvbWV0aW1lcyB0aGUgeWVhcnMgYXJlIGVudGVyZWQgYXMgMjAwOSBhbmQgc29tZXRpbWVzIGFzIDA5LiBJIGNhbiBzb3J0IHRoaXMgYnkgc3Vic2V0dGluZyB0aGUgc3RyaW5nIGZvciBvbmx5IHRoZSBsYXN0IHR3byBkaWdpdHMuIEhvd2V2ZXIgdGhlIG90aGVyIHByb2JsZW0gaXMgdGhhdCB0aGVyZSBhcmUgeWVhcnMgdGhhdCBJIGRpZG4ndCBleHBlY3QgbGlrZSAxOTk5IGFuZCAwMS4gSG93ZXZlciB0aGUgbnVtYmVyIG9mIGVudHJpZXMgZm9yIHRoZXNlIHllYXJzIGlzIHZlcnkgc21hbGwgc28gSSd2ZSByZW1vdmVkIHRoZXNlIGVudHJpZXMgZnJvbSB0aGUgZGF0YS4gSSBzdGlsbCBoYXZlIDU1MTI3IGRhdGEgZW50cmllcy4pIA0KDQpGcm9tIHRoZSBwbG90IG9mIGNyaW1lcyBvdmVyIHRpbWUgaW4geWVhcnMsIGl0IGxvb2tzIGxpa2UgY3JpbWUgaGFzIG92ZXJhbGwgZGVjcmVhc2VkLCB3aXRoIGEgZGlwIGluIDIwMTMuIEhvd2V2ZXIgdGhlIGJpZyBkaXAgZm9yIDIwMTYgaXMgcHJvYmFibHkgdW5yZWFsaXN0aWMgYW5kIHN1Z2dlc3RzIHRoZSBkYXRhIGdyYWIgd2FzIHRha2VuIHBhcnQgd2F5IHRocm91Z2ggdGhlIHllYXIuIEkgY2FuIGNoZWNrIHRvIHNlZSBpZiB0aGUgZGF0YSBmb3IgMjAxNiBjb250YWlucyBhbGwgbW9udGhzLiANCg0KYGBge3J9DQpjaGVja18yMDE2IDwtIHN1YnNldCh5ZWFyX2NyaW1lX2RhdGFfMSwgY3JpbWVfeWVhciAlaW4lIGNvcnJlY3RfeWVhcnMpDQoNCmNoZWNrXzIwMTYgPC0gY2hlY2tfMjAxNiAlPiUNCiAgc2VsZWN0KGNyaW1lX3llYXIsIGNyaW1lX21vbnRoKSAlPiUNCiAgZmlsdGVyKGNyaW1lX3llYXIgPT0gMTYpICU+JQ0KICBncm91cF9ieShjcmltZV9tb250aCkgJT4lDQogIHN1bW1hcmlzZShub19wZXJfbW9udGggPSBuKCkpDQoNCmNvbG5hbWVzKGNoZWNrXzIwMTYpIDwtIGMoIk1vbnRoIGluIDIwMTYiLCAiTm8uIENyaW1lcyBwZXIgTW9udGgiKQ0KICANCmNoZWNrXzIwMTYNCiAgDQpgYGANClRoaXMgc2hvd3Mgd2hhdCB3YXMgZXhwZWN0ZWQgLSB0aGUgbW9udGhzIG9ubHkgZ28gdXAgdG8gMDkgaS5lLiBTZXB0ZW1iZXIuIFNvIHdlJ2QgZXhwZWN0IHRoZSBudW1iZXIgb2YgY3JpbWVzIHRvIGJlIH43NSUgb2YgdGhlIG90aGVyIHllYXJzLiANCg0KU2VlaW5nIGFzIHRoaXMgaXMgZ29pbmcgdG8gbWVzcyB1cCB0aGUgb3ZlcmFsbCB0cmVuZHMsIEkgYW0gZ29pbmcgdG8gZXhjbHVkZSB0aGUgeWVhciAyMDE2IGZyb20gdGhlIGFuYWx5c2lzLg0KDQpUaGUgbmV4dCB0YWJsZSBzaG93cyB0aGUgQ3JpbWUgYW5kIHRoZSBjb3JyZXNwb25kaW5nIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgeWVhcmx5IGluY2lkZW50cyBvZiBlYWNoIGNyaW1lLg0KYGBge3J9DQojeWVhcl9jcmltZV9kYXRhXzENCg0KY3JpbWVzX2J5X3llYXIgPC0geWVhcl9jcmltZV9kYXRhXzEgJT4lDQogIG11dGF0ZShjcmltZV95ZWFyID0gc3RyX3BhZChjcmltZV95ZWFyLCAzLCBzaWRlID0gImxlZnQiLCBwYWQgPSAiMCIpKSAlPiUNCiAgbXV0YXRlKGNyaW1lX3llYXIgPSBzdHJfcGFkKGNyaW1lX3llYXIsIDQsIHNpZGUgPSAibGVmdCIsIHBhZCA9ICIyIikpICU+JQ0KICBtdXRhdGUoY3JpbWVfeWVhciA9IGFzLm51bWVyaWMoY3JpbWVfeWVhcikpICU+JQ0KICBmaWx0ZXIoY3JpbWVfeWVhciA9PSAyMDA5OjIwMTUpICU+JQ0KICBncm91cF9ieShDcmltZSwgY3JpbWVfeWVhcikgJT4lDQogIHN1bW1hcmlzZShub19wZXJfeWVhciA9IG4oKSkgDQoNCiNjcmltZXNfYnlfeWVhcg0KDQp0b3AxMF9zZF95ZWFyX2RhdGEgPC0gY3JpbWVzX2J5X3llYXIgJT4lDQogIGdyb3VwX2J5KENyaW1lKSAlPiUNCiAgc3VtbWFyaXNlKHN0X2RldiA9IHNkKG5vX3Blcl95ZWFyKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhzdF9kZXYpKQ0KDQp0b3AxMCA8LSB0b3AxMF9zZF95ZWFyX2RhdGEkQ3JpbWVbMToxMF0NCg0KdG9wXzEwX2RmIDwtIHRvcDEwX3NkX3llYXJfZGF0YVsxOjEwLF0NCnRvcF8xMF9kZg0KDQpjcmltZXNfYnlfeWVhciA8LSBzdWJzZXQoY3JpbWVzX2J5X3llYXIsIENyaW1lICVpbiUgdG9wMTApDQoNCiNjcmltZXNfYnlfeWVhcg0KDQpnZ3Bsb3QoZGF0YSA9IGNyaW1lc19ieV95ZWFyLA0KICAgICAgIGFlcyh4ID0gY3JpbWVfeWVhciwgeSA9IG5vX3Blcl95ZWFyKSkgKw0KICAgICAgIGZhY2V0X3dyYXAofkNyaW1lLCBucm93ID0gMikgKw0KICAgICAgIGdlb21fbGluZSgpICsNCiAgICAgICBsYWJzKHRpdGxlID0gIkNyaW1lcyBDb21taXR0ZWQgUGVyIFllYXIgaW4gQ2FtYnJpZGdlIiwgeCA9ICJZZWFyIiwgeSA9ICJOby4gb2YgQ3JpbWVzIikgKw0KICAgICAgIHRoZW1lKHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpKQ0KDQogIA0KYGBgDQpBbHRob3VnaCB0aGVzZSBncmFwaHMgc2hvdyB0aGF0IHNvbWUgb2YgdGhlIGNyaW1lcyBhcmUgcXVpdGUgdmFyaWFibGUgeWVhciB0byB5ZWFyLCBtb3N0IG9mIHRoZW0gZG9uJ3Qgc2hvdyBhbiBvYnZpb3VzIGRvd253YXJkIG9yIHVwd2FyZCB0cmVuZC4gVGhlIG9ubHkgb25lIHdvcnRoIG5vdGluZyBoZXJlIGlzIExhcmNlbnkgZnJvbSBNViB3aGljaCBzZWVtcyB0byBiZSBkZWNyZWFzaW5nIGVhY2ggeWVhci4gDQoNCkFuZCBoZXJlIGVuZHMgbXkgYW5hbHlzaXMgb2YgQ2FtYnJpZGdlLCBNQSBDcmltZSBEYXRhISANCg0KDQoNCg0K