### Load standardpackages
library(tidyverse) # Collection of all the good stuff like dplyr, ggplot2 ect.
library(magrittr) # For extra-piping operators (eg. %<>%)

library(tidygraph)
library(igraph)
library(ggraph)

Read Data

el_friendship <- read_delim('https://github.com/SDS-AAU/SDS-master/raw/master/00_data/network_krackhard/Krack-High-Tec-edgelist-Friendship.txt',
                        delim = ' ', col_names = FALSE)
el_advice <- read_delim('https://github.com/SDS-AAU/SDS-master/raw/master/00_data/network_krackhard/Krack-High-Tec-edgelist-Advice.txt',
                        delim = ' ', col_names = FALSE)
el_work <- read_delim('https://github.com/SDS-AAU/SDS-master/raw/master/00_data/network_krackhard/Krack-High-Tec-edgelist-ReportsTo.txt',
                        delim = ' ', col_names = FALSE)
nodes <- read_csv('https://github.com/SDS-AAU/SDS-master/raw/master/00_data/network_krackhard/Krack-High-Tec-Attributes.csv')

Preprocessing

el_friendship %<>%  
  mutate_all(as.numeric) %>%
  filter(X3 == 1) %>%
  select(-X3) %>%
  rename(from = X1, to = X2)

el_advice %<>% 
  mutate_all(as.numeric) %>%
  filter(X3 == 1) %>%
  select(-X3) %>%
  rename(from = X1, to = X2)

el_work %<>% 
  mutate_all(as.numeric) %>%
  filter(X3 == 1) %>%
  select(-X3) %>%
  rename(from = X1, to = X2)
colnames(nodes) <- colnames(nodes) %>% str_to_lower()

nodes %<>%
  rename(name = id) %>%
  mutate(name = name %>% as.character(),
         level = level %>% recode("1" = "ceo", "2" = "vice", "3" = "manager"),
         dept = dept %>% as.character())

1. Create a network

  • Generate network objects for the companies organizational structure (reports to), friendship, advice
  • This networks are generated from the corresponding edgelists
  • Also attach node characteristics from the corresponding nodelist
g_friendship <- el_friendship %>% as_tbl_graph(directed = TRUE) %>%
  left_join(nodes, by = "name")

g_advice <- el_advice %>% as_tbl_graph(directed = TRUE) %>%
  left_join(nodes, by = "name")

g_work <- el_work %>% as_tbl_graph(directed = TRUE) %>%
  left_join(nodes, by = "name")

A: Network level characteristics

Find the overal network level of:

  • Density
  • Transistivity (Clustering Coefficient)
  • Reciprocity

… for the different networks.

nw_stats <- tibble(
  Stat = c('Edge Density', 'Transistivity', 'Reciprocity'),
  Friendship = c(edge_density(g_friendship), transitivity(g_friendship, type ="global"), reciprocity(g_friendship)), 
  Advice = c(edge_density(g_advice), transitivity(g_advice, type ="global"), reciprocity(g_advice)), 
  Work = c(edge_density(g_work), transitivity(g_work, type ="global"), reciprocity(g_work))
  )

Describe and interpret the results. Answer the following questions:

  • Are relationships like friendship and advice giving usually reciprocal?
  • Are friends of your friends also your friends?
  • Are the employees generally more likely to be in a friendship or adviceseeking relationship?
nw_stats

B: Node level characteristics

Likewise, find out:

  • Who is most popular in the networks. Who is the most wanted friend, and advice giver? *Are managers in higher hierarchy more popular as friend, and advice giver?
g_friendship <- g_friendship %N>%
  mutate(cent_dgr = centrality_degree(mode = 'in'))

g_advice <- g_advice %N>%
  mutate(cent_dgr = centrality_degree(mode = 'in'))
g_friendship %N>% as_tibble() %>% arrange(desc(cent_dgr)) 
g_advice %N>% as_tibble() %>% arrange(desc(cent_dgr)) 
g_friendship %N>% as_tibble() %>% 
  group_by(level) %>%
  summarise(cent_dgr = cent_dgr %>% mean())
g_advice %N>% as_tibble() %>% 
  group_by(level) %>%
  summarise(cent_dgr = cent_dgr %>% mean())

