1 introduction

*In this etivity, you will code your first simple model and use it to answer a research question. To get used to the format for models in R, we’ll start by giving you some parts of the code, and you need to fill in the missing numbers or code blocks by replacing the #YOUR CODE# placeholders. At the end of each etivity, we’ll provide a solution file that contains the full code, annotated with comments. Make sure you understand each line, and soon you’ll be able to write your own model from scratch!

Your task is to find out how long it takes for a cohort of infected people to recover. As you saw in the video, to answer this question you need to keep track of 2 populations: those that are infected (compartment 𝐼 ), and those that have recovered (compartment 𝑅 ). Infected people recover at a rate 𝛾 (gamma). The differential equations describing this are:*

Load the packages which you need for this etivity, by running the following cell:

2 Run this cell as it is

library(deSolve)   # package to solve the model
library(reshape2)  # package to change the shape of the model output
library(ggplot2)   # package for plotting

To start, it is useful to code what we know about the situation we want to model. We are looking at a cohort of 10^6 currently infected people, and no one has recovered so far. The average duration of infection is 10 days. The question we want to answer is how many people will recover from the infection over a 4-week period.

Given this data, fill in the correct values to the following variables, and run the cell:

initial_number_infected <- 1000000       # the initial infected population 
                                         # size
initial_number_recovered <- 0  # the initial number of people in "0"
                                         # the recovered state
recovery_rate <- 0.1            # the rate of recovery gamma, 
                                         # in units of days^-1
follow_up_duration <- 28      # the duration to run the model for, 
                                         # in units of days
  
# Hint: the units of the recovery rate and the follow-up duration should be
# consistent.

Now, we combine this data into objects that are recognised by the deSolve package as model input. To do this, again run the code below.

# The initial state values are stored as a vector 
# and each value is assigned a name.
initial_state_values <- c(I = initial_number_infected, 
                          R = initial_number_recovered)

# Parameters are also stored as a vector with assigned names and values. 
parameters <- c(gamma = recovery_rate)  
# In this case we only have one parameter, gamma.

Think about: what kind of information is stored in the “initial_state_values” and parameters vectors?

Additionally, we need to specify the time we want the model to run for. This depends on the question we want to answer. In the cell below, the duration you specified earlier is automatically filled in when you run it.

# The times vector creates a sequence of timepoints at which we want to 
# calculate the number of people in the I and R compartment.
times <- seq(from = 0, to = follow_up_duration, by = 1) 

Think about: what kind of information is stored in the times vector?

Check your answers by having a look at each of these vectors to familiarise yourself with the structure: in the following code cell we have typed the object names, so you just need to press “Run” to see what each of them contains.

initial_state_values
##     I     R 
## 1e+06 0e+00
parameters
## gamma 
##   0.1
times
##  [1]  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
## [26] 25 26 27 28

The next step is specifying the model. Using the example code in the introductory document, complete the following model function with the differential equations above.

cohort_model <- function(time, state, parameters) { 
  
    with(as.list(c(state, parameters)), {
      
      dI <- -gamma*I
      dR <- gamma*I
      
      return(list(c(dI, dR)))
    })
  
}

Now all there’s left to do is solving this set of equations using the deSolve package. Fill in the following command, which calculates and stores the number of infected and recovered people at each timestep in the output dataframe. Don’t forget to run it!

# Hint: if you can't remember what those arguments correspond to,
# just look up the ode help file:
?ode
## starting httpd help server ... done
output <- as.data.frame(ode(y = initial_state_values,  times = times,   func = cohort_model,  parms =  parameters))

Printing the model output returns a dataframe with columns time (containing our times vector), I (containing the number of infected people at each timestep) and R (containing the number of recovered people at each timestep):

output
##    time          I         R
## 1     0 1000000.00      0.00
## 2     1  904837.42  95162.58
## 3     2  818730.75 181269.25
## 4     3  740818.22 259181.78
## 5     4  670320.04 329679.96
## 6     5  606530.66 393469.34
## 7     6  548811.63 451188.37
## 8     7  496585.30 503414.70
## 9     8  449328.96 550671.04
## 10    9  406569.66 593430.34
## 11   10  367879.44 632120.56
## 12   11  332871.08 667128.92
## 13   12  301194.21 698805.79
## 14   13  272531.79 727468.21
## 15   14  246596.96 753403.04
## 16   15  223130.16 776869.84
## 17   16  201896.51 798103.49
## 18   17  182683.52 817316.48
## 19   18  165298.88 834701.12
## 20   19  149568.62 850431.38
## 21   20  135335.28 864664.72
## 22   21  122456.42 877543.58
## 23   22  110803.15 889196.85
## 24   23  100258.84 899741.16
## 25   24   90717.95 909282.05
## 26   25   82085.00 917915.00
## 27   26   74273.58 925726.42
## 28   27   67205.51 932794.49
## 29   28   60810.06 939189.94

3 Question: Based on the output, how many people have recovered after 4 weeks? What proportion of the total population does this correspond to?

Now, plot your model output in the following cell, with time on the x axis and the number of infected and recovered people on the y axis. You can use the introductory document for help with this.

3.1 base on the output, how many people have recovered afetr 4 weeks

output[output$time == 28, c("time","R")]   
##    time        R
## 29   28 939189.9
# printing the "time" and "R" output columns when the timestep equals 28
# Answer: 939189.9 people are in the recovered compartment at timestep 28

