1. Introduction to the terra Package

The terra package is the modern, high-performance replacement for the raster package. It’s designed to work with both raster and vector data efficiently. A raster is a grid of cells, where each cell holds a value (e.g., elevation, temperature, or rainfall).

In terra, a raster object is called a SpatRaster.

2. Reading and Inspecting Raster Data

We can download climate data directly using the geodata package, which works seamlessly with terra. Let’s download the average monthly precipitation for Somalia from the WorldClim database.

library(terra)
library(geodata)

# Download average monthly precipitation data for Somalia
# This returns a SpatRaster with 12 layers (one for each month)
som_precip <- worldclim_country(country = "Somalia", var = "prec", path = tempdir())

# Inspect the SpatRaster object
som_precip
## class       : SpatRaster 
## dimensions  : 1680, 1320, 12  (nrow, ncol, nlyr)
## resolution  : 0.008333333, 0.008333333  (x, y)
## extent      : 40.5, 51.5, -2, 12  (xmin, xmax, ymin, ymax)
## coord. ref. : lon/lat WGS 84 (EPSG:4326) 
## source      : SOM_wc2.1_30s_prec.tif 
## names       : SOM_w~rec_1, SOM_w~rec_2, SOM_w~rec_3, SOM_w~rec_4, SOM_w~rec_5, SOM_w~rec_6, ... 
## min values  :           0,           0,           0,           3,           0,           0, ... 
## max values  :          43,          49,          87,         208,         285,         165, ...

The output tells us: - class: SpatRaster - dimensions: The number of rows, columns, and layers (nlyr = 12 for 12 months). - resolution: The size of each grid cell in degrees. - extent: The geographic bounding box. - crs: The Coordinate Reference System.

We can plot the raster. By default, terra plots all 12 layers.

plot(som_precip)

3. Raster Operations: Summarizing, Cropping, and Masking

A common workflow involves processing a raster to fit our specific research needs.

A. Summarizing Layers We have 12 monthly layers, but we might want the annual average precipitation. We can use the mean() function to calculate the mean value for each cell across all 12 layers.

# Calculate the mean precipitation across all 12 layers
annual_avg_precip <- mean(som_precip)

# Plot the single-layer result
plot(annual_avg_precip, main = "Average Annual Precipitation in Somalia (mm)")

B. Cropping and Masking The raster we downloaded is a simple rectangle. We often want to clip it to the exact shape of our study area (e.g., the administrative boundary of Somalia). This is a two-step process: 1. crop(): Reduces the raster to the bounding box of the shape, making it smaller and faster to process. 2. mask(): Sets all raster cells that fall outside the shape to NA, giving it the precise outline of our study area.

# We need the vector boundary of Somalia from Lecture 1
library(sf)
som_adm0 <- st_read("som_admbnda_adm0_ocha_20250108.shp", quiet = TRUE)

# Convert the sf object to a SpatVector for use with terra
som_adm0_vect <- vect(som_adm0)

# 1. Crop the raster to the extent of the Somalia boundary
precip_cropped <- crop(annual_avg_precip, som_adm0_vect)

# 2. Mask the cropped raster with the Somalia polygon
precip_masked <- mask(precip_cropped, som_adm0_vect)

# Plot the final, masked raster
plot(precip_masked, main = "Average Annual Precipitation Masked to Somalia's Boundary")

4. Extracting Raster Values

The real power comes from combining raster and vector data. The extract() function allows us to “pull” values from a raster at specific locations (points) or summarize them over areas (polygons).

Example 1: Extracting Precipitation at Specific Cities Let’s find the average annual precipitation for Mogadishu and Hargeisa.

# 1. Create a SpatVector of our cities
cities_df <- data.frame(
  name = c("Mogadishu", "Hargeisa"),
  lon = c(45.333, 44.067),
  lat = c(2.033, 9.567)
)
cities_vect <- vect(cities_df, geom=c("lon", "lat"), crs="EPSG:4326")

# 2. Extract the raster values at these point locations
city_precip_values <- extract(precip_masked, cities_vect)

# 3. Combine the results with the city names
city_results <- cbind(cities_df, city_precip_values)
print(city_results)
##        name    lon   lat ID     mean
## 1 Mogadishu 45.333 2.033  1 36.66667
## 2  Hargeisa 44.067 9.567  2 38.66667

The result shows Hargeisa receives significantly more rainfall than Mogadishu, which matches our understanding of the local climate.

