Datos

En este ejemplos consideramos la red de aeropuertos de EU:

library(tidyverse)
library(tidygraph)
library(ggraph)
library(igraphdata)
data("USairports")

US airport network, 2010 December Description The network of passanger flights between airports in the United States. The data set was compiled based on flights in 2010 December. This network is directed and edge directions correspond to flight directions. Each edge is specific to a single carrier aircraft type. Multiple carriers between the same two airports are denoted by multiple edges.

name Symbolic vertex name, this is the three letter IATA airport code.

City City and state, where the airport is located.

Position Position of the airport, in WGS coordinates.

Edge attributes:

Carrier Name of the airline. The network includes both domestic and international carriers that performed at least one flight in December of 2010.

Departures The number of departures (for a given airline and aircraft type.

Seats The total number of seats available on the flights carried out by a given airline, using a given aircraft type.

Passengers The total number of passangers on the flights carried out by a given airline, using a given aircraft type.

Aircraft Type of the aircraft.

Distance The distance between the two airports, in miles.

# ver detalles
?USairports

Nota que cada arista corresponde a una aerolínea (carrier) y tipo de avión (Aircraft), y los nodos son los aeropuertos. Los datos de las aristas corresponden a vuelos de Diciembre de 2010, y es una gráfica dirigida.

airports <- USairports %>% as_tbl_graph()
airports
# A tbl_graph: 755 nodes and 23473 edges
#
# A directed multigraph with 6 components
#
# Node Data: 755 x 3 (active)
  name  City          Position        
  <chr> <chr>         <chr>           
1 BGR   Bangor, ME    N444827 W0684941
2 BOS   Boston, MA    N422152 W0710019
3 ANC   Anchorage, AK N611028 W1495947
4 JFK   New York, NY  N403823 W0734644
5 LAS   Las Vegas, NV N360449 W1150908
6 MIA   Miami, FL     N254736 W0801726
# … with 749 more rows
#
# Edge Data: 23,473 x 8
   from    to Carrier             Departures Seats Passengers Aircraft Distance
  <int> <int> <chr>                    <dbl> <dbl>      <dbl>    <int>    <dbl>
1     1     4 British Airways Plc          1   226        193      627      382
2     1     4 British Airways Plc          1   299        253      819      382
3     2     7 British Airways Plc          1   216        141      627      200
# … with 2.347e+04 more rows

Esta gŕafica es un multigrafo (puede haber varias aristas con la misma dirección en un par de nodos). Nos interesa en primer lugar agregar a un grafo, y considerar el total de pasajeros (puedes también considerar número de asientos, por ejemplo) que viajó entre cada par de aeropuertos. Podemos agregar de las siguiente forma:

# seleccionamos solo pasajeros
vertices <- airports %>% 
  activate(edges) %>% 
  select(to, from, Passengers) %>% as_tibble()
# agregar considerarando el total de pasajeros
vertices_agregados <- vertices %>% 
  group_by(to, from) %>% 
  summarise(pax = sum(Passengers))
# nodos, y agregar estado a la ciudad
nodos <- airports %>% activate(nodes) %>% 
  as_tibble() %>% 
  separate(City, into = c('ciudad_nombre', 'estado'), sep = ', ')
# construir nueva red
aeropuertos <- tbl_graph(nodes = nodos, edges = vertices_agregados) 
aeropuertos 
# A tbl_graph: 755 nodes and 8265 edges
#
# A directed multigraph with 6 components
#
# Node Data: 755 x 4 (active)
  name  ciudad_nombre estado Position        
  <chr> <chr>         <chr>  <chr>           
1 BGR   Bangor        ME     N444827 W0684941
2 BOS   Boston        MA     N422152 W0710019
3 ANC   Anchorage     AK     N611028 W1495947
4 JFK   New York      NY     N403823 W0734644
5 LAS   Las Vegas     NV     N360449 W1150908
6 MIA   Miami         FL     N254736 W0801726
# … with 749 more rows
#
# Edge Data: 8,265 x 3
   from    to   pax
  <int> <int> <dbl>
1     2     1     2
2     4     1    35
3     6     1     3
# … with 8,262 more rows

Filtro de conexiones débiles

Podemos también filtrar opcionalmente aquellas conexiones que tengan un número de pasajeros bajo durante el mes de observación. La distribución de pasajeros podemos examinarla con_

pasajeros <- aeropuertos %>% activate(edges) %>% 
  select(from, to , pax)
quantile(pull(pasajeros, pax), seq(0, 1, 0.1))
      0%      10%      20%      30%      40%      50%      60%      70%      80%      90%     100% 
     1.0     13.0     50.0    142.0    862.2   1856.0   3343.4   5273.8   8948.2  18117.2 142839.0 
corte_pax <- 100
aero_grandes <- aeropuertos %>% activate(edges) %>% 
  filter(pax > corte_pax) %>% 
  activate(nodes) %>% 
  filter(!node_is_isolated()) #eliminar nodos que quedan sin conexiones

Haz una primera gráfica (checa también como colorear según una variable de nodos):

aero_grandes %>% 
    activate(nodes) %>% 
    mutate(color_ca = ifelse(estado == "CA", "CA", "Otros")) %>% 
    ggraph(layout = 'fr', niter = 2000) +  #fr es un algoritmo basado en fuerzas
    geom_edge_link(arrow = arrow(length = unit(2, 'mm')), alpha = 0.1, colour="gray") + 
    geom_node_point(aes(colour = color_ca)) +
    theme_graph()

#Las aristas actúan como resortes, que no permiten que nodos ligados se alejen mucho
#Los nodos tienen fuerzas de repulsión entre ellos (la analogía física es de cargas elécricas), y también a veces de gravedad entre ellos.
#El algoritmo de representación intenta minimizar la energía de la configuración del sistema de atracciones y repulsiones.

EJEMPLO: AQUI CHECAMOS CÓMO COLOREAR OTRA VARIABLE DE NODOS Podemos colorear por estado, ciudad o nombre del aeropuerto

aero_grandes %>% 
    activate(nodes) %>% 
    mutate(color_at = ifelse(estado == "GA", "GA", "Otros")) %>%  #Georgia
    ggraph(layout = 'fr', niter = 2000) + 
    geom_edge_link(arrow = arrow(length = unit(2, 'mm')), alpha = 0.1, colour="gray") + 
    geom_node_point(aes(colour = color_at)) +
    theme_graph()

Pregunta 1: cuántas componentes tiene esta gráfica (tip: haz un mutate con la función group_components)

Tenemos un total de 575 nodos (aeropuertos) y se generaron 8 grupos (redes conexas) el grupo más grande

componentes <- aero_grandes %>% 
    activate(nodes) %>% 
    mutate(color_ca = ifelse(estado == "CA", "CA", "Otros"))  %>% 
    mutate(grupos = group_components())  %>%
#group_components These functions are wrappers around the various clustering functions provided by igraph. As with the other wrappers they automatically use the graph that is being computed on, and otherwise passes on its arguments to the relevant clustering function. The return value is always a numeric vector of group memberships so that nodes or edges with the same number are part of the same group. Grouping is predominantly made on nodes and currently the only grouping of edges supported is biconnected components.
    ggraph(layout = 'fr', niter = 2000) + 
    geom_edge_link(arrow = arrow(length = unit(2, 'mm')), alpha = 0.1, colour="gray") + 
    geom_node_point(aes(colour = color_at)) +
    theme_graph()
componentes$data
componentes$data$name
  [1] "BGR" "BOS" "ANC" "JFK" "LAS" "MIA" "EWR" "LAX" "AEX" "BFI" "ELM" "GEG" "ICT" "PBI" "PIT" "SFO" "VCT" "IAD"
 [19] "ABE" "AGS" "AVL" "AVP" "BDL" "BHM" "BNA" "BTR" "BUF" "BWI" "CAE" "CAK" "CHA" "CHO" "CHS" "CLE" "CLT" "CMH"
 [37] "CRW" "CVG" "DAB" "DAY" "DCA" "DTW" "EWN" "FAY" "GNV" "GPT" "GSO" "GSP" "HPN" "HSV" "ILM" "IND" "JAN" "LEX"
 [55] "LGA" "LIT" "MDT" "MGM" "MKE" "MLB" "MOB" "MSP" "MSY" "MYR" "OAJ" "ORF" "PGV" "PHF" "PHL" "PNS" "PWM" "RDU"
 [73] "RIC" "ROA" "SAV" "SDF" "SRQ" "STL" "SYR" "TLH" "TRI" "TYS" "VPS" "XNA" "ALB" "BGM" "BTV" "ERI" "FLO" "HHH"
 [91] "HTS" "HVN" "IPT" "ISP" "ITH" "LYH" "MHT" "PVD" "ROC" "SBY" "SCE" "SWF" "BFD" "DUJ" "EYW" "FKL" "FLL" "JHW"
[109] "LWB" "MCO" "PKB" "TPA" "ACT" "AOO" "BHB" "BKW" "BPT" "CKB" "CLL" "DRT" "GRK" "IAH" "JST" "LCH" "LFT" "MAF"
[127] "MGW" "MLU" "ORD" "PBG" "PQI" "SHD" "SHV" "TYR" "CID" "MCI" "MLI" "MSN" "OKC" "OMA" "SBN" "SGF" "TUL" "ABQ"
[145] "ATL" "AUS" "BKG" "DEN" "DFW" "HOU" "MDW" "PDX" "PHX" "PIE" "RSW" "SAN" "SAT" "SEA" "SLC" "SMF" "SNA" "TUS"
[163] "ABY" "ACY" "BMI" "DSM" "FNT" "GLH" "GRR" "GTR" "JAX" "MEM" "SJU" "UTM" "GUM" "ROP" "SPN" "TIQ" "SIT" "AMA"
[181] "FSM" "GGG" "LAW" "LBB" "SJT" "SPS" "STT" "STX" "TXK" "BOI" "BUR" "HNL" "KOA" "LIH" "OAK" "OGG" "ONT" "RNO"
[199] "SJC" "JHM" "LNY" "MKK" "HOM" "KEB" "PGM" "SOV" "AIN" "BTI" "FAI" "FYU" "GAL" "KAL" "KSM" "NUI" "NUL" "ORV"
[217] "OTZ" "PHO" "PIZ" "RBY" "SCC" "VEE" "WTK" "ADQ" "KLN" "KOZ" "OLH" "ORI" "MTM" "WFB" "HCR" "MCG" "AET" "AKP"
[235] "HSL" "KYU" "MRI" "TAL" "AKI" "ATT" "BET" "CYF" "EEK" "KKH" "KKI" "KLG" "KPN" "KUK" "KWK" "KWN" "KWT" "MLL"
[253] "NME" "NUP" "OOK" "PKA" "RSH" "TLT" "WNA" "WTL" "WWT" "AKN" "ANI" "BRW" "CDV" "DLG" "EMK" "ENA" "HPB" "UNK"
[271] "VDZ" "ABL" "BKC" "DRG" "ELI" "GAM" "GLV" "IAN" "KKA" "KTS" "KVL" "OBU" "OME" "RDB" "SHG" "SHH" "SKK" "SMK"
[289] "SVA" "TLA" "WBB" "WLK" "WMO" "ABI" "COS" "CRP" "EGE" "ELP" "FAT" "GJT" "HDN" "JAC" "MFE" "MTJ" "PSP" "SFB"
[307] "ADK" "BLI" "EUG" "JNU" "KTN" "PSG" "PUW" "WRG" "YAK" "BQN" "LGB" "PSE" "AUK" "CDB" "DUT" "KOT" "KVC" "MOU"
[325] "MYU" "SCM" "VAK" "ATK" "PQS" "ILI" "SDP" "SNP" "BVU" "TYE" "GST" "HNH" "HNS" "SGY" "ATW" "GUC" "SWO" "BIL"
[343] "BZN" "DLH" "FAR" "FSD" "GRB" "GTF" "IDA" "MBS" "MOT" "MSO" "ABR" "AZO" "BIS" "COU" "DAL" "ECP" "EVV" "FWA"
[361] "GFK" "LAN" "LNK" "LSE" "MQT" "PIA" "PLN" "RST" "TVC" "LJN" "EFD" "FOE" "RAP" "AZA" "BFL" "HRL" "TWF" "BED"
[379] "BQK" "CMI" "GCK" "LCK" "MQY" "PSM" "RFD" "YIP" "ILG" "MHK" "ESD" "FRD" "ASE" "DRO" "AHN" "CNM" "MCN" "MKL"
[397] "OWB" "BID" "WST" "LAR" "ACV" "BTM" "CDC" "CEC" "CIC" "CLD" "CMX" "COD" "CPR" "CWA" "EAU" "EKO" "FCA" "GCC"
[415] "HLN" "IPL" "IYK" "LMT" "LWS" "MFR" "MKG" "MMH" "MOD" "MRY" "OTH" "PAH" "PIH" "PSC" "RDD" "RDM" "RKS" "SBA"
[433] "SBP" "SGU" "SMX" "SPI" "SUN" "YUM" "BLD" "DQR" "GCN" "PGA" "AIA" "ALS" "BFF" "CDR" "CEZ" "CNY" "CVN" "CYS"
[451] "DDC" "DIK" "EAR" "FMN" "GDV" "GGW" "GRI" "HON" "HVR" "HYS" "IGM" "ISN" "JLN" "LBF" "LBL" "MBL" "MCE" "MCK"
[469] "OLF" "PIR" "PRC" "PUB" "RHI" "RIW" "SDY" "SHR" "SOW" "SVC" "TBN" "TEX" "VEL" "VIS" "WRL" "DHN" "FNL" "FTW"
[487] "IFP" "ISO" "LRD" "PAM" "PGD" "SCK" "TOL" "YNG" "ALW" "EAT" "STS" "YKM" "SIG" "SPB" "SSB" "VQS" "CEF" "CSG"
[505] "IAG" "LBE" "ORH" "RME" "MEI" "VLD" "CLM" "LKE" "BRO" "NYL" "ALO" "APN" "ATY" "BJI" "BRD" "CIU" "DVL" "ESC"
[523] "FOD" "HIB" "IMT" "INL" "JMS" "MCW" "MSL" "PIB" "SUX" "TUP" "TVF" "ACK" "LEB" "MVY" "PVC" "1G4" "VGT" "BRL"
[541] "DEC" "DBQ" "ROW" "SAF" "ENV" "ART" "AUG" "CGI" "EWB" "HGR" "HYA" "IRK" "LNS" "MAZ" "MSS" "MWA" "OGS" "RKD"
[559] "RUT" "SLK" "UIN" "FLG" "ITO" "AST" "ELD" "HRO" "ONP" "PDT" "SLN" "STC" "STJ" "PPG" "CPX" "JRV" "LFI"
componentes$data$grupos
  [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
 [55] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[109] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[163] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[217] 1 1 1 1 1 1 1 1 1 1 1 1 4 4 1 1 1 1 1 1 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[271] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[325] 1 1 1 1 1 1 1 1 3 3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[379] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[433] 1 1 1 1 1 1 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[487] 1 1 1 6 1 1 1 1 1 1 1 1 1 7 7 1 1 1 1 1 1 1 1 1 1 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 1
[541] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 6

Preguntar qué significa el parámetro strong/weak

NO CORRER ESTE CHUNK:

aero_grandes %>% 
    activate(nodes) %>% 
    mutate(color_ca = ifelse(estado == "CA", "CA", "Otros"),group=group_components(type = "strong")) %>% 
    ggraph(layout = 'fr', niter = 2000) + 
    geom_edge_link(arrow = arrow(length = unit(2, 'mm')), alpha = 0.1, colour="gray") + 
    geom_node_point(aes(colour = color_ca)) +
    theme_graph()


aero_grandes %>% 
    activate(nodes) %>% 
    mutate(color_ca = ifelse(estado == "CA", "CA", "Otros"),group=group_components(type = "weak")) %>% 
    ggraph(layout = 'fr', niter = 2000) + 
    geom_edge_link(arrow = arrow(length = unit(2, 'mm')), alpha = 0.1, colour="gray") + 
    geom_node_point(aes(colour = color_ca)) +
    theme_graph()

Pregunta 2: prueba otro layout: kk o graphopt, por ejemplo. ¿Puedes reconocer estructuras distintas? ¿Qué método parece funcionar mejor?

Parece que el layout kk elimina de la gráfica los vértices que no son fuertemente conexos es más sencillo apreciar la red pues hace un zoom a donde hay mayor cantidad de nodos conexos. Con este gráfico, notamos que el estado de California (nodos rojos) cuenta con muchos más aeropuertos que aparentemente cada uno debe conectarse con distintos aeropuertos de otros estados.

En cambio, graphopt mantiene todos los nodos pero parece alejar del centro aquellos aeropuertos que tienen poca o nula conexión con el resto de la red lo cual da una perspectiva más alejada y más difícil de leer

aero_grandes %>% 
    activate(nodes) %>% 
    mutate(color_ca = ifelse(estado == "CA", "CA", "Otros")) %>% 
    ggraph(layout = 'kk') +  #Argument `niter' is deprecated and has no effect
    geom_edge_link(arrow = arrow(length = unit(2, 'mm')), alpha = 0.1, colour="gray") + 
    geom_node_point(aes(colour = color_ca)) +
    theme_graph()



aero_grandes %>% 
    activate(nodes) %>% 
    mutate(color_ca = ifelse(estado == "CA", "CA", "Otros")) %>% 
    ggraph(layout = 'graphopt', niter = 2000) +  #fr es un algoritmo basado en fuerzas
    geom_edge_link(arrow = arrow(length = unit(2, 'mm')), alpha = 0.1, colour="gray") + 
    geom_node_point(aes(colour = color_ca)) +
    theme_graph()

Extraer componente grande

Filtra la componente conexa más grande:

aero <- aero_grandes %>% 
    activate(nodes) %>% 
    mutate(component = group_components()) %>%
    filter(component == 1)

Intermediación

Calcula intermediación:

aero <- aero %>% activate(nodes) %>% 
  mutate(intermediacion = centrality_betweenness())

Pregunta 3: ¿cuáles son los aeropuertos con intermediación más grande? (convierte el objeto de la gráfica a tibble después de activar nodos).

El aeropuerto con mayor intermediación es ANC (Aeropuerto Internacional de Anchorage, Alaska) con 86685.51871 Otros aeropuertos importantes son: 35444.42724, DEN, Denver, Colorado 33673.75778, MSP, Minneapolis, Minesota 31411.75000, BET, Bethel, Alaska 30286.27085, SEA, Seattle, Washington 29361.47210, ORD, Chicago, Illinois 26290.08520, ATL, Atlanta, Georgia

aero <- aero %>% 
  activate(nodes) %>% 
  as_tibble %>%
view(aero)

Ahora haz una gráfica coloreando con un estado relevante (considera tu respuesta de la pregunta anterior) y usando la intermediación como tamaño:

aero %>%
    activate(nodes) %>% 
    mutate(color_edo = ifelse(estado == "AK", "AK", "Otros")) %>% 
    ggraph(layout = 'fr', niter=2000) + 
    geom_edge_link(arrow = arrow(length = unit(2, 'mm')), alpha = 0.1, colour="gray") + 
    geom_node_point(aes(size = intermediacion, colour=color_edo)) +
    theme_graph()

Pregunta 4 Explica el nodo con mayor intermediación de la gráfica. ¿Qué conecta?

Seleccionamos el estado de Alaska ya que 2 de sus aeropuertos tienen una intermediación alta.

Con ello, vemos que el aeropuerto de Anchorage está conectando de manera casi exclusiva todos los aeropuertos de Alaska aeropuestos de otros estados de los estados.

Centralidad de eigenvector

Calcula centralidad de eigenvector, y ahora usa tamaño para esta centralidad y color para intermediación

aero <- aero %>%
    activate(nodes) %>% 
    mutate(central_eigen = centrality_eigen())
aero %>%
    activate(nodes) %>% 
    mutate(color_edo = ifelse(estado == "AK", "AK", "Otros")) %>% 
    ggraph(layout = 'fr', niter=2000) + 
    geom_edge_link(arrow = arrow(length = unit(2, 'mm')), alpha = 0.1, colour="gray") + 
    geom_node_point(aes(size = central_eigen, colour=intermediacion)) +
    theme_graph()

Pregunta 5 ¿Cuáles son los aeropuertos con mayor centralidad de eigenvector? Contrasta con intermediación.

El aeropuerto de ATL que tiene mayor centralidad es el séptimo lugar en intermediación, por otro lado, el aeropuerto de ORD se coloca en segundo lugar de centralidad de eigenvector con la sexta posición el aeropuerto de DFW es el tercer lugar en centralidad. Sin embargo, no figuró en los primeros lugares bajo intermediación.

El aeropuerto con mayor centralidad de eigenvector es ATL (Aeropuerto Internacional de Atlanta, Georgia) con 1 Otros aeropuertos importantes son: 0.98400301, ORD, Chicago, Illinois 0.92300746, DFW, Dallas/Ft.Worth, Texas 0.91313227, DEN, Denver, Colorado 0.90823356, MSP, Minneapolis, Minesota 0.89876803, DTW, Detroit, Michigan 0.86630960, LAS, Las Vegas, Nevada

El aeropuerto con mayor intermediación es ANC (Aeropuerto Internacional de Anchorage, Alaska) con 86685.51871 Otros aeropuertos importantes son: 35444.42724, DEN, Denver, Colorado 33673.75778, MSP, Minneapolis, Minesota 31411.75000, BET, Bethel, Alaska 30286.27085, SEA, Seattle, Washington 29361.47210, ORD, Chicago, Illinois 26290.08520, ATL, Atlanta, Georgia

aero <- aero %>% 
  activate(nodes) %>% 
  as_tibble %>%
view(aero)

Examinar centralidad

Elimina los aeropuertos de Alaska y vuelve a graficar, esta vez usando centralidad de eigenvector para color y tamaño.

aero %>%
  activate(nodes) %>% 
  filter(estado!="AK") %>% #Eliminamos estado de Alaska
ggraph(layout = 'graphopt', spring.constant = 0.25, charge = 0.05, niter = 300) + #Usamos layoutgraphopt
  geom_edge_link2(arrow = arrow(length = unit(2, 'mm')), alpha = 0.01, colour="black") + 
  geom_node_point(aes(size = central_eigen, colour=central_eigen)) +
  theme_graph() 

Pregunta 6: ¿calcular centralidad y luego filtrar nodos es lo mismo que filtrar nodos y luego calcular centralidad? No es lo mismo, ya que la centralidad depende de la importancia de los nodos vecinos. Es decir, si primero filtramos los nodos de Alaska y luego calculamos centralidad entonces estos no se toman en cuenta para el cálculo y si los quitamos después de calcular la centralidad, en realidad sólo estamos omitiendo nodos que sí se consideraron para calcular los nodos.

Definición Centralidad de eigenvector

Esta medida considera que la importancia de un nodo está dado por la suma normalizada de las importancias de sus vecinos. De esta forma, es importante estar cercano a nodos importantes (como en cercanía), pero también cuenta conectarse a muchos nodos (como en grado).

  • Nótese que esta es una descripción circular: para saber la importancia de un nodo, hay que saber la importancia de sus vecinos.

Pregunta 7: experimenta con los parámetros del layout (por ejemplo, los 2 que se usan arriba). ¿Cómo obtienes mejores resultados?

Cambiamos los parámetros spring constant y charge.

Aumentar spring constant (Por ejemplo a 10) hace que los nodos con mayor centralidad se aglomeren y traslapen. Por lo que visualmente no es posible apreciarlos bien. Por el contrario, si reducimos este valor a por ejemplo 0.01, los nodos con mayor centralidad se separan demasiado llegando a los extemos del gráfico.

Disminuir charge (por ejemplo a 0.001) hace que los nodos se separen más entre sí, mientras que aumentar la carga (por ejemplo a 0.5) hace que los nodos se repelan.

aero %>%
  activate(nodes) %>% 
  filter(estado!="AK") %>% #Eliminamos estado de Alaska
ggraph(layout = 'graphopt', spring.constant = 0.25, charge = 0.05, niter = 300) + #Usamos layoutgraphopt
  #The spring constant, the default value is one.
  #The charge of the vertices, used to calculate electric repulsion. The default is 0.001.
  geom_edge_link2(arrow = arrow(length = unit(2, 'mm')), alpha = 0.01, colour="black") + 
  geom_node_point(aes(size = central_eigen, colour=central_eigen)) +
  theme_graph() 

Pregunta 8 (más difícil): etiqueta los nodos. Etiqueta solo los nodos que tengan centralidad de eigenvector alta. Puedes experimentar (layout, colores, tamaño de texto) con este código:

nodos_imp <- aero %>% activate(nodes) %>% as_tibble() %>%
    arrange(desc(central_eigen))
qplot(pull(nodos_imp, central_eigen))

Comprobamos cuáles son:

etiquetas <- aero %>% activate(nodes) %>% as_tibble() %>%
    filter(estado!="AK") %>% 
    arrange(desc(central_eigen)) %>% 
    top_n(10) %>% 
    select(name)
Selecting by central_eigen
cota_centro<-.85
aero %>%
  activate(nodes) %>% 
  filter(estado!="AK") %>% 
ggraph(layout = 'graphopt', spring.constant = 0.25, charge = 0.05, niter = 300) + 
  geom_edge_link2(arrow = arrow(length = unit(2, 'mm')), alpha = 0.01, colour="black") + 
  geom_node_point(aes(size = central_eigen, colour=central_eigen)) +
  geom_node_text(aes(filter=central_eigen>cota_centro,label =name, alpha = central_eigen), repel = FALSE, size = 3, color = "red") +
  theme_graph() 

aero %>%
  activate(nodes) %>% 
  filter(estado!="AK") %>% 
ggraph(layout = 'graphopt', spring.constant = 0.25, charge = 0.05, niter = 300) + 
  geom_edge_link2(arrow = arrow(length = unit(2, 'mm')), alpha = 0.01, colour="black") + 
  geom_node_point(aes(size = central_eigen, colour=central_eigen)) +
  geom_node_text(aes(label = ifelse(central_eigen > cota_centro, name, NA), alpha = central_eigen), repel = TRUE, size = 3, color = "black") +
  theme_graph() 

LS0tCnRpdGxlOiAiQ2VudHJhbGlkYWQgZW4gcmVkZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCgojIyMgRGF0b3MKCkVuIGVzdGUgZWplbXBsb3MgY29uc2lkZXJhbW9zIGxhIHJlZCBkZSBhZXJvcHVlcnRvcyBkZSBFVToKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRpZHlncmFwaCkKbGlicmFyeShnZ3JhcGgpCmxpYnJhcnkoaWdyYXBoZGF0YSkKZGF0YSgiVVNhaXJwb3J0cyIpCmBgYAoKVVMgYWlycG9ydCBuZXR3b3JrLCAyMDEwIERlY2VtYmVyCkRlc2NyaXB0aW9uClRoZSBuZXR3b3JrIG9mIHBhc3NhbmdlciBmbGlnaHRzIGJldHdlZW4gYWlycG9ydHMgaW4gdGhlIFVuaXRlZCBTdGF0ZXMuIFRoZSBkYXRhIHNldCB3YXMgY29tcGlsZWQgYmFzZWQgb24gZmxpZ2h0cyBpbiAyMDEwIERlY2VtYmVyLiBUaGlzIG5ldHdvcmsgaXMgZGlyZWN0ZWQgYW5kIGVkZ2UgZGlyZWN0aW9ucyBjb3JyZXNwb25kIHRvIGZsaWdodCBkaXJlY3Rpb25zLiBFYWNoIGVkZ2UgaXMgc3BlY2lmaWMgdG8gYSBzaW5nbGUgY2FycmllciBhaXJjcmFmdCB0eXBlLiBNdWx0aXBsZSBjYXJyaWVycyBiZXR3ZWVuIHRoZSBzYW1lIHR3byBhaXJwb3J0cyBhcmUgZGVub3RlZCBieSBtdWx0aXBsZSBlZGdlcy4KCm5hbWUKU3ltYm9saWMgdmVydGV4IG5hbWUsIHRoaXMgaXMgdGhlIHRocmVlIGxldHRlciBJQVRBIGFpcnBvcnQgY29kZS4KCkNpdHkKQ2l0eSBhbmQgc3RhdGUsIHdoZXJlIHRoZSBhaXJwb3J0IGlzIGxvY2F0ZWQuCgpQb3NpdGlvbgpQb3NpdGlvbiBvZiB0aGUgYWlycG9ydCwgaW4gV0dTIGNvb3JkaW5hdGVzLgoKRWRnZSBhdHRyaWJ1dGVzOgoKQ2FycmllcgpOYW1lIG9mIHRoZSBhaXJsaW5lLiBUaGUgbmV0d29yayBpbmNsdWRlcyBib3RoIGRvbWVzdGljIGFuZCBpbnRlcm5hdGlvbmFsIGNhcnJpZXJzIHRoYXQgcGVyZm9ybWVkIGF0IGxlYXN0IG9uZSBmbGlnaHQgaW4gRGVjZW1iZXIgb2YgMjAxMC4KCkRlcGFydHVyZXMKVGhlIG51bWJlciBvZiBkZXBhcnR1cmVzIChmb3IgYSBnaXZlbiBhaXJsaW5lIGFuZCBhaXJjcmFmdCB0eXBlLgoKU2VhdHMKVGhlIHRvdGFsIG51bWJlciBvZiBzZWF0cyBhdmFpbGFibGUgb24gdGhlIGZsaWdodHMgY2FycmllZCBvdXQgYnkgYSBnaXZlbiBhaXJsaW5lLCB1c2luZyBhIGdpdmVuIGFpcmNyYWZ0IHR5cGUuCgpQYXNzZW5nZXJzClRoZSB0b3RhbCBudW1iZXIgb2YgcGFzc2FuZ2VycyBvbiB0aGUgZmxpZ2h0cyBjYXJyaWVkIG91dCBieSBhIGdpdmVuIGFpcmxpbmUsIHVzaW5nIGEgZ2l2ZW4gYWlyY3JhZnQgdHlwZS4KCkFpcmNyYWZ0ClR5cGUgb2YgdGhlIGFpcmNyYWZ0LgoKRGlzdGFuY2UKVGhlIGRpc3RhbmNlIGJldHdlZW4gdGhlIHR3byBhaXJwb3J0cywgaW4gbWlsZXMuCgpgYGB7cn0KIyB2ZXIgZGV0YWxsZXMKP1VTYWlycG9ydHMKYGBgCgpOb3RhIHF1ZSBjYWRhIGFyaXN0YSBjb3JyZXNwb25kZSBhIHVuYSBhZXJvbMOtbmVhIChjYXJyaWVyKSB5IHRpcG8gZGUgYXZpw7NuIChBaXJjcmFmdCksIHkgbG9zIG5vZG9zIHNvbiAKbG9zIGFlcm9wdWVydG9zLiBMb3MgZGF0b3MgZGUgbGFzIGFyaXN0YXMgY29ycmVzcG9uZGVuIGEgdnVlbG9zIGRlIERpY2llbWJyZSBkZSAyMDEwLCB5CmVzIHVuYSBncsOhZmljYSBkaXJpZ2lkYS4KCmBgYHtyfQphaXJwb3J0cyA8LSBVU2FpcnBvcnRzICU+JSBhc190YmxfZ3JhcGgoKQphaXJwb3J0cwpgYGAKCkVzdGEgZ8WVYWZpY2EgZXMgdW4gKiptdWx0aWdyYWZvKiogKHB1ZWRlIGhhYmVyIHZhcmlhcyBhcmlzdGFzIGNvbiBsYSBtaXNtYSBkaXJlY2Npw7NuIGVuIHVuIHBhciBkZSBub2RvcykuCk5vcyBpbnRlcmVzYSBlbiBwcmltZXIgbHVnYXIgYWdyZWdhciBhIHVuIGdyYWZvLCB5IGNvbnNpZGVyYXIgZWwgdG90YWwgZGUgcGFzYWplcm9zICAocHVlZGVzIHRhbWJpw6luCmNvbnNpZGVyYXIgbsO6bWVybyBkZSBhc2llbnRvcywgcG9yIGVqZW1wbG8pIHF1ZSB2aWFqw7MKZW50cmUgY2FkYSBwYXIgZGUgYWVyb3B1ZXJ0b3MuIFBvZGVtb3MgYWdyZWdhciBkZSBsYXMgc2lndWllbnRlIGZvcm1hOgoKYGBge3J9CiMgc2VsZWNjaW9uYW1vcyBzb2xvIHBhc2FqZXJvcwp2ZXJ0aWNlcyA8LSBhaXJwb3J0cyAlPiUgCiAgYWN0aXZhdGUoZWRnZXMpICU+JSAKICBzZWxlY3QodG8sIGZyb20sIFBhc3NlbmdlcnMpICU+JSBhc190aWJibGUoKQojIGFncmVnYXIgY29uc2lkZXJhcmFuZG8gZWwgdG90YWwgZGUgcGFzYWplcm9zCnZlcnRpY2VzX2FncmVnYWRvcyA8LSB2ZXJ0aWNlcyAlPiUgCiAgZ3JvdXBfYnkodG8sIGZyb20pICU+JSAKICBzdW1tYXJpc2UocGF4ID0gc3VtKFBhc3NlbmdlcnMpKQojIG5vZG9zLCB5IGFncmVnYXIgZXN0YWRvIGEgbGEgY2l1ZGFkCm5vZG9zIDwtIGFpcnBvcnRzICU+JSBhY3RpdmF0ZShub2RlcykgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBzZXBhcmF0ZShDaXR5LCBpbnRvID0gYygnY2l1ZGFkX25vbWJyZScsICdlc3RhZG8nKSwgc2VwID0gJywgJykKIyBjb25zdHJ1aXIgbnVldmEgcmVkCmFlcm9wdWVydG9zIDwtIHRibF9ncmFwaChub2RlcyA9IG5vZG9zLCBlZGdlcyA9IHZlcnRpY2VzX2FncmVnYWRvcykgCmFlcm9wdWVydG9zIApgYGAKCiMjIEZpbHRybyBkZSBjb25leGlvbmVzIGTDqWJpbGVzCgpQb2RlbW9zIHRhbWJpw6luIGZpbHRyYXIgb3BjaW9uYWxtZW50ZSBhcXVlbGxhcyBjb25leGlvbmVzIHF1ZSB0ZW5nYW4gdW4gbsO6bWVybyBkZSBwYXNhamVyb3MKYmFqbyBkdXJhbnRlIGVsIG1lcyBkZSBvYnNlcnZhY2nDs24uIExhIGRpc3RyaWJ1Y2nDs24gZGUgcGFzYWplcm9zIHBvZGVtb3MgZXhhbWluYXJsYSBjb25fCgpgYGB7cn0KcGFzYWplcm9zIDwtIGFlcm9wdWVydG9zICU+JSBhY3RpdmF0ZShlZGdlcykgJT4lIAogIHNlbGVjdChmcm9tLCB0byAsIHBheCkKcXVhbnRpbGUocHVsbChwYXNhamVyb3MsIHBheCksIHNlcSgwLCAxLCAwLjEpKQpgYGAKCmBgYHtyfQpjb3J0ZV9wYXggPC0gMTAwCmFlcm9fZ3JhbmRlcyA8LSBhZXJvcHVlcnRvcyAlPiUgYWN0aXZhdGUoZWRnZXMpICU+JSAKICBmaWx0ZXIocGF4ID4gY29ydGVfcGF4KSAlPiUgCiAgYWN0aXZhdGUobm9kZXMpICU+JSAKICBmaWx0ZXIoIW5vZGVfaXNfaXNvbGF0ZWQoKSkgI2VsaW1pbmFyIG5vZG9zIHF1ZSBxdWVkYW4gc2luIGNvbmV4aW9uZXMKYGBgCgpIYXogdW5hIHByaW1lcmEgZ3LDoWZpY2EgKGNoZWNhIHRhbWJpw6luIGNvbW8gY29sb3JlYXIgc2Vnw7puIHVuYSB2YXJpYWJsZSBkZSBub2Rvcyk6CgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQ9MTB9CmFlcm9fZ3JhbmRlcyAlPiUgCiAgICBhY3RpdmF0ZShub2RlcykgJT4lIAogICAgbXV0YXRlKGNvbG9yX2NhID0gaWZlbHNlKGVzdGFkbyA9PSAiQ0EiLCAiQ0EiLCAiT3Ryb3MiKSkgJT4lIAogICAgZ2dyYXBoKGxheW91dCA9ICdmcicsIG5pdGVyID0gMjAwMCkgKyAgI2ZyIGVzIHVuIGFsZ29yaXRtbyBiYXNhZG8gZW4gZnVlcnphcwogICAgZ2VvbV9lZGdlX2xpbmsoYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDIsICdtbScpKSwgYWxwaGEgPSAwLjEsIGNvbG91cj0iZ3JheSIpICsgCiAgICBnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG91ciA9IGNvbG9yX2NhKSkgKwogICAgdGhlbWVfZ3JhcGgoKQojTGFzIGFyaXN0YXMgYWN0w7phbiBjb21vIHJlc29ydGVzLCBxdWUgbm8gcGVybWl0ZW4gcXVlIG5vZG9zIGxpZ2Fkb3Mgc2UgYWxlamVuIG11Y2hvCiNMb3Mgbm9kb3MgdGllbmVuIGZ1ZXJ6YXMgZGUgcmVwdWxzacOzbiBlbnRyZSBlbGxvcyAobGEgYW5hbG9nw61hIGbDrXNpY2EgZXMgZGUgY2FyZ2FzIGVsw6ljcmljYXMpLCB5IHRhbWJpw6luIGEgdmVjZXMgZGUgZ3JhdmVkYWQgZW50cmUgZWxsb3MuCiNFbCBhbGdvcml0bW8gZGUgcmVwcmVzZW50YWNpw7NuIGludGVudGEgbWluaW1pemFyIGxhIGVuZXJnw61hIGRlIGxhIGNvbmZpZ3VyYWNpw7NuIGRlbCBzaXN0ZW1hIGRlIGF0cmFjY2lvbmVzIHkgcmVwdWxzaW9uZXMuCmBgYAoKRUpFTVBMTzogQVFVSSBDSEVDQU1PUyBDw5NNTyBDT0xPUkVBUiBPVFJBIFZBUklBQkxFIERFIE5PRE9TClBvZGVtb3MgY29sb3JlYXIgcG9yIGVzdGFkbywgY2l1ZGFkIG8gbm9tYnJlIGRlbCBhZXJvcHVlcnRvCgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQ9MTB9CmFlcm9fZ3JhbmRlcyAlPiUgCiAgICBhY3RpdmF0ZShub2RlcykgJT4lIAogICAgbXV0YXRlKGNvbG9yX2F0ID0gaWZlbHNlKGVzdGFkbyA9PSAiR0EiLCAiR0EiLCAiT3Ryb3MiKSkgJT4lICAjR2VvcmdpYQogICAgZ2dyYXBoKGxheW91dCA9ICdmcicsIG5pdGVyID0gMjAwMCkgKyAKICAgIGdlb21fZWRnZV9saW5rKGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgyLCAnbW0nKSksIGFscGhhID0gMC4xLCBjb2xvdXI9ImdyYXkiKSArIAogICAgZ2VvbV9ub2RlX3BvaW50KGFlcyhjb2xvdXIgPSBjb2xvcl9hdCkpICsKICAgIHRoZW1lX2dyYXBoKCkKYGBgCgoqKlByZWd1bnRhIDEqKjogY3XDoW50YXMgY29tcG9uZW50ZXMgdGllbmUgZXN0YSBncsOhZmljYSAodGlwOiBoYXogdW4gbXV0YXRlIGNvbiBsYSBmdW5jacOzbiAKKmdyb3VwX2NvbXBvbmVudHMqKQoKVGVuZW1vcyB1biB0b3RhbCBkZSA1NzUgbm9kb3MgKGFlcm9wdWVydG9zKSB5IHNlIGdlbmVyYXJvbiA4IGdydXBvcyAocmVkZXMgY29uZXhhcykgZWwgZ3J1cG8gbcOhcyBncmFuZGUKCmBgYHtyfQpjb21wb25lbnRlcyA8LSBhZXJvX2dyYW5kZXMgJT4lIAogICAgYWN0aXZhdGUobm9kZXMpICU+JSAKICAgIG11dGF0ZShjb2xvcl9jYSA9IGlmZWxzZShlc3RhZG8gPT0gIkNBIiwgIkNBIiwgIk90cm9zIikpICAlPiUgCiAgICBtdXRhdGUoZ3J1cG9zID0gZ3JvdXBfY29tcG9uZW50cygpKSAgJT4lCiNncm91cF9jb21wb25lbnRzIFRoZXNlIGZ1bmN0aW9ucyBhcmUgd3JhcHBlcnMgYXJvdW5kIHRoZSB2YXJpb3VzIGNsdXN0ZXJpbmcgZnVuY3Rpb25zIHByb3ZpZGVkIGJ5IGlncmFwaC4gQXMgd2l0aCB0aGUgb3RoZXIgd3JhcHBlcnMgdGhleSBhdXRvbWF0aWNhbGx5IHVzZSB0aGUgZ3JhcGggdGhhdCBpcyBiZWluZyBjb21wdXRlZCBvbiwgYW5kIG90aGVyd2lzZSBwYXNzZXMgb24gaXRzIGFyZ3VtZW50cyB0byB0aGUgcmVsZXZhbnQgY2x1c3RlcmluZyBmdW5jdGlvbi4gVGhlIHJldHVybiB2YWx1ZSBpcyBhbHdheXMgYSBudW1lcmljIHZlY3RvciBvZiBncm91cCBtZW1iZXJzaGlwcyBzbyB0aGF0IG5vZGVzIG9yIGVkZ2VzIHdpdGggdGhlIHNhbWUgbnVtYmVyIGFyZSBwYXJ0IG9mIHRoZSBzYW1lIGdyb3VwLiBHcm91cGluZyBpcyBwcmVkb21pbmFudGx5IG1hZGUgb24gbm9kZXMgYW5kIGN1cnJlbnRseSB0aGUgb25seSBncm91cGluZyBvZiBlZGdlcyBzdXBwb3J0ZWQgaXMgYmljb25uZWN0ZWQgY29tcG9uZW50cy4KICAgIGdncmFwaChsYXlvdXQgPSAnZnInLCBuaXRlciA9IDIwMDApICsgCiAgICBnZW9tX2VkZ2VfbGluayhhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMiwgJ21tJykpLCBhbHBoYSA9IDAuMSwgY29sb3VyPSJncmF5IikgKyAKICAgIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gY29sb3JfYXQpKSArCiAgICB0aGVtZV9ncmFwaCgpCmBgYAoKYGBge3J9CmNvbXBvbmVudGVzJGRhdGEKYGBgCgpgYGB7cn0KY29tcG9uZW50ZXMkZGF0YSRuYW1lCmBgYAoKYGBge3J9CmNvbXBvbmVudGVzJGRhdGEkZ3J1cG9zCmBgYAoKUHJlZ3VudGFyIHF1w6kgc2lnbmlmaWNhIGVsIHBhcsOhbWV0cm8gc3Ryb25nL3dlYWsgCgpOTyBDT1JSRVIgRVNURSBDSFVOSzoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0PTEwfQphZXJvX2dyYW5kZXMgJT4lIAogICAgYWN0aXZhdGUobm9kZXMpICU+JSAKICAgIG11dGF0ZShjb2xvcl9jYSA9IGlmZWxzZShlc3RhZG8gPT0gIkNBIiwgIkNBIiwgIk90cm9zIiksZ3JvdXA9Z3JvdXBfY29tcG9uZW50cyh0eXBlID0gInN0cm9uZyIpKSAlPiUgCiAgICBnZ3JhcGgobGF5b3V0ID0gJ2ZyJywgbml0ZXIgPSAyMDAwKSArIAogICAgZ2VvbV9lZGdlX2xpbmsoYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDIsICdtbScpKSwgYWxwaGEgPSAwLjEsIGNvbG91cj0iZ3JheSIpICsgCiAgICBnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG91ciA9IGNvbG9yX2NhKSkgKwogICAgdGhlbWVfZ3JhcGgoKQoKYWVyb19ncmFuZGVzICU+JSAKICAgIGFjdGl2YXRlKG5vZGVzKSAlPiUgCiAgICBtdXRhdGUoY29sb3JfY2EgPSBpZmVsc2UoZXN0YWRvID09ICJDQSIsICJDQSIsICJPdHJvcyIpLGdyb3VwPWdyb3VwX2NvbXBvbmVudHModHlwZSA9ICJ3ZWFrIikpICU+JSAKICAgIGdncmFwaChsYXlvdXQgPSAnZnInLCBuaXRlciA9IDIwMDApICsgCiAgICBnZW9tX2VkZ2VfbGluayhhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMiwgJ21tJykpLCBhbHBoYSA9IDAuMSwgY29sb3VyPSJncmF5IikgKyAKICAgIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gY29sb3JfY2EpKSArCiAgICB0aGVtZV9ncmFwaCgpCmBgYAoKKipQcmVndW50YSAyKio6IHBydWViYSBvdHJvIGxheW91dDoga2sgbyBncmFwaG9wdCwgcG9yIGVqZW1wbG8uIMK/UHVlZGVzIHJlY29ub2NlciBlc3RydWN0dXJhcwpkaXN0aW50YXM/IMK/UXXDqSBtw6l0b2RvIHBhcmVjZSBmdW5jaW9uYXIgbWVqb3I/CgpQYXJlY2UgcXVlIGVsIGxheW91dCBrayBlbGltaW5hIGRlIGxhIGdyw6FmaWNhIGxvcyB2w6lydGljZXMgcXVlIG5vIHNvbiBmdWVydGVtZW50ZSBjb25leG9zCmVzIG3DoXMgc2VuY2lsbG8gYXByZWNpYXIgbGEgcmVkIHB1ZXMgaGFjZSB1biB6b29tIGEgZG9uZGUgaGF5IG1heW9yIGNhbnRpZGFkIGRlIG5vZG9zIGNvbmV4b3MuCkNvbiBlc3RlIGdyw6FmaWNvLCBub3RhbW9zIHF1ZSBlbCBlc3RhZG8gZGUgQ2FsaWZvcm5pYSAobm9kb3Mgcm9qb3MpIGN1ZW50YSBjb24gbXVjaG9zIG3DoXMgCmFlcm9wdWVydG9zIHF1ZSBhcGFyZW50ZW1lbnRlIGNhZGEgdW5vIGRlYmUgY29uZWN0YXJzZSBjb24gZGlzdGludG9zIGFlcm9wdWVydG9zIGRlIG90cm9zIAplc3RhZG9zLgoKRW4gY2FtYmlvLCBncmFwaG9wdCBtYW50aWVuZSB0b2RvcyBsb3Mgbm9kb3MgcGVybyBwYXJlY2UgYWxlamFyIGRlbCBjZW50cm8gYXF1ZWxsb3MgYWVyb3B1ZXJ0b3MgCnF1ZSB0aWVuZW4gcG9jYSBvIG51bGEgY29uZXhpw7NuIGNvbiBlbCByZXN0byBkZSBsYSByZWQgbG8gY3VhbCBkYSB1bmEgcGVyc3BlY3RpdmEgbcOhcyBhbGVqYWRhIAp5IG3DoXMgZGlmw61jaWwgZGUgbGVlcgoKYGBge3J9CmFlcm9fZ3JhbmRlcyAlPiUgCiAgICBhY3RpdmF0ZShub2RlcykgJT4lIAogICAgbXV0YXRlKGNvbG9yX2NhID0gaWZlbHNlKGVzdGFkbyA9PSAiQ0EiLCAiQ0EiLCAiT3Ryb3MiKSkgJT4lIAogICAgZ2dyYXBoKGxheW91dCA9ICdraycpICsgICNBcmd1bWVudCBgbml0ZXInIGlzIGRlcHJlY2F0ZWQgYW5kIGhhcyBubyBlZmZlY3QKICAgIGdlb21fZWRnZV9saW5rKGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgyLCAnbW0nKSksIGFscGhhID0gMC4xLCBjb2xvdXI9ImdyYXkiKSArIAogICAgZ2VvbV9ub2RlX3BvaW50KGFlcyhjb2xvdXIgPSBjb2xvcl9jYSkpICsKICAgIHRoZW1lX2dyYXBoKCkKCgphZXJvX2dyYW5kZXMgJT4lIAogICAgYWN0aXZhdGUobm9kZXMpICU+JSAKICAgIG11dGF0ZShjb2xvcl9jYSA9IGlmZWxzZShlc3RhZG8gPT0gIkNBIiwgIkNBIiwgIk90cm9zIikpICU+JSAKICAgIGdncmFwaChsYXlvdXQgPSAnZ3JhcGhvcHQnLCBuaXRlciA9IDIwMDApICsgIAogICAgZ2VvbV9lZGdlX2xpbmsoYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDIsICdtbScpKSwgYWxwaGEgPSAwLjEsIGNvbG91cj0iZ3JheSIpICsgCiAgICBnZW9tX25vZGVfcG9pbnQoYWVzKGNvbG91ciA9IGNvbG9yX2NhKSkgKwogICAgdGhlbWVfZ3JhcGgoKQpgYGAKCgojIyMgRXh0cmFlciBjb21wb25lbnRlIGdyYW5kZQoKRmlsdHJhIGxhIGNvbXBvbmVudGUgY29uZXhhIG3DoXMgZ3JhbmRlOgoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0PTEwfQphZXJvIDwtIGFlcm9fZ3JhbmRlcyAlPiUgCiAgICBhY3RpdmF0ZShub2RlcykgJT4lIAogICAgbXV0YXRlKGNvbXBvbmVudCA9IGdyb3VwX2NvbXBvbmVudHMoKSkgJT4lCiAgICBmaWx0ZXIoY29tcG9uZW50ID09IDEpCmBgYAoKIyMjIEludGVybWVkaWFjacOzbgoKQ2FsY3VsYSBpbnRlcm1lZGlhY2nDs246CgpgYGB7cn0KYWVybyA8LSBhZXJvICU+JSBhY3RpdmF0ZShub2RlcykgJT4lIAogIG11dGF0ZShpbnRlcm1lZGlhY2lvbiA9IGNlbnRyYWxpdHlfYmV0d2Vlbm5lc3MoKSkKYGBgCgoqKlByZWd1bnRhIDMqKjogwr9jdcOhbGVzIHNvbiBsb3MgYWVyb3B1ZXJ0b3MgY29uIGludGVybWVkaWFjacOzbiBtw6FzIGdyYW5kZT8gCihjb252aWVydGUgZWwgb2JqZXRvIGRlIGxhIGdyw6FmaWNhIGEgdGliYmxlIGRlc3B1w6lzIGRlIGFjdGl2YXIgbm9kb3MpLgoKRWwgYWVyb3B1ZXJ0byBjb24gbWF5b3IgaW50ZXJtZWRpYWNpw7NuIGVzIEFOQyAoQWVyb3B1ZXJ0byBJbnRlcm5hY2lvbmFsIGRlIEFuY2hvcmFnZSwgQWxhc2thKSBjb24gODY2ODUuNTE4NzEKT3Ryb3MgYWVyb3B1ZXJ0b3MgaW1wb3J0YW50ZXMgc29uOgozNTQ0NC40MjcyNCwgREVOLCBEZW52ZXIsIENvbG9yYWRvCjMzNjczLjc1Nzc4LCBNU1AsIE1pbm5lYXBvbGlzLCBNaW5lc290YQozMTQxMS43NTAwMCwgQkVULCBCZXRoZWwsIEFsYXNrYQozMDI4Ni4yNzA4NSwgU0VBLCBTZWF0dGxlLCBXYXNoaW5ndG9uCjI5MzYxLjQ3MjEwLCBPUkQsIENoaWNhZ28sIElsbGlub2lzCjI2MjkwLjA4NTIwLCBBVEwsIEF0bGFudGEsIEdlb3JnaWEKCmBgYHtyfQphZXJvIDwtIGFlcm8gJT4lIAogIGFjdGl2YXRlKG5vZGVzKSAlPiUgCiAgYXNfdGliYmxlICU+JQp2aWV3KGFlcm8pCmBgYAoKQWhvcmEgaGF6IHVuYSBncsOhZmljYSBjb2xvcmVhbmRvIGNvbiB1biBlc3RhZG8gcmVsZXZhbnRlIChjb25zaWRlcmEgdHUgcmVzcHVlc3RhCmRlIGxhIHByZWd1bnRhIGFudGVyaW9yKSB5IHVzYW5kbyBsYSBpbnRlcm1lZGlhY2nDs24gY29tbyB0YW1hw7FvOgoKYGBge3J9CmFlcm8gJT4lCiAgICBhY3RpdmF0ZShub2RlcykgJT4lIAogICAgbXV0YXRlKGNvbG9yX2VkbyA9IGlmZWxzZShlc3RhZG8gPT0gIkFLIiwgIkFLIiwgIk90cm9zIikpICU+JSAKICAgIGdncmFwaChsYXlvdXQgPSAnZnInLCBuaXRlcj0yMDAwKSArIAogICAgZ2VvbV9lZGdlX2xpbmsoYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDIsICdtbScpKSwgYWxwaGEgPSAwLjEsIGNvbG91cj0iZ3JheSIpICsgCiAgICBnZW9tX25vZGVfcG9pbnQoYWVzKHNpemUgPSBpbnRlcm1lZGlhY2lvbiwgY29sb3VyPWNvbG9yX2VkbykpICsKICAgIHRoZW1lX2dyYXBoKCkKYGBgCgoqKlByZWd1bnRhIDQqKiBFeHBsaWNhIGVsIG5vZG8gY29uIG1heW9yIGludGVybWVkaWFjacOzbiBkZSBsYSBncsOhZmljYS4gwr9RdcOpIGNvbmVjdGE/CgpTZWxlY2Npb25hbW9zIGVsIGVzdGFkbyBkZSBBbGFza2EgeWEgcXVlIDIgZGUgc3VzIGFlcm9wdWVydG9zIHRpZW5lbiB1bmEgaW50ZXJtZWRpYWNpw7NuIGFsdGEuCgpDb24gZWxsbywgdmVtb3MgcXVlIGVsIGFlcm9wdWVydG8gZGUgQW5jaG9yYWdlIGVzdMOhIGNvbmVjdGFuZG8gZGUgbWFuZXJhIGNhc2kgZXhjbHVzaXZhCnRvZG9zIGxvcyBhZXJvcHVlcnRvcyBkZSBBbGFza2EgYWVyb3B1ZXN0b3MgZGUgb3Ryb3MgZXN0YWRvcyBkZSBsb3MgZXN0YWRvcy4KCgojIyMgQ2VudHJhbGlkYWQgZGUgZWlnZW52ZWN0b3IKCkNhbGN1bGEgY2VudHJhbGlkYWQgZGUgZWlnZW52ZWN0b3IsIHkgYWhvcmEgdXNhIHRhbWHDsW8gcGFyYSBlc3RhIGNlbnRyYWxpZGFkIHkgCmNvbG9yIHBhcmEgaW50ZXJtZWRpYWNpw7NuCgpgYGB7cn0KYWVybyA8LSBhZXJvICU+JQogICAgYWN0aXZhdGUobm9kZXMpICU+JSAKICAgIG11dGF0ZShjZW50cmFsX2VpZ2VuID0gY2VudHJhbGl0eV9laWdlbigpKQpgYGAKCmBgYHtyfQphZXJvICU+JQogICAgYWN0aXZhdGUobm9kZXMpICU+JSAKICAgIG11dGF0ZShjb2xvcl9lZG8gPSBpZmVsc2UoZXN0YWRvID09ICJBSyIsICJBSyIsICJPdHJvcyIpKSAlPiUgCiAgICBnZ3JhcGgobGF5b3V0ID0gJ2ZyJywgbml0ZXI9MjAwMCkgKyAKICAgIGdlb21fZWRnZV9saW5rKGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgyLCAnbW0nKSksIGFscGhhID0gMC4xLCBjb2xvdXI9ImdyYXkiKSArIAogICAgZ2VvbV9ub2RlX3BvaW50KGFlcyhzaXplID0gY2VudHJhbF9laWdlbiwgY29sb3VyPWludGVybWVkaWFjaW9uKSkgKwogICAgdGhlbWVfZ3JhcGgoKQpgYGAKCioqUHJlZ3VudGEgNSoqIMK/Q3XDoWxlcyBzb24gbG9zIGFlcm9wdWVydG9zIGNvbiBtYXlvciBjZW50cmFsaWRhZCBkZSBlaWdlbnZlY3Rvcj8KQ29udHJhc3RhIGNvbiBpbnRlcm1lZGlhY2nDs24uCgpFbCBhZXJvcHVlcnRvIGRlIEFUTCBxdWUgdGllbmUgbWF5b3IgY2VudHJhbGlkYWQgZXMgZWwgc8OpcHRpbW8gbHVnYXIgZW4gaW50ZXJtZWRpYWNpw7NuLCBwb3Igb3RybyBsYWRvLAplbCBhZXJvcHVlcnRvIGRlIE9SRCBzZSBjb2xvY2EgZW4gc2VndW5kbyBsdWdhciBkZSBjZW50cmFsaWRhZCBkZSBlaWdlbnZlY3RvciBjb24gbGEgc2V4dGEgcG9zaWNpw7NuCmVsIGFlcm9wdWVydG8gZGUgREZXIGVzIGVsIHRlcmNlciBsdWdhciBlbiBjZW50cmFsaWRhZC4gU2luIGVtYmFyZ28sIG5vIGZpZ3Vyw7MgZW4gbG9zIHByaW1lcm9zIGx1Z2FyZXMKYmFqbyBpbnRlcm1lZGlhY2nDs24uCgpFbCBhZXJvcHVlcnRvIGNvbiBtYXlvciBjZW50cmFsaWRhZCBkZSBlaWdlbnZlY3RvciBlcyBBVEwgKEFlcm9wdWVydG8gSW50ZXJuYWNpb25hbCBkZSBBdGxhbnRhLCBHZW9yZ2lhKSBjb24gMQpPdHJvcyBhZXJvcHVlcnRvcyBpbXBvcnRhbnRlcyBzb246CjAuOTg0MDAzMDEsIE9SRCwgQ2hpY2FnbywgSWxsaW5vaXMKMC45MjMwMDc0NiwgREZXLCBEYWxsYXMvRnQuV29ydGgsIFRleGFzCjAuOTEzMTMyMjcsIERFTiwgRGVudmVyLCBDb2xvcmFkbwowLjkwODIzMzU2LCBNU1AsIE1pbm5lYXBvbGlzLCBNaW5lc290YQowLjg5ODc2ODAzLCBEVFcsIERldHJvaXQsIE1pY2hpZ2FuCjAuODY2MzA5NjAsIExBUywgTGFzIFZlZ2FzLCBOZXZhZGEKCkVsIGFlcm9wdWVydG8gY29uIG1heW9yIGludGVybWVkaWFjacOzbiBlcyBBTkMgKEFlcm9wdWVydG8gSW50ZXJuYWNpb25hbCBkZSBBbmNob3JhZ2UsIEFsYXNrYSkgY29uIDg2Njg1LjUxODcxCk90cm9zIGFlcm9wdWVydG9zIGltcG9ydGFudGVzIHNvbjoKMzU0NDQuNDI3MjQsIERFTiwgRGVudmVyLCBDb2xvcmFkbwozMzY3My43NTc3OCwgTVNQLCBNaW5uZWFwb2xpcywgTWluZXNvdGEKMzE0MTEuNzUwMDAsIEJFVCwgQmV0aGVsLCBBbGFza2EKMzAyODYuMjcwODUsIFNFQSwgU2VhdHRsZSwgV2FzaGluZ3RvbgoyOTM2MS40NzIxMCwgT1JELCBDaGljYWdvLCBJbGxpbm9pcwoyNjI5MC4wODUyMCwgQVRMLCBBdGxhbnRhLCBHZW9yZ2lhCgpgYGB7cn0KYWVybyA8LSBhZXJvICU+JSAKICBhY3RpdmF0ZShub2RlcykgJT4lIAogIGFzX3RpYmJsZSAlPiUKdmlldyhhZXJvKQpgYGAKCiMjIyBFeGFtaW5hciBjZW50cmFsaWRhZAoKRWxpbWluYSBsb3MgYWVyb3B1ZXJ0b3MgZGUgQWxhc2thIHkgdnVlbHZlIGEgZ3JhZmljYXIsIGVzdGEgdmV6CnVzYW5kbyBjZW50cmFsaWRhZCBkZSBlaWdlbnZlY3RvciBwYXJhIGNvbG9yIHkgdGFtYcOxby4KCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodD0xMH0KYWVybyAlPiUKICBhY3RpdmF0ZShub2RlcykgJT4lIAogIGZpbHRlcihlc3RhZG8hPSJBSyIpICU+JSAjRWxpbWluYW1vcyBlc3RhZG8gZGUgQWxhc2thCmdncmFwaChsYXlvdXQgPSAnZ3JhcGhvcHQnLCBzcHJpbmcuY29uc3RhbnQgPSAwLjI1LCBjaGFyZ2UgPSAwLjA1LCBuaXRlciA9IDMwMCkgKyAjVXNhbW9zIGxheW91dGdyYXBob3B0CiAgZ2VvbV9lZGdlX2xpbmsyKGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgyLCAnbW0nKSksIGFscGhhID0gMC4wMSwgY29sb3VyPSJibGFjayIpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhzaXplID0gY2VudHJhbF9laWdlbiwgY29sb3VyPWNlbnRyYWxfZWlnZW4pKSArCiAgdGhlbWVfZ3JhcGgoKSAKYGBgCgoqKlByZWd1bnRhIDYqKjogwr9jYWxjdWxhciBjZW50cmFsaWRhZCB5IGx1ZWdvIGZpbHRyYXIgbm9kb3MgZXMgbG8gbWlzbW8gcXVlIGZpbHRyYXIgbm9kb3MKeSBsdWVnbyBjYWxjdWxhciBjZW50cmFsaWRhZD8KTm8gZXMgbG8gbWlzbW8sIHlhIHF1ZSBsYSBjZW50cmFsaWRhZCBkZXBlbmRlIGRlIGxhIGltcG9ydGFuY2lhIGRlIGxvcyBub2RvcyB2ZWNpbm9zLgpFcyBkZWNpciwgc2kgcHJpbWVybyBmaWx0cmFtb3MgbG9zIG5vZG9zIGRlIEFsYXNrYSB5IGx1ZWdvIGNhbGN1bGFtb3MgY2VudHJhbGlkYWQKZW50b25jZXMgZXN0b3Mgbm8gc2UgdG9tYW4gZW4gY3VlbnRhIHBhcmEgZWwgY8OhbGN1bG8geSBzaSBsb3MgcXVpdGFtb3MgZGVzcHXDqXMgZGUKY2FsY3VsYXIgbGEgY2VudHJhbGlkYWQsIGVuIHJlYWxpZGFkIHPDs2xvIGVzdGFtb3Mgb21pdGllbmRvIG5vZG9zIHF1ZSBzw60gc2UgY29uc2lkZXJhcm9uCnBhcmEgY2FsY3VsYXIgbG9zIG5vZG9zLgoKKioqRGVmaW5pY2nDs24gQ2VudHJhbGlkYWQgZGUgZWlnZW52ZWN0b3IqKioKCkVzdGEgbWVkaWRhIGNvbnNpZGVyYSBxdWUgbGEgaW1wb3J0YW5jaWEgZGUgdW4gbm9kbyBlc3TDoSBkYWRvIHBvciBsYSBzdW1hIG5vcm1hbGl6YWRhIGRlIGxhcwppbXBvcnRhbmNpYXMgZGUgc3VzIHZlY2lub3MuIERlIGVzdGEgZm9ybWEsIGVzIGltcG9ydGFudGUgZXN0YXIgY2VyY2FubyBhIG5vZG9zIGltcG9ydGFudGVzCihjb21vIGVuIGNlcmNhbsOtYSksIHBlcm8gdGFtYmnDqW4gY3VlbnRhIGNvbmVjdGFyc2UgYSBtdWNob3Mgbm9kb3MgKGNvbW8gZW4gZ3JhZG8pLgoKLSBOw7N0ZXNlIHF1ZSBlc3RhIGVzIHVuYSBkZXNjcmlwY2nDs24gY2lyY3VsYXI6IHBhcmEgc2FiZXIgbGEgaW1wb3J0YW5jaWEgZGUgdW4gbm9kbywgaGF5IHF1ZSAKc2FiZXIgbGEgaW1wb3J0YW5jaWEgZGUgc3VzIHZlY2lub3MuCgoqKlByZWd1bnRhIDcqKjogZXhwZXJpbWVudGEgY29uIGxvcyBwYXLDoW1ldHJvcyBkZWwgbGF5b3V0IChwb3IgZWplbXBsbywgbG9zIDIgcXVlIHNlIHVzYW4gYXJyaWJhKS4Kwr9Dw7NtbyBvYnRpZW5lcyBtZWpvcmVzIHJlc3VsdGFkb3M/CgpDYW1iaWFtb3MgbG9zIHBhcsOhbWV0cm9zIHNwcmluZyBjb25zdGFudCB5IGNoYXJnZS4KCkF1bWVudGFyIHNwcmluZyBjb25zdGFudCAoUG9yIGVqZW1wbG8gYSAxMCkgaGFjZSBxdWUgbG9zIG5vZG9zIGNvbiBtYXlvciBjZW50cmFsaWRhZCBzZSBhZ2xvbWVyZW4gCnkgdHJhc2xhcGVuLiBQb3IgbG8gcXVlIHZpc3VhbG1lbnRlIG5vIGVzIHBvc2libGUgYXByZWNpYXJsb3MgYmllbi4gUG9yIGVsIGNvbnRyYXJpbywgc2kgcmVkdWNpbW9zCmVzdGUgdmFsb3IgYSBwb3IgZWplbXBsbyAwLjAxLCBsb3Mgbm9kb3MgY29uIG1heW9yIGNlbnRyYWxpZGFkIHNlIHNlcGFyYW4gZGVtYXNpYWRvIGxsZWdhbmRvIGEgbG9zCmV4dGVtb3MgZGVsIGdyw6FmaWNvLgoKRGlzbWludWlyIGNoYXJnZSAocG9yIGVqZW1wbG8gYSAwLjAwMSkgaGFjZSBxdWUgbG9zIG5vZG9zIHNlIHNlcGFyZW4gbcOhcyBlbnRyZSBzw60sIG1pZW50cmFzIHF1ZSAKYXVtZW50YXIgbGEgY2FyZ2EgKHBvciBlamVtcGxvIGEgMC41KSBoYWNlIHF1ZSBsb3Mgbm9kb3Mgc2UgcmVwZWxhbi4KCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodD0xMH0KYWVybyAlPiUKICBhY3RpdmF0ZShub2RlcykgJT4lIAogIGZpbHRlcihlc3RhZG8hPSJBSyIpICU+JSAjRWxpbWluYW1vcyBlc3RhZG8gZGUgQWxhc2thCmdncmFwaChsYXlvdXQgPSAnZ3JhcGhvcHQnLCBzcHJpbmcuY29uc3RhbnQgPSAwLjI1LCBjaGFyZ2UgPSAwLjA1LCBuaXRlciA9IDMwMCkgKyAjVXNhbW9zIGxheW91dGdyYXBob3B0CiAgI1RoZSBzcHJpbmcgY29uc3RhbnQsIHRoZSBkZWZhdWx0IHZhbHVlIGlzIG9uZS4KICAjVGhlIGNoYXJnZSBvZiB0aGUgdmVydGljZXMsIHVzZWQgdG8gY2FsY3VsYXRlIGVsZWN0cmljIHJlcHVsc2lvbi4gVGhlIGRlZmF1bHQgaXMgMC4wMDEuCiAgZ2VvbV9lZGdlX2xpbmsyKGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgyLCAnbW0nKSksIGFscGhhID0gMC4wMSwgY29sb3VyPSJibGFjayIpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhzaXplID0gY2VudHJhbF9laWdlbiwgY29sb3VyPWNlbnRyYWxfZWlnZW4pKSArCiAgdGhlbWVfZ3JhcGgoKSAKYGBgCgoqKlByZWd1bnRhIDgqKiAobcOhcyBkaWbDrWNpbCk6IGV0aXF1ZXRhIGxvcyBub2Rvcy4gRXRpcXVldGEgc29sbyBsb3Mgbm9kb3MgcXVlIHRlbmdhbgpjZW50cmFsaWRhZCBkZSBlaWdlbnZlY3RvciBhbHRhLiBQdWVkZXMgZXhwZXJpbWVudGFyIChsYXlvdXQsIGNvbG9yZXMsIHRhbWHDsW8gZGUgdGV4dG8pCmNvbiBlc3RlIGPDs2RpZ286CgpgYGB7cn0Kbm9kb3NfaW1wIDwtIGFlcm8gJT4lIGFjdGl2YXRlKG5vZGVzKSAlPiUgYXNfdGliYmxlKCkgJT4lCiAgICBhcnJhbmdlKGRlc2MoY2VudHJhbF9laWdlbikpCnFwbG90KHB1bGwobm9kb3NfaW1wLCBjZW50cmFsX2VpZ2VuKSkKYGBgCgpDb21wcm9iYW1vcyBjdcOhbGVzIHNvbjoKCmBgYHtyfQpuPC0xMApldGlxdWV0YXMgPC0gYWVybyAlPiUgYWN0aXZhdGUobm9kZXMpICU+JSBhc190aWJibGUoKSAlPiUKICAgIGZpbHRlcihlc3RhZG8hPSJBSyIpICU+JSAKICAgIGFycmFuZ2UoZGVzYyhjZW50cmFsX2VpZ2VuKSkgJT4lIAogICAgdG9wX24obikgJT4lIAogICAgc2VsZWN0KG5hbWUpCmBgYAoKYGBge3J9CmNvdGFfY2VudHJvPC0uODUKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQ9MTB9CmFlcm8gJT4lCiAgYWN0aXZhdGUobm9kZXMpICU+JSAKICBmaWx0ZXIoZXN0YWRvIT0iQUsiKSAlPiUgCmdncmFwaChsYXlvdXQgPSAnZ3JhcGhvcHQnLCBzcHJpbmcuY29uc3RhbnQgPSAwLjI1LCBjaGFyZ2UgPSAwLjA1LCBuaXRlciA9IDMwMCkgKyAKICBnZW9tX2VkZ2VfbGluazIoYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDIsICdtbScpKSwgYWxwaGEgPSAwLjAxLCBjb2xvdXI9ImJsYWNrIikgKyAKICBnZW9tX25vZGVfcG9pbnQoYWVzKHNpemUgPSBjZW50cmFsX2VpZ2VuLCBjb2xvdXI9Y2VudHJhbF9laWdlbikpICsKICBnZW9tX25vZGVfdGV4dChhZXMoZmlsdGVyPWNlbnRyYWxfZWlnZW4+Y290YV9jZW50cm8sbGFiZWwgPW5hbWUsIGFscGhhID0gY2VudHJhbF9laWdlbiksIHJlcGVsID0gRkFMU0UsIHNpemUgPSAzLCBjb2xvciA9ICJyZWQiKSArCiAgdGhlbWVfZ3JhcGgoKSAKYGBgCgpgYGB7cn0KYWVybyAlPiUKICBhY3RpdmF0ZShub2RlcykgJT4lIAogIGZpbHRlcihlc3RhZG8hPSJBSyIpICU+JSAKZ2dyYXBoKGxheW91dCA9ICdncmFwaG9wdCcsIHNwcmluZy5jb25zdGFudCA9IDAuMjUsIGNoYXJnZSA9IDAuMDUsIG5pdGVyID0gMzAwKSArIAogIGdlb21fZWRnZV9saW5rMihhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMiwgJ21tJykpLCBhbHBoYSA9IDAuMDEsIGNvbG91cj0iYmxhY2siKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoc2l6ZSA9IGNlbnRyYWxfZWlnZW4sIGNvbG91cj1jZW50cmFsX2VpZ2VuKSkgKwogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IGlmZWxzZShjZW50cmFsX2VpZ2VuID4gY290YV9jZW50cm8sIG5hbWUsIE5BKSwgYWxwaGEgPSBjZW50cmFsX2VpZ2VuKSwgcmVwZWwgPSBUUlVFLCBzaXplID0gMywgY29sb3IgPSAiYmxhY2siKSArCiAgdGhlbWVfZ3JhcGgoKSAKYGBgCg==