The Global Database of Events, Language, and Tone, or GDELT, is “a realtime network diagram and database of global human society for open research”.

The potential for a firehose stream of global data has tantalizing possibilities for research in many fields, one of which being security studies.

The following is a cursory walkthrough of GDELT’s event data. It focuses on a country racked by conflict in recent years: Syria. The immense complexity of the Syrian conflict makes monitoring the dozens of international actors and hundreds (if not thousands) of domestic groups extremely challenging. The lion’s share of attention paid to Syria has been in regards to IS with blips of shifted focus following chemical weapons attacks, while systematic open-source tracking of the other involved parties has been disappointingly minimal.

How does GDELT fare in capturing events and trends of a country in the midst of its sixth year of civil war? With minimal massaging, it does pleasingly well.

Accessing GDELT Data

Google Big Query from R

library(dplyr, quietly = TRUE)
library(bigrquery, quietly = TRUE)

source("~/SyriaR/not_for_git_data/db_vars.R") # project "billing" variable
                                              # requires creating GoogleBQ project and
                                              # creating API OAuth keys

db_connection <- DBI::dbConnect(dbi_driver(),
                                project = "gdelt-bq",
                                dataset = "full",
                                billing = big_query_billing)

Database Table Options

DBI::dbListTables(db_connection)
## Auto-refreshing stale OAuth token.
## [1] "crosswalk_geocountrycodetohuman" "events"                         
## [3] "events_partitioned"

A simple geographic filter can be applied by using a coordinate bounding box.

sy_bounds <- list(min_lat = 32,
                  min_long = 36,
                  max_lat =  37,
                  max_long = 42.5)

Query

The database looks to be accessible through both high-level dplyr verbs and SQL.

syria_db <- db_connection %>% 
  tbl("events") %>%         # extract and convert "events" to an object we can reference 
  filter(FractionDate > 2017.75,   # filter legitimately big data to reasonable size
         ActionGeo_Lat >= sy_bounds$min_lat & # filter data by Syria bounding box
           ActionGeo_Lat <= sy_bounds$max_lat & 
           ActionGeo_Long >= sy_bounds$min_long &
           ActionGeo_Long <= sy_bounds$max_long)

When inspecting query results, the object looks like a regular tibble, but indicates the data Source and Database.

syria_db
## # Source:   lazy query [?? x 58]
## # Database: BigQueryConnection
##    GLOBALEVENTID  SQLDATE MonthYear  Year FractionDate Actor1Code
##            <int>    <int>     <int> <int>        <dbl>      <chr>
##  1     703942123 20171104    201711  2017     2017.833        SYR
##  2     703840455 20171104    201711  2017     2017.833        CVL
##  3     703816024 20171104    201711  2017     2017.833        USA
##  4     703888646 20171104    201711  2017     2017.833     JUDMED
##  5     703894322 20171104    201711  2017     2017.833     LBNGOV
##  6     703905528 20171104    201711  2017     2017.833        SYR
##  7     703926089 20171104    201711  2017     2017.833     SYRCVL
##  8     703813873 20171104    201711  2017     2017.833        USA
##  9     703822985 20171028    201710  2017     2017.816     IRQGOV
## 10     703876706 20171104    201711  2017     2017.833        SYR
## # ... with more rows, and 52 more variables: Actor1Name <chr>,
## #   Actor1CountryCode <chr>, Actor1KnownGroupCode <chr>,
## #   Actor1EthnicCode <chr>, Actor1Religion1Code <chr>,
## #   Actor1Religion2Code <chr>, Actor1Type1Code <chr>,
## #   Actor1Type2Code <chr>, Actor1Type3Code <chr>, Actor2Code <chr>,
## #   Actor2Name <chr>, Actor2CountryCode <chr>, Actor2KnownGroupCode <chr>,
## #   Actor2EthnicCode <chr>, Actor2Religion1Code <chr>,
## #   Actor2Religion2Code <chr>, Actor2Type1Code <chr>,
## #   Actor2Type2Code <chr>, Actor2Type3Code <chr>, IsRootEvent <int>,
## #   EventCode <chr>, EventBaseCode <chr>, EventRootCode <chr>,
## #   QuadClass <int>, GoldsteinScale <dbl>, NumMentions <int>,
## #   NumSources <int>, NumArticles <int>, AvgTone <dbl>,
## #   Actor1Geo_Type <int>, Actor1Geo_FullName <chr>,
## #   Actor1Geo_CountryCode <chr>, Actor1Geo_ADM1Code <chr>,
## #   Actor1Geo_Lat <dbl>, Actor1Geo_Long <dbl>, Actor1Geo_FeatureID <chr>,
## #   Actor2Geo_Type <int>, Actor2Geo_FullName <chr>,
## #   Actor2Geo_CountryCode <chr>, Actor2Geo_ADM1Code <chr>,
## #   Actor2Geo_Lat <dbl>, Actor2Geo_Long <dbl>, Actor2Geo_FeatureID <chr>,
## #   ActionGeo_Type <int>, ActionGeo_FullName <chr>,
## #   ActionGeo_CountryCode <chr>, ActionGeo_ADM1Code <chr>,
## #   ActionGeo_Lat <dbl>, ActionGeo_Long <dbl>, ActionGeo_FeatureID <chr>,
## #   DATEADDED <int>, SOURCEURL <chr>

