rm(list=ls())
library(data.table)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
data.table 1.14.6 using 1 threads (see ?getDTthreads).  Latest news: r-datatable.com

Attaching package: ‘data.table’

The following object is masked _by_ ‘.GlobalEnv’:

    .N
library(here)
here() starts at /users/akhann16/code/cadre/data-analysis-plotting/Simulated-Data-Analysis/r
library(DiagrammeR)
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
library(yaml)
library(igraph)

Attaching package: ‘igraph’

The following object is masked from ‘package:DiagrammeR’:

    count_automorphisms

The following objects are masked from ‘package:stats’:

    decompose, spectrum

The following object is masked from ‘package:base’:

    union
library(ggraph)
Loading required package: ggplot2

Attaching package: ‘ggraph’

The following object is masked from ‘package:DiagrammeR’:

    get_edges
library(ggplot2)
network_log_env <- readRDS(here("network-log-analysis", "rds-outs", "network_log_env.RDS"))
network_dt <- network_log_env[["network_dt"]]
input_params <- network_log_env[["input_params"]]
agent_dt <- network_log_env[["agent_dt"]]

Let’s focus on the last tick for which we have agent and network data:

last_tick <- max(network_dt$tick) 
last_tick_network_dt <- network_dt[tick==last_tick,]
last_tick_agent_dt <- agent_dt[tick == last_tick,]
print(last_tick_network_dt)
print(last_tick_agent_dt)

Visualize using DiagrammeR:

# Identify the IDs of the recently released agents
recently_released_agents <- last_tick_agent_dt$id[last_tick_agent_dt$last_release_tick > (last_tick - 365)]

# Get the network data for the recently released agents
network_recently_released <- last_tick_network_dt[(last_tick_network_dt$p1 %in% recently_released_agents) | 
                                                    (last_tick_network_dt$p2 %in% recently_released_agents),]

# Get the first-degree network (neighbors) for each agent
first_degree_neighbors <- unique(c(network_recently_released$p1, network_recently_released$p2))

# Get agent data for the first-degree neighbors
first_degree_neighbors_agent_data <- last_tick_agent_dt[last_tick_agent_dt$id %in% first_degree_neighbors,]

# Create an edge data frame from your network data
edf <- data.frame(from = network_recently_released$p1, 
                  to = network_recently_released$p2)

# Create a node data frame with your agent data
ndf <- data.frame(id = first_degree_neighbors_agent_data$id, 
                  smoking_status = first_degree_neighbors_agent_data$smoking_status,
                  alc_use_status = first_degree_neighbors_agent_data$alc_use_status,
                  recently_released = ifelse(first_degree_neighbors_agent_data$id %in% recently_released_agents, "yes", "no"))

# Create a graph with DiagrammeR
graph <- create_graph(nodes_df = ndf, 
                      edges_df = edf,
                      directed = FALSE)
Failed to create bus connection: No such file or directory
Warning: running command 'timedatectl' had status 1
# Customize the node fillcolor based on smoking_status, alc_use_status and recently_released
graph <- set_node_attrs(graph, "fillcolor", ifelse(ndf$smoking_status == "Current", "red", 
                                                   ifelse(ndf$alc_use_status == 3, "blue", 
                                                          ifelse(ndf$recently_released == "yes", "black", "white"))))

# Customize the node color based on smoking_status, alc_use_status and recently_released
graph <- set_node_attrs(graph, "color", ifelse(ndf$smoking_status == "Current", "red", 
                                               ifelse(ndf$alc_use_status == 3, "blue", 
                                                      ifelse(ndf$recently_released == "yes", "black", "gray"))))

# Customize the node shape based on recently_released
graph <- set_node_attrs(graph, "shape", ifelse(ndf$recently_released == "yes", "square", "circle"))

# Remove labels from nodes to make them stand out more
graph <- set_node_attrs(graph, "label", "")

# Customize the edge color and line type
graph <- set_edge_attrs(graph, "color", "black")  # Change the edge color to gray
graph <- set_edge_attrs(graph, "style", "solid")  # Change the edge line type to dashed

# Customize the edge thickness
graph <- set_edge_attrs(graph, "penwidth", 2)  # Increase the edge thickness

# Customize the outline color of all nodes
graph <- set_node_attrs(graph, "color", "darkgray") 

# Render the graph
render_graph(graph)

# Create a legend
legend <- rbind(data.frame(group = "Recently Released", shape = "square", color = "black"),
                data.frame(group = "Currently Smoking", shape = "circle", color = "red"),
                data.frame(group = "AUD", shape = "circle", color = "blue"))

Prevalence of Current Smoking and AUD among network members:

# Number of agents with Current Smoking status
num_current_smoking <- sum(first_degree_neighbors_agent_data$smoking_status == "Current")

# Number of agents with AUD
num_aud <- sum(first_degree_neighbors_agent_data$alc_use_status == 3)

# Total number of agents in the network
total_agents <- nrow(first_degree_neighbors_agent_data)

# Calculate prevalence
prevalence_smoking <- num_current_smoking / total_agents
prevalence_aud <- num_aud / total_agents

# Print the results
cat("Prevalence of Current Smoking in networks of recently released agents: ", prevalence_smoking, "\n")
Prevalence of Current Smoking in networks of recently released agents:  0.2727273 
cat("Prevalence of AUD in networks of recently released agents: ", prevalence_aud, "\n")
Prevalence of AUD in networks of recently released agents:  0.1818182 

Prevalence of Cyrrent Smoking and AUD among this set of egos:

# Define selected_agents_df, which contains the data for the selected agents
recently_released_agents_df <- last_tick_agent_dt[last_tick_agent_dt$id %in% recently_released_agents,]

# Number of selected agents who are current smokers
num_ego_current_smoking <- sum(recently_released_agents_df$smoking_status == "Current")

# Number of selected agents with AUD
num_ego_aud <- sum(recently_released_agents_df$alc_use_status == 3)

# Total number of selected agents
total_ego_agents <- length(recently_released_agents)

# Calculate prevalence
prevalence_ego_smoking <- num_ego_current_smoking / total_ego_agents
prevalence_ego_aud <- num_ego_aud / total_ego_agents

