Overview

Over the last month, we have witnessed all-time high levels of volatility. This has been reflected by the VIX index, also known as the fear gauge. The spike in volatility came along the large sell-off in the stock market triggered by concerns about the severe economic impact of the COVID-19 epidemic. In this note, I will delve a little into the global data on the confirmed COVID-19 cases, published by Johns Hopkins University. The purpose of this vignette is to help us associate the onslaught of the epidemic with uncertainty in the stock market.

Getting Data

We start by downloading the recent data on COVID-19 cases using the github page of the CSSE at Johns Hopkins University. Rather than downloading manually, we can run the following command:

url = "https://github.com/CSSEGISandData/COVID-19/archive/master.zip"
temp <- tempfile()
download.file(url,temp)
trying URL 'https://github.com/CSSEGISandData/COVID-19/archive/master.zip'
Content type 'application/zip' length 59155051 bytes (56.4 MB)
==================================================
downloaded 56.4 MB

The data file contains a number of data sets on the individual country as well as the aggregate global level. After unzipping the data content, I focus on the aggregate level. This can be done using the following commands:

unz_files <- unzip(temp)
data_files <- unz_files[grep("/csse_covid_19_data/csse_covid_19_time_series/",unz_files)]
data_files <- data_files[grep("confirmed_global.csv",data_files)]
ds_list <- lapply(data_files,function(x) read.csv(x,stringsAsFactors = F))

The above downloads the data for all files and store them in a list. We can now combine the list altogether for some data preparation and manipulation in the following.

Cleaning Data

The main issue is that the data need to be organized in a time series format. We do so in the following steps.

library(plyr)
library(lubridate)
ds <- ldply(ds_list,data.frame)

First, let’s aggregate the data on the country level. We refer to data.table library to do so.

library(data.table)
DS <- data.table(ds)
DS$Lat <- DS$Long <- NULL
select_var <- names(DS)[!names(DS) %in% c("Province.State","Country.Region")]
DS <- DS[,lapply(.SD,sum),by =  "Country.Region", .SDcols = select_var ]

Second, let us pivot the data in an xts format. To do so, let reconstruct the dates from the variables’ names with some fixing

all_dates <- gsub("X","",select_var)
all_dates <- strsplit(all_dates,"\\.")
d <- sapply(all_dates,function(x) x[2])
d[nchar(d) == 1] <- paste(0,d[nchar(d) == 1],sep = "")
m <- sapply(all_dates,function(x) x[1])
m[nchar(m) == 1] <- paste(0,m[nchar(m) == 1],sep = "")
y <- sapply(all_dates,function(x) x[3])
y[nchar(y) == 2] <- paste(20,y[nchar(y) == 2],sep = "")
all_dates <- paste(y,m,d,sep = "-")

Given the dates, we can pivot the data easily using the following commands

library(xts)
DS_t <- data.frame(DS[,select_var,with = F])
DS_t <- t(DS_t)
rownames(DS_t) <- all_dates
colnames(DS_t) <- DS$Country.Region
DS_t <- as.xts(DS_t)

Time Series Summary

Let’s focus on the 10 countries with the largest cases

select_countries <- names(DS_t)[ order(DS_t[nrow(DS_t),],decreasing = T)][1:10]
DS_t10 <- DS_t[,select_countries]
tail(data.frame(DS_t10))

Give the time series data, we plot the number of confirmed cases since the beginning of the data, which is Jan 22, 2020.

library(RColorBrewer)
nb.cols <- length(select_countries)
mycolors <- colorRampPalette(brewer.pal(8, "Set2"))(nb.cols)
plot(DS_t10,legend.loc = "topleft",col = mycolors,main = "Confirmed Cases")

We see that number of confirmed cases in China been roughly constant since mid Fed, whereas the number of cases started to increase exponentially in mid March 2020. We take a closer look at this period below.

plot(DS_t10["20200315/",],legend.loc = "topleft",col = mycolors,main = "Confirmed Cases")

Market Reaction

We consider two major indices to relate to the associate impact of the COVID-19 with the market. We will focus on the S&P 500 and the VIX index. Given the aggregate number of cases, we focus on the average confirmed cases over time as a proxy for the onslaught of the epidemic.

S&P Vs. VIX

We take a quick a look at the cumulative return of each index since the beginning of the year.

library(quantmod)
getSymbols("^VIX")
[1] "^VIX"
getSymbols("^GSPC")
[1] "^GSPC"
SNP <- GSPC$GSPC.Adjusted
VIX <- VIX$VIX.Adjusted
ds_fin <- merge(SNP,VIX)
ds_fin <- ds_fin/lag(ds_fin)-1
ds_fin <- ds_fin["20200101/",]
names(ds_fin) <- c("SNP","VIX")
plot(cumprod(ds_fin+1),legend.loc = "topleft",main = "Cumulative Return")

The red line corresponds to the VIX index, whereas the black line corresponds to the return on the S&P 500. We can see that both are negatively correlated, where drops in the equity index is accompanied by large increases in the VIX, hence the expression the fear gauge. At the same time, we witness a small recovery in the equity market as the number of confirmed cases of COVID-19 has been relatively maintained recently.

Altogether

We move to investigate the market reactions to the increase in confirmed cases. Such number can be viewed as an exponential function of time, as we can see below

ds_covid <- as.xts(apply(DS_t10,1,sum))
plot(ds_covid,main ="Total Confirmed Cases")

To get a better perspective, we can think about the slope of this function, which denotes the velocity of the number of cases

ds_covid_1 <- ds_covid/lag(ds_covid)-1
plot(ds_covid_1,main = "Increase Rate")