Data Wrangling

The data can then be cleaned and structured in a very straightforward fashion.

The following steps are taken here:

  • Convert to tibble
  • Convert SQLDATE to Date class
  • Reshape to long format
  • Tidy ActionGeo_FullName into three separate variables
  • Join with codebook definitions
  • Rearrange desired columns
  • Keep unique rows
  • Sort by date
library(tidyr, quietly = TRUE)

syria_df <- syria_db %>% 
  as_data_frame() %>%
  mutate(date = as.Date(as.character(SQLDATE), 
                        format = "%Y%m%d", origin = "1970-01-01")) %>%
  gather(actor_code_types, code_type, contains("Type")) %>%
  separate(ActionGeo_FullName, c("micro_loc", "meso_loc", "macro_loc"),
           sep = ",", fill = "left") %>%
  inner_join(gdeltr2::get_codes_cameo_events(), 
             by = c("EventCode" = "idCAMEOEvent",
                    "EventRootCode" = "idParentCode")) %>%
  select(date,                            # when?
         descriptionCAMEOEvent,           # what?
         ActionGeo_Lat, ActionGeo_Long,   # where?
         micro_loc, meso_loc, macro_loc,  # where's that?
         Actor1Name, Actor2Name,          # who?
         actor_code_types, code_type,     # who's that? filterable code
         EventCode, EventRootCode,        # filterable codes
         ActionGeo_FeatureID,             # geocoded ID to match exact locations
         SOURCEURL) %>%                   # reference
  distinct() %>%
  arrange(desc(date))

What do the structured data look like?

library(knitr)
library(kableExtra)
options(knitr.table.format = "html")

syria_df %>%
  select(-SOURCEURL) %>%
  head() %>%
  kable() %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                font_size = 8)
date descriptionCAMEOEvent ActionGeo_Lat ActionGeo_Long micro_loc meso_loc macro_loc Actor1Name Actor2Name actor_code_types code_type EventCode EventRootCode ActionGeo_FeatureID
2017-11-05 Host a visit 35 38 NA NA Syria MILITANT NA Actor1Type1Code UAF 043 04 SY
2017-11-05 Make a visit 35 38 NA NA Syria MOSCOW NA Actor1Type1Code NA 042 04 SY
2017-11-05 Make pessimistic comment 35 38 NA NA Syria VANCOUVER NA Actor1Type1Code ELI 012 01 SY
2017-11-05 Investigate, not specified below 35 38 NA NA Syria CRIMINAL NA Actor1Type1Code CRM 090 09 SY
2017-11-05 Make statement, not specified below 35 38 NA NA Syria SAUDI NA Actor1Type1Code NA 010 01 SY
2017-11-05 Occupy territory 35 38 NA NA Syria SAUDI ARABIA NA Actor1Type1Code NA 192 19 SY