# Print the results
cat("Prevalence of Current Smoking among recently released agents: ", prevalence_ego_smoking, "\n")
Prevalence of Current Smoking among recently released agents:  0.5483871 
cat("Prevalence of AUD among recently released agents: ", prevalence_ego_aud, "\n")
Prevalence of AUD among recently released agents:  0.2580645 
# Create a legend
legend <- rbind(
  data.frame(group = "Recently Released", shape = "square", color = "black"),
  data.frame(group = "Recently Released & Currently Smoking", shape = "square", color = "red"),
  data.frame(group = "Recently Released & AUD", shape = "square", color = "blue"),
  data.frame(group = "Currently Smoking", shape = "circle", color = "red"),
  data.frame(group = "AUD", shape = "circle", color = "blue")
)


# The ggplot call
p <- ggplot() +
  geom_point(data = legend, 
             aes(x = 1, y = group, color = color, fill = color, shape = shape), 
             size = 5) +
  geom_text(data = legend, 
            aes(x = 1.1, y = group, label = group), 
            hjust = 0) +
  scale_color_identity() +
  scale_fill_identity() +
  scale_shape_manual(values=c("square"=22, "circle"=21)) +
  theme_void() +
  theme(legend.position = "none") +
  coord_cartesian(xlim = c(1, 2))  # Adjust as necessary to ensure labels fit

# Print the plot
p

Alternate legend:

# Create a legend
legend <- data.frame(
  group = c("Recently Released", "Network Member"),
  shape = c("square", "circle"),
  fillcolor = c("black", "white"),
  color = c("black", "black")
)

# Map the attributes for smoking and alcohol use to the legend
smoking_legend <- data.frame(
  group = c("Current Smoking"),
  shape = c("circle"),
  fillcolor = c("blue"),
  color = c("blue")
)

alc_legend <- data.frame(
  group = c("Heavy Alcohol Use"),
  shape = c("circle"),
  fillcolor = c("red"),
  color = c("red")
)

# Combine the legend data frames
legend <- rbind(legend, smoking_legend, alc_legend)

# The ggplot call
legend_p_2 <- ggplot() +
  geom_point(data = legend, 
             aes(x = 1, y = group, fill = fillcolor, color = color, shape = shape), 
             size = 5) +
  geom_text(data = legend, 
            aes(x = 1.1, y = group, label = group), 
            hjust = 0) +
  scale_fill_identity() +
  scale_color_identity() +
  scale_shape_manual(values = c("square" = 22, "circle" = 21)) +
  theme_void() +
  theme(
    legend.position = "none") +
  coord_cartesian(xlim = c(1, 2))  # Adjust as necessary to ensure labels fit

# Print the plot
legend_p_2

legend_p_2

Horizontal legend alignment:

# Create a legend
legend <- data.frame(
  group = c("Recently Released", "Network Member", "Current Smoking", "Heavy Alcohol Use"),
  shape = c("square", "circle", "circle", "circle"),
  fillcolor = c("black", "white", "blue", "red"),
  color = c("black", "black", "blue", "red")
)

# The ggplot call
horizontal_legend_p <- ggplot() +
  geom_point(data = legend, 
             aes(x = group, y = 1, fill = fillcolor, color = color, shape = shape), 
             size = 5) +
  geom_text(data = legend, 
            aes(x = group, y = 1.1, label = group), 
            vjust = -0.5, angle = 45, hjust = 1) +
  scale_fill_identity() +
  scale_color_identity() +
  scale_shape_manual(values = c("square" = 22, "circle" = 21)) +
  theme_void() +
  theme(
    legend.position = "none"
  ) +
  coord_cartesian(ylim = c(0.8, 2))  # Adjust as necessary to ensure labels fit

# Print the plot
horizontal_legend_p

Plot AUD and Current Smking in the networks of a same number of agents who have never been incarcerated:

# Set seed for reproducibility
set.seed(Sys.time())

# Identify the IDs of the agents who have never been incarcerated
never_incarcerated_agents <- last_tick_agent_dt$id[last_tick_agent_dt$n_incarcerations == 0]

# Randomly select 36 agents who have never been incarcerated
selected_agents <- sample(never_incarcerated_agents, 
                          size = length(recently_released_agents))

# Get the network data for the selected agents
network_selected_agents <- last_tick_network_dt[(last_tick_network_dt$p1 %in% selected_agents) | 
                                                (last_tick_network_dt$p2 %in% selected_agents),]

# Get the first-degree network (neighbors) for each agent
first_degree_neighbors <- unique(c(network_selected_agents$p1, network_selected_agents$p2))

# Get agent data for the first-degree neighbors
first_degree_neighbors_agent_data <- last_tick_agent_dt[last_tick_agent_dt$id %in% first_degree_neighbors,]

# Create an edge data frame from your network data
edf <- data.frame(from = network_selected_agents$p1, 
                  to = network_selected_agents$p2)

# Create a node data frame with your agent data
ndf <- data.frame(id = first_degree_neighbors_agent_data$id, 
                  smoking_status = first_degree_neighbors_agent_data$smoking_status,
                  alc_use_status = first_degree_neighbors_agent_data$alc_use_status)

# Create a graph with DiagrammeR
graph <- create_graph(nodes_df = ndf, 
                      edges_df = edf,
                      directed = FALSE)

# Customize the node fillcolor based on smoking_status and alc_use_status
graph <- set_node_attrs(graph, "fillcolor", ifelse(ndf$smoking_status == "Current", "red", 
                                                   ifelse(ndf$alc_use_status == 3, "blue", "white")))

# Customize the node color based on smoking_status and alc_use_status
graph <- set_node_attrs(graph, "color", ifelse(ndf$smoking_status == "Current", "red", 
                                               ifelse(ndf$alc_use_status == 3, "blue", "gray")))

# Remove labels from nodes to make them stand out more
graph <- set_node_attrs(graph, "label", "")

# Render the graph
render_graph(graph)
NA

Numerical prevalence of AUD and Current Smoking in this network:

# Number of agents with Current Smoking status
num_current_smoking <- sum(first_degree_neighbors_agent_data$smoking_status == "Current")

# Number of agents with AUD
num_aud <- sum(first_degree_neighbors_agent_data$alc_use_status == 3)

# Total number of agents in the network
total_agents <- nrow(first_degree_neighbors_agent_data)

# Calculate prevalence
prevalence_smoking <- num_current_smoking / total_agents
prevalence_aud <- num_aud / total_agents