The above plot indicates the velocity of the confirmed cases. We can see that in all cases it is positive. However, at the same time we observe that rate declined relative to the beginning of the epidemic. This brings us to the acceleration of the confirmed cases, which corresponds to the second derivative of the confirmed cases over time:

ds_covid_2 <- ds_covid_1/lag(ds_covid_1)-1
plot(ds_covid_2,main = "Acceleration Rate")

We note that the acceleration rate spikes in Feb 13, 2020. Taking a closer look this is the case when the data in China exhibits that truncation characteristic. The result of which leads to a large increase in the second derivative. To mitigate this, we use a local regression to smooth out the trend over time and plot below

a <- na.omit(as.numeric(ds_covid_2))
x <- 1:length(a)
a_fit <- predict(loess(a~x))
names(a_fit) <- date(na.omit(ds_covid_2))
a_fit <- as.xts(a_fit)
plot(a_fit, main = "Acceleration Rate Smoothed",cex = 0.5)

The above plot provides a more robust perspective in terms of the acceleration trend over time. We discern that the acceleration of the confirmed cases has decreased over time. In other words, while the number of confirmed cases are still increasing, the increase rate at has been slowing down relatively.

Given the above insights, let us combine altogether and investigate the market reaction with respect to the increase in the confirmed cases. We refer to the plotly package to illustrate this relationship. We do so for a couple of reasons. First, it provides excellent interactive visualization platform. Second, the scale of the y-axis can be easily modified to accommodate a log-scale. This is relevant when controlling for level increases (such as price levels). Finally, two different time series can be plotted easily on the opposite y-axis. On the left hand side, we plot the market data, whereas we plot the COVID-19 data on the right hand side y-axis.

library(plotly)
# choose the labels format
f <- list(
  family = "Courier New, monospace",
  size = 18,
  color = "#7f7f7f"
)

# x-axis 
xl <- list(
  title = "Date",
  titlefont = f
)

# y-axis for S&P
yl <- list(
  title = "S&P 500",
  titlefont = f,
  type = "log"
)

# right hand y-axis for VIX
yl2 <- list(title = "COVID-19 Rate",
        overlaying = "y",
        titlefont = f, 
        side = "right",
        type = "log")


snp <- as.numeric(cumprod(ds_fin$SNP+1))
vix <- as.numeric(cumprod(ds_fin$VIX+1))
covid <- as.numeric(ds_covid_1[,1])
p <- plot_ly()
p <- add_lines(p,x = ~ date(ds_fin), y = ~ snp, name = "S&P 500")
p <- add_lines(p,x = ~ date(ds_fin), y = ~ vix, name = "VIX")
p <- add_lines(p,x = ~ date(ds_covid_1), y = ~ covid ,yaxis = "y2", name = "COVID-19") 
p <- layout(p,yaxis = yl, yaxis2 = yl2,xaxis = xl)
p

NA

A couple of comments are in order. First, we note that the major spike in the VIX index took place during the time that the velocity of the COVID-19 confirmed cases started to increase again. This can be traced back to Feb 23rd, 2020. Before that, this is the time during which China demonstrated positive signs of maintaining it. However, afterwards, this is the time during which we witnessed the spread of the epidemic outside China, especially in the US.

Second, it is interesting to see how much the fear gauge is associated with the COVID-19 velocity, i.e. increase rate. Since mid-March, we observe that the VIX has dropped from its peak, while at the same time the velocity of the COVID-19 has also dropped. We discern that both time series exhibit an inverse U shape since late Feb 2020. The opposite holds true for the S&P 500, where we are currently witnessing a small recovery.

Concluding Remarks

Economic activity is not simply contracting with the ongoing epidemic. We are actually witnessing a complete freeze in the economy. This has already manifested in a large sell-off since late Feb 2020. The velocity of confirmed cases of COVID-19 seems to be dropping over the last two weeks, the same holds true for the market fear gauge (VIX). The S&P 500 seems to be rebounding as the other indicators slow down. Nonetheless, there is more uncertainty to come given the spillover effect of the epidemic and its long-term impact. For the interested reader, I suggest looking into this report by BlackRock.

Acknowledgement

The above vignette has greatly benefited from data, comments, libraries, and other code sources posted on the web. For instance, we followed Dirk Eddelbuettel’s instructions on Stack Overflow to download the data in an automated manner. Special thanks to him and other members of the R community. Also, we thank Data Novia for pointing out how to expand color palettes. Finally, our sincere graduate goes to the team at John Hopkins for putting this great effort and making this data publicly available.

