Introduction

In the realm of epidemiology and public health, understanding social mixing patterns is critical for developing effective strategies to control the spread of infectious diseases. Social mixing matrices provide a structured framework for quantifying interactions between different demographic groups within a population, enabling the simulation of disease transmission dynamics. This document focuses on constructing a social mixing matrix for Vietnam, with a specific emphasis on interactions between different age groups. Given the limited availability of detailed data, our efforts concentrate on elucidating the patterns of social mixing between various age cohorts within the Vietnamese population. By delineating these interactions, we aim to provide valuable insights into the dynamics of disease transmission and inform the design of targeted public health interventions in Vietnam.

The study conducted a diary-based survey in North Vietnam (2007) to explore social contact patterns, crucial for infectious disease spread modeling. It utilized generalized estimating equations, accounting for household sampling and demographic weighting towards the Vietnamese population. Key findings include assortative mixing by age and differences in contact intensity within household and community settings compared to European data. The study emphasizes the importance of context-specific data for accurate infectious disease modeling, particularly in developing countries. For a detailed understanding of the methods and results, please refer to the full article here.

Using R and available packages

This work will use socialmixr package and conmat.

Firstly, load the package socialmixr and required packges

Then load the data from the social contact matrix survey of Horby et. al (2011), available on Zenodo.

The survey object returns a dictionary with contacts and participants datatable

Participants dataframe:

summary(vietnam$participants)
   part_id             hh_id              part_age     part_gender        part_occupation_detail    country       hh_size      sday_id       
 Length:865         Length:865         Min.   : 0.00   Length:865         Length:865             Vietnam:865   Min.   :1.000   Mode:logical  
 Class :character   Class :character   1st Qu.:14.00   Class :character   Class :character                     1st Qu.:3.000   NA's:865      
 Mode  :character   Mode  :character   Median :29.00   Mode  :character   Mode  :character                     Median :4.000                 
                                       Mean   :30.52                                                           Mean   :3.918                 
                                       3rd Qu.:45.00                                                           3rd Qu.:5.000                 
                                       Max.   :90.00                                                           Max.   :9.000                 
                                                                                                                                             
   day           month              year        dayofweek    
 Mode:logical   Mode:logical   Min.   :2007   Min.   :0.000  
 NA's:865       NA's:865       1st Qu.:2007   1st Qu.:3.000  
                               Median :2007   Median :3.000  
                               Mean   :2007   Mean   :3.451  
                               3rd Qu.:2007   3rd Qu.:4.000  
                               Max.   :2007   Max.   :6.000  
                                              NA's   :6      

Contact dataframe:

summary(vietnam$contacts)
   part_id            cont_id          cnt_age_exact  cnt_age_est_min cnt_age_est_max  cnt_gender         cnt_home        cnt_work      
 Length:6675        Length:6675        Mode:logical   Min.   : 0.00   Min.   :  5.0   Length:6675        Mode :logical   Mode :logical  
 Class :character   Class :character   NA's:6675      1st Qu.: 6.00   1st Qu.: 15.0   Class :character   FALSE:2317      FALSE:6009     
 Mode  :character   Mode  :character                  Median :26.00   Median : 34.0   Mode  :character   TRUE :4358      TRUE :666      
                                                      Mean   :25.95   Mean   : 37.7                                                     
                                                      3rd Qu.:35.00   3rd Qu.: 49.0                                                     
                                                      Max.   :65.00   Max.   :100.0                                                     
                                                                                                                                        
 cnt_school      cnt_transport   cnt_leisure     cnt_otherplace  frequency_multi  phys_contact   duration_multi 
 Mode :logical   Mode :logical   Mode :logical   Mode :logical   Min.   :1.000   Min.   :1.000   Min.   :1.000  
 FALSE:5827      FALSE:6435      FALSE:6564      FALSE:6366      1st Qu.:1.000   1st Qu.:1.000   1st Qu.:3.000  
 TRUE :848       TRUE :240       TRUE :111       TRUE :309       Median :1.000   Median :2.000   Median :5.000  
                                                                 Mean   :1.217   Mean   :1.678   Mean   :3.766  
                                                                 3rd Qu.:1.000   3rd Qu.:2.000   3rd Qu.:5.000  
                                                                 Max.   :5.000   Max.   :2.000   Max.   :5.000  
                                                                 NA's   :139     NA's   :652     NA's   :103    

