Discrete-time survival analysis using logit models are different from the Cox proportional hazards models in the last lecture:

1. How Time is Treated:

  • Discrete-Time Logit Models are specifically designed for situations where time is measured in discrete intervals (e.g., years, months, grades in school). The event (e.g., promotion, dropout) is considered to occur within one of these distinct time periods. The data is structured in “person-period” format, where each individual contributes multiple rows, one for each time period they are at risk. The outcome variable is binary, indicating whether the event occurred in that specific interval (1) or not (0), given they survived until the beginning of the interval.
  • Cox Proportional Hazards (Cox PH) Models are designed for continuous time. They analyze the hazard rate, which is the instantaneous risk of the event occurring at a specific point in time, given that the individual has survived up to that time.3 While Cox models can handle tied event times (multiple events occurring at the same recorded time), they fundamentally assume an underlying continuous time process.

2. The Outcome Variable and Modeling Approach:

  • Discrete-Time Logit Models model the probability of the event occurring within a specific discrete time interval, conditional on survival up to the start of that interval. This probability is typically modeled using a logistic regression framework, hence the “logit” in the name. The log-odds of the event occurring in each interval are predicted by the covariates.
  • Cox PH Models directly models the hazard rate. It estimates the hazard ratio, which is the ratio of the hazard rates between two groups or for a one-unit change in a covariate. The model is semi-parametric because it estimates the effect of covariates on the hazard without making assumptions about the shape of the baseline hazard function (the hazard when all covariates are zero).

3. The Baseline Hazard:

  • In Discrete-Time Logit Models, the baseline hazard (the probability of the event in each time interval when all covariates are zero) is often treated as time-dependent. In the example code below, this is implicitly handled by including time and I(time^2) as predictors. More explicitly, one could include dummy variables for each time period to allow the baseline hazard to vary freely across time.
  • The Cox PH models has a non-parametric baseline hazard that is not explicitly estimated. The focus is on how the covariates proportionally scale this baseline hazard. The “proportional hazards” assumption implies that the ratio of the hazard rates for any two individuals remains constant over time.

4. The Proportional Hazards Assumption:

  • While the term “discrete-time proportional hazards model” exists (often using a complementary log-log link), the logit model itself does not inherently assume proportional hazards. The effects of covariates can vary across different time intervals, especially when time-by-covariate interactions are included in the model.
  • A key assumption of the Cox model is that the hazards are proportional over time. This means that the effect of a covariate on the hazard rate is constant across all time points. Violations of this assumption can lead to biased results. Statistical tests and graphical methods are used to assess this assumption.

5. Handling of Ties:

  • Discrete-Time Logit Models: Tied events (multiple events occurring at the same recorded time) are naturally handled within the discrete time intervals. If multiple promotions happen in the same year, they all contribute to the event count for that year.
  • Cox PH Models: Tied event times require specific methods to handle them in the partial likelihood estimation (e.g., Breslow, Efron methods).

6. Data Structure:

  • Discrete-Time Logit Models requires reshaping the data into a long (person-period) format.
  • Cox PH Models__ typically use a data structure where each row represents an individual with their survival time and event status.
Feature Discrete-Time Logit Models Cox Proportional Hazards Models
Time Discrete intervals Continuous
Outcome Probability of event in an interval Hazard rate
Modeling Approach Logistic Regression Semi-parametric hazard regression
Baseline Hazard Can be time-dependent Non-parametric, not directly estimated
Proportional Hazards Not inherently assumed Key assumption
Handling Ties Naturally handled within intervals Requires specific tie-handling methods
Data Structure Long (person-period) Typically one row per subject

When to Choose Which:

  • Choose Discrete-Time Logit Models when:
    • Time is naturally measured in discrete intervals.
    • The proportional hazards assumption of the Cox model is violated.
    • You want to directly model the probability of the event in each time interval.
    • You want more flexibility in how the effects of covariates change over time.
  • Choose Cox Proportional Hazards Models when:
    • Time is continuous or can be reasonably approximated as continuous.
    • The proportional hazards assumption holds.
    • You are primarily interested in estimating hazard ratios.
    • You have a large dataset with many unique event times.

Load Libraries

  • library(tidyverse): This line loads the tidyverse package. Think of this as bringing in your essential toolkit for data manipulation and visualization in R. It includes powerful functions like mutate, pivot_longer, left_join, and filter, which we’ll see in action.
  • library(haven): The haven package is specifically designed to read data files from various statistical software packages, including SAS, SPSS, and Stata. In this case, we’ll use it to read a SAS dataset.
library(tidyverse)
library(haven)

Read in the data

The read_sas() function from the haven package reads the SAS dataset located at the provided URL and stores it in a data frame called rank. This data contains information about associate professors, their characteristics, and their career progression.

rank <- read_sas("https://statisticalhorizons.com/wp-content/uploads/2022/01/rank.sas7bdat")

#assign id numbers to the 301 case:
rank <- rank %>% mutate(id =1:301)

Here, we’re using the pipe operator %>% from dplyr (part of tidyverse). It allows us to chain operations together in a readable way.
- mutate() is a function that adds new variables or modifies existing ones in a data frame.
- id = 1:301 creates a new variable named id and assigns a unique integer from 1 to 301 to each row. This is important for tracking individual cases, especially when we reshape the data later. We’re essentially giving each person in the dataset a unique identifier.

Reshape the data from wide to long for articles

Why reshape to long format? In discrete-time survival analysis, we are interested in the probability of an event (promotion in this case) occurring at each discrete time point. The long format allows us to have each person-year as a separate row, which is the structure needed for fitting our logit model.

rankyrs <- rank %>%
  pivot_longer(
    cols = starts_with("art"),
    names_to  = "atime",
    values_to = "art"
  ) %>%
  mutate(time = as.numeric(str_remove(atime, "art")))

#reshape the data from wide to long for citations:
rankyrs2 <- rank %>%
  pivot_longer(
    cols = starts_with("cit"), 
    names_to = "ctime",
    values_to = "cit"
  ) %>%
  mutate(time = as.numeric(str_remove(ctime, "cit")))
  • pivot_longer() is a powerful function for reshaping data from a “wide” format (where each time point has its own column) to a “long” format (where each row represents a specific time point for an individual). This is crucial for discrete-time survival analysis.

    • cols = starts_with("art") specifies that we want to gather the columns whose names start with “art”. These represent the number of articles published at different time points (e.g., art1, art2, art3…).
    • names_to = "atime" creates a new column named “atime” that will contain the original column names (“art1”, “art2”, etc.).
    • values_to = "art" creates a new column named “art” that will contain the values from the original “art” columns (the actual number of articles).
  • The same logic applies to the block for citations (starts_with("cit")), creating ctime and cit columns.

  • mutate(time = as.numeric(str_remove(atime, "art"))): After pivoting, the atime column (e.g., “art1”, “art2”) is still in character format. We want to extract the time information (the number).

    • str_remove(atime, "art") from the stringr package (part of tidyverse) removes the “art” prefix from the atime column, leaving just the number.
    • as.numeric() converts this remaining string into a numeric value, which we store in a new column called time. We do the same for the citations.

Merge articles and citations

rankyrs <- rankyrs %>%
  left_join(rankyrs2 %>% select(id, time, cit), by = c("id", "time"))
  • left_join(): This function combines two data frames based on common columns. We are merging rankyrs (which now has the article information in long format) with a subset of rankyrs2 (which has the citation information in long format).
    • rankyrs2 %>% select(id, time, cit): We first select only the id, time, and cit columns from rankyrs2 since these are the variables we want to join.
    • by = c("id", "time"): This specifies that the join should be based on matching values in both the id and time columns. This ensures that the number of articles and citations for the same individual at the same time point are combined into a single row in rankyrs.

Sort by id and time

