(Playing along at home? Download the .Rmd for a list of libraries you’ll need!)

0.1 Background

So, as you may or may not know, Uber and Lyft, two major ridesharing services, stopped offering rides in Austin, TX as of May 9, 2016 after a contentious public vote which you can read about here: http://www.bizjournals.com/austin/news/2016/05/07/uber-lyft-defeated-in-prop-1-referendum.html

A common argument is that the presence of ride-sharing services such as Uber or Lyft decreases the incidence of drunken driving in a city in which they operate; it sounds reasonable enough to say that if there are more options for getting home after drinking, at least one of them might be more attractive than driving home in a potentially compromised state.

There have been a few articles and a couple papers studying the availability of ridesharing services and drunk driving (see references below), but in my opinion they fall short in one or more ways:

  • They fail to count all available records of drunk driving (like if, say, a study only counted drunk driving fatalities)
  • They fail to account for trends in drunk driving frequency (like if, say, more people than average drove drunk on certain holidays), or aggregate time-series data too broadly
  • They fail to control for exogenous effects on drunk driving frequency (like if, say, the population of a core drinking demographic increased)
  • They fail to properly treat the regression discontinuity between data before and after ridesharing was available in Austin (more on this later)

I’ve managed to get a hold of three datasets that I think will be helpful:

  1. APD Incident Reports for 2008-2011, Jan-July 2015, Jan-July 2016 (including a number of intoxication-related crimes)
  2. TABC Mixed Beverage Tax Receipts for Austin, 2008-2016.
  3. APD Chief’s Monthly Reports, 2010-2016, with numbers of DWI and Narcotics arrests.

The APD (Austin Police Department) Incident Reports are publicly available for years 2008-2011, and for ‘Year to Date’ which supposedly includes the last 18 months of reported crime in Austin but actually only includes 8 months of 2016 and a small number of reports from 2015. I was able to obtain an archived version of the data from late 2015, which has more complete data for Jan-Jul 2015.

The APD Chief’s Monthly Report is a high-level summary of crime in Austin for the month, including counts for high-profile crimes including DWI. It has no time-of-day or location information, and no info other than just that a DWI occurred, but is another source of data to compare to the incident reports, which may be spotty. It additionally contains data on narcotics arrests, which we can check to see if we can use it as a control variable - narcotics crimes may follow the same broad trends as DWI, but are potentially unaffected by ridesharing.

It’s worth noting that the study of DWI arrest numbers as a proxy for the incidence of drunk driving is an open area of research - some studies prefer drunk driving crashes, although Austin has not released enough monthly statistics on drunk driving crashes to make it a useful for what I want to do. We’ll assume DWI arrests are a viable proxy for drunk driving here. For a more detailed treatment of this, see the appendix.

The TABC (Texas Alcoholic Beverage Commission) Mixed Beverage Tax is a fixed tax charged on alcoholic beverages sold by a holder of a Mixed Beverage License in the state of Texas. I suspect that Mixed Beverage Tax revenues are associated with Units of Alcohol Consumed in Austin, and we’ll check to see if any relationship exists between these tax revenues and DWI counts.

0.2 Dates of Interest

We’ll call June 4 and May 9 treatment dates - the inflection points we’ll investigate to see if the data on either side is substantially different. When dealing with monthly data we’ll have to say that June 2014 is the first month of the treatment and April 2016 is the last month.

You can find the same data I used at these sites:

Or you can pull it from my Github, http://www.github.com/ianwells/atx-dwi

Alright, Let’s get to it.

1 The Data

1.1 DWI Arrests

It’s always a good idea to just poke around in your data and see what’s going on. Here’s a quick glimpse of what the raw APD data looks like:

sample_n(dwi.raw,10)

Cool. We have a bunch of crimes, pre-filtered to intoxication-related ones and the time they approximately occurred. I’ve verified that time and location are unique for each crime (no double-bookings, although there are a few rare cases where two drunk drivers were arrested at the same time), so we can be confident that one incident report = one confirmed instance of drunk driving.

You can check this against the full list of crimes available to commit in Austin, which is available on that same Austin Data Portal site, I’m not including it here because it’s quite long, please trust that I’ve got all of them.

levels(dwi.raw$crime)
[1] "CRASH/INTOX MANSLAUGHTER"     "CRASH/INTOXICATION ASSAULT"  
[3] "DRIVING WHILE INTOX / FELONY" "DUI - AGE 17 TO 20"          
[5] "DWI"                          "DWI  .15 BAC OR ABOVE"       
[7] "DWI 2ND"                     
CRASH/INTOX MANSLAUGHTER

CRASH/INTOXICATION ASSAULT

DRIVING WHILE INTOX / FELONY

DUI - AGE 17 TO 20

DWI

DWI  .15 BAC OR ABOVE

DWI 2ND

If you’re familiar with this data set you’ll notice I’ve removed a few crimes:

  1. BOATING WHILE INTOXICATED - This rare crime doesn’t seem like it could be avoided by hailing an Uber.
  2. DWI - DRUG RECOGNITION EXPERT - You don’t have to have any alcohol in your system to be charged with a DWI: in this case, an officer certified in recognizing the effects of some other substance has decided you shouldn’t be driving. While I imagine you could avoid trouble by hailing a ride in this case, I don’t think I could relate it to bar sales, so this stat is going to be relegated to some other study.
  3. CRASH/LEAVING THE SCENE - This is a tricky one. Certainly a non-zero percentage of hit-and-run offenses are committed by drunk drivers, but this charge doesn’t offer any more details, and worse, there are more of this kind of crime than all the others put together. How should we count them, if at all? For now, let’s leave them all out, as they’re not mentioned specifically in the chief’s monthly report. We might be able to project how many of these crimes involve alcohol at a later date, based on when and where they occurred, but we’ll leave that for another analysis. See the appendix for further discussion.

Let’s take a look at the relative frequency of these offenses. Periodicity can be exploited later on.

qplot(hour(date), data=dwi.raw, geom="histogram", bins = 24)

Perhaps not surprisingly, nearly all DWI offenses occur between 8 PM and 5 AM.

qplot(wday(date), data=dwi.raw, geom="histogram", bins = 7)

Again, looks like Fridays and Saturdays are popular days to get caught drunk driving.

We’re going to look at the whole series, and then a histogram of monthly data to see if there’s a seasonal trend (you might expect more DWI’s to occur in December, January, or July months with holiday weekends that involve a lot of drinking)

Note: we have incomplete data for July 2015 and August 2016, as well as an old offense in 2014, so we’ll remove those months now. We’ll leave 2015 and 2016 out of the monthly histogram because we only have data from a few months for those years.

dwi.raw$year <- year(dwi.raw$date)
dwi.raw$month <- month(dwi.raw$date)
  
dwi.monthly <- dwi.raw %>% group_by(year,month)
dwi.monthly <- summarize(dwi.monthly,count=n())
dwi.monthly$date <- as.Date(paste0(dwi.monthly$year,'-',dwi.monthly$month,'-01'))

dwi.monthly <- dwi.monthly[-56,] #remove partial July 2015 data
dwi.monthly <- dwi.monthly[-63,] #remove partial August 2016 data
dwi.monthly <- dwi.monthly[-49,] #remove lone 2014 arrest

label.months <- c('J','F','M','A','M','J','J','A','S','O','N','D')

ggplot(data=dwi.monthly, aes(x = date, y = count, group = year(date), color = factor(year(date)))) + geom_point()

dummy <- filter(dwi.monthly,date < '2015-01-01') %>% group_by(month(date)) %>% summarize(count = sum(count)) %>% select(count) 
dummy1 <- mean(dummy$count) #1824
dummy2 <- sd(dummy$count) #99

ggplot(data = filter(dwi.monthly,date < '2015-01-01'), aes(factor(month(date)),weight = count) ) + geom_bar() + geom_hline(yintercept=1824, color = 'red') +
geom_hline(yintercept=1724, color = 'gray') +
geom_hline(yintercept=1924, color = 'gray')

So we can get a sense that, for the years 2008-2011, monthly DWI’s seem to be decreasing (good job APD), and as for a monthly trend we see an annual bump in December-January, something in March, as well as something going on in August-October, although all seem to be within one standard deviation of our monthly mean.

Now, I’m curious to see how the Chief’s Monthly Report compares.

apd.raw$date <- as.Date(apd.raw$date)
apd.raw$year <- year(apd.raw$date)
apd.raw$month <- month(apd.raw$date)

apd.monthly <- apd.raw
  
ggplot(data=apd.monthly, aes(x = date, y = count, color = factor(year))) + geom_point() 

dummy <- apd.monthly %>% group_by(month(date)) %>% summarize(count = sum(count)) %>% select(count) 
dummy1 <- mean(dummy$count) #3290
dummy2 <- sd(dummy$count) #145

ggplot(data = apd.monthly, aes(factor(month(date)),weight = count) ) + geom_bar() + geom_hline(yintercept=3290, color = 'red') +
geom_hline(yintercept=3145, color = 'gray') +
geom_hline(yintercept=3435, color = 'gray')

This has similar bumps, with a weaker September. Let’s plot both at the same time.

both.monthly <- merge(apd.monthly,dwi.monthly, by = 'date', all = TRUE);
both.monthly$apd <- both.monthly$count.x
both.monthly$dwi <- both.monthly$count.y

both.monthly <- both.monthly %>% select(date,apd,dwi)
both.melted <-melt(both.monthly, id.vars="date")

ggplot(data=both.melted, mapping = aes(x=date,y=value, color = variable)) + geom_point()

Okay, so it looks like the chief’s report is a little different than the incident report database. That’s annoying, but based on the disclaimers on both websites, and that the chief’s report is updated more often, I’m going to call it and say the chief’s data is what I’m using moving forward. I’d like those extra two years of data that the database has though - and since the data is so historic, and the difference is so consistent, what I’m going to do is nudge the data up slightly so that it lines up.

both.monthly$diff <- both.monthly$apd - both.monthly$dwi
mean(filter(both.monthly,date < '2012-01-01', date > '2010-01-01')$diff)
[1] 14.86957
both.monthly.nudge <- both.monthly
both.monthly.nudge$dwi = both.monthly.nudge$dwi + 15 #approximate mean difference

both.melted.nudge <-melt(both.monthly.nudge, id.vars="date")
ggplot(data=both.melted.nudge, mapping = aes(x=date,y=value, color = variable)) + geom_point()

Alright, that’s a little cleaner. We’ll move forward with this set of monthly data until I can get more comprehensive arrest records, being able to use weekly periodicity might be helpful.

1.2 Narcotics Arrests

The Chief’s Monthly Report lists all Part 1 Offenses (according to the Uniform Crime Reporting standards established by the FBI, mostly violent felonies) and a few key Part 2 Offenses, namely DWI, narcotics, prostitution, and weapons-law related crimes. Prostitution and weapons crimes occur sparsely compared to DWI and narcotics, so we’ll import the narcotics arrest data in hopes that it will allow us to control for sweeping effects across all crime categories - things like the number of officers working, motivation of the police force, population of the city, etc.

ggplot(data=apd.monthly, aes(x = date, y = narc, color = factor(year))) + geom_point() 

qplot(factor(month(date)), data=apd.monthly, geom="bar", weight = narc)

Not a lot to say here - there’s a strong January but not a lot else that lines up with the DWI data.

I’ve saved out our final data set here to save time.

dwi <- read.csv('data/dwi-final.csv')
#sapply(dwi,class)
dwi$date <- as.Date(dwi$date)
dwi$count <- as.numeric(as.character(dwi$count)) #cast strictly
dwi$narc <- as.numeric(as.character(dwi$narc))
dwi$treatment <- as.factor(dwi$treatment) #0: pre uber, 1:uber, 2:post uber

1.3 TABC Mixed Beverage Tax