Taking a glimpse at the data raises questions about how sparse the ActionGeo_FullName variable is. Additionally, the clearly questionable identification of actors in the Actor1Name and Actor2Name variables is concerning. With that in mind, let’s see if events and actor codes can be filtered in a more robust fashion.

Filter for Conflict Events

Referencing GDELT’s CAMEO Codebook, the following can be selected as best representing non-state armed actors, which should assist in focusing more directly on intrastate conflict.

These filters can be further refined by selecting Verbs 18, 19, and 20, which reference “Assault”, “Fight”, and “Engage in Unconventional Mass Violence” respectively.

opposition_role_codes <- c("INS", # insurgent
                           "OPP", # opposition
                           "REB", # rebel
                           "SEP", # separatist
                           "UAF", # armed forces
                           "RAD") # radical

syria_df %>%
  filter(EventRootCode >= 18, 
         code_type %in% opposition_role_codes) %>%
  select(-meso_loc, -macro_loc, -SOURCEURL) %>%
  distinct() %>%
  head() %>%
  kable() %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
                font_size = 8)
date descriptionCAMEOEvent ActionGeo_Lat ActionGeo_Long micro_loc Actor1Name Actor2Name actor_code_types code_type EventCode EventRootCode ActionGeo_FeatureID
2017-11-05 Use unconventional violence, not specified below 35.9500 39.0167 Raqqa TERRORIST NA Actor1Type1Code UAF 180 18 -2538949
2017-11-05 Use conventional military force, not specified below 35.0000 38.0000 NA EXTREMIST MILITARY Actor1Type1Code RAD 190 19 SY
2017-11-05 Use conventional military force, not specified below 36.2028 37.1586 Aleppo OPPOSITION FACTION RUSSIA Actor1Type1Code OPP 190 19 -2541857
2017-11-05 Carry out suicide bombing 35.0000 38.0000 NA SUICIDE BOMBER CIVILIAN Actor1Type1Code REB 1831 18 SY
2017-11-05 Carry out car bombing 35.0000 38.0000 NA TERRORIST CIVILIAN Actor1Type1Code UAF 1832 18 SY
2017-11-05 Carry out suicide bombing 35.0000 38.0000 NA SUICIDE BOMBER KIRKUK Actor1Type1Code REB 1831 18 SY

Mapping

With the data filtered, what does roughly one month of a civil war look like spatially?

Points, 1D

library(ggmap)

sy_map <- ggmap::get_map(location = "Syria", 
                         maptype = "toner-hybrid",
                         zoom = 7)

plot_data <- syria_df %>%
  filter(EventRootCode >= 18,
         code_type %in% opposition_role_codes) %>%
  mutate(`Event Type` = ifelse(EventRootCode == "18", "Assault",
                               ifelse(EventRootCode == "19", "Fight",
                                      "Engage in Unconventional Mass Violence")))
  
sy_map %>%
  ggmap(legend = "bottom", extent = "device", darken = c(.4, "white")) +
  geom_point(data = plot_data,
             size = 3,
             aes(ActionGeo_Long, ActionGeo_Lat, color = code_type)) +
  coord_equal() +
    theme(legend.title = element_blank()) +
  labs(caption = "@synaptogenesis_") +
  ggtitle(label = "GDELT Event Points: 4 October - 4 November",
          subtitle = "Brendan Knapp")

As the capital, Damascus will inevitably enjoy a disproportionate amount of attention, but the cluster does not appear to be directly in Damascus and will need to be investigated.

al-Mayadin, which you may recognize as being the site of the June 2017 Iranian ballistic missile strike, sits on on the Euphrates River. The Euphrates has recently acted as the de facto boundary between the Assad regime’s Syrian Arab Army (SAA) forces to the southwest and U.S.-backed Syrian Democratic Forces (SDF) to the northeast.

By adding another dimension to the data, namely the top-level type of event that GDELT identified, we get a more nuanced picture.

Density, 2D

