1 Libraries and raw data

library(tidyverse)
library(magrittr)
library(sf)

Make sure you have the following sub-folder in your folder: https://www.dropbox.com/scl/fo/xqonwazhrwml6wp3n28md/h?dl=0&rlkey=qd0a56dfzfpqppcan1xi23597

Please note that the sub-folder is not included in the github repo due to storage constraints

Zones <- st_read(
  "Mexico OD Survey/DistritosEODHogaresZMVM2017/DistritosEODHogaresZMVM2017.shp")
Reading layer `DistritosEODHogaresZMVM2017' from data source 
  `C:\Users\Orlan\Dropbox\Teaching\SpatialAnalysis\Tutorials\04_MexicoCity_HTS\Mexico OD Survey\DistritosEODHogaresZMVM2017\DistritosEODHogaresZMVM2017.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 194 features and 2 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 431878.5 ymin: 2093686 xmax: 542232.1 ymax: 2219035
Projected CRS: WGS 84 / UTM zone 14N
Trips <- read_delim(
  "Mexico OD Survey/eod_2017_csv/tviaje_eod2017/conjunto_de_datos/tviaje.csv",
  delim = ",")
Rows: 531594 Columns: 82── Column specification ──────────────────────────────────────────────────────────────
Delimiter: ","
chr (22): n_via, p5_6, p5_7_6, p5_7_7, dto_origen, p5_9_1, p5_9_2, p5_10_1, p5_10_...
dbl (58): id_via, id_soc, p5_3, p5_14_01, p5_15_01, p5_14_02, p5_15_02, p5_14_03, ...
lgl  (2): p5_15_15, p5_15_19
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
#p5_11: HomeTrip or not
#p5_13: Trip Purpose
#p5_9_1: Time the trip started
TripsStages <- read_delim(
  "Mexico OD Survey/eod_2017_csv/ttransporte_eod2017/conjunto_de_datos/ttransporte.csv", 
  delim = ",")
Rows: 890748 Columns: 18── Column specification ──────────────────────────────────────────────────────────────
Delimiter: ","
chr (11): n_via, p5_14, p5_16, p5_16_1_1, p5_16_1_2, p5_16_2, p5_17_1c, p5_17_2c, ...
dbl  (7): id_tra, id_via, p5_3, estrato, factor, tloc, sexo
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# id_via is the unique identifier. It is consistent with Trips
# p5_14 is the transport mode
# p5_16 is the order of the stages. 
People <- read_delim(
  "Mexico OD Survey/eod_2017_csv/tsdem_eod2017/conjunto_de_datos/tsdem.csv",
  delim = ",")
Rows: 200117 Columns: 22── Column specification ──────────────────────────────────────────────────────────────
Delimiter: ","
chr (10): n_ren, edad, niv, p5_4, p6_4, upm_dis, est_dis, distrito, ent, mun
dbl (12): id_soc, id_hog, parentesco, sexo, gra, p3_7, p3_8, p4_2, p4_3, estrato, ...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
#id_soc is the unique identifier por people
Home <- read_delim(
  "Mexico OD Survey/eod_2017_csv/thogar_eod2017/conjunto_de_datos/thogar.csv",
                   delim = ",")
Rows: 56685 Columns: 20── Column specification ──────────────────────────────────────────────────────────────
Delimiter: ","
chr  (7): hogar, n_inf, upm_dis, est_dis, distrito, ent, mun
dbl (13): id_hog, id_viv, p2_1_1, p2_1_2, p2_1_3, p2_2, p2_2b_1, p2_2b_2, p2_2b_3,...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

2 Our Goal

plot(st_geometry(Zones))

Zones %>% glimpse()
Rows: 194
Columns: 3
$ Distrito   <chr> "001", "002", "003", "004", "005", "006", "007", "008", "009", "0…
$ Descripcio <chr> "Centro Histórico", "Buenavista-Reforma", "Tlatelolco", "Morelos"…
$ geometry   <MULTIPOLYGON [m]> MULTIPOLYGON (((485707.7 21..., MULTIPOLYGON (((4850…

3 variables and keys

dim(Trips)
[1] 531594     82
dim(TripsStages)
[1] 890748     18
names(Trips)
 [1] "id_via"     "id_soc"     "p5_3"       "n_via"      "p5_6"       "p5_7_6"    
 [7] "p5_7_7"     "dto_origen" "p5_9_1"     "p5_9_2"     "p5_10_1"    "p5_10_2"   
[13] "p5_11a"     "p5_12_6"    "p5_12_7"    "dto_dest"   "p5_13"      "p5_14_01"  
[19] "p5_15_01"   "p5_14_02"   "p5_15_02"   "p5_14_03"   "p5_15_03"   "p5_14_04"  
[25] "p5_15_04"   "p5_14_05"   "p5_15_05"   "p5_14_06"   "p5_15_06"   "p5_14_07"  
[31] "p5_15_07"   "p5_14_08"   "p5_15_08"   "p5_14_09"   "p5_15_09"   "p5_14_10"  
[37] "p5_15_10"   "p5_14_11"   "p5_15_11"   "p5_14_12"   "p5_15_12"   "p5_14_13"  
[43] "p5_15_13"   "p5_14_14"   "p5_15_14"   "p5_14_15"   "p5_15_15"   "p5_14_16"  
[49] "p5_15_16"   "p5_14_17"   "p5_15_17"   "p5_14_18"   "p5_15_18"   "p5_14_19"  
[55] "p5_15_19"   "p5_14_20"   "p5_15_20"   "p5_18"      "p5_19"      "p5_20"     
[61] "p5_21_1"    "p5_21_2"    "p5_22"      "p5_23"      "p5_24"      "p5_25"     
[67] "p5_26"      "p5_27_1"    "p5_27_2"    "p5_27_3"    "p5_27_4"    "p5_27_5"   
[73] "p5_27_6"    "p5_27_7"    "p5_27_8"    "estrato"    "factor"     "upm_dis"   
[79] "est_dis"    "tloc"       "sexo"       "edad"      
names(TripsStages)
 [1] "id_tra"    "id_via"    "p5_3"      "n_via"     "p5_14"     "p5_16"    
 [7] "p5_16_1_1" "p5_16_1_2" "p5_16_2"   "p5_17_1c"  "p5_17_2c"  "estrato"  
[13] "factor"    "upm_dis"   "est_dis"   "tloc"      "sexo"      "edad"     

Keep in mind that for the “Trips” object:

  • p5_11: HomeTrip or not
  • p5_13: Trip Purpose
  • p5_9_1: Time the trip started
  • dto_origen: Origin of the trip
  • dto_dest: Destination of the trip

And keep in mind that for the “Trips”Stages” object: - id_via is the unique identifier. It is consistent with the “Trips” - p5_14 is the transport mode - p5_16 is the order of the stages.

dim(People)
[1] 200117     22
dim(Home)
[1] 56685    20
names(People)
 [1] "id_soc"     "id_hog"     "n_ren"      "parentesco" "sexo"       "edad"      
 [7] "niv"        "gra"        "p3_7"       "p3_8"       "p4_2"       "p4_3"      
[13] "p5_4"       "p6_4"       "estrato"    "factor"     "upm_dis"    "est_dis"   
[19] "tloc"       "distrito"   "ent"        "mun"       
names(Home)
 [1] "id_hog"   "id_viv"   "hogar"    "n_inf"    "p2_1_1"   "p2_1_2"   "p2_1_3"  
 [8] "p2_2"     "p2_2b_1"  "p2_2b_2"  "p2_2b_3"  "p2_2b_4"  "estrato"  "factor"  
[15] "upm_dis"  "est_dis"  "tloc"     "distrito" "ent"      "mun"     

Keep in mind that id_soc is the unique identifier for every individual

4 Trips

4.1 Mode

Trips %>% group_by(p5_13) %>% summarise(TotalTrips = n()) %>% arrange(desc(TotalTrips))
class(Trips$p5_13)
[1] "character"
PurposeNames <- data.frame(p5_13 = c(1:10,99),
                           Purpose = c("Hogar","Trabajar", "Estudiar", 
                                       "Otro", "Recreacion","Otro", "Otro",
                                       "Salud", rep("Otro",3)))

Trips %<>% 
  mutate(p5_13 = as.numeric(p5_13)) %>% 
  left_join(PurposeNames) %>% 
  select(id_via, Purpose, dto_origen, dto_dest)
Joining, by = "p5_13"
Trips

4.2 Travel time

TripsStages %>% group_by(p5_14) %>% 
  summarise(TotalPerModel = n()) %>% 
  arrange(desc(TotalPerModel))
class(TripsStages$p5_14)
[1] "character"
ModesNames <- data.frame(
  p5_14 = seq(1:20),
  Modes = c("Automovil", "Colectivo_Micro", "App",
            "Taxi", "Metro", "Autobus_RTP_M1",
             "Bicicleta",  "Autobus", "Moto",  "Trolebus", 
             "Metrobus_Mexibus", "TrenLigero","TrenSuburbano", 
             "Caminar", "Mexicable", "Bicitaxi",  "Mototaxi", 
              "TransporteEscolar", "TransporteDePersonal", "Otro"))

TripsStages %<>%
  mutate(p5_14 = as.numeric(p5_14)) %>% 
  left_join(ModesNames) %>% 
  select(id_via, Modes,
         TT_Hours = p5_16_1_1, TT_Minutes = p5_16_1_2) %>% 
  mutate(TT_Hours = as.numeric(TT_Hours),
         TT_Minutes = as.numeric(TT_Minutes)) %>% 
  filter(!TT_Hours == 99) %>% filter(!TT_Minutes == 99) %>%
  filter(TT_Hours < 4) %>%  # Remove trips lasting more than 4 hours. 
  mutate(TravelTime = TT_Hours*60 + TT_Minutes)
Joining, by = "p5_14"

4.3 Merge trips

Trips_Final <- TripsStages %>% left_join(Trips)
Joining, by = "id_via"
Trips_Final

Why is this not accurate?

5 Data to zones

5.1 Trips to zones

5.1.1 Total trips

Agg_TotalTrips <- Trips_Final %>% group_by(dto_origen) %>% 
  summarise(TotalTrips = n())

5.1.2 Trips Per Mode

Agg_TripsPerMode <- Trips_Final %>% 
  group_by(Modes, dto_origen) %>% 
  summarise(
    TripsPerMode = n(),
    TravelTime = mean(TravelTime)
  )
`summarise()` has grouped output by 'Modes'. You can override using the `.groups` argument.

How do we fix this?

Agg_TripsPerMode %>% 
  pivot_wider(id_cols = dto_origen, 
              names_from = Modes, names_prefix = "Trips_", 
              values_from = TripsPerMode, values_fill = 0)
Agg_Trips_Trips <- Agg_TripsPerMode %>% 
  pivot_wider(id_cols = dto_origen, 
              names_from = Modes, names_prefix = "Trips_", 
              values_from = TripsPerMode, values_fill = 0)

Agg_Trips_TravelTime <- Agg_TripsPerMode %>% 
  pivot_wider(id_cols = dto_origen, 
              names_from = Modes, names_prefix = "TravelTime_",
              values_from = TravelTime, values_fill = 0)

5.2 People to zones

5.2.1 Age

summary(People$edad)
   Length     Class      Mode 
   200117 character character 
dim(People)
[1] 200117     22
People %>% filter(edad == "00") %>% dim()
[1] 1779   22
People %>% filter(edad == "97") %>% dim()
[1] 65 22
People %>% filter(edad == "99") %>% dim()
[1] 144  22
People %<>% filter(!edad %in% c("00", "97", "99")) 
dim(People)
[1] 198129     22
People$edad = as.numeric(People$edad)
People_TotalPeople_Age <- People %>% group_by(distrito) %>% 
  summarise(TotalPeople = n(),
            Age = mean(edad, na.rm = TRUE))

People_TotalPeople_Age

5.2.2 Education

People %>% group_by(niv) %>% summarise(Total = n())
People %<>% 
  mutate(EducationLevel = recode(niv,
                                 "00" = "Low",
                                 "01" = "Low",
                                 "02" = "Low",
                                 "03" = "Low",
                                 "99" = "Low", # Is this correct?
                                 "04" = "Medium",
                                 "05" = "Medium",
                                 "06" = "Medium",
                                 "07" = "Medium",
                                 "08" = "High",
                                 "09" = "High")) 
People_EducationLevel <- People %>% group_by(distrito, EducationLevel) %>% 
  summarise(Total = n()) %>% drop_na() %>% 
  pivot_wider(id_cols = distrito, 
              names_from = EducationLevel, names_prefix = "TotalEducation_",
              values_from = Total, values_fill = 0)
`summarise()` has grouped output by 'distrito'. You can override using the `.groups` argument.
People_EducationLevel

5.2.3 Gender

sexo

summary(People$sexo)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   1.000   2.000   1.517   2.000   2.000 
summary(as.factor(People$sexo))
     1      2 
 95779 102350 
People %<>% mutate(Gender = if_else(sexo == 1, "Male", "Female"))
People_Gender <- People %>% group_by(distrito, Gender) %>% 
  summarise(Total = n()) %>% 
  pivot_wider(id_cols = distrito, 
              names_from = Gender, names_prefix = "Total_",
              values_from = Total, values_fill = 0)
`summarise()` has grouped output by 'distrito'. You can override using the `.groups` argument.
People_Gender

5.3 Homes to zones

p2_1_1: ¿Cuántos autos o camionetas tienen para transportarse cotidianamente? p2_1_2: ¿Cuántas motocicletas o motonetas tienen para transportarse cotidianamente? p2_1_3: ¿Cuántas bicicletas tienen para transportarse cotidianamente?

Home %<>%
  select(distrito, 
         Cars = p2_1_1,
         Motos = p2_1_2,
         Bicycles = p2_1_3) %>% 
  mutate(
    Has_Car = if_else(Cars > 0, 1, 0),
    Has_Motos = if_else(Motos > 0, 1, 0),
    Has_Bicycles = if_else(Bicycles > 0, 1, 0))

Home
Homes_TotalHomes <- Home %>% 
  group_by(distrito) %>% 
  summarise(Total_Homes = n())

Homes_CarOwnership <- Home %>% 
  filter(Has_Car == 1) %>% 
  group_by(distrito) %>% 
  summarise(Homes_With_Cars = n())

Homes_MotorbikeOwnership <- Home %>% 
  filter(Has_Motos == 1) %>% 
  group_by(distrito) %>% 
  summarise(Homes_With_Motorbikes = n())

Homes_BicycleOwnership <- Home %>%
  filter(Has_Bicycles == 1) %>% 
  group_by(distrito) %>% 
  summarise(Homes_With_Bicycles = n())

Homes_Mean_Veahicles <- Home %>% 
  group_by(distrito) %>% 
  summarise(
    Cars_mean = mean(Cars),
    Motorbikes_mean = mean(Bicycles),
    Bicycles_mean = mean(Bicycles)
  )

6 Merge

Data_Agg <- Agg_TotalTrips %>% 
  left_join(Agg_Trips_Trips) %>% 
  left_join(Agg_Trips_TravelTime) %>% 
  left_join(People_TotalPeople_Age, by = c("dto_origen" = "distrito")) %>% 
  left_join(People_EducationLevel, by = c("dto_origen" = "distrito")) %>% 
  left_join(People_Gender, by = c("dto_origen" = "distrito")) %>% 
  left_join(Homes_TotalHomes, by = c("dto_origen" = "distrito")) %>% 
  left_join(Homes_CarOwnership, by = c("dto_origen" = "distrito")) %>% 
  left_join(Homes_MotorbikeOwnership, by = c("dto_origen" = "distrito")) %>% 
  left_join(Homes_BicycleOwnership, by = c("dto_origen" = "distrito")) %>% 
  left_join(Homes_Mean_Veahicles, by = c("dto_origen" = "distrito"))
Joining, by = "dto_origen"Joining, by = "dto_origen"

Check the districts 888 and 999

MexicoCity_HTS <- Zones %>% 
  left_join(Data_Agg, by = c("Distrito" = "dto_origen"))
dim(MexicoCity_HTS)
[1] 194  58
names(MexicoCity_HTS)
 [1] "Distrito"                        "Descripcio"                     
 [3] "TotalTrips"                      "Trips_App"                      
 [5] "Trips_Autobus"                   "Trips_Autobus_RTP_M1"           
 [7] "Trips_Automovil"                 "Trips_Bicicleta"                
 [9] "Trips_Bicitaxi"                  "Trips_Caminar"                  
[11] "Trips_Colectivo_Micro"           "Trips_Metro"                    
[13] "Trips_Metrobus_Mexibus"          "Trips_Mexicable"                
[15] "Trips_Moto"                      "Trips_Mototaxi"                 
[17] "Trips_Otro"                      "Trips_Taxi"                     
[19] "Trips_TransporteDePersonal"      "Trips_TransporteEscolar"        
[21] "Trips_TrenLigero"                "Trips_TrenSuburbano"            
[23] "Trips_Trolebus"                  "TravelTime_App"                 
[25] "TravelTime_Autobus"              "TravelTime_Autobus_RTP_M1"      
[27] "TravelTime_Automovil"            "TravelTime_Bicicleta"           
[29] "TravelTime_Bicitaxi"             "TravelTime_Caminar"             
[31] "TravelTime_Colectivo_Micro"      "TravelTime_Metro"               
[33] "TravelTime_Metrobus_Mexibus"     "TravelTime_Mexicable"           
[35] "TravelTime_Moto"                 "TravelTime_Mototaxi"            
[37] "TravelTime_Otro"                 "TravelTime_Taxi"                
[39] "TravelTime_TransporteDePersonal" "TravelTime_TransporteEscolar"   
[41] "TravelTime_TrenLigero"           "TravelTime_TrenSuburbano"       
[43] "TravelTime_Trolebus"             "TotalPeople"                    
[45] "Age"                             "TotalEducation_High"            
[47] "TotalEducation_Low"              "TotalEducation_Medium"          
[49] "Total_Female"                    "Total_Male"                     
[51] "Total_Homes"                     "Homes_With_Cars"                
[53] "Homes_With_Motorbikes"           "Homes_With_Bicycles"            
[55] "Cars_mean"                       "Motorbikes_mean"                
[57] "Bicycles_mean"                   "geometry"                       

7 CRS

st_crs(MexicoCity_HTS)
Coordinate Reference System:
  User input: WGS 84 / UTM zone 14N 
  wkt:
PROJCRS["WGS 84 / UTM zone 14N",
    BASEGEOGCRS["WGS 84",
        DATUM["World Geodetic System 1984",
            ELLIPSOID["WGS 84",6378137,298.257223563,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",4326]],
    CONVERSION["UTM zone 14N",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",0,
            ANGLEUNIT["Degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",-99,
            ANGLEUNIT["Degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",0.9996,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",500000,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",0,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["(E)",east,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["(N)",north,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    ID["EPSG",32614]]

EPSG:32614 EPSG:4326

MexicoCity_HTS <- st_transform(MexicoCity_HTS, 4326)

8 Print

ls()
 [1] "Agg_TotalTrips"           "Agg_Trips_TravelTime"     "Agg_Trips_Trips"         
 [4] "Agg_TripsPerMode"         "Data_Agg"                 "Home"                    
 [7] "Homes_BicycleOwnership"   "Homes_CarOwnership"       "Homes_Mean_Veahicles"    
[10] "Homes_MotorbikeOwnership" "Homes_TotalHomes"         "MexicoCity_HTS"          
[13] "ModesNames"               "People"                   "People_EducationLevel"   
[16] "People_Gender"            "People_TotalPeople_Age"   "PurposeNames"            
[19] "Trips"                    "Trips_Final"              "TripsStages"             
[22] "Zones"                   
rm(
  Agg_TotalTrips, Agg_Trips_TravelTime, Agg_Trips_Trips,         
  Agg_TripsPerMode, Data, Data_Agg, Home, Homes_BicycleOwnership, Homes_CarOwnership,      
  Homes_Mean_Veahicles, Homes_MotorbikeOwnership, Homes_TotalHomes, ModesNames,              People, People_EducationLevel, People_Gender, People_TotalPeople_Age,  
  PurposeNames,Trips, Trips_Final, TripsStages, Zones )
Warning: object 'Data' not found
ls()
[1] "MexicoCity_HTS"
```r
save.image(file = \Mexico_HTS.RData\)

st_write(MexicoCity_HTS, \MexicoCity_HTS.shp\)

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiV2FybmluZzogRmllbGQgbmFtZXMgYWJicmV2aWF0ZWQgZm9yIEVTUkkgU2hhcGVmaWxlIGRyaXZlclxuV3JpdGluZyBsYXllciBgTWV4aWNvQ2l0eV9IVFMnIHRvIGRhdGEgc291cmNlIFxuICBgTWV4aWNvQ2l0eV9IVFMuc2hwJyB1c2luZyBkcml2ZXIgYEVTUkkgU2hhcGVmaWxlJ1xuV3JpdGluZyAxOTQgZmVhdHVyZXMgd2l0aCA1NyBmaWVsZHMgYW5kIGdlb21ldHJ5IHR5cGUgTXVsdGkgUG9seWdvbi5cbiJ9 -->

Warning: Field names abbreviated for ESRI Shapefile driver Writing layer MexicoCity_HTS' to data sourceMexicoCity_HTS.shp’ using driver `ESRI Shapefile’ Writing 194 features with 57 fields and geometry type Multi Polygon.




<!-- rnb-output-end -->

<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuTWV4aWNvQ2l0eV9IVFNfRGF0YWJhc2UgPC0gTWV4aWNvQ2l0eV9IVFMgJT4lIHN0X3NldF9nZW9tZXRyeShOVUxMKVxuTWV4aWNvQ2l0eV9EaXN0cmljdHMgPC0gTWV4aWNvQ2l0eV9IVFMgJT4lIHNlbGVjdChEaXN0cml0bylcblxuXG53cml0ZV9kZWxpbShNZXhpY29DaXR5X0hUU19EYXRhYmFzZSwgXFxNZXhpY29DaXR5X0hUU19EYXRhYmFzZS5jc3ZcXCwgZGVsaW0gPSBcXDtcXClcbnN0X3dyaXRlKE1leGljb0NpdHlfRGlzdHJpY3RzLCBcXE1leGljb0NpdHlfRGlzdHJpY3RzLnNocFxcKVxuYGBgXG5gYGAifQ== -->

```r
```r
MexicoCity_HTS_Database <- MexicoCity_HTS %>% st_set_geometry(NULL)
MexicoCity_Districts <- MexicoCity_HTS %>% select(Distrito)


write_delim(MexicoCity_HTS_Database, \MexicoCity_HTS_Database.csv\, delim = \;\)
st_write(MexicoCity_Districts, \MexicoCity_Districts.shp\)

<!-- rnb-source-end -->

<!-- rnb-output-begin eyJkYXRhIjoiV3JpdGluZyBsYXllciBgTWV4aWNvQ2l0eV9EaXN0cmljdHMnIHRvIGRhdGEgc291cmNlIFxuICBgTWV4aWNvQ2l0eV9EaXN0cmljdHMuc2hwJyB1c2luZyBkcml2ZXIgYEVTUkkgU2hhcGVmaWxlJ1xuV3JpdGluZyAxOTQgZmVhdHVyZXMgd2l0aCAxIGZpZWxkcyBhbmQgZ2VvbWV0cnkgdHlwZSBNdWx0aSBQb2x5Z29uLlxuIn0= -->

Writing layer MexicoCity_Districts' to data sourceMexicoCity_Districts.shp’ using driver `ESRI Shapefile’ Writing 194 features with 1 fields and geometry type Multi Polygon. ```

LS0tDQp0aXRsZTogIkRhdGEgV3JhbmdsaW5nLSBIVFMgTWV4aWNvIENpdHkiDQphdXRob3I6ICJPcmxhbmRvIFNhYm9nYWwtQ2FyZG9uYSINCmRhdGU6ICJTdW1tZXIgMjAyMyINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB0cnVlDQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KLS0tDQogDQojIExpYnJhcmllcyBhbmQgcmF3IGRhdGENCg0KYGBge3IgbGlicmFyaWVzIHVzZWR9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobWFncml0dHIpDQpsaWJyYXJ5KHNmKQ0KYGBgDQoNCk1ha2Ugc3VyZSB5b3UgaGF2ZSB0aGUgZm9sbG93aW5nIHN1Yi1mb2xkZXIgaW4geW91ciBmb2xkZXI6IGh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3NjbC9mby94cW9ud2F6aHJ3bWw2d3AzbjI4bWQvaD9kbD0wJnJsa2V5PXFkMGE1NmRmemZwcXBwY2FuMXhpMjM1OTcgDQoNClBsZWFzZSBub3RlIHRoYXQgdGhlIHN1Yi1mb2xkZXIgaXMgbm90IGluY2x1ZGVkIGluIHRoZSBnaXRodWIgcmVwbyBkdWUgdG8gc3RvcmFnZSBjb25zdHJhaW50cw0KDQpgYGB7ciBEaXN0cmljdHMgc2hhcGVmaWxlc30NClpvbmVzIDwtIHN0X3JlYWQoDQogICJNZXhpY28gT0QgU3VydmV5L0Rpc3RyaXRvc0VPREhvZ2FyZXNaTVZNMjAxNy9EaXN0cml0b3NFT0RIb2dhcmVzWk1WTTIwMTcuc2hwIikNCmBgYA0KDQpgYGB7ciBUcmlwcyBEYXRhYmFzZX0NClRyaXBzIDwtIHJlYWRfZGVsaW0oDQogICJNZXhpY28gT0QgU3VydmV5L2VvZF8yMDE3X2Nzdi90dmlhamVfZW9kMjAxNy9jb25qdW50b19kZV9kYXRvcy90dmlhamUuY3N2IiwNCiAgZGVsaW0gPSAiLCIpDQojcDVfMTE6IEhvbWVUcmlwIG9yIG5vdA0KI3A1XzEzOiBUcmlwIFB1cnBvc2UNCiNwNV85XzE6IFRpbWUgdGhlIHRyaXAgc3RhcnRlZA0KYGBgDQoNCmBgYHtyIFRyaXBzU3RhZ2VzRGF0YWJhc2V9DQpUcmlwc1N0YWdlcyA8LSByZWFkX2RlbGltKA0KICAiTWV4aWNvIE9EIFN1cnZleS9lb2RfMjAxN19jc3YvdHRyYW5zcG9ydGVfZW9kMjAxNy9jb25qdW50b19kZV9kYXRvcy90dHJhbnNwb3J0ZS5jc3YiLCANCiAgZGVsaW0gPSAiLCIpDQoNCiMgaWRfdmlhIGlzIHRoZSB1bmlxdWUgaWRlbnRpZmllci4gSXQgaXMgY29uc2lzdGVudCB3aXRoIFRyaXBzDQojIHA1XzE0IGlzIHRoZSB0cmFuc3BvcnQgbW9kZQ0KIyBwNV8xNiBpcyB0aGUgb3JkZXIgb2YgdGhlIHN0YWdlcy4gDQoNCmBgYA0KDQpgYGB7ciBQZW9wbGUgRGF0YWJhc2V9DQpQZW9wbGUgPC0gcmVhZF9kZWxpbSgNCiAgIk1leGljbyBPRCBTdXJ2ZXkvZW9kXzIwMTdfY3N2L3RzZGVtX2VvZDIwMTcvY29uanVudG9fZGVfZGF0b3MvdHNkZW0uY3N2IiwNCiAgZGVsaW0gPSAiLCIpDQoNCiNpZF9zb2MgaXMgdGhlIHVuaXF1ZSBpZGVudGlmaWVyIHBvciBwZW9wbGUNCmBgYA0KDQpgYGB7ciBIb21lIERhdGFiYXNlfQ0KSG9tZSA8LSByZWFkX2RlbGltKA0KICAiTWV4aWNvIE9EIFN1cnZleS9lb2RfMjAxN19jc3YvdGhvZ2FyX2VvZDIwMTcvY29uanVudG9fZGVfZGF0b3MvdGhvZ2FyLmNzdiIsDQogICAgICAgICAgICAgICAgICAgZGVsaW0gPSAiLCIpDQpgYGANCg0KDQojIE91ciBHb2FsDQoNCmBgYHtyfQ0KcGxvdChzdF9nZW9tZXRyeShab25lcykpDQpgYGANCg0KYGBge3J9DQpab25lcyAlPiUgZ2xpbXBzZSgpDQpgYGANCg0KDQojIHZhcmlhYmxlcyBhbmQga2V5cw0KDQpgYGB7cn0NCmRpbShUcmlwcykNCmRpbShUcmlwc1N0YWdlcykNCmBgYA0KDQpgYGB7cn0NCm5hbWVzKFRyaXBzKQ0KbmFtZXMoVHJpcHNTdGFnZXMpDQpgYGANCg0KDQpLZWVwIGluIG1pbmQgdGhhdCBmb3IgdGhlICoiVHJpcHMiKiBvYmplY3Q6DQoNCi0gKipwNV8xMSoqOiBIb21lVHJpcCBvciBub3QNCi0gKipwNV8xMyoqOiBUcmlwIFB1cnBvc2UNCi0gKipwNV85XzEqKjogVGltZSB0aGUgdHJpcCBzdGFydGVkDQotICoqZHRvX29yaWdlbioqOiBPcmlnaW4gb2YgdGhlIHRyaXANCi0gKipkdG9fZGVzdCoqOiBEZXN0aW5hdGlvbiBvZiB0aGUgdHJpcA0KDQpBbmQga2VlcCBpbiBtaW5kIHRoYXQgZm9yIHRoZSAqIlRyaXBzIlN0YWdlcyIqIG9iamVjdDoNCi0gKippZF92aWEqKiBpcyB0aGUgdW5pcXVlIGlkZW50aWZpZXIuIEl0IGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgKiJUcmlwcyIqDQotICoqcDVfMTQqKiBpcyB0aGUgdHJhbnNwb3J0IG1vZGUNCi0gKipwNV8xNioqIGlzIHRoZSBvcmRlciBvZiB0aGUgc3RhZ2VzLiANCg0KYGBge3J9DQpkaW0oUGVvcGxlKQ0KZGltKEhvbWUpDQpgYGANCg0KYGBge3J9DQpuYW1lcyhQZW9wbGUpDQpuYW1lcyhIb21lKQ0KYGBgDQoNCktlZXAgaW4gbWluZCB0aGF0ICoqaWRfc29jKiogaXMgdGhlIHVuaXF1ZSBpZGVudGlmaWVyIGZvciBldmVyeSBpbmRpdmlkdWFsDQoNCiMgVHJpcHMNCg0KIyMgTW9kZQ0KDQpgYGB7cn0NClRyaXBzICU+JSBncm91cF9ieShwNV8xMykgJT4lIHN1bW1hcmlzZShUb3RhbFRyaXBzID0gbigpKSAlPiUgYXJyYW5nZShkZXNjKFRvdGFsVHJpcHMpKQ0KYGBgDQoNCmBgYHtyfQ0KY2xhc3MoVHJpcHMkcDVfMTMpDQpgYGANCg0KDQpgYGB7cn0NClB1cnBvc2VOYW1lcyA8LSBkYXRhLmZyYW1lKHA1XzEzID0gYygxOjEwLDk5KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFB1cnBvc2UgPSBjKCJIb2dhciIsIlRyYWJhamFyIiwgIkVzdHVkaWFyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3RybyIsICJSZWNyZWFjaW9uIiwiT3RybyIsICJPdHJvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTYWx1ZCIsIHJlcCgiT3RybyIsMykpKQ0KDQpUcmlwcyAlPD4lIA0KICBtdXRhdGUocDVfMTMgPSBhcy5udW1lcmljKHA1XzEzKSkgJT4lIA0KICBsZWZ0X2pvaW4oUHVycG9zZU5hbWVzKSAlPiUgDQogIHNlbGVjdChpZF92aWEsIFB1cnBvc2UsIGR0b19vcmlnZW4sIGR0b19kZXN0KQ0KDQpgYGANCg0KYGBge3J9DQpUcmlwcw0KYGBgDQoNCg0KIyMgVHJhdmVsIHRpbWUNCg0KYGBge3J9DQpUcmlwc1N0YWdlcyAlPiUgZ3JvdXBfYnkocDVfMTQpICU+JSANCiAgc3VtbWFyaXNlKFRvdGFsUGVyTW9kZWwgPSBuKCkpICU+JSANCiAgYXJyYW5nZShkZXNjKFRvdGFsUGVyTW9kZWwpKQ0KYGBgDQoNCmBgYHtyfQ0KY2xhc3MoVHJpcHNTdGFnZXMkcDVfMTQpDQpgYGANCg0KYGBge3J9DQpNb2Rlc05hbWVzIDwtIGRhdGEuZnJhbWUoDQogIHA1XzE0ID0gc2VxKDE6MjApLA0KICBNb2RlcyA9IGMoIkF1dG9tb3ZpbCIsICJDb2xlY3Rpdm9fTWljcm8iLCAiQXBwIiwNCiAgICAgICAgICAgICJUYXhpIiwgIk1ldHJvIiwgIkF1dG9idXNfUlRQX00xIiwNCiAgICAgICAgICAgICAiQmljaWNsZXRhIiwgICJBdXRvYnVzIiwgIk1vdG8iLCAgIlRyb2xlYnVzIiwgDQogICAgICAgICAgICAgIk1ldHJvYnVzX01leGlidXMiLCAiVHJlbkxpZ2VybyIsIlRyZW5TdWJ1cmJhbm8iLCANCiAgICAgICAgICAgICAiQ2FtaW5hciIsICJNZXhpY2FibGUiLCAiQmljaXRheGkiLCAgIk1vdG90YXhpIiwgDQogICAgICAgICAgICAgICJUcmFuc3BvcnRlRXNjb2xhciIsICJUcmFuc3BvcnRlRGVQZXJzb25hbCIsICJPdHJvIikpDQoNClRyaXBzU3RhZ2VzICU8PiUNCiAgbXV0YXRlKHA1XzE0ID0gYXMubnVtZXJpYyhwNV8xNCkpICU+JSANCiAgbGVmdF9qb2luKE1vZGVzTmFtZXMpICU+JSANCiAgc2VsZWN0KGlkX3ZpYSwgTW9kZXMsDQogICAgICAgICBUVF9Ib3VycyA9IHA1XzE2XzFfMSwgVFRfTWludXRlcyA9IHA1XzE2XzFfMikgJT4lIA0KICBtdXRhdGUoVFRfSG91cnMgPSBhcy5udW1lcmljKFRUX0hvdXJzKSwNCiAgICAgICAgIFRUX01pbnV0ZXMgPSBhcy5udW1lcmljKFRUX01pbnV0ZXMpKSAlPiUgDQogIGZpbHRlcighVFRfSG91cnMgPT0gOTkpICU+JSBmaWx0ZXIoIVRUX01pbnV0ZXMgPT0gOTkpICU+JQ0KICBmaWx0ZXIoVFRfSG91cnMgPCA0KSAlPiUgICMgUmVtb3ZlIHRyaXBzIGxhc3RpbmcgbW9yZSB0aGFuIDQgaG91cnMuIA0KICBtdXRhdGUoVHJhdmVsVGltZSA9IFRUX0hvdXJzKjYwICsgVFRfTWludXRlcykNCmBgYA0KIyMgTWVyZ2UgdHJpcHMNCg0KYGBge3J9DQpUcmlwc19GaW5hbCA8LSBUcmlwc1N0YWdlcyAlPiUgbGVmdF9qb2luKFRyaXBzKQ0KYGBgDQoNCmBgYHtyfQ0KVHJpcHNfRmluYWwNCmBgYA0KDQpXaHkgaXMgdGhpcyBub3QgYWNjdXJhdGU/DQoNCiMgRGF0YSB0byB6b25lcw0KDQojIyBUcmlwcyB0byB6b25lcw0KDQojIyMgVG90YWwgdHJpcHMNCg0KYGBge3J9DQpBZ2dfVG90YWxUcmlwcyA8LSBUcmlwc19GaW5hbCAlPiUgZ3JvdXBfYnkoZHRvX29yaWdlbikgJT4lIA0KICBzdW1tYXJpc2UoVG90YWxUcmlwcyA9IG4oKSkNCmBgYA0KDQojIyMgVHJpcHMgUGVyIE1vZGUNCg0KYGBge3J9DQpBZ2dfVHJpcHNQZXJNb2RlIDwtIFRyaXBzX0ZpbmFsICU+JSANCiAgZ3JvdXBfYnkoTW9kZXMsIGR0b19vcmlnZW4pICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIFRyaXBzUGVyTW9kZSA9IG4oKSwNCiAgICBUcmF2ZWxUaW1lID0gbWVhbihUcmF2ZWxUaW1lKQ0KICApDQpgYGANCg0KSG93IGRvIHdlIGZpeCB0aGlzPw0KDQpgYGB7cn0NCkFnZ19Ucmlwc1Blck1vZGUgJT4lIA0KICBwaXZvdF93aWRlcihpZF9jb2xzID0gZHRvX29yaWdlbiwgDQogICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBNb2RlcywgbmFtZXNfcHJlZml4ID0gIlRyaXBzXyIsIA0KICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IFRyaXBzUGVyTW9kZSwgdmFsdWVzX2ZpbGwgPSAwKQ0KYGBgDQoNCmBgYHtyfQ0KQWdnX1RyaXBzX1RyaXBzIDwtIEFnZ19Ucmlwc1Blck1vZGUgJT4lIA0KICBwaXZvdF93aWRlcihpZF9jb2xzID0gZHRvX29yaWdlbiwgDQogICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBNb2RlcywgbmFtZXNfcHJlZml4ID0gIlRyaXBzXyIsIA0KICAgICAgICAgICAgICB2YWx1ZXNfZnJvbSA9IFRyaXBzUGVyTW9kZSwgdmFsdWVzX2ZpbGwgPSAwKQ0KDQpBZ2dfVHJpcHNfVHJhdmVsVGltZSA8LSBBZ2dfVHJpcHNQZXJNb2RlICU+JSANCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGR0b19vcmlnZW4sIA0KICAgICAgICAgICAgICBuYW1lc19mcm9tID0gTW9kZXMsIG5hbWVzX3ByZWZpeCA9ICJUcmF2ZWxUaW1lXyIsDQogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gVHJhdmVsVGltZSwgdmFsdWVzX2ZpbGwgPSAwKQ0KYGBgDQoNCg0KIyMgUGVvcGxlIHRvIHpvbmVzDQoNCiMjIyBBZ2UNCg0KYGBge3J9DQpzdW1tYXJ5KFBlb3BsZSRlZGFkKQ0KYGBgDQoNCmBgYHtyfQ0KZGltKFBlb3BsZSkNClBlb3BsZSAlPiUgZmlsdGVyKGVkYWQgPT0gIjAwIikgJT4lIGRpbSgpDQpQZW9wbGUgJT4lIGZpbHRlcihlZGFkID09ICI5NyIpICU+JSBkaW0oKQ0KUGVvcGxlICU+JSBmaWx0ZXIoZWRhZCA9PSAiOTkiKSAlPiUgZGltKCkNCg0KYGBgDQpgYGB7cn0NClBlb3BsZSAlPD4lIGZpbHRlcighZWRhZCAlaW4lIGMoIjAwIiwgIjk3IiwgIjk5IikpIA0KZGltKFBlb3BsZSkNCmBgYA0KDQpgYGB7cn0NClBlb3BsZSRlZGFkID0gYXMubnVtZXJpYyhQZW9wbGUkZWRhZCkNCmBgYA0KDQoNCmBgYHtyfQ0KUGVvcGxlX1RvdGFsUGVvcGxlX0FnZSA8LSBQZW9wbGUgJT4lIGdyb3VwX2J5KGRpc3RyaXRvKSAlPiUgDQogIHN1bW1hcmlzZShUb3RhbFBlb3BsZSA9IG4oKSwNCiAgICAgICAgICAgIEFnZSA9IG1lYW4oZWRhZCwgbmEucm0gPSBUUlVFKSkNCg0KUGVvcGxlX1RvdGFsUGVvcGxlX0FnZQ0KYGBgDQoNCiMjIyBFZHVjYXRpb24NCg0KYGBge3J9DQpQZW9wbGUgJT4lIGdyb3VwX2J5KG5pdikgJT4lIHN1bW1hcmlzZShUb3RhbCA9IG4oKSkNCmBgYA0KDQoNCmBgYHtyfQ0KUGVvcGxlICU8PiUgDQogIG11dGF0ZShFZHVjYXRpb25MZXZlbCA9IHJlY29kZShuaXYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMDAiID0gIkxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMDEiID0gIkxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMDIiID0gIkxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMDMiID0gIkxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiOTkiID0gIkxvdyIsICMgSXMgdGhpcyBjb3JyZWN0Pw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjA0IiA9ICJNZWRpdW0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjA1IiA9ICJNZWRpdW0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjA2IiA9ICJNZWRpdW0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjA3IiA9ICJNZWRpdW0iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjA4IiA9ICJIaWdoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwOSIgPSAiSGlnaCIpKSANCmBgYA0KDQoNCmBgYHtyfQ0KUGVvcGxlX0VkdWNhdGlvbkxldmVsIDwtIFBlb3BsZSAlPiUgZ3JvdXBfYnkoZGlzdHJpdG8sIEVkdWNhdGlvbkxldmVsKSAlPiUgDQogIHN1bW1hcmlzZShUb3RhbCA9IG4oKSkgJT4lIGRyb3BfbmEoKSAlPiUgDQogIHBpdm90X3dpZGVyKGlkX2NvbHMgPSBkaXN0cml0bywgDQogICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBFZHVjYXRpb25MZXZlbCwgbmFtZXNfcHJlZml4ID0gIlRvdGFsRWR1Y2F0aW9uXyIsDQogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gVG90YWwsIHZhbHVlc19maWxsID0gMCkNCg0KUGVvcGxlX0VkdWNhdGlvbkxldmVsDQpgYGANCg0KDQojIyMgR2VuZGVyDQoNCnNleG8NCmBgYHtyfQ0Kc3VtbWFyeShQZW9wbGUkc2V4bykNCnN1bW1hcnkoYXMuZmFjdG9yKFBlb3BsZSRzZXhvKSkNCg0KUGVvcGxlICU8PiUgbXV0YXRlKEdlbmRlciA9IGlmX2Vsc2Uoc2V4byA9PSAxLCAiTWFsZSIsICJGZW1hbGUiKSkNCmBgYA0KYGBge3J9DQpQZW9wbGVfR2VuZGVyIDwtIFBlb3BsZSAlPiUgZ3JvdXBfYnkoZGlzdHJpdG8sIEdlbmRlcikgJT4lIA0KICBzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JSANCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGRpc3RyaXRvLCANCiAgICAgICAgICAgICAgbmFtZXNfZnJvbSA9IEdlbmRlciwgbmFtZXNfcHJlZml4ID0gIlRvdGFsXyIsDQogICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gVG90YWwsIHZhbHVlc19maWxsID0gMCkNCg0KUGVvcGxlX0dlbmRlcg0KYGBgDQoNCg0KIyMgSG9tZXMgdG8gem9uZXMNCg0KcDJfMV8xOiDCv0N1w6FudG9zIGF1dG9zIG8gY2FtaW9uZXRhcyB0aWVuZW4gcGFyYSB0cmFuc3BvcnRhcnNlIGNvdGlkaWFuYW1lbnRlPw0KcDJfMV8yOiDCv0N1w6FudGFzIG1vdG9jaWNsZXRhcyBvIG1vdG9uZXRhcyB0aWVuZW4gcGFyYSB0cmFuc3BvcnRhcnNlIGNvdGlkaWFuYW1lbnRlPw0KcDJfMV8zOiDCv0N1w6FudGFzIGJpY2ljbGV0YXMgdGllbmVuIHBhcmEgdHJhbnNwb3J0YXJzZSBjb3RpZGlhbmFtZW50ZT8NCg0KDQpgYGB7cn0NCkhvbWUgJTw+JQ0KICBzZWxlY3QoZGlzdHJpdG8sIA0KICAgICAgICAgQ2FycyA9IHAyXzFfMSwNCiAgICAgICAgIE1vdG9zID0gcDJfMV8yLA0KICAgICAgICAgQmljeWNsZXMgPSBwMl8xXzMpICU+JSANCiAgbXV0YXRlKA0KICAgIEhhc19DYXIgPSBpZl9lbHNlKENhcnMgPiAwLCAxLCAwKSwNCiAgICBIYXNfTW90b3MgPSBpZl9lbHNlKE1vdG9zID4gMCwgMSwgMCksDQogICAgSGFzX0JpY3ljbGVzID0gaWZfZWxzZShCaWN5Y2xlcyA+IDAsIDEsIDApKQ0KDQpIb21lDQpgYGANCg0KDQpgYGB7cn0NCkhvbWVzX1RvdGFsSG9tZXMgPC0gSG9tZSAlPiUgDQogIGdyb3VwX2J5KGRpc3RyaXRvKSAlPiUgDQogIHN1bW1hcmlzZShUb3RhbF9Ib21lcyA9IG4oKSkNCg0KSG9tZXNfQ2FyT3duZXJzaGlwIDwtIEhvbWUgJT4lIA0KICBmaWx0ZXIoSGFzX0NhciA9PSAxKSAlPiUgDQogIGdyb3VwX2J5KGRpc3RyaXRvKSAlPiUgDQogIHN1bW1hcmlzZShIb21lc19XaXRoX0NhcnMgPSBuKCkpDQoNCkhvbWVzX01vdG9yYmlrZU93bmVyc2hpcCA8LSBIb21lICU+JSANCiAgZmlsdGVyKEhhc19Nb3RvcyA9PSAxKSAlPiUgDQogIGdyb3VwX2J5KGRpc3RyaXRvKSAlPiUgDQogIHN1bW1hcmlzZShIb21lc19XaXRoX01vdG9yYmlrZXMgPSBuKCkpDQoNCkhvbWVzX0JpY3ljbGVPd25lcnNoaXAgPC0gSG9tZSAlPiUNCiAgZmlsdGVyKEhhc19CaWN5Y2xlcyA9PSAxKSAlPiUgDQogIGdyb3VwX2J5KGRpc3RyaXRvKSAlPiUgDQogIHN1bW1hcmlzZShIb21lc19XaXRoX0JpY3ljbGVzID0gbigpKQ0KDQpIb21lc19NZWFuX1ZlYWhpY2xlcyA8LSBIb21lICU+JSANCiAgZ3JvdXBfYnkoZGlzdHJpdG8pICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIENhcnNfbWVhbiA9IG1lYW4oQ2FycyksDQogICAgTW90b3JiaWtlc19tZWFuID0gbWVhbihCaWN5Y2xlcyksDQogICAgQmljeWNsZXNfbWVhbiA9IG1lYW4oQmljeWNsZXMpDQogICkNCmBgYA0KDQoNCiMgTWVyZ2UNCg0KYGBge3J9DQpEYXRhX0FnZyA8LSBBZ2dfVG90YWxUcmlwcyAlPiUgDQogIGxlZnRfam9pbihBZ2dfVHJpcHNfVHJpcHMpICU+JSANCiAgbGVmdF9qb2luKEFnZ19Ucmlwc19UcmF2ZWxUaW1lKSAlPiUgDQogIGxlZnRfam9pbihQZW9wbGVfVG90YWxQZW9wbGVfQWdlLCBieSA9IGMoImR0b19vcmlnZW4iID0gImRpc3RyaXRvIikpICU+JSANCiAgbGVmdF9qb2luKFBlb3BsZV9FZHVjYXRpb25MZXZlbCwgYnkgPSBjKCJkdG9fb3JpZ2VuIiA9ICJkaXN0cml0byIpKSAlPiUgDQogIGxlZnRfam9pbihQZW9wbGVfR2VuZGVyLCBieSA9IGMoImR0b19vcmlnZW4iID0gImRpc3RyaXRvIikpICU+JSANCiAgbGVmdF9qb2luKEhvbWVzX1RvdGFsSG9tZXMsIGJ5ID0gYygiZHRvX29yaWdlbiIgPSAiZGlzdHJpdG8iKSkgJT4lIA0KICBsZWZ0X2pvaW4oSG9tZXNfQ2FyT3duZXJzaGlwLCBieSA9IGMoImR0b19vcmlnZW4iID0gImRpc3RyaXRvIikpICU+JSANCiAgbGVmdF9qb2luKEhvbWVzX01vdG9yYmlrZU93bmVyc2hpcCwgYnkgPSBjKCJkdG9fb3JpZ2VuIiA9ICJkaXN0cml0byIpKSAlPiUgDQogIGxlZnRfam9pbihIb21lc19CaWN5Y2xlT3duZXJzaGlwLCBieSA9IGMoImR0b19vcmlnZW4iID0gImRpc3RyaXRvIikpICU+JSANCiAgbGVmdF9qb2luKEhvbWVzX01lYW5fVmVhaGljbGVzLCBieSA9IGMoImR0b19vcmlnZW4iID0gImRpc3RyaXRvIikpDQpgYGANCg0KQ2hlY2sgdGhlIGRpc3RyaWN0cyAqODg4KiBhbmQgKjk5OSoNCg0KYGBge3J9DQpNZXhpY29DaXR5X0hUUyA8LSBab25lcyAlPiUgDQogIGxlZnRfam9pbihEYXRhX0FnZywgYnkgPSBjKCJEaXN0cml0byIgPSAiZHRvX29yaWdlbiIpKQ0KYGBgDQoNCmBgYHtyfQ0KZGltKE1leGljb0NpdHlfSFRTKQ0KbmFtZXMoTWV4aWNvQ2l0eV9IVFMpDQpgYGANCg0KIyBDUlMNCg0KYGBge3J9DQpzdF9jcnMoTWV4aWNvQ2l0eV9IVFMpDQpgYGANCg0KW0VQU0c6MzI2MTRdKGh0dHBzOi8vZXBzZy5pby8zMjYxNCkNCltFUFNHOjQzMjZdKGh0dHBzOi8vZXBzZy5pby80MzI2KQ0KDQpgYGB7cn0NCk1leGljb0NpdHlfSFRTIDwtIHN0X3RyYW5zZm9ybShNZXhpY29DaXR5X0hUUywgNDMyNikNCmBgYA0KDQoNCiMgUHJpbnQNCg0KYGBge3J9DQpscygpDQpgYGANCmBgYHtyfQ0Kcm0oDQogIEFnZ19Ub3RhbFRyaXBzLCBBZ2dfVHJpcHNfVHJhdmVsVGltZSwgQWdnX1RyaXBzX1RyaXBzLCAgICAgICAgIA0KICBBZ2dfVHJpcHNQZXJNb2RlLCBEYXRhLCBEYXRhX0FnZywgSG9tZSwgSG9tZXNfQmljeWNsZU93bmVyc2hpcCwgSG9tZXNfQ2FyT3duZXJzaGlwLCAgICAgIA0KICBIb21lc19NZWFuX1ZlYWhpY2xlcywgSG9tZXNfTW90b3JiaWtlT3duZXJzaGlwLCBIb21lc19Ub3RhbEhvbWVzLCBNb2Rlc05hbWVzLCAgICAgICAgICAgICAgUGVvcGxlLCBQZW9wbGVfRWR1Y2F0aW9uTGV2ZWwsIFBlb3BsZV9HZW5kZXIsIFBlb3BsZV9Ub3RhbFBlb3BsZV9BZ2UsICANCiAgUHVycG9zZU5hbWVzLFRyaXBzLCBUcmlwc19GaW5hbCwgVHJpcHNTdGFnZXMsIFpvbmVzICkNCmBgYA0KDQoNCmBgYHtyfQ0KbHMoKQ0KYGBgDQoNCmBgYHtyfQ0Kc2F2ZS5pbWFnZShmaWxlID0gIk1leGljb19IVFMuUkRhdGEiKQ0KDQpzdF93cml0ZShNZXhpY29DaXR5X0hUUywgIk1leGljb0NpdHlfSFRTLnNocCIpDQoNCk1leGljb0NpdHlfSFRTX0RhdGFiYXNlIDwtIE1leGljb0NpdHlfSFRTICU+JSBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkNCk1leGljb0NpdHlfRGlzdHJpY3RzIDwtIE1leGljb0NpdHlfSFRTICU+JSBzZWxlY3QoRGlzdHJpdG8pDQoNCg0Kd3JpdGVfZGVsaW0oTWV4aWNvQ2l0eV9IVFNfRGF0YWJhc2UsICJNZXhpY29DaXR5X0hUU19EYXRhYmFzZS5jc3YiLCBkZWxpbSA9ICI7IikNCnN0X3dyaXRlKE1leGljb0NpdHlfRGlzdHJpY3RzLCAiTWV4aWNvQ2l0eV9EaXN0cmljdHMuc2hwIikNCmBgYA0KDQo=