• 1 Flight Data
    • 1.1 Review xts fundamentals
    • 1.2 Manipulating and visualizing your data
    • 1.3 Saving and exporting xts objects
      • 1.3.1 Assessing flight trends
      • 1.3.2 Saving time
  • 2 Weather Data
    • 2.1 Merging time series data by row
      • 2.1.1 Exploring temperature data
      • 2.1.2 Next steps
      • 2.1.3 Merging using rbind()
      • 2.1.4 Visualizing Boston winters
    • 2.2 Merging time series data by column
      • 2.2.1 Subsetting and adjusting periodicity
      • 2.2.2 Generating a monthly average
      • 2.2.3 Using merge() and plotting over time
      • 2.2.4 Are flight delays related to temperature?
    • 2.3 Time series data workflow
      • 2.3.1 Next steps
      • 2.3.2 Expanding your data
      • 2.3.3 Are flight delays related to visibility or wind?
  • 3 Economic Data
    • 3.1 Handling missingness
      • 3.1.1 Exploring economic data
      • 3.1.2 Replace missing data
      • 3.1.3 Estimating missing GDP
    • 3.2 Lagging and differencing
      • 3.2.1 Exploring unemployment data
      • 3.2.2 Lagging unemployment
      • 3.2.3 Differencing unemployment
    • 3.3 Rolling functions
      • 3.3.1 Add a discrete rolling sum to GDP data
      • 3.3.2 Add a continuous rolling average to unemployment data
      • 3.3.3 Manipulating MA unemployment data
  • 4 Sports Data
    • 4.1 Advanced features of xts
      • 4.1.1 Encoding and plotting Red Sox data
      • 4.1.2 Calculate a closing average
      • 4.1.3 Calculate and plot a seasonal average
      • 4.1.4 Calculate and plot a rolling average
    • 4.2 Indexing commands in xts
      • 4.2.1 Extract weekend games
      • 4.2.2 Calculate a rolling average across all sports

1 Flight Data

1.1 Review xts fundamentals

1.1.1 Flight data

Welcome to this practice course on manipulating time series data using xts & zoo! This course is designed to review the time series tools available in R. As with most components of data analysis, much of the work of time series analysis involves data cleaning and manipulation.

Your task is to understand the travel patterns of tourists visiting Boston. As a first step, you’ve been assigned to explore patterns in flights arriving at Boston’s Logan International Airport (BOS). In this exercise, you’ll view the structure and qualities of some data in preparation for time series manipulation.

Lucky for you, the U.S. Bureau of Transportation Statistics provides open source data on flight arrival times.

# download.file("http://s3.amazonaws.com/assets.datacamp.com/production/course_1964/datasets/flights.RData", destfile = "flights.RData")
flights <- readRDS("flights.RData")

Explore the structure of flights using str() to understand the information contained in the data file.

#View the structure of the flights data
str(flights)
'data.frame':   72 obs. of  5 variables:
 $ total_flights : num  8912 8418 9637 9363 9360 ...
 $ delay_flights : num  1989 1918 2720 1312 1569 ...
 $ cancel_flights: num  279 785 242 58 102 157 222 138 144 131 ...
 $ divert_flights: num  9 23 32 7 8 5 10 20 6 9 ...
 $ date          : chr  "2010-01-01" "2010-02-01" "2010-03-01" "2010-04-01" ...
#Examine the first five rows of the flights data
head(flights, n = 5)
ABCDEFGHIJ0123456789
 
 
total_flights
<dbl>
delay_flights
<dbl>
cancel_flights
<dbl>
divert_flights
<dbl>
date
<chr>
18912198927992010-01-01
284181918785232010-02-01
396372720242322010-03-01
4936313125872010-04-01
59360156910282010-05-01

The first step in preparing an object for conversion to xts is to ensure that the time/date column is in a proper time-based format. Check the class of the relevant column in flights using class().

#Identify class of the column containing date information
class(flights$date)
[1] "character"

It’s always helpful to use these commands to get a feel for your data before you begin analysis. As you can see, the flights object contains four columns of flight data and one column of dates. The date column is currently a character string. You’ll need to convert this into a time-based object before moving forward with time series analysis.

1.1.2 Pick out the xts object

It looks like your flights data will need some modifications before it can be turned into an xts object. As you know, there are many different types of objects in R. xts objects are specifically designed for time series functionality. The internal structure of an xts object is a matrix indexed on a time-based object.

1.1.3 Encoding your flight data

You’re ready to encode your data to an xts object! Remember that flights is a data frame containing four columns of flight data and one column of dates.

To convert to an xts object, you’ll need to ensure that your date column is in a time-based format. As you discovered earlier, the date column is currently a character. Once date is saved in a time-based format, you’re ready to convert to xts! To do so, you’ll use as.xts(), which takes two primary arguments.

First, you’ll need to specify the object being converted (in this case, flights). To avoid redundancies, you should generally remove the time-based column from the data when you convert to xts. In this case, you’ll remove the fifth column (dates), by specifying [, -5] in your as.xts() call.

Second, you’ll need to tell xts how to index your object by specifying the order.by argument. In this case, you want to index your object on the date column.

# Load the xts package
library(xts)
package 㤼㸱xts㤼㸲 was built under R version 4.0.3Loading required package: zoo
package 㤼㸱zoo㤼㸲 was built under R version 4.0.3
Attaching package: 㤼㸱zoo㤼㸲

The following objects are masked from 㤼㸱package:base㤼㸲:

    as.Date, as.Date.numeric
# Convert date column to a time-based class
flights$date <- as.Date(flights$date)

# Convert flights to an xts object using as.xts
flights_xts <- as.xts(flights [ , -5], order.by = flights$date)

# Check the class of flights_xts
class(flights_xts)
[1] "xts" "zoo"
# Examine the first five lines of flights_xts
head(flights_xts, 5)
           total_flights delay_flights cancel_flights divert_flights
2010-01-01          8912          1989            279              9
2010-02-01          8418          1918            785             23
2010-03-01          9637          2720            242             32
2010-04-01          9363          1312             58              7
2010-05-01          9360          1569            102              8

Your new xts object contains four columns of information about flights indexed on a series of months and years.

1.2 Manipulating and visualizing your data

1.2.1 Exploring your flight data

Before any analysis can be done, it is critical to explore the basic qualities of your data, including periodicity, scope, and comprehensiveness.

In this exercise, you’ll gain a better understanding of your data by exploring these qualities. As you may recall from the earlier exercises, your time index seemed to be in months. To check that this is constant throughout your xts object, you can use the periodicity() command to tell you the periodicity and scope of the data.

Once you are sure of periodicity, you may also want to know how many periods are covered. To identify the number of periods in your data, you can use the ndays() command, or one of its wrappers, nmonths(), nyears(), etc.

Finally, you may find it useful to query for a particular date by subsetting For example, inputting xts_object[“date”] will generate the row pertaining to that date.

# Identify the periodicity of flights_xts
periodicity(flights_xts)
Monthly periodicity from 2010-01-01 to 2015-12-01 
# Identify the number of periods in flights_xts
nmonths(flights_xts)
[1] 72
# Find data on flights arriving in BOS in June 2014
flights_xts["2014-06"]
           total_flights delay_flights cancel_flights divert_flights
2014-06-01          9662          2279            141              6

It looks like you have monthly data on flights arriving in Boston over the course of 72 months from January 2010 through December 2015.

1.2.2 Visualize flight data

Now that you have a grip on your data, the next step is to visualize trends in your data over time. In this exercise, you’ll plot the flights_xts data over time using a few different methods for plotting time series data.

Often the simplest way to plot xts objects is to use plot.xts(), which requires only a single argument for the y-axis in the plot. The x-axis is supplied by the time index in your xts object.

For more complicated plots, you may want to use plot.zoo(), which allows you to include multiple columns of data. In particular, the plot.type argument allows you to specify whether you’d like your data to appear in a single panel (“single”) or multiple panels (“multiple”). This can be useful when comparing multiple columns of data over time.

# Use plot.xts() to view total monthly flights into BOS over time
plot.xts(flights_xts$total_flights)


# Use plot.xts() to view monthly delayed flights into BOS over time
plot.xts(flights_xts$delay_flights)


# Use plot.zoo() to view all four columns of data in their own panels
labels <- c("Total", "Delay", "Cancel", "Divert")
plot.zoo(flights_xts, plot.type = "multiple", ylab = labels)


# Use plot.zoo() to view all four columns of data in one panel
lty <- c(1, 2, 3, 4)
plot.zoo(flights_xts, plot.type = "single", lty = lty)
legend("right", lty = lty, legend = labels)

These plots provide some very important information about flights arriving in Boston. It looks like only a small percentage of flights are delayed, cancelled, or diverted.

1.3 Saving and exporting xts objects

1.3.2 Saving time

You’ve now successfully converted your flights data into an xts object, plotted information over time, and calculated a few valuable metrics to help you proceed with analysis. You’ve even been able to conduct some quick descriptive analysis on your data by plotting these metrics over time.

The final step in any time series data manipulation is to save your xts object so you can easily return to it in the future.

As a first step, you’ll want to save your xts object as a rds file for your own use. To do this, you’ll use the command saveRDS(), which saves your object to a file with the name you specify (using the file argument). By default, saveRDS() will save to the current working directory.

When you’re ready to return your saved data, you can use the readRDS() command to reopen the file.

# Save your xts object to rds file using saveRDS
saveRDS(object = flights_xts, file = "flights_xts.rds")

# Read your flights_xts data from the rds file
flights_xts2 <- readRDS("flights_xts.rds")

# Check the class of your new flights_xts2 object
class(flights_xts2)

# Examine the first five rows of your new flights_xts2 object
head(flights_xts2, 5)

As you can see, saving to rds files allows you to maintain the class of your data object. However, rds files are difficult to read into programs other than R.

You’ve saved your flights_xts data to a rds file for future use. But what if you’d like to share your data with colleagues who don’t use R?

A second option for saving xts objects is to convert them to shareable formats beyond the R environment, including comma-separated values (CSV) files. To do this, you’ll use the write.zoo() command.

Once you’ve succesfully exported your xts object to a csv file, you can load the data back into R using the read.zoo() command. Unlike readRDS, however, you will need to re-encode your data to an xts object (using as.xts).

# Export your xts object to a csv file using write.zoo
write.zoo(flights_xts, file = "flights_xts.csv", sep = ",")

# Open your saved object using read.zoo
flights2 <- read.zoo("flights_xts.csv", sep = ",", FUN = as.Date, header = TRUE, index.column = 1)

# Encode your new object back into xts
flights_xts2 <- as.xts(flights_xts)

# Examine the first five rows of your new flights_xts2 object
head(flights_xts2, 5)

2 Weather Data

2.1 Merging time series data by row

2.1.1 Exploring temperature data

Now that you’ve learned a bit about your flights data - and reviewed the basics of time series data manipulation - your next assignment is to explore weather patterns in the Boston area to understand what might be affecting flight delays and cancellations. To do this, you’ll need to compile and manipulate some additional time series data.

In this exercise, you’ll explore some temperature data in the Boston area, including measures of min, mean, and max daily temperature over time. These data were collected using the weatherData package in R, which scrapes publicly available data from Weather Underground.

Before moving forward with your time series data manipulation, the first step in any data analysis is to examine the basic qualities of your data. Specifically, you’ll take a closer look at two temperature data objects (temps_1 and temps_2) to understand what information these objects contain and how you should proceed.

temps_1 <- readRDS("temps_1.rds")
temps_2<- readRDS("temps_2.rds")
# View the structure of each object
str(temps_1)
'data.frame':   2192 obs. of  4 variables:
 $ min : int  21 41 30 24 23 28 24 28 30 28 ...
 $ mean: int  34 46 36 32 28 36 34 37 38 34 ...
 $ max : int  46 50 41 41 33 44 44 46 46 41 ...
 $ date: Date, format: "2007-01-01" "2007-01-02" "2007-01-03" ...
str(temps_2)
'data.frame':   1095 obs. of  4 variables:
 $ min : int  28 33 35 26 32 32 28 21 17 21 ...
 $ mean: int  33 40 42 36 39 36 35 27 28 30 ...
 $ max : int  38 46 50 46 46 41 42 33 39 39 ...
 $ date: Date, format: "2013-01-01" "2013-01-02" "2013-01-03" ...
# View the first and last rows of temps_1
head(temps_1)
ABCDEFGHIJ0123456789
 
 
min
<int>
mean
<int>
max
<int>
date
<date>
12134462007-01-01
24146502007-01-02
33036412007-01-03
42432412007-01-04
52328332007-01-05
62836442007-01-06
tail(temps_1)
ABCDEFGHIJ0123456789
 
 
min
<int>
mean
<int>
max
<int>
date
<date>
21873236402012-12-26
21883540462012-12-27
21893540462012-12-28
21903940422012-12-29
21913340482012-12-30
21922836442012-12-31

# View the first and last rows of temps_2
head(temps_2)
ABCDEFGHIJ0123456789
 
 
min
<int>
mean
<int>
max
<int>
date
<date>
12833382013-01-01
23340462013-01-02
33542502013-01-03
42636462013-01-04
53239462013-01-05
63236412013-01-06
tail(temps_2)
ABCDEFGHIJ0123456789
 
 
min
<int>
mean
<int>
max
<int>
date
<date>
10903040502015-12-26
10912638512015-12-27
10922840522015-12-28
10932839502015-12-29
10942938452015-12-30
10951928342015-12-31

2.1.2 Next steps

Now that you’ve examined your data, your next task will be to proceed with data manipulation. Remember that the underlying goal is to explore the possible relationship between Boston area temperature and flights. To do so, you’ll need to manipulate your temperature data to make sure it covers a comparable time period at a similar scale to your flights data.

Use two calls to class() to check that the date columns in temps_1 and temps_2 are encoded as time-based objects (Date, POSIXct, POSIXlt, yearmon, etc.).

summary(temps_1)
      min             mean            max             date           
 Min.   : 5.00   Min.   :18.00   Min.   :24.00   Min.   :2007-01-01  
 1st Qu.:32.00   1st Qu.:41.00   1st Qu.:48.00   1st Qu.:2008-07-01  
 Median :42.00   Median :52.00   Median :60.00   Median :2009-12-31  
 Mean   :41.83   Mean   :51.83   Mean   :61.79   Mean   :2009-12-31  
 3rd Qu.:51.00   3rd Qu.:63.00   3rd Qu.:75.00   3rd Qu.:2011-07-02  
 Max.   :77.00   Max.   :83.00   Max.   :98.00   Max.   :2012-12-31  
summary(temps_2)
      min             mean            max             date           
 Min.   :10.00   Min.   :15.00   Min.   :19.00   Min.   :2013-01-01  
 1st Qu.:35.00   1st Qu.:42.00   1st Qu.:50.00   1st Qu.:2013-10-01  
 Median :45.00   Median :54.00   Median :63.00   Median :2014-07-02  
 Mean   :44.47   Mean   :53.84   Mean   :63.29   Mean   :2014-07-02  
 3rd Qu.:55.00   3rd Qu.:65.00   3rd Qu.:77.00   3rd Qu.:2015-04-01  
 Max.   :71.00   Max.   :80.00   Max.   :94.00   Max.   :2015-12-31  

It looks like temps_1 and temps_2 are data frames containing time series data over non-overlapping time periods. temps_1 appears to range from 2007 through 2012 and temps_2 appears to range from 2013 through 2015.

2.1.3 Merging using rbind()

Now that you know the structure and scope of your temperature data, your next task will be to convert these objects to xts and merge them using rbind().

Before you can convert an object to xts, you need to identify the column that will form the time index and ensure it is encoded as a time-based object. In this case, you’ll want to check the class of the date column in temps_1 and temps_2. Once you identify the appropriate time-based index, you can encode both objects to xts and merge by row.

# Confirm that the date column in each object is a time-based class
class(temps_1$date)
[1] "Date"
class(temps_2$date)
[1] "Date"
# Encode your two temperature data frames as xts objects
temps_1_xts <- as.xts(temps_1[, -4], order.by = temps_1$date)
temps_2_xts <- as.xts(temps_2[, -4], order.by = temps_2$date)

# View the first few lines of each new xts object to confirm they are properly formatted
head(temps_1_xts)
           min mean max
2007-01-01  21   34  46
2007-01-02  41   46  50
2007-01-03  30   36  41
2007-01-04  24   32  41
2007-01-05  23   28  33
2007-01-06  28   36  44
head(temps_2_xts)
           min mean max
2013-01-01  28   33  38
2013-01-02  33   40  46
2013-01-03  35   42  50
2013-01-04  26   36  46
2013-01-05  32   39  46
2013-01-06  32   36  41
# Use rbind to merge your new xts objects
temps_xts <- rbind(temps_1_xts, temps_2_xts)

# View data for the first 3 days of the last month of the first year in temps_xts
first(last(first(temps_xts, "1 year"), "1 month"), "3 days")
           min mean max
2007-12-01  32   41  50
2007-12-02  28   39  50
2007-12-03  30   40  50

You now have a single xts object containing temperature data in the Boston area from 2007 through 2015. In the next exercise, you’ll begin exploring your data in more depth.

2.1.4 Visualizing Boston winters

You discovered in the previous chapter that a much higher percentage of flights are delayed or cancelled in Boston during the winter. It seems logical that temperature is an important factor here. Perhaps colder temperatures are associated with a higher percentage of flight delays or cancellations?

In this exercise, you’ll probe the plausibility of this hypothesis by plotting temperature trends over time and generating a visual overview of Boston winters.

Before plotting, check the periodicity and duration of your data using periodicity(). Knowing the periodicity will help you interpret your data and will come in handy as you proceed.

# Identify the periodicity of temps_xts
periodicity(temps_xts)
Daily periodicity from 2007-01-01 to 2015-12-31 
# Generate a plot of mean Boston temperature for the duration of your data
plot.xts(temps_xts$mean)


# Generate a plot of mean Boston temperature from November 2010 through April 2011
plot.xts(temps_xts$mean["2010-11/2011-04"])


# Use plot.zoo to generate a single plot showing mean, max, and min temperatures during the same period 
lty <- c(3, 1, 3)
plot.zoo(temps_xts["2010-11/2011-04"], plot.type = "single", lty = lty)

Your temperature data look comprehensive and demonstrates clear variation across seasons. Boston has some cold winters! Your next step will be to combine your temperature data with the flight data.

2.2 Merging time series data by column

2.2.1 Subsetting and adjusting periodicity

Your next step is to merge your temperature data with the flight data from the previous chapter.

Recall from the previous chapter that your flight data stretches from 2010 through 2015 in monthly periods. By contrast, your temperature data ranges from 2007 through 2015 in daily periods. Before you merge, you should subset your data and adjust the periodicity to monthly.

To convert the periodicity of xts objects, you can use to.period(), which allows you to quickly convert your data to a lower frequency period. By default, this command produces specific values across the entire period (namely, Open-High-Low-Close, or OHLC) which are useful in financial analysis but may not be relevant in all contexts.

In this case, you should set the argument OHLC to FALSE. Rather than produce OHLC columns in your monthly xts object, this setting will simply take one row from each period as representative of the entire period. You can specify which row using the indexAt command.

# Subset your temperature data to include only 2010 through 2015: temps_xts_2
temps_xts_2 <- temps_xts["2010/2015"]

# Use to.period to convert temps_xts_2 to monthly periodicity
temps_monthly <- to.period(temps_xts_2, period = "months", OHLC = FALSE, indexAt = "firstof")

# Compare the periodicity and duration of temps_monthly and flights_xts 
periodicity(temps_monthly)
Monthly periodicity from 2010-01-01 to 2015-12-01 
periodicity(flights_xts)
Monthly periodicity from 2010-01-01 to 2015-12-01 

You’ve converted your daily temperature data to monthly and it looks like you are ready to merge with your flights data. Before moving forward, however,you should consider whether the value selected by the to.period() call (in this case, the first of the month) is appropriate for this context.

2.2.2 Generating a monthly average

While the to.period() command is useful in many contexts, for your purposes it may not be useful to select a single row as representative of the entire month.

Instead, it makes more sense to generate average temperature values per month. To do so, you’ll need to manually calculate the monthly average using split() and lapply(), then generate a new xts object using as.xts()

# Split temps_xts_2 into separate lists per month
monthly_split <- split(temps_xts_2$mean , f = "months")

# Use lapply to generate the monthly mean of mean temperatures
mean_of_means <- lapply(monthly_split, FUN = mean)

# Use as.xts to generate an xts object of average monthly temperature data
temps_monthly <- as.xts(as.numeric(mean_of_means), order.by = index)
 
# Compare the periodicity and duration of your new temps_monthly and flights_xts 
periodicity(temps_monthly)
Monthly periodicity from 2010-01-01 to 2015-12-01 
periodicity(flights_xts)
Monthly periodicity from 2010-01-01 to 2015-12-01 

You generated a new xts object containing monthly average temperature in Boston from 2010 through 2015. Although this process is more complicated than using to.period(), it produces a more precise measure of monthly temperature.

2.2.3 Using merge() and plotting over time

Now that you have temperature data covering the same time period (2010-2015) at the same frequency (monthly) as your flights data, you are ready to merge.

To merge xts objects by column, you can use merge(). When two xts objects share the same periodicity, merge() is generally able to combine information into appropriate rows. Even when xts objects do not share the same periodicity, merge() will preserve the correct time ordering of those objects across disparate periods.

you’ll merge your two xts objects by column and generate new plots exploring how flight delays relate to temperature.

# Use merge to combine your flights and temperature objects
flights_temps <- merge(flights_xts, temps_monthly)

# Examine the first few rows of your combined xts object
head(flights_temps)
           total_flights delay_flights cancel_flights divert_flights pct_delay pct_cancel pct_divert
2010-01-01          8912          1989            279              9  22.31822  3.1306104 0.10098743
2010-02-01          8418          1918            785             23  22.78451  9.3252554 0.27322404
2010-03-01          9637          2720            242             32  28.22455  2.5111549 0.33205354
2010-04-01          9363          1312             58              7  14.01260  0.6194596 0.07476236
2010-05-01          9360          1569            102              8  16.76282  1.0897436 0.08547009
2010-06-01          9502          1955            157              5  20.57462  1.6522837 0.05262050
           temps_monthly
2010-01-01      36.12903
2010-02-01      37.71429
2010-03-01      42.22581
2010-04-01      51.26667
2010-05-01      56.87097
2010-06-01      63.56667
# Use plot.zoo to plot these two columns in a single panel
lty <-  c(1, 2)
labels <- c("Pct. Delay", "Temperature")
plot.zoo(flights_temps[,c("pct_delay", "temps_monthly")], plot.type = "single", lty = lty)
legend("topright", lty = lty, legend = labels, bg = "white")

Merging your two xts objects allows you to easily visualize the relationship between flight delays and temperature.

2.3 Time series data workflow

2.3.1 Next steps

Your temperature data revealed a few potential avenues for exploring the causes of flight delays and cancellations. However, your client is insisting that flight arrival patterns in Boston are influenced by visibility and wind, not temperature. Before moving forward, you’ll need to collect more data.

After conducting extensive research, you’ve identified some relevant data on weekly average visibility and wind speed in the Boston area. Which of the following steps would you take before merging these data with your existing monthly xts object, flights_temps?

  1. Encode the data to an xts object with a time-based index.
  2. Convert the data to monthly periodicity using split() and lapply() to generate monthly averages.
  3. Check the periodicity and duration of your xts objects before using merge().

2.3.2 Expanding your data

Now that you have a handle on time series workflow, you’re ready to assess the hypothesis that flight delays are a function of visibility and wind.

In this exercise, you’ll add a few more columns to your xts object by merging data on monthly average visibility (vis) and wind speeds (wind) in the Boston area from 2010 through 2015. These data are derived from the same source as your temperature data.

wind <- readRDS("C:/Mis cosas/Coding/Practica/R/finance/data/wind.RData")
Warning in tzone.xts(object) : index does not have a ‘tzone’ attribute
Warning in tzone.xts(object) : index does not have a ‘tzone’ attribute
vis <- readRDS("C:/Mis cosas/Coding/Practica/R/finance/data/vis.RData")
Warning in tzone.xts(object) : index does not have a ‘tzone’ attribute
Warning in tzone.xts(object) : index does not have a ‘tzone’ attribute
# Confirm the periodicity and duration of the vis and wind data
periodicity(vis)
Monthly periodicity from Jan 2010 to Dec 2015 
periodicity(wind)
Monthly periodicity from Jan 2010 to Dec 2015 
# Merge vis and wind with your existing flights_temps data
flights_weather <- merge(flights_temps, vis, wind)

# View the first few rows of your flights_weather data
head(flights_weather)
           total_flights delay_flights cancel_flights divert_flights pct_delay pct_cancel pct_divert