3.2 What proportion of the total population does this correspond to?

output[output$time == 28,"R"]/(output[output$time == 28,"I"]+
 output[output$time == 28,"R"]) # note this is only on a separate line 
## [1] 0.9391899
                                # for formatting reasons!

# Answer: 93.9%

# All we are doing here is dividing the number of recovered people at the
# 4 week timestep by the total population size (I + R) at this timestep.
# Note that since there are no births and deaths in our model, 
# the total population size is the same at each timestep, so we could 
# also calculate it by taking sum(initial_state_values).

3.3 Plotting the output

# First turn the output dataset into a long format, 
# so that the number in each compartment at each timestep
# are all in the same column
output_long <- melt(as.data.frame(output), id = "time")                  

# Plot the number of people in each compartment over time
ggplot(data = output_long,          # specify object containing data to plot
       aes(x = time, y = value, colour = variable, group = variable)) +          # assign columns to axes and groups
  geom_line() +                     # represent data as lines
  xlab("Time (days)")+              # add label for x axis
  ylab("Number of people") +        # add label for y axis
  labs(title = paste("Number infected and recovered over time when gamma =", parameters["gamma"],"days^-1")) # add title

#Using the #paste command, we can combine sentences with the 
#values stored in variables (here gamma)

3.4 Based on the plot, at what timepoint were infected and recovered individuals equal in number?

# Answer: around 7 days - this where the I and R lines intersect.
# You can confirm that by looking at the output table:
# the number in the I and R compartment are very similar at timestep 7.
output[output$time == 7,]
##   time        I        R
## 8    7 496585.3 503414.7

4 Question: Based on the plot, at what timepoint were infected and recovered individuals equal in number?

For the last part of the etivity, try varying 𝛾 to see how it affects the output. For example, in the cell below change gamma ( 𝛾 ) to correspond to an average infectious period of: a) 2 days b) 20 days.

4.1 What is the recovery rate in 2 days?

Varying 𝛾 Average duration of infection = 2 days so the recovery rate = 1/2 = 0.5 days −1

parameters <- c(gamma = 0.5)
output <- as.data.frame(ode(y = initial_state_values,  times = times, func = cohort_model, parms = parameters))

# Plotting the output
output_long <- melt(as.data.frame(output), id = "time")   
# turn output dataset into long format

ggplot(data = output_long,       # specify object containing data to plot
       aes(x = time, 
           y = value, 
           colour = variable, 
           group = variable)) +  # assign columns to axes and groups
  geom_line() +                                 # represent data as lines
  xlab("Time (days)")+                          # add label for x axis
  ylab("Number of people") +                    # add label for y axis
  labs(title = paste("Number infected and recovered over time when gamma =",
                      parameters["gamma"],"days^-1")) + # add title
  scale_color_brewer(palette = "Set1")

# Since the initial number in each compartment and 
# the timesteps of interest haven't changed, 
# these are the only parts of the code we need to rerun.

# Now, copy-paste your plot code from above here to visualise the output.

4.2 What is the recovery rate in 20 days?

parameters <- c(gamma = 0.05)

# Solving the model
output <- as.data.frame(ode(y = initial_state_values, 
                            times = times, 
                            func = cohort_model,
                            parms = parameters))

# Plotting the output
output_long <- melt(as.data.frame(output), id = "time") 

ggplot(data = output_long,                                 
       aes(x = time, 
           y = value, 
           colour = variable, 
           group = variable)) +  # assign columns to axes and groups
  geom_line() +                  # represent data as lines
  xlab("Time (days)")+           # add label for x axis
  ylab("Number of people") +     # add label for y axis
  labs(title = paste("Number infected and recovered over time when gamma =",
                    parameters["gamma"],"days^-1")) # add title

5 Question: What changes do you observe in the transition to the recovered compartment if 𝛾 is higher or lower? For example, how long does it take for everyone to recover in both cases?

#Answer: if the rate is higher ( 𝛾  = 0.5), we can see that infected people recover more quickly: it takes less than 2 days for half of the infected cohort to recover, and by around 8 days, nearly everyone has recovered. A lower rate ( 𝛾  = 0.05) on the other hand corresponds to a slower transition: it takes around 14 days for half of infected people to move into the  𝑅  compartment, and by the end of our 4 week follow-up around a quarter of people still have not recovered.

(r): source from coursera course. Only for studying purpose #https://www.coursera.org/learn/developing-the-sir-model/home/welcome