rankyrs<-rankyrs %>%
  arrange(id, time)
  • arrange(id, time) sorts the rankyrs data frame first by the id column (so all observations for the same individual are together) and then by the time column (so the observations for each individual are in chronological order). This is helpful for understanding the sequence of events.

Get rid of person years after a promotion

This filtering creates the “risk set” at each time point. For each individual at each time point before or at the time of their event (if it occurred), they are considered to be at risk of the event happening at that time.

ranksub<- rankyrs %>%
  filter(time<=dur)
  • filter(time <= dur) filters the rankyrs data frame to keep only the rows where the time is less than or equal to the dur variable. The dur variable represents the time until the event (promotion) occurred for those who were promoted, or the total observation time for those who were not. By filtering this way, we are only considering the person-years before or at the time of promotion.

Recode event variable to be 0 before event occurrence

In discrete-time survival analysis, we model the probability of the event occurring in a specific time interval, given that it has not occurred before. Our promo variable captures this: for each person-year, it’s 1 if the promotion happened at that exact time, and 0 otherwise.

ranksub <- ranksub %>%
  mutate(promo = if_else(time == dur, event, 0))
  • mutate(promo = if_else(time == dur, event, 0)) creates a new binary outcome variable called promo.
    • if_else(condition, value_if_true, value_if_false) is a conditional function.
    • time == dur is the condition checked to determine whether the current time point (time) is equal to the time of the event (dur).
    • event: If the condition is true (i.e., we are at the time of promotion), the value of promo is set to the value of the event variable (which is 1 for promotion and 0 otherwise).
    • If the condition is false (i.e., we are at a time point before the promotion), the value of promo is set to 0, indicating that the event did not occur at that specific person-year.

Change the missings in jobtime to 11

