1 Introduction and downloading data

1.1 Introduction and downloading data

1.1.1 Introducing getSymbols()

The getSymbols() function from the quantmod package provides a consistent interface to import data from various sources into your workspace. By default, getSymbols() imports the data as a xts object.

This exercise will introduce you to getSymbols(). You will use it to import QQQ data from Yahoo! Finance. QQQ is an exchange-traded fund that tracks the Nasdaq 100 index, and Yahoo! Finance is the default data source for getSymbols().

You use the Symbols argument to specify the instrument (i.e. the ticker symbol) you want to import. Since Symbols is the first argument to getSymbols(), you usually just type the instrument name and omit Symbols =.

# Load the quantmod package
library(quantmod)

# Import QQQ data from Yahoo! Finance
getSymbols(Symbols = "QQQ", auto.assign = TRUE)
[1] "QQQ"
# Look at the structure of the object getSymbols created
str(QQQ)
An ‘xts’ object on 2000-01-03/2020-07-31 containing:
  Data: num [1:5178, 1:6] 96.2 92 87.5 86.9 82.9 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:6] "QQQ.Open" "QQQ.High" "QQQ.Low" "QQQ.Close" ...
  Indexed by objects of class: [Date] TZ: UTC
  xts Attributes:  
List of 2
 $ src    : chr "yahoo"
 $ updated: POSIXct[1:1], format: "2020-08-03 18:02:04"
# Look at the first few rows of QQQ
head(QQQ)
           QQQ.Open QQQ.High QQQ.Low QQQ.Close QQQ.Volume QQQ.Adjusted
2000-01-03  96.1875  96.1875 90.7500  94.75000   36345200     82.61639
2000-01-04  92.0000  93.5000 87.9375  88.25000   33786600     76.94878
2000-01-05  87.5000  89.6250 84.2500  86.00000   42496600     74.98690
2000-01-06  86.8750  88.0000 79.7500  80.09375   37134800     69.83700
2000-01-07  82.9375  90.0000 82.5000  90.00000   28138200     78.47465
2000-01-10  91.0000  93.9375 89.9375  92.50000   29675600     80.65449

1.1.2 Data sources

In the last exercise, you imported data from Yahoo! Finance. The src argument allows you to tell getSymbols() to import data from a different data source.

In this exercise, you will import data from Alpha Vantage and FRED. Alpha Vantage is a source similar to Yahoo! Finance. FRED is an online database of economic time series data created and maintained by the Federal Reserve Bank of St. Louis.

getSymbols() imports data from Yahoo! Finance by default because src = “yahoo” by default. The src values for Alpha Vantage and FRED are “av” and “FRED”, respectively.

# Import QQQ data from Alpha Vantage
# getSymbols(Symbols = "QQQ", src = "av")
# https://www.alphavantage.co/ to get API key
# Look at the structure of QQQ
# str(QQQ)

# Import GDP data from FRED
getSymbols(Symbols = "GDP", src = "FRED")
[1] "GDP"
# Look at the structure of GDP
str(GDP)
An ‘xts’ object on 1947-01-01/2020-04-01 containing:
  Data: num [1:294, 1] 243 246 250 260 266 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr "GDP"
  Indexed by objects of class: [Date] TZ: UTC
  xts Attributes:  
List of 2
 $ src    : chr "FRED"
 $ updated: POSIXct[1:1], format: "2020-08-03 18:02:05"

1.1.3 Make getSymbols() return the data it retrieves

In the last exercise, getSymbols() automatically created an object named like the symbol you provided. This exercise will teach you to make getSymbols() return the data, so you can assign the output yourself.

There are two arguments that will make getSymbols() return the data:

  1. Set auto.assign = FALSE.
  2. Set env = NULL.

The two methods are functionally equivalent, but auto.assign = FALSE describes the behavior better. Use it because you will be more likely to remember what auto.assign = FALSE means in the future.

# Assign SPY data to 'spy' using auto.assign argument
spy <- getSymbols(Symbols = "SPY", auto.assign = FALSE)

# Look at the structure of the 'spy' object
str(spy)
An ‘xts’ object on 2000-01-03/2020-07-31 containing:
  Data: num [1:5178, 1:6] 148 144 140 140 140 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:6] "SPY.Open" "SPY.High" "SPY.Low" "SPY.Close" ...
  Indexed by objects of class: [Date] TZ: UTC
  xts Attributes:  
List of 2
 $ src    : chr "yahoo"
 $ updated: POSIXct[1:1], format: "2020-08-03 18:02:05"
# Assign JNJ data to 'jnj' using env argument
jnj <- getSymbols(Symbols = "JNJ", env = NULL)

# Look at the structure of the 'jnj' object
str(jnj)
An ‘xts’ object on 2000-01-03/2020-07-31 containing:
  Data: num [1:5178, 1:6] 46.6 45.6 44.4 45.2 47.1 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:6] "JNJ.Open" "JNJ.High" "JNJ.Low" "JNJ.Close" ...
  Indexed by objects of class: [Date] TZ: UTC
  xts Attributes:  
List of 2
 $ src    : chr "yahoo"
 $ updated: POSIXct[1:1], format: "2020-08-03 18:02:06"

Turning off auto.assign is useful if you want to assign the data to an object yourself.

1.2 Introduction to Quandl

Similar to how the quantmod package provides getSymbols() to import data from various sources, the Quandl package provides access to the Quandl databases via one simple function: Quandl().

Recall that getSymbols() uses the Symbols and src arguments to specify the instrument and data source, respectively. The Quandl() function specifies both the data source and the instrument via its code argument, in the form “DATABASE/DATASET”.

Two other ways Quandl() differs from getSymbols() are:

  1. Quandl() returns a data.frame by default.
  2. Quandl() will not automatically assign the data to an object.

If you plan on importing a lot of data using Quandl(), you might consider opening a free account with them in order to get an API key.

# Load the Quandl package
library(Quandl)

# Import GDP data from FRED
# gdp <- Quandl(code = "FRED/GDP")

# Look at the structure of the object returned by Quandl
# str(gdp)

Quandl provides access to a large amount of data series. Their website has documentation for it all!

1.2.1 Return data type

The Quandl() function returns a data.frame by default. It can return other classes via the type argument.

The possible values for type are:

  1. “raw” (a data.frame),
  2. “ts” (time-series objects from the stats package),
  3. “zoo”,
  4. “xts”, and
  5. “timeSeries” (from the timeSeries package in the RMetrics suite).

In this exercise, you will learn how to use the type argument to make Quandl() return an xts and a zoo object.

# Import GDP data from FRED as xts
# gdp_xts <- Quandl(code = "FRED/GDP", type = "xts")

# Look at the structure of gdp_xts
# str(gdp_xts)
 
# Import GDP data from FRED as zoo
# gdp_zoo <- Quandl(code = "FRED/GDP", type = "zoo")

# Look at the structure of gdp_zoo
# str(gdp_zoo)

Having the flexibility to return different data types is a great bonus and less work for you!

1.3 Finding data from internet sources

1.3.1 Find stock ticker from Yahoo Finance

You need the instrument identifier to import data from an internet data source. They can often be found on the data source website. In this exercise, you will search Yahoo Finance for the ticker symbol for Pfizer stock.

Note that some sources may not provide data for certain symbols, even if you can see the data displayed on their website in tables and/or charts. getSymbols() will error if the data is not available for download.

# Create an object containing the Pfizer ticker symbol
symbol <- "PFE"

# Use getSymbols to import the data
getSymbols("PFE")
[1] "PFE"
# Look at the first few rows of data
head(PFE)
           PFE.Open PFE.High PFE.Low PFE.Close PFE.Volume PFE.Adjusted
2000-01-03  32.0625   32.375 31.6250   31.8750   12213800     15.85582
2000-01-04  31.2500   31.500 30.0000   30.6875   13481000     15.26512
2000-01-05  30.8750   31.875 30.8125   31.1875   12316500     15.51383
2000-01-06  31.2500   32.750 31.1875   32.3125   10545800     16.07345
2000-01-07  34.0000   34.875 32.3125   34.5000   17041900     17.16160
2000-01-10  35.0000   35.000 34.0625   34.4375    9880200     17.13050

Looking up identifiers online is common when seeking data about a new instrument, so it’s good to get comfortable with the process!

1.3.2 Download exchange rate data from Oanda

Oanda.com provides historical foreign exchange data for many currency pairs. Currency pairs are expressed as two currencies, the “base” and the “quote”, separated by a “/”. For example, the U.S. Dollar to Euro exchange rate would be “USD/EUR”.

Note that getSymbols() will automatically convert “USD/EUR” to a valid name by removing the “/”. For example, getSymbols(“USD/EUR”) would create an object named USDEUR.

Also, Oanda.com only provides 180 days of historical data. getSymbols() will warn and return as much data as possible if you request data from more than 180 days ago. You can use the from and to arguments to set a date range; both should be strings in “%Y-%m-%d” format (e.g. “2016-02-06”).

quantmod::oanda.currencies contains a list of currencies provided by Oanda.com.

# Create a currency_pair object
currency_pair <- "GBP/CAD"

# Load British Pound to Canadian Dollar exchange rate data
getSymbols(currency_pair, src = "oanda")
[1] "GBP/CAD"
# Examine object using str()
str(GBPCAD)
An ‘xts’ object on 2020-02-06/2020-08-02 containing:
  Data: num [1:179, 1] 1.72 1.72 1.71 1.71 1.72 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr "GBP.CAD"
  Indexed by objects of class: [Date] TZ: UTC
  xts Attributes:  
List of 2
 $ src    : chr "oanda"
 $ updated: POSIXct[1:1], format: "2020-08-03 18:02:07"
# Try to load data from 190 days ago
getSymbols(currency_pair, from = Sys.Date() - 190, to = Sys.Date(), src = "oanda")
Oanda only provides historical data for the past 180 days. Symbol: GBP/CAD
[1] "GBP/CAD"

1.3.3 Find and import Unemployment Rate data from FRED

Both getSymbols() and Quandl() provide access to the FRED database. In this exercise, you will find the FRED symbol for the United States civilian unemployment rate. Then you will use the series name to download the data directly from FRED using getSymbols(), and from the Quandl database using Quandl().

Remember that getSymbols() specifies the data source using the src argument and that Quandl() specifies it as part of the Quandl code (i.e. database/series).

# Create a series_name object
series_name <- "UNRATE"

# Load the data using getSymbols
getSymbols(series_name, src = "FRED")
[1] "UNRATE"
# Create a quandl_code object
# quandl_code <- "FRED/UNRATE"

# Load the data using Quandl#
# unemploy_rate <- Quandl(quandl_code)

2 Extracting and transforming data

2.1 Extract one column from one instrument

The quantmod package provides several helper functions to extract specific columns from an object, based on the column name. The Op(), Hi(), Lo(), Cl(), Vo(), and Ad() functions can be used to extract the open, high, low, close, volume, and adjusted close column, respectively.

In this exercise, you will use two of these functions on an xts object named DC. The DC object contains fictitious DataCamp OHLC (open, high, low, close) stock prices created by randomizing some real financial market data. DC is similar to the xts objects created by getSymbols().

While it’s not necessary to complete the exercise, you can learn more about all the extractor functions from help(“OHLC.Transformations”). ## Extracting columns from financial time series

load(file = "DC.RData")
DC <- DC[,c(1,2)]
DC <- to.hourly(DC, indexAt = "startof")
missing values removed from data
library(quantmod)
# Extract the close column
dc_close <- Cl(DC)

# Look at the head of dc_close
head(dc_close)
timezone of object (GMT) is different than current timezone ().
                    DC.Close
2016-01-16 00:00:44    20.84
2016-01-16 01:00:01    20.85
2016-01-16 02:00:00    20.85
2016-01-16 03:02:52    20.85
2016-01-16 04:02:37    20.85
2016-01-16 05:00:00    20.85
# Extract the volume column
dc_volume <- Vo(DC)

# Look at the head of dc_volume
head(dc_volume)
timezone of object (GMT) is different than current timezone ().
                    DC.Volume
2016-01-16 00:00:44       157
2016-01-16 01:00:01       214
2016-01-16 02:00:00       103
2016-01-16 03:02:52       180
2016-01-16 04:02:37       211
2016-01-16 05:00:00        35

2.1.1 Extract multiple columns from one instrument

The quantmod package provides functions to extract a single column, and also has functions to extract specific sets of columns.

Recall OHLC stands for open, high, low, close. Now you can guess which columns the OHLC() and HLC() functions extract. There’s also an OHLCV() function, which adds the volume column.

These functions are helpful when you need to pass a set of columns to another function. For example, you might need to pass the high, low, and close columns (in that order) to a technical indicator function.

# Extract the high, low, and close columns
dc_hlc = HLC(DC)

# Look at the head of dc_hlc
head(dc_hlc)
timezone of object (GMT) is different than current timezone ().
                    DC.High DC.Low DC.Close
2016-01-16 00:00:44   20.85  20.83    20.84
2016-01-16 01:00:01   20.85  20.83    20.85
2016-01-16 02:00:00   20.85  20.84    20.85
2016-01-16 03:02:52   20.85  20.84    20.85
2016-01-16 04:02:37   20.85  20.84    20.85
2016-01-16 05:00:00   20.85  20.84    20.85
# Extract the open, high, low, close, and volume columns
dc_ohlcv = OHLCV(DC)

# Look at the head of dc_ohlcv
head(dc_ohlcv)
timezone of object (GMT) is different than current timezone ().
                    DC.Open DC.High DC.Low DC.Close DC.Volume
2016-01-16 00:00:44   20.84   20.85  20.83    20.84       157
2016-01-16 01:00:01   20.85   20.85  20.83    20.85       214
2016-01-16 02:00:00   20.85   20.85  20.84    20.85       103
2016-01-16 03:02:52   20.85   20.85  20.84    20.85       180
2016-01-16 04:02:37   20.85   20.85  20.84    20.85       211
2016-01-16 05:00:00   20.84   20.85  20.84    20.85        35

2.1.2 Use getPrice to extract other columns

The extractor functions you learned in the previous two exercises do not cover all use cases. Sometimes you might have one object that contains the same price column for multiple instruments. Other times, you might have an object with price data (e.g. bid, ask, trade) that do not have an explicit extractor function.

The getPrice() function in the quantmod package can extract any column by name by using the prefer argument. It can also extract columns for a specific instrument by using the symbol argument, which is useful when an object contains several instruments with the same price type.

You can use regular expressions for both the prefer and symbol arguments, because they are passed to the base::grep() function internally.

# Download CME data for CL and BZ as an xts object
oil_data <- Quandl(code = c("CHRIS/CME_QX7", "CFTC/067653_FO_L_ALL_CR"), type = "xts")

# Look at the column names of the oil_data object
colnames(oil_data)
 [1] "CHRIS.CME_QX7 - Open"                             
 [2] "CHRIS.CME_QX7 - High"                             
 [3] "CHRIS.CME_QX7 - Low"                              
 [4] "CHRIS.CME_QX7 - Last"                             
 [5] "CHRIS.CME_QX7 - Change"                           
 [6] "CHRIS.CME_QX7 - Settle"                           
 [7] "CHRIS.CME_QX7 - Volume"                           
 [8] "CHRIS.CME_QX7 - Previous Day Open Interest"       
 [9] "CFTC.067653_FO_L_ALL_CR - Largest 4 Longs; Gross" 
[10] "CFTC.067653_FO_L_ALL_CR - Largest 4 Shorts; Gross"
[11] "CFTC.067653_FO_L_ALL_CR - Largest 8 Longs; Gross" 
[12] "CFTC.067653_FO_L_ALL_CR - Largest 8 Shorts; Gross"
[13] "CFTC.067653_FO_L_ALL_CR - Largest 4 Longs; Net"   
[14] "CFTC.067653_FO_L_ALL_CR - Largest 4 Shorts; Net"  
[15] "CFTC.067653_FO_L_ALL_CR - Largest 8 Longs; Net"   
[16] "CFTC.067653_FO_L_ALL_CR - Largest 8 Shorts; Net"  
# Extract the Open price for CLH2016
cl_open <- getPrice(oil_data, symbol = "CME_QX7", prefer = "Open$")

# Look at January, 2016 using xts' ISO-8601 subsetting
cl_open["2016-01"]
           CHRIS.CME_QX7 - Open
2016-01-04                39.42
2016-01-05                39.40
2016-01-06                39.40
2016-01-07                40.20
2016-01-08                40.65
2016-01-11                40.70
2016-01-12                40.68
2016-01-13                40.00
2016-01-14                40.00
2016-01-15                40.00
2016-01-19                39.90
2016-01-20                39.90
2016-01-21                39.00
2016-01-22                38.58
2016-01-25                38.55
2016-01-26                39.13
2016-01-27                39.13
2016-01-28                38.47
2016-01-29                38.47

getPrice() is a very flexible way to retrieve the columns you need.

2.2 Importing and transforming multiple instruments

2.2.1 Use Quandl to download weekly returns data

Sometimes you need to aggregate and/or transform raw data before you can continue your analysis. The Quandl() function allows you to specify common aggregations and transformations via the collapse and/or transform arguments. The Quandl API takes care of the details for you.

# Download quarterly CL and BZ prices
qtr_price <- Quandl(code = c("CHRIS/CME_QM1", "CHRIS/CME_QG1"), collapse = "quarterly",type = "xts")

# View the high prices for both series
Hi(qtr_price)
        CHRIS.CME_QM1 - High CHRIS.CME_QG1 - High
2014 Q1              101.950                4.485
2014 Q2              105.800                4.490
2014 Q3               94.925                4.175
2014 Q4               56.600                3.145
2015 Q1               48.750                2.685
2015 Q2               59.700                2.840
2015 Q3               45.850                2.610
2015 Q4               37.775                2.375
2016 Q1               39.025                2.030
2016 Q2               49.600                2.940
2016 Q3               48.300                2.975
2016 Q4               54.100                3.850
2017 Q1               50.850                3.245
2017 Q2               46.375                3.055
2017 Q3               51.775                3.040
2017 Q4               60.500                3.010
2018 Q1               65.275                2.765
2018 Q2               74.475                2.955
2018 Q3               73.725                3.060
2018 Q4               46.525                3.145
2019 Q1               60.725                2.725
2019 Q2               59.800                2.365
2019 Q3               56.600                2.395
2019 Q4               61.900                2.205
2020 Q1               21.875                1.730
2020 Q2               40.100                1.780
2020 Q3               40.550                1.860
# Download quarterly CL and BZ returns
qtr_return <- Quandl(code = c("CHRIS/CME_QM1", "CHRIS/CME_QG1"), collapse = "quarterly",transform = "rdiff", type = "xts")

# View the settle price returns for both series
getPrice(qtr_return, prefer = "Settle")
        CHRIS.CME_QM1 - Settle CHRIS.CME_QG1 - Settle
2014 Q2            0.037310494            0.020590254
2014 Q3           -0.134858119           -0.076216095
2014 Q4           -0.399627029           -0.264013589
2015 Q1           -0.130275900           -0.129574679
2015 Q2            0.249369748            0.072727273
2015 Q3           -0.241802590           -0.108757062
2015 Q4           -0.178531825           -0.074088748
2016 Q1            0.035097192           -0.161745828
2016 Q2            0.260563380            0.492598264
2016 Q3           -0.001862197           -0.006155951
2016 Q4            0.113598673            0.281486579
2017 Q1           -0.058078928           -0.143394200
2017 Q2           -0.090118577           -0.048589342
2017 Q3            0.122284970           -0.009225700
2017 Q4            0.169343913           -0.017958098
2018 Q1            0.074809666           -0.074500508
2018 Q2            0.141823221            0.069886572
2018 Q3           -0.012137559            0.028727770
2018 Q4           -0.380068259           -0.022606383
2019 Q1            0.324377890           -0.094557823
2019 Q2           -0.027768540           -0.132982720
2019 Q3           -0.075252266            0.009532062
2019 Q4            0.129276863           -0.060515021
2020 Q1           -0.664592204           -0.250799452
2020 Q2            0.917480469            0.067682927
2020 Q3            0.025464731            0.027412907

2.2.2 Combine many instruments into one object

What if you need to aggregate or transform your data in ways Quandl() does not support? In those cases, you can use the flexibility of R.

One paradigm involves importing data into a new environment. Then you can use eapply() to call a function on each object in the environment, much like what lapply() does for each element of a list. Also like lapply(), eapply() returns a list.

Then you can merge all the elements of the list into one object by using do.call(), which is like having R programmatically type and run a command for you. Instead of typing merge(my_list[[1]], my_list[[2]]], …), you can type do.call(merge, my_list).

# Create new environment
data_env <- new.env()
# Use getSymbols to load data into the environment
getSymbols(c("SPY", "QQQ"), env = data_env, auto.assign = TRUE)
[1] "SPY" "QQQ"
# Look at a few rows of the SPY data
head(data_env$SPY, 3)
           SPY.Open SPY.High  SPY.Low SPY.Close SPY.Volume SPY.Adjusted
2000-01-03 148.2500 148.2500 143.8750  145.4375    8164300     98.95903
2000-01-04 143.5312 144.0625 139.6406  139.7500    8089800     95.08910
2000-01-05 139.9375 141.5312 137.2500  140.0000   12177900     95.25919
# Look at a few rows of the SPY data
eapply(data_env, head)
$QQQ
           QQQ.Open QQQ.High QQQ.Low QQQ.Close QQQ.Volume QQQ.Adjusted
2000-01-03  96.1875  96.1875 90.7500  94.75000   36345200     82.61639
2000-01-04  92.0000  93.5000 87.9375  88.25000   33786600     76.94878
2000-01-05  87.5000  89.6250 84.2500  86.00000   42496600     74.98690
2000-01-06  86.8750  88.0000 79.7500  80.09375   37134800     69.83700
2000-01-07  82.9375  90.0000 82.5000  90.00000   28138200     78.47465
2000-01-10  91.0000  93.9375 89.9375  92.50000   29675600     80.65449

$SPY
           SPY.Open SPY.High  SPY.Low SPY.Close SPY.Volume SPY.Adjusted
2000-01-03 148.2500 148.2500 143.8750  145.4375    8164300     98.95903
2000-01-04 143.5312 144.0625 139.6406  139.7500    8089800     95.08910
2000-01-05 139.9375 141.5312 137.2500  140.0000   12177900     95.25919
2000-01-06 139.6250 141.5000 137.7500  137.7500    6227200     93.72825
2000-01-07 140.3125 145.7500 140.0625  145.7500    8066500     99.17164
2000-01-10 146.2500 146.9062 145.0312  146.2500    5741700     99.51184
# Call head on each object in data_env using eapply
data_list <- eapply(data_env, head)

# Merge all the list elements into one xts object
data_merged <- do.call(merge, data_list)

# Ensure the columns are ordered: open, high, low, close
data_ohlc <- OHLC(data_merged)
data_ohlc
           QQQ.Open SPY.Open QQQ.High SPY.High QQQ.Low  SPY.Low QQQ.Close
2000-01-03  96.1875 148.2500  96.1875 148.2500 90.7500 143.8750  94.75000
2000-01-04  92.0000 143.5312  93.5000 144.0625 87.9375 139.6406  88.25000
2000-01-05  87.5000 139.9375  89.6250 141.5312 84.2500 137.2500  86.00000
2000-01-06  86.8750 139.6250  88.0000 141.5000 79.7500 137.7500  80.09375
2000-01-07  82.9375 140.3125  90.0000 145.7500 82.5000 140.0625  90.00000
2000-01-10  91.0000 146.2500  93.9375 146.9062 89.9375 145.0312  92.50000
           SPY.Close
2000-01-03  145.4375
2000-01-04  139.7500
2000-01-05  140.0000
2000-01-06  137.7500
2000-01-07  145.7500
2000-01-10  146.2500
# Extract volume column from each object
adjusted_list <- lapply(data_env, Ad)
# Merge each list element into one object
adjusted <- do.call(merge, adjusted_list)
head(adjusted)
           QQQ.Adjusted SPY.Adjusted
2000-01-03     82.61639     98.95903
2000-01-04     76.94878     95.08910
2000-01-05     74.98690     95.25919
2000-01-06     69.83700     93.72825
2000-01-07     78.47465     99.17164
2000-01-10     80.65449     99.51184

2.2.3 Extract the Close column from many instruments

The previous exercise taught you how to use do.call(merge, eapply(env, fun)) to apply a function to each object in an environment and then combine all the results into one object.

Let’s use what you learned to solve a very common problem. Often you will need to load similar data for many instruments, extract a column, and create one object that contains that specific column for every instrument.

# Symbols
symbols <- c("AAPL", "MSFT", "IBM")

# Create new environment
data_env <- new.env()

# Load symbols into data_env
getSymbols(symbols, env = data_env)
[1] "AAPL" "MSFT" "IBM" 
# Extract the close column from each object and combine into one xts object
close_data <- do.call(merge, eapply(data_env, Cl))

# View the head of close_data
head(close_data)
           AAPL.Close IBM.Close MSFT.Close
2000-01-03   3.997768  116.0000   58.28125
2000-01-04   3.660714  112.0625   56.31250
2000-01-05   3.714286  116.0000   56.90625
2000-01-06   3.392857  114.0000   55.00000
2000-01-07   3.553571  113.5000   55.71875
2000-01-10   3.491071  118.0000   56.12500

3 Managing data from multiple sources

3.1 Setting default arguments for getSymbols()

3.1.1 Set a default data source

Recall that getSymbols() imports from Yahoo Finance by default. This exercise will teach you how to change the default data source with the setDefaults() function.

The first argument to setDefaults() is the function you want to update, and the remaining arguments are name = value pairs of the arguments you want to update and the new default value.

Note that this only works with getSymbols() because getSymbols() actively checks to see if you want to use a different default value.