C: Relational Characteristics

Answer the following questions:

  • Are managers from the same 1. department, or on the same 2. hirarchy, 3.age, or 4. tenuere more likely to become friends or give advice? (hint: assortiativity related)
  • Are friends more likely to give each others advice?
assortativity_nominal(g_friendship, V(g_friendship)$level %>% factor(), directed = TRUE)
[1] 0.1875
assortativity(g_friendship, V(g_friendship)$age, directed = TRUE)
[1] 0.1002871
assortativity(g_friendship, V(g_friendship)$tenure, directed = TRUE)
[1] -0.09456003
assortativity_nominal(g_advice, V(g_advice)$level %>% factor(), directed = TRUE)
[1] 0.008073818
assortativity(g_advice, V(g_advice)$age, directed = TRUE)
[1] 0.0387598
assortativity(g_advice, V(g_advice)$tenure, directed = TRUE)
[1] 0.1552188
cor(el_friendship_complete %>% pull(X3), 
    el_advice_complete %>% pull(X3))
[1] 0.1743491

3. Aggregated Networks

  • Reconstruct the advice and friendship network on the aggregated level of departments, where nodes represent departments and edges the number of cross departmental friendships/advice relationships.
el_friendship_dept <- el_friendship %>% 
  mutate_all(as.character) %>%
  left_join(nodes %>% select(name, dept), by = c('from' = 'name')) %>%
  rename(dept_from = dept) %>%
  left_join(nodes %>% select(name, dept), by = c('to' = 'name')) %>%
  rename(dept_to = dept) %>%
  select(dept_from, dept_to)
g_friendship_dept <- el_friendship_dept %>% as_tbl_graph(directed = TRUE)
el_advice_dept <- el_advice %>% 
  mutate_all(as.character) %>%
  left_join(nodes %>% select(name, dept), by = c('from' = 'name')) %>%
  rename(dept_from = dept) %>%
  left_join(nodes %>% select(name, dept), by = c('to' = 'name')) %>%
  rename(dept_to = dept) %>%
  select(dept_from, dept_to)
g_advice_dept <- el_advice_dept %>% as_tbl_graph(directed = TRUE)
el_work_dept <- el_work %>% 
  mutate_all(as.character) %>%
  left_join(nodes %>% select(name, dept), by = c('from' = 'name')) %>%
  rename(dept_from = dept) %>%
  left_join(nodes %>% select(name, dept), by = c('to' = 'name')) %>%
  rename(dept_to = dept) %>%
  select(dept_from, dept_to)
g_work_dept <- el_work_dept %>% as_tbl_graph(directed = TRUE)

4. Visualization

  • Everything goes. Show us some pretty and informative plots.