Let’s have a look at what’s going on with the TABC data. Now, I’ve already done a bit of work with this data set in the past (see http://tabcmap.s3-website-us-east-1.amazonaws.com), so I’ve just pulled values from my database of monthly revenues calculated from monthly tax receipts.

Here’s what a few rows look like:

sample_n(tabc.raw,10)

Let’s do the same series and histogram plots to get a sense of what’s in there.

There’s a lone data point from 1999, let’s clean that up too, and let’s scale revenues into the millions of dollars.

tabc.monthly <- tabc.raw[-40,] #remove lone 1999 point

tabc.monthly$date <- as.Date(tabc.monthly$date)
tabc.monthly$year <- year(tabc.monthly$date)
tabc.monthly$month <- month(tabc.monthly$date)
tabc.monthly$rev <- round(tabc.monthly$rev/1000000,2)

ggplot(data=tabc.monthly, aes(x = date, y = rev, group = year, color = factor(year))) + geom_point()

qplot(factor(month(date)), data=tabc.monthly, geom="bar", weight = rev)

Look at that growth! Notice that spike in March? That’s probably SXSW, a major annual music, technology, and film conference. Saint Patrick’s day is in March, too. See that spike in October? I bet that’s Austin City Limits, a major music festival, and also Halloween. This data is already good to go, so let’s rename it to keep things clean and keep going.

tabc <- select(tabc.monthly,date,rev)

1.4 DWI per $MM

Let’s see about a new variable - DWI per Millions of Dollars Bar Revenue. I think that this variable may be useful as it incorporates things you would expect to vary with bar revenue - drinking-age population and popularity of drinking - into the DWI count. All things the same, a town with a lower DWI-per-drink-consumed number is going better than one with a higher ratio. We may be able to link ridesharing to an improvement in this ratio more convincingly than to just raw DWI’s.

dwi <- merge(dwi,tabc, by = 'date')

dwi$count_per_mm <- dwi$count/dwi$rev

ggplot(data=dwi, aes(x = date, y = count_per_mm, group = year(date), color = factor(year(date)))) + geom_point()

ggplot(data=dwi, aes(x = rev, y = count, color = year(date))) + geom_point() + geom_smooth(method = "lm")

summary(lm(data = dwi, count ~ rev))

Call:
lm(formula = count ~ rev, data = dwi)

Residuals:
     Min       1Q   Median       3Q      Max 
-124.302  -36.895    2.742   37.032  112.456 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 471.91537   21.21465  22.245   <2e-16 ***
rev           0.01024    0.47007   0.022    0.983    
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 51.7 on 105 degrees of freedom
Multiple R-squared:  4.519e-06, Adjusted R-squared:  -0.009519 
F-statistic: 0.0004745 on 1 and 105 DF,  p-value: 0.9827

So while DWI/$MM is decreasing over time, it definitely has periods where it’s still dominated by a rising DWI rate, and it would appear that there’s no direct correlation between DWI counts and bar revenue - which makes sense, as they’re both clearly non-stationary.

qplot(factor(month(date)), data=dwi, geom="bar", weight = count_per_mm)

This variable does however have a much more obvious yearly peak in January - we may be able to exploit this entangled variable more easily than just the raw DWI, if we can isolate the effect of ridesharing on TABC revenue (which we’ll talk about later).

2 The Analysis

Alright, so now that we’ve got some data, what can we do with it? How can we establish one way or the other that the advent of ridesharing affected the number of DWI arrests in Austin, or the number of DWI’s per dollar of alcohol sold? There are a few things I’m going to look at.

2.1 Regression Discontinuity

Typically, when you set out to prove something with science, you sit down and design an experiment. We don’t have the resources to do a city-scale double-blind ridesharing/drunk-driving experiment, so we’ll have to use the next best things: math and historical data.

Regression Discontinuity Design is a method of establishing causality without the benefit of experimental design. The key assumption is that, with regards to a time series, the data on either side of a treatment inflection are otherwise similar - nothing else special has happened. If you can get behind that, you could claim that if there’s a kink in your data, it’s because of the treatment you’re investigating.

Using this technique on time series data can be tricky, especially when you’re working with 8 years of data, because surely something else besides your treatment happened over that time frame. Let’s remind ourselves what the DWI count looks like:

ggplot(data = dwi, mapping = aes(x=date,y=count, color = factor(year(date)))) + geom_point()

You can probably see a lot of jumps in the data - from 2009-2011 there’s a rapid rise in DWI, followed by a swift drop and then a leap up again in 2013, and a gradual drop into 2016. We can’t honestly include all that data, so we’re going to limit things to about two years on either side of the first treatment (Uber and Lyft open for business in Austin), and the 8 months we have after the second treatment (Uber and Lyft cease operations).

First, we’ll plot regressions on either side of the treatment and see how they look - with just lm to start and then with a specialized library.

ggplot(data = filter(dwi,date > '2012-05-01'),mapping = aes(date, count, color = treatment) )+ geom_point() + geom_smooth(method = 'lm')

Visually, you might be tempted to get a sense of the effect of ridesharing over the period marked in green, but let’s keep going. We’re going to use the rddtools library and see if there is a statistically significant change in the regressions before and after each discontinuity, we’ll also compare rddtools to the output of lm .

dwi$index <- seq.int(nrow(dwi))

dwi.w <- filter(dwi, date < '2016-05-01', date > '2012-05-1')
dwi.rdd.w <- rddtools::rdd_data(y = dwi.w$count,x = dwi.w$index,cutpoint = 77)

dwi.wo <- filter(dwi, date < '2016-12-31', date > '2014-05-30')
dwi.rdd.wo <- rddtools::rdd_data(y = dwi.wo$count,x = dwi.wo$index,cutpoint = 100)

lm.w<-lm(count~I(index-77)*treatment,dwi.w) 
reg_para.w <- rdd_reg_lm(rdd_object = dwi.rdd.w, order = 1)

lm.wo<-lm(count~I(index-8)*treatment,dwi.wo) 
reg_para.wo <- rdd_reg_lm(rdd_object = dwi.rdd.wo, order = 1)


print(reg_para.w)
### RDD regression: parametric ###
    Polynomial order:  1 
    Slopes:  separate 
    Number of obs: 47 (left: 23, right: 24)

    Coefficient:
  Estimate Std. Error t value Pr(>|t|)
D  -6.3097    18.7822 -0.3359   0.7386
plot(reg_para.w)

#summary(lm.w) #for a sanity check

For the first treatment, RDD tells us (through the P-value of the regression, 0.7386) the that the drop is small enough relative to the variance in the data that any bump and change in the slope of the regression is too small to be attributed to anything other than randomness - at least when modeled with a straight line. We’ll consider that a straight line isn’t the best way to fit this data later on - remember we spent some time investigating periodic patterns.

It’s also worth noting that our primary assumption here - that everything is the same on either side of the treatment - might not hold, as the popularity and capacity of ridesharing probably grew over time. RDD may not be a rigorous way to inspect this side of the treatment.

print(reg_para.wo)
### RDD regression: parametric ###
    Polynomial order:  1 
    Slopes:  separate 
    Number of obs: 30 (left: 22, right: 8)

    Coefficient:
  Estimate Std. Error t value Pr(>|t|)   
D  -64.579     23.084 -2.7975 0.009565 **
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
plot(reg_para.wo)

#summary(lm.wo) #for a sanity check

For the second treatment, the jump in the regression is more pronounced and the slope changes wildly - our P values are low enough (< 1% chance that this result is due to randomness) to conclude that the change may be due to the discontinuity in May 2016 and not random chance. I think this might be a more valid case for RDD than the first side of the treatment - Uber and Lyft quite literally stopped offering ridesharing the Monday after the vote came down. This is a point in favor of ridesharing, but we’re not out of techniques yet.

2.2 Exponential Smoothing

Our regression discontinuity design fit 1st degree polynomials to the DWI data, but what if the behavior is more complicated than that? We observed earlier that there may be a periodic component to the data, what if ridesharing disrupts busy DWI months but not slower months, would a simple linear regression uncover that? As we mentioned, Uber and Lyft’s ridesharing capacity grew as they added drivers (certainly a metric I’d like to get my hands on), how can we investigate a higher-degree change in DWI?

Exponential Smoothing is a technique used in a whole class of methods for predicting future values in a time series based on manipulations of past values. Holt-Winters Forecasting is a method of predicting time-series data that has strong periodic components by separately smoothing long-term trend, short-term seasonality, and local components to create a forecast that takes into account predictable variations in the data. We saw above that our DWI data probably has some yearly trends in it - the data shows it a little, and you can Google around for articles about DWI in Austin and see for yourself that January is a special month for the police (look for ‘no-refusal weekend’). We also got a sense that a few years saw a continuous reduction in DWI arrests, perhaps as broad anti-DWI measures kicked in. We’ll decompose the DWI and DWI/$ really quick and you can see for yourself:

plot(stl(ts(dwi$count, start = c(2008, 1), frequency = 12), s.window="periodic"))

plot(stl(ts(dwi$count_per_mm, start = c(2008, 1), frequency = 12), s.window="periodic"))

You can see seasonality contributes to a swing of 70 DWI arrests, or 2.5 arrests per $MM. Additionally, you can see a highly smoothed trend for all the data over our entire time fame, and the remainder that this decomposition doesn’t think is attributable to a pattern.

2.2.1 Pre-Uber, and Validating Holt-Winters

What I’m going to do is feed DWI data from January 2008 - May 2014 (the last month before Uber and Lyft were widely available in Austin) into a Holt-Winters model (which will use this same stl seasonal decomposition) and forecast DWI counts for the next few months (we can roll the data back to 2008 again because we’re not concerned with local effects so much as trends inherent in DWI counts).

I’m then going to compare those to the actual data, with the reasoning that since the model takes into account yearly cycles and broad trends, it will come up with a prediction for DWI counts as if ridesharing never appeared. We can call the difference between the prediction and the real data the number of DWI’s ridesharing prevented - or maybe caused.

Let’s get confident in this method - first I’m going to take some untreated months and see if we can predict them reliably.

dwi.pre <- filter(dwi,date < '2013-10-31')
dwi.post <- filter(dwi,date > '2013-10-31')

dwi.pre.count.ts <- ts(dwi.pre$count, start = c(2008, 1), frequency = 12)
dwi.post.count.ts <- ts(dwi.post$count, start = c(2013, 6), frequency = 12)
#dwi.post.count.ts <- ts(dwi.post$count, start = c(2013, 11), frequency = 12) futher back forecast

dwi.pre.count.hw <- HoltWinters(dwi.pre.count.ts)

forecast <- predict(dwi.pre.count.hw, n.ahead = 6, prediction.interval = T, level = 0.9)

#acf((dwi.pre.count.hw$fitted - dwi.pre.count.ts)[,1]) #confirm no autocorrelations in residual
#hist((dwi.pre.count.hw$fitted - dwi.pre.count.ts)[,1],30) #confirm residual looks normal

plot(dwi.pre.count.hw, forecast); lines(dwi.post.count.ts,col='green')

effect <- forecast - dwi.post.count.ts

#ttest for 12month
#pre.residual <- as.numeric((dwi.pre.count.hw$fitted - dwi.pre.count.ts)[,1])
#post.residual <- as.numeric(effect)
#t.test(pre.residual,post.residual) #.59 too high

pct.effect <- cumsum(effect)/cumsum(forecast)
pct.effect[6]
[1] 0.0474804

What we’re looking at here is real data before our treatment (in black), and a fitted model with a forecast extending into our treatment (in red), with two 90% confidence intervals (these are called prediction intervals in this context, they’re in blue), and real treatment data (in green). We’ll plot all our Holt-Winters models like this.

Not bad. The model is a little rough - it fits it approximately but fails to catch all the peaks - the data may not have been periodic enough for this model to be effective, or there may be too much non-seasonal noise.

A failure to fully model the seasonality would have shown up as an autocorrelation or non-normality in the residuals - the difference between the model’s fit and the real data, over the set of data we used to train it. If you’re curious you can uncomment the acf and hist calls and see for yourself - otherwise trust me that I’ve verified that this model fully captures the seasonality available in the training set.

Using the data from January 2008 to October 2013, it looks like we can predict cumulative DWI’s for the next 6 months within 1.5%. That’s pretty close, and that should make us feel better about the numbers coming out, with the caveat that cumulative DWI predictions over longer time frames may be more accurate than picking individual months. (If you’re reading the commented-out bits of code, you’ll note that I also validated predictions 12 months out within 1%). Let’s move the end of the training data to May 2014 (the last month without Uber and Lyft) and see how things look (we’ll improve the model a little more by adding those extra 6 months to the training set as well).

dwi.pre <- filter(dwi,date < '2014-05-31')
dwi.post <- filter(dwi,date > '2014-05-31')

dwi.pre.count.ts <- ts(dwi.pre$count, start = c(2008, 1), frequency = 12)
dwi.post.count.ts <- ts(dwi.post$count, start = c(2014, 6), frequency = 12)

dwi.pre.count.hw <- HoltWinters(dwi.pre.count.ts)

forecast <- predict(dwi.pre.count.hw, n.ahead = 24, prediction.interval = T, level = 0.9)

#acf((dwi.pre.count.hw$fitted - dwi.pre.count.ts)[,1]) #confirm no autocorrelations in residual
#hist((dwi.pre.count.hw$fitted - dwi.pre.count.ts)[,1],30) #confirm residual looks normal

plot(dwi.pre.count.hw, forecast); lines(dwi.post.count.ts,col='green')

effect <- forecast - dwi.post.count.ts

pct.effect <- cumsum(effect)/cumsum(forecast)
pct.effect[12]
[1] 0.07247797
pct.effect[3]
[1] 0.01613347

For the first 12 months Uber and Lyft were available in Austin, the real cumulative DWI count was 440 arrests less than the predicted count - an effect of about 7% (over the whole 24-month period, we see 8%). For the first 3 months, where our error bars are much tighter (and perhaps while Uber and Lyft were still growing in capacity), we’re only 24 DWI’s less than predicted - a decrease of 1.6%.

Now you’re probably wondering - the real values are still well within these prediction bands, what does that mean? If our real data was a few points, it would mean we probably couldn’t count on it to tell us anything - it could be well within the model’s tolerance for random chance, and we wouldn’t be seeing a treatment effect, just a coincidence. But we have a lot of points, and all of them are below the forecast value - can we tell if these values are meaningfully different than the forecast?

We can. Since we’ve validated that our residuals are normally distributed, we can use a t-test to check if the fit-vs-training residuals are different from the forecast-vs-real residuals, which would tell us that the treatment effect we’re seeing is real, with some degree of confidence.

pre.residual <- as.numeric((dwi.pre.count.hw$fitted - dwi.pre.count.ts)[,1])
post.residual <- effect[,1]
t.test(pre.residual,post.residual)

    Welch Two Sample t-test

data:  pre.residual and post.residual
t = -4.4255, df = 44.764, p-value = 6.102e-05
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -69.96023 -26.19307
sample estimates:
mean of x mean of y 
-6.507904 41.568743 
#qplot(as.numeric(pre.residual), geom="density")
#qplot(as.numeric(post.residual), geom="density")

The p-value of 0.00006 tells us these results are significant. We’ll keep an eye on these behind the scenes.

We can try a potentially better-fitting model (really, optimized for a different criterion) from the exponential smoothing family of models with ets.

dwi.pre.count.ets <- ets(dwi.pre.count.ts, model = 'ZZZ')
forecast.ets <- predict(dwi.pre.count.ets, n.ahead = 24, prediction.interval = T, level = 0.9)

plot(forecast.ets); lines(dwi.post.count.ts,col='green')

effect.ets <- forecast.ets$mean - dwi.post.count.ts

#pre.residual <- as.numeric((dwi.pre.count.ets$fitted - dwi.pre.count.ets)[,1])
#post.residual <- as.numeric(effect.ets)
#t.test(pre.residual,post.residual) #e-7

pct.effect.ets <- cumsum(effect.ets)/cumsum(forecast.ets$mean)
pct.effect.ets[12]
[1] 0.08457409
pct.effect.ets[3]
[1] 0.05609513

This plot looks like our Holt-Winters plots, but omits the fitted curve before the treatment, and the forecast is in blue.

With much tighter prediction intervals, ets suggests a drop of 8.5% over 12 months (9.7 over the full 24) and 5.6% over 3 months.

I’d like to look at our DWI per Revenue variable, but first we have to answer, how much did ridesharing affect bar revenues? If it’s a lot, we’ll have a hard time attributing a change in DWI/$ to a change in DWI’s.

dwi.pre.rev.ts <- ts(dwi.pre$rev, start = c(2008, 1), frequency = 12)
dwi.post.rev.ts <- ts(dwi.post$rev, start = c(2014, 6), frequency = 12)

dwi.pre.rev.ets <- ets(dwi.pre.rev.ts, model = 'ZZZ')
forecast.ets <- predict(dwi.pre.rev.ets, n.ahead = 24, prediction.interval = T, level = 0.9)

plot(forecast.ets); lines(dwi.post.rev.ts,col='green')

effect.ets <- forecast.ets$mean - dwi.post.rev.ts

#pre.residual <- as.numeric((dwi.pre.rev.ets$fitted - dwi.pre.rev.ts))
#post.residual <- as.numeric(effect.ets)
#t.test(pre.residual,post.residual) #.001

pct.effect.ets <- cumsum(effect.ets)/cumsum(forecast.ets$mean)
pct.effect.ets[3]
[1] -0.02926871
pct.effect.ets[12]
[1] -0.03358013

Looks like we see a 3% rise in TABC sales due to ridesharing - which seems easy to reason around, if you don’t have to worry about driving you could be drinking more. I don’t want to spend too much time focusing on TABC sales and ridesharing, but I’ll mention that according to this, that’s an increase of about $68,000,000 in revenue to local businesses over 24 months, or roughly $9,500,000 in extra taxes.

dwi.pre.count_per_mm.ts <- ts(dwi.pre$count_per_mm, start = c(2008, 1), frequency = 12)
dwi.post.count_per_mm.ts <- ts(dwi.post$count_per_mm, start = c(2014, 6), frequency = 12)

dwi.pre.count_per_mm.ets <- ets(dwi.pre.count_per_mm.ts, model = 'ZZZ')
forecast.ets <- predict(dwi.pre.count_per_mm.ets, n.ahead = 24, prediction.interval = T, level = 0.9)

plot(forecast.ets); lines(dwi.post.count_per_mm.ts,col='green')

effect.ets <- forecast.ets$mean - dwi.post.count_per_mm.ts

#pre.residual <- as.numeric((dwi.pre.count_per_mm.ets$fitted - dwi.pre.count_per_mm.ts))
#post.residual <- as.numeric(effect.ets)
#t.test(pre.residual,post.residual) #.0007


pct.effect.ets <- cumsum(effect.ets)/cumsum(forecast.ets$mean)
pct.effect.ets[12]
[1] 0.1334951
pct.effect.ets[3]
[1] 0.1029293

ETS tells us a whopping 13% drop over 12 months (10% over 3, 17% over 24) in DWI/$MM is attributable to ridesharing - well beyond the change we saw from just the rise in $MM.

2.2.2 Post-Uber

Let’s try the other side - fit a model from data starting from Uber’s first month, and then stopping on Uber’s last month. If the prediction is lower than the real data, we might be able to say that ridesharing was having an effect, but there was some other factor contaminating the data from 2008-2014 (say an organized campaign against drunk driving or something).

We’re going to cheat a tiny bit because we need another sample of data (Holt-Winters requires 2 full years of data here) - so I’m going to say Uber actually opened for business a month earlier than it did. Hopefully the first month was relatively slow as people started adopting to ridesharing, and it won’t make much of a difference to stretch the effect out over one more month in addition the 23 months Uber and Lyft were in Austin.

dwi.during <- dwi %>% filter(date >= '2014-5-01') %>% filter(date < '2016-05-01')
dwi.exit <- filter(dwi,date >= '2016-05-01')

dwi.during.count.ts <- ts(dwi.during$count, start = c(2014, 5), frequency = 12)
dwi.exit.count.ts <- ts(dwi.exit$count, start = c(2016, 5), frequency = 12)

dwi.during.count.hw <- HoltWinters(dwi.during.count.ts)

forecast <- predict(dwi.during.count.hw, n.ahead = 12, prediction.interval = T, level = 0.9)
plot(dwi.during.count.hw, forecast); lines(dwi.exit.count.ts,col='green')

effect <- forecast - dwi.exit.count.ts

#pre.residual <- as.numeric((dwi.during.count.hw$fitted - dwi.during.count.ts))
#post.residual <- as.numeric(effect)
#t.test(pre.residual,post.residual) #e-9

pct.effect <- cumsum(effect)/cumsum(forecast)
pct.effect[7]
[1] -0.04835785
pct.effect[3]
[1] -0.06414393

This looks better - the model fits better (we’ll stick with this over ets), the confidence interval is tighter, and the treatment effect is 80 DWI’s over the first 3 months, a decrease of about 6%. In other words, not having Uber and Lyft may have resulted in an additional 80 arrests in the first 3 months. After 7 months (taking us to the end of our data), we observe a smaller 5% decrease - perhaps we can attribute this to the smaller ridesharing services (like Fare) that sprung up in Austin after Uber and Lyft stopped offering rides.

This gives us a number to associate with the qualitative change we saw with rdd earlier. Cool!

Let’s do the same with DWI/$MM:

dwi.during.rev.ts <- ts(dwi.during$rev, start = c(2014, 5), frequency = 12)
dwi.exit.rev.ts <- ts(dwi.exit$rev, start = c(2016, 5), frequency = 12)

dwi.during.rev.hw <- HoltWinters(dwi.during.rev.ts)

forecast <- predict(dwi.during.rev.hw, n.ahead = 12, prediction.interval = T, level = 0.9)
plot(dwi.during.rev.hw, forecast); lines(dwi.exit.rev.ts,col='green')

effect <- forecast - dwi.exit.rev.ts

#pre.residual <- as.numeric((dwi.during.rev.hw$fitted - dwi.during.rev.ts))
#post.residual <- as.numeric(effect)
#t.test(pre.residual,post.residual) #0.0004

pct.effect <- cumsum(effect)/cumsum(forecast)
pct.effect[7]
[1] 0.07915371
pct.effect[3]
[1] 0.06589074

Bad news for bars - Holt-Winters suggests that revenues were depressed by 6.5% over the first 3 months without Uber and Lyft. That’s $12,000,000 - and nearly $1,700,000 in lost tax revenue. It’s $34,000,000 over the whole 7 months we have data for.

dwi.during.count_per_mm.ts <- ts(dwi.during$count_per_mm, start = c(2014, 5), frequency = 12)
dwi.exit.count_per_mm.ts <- ts(dwi.exit$count_per_mm, start = c(2016, 5), frequency = 12)

dwi.during.count_per_mm.hw <- HoltWinters(dwi.during.count_per_mm.ts)

forecast <- predict(dwi.during.count_per_mm.hw, n.ahead = 12, prediction.interval = T, level = 0.9)
plot(dwi.during.count_per_mm.hw, forecast); lines(dwi.exit.count_per_mm.ts,col='green')

effect <- forecast - dwi.exit.count_per_mm.ts

#pre.residual <- as.numeric((dwi.during.count_per_mm.hw$fitted - dwi.during.count_per_mm.ts))
#post.residual <- as.numeric(effect)
#t.test(pre.residual,post.residual) #0.018 <- this one is a little high but still acceptable


pct.effect <- cumsum(effect)/cumsum(forecast)
pct.effect[7]
[1] -0.1268825
pct.effect[3]
[1] -0.1481808

14% higher DWI/$MM over the first 3 months without Uber, or 12% through 2016, again exceeding the effect of not having ridesharing on revenue alone.

We’ve got one more trick up our sleeves.

2.3 Bayesian Structural Time-Series

2.3.1 With Google CausalImpact

Google has a great library for testing the causal effect of a given treatment on a time series. Designed for testing the effectiveness of advertising, I think this library will help us out - it’s designed for inference on non-experimental data, which is what we’ve got.

For this, in contrast to regression discontinuity or exponential smoothing methods, we require a response and predictor - one thing that we think a treatment affected and one thing that we are confident it didn’t. Let’s use DWI count as a response, and TABC revenue as a control, as it appears TABC sales growth is less affected than DWI, per our experiments in the previous section, and also narcotic arrests, which we don’t think will be shifted at all.

We need a well-behaved stretch of data (we’re just studying our treatment, not other inflections) to use as a control - so let’s re-use the same cutoff we used for our regression discontinuity design (2012-05-01). Let’s plot it to see if it it looks like anything strange happened to our control data over our period of interest.

uber <- geom_rect(mapping = aes(xmin=as.Date('2014-06-01'), xmax = as.Date('2016-05-01')), ymin=-Inf, ymax=+Inf, color="grey20", alpha=0.3, inherit.aes = FALSE)

ggplot(data=melt(select(filter(dwi,date>="2012-04-01"),narc,count,rev,date),id = 'date'), mapping = aes(x=date, y=value, color = variable)) + uber + geom_point() + geom_smooth(method = 'loess', se = FALSE)

Not the best, but it’s what we’ve got. I’m especially concerned by the trend in TABC revenue and the little uptick in narcotics arrests in late 2016, and generally concerned about the jumpiness of the data. Major drug busts can change the availability of drugs in a city overnight, and could reduce the number of drug arrests in subsequent months. If CausalImpact doesn’t like it it should tell us, we’ll see how it goes.

(If you’re running this at home note that you’ll need the development version of devtools to install CausalImpact due to a bug in the CRAN version of devtools. Get it with devtools::install_github("hadley/devtools") )

2.3.2 TABC as a Control

dwi.ci <- select(filter(dwi,date>="2012-05-01"),date,count,rev)

pre.ci <- as.Date(c("2012-05-01", "2014-05-31"))
post.ci <- as.Date(c("2014-06-01", "2016-05-01"))

impact <- CausalImpact(dwi.ci, pre.ci, post.ci,  model.args = list(prior.level.sd = 0.1,nseasons = 12, season.duration = 1)) 
#i've turned up the sd since this data is more scattered than web traffic data
#notice we've set it to look for a trend with a period of one year

plot(impact)

impact
Posterior inference {CausalImpact}

                         Average        Cumulative    
Actual                   463            11114         
Prediction (s.d.)        507 (15)       12172 (355)   
95% CI                   [479, 539]     [11485, 12926]
                                                      
Absolute effect (s.d.)   -44 (15)       -1058 (355)   
95% CI                   [-75, -15]     [-1812, -371] 
                                                      
Relative effect (s.d.)   -8.7% (2.9%)   -8.7% (2.9%)  
95% CI                   [-15%, -3%]    [-15%, -3%]   

Posterior tail-area probability p:   0.002
Posterior prob. of a causal effect:  99.8%

For more details, type: summary(impact, "report")

CausalImpact attributes a 8.7% drop in DWI’s to ridesharing (with 99.9% certainty, it says), pretty close to what the last model said, but can we trust it? We validated Holt-Winters, let’s validate this as well.

Our control data might have trends and other unrelated treatments in it, or this model might not be as good at handling seasonality. If we give CasualImpact a ‘fake’ treatment date when we know nothing happened - say, in the end of 2013 - it shouldn’t report any change in DWI due to this made-up treatment.

pre.ci <- as.Date(c("2012-05-01", "2013-11-30"))
post.ci <- as.Date(c("2013-12-01", "2014-05-01"))

impact <- CausalImpact(dwi.ci, pre.ci, post.ci,  model.args = list( prior.level.sd = 0.1, nseasons = 12, season.duration = 1))

plot(impact)

impact
Posterior inference {CausalImpact}

                         Average        Cumulative  
Actual                   504            3022        
Prediction (s.d.)        516 (14)       3097 (82)   
95% CI                   [488, 544]     [2929, 3262]
                                                    
Absolute effect (s.d.)   -12 (14)       -75 (82)    
95% CI                   [-40, 16]      [-240, 93]  
                                                    
Relative effect (s.d.)   -2.4% (2.7%)   -2.4% (2.7%)
95% CI                   [-7.8%, 3%]    [-7.8%, 3%] 

Posterior tail-area probability p:   0.18
Posterior prob. of a causal effect:  82%

For more details, type: summary(impact, "report")

Alright, a 2.4% drop (80% sure, it’ll tell you if you check, which isn’t the best). That’s not a lot, but it’s more than the 0% we’d expect. We may not be able to use these results as they are, at least with TABC revenues as a control. The upward trend in revenues through our treatment period and the downward trend in DWI may be distorting the model and may always tell us there’s a drop in DWI arrests.

I’ll note here that other randomly-picked dates for the fake treatment might show different results - we’ve compensated for the higher-than-normal variance in our control data, but if you land on a peak CausalImpact can tell you there’s more of a drop - up to the scale of the real treatment, but with less probability of a causal effect - or no drop at all, or even a slight rise, all with low posterior probabilities. If you’re inclined, I encourage you to play around with it. I’ve picked this one because it’s close to a typical value for the pre-treated range - but a lack of a consistent result from this test should make us feel a little weird about how well suited our data is to this model.

2.3.3 Narcotics Arrests as a Control

Since we were worried TABC revenues are a bad control variable, let’s see if narcotics arrests are any better.

dwi.ci.n <- filter(select(dwi,date,count,narc),date >= '2012-05-01')

pre.ci <- as.Date(c("2012-05-01", "2014-05-31"))
post.ci <- as.Date(c("2014-06-01", "2016-05-09"))

impact.n <- CausalImpact(dwi.ci.n, pre.ci, post.ci,model.args = list(prior.level.sd = 0.1,nseasons = 12, season.duration = 1))
plot(impact.n)

impact.n
Posterior inference {CausalImpact}

                         Average         Cumulative     
Actual                   463             11114          
Prediction (s.d.)        498 (14)        11964 (334)    
95% CI                   [471, 527]      [11314, 12644] 
                                                        
Absolute effect (s.d.)   -35 (14)        -850 (334)     
95% CI                   [-64, -8.3]     [-1530, -200.3]
                                                        
Relative effect (s.d.)   -7.1% (2.8%)    -7.1% (2.8%)   
95% CI                   [-13%, -1.7%]   [-13%, -1.7%]  

Posterior tail-area probability p:   0.005
Posterior prob. of a causal effect:  99.5%

For more details, type: summary(impact, "report")

Using narcotics arrests as a control, ridesharing can account for a 7% drop in DWI arrests, with about the same certainty. Alright, that’s almost the difference we saw earlier - let’s double check on a fake treatment date:

pre.ci <- as.Date(c("2012-05-01", "2013-11-30"))
post.ci <- as.Date(c("2013-12-01", "2014-05-01"))

impact.n <- CausalImpact(dwi.ci.n, pre.ci, post.ci,model.args = list(prior.level.sd = 0.1, nseasons = 12, season.duration = 1))
plot(impact.n)

impact.n
Posterior inference {CausalImpact}

                         Average         Cumulative   
Actual                   504             3022         
Prediction (s.d.)        520 (14)        3118 (85)    
95% CI                   [493, 548]      [2956, 3286] 
                                                      
Absolute effect (s.d.)   -16 (14)        -96 (85)     
95% CI                   [-44, 11]       [-264, 66]   
                                                      
Relative effect (s.d.)   -3.1% (2.7%)    -3.1% (2.7%) 
95% CI                   [-8.5%, 2.1%]   [-8.5%, 2.1%]

Posterior tail-area probability p:   0.136
Posterior prob. of a causal effect:  86%

For more details, type: summary(impact, "report")

Less impact (-3%). 87% sure though - which most statisticians will throw out. This control looks like it’s better, but I’m not super into it. What else could we do?

2.3.4 Both

dwi.ci.b <- filter(select(dwi,date,count,rev,narc),date >= '2012-05-01')

pre.ci <- as.Date(c("2012-05-01", "2014-05-31"))
post.ci <- as.Date(c("2014-06-01", "2016-05-09"))

impact.b <- CausalImpact(dwi.ci.b, pre.ci, post.ci,model.args = list(prior.level.sd = 0.1,nseasons = 12, season.duration = 1))
plot(impact.b)

impact.b
Posterior inference {CausalImpact}

                         Average        Cumulative    
Actual                   463            11114         
Prediction (s.d.)        504 (16)       12103 (377)   
95% CI                   [473, 535]     [11361, 12833]
                                                      
Absolute effect (s.d.)   -41 (16)       -989 (377)    
95% CI                   [-72, -10]     [-1719, -247] 
                                                      
Relative effect (s.d.)   -8.2% (3.1%)   -8.2% (3.1%)  
95% CI                   [-14%, -2%]    [-14%, -2%]   

Posterior tail-area probability p:   0.005
Posterior prob. of a causal effect:  99.5%

For more details, type: summary(impact, "report")

A 8.2% effect. Some validation:

pre.ci <- as.Date(c("2012-05-01", "2013-11-30"))
post.ci <- as.Date(c("2013-12-01", "2014-05-01"))

impact.b <- CausalImpact(dwi.ci.b, pre.ci, post.ci,model.args = list(prior.level.sd = 0.1,nseasons = 12, season.duration = 1))
plot(impact.b)

impact.b
Posterior inference {CausalImpact}

                         Average         Cumulative   
Actual                   504             3022         
Prediction (s.d.)        521 (15)        3126 (87)    
95% CI                   [491, 549]      [2948, 3295] 
                                                      
Absolute effect (s.d.)   -17 (15)        -104 (87)    
95% CI                   [-46, 12]       [-273, 74]   
                                                      
Relative effect (s.d.)   -3.3% (2.8%)    -3.3% (2.8%) 
95% CI                   [-8.7%, 2.4%]   [-8.7%, 2.4%]

Posterior tail-area probability p:   0.112
Posterior prob. of a causal effect:  89%

For more details, type: summary(impact, "report")

A 3.3% effect at 88%. We’re getting semi-workable results - the real inflection date with controls just about matches our exponential smoothing models, and we can sort of discount the fake inflection we’re testing with, but not very confidently. We could mess around with a custom multi-seasonal BSTS model and feed it to CausalImpact, I’ll call that an area for future testing.

We’ll have to revisit this model if we get more data.

3 Conclusions

Our conclusions were a bit mixed, but promising. Investigating with RDD suggested that there might be an intervention effect due to Uber and Lyft ceasing ridesharing in Austin, and exponential smoothing techniques suggested measurable drops in DWI counts and DWI counts per MM bar revenue due to the introduction of ridesharing (as well as a small uptick in bar revenue), as well as a subsequent increase in DWI counts and DWI per MM after Uber and Lyft stopped offering rides, once you took into account broad trends and periodic cycles in both data sets.

CausalImpact analysis didn’t work out to be something we could use - both TABC revenue and narcotics arrests data weren’t suitable controls. They did sort of corroborate the results from the other models, though.

Taking into account our results, the models suggest attributing about a 8% drop in DWI arrests in Austin from June 2014 - May 2016 to ridesharing, and about a 5% increase in DWI arrest from May 2016 - December 2016 to an abrupt cessation of Uber and Lyft’s ridesharing services. An 8% drop in DWI over the two years Uber and Lyft were offering ridesharing services accounts for nearly 1000 DWI’s.

Similarly, our new DWI/TABC Mixed Beverage Revenue (Millions) metric is decreased by about 17% by ridesharing, and increased by about 14% without it.

As a little bonus, modelling just bar sales showed that Austin bar revenues may have been improved by as much as $68,000,000 due to the availablity ridesharing over two years, adding to the TABC’s tax coffers by nearly $9,500,000 over that time. Without Uber and Lyft, bars may have seen as much as a $34,000,000 depression in sales over 7 months, shorting the TABC $4,700,000 in taxes. We didn’t study this as much as DWI’s, though, and unobserved interventions could account for some of these amounts without changing our conclusions about DWI counts directly.

4 Future Work and Caveats

With more fine-grained time series data, or some certified-extra-accurate data from the APD, I think we could improve on this analysis. My original thoughts were to see if ridesharing had a more specific effect on certain kinds of DWI’s - say specifically 1st offenses - and in certain places, but the data was not complete enough for that. Additionally, Austin’s crime data in general may be unreliable (that’s certainly a caveat - see http://www.mystatesman.com/news/local/why-the-austin-police-department-dwi-crash-statistics-keep-changing/GNv8LTrbEgTd7KEObnPwgL/), although we did compare two sources for crime data. Updated data from after the treatment period could alter the models’ results substantially. I would love to get something like number of rideshare rides taken per month, too.

If you’ve got some comments or suggestions regarding this work, contact me! Pull the data and models down and mix them up yourself if you’d like, I’d love to see any new results or conflicting conclusions.

5 Appendix

5.1 DWI Arrests as a Proxy for Drunk Driving

We could be concerned that, rather than being a reasonable proxy for drunk driving, the number of DWI arrests could be constrained by the resources available to the APD - what if drunk driving is out of control, and the APD has hit some sort of arrest ceiling? If this was the case, we would expect to see an unchanging average amount of monthly arrests with some noise, possibly varying with the size of the police force at their maximum capacity for making DWI arrests.

After some quick Googling, we have a few sworn-officer counts for the APD: about 1200 in 2002, 1600 in 2010, and 1800 in 2016, so we can say that the police force is growing. Reading up on the APD also indicates that the number of officers familiar with handling a DWI arrest increased over that time frame as well. Let’s remind ourselves what the DWI incident count looks like:

ggplot(data = dwi, aes(x=date,y=count)) + geom_point() + geom_smooth(method = 'loess')

Even as the APD grows, the amount of arrests varies wildly (a range of nearly 200 arrests per month), in addition to holding several increasing and decreasing trend periods we already studied. From this, I think it’s safe to say that the number of arrests does track drunk driving without saturation.

5.2 Crash/Leaving The Scene

We can assume, I think, that some nonzero percentage of hit-and-run incidents, especially those happening during peak drunk driving hours, involve a drunk driver who was not caught and charged with a DWI. If this number is high enough, and/or fluctuating enough, it could cast doubt on the validity of DWI arrests as a proxy for drunk driving by suggesting that the arrest count is meaninglessly small and invariant with respect to some actual massive population of drunk drivers.

Additionally, if we can confidently extract a portion of these incidents and label them as probable drunk-driving incidents, and this portion is significantly large and not in line with larger trends across our treatment area, it may change the output of our models if we include it. This second one is a stretch and relies on another big assumption (that we can identify a drunk driving hit-and-run), but let’s take a crack at it.

har.raw <- read.csv('data/hitandrun-raw.csv')
har.raw$hour <- substr(har.raw$date,12,13)
#har.raw$longdate <- parse_date_time(har.raw$date,'%Y-%m-%d %H:%M:%S',tz ='America/Chicago')
har.raw$date <- as.Date(har.raw$date)

#qplot(hour(longdate), data=har.raw, geom="histogram", bins = 24)
#qplot(wday(longdate), data=har.raw, geom="histogram", bins = 24)

har.raw$year <- year(har.raw$date)
har.raw$month <- month(har.raw$date)

har.monthly <- har.raw %>% group_by(year,month)
har <- summarize(har.monthly,count=n())
har$date <- as.Date(paste0(har$year,'-',har$month,'-01'))

har <- filter(har,count > 50) #remove a few months outside of the 1-6/2015 and 1-7/2016 range without complete data
har <- har[-63,] 
har <- har[-87,] 

qplot(x=date,y=count,data = har)

There are a lot of incidents here, but not enough to totally swamp the data, so our first concern is ruled out, I think. I’m a little concerned about the jump in hit and runs in the later part of the data though, even though it’s noisy and the incident report is known to disagree with the chief’s report towards the end of the time frame - let’s take a stab at picking the incidents most likely to be alcohol related, by filtering just the ones that occur when DWI’s are most likely to be reported.

har.raw <- filter(filter(har.raw, hour > 19),hour < 6) #only hit-and-runs during prime drinking and driving hours

har.monthly <- har.raw %>% group_by(year,month)
har <- summarize(har.monthly,count=n())
har$date <- as.Date(paste0(har$year,'-',har$month,'-01'))

har <- filter(har,count > 50) #remove a few months outside of the 1-6/2015 and 1-7/2016 range without
har <- har[-63,] 
har <- har[-87,] 

qplot(x=date,y=count,data = har)

#ggplot(data = filter(dwi.monthly,date < '2015-01-01'), aes(factor(month(date)),weight = count) ) + geom_bar()

ggplot(data = filter(har,date < '2015-01-01'), aes(factor(month(date)),weight = count) ) + geom_bar()

That brings the mean down considerably and levels out the trend - although the histogram doesn’t match our incident report DWI histogram.

If we were to further sample this data for likely drunk driving hit-and-runs, we’d have to weight it to match the DWI histogram, and then apply some flat ‘this many hit-and-runs in prime hit-and-run timeframes involve alcohol’ percentage. I don’t have a number for that, we’ll just call it 20%.

filter<-data.frame(month=c(1,2,3,4,5,6,7,8,9,10,11,12),trim=c(1,.70,.7,.60,.64,.56,.58,.62,.76,.72,.73,.81))

har <- merge(har,filter,id ='month')
har$count <- har$count * har$trim
ggplot(data = filter(har,date < '2015-01-01'), aes(factor(month(date)),weight = count) ) + geom_bar()

har$trim <- NULL

har$count = har$count * .20

qplot(x=date,y=count,data = har)

And it’s less than or about the same as the difference between the APD Incident Report and the Chief’s Monthly Report. Maybe a more official estimate of hit-and-run drunk driving may have made it into the Chief’s report, accounting for the discrepancy.

For the range 2008-2012, the difference is small, in line with the prevailing decreasing trend, and as it contributes only to seasonal models I’m comfortable discounting it entirely. For the months in 2015 and 2016, I’m not sure what to do with it - I don’t think it’s a good idea to add it to the Chief’s report, and if it only makes up the difference between the APD Incident Report and the Chief’s report, and since I don’t even have it for the rest of the time frame - I think it’s safe to ignore it and if more accurate data presents itself, test our conclusions again.

5.3 Downtown and All Other Arrest Data

Late in the development of this writeup I noticed that the Chief’s Monthly Report was broken into broad geographic sections, and also considered that the ‘all other Part 2 crimes’ count available on the report would be a better control than narcotics arrests, as it might have a lower variance, and be a better representation of ‘background’ crime. I’ll quickly look at some of this data.

bonus <- read.csv('data/other.csv')
head(bonus)
bonus$date <- as.Date(bonus$date)
bonus$dt.count <- as.numeric(as.character(bonus$dt.count)) #cast strictly
bonus$count <- as.numeric(as.character(bonus$count)) 
bonus$other <- as.numeric(as.character(bonus$other)) 

ggplot(data = bonus, aes(factor(month(date)),weight = dt.count) ) + geom_bar()

ggplot(data = bonus, aes(y=dt.count,x=date)) + geom_point()

ggplot(data = bonus, aes(y=dt.count/count,x=date)) + geom_point()

bonus.pre <- filter(bonus,date < '2014-05-31')
bonus.post <- filter(bonus,date > '2014-05-31')

bonus.pre.ts <- ts(bonus.pre$dt.count, start = c(2010, 1), frequency = 12)
bonus.post.ts <- ts(bonus.post$dt.count, start = c(2014, 6), frequency = 12)

bonus.hw <- HoltWinters(bonus.pre.ts)
forecast <- predict(bonus.hw, n.ahead = 24, prediction.interval = T, level = 0.9)

plot(bonus.hw,forecast); lines(bonus.post.ts,col='green')

effect <- forecast - bonus.post.ts

#pre.residual <- as.numeric((bonus.hw$fitted - bonus.pre.ts))
#post.residual <- as.numeric(effect)
#t.test(pre.residual,post.residual) #e-16

pct.effect <- cumsum(effect)/cumsum(forecast)
pct.effect[24]
[1] 0.1412853

Cool. Some seasonality, a plot that looks like a scaled version of the full DWI plot, and a sense that downtown DWI’s generally account for 10-14% of all DWI’s in Austin.

A quick glance at just the downtown data suggests that ridesharing had the effect of lowering DWI counts downtown by 14% over 24 months (9% over 12.)

ggplot(data = bonus, aes(y=other,x=date)) + geom_point() + geom_smooth()
`geom_smooth()` using method = 'loess'

ggplot(data = bonus, aes(factor(month(date)),weight = other) ) + geom_bar()

bonus.b <- filter(select(bonus,date,count,other),date >= '2012-05-01')

pre.ci <- as.Date(c("2012-05-01", "2014-05-31"))
post.ci <- as.Date(c("2014-06-01", "2016-05-09"))

impact.b <- CausalImpact(bonus.b, pre.ci, post.ci,model.args = list(prior.level.sd = 0.1,nseasons = 12, season.duration = 1))
plot(impact.b)

impact.b
Posterior inference {CausalImpact}

                         Average         Cumulative     
Actual                   463             11114          
Prediction (s.d.)        496 (13)        11900 (316)    
95% CI                   [471, 522]      [11295, 12534] 
                                                        
Absolute effect (s.d.)   -33 (13)        -786 (316)     
95% CI                   [-59, -7.5]     [-1420, -180.9]
                                                        
Relative effect (s.d.)   -6.6% (2.7%)    -6.6% (2.7%)   
95% CI                   [-12%, -1.5%]   [-12%, -1.5%]  

Posterior tail-area probability p:   0.005
Posterior prob. of a causal effect:  99.5%

For more details, type: summary(impact, "report")
pre.ci <- as.Date(c("2012-05-01", "2013-11-30"))
post.ci <- as.Date(c("2013-12-01", "2014-05-01"))

impact.b <- CausalImpact(bonus.b, pre.ci, post.ci,model.args = list(prior.level.sd = 0.1,nseasons = 12, season.duration = 1))
plot(impact.b)

impact.b
Posterior inference {CausalImpact}

                         Average         Cumulative   
Actual                   504             3022         
Prediction (s.d.)        491 (17)        2943 (101)   
95% CI                   [456, 522]      [2737, 3130] 
                                                      
Absolute effect (s.d.)   13 (17)         79 (101)     
95% CI                   [-18, 47]       [-108, 285]  
                                                      
Relative effect (s.d.)   2.7% (3.4%)     2.7% (3.4%)  
95% CI                   [-3.7%, 9.7%]   [-3.7%, 9.7%]

Posterior tail-area probability p:   0.205
Posterior prob. of a causal effect:  80%

For more details, type: summary(impact, "report")

Other Part 2 crimes seem to be on the decline, although there looks like there might be an inflection in late 2013 - early 2014. We see a little seasonality, possibly consistent with studies that have shown a link between warm weather and crime. CausalImpact tells us that we see about a 6% drop in DWI, and it validates much better than our other controls for our selected fake intervention date, but not much better for other dates. I’ll leave it here for future research.

6 References

Deterring Drunk Driving Fatalities: An Economics of Crime Perspective Bruce L. Benson and David W. Rasmussen

Inferring Causal Impact Using Bayesian Structural Time-series Models Kay H. Brodersen, Fabian Gallusser, Jim Koehler, Nicolas Remy, Steven L. Scott

Regression Discontinuity Designs in Economics David S. Lee and Thomas Lemieux

Program Description: APD DWI Enforcement https://one.nhtsa.gov/people/injury/research/AustinPoliceDWI/pages/ProgDesc.html

7 Acknowledgements

This work would have been much worse without the intensely appreciated input of its peer reviewers, who know who they are :)

8 Disclaimers

8.1 APD

The Austin Police Department does not assume any liability for any decision made or action taken or not taken by the recipient in reliance upon any information or data provided.

8.2 TABC

The Comptroller of Public Accounts cannot vouch for the data or analysis derived from data after it has been retrieved from the Comptroller’s Web site.

Some numbers in the R may vary slightly from the numbers in the text, as some models are rolled at render-time and may involve some randomness.

9 License

The MIT License (MIT)

Copyright (c) 2017 Ian Wells

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

LS0tCnRpdGxlOiAiTWVzc2luZyBBcm91bmQgd2l0aCBEV0kgQXJyZXN0cywgVEFCQyBNaXhlZCBCZXZlcmFnZSBUYXhlcywgYW5kIFJpZGVzaGFyaW5nLCBpbiBBdXN0aW4sIFRYIgphdXRob3I6ICJJYW4gV2VsbHMgKEBpYW53ZWxscykiCmRhdGU6ICIyMDE3LTAxLTI2IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIG1hdGhqYXg6IG51bGwKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0aGVtZTogc3BhY2VsYWIKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwotLS0KCihQbGF5aW5nIGFsb25nIGF0IGhvbWU/ICBEb3dubG9hZCB0aGUgLlJtZCBmb3IgYSBsaXN0IG9mIGxpYnJhcmllcyB5b3UnbGwgbmVlZCEpCgpgYGB7ciBpbmNsdWRlID0gRkFMU0V9ICAgIApsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHJlc2hhcGUpCmxpYnJhcnkoQ2F1c2FsSW1wYWN0KQpsaWJyYXJ5KHJkZHRvb2xzKQpsaWJyYXJ5KGZvcmVjYXN0KQpzZWxlY3QgPC0gZHBseXI6OnNlbGVjdAoKYGBgCgojI0JhY2tncm91bmQKClNvLCBhcyB5b3UgbWF5IG9yIG1heSBub3Qga25vdywgVWJlciBhbmQgTHlmdCwgdHdvIG1ham9yIHJpZGVzaGFyaW5nIHNlcnZpY2VzLCBzdG9wcGVkIG9mZmVyaW5nIHJpZGVzIGluIEF1c3RpbiwgVFggYXMgb2YgTWF5IDksIDIwMTYgYWZ0ZXIgYSBjb250ZW50aW91cyBwdWJsaWMgdm90ZSB3aGljaCB5b3UgY2FuIHJlYWQgYWJvdXQgaGVyZTogaHR0cDovL3d3dy5iaXpqb3VybmFscy5jb20vYXVzdGluL25ld3MvMjAxNi8wNS8wNy91YmVyLWx5ZnQtZGVmZWF0ZWQtaW4tcHJvcC0xLXJlZmVyZW5kdW0uaHRtbAoKQSBjb21tb24gYXJndW1lbnQgaXMgdGhhdCB0aGUgcHJlc2VuY2Ugb2YgcmlkZS1zaGFyaW5nIHNlcnZpY2VzIHN1Y2ggYXMgVWJlciBvciBMeWZ0IGRlY3JlYXNlcyB0aGUgaW5jaWRlbmNlIG9mIGRydW5rZW4gZHJpdmluZyBpbiBhIGNpdHkgaW4gd2hpY2ggdGhleSBvcGVyYXRlOyBpdCBzb3VuZHMgcmVhc29uYWJsZSBlbm91Z2ggdG8gc2F5IHRoYXQgaWYgdGhlcmUgYXJlIG1vcmUgb3B0aW9ucyBmb3IgZ2V0dGluZyBob21lIGFmdGVyIGRyaW5raW5nLCBhdCBsZWFzdCBvbmUgb2YgdGhlbSBtaWdodCBiZSBtb3JlIGF0dHJhY3RpdmUgdGhhbiBkcml2aW5nIGhvbWUgaW4gYSBwb3RlbnRpYWxseSBjb21wcm9taXNlZCBzdGF0ZS4KClRoZXJlIGhhdmUgYmVlbiBhIGZldyBhcnRpY2xlcyBhbmQgYSBjb3VwbGUgcGFwZXJzIHN0dWR5aW5nIHRoZSBhdmFpbGFiaWxpdHkgb2YgcmlkZXNoYXJpbmcgc2VydmljZXMgYW5kIGRydW5rIGRyaXZpbmcgKHNlZSByZWZlcmVuY2VzIGJlbG93KSwgYnV0IGluIG15IG9waW5pb24gdGhleSBmYWxsIHNob3J0IGluIG9uZSBvciBtb3JlIHdheXM6CgoqIFRoZXkgZmFpbCB0byBjb3VudCBhbGwgYXZhaWxhYmxlIHJlY29yZHMgb2YgZHJ1bmsgZHJpdmluZyAobGlrZSBpZiwgc2F5LCBhIHN0dWR5IG9ubHkgY291bnRlZCBkcnVuayBkcml2aW5nIGZhdGFsaXRpZXMpCiogVGhleSBmYWlsIHRvIGFjY291bnQgZm9yIHRyZW5kcyBpbiBkcnVuayBkcml2aW5nIGZyZXF1ZW5jeSAobGlrZSBpZiwgc2F5LCBtb3JlIHBlb3BsZSB0aGFuIGF2ZXJhZ2UgZHJvdmUgZHJ1bmsgb24gY2VydGFpbiBob2xpZGF5cyksIG9yIGFnZ3JlZ2F0ZSB0aW1lLXNlcmllcyBkYXRhIHRvbyBicm9hZGx5CiogVGhleSBmYWlsIHRvIGNvbnRyb2wgZm9yIGV4b2dlbm91cyBlZmZlY3RzIG9uIGRydW5rIGRyaXZpbmcgZnJlcXVlbmN5IChsaWtlIGlmLCBzYXksIHRoZSBwb3B1bGF0aW9uIG9mIGEgY29yZSBkcmlua2luZyBkZW1vZ3JhcGhpYyBpbmNyZWFzZWQpCiogVGhleSBmYWlsIHRvIHByb3Blcmx5IHRyZWF0IHRoZSByZWdyZXNzaW9uIGRpc2NvbnRpbnVpdHkgYmV0d2VlbiBkYXRhIGJlZm9yZSBhbmQgYWZ0ZXIgcmlkZXNoYXJpbmcgd2FzIGF2YWlsYWJsZSBpbiBBdXN0aW4gKG1vcmUgb24gdGhpcyBsYXRlcikKCkkndmUgbWFuYWdlZCB0byBnZXQgYSBob2xkIG9mIHRocmVlIGRhdGFzZXRzIHRoYXQgSSB0aGluayB3aWxsIGJlIGhlbHBmdWw6CiAgCjEuIEFQRCBJbmNpZGVudCBSZXBvcnRzIGZvciAyMDA4LTIwMTEsIEphbi1KdWx5IDIwMTUsIEphbi1KdWx5IDIwMTYgKGluY2x1ZGluZyBhIG51bWJlciBvZiBpbnRveGljYXRpb24tcmVsYXRlZCBjcmltZXMpCjIuIFRBQkMgTWl4ZWQgQmV2ZXJhZ2UgVGF4IFJlY2VpcHRzIGZvciBBdXN0aW4sIDIwMDgtMjAxNi4KMy4gQVBEIENoaWVmJ3MgTW9udGhseSBSZXBvcnRzLCAyMDEwLTIwMTYsIHdpdGggbnVtYmVycyBvZiBEV0kgYW5kIE5hcmNvdGljcyBhcnJlc3RzLgoKVGhlIEFQRCAoQXVzdGluIFBvbGljZSBEZXBhcnRtZW50KSBJbmNpZGVudCBSZXBvcnRzIGFyZSBwdWJsaWNseSBhdmFpbGFibGUgZm9yIHllYXJzIDIwMDgtMjAxMSwgYW5kIGZvciAnWWVhciB0byBEYXRlJyB3aGljaCBzdXBwb3NlZGx5IGluY2x1ZGVzIHRoZSBsYXN0IDE4IG1vbnRocyBvZiByZXBvcnRlZCBjcmltZSBpbiBBdXN0aW4gYnV0IGFjdHVhbGx5IG9ubHkgaW5jbHVkZXMgOCBtb250aHMgb2YgMjAxNiBhbmQgYSBzbWFsbCBudW1iZXIgb2YgcmVwb3J0cyBmcm9tIDIwMTUuICBJIHdhcyBhYmxlIHRvIG9idGFpbiBhbiBhcmNoaXZlZCB2ZXJzaW9uIG9mIHRoZSBkYXRhIGZyb20gbGF0ZSAyMDE1LCB3aGljaCBoYXMgbW9yZSBjb21wbGV0ZSBkYXRhIGZvciBKYW4tSnVsIDIwMTUuICAKClRoZSBBUEQgQ2hpZWYncyBNb250aGx5IFJlcG9ydCBpcyBhIGhpZ2gtbGV2ZWwgc3VtbWFyeSBvZiBjcmltZSBpbiBBdXN0aW4gZm9yIHRoZSBtb250aCwgaW5jbHVkaW5nIGNvdW50cyBmb3IgaGlnaC1wcm9maWxlIGNyaW1lcyBpbmNsdWRpbmcgRFdJLiAgSXQgaGFzIG5vIHRpbWUtb2YtZGF5IG9yIGxvY2F0aW9uIGluZm9ybWF0aW9uLCBhbmQgbm8gaW5mbyBvdGhlciB0aGFuIGp1c3QgdGhhdCBhIERXSSBvY2N1cnJlZCwgYnV0IGlzIGFub3RoZXIgc291cmNlIG9mIGRhdGEgdG8gY29tcGFyZSB0byB0aGUgaW5jaWRlbnQgcmVwb3J0cywgd2hpY2ggbWF5IGJlIHNwb3R0eS4gIEl0IGFkZGl0aW9uYWxseSBjb250YWlucyBkYXRhIG9uIG5hcmNvdGljcyBhcnJlc3RzLCB3aGljaCB3ZSBjYW4gY2hlY2sgdG8gc2VlIGlmIHdlIGNhbiB1c2UgaXQgYXMgYSBjb250cm9sIHZhcmlhYmxlIC0gbmFyY290aWNzIGNyaW1lcyBtYXkgZm9sbG93IHRoZSBzYW1lIGJyb2FkIHRyZW5kcyBhcyBEV0ksIGJ1dCBhcmUgcG90ZW50aWFsbHkgdW5hZmZlY3RlZCBieSByaWRlc2hhcmluZy4KCkl0J3Mgd29ydGggbm90aW5nIHRoYXQgdGhlIHN0dWR5IG9mIERXSSBhcnJlc3QgbnVtYmVycyBhcyBhIHByb3h5IGZvciB0aGUgaW5jaWRlbmNlIG9mIGRydW5rIGRyaXZpbmcgaXMgYW4gb3BlbiBhcmVhIG9mIHJlc2VhcmNoIC0gc29tZSBzdHVkaWVzIHByZWZlciBkcnVuayBkcml2aW5nIGNyYXNoZXMsIGFsdGhvdWdoIEF1c3RpbiBoYXMgbm90IHJlbGVhc2VkIGVub3VnaCBtb250aGx5IHN0YXRpc3RpY3Mgb24gZHJ1bmsgZHJpdmluZyBjcmFzaGVzIHRvIG1ha2UgaXQgYSB1c2VmdWwgZm9yIHdoYXQgSSB3YW50IHRvIGRvLiAgV2UnbGwgYXNzdW1lIERXSSBhcnJlc3RzIGFyZSBhIHZpYWJsZSBwcm94eSBmb3IgZHJ1bmsgZHJpdmluZyBoZXJlLiAgRm9yIGEgbW9yZSBkZXRhaWxlZCB0cmVhdG1lbnQgb2YgdGhpcywgc2VlIHRoZSBhcHBlbmRpeC4KClRoZSBUQUJDIChUZXhhcyBBbGNvaG9saWMgQmV2ZXJhZ2UgQ29tbWlzc2lvbikgTWl4ZWQgQmV2ZXJhZ2UgVGF4IGlzIGEgZml4ZWQgdGF4IGNoYXJnZWQgb24gYWxjb2hvbGljIGJldmVyYWdlcyBzb2xkIGJ5IGEgaG9sZGVyIG9mIGEgTWl4ZWQgQmV2ZXJhZ2UgTGljZW5zZSBpbiB0aGUgc3RhdGUgb2YgVGV4YXMuICBJIHN1c3BlY3QgdGhhdCBNaXhlZCBCZXZlcmFnZSBUYXggcmV2ZW51ZXMgYXJlIGFzc29jaWF0ZWQgd2l0aCBVbml0cyBvZiBBbGNvaG9sIENvbnN1bWVkIGluIEF1c3RpbiwgYW5kIHdlJ2xsIGNoZWNrIHRvIHNlZSBpZiBhbnkgcmVsYXRpb25zaGlwIGV4aXN0cyBiZXR3ZWVuIHRoZXNlIHRheCByZXZlbnVlcyBhbmQgRFdJIGNvdW50cy4KCiMjRGF0ZXMgb2YgSW50ZXJlc3QKCiogSnVuZSAzLCAyMDE0OiBMeWZ0IGxhdW5jaGVzIGluIEF1c3Rpbi4KKGh0dHBzOi8vdHdpdHRlci5jb20vQXVzdGluTHlmdC9zdGF0dXMvNDczODU3MDU3NzIwNzY2NDY0KQoKKiBKdW5lIDQsIDIwMTQgOiBVYmVyIGxhdW5jaGVzIGluIEF1c3Rpbi4KKGh0dHBzOi8vdHdpdHRlci5jb20vVWJlcl9BVFgvc3RhdHVzLzQ3NDE5OTc0MDIxNzcxNjczNikKCiogTWF5IDksIDIwMTY6IFViZXIgYW5kIEx5ZnQgc3RvcCBnaXZpbmcgcmlkZXMgaW4gQXVzdGluLgoKV2UnbGwgY2FsbCBKdW5lIDQgYW5kIE1heSA5IHRyZWF0bWVudCBkYXRlcyAtIHRoZSBpbmZsZWN0aW9uIHBvaW50cyB3ZSdsbCBpbnZlc3RpZ2F0ZSB0byBzZWUgaWYgdGhlIGRhdGEgb24gZWl0aGVyIHNpZGUgaXMgc3Vic3RhbnRpYWxseSBkaWZmZXJlbnQuICBXaGVuIGRlYWxpbmcgd2l0aCBtb250aGx5IGRhdGEgd2UnbGwgaGF2ZSB0byBzYXkgdGhhdCBKdW5lIDIwMTQgaXMgdGhlIGZpcnN0IG1vbnRoIG9mIHRoZSB0cmVhdG1lbnQgYW5kIEFwcmlsIDIwMTYgaXMgdGhlIGxhc3QgbW9udGguCgpZb3UgY2FuIGZpbmQgdGhlIHNhbWUgZGF0YSBJIHVzZWQgYXQgdGhlc2Ugc2l0ZXM6CgoqIGh0dHBzOi8vZGF0YS5hdXN0aW50ZXhhcy5nb3YvYnJvd3NlP3E9YXBkJnNvcnRCeT1yZWxldmFuY2UKKiBodHRwczovL3d3dy5jb21wdHJvbGxlci50ZXhhcy5nb3YvdHJhbnNwYXJlbmN5L29wZW4tZGF0YS9zZWFyY2gtZGF0YXNldHMvCiogaHR0cHM6Ly9hdXN0aW50ZXhhcy5nb3YvcGFnZS9jaGllZnMtbW9udGhseS1yZXBvcnRzCiogaHR0cHM6Ly9kdXJzLmNhcnRvLmNvbS90YWJsZXMvYXBkX2luY2lkZW50X2V4dHJhY3RfMjAxNWNzdi9wdWJsaWMKCk9yIHlvdSBjYW4gcHVsbCBpdCBmcm9tIG15IEdpdGh1YiwgCmh0dHA6Ly93d3cuZ2l0aHViLmNvbS9pYW53ZWxscy9hdHgtZHdpCgpBbHJpZ2h0LCBMZXQncyBnZXQgdG8gaXQuCgojVGhlIERhdGEKCiMjRFdJIEFycmVzdHMKCmBgYHtyIGluY2x1ZGUgPSBGQUxTRX0Kc2V0d2QoJy9Vc2Vycy9pYW53ZWxscy9zYW5kYm94L2F0eC1kd2kvJykKZHdpLnJhdyA8LSByZWFkLmNzdignZGF0YS9kd2ktcmF3LW5vaGl0YW5kcnVuLW5vZHJlLmNzdicpCgpzYXBwbHkoZHdpLnJhdyxjbGFzcykKaGVhZChkd2kucmF3KQpkd2kucmF3JGRhdGUgPC0gcGFyc2VfZGF0ZV90aW1lKGR3aS5yYXckZGF0ZSwnJVktJW0tJWQgJUg6JU06JVMnLHR6ID0nQW1lcmljYS9DaGljYWdvJykKCnRhYmMucmF3IDwtIHJlYWQuY3N2KCdkYXRhL3RhYmMtcmF3LmNzdicpCnNhcHBseSh0YWJjLnJhdyxjbGFzcykKdGFiYy5yYXckZGF0ZSA8LSBwYXJzZV9kYXRlX3RpbWUodGFiYy5yYXckZGF0ZSwnJVktJW0tJWQgJUg6JU06JVMnLCB0eiA9ICdBbWVyaWNhL0NoaWNhZ28nKQoKYXBkLnJhdyA8LSByZWFkLmNzdignZGF0YS9jaGllZi1yZXBvcnQtcmF3LmNzdicpCm5hcmMucmF3IDwtIHJlYWQuY3N2KCdkYXRhL25hcmMtcmF3LmNzdicpCmFwZC5yYXcgPC0gbWVyZ2UoYXBkLnJhdyxuYXJjLnJhdywgYnkgPSAnZGF0ZScpCmBgYAoKSXQncyBhbHdheXMgYSBnb29kIGlkZWEgdG8ganVzdCBwb2tlIGFyb3VuZCBpbiB5b3VyIGRhdGEgYW5kIHNlZSB3aGF0J3MgZ29pbmcgb24uICBIZXJlJ3MgYSBxdWljayBnbGltcHNlIG9mIHdoYXQgdGhlIHJhdyBBUEQgZGF0YSBsb29rcyBsaWtlOgoKYGBge3Igd2FybmluZz1GQUxTRX0Kc2FtcGxlX24oZHdpLnJhdywxMCkKYGBgCgpDb29sLiAgV2UgaGF2ZSBhIGJ1bmNoIG9mIGNyaW1lcywgcHJlLWZpbHRlcmVkIHRvIGludG94aWNhdGlvbi1yZWxhdGVkIG9uZXMgYW5kIHRoZSB0aW1lIHRoZXkgYXBwcm94aW1hdGVseSBvY2N1cnJlZC4gIEkndmUgdmVyaWZpZWQgdGhhdCB0aW1lIGFuZCBsb2NhdGlvbiBhcmUgdW5pcXVlIGZvciBlYWNoIGNyaW1lIChubyBkb3VibGUtYm9va2luZ3MsIGFsdGhvdWdoIHRoZXJlIGFyZSBhIGZldyByYXJlIGNhc2VzIHdoZXJlIHR3byBkcnVuayBkcml2ZXJzIHdlcmUgYXJyZXN0ZWQgYXQgdGhlIHNhbWUgdGltZSksIHNvIHdlIGNhbiBiZSBjb25maWRlbnQgdGhhdCBvbmUgaW5jaWRlbnQgcmVwb3J0ID0gb25lIGNvbmZpcm1lZCBpbnN0YW5jZSBvZiBkcnVuayBkcml2aW5nLgoKWW91IGNhbiBjaGVjayB0aGlzIGFnYWluc3QgdGhlIGZ1bGwgbGlzdCBvZiBjcmltZXMgYXZhaWxhYmxlIHRvIGNvbW1pdCBpbiBBdXN0aW4sIHdoaWNoIGlzIGF2YWlsYWJsZSBvbiB0aGF0IHNhbWUgQXVzdGluIERhdGEgUG9ydGFsIHNpdGUsIEknbSBub3QgaW5jbHVkaW5nIGl0IGhlcmUgYmVjYXVzZSBpdCdzIHF1aXRlIGxvbmcsIHBsZWFzZSB0cnVzdCB0aGF0IEkndmUgZ290IGFsbCBvZiB0aGVtLgoKYGBge3Igd2FybmluZz1GQUxTRX0KbGV2ZWxzKGR3aS5yYXckY3JpbWUpCmBgYAoKSWYgeW91J3JlIGZhbWlsaWFyIHdpdGggdGhpcyBkYXRhIHNldCB5b3UnbGwgbm90aWNlIEkndmUgcmVtb3ZlZCBhIGZldyBjcmltZXM6CgoxKSBgQk9BVElORyBXSElMRSBJTlRPWElDQVRFRGAgLSBUaGlzIHJhcmUgY3JpbWUgZG9lc24ndCBzZWVtIGxpa2UgaXQgY291bGQgYmUgYXZvaWRlZCBieSBoYWlsaW5nIGFuIFViZXIuCjIpIGBEV0kgLSBEUlVHIFJFQ09HTklUSU9OIEVYUEVSVGAgLSBZb3UgZG9uJ3QgaGF2ZSB0byBoYXZlIGFueSBhbGNvaG9sIGluIHlvdXIgc3lzdGVtIHRvIGJlIGNoYXJnZWQgd2l0aCBhIERXSTogaW4gdGhpcyBjYXNlLCBhbiBvZmZpY2VyIGNlcnRpZmllZCBpbiByZWNvZ25pemluZyB0aGUgZWZmZWN0cyBvZiBzb21lIG90aGVyIHN1YnN0YW5jZSBoYXMgZGVjaWRlZCB5b3Ugc2hvdWxkbid0IGJlIGRyaXZpbmcuICBXaGlsZSBJIGltYWdpbmUgeW91IGNvdWxkIGF2b2lkIHRyb3VibGUgYnkgaGFpbGluZyBhIHJpZGUgaW4gdGhpcyBjYXNlLCBJIGRvbid0IHRoaW5rIEkgY291bGQgcmVsYXRlIGl0IHRvIGJhciBzYWxlcywgc28gdGhpcyBzdGF0IGlzIGdvaW5nIHRvIGJlIHJlbGVnYXRlZCB0byBzb21lIG90aGVyIHN0dWR5LgozKSBgQ1JBU0gvTEVBVklORyBUSEUgU0NFTkVgIC0gVGhpcyBpcyBhIHRyaWNreSBvbmUuICBDZXJ0YWlubHkgYSBub24temVybyBwZXJjZW50YWdlIG9mIGhpdC1hbmQtcnVuIG9mZmVuc2VzIGFyZSBjb21taXR0ZWQgYnkgZHJ1bmsgZHJpdmVycywgYnV0IHRoaXMgY2hhcmdlIGRvZXNuJ3Qgb2ZmZXIgYW55IG1vcmUgZGV0YWlscywgYW5kIHdvcnNlLCB0aGVyZSBhcmUgbW9yZSBvZiB0aGlzIGtpbmQgb2YgY3JpbWUgdGhhbiBhbGwgdGhlIG90aGVycyBwdXQgdG9nZXRoZXIuICBIb3cgc2hvdWxkIHdlIGNvdW50IHRoZW0sIGlmIGF0IGFsbD8gIEZvciBub3csIGxldCdzIGxlYXZlIHRoZW0gYWxsIG91dCwgYXMgdGhleSdyZSBub3QgbWVudGlvbmVkIHNwZWNpZmljYWxseSBpbiB0aGUgY2hpZWYncyBtb250aGx5IHJlcG9ydC4gIFdlIG1pZ2h0IGJlIGFibGUgdG8gcHJvamVjdCBob3cgbWFueSBvZiB0aGVzZSBjcmltZXMgaW52b2x2ZSBhbGNvaG9sIGF0IGEgbGF0ZXIgZGF0ZSwgYmFzZWQgb24gd2hlbiBhbmQgd2hlcmUgdGhleSBvY2N1cnJlZCwgYnV0IHdlJ2xsIGxlYXZlIHRoYXQgZm9yIGFub3RoZXIgYW5hbHlzaXMuICBTZWUgdGhlIGFwcGVuZGl4IGZvciBmdXJ0aGVyIGRpc2N1c3Npb24uCgpMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgcmVsYXRpdmUgZnJlcXVlbmN5IG9mIHRoZXNlIG9mZmVuc2VzLiAgUGVyaW9kaWNpdHkgY2FuIGJlIGV4cGxvaXRlZCBsYXRlciBvbi4KCmBgYHtyIHdhcm5pbmc9IEZBTFNFfQpxcGxvdChob3VyKGRhdGUpLCBkYXRhPWR3aS5yYXcsIGdlb209Imhpc3RvZ3JhbSIsIGJpbnMgPSAyNCkKYGBgCgpQZXJoYXBzIG5vdCBzdXJwcmlzaW5nbHksIG5lYXJseSBhbGwgRFdJIG9mZmVuc2VzIG9jY3VyIGJldHdlZW4gOCBQTSBhbmQgNSBBTS4KCmBgYHtyIHdhcm5pbmc9IEZBTFNFfQpxcGxvdCh3ZGF5KGRhdGUpLCBkYXRhPWR3aS5yYXcsIGdlb209Imhpc3RvZ3JhbSIsIGJpbnMgPSA3KQpgYGAKCkFnYWluLCBsb29rcyBsaWtlIEZyaWRheXMgYW5kIFNhdHVyZGF5cyBhcmUgcG9wdWxhciBkYXlzIHRvIGdldCBjYXVnaHQgZHJ1bmsgZHJpdmluZy4KCldlJ3JlIGdvaW5nIHRvIGxvb2sgYXQgdGhlIHdob2xlIHNlcmllcywgYW5kIHRoZW4gYSBoaXN0b2dyYW0gb2YgbW9udGhseSBkYXRhIHRvIHNlZSBpZiB0aGVyZSdzIGEgc2Vhc29uYWwgdHJlbmQgKHlvdSBtaWdodCBleHBlY3QgbW9yZSBEV0kncyB0byBvY2N1ciBpbiBEZWNlbWJlciwgSmFudWFyeSwgb3IgSnVseSBtb250aHMgd2l0aCBob2xpZGF5IHdlZWtlbmRzIHRoYXQgaW52b2x2ZSBhIGxvdCBvZiBkcmlua2luZykKCk5vdGU6IHdlIGhhdmUgaW5jb21wbGV0ZSBkYXRhIGZvciBKdWx5IDIwMTUgYW5kIEF1Z3VzdCAyMDE2LCBhcyB3ZWxsIGFzIGFuIG9sZCBvZmZlbnNlIGluIDIwMTQsIHNvIHdlJ2xsIHJlbW92ZSB0aG9zZSBtb250aHMgbm93LiAgV2UnbGwgbGVhdmUgMjAxNSBhbmQgMjAxNiBvdXQgb2YgdGhlIG1vbnRobHkgaGlzdG9ncmFtIGJlY2F1c2Ugd2Ugb25seSBoYXZlIGRhdGEgZnJvbSBhIGZldyBtb250aHMgZm9yIHRob3NlIHllYXJzLgoKYGBge3IgIHdhcm5pbmc9IEZBTFNFfQpkd2kucmF3JHllYXIgPC0geWVhcihkd2kucmF3JGRhdGUpCmR3aS5yYXckbW9udGggPC0gbW9udGgoZHdpLnJhdyRkYXRlKQogIApkd2kubW9udGhseSA8LSBkd2kucmF3ICU+JSBncm91cF9ieSh5ZWFyLG1vbnRoKQpkd2kubW9udGhseSA8LSBzdW1tYXJpemUoZHdpLm1vbnRobHksY291bnQ9bigpKQpkd2kubW9udGhseSRkYXRlIDwtIGFzLkRhdGUocGFzdGUwKGR3aS5tb250aGx5JHllYXIsJy0nLGR3aS5tb250aGx5JG1vbnRoLCctMDEnKSkKCmR3aS5tb250aGx5IDwtIGR3aS5tb250aGx5Wy01NixdICNyZW1vdmUgcGFydGlhbCBKdWx5IDIwMTUgZGF0YQpkd2kubW9udGhseSA8LSBkd2kubW9udGhseVstNjMsXSAjcmVtb3ZlIHBhcnRpYWwgQXVndXN0IDIwMTYgZGF0YQpkd2kubW9udGhseSA8LSBkd2kubW9udGhseVstNDksXSAjcmVtb3ZlIGxvbmUgMjAxNCBhcnJlc3QKCmxhYmVsLm1vbnRocyA8LSBjKCdKJywnRicsJ00nLCdBJywnTScsJ0onLCdKJywnQScsJ1MnLCdPJywnTicsJ0QnKQoKZ2dwbG90KGRhdGE9ZHdpLm1vbnRobHksIGFlcyh4ID0gZGF0ZSwgeSA9IGNvdW50LCBncm91cCA9IHllYXIoZGF0ZSksIGNvbG9yID0gZmFjdG9yKHllYXIoZGF0ZSkpKSkgKyBnZW9tX3BvaW50KCkKCmR1bW15IDwtIGZpbHRlcihkd2kubW9udGhseSxkYXRlIDwgJzIwMTUtMDEtMDEnKSAlPiUgZ3JvdXBfYnkobW9udGgoZGF0ZSkpICU+JSBzdW1tYXJpemUoY291bnQgPSBzdW0oY291bnQpKSAlPiUgc2VsZWN0KGNvdW50KSAKZHVtbXkxIDwtIG1lYW4oZHVtbXkkY291bnQpICMxODI0CmR1bW15MiA8LSBzZChkdW1teSRjb3VudCkgIzk5CgpnZ3Bsb3QoZGF0YSA9IGZpbHRlcihkd2kubW9udGhseSxkYXRlIDwgJzIwMTUtMDEtMDEnKSwgYWVzKGZhY3Rvcihtb250aChkYXRlKSksd2VpZ2h0ID0gY291bnQpICkgKyBnZW9tX2JhcigpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTE4MjQsIGNvbG9yID0gJ3JlZCcpICsKZ2VvbV9obGluZSh5aW50ZXJjZXB0PTE3MjQsIGNvbG9yID0gJ2dyYXknKSArCmdlb21faGxpbmUoeWludGVyY2VwdD0xOTI0LCBjb2xvciA9ICdncmF5JykKYGBgCgpTbyB3ZSBjYW4gZ2V0IGEgc2Vuc2UgdGhhdCwgZm9yIHRoZSB5ZWFycyAyMDA4LTIwMTEsIG1vbnRobHkgRFdJJ3Mgc2VlbSB0byBiZSBkZWNyZWFzaW5nIChnb29kIGpvYiBBUEQpLCBhbmQgYXMgZm9yIGEgbW9udGhseSB0cmVuZCB3ZSBzZWUgYW4gYW5udWFsIGJ1bXAgaW4gRGVjZW1iZXItSmFudWFyeSwgc29tZXRoaW5nIGluIE1hcmNoLCBhcyB3ZWxsIGFzIHNvbWV0aGluZyBnb2luZyBvbiBpbiBBdWd1c3QtT2N0b2JlciwgYWx0aG91Z2ggYWxsIHNlZW0gdG8gYmUgd2l0aGluIG9uZSBzdGFuZGFyZCBkZXZpYXRpb24gb2Ygb3VyIG1vbnRobHkgbWVhbi4KCk5vdywgSSdtIGN1cmlvdXMgdG8gc2VlIGhvdyB0aGUgQ2hpZWYncyBNb250aGx5IFJlcG9ydCBjb21wYXJlcy4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmFwZC5yYXckZGF0ZSA8LSBhcy5EYXRlKGFwZC5yYXckZGF0ZSkKYXBkLnJhdyR5ZWFyIDwtIHllYXIoYXBkLnJhdyRkYXRlKQphcGQucmF3JG1vbnRoIDwtIG1vbnRoKGFwZC5yYXckZGF0ZSkKCmFwZC5tb250aGx5IDwtIGFwZC5yYXcKICAKZ2dwbG90KGRhdGE9YXBkLm1vbnRobHksIGFlcyh4ID0gZGF0ZSwgeSA9IGNvdW50LCBjb2xvciA9IGZhY3Rvcih5ZWFyKSkpICsgZ2VvbV9wb2ludCgpIAoKZHVtbXkgPC0gYXBkLm1vbnRobHkgJT4lIGdyb3VwX2J5KG1vbnRoKGRhdGUpKSAlPiUgc3VtbWFyaXplKGNvdW50ID0gc3VtKGNvdW50KSkgJT4lIHNlbGVjdChjb3VudCkgCmR1bW15MSA8LSBtZWFuKGR1bW15JGNvdW50KSAjMzI5MApkdW1teTIgPC0gc2QoZHVtbXkkY291bnQpICMxNDUKCmdncGxvdChkYXRhID0gYXBkLm1vbnRobHksIGFlcyhmYWN0b3IobW9udGgoZGF0ZSkpLHdlaWdodCA9IGNvdW50KSApICsgZ2VvbV9iYXIoKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0zMjkwLCBjb2xvciA9ICdyZWQnKSArCmdlb21faGxpbmUoeWludGVyY2VwdD0zMTQ1LCBjb2xvciA9ICdncmF5JykgKwpnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MzQzNSwgY29sb3IgPSAnZ3JheScpCgpgYGAKClRoaXMgaGFzIHNpbWlsYXIgYnVtcHMsIHdpdGggYSB3ZWFrZXIgU2VwdGVtYmVyLiAgTGV0J3MgcGxvdCBib3RoIGF0IHRoZSBzYW1lIHRpbWUuCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpib3RoLm1vbnRobHkgPC0gbWVyZ2UoYXBkLm1vbnRobHksZHdpLm1vbnRobHksIGJ5ID0gJ2RhdGUnLCBhbGwgPSBUUlVFKTsKYm90aC5tb250aGx5JGFwZCA8LSBib3RoLm1vbnRobHkkY291bnQueApib3RoLm1vbnRobHkkZHdpIDwtIGJvdGgubW9udGhseSRjb3VudC55Cgpib3RoLm1vbnRobHkgPC0gYm90aC5tb250aGx5ICU+JSBzZWxlY3QoZGF0ZSxhcGQsZHdpKQpib3RoLm1lbHRlZCA8LW1lbHQoYm90aC5tb250aGx5LCBpZC52YXJzPSJkYXRlIikKCmdncGxvdChkYXRhPWJvdGgubWVsdGVkLCBtYXBwaW5nID0gYWVzKHg9ZGF0ZSx5PXZhbHVlLCBjb2xvciA9IHZhcmlhYmxlKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpPa2F5LCBzbyBpdCBsb29rcyBsaWtlIHRoZSBjaGllZidzIHJlcG9ydCBpcyBhIGxpdHRsZSBkaWZmZXJlbnQgdGhhbiB0aGUgaW5jaWRlbnQgcmVwb3J0IGRhdGFiYXNlLiAgVGhhdCdzIGFubm95aW5nLCBidXQgYmFzZWQgb24gdGhlIGRpc2NsYWltZXJzIG9uIGJvdGggd2Vic2l0ZXMsIGFuZCB0aGF0IHRoZSBjaGllZidzIHJlcG9ydCBpcyB1cGRhdGVkIG1vcmUgb2Z0ZW4sIEknbSBnb2luZyB0byBjYWxsIGl0IGFuZCBzYXkgdGhlIGNoaWVmJ3MgZGF0YSBpcyB3aGF0IEknbSB1c2luZyBtb3ZpbmcgZm9yd2FyZC4gIEknZCBsaWtlIHRob3NlIGV4dHJhIHR3byB5ZWFycyBvZiBkYXRhIHRoYXQgdGhlIGRhdGFiYXNlIGhhcyB0aG91Z2ggLSBhbmQgc2luY2UgdGhlIGRhdGEgaXMgc28gaGlzdG9yaWMsIGFuZCB0aGUgZGlmZmVyZW5jZSBpcyBzbyBjb25zaXN0ZW50LCB3aGF0IEknbSBnb2luZyB0byBkbyBpcyBudWRnZSB0aGUgZGF0YSB1cCBzbGlnaHRseSBzbyB0aGF0IGl0IGxpbmVzIHVwLgoKYGBge3Igd2FybmluZz1GQUxTRX0KYm90aC5tb250aGx5JGRpZmYgPC0gYm90aC5tb250aGx5JGFwZCAtIGJvdGgubW9udGhseSRkd2kKbWVhbihmaWx0ZXIoYm90aC5tb250aGx5LGRhdGUgPCAnMjAxMi0wMS0wMScsIGRhdGUgPiAnMjAxMC0wMS0wMScpJGRpZmYpCgpib3RoLm1vbnRobHkubnVkZ2UgPC0gYm90aC5tb250aGx5CmJvdGgubW9udGhseS5udWRnZSRkd2kgPSBib3RoLm1vbnRobHkubnVkZ2UkZHdpICsgMTUgI2FwcHJveGltYXRlIG1lYW4gZGlmZmVyZW5jZQoKYm90aC5tZWx0ZWQubnVkZ2UgPC1tZWx0KGJvdGgubW9udGhseS5udWRnZSwgaWQudmFycz0iZGF0ZSIpCmdncGxvdChkYXRhPWJvdGgubWVsdGVkLm51ZGdlLCBtYXBwaW5nID0gYWVzKHg9ZGF0ZSx5PXZhbHVlLCBjb2xvciA9IHZhcmlhYmxlKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpBbHJpZ2h0LCB0aGF0J3MgYSBsaXR0bGUgY2xlYW5lci4gIFdlJ2xsIG1vdmUgZm9yd2FyZCB3aXRoIHRoaXMgc2V0IG9mIG1vbnRobHkgZGF0YSB1bnRpbCBJIGNhbiBnZXQgbW9yZSBjb21wcmVoZW5zaXZlIGFycmVzdCByZWNvcmRzLCBiZWluZyBhYmxlIHRvIHVzZSB3ZWVrbHkgcGVyaW9kaWNpdHkgbWlnaHQgYmUgaGVscGZ1bC4KCiMjTmFyY290aWNzIEFycmVzdHMKClRoZSBDaGllZidzIE1vbnRobHkgUmVwb3J0IGxpc3RzIGFsbCBQYXJ0IDEgT2ZmZW5zZXMgKGFjY29yZGluZyB0byB0aGUgVW5pZm9ybSBDcmltZSBSZXBvcnRpbmcgc3RhbmRhcmRzIGVzdGFibGlzaGVkIGJ5IHRoZSBGQkksIG1vc3RseSB2aW9sZW50IGZlbG9uaWVzKSBhbmQgYSBmZXcga2V5IFBhcnQgMiBPZmZlbnNlcywgbmFtZWx5IERXSSwgbmFyY290aWNzLCBwcm9zdGl0dXRpb24sIGFuZCB3ZWFwb25zLWxhdyByZWxhdGVkIGNyaW1lcy4gIFByb3N0aXR1dGlvbiBhbmQgd2VhcG9ucyBjcmltZXMgb2NjdXIgc3BhcnNlbHkgY29tcGFyZWQgdG8gRFdJIGFuZCBuYXJjb3RpY3MsIHNvIHdlJ2xsIGltcG9ydCB0aGUgbmFyY290aWNzIGFycmVzdCBkYXRhIGluIGhvcGVzIHRoYXQgaXQgd2lsbCBhbGxvdyB1cyB0byBjb250cm9sIGZvciBzd2VlcGluZyBlZmZlY3RzIGFjcm9zcyBhbGwgY3JpbWUgY2F0ZWdvcmllcyAtIHRoaW5ncyBsaWtlIHRoZSBudW1iZXIgb2Ygb2ZmaWNlcnMgd29ya2luZywgbW90aXZhdGlvbiBvZiB0aGUgcG9saWNlIGZvcmNlLCBwb3B1bGF0aW9uIG9mIHRoZSBjaXR5LCBldGMuCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZGF0YT1hcGQubW9udGhseSwgYWVzKHggPSBkYXRlLCB5ID0gbmFyYywgY29sb3IgPSBmYWN0b3IoeWVhcikpKSArIGdlb21fcG9pbnQoKSAKCnFwbG90KGZhY3Rvcihtb250aChkYXRlKSksIGRhdGE9YXBkLm1vbnRobHksIGdlb209ImJhciIsIHdlaWdodCA9IG5hcmMpCmBgYAoKTm90IGEgbG90IHRvIHNheSBoZXJlIC0gdGhlcmUncyBhIHN0cm9uZyBKYW51YXJ5IGJ1dCBub3QgYSBsb3QgZWxzZSB0aGF0IGxpbmVzIHVwIHdpdGggdGhlIERXSSBkYXRhLgoKSSd2ZSBzYXZlZCBvdXQgb3VyIGZpbmFsIGRhdGEgc2V0IGhlcmUgdG8gc2F2ZSB0aW1lLgoKYGBge3Igd2FybmluZz1GQUxTRX0KZHdpIDwtIHJlYWQuY3N2KCdkYXRhL2R3aS1maW5hbC5jc3YnKQojc2FwcGx5KGR3aSxjbGFzcykKZHdpJGRhdGUgPC0gYXMuRGF0ZShkd2kkZGF0ZSkKZHdpJGNvdW50IDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGR3aSRjb3VudCkpICNjYXN0IHN0cmljdGx5CmR3aSRuYXJjIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGR3aSRuYXJjKSkKZHdpJHRyZWF0bWVudCA8LSBhcy5mYWN0b3IoZHdpJHRyZWF0bWVudCkgIzA6IHByZSB1YmVyLCAxOnViZXIsIDI6cG9zdCB1YmVyCmBgYAoKIyMgVEFCQyBNaXhlZCBCZXZlcmFnZSBUYXgKCkxldCdzIGhhdmUgYSBsb29rIGF0IHdoYXQncyBnb2luZyBvbiB3aXRoIHRoZSBUQUJDIGRhdGEuICBOb3csIEkndmUgYWxyZWFkeSBkb25lIGEgYml0IG9mIHdvcmsgd2l0aCB0aGlzIGRhdGEgc2V0IGluIHRoZSBwYXN0IChzZWUgaHR0cDovL3RhYmNtYXAuczMtd2Vic2l0ZS11cy1lYXN0LTEuYW1hem9uYXdzLmNvbSksIHNvIEkndmUganVzdCBwdWxsZWQgdmFsdWVzIGZyb20gbXkgZGF0YWJhc2Ugb2YgbW9udGhseSByZXZlbnVlcyBjYWxjdWxhdGVkIGZyb20gbW9udGhseSB0YXggcmVjZWlwdHMuCgpIZXJlJ3Mgd2hhdCBhIGZldyByb3dzIGxvb2sgbGlrZToKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnNhbXBsZV9uKHRhYmMucmF3LDEwKQpgYGAKCkxldCdzIGRvIHRoZSBzYW1lIHNlcmllcyBhbmQgaGlzdG9ncmFtIHBsb3RzIHRvIGdldCBhIHNlbnNlIG9mIHdoYXQncyBpbiB0aGVyZS4KClRoZXJlJ3MgYSBsb25lIGRhdGEgcG9pbnQgZnJvbSAxOTk5LCBsZXQncyBjbGVhbiB0aGF0IHVwIHRvbywgYW5kIGxldCdzIHNjYWxlIHJldmVudWVzIGludG8gdGhlIG1pbGxpb25zIG9mIGRvbGxhcnMuCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQp0YWJjLm1vbnRobHkgPC0gdGFiYy5yYXdbLTQwLF0gI3JlbW92ZSBsb25lIDE5OTkgcG9pbnQKCnRhYmMubW9udGhseSRkYXRlIDwtIGFzLkRhdGUodGFiYy5tb250aGx5JGRhdGUpCnRhYmMubW9udGhseSR5ZWFyIDwtIHllYXIodGFiYy5tb250aGx5JGRhdGUpCnRhYmMubW9udGhseSRtb250aCA8LSBtb250aCh0YWJjLm1vbnRobHkkZGF0ZSkKdGFiYy5tb250aGx5JHJldiA8LSByb3VuZCh0YWJjLm1vbnRobHkkcmV2LzEwMDAwMDAsMikKCmdncGxvdChkYXRhPXRhYmMubW9udGhseSwgYWVzKHggPSBkYXRlLCB5ID0gcmV2LCBncm91cCA9IHllYXIsIGNvbG9yID0gZmFjdG9yKHllYXIpKSkgKyBnZW9tX3BvaW50KCkKCnFwbG90KGZhY3Rvcihtb250aChkYXRlKSksIGRhdGE9dGFiYy5tb250aGx5LCBnZW9tPSJiYXIiLCB3ZWlnaHQgPSByZXYpCmBgYAoKTG9vayBhdCB0aGF0IGdyb3d0aCEgIE5vdGljZSB0aGF0IHNwaWtlIGluIE1hcmNoPyAgVGhhdCdzIHByb2JhYmx5IFNYU1csIGEgbWFqb3IgYW5udWFsIG11c2ljLCB0ZWNobm9sb2d5LCBhbmQgZmlsbSBjb25mZXJlbmNlLiAgU2FpbnQgUGF0cmljaydzIGRheSBpcyBpbiBNYXJjaCwgdG9vLiAgU2VlIHRoYXQgc3Bpa2UgaW4gT2N0b2Jlcj8gIEkgYmV0IHRoYXQncyBBdXN0aW4gQ2l0eSBMaW1pdHMsIGEgbWFqb3IgbXVzaWMgZmVzdGl2YWwsIGFuZCBhbHNvIEhhbGxvd2Vlbi4gIFRoaXMgZGF0YSBpcyBhbHJlYWR5IGdvb2QgdG8gZ28sIHNvIGxldCdzIHJlbmFtZSBpdCB0byBrZWVwIHRoaW5ncyBjbGVhbiBhbmQga2VlcCBnb2luZy4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnRhYmMgPC0gc2VsZWN0KHRhYmMubW9udGhseSxkYXRlLHJldikKYGBgCgojI0RXSSBwZXIgJE1NCgpMZXQncyBzZWUgYWJvdXQgYSBuZXcgdmFyaWFibGUgLSBEV0kgcGVyIE1pbGxpb25zIG9mIERvbGxhcnMgQmFyIFJldmVudWUuICBJIHRoaW5rIHRoYXQgdGhpcyB2YXJpYWJsZSBtYXkgYmUgdXNlZnVsIGFzIGl0IGluY29ycG9yYXRlcyB0aGluZ3MgeW91IHdvdWxkIGV4cGVjdCB0byB2YXJ5IHdpdGggYmFyIHJldmVudWUgLSBkcmlua2luZy1hZ2UgcG9wdWxhdGlvbiBhbmQgcG9wdWxhcml0eSBvZiBkcmlua2luZyAtIGludG8gdGhlIERXSSBjb3VudC4gIEFsbCB0aGluZ3MgdGhlIHNhbWUsIGEgdG93biB3aXRoIGEgbG93ZXIgRFdJLXBlci1kcmluay1jb25zdW1lZCBudW1iZXIgaXMgZ29pbmcgYmV0dGVyIHRoYW4gb25lIHdpdGggYSBoaWdoZXIgcmF0aW8uICBXZSBtYXkgYmUgYWJsZSB0byBsaW5rIHJpZGVzaGFyaW5nIHRvIGFuIGltcHJvdmVtZW50IGluIHRoaXMgcmF0aW8gbW9yZSBjb252aW5jaW5nbHkgdGhhbiB0byBqdXN0IHJhdyBEV0kncy4KCmBgYHtyIHdhcm5pbmcgPSBGQUxTRX0KZHdpIDwtIG1lcmdlKGR3aSx0YWJjLCBieSA9ICdkYXRlJykKCmR3aSRjb3VudF9wZXJfbW0gPC0gZHdpJGNvdW50L2R3aSRyZXYKCmdncGxvdChkYXRhPWR3aSwgYWVzKHggPSBkYXRlLCB5ID0gY291bnRfcGVyX21tLCBncm91cCA9IHllYXIoZGF0ZSksIGNvbG9yID0gZmFjdG9yKHllYXIoZGF0ZSkpKSkgKyBnZW9tX3BvaW50KCkKCmdncGxvdChkYXRhPWR3aSwgYWVzKHggPSByZXYsIHkgPSBjb3VudCwgY29sb3IgPSB5ZWFyKGRhdGUpKSkgKyBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQoKc3VtbWFyeShsbShkYXRhID0gZHdpLCBjb3VudCB+IHJldikpCmBgYAoKU28gd2hpbGUgRFdJLyRNTSBpcyBkZWNyZWFzaW5nIG92ZXIgdGltZSwgaXQgZGVmaW5pdGVseSBoYXMgcGVyaW9kcyB3aGVyZSBpdCdzIHN0aWxsIGRvbWluYXRlZCBieSBhIHJpc2luZyBEV0kgcmF0ZSwgYW5kIGl0IHdvdWxkIGFwcGVhciB0aGF0IHRoZXJlJ3Mgbm8gZGlyZWN0IGNvcnJlbGF0aW9uIGJldHdlZW4gRFdJIGNvdW50cyBhbmQgYmFyIHJldmVudWUgLSB3aGljaCBtYWtlcyBzZW5zZSwgYXMgdGhleSdyZSBib3RoIGNsZWFybHkgbm9uLXN0YXRpb25hcnkuCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpxcGxvdChmYWN0b3IobW9udGgoZGF0ZSkpLCBkYXRhPWR3aSwgZ2VvbT0iYmFyIiwgd2VpZ2h0ID0gY291bnRfcGVyX21tKQpgYGAKClRoaXMgdmFyaWFibGUgZG9lcyBob3dldmVyIGhhdmUgYSBtdWNoIG1vcmUgb2J2aW91cyB5ZWFybHkgcGVhayBpbiBKYW51YXJ5IC0gd2UgbWF5IGJlIGFibGUgdG8gZXhwbG9pdCB0aGlzIGVudGFuZ2xlZCB2YXJpYWJsZSBtb3JlIGVhc2lseSB0aGFuIGp1c3QgdGhlIHJhdyBEV0ksIGlmIHdlIGNhbiBpc29sYXRlIHRoZSBlZmZlY3Qgb2YgcmlkZXNoYXJpbmcgb24gVEFCQyByZXZlbnVlICh3aGljaCB3ZSdsbCB0YWxrIGFib3V0IGxhdGVyKS4KCiNUaGUgQW5hbHlzaXMKCkFscmlnaHQsIHNvIG5vdyB0aGF0IHdlJ3ZlIGdvdCBzb21lIGRhdGEsIHdoYXQgY2FuIHdlIGRvIHdpdGggaXQ/ICBIb3cgY2FuIHdlIGVzdGFibGlzaCBvbmUgd2F5IG9yIHRoZSBvdGhlciB0aGF0IHRoZSBhZHZlbnQgb2YgcmlkZXNoYXJpbmcgYWZmZWN0ZWQgdGhlIG51bWJlciBvZiBEV0kgYXJyZXN0cyBpbiBBdXN0aW4sIG9yIHRoZSBudW1iZXIgb2YgRFdJJ3MgcGVyIGRvbGxhciBvZiBhbGNvaG9sIHNvbGQ/IFRoZXJlIGFyZSBhIGZldyB0aGluZ3MgSSdtIGdvaW5nIHRvIGxvb2sgYXQuCgojI1JlZ3Jlc3Npb24gRGlzY29udGludWl0eQoKVHlwaWNhbGx5LCB3aGVuIHlvdSBzZXQgb3V0IHRvIHByb3ZlIHNvbWV0aGluZyB3aXRoIHNjaWVuY2UsIHlvdSBzaXQgZG93biBhbmQgZGVzaWduIGFuIGV4cGVyaW1lbnQuICBXZSBkb24ndCBoYXZlIHRoZSByZXNvdXJjZXMgdG8gZG8gYSBjaXR5LXNjYWxlIGRvdWJsZS1ibGluZCByaWRlc2hhcmluZy9kcnVuay1kcml2aW5nIGV4cGVyaW1lbnQsIHNvIHdlJ2xsIGhhdmUgdG8gdXNlIHRoZSBuZXh0IGJlc3QgdGhpbmdzOiBtYXRoIGFuZCBoaXN0b3JpY2FsIGRhdGEuCgpSZWdyZXNzaW9uIERpc2NvbnRpbnVpdHkgRGVzaWduIGlzIGEgbWV0aG9kIG9mIGVzdGFibGlzaGluZyBjYXVzYWxpdHkgd2l0aG91dCB0aGUgYmVuZWZpdCBvZiBleHBlcmltZW50YWwgZGVzaWduLiAgVGhlIGtleSBhc3N1bXB0aW9uIGlzIHRoYXQsIHdpdGggcmVnYXJkcyB0byBhIHRpbWUgc2VyaWVzLCB0aGUgZGF0YSBvbiBlaXRoZXIgc2lkZSBvZiBhIHRyZWF0bWVudCBpbmZsZWN0aW9uIGFyZSBvdGhlcndpc2Ugc2ltaWxhciAtIG5vdGhpbmcgZWxzZSBzcGVjaWFsIGhhcyBoYXBwZW5lZC4gIElmIHlvdSBjYW4gZ2V0IGJlaGluZCB0aGF0LCB5b3UgY291bGQgY2xhaW0gdGhhdCBpZiB0aGVyZSdzIGEga2luayBpbiB5b3VyIGRhdGEsIGl0J3MgYmVjYXVzZSBvZiB0aGUgdHJlYXRtZW50IHlvdSdyZSBpbnZlc3RpZ2F0aW5nLgoKVXNpbmcgdGhpcyB0ZWNobmlxdWUgb24gdGltZSBzZXJpZXMgZGF0YSBjYW4gYmUgdHJpY2t5LCBlc3BlY2lhbGx5IHdoZW4geW91J3JlIHdvcmtpbmcgd2l0aCA4IHllYXJzIG9mIGRhdGEsIGJlY2F1c2Ugc3VyZWx5IHNvbWV0aGluZyBlbHNlIGJlc2lkZXMgeW91ciB0cmVhdG1lbnQgaGFwcGVuZWQgb3ZlciB0aGF0IHRpbWUgZnJhbWUuICBMZXQncyByZW1pbmQgb3Vyc2VsdmVzIHdoYXQgdGhlIERXSSBjb3VudCBsb29rcyBsaWtlOgoKYGBge3Igd2FybmluZz1GQUxTRX0KZ2dwbG90KGRhdGEgPSBkd2ksIG1hcHBpbmcgPSBhZXMoeD1kYXRlLHk9Y291bnQsIGNvbG9yID0gZmFjdG9yKHllYXIoZGF0ZSkpKSkgKyBnZW9tX3BvaW50KCkKYGBgCgpZb3UgY2FuIHByb2JhYmx5IHNlZSBhIGxvdCBvZiBqdW1wcyBpbiB0aGUgZGF0YSAtIGZyb20gMjAwOS0yMDExIHRoZXJlJ3MgYSByYXBpZCByaXNlIGluIERXSSwgZm9sbG93ZWQgYnkgYSBzd2lmdCBkcm9wIGFuZCB0aGVuIGEgbGVhcCB1cCBhZ2FpbiBpbiAyMDEzLCBhbmQgYSBncmFkdWFsIGRyb3AgaW50byAyMDE2LiAgV2UgY2FuJ3QgaG9uZXN0bHkgaW5jbHVkZSBhbGwgdGhhdCBkYXRhLCBzbyB3ZSdyZSBnb2luZyB0byBsaW1pdCB0aGluZ3MgdG8gYWJvdXQgdHdvIHllYXJzIG9uIGVpdGhlciBzaWRlIG9mIHRoZSBmaXJzdCB0cmVhdG1lbnQgKFViZXIgYW5kIEx5ZnQgb3BlbiBmb3IgYnVzaW5lc3MgaW4gQXVzdGluKSwgYW5kIHRoZSA4IG1vbnRocyB3ZSBoYXZlIGFmdGVyIHRoZSBzZWNvbmQgdHJlYXRtZW50IChVYmVyIGFuZCBMeWZ0IGNlYXNlIG9wZXJhdGlvbnMpLgoKRmlyc3QsIHdlJ2xsIHBsb3QgcmVncmVzc2lvbnMgb24gZWl0aGVyIHNpZGUgb2YgdGhlIHRyZWF0bWVudCBhbmQgc2VlIGhvdyB0aGV5IGxvb2sgLSB3aXRoIGp1c3QgYGxtYCB0byBzdGFydCBhbmQgdGhlbiB3aXRoIGEgc3BlY2lhbGl6ZWQgbGlicmFyeS4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRhID0gZmlsdGVyKGR3aSxkYXRlID4gJzIwMTItMDUtMDEnKSxtYXBwaW5nID0gYWVzKGRhdGUsIGNvdW50LCBjb2xvciA9IHRyZWF0bWVudCkgKSsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJykKYGBgCgpWaXN1YWxseSwgeW91IG1pZ2h0IGJlIHRlbXB0ZWQgdG8gZ2V0IGEgc2Vuc2Ugb2YgdGhlIGVmZmVjdCBvZiByaWRlc2hhcmluZyBvdmVyIHRoZSBwZXJpb2QgbWFya2VkIGluIGdyZWVuLCBidXQgbGV0J3Mga2VlcCBnb2luZy4gV2UncmUgZ29pbmcgdG8gdXNlIHRoZSBgcmRkdG9vbHNgIGxpYnJhcnkgYW5kIHNlZSBpZiB0aGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgY2hhbmdlIGluIHRoZSByZWdyZXNzaW9ucyBiZWZvcmUgYW5kIGFmdGVyIGVhY2ggZGlzY29udGludWl0eSwgd2UnbGwgYWxzbyBjb21wYXJlIGByZGR0b29sc2AgdG8gdGhlIG91dHB1dCBvZiBgbG1gIC4KIApgYGB7ciB3YXJuaW5nPUZBTFNFfQpkd2kkaW5kZXggPC0gc2VxLmludChucm93KGR3aSkpCgpkd2kudyA8LSBmaWx0ZXIoZHdpLCBkYXRlIDwgJzIwMTYtMDUtMDEnLCBkYXRlID4gJzIwMTItMDUtMScpCmR3aS5yZGQudyA8LSByZGR0b29sczo6cmRkX2RhdGEoeSA9IGR3aS53JGNvdW50LHggPSBkd2kudyRpbmRleCxjdXRwb2ludCA9IDc3KQoKZHdpLndvIDwtIGZpbHRlcihkd2ksIGRhdGUgPCAnMjAxNi0xMi0zMScsIGRhdGUgPiAnMjAxNC0wNS0zMCcpCmR3aS5yZGQud28gPC0gcmRkdG9vbHM6OnJkZF9kYXRhKHkgPSBkd2kud28kY291bnQseCA9IGR3aS53byRpbmRleCxjdXRwb2ludCA9IDEwMCkKCmxtLnc8LWxtKGNvdW50fkkoaW5kZXgtNzcpKnRyZWF0bWVudCxkd2kudykgCnJlZ19wYXJhLncgPC0gcmRkX3JlZ19sbShyZGRfb2JqZWN0ID0gZHdpLnJkZC53LCBvcmRlciA9IDEpCgpsbS53bzwtbG0oY291bnR+SShpbmRleC04KSp0cmVhdG1lbnQsZHdpLndvKSAKcmVnX3BhcmEud28gPC0gcmRkX3JlZ19sbShyZGRfb2JqZWN0ID0gZHdpLnJkZC53bywgb3JkZXIgPSAxKQoKCnByaW50KHJlZ19wYXJhLncpCnBsb3QocmVnX3BhcmEudykKI3N1bW1hcnkobG0udykgI2ZvciBhIHNhbml0eSBjaGVjawpgYGAKCkZvciB0aGUgZmlyc3QgdHJlYXRtZW50LCBSREQgdGVsbHMgdXMgKHRocm91Z2ggdGhlIFAtdmFsdWUgb2YgdGhlIHJlZ3Jlc3Npb24sIDAuNzM4NikgdGhlIHRoYXQgdGhlIGRyb3AgaXMgc21hbGwgZW5vdWdoIHJlbGF0aXZlIHRvIHRoZSB2YXJpYW5jZSBpbiB0aGUgZGF0YSB0aGF0IGFueSBidW1wIGFuZCBjaGFuZ2UgaW4gdGhlIHNsb3BlIG9mIHRoZSByZWdyZXNzaW9uIGlzICoqdG9vIHNtYWxsIHRvIGJlIGF0dHJpYnV0ZWQgdG8gYW55dGhpbmcgb3RoZXIgdGhhbiByYW5kb21uZXNzKiogLSBhdCBsZWFzdCB3aGVuIG1vZGVsZWQgd2l0aCBhIHN0cmFpZ2h0IGxpbmUuICBXZSdsbCBjb25zaWRlciB0aGF0IGEgc3RyYWlnaHQgbGluZSBpc24ndCB0aGUgYmVzdCB3YXkgdG8gZml0IHRoaXMgZGF0YSBsYXRlciBvbiAtIHJlbWVtYmVyIHdlIHNwZW50IHNvbWUgdGltZSBpbnZlc3RpZ2F0aW5nIHBlcmlvZGljIHBhdHRlcm5zLgoKSXQncyBhbHNvIHdvcnRoIG5vdGluZyB0aGF0IG91ciBwcmltYXJ5IGFzc3VtcHRpb24gaGVyZSAtIHRoYXQgZXZlcnl0aGluZyBpcyB0aGUgc2FtZSBvbiBlaXRoZXIgc2lkZSBvZiB0aGUgdHJlYXRtZW50IC0gbWlnaHQgbm90IGhvbGQsIGFzIHRoZSBwb3B1bGFyaXR5IGFuZCBjYXBhY2l0eSBvZiByaWRlc2hhcmluZyBwcm9iYWJseSBncmV3IG92ZXIgdGltZS4gIFJERCBtYXkgbm90IGJlIGEgcmlnb3JvdXMgd2F5IHRvIGluc3BlY3QgdGhpcyBzaWRlIG9mIHRoZSB0cmVhdG1lbnQuCgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpwcmludChyZWdfcGFyYS53bykKcGxvdChyZWdfcGFyYS53bykKI3N1bW1hcnkobG0ud28pICNmb3IgYSBzYW5pdHkgY2hlY2sKYGBgCgpGb3IgdGhlIHNlY29uZCB0cmVhdG1lbnQsIHRoZSBqdW1wIGluIHRoZSByZWdyZXNzaW9uIGlzIG1vcmUgcHJvbm91bmNlZCBhbmQgdGhlIHNsb3BlIGNoYW5nZXMgd2lsZGx5IC0gb3VyIFAgdmFsdWVzIGFyZSBsb3cgZW5vdWdoICg8IDElIGNoYW5jZSB0aGF0IHRoaXMgcmVzdWx0IGlzIGR1ZSB0byByYW5kb21uZXNzKSB0byBjb25jbHVkZSB0aGF0IHRoZSBjaGFuZ2UgKiptYXkgYmUgZHVlIHRvIHRoZSBkaXNjb250aW51aXR5IGluIE1heSAyMDE2IGFuZCBub3QgcmFuZG9tIGNoYW5jZSoqLiAgSSB0aGluayB0aGlzIG1pZ2h0IGJlIGEgbW9yZSB2YWxpZCBjYXNlIGZvciBSREQgdGhhbiB0aGUgZmlyc3Qgc2lkZSBvZiB0aGUgdHJlYXRtZW50IC0gVWJlciBhbmQgTHlmdCBxdWl0ZSBsaXRlcmFsbHkgc3RvcHBlZCBvZmZlcmluZyByaWRlc2hhcmluZyB0aGUgTW9uZGF5IGFmdGVyIHRoZSB2b3RlIGNhbWUgZG93bi4gIFRoaXMgaXMgYSBwb2ludCBpbiBmYXZvciBvZiByaWRlc2hhcmluZywgYnV0IHdlJ3JlIG5vdCBvdXQgb2YgdGVjaG5pcXVlcyB5ZXQuCgojI0V4cG9uZW50aWFsIFNtb290aGluZwoKT3VyIHJlZ3Jlc3Npb24gZGlzY29udGludWl0eSBkZXNpZ24gZml0IDFzdCBkZWdyZWUgcG9seW5vbWlhbHMgdG8gdGhlIERXSSBkYXRhLCBidXQgd2hhdCBpZiB0aGUgYmVoYXZpb3IgaXMgbW9yZSBjb21wbGljYXRlZCB0aGFuIHRoYXQ/ICBXZSBvYnNlcnZlZCBlYXJsaWVyIHRoYXQgdGhlcmUgbWF5IGJlIGEgcGVyaW9kaWMgY29tcG9uZW50IHRvIHRoZSBkYXRhLCB3aGF0IGlmIHJpZGVzaGFyaW5nIGRpc3J1cHRzIGJ1c3kgRFdJIG1vbnRocyBidXQgbm90IHNsb3dlciBtb250aHMsIHdvdWxkIGEgc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIHVuY292ZXIgdGhhdD8gIEFzIHdlIG1lbnRpb25lZCwgVWJlciBhbmQgTHlmdCdzIHJpZGVzaGFyaW5nIGNhcGFjaXR5IGdyZXcgYXMgdGhleSBhZGRlZCBkcml2ZXJzIChjZXJ0YWlubHkgIGEgbWV0cmljIEknZCBsaWtlIHRvIGdldCBteSBoYW5kcyBvbiksIGhvdyBjYW4gd2UgaW52ZXN0aWdhdGUgYSBoaWdoZXItZGVncmVlIGNoYW5nZSBpbiBEV0k/CgpFeHBvbmVudGlhbCBTbW9vdGhpbmcgaXMgYSB0ZWNobmlxdWUgdXNlZCBpbiBhIHdob2xlIGNsYXNzIG9mIG1ldGhvZHMgZm9yIHByZWRpY3RpbmcgZnV0dXJlIHZhbHVlcyBpbiBhIHRpbWUgc2VyaWVzIGJhc2VkIG9uIG1hbmlwdWxhdGlvbnMgb2YgcGFzdCB2YWx1ZXMuICBIb2x0LVdpbnRlcnMgRm9yZWNhc3RpbmcgaXMgYSBtZXRob2Qgb2YgcHJlZGljdGluZyB0aW1lLXNlcmllcyBkYXRhIHRoYXQgaGFzIHN0cm9uZyBwZXJpb2RpYyBjb21wb25lbnRzIGJ5IHNlcGFyYXRlbHkgc21vb3RoaW5nIGxvbmctdGVybSB0cmVuZCwgc2hvcnQtdGVybSBzZWFzb25hbGl0eSwgYW5kIGxvY2FsIGNvbXBvbmVudHMgdG8gY3JlYXRlIGEgZm9yZWNhc3QgdGhhdCB0YWtlcyBpbnRvIGFjY291bnQgcHJlZGljdGFibGUgdmFyaWF0aW9ucyBpbiB0aGUgZGF0YS4gIFdlIHNhdyBhYm92ZSB0aGF0IG91ciBEV0kgZGF0YSBwcm9iYWJseSBoYXMgc29tZSB5ZWFybHkgdHJlbmRzIGluIGl0IC0gdGhlIGRhdGEgc2hvd3MgaXQgYSBsaXR0bGUsIGFuZCB5b3UgY2FuIEdvb2dsZSBhcm91bmQgZm9yIGFydGljbGVzIGFib3V0IERXSSBpbiBBdXN0aW4gYW5kIHNlZSBmb3IgeW91cnNlbGYgdGhhdCBKYW51YXJ5IGlzIGEgc3BlY2lhbCBtb250aCBmb3IgdGhlIHBvbGljZSAobG9vayBmb3IgJ25vLXJlZnVzYWwgd2Vla2VuZCcpLiBXZSBhbHNvIGdvdCBhIHNlbnNlIHRoYXQgYSBmZXcgeWVhcnMgc2F3IGEgY29udGludW91cyByZWR1Y3Rpb24gaW4gRFdJIGFycmVzdHMsIHBlcmhhcHMgYXMgYnJvYWQgYW50aS1EV0kgbWVhc3VyZXMga2lja2VkIGluLiAgV2UnbGwgZGVjb21wb3NlIHRoZSBEV0kgYW5kIERXSS8kIHJlYWxseSBxdWljayBhbmQgeW91IGNhbiBzZWUgZm9yIHlvdXJzZWxmOgoKYGBge3Igd2FybmluZz1GQUxTRX0KcGxvdChzdGwodHMoZHdpJGNvdW50LCBzdGFydCA9IGMoMjAwOCwgMSksIGZyZXF1ZW5jeSA9IDEyKSwgcy53aW5kb3c9InBlcmlvZGljIikpCgpwbG90KHN0bCh0cyhkd2kkY291bnRfcGVyX21tLCBzdGFydCA9IGMoMjAwOCwgMSksIGZyZXF1ZW5jeSA9IDEyKSwgcy53aW5kb3c9InBlcmlvZGljIikpCmBgYAoKWW91IGNhbiBzZWUgc2Vhc29uYWxpdHkgY29udHJpYnV0ZXMgdG8gYSBzd2luZyBvZiA3MCBEV0kgYXJyZXN0cywgb3IgMi41IGFycmVzdHMgcGVyICRNTS4gIEFkZGl0aW9uYWxseSwgeW91IGNhbiBzZWUgYSBoaWdobHkgc21vb3RoZWQgdHJlbmQgZm9yIGFsbCB0aGUgZGF0YSBvdmVyIG91ciBlbnRpcmUgdGltZSBmYW1lLCBhbmQgdGhlIHJlbWFpbmRlciB0aGF0IHRoaXMgZGVjb21wb3NpdGlvbiBkb2Vzbid0IHRoaW5rIGlzIGF0dHJpYnV0YWJsZSB0byBhIHBhdHRlcm4uCgojIyNQcmUtVWJlciwgYW5kIFZhbGlkYXRpbmcgSG9sdC1XaW50ZXJzCgpXaGF0IEknbSBnb2luZyB0byBkbyBpcyBmZWVkIERXSSBkYXRhIGZyb20gSmFudWFyeSAyMDA4IC0gTWF5IDIwMTQgKHRoZSBsYXN0IG1vbnRoIGJlZm9yZSBVYmVyIGFuZCBMeWZ0IHdlcmUgd2lkZWx5IGF2YWlsYWJsZSBpbiBBdXN0aW4pIGludG8gYSBIb2x0LVdpbnRlcnMgbW9kZWwgKHdoaWNoIHdpbGwgdXNlIHRoaXMgc2FtZSBgc3RsYCBzZWFzb25hbCBkZWNvbXBvc2l0aW9uKSBhbmQgZm9yZWNhc3QgRFdJIGNvdW50cyBmb3IgdGhlIG5leHQgZmV3IG1vbnRocyAod2UgY2FuIHJvbGwgdGhlIGRhdGEgYmFjayB0byAyMDA4IGFnYWluIGJlY2F1c2Ugd2UncmUgbm90IGNvbmNlcm5lZCB3aXRoIGxvY2FsIGVmZmVjdHMgc28gbXVjaCBhcyB0cmVuZHMgaW5oZXJlbnQgaW4gRFdJIGNvdW50cykuIAoKSSdtIHRoZW4gZ29pbmcgdG8gY29tcGFyZSB0aG9zZSB0byB0aGUgYWN0dWFsIGRhdGEsIHdpdGggdGhlIHJlYXNvbmluZyB0aGF0IF9zaW5jZSB0aGUgbW9kZWwgdGFrZXMgaW50byBhY2NvdW50IHllYXJseSBjeWNsZXMgYW5kIGJyb2FkIHRyZW5kcywgaXQgd2lsbCBjb21lIHVwIHdpdGggYSBwcmVkaWN0aW9uIGZvciBEV0kgY291bnRzIGFzIGlmIHJpZGVzaGFyaW5nIG5ldmVyIGFwcGVhcmVkLl8gIFdlIGNhbiBjYWxsIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHByZWRpY3Rpb24gYW5kIHRoZSByZWFsIGRhdGEgdGhlIG51bWJlciBvZiBEV0kncyByaWRlc2hhcmluZyBwcmV2ZW50ZWQgLSBvciBtYXliZSBjYXVzZWQuCgpMZXQncyBnZXQgY29uZmlkZW50IGluIHRoaXMgbWV0aG9kIC0gZmlyc3QgSSdtIGdvaW5nIHRvIHRha2Ugc29tZSB1bnRyZWF0ZWQgbW9udGhzIGFuZCBzZWUgaWYgd2UgY2FuIHByZWRpY3QgdGhlbSByZWxpYWJseS4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmR3aS5wcmUgPC0gZmlsdGVyKGR3aSxkYXRlIDwgJzIwMTMtMTAtMzEnKQpkd2kucG9zdCA8LSBmaWx0ZXIoZHdpLGRhdGUgPiAnMjAxMy0xMC0zMScpCgpkd2kucHJlLmNvdW50LnRzIDwtIHRzKGR3aS5wcmUkY291bnQsIHN0YXJ0ID0gYygyMDA4LCAxKSwgZnJlcXVlbmN5ID0gMTIpCmR3aS5wb3N0LmNvdW50LnRzIDwtIHRzKGR3aS5wb3N0JGNvdW50LCBzdGFydCA9IGMoMjAxMywgNiksIGZyZXF1ZW5jeSA9IDEyKQojZHdpLnBvc3QuY291bnQudHMgPC0gdHMoZHdpLnBvc3QkY291bnQsIHN0YXJ0ID0gYygyMDEzLCAxMSksIGZyZXF1ZW5jeSA9IDEyKSBmdXRoZXIgYmFjayBmb3JlY2FzdAoKZHdpLnByZS5jb3VudC5odyA8LSBIb2x0V2ludGVycyhkd2kucHJlLmNvdW50LnRzKQoKZm9yZWNhc3QgPC0gcHJlZGljdChkd2kucHJlLmNvdW50Lmh3LCBuLmFoZWFkID0gNiwgcHJlZGljdGlvbi5pbnRlcnZhbCA9IFQsIGxldmVsID0gMC45KQoKI2FjZigoZHdpLnByZS5jb3VudC5odyRmaXR0ZWQgLSBkd2kucHJlLmNvdW50LnRzKVssMV0pICNjb25maXJtIG5vIGF1dG9jb3JyZWxhdGlvbnMgaW4gcmVzaWR1YWwKI2hpc3QoKGR3aS5wcmUuY291bnQuaHckZml0dGVkIC0gZHdpLnByZS5jb3VudC50cylbLDFdLDMwKSAjY29uZmlybSByZXNpZHVhbCBsb29rcyBub3JtYWwKCnBsb3QoZHdpLnByZS5jb3VudC5odywgZm9yZWNhc3QpOyBsaW5lcyhkd2kucG9zdC5jb3VudC50cyxjb2w9J2dyZWVuJykKCmVmZmVjdCA8LSBmb3JlY2FzdCAtIGR3aS5wb3N0LmNvdW50LnRzCgojdHRlc3QgZm9yIDEybW9udGgKI3ByZS5yZXNpZHVhbCA8LSBhcy5udW1lcmljKChkd2kucHJlLmNvdW50Lmh3JGZpdHRlZCAtIGR3aS5wcmUuY291bnQudHMpWywxXSkKI3Bvc3QucmVzaWR1YWwgPC0gYXMubnVtZXJpYyhlZmZlY3QpCiN0LnRlc3QocHJlLnJlc2lkdWFsLHBvc3QucmVzaWR1YWwpICMuNTkgdG9vIGhpZ2gKCnBjdC5lZmZlY3QgPC0gY3Vtc3VtKGVmZmVjdCkvY3Vtc3VtKGZvcmVjYXN0KQpwY3QuZWZmZWN0WzZdCmBgYAoKV2hhdCB3ZSdyZSBsb29raW5nIGF0IGhlcmUgaXMgcmVhbCBkYXRhIGJlZm9yZSBvdXIgdHJlYXRtZW50IChpbiBibGFjayksIGFuZCBhIGZpdHRlZCBtb2RlbCB3aXRoIGEgZm9yZWNhc3QgZXh0ZW5kaW5nIGludG8gb3VyIHRyZWF0bWVudCAoaW4gcmVkKSwgd2l0aCB0d28gOTAlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzICh0aGVzZSBhcmUgY2FsbGVkIHByZWRpY3Rpb24gaW50ZXJ2YWxzIGluIHRoaXMgY29udGV4dCwgdGhleSdyZSBpbiBibHVlKSwgYW5kIHJlYWwgdHJlYXRtZW50IGRhdGEgKGluIGdyZWVuKS4gIFdlJ2xsIHBsb3QgYWxsIG91ciBIb2x0LVdpbnRlcnMgbW9kZWxzIGxpa2UgdGhpcy4KCk5vdCBiYWQuICBUaGUgbW9kZWwgaXMgYSBsaXR0bGUgcm91Z2ggLSBpdCBmaXRzIGl0IGFwcHJveGltYXRlbHkgYnV0IGZhaWxzIHRvIGNhdGNoIGFsbCB0aGUgcGVha3MgLSB0aGUgZGF0YSBtYXkgbm90IGhhdmUgYmVlbiBwZXJpb2RpYyBlbm91Z2ggZm9yIHRoaXMgbW9kZWwgdG8gYmUgZWZmZWN0aXZlLCBvciB0aGVyZSBtYXkgYmUgdG9vIG11Y2ggbm9uLXNlYXNvbmFsIG5vaXNlLgoKQSBmYWlsdXJlIHRvIGZ1bGx5IG1vZGVsIHRoZSBzZWFzb25hbGl0eSB3b3VsZCBoYXZlIHNob3duIHVwIGFzIGFuIGF1dG9jb3JyZWxhdGlvbiBvciBub24tbm9ybWFsaXR5IGluIHRoZSByZXNpZHVhbHMgLSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBtb2RlbCdzIGZpdCBhbmQgdGhlIHJlYWwgZGF0YSwgb3ZlciB0aGUgc2V0IG9mIGRhdGEgd2UgdXNlZCB0byB0cmFpbiBpdC4gIElmIHlvdSdyZSBjdXJpb3VzIHlvdSBjYW4gdW5jb21tZW50IHRoZSBgYWNmYCBhbmQgYGhpc3RgIGNhbGxzIGFuZCBzZWUgZm9yIHlvdXJzZWxmIC0gb3RoZXJ3aXNlIHRydXN0IG1lIHRoYXQgSSd2ZSB2ZXJpZmllZCB0aGF0IHRoaXMgbW9kZWwgZnVsbHkgY2FwdHVyZXMgdGhlIHNlYXNvbmFsaXR5IGF2YWlsYWJsZSBpbiB0aGUgdHJhaW5pbmcgc2V0LgoKVXNpbmcgdGhlIGRhdGEgZnJvbSBKYW51YXJ5IDIwMDggdG8gT2N0b2JlciAyMDEzLCBpdCBsb29rcyBsaWtlIHdlIGNhbiAqKnByZWRpY3QgY3VtdWxhdGl2ZSBEV0kncyBmb3IgdGhlIG5leHQgNiBtb250aHMgd2l0aGluIDEuNSUuKiogIFRoYXQncyBwcmV0dHkgY2xvc2UsIGFuZCB0aGF0IHNob3VsZCBtYWtlIHVzIGZlZWwgYmV0dGVyIGFib3V0IHRoZSBudW1iZXJzIGNvbWluZyBvdXQsIHdpdGggdGhlIGNhdmVhdCB0aGF0IGN1bXVsYXRpdmUgRFdJIHByZWRpY3Rpb25zIG92ZXIgbG9uZ2VyIHRpbWUgZnJhbWVzIG1heSBiZSBtb3JlIGFjY3VyYXRlIHRoYW4gcGlja2luZyBpbmRpdmlkdWFsIG1vbnRocy4gKElmIHlvdSdyZSByZWFkaW5nIHRoZSBjb21tZW50ZWQtb3V0IGJpdHMgb2YgY29kZSwgeW91J2xsIG5vdGUgdGhhdCBJIGFsc28gdmFsaWRhdGVkIHByZWRpY3Rpb25zIDEyIG1vbnRocyBvdXQgd2l0aGluIDElKS4gIExldCdzIG1vdmUgdGhlIGVuZCBvZiB0aGUgdHJhaW5pbmcgZGF0YSB0byBNYXkgMjAxNCAodGhlIGxhc3QgbW9udGggd2l0aG91dCBVYmVyIGFuZCBMeWZ0KSBhbmQgc2VlIGhvdyB0aGluZ3MgbG9vayAod2UnbGwgaW1wcm92ZSB0aGUgbW9kZWwgYSBsaXR0bGUgbW9yZSBieSBhZGRpbmcgdGhvc2UgZXh0cmEgNiBtb250aHMgdG8gdGhlIHRyYWluaW5nIHNldCBhcyB3ZWxsKS4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmR3aS5wcmUgPC0gZmlsdGVyKGR3aSxkYXRlIDwgJzIwMTQtMDUtMzEnKQpkd2kucG9zdCA8LSBmaWx0ZXIoZHdpLGRhdGUgPiAnMjAxNC0wNS0zMScpCgpkd2kucHJlLmNvdW50LnRzIDwtIHRzKGR3aS5wcmUkY291bnQsIHN0YXJ0ID0gYygyMDA4LCAxKSwgZnJlcXVlbmN5ID0gMTIpCmR3aS5wb3N0LmNvdW50LnRzIDwtIHRzKGR3aS5wb3N0JGNvdW50LCBzdGFydCA9IGMoMjAxNCwgNiksIGZyZXF1ZW5jeSA9IDEyKQoKZHdpLnByZS5jb3VudC5odyA8LSBIb2x0V2ludGVycyhkd2kucHJlLmNvdW50LnRzKQoKZm9yZWNhc3QgPC0gcHJlZGljdChkd2kucHJlLmNvdW50Lmh3LCBuLmFoZWFkID0gMjQsIHByZWRpY3Rpb24uaW50ZXJ2YWwgPSBULCBsZXZlbCA9IDAuOSkKCiNhY2YoKGR3aS5wcmUuY291bnQuaHckZml0dGVkIC0gZHdpLnByZS5jb3VudC50cylbLDFdKSAjY29uZmlybSBubyBhdXRvY29ycmVsYXRpb25zIGluIHJlc2lkdWFsCiNoaXN0KChkd2kucHJlLmNvdW50Lmh3JGZpdHRlZCAtIGR3aS5wcmUuY291bnQudHMpWywxXSwzMCkgI2NvbmZpcm0gcmVzaWR1YWwgbG9va3Mgbm9ybWFsCgpwbG90KGR3aS5wcmUuY291bnQuaHcsIGZvcmVjYXN0KTsgbGluZXMoZHdpLnBvc3QuY291bnQudHMsY29sPSdncmVlbicpCgplZmZlY3QgPC0gZm9yZWNhc3QgLSBkd2kucG9zdC5jb3VudC50cwoKcGN0LmVmZmVjdCA8LSBjdW1zdW0oZWZmZWN0KS9jdW1zdW0oZm9yZWNhc3QpCnBjdC5lZmZlY3RbMTJdCnBjdC5lZmZlY3RbM10KYGBgCgpGb3IgdGhlIGZpcnN0IDEyIG1vbnRocyBVYmVyIGFuZCBMeWZ0IHdlcmUgYXZhaWxhYmxlIGluIEF1c3RpbiwgdGhlICoqcmVhbCBjdW11bGF0aXZlIERXSSBjb3VudCB3YXMgNDQwIGFycmVzdHMgbGVzcyB0aGFuIHRoZSBwcmVkaWN0ZWQgY291bnQgLSBhbiBlZmZlY3Qgb2YgYWJvdXQgNyUqKiAob3ZlciB0aGUgd2hvbGUgMjQtbW9udGggcGVyaW9kLCB3ZSBzZWUgOCUpLiAgRm9yIHRoZSBmaXJzdCAzIG1vbnRocywgd2hlcmUgb3VyIGVycm9yIGJhcnMgYXJlIG11Y2ggdGlnaHRlciAoYW5kIHBlcmhhcHMgd2hpbGUgVWJlciBhbmQgTHlmdCB3ZXJlIHN0aWxsIGdyb3dpbmcgaW4gY2FwYWNpdHkpLCB3ZSdyZSBvbmx5IDI0IERXSSdzIGxlc3MgdGhhbiBwcmVkaWN0ZWQgLSBhIGRlY3JlYXNlIG9mIDEuNiUuCgpOb3cgeW91J3JlIHByb2JhYmx5IHdvbmRlcmluZyAtIHRoZSByZWFsIHZhbHVlcyBhcmUgc3RpbGwgd2VsbCB3aXRoaW4gdGhlc2UgcHJlZGljdGlvbiBiYW5kcywgd2hhdCBkb2VzIHRoYXQgbWVhbj8gIElmIG91ciByZWFsIGRhdGEgd2FzIGEgZmV3IHBvaW50cywgaXQgd291bGQgbWVhbiB3ZSBwcm9iYWJseSBjb3VsZG4ndCBjb3VudCBvbiBpdCB0byB0ZWxsIHVzIGFueXRoaW5nIC0gaXQgY291bGQgYmUgd2VsbCB3aXRoaW4gdGhlIG1vZGVsJ3MgdG9sZXJhbmNlIGZvciByYW5kb20gY2hhbmNlLCBhbmQgd2Ugd291bGRuJ3QgYmUgc2VlaW5nIGEgdHJlYXRtZW50IGVmZmVjdCwganVzdCBhIGNvaW5jaWRlbmNlLiAgQnV0IHdlIGhhdmUgYSBsb3Qgb2YgcG9pbnRzLCBhbmQgYWxsIG9mIHRoZW0gYXJlIGJlbG93IHRoZSBmb3JlY2FzdCB2YWx1ZSAtIGNhbiB3ZSB0ZWxsIGlmIHRoZXNlIHZhbHVlcyBhcmUgbWVhbmluZ2Z1bGx5IGRpZmZlcmVudCB0aGFuIHRoZSBmb3JlY2FzdD8KCldlIGNhbi4gIFNpbmNlIHdlJ3ZlIHZhbGlkYXRlZCB0aGF0IG91ciByZXNpZHVhbHMgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCB3ZSBjYW4gdXNlIGEgdC10ZXN0IHRvIGNoZWNrIGlmIHRoZSBmaXQtdnMtdHJhaW5pbmcgcmVzaWR1YWxzIGFyZSBkaWZmZXJlbnQgZnJvbSB0aGUgZm9yZWNhc3QtdnMtcmVhbCByZXNpZHVhbHMsIHdoaWNoIHdvdWxkIHRlbGwgdXMgdGhhdCB0aGUgdHJlYXRtZW50IGVmZmVjdCB3ZSdyZSBzZWVpbmcgaXMgcmVhbCwgd2l0aCBzb21lIGRlZ3JlZSBvZiBjb25maWRlbmNlLgoKYGBge3J9CnByZS5yZXNpZHVhbCA8LSBhcy5udW1lcmljKChkd2kucHJlLmNvdW50Lmh3JGZpdHRlZCAtIGR3aS5wcmUuY291bnQudHMpWywxXSkKcG9zdC5yZXNpZHVhbCA8LSBlZmZlY3RbLDFdCnQudGVzdChwcmUucmVzaWR1YWwscG9zdC5yZXNpZHVhbCkKCiNxcGxvdChhcy5udW1lcmljKHByZS5yZXNpZHVhbCksIGdlb209ImRlbnNpdHkiKQojcXBsb3QoYXMubnVtZXJpYyhwb3N0LnJlc2lkdWFsKSwgZ2VvbT0iZGVuc2l0eSIpCmBgYAoKVGhlIHAtdmFsdWUgb2YgMC4wMDAwNiB0ZWxscyB1cyB0aGVzZSByZXN1bHRzIGFyZSBzaWduaWZpY2FudC4gIFdlJ2xsIGtlZXAgYW4gZXllIG9uIHRoZXNlIGJlaGluZCB0aGUgc2NlbmVzLgoKV2UgY2FuIHRyeSBhIHBvdGVudGlhbGx5IGJldHRlci1maXR0aW5nIG1vZGVsIChyZWFsbHksIG9wdGltaXplZCBmb3IgYSBkaWZmZXJlbnQgY3JpdGVyaW9uKSBmcm9tIHRoZSBleHBvbmVudGlhbCBzbW9vdGhpbmcgZmFtaWx5IG9mIG1vZGVscyB3aXRoIGBldHNgLgoKYGBge3Igd2FybmluZz1GQUxTRX0KZHdpLnByZS5jb3VudC5ldHMgPC0gZXRzKGR3aS5wcmUuY291bnQudHMsIG1vZGVsID0gJ1paWicpCmZvcmVjYXN0LmV0cyA8LSBwcmVkaWN0KGR3aS5wcmUuY291bnQuZXRzLCBuLmFoZWFkID0gMjQsIHByZWRpY3Rpb24uaW50ZXJ2YWwgPSBULCBsZXZlbCA9IDAuOSkKCnBsb3QoZm9yZWNhc3QuZXRzKTsgbGluZXMoZHdpLnBvc3QuY291bnQudHMsY29sPSdncmVlbicpCgplZmZlY3QuZXRzIDwtIGZvcmVjYXN0LmV0cyRtZWFuIC0gZHdpLnBvc3QuY291bnQudHMKCiNwcmUucmVzaWR1YWwgPC0gYXMubnVtZXJpYygoZHdpLnByZS5jb3VudC5ldHMkZml0dGVkIC0gZHdpLnByZS5jb3VudC5ldHMpWywxXSkKI3Bvc3QucmVzaWR1YWwgPC0gYXMubnVtZXJpYyhlZmZlY3QuZXRzKQojdC50ZXN0KHByZS5yZXNpZHVhbCxwb3N0LnJlc2lkdWFsKSAjZS03CgpwY3QuZWZmZWN0LmV0cyA8LSBjdW1zdW0oZWZmZWN0LmV0cykvY3Vtc3VtKGZvcmVjYXN0LmV0cyRtZWFuKQpwY3QuZWZmZWN0LmV0c1sxMl0KcGN0LmVmZmVjdC5ldHNbM10KYGBgCgpUaGlzIHBsb3QgbG9va3MgbGlrZSBvdXIgSG9sdC1XaW50ZXJzIHBsb3RzLCBidXQgb21pdHMgdGhlIGZpdHRlZCBjdXJ2ZSBiZWZvcmUgdGhlIHRyZWF0bWVudCwgYW5kIHRoZSBmb3JlY2FzdCBpcyBpbiBibHVlLgoKV2l0aCBtdWNoIHRpZ2h0ZXIgcHJlZGljdGlvbiBpbnRlcnZhbHMsIGBldHNgIHN1Z2dlc3RzICoqYSBkcm9wIG9mIDguNSUgb3ZlciAxMiBtb250aHMqKiAoOS43IG92ZXIgdGhlIGZ1bGwgMjQpIGFuZCA1LjYlIG92ZXIgMyBtb250aHMuCgpJJ2QgbGlrZSB0byBsb29rIGF0IG91ciBEV0kgcGVyIFJldmVudWUgdmFyaWFibGUsIGJ1dCBmaXJzdCB3ZSBoYXZlIHRvIGFuc3dlciwgaG93IG11Y2ggZGlkIHJpZGVzaGFyaW5nIGFmZmVjdCBiYXIgcmV2ZW51ZXM/ICBJZiBpdCdzIGEgbG90LCB3ZSdsbCBoYXZlIGEgaGFyZCB0aW1lIGF0dHJpYnV0aW5nIGEgY2hhbmdlIGluIERXSS8kIHRvIGEgY2hhbmdlIGluIERXSSdzLgoKYGBge3Igd2FybmluZz1GQUxTRX0KZHdpLnByZS5yZXYudHMgPC0gdHMoZHdpLnByZSRyZXYsIHN0YXJ0ID0gYygyMDA4LCAxKSwgZnJlcXVlbmN5ID0gMTIpCmR3aS5wb3N0LnJldi50cyA8LSB0cyhkd2kucG9zdCRyZXYsIHN0YXJ0ID0gYygyMDE0LCA2KSwgZnJlcXVlbmN5ID0gMTIpCgpkd2kucHJlLnJldi5ldHMgPC0gZXRzKGR3aS5wcmUucmV2LnRzLCBtb2RlbCA9ICdaWlonKQpmb3JlY2FzdC5ldHMgPC0gcHJlZGljdChkd2kucHJlLnJldi5ldHMsIG4uYWhlYWQgPSAyNCwgcHJlZGljdGlvbi5pbnRlcnZhbCA9IFQsIGxldmVsID0gMC45KQoKcGxvdChmb3JlY2FzdC5ldHMpOyBsaW5lcyhkd2kucG9zdC5yZXYudHMsY29sPSdncmVlbicpCgplZmZlY3QuZXRzIDwtIGZvcmVjYXN0LmV0cyRtZWFuIC0gZHdpLnBvc3QucmV2LnRzCgojcHJlLnJlc2lkdWFsIDwtIGFzLm51bWVyaWMoKGR3aS5wcmUucmV2LmV0cyRmaXR0ZWQgLSBkd2kucHJlLnJldi50cykpCiNwb3N0LnJlc2lkdWFsIDwtIGFzLm51bWVyaWMoZWZmZWN0LmV0cykKI3QudGVzdChwcmUucmVzaWR1YWwscG9zdC5yZXNpZHVhbCkgIy4wMDEKCnBjdC5lZmZlY3QuZXRzIDwtIGN1bXN1bShlZmZlY3QuZXRzKS9jdW1zdW0oZm9yZWNhc3QuZXRzJG1lYW4pCnBjdC5lZmZlY3QuZXRzWzNdCnBjdC5lZmZlY3QuZXRzWzEyXQpgYGAKCkxvb2tzIGxpa2Ugd2Ugc2VlIGEgKiozJSByaXNlIGluIFRBQkMgc2FsZXMgZHVlIHRvIHJpZGVzaGFyaW5nKiogLSB3aGljaCBzZWVtcyBlYXN5IHRvIHJlYXNvbiBhcm91bmQsIGlmIHlvdSBkb24ndCBoYXZlIHRvIHdvcnJ5IGFib3V0IGRyaXZpbmcgeW91IGNvdWxkIGJlIGRyaW5raW5nIG1vcmUuICBJIGRvbid0IHdhbnQgdG8gc3BlbmQgdG9vIG11Y2ggdGltZSBmb2N1c2luZyBvbiBUQUJDIHNhbGVzIGFuZCByaWRlc2hhcmluZywgYnV0IEknbGwgbWVudGlvbiB0aGF0IGFjY29yZGluZyB0byB0aGlzLCB0aGF0J3MgYW4gaW5jcmVhc2Ugb2YgYWJvdXQgKiokNjgsMDAwLDAwMCBpbiByZXZlbnVlKiogdG8gbG9jYWwgYnVzaW5lc3NlcyBvdmVyIDI0IG1vbnRocywgb3Igcm91Z2hseSAqKiQ5LDUwMCwwMDAgaW4gZXh0cmEgdGF4ZXMqKi4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmR3aS5wcmUuY291bnRfcGVyX21tLnRzIDwtIHRzKGR3aS5wcmUkY291bnRfcGVyX21tLCBzdGFydCA9IGMoMjAwOCwgMSksIGZyZXF1ZW5jeSA9IDEyKQpkd2kucG9zdC5jb3VudF9wZXJfbW0udHMgPC0gdHMoZHdpLnBvc3QkY291bnRfcGVyX21tLCBzdGFydCA9IGMoMjAxNCwgNiksIGZyZXF1ZW5jeSA9IDEyKQoKZHdpLnByZS5jb3VudF9wZXJfbW0uZXRzIDwtIGV0cyhkd2kucHJlLmNvdW50X3Blcl9tbS50cywgbW9kZWwgPSAnWlpaJykKZm9yZWNhc3QuZXRzIDwtIHByZWRpY3QoZHdpLnByZS5jb3VudF9wZXJfbW0uZXRzLCBuLmFoZWFkID0gMjQsIHByZWRpY3Rpb24uaW50ZXJ2YWwgPSBULCBsZXZlbCA9IDAuOSkKCnBsb3QoZm9yZWNhc3QuZXRzKTsgbGluZXMoZHdpLnBvc3QuY291bnRfcGVyX21tLnRzLGNvbD0nZ3JlZW4nKQoKZWZmZWN0LmV0cyA8LSBmb3JlY2FzdC5ldHMkbWVhbiAtIGR3aS5wb3N0LmNvdW50X3Blcl9tbS50cwoKI3ByZS5yZXNpZHVhbCA8LSBhcy5udW1lcmljKChkd2kucHJlLmNvdW50X3Blcl9tbS5ldHMkZml0dGVkIC0gZHdpLnByZS5jb3VudF9wZXJfbW0udHMpKQojcG9zdC5yZXNpZHVhbCA8LSBhcy5udW1lcmljKGVmZmVjdC5ldHMpCiN0LnRlc3QocHJlLnJlc2lkdWFsLHBvc3QucmVzaWR1YWwpICMuMDAwNwoKCnBjdC5lZmZlY3QuZXRzIDwtIGN1bXN1bShlZmZlY3QuZXRzKS9jdW1zdW0oZm9yZWNhc3QuZXRzJG1lYW4pCnBjdC5lZmZlY3QuZXRzWzEyXQpwY3QuZWZmZWN0LmV0c1szXQpgYGAKCkVUUyB0ZWxscyB1cyBhIHdob3BwaW5nICoqMTMlIGRyb3Agb3ZlciAxMiBtb250aHMgKDEwJSBvdmVyIDMsIDE3JSBvdmVyIDI0KSBpbiBEV0kvJE1NIGlzIGF0dHJpYnV0YWJsZSB0byByaWRlc2hhcmluZyoqIC0gd2VsbCBiZXlvbmQgdGhlIGNoYW5nZSB3ZSBzYXcgZnJvbSBqdXN0IHRoZSByaXNlIGluICRNTS4KCiMjI1Bvc3QtVWJlcgoKTGV0J3MgdHJ5IHRoZSBvdGhlciBzaWRlIC0gZml0IGEgbW9kZWwgZnJvbSBkYXRhIHN0YXJ0aW5nIGZyb20gVWJlcidzIGZpcnN0IG1vbnRoLCBhbmQgdGhlbiBzdG9wcGluZyBvbiBVYmVyJ3MgbGFzdCBtb250aC4gIElmIHRoZSBwcmVkaWN0aW9uIGlzIGxvd2VyIHRoYW4gdGhlIHJlYWwgZGF0YSwgd2UgbWlnaHQgYmUgYWJsZSB0byBzYXkgdGhhdCByaWRlc2hhcmluZyB3YXMgaGF2aW5nIGFuIGVmZmVjdCwgYnV0IHRoZXJlIHdhcyBzb21lIG90aGVyIGZhY3RvciBjb250YW1pbmF0aW5nIHRoZSBkYXRhIGZyb20gMjAwOC0yMDE0IChzYXkgYW4gb3JnYW5pemVkIGNhbXBhaWduIGFnYWluc3QgZHJ1bmsgZHJpdmluZyBvciBzb21ldGhpbmcpLgoKV2UncmUgZ29pbmcgdG8gY2hlYXQgYSB0aW55IGJpdCBiZWNhdXNlIHdlIG5lZWQgYW5vdGhlciBzYW1wbGUgb2YgZGF0YSAoSG9sdC1XaW50ZXJzIHJlcXVpcmVzIDIgZnVsbCB5ZWFycyBvZiBkYXRhIGhlcmUpIC0gc28gSSdtIGdvaW5nIHRvIHNheSBVYmVyIGFjdHVhbGx5IG9wZW5lZCBmb3IgYnVzaW5lc3MgYSBtb250aCBlYXJsaWVyIHRoYW4gaXQgZGlkLiAgSG9wZWZ1bGx5IHRoZSBmaXJzdCBtb250aCB3YXMgcmVsYXRpdmVseSBzbG93IGFzIHBlb3BsZSBzdGFydGVkIGFkb3B0aW5nIHRvIHJpZGVzaGFyaW5nLCBhbmQgaXQgd29uJ3QgbWFrZSBtdWNoIG9mIGEgZGlmZmVyZW5jZSB0byBzdHJldGNoIHRoZSBlZmZlY3Qgb3V0IG92ZXIgb25lIG1vcmUgbW9udGggaW4gYWRkaXRpb24gdGhlIDIzIG1vbnRocyBVYmVyIGFuZCBMeWZ0IHdlcmUgaW4gQXVzdGluLgoKYGBge3Igd2FybmluZz1GQUxTRX0KZHdpLmR1cmluZyA8LSBkd2kgJT4lIGZpbHRlcihkYXRlID49ICcyMDE0LTUtMDEnKSAlPiUgZmlsdGVyKGRhdGUgPCAnMjAxNi0wNS0wMScpCmR3aS5leGl0IDwtIGZpbHRlcihkd2ksZGF0ZSA+PSAnMjAxNi0wNS0wMScpCgpkd2kuZHVyaW5nLmNvdW50LnRzIDwtIHRzKGR3aS5kdXJpbmckY291bnQsIHN0YXJ0ID0gYygyMDE0LCA1KSwgZnJlcXVlbmN5ID0gMTIpCmR3aS5leGl0LmNvdW50LnRzIDwtIHRzKGR3aS5leGl0JGNvdW50LCBzdGFydCA9IGMoMjAxNiwgNSksIGZyZXF1ZW5jeSA9IDEyKQoKZHdpLmR1cmluZy5jb3VudC5odyA8LSBIb2x0V2ludGVycyhkd2kuZHVyaW5nLmNvdW50LnRzKQoKZm9yZWNhc3QgPC0gcHJlZGljdChkd2kuZHVyaW5nLmNvdW50Lmh3LCBuLmFoZWFkID0gMTIsIHByZWRpY3Rpb24uaW50ZXJ2YWwgPSBULCBsZXZlbCA9IDAuOSkKcGxvdChkd2kuZHVyaW5nLmNvdW50Lmh3LCBmb3JlY2FzdCk7IGxpbmVzKGR3aS5leGl0LmNvdW50LnRzLGNvbD0nZ3JlZW4nKQoKZWZmZWN0IDwtIGZvcmVjYXN0IC0gZHdpLmV4aXQuY291bnQudHMKCiNwcmUucmVzaWR1YWwgPC0gYXMubnVtZXJpYygoZHdpLmR1cmluZy5jb3VudC5odyRmaXR0ZWQgLSBkd2kuZHVyaW5nLmNvdW50LnRzKSkKI3Bvc3QucmVzaWR1YWwgPC0gYXMubnVtZXJpYyhlZmZlY3QpCiN0LnRlc3QocHJlLnJlc2lkdWFsLHBvc3QucmVzaWR1YWwpICNlLTkKCnBjdC5lZmZlY3QgPC0gY3Vtc3VtKGVmZmVjdCkvY3Vtc3VtKGZvcmVjYXN0KQpwY3QuZWZmZWN0WzddCnBjdC5lZmZlY3RbM10KYGBgCgpUaGlzIGxvb2tzIGJldHRlciAtIHRoZSBtb2RlbCBmaXRzIGJldHRlciAod2UnbGwgc3RpY2sgd2l0aCB0aGlzIG92ZXIgYGV0c2ApLCB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCBpcyB0aWdodGVyLCBhbmQgdGhlIHRyZWF0bWVudCBlZmZlY3QgaXMgODAgRFdJJ3Mgb3ZlciB0aGUgZmlyc3QgMyBtb250aHMsIGEgZGVjcmVhc2Ugb2YgYWJvdXQgNiUuICBJbiBvdGhlciB3b3JkcywgKipub3QgaGF2aW5nIFViZXIgYW5kIEx5ZnQgbWF5IGhhdmUgcmVzdWx0ZWQgaW4gYW4gYWRkaXRpb25hbCA4MCBhcnJlc3RzIGluIHRoZSBmaXJzdCAzIG1vbnRocyoqLiBBZnRlciA3IG1vbnRocyAodGFraW5nIHVzIHRvIHRoZSBlbmQgb2Ygb3VyIGRhdGEpLCB3ZSBvYnNlcnZlIGEgc21hbGxlciA1JSBkZWNyZWFzZSAtIHBlcmhhcHMgd2UgY2FuIGF0dHJpYnV0ZSB0aGlzIHRvIHRoZSBzbWFsbGVyIHJpZGVzaGFyaW5nIHNlcnZpY2VzIChsaWtlIEZhcmUpIHRoYXQgc3BydW5nIHVwIGluIEF1c3RpbiBhZnRlciBVYmVyIGFuZCBMeWZ0IHN0b3BwZWQgb2ZmZXJpbmcgcmlkZXMuCgpUaGlzIGdpdmVzIHVzIGEgbnVtYmVyIHRvIGFzc29jaWF0ZSB3aXRoIHRoZSBxdWFsaXRhdGl2ZSBjaGFuZ2Ugd2Ugc2F3IHdpdGggYHJkZGAgZWFybGllci4gIENvb2whCgpMZXQncyBkbyB0aGUgc2FtZSB3aXRoIERXSS8kTU06CgpgYGB7ciB3YXJuaW5nPUZBTFNFfQpkd2kuZHVyaW5nLnJldi50cyA8LSB0cyhkd2kuZHVyaW5nJHJldiwgc3RhcnQgPSBjKDIwMTQsIDUpLCBmcmVxdWVuY3kgPSAxMikKZHdpLmV4aXQucmV2LnRzIDwtIHRzKGR3aS5leGl0JHJldiwgc3RhcnQgPSBjKDIwMTYsIDUpLCBmcmVxdWVuY3kgPSAxMikKCmR3aS5kdXJpbmcucmV2Lmh3IDwtIEhvbHRXaW50ZXJzKGR3aS5kdXJpbmcucmV2LnRzKQoKZm9yZWNhc3QgPC0gcHJlZGljdChkd2kuZHVyaW5nLnJldi5odywgbi5haGVhZCA9IDEyLCBwcmVkaWN0aW9uLmludGVydmFsID0gVCwgbGV2ZWwgPSAwLjkpCnBsb3QoZHdpLmR1cmluZy5yZXYuaHcsIGZvcmVjYXN0KTsgbGluZXMoZHdpLmV4aXQucmV2LnRzLGNvbD0nZ3JlZW4nKQoKZWZmZWN0IDwtIGZvcmVjYXN0IC0gZHdpLmV4aXQucmV2LnRzCgojcHJlLnJlc2lkdWFsIDwtIGFzLm51bWVyaWMoKGR3aS5kdXJpbmcucmV2Lmh3JGZpdHRlZCAtIGR3aS5kdXJpbmcucmV2LnRzKSkKI3Bvc3QucmVzaWR1YWwgPC0gYXMubnVtZXJpYyhlZmZlY3QpCiN0LnRlc3QocHJlLnJlc2lkdWFsLHBvc3QucmVzaWR1YWwpICMwLjAwMDQKCnBjdC5lZmZlY3QgPC0gY3Vtc3VtKGVmZmVjdCkvY3Vtc3VtKGZvcmVjYXN0KQpwY3QuZWZmZWN0WzddCnBjdC5lZmZlY3RbM10KYGBgCgpCYWQgbmV3cyBmb3IgYmFycyAtIEhvbHQtV2ludGVycyBzdWdnZXN0cyB0aGF0ICoqcmV2ZW51ZXMgd2VyZSBkZXByZXNzZWQgYnkgNi41JSBvdmVyIHRoZSBmaXJzdCAzIG1vbnRocyoqIHdpdGhvdXQgVWJlciBhbmQgTHlmdC4gIFRoYXQncyAkMTIsMDAwLDAwMCAtIGFuZCBuZWFybHkgJDEsNzAwLDAwMCBpbiBsb3N0IHRheCByZXZlbnVlLiAgSXQncyAkMzQsMDAwLDAwMCBvdmVyIHRoZSB3aG9sZSA3IG1vbnRocyB3ZSBoYXZlIGRhdGEgZm9yLgoKYGBge3Igd2FybmluZz1GQUxTRX0KZHdpLmR1cmluZy5jb3VudF9wZXJfbW0udHMgPC0gdHMoZHdpLmR1cmluZyRjb3VudF9wZXJfbW0sIHN0YXJ0ID0gYygyMDE0LCA1KSwgZnJlcXVlbmN5ID0gMTIpCmR3aS5leGl0LmNvdW50X3Blcl9tbS50cyA8LSB0cyhkd2kuZXhpdCRjb3VudF9wZXJfbW0sIHN0YXJ0ID0gYygyMDE2LCA1KSwgZnJlcXVlbmN5ID0gMTIpCgpkd2kuZHVyaW5nLmNvdW50X3Blcl9tbS5odyA8LSBIb2x0V2ludGVycyhkd2kuZHVyaW5nLmNvdW50X3Blcl9tbS50cykKCmZvcmVjYXN0IDwtIHByZWRpY3QoZHdpLmR1cmluZy5jb3VudF9wZXJfbW0uaHcsIG4uYWhlYWQgPSAxMiwgcHJlZGljdGlvbi5pbnRlcnZhbCA9IFQsIGxldmVsID0gMC45KQpwbG90KGR3aS5kdXJpbmcuY291bnRfcGVyX21tLmh3LCBmb3JlY2FzdCk7IGxpbmVzKGR3aS5leGl0LmNvdW50X3Blcl9tbS50cyxjb2w9J2dyZWVuJykKCmVmZmVjdCA8LSBmb3JlY2FzdCAtIGR3aS5leGl0LmNvdW50X3Blcl9tbS50cwoKI3ByZS5yZXNpZHVhbCA8LSBhcy5udW1lcmljKChkd2kuZHVyaW5nLmNvdW50X3Blcl9tbS5odyRmaXR0ZWQgLSBkd2kuZHVyaW5nLmNvdW50X3Blcl9tbS50cykpCiNwb3N0LnJlc2lkdWFsIDwtIGFzLm51bWVyaWMoZWZmZWN0KQojdC50ZXN0KHByZS5yZXNpZHVhbCxwb3N0LnJlc2lkdWFsKSAjMC4wMTggPC0gdGhpcyBvbmUgaXMgYSBsaXR0bGUgaGlnaCBidXQgc3RpbGwgYWNjZXB0YWJsZQoKCnBjdC5lZmZlY3QgPC0gY3Vtc3VtKGVmZmVjdCkvY3Vtc3VtKGZvcmVjYXN0KQpwY3QuZWZmZWN0WzddCnBjdC5lZmZlY3RbM10KYGBgCgoqKjE0JSBoaWdoZXIgRFdJLyRNTSBvdmVyIHRoZSBmaXJzdCAzIG1vbnRocyB3aXRob3V0IFViZXIqKiwgb3IgMTIlIHRocm91Z2ggMjAxNiwgYWdhaW4gZXhjZWVkaW5nIHRoZSBlZmZlY3Qgb2Ygbm90IGhhdmluZyByaWRlc2hhcmluZyBvbiByZXZlbnVlIGFsb25lLgoKV2UndmUgZ290IG9uZSBtb3JlIHRyaWNrIHVwIG91ciBzbGVldmVzLgoKIyNCYXllc2lhbiBTdHJ1Y3R1cmFsIFRpbWUtU2VyaWVzCiMjI1dpdGggR29vZ2xlIENhdXNhbEltcGFjdAoKR29vZ2xlIGhhcyBhIGdyZWF0IGxpYnJhcnkgZm9yIHRlc3RpbmcgdGhlIGNhdXNhbCBlZmZlY3Qgb2YgYSBnaXZlbiB0cmVhdG1lbnQgb24gYSB0aW1lIHNlcmllcy4gIERlc2lnbmVkIGZvciB0ZXN0aW5nIHRoZSBlZmZlY3RpdmVuZXNzIG9mIGFkdmVydGlzaW5nLCBJIHRoaW5rIHRoaXMgbGlicmFyeSB3aWxsIGhlbHAgdXMgb3V0IC0gaXQncyBkZXNpZ25lZCBmb3IgaW5mZXJlbmNlIG9uIG5vbi1leHBlcmltZW50YWwgZGF0YSwgd2hpY2ggaXMgd2hhdCB3ZSd2ZSBnb3QuCgpGb3IgdGhpcywgaW4gY29udHJhc3QgdG8gcmVncmVzc2lvbiBkaXNjb250aW51aXR5IG9yIGV4cG9uZW50aWFsIHNtb290aGluZyBtZXRob2RzLCB3ZSByZXF1aXJlIGEgcmVzcG9uc2UgYW5kIHByZWRpY3RvciAtIG9uZSB0aGluZyB0aGF0IHdlIHRoaW5rIGEgdHJlYXRtZW50IGFmZmVjdGVkIGFuZCBvbmUgdGhpbmcgdGhhdCB3ZSBhcmUgY29uZmlkZW50IGl0IGRpZG4ndC4gIExldCdzIHVzZSBEV0kgY291bnQgYXMgYSByZXNwb25zZSwgYW5kIFRBQkMgcmV2ZW51ZSBhcyBhIGNvbnRyb2wsIGFzIGl0IGFwcGVhcnMgVEFCQyBzYWxlcyBncm93dGggaXMgbGVzcyBhZmZlY3RlZCB0aGFuIERXSSwgcGVyIG91ciBleHBlcmltZW50cyBpbiB0aGUgcHJldmlvdXMgc2VjdGlvbiwgYW5kIGFsc28gbmFyY290aWMgYXJyZXN0cywgd2hpY2ggd2UgZG9uJ3QgdGhpbmsgd2lsbCBiZSBzaGlmdGVkIGF0IGFsbC4KCldlIG5lZWQgYSB3ZWxsLWJlaGF2ZWQgc3RyZXRjaCBvZiBkYXRhICh3ZSdyZSBqdXN0IHN0dWR5aW5nIG91ciB0cmVhdG1lbnQsIG5vdCBvdGhlciBpbmZsZWN0aW9ucykgdG8gdXNlIGFzIGEgY29udHJvbCAtIHNvIGxldCdzIHJlLXVzZSB0aGUgc2FtZSBjdXRvZmYgd2UgdXNlZCBmb3Igb3VyIHJlZ3Jlc3Npb24gZGlzY29udGludWl0eSBkZXNpZ24gKDIwMTItMDUtMDEpLiAgTGV0J3MgcGxvdCBpdCB0byBzZWUgaWYgaXQgaXQgbG9va3MgbGlrZSBhbnl0aGluZyBzdHJhbmdlIGhhcHBlbmVkIHRvIG91ciBjb250cm9sIGRhdGEgb3ZlciBvdXIgcGVyaW9kIG9mIGludGVyZXN0LgoKYGBge3Igd2FybmluZyA9IEZBTFNFfQp1YmVyIDwtIGdlb21fcmVjdChtYXBwaW5nID0gYWVzKHhtaW49YXMuRGF0ZSgnMjAxNC0wNi0wMScpLCB4bWF4ID0gYXMuRGF0ZSgnMjAxNi0wNS0wMScpKSwgeW1pbj0tSW5mLCB5bWF4PStJbmYsIGNvbG9yPSJncmV5MjAiLCBhbHBoYT0wLjMsIGluaGVyaXQuYWVzID0gRkFMU0UpCgpnZ3Bsb3QoZGF0YT1tZWx0KHNlbGVjdChmaWx0ZXIoZHdpLGRhdGU+PSIyMDEyLTA0LTAxIiksbmFyYyxjb3VudCxyZXYsZGF0ZSksaWQgPSAnZGF0ZScpLCBtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT12YWx1ZSwgY29sb3IgPSB2YXJpYWJsZSkpICsgdWJlciArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZCA9ICdsb2VzcycsIHNlID0gRkFMU0UpCmBgYAoKTm90IHRoZSBiZXN0LCBidXQgaXQncyB3aGF0IHdlJ3ZlIGdvdC4gIEknbSBlc3BlY2lhbGx5IGNvbmNlcm5lZCBieSB0aGUgdHJlbmQgaW4gVEFCQyByZXZlbnVlIGFuZCB0aGUgbGl0dGxlIHVwdGljayBpbiBuYXJjb3RpY3MgYXJyZXN0cyBpbiBsYXRlIDIwMTYsIGFuZCBnZW5lcmFsbHkgY29uY2VybmVkIGFib3V0IHRoZSBqdW1waW5lc3Mgb2YgdGhlIGRhdGEuICBNYWpvciBkcnVnIGJ1c3RzIGNhbiBjaGFuZ2UgdGhlIGF2YWlsYWJpbGl0eSBvZiBkcnVncyBpbiBhIGNpdHkgb3Zlcm5pZ2h0LCBhbmQgY291bGQgcmVkdWNlIHRoZSBudW1iZXIgb2YgZHJ1ZyBhcnJlc3RzIGluIHN1YnNlcXVlbnQgbW9udGhzLiAgSWYgYENhdXNhbEltcGFjdGAgZG9lc24ndCBsaWtlIGl0IGl0IHNob3VsZCB0ZWxsIHVzLCB3ZSdsbCBzZWUgaG93IGl0IGdvZXMuCgooSWYgeW91J3JlIHJ1bm5pbmcgdGhpcyBhdCBob21lIG5vdGUgdGhhdCB5b3UnbGwgbmVlZCB0aGUgZGV2ZWxvcG1lbnQgdmVyc2lvbiBvZiBgZGV2dG9vbHNgIHRvIGluc3RhbGwgYENhdXNhbEltcGFjdGAgZHVlIHRvIGEgYnVnIGluIHRoZSBDUkFOIHZlcnNpb24gb2YgYGRldnRvb2xzYC4gIEdldCBpdCB3aXRoIGBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImhhZGxleS9kZXZ0b29scyIpYCApCgojIyNUQUJDIGFzIGEgQ29udHJvbAoKYGBge3Igd2FybmluZyA9IEZBTFNFfQpkd2kuY2kgPC0gc2VsZWN0KGZpbHRlcihkd2ksZGF0ZT49IjIwMTItMDUtMDEiKSxkYXRlLGNvdW50LHJldikKCnByZS5jaSA8LSBhcy5EYXRlKGMoIjIwMTItMDUtMDEiLCAiMjAxNC0wNS0zMSIpKQpwb3N0LmNpIDwtIGFzLkRhdGUoYygiMjAxNC0wNi0wMSIsICIyMDE2LTA1LTAxIikpCgppbXBhY3QgPC0gQ2F1c2FsSW1wYWN0KGR3aS5jaSwgcHJlLmNpLCBwb3N0LmNpLCAgbW9kZWwuYXJncyA9IGxpc3QocHJpb3IubGV2ZWwuc2QgPSAwLjEsbnNlYXNvbnMgPSAxMiwgc2Vhc29uLmR1cmF0aW9uID0gMSkpIAojaSd2ZSB0dXJuZWQgdXAgdGhlIHNkIHNpbmNlIHRoaXMgZGF0YSBpcyBtb3JlIHNjYXR0ZXJlZCB0aGFuIHdlYiB0cmFmZmljIGRhdGEKI25vdGljZSB3ZSd2ZSBzZXQgaXQgdG8gbG9vayBmb3IgYSB0cmVuZCB3aXRoIGEgcGVyaW9kIG9mIG9uZSB5ZWFyCgpwbG90KGltcGFjdCkKCmltcGFjdApgYGAKCkNhdXNhbEltcGFjdCBhdHRyaWJ1dGVzIGEgOC43JSBkcm9wIGluIERXSSdzIHRvIHJpZGVzaGFyaW5nICh3aXRoIDk5LjklIGNlcnRhaW50eSwgaXQgc2F5cyksIHByZXR0eSBjbG9zZSB0byB3aGF0IHRoZSBsYXN0IG1vZGVsIHNhaWQsIGJ1dCBjYW4gd2UgdHJ1c3QgaXQ/IFdlIHZhbGlkYXRlZCBIb2x0LVdpbnRlcnMsIGxldCdzIHZhbGlkYXRlIHRoaXMgYXMgd2VsbC4gCgpPdXIgY29udHJvbCBkYXRhIG1pZ2h0IGhhdmUgdHJlbmRzIGFuZCBvdGhlciB1bnJlbGF0ZWQgdHJlYXRtZW50cyBpbiBpdCwgb3IgdGhpcyBtb2RlbCBtaWdodCBub3QgYmUgYXMgZ29vZCBhdCBoYW5kbGluZyBzZWFzb25hbGl0eS4gIElmIHdlIGdpdmUgQ2FzdWFsSW1wYWN0IGEgJ2Zha2UnIHRyZWF0bWVudCBkYXRlIHdoZW4gd2Uga25vdyBub3RoaW5nIGhhcHBlbmVkIC0gc2F5LCBpbiB0aGUgZW5kIG9mIDIwMTMgLSBpdCBzaG91bGRuJ3QgcmVwb3J0IGFueSBjaGFuZ2UgaW4gRFdJIGR1ZSB0byB0aGlzIG1hZGUtdXAgdHJlYXRtZW50LgoKYGBge3Igd2FybmluZyA9IEZBTFNFfQpwcmUuY2kgPC0gYXMuRGF0ZShjKCIyMDEyLTA1LTAxIiwgIjIwMTMtMTEtMzAiKSkKcG9zdC5jaSA8LSBhcy5EYXRlKGMoIjIwMTMtMTItMDEiLCAiMjAxNC0wNS0wMSIpKQoKaW1wYWN0IDwtIENhdXNhbEltcGFjdChkd2kuY2ksIHByZS5jaSwgcG9zdC5jaSwgIG1vZGVsLmFyZ3MgPSBsaXN0KCBwcmlvci5sZXZlbC5zZCA9IDAuMSwgbnNlYXNvbnMgPSAxMiwgc2Vhc29uLmR1cmF0aW9uID0gMSkpCgpwbG90KGltcGFjdCkKaW1wYWN0CmBgYAoKQWxyaWdodCwgYSAyLjQlIGRyb3AgKDgwJSBzdXJlLCBpdCdsbCB0ZWxsIHlvdSBpZiB5b3UgY2hlY2ssIHdoaWNoIGlzbid0IHRoZSBiZXN0KS4gIFRoYXQncyBub3QgYSBsb3QsIGJ1dCBpdCdzIG1vcmUgdGhhbiB0aGUgMCUgd2UnZCBleHBlY3QuICBXZSBtYXkgbm90IGJlIGFibGUgdG8gdXNlIHRoZXNlIHJlc3VsdHMgYXMgdGhleSBhcmUsIGF0IGxlYXN0IHdpdGggVEFCQyByZXZlbnVlcyBhcyBhIGNvbnRyb2wuICBUaGUgdXB3YXJkIHRyZW5kIGluIHJldmVudWVzIHRocm91Z2ggb3VyIHRyZWF0bWVudCBwZXJpb2QgYW5kIHRoZSBkb3dud2FyZCB0cmVuZCBpbiBEV0kgbWF5IGJlIGRpc3RvcnRpbmcgdGhlIG1vZGVsIGFuZCBtYXkgYWx3YXlzIHRlbGwgdXMgdGhlcmUncyBhIGRyb3AgaW4gRFdJIGFycmVzdHMuCgpJJ2xsIG5vdGUgaGVyZSB0aGF0IG90aGVyIHJhbmRvbWx5LXBpY2tlZCBkYXRlcyBmb3IgdGhlIGZha2UgdHJlYXRtZW50IG1pZ2h0IHNob3cgZGlmZmVyZW50IHJlc3VsdHMgLSB3ZSd2ZSBjb21wZW5zYXRlZCBmb3IgdGhlIGhpZ2hlci10aGFuLW5vcm1hbCB2YXJpYW5jZSBpbiBvdXIgY29udHJvbCBkYXRhLCBidXQgaWYgeW91IGxhbmQgb24gYSBwZWFrIGBDYXVzYWxJbXBhY3RgIGNhbiB0ZWxsIHlvdSB0aGVyZSdzIG1vcmUgb2YgYSBkcm9wIC0gdXAgdG8gdGhlIHNjYWxlIG9mIHRoZSByZWFsIHRyZWF0bWVudCwgYnV0IHdpdGggbGVzcyBwcm9iYWJpbGl0eSBvZiBhIGNhdXNhbCBlZmZlY3QgLSBvciBubyBkcm9wIGF0IGFsbCwgb3IgZXZlbiBhIHNsaWdodCByaXNlLCBhbGwgd2l0aCBsb3cgcG9zdGVyaW9yIHByb2JhYmlsaXRpZXMuICBJZiB5b3UncmUgaW5jbGluZWQsIEkgZW5jb3VyYWdlIHlvdSB0byBwbGF5IGFyb3VuZCB3aXRoIGl0LiAgSSd2ZSBwaWNrZWQgdGhpcyBvbmUgYmVjYXVzZSBpdCdzIGNsb3NlIHRvIGEgdHlwaWNhbCB2YWx1ZSBmb3IgdGhlIHByZS10cmVhdGVkIHJhbmdlIC0gYnV0IGEgbGFjayBvZiBhIGNvbnNpc3RlbnQgcmVzdWx0IGZyb20gdGhpcyB0ZXN0IHNob3VsZCBtYWtlIHVzIGZlZWwgYSBsaXR0bGUgd2VpcmQgYWJvdXQgaG93IHdlbGwgc3VpdGVkIG91ciBkYXRhIGlzIHRvIHRoaXMgbW9kZWwuCgojIyNOYXJjb3RpY3MgQXJyZXN0cyBhcyBhIENvbnRyb2wKClNpbmNlIHdlIHdlcmUgd29ycmllZCBUQUJDIHJldmVudWVzIGFyZSBhIGJhZCBjb250cm9sIHZhcmlhYmxlLCBsZXQncyBzZWUgaWYgbmFyY290aWNzIGFycmVzdHMgYXJlIGFueSBiZXR0ZXIuCgpgYGB7ciB3YXJuaW5nID0gRkFMU0V9CmR3aS5jaS5uIDwtIGZpbHRlcihzZWxlY3QoZHdpLGRhdGUsY291bnQsbmFyYyksZGF0ZSA+PSAnMjAxMi0wNS0wMScpCgpwcmUuY2kgPC0gYXMuRGF0ZShjKCIyMDEyLTA1LTAxIiwgIjIwMTQtMDUtMzEiKSkKcG9zdC5jaSA8LSBhcy5EYXRlKGMoIjIwMTQtMDYtMDEiLCAiMjAxNi0wNS0wOSIpKQoKaW1wYWN0Lm4gPC0gQ2F1c2FsSW1wYWN0KGR3aS5jaS5uLCBwcmUuY2ksIHBvc3QuY2ksbW9kZWwuYXJncyA9IGxpc3QocHJpb3IubGV2ZWwuc2QgPSAwLjEsbnNlYXNvbnMgPSAxMiwgc2Vhc29uLmR1cmF0aW9uID0gMSkpCnBsb3QoaW1wYWN0Lm4pCgppbXBhY3QubgpgYGAKClVzaW5nIG5hcmNvdGljcyBhcnJlc3RzIGFzIGEgY29udHJvbCwgcmlkZXNoYXJpbmcgY2FuIGFjY291bnQgZm9yIGEgNyUgZHJvcCBpbiBEV0kgYXJyZXN0cywgd2l0aCBhYm91dCB0aGUgc2FtZSBjZXJ0YWludHkuICBBbHJpZ2h0LCB0aGF0J3MgYWxtb3N0IHRoZSBkaWZmZXJlbmNlIHdlIHNhdyBlYXJsaWVyIC0gbGV0J3MgZG91YmxlIGNoZWNrIG9uIGEgZmFrZSB0cmVhdG1lbnQgZGF0ZToKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnByZS5jaSA8LSBhcy5EYXRlKGMoIjIwMTItMDUtMDEiLCAiMjAxMy0xMS0zMCIpKQpwb3N0LmNpIDwtIGFzLkRhdGUoYygiMjAxMy0xMi0wMSIsICIyMDE0LTA1LTAxIikpCgppbXBhY3QubiA8LSBDYXVzYWxJbXBhY3QoZHdpLmNpLm4sIHByZS5jaSwgcG9zdC5jaSxtb2RlbC5hcmdzID0gbGlzdChwcmlvci5sZXZlbC5zZCA9IDAuMSwgbnNlYXNvbnMgPSAxMiwgc2Vhc29uLmR1cmF0aW9uID0gMSkpCnBsb3QoaW1wYWN0Lm4pCgppbXBhY3QubgpgYGAKCkxlc3MgaW1wYWN0ICgtMyUpLiAgODclIHN1cmUgdGhvdWdoIC0gd2hpY2ggbW9zdCBzdGF0aXN0aWNpYW5zIHdpbGwgdGhyb3cgb3V0LiAgVGhpcyBjb250cm9sIGxvb2tzIGxpa2UgaXQncyBiZXR0ZXIsIGJ1dCBJJ20gbm90IHN1cGVyIGludG8gaXQuICBXaGF0IGVsc2UgY291bGQgd2UgZG8/CgohW10oZGF0YS9ib3RoLnBuZykKCiMjI0JvdGgKCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmR3aS5jaS5iIDwtIGZpbHRlcihzZWxlY3QoZHdpLGRhdGUsY291bnQscmV2LG5hcmMpLGRhdGUgPj0gJzIwMTItMDUtMDEnKQoKcHJlLmNpIDwtIGFzLkRhdGUoYygiMjAxMi0wNS0wMSIsICIyMDE0LTA1LTMxIikpCnBvc3QuY2kgPC0gYXMuRGF0ZShjKCIyMDE0LTA2LTAxIiwgIjIwMTYtMDUtMDkiKSkKCmltcGFjdC5iIDwtIENhdXNhbEltcGFjdChkd2kuY2kuYiwgcHJlLmNpLCBwb3N0LmNpLG1vZGVsLmFyZ3MgPSBsaXN0KHByaW9yLmxldmVsLnNkID0gMC4xLG5zZWFzb25zID0gMTIsIHNlYXNvbi5kdXJhdGlvbiA9IDEpKQpwbG90KGltcGFjdC5iKQoKaW1wYWN0LmIKYGBgCgpBIDguMiUgZWZmZWN0LiAgU29tZSB2YWxpZGF0aW9uOgoKYGBge3Igd2FybmluZz1GQUxTRX0KcHJlLmNpIDwtIGFzLkRhdGUoYygiMjAxMi0wNS0wMSIsICIyMDEzLTExLTMwIikpCnBvc3QuY2kgPC0gYXMuRGF0ZShjKCIyMDEzLTEyLTAxIiwgIjIwMTQtMDUtMDEiKSkKCmltcGFjdC5iIDwtIENhdXNhbEltcGFjdChkd2kuY2kuYiwgcHJlLmNpLCBwb3N0LmNpLG1vZGVsLmFyZ3MgPSBsaXN0KHByaW9yLmxldmVsLnNkID0gMC4xLG5zZWFzb25zID0gMTIsIHNlYXNvbi5kdXJhdGlvbiA9IDEpKQpwbG90KGltcGFjdC5iKQoKaW1wYWN0LmIKYGBgCgpBIDMuMyUgZWZmZWN0IGF0IDg4JS4gIFdlJ3JlIGdldHRpbmcgc2VtaS13b3JrYWJsZSByZXN1bHRzIC0gdGhlIHJlYWwgaW5mbGVjdGlvbiBkYXRlIHdpdGggY29udHJvbHMganVzdCBhYm91dCBtYXRjaGVzIG91ciBleHBvbmVudGlhbCBzbW9vdGhpbmcgbW9kZWxzLCBhbmQgd2UgY2FuIHNvcnQgb2YgZGlzY291bnQgdGhlIGZha2UgaW5mbGVjdGlvbiB3ZSdyZSB0ZXN0aW5nIHdpdGgsIGJ1dCBub3QgdmVyeSBjb25maWRlbnRseS4gIFdlIGNvdWxkIG1lc3MgYXJvdW5kIHdpdGggYSBjdXN0b20gbXVsdGktc2Vhc29uYWwgQlNUUyBtb2RlbCBhbmQgZmVlZCBpdCB0byBgQ2F1c2FsSW1wYWN0YCwgSSdsbCBjYWxsIHRoYXQgYW4gYXJlYSBmb3IgZnV0dXJlIHRlc3RpbmcuCgpXZSdsbCBoYXZlIHRvIHJldmlzaXQgdGhpcyBtb2RlbCBpZiB3ZSBnZXQgbW9yZSBkYXRhLgoKI0NvbmNsdXNpb25zCgpPdXIgY29uY2x1c2lvbnMgd2VyZSBhIGJpdCBtaXhlZCwgYnV0IHByb21pc2luZy4gIEludmVzdGlnYXRpbmcgd2l0aCBSREQgc3VnZ2VzdGVkIHRoYXQgdGhlcmUgbWlnaHQgYmUgYW4gaW50ZXJ2ZW50aW9uIGVmZmVjdCBkdWUgdG8gVWJlciBhbmQgTHlmdCBjZWFzaW5nIHJpZGVzaGFyaW5nIGluIEF1c3RpbiwgYW5kIGV4cG9uZW50aWFsIHNtb290aGluZyB0ZWNobmlxdWVzIHN1Z2dlc3RlZCBtZWFzdXJhYmxlIGRyb3BzIGluIERXSSBjb3VudHMgYW5kIERXSSBjb3VudHMgcGVyIE1NIGJhciByZXZlbnVlIGR1ZSB0byB0aGUgaW50cm9kdWN0aW9uIG9mIHJpZGVzaGFyaW5nIChhcyB3ZWxsIGFzIGEgc21hbGwgdXB0aWNrIGluIGJhciByZXZlbnVlKSwgYXMgd2VsbCBhcyBhIHN1YnNlcXVlbnQgaW5jcmVhc2UgaW4gRFdJIGNvdW50cyBhbmQgRFdJIHBlciBNTSBhZnRlciBVYmVyIGFuZCBMeWZ0IHN0b3BwZWQgb2ZmZXJpbmcgcmlkZXMsIG9uY2UgeW91IHRvb2sgaW50byBhY2NvdW50IGJyb2FkIHRyZW5kcyBhbmQgcGVyaW9kaWMgY3ljbGVzIGluIGJvdGggZGF0YSBzZXRzLgoKYENhdXNhbEltcGFjdGAgYW5hbHlzaXMgZGlkbid0IHdvcmsgb3V0IHRvIGJlIHNvbWV0aGluZyB3ZSBjb3VsZCB1c2UgLSBib3RoIFRBQkMgcmV2ZW51ZSBhbmQgbmFyY290aWNzIGFycmVzdHMgZGF0YSB3ZXJlbid0IHN1aXRhYmxlIGNvbnRyb2xzLiAgVGhleSBkaWQgc29ydCBvZiBjb3Jyb2JvcmF0ZSB0aGUgcmVzdWx0cyBmcm9tIHRoZSBvdGhlciBtb2RlbHMsIHRob3VnaC4KCioqVGFraW5nIGludG8gYWNjb3VudCBvdXIgcmVzdWx0cywgdGhlIG1vZGVscyBzdWdnZXN0IGF0dHJpYnV0aW5nIGFib3V0IGEgOCUgZHJvcCBpbiBEV0kgYXJyZXN0cyBpbiBBdXN0aW4gZnJvbSBKdW5lIDIwMTQgLSBNYXkgMjAxNiB0byByaWRlc2hhcmluZywgYW5kIGFib3V0IGEgNSUgaW5jcmVhc2UgaW4gRFdJIGFycmVzdCBmcm9tIE1heSAyMDE2IC0gRGVjZW1iZXIgMjAxNiB0byBhbiBhYnJ1cHQgY2Vzc2F0aW9uIG9mIFViZXIgYW5kIEx5ZnQncyByaWRlc2hhcmluZyBzZXJ2aWNlcy4qKiAgQW4gOCUgZHJvcCBpbiBEV0kgb3ZlciB0aGUgdHdvIHllYXJzIFViZXIgYW5kIEx5ZnQgd2VyZSBvZmZlcmluZyByaWRlc2hhcmluZyBzZXJ2aWNlcyBhY2NvdW50cyBmb3IgKipuZWFybHkgMTAwMCBEV0kncy4qKgoKKipTaW1pbGFybHksIG91ciBuZXcgRFdJL1RBQkMgTWl4ZWQgQmV2ZXJhZ2UgUmV2ZW51ZSAoTWlsbGlvbnMpIG1ldHJpYyBpcyBkZWNyZWFzZWQgYnkgYWJvdXQgMTclIGJ5IHJpZGVzaGFyaW5nLCBhbmQgaW5jcmVhc2VkIGJ5IGFib3V0IDE0JSB3aXRob3V0IGl0LioqCgpBcyBhIGxpdHRsZSBib251cywgbW9kZWxsaW5nIGp1c3QgYmFyIHNhbGVzIHNob3dlZCB0aGF0ICoqQXVzdGluIGJhciByZXZlbnVlcyBtYXkgaGF2ZSBiZWVuIGltcHJvdmVkIGJ5IGFzIG11Y2ggYXMgJDY4LDAwMCwwMDAgZHVlIHRvIHRoZSBhdmFpbGFibGl0eSByaWRlc2hhcmluZyBvdmVyIHR3byB5ZWFycyoqLCBhZGRpbmcgdG8gdGhlIFRBQkMncyB0YXggY29mZmVycyBieSBuZWFybHkgJDksNTAwLDAwMCBvdmVyIHRoYXQgdGltZS4gICoqV2l0aG91dCBVYmVyIGFuZCBMeWZ0LCBiYXJzIG1heSBoYXZlIHNlZW4gYXMgbXVjaCBhcyBhICQzNCwwMDAsMDAwIGRlcHJlc3Npb24gaW4gc2FsZXMgb3ZlciA3IG1vbnRocyoqLCBzaG9ydGluZyB0aGUgVEFCQyAkNCw3MDAsMDAwIGluIHRheGVzLiAgV2UgZGlkbid0IHN0dWR5IHRoaXMgYXMgbXVjaCBhcyBEV0kncywgdGhvdWdoLCBhbmQgdW5vYnNlcnZlZCBpbnRlcnZlbnRpb25zIGNvdWxkIGFjY291bnQgZm9yIHNvbWUgb2YgdGhlc2UgYW1vdW50cyB3aXRob3V0IGNoYW5naW5nIG91ciBjb25jbHVzaW9ucyBhYm91dCBEV0kgY291bnRzIGRpcmVjdGx5LgoKI0Z1dHVyZSBXb3JrIGFuZCBDYXZlYXRzCgpXaXRoIG1vcmUgZmluZS1ncmFpbmVkIHRpbWUgc2VyaWVzIGRhdGEsIG9yIHNvbWUgY2VydGlmaWVkLWV4dHJhLWFjY3VyYXRlIGRhdGEgZnJvbSB0aGUgQVBELCBJIHRoaW5rIHdlIGNvdWxkIGltcHJvdmUgb24gdGhpcyBhbmFseXNpcy4gIE15IG9yaWdpbmFsIHRob3VnaHRzIHdlcmUgdG8gc2VlIGlmIHJpZGVzaGFyaW5nIGhhZCBhIG1vcmUgc3BlY2lmaWMgZWZmZWN0IG9uIGNlcnRhaW4ga2luZHMgb2YgRFdJJ3MgLSBzYXkgc3BlY2lmaWNhbGx5IDFzdCBvZmZlbnNlcyAtIGFuZCBpbiBjZXJ0YWluIHBsYWNlcywgYnV0IHRoZSBkYXRhIHdhcyBub3QgY29tcGxldGUgZW5vdWdoIGZvciB0aGF0LiAgQWRkaXRpb25hbGx5LCBBdXN0aW4ncyBjcmltZSBkYXRhIGluIGdlbmVyYWwgbWF5IGJlIHVucmVsaWFibGUgKHRoYXQncyBjZXJ0YWlubHkgYSBjYXZlYXQgLSBzZWUgaHR0cDovL3d3dy5teXN0YXRlc21hbi5jb20vbmV3cy9sb2NhbC93aHktdGhlLWF1c3Rpbi1wb2xpY2UtZGVwYXJ0bWVudC1kd2ktY3Jhc2gtc3RhdGlzdGljcy1rZWVwLWNoYW5naW5nL0dOdjhMVHJiRWdUZDdLRU9iblB3Z0wvKSwgYWx0aG91Z2ggd2UgZGlkIGNvbXBhcmUgdHdvIHNvdXJjZXMgZm9yIGNyaW1lIGRhdGEuICBVcGRhdGVkIGRhdGEgZnJvbSBhZnRlciB0aGUgdHJlYXRtZW50IHBlcmlvZCBjb3VsZCBhbHRlciB0aGUgbW9kZWxzJyByZXN1bHRzIHN1YnN0YW50aWFsbHkuICBJIHdvdWxkIGxvdmUgdG8gZ2V0IHNvbWV0aGluZyBsaWtlIG51bWJlciBvZiByaWRlc2hhcmUgcmlkZXMgdGFrZW4gcGVyIG1vbnRoLCB0b28uCgpJZiB5b3UndmUgZ290IHNvbWUgY29tbWVudHMgb3Igc3VnZ2VzdGlvbnMgcmVnYXJkaW5nIHRoaXMgd29yaywgY29udGFjdCBtZSEgIFB1bGwgdGhlIGRhdGEgYW5kIG1vZGVscyBkb3duIGFuZCBtaXggdGhlbSB1cCB5b3Vyc2VsZiBpZiB5b3UnZCBsaWtlLCBJJ2QgbG92ZSB0byBzZWUgYW55IG5ldyByZXN1bHRzIG9yIGNvbmZsaWN0aW5nIGNvbmNsdXNpb25zLgoKI0FwcGVuZGl4CgojI0RXSSBBcnJlc3RzIGFzIGEgUHJveHkgZm9yIERydW5rIERyaXZpbmcKCldlIGNvdWxkIGJlIGNvbmNlcm5lZCB0aGF0LCByYXRoZXIgdGhhbiBiZWluZyBhIHJlYXNvbmFibGUgcHJveHkgZm9yIGRydW5rIGRyaXZpbmcsIHRoZSBudW1iZXIgb2YgRFdJIGFycmVzdHMgY291bGQgYmUgY29uc3RyYWluZWQgYnkgdGhlIHJlc291cmNlcyBhdmFpbGFibGUgdG8gdGhlIEFQRCAtIHdoYXQgaWYgZHJ1bmsgZHJpdmluZyBpcyBvdXQgb2YgY29udHJvbCwgYW5kIHRoZSBBUEQgaGFzIGhpdCBzb21lIHNvcnQgb2YgYXJyZXN0IGNlaWxpbmc/ICBJZiB0aGlzIHdhcyB0aGUgY2FzZSwgd2Ugd291bGQgZXhwZWN0IHRvIHNlZSBhbiB1bmNoYW5naW5nIGF2ZXJhZ2UgYW1vdW50IG9mIG1vbnRobHkgYXJyZXN0cyB3aXRoIHNvbWUgbm9pc2UsIHBvc3NpYmx5IHZhcnlpbmcgd2l0aCB0aGUgc2l6ZSBvZiB0aGUgcG9saWNlIGZvcmNlIGF0IHRoZWlyIG1heGltdW0gY2FwYWNpdHkgZm9yIG1ha2luZyBEV0kgYXJyZXN0cy4KCkFmdGVyIHNvbWUgcXVpY2sgR29vZ2xpbmcsIHdlIGhhdmUgYSBmZXcgc3dvcm4tb2ZmaWNlciBjb3VudHMgZm9yIHRoZSBBUEQ6IGFib3V0IDEyMDAgaW4gMjAwMiwgMTYwMCBpbiAyMDEwLCBhbmQgMTgwMCBpbiAyMDE2LCBzbyB3ZSBjYW4gc2F5IHRoYXQgdGhlIHBvbGljZSBmb3JjZSBpcyBncm93aW5nLiAgUmVhZGluZyB1cCBvbiB0aGUgQVBEIGFsc28gaW5kaWNhdGVzIHRoYXQgdGhlIG51bWJlciBvZiBvZmZpY2VycyBmYW1pbGlhciB3aXRoIGhhbmRsaW5nIGEgRFdJIGFycmVzdCBpbmNyZWFzZWQgb3ZlciB0aGF0IHRpbWUgZnJhbWUgYXMgd2VsbC4gIExldCdzIHJlbWluZCBvdXJzZWx2ZXMgd2hhdCB0aGUgRFdJIGluY2lkZW50IGNvdW50IGxvb2tzIGxpa2U6CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkd2ksIGFlcyh4PWRhdGUseT1jb3VudCkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xvZXNzJykKYGBgCgpFdmVuIGFzIHRoZSBBUEQgZ3Jvd3MsIHRoZSBhbW91bnQgb2YgYXJyZXN0cyB2YXJpZXMgd2lsZGx5IChhIHJhbmdlIG9mIG5lYXJseSAyMDAgYXJyZXN0cyBwZXIgbW9udGgpLCBpbiBhZGRpdGlvbiB0byBob2xkaW5nIHNldmVyYWwgaW5jcmVhc2luZyBhbmQgZGVjcmVhc2luZyB0cmVuZCBwZXJpb2RzIHdlIGFscmVhZHkgc3R1ZGllZC4gIEZyb20gdGhpcywgSSB0aGluayBpdCdzIHNhZmUgdG8gc2F5IHRoYXQgdGhlIG51bWJlciBvZiBhcnJlc3RzIGRvZXMgdHJhY2sgZHJ1bmsgZHJpdmluZyB3aXRob3V0IHNhdHVyYXRpb24uCgojI0NyYXNoL0xlYXZpbmcgVGhlIFNjZW5lCgpXZSBjYW4gYXNzdW1lLCBJIHRoaW5rLCB0aGF0IHNvbWUgbm9uemVybyBwZXJjZW50YWdlIG9mIGhpdC1hbmQtcnVuIGluY2lkZW50cywgZXNwZWNpYWxseSB0aG9zZSBoYXBwZW5pbmcgZHVyaW5nIHBlYWsgZHJ1bmsgZHJpdmluZyBob3VycywgaW52b2x2ZSBhIGRydW5rIGRyaXZlciB3aG8gd2FzIG5vdCBjYXVnaHQgYW5kIGNoYXJnZWQgd2l0aCBhIERXSS4gIElmIHRoaXMgbnVtYmVyIGlzIGhpZ2ggZW5vdWdoLCBhbmQvb3IgZmx1Y3R1YXRpbmcgZW5vdWdoLCBpdCBjb3VsZCBjYXN0IGRvdWJ0IG9uIHRoZSB2YWxpZGl0eSBvZiBEV0kgYXJyZXN0cyBhcyBhIHByb3h5IGZvciBkcnVuayBkcml2aW5nIGJ5IHN1Z2dlc3RpbmcgdGhhdCB0aGUgYXJyZXN0IGNvdW50IGlzIG1lYW5pbmdsZXNzbHkgc21hbGwgYW5kIGludmFyaWFudCB3aXRoIHJlc3BlY3QgdG8gc29tZSBhY3R1YWwgbWFzc2l2ZSBwb3B1bGF0aW9uIG9mIGRydW5rIGRyaXZlcnMuCgpBZGRpdGlvbmFsbHksIGlmIHdlIGNhbiBjb25maWRlbnRseSBleHRyYWN0IGEgcG9ydGlvbiBvZiB0aGVzZSBpbmNpZGVudHMgYW5kIGxhYmVsIHRoZW0gYXMgcHJvYmFibGUgZHJ1bmstZHJpdmluZyBpbmNpZGVudHMsIGFuZCB0aGlzIHBvcnRpb24gaXMgc2lnbmlmaWNhbnRseSBsYXJnZSBhbmQgbm90IGluIGxpbmUgd2l0aCBsYXJnZXIgdHJlbmRzIGFjcm9zcyBvdXIgdHJlYXRtZW50IGFyZWEsIGl0IG1heSBjaGFuZ2UgdGhlIG91dHB1dCBvZiBvdXIgbW9kZWxzIGlmIHdlIGluY2x1ZGUgaXQuICBUaGlzIHNlY29uZCBvbmUgaXMgYSBzdHJldGNoIGFuZCByZWxpZXMgb24gYW5vdGhlciBiaWcgYXNzdW1wdGlvbiAodGhhdCB3ZSBjYW4gaWRlbnRpZnkgYSBkcnVuayBkcml2aW5nIGhpdC1hbmQtcnVuKSwgYnV0IGxldCdzIHRha2UgYSBjcmFjayBhdCBpdC4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9Cmhhci5yYXcgPC0gcmVhZC5jc3YoJ2RhdGEvaGl0YW5kcnVuLXJhdy5jc3YnKQpoYXIucmF3JGhvdXIgPC0gc3Vic3RyKGhhci5yYXckZGF0ZSwxMiwxMykKI2hhci5yYXckbG9uZ2RhdGUgPC0gcGFyc2VfZGF0ZV90aW1lKGhhci5yYXckZGF0ZSwnJVktJW0tJWQgJUg6JU06JVMnLHR6ID0nQW1lcmljYS9DaGljYWdvJykKaGFyLnJhdyRkYXRlIDwtIGFzLkRhdGUoaGFyLnJhdyRkYXRlKQoKI3FwbG90KGhvdXIobG9uZ2RhdGUpLCBkYXRhPWhhci5yYXcsIGdlb209Imhpc3RvZ3JhbSIsIGJpbnMgPSAyNCkKI3FwbG90KHdkYXkobG9uZ2RhdGUpLCBkYXRhPWhhci5yYXcsIGdlb209Imhpc3RvZ3JhbSIsIGJpbnMgPSAyNCkKCmhhci5yYXckeWVhciA8LSB5ZWFyKGhhci5yYXckZGF0ZSkKaGFyLnJhdyRtb250aCA8LSBtb250aChoYXIucmF3JGRhdGUpCgpoYXIubW9udGhseSA8LSBoYXIucmF3ICU+JSBncm91cF9ieSh5ZWFyLG1vbnRoKQpoYXIgPC0gc3VtbWFyaXplKGhhci5tb250aGx5LGNvdW50PW4oKSkKaGFyJGRhdGUgPC0gYXMuRGF0ZShwYXN0ZTAoaGFyJHllYXIsJy0nLGhhciRtb250aCwnLTAxJykpCgpoYXIgPC0gZmlsdGVyKGhhcixjb3VudCA+IDUwKSAjcmVtb3ZlIGEgZmV3IG1vbnRocyBvdXRzaWRlIG9mIHRoZSAxLTYvMjAxNSBhbmQgMS03LzIwMTYgcmFuZ2Ugd2l0aG91dCBjb21wbGV0ZSBkYXRhCmhhciA8LSBoYXJbLTYzLF0gCmhhciA8LSBoYXJbLTg3LF0gCgpxcGxvdCh4PWRhdGUseT1jb3VudCxkYXRhID0gaGFyKQoKYGBgCgpUaGVyZSBhcmUgYSBsb3Qgb2YgaW5jaWRlbnRzIGhlcmUsIGJ1dCBub3QgZW5vdWdoIHRvIHRvdGFsbHkgc3dhbXAgdGhlIGRhdGEsIHNvIG91ciBmaXJzdCBjb25jZXJuIGlzIHJ1bGVkIG91dCwgSSB0aGluay4gIEknbSBhIGxpdHRsZSBjb25jZXJuZWQgYWJvdXQgdGhlIGp1bXAgaW4gaGl0IGFuZCBydW5zIGluIHRoZSBsYXRlciBwYXJ0IG9mIHRoZSBkYXRhIHRob3VnaCwgZXZlbiB0aG91Z2ggaXQncyBub2lzeSBhbmQgdGhlIGluY2lkZW50IHJlcG9ydCBpcyBrbm93biB0byBkaXNhZ3JlZSB3aXRoIHRoZSBjaGllZidzIHJlcG9ydCB0b3dhcmRzIHRoZSBlbmQgb2YgdGhlIHRpbWUgZnJhbWUgLSBsZXQncyB0YWtlIGEgc3RhYiBhdCBwaWNraW5nIHRoZSBpbmNpZGVudHMgbW9zdCBsaWtlbHkgdG8gYmUgYWxjb2hvbCByZWxhdGVkLCBieSBmaWx0ZXJpbmcganVzdCB0aGUgb25lcyB0aGF0IG9jY3VyIHdoZW4gRFdJJ3MgYXJlIG1vc3QgbGlrZWx5IHRvIGJlIHJlcG9ydGVkLgoKYGBge3J9Cmhhci5yYXcgPC0gZmlsdGVyKGZpbHRlcihoYXIucmF3LCBob3VyID4gMTkpLGhvdXIgPCA2KSAjb25seSBoaXQtYW5kLXJ1bnMgZHVyaW5nIHByaW1lIGRyaW5raW5nIGFuZCBkcml2aW5nIGhvdXJzCgpoYXIubW9udGhseSA8LSBoYXIucmF3ICU+JSBncm91cF9ieSh5ZWFyLG1vbnRoKQpoYXIgPC0gc3VtbWFyaXplKGhhci5tb250aGx5LGNvdW50PW4oKSkKaGFyJGRhdGUgPC0gYXMuRGF0ZShwYXN0ZTAoaGFyJHllYXIsJy0nLGhhciRtb250aCwnLTAxJykpCgpoYXIgPC0gZmlsdGVyKGhhcixjb3VudCA+IDUwKSAjcmVtb3ZlIGEgZmV3IG1vbnRocyBvdXRzaWRlIG9mIHRoZSAxLTYvMjAxNSBhbmQgMS03LzIwMTYgcmFuZ2Ugd2l0aG91dApoYXIgPC0gaGFyWy02MyxdIApoYXIgPC0gaGFyWy04NyxdIAoKcXBsb3QoeD1kYXRlLHk9Y291bnQsZGF0YSA9IGhhcikKI2dncGxvdChkYXRhID0gZmlsdGVyKGR3aS5tb250aGx5LGRhdGUgPCAnMjAxNS0wMS0wMScpLCBhZXMoZmFjdG9yKG1vbnRoKGRhdGUpKSx3ZWlnaHQgPSBjb3VudCkgKSArIGdlb21fYmFyKCkKCmdncGxvdChkYXRhID0gZmlsdGVyKGhhcixkYXRlIDwgJzIwMTUtMDEtMDEnKSwgYWVzKGZhY3Rvcihtb250aChkYXRlKSksd2VpZ2h0ID0gY291bnQpICkgKyBnZW9tX2JhcigpCmBgYAoKVGhhdCBicmluZ3MgdGhlIG1lYW4gZG93biBjb25zaWRlcmFibHkgYW5kIGxldmVscyBvdXQgdGhlIHRyZW5kIC0gYWx0aG91Z2ggdGhlIGhpc3RvZ3JhbSBkb2Vzbid0IG1hdGNoIG91ciBpbmNpZGVudCByZXBvcnQgRFdJIGhpc3RvZ3JhbS4KCklmIHdlIHdlcmUgdG8gZnVydGhlciBzYW1wbGUgdGhpcyBkYXRhIGZvciBsaWtlbHkgZHJ1bmsgZHJpdmluZyBoaXQtYW5kLXJ1bnMsIHdlJ2QgaGF2ZSB0byB3ZWlnaHQgaXQgdG8gbWF0Y2ggdGhlIERXSSBoaXN0b2dyYW0sIGFuZCB0aGVuIGFwcGx5IHNvbWUgZmxhdCAndGhpcyBtYW55IGhpdC1hbmQtcnVucyBpbiBwcmltZSBoaXQtYW5kLXJ1biB0aW1lZnJhbWVzIGludm9sdmUgYWxjb2hvbCcgcGVyY2VudGFnZS4gIEkgZG9uJ3QgaGF2ZSBhIG51bWJlciBmb3IgdGhhdCwgd2UnbGwganVzdCBjYWxsIGl0IDIwJS4KCmBgYHtyfQpmaWx0ZXI8LWRhdGEuZnJhbWUobW9udGg9YygxLDIsMyw0LDUsNiw3LDgsOSwxMCwxMSwxMiksdHJpbT1jKDEsLjcwLC43LC42MCwuNjQsLjU2LC41OCwuNjIsLjc2LC43MiwuNzMsLjgxKSkKCmhhciA8LSBtZXJnZShoYXIsZmlsdGVyLGlkID0nbW9udGgnKQpoYXIkY291bnQgPC0gaGFyJGNvdW50ICogaGFyJHRyaW0KZ2dwbG90KGRhdGEgPSBmaWx0ZXIoaGFyLGRhdGUgPCAnMjAxNS0wMS0wMScpLCBhZXMoZmFjdG9yKG1vbnRoKGRhdGUpKSx3ZWlnaHQgPSBjb3VudCkgKSArIGdlb21fYmFyKCkKaGFyJHRyaW0gPC0gTlVMTAoKaGFyJGNvdW50ID0gaGFyJGNvdW50ICogLjIwCgpxcGxvdCh4PWRhdGUseT1jb3VudCxkYXRhID0gaGFyKQpgYGAKCkFuZCBpdCdzIGxlc3MgdGhhbiBvciBhYm91dCB0aGUgc2FtZSBhcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBBUEQgSW5jaWRlbnQgUmVwb3J0IGFuZCB0aGUgQ2hpZWYncyBNb250aGx5IFJlcG9ydC4gIE1heWJlIGEgbW9yZSBvZmZpY2lhbCBlc3RpbWF0ZSBvZiBoaXQtYW5kLXJ1biBkcnVuayBkcml2aW5nIG1heSBoYXZlIG1hZGUgaXQgaW50byB0aGUgQ2hpZWYncyByZXBvcnQsIGFjY291bnRpbmcgZm9yIHRoZSBkaXNjcmVwYW5jeS4KCkZvciB0aGUgcmFuZ2UgMjAwOC0yMDEyLCB0aGUgZGlmZmVyZW5jZSBpcyBzbWFsbCwgaW4gbGluZSB3aXRoIHRoZSBwcmV2YWlsaW5nIGRlY3JlYXNpbmcgdHJlbmQsIGFuZCBhcyBpdCBjb250cmlidXRlcyBvbmx5IHRvIHNlYXNvbmFsIG1vZGVscyBJJ20gY29tZm9ydGFibGUgZGlzY291bnRpbmcgaXQgZW50aXJlbHkuICBGb3IgdGhlIG1vbnRocyBpbiAyMDE1IGFuZCAyMDE2LCBJJ20gbm90IHN1cmUgd2hhdCB0byBkbyB3aXRoIGl0IC0gSSBkb24ndCB0aGluayBpdCdzIGEgZ29vZCBpZGVhIHRvIGFkZCBpdCB0byB0aGUgQ2hpZWYncyByZXBvcnQsIGFuZCBpZiBpdCBvbmx5IG1ha2VzIHVwIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIEFQRCBJbmNpZGVudCBSZXBvcnQgYW5kIHRoZSBDaGllZidzIHJlcG9ydCwgYW5kIHNpbmNlIEkgZG9uJ3QgZXZlbiBoYXZlIGl0IGZvciB0aGUgcmVzdCBvZiB0aGUgdGltZSBmcmFtZSAtIEkgdGhpbmsgaXQncyBzYWZlIHRvIGlnbm9yZSBpdCBhbmQgaWYgbW9yZSBhY2N1cmF0ZSBkYXRhIHByZXNlbnRzIGl0c2VsZiwgdGVzdCBvdXIgY29uY2x1c2lvbnMgYWdhaW4uCgojI0Rvd250b3duIGFuZCBBbGwgT3RoZXIgQXJyZXN0IERhdGEKCkxhdGUgaW4gdGhlIGRldmVsb3BtZW50IG9mIHRoaXMgd3JpdGV1cCBJIG5vdGljZWQgdGhhdCB0aGUgQ2hpZWYncyBNb250aGx5IFJlcG9ydCB3YXMgYnJva2VuIGludG8gYnJvYWQgZ2VvZ3JhcGhpYyBzZWN0aW9ucywgYW5kIGFsc28gY29uc2lkZXJlZCB0aGF0IHRoZSAnYWxsIG90aGVyIFBhcnQgMiBjcmltZXMnIGNvdW50IGF2YWlsYWJsZSBvbiB0aGUgcmVwb3J0IHdvdWxkIGJlIGEgYmV0dGVyIGNvbnRyb2wgdGhhbiBuYXJjb3RpY3MgYXJyZXN0cywgYXMgaXQgbWlnaHQgaGF2ZSBhIGxvd2VyIHZhcmlhbmNlLCBhbmQgYmUgYSBiZXR0ZXIgcmVwcmVzZW50YXRpb24gb2YgJ2JhY2tncm91bmQnIGNyaW1lLiAgSSdsbCBxdWlja2x5IGxvb2sgYXQgc29tZSBvZiB0aGlzIGRhdGEuCgpgYGB7ciB3YXJuaW5nID0gRkFMU0V9CmJvbnVzIDwtIHJlYWQuY3N2KCdkYXRhL290aGVyLmNzdicpCmhlYWQoYm9udXMpCgpib251cyRkYXRlIDwtIGFzLkRhdGUoYm9udXMkZGF0ZSkKYm9udXMkZHQuY291bnQgPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoYm9udXMkZHQuY291bnQpKSAjY2FzdCBzdHJpY3RseQpib251cyRjb3VudCA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihib251cyRjb3VudCkpIApib251cyRvdGhlciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3Rlcihib251cyRvdGhlcikpIAoKZ2dwbG90KGRhdGEgPSBib251cywgYWVzKGZhY3Rvcihtb250aChkYXRlKSksd2VpZ2h0ID0gZHQuY291bnQpICkgKyBnZW9tX2JhcigpCgpnZ3Bsb3QoZGF0YSA9IGJvbnVzLCBhZXMoeT1kdC5jb3VudCx4PWRhdGUpKSArIGdlb21fcG9pbnQoKQpnZ3Bsb3QoZGF0YSA9IGJvbnVzLCBhZXMoeT1kdC5jb3VudC9jb3VudCx4PWRhdGUpKSArIGdlb21fcG9pbnQoKQoKCmJvbnVzLnByZSA8LSBmaWx0ZXIoYm9udXMsZGF0ZSA8ICcyMDE0LTA1LTMxJykKYm9udXMucG9zdCA8LSBmaWx0ZXIoYm9udXMsZGF0ZSA+ICcyMDE0LTA1LTMxJykKCmJvbnVzLnByZS50cyA8LSB0cyhib251cy5wcmUkZHQuY291bnQsIHN0YXJ0ID0gYygyMDEwLCAxKSwgZnJlcXVlbmN5ID0gMTIpCmJvbnVzLnBvc3QudHMgPC0gdHMoYm9udXMucG9zdCRkdC5jb3VudCwgc3RhcnQgPSBjKDIwMTQsIDYpLCBmcmVxdWVuY3kgPSAxMikKCmJvbnVzLmh3IDwtIEhvbHRXaW50ZXJzKGJvbnVzLnByZS50cykKZm9yZWNhc3QgPC0gcHJlZGljdChib251cy5odywgbi5haGVhZCA9IDI0LCBwcmVkaWN0aW9uLmludGVydmFsID0gVCwgbGV2ZWwgPSAwLjkpCgpwbG90KGJvbnVzLmh3LGZvcmVjYXN0KTsgbGluZXMoYm9udXMucG9zdC50cyxjb2w9J2dyZWVuJykKZWZmZWN0IDwtIGZvcmVjYXN0IC0gYm9udXMucG9zdC50cwoKI3ByZS5yZXNpZHVhbCA8LSBhcy5udW1lcmljKChib251cy5odyRmaXR0ZWQgLSBib251cy5wcmUudHMpKQojcG9zdC5yZXNpZHVhbCA8LSBhcy5udW1lcmljKGVmZmVjdCkKI3QudGVzdChwcmUucmVzaWR1YWwscG9zdC5yZXNpZHVhbCkgI2UtMTYKCnBjdC5lZmZlY3QgPC0gY3Vtc3VtKGVmZmVjdCkvY3Vtc3VtKGZvcmVjYXN0KQpwY3QuZWZmZWN0WzI0XQpgYGAKQ29vbC4gU29tZSBzZWFzb25hbGl0eSwgYSBwbG90IHRoYXQgbG9va3MgbGlrZSBhIHNjYWxlZCB2ZXJzaW9uIG9mIHRoZSBmdWxsIERXSSBwbG90LCBhbmQgYSBzZW5zZSB0aGF0IGRvd250b3duIERXSSdzIGdlbmVyYWxseSBhY2NvdW50IGZvciAxMC0xNCUgb2YgYWxsIERXSSdzIGluIEF1c3Rpbi4KCkEgcXVpY2sgZ2xhbmNlIGF0IGp1c3QgdGhlIGRvd250b3duIGRhdGEgc3VnZ2VzdHMgdGhhdCByaWRlc2hhcmluZyBoYWQgdGhlIGVmZmVjdCBvZiBsb3dlcmluZyBEV0kgY291bnRzIGRvd250b3duIGJ5IDE0JSBvdmVyIDI0IG1vbnRocyAoOSUgb3ZlciAxMi4pCgpgYGB7ciB3YXJuaW5nID0gRkFMU0V9CmdncGxvdChkYXRhID0gYm9udXMsIGFlcyh5PW90aGVyLHg9ZGF0ZSkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKQoKZ2dwbG90KGRhdGEgPSBib251cywgYWVzKGZhY3Rvcihtb250aChkYXRlKSksd2VpZ2h0ID0gb3RoZXIpICkgKyBnZW9tX2JhcigpCgpib251cy5iIDwtIGZpbHRlcihzZWxlY3QoYm9udXMsZGF0ZSxjb3VudCxvdGhlciksZGF0ZSA+PSAnMjAxMi0wNS0wMScpCgpwcmUuY2kgPC0gYXMuRGF0ZShjKCIyMDEyLTA1LTAxIiwgIjIwMTQtMDUtMzEiKSkKcG9zdC5jaSA8LSBhcy5EYXRlKGMoIjIwMTQtMDYtMDEiLCAiMjAxNi0wNS0wOSIpKQoKaW1wYWN0LmIgPC0gQ2F1c2FsSW1wYWN0KGJvbnVzLmIsIHByZS5jaSwgcG9zdC5jaSxtb2RlbC5hcmdzID0gbGlzdChwcmlvci5sZXZlbC5zZCA9IDAuMSxuc2Vhc29ucyA9IDEyLCBzZWFzb24uZHVyYXRpb24gPSAxKSkKcGxvdChpbXBhY3QuYikKCmltcGFjdC5iCgpwcmUuY2kgPC0gYXMuRGF0ZShjKCIyMDEyLTA1LTAxIiwgIjIwMTMtMTEtMzAiKSkKcG9zdC5jaSA8LSBhcy5EYXRlKGMoIjIwMTMtMTItMDEiLCAiMjAxNC0wNS0wMSIpKQoKaW1wYWN0LmIgPC0gQ2F1c2FsSW1wYWN0KGJvbnVzLmIsIHByZS5jaSwgcG9zdC5jaSxtb2RlbC5hcmdzID0gbGlzdChwcmlvci5sZXZlbC5zZCA9IDAuMSxuc2Vhc29ucyA9IDEyLCBzZWFzb24uZHVyYXRpb24gPSAxKSkKcGxvdChpbXBhY3QuYikKCmltcGFjdC5iCmBgYAoKT3RoZXIgUGFydCAyIGNyaW1lcyBzZWVtIHRvIGJlIG9uIHRoZSBkZWNsaW5lLCBhbHRob3VnaCB0aGVyZSBsb29rcyBsaWtlIHRoZXJlIG1pZ2h0IGJlIGFuIGluZmxlY3Rpb24gaW4gbGF0ZSAyMDEzIC0gZWFybHkgMjAxNC4gIFdlIHNlZSBhIGxpdHRsZSBzZWFzb25hbGl0eSwgcG9zc2libHkgY29uc2lzdGVudCB3aXRoIHN0dWRpZXMgdGhhdCBoYXZlIHNob3duIGEgbGluayBiZXR3ZWVuIHdhcm0gd2VhdGhlciBhbmQgY3JpbWUuICBgQ2F1c2FsSW1wYWN0YCB0ZWxscyB1cyB0aGF0IHdlIHNlZSBhYm91dCBhIDYlIGRyb3AgaW4gRFdJLCBhbmQgaXQgdmFsaWRhdGVzIG11Y2ggYmV0dGVyIHRoYW4gb3VyIG90aGVyIGNvbnRyb2xzIGZvciBvdXIgc2VsZWN0ZWQgZmFrZSBpbnRlcnZlbnRpb24gZGF0ZSwgYnV0IG5vdCBtdWNoIGJldHRlciBmb3Igb3RoZXIgZGF0ZXMuICBJJ2xsIGxlYXZlIGl0IGhlcmUgZm9yIGZ1dHVyZSByZXNlYXJjaC4KCiNSZWZlcmVuY2VzCgpfRGV0ZXJyaW5nIERydW5rIERyaXZpbmcgRmF0YWxpdGllczogQW4gRWNvbm9taWNzIG9mIENyaW1lIFBlcnNwZWN0aXZlXwpCcnVjZSBMLiBCZW5zb24gYW5kIERhdmlkIFcuIFJhc211c3NlbgoKX0luZmVycmluZyBDYXVzYWwgSW1wYWN0IFVzaW5nIEJheWVzaWFuIFN0cnVjdHVyYWwgVGltZS1zZXJpZXMgTW9kZWxzXwpLYXkgSC4gQnJvZGVyc2VuLCBGYWJpYW4gR2FsbHVzc2VyLCBKaW0gS29laGxlciwgTmljb2xhcyBSZW15LCBTdGV2ZW4gTC4gU2NvdHQKCl9SZWdyZXNzaW9uIERpc2NvbnRpbnVpdHkgRGVzaWducyBpbiBFY29ub21pY3NfCkRhdmlkIFMuIExlZSBhbmQgVGhvbWFzIExlbWlldXgKCl9Qcm9ncmFtIERlc2NyaXB0aW9uOiBBUEQgRFdJIEVuZm9yY2VtZW50XwpodHRwczovL29uZS5uaHRzYS5nb3YvcGVvcGxlL2luanVyeS9yZXNlYXJjaC9BdXN0aW5Qb2xpY2VEV0kvcGFnZXMvUHJvZ0Rlc2MuaHRtbAoKI0Fja25vd2xlZGdlbWVudHMKClRoaXMgd29yayB3b3VsZCBoYXZlIGJlZW4gbXVjaCB3b3JzZSB3aXRob3V0IHRoZSBpbnRlbnNlbHkgYXBwcmVjaWF0ZWQgaW5wdXQgb2YgaXRzIHBlZXIgcmV2aWV3ZXJzLCB3aG8ga25vdyB3aG8gdGhleSBhcmUgOikKCiNEaXNjbGFpbWVycwoKIyNBUEQKPlRoZSBBdXN0aW4gUG9saWNlIERlcGFydG1lbnQgZG9lcyBub3QgYXNzdW1lIGFueSBsaWFiaWxpdHkgZm9yIGFueSBkZWNpc2lvbiBtYWRlIG9yIGFjdGlvbiB0YWtlbiBvciBub3QgdGFrZW4gYnkgdGhlIHJlY2lwaWVudCBpbiByZWxpYW5jZSB1cG9uIGFueSBpbmZvcm1hdGlvbiBvciBkYXRhIHByb3ZpZGVkLgoKIyNUQUJDCj5UaGUgQ29tcHRyb2xsZXIgb2YgUHVibGljIEFjY291bnRzIGNhbm5vdCB2b3VjaCBmb3IgdGhlIGRhdGEgb3IgYW5hbHlzaXMgZGVyaXZlZCBmcm9tIGRhdGEgYWZ0ZXIgaXQgaGFzIGJlZW4gcmV0cmlldmVkIGZyb20gdGhlIENvbXB0cm9sbGVyJ3MgV2ViIHNpdGUuCgpTb21lIG51bWJlcnMgaW4gdGhlIFIgbWF5IHZhcnkgc2xpZ2h0bHkgZnJvbSB0aGUgbnVtYmVycyBpbiB0aGUgdGV4dCwgYXMgc29tZSBtb2RlbHMgYXJlIHJvbGxlZCBhdCByZW5kZXItdGltZSBhbmQgbWF5IGludm9sdmUgc29tZSByYW5kb21uZXNzLgoKI0xpY2Vuc2UKClRoZSBNSVQgTGljZW5zZSAoTUlUKQoKQ29weXJpZ2h0IChjKSAyMDE3IElhbiBXZWxscwoKUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSAiU29mdHdhcmUiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6CgpUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS4KClRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCAiQVMgSVMiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS4=