2010-01-01          8912          1989            279              9  22.31822  3.1306104 0.10098743
2010-02-01          8418          1918            785             23  22.78451  9.3252554 0.27322404
2010-03-01          9637          2720            242             32  28.22455  2.5111549 0.33205354
2010-04-01          9363          1312             58              7  14.01260  0.6194596 0.07476236
2010-05-01          9360          1569            102              8  16.76282  1.0897436 0.08547009
2010-06-01          9502          1955            157              5  20.57462  1.6522837 0.05262050
           temps_monthly      vis     wind
2010-01-01      36.12903 5.774194 7.193548
2010-02-01      37.71429 5.857143 5.214286
2010-03-01      42.22581 5.806452 4.903226
2010-04-01      51.26667 6.000000 4.700000
2010-05-01      56.87097 6.000000 4.129032
2010-06-01      63.56667 6.000000 4.300000

Working with time series data using xts can be quite simple once you master the basics. In only a few short commands, you’ve added two more potentially critical pieces of information to your data.

3 Economic Data

3.1 Handling missingness

3.1.1 Exploring economic data

Now that you’ve explored weather and flight patterns in Boston, your client has asked you to step back and prepare some economic data. You’ve gathered some data on the US economy, including gross domestic product (GDP) and unemployment in the US in general and the state of Massachusetts (home to Boston) in particular.

As always, your first step in manipulating time series data should be to convert your data to the xts class. In this exercise, you’ll examine and encode time series data on US GDP.

gdp <- readRDS("C:/Mis cosas/Coding/Practica/R/finance/data/us_gdp.RData")

View information about your gdp data using summary(). What can you conclude from the output of this command?

# Get a summary of your GDP data
summary(gdp)
      date      gdp_billions    
 1947 Q1:  1   Min.   :  243.1  
 1947 Q2:  1   1st Qu.:  708.8  
 1947 Q3:  1   Median : 3167.3  
 1947 Q4:  1   Mean   : 6186.6  
 1948 Q1:  1   3rd Qu.:11497.9  
 1948 Q2:  1   Max.   :18651.2  
 (Other):273   NA's   :80       

Data looks quarterly and has 80 missing values.

Begin the process of encoding gdp to xts by converting the date column to a time object. In this case, it looks like your GDP data are quarterly, so you should use the yearqtr class.

# Convert GDP date column to time object
gdp$date <- as.yearqtr(gdp$date)

# Convert GDP data to xts
gdp_xts <- as.xts(gdp[, -1], order.by = gdp$date)

Use plot.xts() to view your GDP data over time. Does anything stand out in your plot?

# Plot GDP data over time
plot.xts(gdp_xts)

Your plot shows fairly consistent GDP growth in the United States. However, it looks like you are missing quite a bit of data! One of your interns must have fallen asleep on the keyboard. In the next few exercises, you’ll practice some techniques for handling missing data.

3.1.2 Replace missing data

As you discovered in the previous exercise, your quarterly GDP data appear to be missing several observations. In fact, your call to summary() in the previous exercise revealed 80 missing data points!

As you may recall from the first xts course, xts and zoo provide a variety of functions to handle missing data.

The simplest technique is the na.locf() command, which carries forward the last observation before the missing data (hence, “last observation carried forward”, or locf). This approach is often the most appropriate way to handle missingness, especially when you have reasons to be conservative about growth in your data.

A similar approach works in the opposite direction by taking the first observation after the missing value and carrying it backward (“next observation carried backward”, or nocb). This technique can also be done using the na.locf() command by setting the fromLast argument to TRUE.

Which method is best depends on the type of data you are working with and your preconceived notions about how the data changes over time.

# Fill NAs in gdp_xts with the last observation carried forward
gdp_locf <- na.locf(gdp_xts)

# Fill NAs in gdp_xts with the next observation carried backward 
gdp_nocb <- na.locf(gdp_xts, fromLast = TRUE)

# Produce a plot for each of your new xts objects
par(mfrow = c(2,1))
plot.xts(gdp_locf, major.format = "%Y")
plot.xts(gdp_nocb, major.format = "%Y")


# Query for GDP in 1993 in both gdp_locf and gdp_nocb
gdp_locf["1993"]
          [,1]
1993 Q1 5890.8
1993 Q2 5890.8
1993 Q3 5890.8
1993 Q4 5890.8
gdp_nocb["1993"]
          [,1]
1993 Q1 7545.3
1993 Q2 7545.3
1993 Q3 7545.3
1993 Q4 7545.3

You’ve filled in the missing values in your GDP data. As you can see, the locf and nocb techniques sometimes produce drastically different values, especially when you have long spells of missing data. In the next exercise, you’ll practice a third technique for handling missingness: linear interpolation.

Like most aspects of time series data manipulation, there are many ways to handle missingness. As you discovered in the previous exercise, both the locf and nocb approach require you to make certain assumptions about growth patterns in your data. While locf is more conservative and nocb is a more aggressive, both generate step-wise growth from missing data.

But what if you have reason to expect linear growth in your data? In this case, it may be more useful to use linear interpolation, which generates new values between the data on either end of the missing value weighted according to time.

You’ll fill the missing values in your gdp_xts data using the na.approx() command, which uses interpolation to estimate linear values in time.

# Fill NAs in gdp_xts using linear approximation
gdp_approx <- na.approx(gdp_xts)

# Plot your new xts object
plot.xts(gdp_approx, major.format = "%Y")

  
# Query for GDP in 1993 in gdp_approx
gdp_approx["1993"]
            [,1]
1993 Q1 6883.500
1993 Q2 6966.225
1993 Q3 7048.950
1993 Q4 7131.675

Although the values you generate may not be 100% accurate, linear interpolation provides a realistic overall picture of GDP growth from the 1940s through the 2010s. Ultimately, which technique you should use depends on the trends you see in the data you have as well as your preconceived notions about the data.

3.1.3 Estimating missing GDP

Based on the non-missing data, GDP tends to grow at fairly predictable rates (with notable exceptions). For this reason, you should estimate missing values using linear interpolation. This method will not detect sudden shifts in GDP from quarter to quarter, but can provide a general approximation of trends.

3.2 Lagging and differencing

3.2.1 Exploring unemployment data

Now that you’ve reviewed the basic steps for handling missing data, you can more easily examine and clean new time series data on the fly.

In this exercise, you’ll gain a bit more practice by exploring, cleaning, and plotting data on unemployment, both in the United States in general and in Massachusetts (MA) in particular.

unemployment <- readRDS("C:/Mis cosas/Coding/Practica/R/finance/data/unemployment.RData")
# View a summary of your unemployment data
summary(unemployment)
     Index            us               ma        
 Min.   :1976   Min.   : 3.800   Min.   : 2.100  
 1st Qu.:1986   1st Qu.: 5.300   1st Qu.: 4.300  
 Median :1996   Median : 6.000   Median : 5.500  
 Mean   :1996   Mean   : 6.365   Mean   : 5.612  
 3rd Qu.:2006   3rd Qu.: 7.300   3rd Qu.: 6.800  
 Max.   :2016   Max.   :10.800   Max.   :11.600  
                NA's   :73       NA's   :20      
# Use na.approx to remove missing values in unemployment data
unemployment <- na.approx(unemployment)

# Plot new unemployment data
lty <- c(1, 2)
labels <- c("US Unemployment (%)", "MA Unemployemnt (%)")
plot.zoo(unemployment, plot.type = "single", lty = lty)
legend("topright", lty = lty, legend = labels, bg = "white")

3.2.2 Lagging unemployment

Given that economic trends may take some time to influence tourism, it may be helpful to lag your unemployment data before proceeding with analysis.

Generating a lag in xts is straightforward with the lag() command, which requires that you specify the data being lagged (the x argument) and a k value to determine the direction and scale of the lag.

Be careful to keep your formatting consistent. Base R and the zoo package require that you specify a lag with a negative value, so that a lag of 1 is expressed using “-1” (and a lead of 1 is counterintuitively expressed using “1”). By contrast, the xts package specifies lags using a positive value, so that a lag of 1 is expressed using “1” (and a lead of 1 is expressed using “-1”).

# Create a one month lag of US unemployment
us_monthlag <- lag(unemployment$us, k = "1")

# Create a one year lag of US unemployment
us_yearlag <- lag(unemployment$us, k = "12")

# Merge your original data with your new lags 
unemployment_lags <- merge(unemployment, us_monthlag, us_yearlag)

# View the first 15 rows of unemployment_lags
head(unemployment_lags, 15)
           us    ma us.1 us.2
Jan 1976 7.90 11.60   NA   NA
Feb 1976 7.70 11.25 7.90   NA
Mar 1976 7.60 10.90 7.70   NA
Apr 1976 7.70 10.15 7.60   NA
May 1976 7.40  9.40 7.70   NA
Jun 1976 7.60  9.80 7.40   NA
Jul 1976 7.60  9.70 7.60   NA
Aug 1976 7.60  9.00 7.60   NA
Sep 1976 7.60  9.00 7.60   NA
Oct 1976 7.70  8.30 7.60   NA
Nov 1976 7.80  8.30 7.70   NA
Dec 1976 7.65  8.20 7.80   NA
Jan 1977 7.50  9.50 7.65  7.9
Feb 1977 7.60  9.20 7.50  7.7
Mar 1977 7.40  8.80 7.60  7.6

hen it comes to time series analysis, many of the theoretical processes you’ll investigate take some time to have an effect. Including lags in your analysis is an easy way to account for this. However, as you may have noticed in your call to head(), lags generated through this process are not intuitively labelled in your data.

3.2.3 Differencing unemployment

To calculate a difference, simply use the diff() command. This command requires you to specify the original data object, the number of lags (lag), and the order of the difference (differences).

In this exercise, you’ll expand your unemployment data in a different direction by adding a few useful difference measures.

Construct a first order monthly difference in US unemployment using diff(). In your call to diff(), specify the column you are drawing from in unemployment as well as the lag and differences arguments. Rather than saving this to a new object for merging, save your data into a new column in unemployment called us_monthlydiff.

Use a similar call to diff() to construct an annual difference in US unemployment. Save this to unemployment$us_yearlydiff.

# Generate monthly difference in unemployment
unemployment$us_monthlydiff <- diff(unemployment$us, lag = 1, differences = 1)

# Generate yearly difference in unemployment
unemployment$us_yearlydiff <- diff(unemployment$us, lag = 12, differences = 1)

Use two calls to plot.xts() to generate plots of US unemployment (unemployment$us) and annual change (unemployment$us_yearlydiff), respectively. Leave the type argument as is in your second call to plot.xts() to produce a barplot. The pre-written par() command allows you to view both plots at the same time.

# Plot US unemployment and annual difference
par(mfrow = c(2,1))
plot.xts(unemployment$us)
plot.xts(unemployment$us_yearlydiff, type = "h")

While lags are useful in time series analysis, differencing provides a very intuitive way to visualize growth trends over time. Both types of indicators are easy to produce using commands in xts and zoo.

3.3 Rolling functions

3.3.1 Add a discrete rolling sum to GDP data

While it helps to know the amount of change from one period to the next, you may want to know the total change since the beginning of the year. To generate this type of indicator, you can use the split-lapply-rbind pattern.

