1. PREPARE

1a. Purpose and Research Questions

The purpose of this case study is to analyze the social network of tweets about the Next Generation Science Standards (NGSS), and understand how NGSS was publicly received by teachers, students, and parents. Research questions for this case study include

  1. Who are the transmitters, transceivers, and transcenders in the Next Generation Science Standards Twitter network?
  2. How do users interact with each other in the social network?

1b. Data Sources

The data source for this case study is the ngss-tweets.csv file, which has tweets and user information related to online conversations about NGSS.

1c. Set up Project and Load Libraries

library(tidytext)
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.4.0      ✔ purrr   0.3.5 
## ✔ tibble  3.1.8      ✔ dplyr   1.0.10
## ✔ tidyr   1.2.1      ✔ stringr 1.4.1 
## ✔ readr   2.1.3      ✔ forcats 0.5.2 
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
library(vader)
library(tidygraph)
## 
## Attaching package: 'tidygraph'
## 
## The following object is masked from 'package:stats':
## 
##     filter
library(ggraph)
library(igraph)
## 
## Attaching package: 'igraph'
## 
## The following object is masked from 'package:tidygraph':
## 
##     groups
## 
## The following objects are masked from 'package:dplyr':
## 
##     as_data_frame, groups, union
## 
## The following objects are masked from 'package:purrr':
## 
##     compose, simplify
## 
## The following object is masked from 'package:tidyr':
## 
##     crossing
## 
## The following object is masked from 'package:tibble':
## 
##     as_data_frame
## 
## The following objects are masked from 'package:stats':
## 
##     decompose, spectrum
## 
## The following object is masked from 'package:base':
## 
##     union

1d. Import Data

I imported the data from the ngss_tweets.csv file into a new dataframe.

ngss_tweets <- read_csv("data/ngss-tweets.csv")
## Warning: One or more parsing issues, call `problems()` on your data frame for details,
## e.g.:
##   dat <- vroom(...)
##   problems(dat)
## Rows: 8126 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (2): text, source
## dbl  (4): author_id, id, conversation_id, in_reply_to_user_id
## lgl  (1): possibly_sensitive
## dttm (1): created_at
## 
## ℹ 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.
ngss_tweets
## # A tibble: 8,126 × 8
##    text      created_at          autho…¹      id conve…² source possi…³ in_rep…⁴
##    <chr>     <dttm>                <dbl>   <dbl>   <dbl> <chr>  <lgl>      <dbl>
##  1 "Please … 2021-01-06 00:50:49 3.28e 9 1.35e18 1.35e18 Twitt… FALSE   NA      
##  2 "What la… 2021-01-06 00:45:32 1.01e18 1.35e18 1.35e18 Hoots… FALSE   NA      
##  3 "I recen… 2021-01-06 00:39:37 6.18e 7 1.35e18 1.35e18 Twitt… FALSE   NA      
##  4 "I'm thr… 2021-01-06 00:30:13 4.62e 8 1.35e18 1.35e18 Twitt… FALSE   NA      
##  5 "PLS RT.… 2021-01-06 00:15:05 2.23e 7 1.35e18 1.35e18 Twitt… FALSE   NA      
##  6 "Inspire… 2021-01-06 00:00:00 3.32e 9 1.35e18 1.35e18 Tweet… FALSE   NA      
##  7 "PLTW La… 2021-01-05 23:45:06 1.73e 7 1.35e18 1.35e18 Hoots… FALSE   NA      
##  8 "@NGSS_t… 2021-01-05 23:24:01 1.02e18 1.35e18 1.35e18 Twitt… FALSE    1.02e18
##  9 "@NGSS_t… 2021-01-05 23:21:56 1.02e18 1.35e18 1.35e18 Twitt… FALSE    4.92e 9
## 10 "January… 2021-01-05 23:10:03 2.37e 7 1.35e18 1.35e18 Hoots… FALSE   NA      
## # … with 8,116 more rows, and abbreviated variable names ¹​author_id,
## #   ²​conversation_id, ³​possibly_sensitive, ⁴​in_reply_to_user_id

2. WRANGLE

Data Pre-processing and Transformations

To clean and prepare the data for analysis, I transformed the numerical data for user IDs to characters, created an edgelist, formated the network data, and created a network object.

Edgelist

head(ngss_tweets)

Extract Edges and Nodes

edge_1 <- ngss_tweets |>
  relocate(sender = author_id, 
           target = in_reply_to_user_id) |> 
  select(sender,
         target,
         created_at,
         text, source)
edge_1 <- transform(edge_1, sender = as.character(sender)) |>
  transform(edge_1, target = as.character(target))

“Unnest” User Names

edge_2 <- edge_1 |>
  unnest_tokens(input = target,
                output = receiver,
                to_lower = FALSE) |>
  relocate(sender, receiver)
edges <- edge_2 %>%
  drop_na(receiver)