LS0tDQp0aXRsZTogIk1vZGVsbGluZyBhbiBpbmZlY3RlZCBjb2hvcnQgMSINCmF1dGhvcjogIkJpbmggVGhhbmcgVHJhbiAoQykgZnJvbSBjb3Vyc2VyYSINCmRhdGU6ICI1LzEwLzIwMjAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogam91cm5hbA0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICANCi0tLQ0KIyBpbnRyb2R1Y3Rpb24NCipJbiB0aGlzIGV0aXZpdHksIHlvdSB3aWxsIGNvZGUgeW91ciBmaXJzdCBzaW1wbGUgbW9kZWwgYW5kIHVzZSBpdCB0byBhbnN3ZXIgYSByZXNlYXJjaCBxdWVzdGlvbi4gVG8gZ2V0IHVzZWQgdG8gdGhlIGZvcm1hdCBmb3IgbW9kZWxzIGluIFIsIHdlJ2xsIHN0YXJ0IGJ5IGdpdmluZyB5b3Ugc29tZSBwYXJ0cyBvZiB0aGUgY29kZSwgYW5kIHlvdSBuZWVkIHRvIGZpbGwgaW4gdGhlIG1pc3NpbmcgbnVtYmVycyBvciBjb2RlIGJsb2NrcyBieSByZXBsYWNpbmcgdGhlICNZT1VSIENPREUjIHBsYWNlaG9sZGVycy4gQXQgdGhlIGVuZCBvZiBlYWNoIGV0aXZpdHksIHdlJ2xsIHByb3ZpZGUgYSBzb2x1dGlvbiBmaWxlIHRoYXQgY29udGFpbnMgdGhlIGZ1bGwgY29kZSwgYW5ub3RhdGVkIHdpdGggY29tbWVudHMuIE1ha2Ugc3VyZSB5b3UgdW5kZXJzdGFuZCBlYWNoIGxpbmUsIGFuZCBzb29uIHlvdSdsbCBiZSBhYmxlIHRvIHdyaXRlIHlvdXIgb3duIG1vZGVsIGZyb20gc2NyYXRjaCENCg0KWW91ciB0YXNrIGlzIHRvIGZpbmQgb3V0IGhvdyBsb25nIGl0IHRha2VzIGZvciBhIGNvaG9ydCBvZiBpbmZlY3RlZCBwZW9wbGUgdG8gcmVjb3Zlci4gQXMgeW91IHNhdyBpbiB0aGUgdmlkZW8sIHRvIGFuc3dlciB0aGlzIHF1ZXN0aW9uIHlvdSBuZWVkIHRvIGtlZXAgdHJhY2sgb2YgMiBwb3B1bGF0aW9uczogdGhvc2UgdGhhdCBhcmUgaW5mZWN0ZWQgKGNvbXBhcnRtZW50ICDwnZC8ICksIGFuZCB0aG9zZSB0aGF0IGhhdmUgcmVjb3ZlcmVkIChjb21wYXJ0bWVudCAg8J2RhSApLiBJbmZlY3RlZCBwZW9wbGUgcmVjb3ZlciBhdCBhIHJhdGUgIPCdm74gIChnYW1tYSkuIFRoZSBkaWZmZXJlbnRpYWwgZXF1YXRpb25zIGRlc2NyaWJpbmcgdGhpcyBhcmU6Kg0KDQoNCkxvYWQgdGhlIHBhY2thZ2VzIHdoaWNoIHlvdSBuZWVkIGZvciB0aGlzIGV0aXZpdHksIGJ5IHJ1bm5pbmcgdGhlIGZvbGxvd2luZyBjZWxsOg0KDQojIFJ1biB0aGlzIGNlbGwgYXMgaXQgaXMNCg0KYGBge3J9DQpsaWJyYXJ5KGRlU29sdmUpICAgIyBwYWNrYWdlIHRvIHNvbHZlIHRoZSBtb2RlbA0KbGlicmFyeShyZXNoYXBlMikgICMgcGFja2FnZSB0byBjaGFuZ2UgdGhlIHNoYXBlIG9mIHRoZSBtb2RlbCBvdXRwdXQNCmxpYnJhcnkoZ2dwbG90MikgICAjIHBhY2thZ2UgZm9yIHBsb3R0aW5nDQpgYGANCg0KVG8gc3RhcnQsIGl0IGlzIHVzZWZ1bCB0byBjb2RlIHdoYXQgd2Uga25vdyBhYm91dCB0aGUgc2l0dWF0aW9uIHdlIHdhbnQgdG8gbW9kZWwuIFdlIGFyZSBsb29raW5nIGF0IGEgY29ob3J0IG9mIDEwXjYgIGN1cnJlbnRseSBpbmZlY3RlZCBwZW9wbGUsIGFuZCBubyBvbmUgaGFzIHJlY292ZXJlZCBzbyBmYXIuIFRoZSBhdmVyYWdlIGR1cmF0aW9uIG9mIGluZmVjdGlvbiBpcyAxMCBkYXlzLiBUaGUgcXVlc3Rpb24gd2Ugd2FudCB0byBhbnN3ZXIgaXMgaG93IG1hbnkgcGVvcGxlIHdpbGwgcmVjb3ZlciBmcm9tIHRoZSBpbmZlY3Rpb24gb3ZlciBhIDQtd2VlayBwZXJpb2QuDQoNCkdpdmVuIHRoaXMgZGF0YSwgZmlsbCBpbiB0aGUgY29ycmVjdCB2YWx1ZXMgdG8gdGhlIGZvbGxvd2luZyB2YXJpYWJsZXMsIGFuZCBydW4gdGhlIGNlbGw6DQoNCmBgYHtyfQ0KaW5pdGlhbF9udW1iZXJfaW5mZWN0ZWQgPC0gMTAwMDAwMCAgICAgICAjIHRoZSBpbml0aWFsIGluZmVjdGVkIHBvcHVsYXRpb24gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgc2l6ZQ0KaW5pdGlhbF9udW1iZXJfcmVjb3ZlcmVkIDwtIDAgICMgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHBlb3BsZSBpbiAiMCINCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgcmVjb3ZlcmVkIHN0YXRlDQpyZWNvdmVyeV9yYXRlIDwtIDAuMSAgICAgICAgICAgICMgdGhlIHJhdGUgb2YgcmVjb3ZlcnkgZ2FtbWEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHVuaXRzIG9mIGRheXNeLTENCmZvbGxvd191cF9kdXJhdGlvbiA8LSAyOCAgICAgICMgdGhlIGR1cmF0aW9uIHRvIHJ1biB0aGUgbW9kZWwgZm9yLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB1bml0cyBvZiBkYXlzDQogIA0KIyBIaW50OiB0aGUgdW5pdHMgb2YgdGhlIHJlY292ZXJ5IHJhdGUgYW5kIHRoZSBmb2xsb3ctdXAgZHVyYXRpb24gc2hvdWxkIGJlDQojIGNvbnNpc3RlbnQuDQpgYGANCg0KTm93LCB3ZSBjb21iaW5lIHRoaXMgZGF0YSBpbnRvIG9iamVjdHMgdGhhdCBhcmUgcmVjb2duaXNlZCBieSB0aGUgZGVTb2x2ZSBwYWNrYWdlIGFzIG1vZGVsIGlucHV0LiBUbyBkbyB0aGlzLCBhZ2FpbiBydW4gdGhlIGNvZGUgYmVsb3cuDQoNCmBgYHtyfQ0KIyBUaGUgaW5pdGlhbCBzdGF0ZSB2YWx1ZXMgYXJlIHN0b3JlZCBhcyBhIHZlY3RvciANCiMgYW5kIGVhY2ggdmFsdWUgaXMgYXNzaWduZWQgYSBuYW1lLg0KaW5pdGlhbF9zdGF0ZV92YWx1ZXMgPC0gYyhJID0gaW5pdGlhbF9udW1iZXJfaW5mZWN0ZWQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBSID0gaW5pdGlhbF9udW1iZXJfcmVjb3ZlcmVkKQ0KDQojIFBhcmFtZXRlcnMgYXJlIGFsc28gc3RvcmVkIGFzIGEgdmVjdG9yIHdpdGggYXNzaWduZWQgbmFtZXMgYW5kIHZhbHVlcy4gDQpwYXJhbWV0ZXJzIDwtIGMoZ2FtbWEgPSByZWNvdmVyeV9yYXRlKSAgDQojIEluIHRoaXMgY2FzZSB3ZSBvbmx5IGhhdmUgb25lIHBhcmFtZXRlciwgZ2FtbWEuDQpgYGANCg0KDQpUaGluayBhYm91dDogd2hhdCBraW5kIG9mIGluZm9ybWF0aW9uIGlzIHN0b3JlZCBpbiB0aGUgImluaXRpYWxfc3RhdGVfdmFsdWVzIiBhbmQgcGFyYW1ldGVycyB2ZWN0b3JzPw0KDQpBZGRpdGlvbmFsbHksIHdlIG5lZWQgdG8gc3BlY2lmeSB0aGUgdGltZSB3ZSB3YW50IHRoZSBtb2RlbCB0byBydW4gZm9yLiBUaGlzIGRlcGVuZHMgb24gdGhlIHF1ZXN0aW9uIHdlIHdhbnQgdG8gYW5zd2VyLiBJbiB0aGUgY2VsbCBiZWxvdywgdGhlIGR1cmF0aW9uIHlvdSBzcGVjaWZpZWQgZWFybGllciBpcyBhdXRvbWF0aWNhbGx5IGZpbGxlZCBpbiB3aGVuIHlvdSBydW4gaXQuDQoNCmBgYHtyfQ0KIyBUaGUgdGltZXMgdmVjdG9yIGNyZWF0ZXMgYSBzZXF1ZW5jZSBvZiB0aW1lcG9pbnRzIGF0IHdoaWNoIHdlIHdhbnQgdG8gDQojIGNhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIHBlb3BsZSBpbiB0aGUgSSBhbmQgUiBjb21wYXJ0bWVudC4NCnRpbWVzIDwtIHNlcShmcm9tID0gMCwgdG8gPSBmb2xsb3dfdXBfZHVyYXRpb24sIGJ5ID0gMSkgDQpgYGANCg0KVGhpbmsgYWJvdXQ6IHdoYXQga2luZCBvZiBpbmZvcm1hdGlvbiBpcyBzdG9yZWQgaW4gdGhlIHRpbWVzIHZlY3Rvcj8NCg0KQ2hlY2sgeW91ciBhbnN3ZXJzIGJ5IGhhdmluZyBhIGxvb2sgYXQgZWFjaCBvZiB0aGVzZSB2ZWN0b3JzIHRvIGZhbWlsaWFyaXNlIHlvdXJzZWxmIHdpdGggdGhlIHN0cnVjdHVyZTogaW4gdGhlIGZvbGxvd2luZyBjb2RlIGNlbGwgd2UgaGF2ZSB0eXBlZCB0aGUgb2JqZWN0IG5hbWVzLCBzbyB5b3UganVzdCBuZWVkIHRvIHByZXNzICJSdW4iIHRvIHNlZSB3aGF0IGVhY2ggb2YgdGhlbSBjb250YWlucy4NCg0KYGBge3J9DQppbml0aWFsX3N0YXRlX3ZhbHVlcw0KcGFyYW1ldGVycw0KdGltZXMNCmBgYA0KDQoNClRoZSBuZXh0IHN0ZXAgaXMgc3BlY2lmeWluZyB0aGUgbW9kZWwuIFVzaW5nIHRoZSBleGFtcGxlIGNvZGUgaW4gdGhlIGludHJvZHVjdG9yeSBkb2N1bWVudCwgY29tcGxldGUgdGhlIGZvbGxvd2luZyBtb2RlbCBmdW5jdGlvbiB3aXRoIHRoZSBkaWZmZXJlbnRpYWwgZXF1YXRpb25zIGFib3ZlLg0KDQpgYGB7cn0NCmNvaG9ydF9tb2RlbCA8LSBmdW5jdGlvbih0aW1lLCBzdGF0ZSwgcGFyYW1ldGVycykgeyANCiAgDQogICAgd2l0aChhcy5saXN0KGMoc3RhdGUsIHBhcmFtZXRlcnMpKSwgew0KICAgICAgDQogICAgICBkSSA8LSAtZ2FtbWEqSQ0KICAgICAgZFIgPC0gZ2FtbWEqSQ0KICAgICAgDQogICAgICByZXR1cm4obGlzdChjKGRJLCBkUikpKQ0KICAgIH0pDQogIA0KfQ0KYGBgDQoNCg0KTm93IGFsbCB0aGVyZSdzIGxlZnQgdG8gZG8gaXMgc29sdmluZyB0aGlzIHNldCBvZiBlcXVhdGlvbnMgdXNpbmcgdGhlIGRlU29sdmUgcGFja2FnZS4gRmlsbCBpbiB0aGUgZm9sbG93aW5nIGNvbW1hbmQsIHdoaWNoIGNhbGN1bGF0ZXMgYW5kIHN0b3JlcyB0aGUgbnVtYmVyIG9mIGluZmVjdGVkIGFuZCByZWNvdmVyZWQgcGVvcGxlIGF0IGVhY2ggdGltZXN0ZXAgaW4gdGhlIG91dHB1dCBkYXRhZnJhbWUuIERvbid0IGZvcmdldCB0byBydW4gaXQhDQoNCg0KYGBge3J9DQojIEhpbnQ6IGlmIHlvdSBjYW4ndCByZW1lbWJlciB3aGF0IHRob3NlIGFyZ3VtZW50cyBjb3JyZXNwb25kIHRvLA0KIyBqdXN0IGxvb2sgdXAgdGhlIG9kZSBoZWxwIGZpbGU6DQo/b2RlDQoNCmBgYA0KDQoNCmBgYHtyfQ0Kb3V0cHV0IDwtIGFzLmRhdGEuZnJhbWUob2RlKHkgPSBpbml0aWFsX3N0YXRlX3ZhbHVlcywgIHRpbWVzID0gdGltZXMsICAgZnVuYyA9IGNvaG9ydF9tb2RlbCwgIHBhcm1zID0gIHBhcmFtZXRlcnMpKQ0KDQpgYGANCg0KDQpQcmludGluZyB0aGUgbW9kZWwgb3V0cHV0IHJldHVybnMgYSBkYXRhZnJhbWUgd2l0aCBjb2x1bW5zIHRpbWUgKGNvbnRhaW5pbmcgb3VyIHRpbWVzIHZlY3RvciksIEkgKGNvbnRhaW5pbmcgdGhlIG51bWJlciBvZiBpbmZlY3RlZCBwZW9wbGUgYXQgZWFjaCB0aW1lc3RlcCkgYW5kIFIgKGNvbnRhaW5pbmcgdGhlIG51bWJlciBvZiByZWNvdmVyZWQgcGVvcGxlIGF0IGVhY2ggdGltZXN0ZXApOg0KDQpgYGB7cn0NCm91dHB1dA0KDQpgYGANCg0KIyBRdWVzdGlvbjogQmFzZWQgb24gdGhlIG91dHB1dCwgaG93IG1hbnkgcGVvcGxlIGhhdmUgcmVjb3ZlcmVkIGFmdGVyIDQgd2Vla3M/IFdoYXQgcHJvcG9ydGlvbiBvZiB0aGUgdG90YWwgcG9wdWxhdGlvbiBkb2VzIHRoaXMgY29ycmVzcG9uZCB0bz8NCg0KTm93LCBwbG90IHlvdXIgbW9kZWwgb3V0cHV0IGluIHRoZSBmb2xsb3dpbmcgY2VsbCwgd2l0aCB0aW1lIG9uIHRoZSB4IGF4aXMgYW5kIHRoZSBudW1iZXIgb2YgaW5mZWN0ZWQgYW5kIHJlY292ZXJlZCBwZW9wbGUgb24gdGhlIHkgYXhpcy4gWW91IGNhbiB1c2UgdGhlIGludHJvZHVjdG9yeSBkb2N1bWVudCBmb3IgaGVscCB3aXRoIHRoaXMuDQoNCiMjIGJhc2Ugb24gdGhlIG91dHB1dCwgaG93IG1hbnkgcGVvcGxlIGhhdmUgcmVjb3ZlcmVkIGFmZXRyIDQgd2Vla3MNCg0KYGBge3J9DQpvdXRwdXRbb3V0cHV0JHRpbWUgPT0gMjgsIGMoInRpbWUiLCJSIildICAgDQojIHByaW50aW5nIHRoZSAidGltZSIgYW5kICJSIiBvdXRwdXQgY29sdW1ucyB3aGVuIHRoZSB0aW1lc3RlcCBlcXVhbHMgMjgNCiMgQW5zd2VyOiA5MzkxODkuOSBwZW9wbGUgYXJlIGluIHRoZSByZWNvdmVyZWQgY29tcGFydG1lbnQgYXQgdGltZXN0ZXAgMjgNCmBgYA0KDQoNCiMjIFdoYXQgcHJvcG9ydGlvbiBvZiB0aGUgdG90YWwgcG9wdWxhdGlvbiBkb2VzIHRoaXMgY29ycmVzcG9uZCB0bz8NCg0KYGBge3J9DQpvdXRwdXRbb3V0cHV0JHRpbWUgPT0gMjgsIlIiXS8ob3V0cHV0W291dHB1dCR0aW1lID09IDI4LCJJIl0rDQogb3V0cHV0W291dHB1dCR0aW1lID09IDI4LCJSIl0pICMgbm90ZSB0aGlzIGlzIG9ubHkgb24gYSBzZXBhcmF0ZSBsaW5lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGZvciBmb3JtYXR0aW5nIHJlYXNvbnMhDQoNCiMgQW5zd2VyOiA5My45JQ0KDQojIEFsbCB3ZSBhcmUgZG9pbmcgaGVyZSBpcyBkaXZpZGluZyB0aGUgbnVtYmVyIG9mIHJlY292ZXJlZCBwZW9wbGUgYXQgdGhlDQojIDQgd2VlayB0aW1lc3RlcCBieSB0aGUgdG90YWwgcG9wdWxhdGlvbiBzaXplIChJICsgUikgYXQgdGhpcyB0aW1lc3RlcC4NCiMgTm90ZSB0aGF0IHNpbmNlIHRoZXJlIGFyZSBubyBiaXJ0aHMgYW5kIGRlYXRocyBpbiBvdXIgbW9kZWwsIA0KIyB0aGUgdG90YWwgcG9wdWxhdGlvbiBzaXplIGlzIHRoZSBzYW1lIGF0IGVhY2ggdGltZXN0ZXAsIHNvIHdlIGNvdWxkIA0KIyBhbHNvIGNhbGN1bGF0ZSBpdCBieSB0YWtpbmcgc3VtKGluaXRpYWxfc3RhdGVfdmFsdWVzKS4NCmBgYA0KDQojIyBQbG90dGluZyB0aGUgb3V0cHV0DQoNCmBgYHtyfQ0KIyBGaXJzdCB0dXJuIHRoZSBvdXRwdXQgZGF0YXNldCBpbnRvIGEgbG9uZyBmb3JtYXQsIA0KIyBzbyB0aGF0IHRoZSBudW1iZXIgaW4gZWFjaCBjb21wYXJ0bWVudCBhdCBlYWNoIHRpbWVzdGVwDQojIGFyZSBhbGwgaW4gdGhlIHNhbWUgY29sdW1uDQpvdXRwdXRfbG9uZyA8LSBtZWx0KGFzLmRhdGEuZnJhbWUob3V0cHV0KSwgaWQgPSAidGltZSIpICAgICAgICAgICAgICAgICAgDQoNCiMgUGxvdCB0aGUgbnVtYmVyIG9mIHBlb3BsZSBpbiBlYWNoIGNvbXBhcnRtZW50IG92ZXIgdGltZQ0KZ2dwbG90KGRhdGEgPSBvdXRwdXRfbG9uZywgICAgICAgICAgIyBzcGVjaWZ5IG9iamVjdCBjb250YWluaW5nIGRhdGEgdG8gcGxvdA0KICAgICAgIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLCBjb2xvdXIgPSB2YXJpYWJsZSwgZ3JvdXAgPSB2YXJpYWJsZSkpICsgICAgICAgICAgIyBhc3NpZ24gY29sdW1ucyB0byBheGVzIGFuZCBncm91cHMNCiAgZ2VvbV9saW5lKCkgKyAgICAgICAgICAgICAgICAgICAgICMgcmVwcmVzZW50IGRhdGEgYXMgbGluZXMNCiAgeGxhYigiVGltZSAoZGF5cykiKSsgICAgICAgICAgICAgICMgYWRkIGxhYmVsIGZvciB4IGF4aXMNCiAgeWxhYigiTnVtYmVyIG9mIHBlb3BsZSIpICsgICAgICAgICMgYWRkIGxhYmVsIGZvciB5IGF4aXMNCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJOdW1iZXIgaW5mZWN0ZWQgYW5kIHJlY292ZXJlZCBvdmVyIHRpbWUgd2hlbiBnYW1tYSA9IiwgcGFyYW1ldGVyc1siZ2FtbWEiXSwiZGF5c14tMSIpKSAjIGFkZCB0aXRsZQ0KI1VzaW5nIHRoZSAjcGFzdGUgY29tbWFuZCwgd2UgY2FuIGNvbWJpbmUgc2VudGVuY2VzIHdpdGggdGhlIA0KI3ZhbHVlcyBzdG9yZWQgaW4gdmFyaWFibGVzIChoZXJlIGdhbW1hKQ0KICANCmBgYA0KDQojIyBCYXNlZCBvbiB0aGUgcGxvdCwgYXQgd2hhdCB0aW1lcG9pbnQgd2VyZSBpbmZlY3RlZCBhbmQgcmVjb3ZlcmVkIGluZGl2aWR1YWxzIGVxdWFsIGluIG51bWJlcj8NCg0KYGBge3J9DQojIEFuc3dlcjogYXJvdW5kIDcgZGF5cyAtIHRoaXMgd2hlcmUgdGhlIEkgYW5kIFIgbGluZXMgaW50ZXJzZWN0Lg0KIyBZb3UgY2FuIGNvbmZpcm0gdGhhdCBieSBsb29raW5nIGF0IHRoZSBvdXRwdXQgdGFibGU6DQojIHRoZSBudW1iZXIgaW4gdGhlIEkgYW5kIFIgY29tcGFydG1lbnQgYXJlIHZlcnkgc2ltaWxhciBhdCB0aW1lc3RlcCA3Lg0Kb3V0cHV0W291dHB1dCR0aW1lID09IDcsXQ0KYGBgDQoNCiMgUXVlc3Rpb246IEJhc2VkIG9uIHRoZSBwbG90LCBhdCB3aGF0IHRpbWVwb2ludCB3ZXJlIGluZmVjdGVkIGFuZCByZWNvdmVyZWQgaW5kaXZpZHVhbHMgZXF1YWwgaW4gbnVtYmVyPw0KDQpGb3IgdGhlIGxhc3QgcGFydCBvZiB0aGUgZXRpdml0eSwgdHJ5IHZhcnlpbmcgIPCdm74gIHRvIHNlZSBob3cgaXQgYWZmZWN0cyB0aGUgb3V0cHV0LiBGb3IgZXhhbXBsZSwgaW4gdGhlIGNlbGwgYmVsb3cgY2hhbmdlIGdhbW1hICgg8J2bviApIHRvIGNvcnJlc3BvbmQgdG8gYW4gYXZlcmFnZSBpbmZlY3Rpb3VzIHBlcmlvZCBvZjoNCmEpIDIgZGF5cw0KYikgMjAgZGF5cy4NCg0KIyMgV2hhdCBpcyB0aGUgcmVjb3ZlcnkgcmF0ZSBpbiAyIGRheXM/DQoNClZhcnlpbmcgIPCdm74gDQpBdmVyYWdlIGR1cmF0aW9uIG9mIGluZmVjdGlvbiA9IDIgZGF5cyBzbyB0aGUgcmVjb3ZlcnkgcmF0ZSA9IDEvMiA9IDAuNSBkYXlzIOKIkjENCg0KDQpgYGB7cn0NCnBhcmFtZXRlcnMgPC0gYyhnYW1tYSA9IDAuNSkNCm91dHB1dCA8LSBhcy5kYXRhLmZyYW1lKG9kZSh5ID0gaW5pdGlhbF9zdGF0ZV92YWx1ZXMsICB0aW1lcyA9IHRpbWVzLCBmdW5jID0gY29ob3J0X21vZGVsLCBwYXJtcyA9IHBhcmFtZXRlcnMpKQ0KDQojIFBsb3R0aW5nIHRoZSBvdXRwdXQNCm91dHB1dF9sb25nIDwtIG1lbHQoYXMuZGF0YS5mcmFtZShvdXRwdXQpLCBpZCA9ICJ0aW1lIikgICANCiMgdHVybiBvdXRwdXQgZGF0YXNldCBpbnRvIGxvbmcgZm9ybWF0DQoNCmdncGxvdChkYXRhID0gb3V0cHV0X2xvbmcsICAgICAgICMgc3BlY2lmeSBvYmplY3QgY29udGFpbmluZyBkYXRhIHRvIHBsb3QNCiAgICAgICBhZXMoeCA9IHRpbWUsIA0KICAgICAgICAgICB5ID0gdmFsdWUsIA0KICAgICAgICAgICBjb2xvdXIgPSB2YXJpYWJsZSwgDQogICAgICAgICAgIGdyb3VwID0gdmFyaWFibGUpKSArICAjIGFzc2lnbiBjb2x1bW5zIHRvIGF4ZXMgYW5kIGdyb3Vwcw0KICBnZW9tX2xpbmUoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByZXByZXNlbnQgZGF0YSBhcyBsaW5lcw0KICB4bGFiKCJUaW1lIChkYXlzKSIpKyAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhZGQgbGFiZWwgZm9yIHggYXhpcw0KICB5bGFiKCJOdW1iZXIgb2YgcGVvcGxlIikgKyAgICAgICAgICAgICAgICAgICAgIyBhZGQgbGFiZWwgZm9yIHkgYXhpcw0KICBsYWJzKHRpdGxlID0gcGFzdGUoIk51bWJlciBpbmZlY3RlZCBhbmQgcmVjb3ZlcmVkIG92ZXIgdGltZSB3aGVuIGdhbW1hID0iLA0KICAgICAgICAgICAgICAgICAgICAgIHBhcmFtZXRlcnNbImdhbW1hIl0sImRheXNeLTEiKSkgKyAjIGFkZCB0aXRsZQ0KICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikNCiAgICAgICAgICAgICAgICANCiMgU2luY2UgdGhlIGluaXRpYWwgbnVtYmVyIGluIGVhY2ggY29tcGFydG1lbnQgYW5kIA0KIyB0aGUgdGltZXN0ZXBzIG9mIGludGVyZXN0IGhhdmVuJ3QgY2hhbmdlZCwgDQojIHRoZXNlIGFyZSB0aGUgb25seSBwYXJ0cyBvZiB0aGUgY29kZSB3ZSBuZWVkIHRvIHJlcnVuLg0KDQojIE5vdywgY29weS1wYXN0ZSB5b3VyIHBsb3QgY29kZSBmcm9tIGFib3ZlIGhlcmUgdG8gdmlzdWFsaXNlIHRoZSBvdXRwdXQuDQpgYGANCg0KIyMgV2hhdCBpcyB0aGUgcmVjb3ZlcnkgcmF0ZSBpbiAyMCBkYXlzPw0KYGBge3J9DQpwYXJhbWV0ZXJzIDwtIGMoZ2FtbWEgPSAwLjA1KQ0KDQojIFNvbHZpbmcgdGhlIG1vZGVsDQpvdXRwdXQgPC0gYXMuZGF0YS5mcmFtZShvZGUoeSA9IGluaXRpYWxfc3RhdGVfdmFsdWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lcyA9IHRpbWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jID0gY29ob3J0X21vZGVsLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcm1zID0gcGFyYW1ldGVycykpDQoNCiMgUGxvdHRpbmcgdGhlIG91dHB1dA0Kb3V0cHV0X2xvbmcgPC0gbWVsdChhcy5kYXRhLmZyYW1lKG91dHB1dCksIGlkID0gInRpbWUiKSANCg0KZ2dwbG90KGRhdGEgPSBvdXRwdXRfbG9uZywgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICBhZXMoeCA9IHRpbWUsIA0KICAgICAgICAgICB5ID0gdmFsdWUsIA0KICAgICAgICAgICBjb2xvdXIgPSB2YXJpYWJsZSwgDQogICAgICAgICAgIGdyb3VwID0gdmFyaWFibGUpKSArICAjIGFzc2lnbiBjb2x1bW5zIHRvIGF4ZXMgYW5kIGdyb3Vwcw0KICBnZW9tX2xpbmUoKSArICAgICAgICAgICAgICAgICAgIyByZXByZXNlbnQgZGF0YSBhcyBsaW5lcw0KICB4bGFiKCJUaW1lIChkYXlzKSIpKyAgICAgICAgICAgIyBhZGQgbGFiZWwgZm9yIHggYXhpcw0KICB5bGFiKCJOdW1iZXIgb2YgcGVvcGxlIikgKyAgICAgIyBhZGQgbGFiZWwgZm9yIHkgYXhpcw0KICBsYWJzKHRpdGxlID0gcGFzdGUoIk51bWJlciBpbmZlY3RlZCBhbmQgcmVjb3ZlcmVkIG92ZXIgdGltZSB3aGVuIGdhbW1hID0iLA0KICAgICAgICAgICAgICAgICAgICBwYXJhbWV0ZXJzWyJnYW1tYSJdLCJkYXlzXi0xIikpICMgYWRkIHRpdGxlDQpgYGANCg0KDQojIFF1ZXN0aW9uOiBXaGF0IGNoYW5nZXMgZG8geW91IG9ic2VydmUgaW4gdGhlIHRyYW5zaXRpb24gdG8gdGhlIHJlY292ZXJlZCBjb21wYXJ0bWVudCBpZiAg8J2bviAgaXMgaGlnaGVyIG9yIGxvd2VyPyBGb3IgZXhhbXBsZSwgaG93IGxvbmcgZG9lcyBpdCB0YWtlIGZvciBldmVyeW9uZSB0byByZWNvdmVyIGluIGJvdGggY2FzZXM/DQoNCmBgYHtyfQ0KI0Fuc3dlcjogaWYgdGhlIHJhdGUgaXMgaGlnaGVyICgg8J2bviAgPSAwLjUpLCB3ZSBjYW4gc2VlIHRoYXQgaW5mZWN0ZWQgcGVvcGxlIHJlY292ZXIgbW9yZSBxdWlja2x5OiBpdCB0YWtlcyBsZXNzIHRoYW4gMiBkYXlzIGZvciBoYWxmIG9mIHRoZSBpbmZlY3RlZCBjb2hvcnQgdG8gcmVjb3ZlciwgYW5kIGJ5IGFyb3VuZCA4IGRheXMsIG5lYXJseSBldmVyeW9uZSBoYXMgcmVjb3ZlcmVkLiBBIGxvd2VyIHJhdGUgKCDwnZu+ICA9IDAuMDUpIG9uIHRoZSBvdGhlciBoYW5kIGNvcnJlc3BvbmRzIHRvIGEgc2xvd2VyIHRyYW5zaXRpb246IGl0IHRha2VzIGFyb3VuZCAxNCBkYXlzIGZvciBoYWxmIG9mIGluZmVjdGVkIHBlb3BsZSB0byBtb3ZlIGludG8gdGhlICDwnZGFICBjb21wYXJ0bWVudCwgYW5kIGJ5IHRoZSBlbmQgb2Ygb3VyIDQgd2VlayBmb2xsb3ctdXAgYXJvdW5kIGEgcXVhcnRlciBvZiBwZW9wbGUgc3RpbGwgaGF2ZSBub3QgcmVjb3ZlcmVkLg0KYGBgDQoNCg0KDQoocik6IHNvdXJjZSBmcm9tIGNvdXJzZXJhIGNvdXJzZS4gT25seSBmb3Igc3R1ZHlpbmcgcHVycG9zZSAjaHR0cHM6Ly93d3cuY291cnNlcmEub3JnL2xlYXJuL2RldmVsb3BpbmctdGhlLXNpci1tb2RlbC9ob21lL3dlbGNvbWUNCg==