In addition to static GDP values in each quarter, you’d like to generate a measure of GDP change from one quarter to the next (using diff()) as well as a rolling sum of year-to-date GDP change (using split(), lapply() and rbind().

Use diff() to produce a simple quarterly difference in gdp. Be sure to specify the gdp column and set the lag equal to 1 period (in this case, 1 quarter). Save this into your gdp object as quarterly_diff. Now that you have a measure of quarterly GDP change, your next step is to split your quarterly_diff data into years using split(). In your call to split(), be sure to specify the quarterly_diff column of gdp and set the f argument equal to “years” (with quotes).

Use lapply() on your newly split data. To calculate a cumulative sum in each year, set the FUN argument equal to cumsum (without quotes).

Use do.call() to rbind your gdpchange_ytd data back into an xts object. Finally, use plot.xts() to examine year-to-date change in GDP (gdpchange_xts).

gdp <- gdp_approx
gdp <- setNames(gdp, "gdp")
# Add a quarterly difference in gdp
gdp$quarterly_diff <- diff(gdp$gdp , lag = 1, differences = 1)

# Split gdp$quarterly_diff into years
gdpchange_years <- split(gdp$quarterly_diff, f = "years")

# Use lapply to calculate the cumsum each year
gdpchange_ytd <- lapply(gdpchange_years, FUN = cumsum)

# Use do.call to rbind the results
gdpchange_xts <- do.call(rbind, gdpchange_ytd)

# Plot cumulative year-to-date change in GDP
plot.xts(gdpchange_xts, type = "h")

The split-lapply-rbind pattern is complicated but allows you to develop useful and precise indicators across your time series data. In the plot, each bar shows cumulative GDP growth since the beginning of that year. Some additional manipulation would give you a percentage of year-to-date GDP growth - a common indicator in economic analysis!

3.3.2 Add a continuous rolling average to unemployment data

In addition to discrete measures such as year-to-date sums, you may be interested in adding a rolling sum or average to your time series data.

To do so, let’s return to your monthly unemployment data. While you may be interested in static levels of unemployment in any given month, a broader picture of the economic environment might call for rolling indicators over several months.

To do this, you’ll use the rollapply() command, which takes a time series object, a window size width, and a FUN argument to apply to each rolling window.

lwd <- c(1, 2)
lty <- c(2, 1)
# Use rollapply to calculate the rolling yearly average US unemployment
unemployment$year_avg <- rollapply(unemployment$us, width = 12, FUN = mean)

# Plot all columns of US unemployment data
plot.zoo(unemployment[, c("us", "year_avg")], plot.type = "single", lty = lty, lwd = lwd)

Your rolling average helps smooth out some of the short term changes in unemployment from month to month and provides a broader picture of the health of the US economy.

3.3.3 Manipulating MA unemployment data

Now that you’ve added some lags, differences, and rolling values to your GDP and US unemployment data, it’s time to take these skills back to your assignment.

Remember that your client wants information relevant to the Boston tourism industry. In addition to data on the US economy in general, it may help to prepare some relevant indicators for your Massachusetts economic data.

In this exercise, you’ll use your time series data manipulation skills to generate: a one-year lag, a six-month first order difference, a six-month rolling average, and a one-year rolling maximum in the MA unemployment rate.

# Add a one-year lag of MA unemployment
unemployment$ma_yearlag <- lag(unemployment$ma, k = "12")

# Add a six-month difference of MA unemployment
unemployment$ma_sixmonthdiff <- diff(unemployment$ma, lag = 6, differences = 1)

# Add a six-month rolling average of MA unemployment
unemployment$ma_sixmonthavg <- rollapply(unemployment$ma, width = 6, FUN = mean)
  
# Add a yearly rolling maximum of MA unemployment
unemployment$ma_yearmax <- rollapply(unemployment$ma, width = 12, FUN = max)

# View the last year of unemployment data
tail(unemployment, 12)
          us  ma us_monthlydiff us_yearlydiff year_avg ma_yearlag ma_sixmonthdiff ma_sixmonthavg
Jan 2015 5.7 5.8            0.1          -0.9 6.091667       6.80           -0.20       5.375000
Feb 2015 5.5 5.5           -0.2          -1.2 5.991667       6.50           -0.35       5.316667
Mar 2015 5.5 5.2            0.0          -1.2 5.891667       6.20           -0.50       5.233333
Apr 2015 5.4 4.7           -0.1          -0.8 5.825000       5.50           -0.30       5.183333
May 2015 5.5 4.9            0.1          -0.7 5.766667       5.50           -0.10       5.166667
Jun 2015 5.3 5.2           -0.2          -0.8 5.700000       6.00            0.30       5.216667
Jul 2015 5.3 5.2            0.0          -0.9 5.625000       6.00           -0.60       5.116667
Aug 2015 5.1 4.7           -0.2          -1.1 5.533333       5.85           -0.80       4.983333
Sep 2015 5.1 4.9            0.0          -0.9 5.458333       5.70           -0.30       4.933333
Oct 2015 5.0 4.5           -0.1          -0.7 5.400000       5.00           -0.20       4.900000
Nov 2015 5.0 4.5            0.0          -0.8 5.333333       5.00           -0.40       4.833333
Dec 2015 5.0 4.6            0.0          -0.6 5.283333       4.90           -0.60       4.733333
         ma_yearmax
Jan 2015       6.50
Feb 2015       6.20
Mar 2015       6.00
Apr 2015       6.00
May 2015       6.00
Jun 2015       6.00
Jul 2015       5.85
Aug 2015       5.80
Sep 2015       5.80
Oct 2015       5.80
Nov 2015       5.80
Dec 2015       5.80

4 Sports Data

4.1 Advanced features of xts

4.1.1 Encoding and plotting Red Sox data

After exploring and manipulating data on flights, weather, and the economy, your client wants to cover all the bases. Naturally, they’d like you to collect data on Boston’s major sports teams: the Boston Red Sox (baseball), the New England Patriots (football), the Boston Bruins (hockey), and the Boston Celtics (basketball). In this chapter, you’ll prepare data on the schedule and outcome of all games involving these teams from 2010 through 2015. It’s a perfect opportunity to gain further practice manipulating time series data!

As a start, you’ve compiled data on games played by the Boston Red Sox from 2010 through 2015. In this exercise, you’ll explore the data, encode it to xts, and plot some trends over time.

redsox <- readRDS("redsox.rds")
# View summary information about your redsox data
summary(redsox)
      date             boston_score    opponent_score      homegame        mlb         nfl   
 Min.   :2010-04-04   Min.   : 0.000   Min.   : 0.000   Min.   :0.0   Min.   :1   Min.   :0  
 1st Qu.:2011-07-01   1st Qu.: 2.000   1st Qu.: 2.000   1st Qu.:0.0   1st Qu.:1   1st Qu.:0  
 Median :2013-01-01   Median : 4.000   Median : 4.000   Median :0.5   Median :1   Median :0  
 Mean   :2012-12-31   Mean   : 4.796   Mean   : 4.538   Mean   :0.5   Mean   :1   Mean   :0  
 3rd Qu.:2014-06-28   3rd Qu.: 7.000   3rd Qu.: 6.000   3rd Qu.:1.0   3rd Qu.:1   3rd Qu.:0  
 Max.   :2015-10-04   Max.   :22.000   Max.   :20.000   Max.   :1.0   Max.   :1   Max.   :0  
      nhl         nba        season    
 Min.   :0   Min.   :0   Min.   :2010  
 1st Qu.:0   1st Qu.:0   1st Qu.:2011  
 Median :0   Median :0   Median :2012  
 Mean   :0   Mean   :0   Mean   :2012  
 3rd Qu.:0   3rd Qu.:0   3rd Qu.:2014  
 Max.   :0   Max.   :0   Max.   :2015  
# Convert the date column to a time-based format
redsox$date <- as.Date(redsox$date)

# Convert your red sox data to xts
redsox_xts <- as.xts(redsox[,-1], order.by = redsox$date)

# Plot the Red Sox score and the opponent score over time
plot.zoo(redsox_xts[, c("boston_score", "opponent_score")])

You’ve converted your Red Sox data to xts and generated plots showing scores over time. You can clearly see the games clustered into seasons. However, these plots are difficult to interpret. Ideally, you want to visualize Red Sox wins using a clear metric and perhaps provide some indicator of how the team is doing over time. To do that, you’ll need to do some math!

4.1.2 Calculate a closing average

Now that you’ve explored some trends in your Red Sox data, you want to produce some useful indicators. In this exercise, you’ll calculate the team’s win/loss average at the end of each season. In financial terms, you can think of this as the team’s value at the close of the season.

First, you’ll identify wins based on the score of each game. You can do this using a simple ifelse() command and the knowledge that the Red Sox win each game in which they score more points than the opposing team.

Second, you’ll identify the date of the last game in each season using endpoints(). This command identifies the last date in your object within certain periods.

Finally, to calculate the closing win/loss average each season, simply use period.apply() on the win_loss column of your data, specifying the close dates as the index, and mean as the function.

# Generate a new variable coding for red sox wins
redsox_xts$win_loss <- ifelse(redsox_xts$boston_score > redsox_xts$opponent_score, 1, 0)

# Identify the date of the last game each season
close <- endpoints(redsox_xts$win_loss, on = "years")

# Calculate average win/loss record at the end of each season
period.apply(redsox_xts[, "win_loss"], close, mean)
            win_loss
2010-10-03 0.5493827
2011-09-28 0.5555556
2012-10-03 0.4259259
2013-09-29 0.5987654
2014-09-28 0.4382716
2015-10-04 0.4814815

The combination of endpoints() and period.apply() allows you to easily develop indicators as of the end of a period. In this case, you can see the Red Sox had a very strong season in 2013 (avg = 0.599) and a weak season in 2014 (avg = 0.438).

4.1.3 Calculate and plot a seasonal average

In the previous exercise you used endpoints() and period.apply() to quickly calculate the win/loss average for the Boston Red Sox at the end of each season. But what if you need to know the cumulative average throughout each season? Statisticians and sports fans alike often rely on this average to compare a team with its rivals.

To calculate a cumulative average in each season, you’ll need to return to the split-lapply-rbind formula. First, you’ll split the data by season, then you’ll apply a cumulative mean function to the win_loss column in each season, then you’ll bind the values back into an xts object.

A custom cummean() function, which generates a cumulative sum and divides by the number of values included in the sum, has been generated below:

cummean <- function (x){
    cumsum(x)/seq_along(x)
}
# Split redsox_xts win_loss data into years 
redsox_seasons <- split(redsox_xts$win_loss, f = "years")

# Use lapply to calculate the cumulative mean for each season
redsox_ytd <- lapply(redsox_seasons, cummean)

# Use do.call to rbind the results
redsox_winloss <- do.call(rbind, redsox_ytd)

# Plot the win_loss average for the 2013 season
plot.xts(redsox_winloss["2013"], ylim = c(0, 1))

Your plot shows the cumulative win/loss average after each game in the 2013 season! Because each value is a cumulative average within the season, it makes sense that the value is extremely volatile at the beginning of the season, when each win or loss makes a bigger difference.

4.1.4 Calculate and plot a rolling average

The final baseball indicator you’d like to generate is the L10, or the moving win/loss average from the previous ten games. While the cumulative win/loss average tells you how the team is doing overall, the L10 indicator provides a more specific picture of the team’s recent performance. Beyond the world of sports, this measure is comparable to a financial indicator focused on recent portfolio performance.

To generate a rolling win/loss average, return to the rollapply() command used in the previous chapter. In this case, you’ll want to apply the mean function to the last 10 games played by the Red Sox at any given time during the 2013 season.

# Select only the 2013 season
redsox_2013 <- redsox_xts["2013"]

# Use rollapply to generate the last ten average
lastten_2013 <- rollapply(redsox_2013$win_loss, width = 10, FUN = mean)

# Plot the last ten average during the 2013 season
plot.xts(lastten_2013, ylim = c(0, 1))

You’ve now used your time series data manipulation skills to generate a closing average, a cumulative average, and a rolling average from basic sports scores. These types of indicators have diverse applications, whether you’re a baseball fan or a portfolio analyst.

4.2 Indexing commands in xts

4.2.1 Extract weekend games

After calculating some useful indicators from your Red Sox data, it’s time to step back and explore data from other Boston sports teams. Specifically, you’ve collected additional data on the New England Patriots (football), the Boston Bruins (hockey), and the Boston Celtics (basketball). Data for these teams, along with your redsox data, have been merged into a single xts object, sports, which now contains data on all games played by Boston-area sports teams from 2010 through 2015.

sports <- readRDS("C:/Mis cosas/Coding/Practica/R/finance/data/sports.RData")

Before conducting further analysis, you want to refine your data into a few potentially useful subsets. In particular, it may be helpful to focus exclusively on weekend games involving Boston sports teams.

To identify games based on the day of the week, you should use the .indexwday() command, which tells you the day of the week of each observation in your xts object. These values range from 0-6, with Sunday equal to 0 and Saturday equal to 6.

# Extract the day of the week of each observation
weekday <- .indexwday(sports)
head(weekday)
[1] 0 2 3 5 6 0
# Generate an index of weekend dates
weekend <- which(.indexwday(sports) == 0 | .indexwday(sports) == 6)

# Subset only weekend games
weekend_games <- sports[weekend]
head(weekend_games)
           boston_score opponent_score homegame mlb nfl nhl nba season sports_type win_loss
2010-04-04            9              7        1   1   0   0   0   2010           1        1
2010-04-10            8              3        0   1   0   0   0   2010           1        1
2010-04-11            8              6        0   1   0   0   0   2010           1        1
2010-04-17            5              6        1   1   0   0   0   2010           1        0
2010-04-18            1              7        1   1   0   0   0   2010           1        0
2010-04-24            7              6        1   1   0   0   0   2010           1        1

The advanced xts indexing commands make a seemingly difficult task extremely simple. You now have an xts object containing data on all weekend games involving Boston sports teams from 2010 through 2015.

4.2.2 Calculate a rolling average across all sports

Now that you’ve mastered subsetting your data to include only weekend games, your client would like you to take a different approach. Perhaps Boston’s tourism industry receives a boost when local sports teams win more games at home.

Instead of focusing on weekend games, you are tasked with generating a rolling win/loss average focused on games played in Boston. To produce this indicator, you’ll return to the rollapply() command used above, this time applying your calculation to all Boston-area sports teams but subsetting to include only games played at home.

# Generate a subset of sports data with only homegames
homegames <- sports[sports$homegame == 1]

# Calculate the win/loss average of the last 20 home games
homegames$win_loss_20 <- rollapply(homegames$win_loss, width = 20, FUN = mean)

# Calculate the win/loss average of the last 100 home games
homegames$win_loss_100 <- rollapply(homegames$win_loss, width = 100, FUN = mean)

# Use plot.xts to generate
plot.zoo(homegames[, c("win_loss_20", "win_loss_100")], plot.type = "single", lty = lty, lwd = lwd)

Your plot shows the general success of Boston sports teams when playing at home both in the short term (20 games) and the long term (100 games). It looks like Boston teams did very well at home in 2014!

LS0tDQp0aXRsZTogIkNhc2UgU3R1ZGllczogTWFuaXB1bGF0aW5nIFRpbWUgU2VyaWVzIERhdGEgaW4gUiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2NfY29sbGFwc2VkOiBmYWxzZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIA0KdG9jX2RlcHRoOiAzDQotLS0NCiMgRmxpZ2h0IERhdGENCg0KIyMgUmV2aWV3IHh0cyBmdW5kYW1lbnRhbHMNCg0KIyMjIEZsaWdodCBkYXRhDQoNCldlbGNvbWUgdG8gdGhpcyBwcmFjdGljZSBjb3Vyc2Ugb24gbWFuaXB1bGF0aW5nIHRpbWUgc2VyaWVzIGRhdGEgdXNpbmcgeHRzICYgem9vISBUaGlzIGNvdXJzZSBpcyBkZXNpZ25lZCB0byByZXZpZXcgdGhlIHRpbWUgc2VyaWVzIHRvb2xzIGF2YWlsYWJsZSBpbiBSLiBBcyB3aXRoIG1vc3QgY29tcG9uZW50cyBvZiBkYXRhIGFuYWx5c2lzLCBtdWNoIG9mIHRoZSB3b3JrIG9mIHRpbWUgc2VyaWVzIGFuYWx5c2lzIGludm9sdmVzIGRhdGEgY2xlYW5pbmcgYW5kIG1hbmlwdWxhdGlvbi4NCg0KWW91ciB0YXNrIGlzIHRvIHVuZGVyc3RhbmQgdGhlIHRyYXZlbCBwYXR0ZXJucyBvZiB0b3VyaXN0cyB2aXNpdGluZyBCb3N0b24uIEFzIGEgZmlyc3Qgc3RlcCwgeW91J3ZlIGJlZW4gYXNzaWduZWQgdG8gZXhwbG9yZSBwYXR0ZXJucyBpbiBmbGlnaHRzIGFycml2aW5nIGF0IEJvc3RvbidzIExvZ2FuIEludGVybmF0aW9uYWwgQWlycG9ydCAoQk9TKS4gSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIHZpZXcgdGhlIHN0cnVjdHVyZSBhbmQgcXVhbGl0aWVzIG9mIHNvbWUgZGF0YSBpbiBwcmVwYXJhdGlvbiBmb3IgdGltZSBzZXJpZXMgbWFuaXB1bGF0aW9uLg0KDQpMdWNreSBmb3IgeW91LCB0aGUgW1UuUy4gQnVyZWF1IG9mIFRyYW5zcG9ydGF0aW9uIFN0YXRpc3RpY3NdKGh0dHBzOi8vd3d3LnRyYW5zdGF0cy5idHMuZ292L290X2RlbGF5L290X2RlbGF5Y2F1c2UxLmFzcCkgcHJvdmlkZXMgb3BlbiBzb3VyY2UgZGF0YSBvbiBmbGlnaHQgYXJyaXZhbCB0aW1lcy4gDQoNCmBgYHtyfQ0KIyBkb3dubG9hZC5maWxlKCJodHRwOi8vczMuYW1hem9uYXdzLmNvbS9hc3NldHMuZGF0YWNhbXAuY29tL3Byb2R1Y3Rpb24vY291cnNlXzE5NjQvZGF0YXNldHMvZmxpZ2h0cy5SRGF0YSIsIGRlc3RmaWxlID0gImZsaWdodHMuUkRhdGEiKQ0KZmxpZ2h0cyA8LSByZWFkUkRTKCJmbGlnaHRzLlJEYXRhIikNCmBgYA0KRXhwbG9yZSB0aGUgc3RydWN0dXJlIG9mIGZsaWdodHMgdXNpbmcgc3RyKCkgdG8gdW5kZXJzdGFuZCB0aGUgaW5mb3JtYXRpb24gY29udGFpbmVkIGluIHRoZSBkYXRhIGZpbGUuDQpgYGB7cn0NCiNWaWV3IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGZsaWdodHMgZGF0YQ0Kc3RyKGZsaWdodHMpDQoNCiNFeGFtaW5lIHRoZSBmaXJzdCBmaXZlIHJvd3Mgb2YgdGhlIGZsaWdodHMgZGF0YQ0KaGVhZChmbGlnaHRzLCBuID0gNSkNCmBgYA0KVGhlIGZpcnN0IHN0ZXAgaW4gcHJlcGFyaW5nIGFuIG9iamVjdCBmb3IgY29udmVyc2lvbiB0byB4dHMgaXMgdG8gZW5zdXJlIHRoYXQgdGhlIHRpbWUvZGF0ZSBjb2x1bW4gaXMgaW4gYSBwcm9wZXIgdGltZS1iYXNlZCBmb3JtYXQuIENoZWNrIHRoZSBjbGFzcyBvZiB0aGUgcmVsZXZhbnQgY29sdW1uIGluIGZsaWdodHMgdXNpbmcgY2xhc3MoKS4NCmBgYHtyfQ0KI0lkZW50aWZ5IGNsYXNzIG9mIHRoZSBjb2x1bW4gY29udGFpbmluZyBkYXRlIGluZm9ybWF0aW9uDQpjbGFzcyhmbGlnaHRzJGRhdGUpDQpgYGANCkl0J3MgYWx3YXlzIGhlbHBmdWwgdG8gdXNlIHRoZXNlIGNvbW1hbmRzIHRvIGdldCBhIGZlZWwgZm9yIHlvdXIgZGF0YSBiZWZvcmUgeW91IGJlZ2luIGFuYWx5c2lzLiBBcyB5b3UgY2FuIHNlZSwgdGhlIGZsaWdodHMgb2JqZWN0IGNvbnRhaW5zIGZvdXIgY29sdW1ucyBvZiBmbGlnaHQgZGF0YSBhbmQgb25lIGNvbHVtbiBvZiBkYXRlcy4gVGhlIGRhdGUgY29sdW1uIGlzIGN1cnJlbnRseSBhIGNoYXJhY3RlciBzdHJpbmcuIFlvdSdsbCBuZWVkIHRvIGNvbnZlcnQgdGhpcyBpbnRvIGEgdGltZS1iYXNlZCBvYmplY3QgYmVmb3JlIG1vdmluZyBmb3J3YXJkIHdpdGggdGltZSBzZXJpZXMgYW5hbHlzaXMuDQoNCiMjIyBQaWNrIG91dCB0aGUgeHRzIG9iamVjdA0KDQpJdCBsb29rcyBsaWtlIHlvdXIgZmxpZ2h0cyBkYXRhIHdpbGwgbmVlZCBzb21lIG1vZGlmaWNhdGlvbnMgYmVmb3JlIGl0IGNhbiBiZSB0dXJuZWQgaW50byBhbiB4dHMgb2JqZWN0LiBBcyB5b3Uga25vdywgdGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IHR5cGVzIG9mIG9iamVjdHMgaW4gUi4geHRzIG9iamVjdHMgYXJlIHNwZWNpZmljYWxseSBkZXNpZ25lZCBmb3IgdGltZSBzZXJpZXMgZnVuY3Rpb25hbGl0eS4gVGhlIGludGVybmFsIHN0cnVjdHVyZSBvZiBhbiB4dHMgb2JqZWN0IGlzIGEgbWF0cml4IGluZGV4ZWQgb24gYSB0aW1lLWJhc2VkIG9iamVjdC4NCg0KIyMjIEVuY29kaW5nIHlvdXIgZmxpZ2h0IGRhdGENCg0KWW91J3JlIHJlYWR5IHRvIGVuY29kZSB5b3VyIGRhdGEgdG8gYW4geHRzIG9iamVjdCEgUmVtZW1iZXIgdGhhdCBmbGlnaHRzIGlzIGEgZGF0YSBmcmFtZSBjb250YWluaW5nIGZvdXIgY29sdW1ucyBvZiBmbGlnaHQgZGF0YSBhbmQgb25lIGNvbHVtbiBvZiBkYXRlcy4NCg0KVG8gY29udmVydCB0byBhbiB4dHMgb2JqZWN0LCB5b3UnbGwgbmVlZCB0byBlbnN1cmUgdGhhdCB5b3VyIGRhdGUgY29sdW1uIGlzIGluIGEgdGltZS1iYXNlZCBmb3JtYXQuIEFzIHlvdSBkaXNjb3ZlcmVkIGVhcmxpZXIsIHRoZSBkYXRlIGNvbHVtbiBpcyBjdXJyZW50bHkgYSBjaGFyYWN0ZXIuIE9uY2UgZGF0ZSBpcyBzYXZlZCBpbiBhIHRpbWUtYmFzZWQgZm9ybWF0LCB5b3UncmUgcmVhZHkgdG8gY29udmVydCB0byB4dHMhIFRvIGRvIHNvLCB5b3UnbGwgdXNlIGFzLnh0cygpLCB3aGljaCB0YWtlcyB0d28gcHJpbWFyeSBhcmd1bWVudHMuDQoNCkZpcnN0LCB5b3UnbGwgbmVlZCB0byBzcGVjaWZ5IHRoZSBvYmplY3QgYmVpbmcgY29udmVydGVkIChpbiB0aGlzIGNhc2UsIGZsaWdodHMpLiBUbyBhdm9pZCByZWR1bmRhbmNpZXMsIHlvdSBzaG91bGQgZ2VuZXJhbGx5IHJlbW92ZSB0aGUgdGltZS1iYXNlZCBjb2x1bW4gZnJvbSB0aGUgZGF0YSB3aGVuIHlvdSBjb252ZXJ0IHRvIHh0cy4gSW4gdGhpcyBjYXNlLCB5b3UnbGwgcmVtb3ZlIHRoZSBmaWZ0aCBjb2x1bW4gKGRhdGVzKSwgYnkgc3BlY2lmeWluZyBbLCAtNV0gaW4geW91ciBhcy54dHMoKSBjYWxsLg0KDQpTZWNvbmQsIHlvdSdsbCBuZWVkIHRvIHRlbGwgeHRzIGhvdyB0byBpbmRleCB5b3VyIG9iamVjdCBieSBzcGVjaWZ5aW5nIHRoZSBvcmRlci5ieSBhcmd1bWVudC4gSW4gdGhpcyBjYXNlLCB5b3Ugd2FudCB0byBpbmRleCB5b3VyIG9iamVjdCBvbiB0aGUgZGF0ZSBjb2x1bW4uDQoNCmBgYHtyfQ0KIyBMb2FkIHRoZSB4dHMgcGFja2FnZQ0KbGlicmFyeSh4dHMpDQoNCiMgQ29udmVydCBkYXRlIGNvbHVtbiB0byBhIHRpbWUtYmFzZWQgY2xhc3MNCmZsaWdodHMkZGF0ZSA8LSBhcy5EYXRlKGZsaWdodHMkZGF0ZSkNCg0KIyBDb252ZXJ0IGZsaWdodHMgdG8gYW4geHRzIG9iamVjdCB1c2luZyBhcy54dHMNCmZsaWdodHNfeHRzIDwtIGFzLnh0cyhmbGlnaHRzIFsgLCAtNV0sIG9yZGVyLmJ5ID0gZmxpZ2h0cyRkYXRlKQ0KDQojIENoZWNrIHRoZSBjbGFzcyBvZiBmbGlnaHRzX3h0cw0KY2xhc3MoZmxpZ2h0c194dHMpDQoNCiMgRXhhbWluZSB0aGUgZmlyc3QgZml2ZSBsaW5lcyBvZiBmbGlnaHRzX3h0cw0KaGVhZChmbGlnaHRzX3h0cywgNSkNCmBgYA0KWW91ciBuZXcgeHRzIG9iamVjdCBjb250YWlucyBmb3VyIGNvbHVtbnMgb2YgaW5mb3JtYXRpb24gYWJvdXQgZmxpZ2h0cyBpbmRleGVkIG9uIGEgc2VyaWVzIG9mIG1vbnRocyBhbmQgeWVhcnMuDQoNCiMjIE1hbmlwdWxhdGluZyBhbmQgdmlzdWFsaXppbmcgeW91ciBkYXRhDQoNCiMjIyBFeHBsb3JpbmcgeW91ciBmbGlnaHQgZGF0YQ0KDQpCZWZvcmUgYW55IGFuYWx5c2lzIGNhbiBiZSBkb25lLCBpdCBpcyBjcml0aWNhbCB0byBleHBsb3JlIHRoZSBiYXNpYyBxdWFsaXRpZXMgb2YgeW91ciBkYXRhLCBpbmNsdWRpbmcgcGVyaW9kaWNpdHksIHNjb3BlLCBhbmQgY29tcHJlaGVuc2l2ZW5lc3MuDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCBnYWluIGEgYmV0dGVyIHVuZGVyc3RhbmRpbmcgb2YgeW91ciBkYXRhIGJ5IGV4cGxvcmluZyB0aGVzZSBxdWFsaXRpZXMuIEFzIHlvdSBtYXkgcmVjYWxsIGZyb20gdGhlIGVhcmxpZXIgZXhlcmNpc2VzLCB5b3VyIHRpbWUgaW5kZXggc2VlbWVkIHRvIGJlIGluIG1vbnRocy4gVG8gY2hlY2sgdGhhdCB0aGlzIGlzIGNvbnN0YW50IHRocm91Z2hvdXQgeW91ciB4dHMgb2JqZWN0LCB5b3UgY2FuIHVzZSB0aGUgcGVyaW9kaWNpdHkoKSBjb21tYW5kIHRvIHRlbGwgeW91IHRoZSBwZXJpb2RpY2l0eSBhbmQgc2NvcGUgb2YgdGhlIGRhdGEuDQoNCk9uY2UgeW91IGFyZSBzdXJlIG9mIHBlcmlvZGljaXR5LCB5b3UgbWF5IGFsc28gd2FudCB0byBrbm93IGhvdyBtYW55IHBlcmlvZHMgYXJlIGNvdmVyZWQuIFRvIGlkZW50aWZ5IHRoZSBudW1iZXIgb2YgcGVyaW9kcyBpbiB5b3VyIGRhdGEsIHlvdSBjYW4gdXNlIHRoZSBuZGF5cygpIGNvbW1hbmQsIG9yIG9uZSBvZiBpdHMgd3JhcHBlcnMsIG5tb250aHMoKSwgbnllYXJzKCksIGV0Yy4NCg0KRmluYWxseSwgeW91IG1heSBmaW5kIGl0IHVzZWZ1bCB0byBxdWVyeSBmb3IgYSBwYXJ0aWN1bGFyIGRhdGUgYnkgc3Vic2V0dGluZyBGb3IgZXhhbXBsZSwgaW5wdXR0aW5nIHh0c19vYmplY3RbImRhdGUiXSB3aWxsIGdlbmVyYXRlIHRoZSByb3cgcGVydGFpbmluZyB0byB0aGF0IGRhdGUuDQoNCmBgYHtyfQ0KIyBJZGVudGlmeSB0aGUgcGVyaW9kaWNpdHkgb2YgZmxpZ2h0c194dHMNCnBlcmlvZGljaXR5KGZsaWdodHNfeHRzKQ0KDQojIElkZW50aWZ5IHRoZSBudW1iZXIgb2YgcGVyaW9kcyBpbiBmbGlnaHRzX3h0cw0Kbm1vbnRocyhmbGlnaHRzX3h0cykNCg0KIyBGaW5kIGRhdGEgb24gZmxpZ2h0cyBhcnJpdmluZyBpbiBCT1MgaW4gSnVuZSAyMDE0DQpmbGlnaHRzX3h0c1siMjAxNC0wNiJdDQpgYGANCkl0IGxvb2tzIGxpa2UgeW91IGhhdmUgbW9udGhseSBkYXRhIG9uIGZsaWdodHMgYXJyaXZpbmcgaW4gQm9zdG9uIG92ZXIgdGhlIGNvdXJzZSBvZiA3MiBtb250aHMgZnJvbSBKYW51YXJ5IDIwMTAgdGhyb3VnaCBEZWNlbWJlciAyMDE1Lg0KDQojIyMgVmlzdWFsaXplIGZsaWdodCBkYXRhDQoNCk5vdyB0aGF0IHlvdSBoYXZlIGEgZ3JpcCBvbiB5b3VyIGRhdGEsIHRoZSBuZXh0IHN0ZXAgaXMgdG8gdmlzdWFsaXplIHRyZW5kcyBpbiB5b3VyIGRhdGEgb3ZlciB0aW1lLiBJbiB0aGlzIGV4ZXJjaXNlLCB5b3UnbGwgcGxvdCB0aGUgZmxpZ2h0c194dHMgZGF0YSBvdmVyIHRpbWUgdXNpbmcgYSBmZXcgZGlmZmVyZW50IG1ldGhvZHMgZm9yIHBsb3R0aW5nIHRpbWUgc2VyaWVzIGRhdGEuDQoNCk9mdGVuIHRoZSBzaW1wbGVzdCB3YXkgdG8gcGxvdCB4dHMgb2JqZWN0cyBpcyB0byB1c2UgcGxvdC54dHMoKSwgd2hpY2ggcmVxdWlyZXMgb25seSBhIHNpbmdsZSBhcmd1bWVudCBmb3IgdGhlIHktYXhpcyBpbiB0aGUgcGxvdC4gVGhlIHgtYXhpcyBpcyBzdXBwbGllZCBieSB0aGUgdGltZSBpbmRleCBpbiB5b3VyIHh0cyBvYmplY3QuDQoNCkZvciBtb3JlIGNvbXBsaWNhdGVkIHBsb3RzLCB5b3UgbWF5IHdhbnQgdG8gdXNlIHBsb3Quem9vKCksIHdoaWNoIGFsbG93cyB5b3UgdG8gaW5jbHVkZSBtdWx0aXBsZSBjb2x1bW5zIG9mIGRhdGEuIEluIHBhcnRpY3VsYXIsIHRoZSBwbG90LnR5cGUgYXJndW1lbnQgYWxsb3dzIHlvdSB0byBzcGVjaWZ5IHdoZXRoZXIgeW91J2QgbGlrZSB5b3VyIGRhdGEgdG8gYXBwZWFyIGluIGEgc2luZ2xlIHBhbmVsICgic2luZ2xlIikgb3IgbXVsdGlwbGUgcGFuZWxzICgibXVsdGlwbGUiKS4gVGhpcyBjYW4gYmUgdXNlZnVsIHdoZW4gY29tcGFyaW5nIG11bHRpcGxlIGNvbHVtbnMgb2YgZGF0YSBvdmVyIHRpbWUuDQpgYGB7cn0NCiMgVXNlIHBsb3QueHRzKCkgdG8gdmlldyB0b3RhbCBtb250aGx5IGZsaWdodHMgaW50byBCT1Mgb3ZlciB0aW1lDQpwbG90Lnh0cyhmbGlnaHRzX3h0cyR0b3RhbF9mbGlnaHRzKQ0KDQojIFVzZSBwbG90Lnh0cygpIHRvIHZpZXcgbW9udGhseSBkZWxheWVkIGZsaWdodHMgaW50byBCT1Mgb3ZlciB0aW1lDQpwbG90Lnh0cyhmbGlnaHRzX3h0cyRkZWxheV9mbGlnaHRzKQ0KDQojIFVzZSBwbG90LnpvbygpIHRvIHZpZXcgYWxsIGZvdXIgY29sdW1ucyBvZiBkYXRhIGluIHRoZWlyIG93biBwYW5lbHMNCmxhYmVscyA8LSBjKCJUb3RhbCIsICJEZWxheSIsICJDYW5jZWwiLCAiRGl2ZXJ0IikNCnBsb3Quem9vKGZsaWdodHNfeHRzLCBwbG90LnR5cGUgPSAibXVsdGlwbGUiLCB5bGFiID0gbGFiZWxzKQ0KDQojIFVzZSBwbG90LnpvbygpIHRvIHZpZXcgYWxsIGZvdXIgY29sdW1ucyBvZiBkYXRhIGluIG9uZSBwYW5lbA0KbHR5IDwtIGMoMSwgMiwgMywgNCkNCnBsb3Quem9vKGZsaWdodHNfeHRzLCBwbG90LnR5cGUgPSAic2luZ2xlIiwgbHR5ID0gbHR5KQ0KbGVnZW5kKCJyaWdodCIsIGx0eSA9IGx0eSwgbGVnZW5kID0gbGFiZWxzKQ0KYGBgDQpUaGVzZSBwbG90cyBwcm92aWRlIHNvbWUgdmVyeSBpbXBvcnRhbnQgaW5mb3JtYXRpb24gYWJvdXQgZmxpZ2h0cyBhcnJpdmluZyBpbiBCb3N0b24uIEl0IGxvb2tzIGxpa2Ugb25seSBhIHNtYWxsIHBlcmNlbnRhZ2Ugb2YgZmxpZ2h0cyBhcmUgZGVsYXllZCwgY2FuY2VsbGVkLCBvciBkaXZlcnRlZC4NCg0KIyMjIENhbGN1bGF0ZSB0aW1lIHNlcmllcyB0cmVuZHMNCg0KT25lIG9mIHRoZSBtb3N0IHVzZWZ1bCBxdWFsaXRpZXMgb2YgeHRzIG9iamVjdHMgaXMgdGhlIGFiaWxpdHkgdG8gY29uZHVjdCBzaW1wbGUgbWF0aGVtYXRpY2FsIGVxdWF0aW9ucyBhY3Jvc3MgdGltZS4gSW4geW91ciBmbGlnaHQgZGF0YSwgb25lIHZhbHVhYmxlIG1ldHJpYyB0byBjYWxjdWxhdGUgd291bGQgYmUgdGhlIHBlcmNlbnRhZ2Ugb2YgZmxpZ2h0cyBkZWxheWVkLCBjYW5jZWxsZWQsIG9yIGRpdmVydGVkIGVhY2ggbW9udGguDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCB1c2UgeW91ciBkYXRhIHRvIGdlbmVyYXRlIGEgbmV3IHRpbWUgc2VyaWVzIGNvbHVtbiBjb250YWluaW5nIHRoZSBwZXJjZW50YWdlIG9mIGZsaWdodHMgYXJyaXZpbmcgbGF0ZSB0byBCb3N0b24gZWFjaCBtb250aC4gWW91J2xsIHRoZW4gZ2VuZXJhdGUgYSBwbG90IGZvciB0aGlzIG1ldHJpYywgYmVmb3JlIGdvaW5nIG9uIHRvIGNhbGN1bGF0ZSBhZGRpdGlvbmFsIG1ldHJpY3MgZm9yIGZsaWdodCBjYW5jZWxsYXRpb25zIGFuZCBkaXZlcnNpb25zLg0KDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2Ugb2YgZmxpZ2h0cyBkZWxheWVkIGVhY2ggbW9udGg6IHBjdF9kZWxheQ0KZmxpZ2h0c194dHMkcGN0X2RlbGF5IDwtIChmbGlnaHRzX3h0cyRkZWxheV9mbGlnaHRzIC8gZmxpZ2h0c194dHMkdG90YWxfZmxpZ2h0cykgKiAxMDANCg0KIyBVc2UgcGxvdC54dHMoKSB0byB2aWV3IHBjdF9kZWxheSBvdmVyIHRpbWUNCnBsb3QueHRzKGZsaWdodHNfeHRzJHBjdF9kZWxheSkNCg0KIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBvZiBmbGlnaHRzIGNhbmNlbGxlZCBlYWNoIG1vbnRoOiBwY3RfY2FuY2VsDQpmbGlnaHRzX3h0cyRwY3RfY2FuY2VsIDwtIChmbGlnaHRzX3h0cyRjYW5jZWxfZmxpZ2h0cyAvIGZsaWdodHNfeHRzJHRvdGFsX2ZsaWdodHMpICogMTAwDQoNCiMgQ2FsY3VsYXRlIHBlcmNlbnRhZ2Ugb2YgZmxpZ2h0cyBkaXZlcnRlZCBlYWNoIG1vbnRoOiBwY3RfZGl2ZXJ0DQpmbGlnaHRzX3h0cyRwY3RfZGl2ZXJ0IDwtIChmbGlnaHRzX3h0cyRkaXZlcnRfZmxpZ2h0cyAvIGZsaWdodHNfeHRzJHRvdGFsX2ZsaWdodHMpICogMTAwDQoNCiMgVXNlIHBsb3Quem9vKCkgdG8gdmlldyBhbGwgdGhyZWUgdHJlbmRzIG92ZXIgdGltZQ0KcGxvdC56b28oeCA9IGZsaWdodHNfeHRzWyAsIGMoInBjdF9kZWxheSIsICJwY3RfY2FuY2VsIiwgInBjdF9kaXZlcnQiKV0pDQpgYGANClRoaXMgcGxvdCBzaG93cyB0aGUgcGVyY2VudGFnZSBvZiBmbGlnaHRzIGVhY2ggbW9udGggdGhhdCBhcmUgZGVsYXllZCwgY2FuY2VsbGVkLCBvciBkaXZlcnRlZC4gRG8geW91IG5vdGljZSBhbnkgdHJlbmRzPyBQYXkgY2xvc2UgYXR0ZW50aW9uIHRvIGRpZmZlcmVudCB5LWF4aXMgc2NhbGVzIGFjcm9zcyB0aGUgZGlmZmVyZW50IHBhbmVscy4NCg0KIyMgU2F2aW5nIGFuZCBleHBvcnRpbmcgeHRzIG9iamVjdHMNCg0KIyMjIEFzc2Vzc2luZyBmbGlnaHQgdHJlbmRzDQoNClZpc3VhbGl6aW5nIHRpbWUgc2VyaWVzIGRhdGEgLSBhbmQgdmFyaW91cyB2YWx1ZXMgZGVyaXZlZCBmcm9tIHRoZXNlIGRhdGEgLSBpcyBhIGNyaXRpY2FsIGNvbXBvbmVudCBvZiBhbnkgdGltZSBzZXJpZXMgYW5hbHlzaXMsIHdoZXRoZXIgeW91IGFyZSBpbnRlcmVzdGVkIGluIHN0b2NrIHJldHVybnMsIHVzZXIgcmV0ZW50aW9uLCBvciBvcGluaW9uIHBvbGxzLg0KDQpZb3VyIHBsb3Qgc3VnZ2VzdHMgdGhhdCB0aGUgcGVyY2VudGFnZSBvZiBmbGlnaHQgY2FuY2VsbGF0aW9ucyBzcGlrZXMgYXJvdW5kIERlY2VtYmVyIGFuZCBKYW51YXJ5IGVhY2ggeWVhciwgd2l0aCB0aGUgZXhjZXB0aW9uIG9mIDIwMTIuIFdoYXQgY291bGQgYmUgY2F1c2luZyB0aGlzIHRyZW5kPyBZb3UnbGwgZXhwbG9yZSBzb21lIHBvc3NpYmlsaXRpZXMgbGF0ZXIgaW4gdGhlIGNvdXJzZS4NCg0KIyMjIFNhdmluZyB0aW1lIA0KDQpZb3UndmUgbm93IHN1Y2Nlc3NmdWxseSBjb252ZXJ0ZWQgeW91ciBmbGlnaHRzIGRhdGEgaW50byBhbiB4dHMgb2JqZWN0LCBwbG90dGVkIGluZm9ybWF0aW9uIG92ZXIgdGltZSwgYW5kIGNhbGN1bGF0ZWQgYSBmZXcgdmFsdWFibGUgbWV0cmljcyB0byBoZWxwIHlvdSBwcm9jZWVkIHdpdGggYW5hbHlzaXMuIFlvdSd2ZSBldmVuIGJlZW4gYWJsZSB0byBjb25kdWN0IHNvbWUgcXVpY2sgZGVzY3JpcHRpdmUgYW5hbHlzaXMgb24geW91ciBkYXRhIGJ5IHBsb3R0aW5nIHRoZXNlIG1ldHJpY3Mgb3ZlciB0aW1lLg0KDQpUaGUgZmluYWwgc3RlcCBpbiBhbnkgdGltZSBzZXJpZXMgZGF0YSBtYW5pcHVsYXRpb24gaXMgdG8gc2F2ZSB5b3VyIHh0cyBvYmplY3Qgc28geW91IGNhbiBlYXNpbHkgcmV0dXJuIHRvIGl0IGluIHRoZSBmdXR1cmUuDQoNCkFzIGEgZmlyc3Qgc3RlcCwgeW91J2xsIHdhbnQgdG8gc2F2ZSB5b3VyIHh0cyBvYmplY3QgYXMgYSByZHMgZmlsZSBmb3IgeW91ciBvd24gdXNlLiBUbyBkbyB0aGlzLCB5b3UnbGwgdXNlIHRoZSBjb21tYW5kIHNhdmVSRFMoKSwgd2hpY2ggc2F2ZXMgeW91ciBvYmplY3QgdG8gYSBmaWxlIHdpdGggdGhlIG5hbWUgeW91IHNwZWNpZnkgKHVzaW5nIHRoZSBmaWxlIGFyZ3VtZW50KS4gQnkgZGVmYXVsdCwgc2F2ZVJEUygpIHdpbGwgc2F2ZSB0byB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4NCg0KV2hlbiB5b3UncmUgcmVhZHkgdG8gcmV0dXJuIHlvdXIgc2F2ZWQgZGF0YSwgeW91IGNhbiB1c2UgdGhlIHJlYWRSRFMoKSBjb21tYW5kIHRvIHJlb3BlbiB0aGUgZmlsZS4gDQoNCiAgICAjIFNhdmUgeW91ciB4dHMgb2JqZWN0IHRvIHJkcyBmaWxlIHVzaW5nIHNhdmVSRFMNCiAgICBzYXZlUkRTKG9iamVjdCA9IGZsaWdodHNfeHRzLCBmaWxlID0gImZsaWdodHNfeHRzLnJkcyIpDQogICAgDQogICAgIyBSZWFkIHlvdXIgZmxpZ2h0c194dHMgZGF0YSBmcm9tIHRoZSByZHMgZmlsZQ0KICAgIGZsaWdodHNfeHRzMiA8LSByZWFkUkRTKCJmbGlnaHRzX3h0cy5yZHMiKQ0KICAgIA0KICAgICMgQ2hlY2sgdGhlIGNsYXNzIG9mIHlvdXIgbmV3IGZsaWdodHNfeHRzMiBvYmplY3QNCiAgICBjbGFzcyhmbGlnaHRzX3h0czIpDQogICAgDQogICAgIyBFeGFtaW5lIHRoZSBmaXJzdCBmaXZlIHJvd3Mgb2YgeW91ciBuZXcgZmxpZ2h0c194dHMyIG9iamVjdA0KICAgIGhlYWQoZmxpZ2h0c194dHMyLCA1KQ0KDQpBcyB5b3UgY2FuIHNlZSwgc2F2aW5nIHRvIHJkcyBmaWxlcyBhbGxvd3MgeW91IHRvIG1haW50YWluIHRoZSBjbGFzcyBvZiB5b3VyIGRhdGEgb2JqZWN0LiBIb3dldmVyLCByZHMgZmlsZXMgYXJlIGRpZmZpY3VsdCB0byByZWFkIGludG8gcHJvZ3JhbXMgb3RoZXIgdGhhbiBSLiANCg0KWW91J3ZlIHNhdmVkIHlvdXIgZmxpZ2h0c194dHMgZGF0YSB0byBhIHJkcyBmaWxlIGZvciBmdXR1cmUgdXNlLiBCdXQgd2hhdCBpZiB5b3UnZCBsaWtlIHRvIHNoYXJlIHlvdXIgZGF0YSB3aXRoIGNvbGxlYWd1ZXMgd2hvIGRvbid0IHVzZSBSPw0KDQpBIHNlY29uZCBvcHRpb24gZm9yIHNhdmluZyB4dHMgb2JqZWN0cyBpcyB0byBjb252ZXJ0IHRoZW0gdG8gc2hhcmVhYmxlIGZvcm1hdHMgYmV5b25kIHRoZSBSIGVudmlyb25tZW50LCBpbmNsdWRpbmcgY29tbWEtc2VwYXJhdGVkIHZhbHVlcyAoQ1NWKSBmaWxlcy4gVG8gZG8gdGhpcywgeW91J2xsIHVzZSB0aGUgd3JpdGUuem9vKCkgY29tbWFuZC4NCg0KT25jZSB5b3UndmUgc3VjY2VzZnVsbHkgZXhwb3J0ZWQgeW91ciB4dHMgb2JqZWN0IHRvIGEgY3N2IGZpbGUsIHlvdSBjYW4gbG9hZCB0aGUgZGF0YSBiYWNrIGludG8gUiB1c2luZyB0aGUgcmVhZC56b28oKSBjb21tYW5kLiBVbmxpa2UgcmVhZFJEUywgaG93ZXZlciwgeW91IHdpbGwgbmVlZCB0byByZS1lbmNvZGUgeW91ciBkYXRhIHRvIGFuIHh0cyBvYmplY3QgKHVzaW5nIGFzLnh0cykuDQoNCiAgICAjIEV4cG9ydCB5b3VyIHh0cyBvYmplY3QgdG8gYSBjc3YgZmlsZSB1c2luZyB3cml0ZS56b28NCiAgICB3cml0ZS56b28oZmxpZ2h0c194dHMsIGZpbGUgPSAiZmxpZ2h0c194dHMuY3N2Iiwgc2VwID0gIiwiKQ0KICAgIA0KICAgICMgT3BlbiB5b3VyIHNhdmVkIG9iamVjdCB1c2luZyByZWFkLnpvbw0KICAgIGZsaWdodHMyIDwtIHJlYWQuem9vKCJmbGlnaHRzX3h0cy5jc3YiLCBzZXAgPSAiLCIsIEZVTiA9IGFzLkRhdGUsIGhlYWRlciA9IFRSVUUsIGluZGV4LmNvbHVtbiA9IDEpDQogICAgDQogICAgIyBFbmNvZGUgeW91ciBuZXcgb2JqZWN0IGJhY2sgaW50byB4dHMNCiAgICBmbGlnaHRzX3h0czIgPC0gYXMueHRzKGZsaWdodHNfeHRzKQ0KICAgIA0KICAgICMgRXhhbWluZSB0aGUgZmlyc3QgZml2ZSByb3dzIG9mIHlvdXIgbmV3IGZsaWdodHNfeHRzMiBvYmplY3QNCiAgICBoZWFkKGZsaWdodHNfeHRzMiwgNSkNCiAgICANCiMgV2VhdGhlciBEYXRhDQoNCiMjIE1lcmdpbmcgdGltZSBzZXJpZXMgZGF0YSBieSByb3cNCg0KIyMjIEV4cGxvcmluZyB0ZW1wZXJhdHVyZSBkYXRhDQoNCk5vdyB0aGF0IHlvdSd2ZSBsZWFybmVkIGEgYml0IGFib3V0IHlvdXIgZmxpZ2h0cyBkYXRhIC0gYW5kIHJldmlld2VkIHRoZSBiYXNpY3Mgb2YgdGltZSBzZXJpZXMgZGF0YSBtYW5pcHVsYXRpb24gLSB5b3VyIG5leHQgYXNzaWdubWVudCBpcyB0byBleHBsb3JlIHdlYXRoZXIgcGF0dGVybnMgaW4gdGhlIEJvc3RvbiBhcmVhIHRvIHVuZGVyc3RhbmQgd2hhdCBtaWdodCBiZSBhZmZlY3RpbmcgZmxpZ2h0IGRlbGF5cyBhbmQgY2FuY2VsbGF0aW9ucy4gVG8gZG8gdGhpcywgeW91J2xsIG5lZWQgdG8gY29tcGlsZSBhbmQgbWFuaXB1bGF0ZSBzb21lIGFkZGl0aW9uYWwgdGltZSBzZXJpZXMgZGF0YS4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIGV4cGxvcmUgc29tZSB0ZW1wZXJhdHVyZSBkYXRhIGluIHRoZSBCb3N0b24gYXJlYSwgaW5jbHVkaW5nIG1lYXN1cmVzIG9mIG1pbiwgbWVhbiwgYW5kIG1heCBkYWlseSB0ZW1wZXJhdHVyZSBvdmVyIHRpbWUuIFRoZXNlIGRhdGEgd2VyZSBjb2xsZWN0ZWQgdXNpbmcgdGhlIFt3ZWF0aGVyRGF0YV0oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL3dlYXRoZXJEYXRhL3ZlcnNpb25zLzAuNC4xKSBwYWNrYWdlIGluIFIsIHdoaWNoIHNjcmFwZXMgcHVibGljbHkgYXZhaWxhYmxlIGRhdGEgZnJvbSBbV2VhdGhlciBVbmRlcmdyb3VuZF0oaHR0cHM6Ly93d3cud3VuZGVyZ3JvdW5kLmNvbS8pLg0KDQpCZWZvcmUgbW92aW5nIGZvcndhcmQgd2l0aCB5b3VyIHRpbWUgc2VyaWVzIGRhdGEgbWFuaXB1bGF0aW9uLCB0aGUgZmlyc3Qgc3RlcCBpbiBhbnkgZGF0YSBhbmFseXNpcyBpcyB0byBleGFtaW5lIHRoZSBiYXNpYyBxdWFsaXRpZXMgb2YgeW91ciBkYXRhLiBTcGVjaWZpY2FsbHksIHlvdSdsbCB0YWtlIGEgY2xvc2VyIGxvb2sgYXQgdHdvIHRlbXBlcmF0dXJlIGRhdGEgb2JqZWN0cyAodGVtcHNfMSBhbmQgdGVtcHNfMikgdG8gdW5kZXJzdGFuZCB3aGF0IGluZm9ybWF0aW9uIHRoZXNlIG9iamVjdHMgY29udGFpbiBhbmQgaG93IHlvdSBzaG91bGQgcHJvY2VlZC4NCmBgYHtyfQ0KdGVtcHNfMSA8LSByZWFkUkRTKCJ0ZW1wc18xLnJkcyIpDQp0ZW1wc18yPC0gcmVhZFJEUygidGVtcHNfMi5yZHMiKQ0KYGBgDQpgYGB7cn0NCiMgVmlldyB0aGUgc3RydWN0dXJlIG9mIGVhY2ggb2JqZWN0DQpzdHIodGVtcHNfMSkNCnN0cih0ZW1wc18yKQ0KDQojIFZpZXcgdGhlIGZpcnN0IGFuZCBsYXN0IHJvd3Mgb2YgdGVtcHNfMQ0KaGVhZCh0ZW1wc18xKQ0KdGFpbCh0ZW1wc18xKQ0KDQojIFZpZXcgdGhlIGZpcnN0IGFuZCBsYXN0IHJvd3Mgb2YgdGVtcHNfMg0KaGVhZCh0ZW1wc18yKQ0KdGFpbCh0ZW1wc18yKQ0KYGBgDQojIyMgTmV4dCBzdGVwcyANCg0KTm93IHRoYXQgeW91J3ZlIGV4YW1pbmVkIHlvdXIgZGF0YSwgeW91ciBuZXh0IHRhc2sgd2lsbCBiZSB0byBwcm9jZWVkIHdpdGggZGF0YSBtYW5pcHVsYXRpb24uIFJlbWVtYmVyIHRoYXQgdGhlIHVuZGVybHlpbmcgZ29hbCBpcyB0byBleHBsb3JlIHRoZSBwb3NzaWJsZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBCb3N0b24gYXJlYSB0ZW1wZXJhdHVyZSBhbmQgZmxpZ2h0cy4gVG8gZG8gc28sIHlvdSdsbCBuZWVkIHRvIG1hbmlwdWxhdGUgeW91ciB0ZW1wZXJhdHVyZSBkYXRhIHRvIG1ha2Ugc3VyZSBpdCBjb3ZlcnMgYSBjb21wYXJhYmxlIHRpbWUgcGVyaW9kIGF0IGEgc2ltaWxhciBzY2FsZSB0byB5b3VyIGZsaWdodHMgZGF0YS4NCg0KVXNlIHR3byBjYWxscyB0byBjbGFzcygpIHRvIGNoZWNrIHRoYXQgdGhlIGRhdGUgY29sdW1ucyBpbiB0ZW1wc18xIGFuZCB0ZW1wc18yIGFyZSBlbmNvZGVkIGFzIHRpbWUtYmFzZWQgb2JqZWN0cyAoRGF0ZSwgUE9TSVhjdCwgUE9TSVhsdCwgeWVhcm1vbiwgZXRjLikuDQoNCg0KYGBge3J9DQpzdW1tYXJ5KHRlbXBzXzEpDQpzdW1tYXJ5KHRlbXBzXzIpDQpgYGANCkl0IGxvb2tzIGxpa2UgdGVtcHNfMSBhbmQgdGVtcHNfMiBhcmUgZGF0YSBmcmFtZXMgY29udGFpbmluZyB0aW1lIHNlcmllcyBkYXRhIG92ZXIgbm9uLW92ZXJsYXBwaW5nIHRpbWUgcGVyaW9kcy4gdGVtcHNfMSBhcHBlYXJzIHRvIHJhbmdlIGZyb20gMjAwNyB0aHJvdWdoIDIwMTIgYW5kIHRlbXBzXzIgYXBwZWFycyB0byByYW5nZSBmcm9tIDIwMTMgdGhyb3VnaCAyMDE1Lg0KDQoNCiMjIyBNZXJnaW5nIHVzaW5nIHJiaW5kKCkNCg0KTm93IHRoYXQgeW91IGtub3cgdGhlIHN0cnVjdHVyZSBhbmQgc2NvcGUgb2YgeW91ciB0ZW1wZXJhdHVyZSBkYXRhLCB5b3VyIG5leHQgdGFzayB3aWxsIGJlIHRvIGNvbnZlcnQgdGhlc2Ugb2JqZWN0cyB0byB4dHMgYW5kIG1lcmdlIHRoZW0gdXNpbmcgcmJpbmQoKS4NCg0KQmVmb3JlIHlvdSBjYW4gY29udmVydCBhbiBvYmplY3QgdG8geHRzLCB5b3UgbmVlZCB0byBpZGVudGlmeSB0aGUgY29sdW1uIHRoYXQgd2lsbCBmb3JtIHRoZSB0aW1lIGluZGV4IGFuZCBlbnN1cmUgaXQgaXMgZW5jb2RlZCBhcyBhIHRpbWUtYmFzZWQgb2JqZWN0LiBJbiB0aGlzIGNhc2UsIHlvdSdsbCB3YW50IHRvIGNoZWNrIHRoZSBjbGFzcyBvZiB0aGUgZGF0ZSBjb2x1bW4gaW4gdGVtcHNfMSBhbmQgdGVtcHNfMi4gT25jZSB5b3UgaWRlbnRpZnkgdGhlIGFwcHJvcHJpYXRlIHRpbWUtYmFzZWQgaW5kZXgsIHlvdSBjYW4gZW5jb2RlIGJvdGggb2JqZWN0cyB0byB4dHMgYW5kIG1lcmdlIGJ5IHJvdy4NCg0KYGBge3J9DQojIENvbmZpcm0gdGhhdCB0aGUgZGF0ZSBjb2x1bW4gaW4gZWFjaCBvYmplY3QgaXMgYSB0aW1lLWJhc2VkIGNsYXNzDQpjbGFzcyh0ZW1wc18xJGRhdGUpDQpjbGFzcyh0ZW1wc18yJGRhdGUpDQoNCiMgRW5jb2RlIHlvdXIgdHdvIHRlbXBlcmF0dXJlIGRhdGEgZnJhbWVzIGFzIHh0cyBvYmplY3RzDQp0ZW1wc18xX3h0cyA8LSBhcy54dHModGVtcHNfMVssIC00XSwgb3JkZXIuYnkgPSB0ZW1wc18xJGRhdGUpDQp0ZW1wc18yX3h0cyA8LSBhcy54dHModGVtcHNfMlssIC00XSwgb3JkZXIuYnkgPSB0ZW1wc18yJGRhdGUpDQoNCiMgVmlldyB0aGUgZmlyc3QgZmV3IGxpbmVzIG9mIGVhY2ggbmV3IHh0cyBvYmplY3QgdG8gY29uZmlybSB0aGV5IGFyZSBwcm9wZXJseSBmb3JtYXR0ZWQNCmhlYWQodGVtcHNfMV94dHMpDQpoZWFkKHRlbXBzXzJfeHRzKQ0KDQojIFVzZSByYmluZCB0byBtZXJnZSB5b3VyIG5ldyB4dHMgb2JqZWN0cw0KdGVtcHNfeHRzIDwtIHJiaW5kKHRlbXBzXzFfeHRzLCB0ZW1wc18yX3h0cykNCg0KIyBWaWV3IGRhdGEgZm9yIHRoZSBmaXJzdCAzIGRheXMgb2YgdGhlIGxhc3QgbW9udGggb2YgdGhlIGZpcnN0IHllYXIgaW4gdGVtcHNfeHRzDQpmaXJzdChsYXN0KGZpcnN0KHRlbXBzX3h0cywgIjEgeWVhciIpLCAiMSBtb250aCIpLCAiMyBkYXlzIikNCmBgYA0KWW91IG5vdyBoYXZlIGEgc2luZ2xlIHh0cyBvYmplY3QgY29udGFpbmluZyB0ZW1wZXJhdHVyZSBkYXRhIGluIHRoZSBCb3N0b24gYXJlYSBmcm9tIDIwMDcgdGhyb3VnaCAyMDE1LiBJbiB0aGUgbmV4dCBleGVyY2lzZSwgeW91J2xsIGJlZ2luIGV4cGxvcmluZyB5b3VyIGRhdGEgaW4gbW9yZSBkZXB0aC4NCg0KIyMjIFZpc3VhbGl6aW5nIEJvc3RvbiB3aW50ZXJzDQoNCllvdSBkaXNjb3ZlcmVkIGluIHRoZSBwcmV2aW91cyBjaGFwdGVyIHRoYXQgYSBtdWNoIGhpZ2hlciBwZXJjZW50YWdlIG9mIGZsaWdodHMgYXJlIGRlbGF5ZWQgb3IgY2FuY2VsbGVkIGluIEJvc3RvbiBkdXJpbmcgdGhlIHdpbnRlci4gSXQgc2VlbXMgbG9naWNhbCB0aGF0IHRlbXBlcmF0dXJlIGlzIGFuIGltcG9ydGFudCBmYWN0b3IgaGVyZS4gUGVyaGFwcyBjb2xkZXIgdGVtcGVyYXR1cmVzIGFyZSBhc3NvY2lhdGVkIHdpdGggYSBoaWdoZXIgcGVyY2VudGFnZSBvZiBmbGlnaHQgZGVsYXlzIG9yIGNhbmNlbGxhdGlvbnM/DQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCBwcm9iZSB0aGUgcGxhdXNpYmlsaXR5IG9mIHRoaXMgaHlwb3RoZXNpcyBieSBwbG90dGluZyB0ZW1wZXJhdHVyZSB0cmVuZHMgb3ZlciB0aW1lIGFuZCBnZW5lcmF0aW5nIGEgdmlzdWFsIG92ZXJ2aWV3IG9mIEJvc3RvbiB3aW50ZXJzLg0KDQpCZWZvcmUgcGxvdHRpbmcsIGNoZWNrIHRoZSBwZXJpb2RpY2l0eSBhbmQgZHVyYXRpb24gb2YgeW91ciBkYXRhIHVzaW5nIHBlcmlvZGljaXR5KCkuIEtub3dpbmcgdGhlIHBlcmlvZGljaXR5IHdpbGwgaGVscCB5b3UgaW50ZXJwcmV0IHlvdXIgZGF0YSBhbmQgd2lsbCBjb21lIGluIGhhbmR5IGFzIHlvdSBwcm9jZWVkLg0KYGBge3J9DQojIElkZW50aWZ5IHRoZSBwZXJpb2RpY2l0eSBvZiB0ZW1wc194dHMNCnBlcmlvZGljaXR5KHRlbXBzX3h0cykNCg0KIyBHZW5lcmF0ZSBhIHBsb3Qgb2YgbWVhbiBCb3N0b24gdGVtcGVyYXR1cmUgZm9yIHRoZSBkdXJhdGlvbiBvZiB5b3VyIGRhdGENCnBsb3QueHRzKHRlbXBzX3h0cyRtZWFuKQ0KDQojIEdlbmVyYXRlIGEgcGxvdCBvZiBtZWFuIEJvc3RvbiB0ZW1wZXJhdHVyZSBmcm9tIE5vdmVtYmVyIDIwMTAgdGhyb3VnaCBBcHJpbCAyMDExDQpwbG90Lnh0cyh0ZW1wc194dHMkbWVhblsiMjAxMC0xMS8yMDExLTA0Il0pDQoNCiMgVXNlIHBsb3Quem9vIHRvIGdlbmVyYXRlIGEgc2luZ2xlIHBsb3Qgc2hvd2luZyBtZWFuLCBtYXgsIGFuZCBtaW4gdGVtcGVyYXR1cmVzIGR1cmluZyB0aGUgc2FtZSBwZXJpb2QgDQpsdHkgPC0gYygzLCAxLCAzKQ0KcGxvdC56b28odGVtcHNfeHRzWyIyMDEwLTExLzIwMTEtMDQiXSwgcGxvdC50eXBlID0gInNpbmdsZSIsIGx0eSA9IGx0eSkNCmBgYA0KWW91ciB0ZW1wZXJhdHVyZSBkYXRhIGxvb2sgY29tcHJlaGVuc2l2ZSBhbmQgZGVtb25zdHJhdGVzIGNsZWFyIHZhcmlhdGlvbiBhY3Jvc3Mgc2Vhc29ucy4gQm9zdG9uIGhhcyBzb21lIGNvbGQgd2ludGVycyEgWW91ciBuZXh0IHN0ZXAgd2lsbCBiZSB0byBjb21iaW5lIHlvdXIgdGVtcGVyYXR1cmUgZGF0YSB3aXRoIHRoZSBmbGlnaHQgZGF0YS4NCg0KIyMgTWVyZ2luZyB0aW1lIHNlcmllcyBkYXRhIGJ5IGNvbHVtbg0KDQojIyMgU3Vic2V0dGluZyBhbmQgYWRqdXN0aW5nIHBlcmlvZGljaXR5DQoNCllvdXIgbmV4dCBzdGVwIGlzIHRvIG1lcmdlIHlvdXIgdGVtcGVyYXR1cmUgZGF0YSB3aXRoIHRoZSBmbGlnaHQgZGF0YSBmcm9tIHRoZSBwcmV2aW91cyBjaGFwdGVyLg0KDQpSZWNhbGwgZnJvbSB0aGUgcHJldmlvdXMgY2hhcHRlciB0aGF0IHlvdXIgZmxpZ2h0IGRhdGEgc3RyZXRjaGVzIGZyb20gMjAxMCB0aHJvdWdoIDIwMTUgaW4gbW9udGhseSBwZXJpb2RzLiBCeSBjb250cmFzdCwgeW91ciB0ZW1wZXJhdHVyZSBkYXRhIHJhbmdlcyBmcm9tIDIwMDcgdGhyb3VnaCAyMDE1IGluIGRhaWx5IHBlcmlvZHMuIEJlZm9yZSB5b3UgbWVyZ2UsIHlvdSBzaG91bGQgc3Vic2V0IHlvdXIgZGF0YSBhbmQgYWRqdXN0IHRoZSBwZXJpb2RpY2l0eSB0byBtb250aGx5Lg0KDQpUbyBjb252ZXJ0IHRoZSBwZXJpb2RpY2l0eSBvZiB4dHMgb2JqZWN0cywgeW91IGNhbiB1c2UgdG8ucGVyaW9kKCksIHdoaWNoIGFsbG93cyB5b3UgdG8gcXVpY2tseSBjb252ZXJ0IHlvdXIgZGF0YSB0byBhIGxvd2VyIGZyZXF1ZW5jeSBwZXJpb2QuIEJ5IGRlZmF1bHQsIHRoaXMgY29tbWFuZCBwcm9kdWNlcyBzcGVjaWZpYyB2YWx1ZXMgYWNyb3NzIHRoZSBlbnRpcmUgcGVyaW9kIChuYW1lbHksIE9wZW4tSGlnaC1Mb3ctQ2xvc2UsIG9yIE9ITEMpIHdoaWNoIGFyZSB1c2VmdWwgaW4gZmluYW5jaWFsIGFuYWx5c2lzIGJ1dCBtYXkgbm90IGJlIHJlbGV2YW50IGluIGFsbCBjb250ZXh0cy4NCg0KSW4gdGhpcyBjYXNlLCB5b3Ugc2hvdWxkIHNldCB0aGUgYXJndW1lbnQgT0hMQyB0byBGQUxTRS4gUmF0aGVyIHRoYW4gcHJvZHVjZSBPSExDIGNvbHVtbnMgaW4geW91ciBtb250aGx5IHh0cyBvYmplY3QsIHRoaXMgc2V0dGluZyB3aWxsIHNpbXBseSB0YWtlIG9uZSByb3cgZnJvbSBlYWNoIHBlcmlvZCBhcyByZXByZXNlbnRhdGl2ZSBvZiB0aGUgZW50aXJlIHBlcmlvZC4gWW91IGNhbiBzcGVjaWZ5IHdoaWNoIHJvdyB1c2luZyB0aGUgaW5kZXhBdCBjb21tYW5kLg0KDQpgYGB7cn0NCiMgU3Vic2V0IHlvdXIgdGVtcGVyYXR1cmUgZGF0YSB0byBpbmNsdWRlIG9ubHkgMjAxMCB0aHJvdWdoIDIwMTU6IHRlbXBzX3h0c18yDQp0ZW1wc194dHNfMiA8LSB0ZW1wc194dHNbIjIwMTAvMjAxNSJdDQoNCiMgVXNlIHRvLnBlcmlvZCB0byBjb252ZXJ0IHRlbXBzX3h0c18yIHRvIG1vbnRobHkgcGVyaW9kaWNpdHkNCnRlbXBzX21vbnRobHkgPC0gdG8ucGVyaW9kKHRlbXBzX3h0c18yLCBwZXJpb2QgPSAibW9udGhzIiwgT0hMQyA9IEZBTFNFLCBpbmRleEF0ID0gImZpcnN0b2YiKQ0KDQojIENvbXBhcmUgdGhlIHBlcmlvZGljaXR5IGFuZCBkdXJhdGlvbiBvZiB0ZW1wc19tb250aGx5IGFuZCBmbGlnaHRzX3h0cyANCnBlcmlvZGljaXR5KHRlbXBzX21vbnRobHkpDQpwZXJpb2RpY2l0eShmbGlnaHRzX3h0cykNCmBgYA0KWW91J3ZlIGNvbnZlcnRlZCB5b3VyIGRhaWx5IHRlbXBlcmF0dXJlIGRhdGEgdG8gbW9udGhseSBhbmQgaXQgbG9va3MgbGlrZSB5b3UgYXJlIHJlYWR5IHRvIG1lcmdlIHdpdGggeW91ciBmbGlnaHRzIGRhdGEuIEJlZm9yZSBtb3ZpbmcgZm9yd2FyZCwgaG93ZXZlcix5b3Ugc2hvdWxkIGNvbnNpZGVyIHdoZXRoZXIgdGhlIHZhbHVlIHNlbGVjdGVkIGJ5IHRoZSB0by5wZXJpb2QoKSBjYWxsIChpbiB0aGlzIGNhc2UsIHRoZSBmaXJzdCBvZiB0aGUgbW9udGgpIGlzIGFwcHJvcHJpYXRlIGZvciB0aGlzIGNvbnRleHQuDQoNCiMjIyBHZW5lcmF0aW5nIGEgbW9udGhseSBhdmVyYWdlDQoNCldoaWxlIHRoZSB0by5wZXJpb2QoKSBjb21tYW5kIGlzIHVzZWZ1bCBpbiBtYW55IGNvbnRleHRzLCBmb3IgeW91ciBwdXJwb3NlcyBpdCBtYXkgbm90IGJlIHVzZWZ1bCB0byBzZWxlY3QgYSBzaW5nbGUgcm93IGFzIHJlcHJlc2VudGF0aXZlIG9mIHRoZSBlbnRpcmUgbW9udGguDQoNCkluc3RlYWQsIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gZ2VuZXJhdGUgYXZlcmFnZSB0ZW1wZXJhdHVyZSB2YWx1ZXMgcGVyIG1vbnRoLiBUbyBkbyBzbywgeW91J2xsIG5lZWQgdG8gbWFudWFsbHkgY2FsY3VsYXRlIHRoZSBtb250aGx5IGF2ZXJhZ2UgdXNpbmcgc3BsaXQoKSBhbmQgbGFwcGx5KCksIHRoZW4gZ2VuZXJhdGUgYSBuZXcgeHRzIG9iamVjdCB1c2luZyBhcy54dHMoKSANCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmluZGV4IDwtIGFzLkRhdGUoYygxNDYxMCwgMTQ2NDEsIDE0NjY5LCAxNDcwMCwgMTQ3MzAsIDE0NzYxLCAxNDc5MSwgDQoxNDgyMiwgMTQ4NTMsIDE0ODgzLCAxNDkxNCwgMTQ5NDQsIDE0OTc1LCAxNTAwNiwgMTUwMzQsIDE1MDY1LCANCjE1MDk1LCAxNTEyNiwgMTUxNTYsIDE1MTg3LCAxNTIxOCwgMTUyNDgsIDE1Mjc5LCAxNTMwOSwgMTUzNDAsIA0KMTUzNzEsIDE1NDAwLCAxNTQzMSwgMTU0NjEsIDE1NDkyLCAxNTUyMiwgMTU1NTMsIDE1NTg0LCAxNTYxNCwgDQoxNTY0NSwgMTU2NzUsIDE1NzA2LCAxNTczNywgMTU3NjUsIDE1Nzk2LCAxNTgyNiwgMTU4NTcsIDE1ODg3LCANCjE1OTE4LCAxNTk0OSwgMTU5NzksIDE2MDEwLCAxNjA0MCwgMTYwNzEsIDE2MTAyLCAxNjEzMCwgMTYxNjEsIA0KMTYxOTEsIDE2MjIyLCAxNjI1MiwgMTYyODMsIDE2MzE0LCAxNjM0NCwgMTYzNzUsIDE2NDA1LCAxNjQzNiwgDQoxNjQ2NywgMTY0OTUsIDE2NTI2LCAxNjU1NiwgMTY1ODcsIDE2NjE3LCAxNjY0OCwgMTY2NzksIDE2NzA5LCANCjE2NzQwLCAxNjc3MCksIHR6b25lID0gIlVUQyIsIHRjbGFzcyA9ICJEYXRlIiwgY2xhc3MgPSAiRGF0ZSIpDQpgYGANCmBgYHtyfQ0KIyBTcGxpdCB0ZW1wc194dHNfMiBpbnRvIHNlcGFyYXRlIGxpc3RzIHBlciBtb250aA0KbW9udGhseV9zcGxpdCA8LSBzcGxpdCh0ZW1wc194dHNfMiRtZWFuICwgZiA9ICJtb250aHMiKQ0KDQojIFVzZSBsYXBwbHkgdG8gZ2VuZXJhdGUgdGhlIG1vbnRobHkgbWVhbiBvZiBtZWFuIHRlbXBlcmF0dXJlcw0KbWVhbl9vZl9tZWFucyA8LSBsYXBwbHkobW9udGhseV9zcGxpdCwgRlVOID0gbWVhbikNCg0KIyBVc2UgYXMueHRzIHRvIGdlbmVyYXRlIGFuIHh0cyBvYmplY3Qgb2YgYXZlcmFnZSBtb250aGx5IHRlbXBlcmF0dXJlIGRhdGENCnRlbXBzX21vbnRobHkgPC0gYXMueHRzKGFzLm51bWVyaWMobWVhbl9vZl9tZWFucyksIG9yZGVyLmJ5ID0gaW5kZXgpDQogDQojIENvbXBhcmUgdGhlIHBlcmlvZGljaXR5IGFuZCBkdXJhdGlvbiBvZiB5b3VyIG5ldyB0ZW1wc19tb250aGx5IGFuZCBmbGlnaHRzX3h0cyANCnBlcmlvZGljaXR5KHRlbXBzX21vbnRobHkpDQpwZXJpb2RpY2l0eShmbGlnaHRzX3h0cykNCmBgYA0KWW91IGdlbmVyYXRlZCBhIG5ldyB4dHMgb2JqZWN0IGNvbnRhaW5pbmcgbW9udGhseSBhdmVyYWdlIHRlbXBlcmF0dXJlIGluIEJvc3RvbiBmcm9tIDIwMTAgdGhyb3VnaCAyMDE1LiBBbHRob3VnaCB0aGlzIHByb2Nlc3MgaXMgbW9yZSBjb21wbGljYXRlZCB0aGFuIHVzaW5nIHRvLnBlcmlvZCgpLCBpdCBwcm9kdWNlcyBhIG1vcmUgcHJlY2lzZSBtZWFzdXJlIG9mIG1vbnRobHkgdGVtcGVyYXR1cmUuDQoNCiMjIyBVc2luZyBtZXJnZSgpIGFuZCBwbG90dGluZyBvdmVyIHRpbWUNCg0KTm93IHRoYXQgeW91IGhhdmUgdGVtcGVyYXR1cmUgZGF0YSBjb3ZlcmluZyB0aGUgc2FtZSB0aW1lIHBlcmlvZCAoMjAxMC0yMDE1KSBhdCB0aGUgc2FtZSBmcmVxdWVuY3kgKG1vbnRobHkpIGFzIHlvdXIgZmxpZ2h0cyBkYXRhLCB5b3UgYXJlIHJlYWR5IHRvIG1lcmdlLg0KDQpUbyBtZXJnZSB4dHMgb2JqZWN0cyBieSBjb2x1bW4sIHlvdSBjYW4gdXNlIG1lcmdlKCkuIFdoZW4gdHdvIHh0cyBvYmplY3RzIHNoYXJlIHRoZSBzYW1lIHBlcmlvZGljaXR5LCBtZXJnZSgpIGlzIGdlbmVyYWxseSBhYmxlIHRvIGNvbWJpbmUgaW5mb3JtYXRpb24gaW50byBhcHByb3ByaWF0ZSByb3dzLiBFdmVuIHdoZW4geHRzIG9iamVjdHMgZG8gbm90IHNoYXJlIHRoZSBzYW1lIHBlcmlvZGljaXR5LCBtZXJnZSgpIHdpbGwgcHJlc2VydmUgdGhlIGNvcnJlY3QgdGltZSBvcmRlcmluZyBvZiB0aG9zZSBvYmplY3RzIGFjcm9zcyBkaXNwYXJhdGUgcGVyaW9kcy4NCg0KeW91J2xsIG1lcmdlIHlvdXIgdHdvIHh0cyBvYmplY3RzIGJ5IGNvbHVtbiBhbmQgZ2VuZXJhdGUgbmV3IHBsb3RzIGV4cGxvcmluZyBob3cgZmxpZ2h0IGRlbGF5cyByZWxhdGUgdG8gdGVtcGVyYXR1cmUuDQoNCmBgYHtyfQ0KIyBVc2UgbWVyZ2UgdG8gY29tYmluZSB5b3VyIGZsaWdodHMgYW5kIHRlbXBlcmF0dXJlIG9iamVjdHMNCmZsaWdodHNfdGVtcHMgPC0gbWVyZ2UoZmxpZ2h0c194dHMsIHRlbXBzX21vbnRobHkpDQoNCiMgRXhhbWluZSB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgeW91ciBjb21iaW5lZCB4dHMgb2JqZWN0DQpoZWFkKGZsaWdodHNfdGVtcHMpDQoNCiMgVXNlIHBsb3Quem9vIHRvIHBsb3QgdGhlc2UgdHdvIGNvbHVtbnMgaW4gYSBzaW5nbGUgcGFuZWwNCmx0eSA8LSAgYygxLCAyKQ0KbGFiZWxzIDwtIGMoIlBjdC4gRGVsYXkiLCAiVGVtcGVyYXR1cmUiKQ0KcGxvdC56b28oZmxpZ2h0c190ZW1wc1ssYygicGN0X2RlbGF5IiwgInRlbXBzX21vbnRobHkiKV0sIHBsb3QudHlwZSA9ICJzaW5nbGUiLCBsdHkgPSBsdHkpDQpsZWdlbmQoInRvcHJpZ2h0IiwgbHR5ID0gbHR5LCBsZWdlbmQgPSBsYWJlbHMsIGJnID0gIndoaXRlIikNCmBgYA0KTWVyZ2luZyB5b3VyIHR3byB4dHMgb2JqZWN0cyBhbGxvd3MgeW91IHRvIGVhc2lseSB2aXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGZsaWdodCBkZWxheXMgYW5kIHRlbXBlcmF0dXJlLg0KDQojIyMgQXJlIGZsaWdodCBkZWxheXMgcmVsYXRlZCB0byB0ZW1wZXJhdHVyZT8NCg0KUGxvdHRpbmcgb3ZlciB0aW1lIGlzIGEgZ3JlYXQgd2F5IHRvIHZpc3VhbGl6ZSBwb3NzaWJsZSByZWxhdGlvbnNoaXBzIGluIHlvdXIgZGF0YS4gDQpgYGB7cn0NCmx0eSA8LSAgYygyLCAxLCAzKQ0KbGFiZWxzIDwtIGMoIlRlbXBlcmF0dXJlIChGKSIsICJQZXJjZW50IERlbGF5IiwgIlBlcmNlbnQgQ2FuY2VsIikNCnBsb3Quem9vKGZsaWdodHNfdGVtcHNbLGMoICJ0ZW1wc19tb250aGx5IiwgInBjdF9kZWxheSIsICJwY3RfY2FuY2VsIildLCBwbG90LnR5cGUgPSAic2luZ2xlIiwgbHR5ID0gbHR5LCB4bGFiID0gIlllYXIiLCB5bGFiID0gIlBlcmNlbnQgRmxpZ2h0cyIpDQpsZWdlbmQoInRvcGxlZnQiLCBsdHkgPSBsdHksIGxlZ2VuZCA9IGxhYmVscywgYmcgPSAid2hpdGUiKQ0KYGBgDQpUaGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZmxpZ2h0IGNhbmNlbGxhdGlvbnMgYW5kIHRlbXBlcmF0dXJlIGlzIHN0cm9uZywgd2hpbGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGZsaWdodCBkZWxheXMgYW5kIHRlbXBlcmF0dXJlIGlzIGxlc3Mgb2J2aW91cy4gQnkgaW5jbHVkaW5nIGFsbCBvZiB0aGlzIGRhdGEgb24gYSBzaW5nbGUgcGxvdCwgd2UgbGVhcm4gbXVjaCBtb3JlIGFib3V0IHRoZXNlIHJlbGF0aW9uc2hpcHMuDQoNCiMjIFRpbWUgc2VyaWVzIGRhdGEgd29ya2Zsb3cNCg0KIyMjIE5leHQgc3RlcHMNCg0KWW91ciB0ZW1wZXJhdHVyZSBkYXRhIHJldmVhbGVkIGEgZmV3IHBvdGVudGlhbCBhdmVudWVzIGZvciBleHBsb3JpbmcgdGhlIGNhdXNlcyBvZiBmbGlnaHQgZGVsYXlzIGFuZCBjYW5jZWxsYXRpb25zLiBIb3dldmVyLCB5b3VyIGNsaWVudCBpcyBpbnNpc3RpbmcgdGhhdCBmbGlnaHQgYXJyaXZhbCBwYXR0ZXJucyBpbiBCb3N0b24gYXJlIGluZmx1ZW5jZWQgYnkgdmlzaWJpbGl0eSBhbmQgd2luZCwgbm90IHRlbXBlcmF0dXJlLiBCZWZvcmUgbW92aW5nIGZvcndhcmQsIHlvdSdsbCBuZWVkIHRvIGNvbGxlY3QgbW9yZSBkYXRhLg0KDQpBZnRlciBjb25kdWN0aW5nIGV4dGVuc2l2ZSByZXNlYXJjaCwgeW91J3ZlIGlkZW50aWZpZWQgc29tZSByZWxldmFudCBkYXRhIG9uIHdlZWtseSBhdmVyYWdlIHZpc2liaWxpdHkgYW5kIHdpbmQgc3BlZWQgaW4gdGhlIEJvc3RvbiBhcmVhLiBXaGljaCBvZiB0aGUgZm9sbG93aW5nIHN0ZXBzIHdvdWxkIHlvdSB0YWtlIGJlZm9yZSBtZXJnaW5nIHRoZXNlIGRhdGEgd2l0aCB5b3VyIGV4aXN0aW5nIG1vbnRobHkgeHRzIG9iamVjdCwgZmxpZ2h0c190ZW1wcz8NCg0KMS4gRW5jb2RlIHRoZSBkYXRhIHRvIGFuIHh0cyBvYmplY3Qgd2l0aCBhIHRpbWUtYmFzZWQgaW5kZXguDQoyLiBDb252ZXJ0IHRoZSBkYXRhIHRvIG1vbnRobHkgcGVyaW9kaWNpdHkgdXNpbmcgc3BsaXQoKSBhbmQgbGFwcGx5KCkgdG8gZ2VuZXJhdGUgbW9udGhseSBhdmVyYWdlcy4NCjMuIENoZWNrIHRoZSBwZXJpb2RpY2l0eSBhbmQgZHVyYXRpb24gb2YgeW91ciB4dHMgb2JqZWN0cyBiZWZvcmUgdXNpbmcgbWVyZ2UoKS4NCg0KIyMjIEV4cGFuZGluZyB5b3VyIGRhdGENCg0KTm93IHRoYXQgeW91IGhhdmUgYSBoYW5kbGUgb24gdGltZSBzZXJpZXMgd29ya2Zsb3csIHlvdSdyZSByZWFkeSB0byBhc3Nlc3MgdGhlIGh5cG90aGVzaXMgdGhhdCBmbGlnaHQgZGVsYXlzIGFyZSBhIGZ1bmN0aW9uIG9mIHZpc2liaWxpdHkgYW5kIHdpbmQuDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCBhZGQgYSBmZXcgbW9yZSBjb2x1bW5zIHRvIHlvdXIgeHRzIG9iamVjdCBieSBtZXJnaW5nIGRhdGEgb24gbW9udGhseSBhdmVyYWdlIHZpc2liaWxpdHkgKHZpcykgYW5kIHdpbmQgc3BlZWRzICh3aW5kKSBpbiB0aGUgQm9zdG9uIGFyZWEgZnJvbSAyMDEwIHRocm91Z2ggMjAxNS4gVGhlc2UgZGF0YSBhcmUgZGVyaXZlZCBmcm9tIHRoZSBzYW1lIHNvdXJjZSBhcyB5b3VyIHRlbXBlcmF0dXJlIGRhdGEuDQpgYGB7cn0NCndpbmQgPC0gcmVhZFJEUygiQzovTWlzIGNvc2FzL0NvZGluZy9QcmFjdGljYS9SL2ZpbmFuY2UvZGF0YS93aW5kLlJEYXRhIikNCnZpcyA8LSByZWFkUkRTKCJDOi9NaXMgY29zYXMvQ29kaW5nL1ByYWN0aWNhL1IvZmluYW5jZS9kYXRhL3Zpcy5SRGF0YSIpDQpgYGANCmBgYHtyfQ0KIyBDb25maXJtIHRoZSBwZXJpb2RpY2l0eSBhbmQgZHVyYXRpb24gb2YgdGhlIHZpcyBhbmQgd2luZCBkYXRhDQpwZXJpb2RpY2l0eSh2aXMpDQpwZXJpb2RpY2l0eSh3aW5kKQ0KDQojIE1lcmdlIHZpcyBhbmQgd2luZCB3aXRoIHlvdXIgZXhpc3RpbmcgZmxpZ2h0c190ZW1wcyBkYXRhDQpmbGlnaHRzX3dlYXRoZXIgPC0gbWVyZ2UoZmxpZ2h0c190ZW1wcywgdmlzLCB3aW5kKQ0KDQojIFZpZXcgdGhlIGZpcnN0IGZldyByb3dzIG9mIHlvdXIgZmxpZ2h0c193ZWF0aGVyIGRhdGENCmhlYWQoZmxpZ2h0c193ZWF0aGVyKQ0KYGBgDQpXb3JraW5nIHdpdGggdGltZSBzZXJpZXMgZGF0YSB1c2luZyB4dHMgY2FuIGJlIHF1aXRlIHNpbXBsZSBvbmNlIHlvdSBtYXN0ZXIgdGhlIGJhc2ljcy4gSW4gb25seSBhIGZldyBzaG9ydCBjb21tYW5kcywgeW91J3ZlIGFkZGVkIHR3byBtb3JlIHBvdGVudGlhbGx5IGNyaXRpY2FsIHBpZWNlcyBvZiBpbmZvcm1hdGlvbiB0byB5b3VyIGRhdGEuDQoNCiMjIyBBcmUgZmxpZ2h0IGRlbGF5cyByZWxhdGVkIHRvIHZpc2liaWxpdHkgb3Igd2luZD8NCg0KWW91J3ZlIHBhaW5sZXNzbHkgYWRkZWQgc29tZSBuZXcgZGF0YSB0byB5b3VyIHh0cyBvYmplY3QuIEl0IGdldHMgZWFzaWVyIGV2ZXJ5IHRpbWUhDQoNClRoZSBwbG90IG9uIHRoZSBiZWxvdyBzaG93cyB0aGUgZnJ1aXRzIG9mIHlvdXIgbGFib3I6IHRoZSBwZXJjZW50YWdlIG9mIGRlbGF5ZWQgZmxpZ2h0cyAod2hpY2ggeW91IGNhbGN1bGF0ZWQgaW4gdGhlIHByZXZpb3VzIGNoYXB0ZXIpLCB0aGUgYXZlcmFnZSB3aW5kIHNwZWVkIGluIEJvc3RvbiwgYW5kIHRoZSBhdmVyYWdlIHZpc2liaWxpdHksIGFsbCBvbiBhIG1vbnRobHkgYmFzaXMgZnJvbSAyMDEwIHRocm91Z2ggMjAxNS4NCmBgYHtyfQ0KbHR5IDwtICBjKDEsIDIsIDMpDQpsYWJlbHMgPC0gYygiUGVyY2VudCBEZWxheSIsICJXaW5kIiwgIlZpc2liaWxpdHkiKQ0KcGxvdC56b28oZmxpZ2h0c193ZWF0aGVyWyxjKCAicGN0X2RlbGF5IiwgIndpbmQiLCAidmlzIildLCBwbG90LnR5cGUgPSAibXVsdGlwbGUiLCBsdHkgPSBsdHksIHhsYWIgPSAiWWVhciIsIHlsYWIgPSBsYWJlbHMpDQpgYGANCkFsdGhvdWdoIHRoaXMgcGxvdCBkb2Vzbid0IGRlcGljdCBhbnkgc3Ryb25nIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2aXNpYmlsaXR5IG9yIHdpbmQgYW5kIGRlbGF5ZWQgZmxpZ2h0cywgaXQgdGVsbHMgeW91IHF1aXRlIGEgYml0IGFib3V0IHlvdXIgZGF0YS4gV2luZCBzcGVlZCBzb21ldGltZXMgY29ycmVzcG9uZHMgdG8gZmxpZ2h0IGRlbGF5cywgd2hpbGUgdmlzaWJpbGl0eSBkb2VzIG5vdCBhcHBlYXIgcmVsYXRlZCB0byBkZWxheXMuIE1vcmUgaW1wb3J0YW50bHksIHRoZSBmbGF0bGluZSBkYXRhIG9uIHZpc2liaWxpdHkgcHJpb3IgdG8gMjAxMiBzaG91bGQgcmFpc2Ugc29tZSBleWVicm93cy4gQmVmb3JlIHByb2NlZWRpbmcgd2l0aCB5b3VyIGFuYWx5c2lzLCB5b3UgbWF5IHdhbnQgdG8gcmVhc3Nlc3MgdGhlIHF1YWxpdHkgb2YgeW91ciBkYXRhLg0KDQojIEVjb25vbWljIERhdGENCg0KIyMgSGFuZGxpbmcgbWlzc2luZ25lc3MNCg0KIyMjIEV4cGxvcmluZyBlY29ub21pYyBkYXRhDQoNCk5vdyB0aGF0IHlvdSd2ZSBleHBsb3JlZCB3ZWF0aGVyIGFuZCBmbGlnaHQgcGF0dGVybnMgaW4gQm9zdG9uLCB5b3VyIGNsaWVudCBoYXMgYXNrZWQgeW91IHRvIHN0ZXAgYmFjayBhbmQgcHJlcGFyZSBzb21lIGVjb25vbWljIGRhdGEuIFlvdSd2ZSBnYXRoZXJlZCBzb21lIGRhdGEgb24gdGhlIFVTIGVjb25vbXksIGluY2x1ZGluZyBncm9zcyBkb21lc3RpYyBwcm9kdWN0IChHRFApIGFuZCB1bmVtcGxveW1lbnQgaW4gdGhlIFVTIGluIGdlbmVyYWwgYW5kIHRoZSBzdGF0ZSBvZiBNYXNzYWNodXNldHRzIChob21lIHRvIEJvc3RvbikgaW4gcGFydGljdWxhci4NCg0KQXMgYWx3YXlzLCB5b3VyIGZpcnN0IHN0ZXAgaW4gbWFuaXB1bGF0aW5nIHRpbWUgc2VyaWVzIGRhdGEgc2hvdWxkIGJlIHRvIGNvbnZlcnQgeW91ciBkYXRhIHRvIHRoZSB4dHMgY2xhc3MuIEluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCBleGFtaW5lIGFuZCBlbmNvZGUgdGltZSBzZXJpZXMgZGF0YSBvbiBVUyBHRFAuDQoNCmBgYHtyfQ0KZ2RwIDwtIHJlYWRSRFMoIkM6L01pcyBjb3Nhcy9Db2RpbmcvUHJhY3RpY2EvUi9maW5hbmNlL2RhdGEvdXNfZ2RwLlJEYXRhIikNCmBgYA0KVmlldyBpbmZvcm1hdGlvbiBhYm91dCB5b3VyIGdkcCBkYXRhIHVzaW5nIHN1bW1hcnkoKS4gV2hhdCBjYW4geW91IGNvbmNsdWRlIGZyb20gdGhlIG91dHB1dCBvZiB0aGlzIGNvbW1hbmQ/DQpgYGB7cn0NCiMgR2V0IGEgc3VtbWFyeSBvZiB5b3VyIEdEUCBkYXRhDQpzdW1tYXJ5KGdkcCkNCmBgYA0KRGF0YSBsb29rcyBxdWFydGVybHkgYW5kIGhhcyA4MCBtaXNzaW5nIHZhbHVlcy4NCg0KQmVnaW4gdGhlIHByb2Nlc3Mgb2YgZW5jb2RpbmcgZ2RwIHRvIHh0cyBieSBjb252ZXJ0aW5nIHRoZSBkYXRlIGNvbHVtbiB0byBhIHRpbWUgb2JqZWN0LiBJbiB0aGlzIGNhc2UsIGl0IGxvb2tzIGxpa2UgeW91ciBHRFAgZGF0YSBhcmUgcXVhcnRlcmx5LCBzbyB5b3Ugc2hvdWxkIHVzZSB0aGUgeWVhcnF0ciBjbGFzcy4NCmBgYHtyfQ0KIyBDb252ZXJ0IEdEUCBkYXRlIGNvbHVtbiB0byB0aW1lIG9iamVjdA0KZ2RwJGRhdGUgPC0gYXMueWVhcnF0cihnZHAkZGF0ZSkNCg0KIyBDb252ZXJ0IEdEUCBkYXRhIHRvIHh0cw0KZ2RwX3h0cyA8LSBhcy54dHMoZ2RwWywgLTFdLCBvcmRlci5ieSA9IGdkcCRkYXRlKQ0KYGBgDQpVc2UgcGxvdC54dHMoKSB0byB2aWV3IHlvdXIgR0RQIGRhdGEgb3ZlciB0aW1lLiBEb2VzIGFueXRoaW5nIHN0YW5kIG91dCBpbiB5b3VyIHBsb3Q/DQpgYGB7cn0NCiMgUGxvdCBHRFAgZGF0YSBvdmVyIHRpbWUNCnBsb3QueHRzKGdkcF94dHMpDQpgYGANCllvdXIgcGxvdCBzaG93cyBmYWlybHkgY29uc2lzdGVudCBHRFAgZ3Jvd3RoIGluIHRoZSBVbml0ZWQgU3RhdGVzLiBIb3dldmVyLCBpdCBsb29rcyBsaWtlIHlvdSBhcmUgbWlzc2luZyBxdWl0ZSBhIGJpdCBvZiBkYXRhISBPbmUgb2YgeW91ciBpbnRlcm5zIG11c3QgaGF2ZSBmYWxsZW4gYXNsZWVwIG9uIHRoZSBrZXlib2FyZC4gSW4gdGhlIG5leHQgZmV3IGV4ZXJjaXNlcywgeW91J2xsIHByYWN0aWNlIHNvbWUgdGVjaG5pcXVlcyBmb3IgaGFuZGxpbmcgbWlzc2luZyBkYXRhLg0KDQojIyMgUmVwbGFjZSBtaXNzaW5nIGRhdGENCg0KQXMgeW91IGRpc2NvdmVyZWQgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlLCB5b3VyIHF1YXJ0ZXJseSBHRFAgZGF0YSBhcHBlYXIgdG8gYmUgbWlzc2luZyBzZXZlcmFsIG9ic2VydmF0aW9ucy4gSW4gZmFjdCwgeW91ciBjYWxsIHRvIHN1bW1hcnkoKSBpbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UgcmV2ZWFsZWQgODAgbWlzc2luZyBkYXRhIHBvaW50cyENCg0KQXMgeW91IG1heSByZWNhbGwgZnJvbSB0aGUgZmlyc3QgeHRzIGNvdXJzZSwgeHRzIGFuZCB6b28gcHJvdmlkZSBhIHZhcmlldHkgb2YgZnVuY3Rpb25zIHRvIGhhbmRsZSBtaXNzaW5nIGRhdGEuDQoNClRoZSBzaW1wbGVzdCB0ZWNobmlxdWUgaXMgdGhlIG5hLmxvY2YoKSBjb21tYW5kLCB3aGljaCBjYXJyaWVzIGZvcndhcmQgdGhlIGxhc3Qgb2JzZXJ2YXRpb24gYmVmb3JlIHRoZSBtaXNzaW5nIGRhdGEgKGhlbmNlLCAibGFzdCBvYnNlcnZhdGlvbiBjYXJyaWVkIGZvcndhcmQiLCBvciBsb2NmKS4gVGhpcyBhcHByb2FjaCBpcyBvZnRlbiB0aGUgbW9zdCBhcHByb3ByaWF0ZSB3YXkgdG8gaGFuZGxlIG1pc3NpbmduZXNzLCBlc3BlY2lhbGx5IHdoZW4geW91IGhhdmUgcmVhc29ucyB0byBiZSBjb25zZXJ2YXRpdmUgYWJvdXQgZ3Jvd3RoIGluIHlvdXIgZGF0YS4NCg0KQSBzaW1pbGFyIGFwcHJvYWNoIHdvcmtzIGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb24gYnkgdGFraW5nIHRoZSBmaXJzdCBvYnNlcnZhdGlvbiBhZnRlciB0aGUgbWlzc2luZyB2YWx1ZSBhbmQgY2FycnlpbmcgaXQgYmFja3dhcmQgKCJuZXh0IG9ic2VydmF0aW9uIGNhcnJpZWQgYmFja3dhcmQiLCBvciBub2NiKS4gVGhpcyB0ZWNobmlxdWUgY2FuIGFsc28gYmUgZG9uZSB1c2luZyB0aGUgbmEubG9jZigpIGNvbW1hbmQgYnkgc2V0dGluZyB0aGUgZnJvbUxhc3QgYXJndW1lbnQgdG8gVFJVRS4NCg0KV2hpY2ggbWV0aG9kIGlzIGJlc3QgZGVwZW5kcyBvbiB0aGUgdHlwZSBvZiBkYXRhIHlvdSBhcmUgd29ya2luZyB3aXRoIGFuZCB5b3VyIHByZWNvbmNlaXZlZCBub3Rpb25zIGFib3V0IGhvdyB0aGUgZGF0YSBjaGFuZ2VzIG92ZXIgdGltZS4NCmBgYHtyfQ0KIyBGaWxsIE5BcyBpbiBnZHBfeHRzIHdpdGggdGhlIGxhc3Qgb2JzZXJ2YXRpb24gY2FycmllZCBmb3J3YXJkDQpnZHBfbG9jZiA8LSBuYS5sb2NmKGdkcF94dHMpDQoNCiMgRmlsbCBOQXMgaW4gZ2RwX3h0cyB3aXRoIHRoZSBuZXh0IG9ic2VydmF0aW9uIGNhcnJpZWQgYmFja3dhcmQgDQpnZHBfbm9jYiA8LSBuYS5sb2NmKGdkcF94dHMsIGZyb21MYXN0ID0gVFJVRSkNCg0KIyBQcm9kdWNlIGEgcGxvdCBmb3IgZWFjaCBvZiB5b3VyIG5ldyB4dHMgb2JqZWN0cw0KcGFyKG1mcm93ID0gYygyLDEpKQ0KcGxvdC54dHMoZ2RwX2xvY2YsIG1ham9yLmZvcm1hdCA9ICIlWSIpDQpwbG90Lnh0cyhnZHBfbm9jYiwgbWFqb3IuZm9ybWF0ID0gIiVZIikNCg0KIyBRdWVyeSBmb3IgR0RQIGluIDE5OTMgaW4gYm90aCBnZHBfbG9jZiBhbmQgZ2RwX25vY2INCmdkcF9sb2NmWyIxOTkzIl0NCmdkcF9ub2NiWyIxOTkzIl0NCmBgYA0KWW91J3ZlIGZpbGxlZCBpbiB0aGUgbWlzc2luZyB2YWx1ZXMgaW4geW91ciBHRFAgZGF0YS4gQXMgeW91IGNhbiBzZWUsIHRoZSBsb2NmIGFuZCBub2NiIHRlY2huaXF1ZXMgc29tZXRpbWVzIHByb2R1Y2UgZHJhc3RpY2FsbHkgZGlmZmVyZW50IHZhbHVlcywgZXNwZWNpYWxseSB3aGVuIHlvdSBoYXZlIGxvbmcgc3BlbGxzIG9mIG1pc3NpbmcgZGF0YS4gSW4gdGhlIG5leHQgZXhlcmNpc2UsIHlvdSdsbCBwcmFjdGljZSBhIHRoaXJkIHRlY2huaXF1ZSBmb3IgaGFuZGxpbmcgbWlzc2luZ25lc3M6IGxpbmVhciBpbnRlcnBvbGF0aW9uLg0KDQpMaWtlIG1vc3QgYXNwZWN0cyBvZiB0aW1lIHNlcmllcyBkYXRhIG1hbmlwdWxhdGlvbiwgdGhlcmUgYXJlIG1hbnkgd2F5cyB0byBoYW5kbGUgbWlzc2luZ25lc3MuIEFzIHlvdSBkaXNjb3ZlcmVkIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZSwgYm90aCB0aGUgbG9jZiBhbmQgbm9jYiBhcHByb2FjaCByZXF1aXJlIHlvdSB0byBtYWtlIGNlcnRhaW4gYXNzdW1wdGlvbnMgYWJvdXQgZ3Jvd3RoIHBhdHRlcm5zIGluIHlvdXIgZGF0YS4gV2hpbGUgbG9jZiBpcyBtb3JlIGNvbnNlcnZhdGl2ZSBhbmQgbm9jYiBpcyBhIG1vcmUgYWdncmVzc2l2ZSwgYm90aCBnZW5lcmF0ZSBzdGVwLXdpc2UgZ3Jvd3RoIGZyb20gbWlzc2luZyBkYXRhLg0KDQpCdXQgd2hhdCBpZiB5b3UgaGF2ZSByZWFzb24gdG8gZXhwZWN0IGxpbmVhciBncm93dGggaW4geW91ciBkYXRhPyBJbiB0aGlzIGNhc2UsIGl0IG1heSBiZSBtb3JlIHVzZWZ1bCB0byB1c2UgbGluZWFyIGludGVycG9sYXRpb24sIHdoaWNoIGdlbmVyYXRlcyBuZXcgdmFsdWVzIGJldHdlZW4gdGhlIGRhdGEgb24gZWl0aGVyIGVuZCBvZiB0aGUgbWlzc2luZyB2YWx1ZSB3ZWlnaHRlZCBhY2NvcmRpbmcgdG8gdGltZS4NCg0KWW91J2xsIGZpbGwgdGhlIG1pc3NpbmcgdmFsdWVzIGluIHlvdXIgZ2RwX3h0cyBkYXRhIHVzaW5nIHRoZSBuYS5hcHByb3goKSBjb21tYW5kLCB3aGljaCB1c2VzIGludGVycG9sYXRpb24gdG8gZXN0aW1hdGUgbGluZWFyIHZhbHVlcyBpbiB0aW1lLg0KYGBge3J9DQojIEZpbGwgTkFzIGluIGdkcF94dHMgdXNpbmcgbGluZWFyIGFwcHJveGltYXRpb24NCmdkcF9hcHByb3ggPC0gbmEuYXBwcm94KGdkcF94dHMpDQoNCiMgUGxvdCB5b3VyIG5ldyB4dHMgb2JqZWN0DQpwbG90Lnh0cyhnZHBfYXBwcm94LCBtYWpvci5mb3JtYXQgPSAiJVkiKQ0KICANCiMgUXVlcnkgZm9yIEdEUCBpbiAxOTkzIGluIGdkcF9hcHByb3gNCmdkcF9hcHByb3hbIjE5OTMiXQ0KYGBgDQpBbHRob3VnaCB0aGUgdmFsdWVzIHlvdSBnZW5lcmF0ZSBtYXkgbm90IGJlIDEwMCUgYWNjdXJhdGUsIGxpbmVhciBpbnRlcnBvbGF0aW9uIHByb3ZpZGVzIGEgcmVhbGlzdGljIG92ZXJhbGwgcGljdHVyZSBvZiBHRFAgZ3Jvd3RoIGZyb20gdGhlIDE5NDBzIHRocm91Z2ggdGhlIDIwMTBzLiBVbHRpbWF0ZWx5LCB3aGljaCB0ZWNobmlxdWUgeW91IHNob3VsZCB1c2UgZGVwZW5kcyBvbiB0aGUgdHJlbmRzIHlvdSBzZWUgaW4gdGhlIGRhdGEgeW91IGhhdmUgYXMgd2VsbCBhcyB5b3VyIHByZWNvbmNlaXZlZCBub3Rpb25zIGFib3V0IHRoZSBkYXRhLg0KDQojIyMgRXN0aW1hdGluZyBtaXNzaW5nIEdEUA0KDQpCYXNlZCBvbiB0aGUgbm9uLW1pc3NpbmcgZGF0YSwgR0RQIHRlbmRzIHRvIGdyb3cgYXQgZmFpcmx5IHByZWRpY3RhYmxlIHJhdGVzICh3aXRoIG5vdGFibGUgZXhjZXB0aW9ucykuIEZvciB0aGlzIHJlYXNvbiwgeW91IHNob3VsZCBlc3RpbWF0ZSBtaXNzaW5nIHZhbHVlcyB1c2luZyBsaW5lYXIgaW50ZXJwb2xhdGlvbi4gVGhpcyBtZXRob2Qgd2lsbCBub3QgZGV0ZWN0IHN1ZGRlbiBzaGlmdHMgaW4gR0RQIGZyb20gcXVhcnRlciB0byBxdWFydGVyLCBidXQgY2FuIHByb3ZpZGUgYSBnZW5lcmFsIGFwcHJveGltYXRpb24gb2YgdHJlbmRzLg0KDQojIyBMYWdnaW5nIGFuZCBkaWZmZXJlbmNpbmcNCg0KIyMjIEV4cGxvcmluZyB1bmVtcGxveW1lbnQgZGF0YQ0KDQpOb3cgdGhhdCB5b3UndmUgcmV2aWV3ZWQgdGhlIGJhc2ljIHN0ZXBzIGZvciBoYW5kbGluZyBtaXNzaW5nIGRhdGEsIHlvdSBjYW4gbW9yZSBlYXNpbHkgZXhhbWluZSBhbmQgY2xlYW4gbmV3IHRpbWUgc2VyaWVzIGRhdGEgb24gdGhlIGZseS4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIGdhaW4gYSBiaXQgbW9yZSBwcmFjdGljZSBieSBleHBsb3JpbmcsIGNsZWFuaW5nLCBhbmQgcGxvdHRpbmcgZGF0YSBvbiB1bmVtcGxveW1lbnQsIGJvdGggaW4gdGhlIFVuaXRlZCBTdGF0ZXMgaW4gZ2VuZXJhbCBhbmQgaW4gTWFzc2FjaHVzZXR0cyAoTUEpIGluIHBhcnRpY3VsYXIuIA0KYGBge3J9DQp1bmVtcGxveW1lbnQgPC0gcmVhZFJEUygiQzovTWlzIGNvc2FzL0NvZGluZy9QcmFjdGljYS9SL2ZpbmFuY2UvZGF0YS91bmVtcGxveW1lbnQuUkRhdGEiKQ0KYGBgDQpgYGB7cn0NCiMgVmlldyBhIHN1bW1hcnkgb2YgeW91ciB1bmVtcGxveW1lbnQgZGF0YQ0Kc3VtbWFyeSh1bmVtcGxveW1lbnQpDQoNCiMgVXNlIG5hLmFwcHJveCB0byByZW1vdmUgbWlzc2luZyB2YWx1ZXMgaW4gdW5lbXBsb3ltZW50IGRhdGENCnVuZW1wbG95bWVudCA8LSBuYS5hcHByb3godW5lbXBsb3ltZW50KQ0KDQojIFBsb3QgbmV3IHVuZW1wbG95bWVudCBkYXRhDQpsdHkgPC0gYygxLCAyKQ0KbGFiZWxzIDwtIGMoIlVTIFVuZW1wbG95bWVudCAoJSkiLCAiTUEgVW5lbXBsb3llbW50ICglKSIpDQpwbG90Lnpvbyh1bmVtcGxveW1lbnQsIHBsb3QudHlwZSA9ICJzaW5nbGUiLCBsdHkgPSBsdHkpDQpsZWdlbmQoInRvcHJpZ2h0IiwgbHR5ID0gbHR5LCBsZWdlbmQgPSBsYWJlbHMsIGJnID0gIndoaXRlIikNCmBgYA0KIyMjIExhZ2dpbmcgdW5lbXBsb3ltZW50DQoNCkdpdmVuIHRoYXQgZWNvbm9taWMgdHJlbmRzIG1heSB0YWtlIHNvbWUgdGltZSB0byBpbmZsdWVuY2UgdG91cmlzbSwgaXQgbWF5IGJlIGhlbHBmdWwgdG8gbGFnIHlvdXIgdW5lbXBsb3ltZW50IGRhdGEgYmVmb3JlIHByb2NlZWRpbmcgd2l0aCBhbmFseXNpcy4NCg0KR2VuZXJhdGluZyBhIGxhZyBpbiB4dHMgaXMgc3RyYWlnaHRmb3J3YXJkIHdpdGggdGhlIGxhZygpIGNvbW1hbmQsIHdoaWNoIHJlcXVpcmVzIHRoYXQgeW91IHNwZWNpZnkgdGhlIGRhdGEgYmVpbmcgbGFnZ2VkICh0aGUgeCBhcmd1bWVudCkgYW5kIGEgayB2YWx1ZSB0byBkZXRlcm1pbmUgdGhlIGRpcmVjdGlvbiBhbmQgc2NhbGUgb2YgdGhlIGxhZy4NCg0KQmUgY2FyZWZ1bCB0byBrZWVwIHlvdXIgZm9ybWF0dGluZyBjb25zaXN0ZW50LiBCYXNlIFIgYW5kIHRoZSB6b28gcGFja2FnZSByZXF1aXJlIHRoYXQgeW91IHNwZWNpZnkgYSBsYWcgd2l0aCBhIG5lZ2F0aXZlIHZhbHVlLCBzbyB0aGF0IGEgbGFnIG9mIDEgaXMgZXhwcmVzc2VkIHVzaW5nICItMSIgKGFuZCBhIGxlYWQgb2YgMSBpcyBjb3VudGVyaW50dWl0aXZlbHkgZXhwcmVzc2VkIHVzaW5nICIxIikuIEJ5IGNvbnRyYXN0LCB0aGUgeHRzIHBhY2thZ2Ugc3BlY2lmaWVzIGxhZ3MgdXNpbmcgYSBwb3NpdGl2ZSB2YWx1ZSwgc28gdGhhdCBhIGxhZyBvZiAxIGlzIGV4cHJlc3NlZCB1c2luZyAiMSIgKGFuZCBhIGxlYWQgb2YgMSBpcyBleHByZXNzZWQgdXNpbmcgIi0xIikuDQpgYGB7cn0NCiMgQ3JlYXRlIGEgb25lIG1vbnRoIGxhZyBvZiBVUyB1bmVtcGxveW1lbnQNCnVzX21vbnRobGFnIDwtIGxhZyh1bmVtcGxveW1lbnQkdXMsIGsgPSAiMSIpDQoNCiMgQ3JlYXRlIGEgb25lIHllYXIgbGFnIG9mIFVTIHVuZW1wbG95bWVudA0KdXNfeWVhcmxhZyA8LSBsYWcodW5lbXBsb3ltZW50JHVzLCBrID0gIjEyIikNCg0KIyBNZXJnZSB5b3VyIG9yaWdpbmFsIGRhdGEgd2l0aCB5b3VyIG5ldyBsYWdzIA0KdW5lbXBsb3ltZW50X2xhZ3MgPC0gbWVyZ2UodW5lbXBsb3ltZW50LCB1c19tb250aGxhZywgdXNfeWVhcmxhZykNCg0KIyBWaWV3IHRoZSBmaXJzdCAxNSByb3dzIG9mIHVuZW1wbG95bWVudF9sYWdzDQpoZWFkKHVuZW1wbG95bWVudF9sYWdzLCAxNSkNCmBgYA0KaGVuIGl0IGNvbWVzIHRvIHRpbWUgc2VyaWVzIGFuYWx5c2lzLCBtYW55IG9mIHRoZSB0aGVvcmV0aWNhbCBwcm9jZXNzZXMgeW91J2xsIGludmVzdGlnYXRlIHRha2Ugc29tZSB0aW1lIHRvIGhhdmUgYW4gZWZmZWN0LiBJbmNsdWRpbmcgbGFncyBpbiB5b3VyIGFuYWx5c2lzIGlzIGFuIGVhc3kgd2F5IHRvIGFjY291bnQgZm9yIHRoaXMuIEhvd2V2ZXIsIGFzIHlvdSBtYXkgaGF2ZSBub3RpY2VkIGluIHlvdXIgY2FsbCB0byBoZWFkKCksIGxhZ3MgZ2VuZXJhdGVkIHRocm91Z2ggdGhpcyBwcm9jZXNzIGFyZSBub3QgaW50dWl0aXZlbHkgbGFiZWxsZWQgaW4geW91ciBkYXRhLg0KDQojIyMgRGlmZmVyZW5jaW5nIHVuZW1wbG95bWVudA0KDQpUbyBjYWxjdWxhdGUgYSBkaWZmZXJlbmNlLCBzaW1wbHkgdXNlIHRoZSBkaWZmKCkgY29tbWFuZC4gVGhpcyBjb21tYW5kIHJlcXVpcmVzIHlvdSB0byBzcGVjaWZ5IHRoZSBvcmlnaW5hbCBkYXRhIG9iamVjdCwgdGhlIG51bWJlciBvZiBsYWdzIChsYWcpLCBhbmQgdGhlIG9yZGVyIG9mIHRoZSBkaWZmZXJlbmNlIChkaWZmZXJlbmNlcykuDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCBleHBhbmQgeW91ciB1bmVtcGxveW1lbnQgZGF0YSBpbiBhIGRpZmZlcmVudCBkaXJlY3Rpb24gYnkgYWRkaW5nIGEgZmV3IHVzZWZ1bCBkaWZmZXJlbmNlIG1lYXN1cmVzLg0KDQpDb25zdHJ1Y3QgYSBmaXJzdCBvcmRlciBtb250aGx5IGRpZmZlcmVuY2UgaW4gVVMgdW5lbXBsb3ltZW50IHVzaW5nIGRpZmYoKS4gSW4geW91ciBjYWxsIHRvIGRpZmYoKSwgc3BlY2lmeSB0aGUgY29sdW1uIHlvdSBhcmUgZHJhd2luZyBmcm9tIGluIHVuZW1wbG95bWVudCBhcyB3ZWxsIGFzIHRoZSBsYWcgYW5kIGRpZmZlcmVuY2VzIGFyZ3VtZW50cy4gUmF0aGVyIHRoYW4gc2F2aW5nIHRoaXMgdG8gYSBuZXcgb2JqZWN0IGZvciBtZXJnaW5nLCBzYXZlIHlvdXIgZGF0YSBpbnRvIGEgbmV3IGNvbHVtbiBpbiB1bmVtcGxveW1lbnQgY2FsbGVkIHVzX21vbnRobHlkaWZmLg0KDQpVc2UgYSBzaW1pbGFyIGNhbGwgdG8gZGlmZigpIHRvIGNvbnN0cnVjdCBhbiBhbm51YWwgZGlmZmVyZW5jZSBpbiBVUyB1bmVtcGxveW1lbnQuIFNhdmUgdGhpcyB0byB1bmVtcGxveW1lbnQkdXNfeWVhcmx5ZGlmZi4NCmBgYHtyfQ0KIyBHZW5lcmF0ZSBtb250aGx5IGRpZmZlcmVuY2UgaW4gdW5lbXBsb3ltZW50DQp1bmVtcGxveW1lbnQkdXNfbW9udGhseWRpZmYgPC0gZGlmZih1bmVtcGxveW1lbnQkdXMsIGxhZyA9IDEsIGRpZmZlcmVuY2VzID0gMSkNCg0KIyBHZW5lcmF0ZSB5ZWFybHkgZGlmZmVyZW5jZSBpbiB1bmVtcGxveW1lbnQNCnVuZW1wbG95bWVudCR1c195ZWFybHlkaWZmIDwtIGRpZmYodW5lbXBsb3ltZW50JHVzLCBsYWcgPSAxMiwgZGlmZmVyZW5jZXMgPSAxKQ0KYGBgDQpVc2UgdHdvIGNhbGxzIHRvIHBsb3QueHRzKCkgdG8gZ2VuZXJhdGUgcGxvdHMgb2YgVVMgdW5lbXBsb3ltZW50ICh1bmVtcGxveW1lbnRcJHVzKSBhbmQgYW5udWFsIGNoYW5nZSAodW5lbXBsb3ltZW50XCR1c195ZWFybHlkaWZmKSwgcmVzcGVjdGl2ZWx5LiBMZWF2ZSB0aGUgdHlwZSBhcmd1bWVudCBhcyBpcyBpbiB5b3VyIHNlY29uZCBjYWxsIHRvIHBsb3QueHRzKCkgdG8gcHJvZHVjZSBhIGJhcnBsb3QuIFRoZSBwcmUtd3JpdHRlbiBwYXIoKSBjb21tYW5kIGFsbG93cyB5b3UgdG8gdmlldyBib3RoIHBsb3RzIGF0IHRoZSBzYW1lIHRpbWUuDQpgYGB7cn0NCiMgUGxvdCBVUyB1bmVtcGxveW1lbnQgYW5kIGFubnVhbCBkaWZmZXJlbmNlDQpwYXIobWZyb3cgPSBjKDIsMSkpDQpwbG90Lnh0cyh1bmVtcGxveW1lbnQkdXMpDQpwbG90Lnh0cyh1bmVtcGxveW1lbnQkdXNfeWVhcmx5ZGlmZiwgdHlwZSA9ICJoIikNCmBgYA0KV2hpbGUgbGFncyBhcmUgdXNlZnVsIGluIHRpbWUgc2VyaWVzIGFuYWx5c2lzLCBkaWZmZXJlbmNpbmcgcHJvdmlkZXMgYSB2ZXJ5IGludHVpdGl2ZSB3YXkgdG8gdmlzdWFsaXplIGdyb3d0aCB0cmVuZHMgb3ZlciB0aW1lLiBCb3RoIHR5cGVzIG9mIGluZGljYXRvcnMgYXJlIGVhc3kgdG8gcHJvZHVjZSB1c2luZyBjb21tYW5kcyBpbiB4dHMgYW5kIHpvby4NCg0KIyMgUm9sbGluZyBmdW5jdGlvbnMNCg0KIyMjIEFkZCBhIGRpc2NyZXRlIHJvbGxpbmcgc3VtIHRvIEdEUCBkYXRhDQoNCldoaWxlIGl0IGhlbHBzIHRvIGtub3cgdGhlIGFtb3VudCBvZiBjaGFuZ2UgZnJvbSBvbmUgcGVyaW9kIHRvIHRoZSBuZXh0LCB5b3UgbWF5IHdhbnQgdG8ga25vdyB0aGUgdG90YWwgY2hhbmdlIHNpbmNlIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHllYXIuIFRvIGdlbmVyYXRlIHRoaXMgdHlwZSBvZiBpbmRpY2F0b3IsIHlvdSBjYW4gdXNlIHRoZSBzcGxpdC1sYXBwbHktcmJpbmQgcGF0dGVybi4NCg0KSW4gYWRkaXRpb24gdG8gc3RhdGljIEdEUCB2YWx1ZXMgaW4gZWFjaCBxdWFydGVyLCB5b3UnZCBsaWtlIHRvIGdlbmVyYXRlIGEgbWVhc3VyZSBvZiBHRFAgY2hhbmdlIGZyb20gb25lIHF1YXJ0ZXIgdG8gdGhlIG5leHQgKHVzaW5nIGRpZmYoKSkgYXMgd2VsbCBhcyBhIHJvbGxpbmcgc3VtIG9mIHllYXItdG8tZGF0ZSBHRFAgY2hhbmdlICh1c2luZyBzcGxpdCgpLCBsYXBwbHkoKSBhbmQgcmJpbmQoKS4NCiANClVzZSBkaWZmKCkgdG8gcHJvZHVjZSBhIHNpbXBsZSBxdWFydGVybHkgZGlmZmVyZW5jZSBpbiBnZHAuIEJlIHN1cmUgdG8gc3BlY2lmeSB0aGUgZ2RwIGNvbHVtbiBhbmQgc2V0IHRoZSBsYWcgZXF1YWwgdG8gMSBwZXJpb2QgKGluIHRoaXMgY2FzZSwgMSBxdWFydGVyKS4gU2F2ZSB0aGlzIGludG8geW91ciBnZHAgb2JqZWN0IGFzIHF1YXJ0ZXJseV9kaWZmLg0KTm93IHRoYXQgeW91IGhhdmUgYSBtZWFzdXJlIG9mIHF1YXJ0ZXJseSBHRFAgY2hhbmdlLCB5b3VyIG5leHQgc3RlcCBpcyB0byBzcGxpdCB5b3VyIHF1YXJ0ZXJseV9kaWZmIGRhdGEgaW50byB5ZWFycyB1c2luZyBzcGxpdCgpLiBJbiB5b3VyIGNhbGwgdG8gc3BsaXQoKSwgYmUgc3VyZSB0byBzcGVjaWZ5IHRoZSBxdWFydGVybHlfZGlmZiBjb2x1bW4gb2YgZ2RwIGFuZCBzZXQgdGhlIGYgYXJndW1lbnQgZXF1YWwgdG8gInllYXJzIiAod2l0aCBxdW90ZXMpLg0KDQpVc2UgbGFwcGx5KCkgb24geW91ciBuZXdseSBzcGxpdCBkYXRhLiBUbyBjYWxjdWxhdGUgYSBjdW11bGF0aXZlIHN1bSBpbiBlYWNoIHllYXIsIHNldCB0aGUgRlVOIGFyZ3VtZW50IGVxdWFsIHRvIGN1bXN1bSAod2l0aG91dCBxdW90ZXMpLg0KDQpVc2UgZG8uY2FsbCgpIHRvIHJiaW5kIHlvdXIgZ2RwY2hhbmdlX3l0ZCBkYXRhIGJhY2sgaW50byBhbiB4dHMgb2JqZWN0Lg0KRmluYWxseSwgdXNlIHBsb3QueHRzKCkgdG8gZXhhbWluZSB5ZWFyLXRvLWRhdGUgY2hhbmdlIGluIEdEUCAoZ2RwY2hhbmdlX3h0cykuDQpgYGB7cn0NCmdkcCA8LSBnZHBfYXBwcm94DQpnZHAgPC0gc2V0TmFtZXMoZ2RwLCAiZ2RwIikNCmBgYA0KDQpgYGB7cn0NCiMgQWRkIGEgcXVhcnRlcmx5IGRpZmZlcmVuY2UgaW4gZ2RwDQpnZHAkcXVhcnRlcmx5X2RpZmYgPC0gZGlmZihnZHAkZ2RwICwgbGFnID0gMSwgZGlmZmVyZW5jZXMgPSAxKQ0KDQojIFNwbGl0IGdkcCRxdWFydGVybHlfZGlmZiBpbnRvIHllYXJzDQpnZHBjaGFuZ2VfeWVhcnMgPC0gc3BsaXQoZ2RwJHF1YXJ0ZXJseV9kaWZmLCBmID0gInllYXJzIikNCg0KIyBVc2UgbGFwcGx5IHRvIGNhbGN1bGF0ZSB0aGUgY3Vtc3VtIGVhY2ggeWVhcg0KZ2RwY2hhbmdlX3l0ZCA8LSBsYXBwbHkoZ2RwY2hhbmdlX3llYXJzLCBGVU4gPSBjdW1zdW0pDQoNCiMgVXNlIGRvLmNhbGwgdG8gcmJpbmQgdGhlIHJlc3VsdHMNCmdkcGNoYW5nZV94dHMgPC0gZG8uY2FsbChyYmluZCwgZ2RwY2hhbmdlX3l0ZCkNCg0KIyBQbG90IGN1bXVsYXRpdmUgeWVhci10by1kYXRlIGNoYW5nZSBpbiBHRFANCnBsb3QueHRzKGdkcGNoYW5nZV94dHMsIHR5cGUgPSAiaCIpDQpgYGANClRoZSBzcGxpdC1sYXBwbHktcmJpbmQgcGF0dGVybiBpcyBjb21wbGljYXRlZCBidXQgYWxsb3dzIHlvdSB0byBkZXZlbG9wIHVzZWZ1bCBhbmQgcHJlY2lzZSBpbmRpY2F0b3JzIGFjcm9zcyB5b3VyIHRpbWUgc2VyaWVzIGRhdGEuIEluIHRoZSBwbG90LCBlYWNoIGJhciBzaG93cyBjdW11bGF0aXZlIEdEUCBncm93dGggc2luY2UgdGhlIGJlZ2lubmluZyBvZiB0aGF0IHllYXIuIFNvbWUgYWRkaXRpb25hbCBtYW5pcHVsYXRpb24gd291bGQgZ2l2ZSB5b3UgYSBwZXJjZW50YWdlIG9mIHllYXItdG8tZGF0ZSBHRFAgZ3Jvd3RoIC0gYSBjb21tb24gaW5kaWNhdG9yIGluIGVjb25vbWljIGFuYWx5c2lzIQ0KDQojIyMgQWRkIGEgY29udGludW91cyByb2xsaW5nIGF2ZXJhZ2UgdG8gdW5lbXBsb3ltZW50IGRhdGENCg0KSW4gYWRkaXRpb24gdG8gZGlzY3JldGUgbWVhc3VyZXMgc3VjaCBhcyB5ZWFyLXRvLWRhdGUgc3VtcywgeW91IG1heSBiZSBpbnRlcmVzdGVkIGluIGFkZGluZyBhIHJvbGxpbmcgc3VtIG9yIGF2ZXJhZ2UgdG8geW91ciB0aW1lIHNlcmllcyBkYXRhLg0KDQpUbyBkbyBzbywgbGV0J3MgcmV0dXJuIHRvIHlvdXIgbW9udGhseSB1bmVtcGxveW1lbnQgZGF0YS4gV2hpbGUgeW91IG1heSBiZSBpbnRlcmVzdGVkIGluIHN0YXRpYyBsZXZlbHMgb2YgdW5lbXBsb3ltZW50IGluIGFueSBnaXZlbiBtb250aCwgYSBicm9hZGVyIHBpY3R1cmUgb2YgdGhlIGVjb25vbWljIGVudmlyb25tZW50IG1pZ2h0IGNhbGwgZm9yIHJvbGxpbmcgaW5kaWNhdG9ycyBvdmVyIHNldmVyYWwgbW9udGhzLg0KDQpUbyBkbyB0aGlzLCB5b3UnbGwgdXNlIHRoZSByb2xsYXBwbHkoKSBjb21tYW5kLCB3aGljaCB0YWtlcyBhIHRpbWUgc2VyaWVzIG9iamVjdCwgYSB3aW5kb3cgc2l6ZSB3aWR0aCwgYW5kIGEgRlVOIGFyZ3VtZW50IHRvIGFwcGx5IHRvIGVhY2ggcm9sbGluZyB3aW5kb3cuDQpgYGB7cn0NCmx3ZCA8LSBjKDEsIDIpDQpsdHkgPC0gYygyLCAxKQ0KIyBVc2Ugcm9sbGFwcGx5IHRvIGNhbGN1bGF0ZSB0aGUgcm9sbGluZyB5ZWFybHkgYXZlcmFnZSBVUyB1bmVtcGxveW1lbnQNCnVuZW1wbG95bWVudCR5ZWFyX2F2ZyA8LSByb2xsYXBwbHkodW5lbXBsb3ltZW50JHVzLCB3aWR0aCA9IDEyLCBGVU4gPSBtZWFuKQ0KDQojIFBsb3QgYWxsIGNvbHVtbnMgb2YgVVMgdW5lbXBsb3ltZW50IGRhdGENCnBsb3Quem9vKHVuZW1wbG95bWVudFssIGMoInVzIiwgInllYXJfYXZnIildLCBwbG90LnR5cGUgPSAic2luZ2xlIiwgbHR5ID0gbHR5LCBsd2QgPSBsd2QpDQpgYGANCllvdXIgcm9sbGluZyBhdmVyYWdlIGhlbHBzIHNtb290aCBvdXQgc29tZSBvZiB0aGUgc2hvcnQgdGVybSBjaGFuZ2VzIGluIHVuZW1wbG95bWVudCBmcm9tIG1vbnRoIHRvIG1vbnRoIGFuZCBwcm92aWRlcyBhIGJyb2FkZXIgcGljdHVyZSBvZiB0aGUgaGVhbHRoIG9mIHRoZSBVUyBlY29ub215Lg0KDQojIyMgTWFuaXB1bGF0aW5nIE1BIHVuZW1wbG95bWVudCBkYXRhDQoNCk5vdyB0aGF0IHlvdSd2ZSBhZGRlZCBzb21lIGxhZ3MsIGRpZmZlcmVuY2VzLCBhbmQgcm9sbGluZyB2YWx1ZXMgdG8geW91ciBHRFAgYW5kIFVTIHVuZW1wbG95bWVudCBkYXRhLCBpdCdzIHRpbWUgdG8gdGFrZSB0aGVzZSBza2lsbHMgYmFjayB0byB5b3VyIGFzc2lnbm1lbnQuDQoNClJlbWVtYmVyIHRoYXQgeW91ciBjbGllbnQgd2FudHMgaW5mb3JtYXRpb24gcmVsZXZhbnQgdG8gdGhlIEJvc3RvbiB0b3VyaXNtIGluZHVzdHJ5LiBJbiBhZGRpdGlvbiB0byBkYXRhIG9uIHRoZSBVUyBlY29ub215IGluIGdlbmVyYWwsIGl0IG1heSBoZWxwIHRvIHByZXBhcmUgc29tZSByZWxldmFudCBpbmRpY2F0b3JzIGZvciB5b3VyIE1hc3NhY2h1c2V0dHMgZWNvbm9taWMgZGF0YS4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIHVzZSB5b3VyIHRpbWUgc2VyaWVzIGRhdGEgbWFuaXB1bGF0aW9uIHNraWxscyB0byBnZW5lcmF0ZTogYSBvbmUteWVhciBsYWcsIGEgc2l4LW1vbnRoIGZpcnN0IG9yZGVyIGRpZmZlcmVuY2UsIGEgc2l4LW1vbnRoIHJvbGxpbmcgYXZlcmFnZSwgYW5kIGEgb25lLXllYXIgcm9sbGluZyBtYXhpbXVtIGluIHRoZSBNQSB1bmVtcGxveW1lbnQgcmF0ZS4gDQoNCmBgYHtyfQ0KIyBBZGQgYSBvbmUteWVhciBsYWcgb2YgTUEgdW5lbXBsb3ltZW50DQp1bmVtcGxveW1lbnQkbWFfeWVhcmxhZyA8LSBsYWcodW5lbXBsb3ltZW50JG1hLCBrID0gIjEyIikNCg0KIyBBZGQgYSBzaXgtbW9udGggZGlmZmVyZW5jZSBvZiBNQSB1bmVtcGxveW1lbnQNCnVuZW1wbG95bWVudCRtYV9zaXhtb250aGRpZmYgPC0gZGlmZih1bmVtcGxveW1lbnQkbWEsIGxhZyA9IDYsIGRpZmZlcmVuY2VzID0gMSkNCg0KIyBBZGQgYSBzaXgtbW9udGggcm9sbGluZyBhdmVyYWdlIG9mIE1BIHVuZW1wbG95bWVudA0KdW5lbXBsb3ltZW50JG1hX3NpeG1vbnRoYXZnIDwtIHJvbGxhcHBseSh1bmVtcGxveW1lbnQkbWEsIHdpZHRoID0gNiwgRlVOID0gbWVhbikNCiAgDQojIEFkZCBhIHllYXJseSByb2xsaW5nIG1heGltdW0gb2YgTUEgdW5lbXBsb3ltZW50DQp1bmVtcGxveW1lbnQkbWFfeWVhcm1heCA8LSByb2xsYXBwbHkodW5lbXBsb3ltZW50JG1hLCB3aWR0aCA9IDEyLCBGVU4gPSBtYXgpDQoNCiMgVmlldyB0aGUgbGFzdCB5ZWFyIG9mIHVuZW1wbG95bWVudCBkYXRhDQp0YWlsKHVuZW1wbG95bWVudCwgMTIpDQpgYGANCiMgU3BvcnRzIERhdGENCg0KIyMgQWR2YW5jZWQgZmVhdHVyZXMgb2YgeHRzDQoNCiMjIyBFbmNvZGluZyBhbmQgcGxvdHRpbmcgUmVkIFNveCBkYXRhDQoNCkFmdGVyIGV4cGxvcmluZyBhbmQgbWFuaXB1bGF0aW5nIGRhdGEgb24gZmxpZ2h0cywgd2VhdGhlciwgYW5kIHRoZSBlY29ub215LCB5b3VyIGNsaWVudCB3YW50cyB0byBjb3ZlciBhbGwgdGhlIGJhc2VzLiBOYXR1cmFsbHksIHRoZXknZCBsaWtlIHlvdSB0byBjb2xsZWN0IGRhdGEgb24gQm9zdG9uJ3MgbWFqb3Igc3BvcnRzIHRlYW1zOiB0aGUgQm9zdG9uIFJlZCBTb3ggKGJhc2ViYWxsKSwgdGhlIE5ldyBFbmdsYW5kIFBhdHJpb3RzIChmb290YmFsbCksIHRoZSBCb3N0b24gQnJ1aW5zIChob2NrZXkpLCBhbmQgdGhlIEJvc3RvbiBDZWx0aWNzIChiYXNrZXRiYWxsKS4gSW4gdGhpcyBjaGFwdGVyLCB5b3UnbGwgcHJlcGFyZSBkYXRhIG9uIHRoZSBzY2hlZHVsZSBhbmQgb3V0Y29tZSBvZiBhbGwgZ2FtZXMgaW52b2x2aW5nIHRoZXNlIHRlYW1zIGZyb20gMjAxMCB0aHJvdWdoIDIwMTUuIEl0J3MgYSBwZXJmZWN0IG9wcG9ydHVuaXR5IHRvIGdhaW4gZnVydGhlciBwcmFjdGljZSBtYW5pcHVsYXRpbmcgdGltZSBzZXJpZXMgZGF0YSENCg0KQXMgYSBzdGFydCwgeW91J3ZlIGNvbXBpbGVkIGRhdGEgb24gZ2FtZXMgcGxheWVkIGJ5IHRoZSBCb3N0b24gUmVkIFNveCBmcm9tIDIwMTAgdGhyb3VnaCAyMDE1LiBJbiB0aGlzIGV4ZXJjaXNlLCB5b3UnbGwgZXhwbG9yZSB0aGUgZGF0YSwgZW5jb2RlIGl0IHRvIHh0cywgYW5kIHBsb3Qgc29tZSB0cmVuZHMgb3ZlciB0aW1lLiANCmBgYHtyfQ0KcmVkc294IDwtIHJlYWRSRFMoInJlZHNveC5yZHMiKQ0KYGBgDQpgYGB7cn0NCiMgVmlldyBzdW1tYXJ5IGluZm9ybWF0aW9uIGFib3V0IHlvdXIgcmVkc294IGRhdGENCnN1bW1hcnkocmVkc294KQ0KDQojIENvbnZlcnQgdGhlIGRhdGUgY29sdW1uIHRvIGEgdGltZS1iYXNlZCBmb3JtYXQNCnJlZHNveCRkYXRlIDwtIGFzLkRhdGUocmVkc294JGRhdGUpDQoNCiMgQ29udmVydCB5b3VyIHJlZCBzb3ggZGF0YSB0byB4dHMNCnJlZHNveF94dHMgPC0gYXMueHRzKHJlZHNveFssLTFdLCBvcmRlci5ieSA9IHJlZHNveCRkYXRlKQ0KDQojIFBsb3QgdGhlIFJlZCBTb3ggc2NvcmUgYW5kIHRoZSBvcHBvbmVudCBzY29yZSBvdmVyIHRpbWUNCnBsb3Quem9vKHJlZHNveF94dHNbLCBjKCJib3N0b25fc2NvcmUiLCAib3Bwb25lbnRfc2NvcmUiKV0pDQpgYGANCllvdSd2ZSBjb252ZXJ0ZWQgeW91ciBSZWQgU294IGRhdGEgdG8geHRzIGFuZCBnZW5lcmF0ZWQgcGxvdHMgc2hvd2luZyBzY29yZXMgb3ZlciB0aW1lLiBZb3UgY2FuIGNsZWFybHkgc2VlIHRoZSBnYW1lcyBjbHVzdGVyZWQgaW50byBzZWFzb25zLiBIb3dldmVyLCB0aGVzZSBwbG90cyBhcmUgZGlmZmljdWx0IHRvIGludGVycHJldC4gSWRlYWxseSwgeW91IHdhbnQgdG8gdmlzdWFsaXplIFJlZCBTb3ggd2lucyB1c2luZyBhIGNsZWFyIG1ldHJpYyBhbmQgcGVyaGFwcyBwcm92aWRlIHNvbWUgaW5kaWNhdG9yIG9mIGhvdyB0aGUgdGVhbSBpcyBkb2luZyBvdmVyIHRpbWUuIFRvIGRvIHRoYXQsIHlvdSdsbCBuZWVkIHRvIGRvIHNvbWUgbWF0aCENCg0KIyMjIENhbGN1bGF0ZSBhIGNsb3NpbmcgYXZlcmFnZQ0KDQpOb3cgdGhhdCB5b3UndmUgZXhwbG9yZWQgc29tZSB0cmVuZHMgaW4geW91ciBSZWQgU294IGRhdGEsIHlvdSB3YW50IHRvIHByb2R1Y2Ugc29tZSB1c2VmdWwgaW5kaWNhdG9ycy4gSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIGNhbGN1bGF0ZSB0aGUgdGVhbSdzIHdpbi9sb3NzIGF2ZXJhZ2UgYXQgdGhlIGVuZCBvZiBlYWNoIHNlYXNvbi4gSW4gZmluYW5jaWFsIHRlcm1zLCB5b3UgY2FuIHRoaW5rIG9mIHRoaXMgYXMgdGhlIHRlYW0ncyB2YWx1ZSBhdCB0aGUgY2xvc2Ugb2YgdGhlIHNlYXNvbi4NCg0KRmlyc3QsIHlvdSdsbCBpZGVudGlmeSB3aW5zIGJhc2VkIG9uIHRoZSBzY29yZSBvZiBlYWNoIGdhbWUuIFlvdSBjYW4gZG8gdGhpcyB1c2luZyBhIHNpbXBsZSBpZmVsc2UoKSBjb21tYW5kIGFuZCB0aGUga25vd2xlZGdlIHRoYXQgdGhlIFJlZCBTb3ggd2luIGVhY2ggZ2FtZSBpbiB3aGljaCB0aGV5IHNjb3JlIG1vcmUgcG9pbnRzIHRoYW4gdGhlIG9wcG9zaW5nIHRlYW0uDQoNClNlY29uZCwgeW91J2xsIGlkZW50aWZ5IHRoZSBkYXRlIG9mIHRoZSBsYXN0IGdhbWUgaW4gZWFjaCBzZWFzb24gdXNpbmcgZW5kcG9pbnRzKCkuIFRoaXMgY29tbWFuZCBpZGVudGlmaWVzIHRoZSBsYXN0IGRhdGUgaW4geW91ciBvYmplY3Qgd2l0aGluIGNlcnRhaW4gcGVyaW9kcy4NCg0KRmluYWxseSwgdG8gY2FsY3VsYXRlIHRoZSBjbG9zaW5nIHdpbi9sb3NzIGF2ZXJhZ2UgZWFjaCBzZWFzb24sIHNpbXBseSB1c2UgcGVyaW9kLmFwcGx5KCkgb24gdGhlIHdpbl9sb3NzIGNvbHVtbiBvZiB5b3VyIGRhdGEsIHNwZWNpZnlpbmcgdGhlIGNsb3NlIGRhdGVzIGFzIHRoZSBpbmRleCwgYW5kIG1lYW4gYXMgdGhlIGZ1bmN0aW9uLg0KDQpgYGB7cn0NCiMgR2VuZXJhdGUgYSBuZXcgdmFyaWFibGUgY29kaW5nIGZvciByZWQgc294IHdpbnMNCnJlZHNveF94dHMkd2luX2xvc3MgPC0gaWZlbHNlKHJlZHNveF94dHMkYm9zdG9uX3Njb3JlID4gcmVkc294X3h0cyRvcHBvbmVudF9zY29yZSwgMSwgMCkNCg0KIyBJZGVudGlmeSB0aGUgZGF0ZSBvZiB0aGUgbGFzdCBnYW1lIGVhY2ggc2Vhc29uDQpjbG9zZSA8LSBlbmRwb2ludHMocmVkc294X3h0cyR3aW5fbG9zcywgb24gPSAieWVhcnMiKQ0KDQojIENhbGN1bGF0ZSBhdmVyYWdlIHdpbi9sb3NzIHJlY29yZCBhdCB0aGUgZW5kIG9mIGVhY2ggc2Vhc29uDQpwZXJpb2QuYXBwbHkocmVkc294X3h0c1ssICJ3aW5fbG9zcyJdLCBjbG9zZSwgbWVhbikNCmBgYA0KVGhlIGNvbWJpbmF0aW9uIG9mIGVuZHBvaW50cygpIGFuZCBwZXJpb2QuYXBwbHkoKSBhbGxvd3MgeW91IHRvIGVhc2lseSBkZXZlbG9wIGluZGljYXRvcnMgYXMgb2YgdGhlIGVuZCBvZiBhIHBlcmlvZC4gSW4gdGhpcyBjYXNlLCB5b3UgY2FuIHNlZSB0aGUgUmVkIFNveCBoYWQgYSB2ZXJ5IHN0cm9uZyBzZWFzb24gaW4gMjAxMyAoYXZnID0gMC41OTkpIGFuZCBhIHdlYWsgc2Vhc29uIGluIDIwMTQgKGF2ZyA9IDAuNDM4KS4NCg0KIyMjIENhbGN1bGF0ZSBhbmQgcGxvdCBhIHNlYXNvbmFsIGF2ZXJhZ2UNCg0KSW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlIHlvdSB1c2VkIGVuZHBvaW50cygpIGFuZCBwZXJpb2QuYXBwbHkoKSB0byBxdWlja2x5IGNhbGN1bGF0ZSB0aGUgd2luL2xvc3MgYXZlcmFnZSBmb3IgdGhlIEJvc3RvbiBSZWQgU294IGF0IHRoZSBlbmQgb2YgZWFjaCBzZWFzb24uIEJ1dCB3aGF0IGlmIHlvdSBuZWVkIHRvIGtub3cgdGhlIGN1bXVsYXRpdmUgYXZlcmFnZSB0aHJvdWdob3V0IGVhY2ggc2Vhc29uPyBTdGF0aXN0aWNpYW5zIGFuZCBzcG9ydHMgZmFucyBhbGlrZSBvZnRlbiByZWx5IG9uIHRoaXMgYXZlcmFnZSB0byBjb21wYXJlIGEgdGVhbSB3aXRoIGl0cyByaXZhbHMuDQoNClRvIGNhbGN1bGF0ZSBhIGN1bXVsYXRpdmUgYXZlcmFnZSBpbiBlYWNoIHNlYXNvbiwgeW91J2xsIG5lZWQgdG8gcmV0dXJuIHRvIHRoZSBzcGxpdC1sYXBwbHktcmJpbmQgZm9ybXVsYS4gRmlyc3QsIHlvdSdsbCBzcGxpdCB0aGUgZGF0YSBieSBzZWFzb24sIHRoZW4geW91J2xsIGFwcGx5IGEgY3VtdWxhdGl2ZSBtZWFuIGZ1bmN0aW9uIHRvIHRoZSB3aW5fbG9zcyBjb2x1bW4gaW4gZWFjaCBzZWFzb24sIHRoZW4geW91J2xsIGJpbmQgdGhlIHZhbHVlcyBiYWNrIGludG8gYW4geHRzIG9iamVjdC4NCg0KQSBjdXN0b20gY3VtbWVhbigpIGZ1bmN0aW9uLCB3aGljaCBnZW5lcmF0ZXMgYSBjdW11bGF0aXZlIHN1bSBhbmQgZGl2aWRlcyBieSB0aGUgbnVtYmVyIG9mIHZhbHVlcyBpbmNsdWRlZCBpbiB0aGUgc3VtLCBoYXMgYmVlbiBnZW5lcmF0ZWQgYmVsb3c6DQpgYGB7cn0NCmN1bW1lYW4gPC0gZnVuY3Rpb24gKHgpew0KICAgIGN1bXN1bSh4KS9zZXFfYWxvbmcoeCkNCn0NCmBgYA0KYGBge3J9DQojIFNwbGl0IHJlZHNveF94dHMgd2luX2xvc3MgZGF0YSBpbnRvIHllYXJzIA0KcmVkc294X3NlYXNvbnMgPC0gc3BsaXQocmVkc294X3h0cyR3aW5fbG9zcywgZiA9ICJ5ZWFycyIpDQoNCiMgVXNlIGxhcHBseSB0byBjYWxjdWxhdGUgdGhlIGN1bXVsYXRpdmUgbWVhbiBmb3IgZWFjaCBzZWFzb24NCnJlZHNveF95dGQgPC0gbGFwcGx5KHJlZHNveF9zZWFzb25zLCBjdW1tZWFuKQ0KDQojIFVzZSBkby5jYWxsIHRvIHJiaW5kIHRoZSByZXN1bHRzDQpyZWRzb3hfd2lubG9zcyA8LSBkby5jYWxsKHJiaW5kLCByZWRzb3hfeXRkKQ0KDQojIFBsb3QgdGhlIHdpbl9sb3NzIGF2ZXJhZ2UgZm9yIHRoZSAyMDEzIHNlYXNvbg0KcGxvdC54dHMocmVkc294X3dpbmxvc3NbIjIwMTMiXSwgeWxpbSA9IGMoMCwgMSkpDQpgYGANCllvdXIgcGxvdCBzaG93cyB0aGUgY3VtdWxhdGl2ZSB3aW4vbG9zcyBhdmVyYWdlIGFmdGVyIGVhY2ggZ2FtZSBpbiB0aGUgMjAxMyBzZWFzb24hIEJlY2F1c2UgZWFjaCB2YWx1ZSBpcyBhIGN1bXVsYXRpdmUgYXZlcmFnZSB3aXRoaW4gdGhlIHNlYXNvbiwgaXQgbWFrZXMgc2Vuc2UgdGhhdCB0aGUgdmFsdWUgaXMgZXh0cmVtZWx5IHZvbGF0aWxlIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNlYXNvbiwgd2hlbiBlYWNoIHdpbiBvciBsb3NzIG1ha2VzIGEgYmlnZ2VyIGRpZmZlcmVuY2UuDQoNCiMjIyBDYWxjdWxhdGUgYW5kIHBsb3QgYSByb2xsaW5nIGF2ZXJhZ2UNCg0KVGhlIGZpbmFsIGJhc2ViYWxsIGluZGljYXRvciB5b3UnZCBsaWtlIHRvIGdlbmVyYXRlIGlzIHRoZSBMMTAsIG9yIHRoZSBtb3Zpbmcgd2luL2xvc3MgYXZlcmFnZSBmcm9tIHRoZSBwcmV2aW91cyB0ZW4gZ2FtZXMuIFdoaWxlIHRoZSBjdW11bGF0aXZlIHdpbi9sb3NzIGF2ZXJhZ2UgdGVsbHMgeW91IGhvdyB0aGUgdGVhbSBpcyBkb2luZyBvdmVyYWxsLCB0aGUgTDEwIGluZGljYXRvciBwcm92aWRlcyBhIG1vcmUgc3BlY2lmaWMgcGljdHVyZSBvZiB0aGUgdGVhbSdzIHJlY2VudCBwZXJmb3JtYW5jZS4gQmV5b25kIHRoZSB3b3JsZCBvZiBzcG9ydHMsIHRoaXMgbWVhc3VyZSBpcyBjb21wYXJhYmxlIHRvIGEgZmluYW5jaWFsIGluZGljYXRvciBmb2N1c2VkIG9uIHJlY2VudCBwb3J0Zm9saW8gcGVyZm9ybWFuY2UuDQoNClRvIGdlbmVyYXRlIGEgcm9sbGluZyB3aW4vbG9zcyBhdmVyYWdlLCByZXR1cm4gdG8gdGhlIHJvbGxhcHBseSgpIGNvbW1hbmQgdXNlZCBpbiB0aGUgcHJldmlvdXMgY2hhcHRlci4gSW4gdGhpcyBjYXNlLCB5b3UnbGwgd2FudCB0byBhcHBseSB0aGUgbWVhbiBmdW5jdGlvbiB0byB0aGUgbGFzdCAxMCBnYW1lcyBwbGF5ZWQgYnkgdGhlIFJlZCBTb3ggYXQgYW55IGdpdmVuIHRpbWUgZHVyaW5nIHRoZSAyMDEzIHNlYXNvbi4NCg0KYGBge3J9DQojIFNlbGVjdCBvbmx5IHRoZSAyMDEzIHNlYXNvbg0KcmVkc294XzIwMTMgPC0gcmVkc294X3h0c1siMjAxMyJdDQoNCiMgVXNlIHJvbGxhcHBseSB0byBnZW5lcmF0ZSB0aGUgbGFzdCB0ZW4gYXZlcmFnZQ0KbGFzdHRlbl8yMDEzIDwtIHJvbGxhcHBseShyZWRzb3hfMjAxMyR3aW5fbG9zcywgd2lkdGggPSAxMCwgRlVOID0gbWVhbikNCg0KIyBQbG90IHRoZSBsYXN0IHRlbiBhdmVyYWdlIGR1cmluZyB0aGUgMjAxMyBzZWFzb24NCnBsb3QueHRzKGxhc3R0ZW5fMjAxMywgeWxpbSA9IGMoMCwgMSkpDQpgYGANCllvdSd2ZSBub3cgdXNlZCB5b3VyIHRpbWUgc2VyaWVzIGRhdGEgbWFuaXB1bGF0aW9uIHNraWxscyB0byBnZW5lcmF0ZSBhIGNsb3NpbmcgYXZlcmFnZSwgYSBjdW11bGF0aXZlIGF2ZXJhZ2UsIGFuZCBhIHJvbGxpbmcgYXZlcmFnZSBmcm9tIGJhc2ljIHNwb3J0cyBzY29yZXMuIFRoZXNlIHR5cGVzIG9mIGluZGljYXRvcnMgaGF2ZSBkaXZlcnNlIGFwcGxpY2F0aW9ucywgd2hldGhlciB5b3UncmUgYSBiYXNlYmFsbCBmYW4gb3IgYSBwb3J0Zm9saW8gYW5hbHlzdC4NCg0KIyMgSW5kZXhpbmcgY29tbWFuZHMgaW4geHRzDQoNCiMjIyBFeHRyYWN0IHdlZWtlbmQgZ2FtZXMNCg0KQWZ0ZXIgY2FsY3VsYXRpbmcgc29tZSB1c2VmdWwgaW5kaWNhdG9ycyBmcm9tIHlvdXIgUmVkIFNveCBkYXRhLCBpdCdzIHRpbWUgdG8gc3RlcCBiYWNrIGFuZCBleHBsb3JlIGRhdGEgZnJvbSBvdGhlciBCb3N0b24gc3BvcnRzIHRlYW1zLiBTcGVjaWZpY2FsbHksIHlvdSd2ZSBjb2xsZWN0ZWQgYWRkaXRpb25hbCBkYXRhIG9uIHRoZSBOZXcgRW5nbGFuZCBQYXRyaW90cyAoZm9vdGJhbGwpLCB0aGUgQm9zdG9uIEJydWlucyAoaG9ja2V5KSwgYW5kIHRoZSBCb3N0b24gQ2VsdGljcyAoYmFza2V0YmFsbCkuIERhdGEgZm9yIHRoZXNlIHRlYW1zLCBhbG9uZyB3aXRoIHlvdXIgcmVkc294IGRhdGEsIGhhdmUgYmVlbiBtZXJnZWQgaW50byBhIHNpbmdsZSB4dHMgb2JqZWN0LCBzcG9ydHMsIHdoaWNoIG5vdyBjb250YWlucyBkYXRhIG9uIGFsbCBnYW1lcyBwbGF5ZWQgYnkgQm9zdG9uLWFyZWEgc3BvcnRzIHRlYW1zIGZyb20gMjAxMCB0aHJvdWdoIDIwMTUuDQoNCmBgYHtyfQ0Kc3BvcnRzIDwtIHJlYWRSRFMoIkM6L01pcyBjb3Nhcy9Db2RpbmcvUHJhY3RpY2EvUi9maW5hbmNlL2RhdGEvc3BvcnRzLlJEYXRhIikNCmBgYA0KQmVmb3JlIGNvbmR1Y3RpbmcgZnVydGhlciBhbmFseXNpcywgeW91IHdhbnQgdG8gcmVmaW5lIHlvdXIgZGF0YSBpbnRvIGEgZmV3IHBvdGVudGlhbGx5IHVzZWZ1bCBzdWJzZXRzLiBJbiBwYXJ0aWN1bGFyLCBpdCBtYXkgYmUgaGVscGZ1bCB0byBmb2N1cyBleGNsdXNpdmVseSBvbiB3ZWVrZW5kIGdhbWVzIGludm9sdmluZyBCb3N0b24gc3BvcnRzIHRlYW1zLg0KDQpUbyBpZGVudGlmeSBnYW1lcyBiYXNlZCBvbiB0aGUgZGF5IG9mIHRoZSB3ZWVrLCB5b3Ugc2hvdWxkIHVzZSB0aGUgLmluZGV4d2RheSgpIGNvbW1hbmQsIHdoaWNoIHRlbGxzIHlvdSB0aGUgZGF5IG9mIHRoZSB3ZWVrIG9mIGVhY2ggb2JzZXJ2YXRpb24gaW4geW91ciB4dHMgb2JqZWN0LiBUaGVzZSB2YWx1ZXMgcmFuZ2UgZnJvbSAwLTYsIHdpdGggU3VuZGF5IGVxdWFsIHRvIDAgYW5kIFNhdHVyZGF5IGVxdWFsIHRvIDYuDQpgYGB7cn0NCiMgRXh0cmFjdCB0aGUgZGF5IG9mIHRoZSB3ZWVrIG9mIGVhY2ggb2JzZXJ2YXRpb24NCndlZWtkYXkgPC0gLmluZGV4d2RheShzcG9ydHMpDQpoZWFkKHdlZWtkYXkpDQoNCiMgR2VuZXJhdGUgYW4gaW5kZXggb2Ygd2Vla2VuZCBkYXRlcw0Kd2Vla2VuZCA8LSB3aGljaCguaW5kZXh3ZGF5KHNwb3J0cykgPT0gMCB8IC5pbmRleHdkYXkoc3BvcnRzKSA9PSA2KQ0KDQojIFN1YnNldCBvbmx5IHdlZWtlbmQgZ2FtZXMNCndlZWtlbmRfZ2FtZXMgPC0gc3BvcnRzW3dlZWtlbmRdDQpoZWFkKHdlZWtlbmRfZ2FtZXMpDQpgYGANClRoZSBhZHZhbmNlZCB4dHMgaW5kZXhpbmcgY29tbWFuZHMgbWFrZSBhIHNlZW1pbmdseSBkaWZmaWN1bHQgdGFzayBleHRyZW1lbHkgc2ltcGxlLiBZb3Ugbm93IGhhdmUgYW4geHRzIG9iamVjdCBjb250YWluaW5nIGRhdGEgb24gYWxsIHdlZWtlbmQgZ2FtZXMgaW52b2x2aW5nIEJvc3RvbiBzcG9ydHMgdGVhbXMgZnJvbSAyMDEwIHRocm91Z2ggMjAxNS4NCg0KIyMjIENhbGN1bGF0ZSBhIHJvbGxpbmcgYXZlcmFnZSBhY3Jvc3MgYWxsIHNwb3J0cw0KDQpOb3cgdGhhdCB5b3UndmUgbWFzdGVyZWQgc3Vic2V0dGluZyB5b3VyIGRhdGEgdG8gaW5jbHVkZSBvbmx5IHdlZWtlbmQgZ2FtZXMsIHlvdXIgY2xpZW50IHdvdWxkIGxpa2UgeW91IHRvIHRha2UgYSBkaWZmZXJlbnQgYXBwcm9hY2guIFBlcmhhcHMgQm9zdG9uJ3MgdG91cmlzbSBpbmR1c3RyeSByZWNlaXZlcyBhIGJvb3N0IHdoZW4gbG9jYWwgc3BvcnRzIHRlYW1zIHdpbiBtb3JlIGdhbWVzIGF0IGhvbWUuDQoNCkluc3RlYWQgb2YgZm9jdXNpbmcgb24gd2Vla2VuZCBnYW1lcywgeW91IGFyZSB0YXNrZWQgd2l0aCBnZW5lcmF0aW5nIGEgcm9sbGluZyB3aW4vbG9zcyBhdmVyYWdlIGZvY3VzZWQgb24gZ2FtZXMgcGxheWVkIGluIEJvc3Rvbi4gVG8gcHJvZHVjZSB0aGlzIGluZGljYXRvciwgeW91J2xsIHJldHVybiB0byB0aGUgcm9sbGFwcGx5KCkgY29tbWFuZCB1c2VkIGFib3ZlLCB0aGlzIHRpbWUgYXBwbHlpbmcgeW91ciBjYWxjdWxhdGlvbiB0byBhbGwgQm9zdG9uLWFyZWEgc3BvcnRzIHRlYW1zIGJ1dCBzdWJzZXR0aW5nIHRvIGluY2x1ZGUgb25seSBnYW1lcyBwbGF5ZWQgYXQgaG9tZS4NCg0KYGBge3J9DQojIEdlbmVyYXRlIGEgc3Vic2V0IG9mIHNwb3J0cyBkYXRhIHdpdGggb25seSBob21lZ2FtZXMNCmhvbWVnYW1lcyA8LSBzcG9ydHNbc3BvcnRzJGhvbWVnYW1lID09IDFdDQoNCiMgQ2FsY3VsYXRlIHRoZSB3aW4vbG9zcyBhdmVyYWdlIG9mIHRoZSBsYXN0IDIwIGhvbWUgZ2FtZXMNCmhvbWVnYW1lcyR3aW5fbG9zc18yMCA8LSByb2xsYXBwbHkoaG9tZWdhbWVzJHdpbl9sb3NzLCB3aWR0aCA9IDIwLCBGVU4gPSBtZWFuKQ0KDQojIENhbGN1bGF0ZSB0aGUgd2luL2xvc3MgYXZlcmFnZSBvZiB0aGUgbGFzdCAxMDAgaG9tZSBnYW1lcw0KaG9tZWdhbWVzJHdpbl9sb3NzXzEwMCA8LSByb2xsYXBwbHkoaG9tZWdhbWVzJHdpbl9sb3NzLCB3aWR0aCA9IDEwMCwgRlVOID0gbWVhbikNCg0KIyBVc2UgcGxvdC54dHMgdG8gZ2VuZXJhdGUNCnBsb3Quem9vKGhvbWVnYW1lc1ssIGMoIndpbl9sb3NzXzIwIiwgIndpbl9sb3NzXzEwMCIpXSwgcGxvdC50eXBlID0gInNpbmdsZSIsIGx0eSA9IGx0eSwgbHdkID0gbHdkKQ0KYGBgDQpZb3VyIHBsb3Qgc2hvd3MgdGhlIGdlbmVyYWwgc3VjY2VzcyBvZiBCb3N0b24gc3BvcnRzIHRlYW1zIHdoZW4gcGxheWluZyBhdCBob21lIGJvdGggaW4gdGhlIHNob3J0IHRlcm0gKDIwIGdhbWVzKSBhbmQgdGhlIGxvbmcgdGVybSAoMTAwIGdhbWVzKS4gSXQgbG9va3MgbGlrZSBCb3N0b24gdGVhbXMgZGlkIHZlcnkgd2VsbCBhdCBob21lIGluIDIwMTQh