edges

Create Nodelist

network_actors <- edges |>
  select(sender, receiver) |>
  pivot_longer(cols = c(sender,receiver))

network_actors
## # A tibble: 5,602 × 2
##    name     value              
##    <chr>    <chr>              
##  1 sender   1023054370529857536
##  2 receiver 1023054370529857536
##  3 sender   1023054370529857536
##  4 receiver 4918507542         
##  5 sender   1555906686         
##  6 receiver 4918507542         
##  7 sender   1211837761444954112
##  8 receiver 4918507542         
##  9 sender   1342104169         
## 10 receiver 1342104169         
## # … with 5,592 more rows
actors <- network_actors |>
  select(value) |>
  rename(actors = value) |> 
  distinct()

actors
## # A tibble: 1,093 × 1
##    actors             
##    <chr>              
##  1 1023054370529857536
##  2 4918507542         
##  3 1555906686         
##  4 1211837761444954112
##  5 1342104169         
##  6 260773268          
##  7 2198414407         
##  8 3296431010         
##  9 883384220835606528 
## 10 255769626          
## # … with 1,083 more rows

Create Network Object

Combine Edges & Nodes

ngss_network_1 <- tbl_graph(edges = edges, 
                            nodes = actors)

ngss_network_1
## # A tbl_graph: 1093 nodes and 2801 edges
## #
## # A directed multigraph with 241 components
## #
## # Node Data: 1,093 × 1 (active)
##   actors             
##   <chr>              
## 1 1023054370529857536
## 2 4918507542         
## 3 1555906686         
## 4 1211837761444954112
## 5 1342104169         
## 6 260773268          
## # … with 1,087 more rows
## #
## # Edge Data: 2,801 × 10
##    from    to created_at          text  source sender… target…
##   <int> <int> <dttm>              <chr> <chr>    <dbl>   <dbl>
## 1     1     1 2021-01-05 23:24:01 "@NG… Twitt… 1.02e18 1.02e18
## 2     1     2 2021-01-05 23:21:56 "@NG… Twitt… 1.02e18 4.92e 9
## 3     3     2 2021-01-05 23:09:06 "@NG… Twitt… 1.56e 9 4.92e 9
## # … with 2,798 more rows, and 3 more variables: created_at.1 <dttm>,
## #   text.1 <chr>, source.1 <chr>

3. Analyze

Techniques, Metrics, and Data Visualizations.

For this analysis, I used techniques such as calculating meaures of centrality and node degrees, and adding nodes, edges and layouts to determine who the transmitters, transceivers, and transcenders are. In addition to this, I created sociograms with the autograph() and ggraph() functions to visualize the relationships between users and the social network. I also identified groups

Examine Basic Descriptives

Centrality

Node Degree

ngss_network <- ngss_network_1 |>
  activate(nodes) |>
  mutate(degree = centrality_degree(mode = "all")) |>
  mutate(in_degree = centrality_degree(mode = "in"))

ngss_network
## # A tbl_graph: 1093 nodes and 2801 edges
## #
## # A directed multigraph with 241 components
## #
## # Node Data: 1,093 × 3 (active)
##   actors              degree in_degree
##   <chr>                <dbl>     <dbl>
## 1 1023054370529857536     16         6
## 2 4918507542             589       550
## 3 1555906686               4         1
## 4 1211837761444954112     10         1
## 5 1342104169              14         8
## 6 260773268               18         7
## # … with 1,087 more rows
## #
## # Edge Data: 2,801 × 10
##    from    to created_at          text  source sender… target…
##   <int> <int> <dttm>              <chr> <chr>    <dbl>   <dbl>
## 1     1     1 2021-01-05 23:24:01 "@NG… Twitt… 1.02e18 1.02e18
## 2     1     2 2021-01-05 23:21:56 "@NG… Twitt… 1.02e18 4.92e 9
## 3     3     2 2021-01-05 23:09:06 "@NG… Twitt… 1.56e 9 4.92e 9
## # … with 2,798 more rows, and 3 more variables: created_at.1 <dttm>,
## #   text.1 <chr>, source.1 <chr>
ngss_network <- ngss_network_1 |>
  activate(nodes) |>
  mutate(degree = centrality_degree(mode = "all")) |>
  mutate(in_degree = centrality_degree(mode = "in")) |>
  mutate(out_degree = centrality_degree(mode = "out"))