# Set the default to pull data from Alpha Vantage
setDefaults(getSymbols, src = "av")

# Get GOOG data
# getSymbols("GOOG")

# Verify the data was actually pulled from Alpha Vantage
# str(GOOG)

Setting a default source can be useful if you use that source often.

3.1.2 Set default arguments for a getSymbols source

You can also use setDefaults() on individual getSymbols() source methods. This exercise will teach you how to change the default value for the from argument to getSymbols.yahoo().

You can find the arguments for a specific method by using help() (e.g. help(“getSymbols.yahoo”) or by calling args() to print them to the console (e.g. args(getSymbols.yahoo)). Calling getDefaults() will show you the current default values (if there are any).

Remember, you are not supposed to call getSymbols.yahoo() directly!

# Look at getSymbols.yahoo arguments
args(getSymbols.yahoo)
function (Symbols, env, return.class = "xts", index.class = "Date", 
    from = "2007-01-01", to = Sys.Date(), ..., periodicity = "daily", 
    curl.options = list()) 
NULL
# Set default 'from' value for getSymbols.yahoo
setDefaults(getSymbols.yahoo, from = "2000-01-01")

# Confirm defaults were set correctly
getDefaults("getSymbols.yahoo")
$from
[1] "'2000-01-01'"

3.2 Setting per-instrument default arguments

3.2.1 Set default data source for one symbol

Changing the default source for one instrument is useful if multiple sources use the same symbol for different instruments. For example, getSymbols(“CP”, src = “yahoo”) would load Canadian Pacific Railway data from the New York Stock Exchange. But getSymbols(“CP”, src = “FRED”) would load Corporate Profits After Tax from the U.S. Bureau of Economic Analysis.

You can use setSymbolLookup() to specify the default data source for an instrument. In this exercise, you will learn how to make getSymbols(“CP”) load the corporate profit data from FRED instead of the railway stock data from Yahoo Finance.

setSymbolLookup() can take any number of name = value pairs, where name is the symbol and value is a named list of getSymbols() arguments for that one symbol.

setDefaults(getSymbols, src = "yahoo")
setSymbolLookup("CP" = "yahoo")
# Load CP data again
getSymbols("CP")
[1] "CP"
# Look at the first few rows of CP
head(CP)
            CP.Open  CP.High   CP.Low CP.Close CP.Volume CP.Adjusted
2000-01-03 10.84375 10.90625 10.40625 10.43750    358200    7.454829
2000-01-04 10.34375 10.87500 10.34375 10.50000   1160200    7.499471
2000-01-05 10.50000 10.87500 10.50000 10.78125    852200    7.700349
2000-01-06 10.96875 11.46875 10.90625 11.31250   1960400    8.079788
2000-01-07 11.37500 11.62500 11.18750 11.50000   1758800    8.213708
2000-01-10 11.53125 11.68750 11.21875 11.59375   1273600    8.280663
setSymbolLookup("CP" = NULL)

# Set the source for CP to FRED
setSymbolLookup("CP" = "FRED")

# Load CP data again
getSymbols("CP")
[1] "CP"
# Look at the first few rows of CP
head(CP)
            CP.Open  CP.High   CP.Low CP.Close CP.Volume CP.Adjusted
2000-01-03 10.84375 10.90625 10.40625 10.43750    358200    7.454829
2000-01-04 10.34375 10.87500 10.34375 10.50000   1160200    7.499471
2000-01-05 10.50000 10.87500 10.50000 10.78125    852200    7.700349
2000-01-06 10.96875 11.46875 10.90625 11.31250   1960400    8.079788
2000-01-07 11.37500 11.62500 11.18750 11.50000   1758800    8.213708
2000-01-10 11.53125 11.68750 11.21875 11.59375   1273600    8.280663

Occasionally this happens, and it is useful to set a single symbol to be pulled from a specific source.

3.2.2 Save and load symbol lookup table

The previous exercise taught you how to set default arguments on a per-symbol basis, but those settings only last for the current session.

This exercise will teach you how to save and load symbol-based defaults by using saveSymbolLookup() and loadSymbolLookup(), respectively. You can use the file arguments to specify a file to store your defaults.

You can also use the getSymbolLookup() function to check per-symbol defaults before you try to load data using getSymbols().

# Save symbol lookup table
saveSymbolLookup("my_symbol_lookup.rda")

# Set default source for CP to "yahoo"
setSymbolLookup("CP" = "yahoo")

# Verify the default source is "yahoo"
getSymbolLookup("CP")
$CP
$CP$src
[1] "yahoo"
# Load symbol lookup table
loadSymbolLookup("my_symbol_lookup.rda")
getSymbolLookup("CP")
$CP
$CP$src
[1] "FRED"

This will let you load the same lookup table even if you close out of R.

3.3 Handling instrument symbols that clash or are not valid R names

3.3.1 Access the object using get() or backticks

At some point, you might download data for an instrument that does not have a syntactically valid name. Syntactically valid names contain letters, numbers, “.”, and "_“, and must start with a letter or a”." followed by a non-number.

For example, the symbol for Berkshire Hathaway class A shares is “BRK-A”, which is not a syntactically valid name because it contains a “-” character. Another example are Chinese stocks, which have symbols composed of numbers. The Yahoo Finance symbol for the SSE Composite Index is “000001.SS”.

You can use the get function or backticks (`) to access objects that do not have syntactically valid names.

# Load BRK-A data
getSymbols("BRK-A")
[1] "BRK-A"
# Use backticks and head() to look at the loaded data
head(`BRK-A`)
           BRK-A.Open BRK-A.High BRK-A.Low BRK-A.Close BRK-A.Volume
2000-01-03      56100      56100     53800       54800        36000
2000-01-04      53700      53800     52000       52000        44000
2000-01-05      51700      54700     51700       53200        51000
2000-01-06      53300      55000     53100       55000        57000
2000-01-07      55600      56500     55200       56500        67000
2000-01-10      57300      58000     56000       56000        31000
           BRK-A.Adjusted
2000-01-03          54800
2000-01-04          52000
2000-01-05          53200
2000-01-06          55000
2000-01-07          56500
2000-01-10          56000
# Use get() to assign the BRK-A data to an object named BRK.A
BRK.A <- get("BRK-A")

Just remember to use backticks or get() if you ever run into invalid characters.

3.3.2 Create valid name for one instrument

If you are only downloading data for a single symbol and that symbol is not a syntactically valid name, you can set auto.assign = FALSE in your call to getSymbols(). That will allow you to directly assign the output to a syntactically valid name.

You may also want to convert the column names to syntactically valid names. That is a good idea if you plan to use the data in functions that expect column names to be syntactically valid names (e.g. lm()).

# Create BRK.A object
BRK.A <- getSymbols("BRK-A", auto.assign = FALSE)

# Create col_names object with the column names of BRK.A
col_names <- colnames(BRK.A)

# Set BRK.A column names to syntactically valid names
colnames(BRK.A) <- make.names(col_names)

Now you can fix tricky ticker symbols in the column names of your data.

3.3.3 Create valid names for multiple instruments

An earlier exercise taught you how to use setSymbolLookup() to set a default data source for getSymbols(). You can also use setSymbolLookup() to create a mapping between the instrument symbol and the name of the R object.

This is useful if you want to download data for a lot symbols that are not syntactically valid names, or symbols that have names that conflict with other R variable names.

An example of a name that conflicts is the symbol for AT&T’s stock, T, which is often used as a short form for the logical value TRUE.

To change the name of a given symbol, arguments must be passed to setSymbolLookup() as a list, like so: setSymbolLookup(NEW_NAME = list(name = “OLD_NAME”)).

# Set name for BRK-A to BRK.A
setSymbolLookup(BRK.A = list(name = "BRK-A"))

# Set name for T (AT&T) to ATT
setSymbolLookup(ATT = list(name = "T"))

# Load BRK.A and ATT data
getSymbols(c("BRK.A", "ATT"))
[1] "BRK.A" "ATT"  

Now you can map troublesome tickers to new names with setSymbolLookup().

4 Aligning data with different periodicities

4.1 Making irregular data regular

4.1.1 Create a zero-width and regular xts object

In order to create regular data from an irregular data set, the first thing you need is a regular sequence of date-times that span the dates of your irregular data set. A “regular” sequence of date-times has equally-spaced time points.

In this exercise, you will use the irregular_xts object to create a zero-width xts object that has a regular daily index. A zero-width xts object has an index of date-times, but no data columns.

# Extract the start date of the series
start_date <- start(irregular_xts)

# Extract the end date of the series
end_date <- end(irregular_xts)

# Create a regular date sequence
regular_index <- seq(from = start_date, to = end_date, by = "day")

# Create a zero-width xts object
regular_xts <- xts(seq_along(regular_index), order.by = regular_index)
regular_xts
           [,1]
2016-01-02    1
2016-01-03    2
2016-01-04    3
2016-01-05    4
2016-01-06    5
2016-01-07    6
2016-01-08    7
2016-01-09    8
2016-01-10    9
2016-01-11   10

Making regular date-time sequences is useful in many time-series applications.

4.1.2 Use merge to make an irregular index regular

The previous exercise taught you how to make a zero-width xts object with a regular time index. You can use the zero-width object to regularize an irregular xts object.

The regularized series usually has missing values (NA) because the irregular data does not have a value for all observations in the regular index. This exercise will teach you how to handle these missing values when you merge() the two series.

# Merge irregular_xts and regular_xts
merged_xts <- merge(irregular_xts, regular_xts)

# Look at the first few rows of merged_xts
head(merged_xts)
           data regular_xts
2016-01-02    4           1
2016-01-03   NA           2
2016-01-04   NA           3
2016-01-05   21           4
2016-01-06   NA           5
2016-01-07    1           6
# Use the fill argument to fill NA with their previous value
merged_filled_xts <- merge(irregular_xts, regular_xts, fill = na.locf)

# Look at the first few rows of merged_filled_xts
head(merged_filled_xts)
           data regular_xts
2016-01-02    4           1
2016-01-03    4           2
2016-01-04    4           3
2016-01-05   21           4
2016-01-06   21           5
2016-01-07    1           6

Filling forward is a useful operation, but be careful to make sure it is what you want!

4.2 Aggregating to lower frequency

4.2.1 Aggregate daily data and merge with monthly data

Sometimes two series have the same periodicy, but use different conventions to represent a timestamp. For example, monthly series may be timestamped with the first or last date of the month. The different timestamp convention can cause many NA when series are merged. The yearmon class from the zoo package helps solve this problem.

In this exercise, you will aggregate the FRED daily Fed Funds rate (DFF) to a monthly periodicy and merge it with the FRED monthly Fed Funds rate (FEDFUNDS).The DFF aggregate will be timestamped with the last row of the month, while FEDFUNDS is timestamped with the first day of the month.

getSymbols(c("FEDFUNDS", "DFF"), src = "FRED")
[1] "FEDFUNDS" "DFF"     
# Aggregate DFF to monthly
monthly_fedfunds <- apply.monthly(DFF, mean, na.rm = TRUE)

# Convert index to yearmon
index(monthly_fedfunds) <- as.yearmon(index(monthly_fedfunds))

# Merge FEDFUNDS with the monthly aggregate
merged_fedfunds <- merge(FEDFUNDS, monthly_fedfunds)

# Look at the first few rows of the merged object
head(merged_fedfunds)
           FEDFUNDS       DFF
1954-07-01     0.80 0.7993548
1954-08-01     1.22 1.2206452
1954-09-01     1.07 1.0666667
1954-10-01     0.85 0.8487097
1954-11-01     0.83 0.8336667
1954-12-01     1.28 1.2777419

You will often need to aggregate to a lower frequency to align multiple time series.

4.2.2 Align series to first and last day of month

Sometimes you may not be able to use convenience classes like yearmon to represent timestamps. This exercise will teach you how to manually align merged data to the timestamp representation you prefer.

First you merge the lower-frequency data with the aggregate data, then use na.locf() to fill the NA forward (or backward, using fromLast = TRUE). Then you can subset the result using the index of the object with the representation you prefer.

# Aggregate DFF to monthly
monthly_fedfunds <- apply.monthly(DFF, mean, na.rm = TRUE)

# Merge FEDFUNDS with the monthly aggregate
merged_fedfunds <- merge(FEDFUNDS, monthly_fedfunds)

# Look at the first few rows of the merged object
head(merged_fedfunds)
           FEDFUNDS       DFF
1954-07-01     0.80        NA
1954-07-31       NA 0.7993548
1954-08-01     1.22        NA
1954-08-31       NA 1.2206452
1954-09-01     1.07        NA
1954-09-30       NA 1.0666667
# Fill NA forward
merged_fedfunds_locf <- na.locf(merged_fedfunds)

# Extract index values containing last day of month
aligned_last_day <- merged_fedfunds_locf[index(monthly_fedfunds)]
head(aligned_last_day)
           FEDFUNDS       DFF
1954-07-31     0.80 0.7993548
1954-08-31     1.22 1.2206452
1954-09-30     1.07 1.0666667
1954-10-31     0.85 0.8487097
1954-11-30     0.83 0.8336667
1954-12-31     1.28 1.2777419
# Fill NA backward
merged_fedfunds_locb <- na.locf(merged_fedfunds, fromLast = TRUE)

# Extract index values containing first day of month
aligned_first_day <- merged_fedfunds_locb[index(FEDFUNDS)]
head(aligned_first_day)
           FEDFUNDS       DFF
1954-07-01     0.80 0.7993548
1954-08-01     1.22 1.2206452
1954-09-01     1.07 1.0666667
1954-10-01     0.85 0.8487097
1954-11-01     0.83 0.8336667
1954-12-01     1.28 1.2777419

Knowing how to manually align merged data will definitely come in handy!

4.2.3 Aggregate to weekly, ending on Wednesdays

In this exercise, you will learn a general aggregation technique to aggregate daily data to weekly, but with weeks ending on Wednesdays. This is often done in stock market research to avoid intra-week seasonality.

You can supply your own end points to period.apply() (versus using endpoints()). Recall endpoints() returns locations of the last observation in each period specified by the on argument. The first and last elements of the result are always zero and the total number of observations, respectively. The end points you pass to period.apply() must follow this convention.

# Extract index weekdays
index_weekdays <- .indexwday(DFF)

# Find locations of Wednesdays
wednesdays <- which(index_weekdays == 3)

# Create custom end points
end_points <- c(0, wednesdays, nrow(DFF))

# Calculate weekly mean using custom end points
weekly_mean <- period.apply(DFF, end_points, mean)
head(weekly_mean)
timezone of object (UTC) is different than current timezone ().
                 DFF
1954-07-07 1.0014286
1954-07-14 1.2157143
1954-07-21 0.5714286
1954-07-28 0.6257143
1954-08-04 0.2700000
1954-08-11 1.3071429

There are many ways to convert a time series to a lower frequency.

4.3 Aggregating and combining intraday data

4.3.1 Combine data that have timezones

Recall that xts objects store the time index as seconds since midnight, 1970-01-01 in the UTC timezone. merge() uses this underlying index and returns a result with the first object’s timezone.

This exercise provides an example. The two objects in your workspace are identical except for the index timezone. The index values are the same instances in time, but measured in different locations. The london object’s timezone is Europe/London and the chicago object’s timezone is America/Chicago.

# Create merged object with a Europe/London timezone
tz_london <- merge(london, chicago)

# Look at tz_london structure
str(tz_london)
An ‘xts’ object on 2010-01-06 06:00:00/2010-01-14 08:00:00 containing:
  Data: int [1:5, 1:2] 1 2 3 4 5 1 2 3 4 5
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:2] "London" "Chicago"
  Indexed by objects of class: [POSIXct,POSIXt] TZ: Europe/London
  xts Attributes:  
 NULL
# Create merged object with a America/Chicago timezone
tz_chicago <- merge(chicago, london)

# Look at tz_chicago structure
str(tz_chicago)
An ‘xts’ object on 2010-01-06/2010-01-14 02:00:00 containing:
  Data: int [1:5, 1:2] 1 2 3 4 5 1 2 3 4 5
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:2] "Chicago" "London"
  Indexed by objects of class: [POSIXct,POSIXt] TZ: America/Chicago
  xts Attributes:  
 NULL

4.3.2 Make irregular intraday-day data regular

Earlier you learned how to create a regular daily series from irregular daily data. Now you will create regular intra-day data from an irregular series.

Intra-day financial data often does not span a full 24 hour period. Most markets are usually closed at least part of the day. This exercise assumes markets open at 9AM and close at 4PM Monday-Friday.

Your data may not have an observation exactly at the market open and/or close. So, you would not be able to use start() and end() as you could with the daily data. You need to specify the start and end date-times to create this regular sequence.

The regular date-time sequence will include periods when markets are closed, but you can use xts’ time-of-day subsetting to extract periods the market is open.

# Create a regular date-time sequence
regular_index <- seq(as.POSIXct("2010-01-04 09:00"), as.POSIXct("2010-01-08 16:00"), by = "30 min")

# Create a zero-width xts object
regular_xts <- xts(x = NULL, order.by = regular_index)

# Merge irregular_xts and regular_xts, filling NA with their previous value
merged_xts <- merge(irregular_xts, regular_xts, fill = na.locf)

# Subset to trading day (9AM - 4PM)
trade_day <- merged_xts["T09:00/T16:00"]
'indexTZ' is deprecated.
Use 'tzone' instead.
See help("Deprecated") and help("xts-deprecated").
trade_day
                    data
2010-01-04 09:00:00   NA
2010-01-04 09:30:00   NA
2010-01-04 10:00:00   NA
2010-01-04 10:30:00   NA
2010-01-04 11:00:00   NA
2010-01-04 11:30:00   NA
2010-01-04 12:00:00    1
2010-01-04 12:30:00    1
2010-01-04 13:00:00    1
2010-01-04 13:30:00    1
2010-01-04 14:00:00    2
2010-01-04 14:30:00    2
2010-01-04 15:00:00    2
2010-01-04 15:30:00    2
2010-01-04 16:00:00    2
2010-01-05 09:00:00    7
2010-01-05 09:30:00    7
2010-01-05 10:00:00    7
2010-01-05 10:30:00    7
2010-01-05 11:00:00    8
2010-01-05 11:30:00    8
2010-01-05 12:00:00    8
2010-01-05 12:30:00    8
2010-01-05 13:00:00    8
2010-01-05 13:30:00    8
2010-01-05 14:00:00    8
2010-01-05 14:30:00    8
2010-01-05 15:00:00    8
2010-01-05 15:30:00    8
2010-01-05 16:00:00    8
2010-01-06 09:00:00   10
2010-01-06 09:30:00   10
2010-01-06 10:00:00   10
2010-01-06 10:30:00   10
2010-01-06 11:00:00   10
2010-01-06 11:30:00   10
2010-01-06 12:00:00   10
2010-01-06 12:30:00   10
2010-01-06 13:00:00   10
2010-01-06 13:30:00   10
2010-01-06 14:00:00   11
2010-01-06 14:30:00   11
2010-01-06 15:00:00   11
2010-01-06 15:30:00   11
2010-01-06 16:00:00   11
2010-01-07 09:00:00   14
2010-01-07 09:30:00   14
2010-01-07 10:00:00   14
2010-01-07 10:30:00   14
2010-01-07 11:00:00   14
2010-01-07 11:30:00   14
2010-01-07 12:00:00   14
2010-01-07 12:30:00   14
2010-01-07 13:00:00   14
2010-01-07 13:30:00   14
2010-01-07 14:00:00   14
2010-01-07 14:30:00   14
2010-01-07 15:00:00   14
2010-01-07 15:30:00   14
2010-01-07 16:00:00   14
2010-01-08 09:00:00   20
2010-01-08 09:30:00   20
2010-01-08 10:00:00   20
2010-01-08 10:30:00   20
2010-01-08 11:00:00   20
2010-01-08 11:30:00   20
2010-01-08 12:00:00   20
2010-01-08 12:30:00   20
2010-01-08 13:00:00   20
2010-01-08 13:30:00   20
2010-01-08 14:00:00   20
2010-01-08 14:30:00   20
2010-01-08 15:00:00   20
2010-01-08 15:30:00   20
2010-01-08 16:00:00   20

Now you know how to subset your intra-day data to only contain the trading day!

4.3.3 Fill missing values by trading day

The previous exercise carried the last observation of the prior day forward into the first observation of the following day. This exercise will show you how to fill missing values by trading day, without using the prior day’s final value.

You will use the same split-lapply-rbind paradigm from the Introduction to xts and zoo course. For reference, the pattern is below.

x_split <- split(x, f = "months")
x_list <- lapply(x_split, cummax)
x_list_rbind <- do.call(rbind, x_list)

Recall that the do.call(rbind, …) syntax allows you to pass a list of objects to rbind() instead of having to type all their names.

# Split trade_day into days
daily_list <- split(trade_day , f = "days")

# Use lapply to call na.locf for each day in daily_list
daily_filled <- lapply(daily_list, FUN = na.locf)

# Use do.call to rbind the results
filled_by_trade_day <- do.call(rbind, daily_filled)
filled_by_trade_day
                    data
2010-01-04 09:00:00   NA
2010-01-04 09:30:00   NA
2010-01-04 10:00:00   NA
2010-01-04 10:30:00   NA
2010-01-04 11:00:00   NA
2010-01-04 11:30:00   NA
2010-01-04 12:00:00    1
2010-01-04 12:30:00    1
2010-01-04 13:00:00    1
2010-01-04 13:30:00    1
2010-01-04 14:00:00    2
2010-01-04 14:30:00    2
2010-01-04 15:00:00    2
2010-01-04 15:30:00    2
2010-01-04 16:00:00    2
2010-01-05 09:00:00    7
2010-01-05 09:30:00    7
2010-01-05 10:00:00    7
2010-01-05 10:30:00    7
2010-01-05 11:00:00    8
2010-01-05 11:30:00    8
2010-01-05 12:00:00    8
2010-01-05 12:30:00    8
2010-01-05 13:00:00    8
2010-01-05 13:30:00    8
2010-01-05 14:00:00    8
2010-01-05 14:30:00    8
2010-01-05 15:00:00    8
2010-01-05 15:30:00    8
2010-01-05 16:00:00    8
2010-01-06 09:00:00   NA
2010-01-06 09:30:00   NA
2010-01-06 10:00:00   NA
2010-01-06 10:30:00   NA
2010-01-06 11:00:00   NA
2010-01-06 11:30:00   NA
2010-01-06 12:00:00   NA
2010-01-06 12:30:00   NA
2010-01-06 13:00:00   NA
2010-01-06 13:30:00   NA
2010-01-06 14:00:00   11
2010-01-06 14:30:00   11
2010-01-06 15:00:00   11
2010-01-06 15:30:00   11
2010-01-06 16:00:00   11
2010-01-07 09:00:00   NA
2010-01-07 09:30:00   NA
2010-01-07 10:00:00   NA
2010-01-07 10:30:00   NA
2010-01-07 11:00:00   NA
2010-01-07 11:30:00   NA
2010-01-07 12:00:00   NA
2010-01-07 12:30:00   NA
2010-01-07 13:00:00   NA
2010-01-07 13:30:00   NA
2010-01-07 14:00:00   NA
2010-01-07 14:30:00   NA
2010-01-07 15:00:00   NA
2010-01-07 15:30:00   NA
2010-01-07 16:00:00   NA
2010-01-08 09:00:00   NA
2010-01-08 09:30:00   NA
2010-01-08 10:00:00   NA
2010-01-08 10:30:00   NA
2010-01-08 11:00:00   NA
2010-01-08 11:30:00   NA
2010-01-08 12:00:00   NA
2010-01-08 12:30:00   NA
2010-01-08 13:00:00   NA
2010-01-08 13:30:00   NA
2010-01-08 14:00:00   NA
2010-01-08 14:30:00   NA
2010-01-08 15:00:00   NA
2010-01-08 15:30:00   NA
2010-01-08 16:00:00   NA

You used advanced functions to transform data for each trading day!

4.3.4 Aggregate irregular intraday-day data

Intraday data can be huge, with hundreds of thousands of observations per day, millions per month, and hundreds of millions per year. These data sets often need to be aggregated before you can work with them.

You learned how to aggregate daily data in the Introduction to xts and zoo course. This exercise will use to.period() to aggregate intraday data to an OHLC series. You often need to specify both period and k arguments to aggregate intraday data.

load("DC.RData")

dc_intraday <- DC[,1]
# Convert raw prices to 5-second prices
xts_5sec <- to.period(dc_intraday, period = "seconds", k = 5)
missing values removed from data
head(xts_5sec)
timezone of object (GMT) is different than current timezone ().
                    dc_intraday.Open dc_intraday.High dc_intraday.Low
2016-01-16 00:00:44            20.84            20.84           20.84
2016-01-16 00:01:53            20.84            20.84           20.84
2016-01-16 00:01:58            20.84            20.84           20.84
2016-01-16 00:02:06            20.84            20.84           20.84
2016-01-16 00:03:05            20.84            20.84           20.84
2016-01-16 00:03:33            20.84            20.84           20.84
                    dc_intraday.Close
2016-01-16 00:00:44             20.84
2016-01-16 00:01:53             20.84
2016-01-16 00:01:58             20.84
2016-01-16 00:02:06             20.84
2016-01-16 00:03:05             20.84
2016-01-16 00:03:33             20.84
# Convert raw prices to 10-minute prices
xts_10min <- to.period(dc_intraday, period = "minutes", k = 10)
missing values removed from data
head(xts_10min)
timezone of object (GMT) is different than current timezone ().
                    dc_intraday.Open dc_intraday.High dc_intraday.Low
2016-01-16 00:08:21            20.84            20.84           20.84
2016-01-16 00:19:03            20.84            20.84           20.84
2016-01-16 00:25:48            20.84            20.84           20.83
2016-01-16 00:38:33            20.85            20.85           20.84
2016-01-16 00:48:02            20.84            20.84           20.84
2016-01-16 00:57:34            20.85            20.85           20.84
                    dc_intraday.Close
2016-01-16 00:08:21             20.84
2016-01-16 00:19:03             20.84
2016-01-16 00:25:48             20.84
2016-01-16 00:38:33             20.84
2016-01-16 00:48:02             20.84
2016-01-16 00:57:34             20.84
# Convert raw prices to 1-hour prices
xts_1hour <- to.period(dc_intraday, period = "hours", k = 1)
missing values removed from data
head(xts_1hour)
timezone of object (GMT) is different than current timezone ().
                    dc_intraday.Open dc_intraday.High dc_intraday.Low
2016-01-16 00:57:34            20.84            20.85           20.83
2016-01-16 01:58:28            20.85            20.85           20.83
2016-01-16 02:59:39            20.85            20.85           20.84
2016-01-16 03:54:31            20.85            20.85           20.84
2016-01-16 04:59:58            20.85            20.85           20.84
2016-01-16 05:58:43            20.84            20.85           20.84
                    dc_intraday.Close
2016-01-16 00:57:34             20.84
2016-01-16 01:58:28             20.85
2016-01-16 02:59:39             20.85
2016-01-16 03:54:31             20.85
2016-01-16 04:59:58             20.85
2016-01-16 05:58:43             20.85

5 Importing text data, and adjusting for corporate actions

5.1 Importing text files

5.1.1 Import well-formatted daily OHLC data

You can use getSymbols() to import a well-formatted CSV. In this case, well-formatted means the file contains data for a single instrument with date, open, high, low, close, volume, and adjusted close columns, in that order. You might have noticed that this is the same format as getSymbols() returns when you download data from internet sources.

getSymbols() allows you to use a directory of CSV files as a source (like Yahoo Finance and FRED). In this exercise, you will be using AMZN.csv in your working directory. It contains some randomized Amazon.com data from the first half of 2002. You can use dir() to see the file in your working directory.

# Load AMZN.csv
getSymbols("AMZN", src = "csv")
[1] "AMZN"
# Look at AMZN structure
str(AMZN)
An ‘xts’ object on 2002-01-02/2002-06-28 containing:
  Data: num [1:124, 1:6] 11.1 11.3 12.5 11.8 12.8 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:6] "AMZN.Open" "AMZN.High" "AMZN.Low" "AMZN.Close" ...
  Indexed by objects of class: [Date] TZ: UTC
  xts Attributes:  
List of 2
 $ src    : chr "csv"
 $ updated: POSIXct[1:1], format: "2020-08-03 18:02:15"

5.1.2 Import text files in other formats

The previous exercise taught you how to import well-formatted CSV data using getSymbols(). Unfortunately, most data are not well-formatted.

The zoo package provides several functions to import text files as zoo objects. The main function is read.zoo(), which wraps read.table(). The xts class extends zoo, so you can easily convert the result of read.zoo() into an xts object by using as.xts().

# Import AMZN.csv using read.zoo
amzn_zoo <- read.zoo("AMZN.csv", sep = ",", header = TRUE)

# Convert to xts
amzn_xts <- as.xts(amzn_zoo)

# Look at the first few rows of amzn_xts
head(amzn_xts)
           AMZN.Open AMZN.High AMZN.Low AMZN.Close AMZN.Volume
2002-01-02     11.13     11.01    10.46      10.87     6674703
2002-01-03     11.26     12.25    10.76      11.99    11441553
2002-01-04     12.46     12.62    11.71      12.10    12619402
2002-01-07     11.76     12.73    12.01      12.48    12296059
2002-01-08     12.82     12.43    11.35      11.96     6821418
2002-01-09     12.07     12.49    10.93      11.59    10669376
           AMZN.Adjusted
2002-01-02         10.87
2002-01-03         11.99
2002-01-04         12.10
2002-01-07         12.48
2002-01-08         11.96
2002-01-09         11.59

As you will see, read.zoo() is a very flexible import function for time series.

5.1.3 Handle date and time in separate columns

read.zoo() makes it easy to import data when the date and time are in separate columns. The index.column argument allows you to specify the name or number of the column(s) containing the index data. That’s all you need to do if the date and time are specified in the standard format (“%Y-%m-%d” for date, and “%H:%M:%S” for time).

In this exercise, you will use the index.column argument to specify the date and time columns of the file. Your working directory has a file named UNE.csv that contains some 5-minute OHLC data for the energy company, Unron. You will still use read.csv() find the column names of the date and time columns.

# Read data with read.csv
une_data <- read.csv("UNE.csv", nrows = 5)

# Look at the structure of une_data
str(une_data)
'data.frame':   5 obs. of  6 variables:
 $ Date : chr  "2016-11-14" "2016-11-14" "2016-11-14" "2016-11-14" ...
 $ Time : chr  "09:05:00" "09:10:00" "09:15:00" "09:20:00" ...
 $ Open : num  10.4 10.1 10.2 10.1 10.2
 $ High : num  10.4 10.2 10.2 10.2 10.2
 $ Low  : num  10.2 10.1 10.2 10.1 10.2
 $ Close: num  10.2 10.2 10.2 10.2 10.2
# Read data with read.zoo, specifying index columns
une_zoo <- read.zoo("UNE.csv", index.column = c("Date", "Time"), sep = ",", header = TRUE)

# Look at first few rows of data
head(une_zoo)
                     Open  High   Low Close
2016-11-14 09:05:00 10.38 10.38 10.21 10.22
2016-11-14 09:10:00 10.12 10.22 10.12 10.22
2016-11-14 09:15:00 10.18 10.22 10.15 10.22
2016-11-14 09:20:00 10.09 10.22 10.07 10.22
2016-11-14 09:25:00 10.22 10.22 10.21 10.22
2016-11-14 09:30:00 10.16 10.22 10.15 10.22

The index.column argument is great if your dates and times are in separate columns!

5.1.4 Read text file containing multiple instruments

The previous exercises work if each file contains only one instrument. Some software and data vendors may provide data for all instruments in one file. This exercise will teach you how to import a file that contains multiple instruments.

Once again, you can use read.zoo(). This time you will be using its split argument, which allows you to specify the name or number of the columns(s) that contain the variables that identify unique observations.

The two_symbols.csv file in your working directory contains bid/ask data for two instruments, where each row has one bid or ask observation for one instrument. You will use the split argument to import the data into an object that has both bid and ask prices for both instruments on one row.

# Read data with read.csv
two_symbols_data <- read.csv("two_symbols.csv", nrows = 5)

# Look at the structure of two_symbols_data
str(two_symbols_data)
'data.frame':   5 obs. of  4 variables:
 $ Date  : chr  "2016-01-01 10:43:01" "2016-01-01 10:43:01" "2016-01-01 10:43:01" "2016-01-01 10:43:01" ...
 $ Symbol: chr  "A" "A" "B" "B" ...
 $ Type  : chr  "Bid" "Ask" "Bid" "Ask" ...
 $ Price : num  58.2 58.2 29 29 58.2
# Read data with read.zoo, specifying index columns
two_symbols_zoo <- read.zoo("two_symbols.csv", split = c("Symbol", "Type"), sep = ",", header = TRUE)

# Look at first few rows of data
head(two_symbols_zoo)
                    A.Ask B.Ask A.Bid B.Bid
2016-01-01 10:43:01 58.24 28.98 58.23 28.96
2016-01-01 10:43:02 58.25 28.99 58.24 28.97

5.2 Checking for weirdness

5.2.1 Handle missing values

In chapter 3, you used na.locf() to fill missing values with the previous non-missing value. You can use interpolation when carrying the previous value forward isn’t appropriate. In this exercise, you will explore two interpolation methods: linear and spline.

Linear interpolation calculates values that lie on a line between two known data points. This is a good choice for fairly linear data, like a series with a strong trend. Spline interpolation is more appropriate for series without a strong trend, because it calculates a non-linear approximation using multiple data points.

Use these two methods to interpolate the three missing values for the 10-year Treasury rate in the object DGS10. Then compare the results with the output of na.locf().

# fill NA using last observation carried forward
locf <- na.locf(DGS10)

# fill NA using linear interpolation
approx <- na.approx(DGS10)

# fill NA using spline interpolation
spline <- na.spline(DGS10)

# merge into one object
na_filled <- merge(locf, approx, spline)

# plot combined object
plot(na_filled, col = c("black", "red", "green"))

5.2.2 Visualize imported data

It’s important to check your imported data is reasonable. A plot is a quick and easy way to spot oddities. In this exercise, you will use the plot() function to visualize some AAPL data from Yahoo Finance.

A stock split caused a huge price change in June 2014. Apple simultaneously increased the number of shares outstanding and decreased its stock price, leaving the company value unchanged. For example, a 2-for-1 split would double the shares outstanding, and reduce the stock price by 1/2.

You will also use the quantmod extractor functions Cl() and Ad() to access the close and adjusted close columns, respectively. Yahoo Finance provides the split- and/or dividend-adjusted close column.

getSymbols("AAPL", src='yahoo', from = "2007-01-01", to = "2017-09-17")
[1] "AAPL"
head(AAPL)
           AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2007-01-03  12.32714  12.36857 11.70000   11.97143   309579900
2007-01-04  12.00714  12.27857 11.97429   12.23714   211815100
2007-01-05  12.25286  12.31428 12.05714   12.15000   208685400
2007-01-08  12.28000  12.36143 12.18286   12.21000   199276700
2007-01-09  12.35000  13.28286 12.16429   13.22429   837324600
2007-01-10  13.53571  13.97143 13.35000   13.85714   738220000
           AAPL.Adjusted
2007-01-03      10.36364
2007-01-04      10.59366
2007-01-05      10.51822
2007-01-08      10.57016
2007-01-09      11.44823
2007-01-10      11.99609
# Look at the last few rows of AAPL data
tail(AAPL)
           AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2017-09-08    160.86    161.15   158.53     158.63    28611500
2017-09-11    160.50    162.05   159.89     161.50    31580800
2017-09-12    162.61    163.96   158.77     160.86    71714000
2017-09-13    159.87    159.96   157.91     159.65    44907400
2017-09-14    158.99    159.40   158.09     158.28    23760700
2017-09-15    158.47    160.97   158.00     159.88    49114600
           AAPL.Adjusted
2017-09-08      152.6423
2017-09-11      155.4040
2017-09-12      154.7882
2017-09-13      153.6238
2017-09-14      152.3055
2017-09-15      153.8451
# Plot close price
plot(AAPL$AAPL.Close)


# Plot adjusted close price
plot(AAPL$AAPL.Adjusted)

5.2.3 Cross reference sources

In this exercise, you will cross-reference the AAPL raw price data from the previous exercise with AAPL data from another source.

The new data is already adjusted for splits, but not dividends. So the close prices from the new data won’t align closely with the adjusted close prices from the previous exercise (which are adjusted for both splits and dividends). You will learn more about the adjustment process in the next video.

You will compare raw, unadjusted AAPL data with split-adjusted AAPL data. The data have already been loaded to your workspace in aapl_raw and aapl_split_adjusted, respectively.

# Look at first few rows of aapl_raw
head(aapl_raw)

# Look at first few rows of aapl_split_adjusted
head(aapl_split_adjusted)

# Plot difference between adjusted close and split-adjusted close
plot(Ad(aapl_raw$AAPL.Adjusted) - Cl(aapl_split_adjusted$AAPL.Close))

# Plot difference between volume from the raw and split-adjusted sources
plot(Vo(aapl_raw$AAPL.Volume) - Vo(aapl_split_adjusted$AAPL.Volume))

The volumes agree on most (but not all) days, whereas the close prices are completely different.

5.3 Adjusting for corporate actions

5.3.1 Adjust for stock splits and dividends

Stock splits can create large historical price changes even though they do not change the value of the company. So, you must adjust all pre-split prices in order to calculate historical returns correctly.

Similarly, you must adjust all pre-dividend prices. Dividends do reduce the company’s value by the amount of the dividend payment, but the investor’s return isn’t affected because they receive the offsetting dividend payment.

In this exercise, you will learn how to use the adjustOHLC() function to adjust raw historical OHLC prices for splits and dividends, so historical returns can be calculated accurately.

Yahoo Finance provides raw prices and a split- and dividend-adjusted close column. The output of adjustOHLC() should match Yahoo’s adjusted close column. AAPL data from Yahoo Finance is already loaded in your workspace.

While not necessary to complete this exercise, Yahoo Finance provides an accessible example of the adjusted close calculation, if you’re interested in learning more.

# Look at first few rows of AAPL
head(AAPL)
           AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2007-01-03  12.32714  12.36857 11.70000   11.97143   309579900
2007-01-04  12.00714  12.27857 11.97429   12.23714   211815100
2007-01-05  12.25286  12.31428 12.05714   12.15000   208685400
2007-01-08  12.28000  12.36143 12.18286   12.21000   199276700
2007-01-09  12.35000  13.28286 12.16429   13.22429   837324600
2007-01-10  13.53571  13.97143 13.35000   13.85714   738220000
           AAPL.Adjusted
2007-01-03      10.36364
2007-01-04      10.59366
2007-01-05      10.51822
2007-01-08      10.57016
2007-01-09      11.44823
2007-01-10      11.99609
# Adjust AAPL for splits and dividends
aapl_adjusted <- adjustOHLC(AAPL)
incomplete final line found by readTableHeader on 'https://query1.finance.yahoo.com/v7/finance/download/AAPL?period1=-2208988800&period2=1596412800&interval=1d&events=split&crumb=xy3lzdxTZvG'incomplete final line found by readTableHeader on 'https://query1.finance.yahoo.com/v7/finance/download/AAPL?period1=-2208988800&period2=1596412800&interval=1d&events=split&crumb=xy3lzdxTZvG'
# Look at first few rows of aapl_adjusted
head(aapl_adjusted)
           AAPL.Open AAPL.High AAPL.Low AAPL.Close AAPL.Volume
2007-01-03  1.584312  1.589637 1.503711   1.538595   309579900
2007-01-04  1.543185  1.578070 1.538962   1.572745   211815100
2007-01-05  1.574765  1.582660 1.549611   1.561546   208685400
2007-01-08  1.578254  1.588719 1.565769   1.569257   199276700
2007-01-09  1.587250  1.707143 1.563382   1.699615   837324600
2007-01-10  1.739641  1.795640 1.715772   1.780951   738220000
           AAPL.Adjusted
2007-01-03      10.36364
2007-01-04      10.59366
2007-01-05      10.51822
2007-01-08      10.57016
2007-01-09      11.44823
2007-01-10      11.99609

5.3.2 Download split and dividend data

In the previous exercise, you used adjustOHLC() to adjust raw historical OHLC prices for splits and dividends, but it only works for OHLC data. It will not work if you only have close prices, and it does not return any of the split or dividend data it uses.

You need the dates and values for each split and dividend to adjust a non-OHLC price series, or if you simply want to analyze the raw split and dividend data.

You can download the split and dividend data from Yahoo Finance using the quantmod functions getSplits() and getDividends(), respectively. The historical dividend data from Yahoo Finance is adjusted for splits. If you want to download unadjusted dividend data, you need to set split.adjust = FALSE in your call to getDividends().

# Download AAPL split data
splits <- getSplits("AAPL")
incomplete final line found by readTableHeader on 'https://query2.finance.yahoo.com/v7/finance/download/AAPL?period1=0&period2=1596412800&interval=1d&events=split&crumb=xy3lzdxTZvG'
# Download AAPL dividend data
dividends <- getDividends("AAPL")
incomplete final line found by readTableHeader on 'https://query1.finance.yahoo.com/v7/finance/download/AAPL?period1=-2208988800&period2=1596412800&interval=1d&events=split&crumb=xy3lzdxTZvG'
# Look at the first few rows of dividends
head(dividends)
               AAPL.div
1987-05-11 3.821429e-05
1987-08-10 7.642857e-05
1987-11-17 1.021429e-04
1988-02-12 1.021429e-04
1988-05-16 1.021429e-04
1988-08-15 1.021429e-04
# Download unadjusted AAPL dividend data
raw_dividends <- getDividends("AAPL", split.adjust = FALSE)

# Look at the first few rows of raw_dividends
head(dividends)
               AAPL.div
1987-05-11 3.821429e-05
1987-08-10 7.642857e-05
1987-11-17 1.021429e-04
1988-02-12 1.021429e-04
1988-05-16 1.021429e-04
1988-08-15 1.021429e-04

It’s important to get splits and dividends correct when calculating historical returns.

5.3.3 Adjust univariate data for splits and dividends

If you only have close prices, you can adjust them with adjRatios(). It has 3 arguments: splits, dividends, and close. It returns an xts object with split and dividend adjustment ratios in columns “Split” and “Div”, respectively.

You need to provide split data via the splits argument to calculate the split ratio. To calculate the dividend ratio, you need to provide raw dividends and raw prices via the dividends and close arguments, respectively.

Once you have the split and dividend adjustment ratios, you calculate the adjusted price multiplying the unadjusted price by both the split and dividend adjustment ratios.

# Calculate split and dividend adjustment ratios
ratios <- adjRatios(splits = splits, dividends = raw_dividends, close = Cl(AAPL))

# Calculate adjusted close for AAPL
aapl_adjusted <- Cl(AAPL) * ratios[, "Split"] * ratios[, "Div"]

# Look at first few rows of Yahoo adjusted close
head(Ad(AAPL))
           AAPL.Adjusted
2007-01-03      10.36364
2007-01-04      10.59366
2007-01-05      10.51822
2007-01-08      10.57016
2007-01-09      11.44823
2007-01-10      11.99609
# Look at first few rows of aapl_adjusted
head(aapl_adjusted)
           AAPL.Close
2007-01-03   1.538595
2007-01-04   1.572745
2007-01-05   1.561546
2007-01-08   1.569257
2007-01-09   1.699615
2007-01-10   1.780951
LS0tCnRpdGxlOiAiSW1wb3J0aW5nIGFuZCBNYW5hZ2luZyBGaW5hbmNpYWwgRGF0YSBpbiBSIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfY29sbGFwc2VkOiBmYWxzZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICAKdG9jX2RlcHRoOiAzCi0tLQoKIyBJbnRyb2R1Y3Rpb24gYW5kIGRvd25sb2FkaW5nIGRhdGEKCiMjIEludHJvZHVjdGlvbiBhbmQgZG93bmxvYWRpbmcgZGF0YQoKIyMjIEludHJvZHVjaW5nIGdldFN5bWJvbHMoKQoKVGhlIGdldFN5bWJvbHMoKSBmdW5jdGlvbiBmcm9tIHRoZSBxdWFudG1vZCBwYWNrYWdlIHByb3ZpZGVzIGEgY29uc2lzdGVudCBpbnRlcmZhY2UgdG8gaW1wb3J0IGRhdGEgZnJvbSB2YXJpb3VzIHNvdXJjZXMgaW50byB5b3VyIHdvcmtzcGFjZS4gQnkgZGVmYXVsdCwgZ2V0U3ltYm9scygpIGltcG9ydHMgdGhlIGRhdGEgYXMgYSB4dHMgb2JqZWN0LgoKVGhpcyBleGVyY2lzZSB3aWxsIGludHJvZHVjZSB5b3UgdG8gZ2V0U3ltYm9scygpLiBZb3Ugd2lsbCB1c2UgaXQgdG8gaW1wb3J0IFFRUSBkYXRhIGZyb20gWWFob28hIEZpbmFuY2UuIFFRUSBpcyBhbiBleGNoYW5nZS10cmFkZWQgZnVuZCB0aGF0IHRyYWNrcyB0aGUgTmFzZGFxIDEwMCBpbmRleCwgYW5kIFlhaG9vISBGaW5hbmNlIGlzIHRoZSBkZWZhdWx0IGRhdGEgc291cmNlIGZvciBnZXRTeW1ib2xzKCkuCgpZb3UgdXNlIHRoZSBTeW1ib2xzIGFyZ3VtZW50IHRvIHNwZWNpZnkgdGhlIGluc3RydW1lbnQgKGkuZS4gdGhlIHRpY2tlciBzeW1ib2wpIHlvdSB3YW50IHRvIGltcG9ydC4gU2luY2UgU3ltYm9scyBpcyB0aGUgZmlyc3QgYXJndW1lbnQgdG8gZ2V0U3ltYm9scygpLCB5b3UgdXN1YWxseSBqdXN0IHR5cGUgdGhlIGluc3RydW1lbnQgbmFtZSBhbmQgb21pdCBTeW1ib2xzID0uCmBgYHtyfQojIExvYWQgdGhlIHF1YW50bW9kIHBhY2thZ2UKbGlicmFyeShxdWFudG1vZCkKCiMgSW1wb3J0IFFRUSBkYXRhIGZyb20gWWFob28hIEZpbmFuY2UKZ2V0U3ltYm9scyhTeW1ib2xzID0gIlFRUSIsIGF1dG8uYXNzaWduID0gVFJVRSkKCiMgTG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIHRoZSBvYmplY3QgZ2V0U3ltYm9scyBjcmVhdGVkCnN0cihRUVEpCgojIExvb2sgYXQgdGhlIGZpcnN0IGZldyByb3dzIG9mIFFRUQpoZWFkKFFRUSkKYGBgCiMjIyBEYXRhIHNvdXJjZXMKCkluIHRoZSBsYXN0IGV4ZXJjaXNlLCB5b3UgaW1wb3J0ZWQgZGF0YSBmcm9tIFlhaG9vISBGaW5hbmNlLiBUaGUgc3JjIGFyZ3VtZW50IGFsbG93cyB5b3UgdG8gdGVsbCBnZXRTeW1ib2xzKCkgdG8gaW1wb3J0IGRhdGEgZnJvbSBhIGRpZmZlcmVudCBkYXRhIHNvdXJjZS4KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGltcG9ydCBkYXRhIGZyb20gQWxwaGEgVmFudGFnZSBhbmQgRlJFRC4gQWxwaGEgVmFudGFnZSBpcyBhIHNvdXJjZSBzaW1pbGFyIHRvIFlhaG9vISBGaW5hbmNlLiBGUkVEIGlzIGFuIG9ubGluZSBkYXRhYmFzZSBvZiBlY29ub21pYyB0aW1lIHNlcmllcyBkYXRhIGNyZWF0ZWQgYW5kIG1haW50YWluZWQgYnkgdGhlIEZlZGVyYWwgUmVzZXJ2ZSBCYW5rIG9mIFN0LiBMb3Vpcy4KCmdldFN5bWJvbHMoKSBpbXBvcnRzIGRhdGEgZnJvbSBZYWhvbyEgRmluYW5jZSBieSBkZWZhdWx0IGJlY2F1c2Ugc3JjID0gInlhaG9vIiBieSBkZWZhdWx0LiBUaGUgc3JjIHZhbHVlcyBmb3IgQWxwaGEgVmFudGFnZSBhbmQgRlJFRCBhcmUgImF2IiBhbmQgIkZSRUQiLCByZXNwZWN0aXZlbHkuCmBgYHtyfQojIEltcG9ydCBRUVEgZGF0YSBmcm9tIEFscGhhIFZhbnRhZ2UKIyBnZXRTeW1ib2xzKFN5bWJvbHMgPSAiUVFRIiwgc3JjID0gImF2IikKIyBodHRwczovL3d3dy5hbHBoYXZhbnRhZ2UuY28vIHRvIGdldCBBUEkga2V5CiMgTG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIFFRUQojIHN0cihRUVEpCgojIEltcG9ydCBHRFAgZGF0YSBmcm9tIEZSRUQKZ2V0U3ltYm9scyhTeW1ib2xzID0gIkdEUCIsIHNyYyA9ICJGUkVEIikKCiMgTG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIEdEUApzdHIoR0RQKQpgYGAKIyMjIE1ha2UgZ2V0U3ltYm9scygpIHJldHVybiB0aGUgZGF0YSBpdCByZXRyaWV2ZXMKSW4gdGhlIGxhc3QgZXhlcmNpc2UsIGdldFN5bWJvbHMoKSBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQgYW4gb2JqZWN0IG5hbWVkIGxpa2UgdGhlIHN5bWJvbCB5b3UgcHJvdmlkZWQuIFRoaXMgZXhlcmNpc2Ugd2lsbCB0ZWFjaCB5b3UgdG8gbWFrZSBnZXRTeW1ib2xzKCkgcmV0dXJuIHRoZSBkYXRhLCBzbyB5b3UgY2FuIGFzc2lnbiB0aGUgb3V0cHV0IHlvdXJzZWxmLgoKVGhlcmUgYXJlIHR3byBhcmd1bWVudHMgdGhhdCB3aWxsIG1ha2UgZ2V0U3ltYm9scygpIHJldHVybiB0aGUgZGF0YToKCjEuIFNldCBhdXRvLmFzc2lnbiA9IEZBTFNFLgoyLiBTZXQgZW52ID0gTlVMTC4KClRoZSB0d28gbWV0aG9kcyBhcmUgZnVuY3Rpb25hbGx5IGVxdWl2YWxlbnQsIGJ1dCBhdXRvLmFzc2lnbiA9IEZBTFNFIGRlc2NyaWJlcyB0aGUgYmVoYXZpb3IgYmV0dGVyLiBVc2UgaXQgYmVjYXVzZSB5b3Ugd2lsbCBiZSBtb3JlIGxpa2VseSB0byByZW1lbWJlciB3aGF0IGF1dG8uYXNzaWduID0gRkFMU0UgbWVhbnMgaW4gdGhlIGZ1dHVyZS4KYGBge3J9CiMgQXNzaWduIFNQWSBkYXRhIHRvICdzcHknIHVzaW5nIGF1dG8uYXNzaWduIGFyZ3VtZW50CnNweSA8LSBnZXRTeW1ib2xzKFN5bWJvbHMgPSAiU1BZIiwgYXV0by5hc3NpZ24gPSBGQUxTRSkKCiMgTG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIHRoZSAnc3B5JyBvYmplY3QKc3RyKHNweSkKCiMgQXNzaWduIEpOSiBkYXRhIHRvICdqbmonIHVzaW5nIGVudiBhcmd1bWVudApqbmogPC0gZ2V0U3ltYm9scyhTeW1ib2xzID0gIkpOSiIsIGVudiA9IE5VTEwpCgojIExvb2sgYXQgdGhlIHN0cnVjdHVyZSBvZiB0aGUgJ2puaicgb2JqZWN0CnN0cihqbmopCmBgYApUdXJuaW5nIG9mZiBhdXRvLmFzc2lnbiBpcyB1c2VmdWwgaWYgeW91IHdhbnQgdG8gYXNzaWduIHRoZSBkYXRhIHRvIGFuIG9iamVjdCB5b3Vyc2VsZi4KCiMjIEludHJvZHVjdGlvbiB0byBRdWFuZGwKClNpbWlsYXIgdG8gaG93IHRoZSBxdWFudG1vZCBwYWNrYWdlIHByb3ZpZGVzIGdldFN5bWJvbHMoKSB0byBpbXBvcnQgZGF0YSBmcm9tIHZhcmlvdXMgc291cmNlcywgdGhlIFF1YW5kbCBwYWNrYWdlIHByb3ZpZGVzIGFjY2VzcyB0byB0aGUgUXVhbmRsIGRhdGFiYXNlcyB2aWEgb25lIHNpbXBsZSBmdW5jdGlvbjogUXVhbmRsKCkuCgpSZWNhbGwgdGhhdCBnZXRTeW1ib2xzKCkgdXNlcyB0aGUgU3ltYm9scyBhbmQgc3JjIGFyZ3VtZW50cyB0byBzcGVjaWZ5IHRoZSBpbnN0cnVtZW50IGFuZCBkYXRhIHNvdXJjZSwgcmVzcGVjdGl2ZWx5LiBUaGUgUXVhbmRsKCkgZnVuY3Rpb24gc3BlY2lmaWVzIGJvdGggdGhlIGRhdGEgc291cmNlIGFuZCB0aGUgaW5zdHJ1bWVudCB2aWEgaXRzIGNvZGUgYXJndW1lbnQsIGluIHRoZSBmb3JtICJEQVRBQkFTRS9EQVRBU0VUIi4KClR3byBvdGhlciB3YXlzIFF1YW5kbCgpIGRpZmZlcnMgZnJvbSBnZXRTeW1ib2xzKCkgYXJlOgoKMS4gUXVhbmRsKCkgcmV0dXJucyBhIGRhdGEuZnJhbWUgYnkgZGVmYXVsdC4KMi4gUXVhbmRsKCkgd2lsbCBub3QgYXV0b21hdGljYWxseSBhc3NpZ24gdGhlIGRhdGEgdG8gYW4gb2JqZWN0LgoKSWYgeW91IHBsYW4gb24gaW1wb3J0aW5nIGEgbG90IG9mIGRhdGEgdXNpbmcgUXVhbmRsKCksIHlvdSBtaWdodCBjb25zaWRlciBvcGVuaW5nIGEgZnJlZSBhY2NvdW50IHdpdGggdGhlbSBpbiBvcmRlciB0byBnZXQgYW4gQVBJIGtleS4KCmBgYHtyfQojIExvYWQgdGhlIFF1YW5kbCBwYWNrYWdlCmxpYnJhcnkoUXVhbmRsKQoKIyBJbXBvcnQgR0RQIGRhdGEgZnJvbSBGUkVECiMgZ2RwIDwtIFF1YW5kbChjb2RlID0gIkZSRUQvR0RQIikKCiMgTG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIHRoZSBvYmplY3QgcmV0dXJuZWQgYnkgUXVhbmRsCiMgc3RyKGdkcCkKYGBgClF1YW5kbCBwcm92aWRlcyBhY2Nlc3MgdG8gYSBsYXJnZSBhbW91bnQgb2YgZGF0YSBzZXJpZXMuIFRoZWlyIHdlYnNpdGUgaGFzIGRvY3VtZW50YXRpb24gZm9yIGl0IGFsbCEKCiMjIyBSZXR1cm4gZGF0YSB0eXBlCgpUaGUgUXVhbmRsKCkgZnVuY3Rpb24gcmV0dXJucyBhIGRhdGEuZnJhbWUgYnkgZGVmYXVsdC4gSXQgY2FuIHJldHVybiBvdGhlciBjbGFzc2VzIHZpYSB0aGUgdHlwZSBhcmd1bWVudC4KClRoZSBwb3NzaWJsZSB2YWx1ZXMgZm9yIHR5cGUgYXJlOgoKMS4gInJhdyIgKGEgZGF0YS5mcmFtZSksCjIuICJ0cyIgKHRpbWUtc2VyaWVzIG9iamVjdHMgZnJvbSB0aGUgc3RhdHMgcGFja2FnZSksCjMuICJ6b28iLAo0LiAieHRzIiwgYW5kCjUuICJ0aW1lU2VyaWVzIiAoZnJvbSB0aGUgdGltZVNlcmllcyBwYWNrYWdlIGluIHRoZSBSTWV0cmljcyBzdWl0ZSkuCgpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBsZWFybiBob3cgdG8gdXNlIHRoZSB0eXBlIGFyZ3VtZW50IHRvIG1ha2UgUXVhbmRsKCkgcmV0dXJuIGFuIHh0cyBhbmQgYSB6b28gb2JqZWN0LgoKYGBge3J9CiMgSW1wb3J0IEdEUCBkYXRhIGZyb20gRlJFRCBhcyB4dHMKIyBnZHBfeHRzIDwtIFF1YW5kbChjb2RlID0gIkZSRUQvR0RQIiwgdHlwZSA9ICJ4dHMiKQoKIyBMb29rIGF0IHRoZSBzdHJ1Y3R1cmUgb2YgZ2RwX3h0cwojIHN0cihnZHBfeHRzKQogCiMgSW1wb3J0IEdEUCBkYXRhIGZyb20gRlJFRCBhcyB6b28KIyBnZHBfem9vIDwtIFF1YW5kbChjb2RlID0gIkZSRUQvR0RQIiwgdHlwZSA9ICJ6b28iKQoKIyBMb29rIGF0IHRoZSBzdHJ1Y3R1cmUgb2YgZ2RwX3pvbwojIHN0cihnZHBfem9vKQpgYGAKSGF2aW5nIHRoZSBmbGV4aWJpbGl0eSB0byByZXR1cm4gZGlmZmVyZW50IGRhdGEgdHlwZXMgaXMgYSBncmVhdCBib251cyBhbmQgbGVzcyB3b3JrIGZvciB5b3UhCgojIyBGaW5kaW5nIGRhdGEgZnJvbSBpbnRlcm5ldCBzb3VyY2VzCgojIyMgRmluZCBzdG9jayB0aWNrZXIgZnJvbSBZYWhvbyBGaW5hbmNlCgpZb3UgbmVlZCB0aGUgaW5zdHJ1bWVudCBpZGVudGlmaWVyIHRvIGltcG9ydCBkYXRhIGZyb20gYW4gaW50ZXJuZXQgZGF0YSBzb3VyY2UuIFRoZXkgY2FuIG9mdGVuIGJlIGZvdW5kIG9uIHRoZSBkYXRhIHNvdXJjZSB3ZWJzaXRlLiBJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBzZWFyY2ggWWFob28gRmluYW5jZSBmb3IgdGhlIHRpY2tlciBzeW1ib2wgZm9yIFBmaXplciBzdG9jay4KCk5vdGUgdGhhdCBzb21lIHNvdXJjZXMgbWF5IG5vdCBwcm92aWRlIGRhdGEgZm9yIGNlcnRhaW4gc3ltYm9scywgZXZlbiBpZiB5b3UgY2FuIHNlZSB0aGUgZGF0YSBkaXNwbGF5ZWQgb24gdGhlaXIgd2Vic2l0ZSBpbiB0YWJsZXMgYW5kL29yIGNoYXJ0cy4gZ2V0U3ltYm9scygpIHdpbGwgZXJyb3IgaWYgdGhlIGRhdGEgaXMgbm90IGF2YWlsYWJsZSBmb3IgZG93bmxvYWQuCmBgYHtyfQojIENyZWF0ZSBhbiBvYmplY3QgY29udGFpbmluZyB0aGUgUGZpemVyIHRpY2tlciBzeW1ib2wKc3ltYm9sIDwtICJQRkUiCgojIFVzZSBnZXRTeW1ib2xzIHRvIGltcG9ydCB0aGUgZGF0YQpnZXRTeW1ib2xzKCJQRkUiKQoKIyBMb29rIGF0IHRoZSBmaXJzdCBmZXcgcm93cyBvZiBkYXRhCmhlYWQoUEZFKQpgYGAKTG9va2luZyB1cCBpZGVudGlmaWVycyBvbmxpbmUgaXMgY29tbW9uIHdoZW4gc2Vla2luZyBkYXRhIGFib3V0IGEgbmV3IGluc3RydW1lbnQsIHNvIGl0J3MgZ29vZCB0byBnZXQgY29tZm9ydGFibGUgd2l0aCB0aGUgcHJvY2VzcyEKCiMjIyBEb3dubG9hZCBleGNoYW5nZSByYXRlIGRhdGEgZnJvbSBPYW5kYQoKT2FuZGEuY29tIHByb3ZpZGVzIGhpc3RvcmljYWwgZm9yZWlnbiBleGNoYW5nZSBkYXRhIGZvciBtYW55IGN1cnJlbmN5IHBhaXJzLiBDdXJyZW5jeSBwYWlycyBhcmUgZXhwcmVzc2VkIGFzIHR3byBjdXJyZW5jaWVzLCB0aGUgImJhc2UiIGFuZCB0aGUgInF1b3RlIiwgc2VwYXJhdGVkIGJ5IGEgIi8iLiBGb3IgZXhhbXBsZSwgdGhlIFUuUy4gRG9sbGFyIHRvIEV1cm8gZXhjaGFuZ2UgcmF0ZSB3b3VsZCBiZSAiVVNEL0VVUiIuCgpOb3RlIHRoYXQgZ2V0U3ltYm9scygpIHdpbGwgYXV0b21hdGljYWxseSBjb252ZXJ0ICJVU0QvRVVSIiB0byBhIHZhbGlkIG5hbWUgYnkgcmVtb3ZpbmcgdGhlICIvIi4gRm9yIGV4YW1wbGUsIGdldFN5bWJvbHMoIlVTRC9FVVIiKSB3b3VsZCBjcmVhdGUgYW4gb2JqZWN0IG5hbWVkIFVTREVVUi4KCkFsc28sIE9hbmRhLmNvbSBvbmx5IHByb3ZpZGVzIDE4MCBkYXlzIG9mIGhpc3RvcmljYWwgZGF0YS4gZ2V0U3ltYm9scygpIHdpbGwgd2FybiBhbmQgcmV0dXJuIGFzIG11Y2ggZGF0YSBhcyBwb3NzaWJsZSBpZiB5b3UgcmVxdWVzdCBkYXRhIGZyb20gbW9yZSB0aGFuIDE4MCBkYXlzIGFnby4gWW91IGNhbiB1c2UgdGhlIGZyb20gYW5kIHRvIGFyZ3VtZW50cyB0byBzZXQgYSBkYXRlIHJhbmdlOyBib3RoIHNob3VsZCBiZSBzdHJpbmdzIGluICIlWS0lbS0lZCIgZm9ybWF0IChlLmcuICIyMDE2LTAyLTA2IikuCgpxdWFudG1vZDo6b2FuZGEuY3VycmVuY2llcyBjb250YWlucyBhIGxpc3Qgb2YgY3VycmVuY2llcyBwcm92aWRlZCBieSBPYW5kYS5jb20uCmBgYHtyfQojIENyZWF0ZSBhIGN1cnJlbmN5X3BhaXIgb2JqZWN0CmN1cnJlbmN5X3BhaXIgPC0gIkdCUC9DQUQiCgojIExvYWQgQnJpdGlzaCBQb3VuZCB0byBDYW5hZGlhbiBEb2xsYXIgZXhjaGFuZ2UgcmF0ZSBkYXRhCmdldFN5bWJvbHMoY3VycmVuY3lfcGFpciwgc3JjID0gIm9hbmRhIikKCiMgRXhhbWluZSBvYmplY3QgdXNpbmcgc3RyKCkKc3RyKEdCUENBRCkKCiMgVHJ5IHRvIGxvYWQgZGF0YSBmcm9tIDE5MCBkYXlzIGFnbwpnZXRTeW1ib2xzKGN1cnJlbmN5X3BhaXIsIGZyb20gPSBTeXMuRGF0ZSgpIC0gMTkwLCB0byA9IFN5cy5EYXRlKCksIHNyYyA9ICJvYW5kYSIpCmBgYAojIyMgRmluZCBhbmQgaW1wb3J0IFVuZW1wbG95bWVudCBSYXRlIGRhdGEgZnJvbSBGUkVECgpCb3RoIGdldFN5bWJvbHMoKSBhbmQgUXVhbmRsKCkgcHJvdmlkZSBhY2Nlc3MgdG8gdGhlIEZSRUQgZGF0YWJhc2UuIEluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGZpbmQgdGhlIFtGUkVEXShodHRwczovL2ZyZWQuc3Rsb3Vpc2ZlZC5vcmcvKSBzeW1ib2wgZm9yIHRoZSBVbml0ZWQgU3RhdGVzIGNpdmlsaWFuIHVuZW1wbG95bWVudCByYXRlLiBUaGVuIHlvdSB3aWxsIHVzZSB0aGUgc2VyaWVzIG5hbWUgdG8gZG93bmxvYWQgdGhlIGRhdGEgZGlyZWN0bHkgZnJvbSBGUkVEIHVzaW5nIGdldFN5bWJvbHMoKSwgYW5kIGZyb20gdGhlIFF1YW5kbCBkYXRhYmFzZSB1c2luZyBRdWFuZGwoKS4KClJlbWVtYmVyIHRoYXQgZ2V0U3ltYm9scygpIHNwZWNpZmllcyB0aGUgZGF0YSBzb3VyY2UgdXNpbmcgdGhlIHNyYyBhcmd1bWVudCBhbmQgdGhhdCBRdWFuZGwoKSBzcGVjaWZpZXMgaXQgYXMgcGFydCBvZiB0aGUgUXVhbmRsIGNvZGUgKGkuZS4gZGF0YWJhc2Uvc2VyaWVzKS4KYGBge3J9CiMgQ3JlYXRlIGEgc2VyaWVzX25hbWUgb2JqZWN0CnNlcmllc19uYW1lIDwtICJVTlJBVEUiCgojIExvYWQgdGhlIGRhdGEgdXNpbmcgZ2V0U3ltYm9scwpnZXRTeW1ib2xzKHNlcmllc19uYW1lLCBzcmMgPSAiRlJFRCIpCgojIENyZWF0ZSBhIHF1YW5kbF9jb2RlIG9iamVjdAojIHF1YW5kbF9jb2RlIDwtICJGUkVEL1VOUkFURSIKCiMgTG9hZCB0aGUgZGF0YSB1c2luZyBRdWFuZGwjCiMgdW5lbXBsb3lfcmF0ZSA8LSBRdWFuZGwocXVhbmRsX2NvZGUpCmBgYAojIEV4dHJhY3RpbmcgYW5kIHRyYW5zZm9ybWluZyBkYXRhCgojIyBFeHRyYWN0IG9uZSBjb2x1bW4gZnJvbSBvbmUgaW5zdHJ1bWVudAoKVGhlIHF1YW50bW9kIHBhY2thZ2UgcHJvdmlkZXMgc2V2ZXJhbCBoZWxwZXIgZnVuY3Rpb25zIHRvIGV4dHJhY3Qgc3BlY2lmaWMgY29sdW1ucyBmcm9tIGFuIG9iamVjdCwgYmFzZWQgb24gdGhlIGNvbHVtbiBuYW1lLiBUaGUgT3AoKSwgSGkoKSwgTG8oKSwgQ2woKSwgVm8oKSwgYW5kIEFkKCkgZnVuY3Rpb25zIGNhbiBiZSB1c2VkIHRvIGV4dHJhY3QgdGhlIG9wZW4sIGhpZ2gsIGxvdywgY2xvc2UsIHZvbHVtZSwgYW5kIGFkanVzdGVkIGNsb3NlIGNvbHVtbiwgcmVzcGVjdGl2ZWx5LgoKSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgdXNlIHR3byBvZiB0aGVzZSBmdW5jdGlvbnMgb24gYW4geHRzIG9iamVjdCBuYW1lZCBEQy4gVGhlIERDIG9iamVjdCBjb250YWlucyBmaWN0aXRpb3VzIERhdGFDYW1wIE9ITEMgKG9wZW4sIGhpZ2gsIGxvdywgY2xvc2UpIHN0b2NrIHByaWNlcyBjcmVhdGVkIGJ5IHJhbmRvbWl6aW5nIHNvbWUgcmVhbCBmaW5hbmNpYWwgbWFya2V0IGRhdGEuIERDIGlzIHNpbWlsYXIgdG8gdGhlIHh0cyBvYmplY3RzIGNyZWF0ZWQgYnkgZ2V0U3ltYm9scygpLgoKV2hpbGUgaXQncyBub3QgbmVjZXNzYXJ5IHRvIGNvbXBsZXRlIHRoZSBleGVyY2lzZSwgeW91IGNhbiBsZWFybiBtb3JlIGFib3V0IGFsbCB0aGUgZXh0cmFjdG9yIGZ1bmN0aW9ucyBmcm9tIGhlbHAoIk9ITEMuVHJhbnNmb3JtYXRpb25zIikuCiMjIEV4dHJhY3RpbmcgY29sdW1ucyBmcm9tIGZpbmFuY2lhbCB0aW1lIHNlcmllcwoKYGBge3J9CmxvYWQoZmlsZSA9ICJEQy5SRGF0YSIpCmBgYApgYGB7cn0KREMgPC0gRENbLGMoMSwyKV0KREMgPC0gdG8uaG91cmx5KERDLCBpbmRleEF0ID0gInN0YXJ0b2YiKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQojIEV4dHJhY3QgdGhlIGNsb3NlIGNvbHVtbgpkY19jbG9zZSA8LSBDbChEQykKCiMgTG9vayBhdCB0aGUgaGVhZCBvZiBkY19jbG9zZQpoZWFkKGRjX2Nsb3NlKQoKIyBFeHRyYWN0IHRoZSB2b2x1bWUgY29sdW1uCmRjX3ZvbHVtZSA8LSBWbyhEQykKCiMgTG9vayBhdCB0aGUgaGVhZCBvZiBkY192b2x1bWUKaGVhZChkY192b2x1bWUpCmBgYAojIyMgRXh0cmFjdCBtdWx0aXBsZSBjb2x1bW5zIGZyb20gb25lIGluc3RydW1lbnQKClRoZSBxdWFudG1vZCBwYWNrYWdlIHByb3ZpZGVzIGZ1bmN0aW9ucyB0byBleHRyYWN0IGEgc2luZ2xlIGNvbHVtbiwgYW5kIGFsc28gaGFzIGZ1bmN0aW9ucyB0byBleHRyYWN0IHNwZWNpZmljIHNldHMgb2YgY29sdW1ucy4KClJlY2FsbCBPSExDIHN0YW5kcyBmb3Igb3BlbiwgaGlnaCwgbG93LCBjbG9zZS4gTm93IHlvdSBjYW4gZ3Vlc3Mgd2hpY2ggY29sdW1ucyB0aGUgT0hMQygpIGFuZCBITEMoKSBmdW5jdGlvbnMgZXh0cmFjdC4gVGhlcmUncyBhbHNvIGFuIE9ITENWKCkgZnVuY3Rpb24sIHdoaWNoIGFkZHMgdGhlIHZvbHVtZSBjb2x1bW4uCgpUaGVzZSBmdW5jdGlvbnMgYXJlIGhlbHBmdWwgd2hlbiB5b3UgbmVlZCB0byBwYXNzIGEgc2V0IG9mIGNvbHVtbnMgdG8gYW5vdGhlciBmdW5jdGlvbi4gRm9yIGV4YW1wbGUsIHlvdSBtaWdodCBuZWVkIHRvIHBhc3MgdGhlIGhpZ2gsIGxvdywgYW5kIGNsb3NlIGNvbHVtbnMgKGluIHRoYXQgb3JkZXIpIHRvIGEgdGVjaG5pY2FsIGluZGljYXRvciBmdW5jdGlvbi4KYGBge3J9CiMgRXh0cmFjdCB0aGUgaGlnaCwgbG93LCBhbmQgY2xvc2UgY29sdW1ucwpkY19obGMgPSBITEMoREMpCgojIExvb2sgYXQgdGhlIGhlYWQgb2YgZGNfaGxjCmhlYWQoZGNfaGxjKQoKIyBFeHRyYWN0IHRoZSBvcGVuLCBoaWdoLCBsb3csIGNsb3NlLCBhbmQgdm9sdW1lIGNvbHVtbnMKZGNfb2hsY3YgPSBPSExDVihEQykKCiMgTG9vayBhdCB0aGUgaGVhZCBvZiBkY19vaGxjdgpoZWFkKGRjX29obGN2KQpgYGAKIyMjIFVzZSBnZXRQcmljZSB0byBleHRyYWN0IG90aGVyIGNvbHVtbnMKClRoZSBleHRyYWN0b3IgZnVuY3Rpb25zIHlvdSBsZWFybmVkIGluIHRoZSBwcmV2aW91cyB0d28gZXhlcmNpc2VzIGRvIG5vdCBjb3ZlciBhbGwgdXNlIGNhc2VzLiBTb21ldGltZXMgeW91IG1pZ2h0IGhhdmUgb25lIG9iamVjdCB0aGF0IGNvbnRhaW5zIHRoZSBzYW1lIHByaWNlIGNvbHVtbiBmb3IgbXVsdGlwbGUgaW5zdHJ1bWVudHMuIE90aGVyIHRpbWVzLCB5b3UgbWlnaHQgaGF2ZSBhbiBvYmplY3Qgd2l0aCBwcmljZSBkYXRhIChlLmcuIGJpZCwgYXNrLCB0cmFkZSkgdGhhdCBkbyBub3QgaGF2ZSBhbiBleHBsaWNpdCBleHRyYWN0b3IgZnVuY3Rpb24uCgpUaGUgZ2V0UHJpY2UoKSBmdW5jdGlvbiBpbiB0aGUgcXVhbnRtb2QgcGFja2FnZSBjYW4gZXh0cmFjdCBhbnkgY29sdW1uIGJ5IG5hbWUgYnkgdXNpbmcgdGhlIHByZWZlciBhcmd1bWVudC4gSXQgY2FuIGFsc28gZXh0cmFjdCBjb2x1bW5zIGZvciBhIHNwZWNpZmljIGluc3RydW1lbnQgYnkgdXNpbmcgdGhlIHN5bWJvbCBhcmd1bWVudCwgd2hpY2ggaXMgdXNlZnVsIHdoZW4gYW4gb2JqZWN0IGNvbnRhaW5zIHNldmVyYWwgaW5zdHJ1bWVudHMgd2l0aCB0aGUgc2FtZSBwcmljZSB0eXBlLgoKWW91IGNhbiB1c2UgcmVndWxhciBleHByZXNzaW9ucyBmb3IgYm90aCB0aGUgcHJlZmVyIGFuZCBzeW1ib2wgYXJndW1lbnRzLCBiZWNhdXNlIHRoZXkgYXJlIHBhc3NlZCB0byB0aGUgYmFzZTo6Z3JlcCgpIGZ1bmN0aW9uIGludGVybmFsbHkuCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQojYXBpClF1YW5kbC5hcGlfa2V5KCJYU1plUGljMTJqejlDTmYydVZoLSIpCmBgYApgYGB7cn0KIyBEb3dubG9hZCBDTUUgZGF0YSBmb3IgQ0wgYW5kIEJaIGFzIGFuIHh0cyBvYmplY3QKb2lsX2RhdGEgPC0gUXVhbmRsKGNvZGUgPSBjKCJDSFJJUy9DTUVfUVg3IiwgIkNGVEMvMDY3NjUzX0ZPX0xfQUxMX0NSIiksIHR5cGUgPSAieHRzIikKCiMgTG9vayBhdCB0aGUgY29sdW1uIG5hbWVzIG9mIHRoZSBvaWxfZGF0YSBvYmplY3QKY29sbmFtZXMob2lsX2RhdGEpCgojIEV4dHJhY3QgdGhlIE9wZW4gcHJpY2UgZm9yIENMSDIwMTYKY2xfb3BlbiA8LSBnZXRQcmljZShvaWxfZGF0YSwgc3ltYm9sID0gIkNNRV9RWDciLCBwcmVmZXIgPSAiT3BlbiQiKQoKIyBMb29rIGF0IEphbnVhcnksIDIwMTYgdXNpbmcgeHRzJyBJU08tODYwMSBzdWJzZXR0aW5nCmNsX29wZW5bIjIwMTYtMDEiXQpgYGAKZ2V0UHJpY2UoKSBpcyBhIHZlcnkgZmxleGlibGUgd2F5IHRvIHJldHJpZXZlIHRoZSBjb2x1bW5zIHlvdSBuZWVkLgoKIyMgSW1wb3J0aW5nIGFuZCB0cmFuc2Zvcm1pbmcgbXVsdGlwbGUgaW5zdHJ1bWVudHMKCgojIyMgVXNlIFF1YW5kbCB0byBkb3dubG9hZCB3ZWVrbHkgcmV0dXJucyBkYXRhCgpTb21ldGltZXMgeW91IG5lZWQgdG8gYWdncmVnYXRlIGFuZC9vciB0cmFuc2Zvcm0gcmF3IGRhdGEgYmVmb3JlIHlvdSBjYW4gY29udGludWUgeW91ciBhbmFseXNpcy4gVGhlIFF1YW5kbCgpIGZ1bmN0aW9uIGFsbG93cyB5b3UgdG8gc3BlY2lmeSBjb21tb24gYWdncmVnYXRpb25zIGFuZCB0cmFuc2Zvcm1hdGlvbnMgdmlhIHRoZSBjb2xsYXBzZSBhbmQvb3IgdHJhbnNmb3JtIGFyZ3VtZW50cy4gVGhlIFF1YW5kbCBBUEkgdGFrZXMgY2FyZSBvZiB0aGUgZGV0YWlscyBmb3IgeW91LgoKYGBge3J9CiMgRG93bmxvYWQgcXVhcnRlcmx5IENMIGFuZCBCWiBwcmljZXMKcXRyX3ByaWNlIDwtIFF1YW5kbChjb2RlID0gYygiQ0hSSVMvQ01FX1FNMSIsICJDSFJJUy9DTUVfUUcxIiksIGNvbGxhcHNlID0gInF1YXJ0ZXJseSIsdHlwZSA9ICJ4dHMiKQoKIyBWaWV3IHRoZSBoaWdoIHByaWNlcyBmb3IgYm90aCBzZXJpZXMKSGkocXRyX3ByaWNlKQoKIyBEb3dubG9hZCBxdWFydGVybHkgQ0wgYW5kIEJaIHJldHVybnMKcXRyX3JldHVybiA8LSBRdWFuZGwoY29kZSA9IGMoIkNIUklTL0NNRV9RTTEiLCAiQ0hSSVMvQ01FX1FHMSIpLCBjb2xsYXBzZSA9ICJxdWFydGVybHkiLHRyYW5zZm9ybSA9ICJyZGlmZiIsIHR5cGUgPSAieHRzIikKCiMgVmlldyB0aGUgc2V0dGxlIHByaWNlIHJldHVybnMgZm9yIGJvdGggc2VyaWVzCmdldFByaWNlKHF0cl9yZXR1cm4sIHByZWZlciA9ICJTZXR0bGUiKQpgYGAKIyMjIENvbWJpbmUgbWFueSBpbnN0cnVtZW50cyBpbnRvIG9uZSBvYmplY3QKCldoYXQgaWYgeW91IG5lZWQgdG8gYWdncmVnYXRlIG9yIHRyYW5zZm9ybSB5b3VyIGRhdGEgaW4gd2F5cyBRdWFuZGwoKSBkb2VzIG5vdCBzdXBwb3J0PyBJbiB0aG9zZSBjYXNlcywgeW91IGNhbiB1c2UgdGhlIGZsZXhpYmlsaXR5IG9mIFIuCgpPbmUgcGFyYWRpZ20gaW52b2x2ZXMgaW1wb3J0aW5nIGRhdGEgaW50byBhIG5ldyBlbnZpcm9ubWVudC4gVGhlbiB5b3UgY2FuIHVzZSBlYXBwbHkoKSB0byBjYWxsIGEgZnVuY3Rpb24gb24gZWFjaCBvYmplY3QgaW4gdGhlIGVudmlyb25tZW50LCBtdWNoIGxpa2Ugd2hhdCBsYXBwbHkoKSBkb2VzIGZvciBlYWNoIGVsZW1lbnQgb2YgYSBsaXN0LiBBbHNvIGxpa2UgbGFwcGx5KCksIGVhcHBseSgpIHJldHVybnMgYSBsaXN0LgoKVGhlbiB5b3UgY2FuIG1lcmdlIGFsbCB0aGUgZWxlbWVudHMgb2YgdGhlIGxpc3QgaW50byBvbmUgb2JqZWN0IGJ5IHVzaW5nIGRvLmNhbGwoKSwgd2hpY2ggaXMgbGlrZSBoYXZpbmcgUiBwcm9ncmFtbWF0aWNhbGx5IHR5cGUgYW5kIHJ1biBhIGNvbW1hbmQgZm9yIHlvdS4gSW5zdGVhZCBvZiB0eXBpbmcgbWVyZ2UobXlfbGlzdFtbMV1dLCBteV9saXN0W1syXV1dLCAuLi4pLCB5b3UgY2FuIHR5cGUgZG8uY2FsbChtZXJnZSwgbXlfbGlzdCkuCmBgYHtyfQojIENyZWF0ZSBuZXcgZW52aXJvbm1lbnQKZGF0YV9lbnYgPC0gbmV3LmVudigpCiMgVXNlIGdldFN5bWJvbHMgdG8gbG9hZCBkYXRhIGludG8gdGhlIGVudmlyb25tZW50CmdldFN5bWJvbHMoYygiU1BZIiwgIlFRUSIpLCBlbnYgPSBkYXRhX2VudiwgYXV0by5hc3NpZ24gPSBUUlVFKQpgYGAKYGBge3J9CiMgTG9vayBhdCBhIGZldyByb3dzIG9mIHRoZSBTUFkgZGF0YQpoZWFkKGRhdGFfZW52JFNQWSwgMykKYGBgCmBgYHtyfQojIExvb2sgYXQgYSBmZXcgcm93cyBvZiB0aGUgU1BZIGRhdGEKZWFwcGx5KGRhdGFfZW52LCBoZWFkKQpgYGAKYGBge3J9CiMgQ2FsbCBoZWFkIG9uIGVhY2ggb2JqZWN0IGluIGRhdGFfZW52IHVzaW5nIGVhcHBseQpkYXRhX2xpc3QgPC0gZWFwcGx5KGRhdGFfZW52LCBoZWFkKQoKIyBNZXJnZSBhbGwgdGhlIGxpc3QgZWxlbWVudHMgaW50byBvbmUgeHRzIG9iamVjdApkYXRhX21lcmdlZCA8LSBkby5jYWxsKG1lcmdlLCBkYXRhX2xpc3QpCgojIEVuc3VyZSB0aGUgY29sdW1ucyBhcmUgb3JkZXJlZDogb3BlbiwgaGlnaCwgbG93LCBjbG9zZQpkYXRhX29obGMgPC0gT0hMQyhkYXRhX21lcmdlZCkKZGF0YV9vaGxjCmBgYApgYGB7cn0KIyBFeHRyYWN0IHZvbHVtZSBjb2x1bW4gZnJvbSBlYWNoIG9iamVjdAphZGp1c3RlZF9saXN0IDwtIGxhcHBseShkYXRhX2VudiwgQWQpCiMgTWVyZ2UgZWFjaCBsaXN0IGVsZW1lbnQgaW50byBvbmUgb2JqZWN0CmFkanVzdGVkIDwtIGRvLmNhbGwobWVyZ2UsIGFkanVzdGVkX2xpc3QpCmhlYWQoYWRqdXN0ZWQpCmBgYAojIyMgRXh0cmFjdCB0aGUgQ2xvc2UgY29sdW1uIGZyb20gbWFueSBpbnN0cnVtZW50cwoKVGhlIHByZXZpb3VzIGV4ZXJjaXNlIHRhdWdodCB5b3UgaG93IHRvIHVzZSBkby5jYWxsKG1lcmdlLCBlYXBwbHkoZW52LCBmdW4pKSB0byBhcHBseSBhIGZ1bmN0aW9uIHRvIGVhY2ggb2JqZWN0IGluIGFuIGVudmlyb25tZW50IGFuZCB0aGVuIGNvbWJpbmUgYWxsIHRoZSByZXN1bHRzIGludG8gb25lIG9iamVjdC4KCkxldCdzIHVzZSB3aGF0IHlvdSBsZWFybmVkIHRvIHNvbHZlIGEgdmVyeSBjb21tb24gcHJvYmxlbS4gT2Z0ZW4geW91IHdpbGwgbmVlZCB0byBsb2FkIHNpbWlsYXIgZGF0YSBmb3IgbWFueSBpbnN0cnVtZW50cywgZXh0cmFjdCBhIGNvbHVtbiwgYW5kIGNyZWF0ZSBvbmUgb2JqZWN0IHRoYXQgY29udGFpbnMgdGhhdCBzcGVjaWZpYyBjb2x1bW4gZm9yIGV2ZXJ5IGluc3RydW1lbnQuCmBgYHtyfQojIFN5bWJvbHMKc3ltYm9scyA8LSBjKCJBQVBMIiwgIk1TRlQiLCAiSUJNIikKCiMgQ3JlYXRlIG5ldyBlbnZpcm9ubWVudApkYXRhX2VudiA8LSBuZXcuZW52KCkKCiMgTG9hZCBzeW1ib2xzIGludG8gZGF0YV9lbnYKZ2V0U3ltYm9scyhzeW1ib2xzLCBlbnYgPSBkYXRhX2VudikKCiMgRXh0cmFjdCB0aGUgY2xvc2UgY29sdW1uIGZyb20gZWFjaCBvYmplY3QgYW5kIGNvbWJpbmUgaW50byBvbmUgeHRzIG9iamVjdApjbG9zZV9kYXRhIDwtIGRvLmNhbGwobWVyZ2UsIGVhcHBseShkYXRhX2VudiwgQ2wpKQoKIyBWaWV3IHRoZSBoZWFkIG9mIGNsb3NlX2RhdGEKaGVhZChjbG9zZV9kYXRhKQpgYGAKCiMgTWFuYWdpbmcgZGF0YSBmcm9tIG11bHRpcGxlIHNvdXJjZXMKCiMjIFNldHRpbmcgZGVmYXVsdCBhcmd1bWVudHMgZm9yIGdldFN5bWJvbHMoKQoKIyMjIFNldCBhIGRlZmF1bHQgZGF0YSBzb3VyY2UKClJlY2FsbCB0aGF0IGdldFN5bWJvbHMoKSBpbXBvcnRzIGZyb20gWWFob28gRmluYW5jZSBieSBkZWZhdWx0LiBUaGlzIGV4ZXJjaXNlIHdpbGwgdGVhY2ggeW91IGhvdyB0byBjaGFuZ2UgdGhlIGRlZmF1bHQgZGF0YSBzb3VyY2Ugd2l0aCB0aGUgc2V0RGVmYXVsdHMoKSBmdW5jdGlvbi4KClRoZSBmaXJzdCBhcmd1bWVudCB0byBzZXREZWZhdWx0cygpIGlzIHRoZSBmdW5jdGlvbiB5b3Ugd2FudCB0byB1cGRhdGUsIGFuZCB0aGUgcmVtYWluaW5nIGFyZ3VtZW50cyBhcmUgbmFtZSA9IHZhbHVlIHBhaXJzIG9mIHRoZSBhcmd1bWVudHMgeW91IHdhbnQgdG8gdXBkYXRlIGFuZCB0aGUgbmV3IGRlZmF1bHQgdmFsdWUuCgpOb3RlIHRoYXQgdGhpcyBvbmx5IHdvcmtzIHdpdGggZ2V0U3ltYm9scygpIGJlY2F1c2UgZ2V0U3ltYm9scygpIGFjdGl2ZWx5IGNoZWNrcyB0byBzZWUgaWYgeW91IHdhbnQgdG8gdXNlIGEgZGlmZmVyZW50IGRlZmF1bHQgdmFsdWUuCmBgYHtyfQojIFNldCB0aGUgZGVmYXVsdCB0byBwdWxsIGRhdGEgZnJvbSBBbHBoYSBWYW50YWdlCnNldERlZmF1bHRzKGdldFN5bWJvbHMsIHNyYyA9ICJhdiIpCgojIEdldCBHT09HIGRhdGEKIyBnZXRTeW1ib2xzKCJHT09HIikKCiMgVmVyaWZ5IHRoZSBkYXRhIHdhcyBhY3R1YWxseSBwdWxsZWQgZnJvbSBBbHBoYSBWYW50YWdlCiMgc3RyKEdPT0cpCmBgYApTZXR0aW5nIGEgZGVmYXVsdCBzb3VyY2UgY2FuIGJlIHVzZWZ1bCBpZiB5b3UgdXNlIHRoYXQgc291cmNlIG9mdGVuLgoKIyMjIFNldCBkZWZhdWx0IGFyZ3VtZW50cyBmb3IgYSBnZXRTeW1ib2xzIHNvdXJjZQoKWW91IGNhbiBhbHNvIHVzZSBzZXREZWZhdWx0cygpIG9uIGluZGl2aWR1YWwgZ2V0U3ltYm9scygpIHNvdXJjZSBtZXRob2RzLiBUaGlzIGV4ZXJjaXNlIHdpbGwgdGVhY2ggeW91IGhvdyB0byBjaGFuZ2UgdGhlIGRlZmF1bHQgdmFsdWUgZm9yIHRoZSBmcm9tIGFyZ3VtZW50IHRvIGdldFN5bWJvbHMueWFob28oKS4KCllvdSBjYW4gZmluZCB0aGUgYXJndW1lbnRzIGZvciBhIHNwZWNpZmljIG1ldGhvZCBieSB1c2luZyBoZWxwKCkgKGUuZy4gaGVscCgiZ2V0U3ltYm9scy55YWhvbyIpIG9yIGJ5IGNhbGxpbmcgYXJncygpIHRvIHByaW50IHRoZW0gdG8gdGhlIGNvbnNvbGUgKGUuZy4gYXJncyhnZXRTeW1ib2xzLnlhaG9vKSkuIENhbGxpbmcgZ2V0RGVmYXVsdHMoKSB3aWxsIHNob3cgeW91IHRoZSBjdXJyZW50IGRlZmF1bHQgdmFsdWVzIChpZiB0aGVyZSBhcmUgYW55KS4KClJlbWVtYmVyLCB5b3UgYXJlIG5vdCBzdXBwb3NlZCB0byBjYWxsIGdldFN5bWJvbHMueWFob28oKSBkaXJlY3RseSEKYGBge3J9CiMgTG9vayBhdCBnZXRTeW1ib2xzLnlhaG9vIGFyZ3VtZW50cwphcmdzKGdldFN5bWJvbHMueWFob28pCgojIFNldCBkZWZhdWx0ICdmcm9tJyB2YWx1ZSBmb3IgZ2V0U3ltYm9scy55YWhvbwpzZXREZWZhdWx0cyhnZXRTeW1ib2xzLnlhaG9vLCBmcm9tID0gIjIwMDAtMDEtMDEiKQoKIyBDb25maXJtIGRlZmF1bHRzIHdlcmUgc2V0IGNvcnJlY3RseQpnZXREZWZhdWx0cygiZ2V0U3ltYm9scy55YWhvbyIpCmBgYAojIyBTZXR0aW5nIHBlci1pbnN0cnVtZW50IGRlZmF1bHQgYXJndW1lbnRzCgojIyMgU2V0IGRlZmF1bHQgZGF0YSBzb3VyY2UgZm9yIG9uZSBzeW1ib2wKCkNoYW5naW5nIHRoZSBkZWZhdWx0IHNvdXJjZSBmb3Igb25lIGluc3RydW1lbnQgaXMgdXNlZnVsIGlmIG11bHRpcGxlIHNvdXJjZXMgdXNlIHRoZSBzYW1lIHN5bWJvbCBmb3IgZGlmZmVyZW50IGluc3RydW1lbnRzLiBGb3IgZXhhbXBsZSwgZ2V0U3ltYm9scygiQ1AiLCBzcmMgPSAieWFob28iKSB3b3VsZCBsb2FkIENhbmFkaWFuIFBhY2lmaWMgUmFpbHdheSBkYXRhIGZyb20gdGhlIE5ldyBZb3JrIFN0b2NrIEV4Y2hhbmdlLiBCdXQgZ2V0U3ltYm9scygiQ1AiLCBzcmMgPSAiRlJFRCIpIHdvdWxkIGxvYWQgQ29ycG9yYXRlIFByb2ZpdHMgQWZ0ZXIgVGF4IGZyb20gdGhlIFUuUy4gQnVyZWF1IG9mIEVjb25vbWljIEFuYWx5c2lzLgoKWW91IGNhbiB1c2Ugc2V0U3ltYm9sTG9va3VwKCkgdG8gc3BlY2lmeSB0aGUgZGVmYXVsdCBkYXRhIHNvdXJjZSBmb3IgYW4gaW5zdHJ1bWVudC4gSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgbGVhcm4gaG93IHRvIG1ha2UgZ2V0U3ltYm9scygiQ1AiKSBsb2FkIHRoZSBjb3Jwb3JhdGUgcHJvZml0IGRhdGEgZnJvbSBGUkVEIGluc3RlYWQgb2YgdGhlIHJhaWx3YXkgc3RvY2sgZGF0YSBmcm9tIFlhaG9vIEZpbmFuY2UuCgpzZXRTeW1ib2xMb29rdXAoKSBjYW4gdGFrZSBhbnkgbnVtYmVyIG9mIG5hbWUgPSB2YWx1ZSBwYWlycywgd2hlcmUgbmFtZSBpcyB0aGUgc3ltYm9sIGFuZCB2YWx1ZSBpcyBhIG5hbWVkIGxpc3Qgb2YgZ2V0U3ltYm9scygpIGFyZ3VtZW50cyBmb3IgdGhhdCBvbmUgc3ltYm9sLgpgYGB7cn0Kc2V0RGVmYXVsdHMoZ2V0U3ltYm9scywgc3JjID0gInlhaG9vIikKc2V0U3ltYm9sTG9va3VwKCJDUCIgPSAieWFob28iKQojIExvYWQgQ1AgZGF0YSBhZ2FpbgpnZXRTeW1ib2xzKCJDUCIpCiMgTG9vayBhdCB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgQ1AKaGVhZChDUCkKCnNldFN5bWJvbExvb2t1cCgiQ1AiID0gTlVMTCkKCiMgU2V0IHRoZSBzb3VyY2UgZm9yIENQIHRvIEZSRUQKc2V0U3ltYm9sTG9va3VwKCJDUCIgPSAiRlJFRCIpCgojIExvYWQgQ1AgZGF0YSBhZ2FpbgpnZXRTeW1ib2xzKCJDUCIpCgojIExvb2sgYXQgdGhlIGZpcnN0IGZldyByb3dzIG9mIENQCmhlYWQoQ1ApCmBgYApPY2Nhc2lvbmFsbHkgdGhpcyBoYXBwZW5zLCBhbmQgaXQgaXMgdXNlZnVsIHRvIHNldCBhIHNpbmdsZSBzeW1ib2wgdG8gYmUgcHVsbGVkIGZyb20gYSBzcGVjaWZpYyBzb3VyY2UuCgojIyMgU2F2ZSBhbmQgbG9hZCBzeW1ib2wgbG9va3VwIHRhYmxlCgpUaGUgcHJldmlvdXMgZXhlcmNpc2UgdGF1Z2h0IHlvdSBob3cgdG8gc2V0IGRlZmF1bHQgYXJndW1lbnRzIG9uIGEgcGVyLXN5bWJvbCBiYXNpcywgYnV0IHRob3NlIHNldHRpbmdzIG9ubHkgbGFzdCBmb3IgdGhlIGN1cnJlbnQgc2Vzc2lvbi4KClRoaXMgZXhlcmNpc2Ugd2lsbCB0ZWFjaCB5b3UgaG93IHRvIHNhdmUgYW5kIGxvYWQgc3ltYm9sLWJhc2VkIGRlZmF1bHRzIGJ5IHVzaW5nIHNhdmVTeW1ib2xMb29rdXAoKSBhbmQgbG9hZFN5bWJvbExvb2t1cCgpLCByZXNwZWN0aXZlbHkuIFlvdSBjYW4gdXNlIHRoZSBmaWxlIGFyZ3VtZW50cyB0byBzcGVjaWZ5IGEgZmlsZSB0byBzdG9yZSB5b3VyIGRlZmF1bHRzLgoKWW91IGNhbiBhbHNvIHVzZSB0aGUgZ2V0U3ltYm9sTG9va3VwKCkgZnVuY3Rpb24gdG8gY2hlY2sgcGVyLXN5bWJvbCBkZWZhdWx0cyBiZWZvcmUgeW91IHRyeSB0byBsb2FkIGRhdGEgdXNpbmcgZ2V0U3ltYm9scygpLgoKYGBge3J9CiMgU2F2ZSBzeW1ib2wgbG9va3VwIHRhYmxlCnNhdmVTeW1ib2xMb29rdXAoIm15X3N5bWJvbF9sb29rdXAucmRhIikKCiMgU2V0IGRlZmF1bHQgc291cmNlIGZvciBDUCB0byAieWFob28iCnNldFN5bWJvbExvb2t1cCgiQ1AiID0gInlhaG9vIikKCiMgVmVyaWZ5IHRoZSBkZWZhdWx0IHNvdXJjZSBpcyAieWFob28iCmdldFN5bWJvbExvb2t1cCgiQ1AiKQoKIyBMb2FkIHN5bWJvbCBsb29rdXAgdGFibGUKbG9hZFN5bWJvbExvb2t1cCgibXlfc3ltYm9sX2xvb2t1cC5yZGEiKQpnZXRTeW1ib2xMb29rdXAoIkNQIikKYGBgClRoaXMgd2lsbCBsZXQgeW91IGxvYWQgdGhlIHNhbWUgbG9va3VwIHRhYmxlIGV2ZW4gaWYgeW91IGNsb3NlIG91dCBvZiBSLgoKIyMgSGFuZGxpbmcgaW5zdHJ1bWVudCBzeW1ib2xzIHRoYXQgY2xhc2ggb3IgYXJlIG5vdCB2YWxpZCBSIG5hbWVzCgojIyMgQWNjZXNzIHRoZSBvYmplY3QgdXNpbmcgZ2V0KCkgb3IgYmFja3RpY2tzCgpBdCBzb21lIHBvaW50LCB5b3UgbWlnaHQgZG93bmxvYWQgZGF0YSBmb3IgYW4gaW5zdHJ1bWVudCB0aGF0IGRvZXMgbm90IGhhdmUgYSBzeW50YWN0aWNhbGx5IHZhbGlkIG5hbWUuIFN5bnRhY3RpY2FsbHkgdmFsaWQgbmFtZXMgY29udGFpbiBsZXR0ZXJzLCBudW1iZXJzLCAiLiIsIGFuZCAiXyIsIGFuZCBtdXN0IHN0YXJ0IHdpdGggYSBsZXR0ZXIgb3IgYSAiLiIgZm9sbG93ZWQgYnkgYSBub24tbnVtYmVyLgoKRm9yIGV4YW1wbGUsIHRoZSBzeW1ib2wgZm9yIEJlcmtzaGlyZSBIYXRoYXdheSBjbGFzcyBBIHNoYXJlcyBpcyAiQlJLLUEiLCB3aGljaCBpcyBub3QgYSBzeW50YWN0aWNhbGx5IHZhbGlkIG5hbWUgYmVjYXVzZSBpdCBjb250YWlucyBhICItIiBjaGFyYWN0ZXIuIEFub3RoZXIgZXhhbXBsZSBhcmUgQ2hpbmVzZSBzdG9ja3MsIHdoaWNoIGhhdmUgc3ltYm9scyBjb21wb3NlZCBvZiBudW1iZXJzLiBUaGUgWWFob28gRmluYW5jZSBzeW1ib2wgZm9yIHRoZSBTU0UgQ29tcG9zaXRlIEluZGV4IGlzICIwMDAwMDEuU1MiLgoKWW91IGNhbiB1c2UgdGhlIGdldCBmdW5jdGlvbiBvciBiYWNrdGlja3MgKGApIHRvIGFjY2VzcyBvYmplY3RzIHRoYXQgZG8gbm90IGhhdmUgc3ludGFjdGljYWxseSB2YWxpZCBuYW1lcy4KCmBgYHtyfQojIExvYWQgQlJLLUEgZGF0YQpnZXRTeW1ib2xzKCJCUkstQSIpCgojIFVzZSBiYWNrdGlja3MgYW5kIGhlYWQoKSB0byBsb29rIGF0IHRoZSBsb2FkZWQgZGF0YQpoZWFkKGBCUkstQWApCgojIFVzZSBnZXQoKSB0byBhc3NpZ24gdGhlIEJSSy1BIGRhdGEgdG8gYW4gb2JqZWN0IG5hbWVkIEJSSy5BCkJSSy5BIDwtIGdldCgiQlJLLUEiKQpgYGAKSnVzdCByZW1lbWJlciB0byB1c2UgYmFja3RpY2tzIG9yIGdldCgpIGlmIHlvdSBldmVyIHJ1biBpbnRvIGludmFsaWQgY2hhcmFjdGVycy4KCiMjIyBDcmVhdGUgdmFsaWQgbmFtZSBmb3Igb25lIGluc3RydW1lbnQKCklmIHlvdSBhcmUgb25seSBkb3dubG9hZGluZyBkYXRhIGZvciBhIHNpbmdsZSBzeW1ib2wgYW5kIHRoYXQgc3ltYm9sIGlzIG5vdCBhIHN5bnRhY3RpY2FsbHkgdmFsaWQgbmFtZSwgeW91IGNhbiBzZXQgYXV0by5hc3NpZ24gPSBGQUxTRSBpbiB5b3VyIGNhbGwgdG8gZ2V0U3ltYm9scygpLiBUaGF0IHdpbGwgYWxsb3cgeW91IHRvIGRpcmVjdGx5IGFzc2lnbiB0aGUgb3V0cHV0IHRvIGEgc3ludGFjdGljYWxseSB2YWxpZCBuYW1lLgoKWW91IG1heSBhbHNvIHdhbnQgdG8gY29udmVydCB0aGUgY29sdW1uIG5hbWVzIHRvIHN5bnRhY3RpY2FsbHkgdmFsaWQgbmFtZXMuIFRoYXQgaXMgYSBnb29kIGlkZWEgaWYgeW91IHBsYW4gdG8gdXNlIHRoZSBkYXRhIGluIGZ1bmN0aW9ucyB0aGF0IGV4cGVjdCBjb2x1bW4gbmFtZXMgdG8gYmUgc3ludGFjdGljYWxseSB2YWxpZCBuYW1lcyAoZS5nLiBsbSgpKS4KYGBge3J9CiMgQ3JlYXRlIEJSSy5BIG9iamVjdApCUksuQSA8LSBnZXRTeW1ib2xzKCJCUkstQSIsIGF1dG8uYXNzaWduID0gRkFMU0UpCgojIENyZWF0ZSBjb2xfbmFtZXMgb2JqZWN0IHdpdGggdGhlIGNvbHVtbiBuYW1lcyBvZiBCUksuQQpjb2xfbmFtZXMgPC0gY29sbmFtZXMoQlJLLkEpCgojIFNldCBCUksuQSBjb2x1bW4gbmFtZXMgdG8gc3ludGFjdGljYWxseSB2YWxpZCBuYW1lcwpjb2xuYW1lcyhCUksuQSkgPC0gbWFrZS5uYW1lcyhjb2xfbmFtZXMpCmBgYApOb3cgeW91IGNhbiBmaXggdHJpY2t5IHRpY2tlciBzeW1ib2xzIGluIHRoZSBjb2x1bW4gbmFtZXMgb2YgeW91ciBkYXRhLgoKIyMjIENyZWF0ZSB2YWxpZCBuYW1lcyBmb3IgbXVsdGlwbGUgaW5zdHJ1bWVudHMKCkFuIGVhcmxpZXIgZXhlcmNpc2UgdGF1Z2h0IHlvdSBob3cgdG8gdXNlIHNldFN5bWJvbExvb2t1cCgpIHRvIHNldCBhIGRlZmF1bHQgZGF0YSBzb3VyY2UgZm9yIGdldFN5bWJvbHMoKS4gWW91IGNhbiBhbHNvIHVzZSBzZXRTeW1ib2xMb29rdXAoKSB0byBjcmVhdGUgYSBtYXBwaW5nIGJldHdlZW4gdGhlIGluc3RydW1lbnQgc3ltYm9sIGFuZCB0aGUgbmFtZSBvZiB0aGUgUiBvYmplY3QuCgpUaGlzIGlzIHVzZWZ1bCBpZiB5b3Ugd2FudCB0byBkb3dubG9hZCBkYXRhIGZvciBhIGxvdCBzeW1ib2xzIHRoYXQgYXJlIG5vdCBzeW50YWN0aWNhbGx5IHZhbGlkIG5hbWVzLCBvciBzeW1ib2xzIHRoYXQgaGF2ZSBuYW1lcyB0aGF0IGNvbmZsaWN0IHdpdGggb3RoZXIgUiB2YXJpYWJsZSBuYW1lcy4KCkFuIGV4YW1wbGUgb2YgYSBuYW1lIHRoYXQgY29uZmxpY3RzIGlzIHRoZSBzeW1ib2wgZm9yIEFUJlQncyBzdG9jaywgVCwgd2hpY2ggaXMgb2Z0ZW4gdXNlZCBhcyBhIHNob3J0IGZvcm0gZm9yIHRoZSBsb2dpY2FsIHZhbHVlIFRSVUUuCgpUbyBjaGFuZ2UgdGhlIG5hbWUgb2YgYSBnaXZlbiBzeW1ib2wsIGFyZ3VtZW50cyBtdXN0IGJlIHBhc3NlZCB0byBzZXRTeW1ib2xMb29rdXAoKSBhcyBhIGxpc3QsIGxpa2Ugc286IHNldFN5bWJvbExvb2t1cChORVdfTkFNRSA9IGxpc3QobmFtZSA9ICJPTERfTkFNRSIpKS4KYGBge3J9CiMgU2V0IG5hbWUgZm9yIEJSSy1BIHRvIEJSSy5BCnNldFN5bWJvbExvb2t1cChCUksuQSA9IGxpc3QobmFtZSA9ICJCUkstQSIpKQoKIyBTZXQgbmFtZSBmb3IgVCAoQVQmVCkgdG8gQVRUCnNldFN5bWJvbExvb2t1cChBVFQgPSBsaXN0KG5hbWUgPSAiVCIpKQoKIyBMb2FkIEJSSy5BIGFuZCBBVFQgZGF0YQpnZXRTeW1ib2xzKGMoIkJSSy5BIiwgIkFUVCIpKQpgYGAKTm93IHlvdSBjYW4gbWFwIHRyb3VibGVzb21lIHRpY2tlcnMgdG8gbmV3IG5hbWVzIHdpdGggc2V0U3ltYm9sTG9va3VwKCkuCgojIEFsaWduaW5nIGRhdGEgd2l0aCBkaWZmZXJlbnQgcGVyaW9kaWNpdGllcwoKIyMgTWFraW5nIGlycmVndWxhciBkYXRhIHJlZ3VsYXIKCiMjIyBDcmVhdGUgYSB6ZXJvLXdpZHRoIGFuZCByZWd1bGFyIHh0cyBvYmplY3QKCkluIG9yZGVyIHRvIGNyZWF0ZSByZWd1bGFyIGRhdGEgZnJvbSBhbiBpcnJlZ3VsYXIgZGF0YSBzZXQsIHRoZSBmaXJzdCB0aGluZyB5b3UgbmVlZCBpcyBhIHJlZ3VsYXIgc2VxdWVuY2Ugb2YgZGF0ZS10aW1lcyB0aGF0IHNwYW4gdGhlIGRhdGVzIG9mIHlvdXIgaXJyZWd1bGFyIGRhdGEgc2V0LiBBICJyZWd1bGFyIiBzZXF1ZW5jZSBvZiBkYXRlLXRpbWVzIGhhcyBlcXVhbGx5LXNwYWNlZCB0aW1lIHBvaW50cy4KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIHVzZSB0aGUgaXJyZWd1bGFyX3h0cyBvYmplY3QgdG8gY3JlYXRlIGEgemVyby13aWR0aCB4dHMgb2JqZWN0IHRoYXQgaGFzIGEgcmVndWxhciBkYWlseSBpbmRleC4gQSB6ZXJvLXdpZHRoIHh0cyBvYmplY3QgaGFzIGFuIGluZGV4IG9mIGRhdGUtdGltZXMsIGJ1dCBubyBkYXRhIGNvbHVtbnMuCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQppcnJlZ3VsYXJfeHRzIDwtIHJiaW5kKHN0cnVjdHVyZShjKDRMLCAyMUwsIDFMLCAzNEwpLCAuRGltID0gYyg0TCwgMUwpLCBpbmRleCA9IHN0cnVjdHVyZShjKDE0NTE2OTI4MDAsIAoxNDUxOTUyMDAwLCAxNDUyMTI0ODAwLCAxNDUyNDcwNDAwKSwgdHpvbmUgPSAiVVRDIiwgdGNsYXNzID0gIkRhdGUiKSwgY2xhc3MgPSBjKCJ4dHMiLCAKInpvbyIpLCAuRGltbmFtZXMgPSBsaXN0KE5VTEwsICJkYXRhIikpKQpgYGAKCmBgYHtyfQojIEV4dHJhY3QgdGhlIHN0YXJ0IGRhdGUgb2YgdGhlIHNlcmllcwpzdGFydF9kYXRlIDwtIHN0YXJ0KGlycmVndWxhcl94dHMpCgojIEV4dHJhY3QgdGhlIGVuZCBkYXRlIG9mIHRoZSBzZXJpZXMKZW5kX2RhdGUgPC0gZW5kKGlycmVndWxhcl94dHMpCgojIENyZWF0ZSBhIHJlZ3VsYXIgZGF0ZSBzZXF1ZW5jZQpyZWd1bGFyX2luZGV4IDwtIHNlcShmcm9tID0gc3RhcnRfZGF0ZSwgdG8gPSBlbmRfZGF0ZSwgYnkgPSAiZGF5IikKCiMgQ3JlYXRlIGEgemVyby13aWR0aCB4dHMgb2JqZWN0CnJlZ3VsYXJfeHRzIDwtIHh0cyhzZXFfYWxvbmcocmVndWxhcl9pbmRleCksIG9yZGVyLmJ5ID0gcmVndWxhcl9pbmRleCkKYGBgCmBgYHtyfQpyZWd1bGFyX3h0cwpgYGAKIE1ha2luZyByZWd1bGFyIGRhdGUtdGltZSBzZXF1ZW5jZXMgaXMgdXNlZnVsIGluIG1hbnkgdGltZS1zZXJpZXMgYXBwbGljYXRpb25zLgoKIyMjIFVzZSBtZXJnZSB0byBtYWtlIGFuIGlycmVndWxhciBpbmRleCByZWd1bGFyCgpUaGUgcHJldmlvdXMgZXhlcmNpc2UgdGF1Z2h0IHlvdSBob3cgdG8gbWFrZSBhIHplcm8td2lkdGggeHRzIG9iamVjdCB3aXRoIGEgcmVndWxhciB0aW1lIGluZGV4LiBZb3UgY2FuIHVzZSB0aGUgemVyby13aWR0aCBvYmplY3QgdG8gcmVndWxhcml6ZSBhbiBpcnJlZ3VsYXIgeHRzIG9iamVjdC4KClRoZSByZWd1bGFyaXplZCBzZXJpZXMgdXN1YWxseSBoYXMgbWlzc2luZyB2YWx1ZXMgKE5BKSBiZWNhdXNlIHRoZSBpcnJlZ3VsYXIgZGF0YSBkb2VzIG5vdCBoYXZlIGEgdmFsdWUgZm9yIGFsbCBvYnNlcnZhdGlvbnMgaW4gdGhlIHJlZ3VsYXIgaW5kZXguIFRoaXMgZXhlcmNpc2Ugd2lsbCB0ZWFjaCB5b3UgaG93IHRvIGhhbmRsZSB0aGVzZSBtaXNzaW5nIHZhbHVlcyB3aGVuIHlvdSBtZXJnZSgpIHRoZSB0d28gc2VyaWVzLgoKYGBge3J9CiMgTWVyZ2UgaXJyZWd1bGFyX3h0cyBhbmQgcmVndWxhcl94dHMKbWVyZ2VkX3h0cyA8LSBtZXJnZShpcnJlZ3VsYXJfeHRzLCByZWd1bGFyX3h0cykKCiMgTG9vayBhdCB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgbWVyZ2VkX3h0cwpoZWFkKG1lcmdlZF94dHMpCgojIFVzZSB0aGUgZmlsbCBhcmd1bWVudCB0byBmaWxsIE5BIHdpdGggdGhlaXIgcHJldmlvdXMgdmFsdWUKbWVyZ2VkX2ZpbGxlZF94dHMgPC0gbWVyZ2UoaXJyZWd1bGFyX3h0cywgcmVndWxhcl94dHMsIGZpbGwgPSBuYS5sb2NmKQoKIyBMb29rIGF0IHRoZSBmaXJzdCBmZXcgcm93cyBvZiBtZXJnZWRfZmlsbGVkX3h0cwpoZWFkKG1lcmdlZF9maWxsZWRfeHRzKQpgYGAKRmlsbGluZyBmb3J3YXJkIGlzIGEgdXNlZnVsIG9wZXJhdGlvbiwgYnV0IGJlIGNhcmVmdWwgdG8gbWFrZSBzdXJlIGl0IGlzIHdoYXQgeW91IHdhbnQhCgojIyBBZ2dyZWdhdGluZyB0byBsb3dlciBmcmVxdWVuY3kKCiMjIyBBZ2dyZWdhdGUgZGFpbHkgZGF0YSBhbmQgbWVyZ2Ugd2l0aCBtb250aGx5IGRhdGEKClNvbWV0aW1lcyB0d28gc2VyaWVzIGhhdmUgdGhlIHNhbWUgcGVyaW9kaWN5LCBidXQgdXNlIGRpZmZlcmVudCBjb252ZW50aW9ucyB0byByZXByZXNlbnQgYSB0aW1lc3RhbXAuIEZvciBleGFtcGxlLCBtb250aGx5IHNlcmllcyBtYXkgYmUgdGltZXN0YW1wZWQgd2l0aCB0aGUgZmlyc3Qgb3IgbGFzdCBkYXRlIG9mIHRoZSBtb250aC4gVGhlIGRpZmZlcmVudCB0aW1lc3RhbXAgY29udmVudGlvbiBjYW4gY2F1c2UgbWFueSBOQSB3aGVuIHNlcmllcyBhcmUgbWVyZ2VkLiBUaGUgeWVhcm1vbiBjbGFzcyBmcm9tIHRoZSB6b28gcGFja2FnZSBoZWxwcyBzb2x2ZSB0aGlzIHByb2JsZW0uCgpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBhZ2dyZWdhdGUgdGhlIEZSRUQgZGFpbHkgRmVkIEZ1bmRzIHJhdGUgKERGRikgdG8gYSBtb250aGx5IHBlcmlvZGljeSBhbmQgbWVyZ2UgaXQgd2l0aCB0aGUgRlJFRCBtb250aGx5IEZlZCBGdW5kcyByYXRlIChGRURGVU5EUykuVGhlIERGRiBhZ2dyZWdhdGUgd2lsbCBiZSB0aW1lc3RhbXBlZCB3aXRoIHRoZSBsYXN0IHJvdyBvZiB0aGUgbW9udGgsIHdoaWxlIEZFREZVTkRTIGlzIHRpbWVzdGFtcGVkIHdpdGggdGhlIGZpcnN0IGRheSBvZiB0aGUgbW9udGguCmBgYHtyfQpnZXRTeW1ib2xzKGMoIkZFREZVTkRTIiwgIkRGRiIpLCBzcmMgPSAiRlJFRCIpCmBgYApgYGB7cn0KIyBBZ2dyZWdhdGUgREZGIHRvIG1vbnRobHkKbW9udGhseV9mZWRmdW5kcyA8LSBhcHBseS5tb250aGx5KERGRiwgbWVhbiwgbmEucm0gPSBUUlVFKQoKIyBDb252ZXJ0IGluZGV4IHRvIHllYXJtb24KaW5kZXgobW9udGhseV9mZWRmdW5kcykgPC0gYXMueWVhcm1vbihpbmRleChtb250aGx5X2ZlZGZ1bmRzKSkKCiMgTWVyZ2UgRkVERlVORFMgd2l0aCB0aGUgbW9udGhseSBhZ2dyZWdhdGUKbWVyZ2VkX2ZlZGZ1bmRzIDwtIG1lcmdlKEZFREZVTkRTLCBtb250aGx5X2ZlZGZ1bmRzKQoKIyBMb29rIGF0IHRoZSBmaXJzdCBmZXcgcm93cyBvZiB0aGUgbWVyZ2VkIG9iamVjdApoZWFkKG1lcmdlZF9mZWRmdW5kcykKYGBgCllvdSB3aWxsIG9mdGVuIG5lZWQgdG8gYWdncmVnYXRlIHRvIGEgbG93ZXIgZnJlcXVlbmN5IHRvIGFsaWduIG11bHRpcGxlIHRpbWUgc2VyaWVzLgoKIyMjIEFsaWduIHNlcmllcyB0byBmaXJzdCBhbmQgbGFzdCBkYXkgb2YgbW9udGgKClNvbWV0aW1lcyB5b3UgbWF5IG5vdCBiZSBhYmxlIHRvIHVzZSBjb252ZW5pZW5jZSBjbGFzc2VzIGxpa2UgeWVhcm1vbiB0byByZXByZXNlbnQgdGltZXN0YW1wcy4gVGhpcyBleGVyY2lzZSB3aWxsIHRlYWNoIHlvdSBob3cgdG8gbWFudWFsbHkgYWxpZ24gbWVyZ2VkIGRhdGEgdG8gdGhlIHRpbWVzdGFtcCByZXByZXNlbnRhdGlvbiB5b3UgcHJlZmVyLgoKRmlyc3QgeW91IG1lcmdlIHRoZSBsb3dlci1mcmVxdWVuY3kgZGF0YSB3aXRoIHRoZSBhZ2dyZWdhdGUgZGF0YSwgdGhlbiB1c2UgbmEubG9jZigpIHRvIGZpbGwgdGhlIE5BIGZvcndhcmQgKG9yIGJhY2t3YXJkLCB1c2luZyBmcm9tTGFzdCA9IFRSVUUpLiBUaGVuIHlvdSBjYW4gc3Vic2V0IHRoZSByZXN1bHQgdXNpbmcgdGhlIGluZGV4IG9mIHRoZSBvYmplY3Qgd2l0aCB0aGUgcmVwcmVzZW50YXRpb24geW91IHByZWZlci4KCmBgYHtyfQojIEFnZ3JlZ2F0ZSBERkYgdG8gbW9udGhseQptb250aGx5X2ZlZGZ1bmRzIDwtIGFwcGx5Lm1vbnRobHkoREZGLCBtZWFuLCBuYS5ybSA9IFRSVUUpCgojIE1lcmdlIEZFREZVTkRTIHdpdGggdGhlIG1vbnRobHkgYWdncmVnYXRlCm1lcmdlZF9mZWRmdW5kcyA8LSBtZXJnZShGRURGVU5EUywgbW9udGhseV9mZWRmdW5kcykKCiMgTG9vayBhdCB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgdGhlIG1lcmdlZCBvYmplY3QKaGVhZChtZXJnZWRfZmVkZnVuZHMpCmBgYApgYGB7cn0KIyBGaWxsIE5BIGZvcndhcmQKbWVyZ2VkX2ZlZGZ1bmRzX2xvY2YgPC0gbmEubG9jZihtZXJnZWRfZmVkZnVuZHMpCgojIEV4dHJhY3QgaW5kZXggdmFsdWVzIGNvbnRhaW5pbmcgbGFzdCBkYXkgb2YgbW9udGgKYWxpZ25lZF9sYXN0X2RheSA8LSBtZXJnZWRfZmVkZnVuZHNfbG9jZltpbmRleChtb250aGx5X2ZlZGZ1bmRzKV0KaGVhZChhbGlnbmVkX2xhc3RfZGF5KQojIEZpbGwgTkEgYmFja3dhcmQKbWVyZ2VkX2ZlZGZ1bmRzX2xvY2IgPC0gbmEubG9jZihtZXJnZWRfZmVkZnVuZHMsIGZyb21MYXN0ID0gVFJVRSkKCiMgRXh0cmFjdCBpbmRleCB2YWx1ZXMgY29udGFpbmluZyBmaXJzdCBkYXkgb2YgbW9udGgKYWxpZ25lZF9maXJzdF9kYXkgPC0gbWVyZ2VkX2ZlZGZ1bmRzX2xvY2JbaW5kZXgoRkVERlVORFMpXQpoZWFkKGFsaWduZWRfZmlyc3RfZGF5KQpgYGAKS25vd2luZyBob3cgdG8gbWFudWFsbHkgYWxpZ24gbWVyZ2VkIGRhdGEgd2lsbCBkZWZpbml0ZWx5IGNvbWUgaW4gaGFuZHkhCgojIyMgQWdncmVnYXRlIHRvIHdlZWtseSwgZW5kaW5nIG9uIFdlZG5lc2RheXMKCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGxlYXJuIGEgZ2VuZXJhbCBhZ2dyZWdhdGlvbiB0ZWNobmlxdWUgdG8gYWdncmVnYXRlIGRhaWx5IGRhdGEgdG8gd2Vla2x5LCBidXQgd2l0aCB3ZWVrcyBlbmRpbmcgb24gV2VkbmVzZGF5cy4gVGhpcyBpcyBvZnRlbiBkb25lIGluIHN0b2NrIG1hcmtldCByZXNlYXJjaCB0byBhdm9pZCBpbnRyYS13ZWVrIHNlYXNvbmFsaXR5LgoKWW91IGNhbiBzdXBwbHkgeW91ciBvd24gZW5kIHBvaW50cyB0byBwZXJpb2QuYXBwbHkoKSAodmVyc3VzIHVzaW5nIGVuZHBvaW50cygpKS4gUmVjYWxsIGVuZHBvaW50cygpIHJldHVybnMgbG9jYXRpb25zIG9mIHRoZSBsYXN0IG9ic2VydmF0aW9uIGluIGVhY2ggcGVyaW9kIHNwZWNpZmllZCBieSB0aGUgb24gYXJndW1lbnQuIFRoZSBmaXJzdCBhbmQgbGFzdCBlbGVtZW50cyBvZiB0aGUgcmVzdWx0IGFyZSBhbHdheXMgemVybyBhbmQgdGhlIHRvdGFsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMsIHJlc3BlY3RpdmVseS4gVGhlIGVuZCBwb2ludHMgeW91IHBhc3MgdG8gcGVyaW9kLmFwcGx5KCkgbXVzdCBmb2xsb3cgdGhpcyBjb252ZW50aW9uLgoKYGBge3J9CiMgRXh0cmFjdCBpbmRleCB3ZWVrZGF5cwppbmRleF93ZWVrZGF5cyA8LSAuaW5kZXh3ZGF5KERGRikKCiMgRmluZCBsb2NhdGlvbnMgb2YgV2VkbmVzZGF5cwp3ZWRuZXNkYXlzIDwtIHdoaWNoKGluZGV4X3dlZWtkYXlzID09IDMpCgojIENyZWF0ZSBjdXN0b20gZW5kIHBvaW50cwplbmRfcG9pbnRzIDwtIGMoMCwgd2VkbmVzZGF5cywgbnJvdyhERkYpKQoKIyBDYWxjdWxhdGUgd2Vla2x5IG1lYW4gdXNpbmcgY3VzdG9tIGVuZCBwb2ludHMKd2Vla2x5X21lYW4gPC0gcGVyaW9kLmFwcGx5KERGRiwgZW5kX3BvaW50cywgbWVhbikKaGVhZCh3ZWVrbHlfbWVhbikKYGBgClRoZXJlIGFyZSBtYW55IHdheXMgdG8gY29udmVydCBhIHRpbWUgc2VyaWVzIHRvIGEgbG93ZXIgZnJlcXVlbmN5LgoKIyMgQWdncmVnYXRpbmcgYW5kIGNvbWJpbmluZyBpbnRyYWRheSBkYXRhCgojIyMgQ29tYmluZSBkYXRhIHRoYXQgaGF2ZSB0aW1lem9uZXMKClJlY2FsbCB0aGF0IHh0cyBvYmplY3RzIHN0b3JlIHRoZSB0aW1lIGluZGV4IGFzIHNlY29uZHMgc2luY2UgbWlkbmlnaHQsIDE5NzAtMDEtMDEgaW4gdGhlIFVUQyB0aW1lem9uZS4gbWVyZ2UoKSB1c2VzIHRoaXMgdW5kZXJseWluZyBpbmRleCBhbmQgcmV0dXJucyBhIHJlc3VsdCB3aXRoIHRoZSBmaXJzdCBvYmplY3QncyB0aW1lem9uZS4KClRoaXMgZXhlcmNpc2UgcHJvdmlkZXMgYW4gZXhhbXBsZS4gVGhlIHR3byBvYmplY3RzIGluIHlvdXIgd29ya3NwYWNlIGFyZSBpZGVudGljYWwgZXhjZXB0IGZvciB0aGUgaW5kZXggdGltZXpvbmUuIFRoZSBpbmRleCB2YWx1ZXMgYXJlIHRoZSBzYW1lIGluc3RhbmNlcyBpbiB0aW1lLCBidXQgbWVhc3VyZWQgaW4gZGlmZmVyZW50IGxvY2F0aW9ucy4gVGhlIGxvbmRvbiBvYmplY3QncyB0aW1lem9uZSBpcyBFdXJvcGUvTG9uZG9uIGFuZCB0aGUgY2hpY2FnbyBvYmplY3QncyB0aW1lem9uZSBpcyBBbWVyaWNhL0NoaWNhZ28uCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpsb25kb24gPC0gcmJpbmQoc3RydWN0dXJlKDE6NSwgLkRpbSA9IGMoNUwsIDFMKSwgaW5kZXggPSBzdHJ1Y3R1cmUoYygxMjYyNzU3NjAwLCAKMTI2MzIyNTYwMCwgMTI2MzIzNjQwMCwgMTI2MzI0MDAwMCwgMTI2MzQ1NjAwMCksIHR6b25lID0gIkV1cm9wZS9Mb25kb24iLCB0Y2xhc3MgPSBjKCJQT1NJWGN0IiwgCiJQT1NJWHQiKSksIGNsYXNzID0gYygieHRzIiwgInpvbyIpLCAuRGltbmFtZXMgPSBsaXN0KE5VTEwsICJMb25kb24iKSkpCgpjaGljYWdvIDwtIHJiaW5kKHN0cnVjdHVyZSgxOjUsIC5EaW0gPSBjKDVMLCAxTCksIGluZGV4ID0gc3RydWN0dXJlKGMoMTI2Mjc1NzYwMCwgCjEyNjMyMjU2MDAsIDEyNjMyMzY0MDAsIDEyNjMyNDAwMDAsIDEyNjM0NTYwMDApLCB0em9uZSA9ICJBbWVyaWNhL0NoaWNhZ28iLCB0Y2xhc3MgPSBjKCJQT1NJWGN0IiwgCiJQT1NJWHQiKSksIGNsYXNzID0gYygieHRzIiwgInpvbyIpLCAuRGltbmFtZXMgPSBsaXN0KE5VTEwsICJDaGljYWdvIikpKQpgYGAKYGBge3J9CiMgQ3JlYXRlIG1lcmdlZCBvYmplY3Qgd2l0aCBhIEV1cm9wZS9Mb25kb24gdGltZXpvbmUKdHpfbG9uZG9uIDwtIG1lcmdlKGxvbmRvbiwgY2hpY2FnbykKCiMgTG9vayBhdCB0el9sb25kb24gc3RydWN0dXJlCnN0cih0el9sb25kb24pCgojIENyZWF0ZSBtZXJnZWQgb2JqZWN0IHdpdGggYSBBbWVyaWNhL0NoaWNhZ28gdGltZXpvbmUKdHpfY2hpY2FnbyA8LSBtZXJnZShjaGljYWdvLCBsb25kb24pCgojIExvb2sgYXQgdHpfY2hpY2FnbyBzdHJ1Y3R1cmUKc3RyKHR6X2NoaWNhZ28pCmBgYAojIyMgTWFrZSBpcnJlZ3VsYXIgaW50cmFkYXktZGF5IGRhdGEgcmVndWxhcgoKRWFybGllciB5b3UgbGVhcm5lZCBob3cgdG8gY3JlYXRlIGEgcmVndWxhciBkYWlseSBzZXJpZXMgZnJvbSBpcnJlZ3VsYXIgZGFpbHkgZGF0YS4gTm93IHlvdSB3aWxsIGNyZWF0ZSByZWd1bGFyIGludHJhLWRheSBkYXRhIGZyb20gYW4gaXJyZWd1bGFyIHNlcmllcy4KCkludHJhLWRheSBmaW5hbmNpYWwgZGF0YSBvZnRlbiBkb2VzIG5vdCBzcGFuIGEgZnVsbCAyNCBob3VyIHBlcmlvZC4gTW9zdCBtYXJrZXRzIGFyZSB1c3VhbGx5IGNsb3NlZCBhdCBsZWFzdCBwYXJ0IG9mIHRoZSBkYXkuIFRoaXMgZXhlcmNpc2UgYXNzdW1lcyBtYXJrZXRzIG9wZW4gYXQgOUFNIGFuZCBjbG9zZSBhdCA0UE0gTW9uZGF5LUZyaWRheS4KCllvdXIgZGF0YSBtYXkgbm90IGhhdmUgYW4gb2JzZXJ2YXRpb24gZXhhY3RseSBhdCB0aGUgbWFya2V0IG9wZW4gYW5kL29yIGNsb3NlLiBTbywgeW91IHdvdWxkIG5vdCBiZSBhYmxlIHRvIHVzZSBzdGFydCgpIGFuZCBlbmQoKSBhcyB5b3UgY291bGQgd2l0aCB0aGUgZGFpbHkgZGF0YS4gWW91IG5lZWQgdG8gc3BlY2lmeSB0aGUgc3RhcnQgYW5kIGVuZCBkYXRlLXRpbWVzIHRvIGNyZWF0ZSB0aGlzIHJlZ3VsYXIgc2VxdWVuY2UuCgpUaGUgcmVndWxhciBkYXRlLXRpbWUgc2VxdWVuY2Ugd2lsbCBpbmNsdWRlIHBlcmlvZHMgd2hlbiBtYXJrZXRzIGFyZSBjbG9zZWQsIGJ1dCB5b3UgY2FuIHVzZSB4dHMnIHRpbWUtb2YtZGF5IHN1YnNldHRpbmcgdG8gZXh0cmFjdCBwZXJpb2RzIHRoZSBtYXJrZXQgaXMgb3Blbi4KYGBge3IgaW5jbHVkZT1GQUxTRX0KaXJyZWd1bGFyX3h0cyA8LSByYmluZChzdHJ1Y3R1cmUoMToyMCwgLkRpbSA9IGMoMjBMLCAxTCksIGluZGV4ID0gc3RydWN0dXJlKGMoMTI2MjYwNjQwMCwgCjEyNjI2MTM2MDAsIDEyNjI2MjgwMDAsIDEyNjI2NDk2MDAsIDEyNjI2NTMyMDAsIDEyNjI2NjA0MDAsIDEyNjI2ODIwMDAsIAoxMjYyNjg5MjAwLCAxMjYyNzQ2ODAwLCAxMjYyNzYxMjAwLCAxMjYyNzg2NDAwLCAxMjYyNzk3MjAwLCAxMjYyODE4ODAwLCAKMTI2Mjg1MTIwMCwgMTI2Mjg4MzYwMCwgMTI2Mjg4NzIwMCwgMTI2MjkwNTIwMCwgMTI2MjkxOTYwMCwgMTI2MjkzNDAwMCwgCjEyNjI5Mzc2MDApLCB0em9uZSA9ICIiLCB0Y2xhc3MgPSBjKCJQT1NJWGN0IiwgIlBPU0lYdCIpKSwgY2xhc3MgPSBjKCJ4dHMiLCAKInpvbyIpLCAuRGltbmFtZXMgPSBsaXN0KE5VTEwsICJkYXRhIikpKQpgYGAKCmBgYHtyfQojIENyZWF0ZSBhIHJlZ3VsYXIgZGF0ZS10aW1lIHNlcXVlbmNlCnJlZ3VsYXJfaW5kZXggPC0gc2VxKGFzLlBPU0lYY3QoIjIwMTAtMDEtMDQgMDk6MDAiKSwgYXMuUE9TSVhjdCgiMjAxMC0wMS0wOCAxNjowMCIpLCBieSA9ICIzMCBtaW4iKQoKIyBDcmVhdGUgYSB6ZXJvLXdpZHRoIHh0cyBvYmplY3QKcmVndWxhcl94dHMgPC0geHRzKHggPSBOVUxMLCBvcmRlci5ieSA9IHJlZ3VsYXJfaW5kZXgpCgojIE1lcmdlIGlycmVndWxhcl94dHMgYW5kIHJlZ3VsYXJfeHRzLCBmaWxsaW5nIE5BIHdpdGggdGhlaXIgcHJldmlvdXMgdmFsdWUKbWVyZ2VkX3h0cyA8LSBtZXJnZShpcnJlZ3VsYXJfeHRzLCByZWd1bGFyX3h0cywgZmlsbCA9IG5hLmxvY2YpCgojIFN1YnNldCB0byB0cmFkaW5nIGRheSAoOUFNIC0gNFBNKQp0cmFkZV9kYXkgPC0gbWVyZ2VkX3h0c1siVDA5OjAwL1QxNjowMCJdCnRyYWRlX2RheQpgYGAKTm93IHlvdSBrbm93IGhvdyB0byBzdWJzZXQgeW91ciBpbnRyYS1kYXkgZGF0YSB0byBvbmx5IGNvbnRhaW4gdGhlIHRyYWRpbmcgZGF5IQoKIyMjIEZpbGwgbWlzc2luZyB2YWx1ZXMgYnkgdHJhZGluZyBkYXkKClRoZSBwcmV2aW91cyBleGVyY2lzZSBjYXJyaWVkIHRoZSBsYXN0IG9ic2VydmF0aW9uIG9mIHRoZSBwcmlvciBkYXkgZm9yd2FyZCBpbnRvIHRoZSBmaXJzdCBvYnNlcnZhdGlvbiBvZiB0aGUgZm9sbG93aW5nIGRheS4gVGhpcyBleGVyY2lzZSB3aWxsIHNob3cgeW91IGhvdyB0byBmaWxsIG1pc3NpbmcgdmFsdWVzIGJ5IHRyYWRpbmcgZGF5LCB3aXRob3V0IHVzaW5nIHRoZSBwcmlvciBkYXkncyBmaW5hbCB2YWx1ZS4KCllvdSB3aWxsIHVzZSB0aGUgc2FtZSBzcGxpdC1sYXBwbHktcmJpbmQgcGFyYWRpZ20gZnJvbSB0aGUgSW50cm9kdWN0aW9uIHRvIHh0cyBhbmQgem9vIGNvdXJzZS4gRm9yIHJlZmVyZW5jZSwgdGhlIHBhdHRlcm4gaXMgYmVsb3cuCgogICAgeF9zcGxpdCA8LSBzcGxpdCh4LCBmID0gIm1vbnRocyIpCiAgICB4X2xpc3QgPC0gbGFwcGx5KHhfc3BsaXQsIGN1bW1heCkKICAgIHhfbGlzdF9yYmluZCA8LSBkby5jYWxsKHJiaW5kLCB4X2xpc3QpCgpSZWNhbGwgdGhhdCB0aGUgZG8uY2FsbChyYmluZCwgLi4uKSBzeW50YXggYWxsb3dzIHlvdSB0byBwYXNzIGEgbGlzdCBvZiBvYmplY3RzIHRvIHJiaW5kKCkgaW5zdGVhZCBvZiBoYXZpbmcgdG8gdHlwZSBhbGwgdGhlaXIgbmFtZXMuCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQp0cmFkZV9kYXkgPC0gcmJpbmQoc3RydWN0dXJlKGMoTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgMUwsIE5BLCBOQSwgTkEsIDJMLCBOQSwgTkEsIApOQSwgTkEsIDdMLCBOQSwgTkEsIE5BLCA4TCwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgCk5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgMTFMLCBOQSwgTkEsIE5BLCAKTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIApOQSwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BLCBOQSwgTkEsIE5BKSwgY2xhc3MgPSBjKCJ4dHMiLCAKInpvbyIpLCBpbmRleCA9IHN0cnVjdHVyZShjKDEyNjI1OTU2MDAsIDEyNjI1OTc0MDAsIDEyNjI1OTkyMDAsIAoxMjYyNjAxMDAwLCAxMjYyNjAyODAwLCAxMjYyNjA0NjAwLCAxMjYyNjA2NDAwLCAxMjYyNjA4MjAwLCAxMjYyNjEwMDAwLCAKMTI2MjYxMTgwMCwgMTI2MjYxMzYwMCwgMTI2MjYxNTQwMCwgMTI2MjYxNzIwMCwgMTI2MjYxOTAwMCwgMTI2MjYyMDgwMCwgCjEyNjI2ODIwMDAsIDEyNjI2ODM4MDAsIDEyNjI2ODU2MDAsIDEyNjI2ODc0MDAsIDEyNjI2ODkyMDAsIDEyNjI2OTEwMDAsIAoxMjYyNjkyODAwLCAxMjYyNjk0NjAwLCAxMjYyNjk2NDAwLCAxMjYyNjk4MjAwLCAxMjYyNzAwMDAwLCAxMjYyNzAxODAwLCAKMTI2MjcwMzYwMCwgMTI2MjcwNTQwMCwgMTI2MjcwNzIwMCwgMTI2Mjc2ODQwMCwgMTI2Mjc3MDIwMCwgMTI2Mjc3MjAwMCwgCjEyNjI3NzM4MDAsIDEyNjI3NzU2MDAsIDEyNjI3Nzc0MDAsIDEyNjI3NzkyMDAsIDEyNjI3ODEwMDAsIDEyNjI3ODI4MDAsIAoxMjYyNzg0NjAwLCAxMjYyNzg2NDAwLCAxMjYyNzg4MjAwLCAxMjYyNzkwMDAwLCAxMjYyNzkxODAwLCAxMjYyNzkzNjAwLCAKMTI2Mjg1NDgwMCwgMTI2Mjg1NjYwMCwgMTI2Mjg1ODQwMCwgMTI2Mjg2MDIwMCwgMTI2Mjg2MjAwMCwgMTI2Mjg2MzgwMCwgCjEyNjI4NjU2MDAsIDEyNjI4Njc0MDAsIDEyNjI4NjkyMDAsIDEyNjI4NzEwMDAsIDEyNjI4NzI4MDAsIDEyNjI4NzQ2MDAsIAoxMjYyODc2NDAwLCAxMjYyODc4MjAwLCAxMjYyODgwMDAwLCAxMjYyOTQxMjAwLCAxMjYyOTQzMDAwLCAxMjYyOTQ0ODAwLCAKMTI2Mjk0NjYwMCwgMTI2Mjk0ODQwMCwgMTI2Mjk1MDIwMCwgMTI2Mjk1MjAwMCwgMTI2Mjk1MzgwMCwgMTI2Mjk1NTYwMCwgCjEyNjI5NTc0MDAsIDEyNjI5NTkyMDAsIDEyNjI5NjEwMDAsIDEyNjI5NjI4MDAsIDEyNjI5NjQ2MDAsIDEyNjI5NjY0MDAKKSwgdHpvbmUgPSAiIiwgdGNsYXNzID0gYygiUE9TSVhjdCIsICJQT1NJWHQiKSksIC5EaW0gPSBjKDc1TCwgCjFMKSwgLkRpbW5hbWVzID0gbGlzdChOVUxMLCAiZGF0YSIpKSkKYGBgCgpgYGB7cn0KIyBTcGxpdCB0cmFkZV9kYXkgaW50byBkYXlzCmRhaWx5X2xpc3QgPC0gc3BsaXQodHJhZGVfZGF5ICwgZiA9ICJkYXlzIikKCiMgVXNlIGxhcHBseSB0byBjYWxsIG5hLmxvY2YgZm9yIGVhY2ggZGF5IGluIGRhaWx5X2xpc3QKZGFpbHlfZmlsbGVkIDwtIGxhcHBseShkYWlseV9saXN0LCBGVU4gPSBuYS5sb2NmKQoKIyBVc2UgZG8uY2FsbCB0byByYmluZCB0aGUgcmVzdWx0cwpmaWxsZWRfYnlfdHJhZGVfZGF5IDwtIGRvLmNhbGwocmJpbmQsIGRhaWx5X2ZpbGxlZCkKZmlsbGVkX2J5X3RyYWRlX2RheQpgYGAKWW91IHVzZWQgYWR2YW5jZWQgZnVuY3Rpb25zIHRvIHRyYW5zZm9ybSBkYXRhIGZvciBlYWNoIHRyYWRpbmcgZGF5IQoKIyMjIEFnZ3JlZ2F0ZSBpcnJlZ3VsYXIgaW50cmFkYXktZGF5IGRhdGEKCkludHJhZGF5IGRhdGEgY2FuIGJlIGh1Z2UsIHdpdGggaHVuZHJlZHMgb2YgdGhvdXNhbmRzIG9mIG9ic2VydmF0aW9ucyBwZXIgZGF5LCBtaWxsaW9ucyBwZXIgbW9udGgsIGFuZCBodW5kcmVkcyBvZiBtaWxsaW9ucyBwZXIgeWVhci4gVGhlc2UgZGF0YSBzZXRzIG9mdGVuIG5lZWQgdG8gYmUgYWdncmVnYXRlZCBiZWZvcmUgeW91IGNhbiB3b3JrIHdpdGggdGhlbS4KCllvdSBsZWFybmVkIGhvdyB0byBhZ2dyZWdhdGUgZGFpbHkgZGF0YSBpbiB0aGUgSW50cm9kdWN0aW9uIHRvIHh0cyBhbmQgem9vIGNvdXJzZS4gVGhpcyBleGVyY2lzZSB3aWxsIHVzZSB0by5wZXJpb2QoKSB0byBhZ2dyZWdhdGUgaW50cmFkYXkgZGF0YSB0byBhbiBPSExDIHNlcmllcy4gWW91IG9mdGVuIG5lZWQgdG8gc3BlY2lmeSBib3RoIHBlcmlvZCBhbmQgayBhcmd1bWVudHMgdG8gYWdncmVnYXRlIGludHJhZGF5IGRhdGEuCgpgYGB7cn0KbG9hZCgiREMuUkRhdGEiKQoKZGNfaW50cmFkYXkgPC0gRENbLDFdCmBgYApgYGB7cn0KIyBDb252ZXJ0IHJhdyBwcmljZXMgdG8gNS1zZWNvbmQgcHJpY2VzCnh0c181c2VjIDwtIHRvLnBlcmlvZChkY19pbnRyYWRheSwgcGVyaW9kID0gInNlY29uZHMiLCBrID0gNSkKaGVhZCh4dHNfNXNlYykKIyBDb252ZXJ0IHJhdyBwcmljZXMgdG8gMTAtbWludXRlIHByaWNlcwp4dHNfMTBtaW4gPC0gdG8ucGVyaW9kKGRjX2ludHJhZGF5LCBwZXJpb2QgPSAibWludXRlcyIsIGsgPSAxMCkKaGVhZCh4dHNfMTBtaW4pCiMgQ29udmVydCByYXcgcHJpY2VzIHRvIDEtaG91ciBwcmljZXMKeHRzXzFob3VyIDwtIHRvLnBlcmlvZChkY19pbnRyYWRheSwgcGVyaW9kID0gImhvdXJzIiwgayA9IDEpCmhlYWQoeHRzXzFob3VyKQpgYGAKIyBJbXBvcnRpbmcgdGV4dCBkYXRhLCBhbmQgYWRqdXN0aW5nIGZvciBjb3Jwb3JhdGUgYWN0aW9ucwoKIyMgSW1wb3J0aW5nIHRleHQgZmlsZXMKCiMjIyBJbXBvcnQgd2VsbC1mb3JtYXR0ZWQgZGFpbHkgT0hMQyBkYXRhCgpZb3UgY2FuIHVzZSBnZXRTeW1ib2xzKCkgdG8gaW1wb3J0IGEgd2VsbC1mb3JtYXR0ZWQgQ1NWLiBJbiB0aGlzIGNhc2UsIHdlbGwtZm9ybWF0dGVkIG1lYW5zIHRoZSBmaWxlIGNvbnRhaW5zIGRhdGEgZm9yIGEgc2luZ2xlIGluc3RydW1lbnQgd2l0aCBkYXRlLCBvcGVuLCBoaWdoLCBsb3csIGNsb3NlLCB2b2x1bWUsIGFuZCBhZGp1c3RlZCBjbG9zZSBjb2x1bW5zLCBpbiB0aGF0IG9yZGVyLiBZb3UgbWlnaHQgaGF2ZSBub3RpY2VkIHRoYXQgdGhpcyBpcyB0aGUgc2FtZSBmb3JtYXQgYXMgZ2V0U3ltYm9scygpIHJldHVybnMgd2hlbiB5b3UgZG93bmxvYWQgZGF0YSBmcm9tIGludGVybmV0IHNvdXJjZXMuCgpnZXRTeW1ib2xzKCkgYWxsb3dzIHlvdSB0byB1c2UgYSBkaXJlY3Rvcnkgb2YgQ1NWIGZpbGVzIGFzIGEgc291cmNlIChsaWtlIFlhaG9vIEZpbmFuY2UgYW5kIEZSRUQpLiBJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBiZSB1c2luZyBBTVpOLmNzdiBpbiB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5LiBJdCBjb250YWlucyBzb21lIHJhbmRvbWl6ZWQgQW1hem9uLmNvbSBkYXRhIGZyb20gdGhlIGZpcnN0IGhhbGYgb2YgMjAwMi4gWW91IGNhbiB1c2UgZGlyKCkgdG8gc2VlIHRoZSBmaWxlIGluIHlvdXIgd29ya2luZyBkaXJlY3RvcnkuCmBgYHtyfQojIExvYWQgQU1aTi5jc3YKZ2V0U3ltYm9scygiQU1aTiIsIHNyYyA9ICJjc3YiKQoKIyBMb29rIGF0IEFNWk4gc3RydWN0dXJlCnN0cihBTVpOKQpgYGAKIyMjIEltcG9ydCB0ZXh0IGZpbGVzIGluIG90aGVyIGZvcm1hdHMKClRoZSBwcmV2aW91cyBleGVyY2lzZSB0YXVnaHQgeW91IGhvdyB0byBpbXBvcnQgd2VsbC1mb3JtYXR0ZWQgQ1NWIGRhdGEgdXNpbmcgZ2V0U3ltYm9scygpLiBVbmZvcnR1bmF0ZWx5LCBtb3N0IGRhdGEgYXJlIG5vdCB3ZWxsLWZvcm1hdHRlZC4KClRoZSB6b28gcGFja2FnZSBwcm92aWRlcyBzZXZlcmFsIGZ1bmN0aW9ucyB0byBpbXBvcnQgdGV4dCBmaWxlcyBhcyB6b28gb2JqZWN0cy4gVGhlIG1haW4gZnVuY3Rpb24gaXMgcmVhZC56b28oKSwgd2hpY2ggd3JhcHMgcmVhZC50YWJsZSgpLiBUaGUgeHRzIGNsYXNzIGV4dGVuZHMgem9vLCBzbyB5b3UgY2FuIGVhc2lseSBjb252ZXJ0IHRoZSByZXN1bHQgb2YgcmVhZC56b28oKSBpbnRvIGFuIHh0cyBvYmplY3QgYnkgdXNpbmcgYXMueHRzKCkuCgpgYGB7cn0KIyBJbXBvcnQgQU1aTi5jc3YgdXNpbmcgcmVhZC56b28KYW16bl96b28gPC0gcmVhZC56b28oIkFNWk4uY3N2Iiwgc2VwID0gIiwiLCBoZWFkZXIgPSBUUlVFKQoKIyBDb252ZXJ0IHRvIHh0cwphbXpuX3h0cyA8LSBhcy54dHMoYW16bl96b28pCgojIExvb2sgYXQgdGhlIGZpcnN0IGZldyByb3dzIG9mIGFtem5feHRzCmhlYWQoYW16bl94dHMpCmBgYApBcyB5b3Ugd2lsbCBzZWUsIHJlYWQuem9vKCkgaXMgYSB2ZXJ5IGZsZXhpYmxlIGltcG9ydCBmdW5jdGlvbiBmb3IgdGltZSBzZXJpZXMuCgojIyMgSGFuZGxlIGRhdGUgYW5kIHRpbWUgaW4gc2VwYXJhdGUgY29sdW1ucwoKcmVhZC56b28oKSBtYWtlcyBpdCBlYXN5IHRvIGltcG9ydCBkYXRhIHdoZW4gdGhlIGRhdGUgYW5kIHRpbWUgYXJlIGluIHNlcGFyYXRlIGNvbHVtbnMuIFRoZSBpbmRleC5jb2x1bW4gYXJndW1lbnQgYWxsb3dzIHlvdSB0byBzcGVjaWZ5IHRoZSBuYW1lIG9yIG51bWJlciBvZiB0aGUgY29sdW1uKHMpIGNvbnRhaW5pbmcgdGhlIGluZGV4IGRhdGEuIFRoYXQncyBhbGwgeW91IG5lZWQgdG8gZG8gaWYgdGhlIGRhdGUgYW5kIHRpbWUgYXJlIHNwZWNpZmllZCBpbiB0aGUgc3RhbmRhcmQgZm9ybWF0ICgiJVktJW0tJWQiIGZvciBkYXRlLCBhbmQgIiVIOiVNOiVTIiBmb3IgdGltZSkuCgpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCB1c2UgdGhlIGluZGV4LmNvbHVtbiBhcmd1bWVudCB0byBzcGVjaWZ5IHRoZSBkYXRlIGFuZCB0aW1lIGNvbHVtbnMgb2YgdGhlIGZpbGUuIFlvdXIgd29ya2luZyBkaXJlY3RvcnkgaGFzIGEgZmlsZSBuYW1lZCBVTkUuY3N2IHRoYXQgY29udGFpbnMgc29tZSA1LW1pbnV0ZSBPSExDIGRhdGEgZm9yIHRoZSBlbmVyZ3kgY29tcGFueSwgVW5yb24uIFlvdSB3aWxsIHN0aWxsIHVzZSByZWFkLmNzdigpIGZpbmQgdGhlIGNvbHVtbiBuYW1lcyBvZiB0aGUgZGF0ZSBhbmQgdGltZSBjb2x1bW5zLgpgYGB7cn0KIyBSZWFkIGRhdGEgd2l0aCByZWFkLmNzdgp1bmVfZGF0YSA8LSByZWFkLmNzdigiVU5FLmNzdiIsIG5yb3dzID0gNSkKCiMgTG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIHVuZV9kYXRhCnN0cih1bmVfZGF0YSkKYGBgCmBgYHtyfQojIFJlYWQgZGF0YSB3aXRoIHJlYWQuem9vLCBzcGVjaWZ5aW5nIGluZGV4IGNvbHVtbnMKdW5lX3pvbyA8LSByZWFkLnpvbygiVU5FLmNzdiIsIGluZGV4LmNvbHVtbiA9IGMoIkRhdGUiLCAiVGltZSIpLCBzZXAgPSAiLCIsIGhlYWRlciA9IFRSVUUpCgojIExvb2sgYXQgZmlyc3QgZmV3IHJvd3Mgb2YgZGF0YQpoZWFkKHVuZV96b28pCmBgYApUaGUgaW5kZXguY29sdW1uIGFyZ3VtZW50IGlzIGdyZWF0IGlmIHlvdXIgZGF0ZXMgYW5kIHRpbWVzIGFyZSBpbiBzZXBhcmF0ZSBjb2x1bW5zIQoKIyMjIFJlYWQgdGV4dCBmaWxlIGNvbnRhaW5pbmcgbXVsdGlwbGUgaW5zdHJ1bWVudHMKClRoZSBwcmV2aW91cyBleGVyY2lzZXMgd29yayBpZiBlYWNoIGZpbGUgY29udGFpbnMgb25seSBvbmUgaW5zdHJ1bWVudC4gU29tZSBzb2Z0d2FyZSBhbmQgZGF0YSB2ZW5kb3JzIG1heSBwcm92aWRlIGRhdGEgZm9yIGFsbCBpbnN0cnVtZW50cyBpbiBvbmUgZmlsZS4gVGhpcyBleGVyY2lzZSB3aWxsIHRlYWNoIHlvdSBob3cgdG8gaW1wb3J0IGEgZmlsZSB0aGF0IGNvbnRhaW5zIG11bHRpcGxlIGluc3RydW1lbnRzLgoKT25jZSBhZ2FpbiwgeW91IGNhbiB1c2UgcmVhZC56b28oKS4gVGhpcyB0aW1lIHlvdSB3aWxsIGJlIHVzaW5nIGl0cyBzcGxpdCBhcmd1bWVudCwgd2hpY2ggYWxsb3dzIHlvdSB0byBzcGVjaWZ5IHRoZSBuYW1lIG9yIG51bWJlciBvZiB0aGUgY29sdW1ucyhzKSB0aGF0IGNvbnRhaW4gdGhlIHZhcmlhYmxlcyB0aGF0IGlkZW50aWZ5IHVuaXF1ZSBvYnNlcnZhdGlvbnMuCgpUaGUgdHdvX3N5bWJvbHMuY3N2IGZpbGUgaW4geW91ciB3b3JraW5nIGRpcmVjdG9yeSBjb250YWlucyBiaWQvYXNrIGRhdGEgZm9yIHR3byBpbnN0cnVtZW50cywgd2hlcmUgZWFjaCByb3cgaGFzIG9uZSBiaWQgb3IgYXNrIG9ic2VydmF0aW9uIGZvciBvbmUgaW5zdHJ1bWVudC4gWW91IHdpbGwgdXNlIHRoZSBzcGxpdCBhcmd1bWVudCB0byBpbXBvcnQgdGhlIGRhdGEgaW50byBhbiBvYmplY3QgdGhhdCBoYXMgYm90aCBiaWQgYW5kIGFzayBwcmljZXMgZm9yIGJvdGggaW5zdHJ1bWVudHMgb24gb25lIHJvdy4KYGBge3J9CiMgUmVhZCBkYXRhIHdpdGggcmVhZC5jc3YKdHdvX3N5bWJvbHNfZGF0YSA8LSByZWFkLmNzdigidHdvX3N5bWJvbHMuY3N2IiwgbnJvd3MgPSA1KQoKIyBMb29rIGF0IHRoZSBzdHJ1Y3R1cmUgb2YgdHdvX3N5bWJvbHNfZGF0YQpzdHIodHdvX3N5bWJvbHNfZGF0YSkKYGBgCmBgYHtyfQojIFJlYWQgZGF0YSB3aXRoIHJlYWQuem9vLCBzcGVjaWZ5aW5nIGluZGV4IGNvbHVtbnMKdHdvX3N5bWJvbHNfem9vIDwtIHJlYWQuem9vKCJ0d29fc3ltYm9scy5jc3YiLCBzcGxpdCA9IGMoIlN5bWJvbCIsICJUeXBlIiksIHNlcCA9ICIsIiwgaGVhZGVyID0gVFJVRSkKCiMgTG9vayBhdCBmaXJzdCBmZXcgcm93cyBvZiBkYXRhCmhlYWQodHdvX3N5bWJvbHNfem9vKQpgYGAKIyMgQ2hlY2tpbmcgZm9yIHdlaXJkbmVzcwoKIyMjIEhhbmRsZSBtaXNzaW5nIHZhbHVlcwoKSW4gY2hhcHRlciAzLCB5b3UgdXNlZCBuYS5sb2NmKCkgdG8gZmlsbCBtaXNzaW5nIHZhbHVlcyB3aXRoIHRoZSBwcmV2aW91cyBub24tbWlzc2luZyB2YWx1ZS4gWW91IGNhbiB1c2UgaW50ZXJwb2xhdGlvbiB3aGVuIGNhcnJ5aW5nIHRoZSBwcmV2aW91cyB2YWx1ZSBmb3J3YXJkIGlzbid0IGFwcHJvcHJpYXRlLiBJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBleHBsb3JlIHR3byBpbnRlcnBvbGF0aW9uIG1ldGhvZHM6IGxpbmVhciBhbmQgc3BsaW5lLgoKTGluZWFyIGludGVycG9sYXRpb24gY2FsY3VsYXRlcyB2YWx1ZXMgdGhhdCBsaWUgb24gYSBsaW5lIGJldHdlZW4gdHdvIGtub3duIGRhdGEgcG9pbnRzLiBUaGlzIGlzIGEgZ29vZCBjaG9pY2UgZm9yIGZhaXJseSBsaW5lYXIgZGF0YSwgbGlrZSBhIHNlcmllcyB3aXRoIGEgc3Ryb25nIHRyZW5kLiBTcGxpbmUgaW50ZXJwb2xhdGlvbiBpcyBtb3JlIGFwcHJvcHJpYXRlIGZvciBzZXJpZXMgd2l0aG91dCBhIHN0cm9uZyB0cmVuZCwgYmVjYXVzZSBpdCBjYWxjdWxhdGVzIGEgbm9uLWxpbmVhciBhcHByb3hpbWF0aW9uIHVzaW5nIG11bHRpcGxlIGRhdGEgcG9pbnRzLgoKVXNlIHRoZXNlIHR3byBtZXRob2RzIHRvIGludGVycG9sYXRlIHRoZSB0aHJlZSBtaXNzaW5nIHZhbHVlcyBmb3IgdGhlIDEwLXllYXIgVHJlYXN1cnkgcmF0ZSBpbiB0aGUgb2JqZWN0IERHUzEwLiBUaGVuIGNvbXBhcmUgdGhlIHJlc3VsdHMgd2l0aCB0aGUgb3V0cHV0IG9mIG5hLmxvY2YoKS4KCmBgYHtyIGluY2x1ZGU9RkFMU0V9CkRHUzEwIDwtIHJiaW5kKHN0cnVjdHVyZShjKDQuOTQsIDQuODUsIDQuNzgsIDQuNzksIDQuODUsIE5BLCA0Ljk5LCA0Ljk3LCA0Ljg2LCAKNC44LCA0Ljg0LCBOQSwgTkEsIDQuNjQsIDQuNTcsIDQuNjMpLCBjbGFzcyA9IGMoInh0cyIsICJ6b28iKSwgc3JjID0gIkZSRUQiLCB1cGRhdGVkID0gc3RydWN0dXJlKDE1OTU5NTk3ODkuMjk2NzgsIGNsYXNzID0gYygiUE9TSVhjdCIsIAoiUE9TSVh0IikpLCBpbmRleCA9IHN0cnVjdHVyZShjKDk5ODg3MDQwMCwgOTk4OTU2ODAwLCA5OTkwNDMyMDAsIAo5OTkxMjk2MDAsIDk5OTIxNjAwMCwgOTk5NDc1MjAwLCA5OTk1NjE2MDAsIDk5OTY0ODAwMCwgOTk5NzM0NDAwLCAKOTk5ODIwODAwLCAxMDAwMDgwMDAwLCAxMDAwMTY2NDAwLCAxMDAwMjUyODAwLCAxMDAwMzM5MjAwLCAxMDAwNDI1NjAwLCAKMTAwMDY4NDgwMCksIHR6b25lID0gIlVUQyIsIHRjbGFzcyA9ICJEYXRlIiksIC5EaW0gPSBjKDE2TCwgMUwKKSwgLkRpbW5hbWVzID0gbGlzdChOVUxMLCAiREdTMTAiKSkpCmBgYAoKYGBge3J9CiMgZmlsbCBOQSB1c2luZyBsYXN0IG9ic2VydmF0aW9uIGNhcnJpZWQgZm9yd2FyZApsb2NmIDwtIG5hLmxvY2YoREdTMTApCgojIGZpbGwgTkEgdXNpbmcgbGluZWFyIGludGVycG9sYXRpb24KYXBwcm94IDwtIG5hLmFwcHJveChER1MxMCkKCiMgZmlsbCBOQSB1c2luZyBzcGxpbmUgaW50ZXJwb2xhdGlvbgpzcGxpbmUgPC0gbmEuc3BsaW5lKERHUzEwKQoKIyBtZXJnZSBpbnRvIG9uZSBvYmplY3QKbmFfZmlsbGVkIDwtIG1lcmdlKGxvY2YsIGFwcHJveCwgc3BsaW5lKQoKIyBwbG90IGNvbWJpbmVkIG9iamVjdApwbG90KG5hX2ZpbGxlZCwgY29sID0gYygiYmxhY2siLCAicmVkIiwgImdyZWVuIikpCmBgYAojIyMgVmlzdWFsaXplIGltcG9ydGVkIGRhdGEKCkl0J3MgaW1wb3J0YW50IHRvIGNoZWNrIHlvdXIgaW1wb3J0ZWQgZGF0YSBpcyByZWFzb25hYmxlLiBBIHBsb3QgaXMgYSBxdWljayBhbmQgZWFzeSB3YXkgdG8gc3BvdCBvZGRpdGllcy4gSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgdXNlIHRoZSBwbG90KCkgZnVuY3Rpb24gdG8gdmlzdWFsaXplIHNvbWUgQUFQTCBkYXRhIGZyb20gWWFob28gRmluYW5jZS4KCkEgc3RvY2sgc3BsaXQgY2F1c2VkIGEgaHVnZSBwcmljZSBjaGFuZ2UgaW4gSnVuZSAyMDE0LiBBcHBsZSBzaW11bHRhbmVvdXNseSBpbmNyZWFzZWQgdGhlIG51bWJlciBvZiBzaGFyZXMgb3V0c3RhbmRpbmcgYW5kIGRlY3JlYXNlZCBpdHMgc3RvY2sgcHJpY2UsIGxlYXZpbmcgdGhlIGNvbXBhbnkgdmFsdWUgdW5jaGFuZ2VkLiBGb3IgZXhhbXBsZSwgYSAyLWZvci0xIHNwbGl0IHdvdWxkIGRvdWJsZSB0aGUgc2hhcmVzIG91dHN0YW5kaW5nLCBhbmQgcmVkdWNlIHRoZSBzdG9jayBwcmljZSBieSAxLzIuCgpZb3Ugd2lsbCBhbHNvIHVzZSB0aGUgcXVhbnRtb2QgZXh0cmFjdG9yIGZ1bmN0aW9ucyBDbCgpIGFuZCBBZCgpIHRvIGFjY2VzcyB0aGUgY2xvc2UgYW5kIGFkanVzdGVkIGNsb3NlIGNvbHVtbnMsIHJlc3BlY3RpdmVseS4gWWFob28gRmluYW5jZSBwcm92aWRlcyB0aGUgc3BsaXQtIGFuZC9vciBkaXZpZGVuZC1hZGp1c3RlZCBjbG9zZSBjb2x1bW4uCmBgYHtyfQpnZXRTeW1ib2xzKCJBQVBMIiwgc3JjPSd5YWhvbycsIGZyb20gPSAiMjAwNy0wMS0wMSIsIHRvID0gIjIwMTctMDktMTciKQpgYGAKYGBge3J9CmhlYWQoQUFQTCkKYGBgCmBgYHtyfQojIExvb2sgYXQgdGhlIGxhc3QgZmV3IHJvd3Mgb2YgQUFQTCBkYXRhCnRhaWwoQUFQTCkKCiMgUGxvdCBjbG9zZSBwcmljZQpwbG90KEFBUEwkQUFQTC5DbG9zZSkKCiMgUGxvdCBhZGp1c3RlZCBjbG9zZSBwcmljZQpwbG90KEFBUEwkQUFQTC5BZGp1c3RlZCkKYGBgCiMjIyBDcm9zcyByZWZlcmVuY2Ugc291cmNlcwoKSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgY3Jvc3MtcmVmZXJlbmNlIHRoZSBBQVBMIHJhdyBwcmljZSBkYXRhIGZyb20gdGhlIHByZXZpb3VzIGV4ZXJjaXNlIHdpdGggQUFQTCBkYXRhIGZyb20gYW5vdGhlciBzb3VyY2UuCgpUaGUgbmV3IGRhdGEgaXMgYWxyZWFkeSBhZGp1c3RlZCBmb3Igc3BsaXRzLCBidXQgbm90IGRpdmlkZW5kcy4gU28gdGhlIGNsb3NlIHByaWNlcyBmcm9tIHRoZSBuZXcgZGF0YSB3b24ndCBhbGlnbiBjbG9zZWx5IHdpdGggdGhlIGFkanVzdGVkIGNsb3NlIHByaWNlcyBmcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZSAod2hpY2ggYXJlIGFkanVzdGVkIGZvciBib3RoIHNwbGl0cyBhbmQgZGl2aWRlbmRzKS4gWW91IHdpbGwgbGVhcm4gbW9yZSBhYm91dCB0aGUgYWRqdXN0bWVudCBwcm9jZXNzIGluIHRoZSBuZXh0IHZpZGVvLgoKWW91IHdpbGwgY29tcGFyZSByYXcsIHVuYWRqdXN0ZWQgQUFQTCBkYXRhIHdpdGggc3BsaXQtYWRqdXN0ZWQgQUFQTCBkYXRhLiBUaGUgZGF0YSBoYXZlIGFscmVhZHkgYmVlbiBsb2FkZWQgdG8geW91ciB3b3Jrc3BhY2UgaW4gYWFwbF9yYXcgYW5kIGFhcGxfc3BsaXRfYWRqdXN0ZWQsIHJlc3BlY3RpdmVseS4KCiAgICAjIExvb2sgYXQgZmlyc3QgZmV3IHJvd3Mgb2YgYWFwbF9yYXcKICAgIGhlYWQoYWFwbF9yYXcpCiAgICAKICAgICMgTG9vayBhdCBmaXJzdCBmZXcgcm93cyBvZiBhYXBsX3NwbGl0X2FkanVzdGVkCiAgICBoZWFkKGFhcGxfc3BsaXRfYWRqdXN0ZWQpCiAgICAKICAgICMgUGxvdCBkaWZmZXJlbmNlIGJldHdlZW4gYWRqdXN0ZWQgY2xvc2UgYW5kIHNwbGl0LWFkanVzdGVkIGNsb3NlCiAgICBwbG90KEFkKGFhcGxfcmF3JEFBUEwuQWRqdXN0ZWQpIC0gQ2woYWFwbF9zcGxpdF9hZGp1c3RlZCRBQVBMLkNsb3NlKSkKICAgIAogICAgIyBQbG90IGRpZmZlcmVuY2UgYmV0d2VlbiB2b2x1bWUgZnJvbSB0aGUgcmF3IGFuZCBzcGxpdC1hZGp1c3RlZCBzb3VyY2VzCiAgICBwbG90KFZvKGFhcGxfcmF3JEFBUEwuVm9sdW1lKSAtIFZvKGFhcGxfc3BsaXRfYWRqdXN0ZWQkQUFQTC5Wb2x1bWUpKQoKVGhlIHZvbHVtZXMgYWdyZWUgb24gbW9zdCAoYnV0IG5vdCBhbGwpIGRheXMsIHdoZXJlYXMgdGhlIGNsb3NlIHByaWNlcyBhcmUgY29tcGxldGVseSBkaWZmZXJlbnQuCgojIyBBZGp1c3RpbmcgZm9yIGNvcnBvcmF0ZSBhY3Rpb25zCgojIyMgQWRqdXN0IGZvciBzdG9jayBzcGxpdHMgYW5kIGRpdmlkZW5kcwoKU3RvY2sgc3BsaXRzIGNhbiBjcmVhdGUgbGFyZ2UgaGlzdG9yaWNhbCBwcmljZSBjaGFuZ2VzIGV2ZW4gdGhvdWdoIHRoZXkgZG8gbm90IGNoYW5nZSB0aGUgdmFsdWUgb2YgdGhlIGNvbXBhbnkuIFNvLCB5b3UgbXVzdCBhZGp1c3QgYWxsIHByZS1zcGxpdCBwcmljZXMgaW4gb3JkZXIgdG8gY2FsY3VsYXRlIGhpc3RvcmljYWwgcmV0dXJucyBjb3JyZWN0bHkuCgpTaW1pbGFybHksIHlvdSBtdXN0IGFkanVzdCBhbGwgcHJlLWRpdmlkZW5kIHByaWNlcy4gRGl2aWRlbmRzIGRvIHJlZHVjZSB0aGUgY29tcGFueSdzIHZhbHVlIGJ5IHRoZSBhbW91bnQgb2YgdGhlIGRpdmlkZW5kIHBheW1lbnQsIGJ1dCB0aGUgaW52ZXN0b3IncyByZXR1cm4gaXNuJ3QgYWZmZWN0ZWQgYmVjYXVzZSB0aGV5IHJlY2VpdmUgdGhlIG9mZnNldHRpbmcgZGl2aWRlbmQgcGF5bWVudC4KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGxlYXJuIGhvdyB0byB1c2UgdGhlIGFkanVzdE9ITEMoKSBmdW5jdGlvbiB0byBhZGp1c3QgcmF3IGhpc3RvcmljYWwgT0hMQyBwcmljZXMgZm9yIHNwbGl0cyBhbmQgZGl2aWRlbmRzLCBzbyBoaXN0b3JpY2FsIHJldHVybnMgY2FuIGJlIGNhbGN1bGF0ZWQgYWNjdXJhdGVseS4KCllhaG9vIEZpbmFuY2UgcHJvdmlkZXMgcmF3IHByaWNlcyBhbmQgYSBzcGxpdC0gYW5kIGRpdmlkZW5kLWFkanVzdGVkIGNsb3NlIGNvbHVtbi4gVGhlIG91dHB1dCBvZiBhZGp1c3RPSExDKCkgc2hvdWxkIG1hdGNoIFlhaG9vJ3MgYWRqdXN0ZWQgY2xvc2UgY29sdW1uLiBBQVBMIGRhdGEgZnJvbSBZYWhvbyBGaW5hbmNlIGlzIGFscmVhZHkgbG9hZGVkIGluIHlvdXIgd29ya3NwYWNlLgoKV2hpbGUgbm90IG5lY2Vzc2FyeSB0byBjb21wbGV0ZSB0aGlzIGV4ZXJjaXNlLCBZYWhvbyBGaW5hbmNlIHByb3ZpZGVzIGFuIFthY2Nlc3NpYmxlIGV4YW1wbGVdKGh0dHBzOi8vaGVscC55YWhvby5jb20va2IvZmluYW5jZS9TTE4yMzExLmh0bWwpIG9mIHRoZSBhZGp1c3RlZCBjbG9zZSBjYWxjdWxhdGlvbiwgaWYgeW91J3JlIGludGVyZXN0ZWQgaW4gbGVhcm5pbmcgbW9yZS4KCmBgYHtyfQojIExvb2sgYXQgZmlyc3QgZmV3IHJvd3Mgb2YgQUFQTApoZWFkKEFBUEwpCgojIEFkanVzdCBBQVBMIGZvciBzcGxpdHMgYW5kIGRpdmlkZW5kcwphYXBsX2FkanVzdGVkIDwtIGFkanVzdE9ITEMoQUFQTCkKCiMgTG9vayBhdCBmaXJzdCBmZXcgcm93cyBvZiBhYXBsX2FkanVzdGVkCmhlYWQoYWFwbF9hZGp1c3RlZCkKYGBgCiMjIyBEb3dubG9hZCBzcGxpdCBhbmQgZGl2aWRlbmQgZGF0YQpJbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UsIHlvdSB1c2VkIGFkanVzdE9ITEMoKSB0byBhZGp1c3QgcmF3IGhpc3RvcmljYWwgT0hMQyBwcmljZXMgZm9yIHNwbGl0cyBhbmQgZGl2aWRlbmRzLCBidXQgaXQgb25seSB3b3JrcyBmb3IgT0hMQyBkYXRhLiBJdCB3aWxsIG5vdCB3b3JrIGlmIHlvdSBvbmx5IGhhdmUgY2xvc2UgcHJpY2VzLCBhbmQgaXQgZG9lcyBub3QgcmV0dXJuIGFueSBvZiB0aGUgc3BsaXQgb3IgZGl2aWRlbmQgZGF0YSBpdCB1c2VzLgoKWW91IG5lZWQgdGhlIGRhdGVzIGFuZCB2YWx1ZXMgZm9yIGVhY2ggc3BsaXQgYW5kIGRpdmlkZW5kIHRvIGFkanVzdCBhIG5vbi1PSExDIHByaWNlIHNlcmllcywgb3IgaWYgeW91IHNpbXBseSB3YW50IHRvIGFuYWx5emUgdGhlIHJhdyBzcGxpdCBhbmQgZGl2aWRlbmQgZGF0YS4KCllvdSBjYW4gZG93bmxvYWQgdGhlIHNwbGl0IGFuZCBkaXZpZGVuZCBkYXRhIGZyb20gWWFob28gRmluYW5jZSB1c2luZyB0aGUgcXVhbnRtb2QgZnVuY3Rpb25zIGdldFNwbGl0cygpIGFuZCBnZXREaXZpZGVuZHMoKSwgcmVzcGVjdGl2ZWx5LiBUaGUgaGlzdG9yaWNhbCBkaXZpZGVuZCBkYXRhIGZyb20gWWFob28gRmluYW5jZSBpcyBhZGp1c3RlZCBmb3Igc3BsaXRzLiBJZiB5b3Ugd2FudCB0byBkb3dubG9hZCB1bmFkanVzdGVkIGRpdmlkZW5kIGRhdGEsIHlvdSBuZWVkIHRvIHNldCBzcGxpdC5hZGp1c3QgPSBGQUxTRSBpbiB5b3VyIGNhbGwgdG8gZ2V0RGl2aWRlbmRzKCkuCgpgYGB7cn0KIyBEb3dubG9hZCBBQVBMIHNwbGl0IGRhdGEKc3BsaXRzIDwtIGdldFNwbGl0cygiQUFQTCIpCgojIERvd25sb2FkIEFBUEwgZGl2aWRlbmQgZGF0YQpkaXZpZGVuZHMgPC0gZ2V0RGl2aWRlbmRzKCJBQVBMIikKCiMgTG9vayBhdCB0aGUgZmlyc3QgZmV3IHJvd3Mgb2YgZGl2aWRlbmRzCmhlYWQoZGl2aWRlbmRzKQoKIyBEb3dubG9hZCB1bmFkanVzdGVkIEFBUEwgZGl2aWRlbmQgZGF0YQpyYXdfZGl2aWRlbmRzIDwtIGdldERpdmlkZW5kcygiQUFQTCIsIHNwbGl0LmFkanVzdCA9IEZBTFNFKQoKIyBMb29rIGF0IHRoZSBmaXJzdCBmZXcgcm93cyBvZiByYXdfZGl2aWRlbmRzCmhlYWQoZGl2aWRlbmRzKQpgYGAKSXQncyBpbXBvcnRhbnQgdG8gZ2V0IHNwbGl0cyBhbmQgZGl2aWRlbmRzIGNvcnJlY3Qgd2hlbiBjYWxjdWxhdGluZyBoaXN0b3JpY2FsIHJldHVybnMuCgojIyMgQWRqdXN0IHVuaXZhcmlhdGUgZGF0YSBmb3Igc3BsaXRzIGFuZCBkaXZpZGVuZHMKCklmIHlvdSBvbmx5IGhhdmUgY2xvc2UgcHJpY2VzLCB5b3UgY2FuIGFkanVzdCB0aGVtIHdpdGggYWRqUmF0aW9zKCkuIEl0IGhhcyAzIGFyZ3VtZW50czogc3BsaXRzLCBkaXZpZGVuZHMsIGFuZCBjbG9zZS4gSXQgcmV0dXJucyBhbiB4dHMgb2JqZWN0IHdpdGggc3BsaXQgYW5kIGRpdmlkZW5kIGFkanVzdG1lbnQgcmF0aW9zIGluIGNvbHVtbnMgIlNwbGl0IiBhbmQgIkRpdiIsIHJlc3BlY3RpdmVseS4KCllvdSBuZWVkIHRvIHByb3ZpZGUgc3BsaXQgZGF0YSB2aWEgdGhlIHNwbGl0cyBhcmd1bWVudCB0byBjYWxjdWxhdGUgdGhlIHNwbGl0IHJhdGlvLiBUbyBjYWxjdWxhdGUgdGhlIGRpdmlkZW5kIHJhdGlvLCB5b3UgbmVlZCB0byBwcm92aWRlIHJhdyBkaXZpZGVuZHMgYW5kIHJhdyBwcmljZXMgdmlhIHRoZSBkaXZpZGVuZHMgYW5kIGNsb3NlIGFyZ3VtZW50cywgcmVzcGVjdGl2ZWx5LgoKT25jZSB5b3UgaGF2ZSB0aGUgc3BsaXQgYW5kIGRpdmlkZW5kIGFkanVzdG1lbnQgcmF0aW9zLCB5b3UgY2FsY3VsYXRlIHRoZSBhZGp1c3RlZCBwcmljZSBtdWx0aXBseWluZyB0aGUgdW5hZGp1c3RlZCBwcmljZSBieSBib3RoIHRoZSBzcGxpdCBhbmQgZGl2aWRlbmQgYWRqdXN0bWVudCByYXRpb3MuCgpgYGB7cn0KIyBDYWxjdWxhdGUgc3BsaXQgYW5kIGRpdmlkZW5kIGFkanVzdG1lbnQgcmF0aW9zCnJhdGlvcyA8LSBhZGpSYXRpb3Moc3BsaXRzID0gc3BsaXRzLCBkaXZpZGVuZHMgPSByYXdfZGl2aWRlbmRzLCBjbG9zZSA9IENsKEFBUEwpKQoKIyBDYWxjdWxhdGUgYWRqdXN0ZWQgY2xvc2UgZm9yIEFBUEwKYWFwbF9hZGp1c3RlZCA8LSBDbChBQVBMKSAqIHJhdGlvc1ssICJTcGxpdCJdICogcmF0aW9zWywgIkRpdiJdCgojIExvb2sgYXQgZmlyc3QgZmV3IHJvd3Mgb2YgWWFob28gYWRqdXN0ZWQgY2xvc2UKaGVhZChBZChBQVBMKSkKCiMgTG9vayBhdCBmaXJzdCBmZXcgcm93cyBvZiBhYXBsX2FkanVzdGVkCmhlYWQoYWFwbF9hZGp1c3RlZCkKYGBgCgo=