1 Etivity

In this etivity, we are going back to the simple SIR model from week 3, without births or deaths, to look at the effect of vaccination. The aim of this etivity is to represent vaccination in a very simple way - we are assuming it already happened before we run our model! By changing the initial conditions, we can prepare the population so that it has received a certain coverage of vaccination. Even though this is very simplistic, it will allow us to study some important effects of vaccination on the infection dynamics.

We are starting with the transmission and recovery parameters beta = 0.4 days\(^{-1}\) and gamma = 0.1 days \(^{-1}\). To incorporate immunity from vaccination in the model, we assume that a proportion p of the total population starts in the recovered compartment, representing the vaccine coverage and assuming the vaccine is perfectly effective. Again, we assume the epidemic starts with a single infected case introduced into the population.

Model this scenario for a duration of 2 years, assuming that the vaccine coverage is 50%, and plot the prevalence in each compartment over time. Confirm that you observe an epidemic peaking at around 125 days after introduction of the infectious person in the population. Also have a look at the proportion susceptible and recovered, to double-check this looks like what you would expect given your initial conditions.

1.1 Question: Does everyone in the population need to be vaccinated in order to prevent an epidemic? What do you observe if you model the infection dynamics with different values for p? Can you explain why?

Hopefully, you have seen that once a certain proportion of the population is immune, no epidemic occurs. This is called the critical vaccination threshold or herd immunity threshold.

Now, use your code above to investigate how the herd immunity threshold changes if we are modelling a disease with a different infection and recovery rate.

1.2 Question: What proportion of the population needs to be vaccinated in order to prevent an epidemic if beta = 0.4 and gamma = 0.2 days\(^{-1}\)? What if beta = 0.6 and gamma = 0.1 days\(^{-1}\)?

As you can see, the proportion of the population that needs to be vaccinated varies with different infection-related parameters. Think about why that is so in the context of herd immunity, and what is different between the scenarios you have just modelled.

1.3 Question: Remember that vaccination changes the effective reproduction number, by reducing the number of people who are susceptible. Based on your answers to the previous questions, can you use the formula for the effective reproduction number Reff to derive a formula for calculating the critical vaccination threshold?

2 Solutions - A Simple Model for Vaccination

Modelling a disease where \(\beta\) = 0.4 days\(^{-1}\), \(\gamma\) = 0.1 days \(^{-1}\) and the vaccine coverage p = 0.5

#<img src="../../IDM1/Graphics and Data/w4_nb1_model_diagram.png">
# LOAD THE PACKAGES:
library(deSolve)
library(reshape2)
library(ggplot2)

# MODEL INPUTS:

# Vaccine coverage
p <- 0.5

# Total population size
N <- 10^6

# Vector storing the initial number of people in each compartment (at timestep 0)
initial_state_values <- c(S = (1-p)*(N-1),   # a proportion 1-p of the total population is susceptible
                          I = 1,             # the epidemic starts with a single infected person
                          R = p*(N-1))       # a proportion p of the total population is vaccinated/immune

# Vector storing the parameters describing the transition rates in units of days^-1
parameters <- c(beta = 0.4,      # the infection rate, which acts on susceptibles
                gamma = 0.1)     # the rate of recovery, which acts on those infected

# TIMESTEPS:

# Vector storing the sequence of timesteps to solve the model at
times <- seq(from = 0, to = 730, by = 1)   # from 0 to 730 days in daily intervals

# SIR MODEL FUNCTION: 

# The model function takes as input arguments (in the following order): time, state and parameters
sir_model <- function(time, state, parameters) {  

    with(as.list(c(state, parameters)), {  # tell R to look for variable names within the state and parameters objects    
        
    # Calculating the total population size N (the sum of the number of people in each compartment)
      N <- S+I+R
      
    # Defining lambda as a function of beta and I:
      lambda <- beta * I/N
        
    # The differential equations
      dS <- -lambda * S               # people move out of (-) the S compartment at a rate lambda (force of infection)
      dI <- lambda * S - gamma * I    # people move into (+) the I compartment from S at a rate lambda, 
                                      # and move out of (-) the I compartment at a rate gamma (recovery)
      dR <- gamma * I                 # people move into (+) the R compartment from I at a rate gamma
      
    # Return the number of people in the S, I and R compartments at each timestep 
    # (in the same order as the input state variables)
    return(list(c(dS, dI, dR))) 
    })
  
}

# MODEL OUTPUT (solving the differential equations):

# Solving the differential equations using the ode integration algorithm
output <- as.data.frame(ode(y = initial_state_values, 
                            times = times, 
                            func = sir_model,
                            parms = parameters))

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

# Adding a column for the prevalence proportion to the long-format output
output_long$prevalence <- output_long$value/sum(initial_state_values)