ngss_network
## # A tbl_graph: 1093 nodes and 2801 edges
## #
## # A directed multigraph with 241 components
## #
## # Node Data: 1,093 × 4 (active)
##   actors              degree in_degree out_degree
##   <chr>                <dbl>     <dbl>      <dbl>
## 1 1023054370529857536     16         6         10
## 2 4918507542             589       550         39
## 3 1555906686               4         1          3
## 4 1211837761444954112     10         1          9
## 5 1342104169              14         8          6
## 6 260773268               18         7         11
## # … with 1,087 more rows
## #
## # Edge Data: 2,801 × 10
##    from    to created_at          text  source sender… target…
##   <int> <int> <dttm>              <chr> <chr>    <dbl>   <dbl>
## 1     1     1 2021-01-05 23:24:01 "@NG… Twitt… 1.02e18 1.02e18
## 2     1     2 2021-01-05 23:21:56 "@NG… Twitt… 1.02e18 4.92e 9
## 3     3     2 2021-01-05 23:09:06 "@NG… Twitt… 1.56e 9 4.92e 9
## # … with 2,798 more rows, and 3 more variables: created_at.1 <dttm>,
## #   text.1 <chr>, source.1 <chr>

Summarize Centrality Measures

node_measures <- ngss_network |> 
  activate(nodes) |>
  data.frame()

summary(node_measures)
##     actors              degree          in_degree         out_degree     
##  Length:1093        Min.   :  1.000   Min.   :  0.000   Min.   :  0.000  
##  Class :character   1st Qu.:  1.000   1st Qu.:  0.000   1st Qu.:  0.000  
##  Mode  :character   Median :  1.000   Median :  1.000   Median :  1.000  
##                     Mean   :  5.125   Mean   :  2.563   Mean   :  2.563  
##                     3rd Qu.:  3.000   3rd Qu.:  1.000   3rd Qu.:  2.000  
##                     Max.   :589.000   Max.   :550.000   Max.   :121.000
view(node_measures)

Sociograms

autograph(ngss_network)

Adding Nodes

ggraph(ngss_network)+
  geom_node_point()
## Using "stress" as default layout

Adding Layout

ggraph(ngss_network, layout = "fr") +
  geom_node_point()

Tweaking Nodes

ggraph(ngss_network, layout = "fr") + 
geom_node_point(aes(size = out_degree,
                    color = out_degree))

ggraph(ngss_network, layout = "fr") + 
  geom_node_point(aes(size = out_degree,
                      color = out_degree)) +
  geom_node_text(aes(label = actors,
                     size = out_degree/2,
                     color = out_degree),
                 repel=TRUE)
## Warning: ggrepel: 1006 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

Adding Edges

ggraph(ngss_network, layout = "fr") + 
  geom_node_point(aes(size = out_degree,
                      color = out_degree)) +
  geom_node_text(aes(label = actors,
                     size = out_degree/2,
                     color = out_degree),
                 repel=TRUE) +
  geom_edge_link(arrow = arrow(length = unit(1, 'mm')), 
                 end_cap = circle(3, 'mm'),
                 alpha = .2)
## Warning: Using the `size` aesthetic in this geom was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` in the `default_aes` field and elsewhere instead.
## Warning: ggrepel: 1019 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

Adding a Theme

ggraph(ngss_network, layout = "fr") + 
  geom_node_point(aes(size = out_degree,
                      color = out_degree),
                  show.legend = FALSE) +
  geom_node_text(aes(label = actors,
                     size = out_degree/2,
                     color = out_degree),
                 repel=TRUE,
                 show.legend = FALSE) +
  geom_edge_link(arrow = arrow(length = unit(1, 'mm')), 
                 end_cap = circle(3, 'mm'),
                 alpha = .2) + 
  theme_graph()
## Warning: ggrepel: 996 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

ggraph(ngss_network, layout = "fr") + 
  geom_node_point(aes(size = in_degree,
                      color = in_degree),
                  show.legend = FALSE) +
  geom_node_text(aes(label = actors,
                     size = in_degree/2,
                     color = in_degree),
                 repel=TRUE,
                 show.legend = FALSE) +
  geom_edge_link(arrow = arrow(length = unit(1, 'mm')), 
                 end_cap = square(3, 'mm'),
                 alpha = .5) + 
  theme_graph()
## Warning: ggrepel: 949 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps

Identifying Groups

Community Detection

ngss_network_groups <- ngss_network |>
  activate(nodes) |>
  mutate(group = group_components())
  