plot_data %<>% filter(EventRootCode >= 18,
                      code_type %in% opposition_role_codes,
                      code_type != "SEP",        # Not enough points to justify space loss
                      code_type != "INS") %>%    # Not enough points to justify space loss
  mutate(`Event Type` = ifelse(EventRootCode == "18", "Assault",
                               ifelse(EventRootCode == "19", "Fight",
                                      "Engage in Unconventional Mass Violence")))

sy_map %>%
  ggmap(extent = "panel",
        darken = c(.4, "white")) +
  stat_density2d(data = plot_data, aes(ActionGeo_Long, ActionGeo_Lat,
                                       alpha =  ..level..,
                                       fill = code_type),
                 size = 0.5, bins = 5, geom = "polygon") +
  coord_equal() +
  facet_wrap(~`Event Type`, ncol = 2) +
  scale_fill_manual(labels = c("Opposition", "Radical", "Rebel", "Armed Forces"),
                    values = c(c("#FF7256", "#00BFFF", "#ADFF2F", "#836FFF"))) +
  theme(legend.title = element_blank(),
        panel.spacing.x = unit(4, "lines"),
        legend.position = c(0.75, 0.25),
        legend.key.size = unit(1.5, "cm"),
        legend.direction = "horizontal",
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank()) +
  guides(alpha = FALSE) +
  labs(caption = "@synaptogenesis_") +
  ggtitle(label = "GDELT Event Density: 4 October - 4 November",
          subtitle = "Brendan Knapp")

The Radical blue of the “Assault” panel is likely displaying SDF’s capture of Raqqa and their ongoing race with SAA to al-Mayadin, It also appears to capture what is hopefully the homestretch through the remaining IS heartland to the Iraqi border.

Initial Evaluation with Real World Data

We can better review GDELT’s results by referencing more robustly curated data.

load("~/SyriaR/data/occ_polys_df.rda")
source("~/SyriaR/R/hotspots.R")
  
ggplot() +
  geom_polygon(data = occ_polys_df,
               aes(x = long, y = lat, fill = Occupier, group = group),
               alpha = 0.25, color = "transparent") +
  stat_density2d(data = plot_data, aes(ActionGeo_Long, ActionGeo_Lat, 
                                       color = code_type),
                 size = 0.75, bins = 4, inherit.aes = FALSE) +
  geom_text(data = hotspots_df, aes(long, lat, label = name, fontface = "bold"), 
            show.legend = FALSE) +
  coord_equal() +
  scale_fill_manual(values = c("HTS" = "darkgreen", "IDF" = "blue", 
                               "IS" = "black", "SAA" = "red", 
                               "Other Opp." = "green", "SDF" = "yellow")) +
  guides(alpha = FALSE,
         color = guide_legend(title = "GDELT Event Code", ncol = 2)) +
  theme(legend.position = c(0.75, 0.25),
        legend.direction = "horizontal", 
        legend.background = element_rect(fill = "transparent"),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank()) +
  labs(caption = "@synaptogenesis_") +
  ggtitle(label = "GDELT Event Coding and Real World Data", 
          subtitle = "Brendan Knapp")

Idlib, Raqqa, and Deir ez-Zour (DeZ) are all conflict hotspots, and GDELT very clearly captures this. As YPG-led SDF and SAA forces continue their press into IS territory, it will be interesting to see if the density around DeZ shifts toward the Iraqi border while the density around Raqqa diminishes.

The region labeled “Generic Syria Coords?” is exactly 35°N 38°E. It is likely referencing Syria as a whole as articles do not seem to reference this remote patch in the desert. While it is not the country’s centroid, I have not developed a more reasonable explanation.

We can clean up the plot by ignoring the 35°N 38°E events.

filtered_plot_data <- plot_data %>%
  filter(ActionGeo_Lat !=  35 & ActionGeo_Long != 38)

filtered_hotspots <- hotspots_df %>%
  mutate(name = stringr::str_replace(name, "Generic Syria Coords\\?", ""))

