Last update: 2020-06-01 01:34:37
Intro
Our objective is to estimate the survival distribution of patients in the presence of censoring.
- Why not compare mean time-to-event between groups using a t-test or linear regression?
- Why not compare proportion of events in groups using risk/odds ratios or logistic regression?
Time-to-event
In survival analysis the time until the occurrence of a well-defined event is recorded (time-to-event data). “Survival time”.
If everyone had an event, some of the methods we have already learned could be applied.
Often, not everyone has event (censoring) - Loss to follow-up - End of study
Censoring
Subjects are said to be censored if they are lost to follow up or drop out of the study, or if they die of unrelated causes or the study ends before they have the event of interest. They are counted as alive or disease-free for the time they were enrolled in the study. 10
Survival Analysis
Two-variable outcome:
Time variable \((T)\): is a random variable denoting the time of the event. \(t_i\) is the time at last event-free observation or just before the event, is a random variable having a probability distribution. Being this, the Survival function is the probability that the time of the event \((T)\) is later than some specified time \(t\). Formula 1.1
Censoring variable \((C)\): \(c_i\) = 1 if had the event; \(c_i\) = 0 no event by time \(t_i\)
Different models for survival data are distinguished by different choice of distribution for \(t_i\).
The object of primary interest is the survival function, conventionally denoted S, which is defined as
\[
S(t)=\Pr(T>t) \tag{1.1}
\]
Let \(T\) be survival time, which is any positive number. A particular time is designated by the lower case letter \(t\). The cumulative distribution function (or lifetime distribution function) of \(T\) is the function, conventionally denoted \(F\), defined as the complement of the survival function.
- The cumulative distribution function of \(T\)
\[
F(t)=\Pr(T \leq t)= 1 - S(t) \tag{2.1}
\] If \(F\) is differentiable then the first derivative, which is the density function of the lifetime distribution, is conventionally denoted \(f\). The function \(f\) is sometimes called the event density; it is the rate of death or failure events per unit time.
- Density function of the cumulative distribution function of \(T\)
- Rate of death or failure events per unit time
- The probability of the event occurring at exactly time \(t\)
\[f(t)=F'(t)={\frac{d}{dt}}F(t) \tag{3.1}\]
Back to the survival function (1.1), it can be expressed in terms of probability distribution and probability density functions
\[S(t)=\Pr(T>t)=\int _{t}^{{\infty }}f(u)\,du=1-F(t) \tag{4.1}\]
Similarly, a survival event density function can be defined as
\[s(t)=S'(t)={\frac {d}{dt}}S(t)={\frac {d}{dt}}\int _{t}^{{\infty }}f(u)\,du={\frac {d}{dt}}[1-F(t)]=-f(t) \tag{4.2}\]
Hazard function and cumulative hazard function
- \(f(t)\) event density, is rate of death or failure events per unit time. The probability of the event occurring at exactly time \(t\)
- Example: a woman born today has, say, a 1% chance of dying at 80 years
- Hazard rate is an instantaneous incidence rate. It is conditional on survival until time \(t\) or later.
- Example: a woman who is 79 today has, say, a 5% chance of dying at 80 years
The hazard function, conventionally denoted , is defined as the event rate at time \(t\) conditional on survival until time \(t\) or later (that is, \(T ≥ t\)). Suppose that an item has survived for a time \(t\) and we desire the probability that it will not survive for an additional time \(dt\):
\[
{\lambda (t)=\lim _{dt\rightarrow 0}{\frac {\Pr(t\leq T<t+dt)}{dt\cdot S(t)}}={\frac {f(t)}{S(t)}}=-{\frac {S'(t)}{S(t)}}}
\tag{4.1}
\]
Example
- We need two variables: one continuous for the time, and one categorical for flagging the event
library(readr)
library(tidyr)
library(splines2)
library(survival)
library(survminer)
Kaplan-Meier
data_test <- read_delim("data2.csv", ";",
escape_double = FALSE,
locale = locale(decimal_mark = ",", grouping_mark = "."),
trim_ws = TRUE
)
Parsed with column specification:
cols(
id = col_double(),
fu = col_double(),
event = col_double(),
event_HD = col_double(),
event_RT = col_double(),
event_CR = col_double(),
peritonitis = col_double(),
sex = col_double(),
age = col_double(),
diab = col_double(),
first = col_double()
)
km <- survfit(Surv(fu, event) ~ 1, data = data_test)
wb <- survreg(Surv(fu, event) ~ 1, data = data_test)
ggsurvplot(km, conf.int = TRUE, risk.table = "nrisk_cumevents", legend = "none", tables.height = 0.2)


km2 <- survfit(Surv(time, cens) ~ 1, data = GBSG2)
ggsurvplot(km2, palette = "blue", conf.int = TRUE, risk.table = "nrisk_cumevents", surv.median.line = "hv", tables.height = 0.3)


Weibull model
# weibull approximation
wb2 <- survreg(Surv(time, cens) ~ 1, data = GBSG2)
surv <- seq(.99, .01, by = -0.1)
t <- predict(wb2, type = "quantile", p = 1 - surv, newdata = data.frame(1))
surv_wb <- data.frame(time = t, surv = surv, upper = NA, lower = NA, std.err = NA)
ggsurvplot_df(fit = surv_wb, surv.geom = geom_line)

# weibull approximation with covariants
# Compute the Weibull model
wbmod <- survreg(Surv(time, cens) ~ horTh + tsize, data = GBSG2)
# Decide on "imaginary patients"
newdat <- expand.grid(
horTh = levels(GBSG2$horTh),
tsize = quantile(GBSG2$tsize, probs = c(0.25, 0.5, 0.75))
)
# Compute survival curves
surv <- seq(.99, .01, by = -0.1)
t <- predict(wbmod, type = "quantile", p = 1 - surv, newdata = newdat)
surv_wbmod_wide <- cbind(newdat, t)
# Create data.frame with survival curve information
surv_wbmod <- pivot_longer(surv_wbmod_wide, -(horTh:tsize), names_to = "surv_id", values_to = "time")
surv_wbmod$surv <- surv[as.numeric(surv_wbmod$surv_id)]
surv_wbmod[, c("upper", "lower", "std.err", "strata")] <- NA
surv_wbmod <- as.data.frame(surv_wbmod) # survplot bug
# plot
ggsurvplot_df(surv_wbmod, surv.geom = geom_line, linetype = "horTh", color = "tsize", legend.title = NULL)

Cox Model
# Compute the cox model
cxmod <- coxph(Surv(time, cens) ~ horTh + tsize, data = GBSG2)
# Decide on covariate combinations ("imaginary patients")
newdat <- expand.grid(
horTh = levels(GBSG2$horTh),
tsize = quantile(GBSG2$tsize, probs = c(0.25, 0.5, 0.75))
)
rownames(newdat) <- letters[1:6]
# Compute survival curves
cxsf <- survfit(cxmod, data = GBSG2, newdata = newdat, conf.type = "none")
# Create data.frame with survival curve information
surv_cxmod0 <- surv_summary(cxsf)
surv_cxmod <- cbind(surv_cxmod0, newdat[as.character(surv_cxmod0$strata), ])
# Plot
ggsurvplot_df(surv_cxmod, linetype = "horTh", color = "tsize",
legend.title = NULL, censor = FALSE)

LS0tCnRpdGxlOiAiSEVBRFMgLSBISURBIC0gU1RBVFMgLSBTdXJ2aXZhbCBBbmFseXNpcyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0aGVtZTogdW5pdGVkCiAgICB0b2M6IHllcwphdXRob3I6IEZyYW5jaXNjbyBCaXNjaG9mZgotLS0KCkxhc3QgdXBkYXRlOiBgciBsdWJyaWRhdGU6Om5vdygpYAoKIyMgSW50cm8KCk91ciBvYmplY3RpdmUgaXMgdG8gZXN0aW1hdGUgdGhlIHN1cnZpdmFsIGRpc3RyaWJ1dGlvbiBvZiBwYXRpZW50cyBpbiB0aGUgcHJlc2VuY2Ugb2YgY2Vuc29yaW5nLgoKIC0gV2h5IG5vdCBjb21wYXJlIG1lYW4gdGltZS10by1ldmVudCBiZXR3ZWVuIGdyb3VwcyB1c2luZyBhIHQtdGVzdCBvciBsaW5lYXIgcmVncmVzc2lvbj8KICAgLSBJZ25vcmVzIGNlbnNvcmluZwoKIC0gV2h5IG5vdCBjb21wYXJlIHByb3BvcnRpb24gb2YgZXZlbnRzIGluIGdyb3VwcyB1c2luZyByaXNrL29kZHMgcmF0aW9zIG9yIGxvZ2lzdGljIHJlZ3Jlc3Npb24/CiAgIC0gSWdub3JlcyB0aW1lCgojIyBUaW1lLXRvLWV2ZW50CgpJbiBzdXJ2aXZhbCBhbmFseXNpcyB0aGUgdGltZSB1bnRpbCB0aGUgb2NjdXJyZW5jZSBvZiBhIHdlbGwtZGVmaW5lZCBldmVudCBpcyByZWNvcmRlZCAodGltZS10by1ldmVudCBkYXRhKS4gIlN1cnZpdmFsIHRpbWUiLgoKSWYgZXZlcnlvbmUgaGFkIGFuIGV2ZW50LCBzb21lIG9mIHRoZSBtZXRob2RzIHdlIGhhdmUgYWxyZWFkeSBsZWFybmVkIGNvdWxkIGJlIGFwcGxpZWQuCgpPZnRlbiwgbm90IGV2ZXJ5b25lIGhhcyBldmVudCAoY2Vuc29yaW5nKQogLSBMb3NzIHRvIGZvbGxvdy11cAogLSBFbmQgb2Ygc3R1ZHkKCiMjIENlbnNvcmluZwoKU3ViamVjdHMgYXJlIHNhaWQgdG8gYmUgY2Vuc29yZWQgaWYgdGhleSBhcmUgbG9zdCB0byBmb2xsb3cgdXAgb3IgZHJvcCBvdXQgb2YgdGhlIHN0dWR5LCBvciBpZiB0aGV5IGRpZSBvZiB1bnJlbGF0ZWQgY2F1c2VzIG9yIHRoZSBzdHVkeSBlbmRzIGJlZm9yZSB0aGV5IGhhdmUgdGhlIGV2ZW50IG9mIGludGVyZXN0LiBUaGV5IGFyZSBjb3VudGVkIGFzIGFsaXZlIG9yIGRpc2Vhc2UtZnJlZSBmb3IgdGhlIHRpbWUgdGhleSB3ZXJlIGVucm9sbGVkIGluIHRoZSBzdHVkeS4KMTAKCiMjIFN1cnZpdmFsIEFuYWx5c2lzCgpUd28tdmFyaWFibGUgb3V0Y29tZTogCgpUaW1lIHZhcmlhYmxlICQoVCkkOiBpcyBhICpyYW5kb20gdmFyaWFibGUqIGRlbm90aW5nIHRoZSB0aW1lIG9mIHRoZSBldmVudC4gJHRfaSQgaXMgdGhlIHRpbWUgYXQgbGFzdCBldmVudC1mcmVlIG9ic2VydmF0aW9uIG9yIGp1c3QgYmVmb3JlIHRoZSBldmVudCwgaXMgYSByYW5kb20gdmFyaWFibGUgaGF2aW5nIGEgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uLiBCZWluZyB0aGlzLCB0aGUgU3Vydml2YWwgZnVuY3Rpb24gaXMgdGhlIHByb2JhYmlsaXR5IHRoYXQgdGhlIHRpbWUgb2YgdGhlIGV2ZW50ICQoVCkkIGlzIGxhdGVyIHRoYW4gc29tZSBzcGVjaWZpZWQgdGltZSAkdCQuIEZvcm11bGEgWzEuMV0oKQoKQ2Vuc29yaW5nIHZhcmlhYmxlICQoQykkOiAkY19pJCA9IDEgaWYgaGFkIHRoZSBldmVudDsgJGNfaSQgPSAwIG5vIGV2ZW50IGJ5IHRpbWUgJHRfaSQKCgpEaWZmZXJlbnQgbW9kZWxzIGZvciBzdXJ2aXZhbCBkYXRhIGFyZSBkaXN0aW5ndWlzaGVkIGJ5IGRpZmZlcmVudCBjaG9pY2Ugb2YgZGlzdHJpYnV0aW9uIGZvciAkdF9pJC4KCgoKClRoZSBvYmplY3Qgb2YgcHJpbWFyeSBpbnRlcmVzdCBpcyB0aGUgc3Vydml2YWwgZnVuY3Rpb24sIGNvbnZlbnRpb25hbGx5IGRlbm90ZWQgUywgd2hpY2ggaXMgZGVmaW5lZCBhcwoKJCQKUyh0KT1cUHIoVD50KSBcdGFnezEuMX0KJCQKCkxldCAkVCQgYmUgc3Vydml2YWwgdGltZSwgd2hpY2ggaXMgYW55IHBvc2l0aXZlIG51bWJlci4gQSAqcGFydGljdWxhciB0aW1lKiBpcyBkZXNpZ25hdGVkIGJ5IHRoZSAqbG93ZXIgY2FzZSBsZXR0ZXIqICR0JC4gVGhlICoqY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24qKiAob3IgKmxpZmV0aW1lIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiopIG9mICRUJCBpcyB0aGUgZnVuY3Rpb24sIGNvbnZlbnRpb25hbGx5IGRlbm90ZWQgJEYkLCBkZWZpbmVkIGFzIHRoZSBjb21wbGVtZW50IG9mIHRoZSBzdXJ2aXZhbCBmdW5jdGlvbi4KCi0gVGhlICoqY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24qKiBvZiAkVCQKCiQkCkYodCk9XFByKFQgXGxlcSB0KT0gMSAtIFModCkgXHRhZ3syLjF9CiQkCklmICRGJCBpcyBkaWZmZXJlbnRpYWJsZSB0aGVuIHRoZSBmaXJzdCBkZXJpdmF0aXZlLCB3aGljaCBpcyB0aGUgKipkZW5zaXR5IGZ1bmN0aW9uIG9mIHRoZSBsaWZldGltZSBkaXN0cmlidXRpb24qKiwgaXMgY29udmVudGlvbmFsbHkgZGVub3RlZCAkZiQuClRoZSBmdW5jdGlvbiAkZiQgaXMgc29tZXRpbWVzIGNhbGxlZCB0aGUgKipldmVudCBkZW5zaXR5Kio7IGl0IGlzIHRoZSAqKnJhdGUgb2YgZGVhdGggb3IgZmFpbHVyZSBldmVudHMgcGVyIHVuaXQgdGltZSoqLgoKLSBEZW5zaXR5IGZ1bmN0aW9uIG9mIHRoZSAqKmN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uKiogb2YgJFQkCi0gUmF0ZSBvZiBkZWF0aCBvciBmYWlsdXJlIGV2ZW50cyBwZXIgdW5pdCB0aW1lCi0gVGhlIHByb2JhYmlsaXR5IG9mIHRoZSBldmVudCBvY2N1cnJpbmcgYXQgZXhhY3RseSB0aW1lICR0JAoKJCRmKHQpPUYnKHQpPXtcZnJhY3tkfXtkdH19Rih0KSBcdGFnezMuMX0kJAoKQmFjayB0byB0aGUgc3Vydml2YWwgZnVuY3Rpb24gKDEuMSksIGl0IGNhbiBiZSBleHByZXNzZWQgaW4gdGVybXMgb2YgKnByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiogYW5kICpwcm9iYWJpbGl0eSBkZW5zaXR5IGZ1bmN0aW9ucyoKCgokJFModCk9XFByKFQ+dCk9XGludCBfe3R9Xnt7XGluZnR5IH19Zih1KVwsZHU9MS1GKHQpIFx0YWd7NC4xfSQkCgpTaW1pbGFybHksIGEgc3Vydml2YWwgKipldmVudCBkZW5zaXR5KiogZnVuY3Rpb24gY2FuIGJlIGRlZmluZWQgYXMKCiQkcyh0KT1TJyh0KT17XGZyYWMgIHtkfXtkdH19Uyh0KT17XGZyYWMgIHtkfXtkdH19XGludCBfe3R9Xnt7XGluZnR5IH19Zih1KVwsZHU9e1xmcmFjICB7ZH17ZHR9fVsxLUYodCldPS1mKHQpIFx0YWd7NC4yfSQkCgojIyBIYXphcmQgZnVuY3Rpb24gYW5kIGN1bXVsYXRpdmUgaGF6YXJkIGZ1bmN0aW9uCgotICRmKHQpJCAqKmV2ZW50IGRlbnNpdHkqKiwgaXMgcmF0ZSBvZiBkZWF0aCBvciBmYWlsdXJlIGV2ZW50cyBwZXIgdW5pdCB0aW1lLiBUaGUgcHJvYmFiaWxpdHkgb2YgdGhlIGV2ZW50IG9jY3VycmluZyBhdCBleGFjdGx5IHRpbWUgJHQkCiAgLSBFeGFtcGxlOiBhIHdvbWFuIGJvcm4gdG9kYXkgaGFzLCBzYXksIGEgMSUgY2hhbmNlIG9mIGR5aW5nIGF0IDgwIHllYXJzCi0gSGF6YXJkIHJhdGUgaXMgYW4gaW5zdGFudGFuZW91cyAqKmluY2lkZW5jZSByYXRlKiouIEl0IGlzIGNvbmRpdGlvbmFsIG9uIHN1cnZpdmFsIHVudGlsIHRpbWUgJHQkIG9yIGxhdGVyLgogIC0gRXhhbXBsZTogYSB3b21hbiB3aG8gaXMgNzkgdG9kYXkgaGFzLCBzYXksIGEgNSUgY2hhbmNlIG9mIGR5aW5nIGF0IDgwIHllYXJzCgoKVGhlIGhhemFyZCBmdW5jdGlvbiwgY29udmVudGlvbmFsbHkgZGVub3RlZCBcbGFtYmRhLCBpcyBkZWZpbmVkIGFzIHRoZSBldmVudCByYXRlIGF0IHRpbWUgJHQkIGNvbmRpdGlvbmFsIG9uIHN1cnZpdmFsIHVudGlsIHRpbWUgJHQkIG9yIGxhdGVyICh0aGF0IGlzLCAkVCDiiaUgdCQpLiBTdXBwb3NlIHRoYXQgYW4gaXRlbSBoYXMgc3Vydml2ZWQgZm9yIGEgdGltZSAkdCQgYW5kIHdlIGRlc2lyZSB0aGUgcHJvYmFiaWxpdHkgdGhhdCBpdCB3aWxsIG5vdCBzdXJ2aXZlIGZvciBhbiBhZGRpdGlvbmFsIHRpbWUgJGR0JDoKCiQkCntcbGFtYmRhICh0KT1cbGltIF97ZHRccmlnaHRhcnJvdyAwfXtcZnJhYyB7XFByKHRcbGVxIFQ8dCtkdCl9e2R0XGNkb3QgUyh0KX19PXtcZnJhYyB7Zih0KX17Uyh0KX19PS17XGZyYWMge1MnKHQpfXtTKHQpfX19Clx0YWd7NC4xfQokJAoKIyMgRXhhbXBsZQoKLSBXZSBuZWVkIHR3byB2YXJpYWJsZXM6IG9uZSBjb250aW51b3VzIGZvciB0aGUgdGltZSwgYW5kIG9uZSBjYXRlZ29yaWNhbCBmb3IgZmxhZ2dpbmcgdGhlIGV2ZW50CgoKYGBge3Igc2V0dXAsIG1lc3NhZ2UgPSBGQUxTRSwJd2FybmluZyA9IEZBTFNFfQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHNwbGluZXMyKQpsaWJyYXJ5KHN1cnZpdmFsKQpsaWJyYXJ5KHN1cnZtaW5lcikKYGBgCgoKIyMjIEthcGxhbi1NZWllcgoKYGBge3J9CmRhdGFfdGVzdCA8LSByZWFkX2RlbGltKCJkYXRhMi5jc3YiLCAiOyIsCiAgZXNjYXBlX2RvdWJsZSA9IEZBTFNFLAogIGxvY2FsZSA9IGxvY2FsZShkZWNpbWFsX21hcmsgPSAiLCIsIGdyb3VwaW5nX21hcmsgPSAiLiIpLAogIHRyaW1fd3MgPSBUUlVFCikKCmttIDwtIHN1cnZmaXQoU3VydihmdSwgZXZlbnQpIH4gMSwgZGF0YSA9IGRhdGFfdGVzdCkKd2IgPC0gc3VydnJlZyhTdXJ2KGZ1LCBldmVudCkgfiAxLCBkYXRhID0gZGF0YV90ZXN0KQoKZ2dzdXJ2cGxvdChrbSwgY29uZi5pbnQgPSBUUlVFLCByaXNrLnRhYmxlID0gIm5yaXNrX2N1bWV2ZW50cyIsIGxlZ2VuZCA9ICJub25lIiwgdGFibGVzLmhlaWdodCA9IDAuMikKYGBgCgoKYGBge3J9CmttMiA8LSBzdXJ2Zml0KFN1cnYodGltZSwgY2VucykgfiAxLCBkYXRhID0gR0JTRzIpCmdnc3VydnBsb3Qoa20yLCBwYWxldHRlID0gImJsdWUiLCBjb25mLmludCA9IFRSVUUsIHJpc2sudGFibGUgPSAibnJpc2tfY3VtZXZlbnRzIiwgc3Vydi5tZWRpYW4ubGluZSA9ICJodiIsIHRhYmxlcy5oZWlnaHQgPSAwLjMpCmBgYAoKCiMjIyBXZWlidWxsIG1vZGVsCgpgYGB7cn0KIyB3ZWlidWxsIGFwcHJveGltYXRpb24Kd2IyIDwtIHN1cnZyZWcoU3Vydih0aW1lLCBjZW5zKSB+IDEsIGRhdGEgPSBHQlNHMikKc3VydiA8LSBzZXEoLjk5LCAuMDEsIGJ5ID0gLTAuMSkKdCA8LSBwcmVkaWN0KHdiMiwgdHlwZSA9ICJxdWFudGlsZSIsIHAgPSAxIC0gc3VydiwgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoMSkpCnN1cnZfd2IgPC0gZGF0YS5mcmFtZSh0aW1lID0gdCwgc3VydiA9IHN1cnYsIHVwcGVyID0gTkEsIGxvd2VyID0gTkEsIHN0ZC5lcnIgPSBOQSkKZ2dzdXJ2cGxvdF9kZihmaXQgPSBzdXJ2X3diLCBzdXJ2Lmdlb20gPSBnZW9tX2xpbmUpCgoKIyB3ZWlidWxsIGFwcHJveGltYXRpb24gd2l0aCBjb3ZhcmlhbnRzCiMgQ29tcHV0ZSB0aGUgV2VpYnVsbCBtb2RlbAp3Ym1vZCA8LSBzdXJ2cmVnKFN1cnYodGltZSwgY2VucykgfiBob3JUaCArIHRzaXplLCBkYXRhID0gR0JTRzIpCgojIERlY2lkZSBvbiAiaW1hZ2luYXJ5IHBhdGllbnRzIgpuZXdkYXQgPC0gZXhwYW5kLmdyaWQoCiAgaG9yVGggPSBsZXZlbHMoR0JTRzIkaG9yVGgpLAogIHRzaXplID0gcXVhbnRpbGUoR0JTRzIkdHNpemUsIHByb2JzID0gYygwLjI1LCAwLjUsIDAuNzUpKQopCgojIENvbXB1dGUgc3Vydml2YWwgY3VydmVzCnN1cnYgPC0gc2VxKC45OSwgLjAxLCBieSA9IC0wLjEpCnQgPC0gcHJlZGljdCh3Ym1vZCwgdHlwZSA9ICJxdWFudGlsZSIsIHAgPSAxIC0gc3VydiwgbmV3ZGF0YSA9IG5ld2RhdCkKc3Vydl93Ym1vZF93aWRlIDwtIGNiaW5kKG5ld2RhdCwgdCkKCiMgQ3JlYXRlIGRhdGEuZnJhbWUgd2l0aCBzdXJ2aXZhbCBjdXJ2ZSBpbmZvcm1hdGlvbgpzdXJ2X3dibW9kIDwtIHBpdm90X2xvbmdlcihzdXJ2X3dibW9kX3dpZGUsIC0oaG9yVGg6dHNpemUpLCBuYW1lc190byA9ICJzdXJ2X2lkIiwgdmFsdWVzX3RvID0gInRpbWUiKQpzdXJ2X3dibW9kJHN1cnYgPC0gc3Vydlthcy5udW1lcmljKHN1cnZfd2Jtb2Qkc3Vydl9pZCldCnN1cnZfd2Jtb2RbLCBjKCJ1cHBlciIsICJsb3dlciIsICJzdGQuZXJyIiwgInN0cmF0YSIpXSA8LSBOQQpzdXJ2X3dibW9kIDwtIGFzLmRhdGEuZnJhbWUoc3Vydl93Ym1vZCkgIyBzdXJ2cGxvdCBidWcKCiMgcGxvdApnZ3N1cnZwbG90X2RmKHN1cnZfd2Jtb2QsIHN1cnYuZ2VvbSA9IGdlb21fbGluZSwgbGluZXR5cGUgPSAiaG9yVGgiLCBjb2xvciA9ICJ0c2l6ZSIsIGxlZ2VuZC50aXRsZSA9IE5VTEwpCmBgYAoKCiMjIyBDb3ggTW9kZWwKCgpgYGB7cn0KCiMgQ29tcHV0ZSB0aGUgY294IG1vZGVsCmN4bW9kIDwtIGNveHBoKFN1cnYodGltZSwgY2VucykgfiBob3JUaCArIHRzaXplLCBkYXRhID0gR0JTRzIpCgojIERlY2lkZSBvbiBjb3ZhcmlhdGUgY29tYmluYXRpb25zICgiaW1hZ2luYXJ5IHBhdGllbnRzIikKbmV3ZGF0IDwtIGV4cGFuZC5ncmlkKAogIGhvclRoID0gbGV2ZWxzKEdCU0cyJGhvclRoKSwKICB0c2l6ZSA9IHF1YW50aWxlKEdCU0cyJHRzaXplLCBwcm9icyA9IGMoMC4yNSwgMC41LCAwLjc1KSkKKQpyb3duYW1lcyhuZXdkYXQpIDwtIGxldHRlcnNbMTo2XQoKIyBDb21wdXRlIHN1cnZpdmFsIGN1cnZlcwpjeHNmIDwtIHN1cnZmaXQoY3htb2QsIGRhdGEgPSBHQlNHMiwgbmV3ZGF0YSA9IG5ld2RhdCwgY29uZi50eXBlID0gIm5vbmUiKQoKIyBDcmVhdGUgZGF0YS5mcmFtZSB3aXRoIHN1cnZpdmFsIGN1cnZlIGluZm9ybWF0aW9uCgpzdXJ2X2N4bW9kMCA8LSBzdXJ2X3N1bW1hcnkoY3hzZikKc3Vydl9jeG1vZCA8LSBjYmluZChzdXJ2X2N4bW9kMCwgbmV3ZGF0W2FzLmNoYXJhY3RlcihzdXJ2X2N4bW9kMCRzdHJhdGEpLCBdKQoKIyBQbG90Cmdnc3VydnBsb3RfZGYoc3Vydl9jeG1vZCwgbGluZXR5cGUgPSAiaG9yVGgiLCBjb2xvciA9ICJ0c2l6ZSIsCiAgICAgICAgICAgICAgbGVnZW5kLnRpdGxlID0gTlVMTCwgY2Vuc29yID0gRkFMU0UpCmBgYAo=