The choice of 11 might be based on the context of the data (e.g., the maximum observed job time plus one.

ranksub <- ranksub %>%
  mutate(jobtime = if_else(is.na(jobtime), 11,  jobtime))
  • mutate(jobtime = if_else(is.na(jobtime), 11, jobtime)):
    • is.na(jobtime) checks for missing values (represented as NA) in the jobtime column.
    • If a value is missing (TRUE), it’s replaced with 11.
    • If a value is not missing (FALSE), it remains its original value.

Define jobpres, a time-varying coviariate

This demonstrates how to handle time-varying covariates in discrete-time survival analysis. The value of jobpres can change for an individual as time progresses, and our data structure in long format allows us to capture these changes.

ranksub <- ranksub %>%
  mutate(jobpres = if_else(time<jobtime,prest1, prest2))
  • mutate(jobpres = if_else(time < jobtime, prest1, prest2)) creates a new variable jobpres.
    • time < jobtime is the condition checked where the current time point (time) is less than the jobtime.
    • If the condition is true (i.e., before jobtime), the value of jobpres is taken from the prest1 variable (likely prestige at an earlier job).
    • If the condition is false (i.e., at or after jobtime), the value of jobpres is taken from the prest2 variable (likely prestige at a later or current job).

Fit discrete time logit

This glm() call fits a discrete-time logit model where the outcome is the log-odds of promotion at a specific time point. The coefficients from this model will tell us how each predictor variable is associated with this log-odds, holding other variables constant. We will need to exponentiate these coefficients to interpret them as odds ratios.

myfit<-glm(promo~undgrad + phdmed + phdprest + art + cit + jobpres + time + I(time^2), family=binomial,data=ranksub)
library(gtsummary)

# Create a summary table of the model results
model_table <- tbl_regression(
  myfit,
  exponentiate = TRUE, # Display odds ratios instead of log-odds
  pvalue_fun = ~style_pvalue(.x, digits = 3), # Format p-values
  label = list(
    "undgrad" ~ "Undergraduate Institution Prestige",
    "phdmed" ~ "Medical PhD",
    "phdprest" ~ "PhD Program Prestige",
    "art" ~ "Number of Articles",
    "cit" ~ "Number of Citations",
    "jobpres" ~ "Job Prestige",
    "time" ~ "Time (Years)",
    "I(time^2)" ~ "Time Squared" # Use the exact string "I(time^2)"
  ) # Custom labels for variables
)

# Print the table to the console
model_table
Characteristic OR 95% CI p-value
Undergraduate Institution Prestige 1.21 1.07, 1.38 0.002
Medical PhD 0.79 0.56, 1.11 0.170
PhD Program Prestige 1.03 0.86, 1.23 0.772
Number of Articles 1.08 1.04, 1.12 <0.001
Number of Citations 1.00 1.00, 1.00 0.924
Job Prestige 0.78 0.62, 0.97 0.026
Time (Years) 8.02 5.18, 13.0 <0.001
Time Squared 0.85 0.82, 0.89 <0.001
Abbreviations: CI = Confidence Interval, OR = Odds Ratio
# You can further customize the table, for example, adding a title and caption
model_table <- model_table %>%
  as_gt() %>% # Convert to a gt table for more advanced formatting
  gt::tab_header(
    title = "Discrete-Time Logit Model Results",
    subtitle = "Predicting Probability of Promotion"
  ) %>%
  gt::tab_caption("Odds ratios and p-values are reported.")

# Print the customized table
model_table
LS0tDQp0aXRsZTogIkRpc2NyZXRlIFRpbWUgTG9naXQgTW9kZWxzIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCi0tLQ0KRGlzY3JldGUtdGltZSBzdXJ2aXZhbCBhbmFseXNpcyB1c2luZyBsb2dpdCBtb2RlbHMgYXJlIGRpZmZlcmVudCBmcm9tIHRoZSBDb3ggcHJvcG9ydGlvbmFsIGhhemFyZHMgbW9kZWxzIGluIHRoZSBsYXN0IGxlY3R1cmU6DQoNCiMjIyAxLiBIb3cgVGltZSBpcyBUcmVhdGVkOg0KIC0gX19EaXNjcmV0ZS1UaW1lIExvZ2l0IE1vZGVsc19fIGFyZSBzcGVjaWZpY2FsbHkgZGVzaWduZWQgZm9yIHNpdHVhdGlvbnMgd2hlcmUgdGltZSBpcyBtZWFzdXJlZCBpbiBkaXNjcmV0ZSBpbnRlcnZhbHMgKGUuZy4sIHllYXJzLCBtb250aHMsIGdyYWRlcyBpbiBzY2hvb2wpLiBUaGUgZXZlbnQgKGUuZy4sIHByb21vdGlvbiwgZHJvcG91dCkgaXMgY29uc2lkZXJlZCB0byBvY2N1ciB3aXRoaW4gb25lIG9mIHRoZXNlIGRpc3RpbmN0IHRpbWUgcGVyaW9kcy4gVGhlIGRhdGEgaXMgc3RydWN0dXJlZCBpbiAicGVyc29uLXBlcmlvZCIgZm9ybWF0LCB3aGVyZSBlYWNoIGluZGl2aWR1YWwgY29udHJpYnV0ZXMgbXVsdGlwbGUgcm93cywgb25lIGZvciBlYWNoIHRpbWUgcGVyaW9kIHRoZXkgYXJlIGF0IHJpc2suIFRoZSBvdXRjb21lIHZhcmlhYmxlIGlzIGJpbmFyeSwgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBldmVudCBvY2N1cnJlZCBpbiB0aGF0IHNwZWNpZmljIGludGVydmFsICgxKSBvciBub3QgKDApLCBnaXZlbiB0aGV5IHN1cnZpdmVkIHVudGlsIHRoZSBiZWdpbm5pbmcgb2YgdGhlIGludGVydmFsLiAgDQogLSBfX0NveCBQcm9wb3J0aW9uYWwgSGF6YXJkcyAoQ294IFBIKSBNb2RlbHNfXyBhcmUgZGVzaWduZWQgZm9yIGNvbnRpbnVvdXMgdGltZS4gVGhleSBhbmFseXplIHRoZSBoYXphcmQgcmF0ZSwgd2hpY2ggaXMgdGhlIGluc3RhbnRhbmVvdXMgcmlzayBvZiB0aGUgZXZlbnQgb2NjdXJyaW5nIGF0IGEgc3BlY2lmaWMgcG9pbnQgaW4gdGltZSwgZ2l2ZW4gdGhhdCB0aGUgaW5kaXZpZHVhbCBoYXMgc3Vydml2ZWQgdXAgdG8gdGhhdCB0aW1lLjMgV2hpbGUgQ294IG1vZGVscyBjYW4gaGFuZGxlIHRpZWQgZXZlbnQgdGltZXMgKG11bHRpcGxlIGV2ZW50cyBvY2N1cnJpbmcgYXQgdGhlIHNhbWUgcmVjb3JkZWQgdGltZSksIHRoZXkgZnVuZGFtZW50YWxseSBhc3N1bWUgYW4gdW5kZXJseWluZyBjb250aW51b3VzIHRpbWUgcHJvY2Vzcy4NCiANCiMjIyAyLiBUaGUgT3V0Y29tZSBWYXJpYWJsZSBhbmQgTW9kZWxpbmcgQXBwcm9hY2g6DQogLSBfX0Rpc2NyZXRlLVRpbWUgTG9naXQgTW9kZWxzX18gbW9kZWwgdGhlIHByb2JhYmlsaXR5IG9mIHRoZSBldmVudCBvY2N1cnJpbmcgd2l0aGluIGEgc3BlY2lmaWMgZGlzY3JldGUgdGltZSBpbnRlcnZhbCwgY29uZGl0aW9uYWwgb24gc3Vydml2YWwgdXAgdG8gdGhlIHN0YXJ0IG9mIHRoYXQgaW50ZXJ2YWwuIFRoaXMgcHJvYmFiaWxpdHkgaXMgdHlwaWNhbGx5IG1vZGVsZWQgdXNpbmcgYSBsb2dpc3RpYyByZWdyZXNzaW9uIGZyYW1ld29yaywgaGVuY2UgdGhlICJsb2dpdCIgaW4gdGhlIG5hbWUuIFRoZSBsb2ctb2RkcyBvZiB0aGUgZXZlbnQgb2NjdXJyaW5nIGluIGVhY2ggaW50ZXJ2YWwgYXJlIHByZWRpY3RlZCBieSB0aGUgY292YXJpYXRlcy4gIA0KIC0gX19Db3ggUEggTW9kZWxzX18gZGlyZWN0bHkgbW9kZWxzIHRoZSBoYXphcmQgcmF0ZS4gSXQgZXN0aW1hdGVzIHRoZSBoYXphcmQgcmF0aW8sIHdoaWNoIGlzIHRoZSByYXRpbyBvZiB0aGUgaGF6YXJkIHJhdGVzIGJldHdlZW4gdHdvIGdyb3VwcyBvciBmb3IgYSBvbmUtdW5pdCBjaGFuZ2UgaW4gYSBjb3ZhcmlhdGUuIFRoZSBtb2RlbCBpcyBzZW1pLXBhcmFtZXRyaWMgYmVjYXVzZSBpdCBlc3RpbWF0ZXMgdGhlIGVmZmVjdCBvZiBjb3ZhcmlhdGVzIG9uIHRoZSBoYXphcmQgd2l0aG91dCBtYWtpbmcgYXNzdW1wdGlvbnMgYWJvdXQgdGhlIHNoYXBlIG9mIHRoZSBiYXNlbGluZSBoYXphcmQgZnVuY3Rpb24gKHRoZSBoYXphcmQgd2hlbiBhbGwgY292YXJpYXRlcyBhcmUgemVybykuICANCiANCiMjIyAzLiBUaGUgQmFzZWxpbmUgSGF6YXJkOg0KIC0gSW4gX19EaXNjcmV0ZS1UaW1lIExvZ2l0IE1vZGVsc19fLCB0aGUgYmFzZWxpbmUgaGF6YXJkICh0aGUgcHJvYmFiaWxpdHkgb2YgdGhlIGV2ZW50IGluIGVhY2ggdGltZSBpbnRlcnZhbCB3aGVuIGFsbCBjb3ZhcmlhdGVzIGFyZSB6ZXJvKSBpcyBvZnRlbiB0cmVhdGVkIGFzIHRpbWUtZGVwZW5kZW50LiBJbiB0aGUgZXhhbXBsZSBjb2RlIGJlbG93LCB0aGlzIGlzIGltcGxpY2l0bHkgaGFuZGxlZCBieSBpbmNsdWRpbmcgYHRpbWVgIGFuZCBgSSh0aW1lXjIpYCBhcyBwcmVkaWN0b3JzLiBNb3JlIGV4cGxpY2l0bHksIG9uZSBjb3VsZCBpbmNsdWRlIGR1bW15IHZhcmlhYmxlcyBmb3IgZWFjaCB0aW1lIHBlcmlvZCB0byBhbGxvdyB0aGUgYmFzZWxpbmUgaGF6YXJkIHRvIHZhcnkgZnJlZWx5IGFjcm9zcyB0aW1lLiAgDQogLSBUaGUgX19Db3ggUEggbW9kZWxzX18gIGhhcyBhIG5vbi1wYXJhbWV0cmljIGJhc2VsaW5lIGhhemFyZCB0aGF0IGlzIG5vdCBleHBsaWNpdGx5IGVzdGltYXRlZC4gVGhlIGZvY3VzIGlzIG9uIGhvdyB0aGUgY292YXJpYXRlcyBwcm9wb3J0aW9uYWxseSBzY2FsZSB0aGlzIGJhc2VsaW5lIGhhemFyZC4gVGhlICJwcm9wb3J0aW9uYWwgaGF6YXJkcyIgYXNzdW1wdGlvbiBpbXBsaWVzIHRoYXQgdGhlIHJhdGlvIG9mIHRoZSBoYXphcmQgcmF0ZXMgZm9yIGFueSB0d28gaW5kaXZpZHVhbHMgcmVtYWlucyBjb25zdGFudCBvdmVyIHRpbWUuICANCiANCiMjIyA0LiBUaGUgUHJvcG9ydGlvbmFsIEhhemFyZHMgQXNzdW1wdGlvbjoNCiAtIFdoaWxlIHRoZSB0ZXJtIF9fImRpc2NyZXRlLXRpbWUgcHJvcG9ydGlvbmFsIGhhemFyZHMgbW9kZWwiX18gZXhpc3RzIChvZnRlbiB1c2luZyBhIGNvbXBsZW1lbnRhcnkgbG9nLWxvZyBsaW5rKSwgdGhlIGxvZ2l0IG1vZGVsIGl0c2VsZiBkb2VzIG5vdCBpbmhlcmVudGx5IGFzc3VtZSBwcm9wb3J0aW9uYWwgaGF6YXJkcy4gVGhlIGVmZmVjdHMgb2YgY292YXJpYXRlcyBjYW4gdmFyeSBhY3Jvc3MgZGlmZmVyZW50IHRpbWUgaW50ZXJ2YWxzLCBlc3BlY2lhbGx5IHdoZW4gdGltZS1ieS1jb3ZhcmlhdGUgaW50ZXJhY3Rpb25zIGFyZSBpbmNsdWRlZCBpbiB0aGUgbW9kZWwuICAgIA0KIC0gQSBrZXkgYXNzdW1wdGlvbiBvZiBfX3RoZSBDb3ggbW9kZWxfXyBpcyB0aGF0IHRoZSBoYXphcmRzIGFyZSBwcm9wb3J0aW9uYWwgb3ZlciB0aW1lLiBUaGlzIG1lYW5zIHRoYXQgdGhlIGVmZmVjdCBvZiBhIGNvdmFyaWF0ZSBvbiB0aGUgaGF6YXJkIHJhdGUgaXMgY29uc3RhbnQgYWNyb3NzIGFsbCB0aW1lIHBvaW50cy4gVmlvbGF0aW9ucyBvZiB0aGlzIGFzc3VtcHRpb24gY2FuIGxlYWQgdG8gYmlhc2VkIHJlc3VsdHMuIFN0YXRpc3RpY2FsIHRlc3RzIGFuZCBncmFwaGljYWwgbWV0aG9kcyBhcmUgdXNlZCB0byBhc3Nlc3MgdGhpcyBhc3N1bXB0aW9uLiAgDQogDQojIyMgNS4gSGFuZGxpbmcgb2YgVGllczogIA0KIC0gX19EaXNjcmV0ZS1UaW1lIExvZ2l0IE1vZGVsczpfXyBUaWVkIGV2ZW50cyAobXVsdGlwbGUgZXZlbnRzIG9jY3VycmluZyBhdCB0aGUgc2FtZSByZWNvcmRlZCB0aW1lKSBhcmUgbmF0dXJhbGx5IGhhbmRsZWQgd2l0aGluIHRoZSBkaXNjcmV0ZSB0aW1lIGludGVydmFscy4gSWYgbXVsdGlwbGUgcHJvbW90aW9ucyBoYXBwZW4gaW4gdGhlIHNhbWUgeWVhciwgdGhleSBhbGwgY29udHJpYnV0ZSB0byB0aGUgZXZlbnQgY291bnQgZm9yIHRoYXQgeWVhci4gIA0KIC0gX19Db3ggUEggTW9kZWxzOl9fIFRpZWQgZXZlbnQgdGltZXMgcmVxdWlyZSBzcGVjaWZpYyBtZXRob2RzIHRvIGhhbmRsZSB0aGVtIGluIHRoZSBwYXJ0aWFsIGxpa2VsaWhvb2QgZXN0aW1hdGlvbiAoZS5nLiwgQnJlc2xvdywgRWZyb24gbWV0aG9kcykuDQoNCiMjIyA2LiBEYXRhIFN0cnVjdHVyZToNCiAtIF9fRGlzY3JldGUtVGltZSBMb2dpdCBNb2RlbHNfXyByZXF1aXJlcyByZXNoYXBpbmcgdGhlIGRhdGEgaW50byBhIGxvbmcgKHBlcnNvbi1wZXJpb2QpIGZvcm1hdC4gIA0KIC0gQ294IFBIIE1vZGVsc19fIHR5cGljYWxseSB1c2UgYSBkYXRhIHN0cnVjdHVyZSB3aGVyZSBlYWNoIHJvdyByZXByZXNlbnRzIGFuIGluZGl2aWR1YWwgd2l0aCB0aGVpciBzdXJ2aXZhbCB0aW1lIGFuZCBldmVudCBzdGF0dXMuICANCiANCg0KfCBGZWF0dXJlICAgICAgICAgICAgICB8IERpc2NyZXRlLVRpbWUgTG9naXQgTW9kZWxzICAgICAgICAgIHwgQ294IFByb3BvcnRpb25hbCBIYXphcmRzIE1vZGVscyAgICAgICAgfA0KfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBUaW1lICAgICAgICAgICAgICAgICB8IERpc2NyZXRlIGludGVydmFscyAgICAgICAgICAgICAgICAgIHwgQ29udGludW91cyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBPdXRjb21lICAgICAgICAgICAgICB8IFByb2JhYmlsaXR5IG9mIGV2ZW50IGluIGFuIGludGVydmFsIHwgSGF6YXJkIHJhdGUgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBNb2RlbGluZyBBcHByb2FjaCAgICB8IExvZ2lzdGljIFJlZ3Jlc3Npb24gICAgICAgICAgICAgICAgIHwgU2VtaS1wYXJhbWV0cmljIGhhemFyZCByZWdyZXNzaW9uICAgICAgfA0KfCBCYXNlbGluZSBIYXphcmQgICAgICB8IENhbiBiZSB0aW1lLWRlcGVuZGVudCAgICAgICAgICAgICAgIHwgTm9uLXBhcmFtZXRyaWMsIG5vdCBkaXJlY3RseSBlc3RpbWF0ZWQgfA0KfCBQcm9wb3J0aW9uYWwgSGF6YXJkcyB8IE5vdCBpbmhlcmVudGx5IGFzc3VtZWQgICAgICAgICAgICAgIHwgS2V5IGFzc3VtcHRpb24gICAgICAgICAgICAgICAgICAgICAgICAgfA0KfCBIYW5kbGluZyBUaWVzICAgICAgICB8IE5hdHVyYWxseSBoYW5kbGVkIHdpdGhpbiBpbnRlcnZhbHMgIHwgUmVxdWlyZXMgc3BlY2lmaWMgdGllLWhhbmRsaW5nIG1ldGhvZHMgfA0KfCBEYXRhIFN0cnVjdHVyZSAgICAgICB8IExvbmcgKHBlcnNvbi1wZXJpb2QpICAgICAgICAgICAgICAgIHwgVHlwaWNhbGx5IG9uZSByb3cgcGVyIHN1YmplY3QgICAgICAgICAgfCAgDQoNCiMjIFdoZW4gdG8gQ2hvb3NlIFdoaWNoOg0KIC0gQ2hvb3NlIERpc2NyZXRlLVRpbWUgTG9naXQgTW9kZWxzIHdoZW46ICANCiAgIC0gVGltZSBpcyBuYXR1cmFsbHkgbWVhc3VyZWQgaW4gZGlzY3JldGUgaW50ZXJ2YWxzLg0KICAgLSBUaGUgcHJvcG9ydGlvbmFsIGhhemFyZHMgYXNzdW1wdGlvbiBvZiB0aGUgQ294IG1vZGVsIGlzIHZpb2xhdGVkLiAgDQogICAtIFlvdSB3YW50IHRvIGRpcmVjdGx5IG1vZGVsIHRoZSBwcm9iYWJpbGl0eSBvZiB0aGUgZXZlbnQgaW4gZWFjaCB0aW1lIGludGVydmFsLiAgDQogICAtIFlvdSB3YW50IG1vcmUgZmxleGliaWxpdHkgaW4gaG93IHRoZSBlZmZlY3RzIG9mIGNvdmFyaWF0ZXMgY2hhbmdlIG92ZXIgdGltZS4gIA0KIC0gQ2hvb3NlIENveCBQcm9wb3J0aW9uYWwgSGF6YXJkcyBNb2RlbHMgd2hlbjogIA0KICAgLSBUaW1lIGlzIGNvbnRpbnVvdXMgb3IgY2FuIGJlIHJlYXNvbmFibHkgYXBwcm94aW1hdGVkIGFzIGNvbnRpbnVvdXMuICANCiAgIC0gVGhlIHByb3BvcnRpb25hbCBoYXphcmRzIGFzc3VtcHRpb24gaG9sZHMuICANCiAgIC0gWW91IGFyZSBwcmltYXJpbHkgaW50ZXJlc3RlZCBpbiBlc3RpbWF0aW5nIGhhemFyZCByYXRpb3MuICANCiAgIC0gWW91IGhhdmUgYSBsYXJnZSBkYXRhc2V0IHdpdGggbWFueSB1bmlxdWUgZXZlbnQgdGltZXMuICANCg0KIyMgTG9hZCBMaWJyYXJpZXMNCiAtIGBsaWJyYXJ5KHRpZHl2ZXJzZSlgOiBUaGlzIGxpbmUgbG9hZHMgdGhlIFt0aWR5dmVyc2VdKGh0dHBzOi8vd3d3LnRpZHl2ZXJzZS5vcmcvcGFja2FnZXMvKSBwYWNrYWdlLiBUaGluayBvZiB0aGlzIGFzIGJyaW5naW5nIGluIHlvdXIgZXNzZW50aWFsIHRvb2xraXQgZm9yIGRhdGEgbWFuaXB1bGF0aW9uIGFuZCB2aXN1YWxpemF0aW9uIGluIFIuIEl0IGluY2x1ZGVzIHBvd2VyZnVsIGZ1bmN0aW9ucyBsaWtlIGBtdXRhdGVgLCBgcGl2b3RfbG9uZ2VyYCwgYGxlZnRfam9pbmAsIGFuZCBgZmlsdGVyYCwgd2hpY2ggd2UnbGwgc2VlIGluIGFjdGlvbi4gICAgDQogLSBsaWJyYXJ5KGhhdmVuKTogVGhlIFtoYXZlbl0oaHR0cHM6Ly9oYXZlbi50aWR5dmVyc2Uub3JnLykgcGFja2FnZSBpcyBzcGVjaWZpY2FsbHkgZGVzaWduZWQgdG8gcmVhZCBkYXRhIGZpbGVzIGZyb20gdmFyaW91cyBzdGF0aXN0aWNhbCBzb2Z0d2FyZSBwYWNrYWdlcywgaW5jbHVkaW5nIFNBUywgU1BTUywgYW5kIFN0YXRhLiBJbiB0aGlzIGNhc2UsIHdlJ2xsIHVzZSBpdCB0byByZWFkIGEgU0FTIGRhdGFzZXQuICANCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGhhdmVuKQ0KYGBgDQoNCiMjIFJlYWQgaW4gdGhlIGRhdGENClRoZSBgcmVhZF9zYXMoKWAgZnVuY3Rpb24gZnJvbSB0aGUgaGF2ZW4gcGFja2FnZSByZWFkcyB0aGUgU0FTIGRhdGFzZXQgbG9jYXRlZCBhdCB0aGUgcHJvdmlkZWQgVVJMIGFuZCBzdG9yZXMgaXQgaW4gYSBkYXRhIGZyYW1lIGNhbGxlZCByYW5rLiBUaGlzIGRhdGEgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgYXNzb2NpYXRlIHByb2Zlc3NvcnMsIHRoZWlyIGNoYXJhY3RlcmlzdGljcywgYW5kIHRoZWlyIGNhcmVlciBwcm9ncmVzc2lvbi4NCg0KYGBge3J9DQpyYW5rIDwtIHJlYWRfc2FzKCJodHRwczovL3N0YXRpc3RpY2FsaG9yaXpvbnMuY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDIyLzAxL3Jhbmsuc2FzN2JkYXQiKQ0KDQojYXNzaWduIGlkIG51bWJlcnMgdG8gdGhlIDMwMSBjYXNlOg0KcmFuayA8LSByYW5rICU+JSBtdXRhdGUoaWQgPTE6MzAxKQ0KYGBgDQpIZXJlLCB3ZSdyZSB1c2luZyB0aGUgcGlwZSBvcGVyYXRvciBgJT4lYCBmcm9tIGBkcGx5cmAgKHBhcnQgb2YgYHRpZHl2ZXJzZWApLiBJdCBhbGxvd3MgdXMgdG8gY2hhaW4gb3BlcmF0aW9ucyB0b2dldGhlciBpbiBhIHJlYWRhYmxlIHdheS4gIA0KIC0gYG11dGF0ZSgpYCBpcyBhIGZ1bmN0aW9uIHRoYXQgYWRkcyBuZXcgdmFyaWFibGVzIG9yIG1vZGlmaWVzIGV4aXN0aW5nIG9uZXMgaW4gYSBkYXRhIGZyYW1lLiAgDQogLSBgaWQgPSAxOjMwMWAgY3JlYXRlcyBhIG5ldyB2YXJpYWJsZSBuYW1lZCBpZCBhbmQgYXNzaWducyBhIHVuaXF1ZSBpbnRlZ2VyIGZyb20gMSB0byAzMDEgdG8gZWFjaCByb3cuIFRoaXMgaXMgaW1wb3J0YW50IGZvciB0cmFja2luZyBpbmRpdmlkdWFsIGNhc2VzLCBlc3BlY2lhbGx5IHdoZW4gd2UgcmVzaGFwZSB0aGUgZGF0YSBsYXRlci4gV2UncmUgZXNzZW50aWFsbHkgZ2l2aW5nIGVhY2ggcGVyc29uIGluIHRoZSBkYXRhc2V0IGEgdW5pcXVlIGlkZW50aWZpZXIuICANCg0KIyMgUmVzaGFwZSB0aGUgZGF0YSBmcm9tIHdpZGUgdG8gbG9uZyBmb3IgYXJ0aWNsZXMNCldoeSByZXNoYXBlIHRvIGxvbmcgZm9ybWF0PyBJbiBkaXNjcmV0ZS10aW1lIHN1cnZpdmFsIGFuYWx5c2lzLCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgcHJvYmFiaWxpdHkgb2YgYW4gZXZlbnQgKHByb21vdGlvbiBpbiB0aGlzIGNhc2UpIG9jY3VycmluZyBhdCBlYWNoIGRpc2NyZXRlIHRpbWUgcG9pbnQuIFRoZSBsb25nIGZvcm1hdCBhbGxvd3MgdXMgdG8gaGF2ZSBlYWNoIHBlcnNvbi15ZWFyIGFzIGEgc2VwYXJhdGUgcm93LCB3aGljaCBpcyB0aGUgc3RydWN0dXJlIG5lZWRlZCBmb3IgZml0dGluZyBvdXIgbG9naXQgbW9kZWwuICANCg0KYGBge3J9DQpyYW5reXJzIDwtIHJhbmsgJT4lDQogIHBpdm90X2xvbmdlcigNCiAgICBjb2xzID0gc3RhcnRzX3dpdGgoImFydCIpLA0KICAgIG5hbWVzX3RvICA9ICJhdGltZSIsDQogICAgdmFsdWVzX3RvID0gImFydCINCiAgKSAlPiUNCiAgbXV0YXRlKHRpbWUgPSBhcy5udW1lcmljKHN0cl9yZW1vdmUoYXRpbWUsICJhcnQiKSkpDQoNCiNyZXNoYXBlIHRoZSBkYXRhIGZyb20gd2lkZSB0byBsb25nIGZvciBjaXRhdGlvbnM6DQpyYW5reXJzMiA8LSByYW5rICU+JQ0KICBwaXZvdF9sb25nZXIoDQogICAgY29scyA9IHN0YXJ0c193aXRoKCJjaXQiKSwgDQogICAgbmFtZXNfdG8gPSAiY3RpbWUiLA0KICAgIHZhbHVlc190byA9ICJjaXQiDQogICkgJT4lDQogIG11dGF0ZSh0aW1lID0gYXMubnVtZXJpYyhzdHJfcmVtb3ZlKGN0aW1lLCAiY2l0IikpKQ0KYGBgDQoNCiAtIGBwaXZvdF9sb25nZXIoKWAgaXMgYSBwb3dlcmZ1bCBmdW5jdGlvbiBmb3IgcmVzaGFwaW5nIGRhdGEgZnJvbSBhICJ3aWRlIiBmb3JtYXQgKHdoZXJlIGVhY2ggdGltZSBwb2ludCBoYXMgaXRzIG93biBjb2x1bW4pIHRvIGEgImxvbmciIGZvcm1hdCAod2hlcmUgZWFjaCByb3cgcmVwcmVzZW50cyBhIHNwZWNpZmljIHRpbWUgcG9pbnQgZm9yIGFuIGluZGl2aWR1YWwpLiBUaGlzIGlzIGNydWNpYWwgZm9yIGRpc2NyZXRlLXRpbWUgc3Vydml2YWwgYW5hbHlzaXMuICANCiANCiAgIC0gYGNvbHMgPSBzdGFydHNfd2l0aCgiYXJ0IilgIHNwZWNpZmllcyB0aGF0IHdlIHdhbnQgdG8gZ2F0aGVyIHRoZSBjb2x1bW5zIHdob3NlIG5hbWVzIHN0YXJ0IHdpdGggImFydCIuIFRoZXNlIHJlcHJlc2VudCB0aGUgbnVtYmVyIG9mIGFydGljbGVzIHB1Ymxpc2hlZCBhdCBkaWZmZXJlbnQgdGltZSBwb2ludHMgKGUuZy4sIGFydDEsIGFydDIsIGFydDMuLi4pLiAgDQogICAtIGBuYW1lc190byA9ICJhdGltZSJgIGNyZWF0ZXMgYSBuZXcgY29sdW1uIG5hbWVkICJhdGltZSIgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIG9yaWdpbmFsIGNvbHVtbiBuYW1lcyAoImFydDEiLCAiYXJ0MiIsIGV0Yy4pLiAgDQogICAtIGB2YWx1ZXNfdG8gPSAiYXJ0ImAgY3JlYXRlcyBhIG5ldyBjb2x1bW4gbmFtZWQgImFydCIgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIHZhbHVlcyBmcm9tIHRoZSBvcmlnaW5hbCAiYXJ0IiBjb2x1bW5zICh0aGUgYWN0dWFsIG51bWJlciBvZiBhcnRpY2xlcykuICANCiAtIFRoZSBzYW1lIGxvZ2ljIGFwcGxpZXMgdG8gdGhlIGJsb2NrIGZvciBjaXRhdGlvbnMgKGBzdGFydHNfd2l0aCgiY2l0IilgKSwgY3JlYXRpbmcgYGN0aW1lYCBhbmQgYGNpdGAgY29sdW1ucy4gIA0KIC0gbXV0YXRlKGB0aW1lID0gYXMubnVtZXJpYyhzdHJfcmVtb3ZlKGF0aW1lLCAiYXJ0IikpYCk6IEFmdGVyIHBpdm90aW5nLCB0aGUgYGF0aW1lYCBjb2x1bW4gKGUuZy4sICJhcnQxIiwgImFydDIiKSBpcyBzdGlsbCBpbiBjaGFyYWN0ZXIgZm9ybWF0LiBXZSB3YW50IHRvIGV4dHJhY3QgdGhlIHRpbWUgaW5mb3JtYXRpb24gKHRoZSBudW1iZXIpLiAgDQogICAtIGBzdHJfcmVtb3ZlKGF0aW1lLCAiYXJ0IilgIGZyb20gdGhlIGBzdHJpbmdyYCBwYWNrYWdlIChwYXJ0IG9mIGB0aWR5dmVyc2VgKSByZW1vdmVzIHRoZSAiYXJ0IiBwcmVmaXggZnJvbSB0aGUgYGF0aW1lYCBjb2x1bW4sIGxlYXZpbmcganVzdCB0aGUgbnVtYmVyLiAgDQogICAtIGBhcy5udW1lcmljKClgIGNvbnZlcnRzIHRoaXMgcmVtYWluaW5nIHN0cmluZyBpbnRvIGEgbnVtZXJpYyB2YWx1ZSwgd2hpY2ggd2Ugc3RvcmUgaW4gYSBuZXcgY29sdW1uIGNhbGxlZCBgdGltZWAuIFdlIGRvIHRoZSBzYW1lIGZvciB0aGUgY2l0YXRpb25zLiAgDQoNCiMjIE1lcmdlIGFydGljbGVzIGFuZCBjaXRhdGlvbnMNCmBgYHtyfQ0KcmFua3lycyA8LSByYW5reXJzICU+JQ0KICBsZWZ0X2pvaW4ocmFua3lyczIgJT4lIHNlbGVjdChpZCwgdGltZSwgY2l0KSwgYnkgPSBjKCJpZCIsICJ0aW1lIikpDQpgYGANCg0KIC0gYGxlZnRfam9pbigpOmAgVGhpcyBmdW5jdGlvbiBjb21iaW5lcyB0d28gZGF0YSBmcmFtZXMgYmFzZWQgb24gY29tbW9uIGNvbHVtbnMuIFdlIGFyZSBtZXJnaW5nIGByYW5reXJzYCAod2hpY2ggbm93IGhhcyB0aGUgYXJ0aWNsZSBpbmZvcm1hdGlvbiBpbiBsb25nIGZvcm1hdCkgd2l0aCBhIHN1YnNldCBvZiBgcmFua3lyczJgICh3aGljaCBoYXMgdGhlIGNpdGF0aW9uIGluZm9ybWF0aW9uIGluIGxvbmcgZm9ybWF0KS4gIA0KICAgLSBgcmFua3lyczIgJT4lIHNlbGVjdChpZCwgdGltZSwgY2l0KWA6IFdlIGZpcnN0IHNlbGVjdCBvbmx5IHRoZSBgaWRgLCBgdGltZWAsIGFuZCBgY2l0YCBjb2x1bW5zIGZyb20gYHJhbmt5cnMyYCBzaW5jZSB0aGVzZSBhcmUgdGhlIHZhcmlhYmxlcyB3ZSB3YW50IHRvIGpvaW4uICANCiAgIC0gYGJ5ID0gYygiaWQiLCAidGltZSIpYDogVGhpcyBzcGVjaWZpZXMgdGhhdCB0aGUgam9pbiBzaG91bGQgYmUgYmFzZWQgb24gbWF0Y2hpbmcgdmFsdWVzIGluIGJvdGggdGhlIGBpZGAgYW5kIGB0aW1lYCBjb2x1bW5zLiBUaGlzIGVuc3VyZXMgdGhhdCB0aGUgbnVtYmVyIG9mIGFydGljbGVzIGFuZCBjaXRhdGlvbnMgZm9yIHRoZSBzYW1lIGluZGl2aWR1YWwgYXQgdGhlIHNhbWUgdGltZSBwb2ludCBhcmUgY29tYmluZWQgaW50byBhIHNpbmdsZSByb3cgaW4gYHJhbmt5cnNgLiAgDQoNCiMjIFNvcnQgYnkgaWQgYW5kIHRpbWUNCmBgYHtyfQ0KcmFua3lyczwtcmFua3lycyAlPiUNCiAgYXJyYW5nZShpZCwgdGltZSkNCmBgYA0KDQogLSBgYXJyYW5nZShpZCwgdGltZSlgIHNvcnRzIHRoZSBgcmFua3lyc2AgZGF0YSBmcmFtZSBmaXJzdCBieSB0aGUgYGlkYCBjb2x1bW4gKHNvIGFsbCBvYnNlcnZhdGlvbnMgZm9yIHRoZSBzYW1lIGluZGl2aWR1YWwgYXJlIHRvZ2V0aGVyKSBhbmQgdGhlbiBieSB0aGUgYHRpbWVgIGNvbHVtbiAoc28gdGhlIG9ic2VydmF0aW9ucyBmb3IgZWFjaCBpbmRpdmlkdWFsIGFyZSBpbiBjaHJvbm9sb2dpY2FsIG9yZGVyKS4gVGhpcyBpcyBoZWxwZnVsIGZvciB1bmRlcnN0YW5kaW5nIHRoZSBzZXF1ZW5jZSBvZiBldmVudHMuICANCg0KIyMgR2V0IHJpZCBvZiBwZXJzb24geWVhcnMgYWZ0ZXIgYSBwcm9tb3Rpb24gIA0KVGhpcyBmaWx0ZXJpbmcgY3JlYXRlcyB0aGUgInJpc2sgc2V0IiBhdCBlYWNoIHRpbWUgcG9pbnQuIEZvciBlYWNoIGluZGl2aWR1YWwgYXQgZWFjaCB0aW1lIHBvaW50IGJlZm9yZSBvciBhdCB0aGUgdGltZSBvZiB0aGVpciBldmVudCAoaWYgaXQgb2NjdXJyZWQpLCB0aGV5IGFyZSBjb25zaWRlcmVkIHRvIGJlIGF0IHJpc2sgb2YgdGhlIGV2ZW50IGhhcHBlbmluZyBhdCB0aGF0IHRpbWUuICANCmBgYHtyfQ0KcmFua3N1YjwtIHJhbmt5cnMgJT4lDQogIGZpbHRlcih0aW1lPD1kdXIpDQpgYGANCg0KIC0gYGZpbHRlcih0aW1lIDw9IGR1cilgIGZpbHRlcnMgdGhlIGByYW5reXJzYCBkYXRhIGZyYW1lIHRvIGtlZXAgb25seSB0aGUgcm93cyB3aGVyZSB0aGUgdGltZSBpcyBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gdGhlIGBkdXJgIHZhcmlhYmxlLiBUaGUgYGR1cmAgdmFyaWFibGUgcmVwcmVzZW50cyB0aGUgdGltZSB1bnRpbCB0aGUgZXZlbnQgKHByb21vdGlvbikgb2NjdXJyZWQgZm9yIHRob3NlIHdobyB3ZXJlIHByb21vdGVkLCBvciB0aGUgdG90YWwgb2JzZXJ2YXRpb24gdGltZSBmb3IgdGhvc2Ugd2hvIHdlcmUgbm90LiBCeSBmaWx0ZXJpbmcgdGhpcyB3YXksIHdlIGFyZSBvbmx5IGNvbnNpZGVyaW5nIHRoZSBwZXJzb24teWVhcnMgYmVmb3JlIG9yIGF0IHRoZSB0aW1lIG9mIHByb21vdGlvbi4gIA0KIA0KIyMgUmVjb2RlIGV2ZW50IHZhcmlhYmxlIHRvIGJlIDAgYmVmb3JlIGV2ZW50IG9jY3VycmVuY2UgIA0KSW4gZGlzY3JldGUtdGltZSBzdXJ2aXZhbCBhbmFseXNpcywgd2UgbW9kZWwgdGhlIHByb2JhYmlsaXR5IG9mIHRoZSBldmVudCBvY2N1cnJpbmcgaW4gYSBzcGVjaWZpYyB0aW1lIGludGVydmFsLCBnaXZlbiB0aGF0IGl0IGhhcyBub3Qgb2NjdXJyZWQgYmVmb3JlLiBPdXIgcHJvbW8gdmFyaWFibGUgY2FwdHVyZXMgdGhpczogZm9yIGVhY2ggcGVyc29uLXllYXIsIGl0J3MgMSBpZiB0aGUgcHJvbW90aW9uIGhhcHBlbmVkIGF0IHRoYXQgZXhhY3QgdGltZSwgYW5kIDAgb3RoZXJ3aXNlLiAgDQoNCmBgYHtyfQ0KcmFua3N1YiA8LSByYW5rc3ViICU+JQ0KICBtdXRhdGUocHJvbW8gPSBpZl9lbHNlKHRpbWUgPT0gZHVyLCBldmVudCwgMCkpDQpgYGANCg0KIC0gYG11dGF0ZShwcm9tbyA9IGlmX2Vsc2UodGltZSA9PSBkdXIsIGV2ZW50LCAwKSlgIGNyZWF0ZXMgYSBuZXcgYmluYXJ5IG91dGNvbWUgdmFyaWFibGUgY2FsbGVkIGBwcm9tb2AuICANCiAgIC0gYGlmX2Vsc2UoY29uZGl0aW9uLCB2YWx1ZV9pZl90cnVlLCB2YWx1ZV9pZl9mYWxzZSlgIGlzIGEgY29uZGl0aW9uYWwgZnVuY3Rpb24uICANCiAgIC0gYHRpbWUgPT0gZHVyYCBpcyB0aGUgY29uZGl0aW9uIGNoZWNrZWQgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGN1cnJlbnQgdGltZSBwb2ludCAoYHRpbWVgKSBpcyBlcXVhbCB0byB0aGUgdGltZSBvZiB0aGUgZXZlbnQgKGBkdXJgKS4gIA0KICAgLSBgZXZlbnRgOiBJZiB0aGUgY29uZGl0aW9uIGlzIHRydWUgKGkuZS4sIHdlIGFyZSBhdCB0aGUgdGltZSBvZiBwcm9tb3Rpb24pLCB0aGUgdmFsdWUgb2YgYHByb21vYCBpcyBzZXQgdG8gdGhlIHZhbHVlIG9mIHRoZSBgZXZlbnRgIHZhcmlhYmxlICh3aGljaCBpcyAxIGZvciBwcm9tb3Rpb24gYW5kIDAgb3RoZXJ3aXNlKS4gIA0KICAgLSBJZiB0aGUgY29uZGl0aW9uIGlzIGZhbHNlIChpLmUuLCB3ZSBhcmUgYXQgYSB0aW1lIHBvaW50IGJlZm9yZSB0aGUgcHJvbW90aW9uKSwgdGhlIHZhbHVlIG9mIHByb21vIGlzIHNldCB0byBgMGAsIGluZGljYXRpbmcgdGhhdCB0aGUgZXZlbnQgZGlkIG5vdCBvY2N1ciBhdCB0aGF0IHNwZWNpZmljIHBlcnNvbi15ZWFyLg0KDQojIyBDaGFuZ2UgdGhlIG1pc3NpbmdzIGluIGpvYnRpbWUgdG8gMTEgIA0KVGhlIGNob2ljZSBvZiAxMSBtaWdodCBiZSBiYXNlZCBvbiB0aGUgY29udGV4dCBvZiB0aGUgZGF0YSAoZS5nLiwgdGhlIG1heGltdW0gb2JzZXJ2ZWQgam9iIHRpbWUgcGx1cyBvbmUuIA0KYGBge3J9DQpyYW5rc3ViIDwtIHJhbmtzdWIgJT4lDQogIG11dGF0ZShqb2J0aW1lID0gaWZfZWxzZShpcy5uYShqb2J0aW1lKSwgMTEsICBqb2J0aW1lKSkNCmBgYA0KDQogLSBgbXV0YXRlKGpvYnRpbWUgPSBpZl9lbHNlKGlzLm5hKGpvYnRpbWUpLCAxMSwgam9idGltZSkpYDoNCiAgIC0gYGlzLm5hKGpvYnRpbWUpYCBjaGVja3MgZm9yIG1pc3NpbmcgdmFsdWVzIChyZXByZXNlbnRlZCBhcyBgTkFgKSBpbiB0aGUgYGpvYnRpbWVgIGNvbHVtbi4gIA0KICAgLSBJZiBhIHZhbHVlIGlzIG1pc3NpbmcgKFRSVUUpLCBpdCdzIHJlcGxhY2VkIHdpdGggMTEuICANCiAgIC0gSWYgYSB2YWx1ZSBpcyBub3QgbWlzc2luZyAoRkFMU0UpLCBpdCByZW1haW5zIGl0cyBvcmlnaW5hbCB2YWx1ZS4NCg0KIyMgRGVmaW5lIGpvYnByZXMsIGEgdGltZS12YXJ5aW5nIGNvdmlhcmlhdGUNClRoaXMgZGVtb25zdHJhdGVzIGhvdyB0byBoYW5kbGUgdGltZS12YXJ5aW5nIGNvdmFyaWF0ZXMgaW4gZGlzY3JldGUtdGltZSBzdXJ2aXZhbCBhbmFseXNpcy4gVGhlIHZhbHVlIG9mIGBqb2JwcmVzYCBjYW4gY2hhbmdlIGZvciBhbiBpbmRpdmlkdWFsIGFzIHRpbWUgcHJvZ3Jlc3NlcywgYW5kIG91ciBkYXRhIHN0cnVjdHVyZSBpbiBsb25nIGZvcm1hdCBhbGxvd3MgdXMgdG8gY2FwdHVyZSB0aGVzZSBjaGFuZ2VzLg0KDQpgYGB7cn0NCnJhbmtzdWIgPC0gcmFua3N1YiAlPiUNCiAgbXV0YXRlKGpvYnByZXMgPSBpZl9lbHNlKHRpbWU8am9idGltZSxwcmVzdDEsIHByZXN0MikpDQpgYGANCiAtIGBtdXRhdGUoam9icHJlcyA9IGlmX2Vsc2UodGltZSA8IGpvYnRpbWUsIHByZXN0MSwgcHJlc3QyKSlgIGNyZWF0ZXMgYSBuZXcgdmFyaWFibGUgYGpvYnByZXNgLiAgDQogICAtIGB0aW1lIDwgam9idGltZWAgaXMgdGhlIGNvbmRpdGlvbiBjaGVja2VkIHdoZXJlIHRoZSBjdXJyZW50IHRpbWUgcG9pbnQgKHRpbWUpIGlzIGxlc3MgdGhhbiB0aGUgam9idGltZS4gIA0KICAgLSBJZiB0aGUgY29uZGl0aW9uIGlzIHRydWUgKGkuZS4sIGJlZm9yZSBgam9idGltZWApLCB0aGUgdmFsdWUgb2YgYGpvYnByZXNgIGlzIHRha2VuIGZyb20gdGhlIGBwcmVzdDFgIHZhcmlhYmxlIChsaWtlbHkgcHJlc3RpZ2UgYXQgYW4gZWFybGllciBqb2IpLiAgDQogICAtIElmIHRoZSBjb25kaXRpb24gaXMgZmFsc2UgKGkuZS4sIGF0IG9yIGFmdGVyIGBqb2J0aW1lYCksIHRoZSB2YWx1ZSBvZiBgam9icHJlc2AgaXMgdGFrZW4gZnJvbSB0aGUgYHByZXN0MmAgdmFyaWFibGUgKGxpa2VseSBwcmVzdGlnZSBhdCBhIGxhdGVyIG9yIGN1cnJlbnQgam9iKS4gIA0KDQojIyBGaXQgZGlzY3JldGUgdGltZSBsb2dpdCAgDQpUaGlzIGBnbG0oKWAgY2FsbCBmaXRzIGEgZGlzY3JldGUtdGltZSBsb2dpdCBtb2RlbCB3aGVyZSB0aGUgb3V0Y29tZSBpcyB0aGUgbG9nLW9kZHMgb2YgcHJvbW90aW9uIGF0IGEgc3BlY2lmaWMgdGltZSBwb2ludC4gVGhlIGNvZWZmaWNpZW50cyBmcm9tIHRoaXMgbW9kZWwgd2lsbCB0ZWxsIHVzIGhvdyBlYWNoIHByZWRpY3RvciB2YXJpYWJsZSBpcyBhc3NvY2lhdGVkIHdpdGggdGhpcyBsb2ctb2RkcywgaG9sZGluZyBvdGhlciB2YXJpYWJsZXMgY29uc3RhbnQuIFdlIHdpbGwgbmVlZCB0byBleHBvbmVudGlhdGUgdGhlc2UgY29lZmZpY2llbnRzIHRvIGludGVycHJldCB0aGVtIGFzIG9kZHMgcmF0aW9zLg0KDQpgYGB7cn0NCm15Zml0PC1nbG0ocHJvbW9+dW5kZ3JhZCArIHBoZG1lZCArIHBoZHByZXN0ICsgYXJ0ICsgY2l0ICsgam9icHJlcyArIHRpbWUgKyBJKHRpbWVeMiksIGZhbWlseT1iaW5vbWlhbCxkYXRhPXJhbmtzdWIpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZ3RzdW1tYXJ5KQ0KDQojIENyZWF0ZSBhIHN1bW1hcnkgdGFibGUgb2YgdGhlIG1vZGVsIHJlc3VsdHMNCm1vZGVsX3RhYmxlIDwtIHRibF9yZWdyZXNzaW9uKA0KICBteWZpdCwNCiAgZXhwb25lbnRpYXRlID0gVFJVRSwgIyBEaXNwbGF5IG9kZHMgcmF0aW9zIGluc3RlYWQgb2YgbG9nLW9kZHMNCiAgcHZhbHVlX2Z1biA9IH5zdHlsZV9wdmFsdWUoLngsIGRpZ2l0cyA9IDMpLCAjIEZvcm1hdCBwLXZhbHVlcw0KICBsYWJlbCA9IGxpc3QoDQogICAgInVuZGdyYWQiIH4gIlVuZGVyZ3JhZHVhdGUgSW5zdGl0dXRpb24gUHJlc3RpZ2UiLA0KICAgICJwaGRtZWQiIH4gIk1lZGljYWwgUGhEIiwNCiAgICAicGhkcHJlc3QiIH4gIlBoRCBQcm9ncmFtIFByZXN0aWdlIiwNCiAgICAiYXJ0IiB+ICJOdW1iZXIgb2YgQXJ0aWNsZXMiLA0KICAgICJjaXQiIH4gIk51bWJlciBvZiBDaXRhdGlvbnMiLA0KICAgICJqb2JwcmVzIiB+ICJKb2IgUHJlc3RpZ2UiLA0KICAgICJ0aW1lIiB+ICJUaW1lIChZZWFycykiLA0KICAgICJJKHRpbWVeMikiIH4gIlRpbWUgU3F1YXJlZCIgIyBVc2UgdGhlIGV4YWN0IHN0cmluZyAiSSh0aW1lXjIpIg0KICApICMgQ3VzdG9tIGxhYmVscyBmb3IgdmFyaWFibGVzDQopDQoNCiMgUHJpbnQgdGhlIHRhYmxlIHRvIHRoZSBjb25zb2xlDQptb2RlbF90YWJsZQ0KYGBgDQoNCmBgYHtyfQ0KIyBZb3UgY2FuIGZ1cnRoZXIgY3VzdG9taXplIHRoZSB0YWJsZSwgZm9yIGV4YW1wbGUsIGFkZGluZyBhIHRpdGxlIGFuZCBjYXB0aW9uDQptb2RlbF90YWJsZSA8LSBtb2RlbF90YWJsZSAlPiUNCiAgYXNfZ3QoKSAlPiUgIyBDb252ZXJ0IHRvIGEgZ3QgdGFibGUgZm9yIG1vcmUgYWR2YW5jZWQgZm9ybWF0dGluZw0KICBndDo6dGFiX2hlYWRlcigNCiAgICB0aXRsZSA9ICJEaXNjcmV0ZS1UaW1lIExvZ2l0IE1vZGVsIFJlc3VsdHMiLA0KICAgIHN1YnRpdGxlID0gIlByZWRpY3RpbmcgUHJvYmFiaWxpdHkgb2YgUHJvbW90aW9uIg0KICApICU+JQ0KICBndDo6dGFiX2NhcHRpb24oIk9kZHMgcmF0aW9zIGFuZCBwLXZhbHVlcyBhcmUgcmVwb3J0ZWQuIikNCg0KIyBQcmludCB0aGUgY3VzdG9taXplZCB0YWJsZQ0KbW9kZWxfdGFibGU=