ggplot() +
  geom_polygon(data = occ_polys_df,
               aes(x = long, y = lat, fill = Occupier, group = group),
               alpha = 0.25, color = "transparent") +
  stat_density_2d(data = filtered_plot_data, 
                 aes(ActionGeo_Long, ActionGeo_Lat, 
                     color = code_type),
                 size = 0.75, bins = 4.1, inherit.aes = FALSE) +
  geom_text(data = filtered_hotspots, 
            aes(long, lat, label = name, fontface = "bold"), 
            show.legend = FALSE) +
  geom_text(data = tiyas_airbase, aes(long, lat, label = name, fontface = "bold"), 
            show.legend = FALSE) +
  coord_equal() +
  scale_fill_manual(values = c("HTS" = "darkgreen", "IDF" = "blue", 
                               "IS" = "black", "SAA" = "red", 
                               "Other Opp." = "green", "SDF" = "yellow")) +
  guides(alpha = FALSE,
         color = guide_legend(title = "GDELT Event Code", ncol = 2)) +
  theme(legend.position = c(0.75, 0.25),
        legend.direction = "horizontal", 
        legend.background = element_rect(fill = "transparent"),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank()) +
  labs(caption = "@synaptogenesis_") +
  ggtitle(label = "GDELT Event Coding and Real World Data", 
          subtitle = "Brendan Knapp")

Hidden in the noise of what were likely general coordinates for Syria is a major military installation that is uncovered with slight tweaking of density binning.

Identification of a Military Installation

Filtering by coordinates reveals that the density seen was not simply an artifact of references to the whole of Syria, as a desert area roughly 50 miles from downtown Homs is identified. Further investigation reveals that what is being detected is actually Tiyas Military Airbase, or T4 Airbase (the name of the nearby pumping station).

Even if one were not familiar with the bases of the Syrian Arab Armed Forces, GDELT clearly identifies the base and surrounding area. With minor investigation, the installation reveals itself to be quite extensive.

library(leaflet)
library(leaflet.extras)

radar_icon <- awesomeIcons(icon = "fa-feed", iconColor = "red",
                           markerColor = "gray", library = 'fa')
housing_icon <- awesomeIcons(icon = "fa-home", iconColor = "green",
                             markerColor = "lightblue", library = 'fa')
fixed_wing_icon <- awesomeIcons(icon = "fa-fighter-jet", iconColor = "black",
                                markerColor = "darkred", library = 'fa')
pump_station_icon <- awesomeIcons(icon = "fa-industry", iconColor = "black",
                                  markerColor = "white", library = 'fa')
rotary_icon <- awesomeIcons(icon = "fa-spinner", iconColor = "black",
                            markerColor = "darkred", library = 'fa')
hangar_icon <- awesomeIcons(icon = "fa-low-vision", iconColor = "beige",
                            markerColor = "green", library = 'fa')

  
leaflet() %>%
  setView(lng = 37.642554, lat = 34.532257, zoom = 14) %>%
  addProviderTiles(providers$Esri.WorldImagery, 
                   options = providerTileOptions(maxZoom = 17),
                   group = "Esri Imagery") %>%
  addAwesomeMarkers(data = T4_pump_station, lng = ~long, lat = ~lat, 
             popup = paste(T4_pump_station$name),
             icon = pump_station_icon,
             group = "Pump Station") %>%
  addAwesomeMarkers(data = T4_housing, lng = ~long, lat = ~lat, 
             popup = paste(T4_housing$name),
             icon = housing_icon,
             group = "Housing") %>%
  addAwesomeMarkers(data = T4_radars, lng = ~long, lat = ~lat, 
             popup = paste(T4_radars$name),
             icon = radar_icon,
             group = "Radars") %>%
  addAwesomeMarkers(data = T4_fixed_wing, lng = ~long, lat = ~lat, 
             popup = paste(T4_fixed_wing$name),
             icon = fixed_wing_icon,
             group = "Fixed-Wing") %>%
  addAwesomeMarkers(data = T4_rotary, lng = ~long, lat = ~lat, 
             popup = paste(T4_rotary$name),
             icon = rotary_icon,
             group = "Rotary-Wing") %>%
  addAwesomeMarkers(data = T4_hangars, lng = ~long, lat = ~lat, 
                    popup = paste(T4_hangars$name),
                    icon = hangar_icon,
                    group = "Hangars") %>%
  addLayersControl(overlayGroups = c("Pump Station",
                                     "Housing",
                                     "Radars",
                                     "Fixed-Wing",
                                     "Rotary-Wing",
                                     "Hangars"),
                   options = layersControlOptions(collapsed = FALSE),
                   position = "topright") %>%
  addMiniMap(zoomLevelFixed = 5, 
             tiles = providers$Esri.WorldGrayCanvas) %>%
  mapview::addMouseCoordinates(style = "basic")