Creating a contact matrix object:

The contact_matrix function in R is used to construct contact matrices from survey data. Specifically, it allows customization of age groups, weighting by age, and applying various filters to refine the analysis. Input is survey data from Vietnam with age limits of (0,5,15,35,50,70) and weighting by age enabled (weigh.age = TRUE), taking into account the age distribution of the population and computes the mean of contacts per day for each age group. For detailed usage and argument explanations, please refer to the documentation.

mr <- vncm$matrix
mr
      contact.age.group
           [0,5)    [5,15)  [15,35)  [35,50)   [50,70)        70+
  [1,] 1.0081382 1.0345059 2.679943 1.015341 0.4792535 0.06372883
  [2,] 0.4333715 3.6475693 1.559493 1.266675 0.3174873 0.17016764
  [3,] 0.5748874 0.7985706 3.030877 1.438238 0.7411519 0.19228457
  [4,] 0.4100289 1.2210695 2.707548 2.775660 1.2706702 0.46192042
  [5,] 0.3516335 0.5560628 2.534982 2.308633 2.5107631 0.79998885
  [6,] 0.1091823 0.6959308 1.535690 1.959661 1.8679943 1.20843314

Plotting the matrix:

matrix_plot(mr, main = "Contact matrix")

Then we use bootstrapfor 1000 times:

mb <- Reduce("+", lapply(m["matrix", ], function(x) x / ncol(m)))
matrix_plot(mb, main = "Contact matrix using 1000-time bootstrap")

Comparing two matrices:

dm <- mr - mb
matrix_plot(dm, main = "Difference between two contact matrices")

Use conmat:

#| warning: false
popM1= read_csv("popM.csv")
Rows: 5229 Columns: 18── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): name, age
dbl (16): country_code, 1950, 1955, 1960, 1965, 1970, 1975, 1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
popF1= read_csv("popF.csv")
Rows: 5229 Columns: 18── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): name, age
dbl (16): country_code, 1950, 1955, 1960, 1965, 1970, 1975, 1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
vnpopM = popM1 %>% filter(name=='Viet Nam')
vnpopF = popF1 %>% filter(name=='Viet Nam')

combine_and_transform <- function(dfM, dfF) {
  combined_df <- bind_rows(dfM, dfF) %>%
    mutate(lower.age.limit = case_when(
      age == "100+" ~ as.integer(100),  # Handle the "100+" case explicitly as integer
      TRUE ~ as.integer(as.numeric(sub("^(\\d+)-.*", "\\1", age)))  # Convert other cases to integer
    ),
    country = "Viet Nam",  # Add the country column
    year = 2020,  # Add the year column
    population = `2020`) %>%  # Use the "2020" column for population
    # Group by the new `lower.age.limit` (now an integer) and sum the populations
    group_by(lower.age.limit) %>%
    summarise(population = sum(population, na.rm = TRUE),
              country = first(country),
              year = first(year)) %>%
    ungroup() %>%
    select(country, lower.age.limit, year, population)  # Arrange the columns as desired
  
  return(combined_df)
}
# Assuming `vnpopM` and `vnpopF` are your male and female dataframes
final_dataset <- combine_and_transform(vnpopM, vnpopF)

# Display the transformed dataset
final_dataset$population = final_dataset$population * 1000

Genereting matrix using polymod:

polymod_survey_data <- get_polymod_population()
polymod_contact_data <- get_polymod_contact_data()

contact_model <- fit_single_contact_model(
  contact_data <- polymod_contact_data,
  population <- polymod_survey_data
)
#vnp <-wpp_age("Vietnam", 2020)
vn_2020_pop <- as_conmat_population(
  data = final_dataset,
  age = lower.age.limit,
  population = population
)