ngss_network_groups
## # A tbl_graph: 1093 nodes and 2801 edges
## #
## # A directed multigraph with 241 components
## #
## # Node Data: 1,093 × 5 (active)
##   actors              degree in_degree out_degree group
##   <chr>                <dbl>     <dbl>      <dbl> <int>
## 1 1023054370529857536     16         6         10     1
## 2 4918507542             589       550         39     1
## 3 1555906686               4         1          3     1
## 4 1211837761444954112     10         1          9     1
## 5 1342104169              14         8          6     1
## 6 260773268               18         7         11     1
## # … with 1,087 more rows
## #
## # Edge Data: 2,801 × 10
##    from    to created_at          text  source sender… target…
##   <int> <int> <dttm>              <chr> <chr>    <dbl>   <dbl>
## 1     1     1 2021-01-05 23:24:01 "@NG… Twitt… 1.02e18 1.02e18
## 2     1     2 2021-01-05 23:21:56 "@NG… Twitt… 1.02e18 4.92e 9
## 3     3     2 2021-01-05 23:09:06 "@NG… Twitt… 1.56e 9 4.92e 9
## # … with 2,798 more rows, and 3 more variables: created_at.1 <dttm>,
## #   text.1 <chr>, source.1 <chr>
ngss_network_groups |>
  ggraph(layout = "fr") + 
  geom_node_point(aes(size = out_degree, 
                      color = out_degree),
                  show.legend = FALSE) +
  geom_node_text(aes(label = actors, 
                     color = out_degree,
                     size = out_degree), 
                     repel=TRUE,
                 show.legend = FALSE) +
  geom_edge_link(arrow = arrow(length = unit(1, 'mm')), 
                 end_cap = circle(3, 'mm'),
                 alpha = .2) + 
  theme_graph() + 
  geom_node_voronoi(aes(fill = factor(group),
                         alpha = .05), 
                    max.radius = .5,
                    show.legend = FALSE) 
## Warning: ggrepel: 991 unlabeled data points (too many overlaps). Consider
## increasing max.overlaps


5. COMMUNICATE

Key Findings

Some key findings are who the transcenders, tranceivers, and transformers are:

  • Transmitters: User 558971700 because they have the highest outdegree measurement

  • Transceivers: User 4918507542 because they have the highest indegree measurement

  • Transcenders: User 184649645 because they have the same indegree and outdegree measurement and the highest combination of the two

In addition to this, the sociograms show a large of cluster of nodes, indicating high activity among those users.

Potential action

One potential course of action could be to do a sentiment analysis on this data to understand the public reaction to the NGSS standards. In addition, it would be interesting to see if the reactions are influenced by other factors, such as political affiliation, the age of the students affected, and the social media network the user is posting on.

Limitations and ethical issues

One limitation is that the users are identified through a numeric author ID instead of a user name or screen name. This makes it difficult to identify and keep track of users.

In addition, it’s important to make sure social media users like in this case study are aware of how thier information is being used. Even though they are not identifiable by screen name, they may not be comfortable that what they posted in circulating in studies and platforms they may not be familiar with.

LS0tCnRpdGxlOiAiYWRveWxlLWZpbmFsLXByb2plY3QuUm1kIgphdXRob3I6ICJBaW5lIERveWxlIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgY29kZV9kb3dubG9hZDogVFJVRQplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IDcyCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIDEuIFBSRVBBUkUge2RhdGEtbGluaz0iMS4gUFJFUEFSRSJ9CgojIyAxYS4gUHVycG9zZSBhbmQgUmVzZWFyY2ggUXVlc3Rpb25zIHtkYXRhLWxpbms9IjFhLiBQdXJwb3NlIGFuZCBSZXNlYXJjaCBRdWVzdGlvbnMifQoKVGhlIHB1cnBvc2Ugb2YgdGhpcyBjYXNlIHN0dWR5IGlzIHRvIGFuYWx5emUgdGhlIHNvY2lhbCBuZXR3b3JrIG9mCnR3ZWV0cyBhYm91dCB0aGUgTmV4dCBHZW5lcmF0aW9uIFNjaWVuY2UgU3RhbmRhcmRzIChOR1NTKSwgYW5kCnVuZGVyc3RhbmQgaG93IE5HU1Mgd2FzIHB1YmxpY2x5IHJlY2VpdmVkIGJ5IHRlYWNoZXJzLCBzdHVkZW50cywgYW5kCnBhcmVudHMuIFJlc2VhcmNoIHF1ZXN0aW9ucyBmb3IgdGhpcyBjYXNlIHN0dWR5IGluY2x1ZGUKCjEuICBXaG8gYXJlIHRoZSB0cmFuc21pdHRlcnMsIHRyYW5zY2VpdmVycywgYW5kIHRyYW5zY2VuZGVycyBpbiB0aGUgTmV4dAogICAgR2VuZXJhdGlvbiBTY2llbmNlIFN0YW5kYXJkcyBUd2l0dGVyIG5ldHdvcms/CjIuICBIb3cgZG8gdXNlcnMgaW50ZXJhY3Qgd2l0aCBlYWNoIG90aGVyIGluIHRoZSBzb2NpYWwgbmV0d29yaz8KCiMjIDFiLiBEYXRhIFNvdXJjZXMge2RhdGEtbGluaz0iMWIuIERhdGEgU291cmNlcyJ9CgpUaGUgZGF0YSBzb3VyY2UgZm9yIHRoaXMgY2FzZSBzdHVkeSBpcyB0aGUgYG5nc3MtdHdlZXRzLmNzdmAgZmlsZSwgd2hpY2gKaGFzIHR3ZWV0cyBhbmQgdXNlciBpbmZvcm1hdGlvbiByZWxhdGVkIHRvIG9ubGluZSBjb252ZXJzYXRpb25zIGFib3V0Ck5HU1MuCgojIyAxYy4gU2V0IHVwIFByb2plY3QgYW5kIExvYWQgTGlicmFyaWVzIHtkYXRhLWxpbms9IjFjLiBTZXQgdXAgUHJvamVjdCBhbmQgTG9hZCBMaWJyYXJpZXMifQoKYGBge3J9CgpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh2YWRlcikKbGlicmFyeSh0aWR5Z3JhcGgpCmxpYnJhcnkoZ2dyYXBoKQpsaWJyYXJ5KGlncmFwaCkKYGBgCgojIyAxZC4gSW1wb3J0IERhdGEge2RhdGEtbGluaz0iMWQuIEltcG9ydCBEYXRhIn0KCkkgaW1wb3J0ZWQgdGhlIGRhdGEgZnJvbSB0aGUgYG5nc3NfdHdlZXRzLmNzdmAgZmlsZSBpbnRvIGEgbmV3CmRhdGFmcmFtZS4KCmBgYHtyfQpuZ3NzX3R3ZWV0cyA8LSByZWFkX2NzdigiZGF0YS9uZ3NzLXR3ZWV0cy5jc3YiKQoKbmdzc190d2VldHMKCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIDIuIFdSQU5HTEUKCiMjIERhdGEgUHJlLXByb2Nlc3NpbmcgYW5kIFRyYW5zZm9ybWF0aW9ucwoKVG8gY2xlYW4gYW5kIHByZXBhcmUgdGhlIGRhdGEgZm9yIGFuYWx5c2lzLCBJIHRyYW5zZm9ybWVkIHRoZSBudW1lcmljYWwKZGF0YSBmb3IgdXNlciBJRHMgdG8gY2hhcmFjdGVycywgY3JlYXRlZCBhbiBlZGdlbGlzdCwgZm9ybWF0ZWQgdGhlCm5ldHdvcmsgZGF0YSwgYW5kIGNyZWF0ZWQgYSBuZXR3b3JrIG9iamVjdC4KCiMjIyBFZGdlbGlzdAoKYGBge3IsIGV2YWw9RkFMU0V9CmhlYWQobmdzc190d2VldHMpCgpgYGAKCiMjIyMgRXh0cmFjdCBFZGdlcyBhbmQgTm9kZXMKCmBgYHtyfQplZGdlXzEgPC0gbmdzc190d2VldHMgfD4KICByZWxvY2F0ZShzZW5kZXIgPSBhdXRob3JfaWQsIAogICAgICAgICAgIHRhcmdldCA9IGluX3JlcGx5X3RvX3VzZXJfaWQpIHw+IAogIHNlbGVjdChzZW5kZXIsCiAgICAgICAgIHRhcmdldCwKICAgICAgICAgY3JlYXRlZF9hdCwKICAgICAgICAgdGV4dCwgc291cmNlKQoKCmBgYAoKYGBge3J9CmVkZ2VfMSA8LSB0cmFuc2Zvcm0oZWRnZV8xLCBzZW5kZXIgPSBhcy5jaGFyYWN0ZXIoc2VuZGVyKSkgfD4KICB0cmFuc2Zvcm0oZWRnZV8xLCB0YXJnZXQgPSBhcy5jaGFyYWN0ZXIodGFyZ2V0KSkKYGBgCgojIyMjICJVbm5lc3QiIFVzZXIgTmFtZXMKCmBgYHtyfQplZGdlXzIgPC0gZWRnZV8xIHw+CiAgdW5uZXN0X3Rva2VucyhpbnB1dCA9IHRhcmdldCwKICAgICAgICAgICAgICAgIG91dHB1dCA9IHJlY2VpdmVyLAogICAgICAgICAgICAgICAgdG9fbG93ZXIgPSBGQUxTRSkgfD4KICByZWxvY2F0ZShzZW5kZXIsIHJlY2VpdmVyKQoKYGBgCgpgYGB7cn0KZWRnZXMgPC0gZWRnZV8yICU+JQogIGRyb3BfbmEocmVjZWl2ZXIpCgpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQoKZWRnZXMKYGBgCgojIyMgQ3JlYXRlIE5vZGVsaXN0CgpgYGB7cn0KbmV0d29ya19hY3RvcnMgPC0gZWRnZXMgfD4KICBzZWxlY3Qoc2VuZGVyLCByZWNlaXZlcikgfD4KICBwaXZvdF9sb25nZXIoY29scyA9IGMoc2VuZGVyLHJlY2VpdmVyKSkKCm5ldHdvcmtfYWN0b3JzCmBgYAoKYGBge3J9CmFjdG9ycyA8LSBuZXR3b3JrX2FjdG9ycyB8PgogIHNlbGVjdCh2YWx1ZSkgfD4KICByZW5hbWUoYWN0b3JzID0gdmFsdWUpIHw+IAogIGRpc3RpbmN0KCkKCmFjdG9ycwpgYGAKCiMjIyAKCiMjIENyZWF0ZSBOZXR3b3JrIE9iamVjdAoKIyMjIENvbWJpbmUgRWRnZXMgJiBOb2RlcwoKYGBge3J9Cm5nc3NfbmV0d29ya18xIDwtIHRibF9ncmFwaChlZGdlcyA9IGVkZ2VzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vZGVzID0gYWN0b3JzKQoKbmdzc19uZXR3b3JrXzEKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgMy4gQW5hbHl6ZQoKIyMgVGVjaG5pcXVlcywgTWV0cmljcywgYW5kIERhdGEgVmlzdWFsaXphdGlvbnMuCgpGb3IgdGhpcyBhbmFseXNpcywgSSB1c2VkIHRlY2huaXF1ZXMgc3VjaCBhcyBjYWxjdWxhdGluZyBtZWF1cmVzIG9mCmNlbnRyYWxpdHkgYW5kIG5vZGUgZGVncmVlcywgYW5kIGFkZGluZyBub2RlcywgZWRnZXMgYW5kIGxheW91dHMgdG8KZGV0ZXJtaW5lIHdobyB0aGUgdHJhbnNtaXR0ZXJzLCB0cmFuc2NlaXZlcnMsIGFuZCB0cmFuc2NlbmRlcnMgYXJlLiBJbgphZGRpdGlvbiB0byB0aGlzLCBJIGNyZWF0ZWQgc29jaW9ncmFtcyB3aXRoIHRoZSBgYXV0b2dyYXBoKClgIGFuZApgZ2dyYXBoKClgIGZ1bmN0aW9ucyB0byB2aXN1YWxpemUgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB1c2VycyBhbmQKdGhlIHNvY2lhbCBuZXR3b3JrLiBJIGFsc28gaWRlbnRpZmllZCBncm91cHMKCiMjIEV4YW1pbmUgQmFzaWMgRGVzY3JpcHRpdmVzCgojIyMgQ2VudHJhbGl0eQoKIyMjIyBOb2RlIERlZ3JlZQoKYGBge3J9Cm5nc3NfbmV0d29yayA8LSBuZ3NzX25ldHdvcmtfMSB8PgogIGFjdGl2YXRlKG5vZGVzKSB8PgogIG11dGF0ZShkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImFsbCIpKSB8PgogIG11dGF0ZShpbl9kZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIikpCgpuZ3NzX25ldHdvcmsKYGBgCgpgYGB7cn0KCm5nc3NfbmV0d29yayA8LSBuZ3NzX25ldHdvcmtfMSB8PgogIGFjdGl2YXRlKG5vZGVzKSB8PgogIG11dGF0ZShkZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImFsbCIpKSB8PgogIG11dGF0ZShpbl9kZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIikpIHw+CiAgbXV0YXRlKG91dF9kZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gIm91dCIpKQoKCm5nc3NfbmV0d29yawoKCmBgYAoKIyMjIyBTdW1tYXJpemUgQ2VudHJhbGl0eSBNZWFzdXJlcwoKYGBge3J9Cm5vZGVfbWVhc3VyZXMgPC0gbmdzc19uZXR3b3JrIHw+IAogIGFjdGl2YXRlKG5vZGVzKSB8PgogIGRhdGEuZnJhbWUoKQoKc3VtbWFyeShub2RlX21lYXN1cmVzKQpgYGAKCmBgYHtyLCBldmFsPUZBTFNFfQoKdmlldyhub2RlX21lYXN1cmVzKQpgYGAKCiMjIFNvY2lvZ3JhbXMKCmBgYHtyfQoKYXV0b2dyYXBoKG5nc3NfbmV0d29yaykKYGBgCgojIyMjIEFkZGluZyBOb2RlcwoKYGBge3J9CgpnZ3JhcGgobmdzc19uZXR3b3JrKSsKICBnZW9tX25vZGVfcG9pbnQoKQoKYGBgCgojIyMjIEFkZGluZyBMYXlvdXQKCmBgYHtyfQpnZ3JhcGgobmdzc19uZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9ub2RlX3BvaW50KCkKYGBgCgojIyMjIFR3ZWFraW5nIE5vZGVzCgpgYGB7cn0KZ2dyYXBoKG5nc3NfbmV0d29yaywgbGF5b3V0ID0gImZyIikgKyAKZ2VvbV9ub2RlX3BvaW50KGFlcyhzaXplID0gb3V0X2RlZ3JlZSwKICAgICAgICAgICAgICAgICAgICBjb2xvciA9IG91dF9kZWdyZWUpKQpgYGAKCmBgYHtyfQpnZ3JhcGgobmdzc19uZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoc2l6ZSA9IG91dF9kZWdyZWUsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IG91dF9kZWdyZWUpKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gYWN0b3JzLAogICAgICAgICAgICAgICAgICAgICBzaXplID0gb3V0X2RlZ3JlZS8yLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IG91dF9kZWdyZWUpLAogICAgICAgICAgICAgICAgIHJlcGVsPVRSVUUpCmBgYAoKIyMjIyBBZGRpbmcgRWRnZXMKCmBgYHtyfQpnZ3JhcGgobmdzc19uZXR3b3JrLCBsYXlvdXQgPSAiZnIiKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoc2l6ZSA9IG91dF9kZWdyZWUsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IG91dF9kZWdyZWUpKSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gYWN0b3JzLAogICAgICAgICAgICAgICAgICAgICBzaXplID0gb3V0X2RlZ3JlZS8yLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IG91dF9kZWdyZWUpLAogICAgICAgICAgICAgICAgIHJlcGVsPVRSVUUpICsKICBnZW9tX2VkZ2VfbGluayhhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMSwgJ21tJykpLCAKICAgICAgICAgICAgICAgICBlbmRfY2FwID0gY2lyY2xlKDMsICdtbScpLAogICAgICAgICAgICAgICAgIGFscGhhID0gLjIpCmBgYAoKIyMjIyBBZGRpbmcgYSBUaGVtZQoKYGBge3J9CmdncmFwaChuZ3NzX25ldHdvcmssIGxheW91dCA9ICJmciIpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhzaXplID0gb3V0X2RlZ3JlZSwKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gb3V0X2RlZ3JlZSksCiAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBhY3RvcnMsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBvdXRfZGVncmVlLzIsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gb3V0X2RlZ3JlZSksCiAgICAgICAgICAgICAgICAgcmVwZWw9VFJVRSwKICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9lZGdlX2xpbmsoYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDEsICdtbScpKSwgCiAgICAgICAgICAgICAgICAgZW5kX2NhcCA9IGNpcmNsZSgzLCAnbW0nKSwKICAgICAgICAgICAgICAgICBhbHBoYSA9IC4yKSArIAogIHRoZW1lX2dyYXBoKCkKYGBgCgpgYGB7cn0KZ2dyYXBoKG5nc3NfbmV0d29yaywgbGF5b3V0ID0gImZyIikgKyAKICBnZW9tX25vZGVfcG9pbnQoYWVzKHNpemUgPSBpbl9kZWdyZWUsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGluX2RlZ3JlZSksCiAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBhY3RvcnMsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBpbl9kZWdyZWUvMiwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBpbl9kZWdyZWUpLAogICAgICAgICAgICAgICAgIHJlcGVsPVRSVUUsCiAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fZWRnZV9saW5rKGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgxLCAnbW0nKSksIAogICAgICAgICAgICAgICAgIGVuZF9jYXAgPSBzcXVhcmUoMywgJ21tJyksCiAgICAgICAgICAgICAgICAgYWxwaGEgPSAuNSkgKyAKICB0aGVtZV9ncmFwaCgpCmBgYAoKIyMgSWRlbnRpZnlpbmcgR3JvdXBzCgojIyMgQ29tbXVuaXR5IERldGVjdGlvbgoKYGBge3J9Cm5nc3NfbmV0d29ya19ncm91cHMgPC0gbmdzc19uZXR3b3JrIHw+CiAgYWN0aXZhdGUobm9kZXMpIHw+CiAgbXV0YXRlKGdyb3VwID0gZ3JvdXBfY29tcG9uZW50cygpKQogIApuZ3NzX25ldHdvcmtfZ3JvdXBzCmBgYAoKYGBge3J9Cm5nc3NfbmV0d29ya19ncm91cHMgfD4KICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKyAKICBnZW9tX25vZGVfcG9pbnQoYWVzKHNpemUgPSBvdXRfZGVncmVlLCAKICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gb3V0X2RlZ3JlZSksCiAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBhY3RvcnMsIAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IG91dF9kZWdyZWUsCiAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBvdXRfZGVncmVlKSwgCiAgICAgICAgICAgICAgICAgICAgIHJlcGVsPVRSVUUsCiAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fZWRnZV9saW5rKGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgxLCAnbW0nKSksIAogICAgICAgICAgICAgICAgIGVuZF9jYXAgPSBjaXJjbGUoMywgJ21tJyksCiAgICAgICAgICAgICAgICAgYWxwaGEgPSAuMikgKyAKICB0aGVtZV9ncmFwaCgpICsgCiAgZ2VvbV9ub2RlX3Zvcm9ub2koYWVzKGZpbGwgPSBmYWN0b3IoZ3JvdXApLAogICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAuMDUpLCAKICAgICAgICAgICAgICAgICAgICBtYXgucmFkaXVzID0gLjUsCiAgICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIDUuIENPTU1VTklDQVRFCgojIyBLZXkgRmluZGluZ3MKClNvbWUga2V5IGZpbmRpbmdzIGFyZSB3aG8gdGhlIHRyYW5zY2VuZGVycywgdHJhbmNlaXZlcnMsIGFuZAp0cmFuc2Zvcm1lcnMgYXJlOgoKLSAgICoqVHJhbnNtaXR0ZXJzOioqIFVzZXIgNTU4OTcxNzAwIGJlY2F1c2UgdGhleSBoYXZlIHRoZSBoaWdoZXN0CiAgICBvdXRkZWdyZWUgbWVhc3VyZW1lbnQKCi0gICAqKlRyYW5zY2VpdmVyczoqKiBVc2VyIDQ5MTg1MDc1NDIgYmVjYXVzZSB0aGV5IGhhdmUgdGhlIGhpZ2hlc3QKICAgIGluZGVncmVlIG1lYXN1cmVtZW50CgotICAgKipUcmFuc2NlbmRlcnM6KiogVXNlciAxODQ2NDk2NDUgYmVjYXVzZSB0aGV5IGhhdmUgdGhlIHNhbWUgaW5kZWdyZWUKICAgIGFuZCBvdXRkZWdyZWUgbWVhc3VyZW1lbnQgYW5kIHRoZSBoaWdoZXN0IGNvbWJpbmF0aW9uIG9mIHRoZSB0d28KCkluIGFkZGl0aW9uIHRvIHRoaXMsIHRoZSBzb2Npb2dyYW1zIHNob3cgYSBsYXJnZSBvZiBjbHVzdGVyIG9mIG5vZGVzLAppbmRpY2F0aW5nIGhpZ2ggYWN0aXZpdHkgYW1vbmcgdGhvc2UgdXNlcnMuCgojIyBQb3RlbnRpYWwgYWN0aW9uCgpPbmUgcG90ZW50aWFsIGNvdXJzZSBvZiBhY3Rpb24gY291bGQgYmUgdG8gZG8gYSBzZW50aW1lbnQgYW5hbHlzaXMgb24KdGhpcyBkYXRhIHRvIHVuZGVyc3RhbmQgdGhlIHB1YmxpYyByZWFjdGlvbiB0byB0aGUgTkdTUyBzdGFuZGFyZHMuIEluCmFkZGl0aW9uLCBpdCB3b3VsZCBiZSBpbnRlcmVzdGluZyB0byBzZWUgaWYgdGhlIHJlYWN0aW9ucyBhcmUgaW5mbHVlbmNlZApieSBvdGhlciBmYWN0b3JzLCBzdWNoIGFzIHBvbGl0aWNhbCBhZmZpbGlhdGlvbiwgdGhlIGFnZSBvZiB0aGUgc3R1ZGVudHMKYWZmZWN0ZWQsIGFuZCB0aGUgc29jaWFsIG1lZGlhIG5ldHdvcmsgdGhlIHVzZXIgaXMgcG9zdGluZyBvbi4KCiMjIExpbWl0YXRpb25zIGFuZCBldGhpY2FsIGlzc3VlcwoKT25lIGxpbWl0YXRpb24gaXMgdGhhdCB0aGUgdXNlcnMgYXJlIGlkZW50aWZpZWQgdGhyb3VnaCBhIG51bWVyaWMgYXV0aG9yCklEIGluc3RlYWQgb2YgYSB1c2VyIG5hbWUgb3Igc2NyZWVuIG5hbWUuIFRoaXMgbWFrZXMgaXQgZGlmZmljdWx0IHRvCmlkZW50aWZ5IGFuZCBrZWVwIHRyYWNrIG9mIHVzZXJzLgoKSW4gYWRkaXRpb24sIGl0J3MgaW1wb3J0YW50IHRvIG1ha2Ugc3VyZSBzb2NpYWwgbWVkaWEgdXNlcnMgbGlrZSBpbiB0aGlzCmNhc2Ugc3R1ZHkgYXJlIGF3YXJlIG9mIGhvdyB0aGllciBpbmZvcm1hdGlvbiBpcyBiZWluZyB1c2VkLiBFdmVuIHRob3VnaAp0aGV5IGFyZSBub3QgaWRlbnRpZmlhYmxlIGJ5IHNjcmVlbiBuYW1lLCB0aGV5IG1heSBub3QgYmUgY29tZm9ydGFibGUKdGhhdCB3aGF0IHRoZXkgcG9zdGVkIGluIGNpcmN1bGF0aW5nIGluIHN0dWRpZXMgYW5kIHBsYXRmb3JtcyB0aGV5IG1heQpub3QgYmUgZmFtaWxpYXIgd2l0aC4K