LS0tCnRpdGxlOiAnTmV0d29ya3MgQXNzaWdubWVudCAxOiBNaW5pbWFsIGV4YW1wbGUgc29sdXRpb24gKFIpJwphdXRob3I6ICJEYW5pZWwgUy4gSGFpbiAoZHNoQGJ1c2luZXNzLmFhdS5kaykiCmRhdGU6ICJVcGRhdGVkIGByIGZvcm1hdChTeXMudGltZSgpLCAnJUIgJWQsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMgogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICB0aGVtZTogZmxhdGx5Ci0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CiMjIyBHZW5lcmljIHByZWFtYmxlCnJtKGxpc3Q9bHMoKSkKU3lzLnNldGVudihMQU5HID0gImVuIikgIyBGb3IgZW5nbGlzaCBsYW5ndWFnZQpvcHRpb25zKHNjaXBlbiA9IDUpICMgVG8gZGVhY3RpdmF0ZSBhbm5veWluZyBzY2llbnRpZmljIG51bWJlciBub3RhdGlvbgoKIyMjIEtuaXRyIG9wdGlvbnMKbGlicmFyeShrbml0cikgIyBGb3IgZGlzcGxheSBvZiB0aGUgbWFya2Rvd24Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmc9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2U9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQ9RkFMU0UsIAogICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ249ImNlbnRlciIKICAgICAgICAgICAgICAgICAgICAgKQpgYGAKCmBgYHtyfQojIyMgTG9hZCBzdGFuZGFyZHBhY2thZ2VzCmxpYnJhcnkodGlkeXZlcnNlKSAjIENvbGxlY3Rpb24gb2YgYWxsIHRoZSBnb29kIHN0dWZmIGxpa2UgZHBseXIsIGdncGxvdDIgZWN0LgpsaWJyYXJ5KG1hZ3JpdHRyKSAjIEZvciBleHRyYS1waXBpbmcgb3BlcmF0b3JzIChlZy4gJTw+JSkKCmxpYnJhcnkodGlkeWdyYXBoKQpsaWJyYXJ5KGlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmBgYAoKIyBSZWFkIERhdGEKCmBgYHtyfQplbF9mcmllbmRzaGlwIDwtIHJlYWRfZGVsaW0oJ2h0dHBzOi8vZ2l0aHViLmNvbS9TRFMtQUFVL1NEUy1tYXN0ZXIvcmF3L21hc3Rlci8wMF9kYXRhL25ldHdvcmtfa3JhY2toYXJkL0tyYWNrLUhpZ2gtVGVjLWVkZ2VsaXN0LUZyaWVuZHNoaXAudHh0JywKICAgICAgICAgICAgICAgICAgICAgICAgZGVsaW0gPSAnICcsIGNvbF9uYW1lcyA9IEZBTFNFKQplbF9hZHZpY2UgPC0gcmVhZF9kZWxpbSgnaHR0cHM6Ly9naXRodWIuY29tL1NEUy1BQVUvU0RTLW1hc3Rlci9yYXcvbWFzdGVyLzAwX2RhdGEvbmV0d29ya19rcmFja2hhcmQvS3JhY2stSGlnaC1UZWMtZWRnZWxpc3QtQWR2aWNlLnR4dCcsCiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGltID0gJyAnLCBjb2xfbmFtZXMgPSBGQUxTRSkKZWxfd29yayA8LSByZWFkX2RlbGltKCdodHRwczovL2dpdGh1Yi5jb20vU0RTLUFBVS9TRFMtbWFzdGVyL3Jhdy9tYXN0ZXIvMDBfZGF0YS9uZXR3b3JrX2tyYWNraGFyZC9LcmFjay1IaWdoLVRlYy1lZGdlbGlzdC1SZXBvcnRzVG8udHh0JywKICAgICAgICAgICAgICAgICAgICAgICAgZGVsaW0gPSAnICcsIGNvbF9uYW1lcyA9IEZBTFNFKQpgYGAKCmBgYHtyfQpub2RlcyA8LSByZWFkX2NzdignaHR0cHM6Ly9naXRodWIuY29tL1NEUy1BQVUvU0RTLW1hc3Rlci9yYXcvbWFzdGVyLzAwX2RhdGEvbmV0d29ya19rcmFja2hhcmQvS3JhY2stSGlnaC1UZWMtQXR0cmlidXRlcy5jc3YnKQpgYGAKCiMgUHJlcHJvY2Vzc2luZwoKYGBge3J9CmVsX2ZyaWVuZHNoaXAgJTw+JSAgCiAgbXV0YXRlX2FsbChhcy5udW1lcmljKSAlPiUKICBmaWx0ZXIoWDMgPT0gMSkgJT4lCiAgc2VsZWN0KC1YMykgJT4lCiAgcmVuYW1lKGZyb20gPSBYMSwgdG8gPSBYMikKCmVsX2FkdmljZSAlPD4lIAogIG11dGF0ZV9hbGwoYXMubnVtZXJpYykgJT4lCiAgZmlsdGVyKFgzID09IDEpICU+JQogIHNlbGVjdCgtWDMpICU+JQogIHJlbmFtZShmcm9tID0gWDEsIHRvID0gWDIpCgplbF93b3JrICU8PiUgCiAgbXV0YXRlX2FsbChhcy5udW1lcmljKSAlPiUKICBmaWx0ZXIoWDMgPT0gMSkgJT4lCiAgc2VsZWN0KC1YMykgJT4lCiAgcmVuYW1lKGZyb20gPSBYMSwgdG8gPSBYMikKYGBgCgpgYGB7cn0KY29sbmFtZXMobm9kZXMpIDwtIGNvbG5hbWVzKG5vZGVzKSAlPiUgc3RyX3RvX2xvd2VyKCkKCm5vZGVzICU8PiUKICByZW5hbWUobmFtZSA9IGlkKSAlPiUKICBtdXRhdGUobmFtZSA9IG5hbWUgJT4lIGFzLmNoYXJhY3RlcigpLAogICAgICAgICBsZXZlbCA9IGxldmVsICU+JSByZWNvZGUoIjEiID0gImNlbyIsICIyIiA9ICJ2aWNlIiwgIjMiID0gIm1hbmFnZXIiKSwKICAgICAgICAgZGVwdCA9IGRlcHQgJT4lIGFzLmNoYXJhY3RlcigpKQpgYGAKCiMgMS4gQ3JlYXRlIGEgbmV0d29yawoKKiBHZW5lcmF0ZSBuZXR3b3JrIG9iamVjdHMgZm9yIHRoZSBjb21wYW5pZXMgb3JnYW5pemF0aW9uYWwgc3RydWN0dXJlIChyZXBvcnRzIHRvKSwgZnJpZW5kc2hpcCwgYWR2aWNlCiogVGhpcyBuZXR3b3JrcyBhcmUgZ2VuZXJhdGVkIGZyb20gdGhlIGNvcnJlc3BvbmRpbmcgZWRnZWxpc3RzCiogQWxzbyBhdHRhY2ggbm9kZSBjaGFyYWN0ZXJpc3RpY3MgZnJvbSB0aGUgY29ycmVzcG9uZGluZyBub2RlbGlzdAoKYGBge3J9CmdfZnJpZW5kc2hpcCA8LSBlbF9mcmllbmRzaGlwICU+JSBhc190YmxfZ3JhcGgoZGlyZWN0ZWQgPSBUUlVFKSAlPiUKICBsZWZ0X2pvaW4obm9kZXMsIGJ5ID0gIm5hbWUiKQoKZ19hZHZpY2UgPC0gZWxfYWR2aWNlICU+JSBhc190YmxfZ3JhcGgoZGlyZWN0ZWQgPSBUUlVFKSAlPiUKICBsZWZ0X2pvaW4obm9kZXMsIGJ5ID0gIm5hbWUiKQoKZ193b3JrIDwtIGVsX3dvcmsgJT4lIGFzX3RibF9ncmFwaChkaXJlY3RlZCA9IFRSVUUpICU+JQogIGxlZnRfam9pbihub2RlcywgYnkgPSAibmFtZSIpCmBgYAoKIyBBOiBOZXR3b3JrIGxldmVsIGNoYXJhY3RlcmlzdGljcwoKRmluZCB0aGUgb3ZlcmFsIG5ldHdvcmsgbGV2ZWwgb2Y6CgoqIERlbnNpdHkKKiBUcmFuc2lzdGl2aXR5IChDbHVzdGVyaW5nIENvZWZmaWNpZW50KQoqIFJlY2lwcm9jaXR5CgouLi4gZm9yIHRoZSBkaWZmZXJlbnQgbmV0d29ya3MuIAoKYGBge3J9Cm53X3N0YXRzIDwtIHRpYmJsZSgKICBTdGF0ID0gYygnRWRnZSBEZW5zaXR5JywgJ1RyYW5zaXN0aXZpdHknLCAnUmVjaXByb2NpdHknKSwKICBGcmllbmRzaGlwID0gYyhlZGdlX2RlbnNpdHkoZ19mcmllbmRzaGlwKSwgdHJhbnNpdGl2aXR5KGdfZnJpZW5kc2hpcCwgdHlwZSA9Imdsb2JhbCIpLCByZWNpcHJvY2l0eShnX2ZyaWVuZHNoaXApKSwgCiAgQWR2aWNlID0gYyhlZGdlX2RlbnNpdHkoZ19hZHZpY2UpLCB0cmFuc2l0aXZpdHkoZ19hZHZpY2UsIHR5cGUgPSJnbG9iYWwiKSwgcmVjaXByb2NpdHkoZ19hZHZpY2UpKSwgCiAgV29yayA9IGMoZWRnZV9kZW5zaXR5KGdfd29yayksIHRyYW5zaXRpdml0eShnX3dvcmssIHR5cGUgPSJnbG9iYWwiKSwgcmVjaXByb2NpdHkoZ193b3JrKSkKICApCmBgYAoKRGVzY3JpYmUgYW5kIGludGVycHJldCB0aGUgcmVzdWx0cy4gQW5zd2VyIHRoZSBmb2xsb3dpbmcKcXVlc3Rpb25zOgoKKiBBcmUgcmVsYXRpb25zaGlwcyBsaWtlIGZyaWVuZHNoaXAgYW5kIGFkdmljZSBnaXZpbmcgdXN1YWxseSByZWNpcHJvY2FsPwoqIEFyZSBmcmllbmRzIG9mIHlvdXIgZnJpZW5kcyBhbHNvIHlvdXIgZnJpZW5kcz8KKiBBcmUgdGhlIGVtcGxveWVlcyBnZW5lcmFsbHkgbW9yZSBsaWtlbHkgdG8gYmUgaW4gYSBmcmllbmRzaGlwIG9yIGFkdmljZXNlZWtpbmcKcmVsYXRpb25zaGlwPwoKYGBge3J9Cm53X3N0YXRzCmBgYAoKIyBCOiBOb2RlIGxldmVsIGNoYXJhY3RlcmlzdGljcwoKTGlrZXdpc2UsIGZpbmQgb3V0OgoKKiBXaG8gaXMgbW9zdCBwb3B1bGFyIGluIHRoZSBuZXR3b3Jrcy4gV2hvIGlzIHRoZSBtb3N0IHdhbnRlZCBmcmllbmQsIGFuZCBhZHZpY2UgZ2l2ZXI/CipBcmUgbWFuYWdlcnMgaW4gaGlnaGVyIGhpZXJhcmNoeSBtb3JlIHBvcHVsYXIgYXMgZnJpZW5kLCBhbmQgYWR2aWNlIGdpdmVyPwoKYGBge3J9CmdfZnJpZW5kc2hpcCA8LSBnX2ZyaWVuZHNoaXAgJU4+JQogIG11dGF0ZShjZW50X2RnciA9IGNlbnRyYWxpdHlfZGVncmVlKG1vZGUgPSAnaW4nKSkKCmdfYWR2aWNlIDwtIGdfYWR2aWNlICVOPiUKICBtdXRhdGUoY2VudF9kZ3IgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gJ2luJykpCmBgYAoKYGBge3J9CmdfZnJpZW5kc2hpcCAlTj4lIGFzX3RpYmJsZSgpICU+JSBhcnJhbmdlKGRlc2MoY2VudF9kZ3IpKSAKYGBgCmBgYHtyfQpnX2FkdmljZSAlTj4lIGFzX3RpYmJsZSgpICU+JSBhcnJhbmdlKGRlc2MoY2VudF9kZ3IpKSAKYGBgCgpgYGB7cn0KZ19mcmllbmRzaGlwICVOPiUgYXNfdGliYmxlKCkgJT4lIAogIGdyb3VwX2J5KGxldmVsKSAlPiUKICBzdW1tYXJpc2UoY2VudF9kZ3IgPSBjZW50X2RnciAlPiUgbWVhbigpKQpgYGAKCmBgYHtyfQpnX2FkdmljZSAlTj4lIGFzX3RpYmJsZSgpICU+JSAKICBncm91cF9ieShsZXZlbCkgJT4lCiAgc3VtbWFyaXNlKGNlbnRfZGdyID0gY2VudF9kZ3IgJT4lIG1lYW4oKSkKYGBgCgoKIyBDOiBSZWxhdGlvbmFsIENoYXJhY3RlcmlzdGljcwoKQW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zOgoKKiBBcmUgbWFuYWdlcnMgZnJvbSB0aGUgc2FtZSAxLiBkZXBhcnRtZW50LCBvciBvbiB0aGUgc2FtZSAyLiBoaXJhcmNoeSwgMy5hZ2UsIG9yIDQuIHRlbnVlcmUgbW9yZSBsaWtlbHkgdG8gYmVjb21lIGZyaWVuZHMgb3IgZ2l2ZSBhZHZpY2U/IChoaW50OiBhc3NvcnRpYXRpdml0eSByZWxhdGVkKQoqIEFyZSBmcmllbmRzIG1vcmUgbGlrZWx5IHRvIGdpdmUgZWFjaCBvdGhlcnMgYWR2aWNlPwoKYGBge3J9CmFzc29ydGF0aXZpdHlfbm9taW5hbChnX2ZyaWVuZHNoaXAsIFYoZ19mcmllbmRzaGlwKSRsZXZlbCAlPiUgZmFjdG9yKCksIGRpcmVjdGVkID0gVFJVRSkKYGBgCgpgYGB7cn0KYXNzb3J0YXRpdml0eShnX2ZyaWVuZHNoaXAsIFYoZ19mcmllbmRzaGlwKSRhZ2UsIGRpcmVjdGVkID0gVFJVRSkKYGBgCgpgYGB7cn0KYXNzb3J0YXRpdml0eShnX2ZyaWVuZHNoaXAsIFYoZ19mcmllbmRzaGlwKSR0ZW51cmUsIGRpcmVjdGVkID0gVFJVRSkKYGBgCgpgYGB7cn0KYXNzb3J0YXRpdml0eV9ub21pbmFsKGdfYWR2aWNlLCBWKGdfYWR2aWNlKSRsZXZlbCAlPiUgZmFjdG9yKCksIGRpcmVjdGVkID0gVFJVRSkKYGBgCgpgYGB7cn0KYXNzb3J0YXRpdml0eShnX2FkdmljZSwgVihnX2FkdmljZSkkYWdlLCBkaXJlY3RlZCA9IFRSVUUpCmBgYAoKYGBge3J9CmFzc29ydGF0aXZpdHkoZ19hZHZpY2UsIFYoZ19hZHZpY2UpJHRlbnVyZSwgZGlyZWN0ZWQgPSBUUlVFKQpgYGAKCmBgYHtyfQplbF9mcmllbmRzaGlwX2NvbXBsZXRlIDwtIHJlYWRfZGVsaW0oJ2h0dHBzOi8vZ2l0aHViLmNvbS9TRFMtQUFVL1NEUy1tYXN0ZXIvcmF3L21hc3Rlci8wMF9kYXRhL25ldHdvcmtfa3JhY2toYXJkL0tyYWNrLUhpZ2gtVGVjLWVkZ2VsaXN0LUZyaWVuZHNoaXAudHh0JywKICAgICAgICAgICAgICAgICAgICAgICAgZGVsaW0gPSAnICcsIGNvbF9uYW1lcyA9IEZBTFNFKQplbF9hZHZpY2VfY29tcGxldGUgPC0gcmVhZF9kZWxpbSgnaHR0cHM6Ly9naXRodWIuY29tL1NEUy1BQVUvU0RTLW1hc3Rlci9yYXcvbWFzdGVyLzAwX2RhdGEvbmV0d29ya19rcmFja2hhcmQvS3JhY2stSGlnaC1UZWMtZWRnZWxpc3QtQWR2aWNlLnR4dCcsCiAgICAgICAgICAgICAgICAgICAgICAgIGRlbGltID0gJyAnLCBjb2xfbmFtZXMgPSBGQUxTRSkKYGBgCgpgYGB7cn0KY29yKGVsX2ZyaWVuZHNoaXBfY29tcGxldGUgJT4lIHB1bGwoWDMpLCAKICAgIGVsX2FkdmljZV9jb21wbGV0ZSAlPiUgcHVsbChYMykpCmBgYAoKCgoKIyAzLiBBZ2dyZWdhdGVkIE5ldHdvcmtzCgoqIFJlY29uc3RydWN0IHRoZSBhZHZpY2UgYW5kIGZyaWVuZHNoaXAgbmV0d29yayBvbiB0aGUgYWdncmVnYXRlZCBsZXZlbCBvZiBkZXBhcnRtZW50cywgd2hlcmUgbm9kZXMgcmVwcmVzZW50IGRlcGFydG1lbnRzIGFuZCBlZGdlcyB0aGUgbnVtYmVyIG9mIGNyb3NzIGRlcGFydG1lbnRhbCBmcmllbmRzaGlwcy9hZHZpY2UgcmVsYXRpb25zaGlwcy4KCmBgYHtyfQplbF9mcmllbmRzaGlwX2RlcHQgPC0gZWxfZnJpZW5kc2hpcCAlPiUgCiAgbXV0YXRlX2FsbChhcy5jaGFyYWN0ZXIpICU+JQogIGxlZnRfam9pbihub2RlcyAlPiUgc2VsZWN0KG5hbWUsIGRlcHQpLCBieSA9IGMoJ2Zyb20nID0gJ25hbWUnKSkgJT4lCiAgcmVuYW1lKGRlcHRfZnJvbSA9IGRlcHQpICU+JQogIGxlZnRfam9pbihub2RlcyAlPiUgc2VsZWN0KG5hbWUsIGRlcHQpLCBieSA9IGMoJ3RvJyA9ICduYW1lJykpICU+JQogIHJlbmFtZShkZXB0X3RvID0gZGVwdCkgJT4lCiAgc2VsZWN0KGRlcHRfZnJvbSwgZGVwdF90bykKYGBgCgpgYGB7cn0KZ19mcmllbmRzaGlwX2RlcHQgPC0gZWxfZnJpZW5kc2hpcF9kZXB0ICU+JSBhc190YmxfZ3JhcGgoZGlyZWN0ZWQgPSBUUlVFKQpgYGAKCmBgYHtyfQplbF9hZHZpY2VfZGVwdCA8LSBlbF9hZHZpY2UgJT4lIAogIG11dGF0ZV9hbGwoYXMuY2hhcmFjdGVyKSAlPiUKICBsZWZ0X2pvaW4obm9kZXMgJT4lIHNlbGVjdChuYW1lLCBkZXB0KSwgYnkgPSBjKCdmcm9tJyA9ICduYW1lJykpICU+JQogIHJlbmFtZShkZXB0X2Zyb20gPSBkZXB0KSAlPiUKICBsZWZ0X2pvaW4obm9kZXMgJT4lIHNlbGVjdChuYW1lLCBkZXB0KSwgYnkgPSBjKCd0bycgPSAnbmFtZScpKSAlPiUKICByZW5hbWUoZGVwdF90byA9IGRlcHQpICU+JQogIHNlbGVjdChkZXB0X2Zyb20sIGRlcHRfdG8pCmBgYAoKYGBge3J9CmdfYWR2aWNlX2RlcHQgPC0gZWxfYWR2aWNlX2RlcHQgJT4lIGFzX3RibF9ncmFwaChkaXJlY3RlZCA9IFRSVUUpCmBgYAoKYGBge3J9CmVsX3dvcmtfZGVwdCA8LSBlbF93b3JrICU+JSAKICBtdXRhdGVfYWxsKGFzLmNoYXJhY3RlcikgJT4lCiAgbGVmdF9qb2luKG5vZGVzICU+JSBzZWxlY3QobmFtZSwgZGVwdCksIGJ5ID0gYygnZnJvbScgPSAnbmFtZScpKSAlPiUKICByZW5hbWUoZGVwdF9mcm9tID0gZGVwdCkgJT4lCiAgbGVmdF9qb2luKG5vZGVzICU+JSBzZWxlY3QobmFtZSwgZGVwdCksIGJ5ID0gYygndG8nID0gJ25hbWUnKSkgJT4lCiAgcmVuYW1lKGRlcHRfdG8gPSBkZXB0KSAlPiUKICBzZWxlY3QoZGVwdF9mcm9tLCBkZXB0X3RvKQpgYGAKCmBgYHtyfQpnX3dvcmtfZGVwdCA8LSBlbF93b3JrX2RlcHQgJT4lIGFzX3RibF9ncmFwaChkaXJlY3RlZCA9IFRSVUUpCmBgYAoKIyA0LiBWaXN1YWxpemF0aW9uCgoqIEV2ZXJ5dGhpbmcgZ29lcy4gU2hvdyB1cyBzb21lIHByZXR0eSBhbmQgaW5mb3JtYXRpdmUgcGxvdHMuIAoKCg==