LS0tCnRpdGxlOiAiQ09WSUQtMTkgYW5kIHRoZSBGZWFyIEdhdWdlIgphdXRob3I6ICJNYWplZWQgU2ltYWFuIgpkYXRlOiAiQXByaWwgOCwgMjAyMCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmEgdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAotLS0KCiMgT3ZlcnZpZXcKT3ZlciB0aGUgbGFzdCBtb250aCwgd2UgaGF2ZSB3aXRuZXNzZWQgYWxsLXRpbWUgaGlnaCBsZXZlbHMgb2Ygdm9sYXRpbGl0eS4gVGhpcyBoYXMgYmVlbiByZWZsZWN0ZWQgYnkgdGhlIFZJWCBpbmRleCwgYWxzbyBrbm93biBhcyB0aGUgZmVhciBnYXVnZS4gVGhlIHNwaWtlIGluIHZvbGF0aWxpdHkgY2FtZSBhbG9uZyB0aGUgbGFyZ2Ugc2VsbC1vZmYgaW4gdGhlIHN0b2NrIG1hcmtldCB0cmlnZ2VyZWQgYnkgY29uY2VybnMgYWJvdXQgdGhlIHNldmVyZSBlY29ub21pYyBpbXBhY3Qgb2YgdGhlIENPVklELTE5IGVwaWRlbWljLiBJbiB0aGlzIG5vdGUsIEkgd2lsbCBkZWx2ZSBhIGxpdHRsZSBpbnRvIHRoZSBnbG9iYWwgZGF0YSBvbiB0aGUgY29uZmlybWVkIENPVklELTE5IGNhc2VzLCBwdWJsaXNoZWQgYnkgIEpvaG5zIEhvcGtpbnMgVW5pdmVyc2l0eS4gVGhlIHB1cnBvc2Ugb2YgdGhpcyB2aWduZXR0ZSBpcyB0byBoZWxwIHVzIGFzc29jaWF0ZSAgdGhlIG9uc2xhdWdodCBvZiB0aGUgZXBpZGVtaWMgd2l0aCB1bmNlcnRhaW50eSBpbiB0aGUgc3RvY2sgbWFya2V0LgoKCiMgR2V0dGluZyBEYXRhCldlIHN0YXJ0IGJ5IGRvd25sb2FkaW5nIHRoZSByZWNlbnQgZGF0YSBvbiBDT1ZJRC0xOSBjYXNlcyB1c2luZyB0aGUgZ2l0aHViIHBhZ2Ugb2YgdGhlIENTU0UgYXQgSm9obnMgSG9wa2lucyBVbml2ZXJzaXR5LiBSYXRoZXIgdGhhbiBkb3dubG9hZGluZyBtYW51YWxseSwgd2UgY2FuIHJ1biB0aGUgZm9sbG93aW5nIGNvbW1hbmQ6CmBgYHtyfQp1cmwgPSAiaHR0cHM6Ly9naXRodWIuY29tL0NTU0VHSVNhbmREYXRhL0NPVklELTE5L2FyY2hpdmUvbWFzdGVyLnppcCIKdGVtcCA8LSB0ZW1wZmlsZSgpCmRvd25sb2FkLmZpbGUodXJsLHRlbXApCmBgYApUaGUgZGF0YSBmaWxlIGNvbnRhaW5zIGEgbnVtYmVyIG9mIGRhdGEgc2V0cyBvbiB0aGUgaW5kaXZpZHVhbCBjb3VudHJ5IGFzIHdlbGwgYXMgdGhlIGFnZ3JlZ2F0ZSAgZ2xvYmFsIGxldmVsLiBBZnRlciB1bnppcHBpbmcgdGhlIGRhdGEgY29udGVudCwgSSBmb2N1cyBvbiB0aGUgYWdncmVnYXRlIGxldmVsLiBUaGlzIGNhbiBiZSBkb25lIHVzaW5nIHRoZSBmb2xsb3dpbmcgY29tbWFuZHM6CmBgYHtyfQp1bnpfZmlsZXMgPC0gdW56aXAodGVtcCkKZGF0YV9maWxlcyA8LSB1bnpfZmlsZXNbZ3JlcCgiL2Nzc2VfY292aWRfMTlfZGF0YS9jc3NlX2NvdmlkXzE5X3RpbWVfc2VyaWVzLyIsdW56X2ZpbGVzKV0KZGF0YV9maWxlcyA8LSBkYXRhX2ZpbGVzW2dyZXAoImNvbmZpcm1lZF9nbG9iYWwuY3N2IixkYXRhX2ZpbGVzKV0KZHNfbGlzdCA8LSBsYXBwbHkoZGF0YV9maWxlcyxmdW5jdGlvbih4KSByZWFkLmNzdih4LHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSkKYGBgClRoZSBhYm92ZSBkb3dubG9hZHMgdGhlIGRhdGEgZm9yIGFsbCBmaWxlcyBhbmQgc3RvcmUgdGhlbSBpbiBhIGxpc3QuIFdlIGNhbiBub3cgY29tYmluZSB0aGUgbGlzdCBhbHRvZ2V0aGVyIGZvciBzb21lIGRhdGEgcHJlcGFyYXRpb24gYW5kIG1hbmlwdWxhdGlvbiBpbiB0aGUgZm9sbG93aW5nLgoKIyMgQ2xlYW5pbmcgRGF0YQpUaGUgbWFpbiBpc3N1ZSBpcyB0aGF0IHRoZSBkYXRhIG5lZWQgdG8gYmUgb3JnYW5pemVkIGluIGEgdGltZSBzZXJpZXMgZm9ybWF0LiBXZSBkbyBzbyBpbiB0aGUgZm9sbG93aW5nIHN0ZXBzLgpgYGB7cixtZXNzYWdlPUYsd2FybmluZz1GfQpsaWJyYXJ5KHBseXIpCmxpYnJhcnkobHVicmlkYXRlKQpkcyA8LSBsZHBseShkc19saXN0LGRhdGEuZnJhbWUpCmBgYApGaXJzdCwgbGV0J3MgYWdncmVnYXRlIHRoZSBkYXRhIG9uIHRoZSBjb3VudHJ5IGxldmVsLiBXZSByZWZlciB0byBgZGF0YS50YWJsZWAgbGlicmFyeSB0byBkbyBzby4KYGBge3IsbWVzc2FnZSA9IEYsd2FybmluZz1GfQpsaWJyYXJ5KGRhdGEudGFibGUpCkRTIDwtIGRhdGEudGFibGUoZHMpCkRTJExhdCA8LSBEUyRMb25nIDwtIE5VTEwKc2VsZWN0X3ZhciA8LSBuYW1lcyhEUylbIW5hbWVzKERTKSAlaW4lIGMoIlByb3ZpbmNlLlN0YXRlIiwiQ291bnRyeS5SZWdpb24iKV0KRFMgPC0gRFNbLGxhcHBseSguU0Qsc3VtKSxieSA9ICAiQ291bnRyeS5SZWdpb24iLCAuU0Rjb2xzID0gc2VsZWN0X3ZhciBdCmBgYApTZWNvbmQsIGxldCB1cyBwaXZvdCB0aGUgZGF0YSBpbiBhbiBgeHRzYCBmb3JtYXQuIFRvIGRvIHNvLCBsZXQgcmVjb25zdHJ1Y3QgdGhlIGRhdGVzIGZyb20gdGhlIHZhcmlhYmxlcycgbmFtZXMgd2l0aCBzb21lIGZpeGluZwpgYGB7cn0KYWxsX2RhdGVzIDwtIGdzdWIoIlgiLCIiLHNlbGVjdF92YXIpCmFsbF9kYXRlcyA8LSBzdHJzcGxpdChhbGxfZGF0ZXMsIlxcLiIpCmQgPC0gc2FwcGx5KGFsbF9kYXRlcyxmdW5jdGlvbih4KSB4WzJdKQpkW25jaGFyKGQpID09IDFdIDwtIHBhc3RlKDAsZFtuY2hhcihkKSA9PSAxXSxzZXAgPSAiIikKbSA8LSBzYXBwbHkoYWxsX2RhdGVzLGZ1bmN0aW9uKHgpIHhbMV0pCm1bbmNoYXIobSkgPT0gMV0gPC0gcGFzdGUoMCxtW25jaGFyKG0pID09IDFdLHNlcCA9ICIiKQp5IDwtIHNhcHBseShhbGxfZGF0ZXMsZnVuY3Rpb24oeCkgeFszXSkKeVtuY2hhcih5KSA9PSAyXSA8LSBwYXN0ZSgyMCx5W25jaGFyKHkpID09IDJdLHNlcCA9ICIiKQphbGxfZGF0ZXMgPC0gcGFzdGUoeSxtLGQsc2VwID0gIi0iKQpgYGAKR2l2ZW4gdGhlIGRhdGVzLCB3ZSBjYW4gcGl2b3QgdGhlIGRhdGEgZWFzaWx5IHVzaW5nIHRoZSBmb2xsb3dpbmcgY29tbWFuZHMKYGBge3IsbWVzc2FnZSA9IEYsd2FybmluZz1GfQpsaWJyYXJ5KHh0cykKRFNfdCA8LSBkYXRhLmZyYW1lKERTWyxzZWxlY3RfdmFyLHdpdGggPSBGXSkKRFNfdCA8LSB0KERTX3QpCnJvd25hbWVzKERTX3QpIDwtIGFsbF9kYXRlcwpjb2xuYW1lcyhEU190KSA8LSBEUyRDb3VudHJ5LlJlZ2lvbgpEU190IDwtIGFzLnh0cyhEU190KQpgYGAKCiMjIFRpbWUgU2VyaWVzIFN1bW1hcnkKTGV0J3MgZm9jdXMgb24gdGhlIDEwIGNvdW50cmllcyB3aXRoIHRoZSBsYXJnZXN0IGNhc2VzCmBgYHtyfQpzZWxlY3RfY291bnRyaWVzIDwtIG5hbWVzKERTX3QpWyBvcmRlcihEU190W25yb3coRFNfdCksXSxkZWNyZWFzaW5nID0gVCldWzE6MTBdCkRTX3QxMCA8LSBEU190WyxzZWxlY3RfY291bnRyaWVzXQp0YWlsKGRhdGEuZnJhbWUoRFNfdDEwKSkKYGBgCgpHaXZlIHRoZSB0aW1lIHNlcmllcyBkYXRhLCB3ZSBwbG90IHRoZSBudW1iZXIgb2YgY29uZmlybWVkIGNhc2VzIHNpbmNlIHRoZSBiZWdpbm5pbmcgb2YgdGhlIGRhdGEsIHdoaWNoIGlzIEphbiAyMiwgMjAyMC4KYGBge3IsZmlnLmFsaWduPSJjZW50ZXIiLG1lc3NhZ2U9Rix3YXJuaW5nPUYsZmlnLndpZHRoPTZ9CmxpYnJhcnkoUkNvbG9yQnJld2VyKQpuYi5jb2xzIDwtIGxlbmd0aChzZWxlY3RfY291bnRyaWVzKQpteWNvbG9ycyA8LSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwoOCwgIlNldDIiKSkobmIuY29scykKcGxvdChEU190MTAsbGVnZW5kLmxvYyA9ICJ0b3BsZWZ0Iixjb2wgPSBteWNvbG9ycyxtYWluID0gIkNvbmZpcm1lZCBDYXNlcyIpCmBgYApXZSBzZWUgdGhhdCBudW1iZXIgb2YgY29uZmlybWVkIGNhc2VzIGluIENoaW5hIGJlZW4gcm91Z2hseSBjb25zdGFudCBzaW5jZSBtaWQgRmVkLCB3aGVyZWFzIHRoZSBudW1iZXIgb2YgY2FzZXMgc3RhcnRlZCB0byBpbmNyZWFzZSBleHBvbmVudGlhbGx5IGluIG1pZCBNYXJjaCAyMDIwLiBXZSB0YWtlIGEgY2xvc2VyIGxvb2sgYXQgdGhpcyBwZXJpb2QgYmVsb3cuCgpgYGB7cixmaWcud2lkdGg9NixmaWcuYWxpZ249ImNlbnRlciJ9CnBsb3QoRFNfdDEwWyIyMDIwMDMxNS8iLF0sbGVnZW5kLmxvYyA9ICJ0b3BsZWZ0Iixjb2wgPSBteWNvbG9ycyxtYWluID0gIkNvbmZpcm1lZCBDYXNlcyIpCmBgYAoKCiMgTWFya2V0IFJlYWN0aW9uIApXZSBjb25zaWRlciB0d28gbWFqb3IgaW5kaWNlcyB0byByZWxhdGUgdG8gdGhlIGFzc29jaWF0ZSBpbXBhY3Qgb2YgdGhlIENPVklELTE5IHdpdGggdGhlIG1hcmtldC4gV2Ugd2lsbCBmb2N1cyBvbiB0aGUgU1wmUCA1MDAgYW5kIHRoZSBWSVggaW5kZXguIEdpdmVuIHRoZSBhZ2dyZWdhdGUgbnVtYmVyIG9mIGNhc2VzLCB3ZSBmb2N1cyBvbiB0aGUgYXZlcmFnZSBjb25maXJtZWQgY2FzZXMgb3ZlciB0aW1lIGFzIGEgcHJveHkgZm9yIHRoZSBvbnNsYXVnaHQgb2YgdGhlIGVwaWRlbWljLgoKIyMgU1wmUCBWcy4gVklYCldlIHRha2UgYSBxdWljayBhIGxvb2sgYXQgdGhlIGN1bXVsYXRpdmUgcmV0dXJuIG9mIGVhY2ggaW5kZXggc2luY2UgdGhlIGJlZ2lubmluZyBvZiB0aGUgeWVhci4gCmBgYHtyLG1lc3NhZ2U9Rix3YXJuaW5nPUYsZmlnLndpZHRoPTYsZmlnLmFsaWduPSJjZW50ZXIifQpsaWJyYXJ5KHF1YW50bW9kKQpnZXRTeW1ib2xzKCJeVklYIikKZ2V0U3ltYm9scygiXkdTUEMiKQoKU05QIDwtIEdTUEMkR1NQQy5BZGp1c3RlZApWSVggPC0gVklYJFZJWC5BZGp1c3RlZApkc19maW4gPC0gbWVyZ2UoU05QLFZJWCkKZHNfZmluIDwtIGRzX2Zpbi9sYWcoZHNfZmluKS0xCmRzX2ZpbiA8LSBkc19maW5bIjIwMjAwMTAxLyIsXQpuYW1lcyhkc19maW4pIDwtIGMoIlNOUCIsIlZJWCIpCnBsb3QoY3VtcHJvZChkc19maW4rMSksbGVnZW5kLmxvYyA9ICJ0b3BsZWZ0IixtYWluID0gIkN1bXVsYXRpdmUgUmV0dXJuIikKYGBgClRoZSByZWQgbGluZSBjb3JyZXNwb25kcyB0byB0aGUgVklYIGluZGV4LCB3aGVyZWFzIHRoZSBibGFjayBsaW5lIGNvcnJlc3BvbmRzIHRvIHRoZSByZXR1cm4gb24gdGhlIFNcJlAgNTAwLiBXZSBjYW4gc2VlIHRoYXQgYm90aCBhcmUgbmVnYXRpdmVseSBjb3JyZWxhdGVkLCB3aGVyZSBkcm9wcyBpbiB0aGUgZXF1aXR5IGluZGV4IGlzIGFjY29tcGFuaWVkIGJ5IGxhcmdlIGluY3JlYXNlcyBpbiB0aGUgVklYLCBoZW5jZSB0aGUgZXhwcmVzc2lvbiB0aGUgZmVhciBnYXVnZS4gQXQgdGhlIHNhbWUgdGltZSwgd2Ugd2l0bmVzcyBhIHNtYWxsIHJlY292ZXJ5IGluIHRoZSBlcXVpdHkgbWFya2V0ICBhcyB0aGUgbnVtYmVyIG9mIGNvbmZpcm1lZCBjYXNlcyBvZiBDT1ZJRC0xOSBoYXMgYmVlbiByZWxhdGl2ZWx5IG1haW50YWluZWQgcmVjZW50bHkuIAoKIyMgQWx0b2dldGhlcgpXZSBtb3ZlIHRvIGludmVzdGlnYXRlIHRoZSBtYXJrZXQgcmVhY3Rpb25zIHRvIHRoZSBpbmNyZWFzZSBpbiBjb25maXJtZWQgY2FzZXMuIFN1Y2ggbnVtYmVyIGNhbiBiZSB2aWV3ZWQgYXMgYW4gZXhwb25lbnRpYWwgZnVuY3Rpb24gb2YgdGltZSwgYXMgd2UgY2FuIHNlZSBiZWxvdwpgYGB7cixmaWcud2lkdGg9NixmaWcuYWxpZ249ImNlbnRlciJ9CmRzX2NvdmlkIDwtIGFzLnh0cyhhcHBseShEU190MTAsMSxzdW0pKQpwbG90KGRzX2NvdmlkLG1haW4gPSJUb3RhbCBDb25maXJtZWQgQ2FzZXMiKQpgYGAKVG8gZ2V0IGEgYmV0dGVyIHBlcnNwZWN0aXZlLCB3ZSBjYW4gdGhpbmsgYWJvdXQgdGhlIHNsb3BlIG9mIHRoaXMgZnVuY3Rpb24sIHdoaWNoIGRlbm90ZXMgdGhlIHZlbG9jaXR5IG9mIHRoZSBudW1iZXIgb2YgY2FzZXMgCmBgYHtyLGZpZy53aWR0aD02LGZpZy5hbGlnbj0iY2VudGVyIn0KZHNfY292aWRfMSA8LSBkc19jb3ZpZC9sYWcoZHNfY292aWQpLTEKcGxvdChkc19jb3ZpZF8xLG1haW4gPSAiSW5jcmVhc2UgUmF0ZSIpCmBgYApUaGUgYWJvdmUgcGxvdCBpbmRpY2F0ZXMgdGhlIHZlbG9jaXR5IG9mIHRoZSBjb25maXJtZWQgY2FzZXMuIFdlIGNhbiBzZWUgdGhhdCBpbiBhbGwgY2FzZXMgaXQgaXMgcG9zaXRpdmUuIEhvd2V2ZXIsIGF0IHRoZSBzYW1lIHRpbWUgd2Ugb2JzZXJ2ZSB0aGF0IHJhdGUgZGVjbGluZWQgcmVsYXRpdmUgdG8gdGhlIGJlZ2lubmluZyBvZiB0aGUgZXBpZGVtaWMuIFRoaXMgYnJpbmdzIHVzIHRvIHRoZSBhY2NlbGVyYXRpb24gb2YgdGhlIGNvbmZpcm1lZCBjYXNlcywgd2hpY2ggY29ycmVzcG9uZHMgdG8gdGhlIHNlY29uZCBkZXJpdmF0aXZlIG9mIHRoZSBjb25maXJtZWQgY2FzZXMgb3ZlciB0aW1lOgpgYGB7cixmaWcud2lkdGg9NixmaWcuYWxpZ249ImNlbnRlciJ9CmRzX2NvdmlkXzIgPC0gZHNfY292aWRfMS9sYWcoZHNfY292aWRfMSktMQpwbG90KGRzX2NvdmlkXzIsbWFpbiA9ICJBY2NlbGVyYXRpb24gUmF0ZSIpCmBgYApXZSBub3RlIHRoYXQgdGhlIGFjY2VsZXJhdGlvbiByYXRlIHNwaWtlcyBpbiBGZWIgMTMsIDIwMjAuIFRha2luZyBhIGNsb3NlciBsb29rIHRoaXMgaXMgdGhlIGNhc2Ugd2hlbiB0aGUgZGF0YSBpbiBDaGluYSBleGhpYml0cyB0aGF0IHRydW5jYXRpb24gY2hhcmFjdGVyaXN0aWMuIFRoZSByZXN1bHQgb2Ygd2hpY2ggbGVhZHMgdG8gYSBsYXJnZSBpbmNyZWFzZSBpbiB0aGUgc2Vjb25kIGRlcml2YXRpdmUuIFRvIG1pdGlnYXRlIHRoaXMsIHdlIHVzZSBhIGxvY2FsIHJlZ3Jlc3Npb24gdG8gc21vb3RoIG91dCB0aGUgdHJlbmQgb3ZlciB0aW1lIGFuZCBwbG90IGJlbG93CmBgYHtyLGZpZy53aWR0aD02LGZpZy5hbGlnbj0iY2VudGVyIn0KYSA8LSBuYS5vbWl0KGFzLm51bWVyaWMoZHNfY292aWRfMikpCnggPC0gMTpsZW5ndGgoYSkKYV9maXQgPC0gcHJlZGljdChsb2VzcyhhfngpKQpuYW1lcyhhX2ZpdCkgPC0gZGF0ZShuYS5vbWl0KGRzX2NvdmlkXzIpKQphX2ZpdCA8LSBhcy54dHMoYV9maXQpCnBsb3QoYV9maXQsIG1haW4gPSAiQWNjZWxlcmF0aW9uIFJhdGUgU21vb3RoZWQiLGNleCA9IDAuNSkKYGBgClRoZSBhYm92ZSBwbG90IHByb3ZpZGVzIGEgbW9yZSByb2J1c3QgcGVyc3BlY3RpdmUgaW4gdGVybXMgb2YgdGhlIGFjY2VsZXJhdGlvbiB0cmVuZCBvdmVyIHRpbWUuIFdlIGRpc2Nlcm4gdGhhdCB0aGUgYWNjZWxlcmF0aW9uIG9mIHRoZSBjb25maXJtZWQgY2FzZXMgaGFzIGRlY3JlYXNlZCBvdmVyIHRpbWUuIEluIG90aGVyIHdvcmRzLCB3aGlsZSB0aGUgbnVtYmVyIG9mIGNvbmZpcm1lZCBjYXNlcyBhcmUgc3RpbGwgaW5jcmVhc2luZywgdGhlIGluY3JlYXNlIHJhdGUgYXQgaGFzIGJlZW4gc2xvd2luZyBkb3duIHJlbGF0aXZlbHkuIAoKR2l2ZW4gdGhlIGFib3ZlIGluc2lnaHRzLCBsZXQgdXMgY29tYmluZSBhbHRvZ2V0aGVyIGFuZCBpbnZlc3RpZ2F0ZSB0aGUgbWFya2V0IHJlYWN0aW9uIHdpdGggcmVzcGVjdCB0byB0aGUgaW5jcmVhc2UgaW4gdGhlIGNvbmZpcm1lZCBjYXNlcy4gV2UgcmVmZXIgdG8gdGhlIGBwbG90bHlgIHBhY2thZ2UgdG8gaWxsdXN0cmF0ZSB0aGlzIHJlbGF0aW9uc2hpcC4gV2UgZG8gc28gZm9yIGEgY291cGxlIG9mIHJlYXNvbnMuIEZpcnN0LCBpdCBwcm92aWRlcyBleGNlbGxlbnQgaW50ZXJhY3RpdmUgdmlzdWFsaXphdGlvbiBwbGF0Zm9ybS4gU2Vjb25kLCB0aGUgc2NhbGUgb2YgdGhlIHktYXhpcyBjYW4gYmUgZWFzaWx5IG1vZGlmaWVkIHRvIGFjY29tbW9kYXRlIGEgbG9nLXNjYWxlLiBUaGlzIGlzIHJlbGV2YW50IHdoZW4gY29udHJvbGxpbmcgZm9yIGxldmVsIGluY3JlYXNlcyAoc3VjaCBhcyBwcmljZSBsZXZlbHMpLiBGaW5hbGx5LCB0d28gZGlmZmVyZW50IHRpbWUgc2VyaWVzIGNhbiBiZSBwbG90dGVkIGVhc2lseSBvbiB0aGUgb3Bwb3NpdGUgeS1heGlzLiBPbiB0aGUgbGVmdCBoYW5kIHNpZGUsIHdlIHBsb3QgdGhlIG1hcmtldCBkYXRhLCB3aGVyZWFzIHdlIHBsb3QgdGhlIENPVklELTE5IGRhdGEgb24gdGhlIHJpZ2h0IGhhbmQgc2lkZSB5LWF4aXMuCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GLGZpZy53aWR0aD02LGZpZy5hbGlnbj0iY2VudGVyIn0KbGlicmFyeShwbG90bHkpCiMgY2hvb3NlIHRoZSBsYWJlbHMgZm9ybWF0CmYgPC0gbGlzdCgKICBmYW1pbHkgPSAiQ291cmllciBOZXcsIG1vbm9zcGFjZSIsCiAgc2l6ZSA9IDE4LAogIGNvbG9yID0gIiM3ZjdmN2YiCikKCiMgeC1heGlzIAp4bCA8LSBsaXN0KAogIHRpdGxlID0gIkRhdGUiLAogIHRpdGxlZm9udCA9IGYKKQoKIyB5LWF4aXMgZm9yIFMmUAp5bCA8LSBsaXN0KAogIHRpdGxlID0gIlMmUCA1MDAiLAogIHRpdGxlZm9udCA9IGYsCiAgdHlwZSA9ICJsb2ciCikKCiMgcmlnaHQgaGFuZCB5LWF4aXMgZm9yIFZJWAp5bDIgPC0gbGlzdCh0aXRsZSA9ICJDT1ZJRC0xOSBSYXRlIiwKICAgICAgICBvdmVybGF5aW5nID0gInkiLAogICAgICAgIHRpdGxlZm9udCA9IGYsIAogICAgICAgIHNpZGUgPSAicmlnaHQiLAogICAgICAgIHR5cGUgPSAibG9nIikKCgpzbnAgPC0gYXMubnVtZXJpYyhjdW1wcm9kKGRzX2ZpbiRTTlArMSkpCnZpeCA8LSBhcy5udW1lcmljKGN1bXByb2QoZHNfZmluJFZJWCsxKSkKY292aWQgPC0gYXMubnVtZXJpYyhkc19jb3ZpZF8xWywxXSkKcCA8LSBwbG90X2x5KCkKcCA8LSBhZGRfbGluZXMocCx4ID0gfiBkYXRlKGRzX2ZpbiksIHkgPSB+IHNucCwgbmFtZSA9ICJTJlAgNTAwIikKcCA8LSBhZGRfbGluZXMocCx4ID0gfiBkYXRlKGRzX2ZpbiksIHkgPSB+IHZpeCwgbmFtZSA9ICJWSVgiKQpwIDwtIGFkZF9saW5lcyhwLHggPSB+IGRhdGUoZHNfY292aWRfMSksIHkgPSB+IGNvdmlkICx5YXhpcyA9ICJ5MiIsIG5hbWUgPSAiQ09WSUQtMTkiKSAKcCA8LSBsYXlvdXQocCx5YXhpcyA9IHlsLCB5YXhpczIgPSB5bDIseGF4aXMgPSB4bCkKcAoKYGBgCkEgY291cGxlIG9mIGNvbW1lbnRzIGFyZSBpbiBvcmRlci4gRmlyc3QsIHdlIG5vdGUgdGhhdCB0aGUgbWFqb3Igc3Bpa2UgaW4gdGhlIFZJWCBpbmRleCB0b29rIHBsYWNlIGR1cmluZyB0aGUgdGltZSB0aGF0IHRoZSB2ZWxvY2l0eSBvZiB0aGUgQ09WSUQtMTkgY29uZmlybWVkIGNhc2VzIHN0YXJ0ZWQgdG8gaW5jcmVhc2UgYWdhaW4uIFRoaXMgY2FuIGJlIHRyYWNlZCBiYWNrIHRvIEZlYiAyM3JkLCAyMDIwLiBCZWZvcmUgdGhhdCwgdGhpcyBpcyB0aGUgdGltZSBkdXJpbmcgd2hpY2ggQ2hpbmEgZGVtb25zdHJhdGVkIHBvc2l0aXZlIHNpZ25zIG9mIG1haW50YWluaW5nIGl0LiBIb3dldmVyLCBhZnRlcndhcmRzLCB0aGlzIGlzIHRoZSB0aW1lIGR1cmluZyB3aGljaCB3ZSB3aXRuZXNzZWQgdGhlIHNwcmVhZCBvZiB0aGUgZXBpZGVtaWMgb3V0c2lkZSBDaGluYSwgZXNwZWNpYWxseSBpbiB0aGUgVVMuIAoKU2Vjb25kLCBpdCBpcyBpbnRlcmVzdGluZyB0byBzZWUgaG93IG11Y2ggdGhlIGZlYXIgZ2F1Z2UgaXMgYXNzb2NpYXRlZCB3aXRoIHRoZSBDT1ZJRC0xOSB2ZWxvY2l0eSwgaS5lLiBpbmNyZWFzZSByYXRlLiBTaW5jZSBtaWQtTWFyY2gsIHdlIG9ic2VydmUgdGhhdCB0aGUgVklYIGhhcyBkcm9wcGVkIGZyb20gaXRzIHBlYWssIHdoaWxlIGF0IHRoZSBzYW1lIHRpbWUgdGhlIHZlbG9jaXR5IG9mIHRoZSBDT1ZJRC0xOSBoYXMgYWxzbyBkcm9wcGVkLiBXZSBkaXNjZXJuIHRoYXQgYm90aCB0aW1lIHNlcmllcyBleGhpYml0IGFuIGludmVyc2UgVSBzaGFwZSBzaW5jZSBsYXRlIEZlYiAyMDIwLiBUaGUgb3Bwb3NpdGUgaG9sZHMgdHJ1ZSBmb3IgdGhlIFNcJlAgNTAwLCB3aGVyZSB3ZSBhcmUgY3VycmVudGx5IHdpdG5lc3NpbmcgYSAgc21hbGwgcmVjb3ZlcnkuCgojIENvbmNsdWRpbmcgUmVtYXJrcwpFY29ub21pYyBhY3Rpdml0eSBpcyBub3Qgc2ltcGx5IGNvbnRyYWN0aW5nIHdpdGggdGhlIG9uZ29pbmcgZXBpZGVtaWMuIFdlIGFyZSBhY3R1YWxseSB3aXRuZXNzaW5nIGEgY29tcGxldGUgZnJlZXplIGluIHRoZSBlY29ub215LiBUaGlzIGhhcyBhbHJlYWR5IG1hbmlmZXN0ZWQgaW4gYSBsYXJnZSBzZWxsLW9mZiBzaW5jZSBsYXRlIEZlYiAyMDIwLiBUaGUgdmVsb2NpdHkgb2YgY29uZmlybWVkIGNhc2VzIG9mIENPVklELTE5IHNlZW1zIHRvIGJlIGRyb3BwaW5nIG92ZXIgdGhlIGxhc3QgdHdvIHdlZWtzLCB0aGUgc2FtZSBob2xkcyB0cnVlIGZvciB0aGUgbWFya2V0IGZlYXIgZ2F1Z2UgKFZJWCkuIFRoZSBTXCZQIDUwMCBzZWVtcyB0byBiZSByZWJvdW5kaW5nIGFzIHRoZSBvdGhlciBpbmRpY2F0b3JzIHNsb3cgZG93bi4gTm9uZXRoZWxlc3MsIHRoZXJlIGlzIG1vcmUgdW5jZXJ0YWludHkgdG8gY29tZSBnaXZlbiB0aGUgc3BpbGxvdmVyIGVmZmVjdCBvZiB0aGUgZXBpZGVtaWMgYW5kIGl0cyBsb25nLXRlcm0gaW1wYWN0LiBGb3IgdGhlIGludGVyZXN0ZWQgcmVhZGVyLCBJIHN1Z2dlc3QgbG9va2luZyBpbnRvIHRoaXMgW3JlcG9ydF0oaHR0cHM6Ly93d3cuYmxhY2tyb2NrLmNvbS9jb3Jwb3JhdGUvaW5zaWdodHMvYmxhY2tyb2NrLWludmVzdG1lbnQtaW5zdGl0dXRlL3B1YmxpY2F0aW9ucy9nbG9iYWwtbWFjcm8tb3V0bG9vaykgYnkgQmxhY2tSb2NrLiAKCiMgQWNrbm93bGVkZ2VtZW50ClRoZSBhYm92ZSB2aWduZXR0ZSBoYXMgZ3JlYXRseSBiZW5lZml0ZWQgZnJvbSBkYXRhLCBjb21tZW50cywgbGlicmFyaWVzLCAgYW5kIG90aGVyIGNvZGUgc291cmNlcyBwb3N0ZWQgb24gdGhlIHdlYi4gRm9yIGluc3RhbmNlLCB3ZSBmb2xsb3dlZCBEaXJrIEVkZGVsYnVldHRlbCdzIGluc3RydWN0aW9ucyBvbiBbU3RhY2sgT3ZlcmZsb3ddKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzMwNTM4MzMvdXNpbmctci10by1kb3dubG9hZC16aXBwZWQtZGF0YS1maWxlLWV4dHJhY3QtYW5kLWltcG9ydC1kYXRhKSB0byBkb3dubG9hZCB0aGUgZGF0YSBpbiBhbiBhdXRvbWF0ZWQgbWFubmVyLiBTcGVjaWFsIHRoYW5rcyB0byBoaW0gYW5kIG90aGVyIG1lbWJlcnMgb2YgdGhlIFIgY29tbXVuaXR5LiBBbHNvLCB3ZSB0aGFuayBbRGF0YSBOb3ZpYV0oaHR0cHM6Ly93d3cuZGF0YW5vdmlhLmNvbS9lbi9ibG9nL2Vhc3ktd2F5LXRvLWV4cGFuZC1jb2xvci1wYWxldHRlcy1pbi1yKSBmb3IgcG9pbnRpbmcgb3V0IGhvdyB0byBleHBhbmQgY29sb3IgcGFsZXR0ZXMuIApGaW5hbGx5LCBvdXIgc2luY2VyZSBncmFkdWF0ZSBnb2VzIHRvIHRoZSB0ZWFtIGF0IEpvaG4gSG9wa2lucyBmb3IgcHV0dGluZyB0aGlzIGdyZWF0IGVmZm9ydCBhbmQgbWFraW5nIHRoaXMgZGF0YSBwdWJsaWNseSBhdmFpbGFibGUuIA==