# Print the results
cat("Prevalence of Current Smoking in the networks of randomly 
    selected never incarcerated persons: ", prevalence_smoking, "\n")
Prevalence of Current Smoking in the networks of randomly 
    selected never incarcerated persons:  0.1870504 
cat("Prevalence of AUD in the networks of randomly 
    selected never incarcerated persons: ", prevalence_aud, "\n")
Prevalence of AUD in the networks of randomly 
    selected never incarcerated persons:  0.1510791 

Smoking and AUD among the egos:

# Define selected_agents_df, which contains the data for the selected agents
selected_agents_df <- last_tick_agent_dt[last_tick_agent_dt$id %in% selected_agents,]

# Number of selected agents who are current smokers
num_ego_current_smoking <- sum(selected_agents_df$smoking_status == "Current")

# Number of selected agents with AUD
num_ego_aud <- sum(selected_agents_df$alc_use_status == 3)

# Total number of selected agents
total_ego_agents <- length(selected_agents)

# Calculate prevalence
prevalence_ego_smoking <- num_ego_current_smoking / total_ego_agents
prevalence_ego_aud <- num_ego_aud / total_ego_agents

# Print the results
cat("Prevalence of Current Smoking among selected agents: ", prevalence_ego_smoking, "\n")
Prevalence of Current Smoking among selected agents:  0.1935484 
cat("Prevalence of AUD among selected agents: ", prevalence_ego_aud, "\n")
Prevalence of AUD among selected agents:  0.1290323 
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CnJtKGxpc3Q9bHMoKSkKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkoRGlhZ3JhbW1lUikKbGlicmFyeSh5YW1sKQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoZ2dwbG90MikKCmBgYAoKYGBge3J9Cm5ldHdvcmtfbG9nX2VudiA8LSByZWFkUkRTKGhlcmUoIm5ldHdvcmstbG9nLWFuYWx5c2lzIiwgInJkcy1vdXRzIiwgIm5ldHdvcmtfbG9nX2Vudi5SRFMiKSkKbmV0d29ya19kdCA8LSBuZXR3b3JrX2xvZ19lbnZbWyJuZXR3b3JrX2R0Il1dCmlucHV0X3BhcmFtcyA8LSBuZXR3b3JrX2xvZ19lbnZbWyJpbnB1dF9wYXJhbXMiXV0KYWdlbnRfZHQgPC0gbmV0d29ya19sb2dfZW52W1siYWdlbnRfZHQiXV0KYGBgCiAKCkxldCdzIGZvY3VzIG9uIHRoZSBsYXN0IHRpY2sgZm9yIHdoaWNoIHdlIGhhdmUgYWdlbnQgYW5kIG5ldHdvcmsgZGF0YToKCmBgYHtyfQpsYXN0X3RpY2sgPC0gbWF4KG5ldHdvcmtfZHQkdGljaykgCmxhc3RfdGlja19uZXR3b3JrX2R0IDwtIG5ldHdvcmtfZHRbdGljaz09bGFzdF90aWNrLF0KbGFzdF90aWNrX2FnZW50X2R0IDwtIGFnZW50X2R0W3RpY2sgPT0gbGFzdF90aWNrLF0KcHJpbnQobGFzdF90aWNrX25ldHdvcmtfZHQpCnByaW50KGxhc3RfdGlja19hZ2VudF9kdCkKYGBgCgpWaXN1YWxpemUgdXNpbmcgYERpYWdyYW1tZVJgOgoKCmBgYHtyfQojIElkZW50aWZ5IHRoZSBJRHMgb2YgdGhlIHJlY2VudGx5IHJlbGVhc2VkIGFnZW50cwpyZWNlbnRseV9yZWxlYXNlZF9hZ2VudHMgPC0gbGFzdF90aWNrX2FnZW50X2R0JGlkW2xhc3RfdGlja19hZ2VudF9kdCRsYXN0X3JlbGVhc2VfdGljayA+IChsYXN0X3RpY2sgLSAzNjUpXQoKIyBHZXQgdGhlIG5ldHdvcmsgZGF0YSBmb3IgdGhlIHJlY2VudGx5IHJlbGVhc2VkIGFnZW50cwpuZXR3b3JrX3JlY2VudGx5X3JlbGVhc2VkIDwtIGxhc3RfdGlja19uZXR3b3JrX2R0WyhsYXN0X3RpY2tfbmV0d29ya19kdCRwMSAlaW4lIHJlY2VudGx5X3JlbGVhc2VkX2FnZW50cykgfCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChsYXN0X3RpY2tfbmV0d29ya19kdCRwMiAlaW4lIHJlY2VudGx5X3JlbGVhc2VkX2FnZW50cyksXQoKIyBHZXQgdGhlIGZpcnN0LWRlZ3JlZSBuZXR3b3JrIChuZWlnaGJvcnMpIGZvciBlYWNoIGFnZW50CmZpcnN0X2RlZ3JlZV9uZWlnaGJvcnMgPC0gdW5pcXVlKGMobmV0d29ya19yZWNlbnRseV9yZWxlYXNlZCRwMSwgbmV0d29ya19yZWNlbnRseV9yZWxlYXNlZCRwMikpCgojIEdldCBhZ2VudCBkYXRhIGZvciB0aGUgZmlyc3QtZGVncmVlIG5laWdoYm9ycwpmaXJzdF9kZWdyZWVfbmVpZ2hib3JzX2FnZW50X2RhdGEgPC0gbGFzdF90aWNrX2FnZW50X2R0W2xhc3RfdGlja19hZ2VudF9kdCRpZCAlaW4lIGZpcnN0X2RlZ3JlZV9uZWlnaGJvcnMsXQoKIyBDcmVhdGUgYW4gZWRnZSBkYXRhIGZyYW1lIGZyb20geW91ciBuZXR3b3JrIGRhdGEKZWRmIDwtIGRhdGEuZnJhbWUoZnJvbSA9IG5ldHdvcmtfcmVjZW50bHlfcmVsZWFzZWQkcDEsIAogICAgICAgICAgICAgICAgICB0byA9IG5ldHdvcmtfcmVjZW50bHlfcmVsZWFzZWQkcDIpCgojIENyZWF0ZSBhIG5vZGUgZGF0YSBmcmFtZSB3aXRoIHlvdXIgYWdlbnQgZGF0YQpuZGYgPC0gZGF0YS5mcmFtZShpZCA9IGZpcnN0X2RlZ3JlZV9uZWlnaGJvcnNfYWdlbnRfZGF0YSRpZCwgCiAgICAgICAgICAgICAgICAgIHNtb2tpbmdfc3RhdHVzID0gZmlyc3RfZGVncmVlX25laWdoYm9yc19hZ2VudF9kYXRhJHNtb2tpbmdfc3RhdHVzLAogICAgICAgICAgICAgICAgICBhbGNfdXNlX3N0YXR1cyA9IGZpcnN0X2RlZ3JlZV9uZWlnaGJvcnNfYWdlbnRfZGF0YSRhbGNfdXNlX3N0YXR1cywKICAgICAgICAgICAgICAgICAgcmVjZW50bHlfcmVsZWFzZWQgPSBpZmVsc2UoZmlyc3RfZGVncmVlX25laWdoYm9yc19hZ2VudF9kYXRhJGlkICVpbiUgcmVjZW50bHlfcmVsZWFzZWRfYWdlbnRzLCAieWVzIiwgIm5vIikpCgojIENyZWF0ZSBhIGdyYXBoIHdpdGggRGlhZ3JhbW1lUgpncmFwaCA8LSBjcmVhdGVfZ3JhcGgobm9kZXNfZGYgPSBuZGYsIAogICAgICAgICAgICAgICAgICAgICAgZWRnZXNfZGYgPSBlZGYsCiAgICAgICAgICAgICAgICAgICAgICBkaXJlY3RlZCA9IEZBTFNFKQoKIyBDdXN0b21pemUgdGhlIG5vZGUgZmlsbGNvbG9yIGJhc2VkIG9uIHNtb2tpbmdfc3RhdHVzLCBhbGNfdXNlX3N0YXR1cyBhbmQgcmVjZW50bHlfcmVsZWFzZWQKZ3JhcGggPC0gc2V0X25vZGVfYXR0cnMoZ3JhcGgsICJmaWxsY29sb3IiLCBpZmVsc2UobmRmJHNtb2tpbmdfc3RhdHVzID09ICJDdXJyZW50IiwgInJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobmRmJGFsY191c2Vfc3RhdHVzID09IDMsICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobmRmJHJlY2VudGx5X3JlbGVhc2VkID09ICJ5ZXMiLCAiYmxhY2siLCAid2hpdGUiKSkpKQoKIyBDdXN0b21pemUgdGhlIG5vZGUgY29sb3IgYmFzZWQgb24gc21va2luZ19zdGF0dXMsIGFsY191c2Vfc3RhdHVzIGFuZCByZWNlbnRseV9yZWxlYXNlZApncmFwaCA8LSBzZXRfbm9kZV9hdHRycyhncmFwaCwgImNvbG9yIiwgaWZlbHNlKG5kZiRzbW9raW5nX3N0YXR1cyA9PSAiQ3VycmVudCIsICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobmRmJGFsY191c2Vfc3RhdHVzID09IDMsICJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShuZGYkcmVjZW50bHlfcmVsZWFzZWQgPT0gInllcyIsICJibGFjayIsICJncmF5IikpKSkKCiMgQ3VzdG9taXplIHRoZSBub2RlIHNoYXBlIGJhc2VkIG9uIHJlY2VudGx5X3JlbGVhc2VkCmdyYXBoIDwtIHNldF9ub2RlX2F0dHJzKGdyYXBoLCAic2hhcGUiLCBpZmVsc2UobmRmJHJlY2VudGx5X3JlbGVhc2VkID09ICJ5ZXMiLCAic3F1YXJlIiwgImNpcmNsZSIpKQoKIyBSZW1vdmUgbGFiZWxzIGZyb20gbm9kZXMgdG8gbWFrZSB0aGVtIHN0YW5kIG91dCBtb3JlCmdyYXBoIDwtIHNldF9ub2RlX2F0dHJzKGdyYXBoLCAibGFiZWwiLCAiIikKCiMgQ3VzdG9taXplIHRoZSBlZGdlIGNvbG9yIGFuZCBsaW5lIHR5cGUKZ3JhcGggPC0gc2V0X2VkZ2VfYXR0cnMoZ3JhcGgsICJjb2xvciIsICJibGFjayIpICAjIENoYW5nZSB0aGUgZWRnZSBjb2xvciB0byBncmF5CmdyYXBoIDwtIHNldF9lZGdlX2F0dHJzKGdyYXBoLCAic3R5bGUiLCAic29saWQiKSAgIyBDaGFuZ2UgdGhlIGVkZ2UgbGluZSB0eXBlIHRvIGRhc2hlZAoKIyBDdXN0b21pemUgdGhlIGVkZ2UgdGhpY2tuZXNzCmdyYXBoIDwtIHNldF9lZGdlX2F0dHJzKGdyYXBoLCAicGVud2lkdGgiLCAyKSAgIyBJbmNyZWFzZSB0aGUgZWRnZSB0aGlja25lc3MKCiMgQ3VzdG9taXplIHRoZSBvdXRsaW5lIGNvbG9yIG9mIGFsbCBub2RlcwpncmFwaCA8LSBzZXRfbm9kZV9hdHRycyhncmFwaCwgImNvbG9yIiwgImRhcmtncmF5IikgCgojIFJlbmRlciB0aGUgZ3JhcGgKcmVuZGVyX2dyYXBoKGdyYXBoKQoKIyBDcmVhdGUgYSBsZWdlbmQKbGVnZW5kIDwtIHJiaW5kKGRhdGEuZnJhbWUoZ3JvdXAgPSAiUmVjZW50bHkgUmVsZWFzZWQiLCBzaGFwZSA9ICJzcXVhcmUiLCBjb2xvciA9ICJibGFjayIpLAogICAgICAgICAgICAgICAgZGF0YS5mcmFtZShncm91cCA9ICJDdXJyZW50bHkgU21va2luZyIsIHNoYXBlID0gImNpcmNsZSIsIGNvbG9yID0gInJlZCIpLAogICAgICAgICAgICAgICAgZGF0YS5mcmFtZShncm91cCA9ICJBVUQiLCBzaGFwZSA9ICJjaXJjbGUiLCBjb2xvciA9ICJibHVlIikpCgpgYGAKClByZXZhbGVuY2Ugb2YgQ3VycmVudCBTbW9raW5nIGFuZCBBVUQgYW1vbmcgbmV0d29yayBtZW1iZXJzOgoKYGBge3J9CiMgTnVtYmVyIG9mIGFnZW50cyB3aXRoIEN1cnJlbnQgU21va2luZyBzdGF0dXMKbnVtX2N1cnJlbnRfc21va2luZyA8LSBzdW0oZmlyc3RfZGVncmVlX25laWdoYm9yc19hZ2VudF9kYXRhJHNtb2tpbmdfc3RhdHVzID09ICJDdXJyZW50IikKCiMgTnVtYmVyIG9mIGFnZW50cyB3aXRoIEFVRApudW1fYXVkIDwtIHN1bShmaXJzdF9kZWdyZWVfbmVpZ2hib3JzX2FnZW50X2RhdGEkYWxjX3VzZV9zdGF0dXMgPT0gMykKCiMgVG90YWwgbnVtYmVyIG9mIGFnZW50cyBpbiB0aGUgbmV0d29yawp0b3RhbF9hZ2VudHMgPC0gbnJvdyhmaXJzdF9kZWdyZWVfbmVpZ2hib3JzX2FnZW50X2RhdGEpCgojIENhbGN1bGF0ZSBwcmV2YWxlbmNlCnByZXZhbGVuY2Vfc21va2luZyA8LSBudW1fY3VycmVudF9zbW9raW5nIC8gdG90YWxfYWdlbnRzCnByZXZhbGVuY2VfYXVkIDwtIG51bV9hdWQgLyB0b3RhbF9hZ2VudHMKCiMgUHJpbnQgdGhlIHJlc3VsdHMKY2F0KCJQcmV2YWxlbmNlIG9mIEN1cnJlbnQgU21va2luZyBpbiBuZXR3b3JrcyBvZiByZWNlbnRseSByZWxlYXNlZCBhZ2VudHM6ICIsIHByZXZhbGVuY2Vfc21va2luZywgIlxuIikKY2F0KCJQcmV2YWxlbmNlIG9mIEFVRCBpbiBuZXR3b3JrcyBvZiByZWNlbnRseSByZWxlYXNlZCBhZ2VudHM6ICIsIHByZXZhbGVuY2VfYXVkLCAiXG4iKQoKYGBgCgpQcmV2YWxlbmNlIG9mIEN5cnJlbnQgU21va2luZyBhbmQgQVVEIGFtb25nIHRoaXMgc2V0IG9mIGVnb3M6CgpgYGB7cn0KIyBEZWZpbmUgc2VsZWN0ZWRfYWdlbnRzX2RmLCB3aGljaCBjb250YWlucyB0aGUgZGF0YSBmb3IgdGhlIHNlbGVjdGVkIGFnZW50cwpyZWNlbnRseV9yZWxlYXNlZF9hZ2VudHNfZGYgPC0gbGFzdF90aWNrX2FnZW50X2R0W2xhc3RfdGlja19hZ2VudF9kdCRpZCAlaW4lIHJlY2VudGx5X3JlbGVhc2VkX2FnZW50cyxdCgojIE51bWJlciBvZiBzZWxlY3RlZCBhZ2VudHMgd2hvIGFyZSBjdXJyZW50IHNtb2tlcnMKbnVtX2Vnb19jdXJyZW50X3Ntb2tpbmcgPC0gc3VtKHJlY2VudGx5X3JlbGVhc2VkX2FnZW50c19kZiRzbW9raW5nX3N0YXR1cyA9PSAiQ3VycmVudCIpCgojIE51bWJlciBvZiBzZWxlY3RlZCBhZ2VudHMgd2l0aCBBVUQKbnVtX2Vnb19hdWQgPC0gc3VtKHJlY2VudGx5X3JlbGVhc2VkX2FnZW50c19kZiRhbGNfdXNlX3N0YXR1cyA9PSAzKQoKIyBUb3RhbCBudW1iZXIgb2Ygc2VsZWN0ZWQgYWdlbnRzCnRvdGFsX2Vnb19hZ2VudHMgPC0gbGVuZ3RoKHJlY2VudGx5X3JlbGVhc2VkX2FnZW50cykKCiMgQ2FsY3VsYXRlIHByZXZhbGVuY2UKcHJldmFsZW5jZV9lZ29fc21va2luZyA8LSBudW1fZWdvX2N1cnJlbnRfc21va2luZyAvIHRvdGFsX2Vnb19hZ2VudHMKcHJldmFsZW5jZV9lZ29fYXVkIDwtIG51bV9lZ29fYXVkIC8gdG90YWxfZWdvX2FnZW50cwoKIyBQcmludCB0aGUgcmVzdWx0cwpjYXQoIlByZXZhbGVuY2Ugb2YgQ3VycmVudCBTbW9raW5nIGFtb25nIHJlY2VudGx5IHJlbGVhc2VkIGFnZW50czogIiwgcHJldmFsZW5jZV9lZ29fc21va2luZywgIlxuIikKY2F0KCJQcmV2YWxlbmNlIG9mIEFVRCBhbW9uZyByZWNlbnRseSByZWxlYXNlZCBhZ2VudHM6ICIsIHByZXZhbGVuY2VfZWdvX2F1ZCwgIlxuIikKCmBgYAoKCmBgYHtyfQojIENyZWF0ZSBhIGxlZ2VuZApsZWdlbmQgPC0gcmJpbmQoCiAgZGF0YS5mcmFtZShncm91cCA9ICJSZWNlbnRseSBSZWxlYXNlZCIsIHNoYXBlID0gInNxdWFyZSIsIGNvbG9yID0gImJsYWNrIiksCiAgZGF0YS5mcmFtZShncm91cCA9ICJSZWNlbnRseSBSZWxlYXNlZCAmIEN1cnJlbnRseSBTbW9raW5nIiwgc2hhcGUgPSAic3F1YXJlIiwgY29sb3IgPSAicmVkIiksCiAgZGF0YS5mcmFtZShncm91cCA9ICJSZWNlbnRseSBSZWxlYXNlZCAmIEFVRCIsIHNoYXBlID0gInNxdWFyZSIsIGNvbG9yID0gImJsdWUiKSwKICBkYXRhLmZyYW1lKGdyb3VwID0gIkN1cnJlbnRseSBTbW9raW5nIiwgc2hhcGUgPSAiY2lyY2xlIiwgY29sb3IgPSAicmVkIiksCiAgZGF0YS5mcmFtZShncm91cCA9ICJBVUQiLCBzaGFwZSA9ICJjaXJjbGUiLCBjb2xvciA9ICJibHVlIikKKQoKCiMgVGhlIGdncGxvdCBjYWxsCnAgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGxlZ2VuZCwgCiAgICAgICAgICAgICBhZXMoeCA9IDEsIHkgPSBncm91cCwgY29sb3IgPSBjb2xvciwgZmlsbCA9IGNvbG9yLCBzaGFwZSA9IHNoYXBlKSwgCiAgICAgICAgICAgICBzaXplID0gNSkgKwogIGdlb21fdGV4dChkYXRhID0gbGVnZW5kLCAKICAgICAgICAgICAgYWVzKHggPSAxLjEsIHkgPSBncm91cCwgbGFiZWwgPSBncm91cCksIAogICAgICAgICAgICBoanVzdCA9IDApICsKICBzY2FsZV9jb2xvcl9pZGVudGl0eSgpICsKICBzY2FsZV9maWxsX2lkZW50aXR5KCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9Yygic3F1YXJlIj0yMiwgImNpcmNsZSI9MjEpKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMSwgMikpICAjIEFkanVzdCBhcyBuZWNlc3NhcnkgdG8gZW5zdXJlIGxhYmVscyBmaXQKCiMgUHJpbnQgdGhlIHBsb3QKcAoKYGBgCgpBbHRlcm5hdGUgbGVnZW5kOgoKYGBge3J9CiMgQ3JlYXRlIGEgbGVnZW5kCmxlZ2VuZCA8LSBkYXRhLmZyYW1lKAogIGdyb3VwID0gYygiUmVjZW50bHkgUmVsZWFzZWQiLCAiTmV0d29yayBNZW1iZXIiKSwKICBzaGFwZSA9IGMoInNxdWFyZSIsICJjaXJjbGUiKSwKICBmaWxsY29sb3IgPSBjKCJibGFjayIsICJ3aGl0ZSIpLAogIGNvbG9yID0gYygiYmxhY2siLCAiYmxhY2siKQopCgojIE1hcCB0aGUgYXR0cmlidXRlcyBmb3Igc21va2luZyBhbmQgYWxjb2hvbCB1c2UgdG8gdGhlIGxlZ2VuZApzbW9raW5nX2xlZ2VuZCA8LSBkYXRhLmZyYW1lKAogIGdyb3VwID0gYygiQ3VycmVudCBTbW9raW5nIiksCiAgc2hhcGUgPSBjKCJjaXJjbGUiKSwKICBmaWxsY29sb3IgPSBjKCJibHVlIiksCiAgY29sb3IgPSBjKCJibHVlIikKKQoKYWxjX2xlZ2VuZCA8LSBkYXRhLmZyYW1lKAogIGdyb3VwID0gYygiSGVhdnkgQWxjb2hvbCBVc2UiKSwKICBzaGFwZSA9IGMoImNpcmNsZSIpLAogIGZpbGxjb2xvciA9IGMoInJlZCIpLAogIGNvbG9yID0gYygicmVkIikKKQoKIyBDb21iaW5lIHRoZSBsZWdlbmQgZGF0YSBmcmFtZXMKbGVnZW5kIDwtIHJiaW5kKGxlZ2VuZCwgc21va2luZ19sZWdlbmQsIGFsY19sZWdlbmQpCgojIFRoZSBnZ3Bsb3QgY2FsbApsZWdlbmRfcF8yIDwtIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGRhdGEgPSBsZWdlbmQsIAogICAgICAgICAgICAgYWVzKHggPSAxLCB5ID0gZ3JvdXAsIGZpbGwgPSBmaWxsY29sb3IsIGNvbG9yID0gY29sb3IsIHNoYXBlID0gc2hhcGUpLCAKICAgICAgICAgICAgIHNpemUgPSA1KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBsZWdlbmQsIAogICAgICAgICAgICBhZXMoeCA9IDEuMSwgeSA9IGdyb3VwLCBsYWJlbCA9IGdyb3VwKSwgCiAgICAgICAgICAgIGhqdXN0ID0gMCkgKwogIHNjYWxlX2ZpbGxfaWRlbnRpdHkoKSArCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoInNxdWFyZSIgPSAyMiwgImNpcmNsZSIgPSAyMSkpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDEsIDIpKSAgIyBBZGp1c3QgYXMgbmVjZXNzYXJ5IHRvIGVuc3VyZSBsYWJlbHMgZml0CgojIFByaW50IHRoZSBwbG90CmxlZ2VuZF9wXzIKCmBgYAoKYGBge3J9CmxlZ2VuZF9wXzIKYGBgCgpIb3Jpem9udGFsIGxlZ2VuZCBhbGlnbm1lbnQ6CgpgYGB7cn0KIyBDcmVhdGUgYSBsZWdlbmQKbGVnZW5kIDwtIGRhdGEuZnJhbWUoCiAgZ3JvdXAgPSBjKCJSZWNlbnRseSBSZWxlYXNlZCIsICJOZXR3b3JrIE1lbWJlciIsICJDdXJyZW50IFNtb2tpbmciLCAiSGVhdnkgQWxjb2hvbCBVc2UiKSwKICBzaGFwZSA9IGMoInNxdWFyZSIsICJjaXJjbGUiLCAiY2lyY2xlIiwgImNpcmNsZSIpLAogIGZpbGxjb2xvciA9IGMoImJsYWNrIiwgIndoaXRlIiwgImJsdWUiLCAicmVkIiksCiAgY29sb3IgPSBjKCJibGFjayIsICJibGFjayIsICJibHVlIiwgInJlZCIpCikKCiMgVGhlIGdncGxvdCBjYWxsCmhvcml6b250YWxfbGVnZW5kX3AgPC0gZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGxlZ2VuZCwgCiAgICAgICAgICAgICBhZXMoeCA9IGdyb3VwLCB5ID0gMSwgZmlsbCA9IGZpbGxjb2xvciwgY29sb3IgPSBjb2xvciwgc2hhcGUgPSBzaGFwZSksIAogICAgICAgICAgICAgc2l6ZSA9IDUpICsKICBnZW9tX3RleHQoZGF0YSA9IGxlZ2VuZCwgCiAgICAgICAgICAgIGFlcyh4ID0gZ3JvdXAsIHkgPSAxLjEsIGxhYmVsID0gZ3JvdXApLCAKICAgICAgICAgICAgdmp1c3QgPSAtMC41LCBhbmdsZSA9IDQ1LCBoanVzdCA9IDEpICsKICBzY2FsZV9maWxsX2lkZW50aXR5KCkgKwogIHNjYWxlX2NvbG9yX2lkZW50aXR5KCkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJzcXVhcmUiID0gMjIsICJjaXJjbGUiID0gMjEpKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIgogICkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLjgsIDIpKSAgIyBBZGp1c3QgYXMgbmVjZXNzYXJ5IHRvIGVuc3VyZSBsYWJlbHMgZml0CgojIFByaW50IHRoZSBwbG90Cmhvcml6b250YWxfbGVnZW5kX3AKCmBgYAoKUGxvdCBBVUQgYW5kIEN1cnJlbnQgU21raW5nIGluIHRoZSBuZXR3b3JrcyBvZiBhIHNhbWUgbnVtYmVyIG9mIGFnZW50cyB3aG8gaGF2ZSBuZXZlciBiZWVuIGluY2FyY2VyYXRlZDoKCmBgYHtyfQojIFNldCBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoU3lzLnRpbWUoKSkKCiMgSWRlbnRpZnkgdGhlIElEcyBvZiB0aGUgYWdlbnRzIHdobyBoYXZlIG5ldmVyIGJlZW4gaW5jYXJjZXJhdGVkCm5ldmVyX2luY2FyY2VyYXRlZF9hZ2VudHMgPC0gbGFzdF90aWNrX2FnZW50X2R0JGlkW2xhc3RfdGlja19hZ2VudF9kdCRuX2luY2FyY2VyYXRpb25zID09IDBdCgojIFJhbmRvbWx5IHNlbGVjdCAzNiBhZ2VudHMgd2hvIGhhdmUgbmV2ZXIgYmVlbiBpbmNhcmNlcmF0ZWQKc2VsZWN0ZWRfYWdlbnRzIDwtIHNhbXBsZShuZXZlcl9pbmNhcmNlcmF0ZWRfYWdlbnRzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gbGVuZ3RoKHJlY2VudGx5X3JlbGVhc2VkX2FnZW50cykpCgojIEdldCB0aGUgbmV0d29yayBkYXRhIGZvciB0aGUgc2VsZWN0ZWQgYWdlbnRzCm5ldHdvcmtfc2VsZWN0ZWRfYWdlbnRzIDwtIGxhc3RfdGlja19uZXR3b3JrX2R0WyhsYXN0X3RpY2tfbmV0d29ya19kdCRwMSAlaW4lIHNlbGVjdGVkX2FnZW50cykgfCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGxhc3RfdGlja19uZXR3b3JrX2R0JHAyICVpbiUgc2VsZWN0ZWRfYWdlbnRzKSxdCgojIEdldCB0aGUgZmlyc3QtZGVncmVlIG5ldHdvcmsgKG5laWdoYm9ycykgZm9yIGVhY2ggYWdlbnQKZmlyc3RfZGVncmVlX25laWdoYm9ycyA8LSB1bmlxdWUoYyhuZXR3b3JrX3NlbGVjdGVkX2FnZW50cyRwMSwgbmV0d29ya19zZWxlY3RlZF9hZ2VudHMkcDIpKQoKIyBHZXQgYWdlbnQgZGF0YSBmb3IgdGhlIGZpcnN0LWRlZ3JlZSBuZWlnaGJvcnMKZmlyc3RfZGVncmVlX25laWdoYm9yc19hZ2VudF9kYXRhIDwtIGxhc3RfdGlja19hZ2VudF9kdFtsYXN0X3RpY2tfYWdlbnRfZHQkaWQgJWluJSBmaXJzdF9kZWdyZWVfbmVpZ2hib3JzLF0KCiMgQ3JlYXRlIGFuIGVkZ2UgZGF0YSBmcmFtZSBmcm9tIHlvdXIgbmV0d29yayBkYXRhCmVkZiA8LSBkYXRhLmZyYW1lKGZyb20gPSBuZXR3b3JrX3NlbGVjdGVkX2FnZW50cyRwMSwgCiAgICAgICAgICAgICAgICAgIHRvID0gbmV0d29ya19zZWxlY3RlZF9hZ2VudHMkcDIpCgojIENyZWF0ZSBhIG5vZGUgZGF0YSBmcmFtZSB3aXRoIHlvdXIgYWdlbnQgZGF0YQpuZGYgPC0gZGF0YS5mcmFtZShpZCA9IGZpcnN0X2RlZ3JlZV9uZWlnaGJvcnNfYWdlbnRfZGF0YSRpZCwgCiAgICAgICAgICAgICAgICAgIHNtb2tpbmdfc3RhdHVzID0gZmlyc3RfZGVncmVlX25laWdoYm9yc19hZ2VudF9kYXRhJHNtb2tpbmdfc3RhdHVzLAogICAgICAgICAgICAgICAgICBhbGNfdXNlX3N0YXR1cyA9IGZpcnN0X2RlZ3JlZV9uZWlnaGJvcnNfYWdlbnRfZGF0YSRhbGNfdXNlX3N0YXR1cykKCiMgQ3JlYXRlIGEgZ3JhcGggd2l0aCBEaWFncmFtbWVSCmdyYXBoIDwtIGNyZWF0ZV9ncmFwaChub2Rlc19kZiA9IG5kZiwgCiAgICAgICAgICAgICAgICAgICAgICBlZGdlc19kZiA9IGVkZiwKICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGVkID0gRkFMU0UpCgojIEN1c3RvbWl6ZSB0aGUgbm9kZSBmaWxsY29sb3IgYmFzZWQgb24gc21va2luZ19zdGF0dXMgYW5kIGFsY191c2Vfc3RhdHVzCmdyYXBoIDwtIHNldF9ub2RlX2F0dHJzKGdyYXBoLCAiZmlsbGNvbG9yIiwgaWZlbHNlKG5kZiRzbW9raW5nX3N0YXR1cyA9PSAiQ3VycmVudCIsICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG5kZiRhbGNfdXNlX3N0YXR1cyA9PSAzLCAiYmx1ZSIsICJ3aGl0ZSIpKSkKCiMgQ3VzdG9taXplIHRoZSBub2RlIGNvbG9yIGJhc2VkIG9uIHNtb2tpbmdfc3RhdHVzIGFuZCBhbGNfdXNlX3N0YXR1cwpncmFwaCA8LSBzZXRfbm9kZV9hdHRycyhncmFwaCwgImNvbG9yIiwgaWZlbHNlKG5kZiRzbW9raW5nX3N0YXR1cyA9PSAiQ3VycmVudCIsICJyZWQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobmRmJGFsY191c2Vfc3RhdHVzID09IDMsICJibHVlIiwgImdyYXkiKSkpCgojIFJlbW92ZSBsYWJlbHMgZnJvbSBub2RlcyB0byBtYWtlIHRoZW0gc3RhbmQgb3V0IG1vcmUKZ3JhcGggPC0gc2V0X25vZGVfYXR0cnMoZ3JhcGgsICJsYWJlbCIsICIiKQoKIyBSZW5kZXIgdGhlIGdyYXBoCnJlbmRlcl9ncmFwaChncmFwaCkKCmBgYAoKTnVtZXJpY2FsIHByZXZhbGVuY2Ugb2YgQVVEIGFuZCBDdXJyZW50IFNtb2tpbmcgaW4gdGhpcyBuZXR3b3JrOgpgYGB7cn0KIyBOdW1iZXIgb2YgYWdlbnRzIHdpdGggQ3VycmVudCBTbW9raW5nIHN0YXR1cwpudW1fY3VycmVudF9zbW9raW5nIDwtIHN1bShmaXJzdF9kZWdyZWVfbmVpZ2hib3JzX2FnZW50X2RhdGEkc21va2luZ19zdGF0dXMgPT0gIkN1cnJlbnQiKQoKIyBOdW1iZXIgb2YgYWdlbnRzIHdpdGggQVVECm51bV9hdWQgPC0gc3VtKGZpcnN0X2RlZ3JlZV9uZWlnaGJvcnNfYWdlbnRfZGF0YSRhbGNfdXNlX3N0YXR1cyA9PSAzKQoKIyBUb3RhbCBudW1iZXIgb2YgYWdlbnRzIGluIHRoZSBuZXR3b3JrCnRvdGFsX2FnZW50cyA8LSBucm93KGZpcnN0X2RlZ3JlZV9uZWlnaGJvcnNfYWdlbnRfZGF0YSkKCiMgQ2FsY3VsYXRlIHByZXZhbGVuY2UKcHJldmFsZW5jZV9zbW9raW5nIDwtIG51bV9jdXJyZW50X3Ntb2tpbmcgLyB0b3RhbF9hZ2VudHMKcHJldmFsZW5jZV9hdWQgPC0gbnVtX2F1ZCAvIHRvdGFsX2FnZW50cwoKIyBQcmludCB0aGUgcmVzdWx0cwpjYXQoIlByZXZhbGVuY2Ugb2YgQ3VycmVudCBTbW9raW5nIGluIHRoZSBuZXR3b3JrcyBvZiByYW5kb21seSAKICAgIHNlbGVjdGVkIG5ldmVyIGluY2FyY2VyYXRlZCBwZXJzb25zOiAiLCBwcmV2YWxlbmNlX3Ntb2tpbmcsICJcbiIpCmNhdCgiUHJldmFsZW5jZSBvZiBBVUQgaW4gdGhlIG5ldHdvcmtzIG9mIHJhbmRvbWx5IAogICAgc2VsZWN0ZWQgbmV2ZXIgaW5jYXJjZXJhdGVkIHBlcnNvbnM6ICIsIHByZXZhbGVuY2VfYXVkLCAiXG4iKQoKYGBgCgpTbW9raW5nIGFuZCBBVUQgYW1vbmcgdGhlIGVnb3M6CgpgYGB7cn0KIyBEZWZpbmUgc2VsZWN0ZWRfYWdlbnRzX2RmLCB3aGljaCBjb250YWlucyB0aGUgZGF0YSBmb3IgdGhlIHNlbGVjdGVkIGFnZW50cwpzZWxlY3RlZF9hZ2VudHNfZGYgPC0gbGFzdF90aWNrX2FnZW50X2R0W2xhc3RfdGlja19hZ2VudF9kdCRpZCAlaW4lIHNlbGVjdGVkX2FnZW50cyxdCgojIE51bWJlciBvZiBzZWxlY3RlZCBhZ2VudHMgd2hvIGFyZSBjdXJyZW50IHNtb2tlcnMKbnVtX2Vnb19jdXJyZW50X3Ntb2tpbmcgPC0gc3VtKHNlbGVjdGVkX2FnZW50c19kZiRzbW9raW5nX3N0YXR1cyA9PSAiQ3VycmVudCIpCgojIE51bWJlciBvZiBzZWxlY3RlZCBhZ2VudHMgd2l0aCBBVUQKbnVtX2Vnb19hdWQgPC0gc3VtKHNlbGVjdGVkX2FnZW50c19kZiRhbGNfdXNlX3N0YXR1cyA9PSAzKQoKIyBUb3RhbCBudW1iZXIgb2Ygc2VsZWN0ZWQgYWdlbnRzCnRvdGFsX2Vnb19hZ2VudHMgPC0gbGVuZ3RoKHNlbGVjdGVkX2FnZW50cykKCiMgQ2FsY3VsYXRlIHByZXZhbGVuY2UKcHJldmFsZW5jZV9lZ29fc21va2luZyA8LSBudW1fZWdvX2N1cnJlbnRfc21va2luZyAvIHRvdGFsX2Vnb19hZ2VudHMKcHJldmFsZW5jZV9lZ29fYXVkIDwtIG51bV9lZ29fYXVkIC8gdG90YWxfZWdvX2FnZW50cwoKIyBQcmludCB0aGUgcmVzdWx0cwpjYXQoIlByZXZhbGVuY2Ugb2YgQ3VycmVudCBTbW9raW5nIGFtb25nIHNlbGVjdGVkIGFnZW50czogIiwgcHJldmFsZW5jZV9lZ29fc21va2luZywgIlxuIikKY2F0KCJQcmV2YWxlbmNlIG9mIEFVRCBhbW9uZyBzZWxlY3RlZCBhZ2VudHM6ICIsIHByZXZhbGVuY2VfZWdvX2F1ZCwgIlxuIikKCmBgYAoK