Example 2: Summarizing Precipitation by Region What is the average precipitation for each administrative region in Somalia? We can use extract() with polygons.

library(dplyr)
library(ggplot2)
library(tidyterra) # For plotting terra objects with ggplot

# 1. Load the regions vector data (from Lecture 1)
som_adm1 <- st_read("som_admbnda_adm1_ocha_20250108.shp", quiet = TRUE)
som_adm1_vect <- vect(som_adm1)

# 2. Extract the mean precipitation for each polygon (region)
# We use fun="mean" to specify the summary statistic. na.rm=TRUE ignores NA cells.
regional_precip <- extract(precip_masked, som_adm1_vect, fun = "mean", na.rm = TRUE)

# 3. Add the extracted values back to our vector object
som_adm1_vect$avg_precip <- regional_precip[,2] # The second column has the values

# 4. Map the results
ggplot() +
  geom_spatvector(data = som_adm1_vect, aes(fill = avg_precip)) +
  scale_fill_viridis_c(name = "Avg. Monthly\nPrecipitation (mm)") +
  ggtitle("Average Monthly Precipitation by Region") +
  theme_bw()

This map provides a clear and powerful visualization of the spatial distribution of rainfall across Somalia, revealing distinct climatic zones that profoundly influence livelihoods, food security, and potential for conflict. The patterns observed align closely with the country’s known topography and agricultural systems.

The “Sorghum Belt” and Riverine Areas (Highest Precipitation): The two areas with the highest average precipitation (shown in yellow, ~40 mm/month or ~480 mm/year) are the northwestern regions of Awdal and Woqooyi Galbeed (Somaliland) and the southwestern regions of Gedo, Bay, and the Jubas.

The northwestern highlands benefit from higher elevation and orographic lift, making them the most productive zone in Somaliland for rain-fed agriculture and pastoralism.

The southwestern area is the breadbasket of Somalia, benefiting not only from higher rainfall but also from the presence of the Jubba and Shabelle rivers, which support irrigation-based farming.

The Arid Central and Northeastern Regions (Lowest Precipitation): A vast corridor stretching from the central regions (Galgaduud, Mudug) up through the entire northeastern tip of the Horn (Nugaal and Bari regions of Puntland) experiences hyper-arid conditions (dark purple, ~10 mm/month or ~120 mm/year). This area is predominantly suited for nomadic pastoralism, and its inhabitants are highly vulnerable to drought. The low rainfall here makes water a scarce and critical resource.

Transitional Zones: The regions shown in green and teal represent transitional semi-arid zones. These areas, such as Togdheer in the north and Hiraan in the south, often serve as crucial grazing lands but are highly susceptible to climate variability.

In conclusion, this map is not just a climatic summary; it is a foundational map for understanding human geography in Somalia. It helps explain why agricultural activity is concentrated in the southwest, why pastoralist migration routes dominate the central and northeast, and which regions are most ecologically fragile and prone to drought-related humanitarian crises. Any analysis of food security, resource management, or development planning in Somalia must be grounded in this spatial reality of water availability.

Example 3: Summarizing Precipitation by District What is the average precipitation for each administrative district in Somalia? We can use extract() with polygons.

library(dplyr)
library(ggplot2)
library(tidyterra) # For plotting terra objects with ggplot

# 1. Load the districts vector data (from Lecture 1)
som_adm2 <- st_read("som_admbnda_adm2_ocha_20250108.shp", quiet = TRUE)
som_adm2_vect <- vect(som_adm2)

# 2. Extract the mean precipitation for each polygon (district)
# We use fun="mean" to specify the summary statistic. na.rm=TRUE ignores NA cells.
district_precip <- extract(precip_masked, som_adm2_vect, fun = "mean", na.rm = TRUE)

# 3. Add the extracted values back to our vector object
som_adm2_vect$avg_precip <- district_precip[,2] # The second column has the values

# 4. Map the results
ggplot() +
  geom_spatvector(data = som_adm2_vect, aes(fill = avg_precip)) +
  scale_fill_viridis_c(name = "Avg. Monthly\nPrecipitation (mm)") +
  ggtitle("Average Monthly Precipitation by District") +
  theme_bw()