synthetic_contact_matrix = predict_contacts(
  model = contact_model,
  population = vn_2020_pop,
  age_breaks = c(0,5,15,35,50,70, Inf)
)

df_wide <- synthetic_contact_matrix %>% 
  pivot_wider(names_from = age_group_to, values_from = contacts)

# Convert to matrix, excluding the first column which contains the row names
contact_matrix <- as.matrix(df_wide[, -1])

# Set the row names of the matrix to be the first column of df_wide
row.names(contact_matrix) <- df_wide$age_group_from
matrix_plot(contact_matrix, main = "Contact matrix from conmat")

LS0tCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAotLS0KIyMgSW50cm9kdWN0aW9uCgpJbiB0aGUgcmVhbG0gb2YgZXBpZGVtaW9sb2d5IGFuZCBwdWJsaWMgaGVhbHRoLCB1bmRlcnN0YW5kaW5nIHNvY2lhbCBtaXhpbmcgcGF0dGVybnMgaXMgY3JpdGljYWwgZm9yIGRldmVsb3BpbmcgZWZmZWN0aXZlIHN0cmF0ZWdpZXMgdG8gY29udHJvbCB0aGUgc3ByZWFkIG9mIGluZmVjdGlvdXMgZGlzZWFzZXMuIFNvY2lhbCBtaXhpbmcgbWF0cmljZXMgcHJvdmlkZSBhIHN0cnVjdHVyZWQgZnJhbWV3b3JrIGZvciBxdWFudGlmeWluZyBpbnRlcmFjdGlvbnMgYmV0d2VlbiBkaWZmZXJlbnQgZGVtb2dyYXBoaWMgZ3JvdXBzIHdpdGhpbiBhIHBvcHVsYXRpb24sIGVuYWJsaW5nIHRoZSBzaW11bGF0aW9uIG9mIGRpc2Vhc2UgdHJhbnNtaXNzaW9uIGR5bmFtaWNzLiBUaGlzIGRvY3VtZW50IGZvY3VzZXMgb24gY29uc3RydWN0aW5nIGEgc29jaWFsIG1peGluZyBtYXRyaXggZm9yIFZpZXRuYW0sIHdpdGggYSBzcGVjaWZpYyBlbXBoYXNpcyBvbiBpbnRlcmFjdGlvbnMgYmV0d2VlbiBkaWZmZXJlbnQgYWdlIGdyb3Vwcy4gR2l2ZW4gdGhlIGxpbWl0ZWQgYXZhaWxhYmlsaXR5IG9mIGRldGFpbGVkIGRhdGEsIG91ciBlZmZvcnRzIGNvbmNlbnRyYXRlIG9uIGVsdWNpZGF0aW5nIHRoZSBwYXR0ZXJucyBvZiBzb2NpYWwgbWl4aW5nIGJldHdlZW4gdmFyaW91cyBhZ2UgY29ob3J0cyB3aXRoaW4gdGhlIFZpZXRuYW1lc2UgcG9wdWxhdGlvbi4gQnkgZGVsaW5lYXRpbmcgdGhlc2UgaW50ZXJhY3Rpb25zLCB3ZSBhaW0gdG8gcHJvdmlkZSB2YWx1YWJsZSBpbnNpZ2h0cyBpbnRvIHRoZSBkeW5hbWljcyBvZiBkaXNlYXNlIHRyYW5zbWlzc2lvbiBhbmQgaW5mb3JtIHRoZSBkZXNpZ24gb2YgdGFyZ2V0ZWQgcHVibGljIGhlYWx0aCBpbnRlcnZlbnRpb25zIGluIFZpZXRuYW0uCgpUaGUgc3R1ZHkgY29uZHVjdGVkIGEgZGlhcnktYmFzZWQgc3VydmV5IGluIE5vcnRoIFZpZXRuYW0gKDIwMDcpIHRvIGV4cGxvcmUgc29jaWFsIGNvbnRhY3QgcGF0dGVybnMsIGNydWNpYWwgZm9yIGluZmVjdGlvdXMgZGlzZWFzZSBzcHJlYWQgbW9kZWxpbmcuIEl0IHV0aWxpemVkIGdlbmVyYWxpemVkIGVzdGltYXRpbmcgZXF1YXRpb25zLCBhY2NvdW50aW5nIGZvciBob3VzZWhvbGQgc2FtcGxpbmcgYW5kIGRlbW9ncmFwaGljIHdlaWdodGluZyB0b3dhcmRzIHRoZSBWaWV0bmFtZXNlIHBvcHVsYXRpb24uIEtleSBmaW5kaW5ncyBpbmNsdWRlIGFzc29ydGF0aXZlIG1peGluZyBieSBhZ2UgYW5kIGRpZmZlcmVuY2VzIGluIGNvbnRhY3QgaW50ZW5zaXR5IHdpdGhpbiBob3VzZWhvbGQgYW5kIGNvbW11bml0eSBzZXR0aW5ncyBjb21wYXJlZCB0byBFdXJvcGVhbiBkYXRhLiBUaGUgc3R1ZHkgZW1waGFzaXplcyB0aGUgaW1wb3J0YW5jZSBvZiBjb250ZXh0LXNwZWNpZmljIGRhdGEgZm9yIGFjY3VyYXRlIGluZmVjdGlvdXMgZGlzZWFzZSBtb2RlbGluZywgcGFydGljdWxhcmx5IGluIGRldmVsb3BpbmcgY291bnRyaWVzLiBGb3IgYSBkZXRhaWxlZCB1bmRlcnN0YW5kaW5nIG9mIHRoZSBtZXRob2RzIGFuZCByZXN1bHRzLCBwbGVhc2UgcmVmZXIgdG8gdGhlIGZ1bGwgYXJ0aWNsZSBbaGVyZV0oaHR0cHM6Ly9qb3VybmFscy5wbG9zLm9yZy9wbG9zb25lL2FydGljbGU/aWQ9MTAuMTM3MS9qb3VybmFsLnBvbmUuMDAxNjk2NSkuCgojIyBVc2luZyBSIGFuZCBhdmFpbGFibGUgcGFja2FnZXMKClRoaXMgd29yayB3aWxsIHVzZSBzb2NpYWxtaXhyIHBhY2thZ2UgYW5kIGNvbm1hdC4KCkZpcnN0bHksIGxvYWQgdGhlIHBhY2thZ2Ugc29jaWFsbWl4ciBhbmQgcmVxdWlyZWQgcGFja2dlcwoKYGBge3J9CiN8IGluY2x1ZGU6IGZhbHNlCnBhY2thZ2VzIDwtIGMoInNvY2lhbG1peHIiLCAiZ2dwbG90MiIsICJyZXNoYXBlMiIsICJyZWFkciIgLCAiY29ubWF0IikKCmZvciAocGtnIGluIHBhY2thZ2VzKSB7CiAgICBsaWJyYXJ5KHBrZywgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQp9CgpgYGAKClRoZW4gbG9hZCB0aGUgZGF0YSBmcm9tIHRoZSBzb2NpYWwgY29udGFjdCBtYXRyaXggc3VydmV5IG9mIEhvcmJ5IGV0LiBhbCAoMjAxMSksIGF2YWlsYWJsZSBvbiBbWmVub2RvXShodHRwczovL3plbm9kby5vcmcvZG9pLzEwLjUyODEvemVub2RvLjEyODk0NzMpLgoKYGBge3J9CiN8IGluY2x1ZGU6IGZhbHNlCnZpZXRuYW0gPC0gZ2V0X3N1cnZleSgiaHR0cHM6Ly96ZW5vZG8ub3JnL2RvaS8xMC41MjgxL3plbm9kby4xMjg5NDczIikKYGBgCgpUaGUgc3VydmV5IG9iamVjdCByZXR1cm5zIGEgZGljdGlvbmFyeSB3aXRoIGNvbnRhY3RzIGFuZCBwYXJ0aWNpcGFudHMgZGF0YXRhYmxlCgojIyMjIFBhcnRpY2lwYW50cyBkYXRhZnJhbWU6CgpgYGB7cn0Kc3VtbWFyeSh2aWV0bmFtJHBhcnRpY2lwYW50cykKYGBgCgojIyMjIENvbnRhY3QgZGF0YWZyYW1lOgoKYGBge3J9CnN1bW1hcnkodmlldG5hbSRjb250YWN0cykKYGBgCgojIyMjIENyZWF0aW5nIGEgY29udGFjdCBtYXRyaXggb2JqZWN0OgoKVGhlICoqYGNvbnRhY3RfbWF0cml4YCoqIGZ1bmN0aW9uIGluIFIgaXMgdXNlZCB0byBjb25zdHJ1Y3QgY29udGFjdCBtYXRyaWNlcyBmcm9tIHN1cnZleSBkYXRhLiBTcGVjaWZpY2FsbHksIGl0IGFsbG93cyBjdXN0b21pemF0aW9uIG9mIGFnZSBncm91cHMsIHdlaWdodGluZyBieSBhZ2UsIGFuZCBhcHBseWluZyB2YXJpb3VzIGZpbHRlcnMgdG8gcmVmaW5lIHRoZSBhbmFseXNpcy4gSW5wdXQgaXMgc3VydmV5IGRhdGEgZnJvbSBWaWV0bmFtIHdpdGggYWdlIGxpbWl0cyBvZiAoMCw1LDE1LDM1LDUwLDcwKSBhbmQgd2VpZ2h0aW5nIGJ5IGFnZSBlbmFibGVkICh3ZWlnaC5hZ2UgPSBUUlVFKSwgdGFraW5nIGludG8gYWNjb3VudCB0aGUgYWdlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcG9wdWxhdGlvbiBhbmQgY29tcHV0ZXMgdGhlIG1lYW4gb2YgY29udGFjdHMgcGVyIGRheSBmb3IgZWFjaCBhZ2UgZ3JvdXAuIEZvciBkZXRhaWxlZCB1c2FnZSBhbmQgYXJndW1lbnQgZXhwbGFuYXRpb25zLCBwbGVhc2UgcmVmZXIgdG8gdGhlIFtkb2N1bWVudGF0aW9uXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc29jaWFsbWl4ci9zb2NpYWxtaXhyLnBkZikuCgpgYGB7cn0KI3wgaW5jbHVkZTogZmFsc2UKdm5jbSA8LSBjb250YWN0X21hdHJpeCh2aWV0bmFtLCBhZ2UubGltaXRzID0gYygwLDUsMTUsMzUsNTAsNzApLCByZXR1cm4uZGVtb2dyYXBoeSA9IFRSVUUsIHN5bW1ldHJpYyA9IFRSVUUsIHdlaWdoLmFnZSA9IFRSVUUpCgpgYGAKCmBgYHtyfQptciA8LSB2bmNtJG1hdHJpeAptcgpgYGAKCiMjIyMgKipQbG90dGluZyB0aGUgbWF0cml4OioqCgpgYGB7cn0KbWF0cml4X3Bsb3QobXIsIG1haW4gPSAiQ29udGFjdCBtYXRyaXgiKQpgYGAKCioqVGhlbiB3ZSB1c2UgYm9vdHN0cmFwZm9yIDEwMDAgdGltZXM6KioKCmBgYHtyfQojfCBpbmNsdWRlOiBmYWxzZQptIDwtIHJlcGxpY2F0ZSgKICBuID0gNSwgIyBmb3IgcXVpY2sgcnVuCiBjb250YWN0X21hdHJpeCh2aWV0bmFtLCBhZ2UubGltaXRzID0gYygwLDUsMTUsMzUsNTAsNzApLCByZXR1cm4uZGVtb2dyYXBoeSA9IFRSVUUsIHN5bW1ldHJpYyA9IFRSVUUsIHdlaWdoLmFnZSA9IFRSVUUsIHNhbXBsZS5wYXJ0aWNpcGFudHMgPSBUUlVFKQopCmBgYAoKYGBge3J9Cm1iIDwtIFJlZHVjZSgiKyIsIGxhcHBseShtWyJtYXRyaXgiLCBdLCBmdW5jdGlvbih4KSB4IC8gbmNvbChtKSkpCm1hdHJpeF9wbG90KG1iLCBtYWluID0gIkNvbnRhY3QgbWF0cml4IHVzaW5nIDEwMDAtdGltZSBib290c3RyYXAiKQpgYGAKCioqQ29tcGFyaW5nIHR3byBtYXRyaWNlczoqKgoKYGBge3J9CmRtIDwtIG1yIC0gbWIKbWF0cml4X3Bsb3QoZG0sIG1haW4gPSAiRGlmZmVyZW5jZSBiZXR3ZWVuIHR3byBjb250YWN0IG1hdHJpY2VzIikKYGBgCgojICoqVXNlIGNvbm1hdDoqKgoKYGBge3J9CiN8IHdhcm5pbmc6IGZhbHNlCnBvcE0xPSByZWFkX2NzdigicG9wTS5jc3YiKQpwb3BGMT0gcmVhZF9jc3YoInBvcEYuY3N2IikKdm5wb3BNID0gcG9wTTEgJT4lIGZpbHRlcihuYW1lPT0nVmlldCBOYW0nKQp2bnBvcEYgPSBwb3BGMSAlPiUgZmlsdGVyKG5hbWU9PSdWaWV0IE5hbScpCgpjb21iaW5lX2FuZF90cmFuc2Zvcm0gPC0gZnVuY3Rpb24oZGZNLCBkZkYpIHsKICBjb21iaW5lZF9kZiA8LSBiaW5kX3Jvd3MoZGZNLCBkZkYpICU+JQogICAgbXV0YXRlKGxvd2VyLmFnZS5saW1pdCA9IGNhc2Vfd2hlbigKICAgICAgYWdlID09ICIxMDArIiB+IGFzLmludGVnZXIoMTAwKSwgICMgSGFuZGxlIHRoZSAiMTAwKyIgY2FzZSBleHBsaWNpdGx5IGFzIGludGVnZXIKICAgICAgVFJVRSB+IGFzLmludGVnZXIoYXMubnVtZXJpYyhzdWIoIl4oXFxkKyktLioiLCAiXFwxIiwgYWdlKSkpICAjIENvbnZlcnQgb3RoZXIgY2FzZXMgdG8gaW50ZWdlcgogICAgKSwKICAgIGNvdW50cnkgPSAiVmlldCBOYW0iLCAgIyBBZGQgdGhlIGNvdW50cnkgY29sdW1uCiAgICB5ZWFyID0gMjAyMCwgICMgQWRkIHRoZSB5ZWFyIGNvbHVtbgogICAgcG9wdWxhdGlvbiA9IGAyMDIwYCkgJT4lICAjIFVzZSB0aGUgIjIwMjAiIGNvbHVtbiBmb3IgcG9wdWxhdGlvbgogICAgIyBHcm91cCBieSB0aGUgbmV3IGBsb3dlci5hZ2UubGltaXRgIChub3cgYW4gaW50ZWdlcikgYW5kIHN1bSB0aGUgcG9wdWxhdGlvbnMKICAgIGdyb3VwX2J5KGxvd2VyLmFnZS5saW1pdCkgJT4lCiAgICBzdW1tYXJpc2UocG9wdWxhdGlvbiA9IHN1bShwb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICAgIGNvdW50cnkgPSBmaXJzdChjb3VudHJ5KSwKICAgICAgICAgICAgICB5ZWFyID0gZmlyc3QoeWVhcikpICU+JQogICAgdW5ncm91cCgpICU+JQogICAgc2VsZWN0KGNvdW50cnksIGxvd2VyLmFnZS5saW1pdCwgeWVhciwgcG9wdWxhdGlvbikgICMgQXJyYW5nZSB0aGUgY29sdW1ucyBhcyBkZXNpcmVkCiAgCiAgcmV0dXJuKGNvbWJpbmVkX2RmKQp9CiMgQXNzdW1pbmcgYHZucG9wTWAgYW5kIGB2bnBvcEZgIGFyZSB5b3VyIG1hbGUgYW5kIGZlbWFsZSBkYXRhZnJhbWVzCmZpbmFsX2RhdGFzZXQgPC0gY29tYmluZV9hbmRfdHJhbnNmb3JtKHZucG9wTSwgdm5wb3BGKQoKIyBEaXNwbGF5IHRoZSB0cmFuc2Zvcm1lZCBkYXRhc2V0CmZpbmFsX2RhdGFzZXQkcG9wdWxhdGlvbiA9IGZpbmFsX2RhdGFzZXQkcG9wdWxhdGlvbiAqIDEwMDAKCmBgYAoKIyMjIyAqKkdlbmVyZXRpbmcgbWF0cml4IHVzaW5nIHBvbHltb2Q6KioKCmBgYHtyfQpwb2x5bW9kX3N1cnZleV9kYXRhIDwtIGdldF9wb2x5bW9kX3BvcHVsYXRpb24oKQpwb2x5bW9kX2NvbnRhY3RfZGF0YSA8LSBnZXRfcG9seW1vZF9jb250YWN0X2RhdGEoKQoKY29udGFjdF9tb2RlbCA8LSBmaXRfc2luZ2xlX2NvbnRhY3RfbW9kZWwoCiAgY29udGFjdF9kYXRhIDwtIHBvbHltb2RfY29udGFjdF9kYXRhLAogIHBvcHVsYXRpb24gPC0gcG9seW1vZF9zdXJ2ZXlfZGF0YQopCiN2bnAgPC13cHBfYWdlKCJWaWV0bmFtIiwgMjAyMCkKdm5fMjAyMF9wb3AgPC0gYXNfY29ubWF0X3BvcHVsYXRpb24oCiAgZGF0YSA9IGZpbmFsX2RhdGFzZXQsCiAgYWdlID0gbG93ZXIuYWdlLmxpbWl0LAogIHBvcHVsYXRpb24gPSBwb3B1bGF0aW9uCikKCnN5bnRoZXRpY19jb250YWN0X21hdHJpeCA9IHByZWRpY3RfY29udGFjdHMoCiAgbW9kZWwgPSBjb250YWN0X21vZGVsLAogIHBvcHVsYXRpb24gPSB2bl8yMDIwX3BvcCwKICBhZ2VfYnJlYWtzID0gYygwLDUsMTUsMzUsNTAsNzAsIEluZikKKQoKZGZfd2lkZSA8LSBzeW50aGV0aWNfY29udGFjdF9tYXRyaXggJT4lIAogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBhZ2VfZ3JvdXBfdG8sIHZhbHVlc19mcm9tID0gY29udGFjdHMpCgojIENvbnZlcnQgdG8gbWF0cml4LCBleGNsdWRpbmcgdGhlIGZpcnN0IGNvbHVtbiB3aGljaCBjb250YWlucyB0aGUgcm93IG5hbWVzCmNvbnRhY3RfbWF0cml4IDwtIGFzLm1hdHJpeChkZl93aWRlWywgLTFdKQoKIyBTZXQgdGhlIHJvdyBuYW1lcyBvZiB0aGUgbWF0cml4IHRvIGJlIHRoZSBmaXJzdCBjb2x1bW4gb2YgZGZfd2lkZQpyb3cubmFtZXMoY29udGFjdF9tYXRyaXgpIDwtIGRmX3dpZGUkYWdlX2dyb3VwX2Zyb20KbWF0cml4X3Bsb3QoY29udGFjdF9tYXRyaXgsIG1haW4gPSAiQ29udGFjdCBtYXRyaXggZnJvbSBjb25tYXQiKQpgYGAKCgo=