# Plot the prevalence proportion
ggplot(data = output_long,                                               # specify object containing data to plot
       aes(x = time, y = prevalence, 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("Prevalence (proportion)") +                                      # add label for y axis
  labs(colour = "Compartment",                                           # add legend title
       title = "Prevalence of infection, susceptibility and recovery over time")   # add plot title    

Increasing the vaccine coverage to 75%

# MODEL INPUTS:

# Vaccine coverage
p <- 0.75

# Vector storing the initial number of people in each compartment (at timestep 0)
initial_state_values <- c(S = (1-p)*(N-1),   # a proportion 1-p of the total population is susceptible
                          I = 1,             # the epidemic starts with a single infected person
                          R = p*(N-1))       # a proportion p of the total population is vaccinated/immune

# MODEL OUTPUT (solving the differential equations):

# Solving the differential equations using the ode integration algorithm
output <- as.data.frame(ode(y = initial_state_values, 
                            times = times, 
                            func = sir_model,
                            parms = parameters))

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

# Adding a column for the prevalence proportion to the long-format output
output_long$prevalence <- output_long$value/sum(initial_state_values)

# Plot the prevalence proportion
ggplot(data = output_long,                                               # specify object containing data to plot
       aes(x = time, y = prevalence, 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("Prevalence (proportion)") +                                      # add label for y axis
  labs(colour = "Compartment",                                           # add legend title
       title = "Prevalence of infection, susceptibility and recovery over time")   # add plot title    

2.0.1 Does everyone in the population need to be vaccinated in order to prevent an epidemic? What do you observe if you model the infection dynamics with different values for p? Can you explain why?

No, not everyone in the population needs to be vaccinated in order to prevent an epidemic. In this scenario, if p equals 0.75 or higher, no epidemic occurs - 75% is the critical vaccination/herd immunity threshold. Remember, as you heard in week 2, herd immunity describes the phenomenon in which there is sufficient immunity in a population to interrupt transmission. Because of this, not everyone needs to be vaccinated to prevent an outbreak.

2.0.2 What proportion of the population needs to be vaccinated in order to prevent an epidemic if \(\beta\) = 0.4 and \(\gamma\) = 0.2 days\(^{-1}\)? What if \(\beta\) = 0.6 and \(\gamma\) = 0.1 days\(^{-1}\)?

If \(\beta\) = 0.4 and \(\gamma\) = 0.2 days\(^{-1}\), the herd immunity threshold is 50%. If \(\beta\) = 0.6 and \(\gamma\) = 0.1 days\(^{-1}\), the required vaccination coverage is around 83%.

2.0.3 Remember that vaccination changes the effective reproduction number, by reducing the number of people who are susceptible. Based on your answers to the previous questions, can you use the formula for the effective reproduction number Reff to derive a formula for calculating the critical vaccination threshold?

In mathematical modelling terms, herd immunity is just the same as saying that Reff < 1. We can derive the herd immunity threshold by solving the formula for Reff for p when Reff = 1:

\[\begin{align} R_{eff} & = R_{0} \frac{S}{N} \\ R_{eff} & = R_{0} (1-p) \\ p = 1-\frac{1}{R_{0}} \end{align}\]

Remember, we can calculate R0 by dividing \(\beta\) by \(\gamma\).

LS0tDQp0aXRsZTogIkEgc2ltcGxlIG1vZGVsIGZvciB2YWNjaW5hdGlvbiAodzQgU0lSKSINCmF1dGhvcjogIkJJbmggVGhhbmcgVHJhbiINCmRhdGU6ICI1LzI2LzIwMjAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogam91cm5hbA0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgd29yZF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCiMgRXRpdml0eQ0KDQpJbiB0aGlzIGV0aXZpdHksIHdlIGFyZSBnb2luZyBiYWNrIHRvIHRoZSBzaW1wbGUgU0lSIG1vZGVsIGZyb20gd2VlayAzLCB3aXRob3V0IGJpcnRocyBvciBkZWF0aHMsIHRvIGxvb2sgYXQgdGhlIGVmZmVjdCBvZiB2YWNjaW5hdGlvbi4gVGhlIGFpbSBvZiB0aGlzIGV0aXZpdHkgaXMgdG8gcmVwcmVzZW50IHZhY2NpbmF0aW9uIGluIGEgdmVyeSBzaW1wbGUgd2F5IC0gd2UgYXJlIGFzc3VtaW5nIGl0IGFscmVhZHkgaGFwcGVuZWQgYmVmb3JlIHdlIHJ1biBvdXIgbW9kZWwhIEJ5IGNoYW5naW5nIHRoZSBpbml0aWFsIGNvbmRpdGlvbnMsIHdlIGNhbiBwcmVwYXJlIHRoZSBwb3B1bGF0aW9uIHNvIHRoYXQgaXQgaGFzIHJlY2VpdmVkIGEgY2VydGFpbiBjb3ZlcmFnZSBvZiB2YWNjaW5hdGlvbi4gRXZlbiB0aG91Z2ggdGhpcyBpcyB2ZXJ5IHNpbXBsaXN0aWMsIGl0IHdpbGwgYWxsb3cgdXMgdG8gc3R1ZHkgc29tZSBpbXBvcnRhbnQgZWZmZWN0cyBvZiB2YWNjaW5hdGlvbiBvbiB0aGUgaW5mZWN0aW9uIGR5bmFtaWNzLg0KDQpXZSBhcmUgc3RhcnRpbmcgd2l0aCB0aGUgdHJhbnNtaXNzaW9uIGFuZCByZWNvdmVyeSBwYXJhbWV0ZXJzICpiZXRhKiA9IDAuNCBkYXlzJF57LTF9JCBhbmQgKmdhbW1hKiA9IDAuMSBkYXlzICReey0xfSQuIFRvIGluY29ycG9yYXRlIGltbXVuaXR5IGZyb20gdmFjY2luYXRpb24gaW4gdGhlIG1vZGVsLCB3ZSBhc3N1bWUgdGhhdCBhIHByb3BvcnRpb24gKnAqIG9mIHRoZSB0b3RhbCBwb3B1bGF0aW9uIHN0YXJ0cyBpbiB0aGUgcmVjb3ZlcmVkIGNvbXBhcnRtZW50LCByZXByZXNlbnRpbmcgdGhlIHZhY2NpbmUgY292ZXJhZ2UgYW5kIGFzc3VtaW5nIHRoZSB2YWNjaW5lIGlzIHBlcmZlY3RseSBlZmZlY3RpdmUuIEFnYWluLCB3ZSBhc3N1bWUgdGhlIGVwaWRlbWljIHN0YXJ0cyB3aXRoIGEgc2luZ2xlIGluZmVjdGVkIGNhc2UgaW50cm9kdWNlZCBpbnRvIHRoZSBwb3B1bGF0aW9uLg0KDQpNb2RlbCB0aGlzIHNjZW5hcmlvIGZvciBhIGR1cmF0aW9uIG9mIDIgeWVhcnMsIGFzc3VtaW5nIHRoYXQgdGhlIHZhY2NpbmUgY292ZXJhZ2UgaXMgNTAlLCBhbmQgcGxvdCB0aGUgcHJldmFsZW5jZSBpbiBlYWNoIGNvbXBhcnRtZW50IG92ZXIgdGltZS4gQ29uZmlybSB0aGF0IHlvdSBvYnNlcnZlIGFuIGVwaWRlbWljIHBlYWtpbmcgYXQgYXJvdW5kIDEyNSBkYXlzIGFmdGVyIGludHJvZHVjdGlvbiBvZiB0aGUgaW5mZWN0aW91cyBwZXJzb24gaW4gdGhlIHBvcHVsYXRpb24uIEFsc28gaGF2ZSBhIGxvb2sgYXQgdGhlIHByb3BvcnRpb24gc3VzY2VwdGlibGUgYW5kIHJlY292ZXJlZCwgdG8gZG91YmxlLWNoZWNrIHRoaXMgbG9va3MgbGlrZSB3aGF0IHlvdSB3b3VsZCBleHBlY3QgZ2l2ZW4geW91ciBpbml0aWFsIGNvbmRpdGlvbnMuDQoNCiMjIFF1ZXN0aW9uOiBEb2VzIGV2ZXJ5b25lIGluIHRoZSBwb3B1bGF0aW9uIG5lZWQgdG8gYmUgdmFjY2luYXRlZCBpbiBvcmRlciB0byBwcmV2ZW50IGFuIGVwaWRlbWljPyBXaGF0IGRvIHlvdSBvYnNlcnZlIGlmIHlvdSBtb2RlbCB0aGUgaW5mZWN0aW9uIGR5bmFtaWNzIHdpdGggZGlmZmVyZW50IHZhbHVlcyBmb3IgKnAqPyBDYW4geW91IGV4cGxhaW4gd2h5Pw0KDQpIb3BlZnVsbHksIHlvdSBoYXZlIHNlZW4gdGhhdCBvbmNlIGEgY2VydGFpbiBwcm9wb3J0aW9uIG9mIHRoZSBwb3B1bGF0aW9uIGlzIGltbXVuZSwgbm8gZXBpZGVtaWMgb2NjdXJzLiBUaGlzIGlzIGNhbGxlZCB0aGUgKipjcml0aWNhbCB2YWNjaW5hdGlvbiB0aHJlc2hvbGQqKiBvciAqKmhlcmQgaW1tdW5pdHkgdGhyZXNob2xkKiouDQoNCk5vdywgdXNlIHlvdXIgY29kZSBhYm92ZSB0byBpbnZlc3RpZ2F0ZSBob3cgdGhlIGhlcmQgaW1tdW5pdHkgdGhyZXNob2xkIGNoYW5nZXMgaWYgd2UgYXJlIG1vZGVsbGluZyBhIGRpc2Vhc2Ugd2l0aCBhIGRpZmZlcmVudCBpbmZlY3Rpb24gYW5kIHJlY292ZXJ5IHJhdGUuIA0KDQojIyBRdWVzdGlvbjogV2hhdCBwcm9wb3J0aW9uIG9mIHRoZSBwb3B1bGF0aW9uIG5lZWRzIHRvIGJlIHZhY2NpbmF0ZWQgaW4gb3JkZXIgdG8gcHJldmVudCBhbiBlcGlkZW1pYyBpZiAqYmV0YSogPSAwLjQgYW5kICpnYW1tYSogPSAwLjIgZGF5cyReey0xfSQ/IFdoYXQgaWYgKmJldGEqID0gMC42IGFuZCAqZ2FtbWEqID0gMC4xIGRheXMkXnstMX0kPw0KDQpBcyB5b3UgY2FuIHNlZSwgdGhlIHByb3BvcnRpb24gb2YgdGhlIHBvcHVsYXRpb24gdGhhdCBuZWVkcyB0byBiZSB2YWNjaW5hdGVkIHZhcmllcyB3aXRoIGRpZmZlcmVudCBpbmZlY3Rpb24tcmVsYXRlZCBwYXJhbWV0ZXJzLiBUaGluayBhYm91dCB3aHkgdGhhdCBpcyBzbyBpbiB0aGUgY29udGV4dCBvZiBoZXJkIGltbXVuaXR5LCBhbmQgd2hhdCBpcyBkaWZmZXJlbnQgYmV0d2VlbiB0aGUgc2NlbmFyaW9zIHlvdSBoYXZlIGp1c3QgbW9kZWxsZWQuIA0KDQojIyBRdWVzdGlvbjogUmVtZW1iZXIgdGhhdCB2YWNjaW5hdGlvbiBjaGFuZ2VzIHRoZSBlZmZlY3RpdmUgcmVwcm9kdWN0aW9uIG51bWJlciwgYnkgcmVkdWNpbmcgdGhlIG51bWJlciBvZiBwZW9wbGUgd2hvIGFyZSBzdXNjZXB0aWJsZS4gQmFzZWQgb24geW91ciBhbnN3ZXJzIHRvIHRoZSBwcmV2aW91cyBxdWVzdGlvbnMsIGNhbiB5b3UgdXNlIHRoZSBmb3JtdWxhIGZvciB0aGUgZWZmZWN0aXZlIHJlcHJvZHVjdGlvbiBudW1iZXIgUjxzdWI+ZWZmPC9zdWI+IHRvIGRlcml2ZSBhIGZvcm11bGEgZm9yIGNhbGN1bGF0aW5nIHRoZSBjcml0aWNhbCB2YWNjaW5hdGlvbiB0aHJlc2hvbGQ/DQoNCg0KDQoNCiMgU29sdXRpb25zIC0gQSBTaW1wbGUgTW9kZWwgZm9yIFZhY2NpbmF0aW9uDQoNCiBNb2RlbGxpbmcgYSBkaXNlYXNlIHdoZXJlICRcYmV0YSQgPSAwLjQgZGF5cyReey0xfSQsICRcZ2FtbWEkID0gMC4xIGRheXMgJF57LTF9JCBhbmQgdGhlIHZhY2NpbmUgY292ZXJhZ2UgKnAqID0gMC41DQogDQpgYGB7cn0NCiM8aW1nIHNyYz0iLi4vLi4vSURNMS9HcmFwaGljcyBhbmQgRGF0YS93NF9uYjFfbW9kZWxfZGlhZ3JhbS5wbmciPg0KYGBgDQogDQogDQpgYGB7cn0NCiMgTE9BRCBUSEUgUEFDS0FHRVM6DQpsaWJyYXJ5KGRlU29sdmUpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIE1PREVMIElOUFVUUzoNCg0KIyBWYWNjaW5lIGNvdmVyYWdlDQpwIDwtIDAuNQ0KDQojIFRvdGFsIHBvcHVsYXRpb24gc2l6ZQ0KTiA8LSAxMF42DQoNCiMgVmVjdG9yIHN0b3JpbmcgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHBlb3BsZSBpbiBlYWNoIGNvbXBhcnRtZW50IChhdCB0aW1lc3RlcCAwKQ0KaW5pdGlhbF9zdGF0ZV92YWx1ZXMgPC0gYyhTID0gKDEtcCkqKE4tMSksICAgIyBhIHByb3BvcnRpb24gMS1wIG9mIHRoZSB0b3RhbCBwb3B1bGF0aW9uIGlzIHN1c2NlcHRpYmxlDQogICAgICAgICAgICAgICAgICAgICAgICAgIEkgPSAxLCAgICAgICAgICAgICAjIHRoZSBlcGlkZW1pYyBzdGFydHMgd2l0aCBhIHNpbmdsZSBpbmZlY3RlZCBwZXJzb24NCiAgICAgICAgICAgICAgICAgICAgICAgICAgUiA9IHAqKE4tMSkpICAgICAgICMgYSBwcm9wb3J0aW9uIHAgb2YgdGhlIHRvdGFsIHBvcHVsYXRpb24gaXMgdmFjY2luYXRlZC9pbW11bmUNCg0KIyBWZWN0b3Igc3RvcmluZyB0aGUgcGFyYW1ldGVycyBkZXNjcmliaW5nIHRoZSB0cmFuc2l0aW9uIHJhdGVzIGluIHVuaXRzIG9mIGRheXNeLTENCnBhcmFtZXRlcnMgPC0gYyhiZXRhID0gMC40LCAgICAgICMgdGhlIGluZmVjdGlvbiByYXRlLCB3aGljaCBhY3RzIG9uIHN1c2NlcHRpYmxlcw0KICAgICAgICAgICAgICAgIGdhbW1hID0gMC4xKSAgICAgIyB0aGUgcmF0ZSBvZiByZWNvdmVyeSwgd2hpY2ggYWN0cyBvbiB0aG9zZSBpbmZlY3RlZA0KDQojIFRJTUVTVEVQUzoNCg0KIyBWZWN0b3Igc3RvcmluZyB0aGUgc2VxdWVuY2Ugb2YgdGltZXN0ZXBzIHRvIHNvbHZlIHRoZSBtb2RlbCBhdA0KdGltZXMgPC0gc2VxKGZyb20gPSAwLCB0byA9IDczMCwgYnkgPSAxKSAgICMgZnJvbSAwIHRvIDczMCBkYXlzIGluIGRhaWx5IGludGVydmFscw0KDQojIFNJUiBNT0RFTCBGVU5DVElPTjogDQoNCiMgVGhlIG1vZGVsIGZ1bmN0aW9uIHRha2VzIGFzIGlucHV0IGFyZ3VtZW50cyAoaW4gdGhlIGZvbGxvd2luZyBvcmRlcik6IHRpbWUsIHN0YXRlIGFuZCBwYXJhbWV0ZXJzDQpzaXJfbW9kZWwgPC0gZnVuY3Rpb24odGltZSwgc3RhdGUsIHBhcmFtZXRlcnMpIHsgIA0KDQogICAgd2l0aChhcy5saXN0KGMoc3RhdGUsIHBhcmFtZXRlcnMpKSwgeyAgIyB0ZWxsIFIgdG8gbG9vayBmb3IgdmFyaWFibGUgbmFtZXMgd2l0aGluIHRoZSBzdGF0ZSBhbmQgcGFyYW1ldGVycyBvYmplY3RzICAgIA0KICAgICAgICANCiAgICAjIENhbGN1bGF0aW5nIHRoZSB0b3RhbCBwb3B1bGF0aW9uIHNpemUgTiAodGhlIHN1bSBvZiB0aGUgbnVtYmVyIG9mIHBlb3BsZSBpbiBlYWNoIGNvbXBhcnRtZW50KQ0KICAgICAgTiA8LSBTK0krUg0KICAgICAgDQogICAgIyBEZWZpbmluZyBsYW1iZGEgYXMgYSBmdW5jdGlvbiBvZiBiZXRhIGFuZCBJOg0KICAgICAgbGFtYmRhIDwtIGJldGEgKiBJL04NCiAgICAgICAgDQogICAgIyBUaGUgZGlmZmVyZW50aWFsIGVxdWF0aW9ucw0KICAgICAgZFMgPC0gLWxhbWJkYSAqIFMgICAgICAgICAgICAgICAjIHBlb3BsZSBtb3ZlIG91dCBvZiAoLSkgdGhlIFMgY29tcGFydG1lbnQgYXQgYSByYXRlIGxhbWJkYSAoZm9yY2Ugb2YgaW5mZWN0aW9uKQ0KICAgICAgZEkgPC0gbGFtYmRhICogUyAtIGdhbW1hICogSSAgICAjIHBlb3BsZSBtb3ZlIGludG8gKCspIHRoZSBJIGNvbXBhcnRtZW50IGZyb20gUyBhdCBhIHJhdGUgbGFtYmRhLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhbmQgbW92ZSBvdXQgb2YgKC0pIHRoZSBJIGNvbXBhcnRtZW50IGF0IGEgcmF0ZSBnYW1tYSAocmVjb3ZlcnkpDQogICAgICBkUiA8LSBnYW1tYSAqIEkgICAgICAgICAgICAgICAgICMgcGVvcGxlIG1vdmUgaW50byAoKykgdGhlIFIgY29tcGFydG1lbnQgZnJvbSBJIGF0IGEgcmF0ZSBnYW1tYQ0KICAgICAgDQogICAgIyBSZXR1cm4gdGhlIG51bWJlciBvZiBwZW9wbGUgaW4gdGhlIFMsIEkgYW5kIFIgY29tcGFydG1lbnRzIGF0IGVhY2ggdGltZXN0ZXAgDQogICAgIyAoaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhlIGlucHV0IHN0YXRlIHZhcmlhYmxlcykNCiAgICByZXR1cm4obGlzdChjKGRTLCBkSSwgZFIpKSkgDQogICAgfSkNCiAgDQp9DQoNCiMgTU9ERUwgT1VUUFVUIChzb2x2aW5nIHRoZSBkaWZmZXJlbnRpYWwgZXF1YXRpb25zKToNCg0KIyBTb2x2aW5nIHRoZSBkaWZmZXJlbnRpYWwgZXF1YXRpb25zIHVzaW5nIHRoZSBvZGUgaW50ZWdyYXRpb24gYWxnb3JpdGhtDQpvdXRwdXQgPC0gYXMuZGF0YS5mcmFtZShvZGUoeSA9IGluaXRpYWxfc3RhdGVfdmFsdWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lcyA9IHRpbWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jID0gc2lyX21vZGVsLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcm1zID0gcGFyYW1ldGVycykpDQoNCm91dHB1dF9sb25nIDwtIG1lbHQoYXMuZGF0YS5mcmFtZShvdXRwdXQpLCBpZCA9ICJ0aW1lIikgICAgICAgICAgICAgICAgICAjIHR1cm4gb3V0cHV0IGRhdGFzZXQgaW50byBsb25nIGZvcm1hdA0KDQojIEFkZGluZyBhIGNvbHVtbiBmb3IgdGhlIHByZXZhbGVuY2UgcHJvcG9ydGlvbiB0byB0aGUgbG9uZy1mb3JtYXQgb3V0cHV0DQpvdXRwdXRfbG9uZyRwcmV2YWxlbmNlIDwtIG91dHB1dF9sb25nJHZhbHVlL3N1bShpbml0aWFsX3N0YXRlX3ZhbHVlcykNCg0KIyBQbG90IHRoZSBwcmV2YWxlbmNlIHByb3BvcnRpb24NCmdncGxvdChkYXRhID0gb3V0cHV0X2xvbmcsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNwZWNpZnkgb2JqZWN0IGNvbnRhaW5pbmcgZGF0YSB0byBwbG90DQogICAgICAgYWVzKHggPSB0aW1lLCB5ID0gcHJldmFsZW5jZSwgY29sb3VyID0gdmFyaWFibGUsIGdyb3VwID0gdmFyaWFibGUpKSArICAjIGFzc2lnbiBjb2x1bW5zIHRvIGF4ZXMgYW5kIGdyb3Vwcw0KICBnZW9tX2xpbmUoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcmVwcmVzZW50IGRhdGEgYXMgbGluZXMNCiAgeGxhYigiVGltZSAoZGF5cykiKSsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGFkZCBsYWJlbCBmb3IgeCBheGlzDQogIHlsYWIoIlByZXZhbGVuY2UgKHByb3BvcnRpb24pIikgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhZGQgbGFiZWwgZm9yIHkgYXhpcw0KICBsYWJzKGNvbG91ciA9ICJDb21wYXJ0bWVudCIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYWRkIGxlZ2VuZCB0aXRsZQ0KICAgICAgIHRpdGxlID0gIlByZXZhbGVuY2Ugb2YgaW5mZWN0aW9uLCBzdXNjZXB0aWJpbGl0eSBhbmQgcmVjb3Zlcnkgb3ZlciB0aW1lIikgICAjIGFkZCBwbG90IHRpdGxlICAgIA0KYGBgDQoNCioqSW5jcmVhc2luZyB0aGUgdmFjY2luZSBjb3ZlcmFnZSB0byA3NSUqKg0KDQpgYGB7cn0NCiMgTU9ERUwgSU5QVVRTOg0KDQojIFZhY2NpbmUgY292ZXJhZ2UNCnAgPC0gMC43NQ0KDQojIFZlY3RvciBzdG9yaW5nIHRoZSBpbml0aWFsIG51bWJlciBvZiBwZW9wbGUgaW4gZWFjaCBjb21wYXJ0bWVudCAoYXQgdGltZXN0ZXAgMCkNCmluaXRpYWxfc3RhdGVfdmFsdWVzIDwtIGMoUyA9ICgxLXApKihOLTEpLCAgICMgYSBwcm9wb3J0aW9uIDEtcCBvZiB0aGUgdG90YWwgcG9wdWxhdGlvbiBpcyBzdXNjZXB0aWJsZQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBJID0gMSwgICAgICAgICAgICAgIyB0aGUgZXBpZGVtaWMgc3RhcnRzIHdpdGggYSBzaW5nbGUgaW5mZWN0ZWQgcGVyc29uDQogICAgICAgICAgICAgICAgICAgICAgICAgIFIgPSBwKihOLTEpKSAgICAgICAjIGEgcHJvcG9ydGlvbiBwIG9mIHRoZSB0b3RhbCBwb3B1bGF0aW9uIGlzIHZhY2NpbmF0ZWQvaW1tdW5lDQoNCiMgTU9ERUwgT1VUUFVUIChzb2x2aW5nIHRoZSBkaWZmZXJlbnRpYWwgZXF1YXRpb25zKToNCg0KIyBTb2x2aW5nIHRoZSBkaWZmZXJlbnRpYWwgZXF1YXRpb25zIHVzaW5nIHRoZSBvZGUgaW50ZWdyYXRpb24gYWxnb3JpdGhtDQpvdXRwdXQgPC0gYXMuZGF0YS5mcmFtZShvZGUoeSA9IGluaXRpYWxfc3RhdGVfdmFsdWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lcyA9IHRpbWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jID0gc2lyX21vZGVsLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcm1zID0gcGFyYW1ldGVycykpDQoNCm91dHB1dF9sb25nIDwtIG1lbHQoYXMuZGF0YS5mcmFtZShvdXRwdXQpLCBpZCA9ICJ0aW1lIikgICAgICAgICAgICAgICAgICAjIHR1cm4gb3V0cHV0IGRhdGFzZXQgaW50byBsb25nIGZvcm1hdA0KDQojIEFkZGluZyBhIGNvbHVtbiBmb3IgdGhlIHByZXZhbGVuY2UgcHJvcG9ydGlvbiB0byB0aGUgbG9uZy1mb3JtYXQgb3V0cHV0DQpvdXRwdXRfbG9uZyRwcmV2YWxlbmNlIDwtIG91dHB1dF9sb25nJHZhbHVlL3N1bShpbml0aWFsX3N0YXRlX3ZhbHVlcykNCg0KIyBQbG90IHRoZSBwcmV2YWxlbmNlIHByb3BvcnRpb24NCmdncGxvdChkYXRhID0gb3V0cHV0X2xvbmcsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNwZWNpZnkgb2JqZWN0IGNvbnRhaW5pbmcgZGF0YSB0byBwbG90DQogICAgICAgYWVzKHggPSB0aW1lLCB5ID0gcHJldmFsZW5jZSwgY29sb3VyID0gdmFyaWFibGUsIGdyb3VwID0gdmFyaWFibGUpKSArICAjIGFzc2lnbiBjb2x1bW5zIHRvIGF4ZXMgYW5kIGdyb3Vwcw0KICBnZW9tX2xpbmUoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcmVwcmVzZW50IGRhdGEgYXMgbGluZXMNCiAgeGxhYigiVGltZSAoZGF5cykiKSsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGFkZCBsYWJlbCBmb3IgeCBheGlzDQogIHlsYWIoIlByZXZhbGVuY2UgKHByb3BvcnRpb24pIikgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhZGQgbGFiZWwgZm9yIHkgYXhpcw0KICBsYWJzKGNvbG91ciA9ICJDb21wYXJ0bWVudCIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgYWRkIGxlZ2VuZCB0aXRsZQ0KICAgICAgIHRpdGxlID0gIlByZXZhbGVuY2Ugb2YgaW5mZWN0aW9uLCBzdXNjZXB0aWJpbGl0eSBhbmQgcmVjb3Zlcnkgb3ZlciB0aW1lIikgICAjIGFkZCBwbG90IHRpdGxlICAgIA0KYGBgDQoNCg0KIyMjIERvZXMgZXZlcnlvbmUgaW4gdGhlIHBvcHVsYXRpb24gbmVlZCB0byBiZSB2YWNjaW5hdGVkIGluIG9yZGVyIHRvIHByZXZlbnQgYW4gZXBpZGVtaWM/IFdoYXQgZG8geW91IG9ic2VydmUgaWYgeW91IG1vZGVsIHRoZSBpbmZlY3Rpb24gZHluYW1pY3Mgd2l0aCBkaWZmZXJlbnQgdmFsdWVzIGZvciAqcCo/IENhbiB5b3UgZXhwbGFpbiB3aHk/DQoNCk5vLCBub3QgZXZlcnlvbmUgaW4gdGhlIHBvcHVsYXRpb24gbmVlZHMgdG8gYmUgdmFjY2luYXRlZCBpbiBvcmRlciB0byBwcmV2ZW50IGFuIGVwaWRlbWljLiBJbiB0aGlzIHNjZW5hcmlvLCBpZiAqcCogZXF1YWxzIDAuNzUgb3IgaGlnaGVyLCBubyBlcGlkZW1pYyBvY2N1cnMgLSA3NSUgaXMgdGhlIGNyaXRpY2FsIHZhY2NpbmF0aW9uL2hlcmQgaW1tdW5pdHkgdGhyZXNob2xkLiBSZW1lbWJlciwgYXMgeW91IGhlYXJkIGluIHdlZWsgMiwgaGVyZCBpbW11bml0eSBkZXNjcmliZXMgdGhlIHBoZW5vbWVub24gaW4gd2hpY2ggdGhlcmUgaXMgc3VmZmljaWVudCBpbW11bml0eSBpbiBhIHBvcHVsYXRpb24gdG8gaW50ZXJydXB0IHRyYW5zbWlzc2lvbi4gQmVjYXVzZSBvZiB0aGlzLCBub3QgZXZlcnlvbmUgbmVlZHMgdG8gYmUgdmFjY2luYXRlZCB0byBwcmV2ZW50IGFuIG91dGJyZWFrLg0KDQoNCiMjIyBXaGF0IHByb3BvcnRpb24gb2YgdGhlIHBvcHVsYXRpb24gbmVlZHMgdG8gYmUgdmFjY2luYXRlZCBpbiBvcmRlciB0byBwcmV2ZW50IGFuIGVwaWRlbWljIGlmICRcYmV0YSQgPSAwLjQgYW5kICRcZ2FtbWEkID0gMC4yIGRheXMkXnstMX0kPyBXaGF0IGlmICRcYmV0YSQgPSAwLjYgYW5kICRcZ2FtbWEkID0gMC4xIGRheXMkXnstMX0kPw0KDQpJZiAkXGJldGEkID0gMC40IGFuZCAkXGdhbW1hJCA9IDAuMiBkYXlzJF57LTF9JCwgdGhlIGhlcmQgaW1tdW5pdHkgdGhyZXNob2xkIGlzIDUwJS4gSWYgJFxiZXRhJCA9IDAuNiBhbmQgJFxnYW1tYSQgPSAwLjEgZGF5cyReey0xfSQsIHRoZSByZXF1aXJlZCB2YWNjaW5hdGlvbiBjb3ZlcmFnZSBpcyBhcm91bmQgODMlLg0KDQojIyMgUmVtZW1iZXIgdGhhdCB2YWNjaW5hdGlvbiBjaGFuZ2VzIHRoZSBlZmZlY3RpdmUgcmVwcm9kdWN0aW9uIG51bWJlciwgYnkgcmVkdWNpbmcgdGhlIG51bWJlciBvZiBwZW9wbGUgd2hvIGFyZSBzdXNjZXB0aWJsZS4gQmFzZWQgb24geW91ciBhbnN3ZXJzIHRvIHRoZSBwcmV2aW91cyBxdWVzdGlvbnMsIGNhbiB5b3UgdXNlIHRoZSBmb3JtdWxhIGZvciB0aGUgZWZmZWN0aXZlIHJlcHJvZHVjdGlvbiBudW1iZXIgUjxzdWI+ZWZmPC9zdWI+IHRvIGRlcml2ZSBhIGZvcm11bGEgZm9yIGNhbGN1bGF0aW5nIHRoZSBjcml0aWNhbCB2YWNjaW5hdGlvbiB0aHJlc2hvbGQ/DQoNCkluIG1hdGhlbWF0aWNhbCBtb2RlbGxpbmcgdGVybXMsIGhlcmQgaW1tdW5pdHkgaXMganVzdCB0aGUgc2FtZSBhcyBzYXlpbmcgdGhhdCBSPHN1Yj5lZmY8L3N1Yj4gPCAxLiBXZSBjYW4gZGVyaXZlIHRoZSBoZXJkIGltbXVuaXR5IHRocmVzaG9sZCBieSBzb2x2aW5nIHRoZSBmb3JtdWxhIGZvciBSPHN1Yj5lZmY8L3N1Yj4gZm9yICpwKiB3aGVuIFI8c3ViPmVmZjwvc3ViPiA9IDE6DQoNClxiZWdpbnthbGlnbn0NClJfe2VmZn0gJiA9IFJfezB9IFxmcmFje1N9e059IFxcDQpSX3tlZmZ9ICYgPSBSX3swfSAoMS1wKSBcXA0KcCA9IDEtXGZyYWN7MX17Ul97MH19DQpcZW5ke2FsaWdufQ0KDQpSZW1lbWJlciwgd2UgY2FuIGNhbGN1bGF0ZSBSPHN1Yj4wPC9zdWI+IGJ5IGRpdmlkaW5nICRcYmV0YSQgYnkgJFxnYW1tYSQuDQo=