This is not a remotely exhaustive annotation of the imagery, but provides enough evidence to convince anyone unfamiliar with the topic that the location is not insignificant. If one looks north of the highway, there are more sub installations and zooming out will display a perimeter, some of which appears to be mined.

Why exactly did GDELT identify the T4 Airbase? There were numerous articles referencing Russian casualties in the area. They explain the process of the numbering of Russian death certificates and evidence that 131 Russians died in Syria between January and September 2017. Acquaintances of some of the dead have described them as private military contractors, despite Moscow denial of Russian PMCs operating in Syria.

Considering that the data were referencing personnel connected to the base, rather than the base itself, and that the base is of relatively limited size, it is very encouraging to see that GDELT was able to capture its location with little manual investigation.

Damascus

Interestingly, while first appearing to be Damascus itself, the density around the capital may actually be capturing turmoil in the suburb of Ghouta. Ghouta has been a battleground throughout the conflict and is reported to be occupied by branches of Jaysh al-Islam, Hayyat Tahrir al-Sham (HTS), Faylaq al-Rahman, and others. However, it is probably most recognizable as the target of a sarin attack in August 2013.

The kernel density seen may also be in reference to Jobar. Demonstrating the divide between regime-held Damascus proper and opposition-held and extensively bombed Jobar only takes looking at imagery of the boundary.

damascus_jobar_boundary <- ggmap::get_map(c(36.326248, 33.519928),
                                    maptype = "hybrid",
                                    zoom = 15)

inset_imagery <- ggmap::get_map(c(36.305231, 33.514929),
                                maptype = "roadmap",
                                zoom = 13)

inset <- ggplotGrob(ggmap(inset_imagery, extent = "device", padding = 5) +
  geom_point(aes(36.326248, 33.519928),
             color = "red", size = 3))

ggmap(damascus_jobar_boundary, extent = "device") +
  geom_point(aes(36.326248, 33.519928),
             color = "red", size = 5) +
  coord_cartesian() +
  annotation_custom(grob = inset,
                    xmin = 36.326, xmax = 36.345, 
                    ymin = 33.509, ymax = 33.516)

Wrap Up

This hasty assessment of GDELT is rather promising. After sufficiently filtering the data, it did not cause alarm or serious skepticism regarding its accuracy in identifying significant locations. In spite of the media exhaustion regarding the Syrian conflict, and its overwhelming focus on IS, GDELT was still able to paint a tantalizingly accurate picture of the current state of affairs, one which can surely be further refined with future trials in filtering and processing data.

My take away? As with any sort of analysis, meaningful interpretation is almost guaranteed to require familiarity with the topic. With some background knowledge, GDELT may prove itself to be a powerful resource and I look forward to deeper dives in the future.

sessionInfo()