```

LS0tDQp0aXRsZTogJ01vZHVsZSBJSUk6IFdvcmtpbmcgd2l0aCBSYXN0ZXIgRGF0YSBpbiBSIHVzaW5nIHRoZSBgdGVycmFgIFBhY2thZ2UnDQphdXRob3I6ICJBYmRpc2FsYW0gSGFzc2FuIE11c2UsIFBoRCINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KYGBge3Igc2V0dXAyLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkNCmBgYA0KDQojIyMgMS4gSW50cm9kdWN0aW9uIHRvIHRoZSBgdGVycmFgIFBhY2thZ2UNCg0KVGhlIGB0ZXJyYWAgcGFja2FnZSBpcyB0aGUgbW9kZXJuLCBoaWdoLXBlcmZvcm1hbmNlIHJlcGxhY2VtZW50IGZvciB0aGUgYHJhc3RlcmAgcGFja2FnZS4gSXQncyBkZXNpZ25lZCB0byB3b3JrIHdpdGggYm90aCAqKnJhc3RlcioqIGFuZCAqKnZlY3RvcioqIGRhdGEgZWZmaWNpZW50bHkuIEEgcmFzdGVyIGlzIGEgZ3JpZCBvZiBjZWxscywgd2hlcmUgZWFjaCBjZWxsIGhvbGRzIGEgdmFsdWUgKGUuZy4sIGVsZXZhdGlvbiwgdGVtcGVyYXR1cmUsIG9yIHJhaW5mYWxsKS4NCg0KSW4gYHRlcnJhYCwgYSByYXN0ZXIgb2JqZWN0IGlzIGNhbGxlZCBhIGBTcGF0UmFzdGVyYC4NCg0KIyMjIDIuIFJlYWRpbmcgYW5kIEluc3BlY3RpbmcgUmFzdGVyIERhdGENCg0KV2UgY2FuIGRvd25sb2FkIGNsaW1hdGUgZGF0YSBkaXJlY3RseSB1c2luZyB0aGUgYGdlb2RhdGFgIHBhY2thZ2UsIHdoaWNoIHdvcmtzIHNlYW1sZXNzbHkgd2l0aCBgdGVycmFgLiBMZXQncyBkb3dubG9hZCB0aGUgYXZlcmFnZSBtb250aGx5IHByZWNpcGl0YXRpb24gZm9yIFNvbWFsaWEgZnJvbSB0aGUgV29ybGRDbGltIGRhdGFiYXNlLg0KDQpgYGB7ciBsb2FkX3RlcnJhfQ0KbGlicmFyeSh0ZXJyYSkNCmxpYnJhcnkoZ2VvZGF0YSkNCg0KIyBEb3dubG9hZCBhdmVyYWdlIG1vbnRobHkgcHJlY2lwaXRhdGlvbiBkYXRhIGZvciBTb21hbGlhDQojIFRoaXMgcmV0dXJucyBhIFNwYXRSYXN0ZXIgd2l0aCAxMiBsYXllcnMgKG9uZSBmb3IgZWFjaCBtb250aCkNCnNvbV9wcmVjaXAgPC0gd29ybGRjbGltX2NvdW50cnkoY291bnRyeSA9ICJTb21hbGlhIiwgdmFyID0gInByZWMiLCBwYXRoID0gdGVtcGRpcigpKQ0KDQojIEluc3BlY3QgdGhlIFNwYXRSYXN0ZXIgb2JqZWN0DQpzb21fcHJlY2lwDQpgYGANCg0KVGhlIG91dHB1dCB0ZWxscyB1czoNCi0gKipjbGFzczoqKiBTcGF0UmFzdGVyDQotICoqZGltZW5zaW9uczoqKiBUaGUgbnVtYmVyIG9mIHJvd3MsIGNvbHVtbnMsIGFuZCBsYXllcnMgKG5seXIgPSAxMiBmb3IgMTIgbW9udGhzKS4NCi0gKipyZXNvbHV0aW9uOioqIFRoZSBzaXplIG9mIGVhY2ggZ3JpZCBjZWxsIGluIGRlZ3JlZXMuDQotICoqZXh0ZW50OioqIFRoZSBnZW9ncmFwaGljIGJvdW5kaW5nIGJveC4NCi0gKipjcnM6KiogVGhlIENvb3JkaW5hdGUgUmVmZXJlbmNlIFN5c3RlbS4NCg0KV2UgY2FuIHBsb3QgdGhlIHJhc3Rlci4gQnkgZGVmYXVsdCwgYHRlcnJhYCBwbG90cyBhbGwgMTIgbGF5ZXJzLg0KDQpgYGB7ciBwbG90X3RlcnJhfQ0KcGxvdChzb21fcHJlY2lwKQ0KYGBgDQoNCiMjIyAzLiBSYXN0ZXIgT3BlcmF0aW9uczogU3VtbWFyaXppbmcsIENyb3BwaW5nLCBhbmQgTWFza2luZw0KDQpBIGNvbW1vbiB3b3JrZmxvdyBpbnZvbHZlcyBwcm9jZXNzaW5nIGEgcmFzdGVyIHRvIGZpdCBvdXIgc3BlY2lmaWMgcmVzZWFyY2ggbmVlZHMuDQoNCioqQS4gU3VtbWFyaXppbmcgTGF5ZXJzKioNCldlIGhhdmUgMTIgbW9udGhseSBsYXllcnMsIGJ1dCB3ZSBtaWdodCB3YW50IHRoZSAqYW5udWFsIGF2ZXJhZ2UgcHJlY2lwaXRhdGlvbiouIFdlIGNhbiB1c2UgdGhlIGBtZWFuKClgIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgbWVhbiB2YWx1ZSBmb3IgZWFjaCBjZWxsIGFjcm9zcyBhbGwgMTIgbGF5ZXJzLg0KDQpgYGB7ciBzdW1tYXJpemVfcmFzdGVyfQ0KIyBDYWxjdWxhdGUgdGhlIG1lYW4gcHJlY2lwaXRhdGlvbiBhY3Jvc3MgYWxsIDEyIGxheWVycw0KYW5udWFsX2F2Z19wcmVjaXAgPC0gbWVhbihzb21fcHJlY2lwKQ0KDQojIFBsb3QgdGhlIHNpbmdsZS1sYXllciByZXN1bHQNCnBsb3QoYW5udWFsX2F2Z19wcmVjaXAsIG1haW4gPSAiQXZlcmFnZSBBbm51YWwgUHJlY2lwaXRhdGlvbiBpbiBTb21hbGlhIChtbSkiKQ0KYGBgDQoNCioqQi4gQ3JvcHBpbmcgYW5kIE1hc2tpbmcqKg0KVGhlIHJhc3RlciB3ZSBkb3dubG9hZGVkIGlzIGEgc2ltcGxlIHJlY3RhbmdsZS4gV2Ugb2Z0ZW4gd2FudCB0byBjbGlwIGl0IHRvIHRoZSBleGFjdCBzaGFwZSBvZiBvdXIgc3R1ZHkgYXJlYSAoZS5nLiwgdGhlIGFkbWluaXN0cmF0aXZlIGJvdW5kYXJ5IG9mIFNvbWFsaWEpLiBUaGlzIGlzIGEgdHdvLXN0ZXAgcHJvY2VzczoNCjEuICAqKmBjcm9wKClgOioqIFJlZHVjZXMgdGhlIHJhc3RlciB0byB0aGUgYm91bmRpbmcgYm94IG9mIHRoZSBzaGFwZSwgbWFraW5nIGl0IHNtYWxsZXIgYW5kIGZhc3RlciB0byBwcm9jZXNzLg0KMi4gICoqYG1hc2soKWA6KiogU2V0cyBhbGwgcmFzdGVyIGNlbGxzIHRoYXQgZmFsbCAqb3V0c2lkZSogdGhlIHNoYXBlIHRvIGBOQWAsIGdpdmluZyBpdCB0aGUgcHJlY2lzZSBvdXRsaW5lIG9mIG91ciBzdHVkeSBhcmVhLg0KDQpgYGB7ciBjcm9wX21hc2t9DQojIFdlIG5lZWQgdGhlIHZlY3RvciBib3VuZGFyeSBvZiBTb21hbGlhIGZyb20gTGVjdHVyZSAxDQpsaWJyYXJ5KHNmKQ0Kc29tX2FkbTAgPC0gc3RfcmVhZCgic29tX2FkbWJuZGFfYWRtMF9vY2hhXzIwMjUwMTA4LnNocCIsIHF1aWV0ID0gVFJVRSkNCg0KIyBDb252ZXJ0IHRoZSBzZiBvYmplY3QgdG8gYSBTcGF0VmVjdG9yIGZvciB1c2Ugd2l0aCB0ZXJyYQ0Kc29tX2FkbTBfdmVjdCA8LSB2ZWN0KHNvbV9hZG0wKQ0KDQojIDEuIENyb3AgdGhlIHJhc3RlciB0byB0aGUgZXh0ZW50IG9mIHRoZSBTb21hbGlhIGJvdW5kYXJ5DQpwcmVjaXBfY3JvcHBlZCA8LSBjcm9wKGFubnVhbF9hdmdfcHJlY2lwLCBzb21fYWRtMF92ZWN0KQ0KDQojIDIuIE1hc2sgdGhlIGNyb3BwZWQgcmFzdGVyIHdpdGggdGhlIFNvbWFsaWEgcG9seWdvbg0KcHJlY2lwX21hc2tlZCA8LSBtYXNrKHByZWNpcF9jcm9wcGVkLCBzb21fYWRtMF92ZWN0KQ0KDQojIFBsb3QgdGhlIGZpbmFsLCBtYXNrZWQgcmFzdGVyDQpwbG90KHByZWNpcF9tYXNrZWQsIG1haW4gPSAiQXZlcmFnZSBBbm51YWwgUHJlY2lwaXRhdGlvbiBNYXNrZWQgdG8gU29tYWxpYSdzIEJvdW5kYXJ5IikNCmBgYA0KDQojIyMgNC4gRXh0cmFjdGluZyBSYXN0ZXIgVmFsdWVzDQoNClRoZSByZWFsIHBvd2VyIGNvbWVzIGZyb20gY29tYmluaW5nIHJhc3RlciBhbmQgdmVjdG9yIGRhdGEuIFRoZSBgZXh0cmFjdCgpYCBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gInB1bGwiIHZhbHVlcyBmcm9tIGEgcmFzdGVyIGF0IHNwZWNpZmljIGxvY2F0aW9ucyAocG9pbnRzKSBvciBzdW1tYXJpemUgdGhlbSBvdmVyIGFyZWFzIChwb2x5Z29ucykuDQoNCioqRXhhbXBsZSAxOiBFeHRyYWN0aW5nIFByZWNpcGl0YXRpb24gYXQgU3BlY2lmaWMgQ2l0aWVzKioNCkxldCdzIGZpbmQgdGhlIGF2ZXJhZ2UgYW5udWFsIHByZWNpcGl0YXRpb24gZm9yIE1vZ2FkaXNodSBhbmQgSGFyZ2Vpc2EuDQoNCmBgYHtyIGV4dHJhY3RfcG9pbnRzfQ0KIyAxLiBDcmVhdGUgYSBTcGF0VmVjdG9yIG9mIG91ciBjaXRpZXMNCmNpdGllc19kZiA8LSBkYXRhLmZyYW1lKA0KICBuYW1lID0gYygiTW9nYWRpc2h1IiwgIkhhcmdlaXNhIiksDQogIGxvbiA9IGMoNDUuMzMzLCA0NC4wNjcpLA0KICBsYXQgPSBjKDIuMDMzLCA5LjU2NykNCikNCmNpdGllc192ZWN0IDwtIHZlY3QoY2l0aWVzX2RmLCBnZW9tPWMoImxvbiIsICJsYXQiKSwgY3JzPSJFUFNHOjQzMjYiKQ0KDQojIDIuIEV4dHJhY3QgdGhlIHJhc3RlciB2YWx1ZXMgYXQgdGhlc2UgcG9pbnQgbG9jYXRpb25zDQpjaXR5X3ByZWNpcF92YWx1ZXMgPC0gZXh0cmFjdChwcmVjaXBfbWFza2VkLCBjaXRpZXNfdmVjdCkNCg0KIyAzLiBDb21iaW5lIHRoZSByZXN1bHRzIHdpdGggdGhlIGNpdHkgbmFtZXMNCmNpdHlfcmVzdWx0cyA8LSBjYmluZChjaXRpZXNfZGYsIGNpdHlfcHJlY2lwX3ZhbHVlcykNCnByaW50KGNpdHlfcmVzdWx0cykNCmBgYA0KVGhlIHJlc3VsdCBzaG93cyBIYXJnZWlzYSByZWNlaXZlcyBzaWduaWZpY2FudGx5IG1vcmUgcmFpbmZhbGwgdGhhbiBNb2dhZGlzaHUsIHdoaWNoIG1hdGNoZXMgb3VyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIGxvY2FsIGNsaW1hdGUuDQoNCioqRXhhbXBsZSAyOiBTdW1tYXJpemluZyBQcmVjaXBpdGF0aW9uIGJ5IFJlZ2lvbioqDQpXaGF0IGlzIHRoZSBhdmVyYWdlIHByZWNpcGl0YXRpb24gZm9yIGVhY2ggYWRtaW5pc3RyYXRpdmUgcmVnaW9uIGluIFNvbWFsaWE/IFdlIGNhbiB1c2UgYGV4dHJhY3QoKWAgd2l0aCBwb2x5Z29ucy4NCg0KYGBge3IgZXh0cmFjdF9wb2x5Z29uc30NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRpZHl0ZXJyYSkgIyBGb3IgcGxvdHRpbmcgdGVycmEgb2JqZWN0cyB3aXRoIGdncGxvdA0KDQojIDEuIExvYWQgdGhlIHJlZ2lvbnMgdmVjdG9yIGRhdGEgKGZyb20gTGVjdHVyZSAxKQ0Kc29tX2FkbTEgPC0gc3RfcmVhZCgic29tX2FkbWJuZGFfYWRtMV9vY2hhXzIwMjUwMTA4LnNocCIsIHF1aWV0ID0gVFJVRSkNCnNvbV9hZG0xX3ZlY3QgPC0gdmVjdChzb21fYWRtMSkNCg0KIyAyLiBFeHRyYWN0IHRoZSBtZWFuIHByZWNpcGl0YXRpb24gZm9yIGVhY2ggcG9seWdvbiAocmVnaW9uKQ0KIyBXZSB1c2UgZnVuPSJtZWFuIiB0byBzcGVjaWZ5IHRoZSBzdW1tYXJ5IHN0YXRpc3RpYy4gbmEucm09VFJVRSBpZ25vcmVzIE5BIGNlbGxzLg0KcmVnaW9uYWxfcHJlY2lwIDwtIGV4dHJhY3QocHJlY2lwX21hc2tlZCwgc29tX2FkbTFfdmVjdCwgZnVuID0gIm1lYW4iLCBuYS5ybSA9IFRSVUUpDQoNCiMgMy4gQWRkIHRoZSBleHRyYWN0ZWQgdmFsdWVzIGJhY2sgdG8gb3VyIHZlY3RvciBvYmplY3QNCnNvbV9hZG0xX3ZlY3QkYXZnX3ByZWNpcCA8LSByZWdpb25hbF9wcmVjaXBbLDJdICMgVGhlIHNlY29uZCBjb2x1bW4gaGFzIHRoZSB2YWx1ZXMNCg0KIyA0LiBNYXAgdGhlIHJlc3VsdHMNCmdncGxvdCgpICsNCiAgZ2VvbV9zcGF0dmVjdG9yKGRhdGEgPSBzb21fYWRtMV92ZWN0LCBhZXMoZmlsbCA9IGF2Z19wcmVjaXApKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hbWUgPSAiQXZnLiBNb250aGx5XG5QcmVjaXBpdGF0aW9uIChtbSkiKSArDQogIGdndGl0bGUoIkF2ZXJhZ2UgTW9udGhseSBQcmVjaXBpdGF0aW9uIGJ5IFJlZ2lvbiIpICsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCg0KVGhpcyBtYXAgcHJvdmlkZXMgYSBjbGVhciBhbmQgcG93ZXJmdWwgdmlzdWFsaXphdGlvbiBvZiB0aGUgc3BhdGlhbCBkaXN0cmlidXRpb24gb2YgcmFpbmZhbGwgYWNyb3NzIFNvbWFsaWEsIHJldmVhbGluZyBkaXN0aW5jdCBjbGltYXRpYyB6b25lcyB0aGF0IHByb2ZvdW5kbHkgaW5mbHVlbmNlIGxpdmVsaWhvb2RzLCBmb29kIHNlY3VyaXR5LCBhbmQgcG90ZW50aWFsIGZvciBjb25mbGljdC4gVGhlIHBhdHRlcm5zIG9ic2VydmVkIGFsaWduIGNsb3NlbHkgd2l0aCB0aGUgY291bnRyeSdzIGtub3duIHRvcG9ncmFwaHkgYW5kIGFncmljdWx0dXJhbCBzeXN0ZW1zLg0KDQpUaGUgIlNvcmdodW0gQmVsdCIgYW5kIFJpdmVyaW5lIEFyZWFzIChIaWdoZXN0IFByZWNpcGl0YXRpb24pOiBUaGUgdHdvIGFyZWFzIHdpdGggdGhlIGhpZ2hlc3QgYXZlcmFnZSBwcmVjaXBpdGF0aW9uIChzaG93biBpbiB5ZWxsb3csIH40MCBtbS9tb250aCBvciB+NDgwIG1tL3llYXIpIGFyZSB0aGUgbm9ydGh3ZXN0ZXJuIHJlZ2lvbnMgb2YgQXdkYWwgYW5kIFdvcW9veWkgR2FsYmVlZCAoU29tYWxpbGFuZCkgYW5kIHRoZSBzb3V0aHdlc3Rlcm4gcmVnaW9ucyBvZiBHZWRvLCBCYXksIGFuZCB0aGUgSnViYXMuDQoNClRoZSBub3J0aHdlc3Rlcm4gaGlnaGxhbmRzIGJlbmVmaXQgZnJvbSBoaWdoZXIgZWxldmF0aW9uIGFuZCBvcm9ncmFwaGljIGxpZnQsIG1ha2luZyB0aGVtIHRoZSBtb3N0IHByb2R1Y3RpdmUgem9uZSBpbiBTb21hbGlsYW5kIGZvciByYWluLWZlZCBhZ3JpY3VsdHVyZSBhbmQgcGFzdG9yYWxpc20uDQoNClRoZSBzb3V0aHdlc3Rlcm4gYXJlYSBpcyB0aGUgYnJlYWRiYXNrZXQgb2YgU29tYWxpYSwgYmVuZWZpdGluZyBub3Qgb25seSBmcm9tIGhpZ2hlciByYWluZmFsbCBidXQgYWxzbyBmcm9tIHRoZSBwcmVzZW5jZSBvZiB0aGUgSnViYmEgYW5kIFNoYWJlbGxlIHJpdmVycywgd2hpY2ggc3VwcG9ydCBpcnJpZ2F0aW9uLWJhc2VkIGZhcm1pbmcuDQoNClRoZSBBcmlkIENlbnRyYWwgYW5kIE5vcnRoZWFzdGVybiBSZWdpb25zIChMb3dlc3QgUHJlY2lwaXRhdGlvbik6IEEgdmFzdCBjb3JyaWRvciBzdHJldGNoaW5nIGZyb20gdGhlIGNlbnRyYWwgcmVnaW9ucyAoR2FsZ2FkdXVkLCBNdWR1ZykgdXAgdGhyb3VnaCB0aGUgZW50aXJlIG5vcnRoZWFzdGVybiB0aXAgb2YgdGhlIEhvcm4gKE51Z2FhbCBhbmQgQmFyaSByZWdpb25zIG9mIFB1bnRsYW5kKSBleHBlcmllbmNlcyBoeXBlci1hcmlkIGNvbmRpdGlvbnMgKGRhcmsgcHVycGxlLCB+MTAgbW0vbW9udGggb3IgfjEyMCBtbS95ZWFyKS4gVGhpcyBhcmVhIGlzIHByZWRvbWluYW50bHkgc3VpdGVkIGZvciBub21hZGljIHBhc3RvcmFsaXNtLCBhbmQgaXRzIGluaGFiaXRhbnRzIGFyZSBoaWdobHkgdnVsbmVyYWJsZSB0byBkcm91Z2h0LiBUaGUgbG93IHJhaW5mYWxsIGhlcmUgbWFrZXMgd2F0ZXIgYSBzY2FyY2UgYW5kIGNyaXRpY2FsIHJlc291cmNlLg0KDQpUcmFuc2l0aW9uYWwgWm9uZXM6IFRoZSByZWdpb25zIHNob3duIGluIGdyZWVuIGFuZCB0ZWFsIHJlcHJlc2VudCB0cmFuc2l0aW9uYWwgc2VtaS1hcmlkIHpvbmVzLiBUaGVzZSBhcmVhcywgc3VjaCBhcyBUb2dkaGVlciBpbiB0aGUgbm9ydGggYW5kIEhpcmFhbiBpbiB0aGUgc291dGgsIG9mdGVuIHNlcnZlIGFzIGNydWNpYWwgZ3JhemluZyBsYW5kcyBidXQgYXJlIGhpZ2hseSBzdXNjZXB0aWJsZSB0byBjbGltYXRlIHZhcmlhYmlsaXR5Lg0KDQpJbiBjb25jbHVzaW9uLCB0aGlzIG1hcCBpcyBub3QganVzdCBhIGNsaW1hdGljIHN1bW1hcnk7IGl0IGlzIGEgZm91bmRhdGlvbmFsIG1hcCBmb3IgdW5kZXJzdGFuZGluZyBodW1hbiBnZW9ncmFwaHkgaW4gU29tYWxpYS4gSXQgaGVscHMgZXhwbGFpbiB3aHkgYWdyaWN1bHR1cmFsIGFjdGl2aXR5IGlzIGNvbmNlbnRyYXRlZCBpbiB0aGUgc291dGh3ZXN0LCB3aHkgcGFzdG9yYWxpc3QgbWlncmF0aW9uIHJvdXRlcyBkb21pbmF0ZSB0aGUgY2VudHJhbCBhbmQgbm9ydGhlYXN0LCBhbmQgd2hpY2ggcmVnaW9ucyBhcmUgbW9zdCBlY29sb2dpY2FsbHkgZnJhZ2lsZSBhbmQgcHJvbmUgdG8gZHJvdWdodC1yZWxhdGVkIGh1bWFuaXRhcmlhbiBjcmlzZXMuIEFueSBhbmFseXNpcyBvZiBmb29kIHNlY3VyaXR5LCByZXNvdXJjZSBtYW5hZ2VtZW50LCBvciBkZXZlbG9wbWVudCBwbGFubmluZyBpbiBTb21hbGlhIG11c3QgYmUgZ3JvdW5kZWQgaW4gdGhpcyBzcGF0aWFsIHJlYWxpdHkgb2Ygd2F0ZXIgYXZhaWxhYmlsaXR5Lg0KDQoNCg0KDQoNCg0KDQoqKkV4YW1wbGUgMzogU3VtbWFyaXppbmcgUHJlY2lwaXRhdGlvbiBieSBEaXN0cmljdCoqDQpXaGF0IGlzIHRoZSBhdmVyYWdlIHByZWNpcGl0YXRpb24gZm9yIGVhY2ggYWRtaW5pc3RyYXRpdmUgZGlzdHJpY3QgaW4gU29tYWxpYT8gV2UgY2FuIHVzZSBgZXh0cmFjdCgpYCB3aXRoIHBvbHlnb25zLg0KDQpgYGB7ciBleHRyYWN0X2Rpc3RyaWN0c30NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRpZHl0ZXJyYSkgIyBGb3IgcGxvdHRpbmcgdGVycmEgb2JqZWN0cyB3aXRoIGdncGxvdA0KDQojIDEuIExvYWQgdGhlIGRpc3RyaWN0cyB2ZWN0b3IgZGF0YSAoZnJvbSBMZWN0dXJlIDEpDQpzb21fYWRtMiA8LSBzdF9yZWFkKCJzb21fYWRtYm5kYV9hZG0yX29jaGFfMjAyNTAxMDguc2hwIiwgcXVpZXQgPSBUUlVFKQ0Kc29tX2FkbTJfdmVjdCA8LSB2ZWN0KHNvbV9hZG0yKQ0KDQojIDIuIEV4dHJhY3QgdGhlIG1lYW4gcHJlY2lwaXRhdGlvbiBmb3IgZWFjaCBwb2x5Z29uIChkaXN0cmljdCkNCiMgV2UgdXNlIGZ1bj0ibWVhbiIgdG8gc3BlY2lmeSB0aGUgc3VtbWFyeSBzdGF0aXN0aWMuIG5hLnJtPVRSVUUgaWdub3JlcyBOQSBjZWxscy4NCmRpc3RyaWN0X3ByZWNpcCA8LSBleHRyYWN0KHByZWNpcF9tYXNrZWQsIHNvbV9hZG0yX3ZlY3QsIGZ1biA9ICJtZWFuIiwgbmEucm0gPSBUUlVFKQ0KDQojIDMuIEFkZCB0aGUgZXh0cmFjdGVkIHZhbHVlcyBiYWNrIHRvIG91ciB2ZWN0b3Igb2JqZWN0DQpzb21fYWRtMl92ZWN0JGF2Z19wcmVjaXAgPC0gZGlzdHJpY3RfcHJlY2lwWywyXSAjIFRoZSBzZWNvbmQgY29sdW1uIGhhcyB0aGUgdmFsdWVzDQoNCiMgNC4gTWFwIHRoZSByZXN1bHRzDQpnZ3Bsb3QoKSArDQogIGdlb21fc3BhdHZlY3RvcihkYXRhID0gc29tX2FkbTJfdmVjdCwgYWVzKGZpbGwgPSBhdmdfcHJlY2lwKSkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhuYW1lID0gIkF2Zy4gTW9udGhseVxuUHJlY2lwaXRhdGlvbiAobW0pIikgKw0KICBnZ3RpdGxlKCJBdmVyYWdlIE1vbnRobHkgUHJlY2lwaXRhdGlvbiBieSBEaXN0cmljdCIpICsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCmBgYA==