Données TELLi

Ce site a pour but de référencer un ensemble de données spatiales utilisé dans des analyses spatiales.

GEOFER

Gares

gares <- sf::st_read("C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/GEOFER/gares_2154.gpkg")
# Packages ----
pacman::p_load(sf, dplyr, mapview,tmap)

# Chargement de la couche 
lignes_CEREMA <- sf::st_read('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/GEOFER/lignes-par-statut_queEdC_modifOT.gpkg')
## Reading layer `lignes-par-statut_queEdC_modifOT' from data source 
##   `C:\Users\otheureaux\Documents\OT\RAILENIUM\BDD_TELLI\GEOFER\lignes-par-statut_queEdC_modifOT.gpkg' 
##   using driver `GPKG'
## Simple feature collection with 44 features and 20 fields
## Geometry type: LINESTRING
## Dimension:     XY
## Bounding box:  xmin: 213525.7 ymin: 6239088 xmax: 1023721 ymax: 7048345
## Projected CRS: RGF93 v1 / Lambert-93
lignes_CEREMA_2154 <- sf::st_transform(lignes_CEREMA, 2154)

# sélection de la ligne de travail
# ICI inscrire le nom de la ligne à étudier
names(lignes_CEREMA_2154)
##  [1] "code_ligne"   "lib_ligne"    "statut"       "rg_troncon"   "pkd"         
##  [6] "pkf"          "idgaia"       "x_d_l93"      "y_d_l93"      "x_f_l93"     
## [11] "y_f_l93"      "x_d_wgs84"    "y_d_wgs84"    "x_f_wgs84"    "y_f_wgs84"   
## [16] "c_geo_d"      "c_geo_f"      "geo_point_2d" "étude.de.cas" "Numéro.EdC"  
## [21] "geom"
table(lignes_CEREMA_2154$étude.de.cas)
## 
## Bayonne-St jean Pied de port   Besançon-La chaux de Fonds 
##                            2                            2 
##          Béziers-Neussargues           Bordeaux-Le Verdon 
##                            1                            4 
##              Clermont-Volvic            Deauville-Cabourg 
##                            3                            1 
##                étoile St Pol            Limoges-Angoulême 
##                            3                            4 
##            Marseille-Miramas Metzeral - Colmar - Fribourg 
##                            3                            1 
##       Nantes-StGilles-Pornic       Nimes - le Grau du Roi 
##                            5                            2 
##     Paimpol-Guingamp-Carhaix                Reims-Epernay 
##                            3                            1 
##        Rennes- Chateaubriant        St Gervais-Vallorcine 
##                            2                            1 
##          Tours-Chinon-Loches 
##                            5
ligne_filter <- lignes_CEREMA_2154 %>% 
  filter(étude.de.cas == 'étoile St Pol') # ICI inscrire le nom de la ligne à étudier
mapview(ligne_filter)
# Création de l'emprise de la zone d'étude ----
zone_etude <- st_as_sf(st_buffer(st_union(ligne_filter), 50))
mapview(zone_etude)
gares <- sf::st_read("C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/GEOFER/gares_2154.gpkg")
## Reading layer `gares' from data source 
##   `C:\Users\otheureaux\Documents\OT\RAILENIUM\BDD_TELLI\GEOFER\gares_2154.gpkg' 
##   using driver `GPKG'
## Simple feature collection with 3489 features and 65 fields
## Geometry type: POINT
## Dimension:     XY
## Bounding box:  xmin: 147139.3 ymin: 6147218 xmax: 1079190 ymax: 7108435
## Projected CRS: RGF93 v1 / Lambert-93
names(gares)
##  [1] "commune"                    "code_com"                  
##  [3] "insee_dep"                  "code_uic"                  
##  [5] "nom_gare"                   "pop_p15_2017"              
##  [7] "pop_p30_2017"               "pop_v10_2017"              
##  [9] "pop_p15_2020"               "pop_p30_2020"              
## [11] "pop_v10_2020"               "eleve_p15_2015"            
## [13] "eleve_p30_2015"             "eleve_v10_2015"            
## [15] "eleve_p15_2016"             "eleve_p30_2016"            
## [17] "eleve_v10_2016"             "eleve_p15_2017"            
## [19] "eleve_p30_2017"             "eleve_v10_2017"            
## [21] "eleve_p15_2018"             "eleve_p30_2018"            
## [23] "eleve_v10_2018"             "eleve_p15_2019"            
## [25] "eleve_p30_2019"             "eleve_v10_2019"            
## [27] "salarie_p15_2017"           "salarie_p30_2017"          
## [29] "salarie_v10_2017"           "voy_2014"                  
## [31] "voy_2015"                   "voy_2016"                  
## [33] "voy_2017"                   "voy_2018"                  
## [35] "voy_2019"                   "voy_2020"                  
## [37] "chambre_emplacement_p15"    "chambre_emplacement_p30"   
## [39] "loisirs_p15"                "loisirs_p30"               
## [41] "achats_p15"                 "achats_p30"                
## [43] "restauration_p15"           "restauration_p30"          
## [45] "sante_p15"                  "sante_p30"                 
## [47] "sports_p15"                 "sports_p30"                
## [49] "nombre_arrets_en_gare_2017" "nombre_arrets_en_gare_2019"
## [51] "statut_gare"                "nom_aom"                   
## [53] "voy_2021"                   "voy_2022"                  
## [55] "salarie_p30_2021"           "Car"                       
## [57] "TGV"                        "TER"                       
## [59] "Intercités"                 "nb_arret_total"            
## [61] "salarie_p15_2021"           "Automates.TGV.INTERCITES"  
## [63] "Automates.TER"              "Poste.de.vente.guichet"    
## [65] "Libre.Service.Assisté"      "geom"
gares_select <- gares %>% 
  select(nom_gare, voy_2022)
mapview(gares_select)
gares_select_inter <- sf::st_intersection(gares_select,zone_etude)
## Warning: attribute variables are assumed to be spatially constant throughout
## all geometries
mapview(gares_select_inter)
gares_select_inter_drop <- st_drop_geometry(gares_select_inter)
knitr::kable(
  gares_select_inter_drop,
  format = "pipe",
  col.names = c("Gares", "Voyageurs 2022"),
  digits = 2
)
Gares Voyageurs 2022
62 Beutin 0
169 Wavrans 0
878 Savy Berlette 23412
1057 Vis à Marles 17063
1095 Fouquereuil 1438
1188 Saint-Pol sur Ternoise 145944
1263 Auchy lès Hesdin 15943
1317 Maresquel 2151
1394 Frévin Capelle 2396
1397 Aubigny en Artois 21509
1705 Béthune 1601485
1783 Anvin 7494
1893 Hesdin 45253
1928 Brimeux 2929
2122 Etaples-le Touquet 533197
2130 Blangy sur Ternoise 1373
2341 Tincques 7677
2349 Pernes-Camblain 14043
2819 Calonne-Ricouart 30702
3004 Beaurainville 22374
3259 Aubin Saint-Vaast 1691
3343 Montreuil sur Mer 41868
3453 Maroeuil 4074

Lignes

lignes <- sf::st_read("C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/GEOFER/reseau_ferroviaire.geojson")

INSEE

  • Population au niveau de la commune

La population est présente dans la couche des communes :

communes <- sf::st_read("C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/COMMUNES/commune.shp")


  • Population par carreaux 200m x 200m
##  Données carroyées 2019 ----
carreaux_200_2019 <- st_read('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/CARREAU/Filosofi2019_carreaux_200m_gpkg/carreaux_200m_met.gpkg')
  • Emploi-Population active en 2020

Recensement de la population - Base des principaux indicateurs

communes <- sf::st_read('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/COMMUNES/COMMUNE.shp')
base_emploi <- read.csv2('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/base-cc-emploi-pop-active-2020_csv/base-cc-emploi-pop-active-2020_v2.CSV')
names(communes)
names(base_emploi)
communes <- communes %>% 
  rename(CODGEO = INSEE_COM)
communes_join <- right_join(communes, base_emploi, by='CODGEO')
names(communes_join)
communes_select <- communes_join %>% 
  dplyr::select(ID, NOM, CODGEO, P20_ACT1564)


* Capacité des communes en hébergement touristique en 2023

communes <- sf::st_read('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/COMMUNES/COMMUNE.shp')
base_tourisme <- read.csv2('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/base-cc-tourisme-2023-geo2023-CSV/base-cc-tourisme-2023-geo2023.csv')
names(communes)
names(base_tourisme)
communes <- communes %>% 
  rename(CODGEO = INSEE_COM)
communes_join <- right_join(communes_select, base_tourisme, by='CODGEO')
names(communes_join)
communes_select <- communes_join %>% 
  dplyr::select(ID, NOM, CODGEO, 
                P20_ACT1564, 
                POPULATION, 
                CPGE23 # Nombre d'emplacements de camping en 2023
                )


  • Capacité des communes en nombre d’élèves
# Effectifs d’élèves par niveau, sexe, langues vivantes 1 et 2 les plus fréquentes, par collège – Date d’observation au début du mois d’octobre chaque année
base_eleves_colleges <- read.csv2('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/ELEVES/fr-en-college-effectifs-niveau-sexe-lv.csv')
names(base_eleves_colleges)
base_eleves_colleges_2021 <- base_eleves_colleges %>% 
  filter(Rentrée.scolaire == '2021') %>% 
  rename(numero_ets = Numéro.du.collège) %>% 
  select(Rentrée.scolaire, Région.académique,Académie,
         Département, Commune,numero_ets,
         Dénomination.principale,Patronyme, Secteur,REP,
         REP..,Nombre.d.élèves.total..nombre.d.élèves.dans.les.formations.du.1er.cycle.du.2nd.degré.et.non.du.nombre.total.d.élèves.inscrits.dans.l.établissement..les.DIMA.et.les.dispositifs.relais.sont.exclus.)
names(base_eleves_colleges_2021)
base_eleves_colleges_2021_cut <- right_join(localisation_colleges_lycees_cut,
                                            base_eleves_colleges_2021,
                                            by = 'numero_ets')
base_eleves_colleges_2021_cut <- base_eleves_colleges_2021_cut %>% 
  filter(!st_is_empty(geometry)) %>% 
  rename(nb_eleves = Nombre.d.élèves.total..nombre.d.élèves.dans.les.formations.du.1er.cycle.du.2nd.degré.et.non.du.nombre.total.d.élèves.inscrits.dans.l.établissement..les.DIMA.et.les.dispositifs.relais.sont.exclus.) %>% 
  select(numero_ets, appellation, nb_eleves)
names(base_eleves_colleges_2021_cut)


# Effectifs d’élèves par niveau, sexe, langues vivantes 1 et 2 les plus fréquentes, par lycée professionnel – Date d’observation au début du mois d’octobre chaque année
base_eleves_lycees_pro <- read.csv2('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/ELEVES/fr-en-lycee_pro-effectifs-niveau-sexe-lv.csv')
names(base_eleves_lycees_pro)
base_eleves_lycees_pro_2021 <- base_eleves_lycees_pro %>% 
  filter(Rentrée.scolaire == '2021') %>% 
  rename(numero_ets = Numéro.du.lycée) %>% 
  select(Rentrée.scolaire, Région.académique,
         Académie, Département,Commune, numero_ets,                    Dénomination.principale,  Patronyme, Secteur,    
         Nombre.d.élèves)
names(base_eleves_lycees_pro_2021)
base_eleves_lycees_pro_2021_cut <- right_join(localisation_colleges_lycees_cut,
                                base_eleves_lycees_pro_2021,
                                            by = 'numero_ets')
base_eleves_lycees_pro_2021_cut <- base_eleves_lycees_pro_2021_cut %>% 
  filter(!st_is_empty(geometry)) %>% 
  rename(nb_eleves = Nombre.d.élèves) %>% 
  select(numero_ets, appellation, nb_eleves)
names(base_eleves_lycees_pro_2021_cut)

# Effectifs d’élèves par niveau, sexe, langues vivantes 1 et 2 les plus fréquentes, par lycée d’enseignement général et technologique – Date d’observation au début du mois d’octobre chaque année
base_eleves_lycees_gt <- read.csv2('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/ELEVES/fr-en-lycee_gt-effectifs-niveau-sexe-lv.csv')
names(base_eleves_lycees_gt)
base_eleves_lycees_gt_2021 <- base_eleves_lycees_gt %>% 
  filter(Rentrée.scolaire == '2021') %>% 
  rename(numero_ets = Numéro.du.lycée) %>% 
  select(Rentrée.scolaire,  
         Région.académique,                                            Académie       ,                                              Département,  Commune, numero_ets,
         Dénomination.principale, Patronyme,Secteur,    
         Nombre.d.élèves)
names(base_eleves_lycees_gt_2021)
base_eleves_lycees_gt_2021_cut <- right_join(localisation_colleges_lycees_cut,
                                             base_eleves_lycees_gt_2021,
                                              by = 'numero_ets')
names(base_eleves_lycees_gt_2021_cut)
base_eleves_lycees_gt_2021_cut <- base_eleves_lycees_gt_2021_cut %>% 
  filter(!st_is_empty(geometry)) %>% 
  rename(nb_eleves = Nombre.d.élèves) %>% 
  select(numero_ets, appellation, nb_eleves)
names(base_eleves_lycees_gt_2021_cut)


# Effectifs des élèves en voie professionnelle ou BTS par niveau, sexe et lycée professionnel – Date d’observation au début du mois d’octobre chaque année
voie_pro_bts <- read.csv2('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/ELEVES/fr-en-lycee_pro-effectifs-niveau-sexe-mef.csv')
names(voie_pro_bts)
voie_pro_bts_2021 <- voie_pro_bts %>% 
  filter(Rentrée.scolaire == '2021') %>% 
  rename(numero_ets = Numéro.d.établissement) %>% 
  select(Rentrée.scolaire,
         Académie.2020,
         Académie.2020.Lib.L,  
         numero_ets,
         Patronyme,  
         Adresse.condensée,
         Code.postal,
         Commune.d.implantation,
         Nombre.d.élèves...Total)                           
names(base_eleves_lycees_pro_2021)
voie_pro_bts_2021_cut <- right_join(localisation_colleges_lycees_cut,
                                             voie_pro_bts_2021,
                                             by = 'numero_ets')
voie_pro_bts_2021_cut <- voie_pro_bts_2021_cut %>% 
  filter(!st_is_empty(geometry))
# Groupement des données par 'numero_ets' et somme de 'nb_eleves'
voie_pro_bts_2021_cut_sum <- voie_pro_bts_2021_cut %>%
  group_by(numero_ets, appellation) %>%
  summarise(nb_eleves_total = sum(Nombre.d.élèves...Total)) %>% 
  rename(nb_eleves = nb_eleves_total)

donnees_all <- rbind(base_eleves_colleges_2021_cut,
base_eleves_lycees_pro_2021_cut,
base_eleves_lycees_gt_2021_cut,
voie_pro_bts_2021_cut_sum)

nb_eleves_colleges_lycees_bts <- donnees_all %>%
  group_by(numero_ets, appellation) %>%
  summarise(nb_eleves_total = sum(nb_eleves))

comment récupérer le nombre d’élèves ?





BDTOPO

  • PARKINGS
pacman::p_load(sf,dplyr)
c <- "G:/Mon Drive/BDD/parkings"
c <- "C:/Users/Othaureau/Documents/BDD" # donnees sur PC LVMT
parkings <- list.files(c, 
                      full.names = T, 
                      pattern = "EQUIPEMENT_DE_TRANSPORT.shp", 
                      recursive = T) # inclure tous les sous-dossiers
for(i in 1:13) {
parkings_ <- sf::st_read(parkings[i])
parkings_ <- parkings_ %>% 
  dplyr::filter(NATURE == 'Parking') 

parkings_ <-  st_make_valid(parkings_) %>% 
  dplyr::select(ID, NATURE, NAT_DETAIL, geometry)

parkings_centroid <- sf::st_centroid(parkings_)
sf::st_write(parkings_centroid, paste0("C:/Users/Othaureau/Documents/BDD/PARKING_CENTROID/PARKING_CENTROID_R",i,".gpkg"))
}

Base national des lieux de stationnement Base Nationale des Lieux de Stationnement :
Cette base de données n’est pas représentative de l’ensemble des lieux de stationnement hors voirie. Elle n’est pas forcément à jour car sa consolidation n’est pas automatisée.
La base des stationnements permet de regrouper en un unique fichier consolidé l’ensemble de l’offre de stationnement en France, dans un format standard et unifié. Cette standardisation des données facilite grandement le travail d’intégration de ces données par des services réutilisateurs.

Ce dataset comprend notamment : * la géolocalisation des parkings
* la hauteur maximale des véhicules pouvant pénétrer dans au moins un espace du parking
* le nombre de places dans le parking (parfois déclinées en places réservées pour les abonnés, les personnes à mobilité réduite, pour les voitures électriques, les véhicules à deux-roues motorisés et non-motorisés)
* le code SIRET de l’établissement gestionnaire du parking
* le caractère gratuit ou payant du parking (parfois un détail est apporté sur le prix horaire ou le prix d’un abonnement mensuel/annuel)

lien.

Réseau pédestre (BDTOPO)

Je sélectionne le fichier shapefile (TRONCON_DE_ROUTE.shp) correspondant à la région à étudier.

Cette couche contient des informations sur :

  • les routes goudronnées : type autoroutier, route à 2 chaussées, route à 1 chaussée, bretelle et rond-point
  • les routes non goudronnées : chemins, routes empierrées, sentiers
  • les bacs ou liaisons maritimes
  • les escaliers

Pour le réseau piéton nous conservons l’ensemble de ces données.

Réseau Voiture (BDTOPO)

Pour le réseau voiture nous ne conservons que les routes goudronnées : * type autoroutier * route à 2 chaussées * route à 1 chaussée * bretelle * rond-point

c <- "D:/"
c <- "C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/BDTOPO_SELECT/" # donnees sur PC LVMT
routes <- list.files(c, 
                       full.names = T, 
                       pattern = "TRONCON_DE_ROUTE.shp", 
                       recursive = T) # inclure tous les sous-dossiers

for(i in 1:13) {
routes_ <- sf::st_read(routes[i])

routes_filter <- routes_ %>% 
  dplyr::filter(NATURE %in% c('Route à 1 chaussée', 
                              'Route à 2 chaussées',
                              'Type autoroutier',
                              'Bretelle',
                              'Rond-point'
                              ))
routes_filter_select <- routes_filter %>% 
  sf::st_make_valid() %>% 
  dplyr::select(ID, NB_VOIES, geometry)
st_write(routes_filter_select, 
         paste0('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/TRONCON_DE_ROUTE/TRONCON_DE_ROUTE_R',i,'_V2.gpkg'))
}

Nombre d’intersections du réseau voiture

reseau_voiture <- sf::st_read('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/TRONCON_DE_ROUTE/TRONCON_DE_ROUTE_R8_V2.gpkg') # région Bretagne


## 05 nombre d'intersection du réseau routier 

# Calcul de la longueur du réseau voiture
all_sum <- list()

# Initialisation du compteur
compteur <- 0

for(i in 1:nrow(all_isochrones)) {
  reseau_voiture_intersection <- st_intersection(reseau_voiture, all_isochrones[i,])

  # Vérifiez si l'intersection est vide
  if (nrow(reseau_voiture_intersection) > 0) {
    
    # Calcul du nombre d'intersection du réseau voiture pour chaque isochrone
    intersections <- st_intersection(reseau_voiture_intersection)
    
    # Filtrage des Points Uniques
    intersections_points <- intersections[st_dimension(intersections) == 0, ]
    
    # Comptage des Intersections
    nombre_intersections <- length(st_geometry(intersections_points))
    
    sum <- data.frame(as.numeric(nombre_intersections))
    sum <- cbind(sum, unique(reseau_voiture_intersection$point.ID_number))
    
    names(sum) <- c("nb_intersections", "ID_number")
  } 
  else {
    
    # Si l'intersection est vide, définissez la longueur à 0 et ID_number à NA
    sum <- data.frame(0, NA)
    names(sum) <- c("nb_intersections", "ID_number")
  }

  all_sum[[i]] <- sum
  
  # Incrémenter le compteur après chaque itération réussie
  compteur <- compteur + 1
  
  # Afficher le progrès si nécessaire
  if (compteur %% 100 == 0) {  # Affiche le progrès toutes les 10 itérations
    message("Nombre d'itérations complétées : ", compteur)
  }  
}

# Afficher le nombre total d'itérations à la fin
message("Nombre total d'itérations : ", compteur)

all_sum_dt <- do.call(rbind, all_sum)

Zones de végétation (BDTOPO)

Fichier BDTOPO - Zone de végétation





OSM

Ronds-points

Beyondthemap
Source : https://www.dropbox.com/s/l0psz2h3a0rurh5/Europe_roundabouts_2018.zip?dl=0


Pistes cyclables

Extraction des pistes cyclables avec le package R OSM Extract

pacman::p_load(sf, dplyr, mapview, httr, osmextract)

region_osm <- c("Midi-Pyrenees", "Provence Alpes-Cote-d'Azur", "Champagne Ardenne","Bourgogne", 
                "Franche Comte", "Auvergne", "Alsace", "Lorraine", 
                "Picardie", "Bretagne", "Rhone-Alpes", "Languedoc-Roussillon", 
                "Ile-de-France", "Centre", "Nord-Pas-de-Calais", "Corse",
                "Basse-Normandie", "Haute-Normandie", "Pays de la Loire", "Aquitaine",
                "Limousin", "Poitou-Charentes")

pistes_cyclables <- tibble()

for (i in 1:22) {

print(paste("Traitement de la région numéro", i))
  
# couche 1 : highway / cycleway # When cycleway is drawn as its own way 
highway_cycleway = osmextract::oe_get(region_osm[i],
                                        layer = "lines",
                                        extra_tags = "highway", 
                                        query = "SELECT * FROM lines WHERE highway IN ('cycleway')",
                                        quiet = FALSE)
names(highway_cycleway)

highway_cycleway_light <- highway_cycleway %>% 
  select(osm_id, geometry)

# couche 2 : bicycle / designated # Where a way has been specially designated (typically by a government) for bicycle use
bicycle_designated = osmextract::oe_get(region_osm[i],
                                        layer = "lines",
                                        extra_tags = "bicycle", 
                                        query = "SELECT * FROM lines WHERE bicycle IN ('designated')",
                                        quiet = FALSE)
names(bicycle_designated)

bicycle_designated_light <- bicycle_designated %>% 
  select(osm_id,geometry)

# couche 3 : cycleway / lane # Cycleway tagged on the main roadway or lane, A lane is a route that lies within the roadway
cycleway_lane = osmextract::oe_get(region_osm[i],
                                        layer = "lines",
                                        extra_tags = "cycleway", 
                                        query = "SELECT * FROM lines WHERE cycleway IN ('lane')",
                                        quiet = FALSE)
names(cycleway_lane)

cycleway_lane_light <- cycleway_lane %>% 
  select(osm_id,geometry)


pistes_cyclables_osm_all <- rbind(data.frame(highway_cycleway_light), 
                                  data.frame(bicycle_designated_light),
                                  data.frame(cycleway_lane_light))

pistes_cyclables <- rbind(data.frame(pistes_cyclables_osm_all), pistes_cyclables)
}

commerces_osm_all_sf <- st_as_sf(pistes_cyclables)
# st_write(commerces_osm_all_sf, paste0("processed_data/pistes_cyclables_", "2",".gpkg"))



Figure 1 : highway / cycleway # When cycleway is drawn as its own way

Figure 2 : bicycle / designated # Where a way has been specially designated (typically by a government) for bicycle use


Figure 3 : cycleway / lane # Cycleway tagged on the main roadway or lane, A lane is a route that lies within the roadway

SIRENE

pacman::p_load(dplyr)


base_sirene <- read.csv2("C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/SIRENE/StockEtablissement_utf8/StockEtablissement_utf8.csv", 
                         sep = ",")
names(base_sirene)

# Filtre sur les établissements actifs
base_sirene_actif <- base_sirene %>% 
  dplyr::filter(etatAdministratifEtablissement == "A")

rm(base_sirene)



list.files('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/SIRENE/geolocalisationetablissement-sirene-pour-etudes-statistiques-du-21-novembre-2023')

# Chargement du fichier géolocalisé
sirene_geoloc <- read.csv("C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/SIRENE/geolocalisationetablissement-sirene-pour-etudes-statistiques-du-21-novembre-2023/GeolocalisationEtablissement_Sirene_pour_etudes_statistiques_utf8.csv", 
                          sep=";", 
                          dec=".", 
                          header = T)


# Jointure Géolocalisation / code activités : **jointure par le SIRET**
stock_geoloc <- left_join(base_sirene_actif, 
                          sirene_geoloc, 
                          by = c("siret"))

# Suppression des adresses sans coordonnées
geoloc_sans_NA <- stock_geoloc %>% 
  filter(!is.na(x_longitude))

# Création d'une variable département
geoloc_sans_NA$departement <- geoloc_sans_NA$codePostalEtablissement %/% 1000*1000

rm(base_sirene_actif)
rm(sirene_geoloc)
rm(stock_geoloc)

getwd()
# save.image("C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/MonEnvironnement.RData")
# Me permet de charger la base SIRENE des établissements actifs
# load("C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/MonEnvironnement.RData")


names(geoloc_sans_NA)


# Filtre sur les  loisirs
base_sirene_loisirs <- geoloc_sans_NA %>%
  dplyr::filter(activitePrincipaleEtablissement %in% c(
      "90.01Z",# Arts du spectacle vivant
      "90.04Z",# Gestion de salles de spectacles 
      "93.21Z",# Activités des parcs d’attractions et parcs à thèmes
      "93.29Z",# Autres activités récréatives et de loisirs
      "91.01Z",# Gestion des bibliothèques et des archives
      "91.02Z",# Gestion des musées 
      "91.03Z",# Gestion des sites et monuments historiques et des attractions touristiques similaires 
      "91.04Z",# Gestion des jardins botaniques et zoologiques et des réserves naturelles 
      "92.00Z" # Organisation de jeux de hasard et d’argent
    )
  )


getwd()
list.files('processed_data')
sf::st_write(base_sirene_loisirs, 'processed_data/base_sirene_loisirs.gpkg')

# déplacé ici : C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/SIRENE/

# Filtre sur santé
base_sirene_sante <- geoloc_sans_NA %>%
  dplyr::filter(
    activitePrincipaleEtablissement %in% c(
      "86.23Z",# Pratique dentaire 
      "86.21Z",# Activité des médecins généralistes
      "86.22A",# Activités de radiodiagnostic et de radiothérapie
      "86.22B",# Activités chirurgicales 
      "86.22C",# Autres activités des médecins spécialistes
      "86.10Z" # Activités hospitalières 
    )
  )

sf::st_write(base_sirene_sante, 'processed_data/base_sirene_sante.gpkg')

# déplacé ici : C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/SIRENE/

# Filtre sur commerces
base_sirene_commerces <- geoloc_sans_NA %>%
  dplyr::filter(
    activitePrincipaleEtablissement %in% c(
      "10.71C",# Boulangerie et boulangerie-pâtisserie
      "10.71D",# Pâtisserie 
      "10.71B",# Cuisson de produits de boulangerie
      "10.13B",# Charcuterie 
      "47.21Z",# Commerce de détail de fruits et légumes en magasin spécialisé 
      "47.11A",# Commerce de détail de produits surgelés
      "47.11B",# Commerce d’alimentation générale
      "47.11C",# Supérettes 
      "47.11D",# Supermarchés 
      "47.11E",# Magasins multi-commerces
      "47.11F",# Hypermarchés 
      "47.19A",# Commerce de détail non alimentaire 
      "47.19B",# Autres commerces de détail en magasin non spécialisé
      "47.71Z",# Commerce de détail d’habillement en magasin spécialisé
      "47.72A",# Commerce de détail de la chaussure
      "47.72B" # Commerce de détail de maroquinerie et d’articles de voyage
    )
  )

sf::st_write(base_sirene_commerces, 'processed_data/base_sirene_commerces.gpkg')

# déplacé ici : C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/SIRENE/


# Filtre sur restauration
base_sirene_restauration <- geoloc_sans_NA %>%
  dplyr::filter(
    activitePrincipaleEtablissement %in% c(
      "56.30Z",# Débits de boisson 
      "56.10A",# Restauration traditionnelle 
      "56.10B",# Cafétérias et autres libres-services 
      "56.10C" # Restauration de type rapide
    )
  )

sf::st_write(base_sirene_restauration, 'processed_data/base_sirene_restauration.gpkg')

# déplacé ici : C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/SIRENE/


# Filtre sur sport
base_sirene_sport <- geoloc_sans_NA %>%
  dplyr::filter(
    activitePrincipaleEtablissement %in% c(
      "93.11Z",# Gestion d’installations sportives
      "93.13Z" # Activités des centres de culture physique
    )
  )

sf::st_write(base_sirene_sport, 'processed_data/base_sirene_sport.gpkg')

# déplacé ici : C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/SIRENE/

# Filtre sur tout
base_sirene_loisirs <- geoloc_sans_NA %>%
  dplyr::filter(
    activitePrincipaleEtablissement %in% c(
      "90.01Z",# Arts du spectacle vivant
      "90.04Z",# Gestion de salles de spectacles 
      "93.21Z",# Activités des parcs d’attractions et parcs à thèmes
      "93.29Z",# Autres activités récréatives et de loisirs
      "91.01Z",# Gestion des bibliothèques et des archives
      "91.02Z",# Gestion des musées 
      "91.03Z",# Gestion des sites et monuments historiques et des attractions touristiques similaires 
      "91.04Z",# Gestion des jardins botaniques et zoologiques et des réserves naturelles 
      "92.00Z",# Organisation de jeux de hasard et d’argent  
      "86.23Z",# Pratique dentaire 
      "86.21Z",# Activité des médecins généralistes
      "86.22A",# Activités de radiodiagnostic et de radiothérapie
      "86.22B",# Activités chirurgicales 
      "86.22C",# Autres activités des médecins spécialistes
      "86.10Z",# Activités hospitalières 
      "10.71C",# Boulangerie et boulangerie-pâtisserie
      "10.71D",# Pâtisserie 
      "10.71B",# Cuisson de produits de boulangerie
      "10.13B",# Charcuterie 
      "47.21Z",# Commerce de détail de fruits et légumes en magasin spécialisé 
      "47.11A",# Commerce de détail de produits surgelés
      "47.11B",# Commerce d’alimentation générale
      "47.11C",# Supérettes 
      "47.11D",# Supermarchés 
      "47.11E",# Magasins multi-commerces
      "47.11F",# Hypermarchés 
      "47.19A",# Commerce de détail non alimentaire 
      "47.19B",# Autres commerces de détail en magasin non spécialisé
      "47.71Z",# Commerce de détail d’habillement en magasin spécialisé
      "47.72A",# Commerce de détail de la chaussure
      "47.72B",# Commerce de détail de maroquinerie et d’articles de voyage
      "56.30Z",# Débits de boisson 
      "56.10A",# Restauration traditionnelle 
      "56.10B",# Cafétérias et autres libres-services 
      "56.10C",# Restauration de type rapide
      "93.11Z",# Gestion d’installations sportives
      "93.13Z" # Activités des centres de culture physique
      
    )
  )

SNCF

Lien vers la source : Données Open Data SNCF

liste_des_passages_a_niveau <- sf::st_read('data/liste-des-passages-a-niveau/liste-des-passages-a-niveau.shp')

MNT

Données recueilles pour le calcul de la pente moyenne dans chaque isochrone.

# Données MNT IGN
ras_lst <- list.files('C:/Users/otheureaux/Downloads/RGEALTI_2-0_5M_ASC_LAMB93-IGN69_D062_2021-09-20/RGEALTI_2-0_5M_ASC_LAMB93-IGN69_D062_2021-09-20/RGEALTI/', 
                      full.names = T, 
                      pattern = ".asc$", 
                      recursive = T) # sélection de toutes les dalles
head(ras_lst)
terra::vrt(ras_lst, 
           "C:/Users/otheureaux/Downloads/new.vrt", # name of virtual raster, 
           overwrite = T) # création du raster virtuel
ras <- raster::raster("C:/Users/otheureaux/Downloads/new.vrt")
raster::crs(ras) <- "EPSG:2154"

mapview(ras)
# Calcul du nombre de ronds-points
all_sum <- list()

# Initialisation du compteur
compteur <- 0

for(i in 1:nrow(all_isochrones)) {
  mnt_intersection <- raster::crop(ras, all_isochrones[i,])
  a <- raster::mask(mnt_intersection, all_isochrones[i,])
  # mapview(a)
  
  b <- qgis_run_algorithm("native:slope", 
    INPUT = a, 
    OUTPUT = paste('C:/Users/otheureaux/Documents/OT/RAILENIUM/DONNEES_CARTO/raster/mnt/', 
                   i, 
                   ".tif"))
  b_ras <- raster::raster(paste('C:/Users/otheureaux/Documents/OT/RAILENIUM/DONNEES_CARTO/raster/mnt/', 
                        i, 
                        ".tif"))
  
  mean <- raster::cellStats(b_ras, 
                    stat = "mean", 
                    na.rm = TRUE)
  
    sum <- data.frame(pente_moyenne = mean, 
                      ID_number = all_isochrones$point.ID_number[i])
    
  
  
  all_sum[[i]] <- sum
  
  # Incrémenter le compteur après chaque itération réussie
  compteur <- compteur + 1
  
  # Afficher le progrès si nécessaire
  if (compteur %% 10 == 0) {  # Affiche le progrès toutes les 10 itérations
    message("Nombre d'itérations complétées : ", compteur)
  }  
}

PNR

Pour plus de détails sur la couche des PNR vous pouvez consulter ce lien.

PNR <- sf::st_read('C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/france_pnr_polygon/france_pnr_polygonPolygon.shp')  

EMPRISES

  • France
emprise_france <- sf::st_read("C:/Users/otheureaux/Documents/OT/DECOUPAGES_FR/FRANCE_METRO_2154.gpkg")
  • Régions
regions_FR <- sf::st_read("C:/Users/otheureaux/Documents/OT/DECOUPAGES_FR/REGION.shp")
  • Départements France
departements <- sf::st_read("C:/Users/otheureaux/Documents/OT/DECOUPAGES_FR/DEPARTEMENT.shp")
  • Communes France
communes <- sf::st_read("C:/Users/otheureaux/Documents/OT/RAILENIUM/BDD_TELLI/COMMUNES/commune.shp")

Citation

Pour citer ces travaux :

Olivier Theureaux. n.d. “Tutoriels R dans le cadre d’une mission de géomaticien au sein du LVMT”

LS0tDQp0aXRsZTogIiINCm91dHB1dDogaHRtbF9kb2N1bWVudA0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCiMgRG9ubsOpZXMgVEVMTGkgey50YWJzZXQgLnVubnVtYmVyZWR9DQoNCkNlIHNpdGUgYSBwb3VyIGJ1dCBkZSByw6lmw6lyZW5jZXIgdW4gZW5zZW1ibGUgZGUgZG9ubsOpZXMgc3BhdGlhbGVzIHV0aWxpc8OpIGRhbnMgZGVzIGFuYWx5c2VzIHNwYXRpYWxlcy4gIA0KDQoNCg0KIyMgR0VPRkVSDQoNCg0KKipHYXJlcyoqDQpgYGB7ciwgZXZhbD1GfQ0KZ2FyZXMgPC0gc2Y6OnN0X3JlYWQoIkM6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvR0VPRkVSL2dhcmVzXzIxNTQuZ3BrZyIpDQpgYGANCg0KDQpgYGB7ciwgb3V0LndpZHRoPScxMDAlJ30NCiMgUGFja2FnZXMgLS0tLQ0KcGFjbWFuOjpwX2xvYWQoc2YsIGRwbHlyLCBtYXB2aWV3LHRtYXApDQoNCiMgQ2hhcmdlbWVudCBkZSBsYSBjb3VjaGUgDQpsaWduZXNfQ0VSRU1BIDwtIHNmOjpzdF9yZWFkKCdDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9SQUlMRU5JVU0vQkREX1RFTExJL0dFT0ZFUi9saWduZXMtcGFyLXN0YXR1dF9xdWVFZENfbW9kaWZPVC5ncGtnJykNCmxpZ25lc19DRVJFTUFfMjE1NCA8LSBzZjo6c3RfdHJhbnNmb3JtKGxpZ25lc19DRVJFTUEsIDIxNTQpDQoNCiMgc8OpbGVjdGlvbiBkZSBsYSBsaWduZSBkZSB0cmF2YWlsDQojIElDSSBpbnNjcmlyZSBsZSBub20gZGUgbGEgbGlnbmUgw6Agw6l0dWRpZXINCm5hbWVzKGxpZ25lc19DRVJFTUFfMjE1NCkNCnRhYmxlKGxpZ25lc19DRVJFTUFfMjE1NCTDqXR1ZGUuZGUuY2FzKQ0KbGlnbmVfZmlsdGVyIDwtIGxpZ25lc19DRVJFTUFfMjE1NCAlPiUgDQogIGZpbHRlcijDqXR1ZGUuZGUuY2FzID09ICfDqXRvaWxlIFN0IFBvbCcpICMgSUNJIGluc2NyaXJlIGxlIG5vbSBkZSBsYSBsaWduZSDDoCDDqXR1ZGllcg0KbWFwdmlldyhsaWduZV9maWx0ZXIpDQoNCiMgQ3LDqWF0aW9uIGRlIGwnZW1wcmlzZSBkZSBsYSB6b25lIGQnw6l0dWRlIC0tLS0NCnpvbmVfZXR1ZGUgPC0gc3RfYXNfc2Yoc3RfYnVmZmVyKHN0X3VuaW9uKGxpZ25lX2ZpbHRlciksIDUwKSkNCm1hcHZpZXcoem9uZV9ldHVkZSkNCg0KZ2FyZXMgPC0gc2Y6OnN0X3JlYWQoIkM6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvR0VPRkVSL2dhcmVzXzIxNTQuZ3BrZyIpDQpuYW1lcyhnYXJlcykNCmdhcmVzX3NlbGVjdCA8LSBnYXJlcyAlPiUgDQogIHNlbGVjdChub21fZ2FyZSwgdm95XzIwMjIpDQptYXB2aWV3KGdhcmVzX3NlbGVjdCkNCg0KZ2FyZXNfc2VsZWN0X2ludGVyIDwtIHNmOjpzdF9pbnRlcnNlY3Rpb24oZ2FyZXNfc2VsZWN0LHpvbmVfZXR1ZGUpDQptYXB2aWV3KGdhcmVzX3NlbGVjdF9pbnRlcikNCg0KZ2FyZXNfc2VsZWN0X2ludGVyX2Ryb3AgPC0gc3RfZHJvcF9nZW9tZXRyeShnYXJlc19zZWxlY3RfaW50ZXIpDQprbml0cjo6a2FibGUoDQogIGdhcmVzX3NlbGVjdF9pbnRlcl9kcm9wLA0KICBmb3JtYXQgPSAicGlwZSIsDQogIGNvbC5uYW1lcyA9IGMoIkdhcmVzIiwgIlZveWFnZXVycyAyMDIyIiksDQogIGRpZ2l0cyA9IDINCikNCmBgYA0KDQoNCg0KKipMaWduZXMqKg0KDQpgYGB7ciwgZXZhbD1GfQ0KbGlnbmVzIDwtIHNmOjpzdF9yZWFkKCJDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9SQUlMRU5JVU0vQkREX1RFTExJL0dFT0ZFUi9yZXNlYXVfZmVycm92aWFpcmUuZ2VvanNvbiIpDQpgYGANCg0KDQojIyBJTlNFRQ0KDQoqICoqUG9wdWxhdGlvbiBhdSBuaXZlYXUgZGUgbGEgY29tbXVuZSoqDQoNCkxhIHBvcHVsYXRpb24gZXN0IHByw6lzZW50ZSBkYW5zIGxhIGNvdWNoZSBkZXMgY29tbXVuZXMgOiAgDQpgYGB7ciwgZXZhbD1GfQ0KY29tbXVuZXMgPC0gc2Y6OnN0X3JlYWQoIkM6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvQ09NTVVORVMvY29tbXVuZS5zaHAiKQ0KYGBgDQo8YnI+ICANCg0KKiAqKlBvcHVsYXRpb24gcGFyIGNhcnJlYXV4IDIwMG0geCAyMDBtKioNCmBgYHtyLCBldmFsID0gRn0NCiMjICBEb25uw6llcyBjYXJyb3nDqWVzIDIwMTkgLS0tLQ0KY2FycmVhdXhfMjAwXzIwMTkgPC0gc3RfcmVhZCgnQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9DQVJSRUFVL0ZpbG9zb2ZpMjAxOV9jYXJyZWF1eF8yMDBtX2dwa2cvY2FycmVhdXhfMjAwbV9tZXQuZ3BrZycpDQpgYGANCg0KKiAqKkVtcGxvaS1Qb3B1bGF0aW9uIGFjdGl2ZSBlbiAyMDIwKioNCg0KUmVjZW5zZW1lbnQgZGUgbGEgcG9wdWxhdGlvbiAtIEJhc2UgZGVzIHByaW5jaXBhdXggaW5kaWNhdGV1cnMgIA0KDQpgYGB7ciwgZXZhbD1GfQ0KY29tbXVuZXMgPC0gc2Y6OnN0X3JlYWQoJ0M6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvQ09NTVVORVMvQ09NTVVORS5zaHAnKQ0KYmFzZV9lbXBsb2kgPC0gcmVhZC5jc3YyKCdDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9SQUlMRU5JVU0vQkREX1RFTExJL2Jhc2UtY2MtZW1wbG9pLXBvcC1hY3RpdmUtMjAyMF9jc3YvYmFzZS1jYy1lbXBsb2ktcG9wLWFjdGl2ZS0yMDIwX3YyLkNTVicpDQpuYW1lcyhjb21tdW5lcykNCm5hbWVzKGJhc2VfZW1wbG9pKQ0KY29tbXVuZXMgPC0gY29tbXVuZXMgJT4lIA0KICByZW5hbWUoQ09ER0VPID0gSU5TRUVfQ09NKQ0KY29tbXVuZXNfam9pbiA8LSByaWdodF9qb2luKGNvbW11bmVzLCBiYXNlX2VtcGxvaSwgYnk9J0NPREdFTycpDQpuYW1lcyhjb21tdW5lc19qb2luKQ0KY29tbXVuZXNfc2VsZWN0IDwtIGNvbW11bmVzX2pvaW4gJT4lIA0KICBkcGx5cjo6c2VsZWN0KElELCBOT00sIENPREdFTywgUDIwX0FDVDE1NjQpDQpgYGANCjxicj4NCiogKipDYXBhY2l0w6kgZGVzIGNvbW11bmVzIGVuIGjDqWJlcmdlbWVudCB0b3VyaXN0aXF1ZSBlbiAyMDIzKioNCg0KYGBge3IsIGV2YWw9Rn0NCmNvbW11bmVzIDwtIHNmOjpzdF9yZWFkKCdDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9SQUlMRU5JVU0vQkREX1RFTExJL0NPTU1VTkVTL0NPTU1VTkUuc2hwJykNCmJhc2VfdG91cmlzbWUgPC0gcmVhZC5jc3YyKCdDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9SQUlMRU5JVU0vQkREX1RFTExJL2Jhc2UtY2MtdG91cmlzbWUtMjAyMy1nZW8yMDIzLUNTVi9iYXNlLWNjLXRvdXJpc21lLTIwMjMtZ2VvMjAyMy5jc3YnKQ0KbmFtZXMoY29tbXVuZXMpDQpuYW1lcyhiYXNlX3RvdXJpc21lKQ0KY29tbXVuZXMgPC0gY29tbXVuZXMgJT4lIA0KICByZW5hbWUoQ09ER0VPID0gSU5TRUVfQ09NKQ0KY29tbXVuZXNfam9pbiA8LSByaWdodF9qb2luKGNvbW11bmVzX3NlbGVjdCwgYmFzZV90b3VyaXNtZSwgYnk9J0NPREdFTycpDQpuYW1lcyhjb21tdW5lc19qb2luKQ0KY29tbXVuZXNfc2VsZWN0IDwtIGNvbW11bmVzX2pvaW4gJT4lIA0KICBkcGx5cjo6c2VsZWN0KElELCBOT00sIENPREdFTywgDQogICAgICAgICAgICAgICAgUDIwX0FDVDE1NjQsIA0KICAgICAgICAgICAgICAgIFBPUFVMQVRJT04sIA0KICAgICAgICAgICAgICAgIENQR0UyMyAjIE5vbWJyZSBkJ2VtcGxhY2VtZW50cyBkZSBjYW1waW5nIGVuIDIwMjMNCiAgICAgICAgICAgICAgICApDQoNCmBgYA0KDQoNCjxicj4NCg0KKiAqKkNhcGFjaXTDqSBkZXMgY29tbXVuZXMgZW4gbm9tYnJlIGQnw6lsw6h2ZXMqKiAgDQoNCmBgYHtyLCBldmFsID0gRn0NCg0KIyBFZmZlY3RpZnMgZOKAmcOpbMOodmVzIHBhciBuaXZlYXUsIHNleGUsIGxhbmd1ZXMgdml2YW50ZXMgMSBldCAyIGxlcyBwbHVzIGZyw6lxdWVudGVzLCBwYXIgY29sbMOoZ2Ug4oCTIERhdGUgZOKAmW9ic2VydmF0aW9uIGF1IGTDqWJ1dCBkdSBtb2lzIGTigJlvY3RvYnJlIGNoYXF1ZSBhbm7DqWUNCmJhc2VfZWxldmVzX2NvbGxlZ2VzIDwtIHJlYWQuY3N2MignQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9FTEVWRVMvZnItZW4tY29sbGVnZS1lZmZlY3RpZnMtbml2ZWF1LXNleGUtbHYuY3N2JykNCm5hbWVzKGJhc2VfZWxldmVzX2NvbGxlZ2VzKQ0KYmFzZV9lbGV2ZXNfY29sbGVnZXNfMjAyMSA8LSBiYXNlX2VsZXZlc19jb2xsZWdlcyAlPiUgDQogIGZpbHRlcihSZW50csOpZS5zY29sYWlyZSA9PSAnMjAyMScpICU+JSANCiAgcmVuYW1lKG51bWVyb19ldHMgPSBOdW3DqXJvLmR1LmNvbGzDqGdlKSAlPiUgDQogIHNlbGVjdChSZW50csOpZS5zY29sYWlyZSwgUsOpZ2lvbi5hY2Fkw6ltaXF1ZSxBY2Fkw6ltaWUsDQogICAgICAgICBEw6lwYXJ0ZW1lbnQsIENvbW11bmUsbnVtZXJvX2V0cywNCiAgICAgICAgIETDqW5vbWluYXRpb24ucHJpbmNpcGFsZSxQYXRyb255bWUsIFNlY3RldXIsUkVQLA0KICAgICAgICAgUkVQLi4sTm9tYnJlLmQuw6lsw6h2ZXMudG90YWwuLm5vbWJyZS5kLsOpbMOodmVzLmRhbnMubGVzLmZvcm1hdGlvbnMuZHUuMWVyLmN5Y2xlLmR1LjJuZC5kZWdyw6kuZXQubm9uLmR1Lm5vbWJyZS50b3RhbC5kLsOpbMOodmVzLmluc2NyaXRzLmRhbnMubC7DqXRhYmxpc3NlbWVudC4ubGVzLkRJTUEuZXQubGVzLmRpc3Bvc2l0aWZzLnJlbGFpcy5zb250LmV4Y2x1cy4pDQpuYW1lcyhiYXNlX2VsZXZlc19jb2xsZWdlc18yMDIxKQ0KYmFzZV9lbGV2ZXNfY29sbGVnZXNfMjAyMV9jdXQgPC0gcmlnaHRfam9pbihsb2NhbGlzYXRpb25fY29sbGVnZXNfbHljZWVzX2N1dCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZV9lbGV2ZXNfY29sbGVnZXNfMjAyMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAnbnVtZXJvX2V0cycpDQpiYXNlX2VsZXZlc19jb2xsZWdlc18yMDIxX2N1dCA8LSBiYXNlX2VsZXZlc19jb2xsZWdlc18yMDIxX2N1dCAlPiUgDQogIGZpbHRlcighc3RfaXNfZW1wdHkoZ2VvbWV0cnkpKSAlPiUgDQogIHJlbmFtZShuYl9lbGV2ZXMgPSBOb21icmUuZC7DqWzDqHZlcy50b3RhbC4ubm9tYnJlLmQuw6lsw6h2ZXMuZGFucy5sZXMuZm9ybWF0aW9ucy5kdS4xZXIuY3ljbGUuZHUuMm5kLmRlZ3LDqS5ldC5ub24uZHUubm9tYnJlLnRvdGFsLmQuw6lsw6h2ZXMuaW5zY3JpdHMuZGFucy5sLsOpdGFibGlzc2VtZW50Li5sZXMuRElNQS5ldC5sZXMuZGlzcG9zaXRpZnMucmVsYWlzLnNvbnQuZXhjbHVzLikgJT4lIA0KICBzZWxlY3QobnVtZXJvX2V0cywgYXBwZWxsYXRpb24sIG5iX2VsZXZlcykNCm5hbWVzKGJhc2VfZWxldmVzX2NvbGxlZ2VzXzIwMjFfY3V0KQ0KDQoNCiMgRWZmZWN0aWZzIGTigJnDqWzDqHZlcyBwYXIgbml2ZWF1LCBzZXhlLCBsYW5ndWVzIHZpdmFudGVzIDEgZXQgMiBsZXMgcGx1cyBmcsOpcXVlbnRlcywgcGFyIGx5Y8OpZSBwcm9mZXNzaW9ubmVsIOKAkyBEYXRlIGTigJlvYnNlcnZhdGlvbiBhdSBkw6lidXQgZHUgbW9pcyBk4oCZb2N0b2JyZSBjaGFxdWUgYW5uw6llDQpiYXNlX2VsZXZlc19seWNlZXNfcHJvIDwtIHJlYWQuY3N2MignQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9FTEVWRVMvZnItZW4tbHljZWVfcHJvLWVmZmVjdGlmcy1uaXZlYXUtc2V4ZS1sdi5jc3YnKQ0KbmFtZXMoYmFzZV9lbGV2ZXNfbHljZWVzX3BybykNCmJhc2VfZWxldmVzX2x5Y2Vlc19wcm9fMjAyMSA8LSBiYXNlX2VsZXZlc19seWNlZXNfcHJvICU+JSANCiAgZmlsdGVyKFJlbnRyw6llLnNjb2xhaXJlID09ICcyMDIxJykgJT4lIA0KICByZW5hbWUobnVtZXJvX2V0cyA9IE51bcOpcm8uZHUubHljw6llKSAlPiUgDQogIHNlbGVjdChSZW50csOpZS5zY29sYWlyZSwgUsOpZ2lvbi5hY2Fkw6ltaXF1ZSwNCiAgICAgICAgIEFjYWTDqW1pZSwgRMOpcGFydGVtZW50LENvbW11bmUsIG51bWVyb19ldHMsICAgICAgICAgICAgICAgICAgICBEw6lub21pbmF0aW9uLnByaW5jaXBhbGUsICBQYXRyb255bWUsIFNlY3RldXIsICAgIA0KICAgICAgICAgTm9tYnJlLmQuw6lsw6h2ZXMpDQpuYW1lcyhiYXNlX2VsZXZlc19seWNlZXNfcHJvXzIwMjEpDQpiYXNlX2VsZXZlc19seWNlZXNfcHJvXzIwMjFfY3V0IDwtIHJpZ2h0X2pvaW4obG9jYWxpc2F0aW9uX2NvbGxlZ2VzX2x5Y2Vlc19jdXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhc2VfZWxldmVzX2x5Y2Vlc19wcm9fMjAyMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAnbnVtZXJvX2V0cycpDQpiYXNlX2VsZXZlc19seWNlZXNfcHJvXzIwMjFfY3V0IDwtIGJhc2VfZWxldmVzX2x5Y2Vlc19wcm9fMjAyMV9jdXQgJT4lIA0KICBmaWx0ZXIoIXN0X2lzX2VtcHR5KGdlb21ldHJ5KSkgJT4lIA0KICByZW5hbWUobmJfZWxldmVzID0gTm9tYnJlLmQuw6lsw6h2ZXMpICU+JSANCiAgc2VsZWN0KG51bWVyb19ldHMsIGFwcGVsbGF0aW9uLCBuYl9lbGV2ZXMpDQpuYW1lcyhiYXNlX2VsZXZlc19seWNlZXNfcHJvXzIwMjFfY3V0KQ0KDQojIEVmZmVjdGlmcyBk4oCZw6lsw6h2ZXMgcGFyIG5pdmVhdSwgc2V4ZSwgbGFuZ3VlcyB2aXZhbnRlcyAxIGV0IDIgbGVzIHBsdXMgZnLDqXF1ZW50ZXMsIHBhciBseWPDqWUgZOKAmWVuc2VpZ25lbWVudCBnw6luw6lyYWwgZXQgdGVjaG5vbG9naXF1ZSDigJMgRGF0ZSBk4oCZb2JzZXJ2YXRpb24gYXUgZMOpYnV0IGR1IG1vaXMgZOKAmW9jdG9icmUgY2hhcXVlIGFubsOpZQ0KYmFzZV9lbGV2ZXNfbHljZWVzX2d0IDwtIHJlYWQuY3N2MignQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9FTEVWRVMvZnItZW4tbHljZWVfZ3QtZWZmZWN0aWZzLW5pdmVhdS1zZXhlLWx2LmNzdicpDQpuYW1lcyhiYXNlX2VsZXZlc19seWNlZXNfZ3QpDQpiYXNlX2VsZXZlc19seWNlZXNfZ3RfMjAyMSA8LSBiYXNlX2VsZXZlc19seWNlZXNfZ3QgJT4lIA0KICBmaWx0ZXIoUmVudHLDqWUuc2NvbGFpcmUgPT0gJzIwMjEnKSAlPiUgDQogIHJlbmFtZShudW1lcm9fZXRzID0gTnVtw6lyby5kdS5seWPDqWUpICU+JSANCiAgc2VsZWN0KFJlbnRyw6llLnNjb2xhaXJlLCAgDQogICAgICAgICBSw6lnaW9uLmFjYWTDqW1pcXVlLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQWNhZMOpbWllICAgICAgICwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRMOpcGFydGVtZW50LCAgQ29tbXVuZSwgbnVtZXJvX2V0cywNCiAgICAgICAgIETDqW5vbWluYXRpb24ucHJpbmNpcGFsZSwgUGF0cm9ueW1lLFNlY3RldXIsICAgIA0KICAgICAgICAgTm9tYnJlLmQuw6lsw6h2ZXMpDQpuYW1lcyhiYXNlX2VsZXZlc19seWNlZXNfZ3RfMjAyMSkNCmJhc2VfZWxldmVzX2x5Y2Vlc19ndF8yMDIxX2N1dCA8LSByaWdodF9qb2luKGxvY2FsaXNhdGlvbl9jb2xsZWdlc19seWNlZXNfY3V0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFzZV9lbGV2ZXNfbHljZWVzX2d0XzIwMjEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAnbnVtZXJvX2V0cycpDQpuYW1lcyhiYXNlX2VsZXZlc19seWNlZXNfZ3RfMjAyMV9jdXQpDQpiYXNlX2VsZXZlc19seWNlZXNfZ3RfMjAyMV9jdXQgPC0gYmFzZV9lbGV2ZXNfbHljZWVzX2d0XzIwMjFfY3V0ICU+JSANCiAgZmlsdGVyKCFzdF9pc19lbXB0eShnZW9tZXRyeSkpICU+JSANCiAgcmVuYW1lKG5iX2VsZXZlcyA9IE5vbWJyZS5kLsOpbMOodmVzKSAlPiUgDQogIHNlbGVjdChudW1lcm9fZXRzLCBhcHBlbGxhdGlvbiwgbmJfZWxldmVzKQ0KbmFtZXMoYmFzZV9lbGV2ZXNfbHljZWVzX2d0XzIwMjFfY3V0KQ0KDQoNCiMgRWZmZWN0aWZzIGRlcyDDqWzDqHZlcyBlbiB2b2llIHByb2Zlc3Npb25uZWxsZSBvdSBCVFMgcGFyIG5pdmVhdSwgc2V4ZSBldCBseWPDqWUgcHJvZmVzc2lvbm5lbCDigJMgRGF0ZSBk4oCZb2JzZXJ2YXRpb24gYXUgZMOpYnV0IGR1IG1vaXMgZOKAmW9jdG9icmUgY2hhcXVlIGFubsOpZQ0Kdm9pZV9wcm9fYnRzIDwtIHJlYWQuY3N2MignQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9FTEVWRVMvZnItZW4tbHljZWVfcHJvLWVmZmVjdGlmcy1uaXZlYXUtc2V4ZS1tZWYuY3N2JykNCm5hbWVzKHZvaWVfcHJvX2J0cykNCnZvaWVfcHJvX2J0c18yMDIxIDwtIHZvaWVfcHJvX2J0cyAlPiUgDQogIGZpbHRlcihSZW50csOpZS5zY29sYWlyZSA9PSAnMjAyMScpICU+JSANCiAgcmVuYW1lKG51bWVyb19ldHMgPSBOdW3DqXJvLmQuw6l0YWJsaXNzZW1lbnQpICU+JSANCiAgc2VsZWN0KFJlbnRyw6llLnNjb2xhaXJlLA0KICAgICAgICAgQWNhZMOpbWllLjIwMjAsDQogICAgICAgICBBY2Fkw6ltaWUuMjAyMC5MaWIuTCwgIA0KICAgICAgICAgbnVtZXJvX2V0cywNCiAgICAgICAgIFBhdHJvbnltZSwgIA0KICAgICAgICAgQWRyZXNzZS5jb25kZW5zw6llLA0KICAgICAgICAgQ29kZS5wb3N0YWwsDQogICAgICAgICBDb21tdW5lLmQuaW1wbGFudGF0aW9uLA0KICAgICAgICAgTm9tYnJlLmQuw6lsw6h2ZXMuLi5Ub3RhbCkgICAgICAgICAgICAgICAgICAgICAgICAgICANCm5hbWVzKGJhc2VfZWxldmVzX2x5Y2Vlc19wcm9fMjAyMSkNCnZvaWVfcHJvX2J0c18yMDIxX2N1dCA8LSByaWdodF9qb2luKGxvY2FsaXNhdGlvbl9jb2xsZWdlc19seWNlZXNfY3V0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdm9pZV9wcm9fYnRzXzIwMjEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9ICdudW1lcm9fZXRzJykNCnZvaWVfcHJvX2J0c18yMDIxX2N1dCA8LSB2b2llX3Byb19idHNfMjAyMV9jdXQgJT4lIA0KICBmaWx0ZXIoIXN0X2lzX2VtcHR5KGdlb21ldHJ5KSkNCiMgR3JvdXBlbWVudCBkZXMgZG9ubsOpZXMgcGFyICdudW1lcm9fZXRzJyBldCBzb21tZSBkZSAnbmJfZWxldmVzJw0Kdm9pZV9wcm9fYnRzXzIwMjFfY3V0X3N1bSA8LSB2b2llX3Byb19idHNfMjAyMV9jdXQgJT4lDQogIGdyb3VwX2J5KG51bWVyb19ldHMsIGFwcGVsbGF0aW9uKSAlPiUNCiAgc3VtbWFyaXNlKG5iX2VsZXZlc190b3RhbCA9IHN1bShOb21icmUuZC7DqWzDqHZlcy4uLlRvdGFsKSkgJT4lIA0KICByZW5hbWUobmJfZWxldmVzID0gbmJfZWxldmVzX3RvdGFsKQ0KDQpkb25uZWVzX2FsbCA8LSByYmluZChiYXNlX2VsZXZlc19jb2xsZWdlc18yMDIxX2N1dCwNCmJhc2VfZWxldmVzX2x5Y2Vlc19wcm9fMjAyMV9jdXQsDQpiYXNlX2VsZXZlc19seWNlZXNfZ3RfMjAyMV9jdXQsDQp2b2llX3Byb19idHNfMjAyMV9jdXRfc3VtKQ0KDQpuYl9lbGV2ZXNfY29sbGVnZXNfbHljZWVzX2J0cyA8LSBkb25uZWVzX2FsbCAlPiUNCiAgZ3JvdXBfYnkobnVtZXJvX2V0cywgYXBwZWxsYXRpb24pICU+JQ0KICBzdW1tYXJpc2UobmJfZWxldmVzX3RvdGFsID0gc3VtKG5iX2VsZXZlcykpDQpgYGANCg0KY29tbWVudCByw6ljdXDDqXJlciBsZSBub21icmUgZCfDqWzDqHZlcyA/DQoNCjxicj4NCjxicj4NCjxicj4NCjxicj4NCg0KIyMgQkRUT1BPDQoNCiogKipQQVJLSU5HUyoqDQoNCmBgYHtyLCBldmFsPUZ9DQpwYWNtYW46OnBfbG9hZChzZixkcGx5cikNCmMgPC0gIkc6L01vbiBEcml2ZS9CREQvcGFya2luZ3MiDQpjIDwtICJDOi9Vc2Vycy9PdGhhdXJlYXUvRG9jdW1lbnRzL0JERCIgIyBkb25uZWVzIHN1ciBQQyBMVk1UDQpwYXJraW5ncyA8LSBsaXN0LmZpbGVzKGMsIA0KICAgICAgICAgICAgICAgICAgICAgIGZ1bGwubmFtZXMgPSBULCANCiAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIkVRVUlQRU1FTlRfREVfVFJBTlNQT1JULnNocCIsIA0KICAgICAgICAgICAgICAgICAgICAgIHJlY3Vyc2l2ZSA9IFQpICMgaW5jbHVyZSB0b3VzIGxlcyBzb3VzLWRvc3NpZXJzDQpmb3IoaSBpbiAxOjEzKSB7DQpwYXJraW5nc18gPC0gc2Y6OnN0X3JlYWQocGFya2luZ3NbaV0pDQpwYXJraW5nc18gPC0gcGFya2luZ3NfICU+JSANCiAgZHBseXI6OmZpbHRlcihOQVRVUkUgPT0gJ1BhcmtpbmcnKSANCg0KcGFya2luZ3NfIDwtICBzdF9tYWtlX3ZhbGlkKHBhcmtpbmdzXykgJT4lIA0KICBkcGx5cjo6c2VsZWN0KElELCBOQVRVUkUsIE5BVF9ERVRBSUwsIGdlb21ldHJ5KQ0KDQpwYXJraW5nc19jZW50cm9pZCA8LSBzZjo6c3RfY2VudHJvaWQocGFya2luZ3NfKQ0Kc2Y6OnN0X3dyaXRlKHBhcmtpbmdzX2NlbnRyb2lkLCBwYXN0ZTAoIkM6L1VzZXJzL090aGF1cmVhdS9Eb2N1bWVudHMvQkREL1BBUktJTkdfQ0VOVFJPSUQvUEFSS0lOR19DRU5UUk9JRF9SIixpLCIuZ3BrZyIpKQ0KfQ0KYGBgDQoNCioqQmFzZSBuYXRpb25hbCBkZXMgbGlldXggZGUgc3RhdGlvbm5lbWVudCoqDQpCYXNlIE5hdGlvbmFsZSBkZXMgTGlldXggZGUgU3RhdGlvbm5lbWVudCA6ICAgDQpDZXR0ZSBiYXNlIGRlIGRvbm7DqWVzIG4nZXN0IHBhcyByZXByw6lzZW50YXRpdmUgZGUgbCdlbnNlbWJsZSBkZXMgbGlldXggZGUgc3RhdGlvbm5lbWVudCBob3JzIHZvaXJpZS4gRWxsZSBuJ2VzdCBwYXMgZm9yY8OpbWVudCDDoCBqb3VyIGNhciBzYSBjb25zb2xpZGF0aW9uIG4nZXN0IHBhcyBhdXRvbWF0aXPDqWUuICANCkxhIGJhc2UgZGVzIHN0YXRpb25uZW1lbnRzIHBlcm1ldCBkZSByZWdyb3VwZXIgZW4gdW4gdW5pcXVlIGZpY2hpZXIgY29uc29saWTDqSBs4oCZZW5zZW1ibGUgZGUgbOKAmW9mZnJlIGRlIHN0YXRpb25uZW1lbnQgZW4gRnJhbmNlLCBkYW5zIHVuIGZvcm1hdCBzdGFuZGFyZCBldCB1bmlmacOpLiBDZXR0ZSBzdGFuZGFyZGlzYXRpb24gZGVzIGRvbm7DqWVzIGZhY2lsaXRlIGdyYW5kZW1lbnQgbGUgdHJhdmFpbCBk4oCZaW50w6lncmF0aW9uIGRlIGNlcyBkb25uw6llcyBwYXIgZGVzIHNlcnZpY2VzIHLDqXV0aWxpc2F0ZXVycy4gIA0KDQpDZSBkYXRhc2V0IGNvbXByZW5kIG5vdGFtbWVudCA6DQoqIGxhIGfDqW9sb2NhbGlzYXRpb24gZGVzIHBhcmtpbmdzICANCiogbGEgaGF1dGV1ciBtYXhpbWFsZSBkZXMgdsOpaGljdWxlcyBwb3V2YW50IHDDqW7DqXRyZXIgZGFucyBhdSBtb2lucyB1biBlc3BhY2UgZHUgcGFya2luZyAgDQoqIGxlIG5vbWJyZSBkZSBwbGFjZXMgZGFucyBsZSBwYXJraW5nIChwYXJmb2lzIGTDqWNsaW7DqWVzIGVuIHBsYWNlcyByw6lzZXJ2w6llcyBwb3VyIGxlcyBhYm9ubsOpcywgbGVzIHBlcnNvbm5lcyDDoCBtb2JpbGl0w6kgcsOpZHVpdGUsIHBvdXIgbGVzIHZvaXR1cmVzIMOpbGVjdHJpcXVlcywgbGVzIHbDqWhpY3VsZXMgw6AgZGV1eC1yb3VlcyBtb3Rvcmlzw6lzIGV0IG5vbi1tb3Rvcmlzw6lzKSAgDQoqIGxlIGNvZGUgU0lSRVQgZGUgbCfDqXRhYmxpc3NlbWVudCBnZXN0aW9ubmFpcmUgZHUgcGFya2luZyAgDQoqIGxlIGNhcmFjdMOocmUgZ3JhdHVpdCBvdSBwYXlhbnQgZHUgcGFya2luZyAocGFyZm9pcyB1biBkw6l0YWlsIGVzdCBhcHBvcnTDqSBzdXIgbGUgcHJpeCBob3JhaXJlIG91IGxlIHByaXggZCd1biBhYm9ubmVtZW50IG1lbnN1ZWwvYW5udWVsKSAgIA0KDQo8YSBocmVmPSJodHRwczovL3d3dy5kYXRhLmdvdXYuZnIvZnIvZGF0YXNldHMvYmFzZS1uYXRpb25hbGUtZGVzLWxpZXV4LWRlLXN0YXRpb25uZW1lbnQvDQoiIHRhcmdldD0iX2JsYW5rIj5saWVuLg0KPC9hPiAgDQoNCioqUsOpc2VhdSBww6lkZXN0cmUgKEJEVE9QTykqKg0KDQoNCkplIHPDqWxlY3Rpb25uZSBsZSBmaWNoaWVyIHNoYXBlZmlsZSAoVFJPTkNPTl9ERV9ST1VURS5zaHApIGNvcnJlc3BvbmRhbnQgw6AgbGEgcsOpZ2lvbiDDoCDDqXR1ZGllci4NCg0KQ2V0dGUgY291Y2hlIGNvbnRpZW50IGRlcyBpbmZvcm1hdGlvbnMgc3VyIDogIA0KDQoqIGxlcyByb3V0ZXMgZ291ZHJvbm7DqWVzIDogdHlwZSBhdXRvcm91dGllciwgcm91dGUgw6AgMiBjaGF1c3PDqWVzLCByb3V0ZSDDoCAxIGNoYXVzc8OpZSwgYnJldGVsbGUgZXQgcm9uZC1wb2ludA0KKiBsZXMgcm91dGVzIG5vbiBnb3Vkcm9ubsOpZXMgOiBjaGVtaW5zLCByb3V0ZXMgZW1waWVycsOpZXMsIHNlbnRpZXJzDQoqIGxlcyBiYWNzIG91IGxpYWlzb25zIG1hcml0aW1lcw0KKiBsZXMgZXNjYWxpZXJzICANCg0KUG91ciBsZSByw6lzZWF1IHBpw6l0b24gbm91cyBjb25zZXJ2b25zIGwnZW5zZW1ibGUgZGUgY2VzIGRvbm7DqWVzLiANCg0KKipSw6lzZWF1IFZvaXR1cmUgKEJEVE9QTykqKg0KDQpQb3VyIGxlIHLDqXNlYXUgdm9pdHVyZSBub3VzIG5lIGNvbnNlcnZvbnMgcXVlIGxlcyByb3V0ZXMgZ291ZHJvbm7DqWVzIDogDQoqIHR5cGUgYXV0b3JvdXRpZXINCiogcm91dGUgw6AgMiBjaGF1c3PDqWVzDQoqIHJvdXRlIMOgIDEgY2hhdXNzw6llDQoqIGJyZXRlbGxlDQoqIHJvbmQtcG9pbnQNCg0KYGBge3IsIGV2YWwgPSBGfQ0KYyA8LSAiRDovIg0KYyA8LSAiQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9CRFRPUE9fU0VMRUNULyIgIyBkb25uZWVzIHN1ciBQQyBMVk1UDQpyb3V0ZXMgPC0gbGlzdC5maWxlcyhjLCANCiAgICAgICAgICAgICAgICAgICAgICAgZnVsbC5uYW1lcyA9IFQsIA0KICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gIlRST05DT05fREVfUk9VVEUuc2hwIiwgDQogICAgICAgICAgICAgICAgICAgICAgIHJlY3Vyc2l2ZSA9IFQpICMgaW5jbHVyZSB0b3VzIGxlcyBzb3VzLWRvc3NpZXJzDQoNCmZvcihpIGluIDE6MTMpIHsNCnJvdXRlc18gPC0gc2Y6OnN0X3JlYWQocm91dGVzW2ldKQ0KDQpyb3V0ZXNfZmlsdGVyIDwtIHJvdXRlc18gJT4lIA0KICBkcGx5cjo6ZmlsdGVyKE5BVFVSRSAlaW4lIGMoJ1JvdXRlIMOgIDEgY2hhdXNzw6llJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUm91dGUgw6AgMiBjaGF1c3PDqWVzJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdUeXBlIGF1dG9yb3V0aWVyJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdCcmV0ZWxsZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUm9uZC1wb2ludCcNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpDQpyb3V0ZXNfZmlsdGVyX3NlbGVjdCA8LSByb3V0ZXNfZmlsdGVyICU+JSANCiAgc2Y6OnN0X21ha2VfdmFsaWQoKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoSUQsIE5CX1ZPSUVTLCBnZW9tZXRyeSkNCnN0X3dyaXRlKHJvdXRlc19maWx0ZXJfc2VsZWN0LCANCiAgICAgICAgIHBhc3RlMCgnQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9UUk9OQ09OX0RFX1JPVVRFL1RST05DT05fREVfUk9VVEVfUicsaSwnX1YyLmdwa2cnKSkNCn0NCmBgYA0KDQoqKk5vbWJyZSBkJ2ludGVyc2VjdGlvbnMgZHUgcsOpc2VhdSB2b2l0dXJlKioNCg0KDQpgYGB7ciwgZXZhbD1GLCBlY2hvPVR9DQoNCnJlc2VhdV92b2l0dXJlIDwtIHNmOjpzdF9yZWFkKCdDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9SQUlMRU5JVU0vQkREX1RFTExJL1RST05DT05fREVfUk9VVEUvVFJPTkNPTl9ERV9ST1VURV9SOF9WMi5ncGtnJykgIyByw6lnaW9uIEJyZXRhZ25lDQoNCg0KIyMgMDUgbm9tYnJlIGQnaW50ZXJzZWN0aW9uIGR1IHLDqXNlYXUgcm91dGllciANCg0KIyBDYWxjdWwgZGUgbGEgbG9uZ3VldXIgZHUgcsOpc2VhdSB2b2l0dXJlDQphbGxfc3VtIDwtIGxpc3QoKQ0KDQojIEluaXRpYWxpc2F0aW9uIGR1IGNvbXB0ZXVyDQpjb21wdGV1ciA8LSAwDQoNCmZvcihpIGluIDE6bnJvdyhhbGxfaXNvY2hyb25lcykpIHsNCiAgcmVzZWF1X3ZvaXR1cmVfaW50ZXJzZWN0aW9uIDwtIHN0X2ludGVyc2VjdGlvbihyZXNlYXVfdm9pdHVyZSwgYWxsX2lzb2Nocm9uZXNbaSxdKQ0KDQogICMgVsOpcmlmaWV6IHNpIGwnaW50ZXJzZWN0aW9uIGVzdCB2aWRlDQogIGlmIChucm93KHJlc2VhdV92b2l0dXJlX2ludGVyc2VjdGlvbikgPiAwKSB7DQogICAgDQogICAgIyBDYWxjdWwgZHUgbm9tYnJlIGQnaW50ZXJzZWN0aW9uIGR1IHLDqXNlYXUgdm9pdHVyZSBwb3VyIGNoYXF1ZSBpc29jaHJvbmUNCiAgICBpbnRlcnNlY3Rpb25zIDwtIHN0X2ludGVyc2VjdGlvbihyZXNlYXVfdm9pdHVyZV9pbnRlcnNlY3Rpb24pDQogICAgDQogICAgIyBGaWx0cmFnZSBkZXMgUG9pbnRzIFVuaXF1ZXMNCiAgICBpbnRlcnNlY3Rpb25zX3BvaW50cyA8LSBpbnRlcnNlY3Rpb25zW3N0X2RpbWVuc2lvbihpbnRlcnNlY3Rpb25zKSA9PSAwLCBdDQogICAgDQogICAgIyBDb21wdGFnZSBkZXMgSW50ZXJzZWN0aW9ucw0KICAgIG5vbWJyZV9pbnRlcnNlY3Rpb25zIDwtIGxlbmd0aChzdF9nZW9tZXRyeShpbnRlcnNlY3Rpb25zX3BvaW50cykpDQogICAgDQogICAgc3VtIDwtIGRhdGEuZnJhbWUoYXMubnVtZXJpYyhub21icmVfaW50ZXJzZWN0aW9ucykpDQogICAgc3VtIDwtIGNiaW5kKHN1bSwgdW5pcXVlKHJlc2VhdV92b2l0dXJlX2ludGVyc2VjdGlvbiRwb2ludC5JRF9udW1iZXIpKQ0KICAgIA0KICAgIG5hbWVzKHN1bSkgPC0gYygibmJfaW50ZXJzZWN0aW9ucyIsICJJRF9udW1iZXIiKQ0KICB9IA0KICBlbHNlIHsNCiAgICANCiAgICAjIFNpIGwnaW50ZXJzZWN0aW9uIGVzdCB2aWRlLCBkw6lmaW5pc3NleiBsYSBsb25ndWV1ciDDoCAwIGV0IElEX251bWJlciDDoCBOQQ0KICAgIHN1bSA8LSBkYXRhLmZyYW1lKDAsIE5BKQ0KICAgIG5hbWVzKHN1bSkgPC0gYygibmJfaW50ZXJzZWN0aW9ucyIsICJJRF9udW1iZXIiKQ0KICB9DQoNCiAgYWxsX3N1bVtbaV1dIDwtIHN1bQ0KICANCiAgIyBJbmNyw6ltZW50ZXIgbGUgY29tcHRldXIgYXByw6hzIGNoYXF1ZSBpdMOpcmF0aW9uIHLDqXVzc2llDQogIGNvbXB0ZXVyIDwtIGNvbXB0ZXVyICsgMQ0KICANCiAgIyBBZmZpY2hlciBsZSBwcm9ncsOocyBzaSBuw6ljZXNzYWlyZQ0KICBpZiAoY29tcHRldXIgJSUgMTAwID09IDApIHsgICMgQWZmaWNoZSBsZSBwcm9ncsOocyB0b3V0ZXMgbGVzIDEwIGl0w6lyYXRpb25zDQogICAgbWVzc2FnZSgiTm9tYnJlIGQnaXTDqXJhdGlvbnMgY29tcGzDqXTDqWVzIDogIiwgY29tcHRldXIpDQogIH0gIA0KfQ0KDQojIEFmZmljaGVyIGxlIG5vbWJyZSB0b3RhbCBkJ2l0w6lyYXRpb25zIMOgIGxhIGZpbg0KbWVzc2FnZSgiTm9tYnJlIHRvdGFsIGQnaXTDqXJhdGlvbnMgOiAiLCBjb21wdGV1cikNCg0KYWxsX3N1bV9kdCA8LSBkby5jYWxsKHJiaW5kLCBhbGxfc3VtKQ0KDQpgYGANCg0KIA0KKipab25lcyBkZSB2w6lnw6l0YXRpb24gKEJEVE9QTykqKg0KDQpGaWNoaWVyIEJEVE9QTyAtIFpvbmUgZGUgdsOpZ8OpdGF0aW9uDQoNCjxicj4NCjxicj4NCjxicj4NCjxicj4NCg0KDQojIyBPU00NCg0KKipSb25kcy1wb2ludHMqKg0KDQpCZXlvbmR0aGVtYXAgIA0KU291cmNlIDogaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vcy9sMHBzejJoM2EwcnVyaDUvRXVyb3BlX3JvdW5kYWJvdXRzXzIwMTguemlwP2RsPTANCg0KKioqDQoNCioqUGlzdGVzIGN5Y2xhYmxlcyoqDQoNCkV4dHJhY3Rpb24gZGVzIHBpc3RlcyBjeWNsYWJsZXMgYXZlYyBsZSBwYWNrYWdlIFIgKk9TTSBFeHRyYWN0Kg0KDQpgYGB7ciwgZXZhbCA9IEZ9DQpwYWNtYW46OnBfbG9hZChzZiwgZHBseXIsIG1hcHZpZXcsIGh0dHIsIG9zbWV4dHJhY3QpDQoNCnJlZ2lvbl9vc20gPC0gYygiTWlkaS1QeXJlbmVlcyIsICJQcm92ZW5jZSBBbHBlcy1Db3RlLWQnQXp1ciIsICJDaGFtcGFnbmUgQXJkZW5uZSIsIkJvdXJnb2duZSIsIA0KICAgICAgICAgICAgICAgICJGcmFuY2hlIENvbXRlIiwgIkF1dmVyZ25lIiwgIkFsc2FjZSIsICJMb3JyYWluZSIsIA0KICAgICAgICAgICAgICAgICJQaWNhcmRpZSIsICJCcmV0YWduZSIsICJSaG9uZS1BbHBlcyIsICJMYW5ndWVkb2MtUm91c3NpbGxvbiIsIA0KICAgICAgICAgICAgICAgICJJbGUtZGUtRnJhbmNlIiwgIkNlbnRyZSIsICJOb3JkLVBhcy1kZS1DYWxhaXMiLCAiQ29yc2UiLA0KICAgICAgICAgICAgICAgICJCYXNzZS1Ob3JtYW5kaWUiLCAiSGF1dGUtTm9ybWFuZGllIiwgIlBheXMgZGUgbGEgTG9pcmUiLCAiQXF1aXRhaW5lIiwNCiAgICAgICAgICAgICAgICAiTGltb3VzaW4iLCAiUG9pdG91LUNoYXJlbnRlcyIpDQoNCnBpc3Rlc19jeWNsYWJsZXMgPC0gdGliYmxlKCkNCg0KZm9yIChpIGluIDE6MjIpIHsNCg0KcHJpbnQocGFzdGUoIlRyYWl0ZW1lbnQgZGUgbGEgcsOpZ2lvbiBudW3DqXJvIiwgaSkpDQogIA0KIyBjb3VjaGUgMSA6IGhpZ2h3YXkgLyBjeWNsZXdheSAjIFdoZW4gY3ljbGV3YXkgaXMgZHJhd24gYXMgaXRzIG93biB3YXkgDQpoaWdod2F5X2N5Y2xld2F5ID0gb3NtZXh0cmFjdDo6b2VfZ2V0KHJlZ2lvbl9vc21baV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXIgPSAibGluZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX3RhZ3MgPSAiaGlnaHdheSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXJ5ID0gIlNFTEVDVCAqIEZST00gbGluZXMgV0hFUkUgaGlnaHdheSBJTiAoJ2N5Y2xld2F5JykiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1aWV0ID0gRkFMU0UpDQpuYW1lcyhoaWdod2F5X2N5Y2xld2F5KQ0KDQpoaWdod2F5X2N5Y2xld2F5X2xpZ2h0IDwtIGhpZ2h3YXlfY3ljbGV3YXkgJT4lIA0KICBzZWxlY3Qob3NtX2lkLCBnZW9tZXRyeSkNCg0KIyBjb3VjaGUgMiA6IGJpY3ljbGUgLyBkZXNpZ25hdGVkICMgV2hlcmUgYSB3YXkgaGFzIGJlZW4gc3BlY2lhbGx5IGRlc2lnbmF0ZWQgKHR5cGljYWxseSBieSBhIGdvdmVybm1lbnQpIGZvciBiaWN5Y2xlIHVzZQ0KYmljeWNsZV9kZXNpZ25hdGVkID0gb3NtZXh0cmFjdDo6b2VfZ2V0KHJlZ2lvbl9vc21baV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXIgPSAibGluZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX3RhZ3MgPSAiYmljeWNsZSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHF1ZXJ5ID0gIlNFTEVDVCAqIEZST00gbGluZXMgV0hFUkUgYmljeWNsZSBJTiAoJ2Rlc2lnbmF0ZWQnKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcXVpZXQgPSBGQUxTRSkNCm5hbWVzKGJpY3ljbGVfZGVzaWduYXRlZCkNCg0KYmljeWNsZV9kZXNpZ25hdGVkX2xpZ2h0IDwtIGJpY3ljbGVfZGVzaWduYXRlZCAlPiUgDQogIHNlbGVjdChvc21faWQsZ2VvbWV0cnkpDQoNCiMgY291Y2hlIDMgOiBjeWNsZXdheSAvIGxhbmUgIyBDeWNsZXdheSB0YWdnZWQgb24gdGhlIG1haW4gcm9hZHdheSBvciBsYW5lLCBBIGxhbmUgaXMgYSByb3V0ZSB0aGF0IGxpZXMgd2l0aGluIHRoZSByb2Fkd2F5DQpjeWNsZXdheV9sYW5lID0gb3NtZXh0cmFjdDo6b2VfZ2V0KHJlZ2lvbl9vc21baV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5ZXIgPSAibGluZXMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJhX3RhZ3MgPSAiY3ljbGV3YXkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWVyeSA9ICJTRUxFQ1QgKiBGUk9NIGxpbmVzIFdIRVJFIGN5Y2xld2F5IElOICgnbGFuZScpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBxdWlldCA9IEZBTFNFKQ0KbmFtZXMoY3ljbGV3YXlfbGFuZSkNCg0KY3ljbGV3YXlfbGFuZV9saWdodCA8LSBjeWNsZXdheV9sYW5lICU+JSANCiAgc2VsZWN0KG9zbV9pZCxnZW9tZXRyeSkNCg0KDQpwaXN0ZXNfY3ljbGFibGVzX29zbV9hbGwgPC0gcmJpbmQoZGF0YS5mcmFtZShoaWdod2F5X2N5Y2xld2F5X2xpZ2h0KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShiaWN5Y2xlX2Rlc2lnbmF0ZWRfbGlnaHQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoY3ljbGV3YXlfbGFuZV9saWdodCkpDQoNCnBpc3Rlc19jeWNsYWJsZXMgPC0gcmJpbmQoZGF0YS5mcmFtZShwaXN0ZXNfY3ljbGFibGVzX29zbV9hbGwpLCBwaXN0ZXNfY3ljbGFibGVzKQ0KfQ0KDQpjb21tZXJjZXNfb3NtX2FsbF9zZiA8LSBzdF9hc19zZihwaXN0ZXNfY3ljbGFibGVzKQ0KIyBzdF93cml0ZShjb21tZXJjZXNfb3NtX2FsbF9zZiwgcGFzdGUwKCJwcm9jZXNzZWRfZGF0YS9waXN0ZXNfY3ljbGFibGVzXyIsICIyIiwiLmdwa2ciKSkNCmBgYA0KDQo8YnI+DQogIA0KPGNlbnRlcj4NCiFbXShpbWFnZXMvaGlnaHdheV9jeWNsZXdheS5qcGcpICANCipGaWd1cmUgMSA6IGhpZ2h3YXkgLyBjeWNsZXdheSAjIFdoZW4gY3ljbGV3YXkgaXMgZHJhd24gYXMgaXRzIG93biB3YXkgKiAgDQo8L2NlbnRlcj4NCg0KDQo8Y2VudGVyPg0KIVtdKGltYWdlcy9iaWN5Y2xlX2Rlc2lnbmF0ZWQuanBnKSAgDQoqRmlndXJlIDIgOiBiaWN5Y2xlIC8gZGVzaWduYXRlZCAjIFdoZXJlIGEgd2F5IGhhcyBiZWVuIHNwZWNpYWxseSBkZXNpZ25hdGVkICh0eXBpY2FsbHkgYnkgYSBnb3Zlcm5tZW50KSBmb3IgYmljeWNsZSB1c2UqICANCjxicj4NCjwvY2VudGVyPg0KDQoNCjxjZW50ZXI+DQohW10oaW1hZ2VzL2N5Y2xld2F5X2xhbmUuanBnKSAgDQoqRmlndXJlIDMgOiBjeWNsZXdheSAvIGxhbmUgIyBDeWNsZXdheSB0YWdnZWQgb24gdGhlIG1haW4gcm9hZHdheSBvciBsYW5lLCBBIGxhbmUgaXMgYSByb3V0ZSB0aGF0IGxpZXMgd2l0aGluIHRoZSByb2Fkd2F5KiAgDQo8YnI+DQo8L2NlbnRlcj4NCg0KDQoNCiMjIFRSQU5TUE9SVCBQVUJMSUMNCg0KU291cmNlIDogaHR0cHM6Ly9kYXRhLmdvdXYuZnIvZnIvZGF0YXNldHMvcG9zaXRpb24tZGVzLWFycmV0cy1kZS10cmFuc3BvcnQtZXQtdHJhY2VzLWRlLWxpZ25lcy8NCg0KPGJyPg0KPGJyPg0KPGJyPg0KPGJyPg0KDQoNCg0KDQojIyBTSVJFTkUNCg0KYGBge3IsIGV2YWw9Rn0NCg0KDQpwYWNtYW46OnBfbG9hZChkcGx5cikNCg0KDQpiYXNlX3NpcmVuZSA8LSByZWFkLmNzdjIoIkM6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvU0lSRU5FL1N0b2NrRXRhYmxpc3NlbWVudF91dGY4L1N0b2NrRXRhYmxpc3NlbWVudF91dGY4LmNzdiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIsIikNCm5hbWVzKGJhc2Vfc2lyZW5lKQ0KDQojIEZpbHRyZSBzdXIgbGVzIMOpdGFibGlzc2VtZW50cyBhY3RpZnMNCmJhc2Vfc2lyZW5lX2FjdGlmIDwtIGJhc2Vfc2lyZW5lICU+JSANCiAgZHBseXI6OmZpbHRlcihldGF0QWRtaW5pc3RyYXRpZkV0YWJsaXNzZW1lbnQgPT0gIkEiKQ0KDQpybShiYXNlX3NpcmVuZSkNCg0KDQoNCmxpc3QuZmlsZXMoJ0M6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvU0lSRU5FL2dlb2xvY2FsaXNhdGlvbmV0YWJsaXNzZW1lbnQtc2lyZW5lLXBvdXItZXR1ZGVzLXN0YXRpc3RpcXVlcy1kdS0yMS1ub3ZlbWJyZS0yMDIzJykNCg0KIyBDaGFyZ2VtZW50IGR1IGZpY2hpZXIgZ8Opb2xvY2FsaXPDqQ0Kc2lyZW5lX2dlb2xvYyA8LSByZWFkLmNzdigiQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9TSVJFTkUvZ2VvbG9jYWxpc2F0aW9uZXRhYmxpc3NlbWVudC1zaXJlbmUtcG91ci1ldHVkZXMtc3RhdGlzdGlxdWVzLWR1LTIxLW5vdmVtYnJlLTIwMjMvR2VvbG9jYWxpc2F0aW9uRXRhYmxpc3NlbWVudF9TaXJlbmVfcG91cl9ldHVkZXNfc3RhdGlzdGlxdWVzX3V0ZjguY3N2IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlcD0iOyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBkZWM9Ii4iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCkNCg0KDQojIEpvaW50dXJlIEfDqW9sb2NhbGlzYXRpb24gLyBjb2RlIGFjdGl2aXTDqXMgOiAqKmpvaW50dXJlIHBhciBsZSBTSVJFVCoqDQpzdG9ja19nZW9sb2MgPC0gbGVmdF9qb2luKGJhc2Vfc2lyZW5lX2FjdGlmLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2lyZW5lX2dlb2xvYywgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygic2lyZXQiKSkNCg0KIyBTdXBwcmVzc2lvbiBkZXMgYWRyZXNzZXMgc2FucyBjb29yZG9ubsOpZXMNCmdlb2xvY19zYW5zX05BIDwtIHN0b2NrX2dlb2xvYyAlPiUgDQogIGZpbHRlcighaXMubmEoeF9sb25naXR1ZGUpKQ0KDQojIENyw6lhdGlvbiBkJ3VuZSB2YXJpYWJsZSBkw6lwYXJ0ZW1lbnQNCmdlb2xvY19zYW5zX05BJGRlcGFydGVtZW50IDwtIGdlb2xvY19zYW5zX05BJGNvZGVQb3N0YWxFdGFibGlzc2VtZW50ICUvJSAxMDAwKjEwMDANCg0Kcm0oYmFzZV9zaXJlbmVfYWN0aWYpDQpybShzaXJlbmVfZ2VvbG9jKQ0Kcm0oc3RvY2tfZ2VvbG9jKQ0KDQpnZXR3ZCgpDQojIHNhdmUuaW1hZ2UoIkM6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvTW9uRW52aXJvbm5lbWVudC5SRGF0YSIpDQojIE1lIHBlcm1ldCBkZSBjaGFyZ2VyIGxhIGJhc2UgU0lSRU5FIGRlcyDDqXRhYmxpc3NlbWVudHMgYWN0aWZzDQojIGxvYWQoIkM6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvTW9uRW52aXJvbm5lbWVudC5SRGF0YSIpDQoNCg0KbmFtZXMoZ2VvbG9jX3NhbnNfTkEpDQoNCg0KIyBGaWx0cmUgc3VyIGxlcyAgbG9pc2lycw0KYmFzZV9zaXJlbmVfbG9pc2lycyA8LSBnZW9sb2Nfc2Fuc19OQSAlPiUNCiAgZHBseXI6OmZpbHRlcihhY3Rpdml0ZVByaW5jaXBhbGVFdGFibGlzc2VtZW50ICVpbiUgYygNCiAgICAgICI5MC4wMVoiLCMgQXJ0cyBkdSBzcGVjdGFjbGUgdml2YW50DQogICAgICAiOTAuMDRaIiwjIEdlc3Rpb24gZGUgc2FsbGVzIGRlIHNwZWN0YWNsZXMgDQogICAgICAiOTMuMjFaIiwjIEFjdGl2aXTDqXMgZGVzIHBhcmNzIGTigJlhdHRyYWN0aW9ucyBldCBwYXJjcyDDoCB0aMOobWVzDQogICAgICAiOTMuMjlaIiwjIEF1dHJlcyBhY3Rpdml0w6lzIHLDqWNyw6lhdGl2ZXMgZXQgZGUgbG9pc2lycw0KICAgICAgIjkxLjAxWiIsIyBHZXN0aW9uIGRlcyBiaWJsaW90aMOocXVlcyBldCBkZXMgYXJjaGl2ZXMNCiAgICAgICI5MS4wMloiLCMgR2VzdGlvbiBkZXMgbXVzw6llcyANCiAgICAgICI5MS4wM1oiLCMgR2VzdGlvbiBkZXMgc2l0ZXMgZXQgbW9udW1lbnRzIGhpc3RvcmlxdWVzIGV0IGRlcyBhdHRyYWN0aW9ucyB0b3VyaXN0aXF1ZXMgc2ltaWxhaXJlcyANCiAgICAgICI5MS4wNFoiLCMgR2VzdGlvbiBkZXMgamFyZGlucyBib3RhbmlxdWVzIGV0IHpvb2xvZ2lxdWVzIGV0IGRlcyByw6lzZXJ2ZXMgbmF0dXJlbGxlcyANCiAgICAgICI5Mi4wMFoiICMgT3JnYW5pc2F0aW9uIGRlIGpldXggZGUgaGFzYXJkIGV0IGTigJlhcmdlbnQNCiAgICApDQogICkNCg0KDQpnZXR3ZCgpDQpsaXN0LmZpbGVzKCdwcm9jZXNzZWRfZGF0YScpDQpzZjo6c3Rfd3JpdGUoYmFzZV9zaXJlbmVfbG9pc2lycywgJ3Byb2Nlc3NlZF9kYXRhL2Jhc2Vfc2lyZW5lX2xvaXNpcnMuZ3BrZycpDQoNCiMgZMOpcGxhY8OpIGljaSA6IEM6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvU0lSRU5FLw0KDQojIEZpbHRyZSBzdXIgc2FudMOpDQpiYXNlX3NpcmVuZV9zYW50ZSA8LSBnZW9sb2Nfc2Fuc19OQSAlPiUNCiAgZHBseXI6OmZpbHRlcigNCiAgICBhY3Rpdml0ZVByaW5jaXBhbGVFdGFibGlzc2VtZW50ICVpbiUgYygNCiAgICAgICI4Ni4yM1oiLCMgUHJhdGlxdWUgZGVudGFpcmUgDQogICAgICAiODYuMjFaIiwjIEFjdGl2aXTDqSBkZXMgbcOpZGVjaW5zIGfDqW7DqXJhbGlzdGVzDQogICAgICAiODYuMjJBIiwjIEFjdGl2aXTDqXMgZGUgcmFkaW9kaWFnbm9zdGljIGV0IGRlIHJhZGlvdGjDqXJhcGllDQogICAgICAiODYuMjJCIiwjIEFjdGl2aXTDqXMgY2hpcnVyZ2ljYWxlcyANCiAgICAgICI4Ni4yMkMiLCMgQXV0cmVzIGFjdGl2aXTDqXMgZGVzIG3DqWRlY2lucyBzcMOpY2lhbGlzdGVzDQogICAgICAiODYuMTBaIiAjIEFjdGl2aXTDqXMgaG9zcGl0YWxpw6hyZXMgDQogICAgKQ0KICApDQoNCnNmOjpzdF93cml0ZShiYXNlX3NpcmVuZV9zYW50ZSwgJ3Byb2Nlc3NlZF9kYXRhL2Jhc2Vfc2lyZW5lX3NhbnRlLmdwa2cnKQ0KDQojIGTDqXBsYWPDqSBpY2kgOiBDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9SQUlMRU5JVU0vQkREX1RFTExJL1NJUkVORS8NCg0KIyBGaWx0cmUgc3VyIGNvbW1lcmNlcw0KYmFzZV9zaXJlbmVfY29tbWVyY2VzIDwtIGdlb2xvY19zYW5zX05BICU+JQ0KICBkcGx5cjo6ZmlsdGVyKA0KICAgIGFjdGl2aXRlUHJpbmNpcGFsZUV0YWJsaXNzZW1lbnQgJWluJSBjKA0KICAgICAgIjEwLjcxQyIsIyBCb3VsYW5nZXJpZSBldCBib3VsYW5nZXJpZS1ww6J0aXNzZXJpZQ0KICAgICAgIjEwLjcxRCIsIyBQw6J0aXNzZXJpZSANCiAgICAgICIxMC43MUIiLCMgQ3Vpc3NvbiBkZSBwcm9kdWl0cyBkZSBib3VsYW5nZXJpZQ0KICAgICAgIjEwLjEzQiIsIyBDaGFyY3V0ZXJpZSANCiAgICAgICI0Ny4yMVoiLCMgQ29tbWVyY2UgZGUgZMOpdGFpbCBkZSBmcnVpdHMgZXQgbMOpZ3VtZXMgZW4gbWFnYXNpbiBzcMOpY2lhbGlzw6kgDQogICAgICAiNDcuMTFBIiwjIENvbW1lcmNlIGRlIGTDqXRhaWwgZGUgcHJvZHVpdHMgc3VyZ2Vsw6lzDQogICAgICAiNDcuMTFCIiwjIENvbW1lcmNlIGTigJlhbGltZW50YXRpb24gZ8OpbsOpcmFsZQ0KICAgICAgIjQ3LjExQyIsIyBTdXDDqXJldHRlcyANCiAgICAgICI0Ny4xMUQiLCMgU3VwZXJtYXJjaMOpcyANCiAgICAgICI0Ny4xMUUiLCMgTWFnYXNpbnMgbXVsdGktY29tbWVyY2VzDQogICAgICAiNDcuMTFGIiwjIEh5cGVybWFyY2jDqXMgDQogICAgICAiNDcuMTlBIiwjIENvbW1lcmNlIGRlIGTDqXRhaWwgbm9uIGFsaW1lbnRhaXJlIA0KICAgICAgIjQ3LjE5QiIsIyBBdXRyZXMgY29tbWVyY2VzIGRlIGTDqXRhaWwgZW4gbWFnYXNpbiBub24gc3DDqWNpYWxpc8OpDQogICAgICAiNDcuNzFaIiwjIENvbW1lcmNlIGRlIGTDqXRhaWwgZOKAmWhhYmlsbGVtZW50IGVuIG1hZ2FzaW4gc3DDqWNpYWxpc8OpDQogICAgICAiNDcuNzJBIiwjIENvbW1lcmNlIGRlIGTDqXRhaWwgZGUgbGEgY2hhdXNzdXJlDQogICAgICAiNDcuNzJCIiAjIENvbW1lcmNlIGRlIGTDqXRhaWwgZGUgbWFyb3F1aW5lcmllIGV0IGTigJlhcnRpY2xlcyBkZSB2b3lhZ2UNCiAgICApDQogICkNCg0Kc2Y6OnN0X3dyaXRlKGJhc2Vfc2lyZW5lX2NvbW1lcmNlcywgJ3Byb2Nlc3NlZF9kYXRhL2Jhc2Vfc2lyZW5lX2NvbW1lcmNlcy5ncGtnJykNCg0KIyBkw6lwbGFjw6kgaWNpIDogQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9TSVJFTkUvDQoNCg0KIyBGaWx0cmUgc3VyIHJlc3RhdXJhdGlvbg0KYmFzZV9zaXJlbmVfcmVzdGF1cmF0aW9uIDwtIGdlb2xvY19zYW5zX05BICU+JQ0KICBkcGx5cjo6ZmlsdGVyKA0KICAgIGFjdGl2aXRlUHJpbmNpcGFsZUV0YWJsaXNzZW1lbnQgJWluJSBjKA0KICAgICAgIjU2LjMwWiIsIyBEw6liaXRzIGRlIGJvaXNzb24gDQogICAgICAiNTYuMTBBIiwjIFJlc3RhdXJhdGlvbiB0cmFkaXRpb25uZWxsZSANCiAgICAgICI1Ni4xMEIiLCMgQ2Fmw6l0w6lyaWFzIGV0IGF1dHJlcyBsaWJyZXMtc2VydmljZXMgDQogICAgICAiNTYuMTBDIiAjIFJlc3RhdXJhdGlvbiBkZSB0eXBlIHJhcGlkZQ0KICAgICkNCiAgKQ0KDQpzZjo6c3Rfd3JpdGUoYmFzZV9zaXJlbmVfcmVzdGF1cmF0aW9uLCAncHJvY2Vzc2VkX2RhdGEvYmFzZV9zaXJlbmVfcmVzdGF1cmF0aW9uLmdwa2cnKQ0KDQojIGTDqXBsYWPDqSBpY2kgOiBDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9SQUlMRU5JVU0vQkREX1RFTExJL1NJUkVORS8NCg0KDQojIEZpbHRyZSBzdXIgc3BvcnQNCmJhc2Vfc2lyZW5lX3Nwb3J0IDwtIGdlb2xvY19zYW5zX05BICU+JQ0KICBkcGx5cjo6ZmlsdGVyKA0KICAgIGFjdGl2aXRlUHJpbmNpcGFsZUV0YWJsaXNzZW1lbnQgJWluJSBjKA0KICAgICAgIjkzLjExWiIsIyBHZXN0aW9uIGTigJlpbnN0YWxsYXRpb25zIHNwb3J0aXZlcw0KICAgICAgIjkzLjEzWiIgIyBBY3Rpdml0w6lzIGRlcyBjZW50cmVzIGRlIGN1bHR1cmUgcGh5c2lxdWUNCiAgICApDQogICkNCg0Kc2Y6OnN0X3dyaXRlKGJhc2Vfc2lyZW5lX3Nwb3J0LCAncHJvY2Vzc2VkX2RhdGEvYmFzZV9zaXJlbmVfc3BvcnQuZ3BrZycpDQoNCiMgZMOpcGxhY8OpIGljaSA6IEM6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvU0lSRU5FLw0KDQojIEZpbHRyZSBzdXIgdG91dA0KYmFzZV9zaXJlbmVfbG9pc2lycyA8LSBnZW9sb2Nfc2Fuc19OQSAlPiUNCiAgZHBseXI6OmZpbHRlcigNCiAgICBhY3Rpdml0ZVByaW5jaXBhbGVFdGFibGlzc2VtZW50ICVpbiUgYygNCiAgICAgICI5MC4wMVoiLCMgQXJ0cyBkdSBzcGVjdGFjbGUgdml2YW50DQogICAgICAiOTAuMDRaIiwjIEdlc3Rpb24gZGUgc2FsbGVzIGRlIHNwZWN0YWNsZXMgDQogICAgICAiOTMuMjFaIiwjIEFjdGl2aXTDqXMgZGVzIHBhcmNzIGTigJlhdHRyYWN0aW9ucyBldCBwYXJjcyDDoCB0aMOobWVzDQogICAgICAiOTMuMjlaIiwjIEF1dHJlcyBhY3Rpdml0w6lzIHLDqWNyw6lhdGl2ZXMgZXQgZGUgbG9pc2lycw0KICAgICAgIjkxLjAxWiIsIyBHZXN0aW9uIGRlcyBiaWJsaW90aMOocXVlcyBldCBkZXMgYXJjaGl2ZXMNCiAgICAgICI5MS4wMloiLCMgR2VzdGlvbiBkZXMgbXVzw6llcyANCiAgICAgICI5MS4wM1oiLCMgR2VzdGlvbiBkZXMgc2l0ZXMgZXQgbW9udW1lbnRzIGhpc3RvcmlxdWVzIGV0IGRlcyBhdHRyYWN0aW9ucyB0b3VyaXN0aXF1ZXMgc2ltaWxhaXJlcyANCiAgICAgICI5MS4wNFoiLCMgR2VzdGlvbiBkZXMgamFyZGlucyBib3RhbmlxdWVzIGV0IHpvb2xvZ2lxdWVzIGV0IGRlcyByw6lzZXJ2ZXMgbmF0dXJlbGxlcyANCiAgICAgICI5Mi4wMFoiLCMgT3JnYW5pc2F0aW9uIGRlIGpldXggZGUgaGFzYXJkIGV0IGTigJlhcmdlbnQgIA0KICAgICAgIjg2LjIzWiIsIyBQcmF0aXF1ZSBkZW50YWlyZSANCiAgICAgICI4Ni4yMVoiLCMgQWN0aXZpdMOpIGRlcyBtw6lkZWNpbnMgZ8OpbsOpcmFsaXN0ZXMNCiAgICAgICI4Ni4yMkEiLCMgQWN0aXZpdMOpcyBkZSByYWRpb2RpYWdub3N0aWMgZXQgZGUgcmFkaW90aMOpcmFwaWUNCiAgICAgICI4Ni4yMkIiLCMgQWN0aXZpdMOpcyBjaGlydXJnaWNhbGVzIA0KICAgICAgIjg2LjIyQyIsIyBBdXRyZXMgYWN0aXZpdMOpcyBkZXMgbcOpZGVjaW5zIHNww6ljaWFsaXN0ZXMNCiAgICAgICI4Ni4xMFoiLCMgQWN0aXZpdMOpcyBob3NwaXRhbGnDqHJlcyANCiAgICAgICIxMC43MUMiLCMgQm91bGFuZ2VyaWUgZXQgYm91bGFuZ2VyaWUtcMOidGlzc2VyaWUNCiAgICAgICIxMC43MUQiLCMgUMOidGlzc2VyaWUgDQogICAgICAiMTAuNzFCIiwjIEN1aXNzb24gZGUgcHJvZHVpdHMgZGUgYm91bGFuZ2VyaWUNCiAgICAgICIxMC4xM0IiLCMgQ2hhcmN1dGVyaWUgDQogICAgICAiNDcuMjFaIiwjIENvbW1lcmNlIGRlIGTDqXRhaWwgZGUgZnJ1aXRzIGV0IGzDqWd1bWVzIGVuIG1hZ2FzaW4gc3DDqWNpYWxpc8OpIA0KICAgICAgIjQ3LjExQSIsIyBDb21tZXJjZSBkZSBkw6l0YWlsIGRlIHByb2R1aXRzIHN1cmdlbMOpcw0KICAgICAgIjQ3LjExQiIsIyBDb21tZXJjZSBk4oCZYWxpbWVudGF0aW9uIGfDqW7DqXJhbGUNCiAgICAgICI0Ny4xMUMiLCMgU3Vww6lyZXR0ZXMgDQogICAgICAiNDcuMTFEIiwjIFN1cGVybWFyY2jDqXMgDQogICAgICAiNDcuMTFFIiwjIE1hZ2FzaW5zIG11bHRpLWNvbW1lcmNlcw0KICAgICAgIjQ3LjExRiIsIyBIeXBlcm1hcmNow6lzIA0KICAgICAgIjQ3LjE5QSIsIyBDb21tZXJjZSBkZSBkw6l0YWlsIG5vbiBhbGltZW50YWlyZSANCiAgICAgICI0Ny4xOUIiLCMgQXV0cmVzIGNvbW1lcmNlcyBkZSBkw6l0YWlsIGVuIG1hZ2FzaW4gbm9uIHNww6ljaWFsaXPDqQ0KICAgICAgIjQ3LjcxWiIsIyBDb21tZXJjZSBkZSBkw6l0YWlsIGTigJloYWJpbGxlbWVudCBlbiBtYWdhc2luIHNww6ljaWFsaXPDqQ0KICAgICAgIjQ3LjcyQSIsIyBDb21tZXJjZSBkZSBkw6l0YWlsIGRlIGxhIGNoYXVzc3VyZQ0KICAgICAgIjQ3LjcyQiIsIyBDb21tZXJjZSBkZSBkw6l0YWlsIGRlIG1hcm9xdWluZXJpZSBldCBk4oCZYXJ0aWNsZXMgZGUgdm95YWdlDQogICAgICAiNTYuMzBaIiwjIETDqWJpdHMgZGUgYm9pc3NvbiANCiAgICAgICI1Ni4xMEEiLCMgUmVzdGF1cmF0aW9uIHRyYWRpdGlvbm5lbGxlIA0KICAgICAgIjU2LjEwQiIsIyBDYWbDqXTDqXJpYXMgZXQgYXV0cmVzIGxpYnJlcy1zZXJ2aWNlcyANCiAgICAgICI1Ni4xMEMiLCMgUmVzdGF1cmF0aW9uIGRlIHR5cGUgcmFwaWRlDQogICAgICAiOTMuMTFaIiwjIEdlc3Rpb24gZOKAmWluc3RhbGxhdGlvbnMgc3BvcnRpdmVzDQogICAgICAiOTMuMTNaIiAjIEFjdGl2aXTDqXMgZGVzIGNlbnRyZXMgZGUgY3VsdHVyZSBwaHlzaXF1ZQ0KICAgICAgDQogICAgKQ0KICApDQpgYGANCg0KDQojIyBTTkNGDQoNCkxpZW4gdmVycyBsYSBzb3VyY2UgOiBbRG9ubsOpZXMgT3BlbiBEYXRhIFNOQ0ZdKGh0dHBzOi8vcmVzc291cmNlcy5kYXRhLnNuY2YuY29tL2V4cGxvcmUvZGF0YXNldC9saXN0ZS1kZXMtcGFzc2FnZXMtYS1uaXZlYXUvbWFwLz9sb2NhdGlvbj0xNCZiYXNlbWFwPTYzYTQxNikNCg0KYGBge3IsIGVjaG8gPSBULCBldmFsID0gRn0NCmxpc3RlX2Rlc19wYXNzYWdlc19hX25pdmVhdSA8LSBzZjo6c3RfcmVhZCgnZGF0YS9saXN0ZS1kZXMtcGFzc2FnZXMtYS1uaXZlYXUvbGlzdGUtZGVzLXBhc3NhZ2VzLWEtbml2ZWF1LnNocCcpDQoNCmBgYA0KDQojIyBNTlQNCg0KRG9ubsOpZXMgcmVjdWVpbGxlcyBwb3VyIGxlIGNhbGN1bCBkZSBsYSBwZW50ZSBtb3llbm5lIGRhbnMgY2hhcXVlIGlzb2Nocm9uZS4gIA0KDQoNCmBgYHtyLCBvdXQud2lkdGg9JzEwMCUnLCBldmFsPSBGfQ0KIyBEb25uw6llcyBNTlQgSUdODQpyYXNfbHN0IDwtIGxpc3QuZmlsZXMoJ0M6L1VzZXJzL290aGV1cmVhdXgvRG93bmxvYWRzL1JHRUFMVElfMi0wXzVNX0FTQ19MQU1COTMtSUdONjlfRDA2Ml8yMDIxLTA5LTIwL1JHRUFMVElfMi0wXzVNX0FTQ19MQU1COTMtSUdONjlfRDA2Ml8yMDIxLTA5LTIwL1JHRUFMVEkvJywgDQogICAgICAgICAgICAgICAgICAgICAgZnVsbC5uYW1lcyA9IFQsIA0KICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLmFzYyQiLCANCiAgICAgICAgICAgICAgICAgICAgICByZWN1cnNpdmUgPSBUKSAjIHPDqWxlY3Rpb24gZGUgdG91dGVzIGxlcyBkYWxsZXMNCmhlYWQocmFzX2xzdCkNCnRlcnJhOjp2cnQocmFzX2xzdCwgDQogICAgICAgICAgICJDOi9Vc2Vycy9vdGhldXJlYXV4L0Rvd25sb2Fkcy9uZXcudnJ0IiwgIyBuYW1lIG9mIHZpcnR1YWwgcmFzdGVyLCANCiAgICAgICAgICAgb3ZlcndyaXRlID0gVCkgIyBjcsOpYXRpb24gZHUgcmFzdGVyIHZpcnR1ZWwNCnJhcyA8LSByYXN0ZXI6OnJhc3RlcigiQzovVXNlcnMvb3RoZXVyZWF1eC9Eb3dubG9hZHMvbmV3LnZydCIpDQpyYXN0ZXI6OmNycyhyYXMpIDwtICJFUFNHOjIxNTQiDQoNCm1hcHZpZXcocmFzKQ0KYGBgDQoNCmBgYHtyLCBvdXQud2lkdGg9JzEwMCUnLCBldmFsPSBGfQ0KIyBDYWxjdWwgZHUgbm9tYnJlIGRlIHJvbmRzLXBvaW50cw0KYWxsX3N1bSA8LSBsaXN0KCkNCg0KIyBJbml0aWFsaXNhdGlvbiBkdSBjb21wdGV1cg0KY29tcHRldXIgPC0gMA0KDQpmb3IoaSBpbiAxOm5yb3coYWxsX2lzb2Nocm9uZXMpKSB7DQogIG1udF9pbnRlcnNlY3Rpb24gPC0gcmFzdGVyOjpjcm9wKHJhcywgYWxsX2lzb2Nocm9uZXNbaSxdKQ0KICBhIDwtIHJhc3Rlcjo6bWFzayhtbnRfaW50ZXJzZWN0aW9uLCBhbGxfaXNvY2hyb25lc1tpLF0pDQogICMgbWFwdmlldyhhKQ0KICANCiAgYiA8LSBxZ2lzX3J1bl9hbGdvcml0aG0oIm5hdGl2ZTpzbG9wZSIsIA0KICAgIElOUFVUID0gYSwgDQogICAgT1VUUFVUID0gcGFzdGUoJ0M6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9ET05ORUVTX0NBUlRPL3Jhc3Rlci9tbnQvJywgDQogICAgICAgICAgICAgICAgICAgaSwgDQogICAgICAgICAgICAgICAgICAgIi50aWYiKSkNCiAgYl9yYXMgPC0gcmFzdGVyOjpyYXN0ZXIocGFzdGUoJ0M6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9ET05ORUVTX0NBUlRPL3Jhc3Rlci9tbnQvJywgDQogICAgICAgICAgICAgICAgICAgICAgICBpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICIudGlmIikpDQogIA0KICBtZWFuIDwtIHJhc3Rlcjo6Y2VsbFN0YXRzKGJfcmFzLCANCiAgICAgICAgICAgICAgICAgICAgc3RhdCA9ICJtZWFuIiwgDQogICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkNCiAgDQogICAgc3VtIDwtIGRhdGEuZnJhbWUocGVudGVfbW95ZW5uZSA9IG1lYW4sIA0KICAgICAgICAgICAgICAgICAgICAgIElEX251bWJlciA9IGFsbF9pc29jaHJvbmVzJHBvaW50LklEX251bWJlcltpXSkNCiAgICANCiAgDQogIA0KICBhbGxfc3VtW1tpXV0gPC0gc3VtDQogIA0KICAjIEluY3LDqW1lbnRlciBsZSBjb21wdGV1ciBhcHLDqHMgY2hhcXVlIGl0w6lyYXRpb24gcsOpdXNzaWUNCiAgY29tcHRldXIgPC0gY29tcHRldXIgKyAxDQogIA0KICAjIEFmZmljaGVyIGxlIHByb2dyw6hzIHNpIG7DqWNlc3NhaXJlDQogIGlmIChjb21wdGV1ciAlJSAxMCA9PSAwKSB7ICAjIEFmZmljaGUgbGUgcHJvZ3LDqHMgdG91dGVzIGxlcyAxMCBpdMOpcmF0aW9ucw0KICAgIG1lc3NhZ2UoIk5vbWJyZSBkJ2l0w6lyYXRpb25zIGNvbXBsw6l0w6llcyA6ICIsIGNvbXB0ZXVyKQ0KICB9ICANCn0NCmBgYA0KDQojIyBQTlINCg0KUG91ciBwbHVzIGRlIGTDqXRhaWxzIHN1ciBsYSBjb3VjaGUgZGVzIFBOUiB2b3VzIHBvdXZleiBjb25zdWx0ZXIgY2UgDQo8YSBocmVmPSJodHRwczovL3d3dy5kYXRhLmdvdXYuZnIvZnIvZGF0YXNldHMvcGFyY3MtbmF0dXJlbHMtcmVnaW9uYXV4LXBuci1mcmFuY2UtbWV0cm9wb2xpdGFpbmUvIiB0YXJnZXQ9Il9ibGFuayI+bGllbi4NCjwvYT4NCg0KDQpgYGB7ciwgZXZhbCA9IEZ9DQpQTlIgPC0gc2Y6OnN0X3JlYWQoJ0M6L1VzZXJzL290aGV1cmVhdXgvRG9jdW1lbnRzL09UL1JBSUxFTklVTS9CRERfVEVMTEkvZnJhbmNlX3Bucl9wb2x5Z29uL2ZyYW5jZV9wbnJfcG9seWdvblBvbHlnb24uc2hwJykgIA0KDQpgYGANCg0KDQojIyBFTVBSSVNFUw0KDQoqICoqRnJhbmNlKiogIA0KYGBge3IsIGV2YWw9Rn0NCmVtcHJpc2VfZnJhbmNlIDwtIHNmOjpzdF9yZWFkKCJDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9ERUNPVVBBR0VTX0ZSL0ZSQU5DRV9NRVRST18yMTU0Lmdwa2ciKQ0KYGBgDQoNCiogKipSw6lnaW9ucyoqDQpgYGB7ciwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KcmVnaW9uc19GUiA8LSBzZjo6c3RfcmVhZCgiQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvREVDT1VQQUdFU19GUi9SRUdJT04uc2hwIikNCmBgYA0KDQoNCiogKipEw6lwYXJ0ZW1lbnRzIEZyYW5jZSoqDQpgYGB7ciwgZXZhbD1GfQ0KZGVwYXJ0ZW1lbnRzIDwtIHNmOjpzdF9yZWFkKCJDOi9Vc2Vycy9vdGhldXJlYXV4L0RvY3VtZW50cy9PVC9ERUNPVVBBR0VTX0ZSL0RFUEFSVEVNRU5ULnNocCIpDQpgYGANCg0KDQoqICoqQ29tbXVuZXMgRnJhbmNlKioNCmBgYHtyLCBldmFsPUZ9DQpjb21tdW5lcyA8LSBzZjo6c3RfcmVhZCgiQzovVXNlcnMvb3RoZXVyZWF1eC9Eb2N1bWVudHMvT1QvUkFJTEVOSVVNL0JERF9URUxMSS9DT01NVU5FUy9jb21tdW5lLnNocCIpDQoNCmBgYA0KDQoNCiMgQ2l0YXRpb24NCg0KUG91ciBjaXRlciBjZXMgdHJhdmF1eCA6DQoNCk9saXZpZXIgVGhldXJlYXV4LiBuLmQuIOKAnFR1dG9yaWVscyBSIGRhbnMgbGUgY2FkcmUgZCd1bmUgbWlzc2lvbiBkZSBnw6lvbWF0aWNpZW4gYXUgc2VpbiBkdSBMVk1U4oCd