sessionInfo()
## R version 3.4.2 (2017-09-28)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 15063)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=English_United States.1252 
## [2] LC_CTYPE=English_United States.1252   
## [3] LC_MONETARY=English_United States.1252
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.1252    
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] leaflet.extras_0.2 leaflet_1.1.0      ggmap_2.6.1       
##  [4] ggplot2_2.2.1      kableExtra_0.5.2   knitr_1.17        
##  [7] bindrcpp_0.2       tidyr_0.7.1        bigrquery_0.4.1   
## [10] dplyr_0.7.4       
## 
## loaded via a namespace (and not attached):
##   [1] colorspace_1.3-2        rjson_0.2.15           
##   [3] gdalUtils_2.0.1.7       rgdal_1.2-13           
##   [5] rprojroot_1.2           satellite_1.0.1        
##   [7] base64enc_0.1-3         urltools_1.6.0         
##   [9] RApiDatetime_0.0.3      lubridate_1.6.0        
##  [11] xml2_1.1.1              R.methodsS3_1.7.1      
##  [13] codetools_0.2-15        extrafont_0.17         
##  [15] mnormt_1.5-5            trelliscopejs_0.1.9    
##  [17] rlist_0.4.6.1           jsonlite_1.5           
##  [19] broom_0.4.2             Rttf2pt1_1.3.4         
##  [21] anytime_0.3.0           dbplyr_1.1.0           
##  [23] R.oo_1.21.0             png_0.1-7              
##  [25] shiny_1.0.5             wordcloud2_0.2.0       
##  [27] mapproj_1.2-5           readr_1.1.1.9000       
##  [29] compiler_3.4.2          httr_1.3.1             
##  [31] backports_1.1.1         mapview_2.1.4          
##  [33] assertthat_0.2.0        lazyeval_0.2.0         
##  [35] hrbrthemes_0.1.0        htmltools_0.3.6        
##  [37] prettyunits_1.0.2       tools_3.4.2            
##  [39] igraph_1.1.2            gtable_0.2.0           
##  [41] glue_1.1.1              reshape2_1.4.2         
##  [43] ggthemes_3.4.0          maps_3.2.0             
##  [45] Rcpp_0.12.13            raster_2.5-8           
##  [47] cellranger_1.1.0        nlme_3.1-131           
##  [49] udunits2_0.13           extrafontdb_1.0        
##  [51] iterators_1.0.8         crosstalk_1.0.0        
##  [53] psych_1.7.8             stringr_1.2.0          
##  [55] proto_1.0.0             rvest_0.3.2.9000       
##  [57] mime_0.5                devtools_1.13.3        
##  [59] MASS_7.3-47             zoo_1.8-0              
##  [61] scales_0.5.0            highcharter_0.5.0.9999 
##  [63] DistributionUtils_0.5-1 hms_0.3                
##  [65] parallel_3.4.2          tidyverse_1.1.1        
##  [67] yaml_2.1.14             quantmod_0.4-11        
##  [69] curl_3.0                memoise_1.1.0          
##  [71] geosphere_1.5-5         purrrlyr_0.0.2         
##  [73] triebeard_0.3.0         hunspell_2.6           
##  [75] stringi_1.1.5           highr_0.6              
##  [77] foreach_1.4.3           TTR_0.23-2             
##  [79] RgoogleMaps_1.4.1       rlang_0.1.2.9000       
##  [81] pkgconfig_2.0.1         evaluate_0.10.1        
##  [83] lattice_0.20-35         sf_0.5-4               
##  [85] purrr_0.2.3             bindr_0.1              
##  [87] htmlwidgets_0.9         labeling_0.3           
##  [89] tidyselect_0.2.2        plyr_1.8.4             
##  [91] magrittr_1.5            R6_2.2.2               
##  [93] DBI_0.7                 haven_1.1.0            
##  [95] whisker_0.3-2           foreign_0.8-69         
##  [97] withr_2.0.0             units_0.4-6            
##  [99] xts_0.10-0              sp_1.2-5               
## [101] tibble_1.3.4            modelr_0.1.1           
## [103] plotly_4.7.1            rmarkdown_1.6          
## [105] jpeg_0.1-8              progress_1.1.2         
## [107] grid_3.4.2              readxl_1.0.0           
## [109] data.table_1.10.4-2     forcats_0.2.0          
## [111] digest_0.6.12           webshot_0.4.2          
## [113] xtable_1.8-2            httpuv_1.3.5           
## [115] gdeltr2_0.3.11023026    R.utils_2.5.0          
## [117] stats4_3.4.2            openssl_0.9.7          
## [119] munsell_0.4.3           viridisLite_0.2.0