Mexico and Its Attractiveness for Nearshoring

Introduction

In a rapidly changing global environment marked by trade wars, geopolitical tensions, and health crises such as the COVID-19 pandemic, countries and businesses are re-evaluating their supply chain strategies. One such strategy gaining traction is ‘nearshoring’. Mexico, with its proximity to the US market, has emerged as a potential hub for this strategy. This document aims to analyze Mexico’s attractiveness as a nearshoring destination and understand the specific factors influencing this appeal.

Problem Context

Several factors have disrupted the global supply chain: - The spread of COVID-19 from its epicenter in Wuhan, China. - China, known as the “factory of the world”, experiencing a halt in business activities. - Ongoing US-China trade tensions since 2017. - Escalation of conflict between Russia and Ukraine in 2022.

Due to these disruptions, there’s a need for international companies to diversify their production chains to reduce dependency on any single region.

Nearshoring as a Solution

Nearshoring involves relocating business projects closer to end markets. Mexico’s strategic geographic location offers it a competitive advantage in this realm, potentially leading to significant economic growth.

Examples such as Tesla’s investment in Nuevo Leon in 2023 underline the increasing interest in Mexico for nearshoring purposes. However, to leverage this interest, it’s crucial to identify the factors that make Mexico attractive for such investments.

Analytical Approach

Using econometrics, we can analyze the conditions that Mexico offers for nearshoring. By tapping into databases from INEGI, Banxico, and the Ministry of Economy, we can explore factors like socioeconomic conditions, business environments, and technological capabilities. This will help in predicting the effect of nearshoring in Mexico and identify areas of opportunity for future investments.

Data Analysis

Below, we’ll analyze data that helps answer why Mexico is an appealing country for nearshoring:

Loading Necessary Libraries

library(foreign)
library(tidyverse)    # collection of R packages designed for data science
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.2     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.3     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.1     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)        # data manipulation 
library(forcats)      # to work with categorical variables
library(ggplot2)      # data visualization 
library(cowplot)      # for arranging plots
## 
## Attaching package: 'cowplot'
## 
## The following object is masked from 'package:lubridate':
## 
##     stamp
library(readr)        # read specific csv files
library(janitor)      # data exploration and cleaning 
## 
## Attaching package: 'janitor'
## 
## The following objects are masked from 'package:stats':
## 
##     chisq.test, fisher.test
library(Hmisc)        # several useful functions for data analysis 
## 
## Attaching package: 'Hmisc'
## 
## The following objects are masked from 'package:dplyr':
## 
##     src, summarize
## 
## The following objects are masked from 'package:base':
## 
##     format.pval, units
library(psych)        # functions for multivariate analysis 
## 
## Attaching package: 'psych'
## 
## The following object is masked from 'package:Hmisc':
## 
##     describe
## 
## The following objects are masked from 'package:ggplot2':
## 
##     %+%, alpha
library(naniar)       # summaries and visualization of missing values NA's
library(dlookr)       # summaries and visualization of missing values NA's
## 
## Attaching package: 'dlookr'
## 
## The following object is masked from 'package:psych':
## 
##     describe
## 
## The following object is masked from 'package:Hmisc':
## 
##     describe
## 
## The following object is masked from 'package:tidyr':
## 
##     extract
## 
## The following object is masked from 'package:base':
## 
##     transform
library(corrplot)     # correlation plots
## corrplot 0.92 loaded
library(jtools)       # presentation of regression analysis 
## 
## Attaching package: 'jtools'
## 
## The following object is masked from 'package:Hmisc':
## 
##     %nin%
library(lmtest)       # diagnostic checks - linear regression analysis 
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## 
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
library(car)          # diagnostic checks - linear regression analysis
## Loading required package: carData
## 
## Attaching package: 'car'
## 
## The following object is masked from 'package:psych':
## 
##     logit
## 
## The following object is masked from 'package:dplyr':
## 
##     recode
## 
## The following object is masked from 'package:purrr':
## 
##     some
library(olsrr)        # diagnostic checks - linear regression analysis 
## 
## Attaching package: 'olsrr'
## 
## The following object is masked from 'package:datasets':
## 
##     rivers
library(naniar)       # identifying missing values
library(stargazer)    # create publication quality tables
## 
## Please cite as: 
## 
##  Hlavac, Marek (2022). stargazer: Well-Formatted Regression and Summary Statistics Tables.
##  R package version 5.2.3. https://CRAN.R-project.org/package=stargazer
library(effects)      # displays for linear and other regression models
## Registered S3 method overwritten by 'survey':
##   method      from  
##   summary.pps dlookr
## lattice theme set by effectsTheme()
## See ?effectsTheme for details.
library(caret)        # Classification and Regression Training 
## Loading required package: lattice
## 
## Attaching package: 'caret'
## 
## The following object is masked from 'package:purrr':
## 
##     lift
library(glmnet)       # methods for prediction and plotting, and functions for cross-validation
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## 
## The following objects are masked from 'package:tidyr':
## 
##     expand, pack, unpack
## 
## Loaded glmnet 4.1-7

Reading the Data

# Reading the dataset
sp_data <- read.csv("/Users/daviddrums180/Desktop/sp_data.csv")

# Getting a glimpse of the data
head(sp_data)
##   periodo IED_Flujos    IED_M Exportaciones Exportaciones_m Empleo Educacion
## 1    1997   12145.60 294151.2       9087.62        220090.8     NA      7.20
## 2    1998    8373.50 210875.6       9875.07        248690.6     NA      7.31
## 3    1999   13960.32 299734.4      10990.01        235960.5     NA      7.43
## 4    2000   18248.69 362631.8      12482.96        248057.2  97.83      7.56
## 5    2001   30057.18 546548.4      11300.44        205482.9  97.36      7.68
## 6    2002   24099.21 468332.0      11923.10        231707.6  97.66      7.80
##   Salario_Diario Innovacion Inseguridad_Robo Inseguridad_Homicidio
## 1          24.30      11.30           266.51                 14.55
## 2          31.91      11.37           314.78                 14.32
## 3          31.91      12.46           272.89                 12.64
## 4          35.12      13.15           216.98                 10.86
## 5          37.57      13.47           214.53                 10.25
## 6          39.74      12.80           197.80                  9.94
##   Tipo_de_Cambio Densidad_Carretera Densidad_Poblacion CO2_Emisiones
## 1           8.06               0.05              47.44          3.68
## 2           9.94               0.05              48.76          3.85
## 3           9.52               0.06              49.48          3.69
## 4           9.60               0.06              50.58          3.87
## 5           9.17               0.06              51.28          3.81
## 6          10.36               0.06              51.95          3.82
##   PIB_Per_Capita  INPC crisis_financiera
## 1       127570.1 33.28                 0
## 2       126738.8 39.47                 0
## 3       129164.7 44.34                 0
## 4       130874.9 48.31                 0
## 5       128083.4 50.43                 0
## 6       128205.9 53.31                 0

1. Exploratory Data Analisis

1.1. Descriptive Statistics

Descriptive statistics provide a quick overview of the central tendency, dispersion, and shape of the data distribution. We’ll start by examining measures like mean, median, and mode for the numerical columns.

# Descriptive statistics of the dataset
summary(sp_data)
##     periodo       IED_Flujos        IED_M        Exportaciones  
##  Min.   :1997   Min.   : 8374   Min.   :210876   Min.   : 9088  
##  1st Qu.:2003   1st Qu.:21367   1st Qu.:368560   1st Qu.:13260  
##  Median :2010   Median :27698   Median :497054   Median :21188  
##  Mean   :2010   Mean   :26770   Mean   :493596   Mean   :23601  
##  3rd Qu.:2016   3rd Qu.:32183   3rd Qu.:578606   3rd Qu.:31601  
##  Max.   :2022   Max.   :48354   Max.   :754438   Max.   :46478  
##                                                                 
##  Exportaciones_m      Empleo        Educacion     Salario_Diario  
##  Min.   :205483   Min.   :95.06   Min.   :7.200   Min.   : 24.30  
##  1st Qu.:262337   1st Qu.:95.89   1st Qu.:7.865   1st Qu.: 41.97  
##  Median :366294   Median :96.53   Median :8.460   Median : 54.48  
##  Mean   :433856   Mean   :96.47   Mean   :8.423   Mean   : 65.16  
##  3rd Qu.:632356   3rd Qu.:97.08   3rd Qu.:9.000   3rd Qu.: 72.31  
##  Max.   :785654   Max.   :97.83   Max.   :9.580   Max.   :172.87  
##                   NA's   :3       NA's   :3                       
##    Innovacion    Inseguridad_Robo Inseguridad_Homicidio Tipo_de_Cambio 
##  Min.   :11.28   Min.   :120.5    Min.   : 8.04         Min.   : 8.06  
##  1st Qu.:12.56   1st Qu.:148.3    1st Qu.:10.25         1st Qu.:10.75  
##  Median :13.09   Median :181.8    Median :16.93         Median :13.02  
##  Mean   :13.11   Mean   :185.4    Mean   :17.29         Mean   :13.91  
##  3rd Qu.:13.75   3rd Qu.:209.9    3rd Qu.:22.43         3rd Qu.:18.49  
##  Max.   :15.11   Max.   :314.8    Max.   :29.59         Max.   :20.66  
##  NA's   :2                        NA's   :1                            
##  Densidad_Carretera Densidad_Poblacion CO2_Emisiones   PIB_Per_Capita  
##  Min.   :0.05000    Min.   :47.44      Min.   :3.590   Min.   :126739  
##  1st Qu.:0.06000    1st Qu.:52.77      1st Qu.:3.830   1st Qu.:130964  
##  Median :0.07000    Median :58.09      Median :3.930   Median :136845  
##  Mean   :0.07115    Mean   :57.33      Mean   :3.945   Mean   :138550  
##  3rd Qu.:0.08000    3rd Qu.:61.39      3rd Qu.:4.105   3rd Qu.:146148  
##  Max.   :0.09000    Max.   :65.60      Max.   :4.220   Max.   :153236  
##                                        NA's   :3                       
##       INPC        crisis_financiera
##  Min.   : 33.28   Min.   :0.00000  
##  1st Qu.: 56.15   1st Qu.:0.00000  
##  Median : 73.35   Median :0.00000  
##  Mean   : 75.17   Mean   :0.07692  
##  3rd Qu.: 91.29   3rd Qu.:0.00000  
##  Max.   :126.48   Max.   :1.00000  
## 

1.1.2 Transform variablesd

Based on our understanding of the dataset, we can make several transformations to make our analysis more meaningful.

# Transforming 'periodo' into a factor (categorical variable)
# sp_data$periodo <- as.factor(sp_data$periodo)
sp_data$crisis_financiera <- as.factor(sp_data$crisis_financiera)

# Creating 'exportaciones_mx' by multiplying 'Exportaciones' and 'Tipo_de_Cambio'
# sp_data <- sp_data %>%
#  mutate(exportaciones_mx = Exportaciones * Tipo_de_Cambio)

# Creating 'salario_diario_mx' by multiplying 'Salario_Diario' and 'Tipo_de_Cambio'
sp_data <- sp_data %>%
  mutate(salario_diario_mx = Salario_Diario * Tipo_de_Cambio)

# Checking the first few rows to ensure our new variables are correctly added
head(sp_data)
##   periodo IED_Flujos    IED_M Exportaciones Exportaciones_m Empleo Educacion
## 1    1997   12145.60 294151.2       9087.62        220090.8     NA      7.20
## 2    1998    8373.50 210875.6       9875.07        248690.6     NA      7.31
## 3    1999   13960.32 299734.4      10990.01        235960.5     NA      7.43
## 4    2000   18248.69 362631.8      12482.96        248057.2  97.83      7.56
## 5    2001   30057.18 546548.4      11300.44        205482.9  97.36      7.68
## 6    2002   24099.21 468332.0      11923.10        231707.6  97.66      7.80
##   Salario_Diario Innovacion Inseguridad_Robo Inseguridad_Homicidio
## 1          24.30      11.30           266.51                 14.55
## 2          31.91      11.37           314.78                 14.32
## 3          31.91      12.46           272.89                 12.64
## 4          35.12      13.15           216.98                 10.86
## 5          37.57      13.47           214.53                 10.25
## 6          39.74      12.80           197.80                  9.94
##   Tipo_de_Cambio Densidad_Carretera Densidad_Poblacion CO2_Emisiones
## 1           8.06               0.05              47.44          3.68
## 2           9.94               0.05              48.76          3.85
## 3           9.52               0.06              49.48          3.69
## 4           9.60               0.06              50.58          3.87
## 5           9.17               0.06              51.28          3.81
## 6          10.36               0.06              51.95          3.82
##   PIB_Per_Capita  INPC crisis_financiera salario_diario_mx
## 1       127570.1 33.28                 0          195.8580
## 2       126738.8 39.47                 0          317.1854
## 3       129164.7 44.34                 0          303.7832
## 4       130874.9 48.31                 0          337.1520
## 5       128083.4 50.43                 0          344.5169
## 6       128205.9 53.31                 0          411.7064

1.2. Measures of Dispersion

While the summary function provides a quick overview that includes some measures of dispersion (like the min, max, 1st quartile, and 3rd quartile), we might want to delve deeper into certain columns. Here we’ll focus on variance and standard deviation.

# List of variables for which to compute variance and standard deviation
columns_to_check <- c("IED_Flujos", "Exportaciones", "Empleo", "Educacion", "Salario_Diario", 
                     "Innovacion", "Inseguridad_Robo", "Inseguridad_Homicidio", "Tipo_de_Cambio",
                     "Densidad_Carretera", "Densidad_Poblacion", "CO2_Emisiones", "PIB_Per_Capita", "INPC")

# Using sapply to compute variance and standard deviation for each column
variances <- sapply(sp_data[, columns_to_check], var, na.rm = TRUE)
std_devs <- sapply(sp_data[, columns_to_check], sd, na.rm = TRUE)

# Combining results into a data frame
dispersion_data <- data.frame(Variable = names(variances), 
                             Variance = variances, 
                             Standard_Deviation = std_devs)

dispersion_data
##                                    Variable     Variance Standard_Deviation
## IED_Flujos                       IED_Flujos 7.692480e+07       8.770679e+03
## Exportaciones                 Exportaciones 1.287347e+08       1.134613e+04
## Empleo                               Empleo 5.901316e-01       7.682002e-01
## Educacion                         Educacion 5.179146e-01       7.196629e-01
## Salario_Diario               Salario_Diario 1.285149e+03       3.584897e+01
## Innovacion                       Innovacion 1.249904e+00       1.117991e+00
## Inseguridad_Robo           Inseguridad_Robo 2.272065e+03       4.766618e+01
## Inseguridad_Homicidio Inseguridad_Homicidio 5.274689e+01       7.262705e+00
## Tipo_de_Cambio               Tipo_de_Cambio 1.722372e+01       4.150147e+00
## Densidad_Carretera       Densidad_Carretera 1.786154e-04       1.336471e-02
## Densidad_Poblacion       Densidad_Poblacion 2.928160e+01       5.411248e+00
## CO2_Emisiones                 CO2_Emisiones 3.679881e-02       1.918302e-01
## PIB_Per_Capita               PIB_Per_Capita 7.851913e+07       8.861102e+03
## INPC                                   INPC 6.154715e+02       2.480870e+01

1.3. Identifying & Handling Missing Values

It’s crucial to identify any missing values in the dataset, as they can influence the outcome of the analysis.

# Checking for missing values
missing_vals <- is.na(sp_data)
missing_summary <- colSums(missing_vals)

# Printing the summary of missing values by column
print(missing_summary)
##               periodo            IED_Flujos                 IED_M 
##                     0                     0                     0 
##         Exportaciones       Exportaciones_m                Empleo 
##                     0                     0                     3 
##             Educacion        Salario_Diario            Innovacion 
##                     3                     0                     2 
##      Inseguridad_Robo Inseguridad_Homicidio        Tipo_de_Cambio 
##                     0                     1                     0 
##    Densidad_Carretera    Densidad_Poblacion         CO2_Emisiones 
##                     0                     0                     3 
##        PIB_Per_Capita                  INPC     crisis_financiera 
##                     0                     0                     0 
##     salario_diario_mx 
##                     0
# Replacing NA values with median for each column
for(column in names(sp_data)) {
  if(is.numeric(sp_data[[column]])) {
    sp_data[[column]][is.na(sp_data[[column]])] <- median(sp_data[[column]], na.rm = TRUE)
  }
}

# Check if there are any remaining missing values
post_replacement_missing_summary <- colSums(is.na(sp_data))
print(post_replacement_missing_summary)
##               periodo            IED_Flujos                 IED_M 
##                     0                     0                     0 
##         Exportaciones       Exportaciones_m                Empleo 
##                     0                     0                     0 
##             Educacion        Salario_Diario            Innovacion 
##                     0                     0                     0 
##      Inseguridad_Robo Inseguridad_Homicidio        Tipo_de_Cambio 
##                     0                     0                     0 
##    Densidad_Carretera    Densidad_Poblacion         CO2_Emisiones 
##                     0                     0                     0 
##        PIB_Per_Capita                  INPC     crisis_financiera 
##                     0                     0                     0 
##     salario_diario_mx 
##                     0

1.4. Descriptive Statistics

This is especially useful when we want to get insights about the distribution, central tendency, and spread of out data at a granular level.

# Obtain descriptive statistics for the dataset
descriptive_stats <- describe(sp_data)

# Print the descriptive statistics
print(descriptive_stats)
## # A tibble: 18 × 26
##    described_variables       n    na       mean      sd se_mean     IQR skewness
##    <chr>                 <int> <int>      <dbl>   <dbl>   <dbl>   <dbl>    <dbl>
##  1 periodo                  26     0    2.01e+3 7.65e+0 1.5 e+0 1.25e+1   0     
##  2 IED_Flujos               26     0    2.68e+4 8.77e+3 1.72e+3 1.08e+4  -0.0209
##  3 IED_M                    26     0    4.94e+5 1.44e+5 2.82e+4 2.10e+5  -0.0117
##  4 Exportaciones            26     0    2.36e+4 1.13e+4 2.23e+3 1.83e+4   0.514 
##  5 Exportaciones_m          26     0    4.34e+5 1.95e+5 3.82e+4 3.70e+5   0.546 
##  6 Empleo                   26     0    9.65e+1 7.21e-1 1.41e-1 9.25e-1  -0.193 
##  7 Educacion                26     0    8.43e+0 6.75e-1 1.32e-1 9.67e-1  -0.134 
##  8 Salario_Diario           26     0    6.52e+1 3.58e+1 7.03e+0 3.03e+1   1.62  
##  9 Innovacion               26     0    1.31e+1 1.07e+0 2.10e-1 1.01e+0   0.141 
## 10 Inseguridad_Robo         26     0    1.85e+2 4.77e+1 9.35e+0 6.16e+1   1.00  
## 11 Inseguridad_Homicidio    26     0    1.73e+1 7.12e+0 1.40e+0 1.19e+1   0.430 
## 12 Tipo_de_Cambio           26     0    1.39e+1 4.15e+0 8.14e-1 7.73e+0   0.498 
## 13 Densidad_Carretera       26     0    7.12e-2 1.34e-2 2.62e-3 2   e-2   0.209 
## 14 Densidad_Poblacion       26     0    5.73e+1 5.41e+0 1.06e+0 8.62e+0  -0.209 
## 15 CO2_Emisiones            26     0    3.94e+0 1.80e-1 3.53e-2 2.48e-1  -0.126 
## 16 PIB_Per_Capita           26     0    1.39e+5 8.86e+3 1.74e+3 1.52e+4   0.310 
## 17 INPC                     26     0    7.52e+1 2.48e+1 4.87e+0 3.51e+1   0.295 
## 18 salario_diario_mx        26     0    1.03e+3 8.50e+2 1.67e+2 9.66e+2   1.46  
## # ℹ 18 more variables: kurtosis <dbl>, p00 <dbl>, p01 <dbl>, p05 <dbl>,
## #   p10 <dbl>, p20 <dbl>, p25 <dbl>, p30 <dbl>, p40 <dbl>, p50 <dbl>,
## #   p60 <dbl>, p70 <dbl>, p75 <dbl>, p80 <dbl>, p90 <dbl>, p95 <dbl>,
## #   p99 <dbl>, p100 <dbl>

1.5 Standardization of variables

By standardizing all variables to minuscules, we create an standard so when we are making analysis we can call variables easily.

# Convert all column names to lowercase
names(sp_data) <- tolower(names(sp_data))

# Rename columns that end with "_m" to end with "_mx"
new_column_names <- gsub("_m$", "_mx", names(sp_data))
names(sp_data) <- new_column_names

# Check the updated column names
head(sp_data)
##   periodo ied_flujos   ied_mx exportaciones exportaciones_mx empleo educacion
## 1    1997   12145.60 294151.2       9087.62         220090.8  96.53      7.20
## 2    1998    8373.50 210875.6       9875.07         248690.6  96.53      7.31
## 3    1999   13960.32 299734.4      10990.01         235960.5  96.53      7.43
## 4    2000   18248.69 362631.8      12482.96         248057.2  97.83      7.56
## 5    2001   30057.18 546548.4      11300.44         205482.9  97.36      7.68
## 6    2002   24099.21 468332.0      11923.10         231707.6  97.66      7.80
##   salario_diario innovacion inseguridad_robo inseguridad_homicidio
## 1          24.30      11.30           266.51                 14.55
## 2          31.91      11.37           314.78                 14.32
## 3          31.91      12.46           272.89                 12.64
## 4          35.12      13.15           216.98                 10.86
## 5          37.57      13.47           214.53                 10.25
## 6          39.74      12.80           197.80                  9.94
##   tipo_de_cambio densidad_carretera densidad_poblacion co2_emisiones
## 1           8.06               0.05              47.44          3.68
## 2           9.94               0.05              48.76          3.85
## 3           9.52               0.06              49.48          3.69
## 4           9.60               0.06              50.58          3.87
## 5           9.17               0.06              51.28          3.81
## 6          10.36               0.06              51.95          3.82
##   pib_per_capita  inpc crisis_financiera salario_diario_mx
## 1       127570.1 33.28                 0          195.8580
## 2       126738.8 39.47                 0          317.1854
## 3       129164.7 44.34                 0          303.7832
## 4       130874.9 48.31                 0          337.1520
## 5       128083.4 50.43                 0          344.5169
## 6       128205.9 53.31                 0          411.7064

1.6 Selecting only distinct variables

Since there are columns that are the same but with a change in the currency, it is best if we only mantain the columns that will be used for the analysis.

# Removing specified columns from the dataset
sp_data <- sp_data %>% select(-c(exportaciones, ied_flujos, salario_diario))

2. Data Visualization

In this section, visual representations of the dataset are constructed to offer insights into its structure and trends. By visually exploring the data, we can uncover patterns, correlations, or anomalies which might not be immediately evident through numeric summaries alone.

# 1. salario_diario plot
ggplot(sp_data, aes(x = salario_diario_mx, y = ied_mx)) +
  geom_line() +
  labs(title = "Salario Diario vs. IED_MX",
       x = "Salario Diario",
       y = "IED_MX") +
  theme_minimal()

# 2. densidad_poblacion plot
ggplot(sp_data, aes(x = densidad_poblacion, y = ied_mx)) +
  geom_histogram(stat = "identity", fill = "skyblue", color = "black") +
  labs(title = "Densidad Poblacion vs. IED_MX",
       x = "Densidad Poblacion",
       y = "IED_MX") +
  theme_minimal()
## Warning in geom_histogram(stat = "identity", fill = "skyblue", color = "black"):
## Ignoring unknown parameters: `binwidth`, `bins`, and `pad`

# 3. Bar graph for crisis_financiera
sp_data %>%
  group_by(periodo, crisis_financiera) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = periodo, y = count, fill = as.factor(crisis_financiera))) +
  geom_bar(stat = "identity", position = "dodge") +
  geom_text(aes(label=periodo), vjust=0.5, hjust=10, position=position_dodge(width=0.9), size=3.5, angle=90, color="white") +
  geom_hline(aes(yintercept = median(count, na.rm = TRUE)), color = "red") +
  labs(title = "Distribution of Financial Crisis over Years",
       x = "Year",
       y = "Count",
       fill = "Financial Crisis") +
  theme_minimal() +
  theme(axis.text.x = element_blank())
## `summarise()` has grouped output by 'periodo'. You can override using the
## `.groups` argument.

# 4. Correlation plot
cor_data <- sp_data %>% select_if(is.numeric) # removing factor variables
cor_matrix <- cor(cor_data, use = "pairwise.complete.obs")

# Visualization
plot_corr <- corrplot(cor_matrix, 
                      method = "circle", 
                      type = "full", 
                      tl.cex = 0.4, 
                      tl.col = "black", 
                      tl.srt = 90,
                      )

# 5. Innovacion vs. ied_mx (using a bar graph)
ggplot(sp_data, aes(x = innovacion, y = ied_mx)) +
  geom_bar(stat = "identity", fill = "skyblue", color = "black") +
  labs(title = "Innovacion vs. IED_MX",
       x = "Innovacion",
       y = "IED_MX") +
  theme_minimal()

# 6. Histogram for ied_mx
plot_ied_mx <- ggplot(sp_data, aes(x = ied_mx)) +
  geom_histogram(fill = "purple", color = "black", bins = 30) +
  labs(title = "Histogram of IED", 
       x = "IED") +
  theme_minimal()

plot_ied_mx

3. Regression Models

1.1. Basic Multiple Regression Model Using All Variables

Description of Model:

In this regression model, we’ll use all the variables as independent variables to predict the ied_mx (inward foreign direct investment). This approach provides a holistic view of the relationship each independent variable has with the dependent variable. It can serve as a foundation, upon which we refine and optimize our model in subsequent iterations.

# Regression Model 1
model_all_vars <- lm(ied_mx ~ ., data = sp_data)
summary(model_all_vars)
## 
## Call:
## lm(formula = ied_mx ~ ., data = sp_data)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -93838 -22410   1652  32302  78251 
## 
## Coefficients:
##                         Estimate Std. Error t value Pr(>|t|)  
## (Intercept)           -4.691e+08  1.614e+08  -2.907   0.0156 *
## periodo                2.363e+05  8.085e+04   2.923   0.0152 *
## exportaciones_mx      -2.715e+00  1.277e+00  -2.125   0.0595 .
## empleo                 6.075e+04  5.511e+04   1.102   0.2962  
## educacion             -1.303e+05  3.089e+05  -0.422   0.6822  
## innovacion             7.813e+04  2.996e+04   2.608   0.0261 *
## inseguridad_robo      -9.310e+01  8.821e+02  -0.106   0.9180  
## inseguridad_homicidio  9.810e+03  1.226e+04   0.800   0.4421  
## tipo_de_cambio         6.523e+04  3.966e+04   1.645   0.1310  
## densidad_carretera     9.336e+06  1.174e+07   0.796   0.4448  
## densidad_poblacion    -1.704e+05  9.355e+04  -1.822   0.0985 .
## co2_emisiones          1.725e+05  2.846e+05   0.606   0.5579  
## pib_per_capita        -4.410e+00  1.430e+01  -0.308   0.7641  
## inpc                  -2.550e+04  2.105e+04  -1.212   0.2535  
## crisis_financiera1    -1.228e+05  1.122e+05  -1.095   0.2993  
## salario_diario_mx      5.722e+00  3.075e+02   0.019   0.9855  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 70240 on 10 degrees of freedom
## Multiple R-squared:  0.9046, Adjusted R-squared:  0.7615 
## F-statistic: 6.323 on 15 and 10 DF,  p-value: 0.002819

1.2. Accuracy Measures for the Model

Description of Accuracy Measures:

To assess the performance and reliability of our regression model, we will use the following metrics:

R-Squared: This statistic provides a measure of how well the observed outcomes are replicated by the model. It explains the proportion of variance in the dependent variable that’s explained by the independent variables. RMSE (Root Mean Square Error): It signifies the model’s prediction error. Essentially, it tells us how concentrated the data is around the line of best fit. AIC (Akaike Information Criterion): This measures the goodness of fit of our model. A lower AIC value suggests a better-fitting model.

# R-Squared
r_squared <- summary(model_all_vars)$r.squared

# RMSE
rmse <- sqrt(mean(model_all_vars$residuals^2))

# AIC
aic_value <- AIC(model_all_vars)

list(R_Squared = r_squared, RMSE = rmse, AIC = aic_value)
## $R_Squared
## [1] 0.9046175
## 
## $RMSE
## [1] 43563.72
## 
## $AIC
## [1] 663.2478

1.3. Diagnostic Tests

Description of Diagnostic Tests:

Post-regression diagnostics are crucial for validating the assumptions of regression analysis. We’ll be performing:

VIF (Variance Inflation Factor): To check for multicollinearity among the predictor variables. A VIF greater than 5-10 usually suggests high multicollinearity. Breusch-Pagan Test: To check for heteroskedasticity. If the p-value is less than a chosen alpha level (commonly 0.05), heteroskedasticity is present. Histogram of Residuals: To check the normality of the residuals. Ideally, the residuals should be normally distributed around zero.

# VIF for multicollinearity
vif_values <- car::vif(model_all_vars)

# Breusch-Pagan Test for heteroskedasticity
bp_test <- lmtest::bptest(model_all_vars)

# Histogram for normalization of residuals
hist(model_all_vars$residuals, main = "Histogram of Residuals", xlab = "Residuals")

# Print Results

# VIF for multicollinearity
cat("VIF Values:\n")
## VIF Values:
print(vif_values)
##               periodo      exportaciones_mx                empleo 
##           1937.375659            314.388179              7.997350 
##             educacion            innovacion      inseguridad_robo 
##            220.456731              5.228816              8.958156 
## inseguridad_homicidio        tipo_de_cambio    densidad_carretera 
##             38.545261            137.259856            124.624326 
##    densidad_poblacion         co2_emisiones        pib_per_capita 
##           1298.478091             13.294804             81.341486 
##                  inpc     crisis_financiera     salario_diario_mx 
##           1381.397996              4.710371            345.897912
cat("\n")
# Breusch-Pagan Test for heteroskedasticity
cat("Breusch-Pagan Test:\n")
## Breusch-Pagan Test:
print(bp_test)
## 
##  studentized Breusch-Pagan test
## 
## data:  model_all_vars
## BP = 14.602, df = 15, p-value = 0.4805
cat("\n")

2.1. Selected - Polynomial Multiple Regression Model

Description of Model:

In this iteration, we move towards a more sophisticated model by incorporating polynomial regression, specifically targeting the densidad_poblacion variable. Polynomial regression helps to capture non-linear relationships in the data.

# Regression Model 2
model_poly_selected <- lm(ied_mx ~ periodo+exportaciones_mx+educacion+innovacion+densidad_poblacion+I(densidad_poblacion^2)+pib_per_capita+crisis_financiera,data=sp_data)
summary(model_poly_selected)
## 
## Call:
## lm(formula = ied_mx ~ periodo + exportaciones_mx + educacion + 
##     innovacion + densidad_poblacion + I(densidad_poblacion^2) + 
##     pib_per_capita + crisis_financiera, data = sp_data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -140941  -41792    8327   42336  111494 
## 
## Coefficients:
##                           Estimate Std. Error t value Pr(>|t|)  
## (Intercept)             -2.627e+08  9.228e+07  -2.847   0.0111 *
## periodo                  1.339e+05  4.685e+04   2.859   0.0109 *
## exportaciones_mx        -9.361e-02  4.692e-01  -0.199   0.8442  
## educacion                1.505e+05  1.318e+05   1.142   0.2691  
## innovacion               6.604e+04  2.734e+04   2.415   0.0273 *
## densidad_poblacion      -5.146e+04  1.703e+05  -0.302   0.7662  
## I(densidad_poblacion^2) -1.049e+03  1.628e+03  -0.644   0.5281  
## pib_per_capita          -1.158e+01  1.254e+01  -0.923   0.3688  
## crisis_financiera1      -5.802e+04  7.903e+04  -0.734   0.4728  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 79320 on 17 degrees of freedom
## Multiple R-squared:  0.7932, Adjusted R-squared:  0.6959 
## F-statistic: 8.152 on 8 and 17 DF,  p-value: 0.0001576

2.2. Accuracy Measures for the Model

Description of Accuracy Measures:

To assess the performance and reliability of our regression model, we will use the following metrics:

R-Squared: This statistic provides a measure of how well the observed outcomes are replicated by the model. It explains the proportion of variance in the dependent variable that’s explained by the independent variables. RMSE (Root Mean Square Error): It signifies the model’s prediction error. Essentially, it tells us how concentrated the data is around the line of best fit. AIC (Akaike Information Criterion): This measures the goodness of fit of our model. A lower AIC value suggests a better-fitting model.

# R-Squared
r_squared <- summary(model_poly_selected)$r.squared

# RMSE
rmse <- sqrt(mean(model_poly_selected$residuals^2))

# AIC
aic_value <- AIC(model_poly_selected)

list(R_Squared = r_squared, RMSE = rmse, AIC = aic_value)
## $R_Squared
## [1] 0.7932225
## 
## $RMSE
## [1] 64141.98
## 
## $AIC
## [1] 669.3652

2.3. Diagnostic Tests

Description of Diagnostic Tests:

Post-regression diagnostics are crucial for validating the assumptions of regression analysis. We’ll be performing:

VIF (Variance Inflation Factor): To check for multicollinearity among the predictor variables. A VIF greater than 5-10 usually suggests high multicollinearity. Breusch-Pagan Test: To check for heteroskedasticity. If the p-value is less than a chosen alpha level (commonly 0.05), heteroskedasticity is present. Histogram of Residuals: To check the normality of the residuals. Ideally, the residuals should be normally distributed around zero.

# VIF for multicollinearity
vif_values <- car::vif(model_poly_selected)

# Breusch-Pagan Test for heteroskedasticity
bp_test <- lmtest::bptest(model_poly_selected)

# Histogram for normalization of residuals
hist(model_poly_selected$residuals, main = "Histogram of Residuals", xlab = "Residuals")

# Print Results

# VIF for multicollinearity
cat("VIF Values:\n")
## VIF Values:
print(vif_values)
##                 periodo        exportaciones_mx               educacion 
##              510.208408               33.271350               31.446184 
##              innovacion      densidad_poblacion I(densidad_poblacion^2) 
##                3.416102             3373.357013             3988.545670 
##          pib_per_capita       crisis_financiera 
##               49.045748                1.832373
cat("\n")
# Breusch-Pagan Test for heteroskedasticity
cat("Breusch-Pagan Test:\n")
## Breusch-Pagan Test:
print(bp_test)
## 
##  studentized Breusch-Pagan test
## 
## data:  model_poly_selected
## BP = 8.2055, df = 8, p-value = 0.4137
cat("\n")

3.1. Selected - Poly-Logarithmic Multiple Regression Model

Description of Model:

This Poly-Logarithmic Multiple Regression Model omits the standard ‘densidad_poblacion’ to mitigate multicollinearity while retaining its polynomial effect and linearizes the ‘innovacion’ variable through a logarithm to address its non-linear relationship with the dependent variable, ied_mx. This approach aims to capture the intricate relationships between key predictors and the outcome more accurately.

# Regression Model 3
model_poly_log <- lm(ied_mx ~ periodo+exportaciones_mx+educacion+log(innovacion)+I(densidad_poblacion^2)+pib_per_capita+crisis_financiera,data=sp_data)
summary(model_poly_log)
## 
## Call:
## lm(formula = ied_mx ~ periodo + exportaciones_mx + educacion + 
##     log(innovacion) + I(densidad_poblacion^2) + pib_per_capita + 
##     crisis_financiera, data = sp_data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -147647  -39315   11008   38973  108161 
## 
## Coefficients:
##                           Estimate Std. Error t value Pr(>|t|)   
## (Intercept)             -2.642e+08  8.985e+07  -2.940  0.00875 **
## periodo                  1.334e+05  4.571e+04   2.917  0.00920 **
## exportaciones_mx        -3.909e-02  4.406e-01  -0.089  0.93029   
## educacion                1.207e+05  9.404e+04   1.283  0.21578   
## log(innovacion)          7.982e+05  2.861e+05   2.790  0.01208 * 
## I(densidad_poblacion^2) -1.506e+03  5.221e+02  -2.885  0.00986 **
## pib_per_capita          -9.559e+00  1.094e+01  -0.874  0.39373   
## crisis_financiera1      -4.875e+04  7.458e+04  -0.654  0.52161   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 77550 on 18 degrees of freedom
## Multiple R-squared:  0.7908, Adjusted R-squared:  0.7094 
## F-statistic: 9.718 on 7 and 18 DF,  p-value: 5.181e-05

3.2. Accuracy Measures for the Model

Description of Accuracy Measures:

To assess the performance and reliability of our regression model, we will use the following metrics:

R-Squared: This statistic provides a measure of how well the observed outcomes are replicated by the model. It explains the proportion of variance in the dependent variable that’s explained by the independent variables. RMSE (Root Mean Square Error): It signifies the model’s prediction error. Essentially, it tells us how concentrated the data is around the line of best fit. AIC (Akaike Information Criterion): This measures the goodness of fit of our model. A lower AIC value suggests a better-fitting model.

# R-Squared
r_squared <- summary(model_poly_log)$r.squared

# RMSE
rmse <- sqrt(mean(model_poly_log$residuals^2))

# AIC
aic_value <- AIC(model_poly_log)

list(R_Squared = r_squared, RMSE = rmse, AIC = aic_value)
## $R_Squared
## [1] 0.7907686
## 
## $RMSE
## [1] 64521.45
## 
## $AIC
## [1] 667.672

3.3. Diagnostic Tests

Description of Diagnostic Tests:

Post-regression diagnostics are crucial for validating the assumptions of regression analysis. We’ll be performing:

VIF (Variance Inflation Factor): To check for multicollinearity among the predictor variables. A VIF greater than 5-10 usually suggests high multicollinearity. Breusch-Pagan Test: To check for heteroskedasticity. If the p-value is less than a chosen alpha level (commonly 0.05), heteroskedasticity is present. Histogram of Residuals: To check the normality of the residuals. Ideally, the residuals should be normally distributed around zero.

# VIF for multicollinearity
vif_values <- car::vif(model_poly_log)

# Breusch-Pagan Test for heteroskedasticity
bp_test <- lmtest::bptest(model_poly_log)

# Histogram for normalization of residuals
hist(model_poly_log$residuals, main = "Histogram of Residuals", xlab = "Residuals")

# Print Results

# VIF for multicollinearity
cat("VIF Values:\n")
## VIF Values:
print(vif_values)
##                 periodo        exportaciones_mx               educacion 
##              508.278977               30.693045               16.762437 
##         log(innovacion) I(densidad_poblacion^2)          pib_per_capita 
##                2.283523              429.161622               39.065363 
##       crisis_financiera 
##                1.707500
cat("\n")
# Breusch-Pagan Test for heteroskedasticity
cat("Breusch-Pagan Test:\n")
## Breusch-Pagan Test:
print(bp_test)
## 
##  studentized Breusch-Pagan test
## 
## data:  model_poly_log
## BP = 6.0693, df = 7, p-value = 0.5317
cat("\n")

4. Predicted values

Description

In the analysis below, we’ll be visualizing the predicted values from Model 3 and evaluating its performance against the actual observed values.

predicted_values <- predict(model_poly_log)

# The list of predictor variables to analyze
predictor_variables <- c("periodo", "exportaciones_mx", "educacion", "log(innovacion)    ", "I(densidad_poblacion^2)", "pib_per_capita", "crisis_financiera")

# Loop through each predictor variable
for (var in predictor_variables) {
  effect_plot <- effect(var, model_poly_log)
  plot(effect_plot, main=paste("Effect of", var))
}

Actual vs. Predicted Scatter Plot:

Points represent individual observations.

The x-axis portrays the real values of the dependent variable (ied_mx), while the y-axis depicts the model’s predictions for those observations.

The red line represents perfect prediction, meaning the model’s prediction matches the actual value. The closer the points are to this line, the more accurate the model’s predictions for those observations. Observations that deviate significantly from this line indicate areas where the model might be under or over-predicting.

actual_values <- sp_data$ied_mx
plot(actual_values, predicted_values, main="Model 3: Actual vs. Predicted",
     xlab="Actual", ylab="Predicted", pch=19, col="blue")
abline(a=0, b=1, col="red")

5. Annexes

Divide Data into Training and Testing

### Split the Data in Training Data vs Test Data
# Lets randomly split the data into train and test set
set.seed(123)                                  ### sets the random seed for reproducibility of results
training.samples<-sp_data$ied_mx %>%
  createDataPartition(p=0.75,list=FALSE)       ### Lets consider 75% of the data to build a predictive model

train.data<-sp_data[training.samples, ]  ### training data to fit the linear regression model 
test.data<-sp_data[-training.samples, ]  ### testing data to test the linear regression model         

Lasso Regression

# LASSO regression via glmnet package can only take numerical observations. Then, the dataset is transformed to model.matrix() format. 
# Independent variables
x<-model.matrix(ied_mx ~ periodo+exportaciones_mx+educacion+log(innovacion)+I(densidad_poblacion^2)+pib_per_capita+crisis_financiera,train.data)[,-1] ### OLS model specification
# x<-model.matrix(Weekly_Sales~.,train.data)[,-1] ### matrix of independent variables X's
y<-train.data$ied_mx ### dependent variable 

# In estimating LASSO regression it is important to define the lambda that minimizes the prediction error rate. 
# Cross-validation ensures that every data / observation from the original dataset (datains) has a chance of appearing in train and test datasets.
# Find the best lambda using cross-validation.
set.seed(123) 
cv.lasso<-cv.glmnet(x,y,alpha=1) # alpha = 1 for LASSO

# Display the best lambda value
cv.lasso$lambda.min                      ### lambda: a numeric value defining the amount of shrinkage. Why min? the higher the value of ?? , the more penalization there is
## [1] 10541.76
# Fit the final model on the training data
lassomodel<-glmnet(x,y,alpha=1,lambda=cv.lasso$lambda.min)

# Display regression coefficients
coef(lassomodel)
## 8 x 1 sparse Matrix of class "dgCMatrix"
##                                    s0
## (Intercept)             -1.776829e+06
## periodo                  .           
## exportaciones_mx         2.422802e-01
## educacion                1.427426e+04
## log(innovacion)          6.100960e+05
## I(densidad_poblacion^2)  .           
## pib_per_capita           3.359098e+00
## crisis_financiera1       .
# Make predictions on the test data
x.test<-model.matrix(ied_mx ~ periodo+exportaciones_mx+educacion+log(innovacion)+I(densidad_poblacion^2)+pib_per_capita+crisis_financiera,test.data)[,-1] ### OLS model specification
# x.test<-model.matrix(Weekly_Sales~.,test.data)[,-1]
lassopredictions <- lassomodel %>% predict(x.test) %>% as.vector()

# Model Accuracy
data.frame(
  RMSE = RMSE(lassopredictions, test.data$ied_mx),
  Rsquare = R2(lassopredictions, test.data$ied_mx))
##       RMSE   Rsquare
## 1 129268.3 0.6128246
### visualizing lasso regression results 
lbs_fun <- function(fit, offset_x=1, ...) {
  L <- length(fit$lambda)
  x <- log(fit$lambda[L])+ offset_x
  y <- fit$beta[, L]
  labs <- names(y)
  text(x, y, labels=labs, ...)
}

lasso<-glmnet(scale(x),y,alpha=1)

plot(lasso,xvar="lambda",label=T)
lbs_fun(lasso)
abline(v=cv.lasso$lambda.min,col="red",lty=2)
abline(v=cv.lasso$lambda.1se,col="blue",lty=2)

Ridge Regression

# Find the best lambda using cross-validation
set.seed(123)                           # x: independent variables | y: dependent variable 
cv.ridge <- cv.glmnet(x,y,alpha=0.1)      # alpha = 0 for RIDGE

# Display the best lambda value
cv.ridge$lambda.min                     # lambda: a numeric value defining the amount of shrinkage. Why min? the higher the value of ?? , the more penalization there is
## [1] 45632.75
# Fit the final model on the training data
ridgemodel<-glmnet(x,y,alpha=0,lambda=cv.ridge$lambda.min)

# Display regression coefficients
coef(ridgemodel)
## 8 x 1 sparse Matrix of class "dgCMatrix"
##                                    s0
## (Intercept)             -5.564743e+06
## periodo                  1.962827e+03
## exportaciones_mx         1.249883e-01
## educacion                2.816894e+04
## log(innovacion)          5.351597e+05
## I(densidad_poblacion^2)  1.561430e+01
## pib_per_capita           2.778428e+00
## crisis_financiera1      -1.992969e+04
# Make predictions on the test data
x.test<-model.matrix(ied_mx ~ periodo+exportaciones_mx+educacion+log(innovacion)+I(densidad_poblacion^2)+pib_per_capita+crisis_financiera,test.data)[,-1]
ridgepredictions<-ridgemodel %>% predict(x.test) %>% as.vector()

# Model Accuracy
data.frame(
  RMSE = RMSE(ridgepredictions, test.data$ied_mx),
  Rsquare = R2(ridgepredictions, test.data$ied_mx)
)
##       RMSE  Rsquare
## 1 122548.3 0.682736
### visualizing ridge regression results 

ridge<-glmnet(scale(x),y,alpha=0)

plot(ridge, xvar = "lambda", label=T)
lbs_fun(ridge)
abline(v=cv.ridge$lambda.min, col = "red", lty=2)
abline(v=cv.ridge$lambda.1se, col="blue", lty=2)

tab <- matrix(c(17587,6324,6322,0.77,0.71,0.71), ncol=2, byrow=FALSE)
colnames(tab) <- c('RMSE','R2')
rownames(tab) <- c('Linear Regression','Lasso','Ridge')
tab <- as.table(tab)
LS0tCnRpdGxlOiAiRXZpZGVuY2UxIgphdXRob3I6ICJEYXZpZCBEb21pbmd1ZXoiCmRhdGU6ICIyMDIzLTA4LTMwIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQogICAgY29kZV9kb3dubG9hZDogVFJVRQotLS0KCiMgTWV4aWNvIGFuZCBJdHMgQXR0cmFjdGl2ZW5lc3MgZm9yIE5lYXJzaG9yaW5nCgojIyBJbnRyb2R1Y3Rpb24KCkluIGEgcmFwaWRseSBjaGFuZ2luZyBnbG9iYWwgZW52aXJvbm1lbnQgbWFya2VkIGJ5IHRyYWRlIHdhcnMsIGdlb3BvbGl0aWNhbCB0ZW5zaW9ucywgYW5kIGhlYWx0aCBjcmlzZXMgc3VjaCBhcyB0aGUgQ09WSUQtMTkgcGFuZGVtaWMsIGNvdW50cmllcyBhbmQgYnVzaW5lc3NlcyBhcmUgcmUtZXZhbHVhdGluZyB0aGVpciBzdXBwbHkgY2hhaW4gc3RyYXRlZ2llcy4gT25lIHN1Y2ggc3RyYXRlZ3kgZ2FpbmluZyB0cmFjdGlvbiBpcyAnbmVhcnNob3JpbmcnLiBNZXhpY28sIHdpdGggaXRzIHByb3hpbWl0eSB0byB0aGUgVVMgbWFya2V0LCBoYXMgZW1lcmdlZCBhcyBhIHBvdGVudGlhbCBodWIgZm9yIHRoaXMgc3RyYXRlZ3kuIFRoaXMgZG9jdW1lbnQgYWltcyB0byBhbmFseXplIE1leGljbydzIGF0dHJhY3RpdmVuZXNzIGFzIGEgbmVhcnNob3JpbmcgZGVzdGluYXRpb24gYW5kIHVuZGVyc3RhbmQgdGhlIHNwZWNpZmljIGZhY3RvcnMgaW5mbHVlbmNpbmcgdGhpcyBhcHBlYWwuCgojIyBQcm9ibGVtIENvbnRleHQKClNldmVyYWwgZmFjdG9ycyBoYXZlIGRpc3J1cHRlZCB0aGUgZ2xvYmFsIHN1cHBseSBjaGFpbjoKLSBUaGUgc3ByZWFkIG9mIENPVklELTE5IGZyb20gaXRzIGVwaWNlbnRlciBpbiBXdWhhbiwgQ2hpbmEuCi0gQ2hpbmEsIGtub3duIGFzIHRoZSAiZmFjdG9yeSBvZiB0aGUgd29ybGQiLCBleHBlcmllbmNpbmcgYSBoYWx0IGluIGJ1c2luZXNzIGFjdGl2aXRpZXMuCi0gT25nb2luZyBVUy1DaGluYSB0cmFkZSB0ZW5zaW9ucyBzaW5jZSAyMDE3LgotIEVzY2FsYXRpb24gb2YgY29uZmxpY3QgYmV0d2VlbiBSdXNzaWEgYW5kIFVrcmFpbmUgaW4gMjAyMi4KCkR1ZSB0byB0aGVzZSBkaXNydXB0aW9ucywgdGhlcmUncyBhIG5lZWQgZm9yIGludGVybmF0aW9uYWwgY29tcGFuaWVzIHRvIGRpdmVyc2lmeSB0aGVpciBwcm9kdWN0aW9uIGNoYWlucyB0byByZWR1Y2UgZGVwZW5kZW5jeSBvbiBhbnkgc2luZ2xlIHJlZ2lvbi4KCiMjIE5lYXJzaG9yaW5nIGFzIGEgU29sdXRpb24KCk5lYXJzaG9yaW5nIGludm9sdmVzIHJlbG9jYXRpbmcgYnVzaW5lc3MgcHJvamVjdHMgY2xvc2VyIHRvIGVuZCBtYXJrZXRzLiBNZXhpY28ncyBzdHJhdGVnaWMgZ2VvZ3JhcGhpYyBsb2NhdGlvbiBvZmZlcnMgaXQgYSBjb21wZXRpdGl2ZSBhZHZhbnRhZ2UgaW4gdGhpcyByZWFsbSwgcG90ZW50aWFsbHkgbGVhZGluZyB0byBzaWduaWZpY2FudCBlY29ub21pYyBncm93dGguCgpFeGFtcGxlcyBzdWNoIGFzIFRlc2xhJ3MgaW52ZXN0bWVudCBpbiBOdWV2byBMZW9uIGluIDIwMjMgdW5kZXJsaW5lIHRoZSBpbmNyZWFzaW5nIGludGVyZXN0IGluIE1leGljbyBmb3IgbmVhcnNob3JpbmcgcHVycG9zZXMuIEhvd2V2ZXIsIHRvIGxldmVyYWdlIHRoaXMgaW50ZXJlc3QsIGl0J3MgY3J1Y2lhbCB0byBpZGVudGlmeSB0aGUgZmFjdG9ycyB0aGF0IG1ha2UgTWV4aWNvIGF0dHJhY3RpdmUgZm9yIHN1Y2ggaW52ZXN0bWVudHMuCgojIyBBbmFseXRpY2FsIEFwcHJvYWNoCgpVc2luZyBlY29ub21ldHJpY3MsIHdlIGNhbiBhbmFseXplIHRoZSBjb25kaXRpb25zIHRoYXQgTWV4aWNvIG9mZmVycyBmb3IgbmVhcnNob3JpbmcuIEJ5IHRhcHBpbmcgaW50byBkYXRhYmFzZXMgZnJvbSBJTkVHSSwgQmFueGljbywgYW5kIHRoZSBNaW5pc3RyeSBvZiBFY29ub215LCB3ZSBjYW4gZXhwbG9yZSBmYWN0b3JzIGxpa2Ugc29jaW9lY29ub21pYyBjb25kaXRpb25zLCBidXNpbmVzcyBlbnZpcm9ubWVudHMsIGFuZCB0ZWNobm9sb2dpY2FsIGNhcGFiaWxpdGllcy4gVGhpcyB3aWxsIGhlbHAgaW4gcHJlZGljdGluZyB0aGUgZWZmZWN0IG9mIG5lYXJzaG9yaW5nIGluIE1leGljbyBhbmQgaWRlbnRpZnkgYXJlYXMgb2Ygb3Bwb3J0dW5pdHkgZm9yIGZ1dHVyZSBpbnZlc3RtZW50cy4KCiMjIERhdGEgQW5hbHlzaXMKCkJlbG93LCB3ZSdsbCBhbmFseXplIGRhdGEgdGhhdCBoZWxwcyBhbnN3ZXIgd2h5IE1leGljbyBpcyBhbiBhcHBlYWxpbmcgY291bnRyeSBmb3IgbmVhcnNob3Jpbmc6CgojIyBMb2FkaW5nIE5lY2Vzc2FyeSBMaWJyYXJpZXMKYGBge3IgbG9hZGluZyBsaWJyYXJpZXN9CmxpYnJhcnkoZm9yZWlnbikKbGlicmFyeSh0aWR5dmVyc2UpICAgICMgY29sbGVjdGlvbiBvZiBSIHBhY2thZ2VzIGRlc2lnbmVkIGZvciBkYXRhIHNjaWVuY2UKbGlicmFyeShkcGx5cikgICAgICAgICMgZGF0YSBtYW5pcHVsYXRpb24gCmxpYnJhcnkoZm9yY2F0cykgICAgICAjIHRvIHdvcmsgd2l0aCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMKbGlicmFyeShnZ3Bsb3QyKSAgICAgICMgZGF0YSB2aXN1YWxpemF0aW9uIApsaWJyYXJ5KGNvd3Bsb3QpICAgICAgIyBmb3IgYXJyYW5naW5nIHBsb3RzCmxpYnJhcnkocmVhZHIpICAgICAgICAjIHJlYWQgc3BlY2lmaWMgY3N2IGZpbGVzCmxpYnJhcnkoamFuaXRvcikgICAgICAjIGRhdGEgZXhwbG9yYXRpb24gYW5kIGNsZWFuaW5nIApsaWJyYXJ5KEhtaXNjKSAgICAgICAgIyBzZXZlcmFsIHVzZWZ1bCBmdW5jdGlvbnMgZm9yIGRhdGEgYW5hbHlzaXMgCmxpYnJhcnkocHN5Y2gpICAgICAgICAjIGZ1bmN0aW9ucyBmb3IgbXVsdGl2YXJpYXRlIGFuYWx5c2lzIApsaWJyYXJ5KG5hbmlhcikgICAgICAgIyBzdW1tYXJpZXMgYW5kIHZpc3VhbGl6YXRpb24gb2YgbWlzc2luZyB2YWx1ZXMgTkEncwpsaWJyYXJ5KGRsb29rcikgICAgICAgIyBzdW1tYXJpZXMgYW5kIHZpc3VhbGl6YXRpb24gb2YgbWlzc2luZyB2YWx1ZXMgTkEncwpsaWJyYXJ5KGNvcnJwbG90KSAgICAgIyBjb3JyZWxhdGlvbiBwbG90cwpsaWJyYXJ5KGp0b29scykgICAgICAgIyBwcmVzZW50YXRpb24gb2YgcmVncmVzc2lvbiBhbmFseXNpcyAKbGlicmFyeShsbXRlc3QpICAgICAgICMgZGlhZ25vc3RpYyBjaGVja3MgLSBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcyAKbGlicmFyeShjYXIpICAgICAgICAgICMgZGlhZ25vc3RpYyBjaGVja3MgLSBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcwpsaWJyYXJ5KG9sc3JyKSAgICAgICAgIyBkaWFnbm9zdGljIGNoZWNrcyAtIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzIApsaWJyYXJ5KG5hbmlhcikgICAgICAgIyBpZGVudGlmeWluZyBtaXNzaW5nIHZhbHVlcwpsaWJyYXJ5KHN0YXJnYXplcikgICAgIyBjcmVhdGUgcHVibGljYXRpb24gcXVhbGl0eSB0YWJsZXMKbGlicmFyeShlZmZlY3RzKSAgICAgICMgZGlzcGxheXMgZm9yIGxpbmVhciBhbmQgb3RoZXIgcmVncmVzc2lvbiBtb2RlbHMKbGlicmFyeShjYXJldCkgICAgICAgICMgQ2xhc3NpZmljYXRpb24gYW5kIFJlZ3Jlc3Npb24gVHJhaW5pbmcgCmxpYnJhcnkoZ2xtbmV0KSAgICAgICAjIG1ldGhvZHMgZm9yIHByZWRpY3Rpb24gYW5kIHBsb3R0aW5nLCBhbmQgZnVuY3Rpb25zIGZvciBjcm9zcy12YWxpZGF0aW9uCmBgYAoKIyMgUmVhZGluZyB0aGUgRGF0YQpgYGB7ciBsb2FkaW5nIGRhdGF9CiMgUmVhZGluZyB0aGUgZGF0YXNldApzcF9kYXRhIDwtIHJlYWQuY3N2KCIvVXNlcnMvZGF2aWRkcnVtczE4MC9EZXNrdG9wL3NwX2RhdGEuY3N2IikKCiMgR2V0dGluZyBhIGdsaW1wc2Ugb2YgdGhlIGRhdGEKaGVhZChzcF9kYXRhKQpgYGAKCiMjIDEuIEV4cGxvcmF0b3J5IERhdGEgQW5hbGlzaXMKIyMjIDEuMS4gRGVzY3JpcHRpdmUgU3RhdGlzdGljcwpEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHByb3ZpZGUgYSBxdWljayBvdmVydmlldyBvZiB0aGUgY2VudHJhbCB0ZW5kZW5jeSwgZGlzcGVyc2lvbiwgYW5kIHNoYXBlIG9mIHRoZSBkYXRhIGRpc3RyaWJ1dGlvbi4gV2UnbGwgc3RhcnQgYnkgZXhhbWluaW5nIG1lYXN1cmVzIGxpa2UgbWVhbiwgbWVkaWFuLCBhbmQgbW9kZSBmb3IgdGhlIG51bWVyaWNhbCBjb2x1bW5zLgpgYGB7ciBzdW1tYXJ5fQojIERlc2NyaXB0aXZlIHN0YXRpc3RpY3Mgb2YgdGhlIGRhdGFzZXQKc3VtbWFyeShzcF9kYXRhKQpgYGAKCiMjIyAxLjEuMiBUcmFuc2Zvcm0gdmFyaWFibGVzZApCYXNlZCBvbiBvdXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgZGF0YXNldCwgd2UgY2FuIG1ha2Ugc2V2ZXJhbCB0cmFuc2Zvcm1hdGlvbnMgdG8gbWFrZSBvdXIgYW5hbHlzaXMgbW9yZSBtZWFuaW5nZnVsLgpgYGB7ciB0cmFuc2Zvcm0gdmFyaWFibGVzfQojIFRyYW5zZm9ybWluZyAncGVyaW9kbycgaW50byBhIGZhY3RvciAoY2F0ZWdvcmljYWwgdmFyaWFibGUpCiMgc3BfZGF0YSRwZXJpb2RvIDwtIGFzLmZhY3RvcihzcF9kYXRhJHBlcmlvZG8pCnNwX2RhdGEkY3Jpc2lzX2ZpbmFuY2llcmEgPC0gYXMuZmFjdG9yKHNwX2RhdGEkY3Jpc2lzX2ZpbmFuY2llcmEpCgojIENyZWF0aW5nICdleHBvcnRhY2lvbmVzX214JyBieSBtdWx0aXBseWluZyAnRXhwb3J0YWNpb25lcycgYW5kICdUaXBvX2RlX0NhbWJpbycKIyBzcF9kYXRhIDwtIHNwX2RhdGEgJT4lCiMgIG11dGF0ZShleHBvcnRhY2lvbmVzX214ID0gRXhwb3J0YWNpb25lcyAqIFRpcG9fZGVfQ2FtYmlvKQoKIyBDcmVhdGluZyAnc2FsYXJpb19kaWFyaW9fbXgnIGJ5IG11bHRpcGx5aW5nICdTYWxhcmlvX0RpYXJpbycgYW5kICdUaXBvX2RlX0NhbWJpbycKc3BfZGF0YSA8LSBzcF9kYXRhICU+JQogIG11dGF0ZShzYWxhcmlvX2RpYXJpb19teCA9IFNhbGFyaW9fRGlhcmlvICogVGlwb19kZV9DYW1iaW8pCgojIENoZWNraW5nIHRoZSBmaXJzdCBmZXcgcm93cyB0byBlbnN1cmUgb3VyIG5ldyB2YXJpYWJsZXMgYXJlIGNvcnJlY3RseSBhZGRlZApoZWFkKHNwX2RhdGEpCmBgYAoKIyMjIDEuMi4gTWVhc3VyZXMgb2YgRGlzcGVyc2lvbgpXaGlsZSB0aGUgc3VtbWFyeSBmdW5jdGlvbiBwcm92aWRlcyBhIHF1aWNrIG92ZXJ2aWV3IHRoYXQgaW5jbHVkZXMgc29tZSBtZWFzdXJlcyBvZiBkaXNwZXJzaW9uIChsaWtlIHRoZSBtaW4sIG1heCwgMXN0IHF1YXJ0aWxlLCBhbmQgM3JkIHF1YXJ0aWxlKSwgd2UgbWlnaHQgd2FudCB0byBkZWx2ZSBkZWVwZXIgaW50byBjZXJ0YWluIGNvbHVtbnMuIEhlcmUgd2UnbGwgZm9jdXMgb24gdmFyaWFuY2UgYW5kIHN0YW5kYXJkIGRldmlhdGlvbi4KYGBge3IgdmFyIGFuZCBkZXN9CiMgTGlzdCBvZiB2YXJpYWJsZXMgZm9yIHdoaWNoIHRvIGNvbXB1dGUgdmFyaWFuY2UgYW5kIHN0YW5kYXJkIGRldmlhdGlvbgpjb2x1bW5zX3RvX2NoZWNrIDwtIGMoIklFRF9GbHVqb3MiLCAiRXhwb3J0YWNpb25lcyIsICJFbXBsZW8iLCAiRWR1Y2FjaW9uIiwgIlNhbGFyaW9fRGlhcmlvIiwgCiAgICAgICAgICAgICAgICAgICAgICJJbm5vdmFjaW9uIiwgIkluc2VndXJpZGFkX1JvYm8iLCAiSW5zZWd1cmlkYWRfSG9taWNpZGlvIiwgIlRpcG9fZGVfQ2FtYmlvIiwKICAgICAgICAgICAgICAgICAgICAgIkRlbnNpZGFkX0NhcnJldGVyYSIsICJEZW5zaWRhZF9Qb2JsYWNpb24iLCAiQ08yX0VtaXNpb25lcyIsICJQSUJfUGVyX0NhcGl0YSIsICJJTlBDIikKCiMgVXNpbmcgc2FwcGx5IHRvIGNvbXB1dGUgdmFyaWFuY2UgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBmb3IgZWFjaCBjb2x1bW4KdmFyaWFuY2VzIDwtIHNhcHBseShzcF9kYXRhWywgY29sdW1uc190b19jaGVja10sIHZhciwgbmEucm0gPSBUUlVFKQpzdGRfZGV2cyA8LSBzYXBwbHkoc3BfZGF0YVssIGNvbHVtbnNfdG9fY2hlY2tdLCBzZCwgbmEucm0gPSBUUlVFKQoKIyBDb21iaW5pbmcgcmVzdWx0cyBpbnRvIGEgZGF0YSBmcmFtZQpkaXNwZXJzaW9uX2RhdGEgPC0gZGF0YS5mcmFtZShWYXJpYWJsZSA9IG5hbWVzKHZhcmlhbmNlcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZhcmlhbmNlID0gdmFyaWFuY2VzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdGFuZGFyZF9EZXZpYXRpb24gPSBzdGRfZGV2cykKCmRpc3BlcnNpb25fZGF0YQpgYGAKCiMjIyAxLjMuIElkZW50aWZ5aW5nICYgSGFuZGxpbmcgTWlzc2luZyBWYWx1ZXMKSXQncyBjcnVjaWFsIHRvIGlkZW50aWZ5IGFueSBtaXNzaW5nIHZhbHVlcyBpbiB0aGUgZGF0YXNldCwgYXMgdGhleSBjYW4gaW5mbHVlbmNlIHRoZSBvdXRjb21lIG9mIHRoZSBhbmFseXNpcy4KYGBge3IgY2hlY2tpbmcgZm9yIG1pc3NpbmcgdmFsdWVzfQojIENoZWNraW5nIGZvciBtaXNzaW5nIHZhbHVlcwptaXNzaW5nX3ZhbHMgPC0gaXMubmEoc3BfZGF0YSkKbWlzc2luZ19zdW1tYXJ5IDwtIGNvbFN1bXMobWlzc2luZ192YWxzKQoKIyBQcmludGluZyB0aGUgc3VtbWFyeSBvZiBtaXNzaW5nIHZhbHVlcyBieSBjb2x1bW4KcHJpbnQobWlzc2luZ19zdW1tYXJ5KQpgYGAKCmBgYHtyIGNvcnJlY3Rpb24gbWlzc2luZyB2YWx1ZXN9CiMgUmVwbGFjaW5nIE5BIHZhbHVlcyB3aXRoIG1lZGlhbiBmb3IgZWFjaCBjb2x1bW4KZm9yKGNvbHVtbiBpbiBuYW1lcyhzcF9kYXRhKSkgewogIGlmKGlzLm51bWVyaWMoc3BfZGF0YVtbY29sdW1uXV0pKSB7CiAgICBzcF9kYXRhW1tjb2x1bW5dXVtpcy5uYShzcF9kYXRhW1tjb2x1bW5dXSldIDwtIG1lZGlhbihzcF9kYXRhW1tjb2x1bW5dXSwgbmEucm0gPSBUUlVFKQogIH0KfQoKIyBDaGVjayBpZiB0aGVyZSBhcmUgYW55IHJlbWFpbmluZyBtaXNzaW5nIHZhbHVlcwpwb3N0X3JlcGxhY2VtZW50X21pc3Npbmdfc3VtbWFyeSA8LSBjb2xTdW1zKGlzLm5hKHNwX2RhdGEpKQpwcmludChwb3N0X3JlcGxhY2VtZW50X21pc3Npbmdfc3VtbWFyeSkKYGBgCgojIyMgMS40LiBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzIApUaGlzIGlzIGVzcGVjaWFsbHkgdXNlZnVsIHdoZW4gd2Ugd2FudCB0byBnZXQgaW5zaWdodHMgYWJvdXQgdGhlIGRpc3RyaWJ1dGlvbiwgY2VudHJhbCB0ZW5kZW5jeSwgYW5kIHNwcmVhZCBvZiBvdXQgZGF0YSBhdCBhIGdyYW51bGFyIGxldmVsLgpgYGB7cn0KIyBPYnRhaW4gZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBmb3IgdGhlIGRhdGFzZXQKZGVzY3JpcHRpdmVfc3RhdHMgPC0gZGVzY3JpYmUoc3BfZGF0YSkKCiMgUHJpbnQgdGhlIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MKcHJpbnQoZGVzY3JpcHRpdmVfc3RhdHMpCmBgYAoKIyMjIDEuNSBTdGFuZGFyZGl6YXRpb24gb2YgdmFyaWFibGVzCkJ5IHN0YW5kYXJkaXppbmcgYWxsIHZhcmlhYmxlcyB0byBtaW51c2N1bGVzLCB3ZSBjcmVhdGUgYW4gc3RhbmRhcmQgc28gd2hlbiB3ZSBhcmUgbWFraW5nIGFuYWx5c2lzIHdlIGNhbiBjYWxsIHZhcmlhYmxlcyBlYXNpbHkuCmBgYHtyfQojIENvbnZlcnQgYWxsIGNvbHVtbiBuYW1lcyB0byBsb3dlcmNhc2UKbmFtZXMoc3BfZGF0YSkgPC0gdG9sb3dlcihuYW1lcyhzcF9kYXRhKSkKCiMgUmVuYW1lIGNvbHVtbnMgdGhhdCBlbmQgd2l0aCAiX20iIHRvIGVuZCB3aXRoICJfbXgiCm5ld19jb2x1bW5fbmFtZXMgPC0gZ3N1YigiX20kIiwgIl9teCIsIG5hbWVzKHNwX2RhdGEpKQpuYW1lcyhzcF9kYXRhKSA8LSBuZXdfY29sdW1uX25hbWVzCgojIENoZWNrIHRoZSB1cGRhdGVkIGNvbHVtbiBuYW1lcwpoZWFkKHNwX2RhdGEpCmBgYAoKIyMjIDEuNiBTZWxlY3Rpbmcgb25seSBkaXN0aW5jdCB2YXJpYWJsZXMgClNpbmNlIHRoZXJlIGFyZSBjb2x1bW5zIHRoYXQgYXJlIHRoZSBzYW1lIGJ1dCB3aXRoIGEgY2hhbmdlIGluIHRoZSBjdXJyZW5jeSwgaXQgaXMgYmVzdCBpZiB3ZSBvbmx5IG1hbnRhaW4gdGhlIGNvbHVtbnMgdGhhdCB3aWxsIGJlIHVzZWQgZm9yIHRoZSBhbmFseXNpcy4KCmBgYHtyfQojIFJlbW92aW5nIHNwZWNpZmllZCBjb2x1bW5zIGZyb20gdGhlIGRhdGFzZXQKc3BfZGF0YSA8LSBzcF9kYXRhICU+JSBzZWxlY3QoLWMoZXhwb3J0YWNpb25lcywgaWVkX2ZsdWpvcywgc2FsYXJpb19kaWFyaW8pKQpgYGAKCgojIyAyLiBEYXRhIFZpc3VhbGl6YXRpb24KSW4gdGhpcyBzZWN0aW9uLCB2aXN1YWwgcmVwcmVzZW50YXRpb25zIG9mIHRoZSBkYXRhc2V0IGFyZSBjb25zdHJ1Y3RlZCB0byBvZmZlciBpbnNpZ2h0cyBpbnRvIGl0cyBzdHJ1Y3R1cmUgYW5kIHRyZW5kcy4gQnkgdmlzdWFsbHkgZXhwbG9yaW5nIHRoZSBkYXRhLCB3ZSBjYW4gdW5jb3ZlciBwYXR0ZXJucywgY29ycmVsYXRpb25zLCBvciBhbm9tYWxpZXMgd2hpY2ggbWlnaHQgbm90IGJlIGltbWVkaWF0ZWx5IGV2aWRlbnQgdGhyb3VnaCBudW1lcmljIHN1bW1hcmllcyBhbG9uZS4KYGBge3J9CiMgMS4gc2FsYXJpb19kaWFyaW8gcGxvdApnZ3Bsb3Qoc3BfZGF0YSwgYWVzKHggPSBzYWxhcmlvX2RpYXJpb19teCwgeSA9IGllZF9teCkpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJTYWxhcmlvIERpYXJpbyB2cy4gSUVEX01YIiwKICAgICAgIHggPSAiU2FsYXJpbyBEaWFyaW8iLAogICAgICAgeSA9ICJJRURfTVgiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKYGBge3J9CiMgMi4gZGVuc2lkYWRfcG9ibGFjaW9uIHBsb3QKZ2dwbG90KHNwX2RhdGEsIGFlcyh4ID0gZGVuc2lkYWRfcG9ibGFjaW9uLCB5ID0gaWVkX214KSkgKwogIGdlb21faGlzdG9ncmFtKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiLCBjb2xvciA9ICJibGFjayIpICsKICBsYWJzKHRpdGxlID0gIkRlbnNpZGFkIFBvYmxhY2lvbiB2cy4gSUVEX01YIiwKICAgICAgIHggPSAiRGVuc2lkYWQgUG9ibGFjaW9uIiwKICAgICAgIHkgPSAiSUVEX01YIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQojIDMuIEJhciBncmFwaCBmb3IgY3Jpc2lzX2ZpbmFuY2llcmEKc3BfZGF0YSAlPiUKICBncm91cF9ieShwZXJpb2RvLCBjcmlzaXNfZmluYW5jaWVyYSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwZXJpb2RvLCB5ID0gY291bnQsIGZpbGwgPSBhcy5mYWN0b3IoY3Jpc2lzX2ZpbmFuY2llcmEpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPXBlcmlvZG8pLCB2anVzdD0wLjUsIGhqdXN0PTEwLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aD0wLjkpLCBzaXplPTMuNSwgYW5nbGU9OTAsIGNvbG9yPSJ3aGl0ZSIpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gbWVkaWFuKGNvdW50LCBuYS5ybSA9IFRSVUUpKSwgY29sb3IgPSAicmVkIikgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEZpbmFuY2lhbCBDcmlzaXMgb3ZlciBZZWFycyIsCiAgICAgICB4ID0gIlllYXIiLAogICAgICAgeSA9ICJDb3VudCIsCiAgICAgICBmaWxsID0gIkZpbmFuY2lhbCBDcmlzaXMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCgpgYGB7cn0KIyA0LiBDb3JyZWxhdGlvbiBwbG90CmNvcl9kYXRhIDwtIHNwX2RhdGEgJT4lIHNlbGVjdF9pZihpcy5udW1lcmljKSAjIHJlbW92aW5nIGZhY3RvciB2YXJpYWJsZXMKY29yX21hdHJpeCA8LSBjb3IoY29yX2RhdGEsIHVzZSA9ICJwYWlyd2lzZS5jb21wbGV0ZS5vYnMiKQoKIyBWaXN1YWxpemF0aW9uCnBsb3RfY29yciA8LSBjb3JycGxvdChjb3JfbWF0cml4LCAKICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJjaXJjbGUiLCAKICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiZnVsbCIsIAogICAgICAgICAgICAgICAgICAgICAgdGwuY2V4ID0gMC40LCAKICAgICAgICAgICAgICAgICAgICAgIHRsLmNvbCA9ICJibGFjayIsIAogICAgICAgICAgICAgICAgICAgICAgdGwuc3J0ID0gOTAsCiAgICAgICAgICAgICAgICAgICAgICApCmBgYAoKYGBge3J9CiMgNS4gSW5ub3ZhY2lvbiB2cy4gaWVkX214ICh1c2luZyBhIGJhciBncmFwaCkKZ2dwbG90KHNwX2RhdGEsIGFlcyh4ID0gaW5ub3ZhY2lvbiwgeSA9IGllZF9teCkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgbGFicyh0aXRsZSA9ICJJbm5vdmFjaW9uIHZzLiBJRURfTVgiLAogICAgICAgeCA9ICJJbm5vdmFjaW9uIiwKICAgICAgIHkgPSAiSUVEX01YIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCmBgYHtyfQojIDYuIEhpc3RvZ3JhbSBmb3IgaWVkX214CnBsb3RfaWVkX214IDwtIGdncGxvdChzcF9kYXRhLCBhZXMoeCA9IGllZF9teCkpICsKICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gInB1cnBsZSIsIGNvbG9yID0gImJsYWNrIiwgYmlucyA9IDMwKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW0gb2YgSUVEIiwgCiAgICAgICB4ID0gIklFRCIpICsKICB0aGVtZV9taW5pbWFsKCkKCnBsb3RfaWVkX214CmBgYAoKCiMjIDMuIFJlZ3Jlc3Npb24gTW9kZWxzCgojIyMgMS4xLiBCYXNpYyBNdWx0aXBsZSBSZWdyZXNzaW9uIE1vZGVsIFVzaW5nIEFsbCBWYXJpYWJsZXMKIyMjIyBEZXNjcmlwdGlvbiBvZiBNb2RlbDoKSW4gdGhpcyByZWdyZXNzaW9uIG1vZGVsLCB3ZSdsbCB1c2UgYWxsIHRoZSB2YXJpYWJsZXMgYXMgaW5kZXBlbmRlbnQgdmFyaWFibGVzIHRvIHByZWRpY3QgdGhlIGllZF9teCAoaW53YXJkIGZvcmVpZ24gZGlyZWN0IGludmVzdG1lbnQpLiBUaGlzIGFwcHJvYWNoIHByb3ZpZGVzIGEgaG9saXN0aWMgdmlldyBvZiB0aGUgcmVsYXRpb25zaGlwIGVhY2ggaW5kZXBlbmRlbnQgdmFyaWFibGUgaGFzIHdpdGggdGhlIGRlcGVuZGVudCB2YXJpYWJsZS4gSXQgY2FuIHNlcnZlIGFzIGEgZm91bmRhdGlvbiwgdXBvbiB3aGljaCB3ZSByZWZpbmUgYW5kIG9wdGltaXplIG91ciBtb2RlbCBpbiBzdWJzZXF1ZW50IGl0ZXJhdGlvbnMuCgpgYGB7cn0KIyBSZWdyZXNzaW9uIE1vZGVsIDEKbW9kZWxfYWxsX3ZhcnMgPC0gbG0oaWVkX214IH4gLiwgZGF0YSA9IHNwX2RhdGEpCnN1bW1hcnkobW9kZWxfYWxsX3ZhcnMpCmBgYAoKIyMjIDEuMi4gQWNjdXJhY3kgTWVhc3VyZXMgZm9yIHRoZSBNb2RlbAojIyMjIERlc2NyaXB0aW9uIG9mIEFjY3VyYWN5IE1lYXN1cmVzOgpUbyBhc3Nlc3MgdGhlIHBlcmZvcm1hbmNlIGFuZCByZWxpYWJpbGl0eSBvZiBvdXIgcmVncmVzc2lvbiBtb2RlbCwgd2Ugd2lsbCB1c2UgdGhlIGZvbGxvd2luZyBtZXRyaWNzOgoKPlItU3F1YXJlZDogVGhpcyBzdGF0aXN0aWMgcHJvdmlkZXMgYSBtZWFzdXJlIG9mIGhvdyB3ZWxsIHRoZSBvYnNlcnZlZCBvdXRjb21lcyBhcmUgcmVwbGljYXRlZCBieSB0aGUgbW9kZWwuIEl0IGV4cGxhaW5zIHRoZSBwcm9wb3J0aW9uIG9mIHZhcmlhbmNlIGluIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgdGhhdCdzIGV4cGxhaW5lZCBieSB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGVzLgpSTVNFIChSb290IE1lYW4gU3F1YXJlIEVycm9yKTogSXQgc2lnbmlmaWVzIHRoZSBtb2RlbCdzIHByZWRpY3Rpb24gZXJyb3IuIEVzc2VudGlhbGx5LCBpdCB0ZWxscyB1cyBob3cgY29uY2VudHJhdGVkIHRoZSBkYXRhIGlzIGFyb3VuZCB0aGUgbGluZSBvZiBiZXN0IGZpdC4KQUlDIChBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uKTogVGhpcyBtZWFzdXJlcyB0aGUgZ29vZG5lc3Mgb2YgZml0IG9mIG91ciBtb2RlbC4gQSBsb3dlciBBSUMgdmFsdWUgc3VnZ2VzdHMgYSBiZXR0ZXItZml0dGluZyBtb2RlbC4KCmBgYHtyfQojIFItU3F1YXJlZApyX3NxdWFyZWQgPC0gc3VtbWFyeShtb2RlbF9hbGxfdmFycykkci5zcXVhcmVkCgojIFJNU0UKcm1zZSA8LSBzcXJ0KG1lYW4obW9kZWxfYWxsX3ZhcnMkcmVzaWR1YWxzXjIpKQoKIyBBSUMKYWljX3ZhbHVlIDwtIEFJQyhtb2RlbF9hbGxfdmFycykKCmxpc3QoUl9TcXVhcmVkID0gcl9zcXVhcmVkLCBSTVNFID0gcm1zZSwgQUlDID0gYWljX3ZhbHVlKQpgYGAKCiMjIyAxLjMuIERpYWdub3N0aWMgVGVzdHMKIyMjIyBEZXNjcmlwdGlvbiBvZiBEaWFnbm9zdGljIFRlc3RzOgpQb3N0LXJlZ3Jlc3Npb24gZGlhZ25vc3RpY3MgYXJlIGNydWNpYWwgZm9yIHZhbGlkYXRpbmcgdGhlIGFzc3VtcHRpb25zIG9mIHJlZ3Jlc3Npb24gYW5hbHlzaXMuIFdlJ2xsIGJlIHBlcmZvcm1pbmc6Cgo+IFZJRiAoVmFyaWFuY2UgSW5mbGF0aW9uIEZhY3Rvcik6IFRvIGNoZWNrIGZvciBtdWx0aWNvbGxpbmVhcml0eSBhbW9uZyB0aGUgcHJlZGljdG9yIHZhcmlhYmxlcy4gQSBWSUYgZ3JlYXRlciB0aGFuIDUtMTAgdXN1YWxseSBzdWdnZXN0cyBoaWdoIG11bHRpY29sbGluZWFyaXR5LgpCcmV1c2NoLVBhZ2FuIFRlc3Q6IFRvIGNoZWNrIGZvciBoZXRlcm9za2VkYXN0aWNpdHkuIElmIHRoZSBwLXZhbHVlIGlzIGxlc3MgdGhhbiBhIGNob3NlbiBhbHBoYSBsZXZlbCAoY29tbW9ubHkgMC4wNSksIGhldGVyb3NrZWRhc3RpY2l0eSBpcyBwcmVzZW50LgpIaXN0b2dyYW0gb2YgUmVzaWR1YWxzOiBUbyBjaGVjayB0aGUgbm9ybWFsaXR5IG9mIHRoZSByZXNpZHVhbHMuIElkZWFsbHksIHRoZSByZXNpZHVhbHMgc2hvdWxkIGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGFyb3VuZCB6ZXJvLgoKYGBge3J9CiMgVklGIGZvciBtdWx0aWNvbGxpbmVhcml0eQp2aWZfdmFsdWVzIDwtIGNhcjo6dmlmKG1vZGVsX2FsbF92YXJzKQoKIyBCcmV1c2NoLVBhZ2FuIFRlc3QgZm9yIGhldGVyb3NrZWRhc3RpY2l0eQpicF90ZXN0IDwtIGxtdGVzdDo6YnB0ZXN0KG1vZGVsX2FsbF92YXJzKQoKIyBIaXN0b2dyYW0gZm9yIG5vcm1hbGl6YXRpb24gb2YgcmVzaWR1YWxzCmhpc3QobW9kZWxfYWxsX3ZhcnMkcmVzaWR1YWxzLCBtYWluID0gIkhpc3RvZ3JhbSBvZiBSZXNpZHVhbHMiLCB4bGFiID0gIlJlc2lkdWFscyIpCgojIFByaW50IFJlc3VsdHMKCiMgVklGIGZvciBtdWx0aWNvbGxpbmVhcml0eQpjYXQoIlZJRiBWYWx1ZXM6XG4iKQpwcmludCh2aWZfdmFsdWVzKQpjYXQoIlxuIikKCiMgQnJldXNjaC1QYWdhbiBUZXN0IGZvciBoZXRlcm9za2VkYXN0aWNpdHkKY2F0KCJCcmV1c2NoLVBhZ2FuIFRlc3Q6XG4iKQpwcmludChicF90ZXN0KQpjYXQoIlxuIikKYGBgCgojIyMgMi4xLiBTZWxlY3RlZCAtIFBvbHlub21pYWwgTXVsdGlwbGUgUmVncmVzc2lvbiBNb2RlbAojIyMjIERlc2NyaXB0aW9uIG9mIE1vZGVsOgpJbiB0aGlzIGl0ZXJhdGlvbiwgd2UgbW92ZSB0b3dhcmRzIGEgbW9yZSBzb3BoaXN0aWNhdGVkIG1vZGVsIGJ5IGluY29ycG9yYXRpbmcgcG9seW5vbWlhbCByZWdyZXNzaW9uLCBzcGVjaWZpY2FsbHkgdGFyZ2V0aW5nIHRoZSBkZW5zaWRhZF9wb2JsYWNpb24gdmFyaWFibGUuIFBvbHlub21pYWwgcmVncmVzc2lvbiBoZWxwcyB0byBjYXB0dXJlIG5vbi1saW5lYXIgcmVsYXRpb25zaGlwcyBpbiB0aGUgZGF0YS4KCmBgYHtyfQojIFJlZ3Jlc3Npb24gTW9kZWwgMgptb2RlbF9wb2x5X3NlbGVjdGVkIDwtIGxtKGllZF9teCB+IHBlcmlvZG8rZXhwb3J0YWNpb25lc19teCtlZHVjYWNpb24raW5ub3ZhY2lvbitkZW5zaWRhZF9wb2JsYWNpb24rSShkZW5zaWRhZF9wb2JsYWNpb25eMikrcGliX3Blcl9jYXBpdGErY3Jpc2lzX2ZpbmFuY2llcmEsZGF0YT1zcF9kYXRhKQpzdW1tYXJ5KG1vZGVsX3BvbHlfc2VsZWN0ZWQpCmBgYAoKIyMjIDIuMi4gQWNjdXJhY3kgTWVhc3VyZXMgZm9yIHRoZSBNb2RlbAojIyMjIERlc2NyaXB0aW9uIG9mIEFjY3VyYWN5IE1lYXN1cmVzOgpUbyBhc3Nlc3MgdGhlIHBlcmZvcm1hbmNlIGFuZCByZWxpYWJpbGl0eSBvZiBvdXIgcmVncmVzc2lvbiBtb2RlbCwgd2Ugd2lsbCB1c2UgdGhlIGZvbGxvd2luZyBtZXRyaWNzOgoKUi1TcXVhcmVkOiBUaGlzIHN0YXRpc3RpYyBwcm92aWRlcyBhIG1lYXN1cmUgb2YgaG93IHdlbGwgdGhlIG9ic2VydmVkIG91dGNvbWVzIGFyZSByZXBsaWNhdGVkIGJ5IHRoZSBtb2RlbC4gSXQgZXhwbGFpbnMgdGhlIHByb3BvcnRpb24gb2YgdmFyaWFuY2UgaW4gdGhlIGRlcGVuZGVudCB2YXJpYWJsZSB0aGF0J3MgZXhwbGFpbmVkIGJ5IHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMuClJNU0UgKFJvb3QgTWVhbiBTcXVhcmUgRXJyb3IpOiBJdCBzaWduaWZpZXMgdGhlIG1vZGVsJ3MgcHJlZGljdGlvbiBlcnJvci4gRXNzZW50aWFsbHksIGl0IHRlbGxzIHVzIGhvdyBjb25jZW50cmF0ZWQgdGhlIGRhdGEgaXMgYXJvdW5kIHRoZSBsaW5lIG9mIGJlc3QgZml0LgpBSUMgKEFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24pOiBUaGlzIG1lYXN1cmVzIHRoZSBnb29kbmVzcyBvZiBmaXQgb2Ygb3VyIG1vZGVsLiBBIGxvd2VyIEFJQyB2YWx1ZSBzdWdnZXN0cyBhIGJldHRlci1maXR0aW5nIG1vZGVsLgpgYGB7cn0KIyBSLVNxdWFyZWQKcl9zcXVhcmVkIDwtIHN1bW1hcnkobW9kZWxfcG9seV9zZWxlY3RlZCkkci5zcXVhcmVkCgojIFJNU0UKcm1zZSA8LSBzcXJ0KG1lYW4obW9kZWxfcG9seV9zZWxlY3RlZCRyZXNpZHVhbHNeMikpCgojIEFJQwphaWNfdmFsdWUgPC0gQUlDKG1vZGVsX3BvbHlfc2VsZWN0ZWQpCgpsaXN0KFJfU3F1YXJlZCA9IHJfc3F1YXJlZCwgUk1TRSA9IHJtc2UsIEFJQyA9IGFpY192YWx1ZSkKYGBgCgojIyMgMi4zLiBEaWFnbm9zdGljIFRlc3RzCiMjIyMgRGVzY3JpcHRpb24gb2YgRGlhZ25vc3RpYyBUZXN0czoKUG9zdC1yZWdyZXNzaW9uIGRpYWdub3N0aWNzIGFyZSBjcnVjaWFsIGZvciB2YWxpZGF0aW5nIHRoZSBhc3N1bXB0aW9ucyBvZiByZWdyZXNzaW9uIGFuYWx5c2lzLiBXZSdsbCBiZSBwZXJmb3JtaW5nOgoKVklGIChWYXJpYW5jZSBJbmZsYXRpb24gRmFjdG9yKTogVG8gY2hlY2sgZm9yIG11bHRpY29sbGluZWFyaXR5IGFtb25nIHRoZSBwcmVkaWN0b3IgdmFyaWFibGVzLiBBIFZJRiBncmVhdGVyIHRoYW4gNS0xMCB1c3VhbGx5IHN1Z2dlc3RzIGhpZ2ggbXVsdGljb2xsaW5lYXJpdHkuCkJyZXVzY2gtUGFnYW4gVGVzdDogVG8gY2hlY2sgZm9yIGhldGVyb3NrZWRhc3RpY2l0eS4gSWYgdGhlIHAtdmFsdWUgaXMgbGVzcyB0aGFuIGEgY2hvc2VuIGFscGhhIGxldmVsIChjb21tb25seSAwLjA1KSwgaGV0ZXJvc2tlZGFzdGljaXR5IGlzIHByZXNlbnQuCkhpc3RvZ3JhbSBvZiBSZXNpZHVhbHM6IFRvIGNoZWNrIHRoZSBub3JtYWxpdHkgb2YgdGhlIHJlc2lkdWFscy4gSWRlYWxseSwgdGhlIHJlc2lkdWFscyBzaG91bGQgYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYXJvdW5kIHplcm8uCgpgYGB7cn0KIyBWSUYgZm9yIG11bHRpY29sbGluZWFyaXR5CnZpZl92YWx1ZXMgPC0gY2FyOjp2aWYobW9kZWxfcG9seV9zZWxlY3RlZCkKCiMgQnJldXNjaC1QYWdhbiBUZXN0IGZvciBoZXRlcm9za2VkYXN0aWNpdHkKYnBfdGVzdCA8LSBsbXRlc3Q6OmJwdGVzdChtb2RlbF9wb2x5X3NlbGVjdGVkKQoKIyBIaXN0b2dyYW0gZm9yIG5vcm1hbGl6YXRpb24gb2YgcmVzaWR1YWxzCmhpc3QobW9kZWxfcG9seV9zZWxlY3RlZCRyZXNpZHVhbHMsIG1haW4gPSAiSGlzdG9ncmFtIG9mIFJlc2lkdWFscyIsIHhsYWIgPSAiUmVzaWR1YWxzIikKCiMgUHJpbnQgUmVzdWx0cwoKIyBWSUYgZm9yIG11bHRpY29sbGluZWFyaXR5CmNhdCgiVklGIFZhbHVlczpcbiIpCnByaW50KHZpZl92YWx1ZXMpCmNhdCgiXG4iKQoKIyBCcmV1c2NoLVBhZ2FuIFRlc3QgZm9yIGhldGVyb3NrZWRhc3RpY2l0eQpjYXQoIkJyZXVzY2gtUGFnYW4gVGVzdDpcbiIpCnByaW50KGJwX3Rlc3QpCmNhdCgiXG4iKQpgYGAKCiMjIyAzLjEuIFNlbGVjdGVkIC0gUG9seS1Mb2dhcml0aG1pYyBNdWx0aXBsZSBSZWdyZXNzaW9uIE1vZGVsCiMjIyMgRGVzY3JpcHRpb24gb2YgTW9kZWw6ClRoaXMgUG9seS1Mb2dhcml0aG1pYyBNdWx0aXBsZSBSZWdyZXNzaW9uIE1vZGVsIG9taXRzIHRoZSBzdGFuZGFyZCAnZGVuc2lkYWRfcG9ibGFjaW9uJyB0byBtaXRpZ2F0ZSBtdWx0aWNvbGxpbmVhcml0eSB3aGlsZSByZXRhaW5pbmcgaXRzIHBvbHlub21pYWwgZWZmZWN0IGFuZCBsaW5lYXJpemVzIHRoZSAnaW5ub3ZhY2lvbicgdmFyaWFibGUgdGhyb3VnaCBhIGxvZ2FyaXRobSB0byBhZGRyZXNzIGl0cyBub24tbGluZWFyIHJlbGF0aW9uc2hpcCB3aXRoIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUsIGllZF9teC4gVGhpcyBhcHByb2FjaCBhaW1zIHRvIGNhcHR1cmUgdGhlIGludHJpY2F0ZSByZWxhdGlvbnNoaXBzIGJldHdlZW4ga2V5IHByZWRpY3RvcnMgYW5kIHRoZSBvdXRjb21lIG1vcmUgYWNjdXJhdGVseS4KYGBge3J9CiMgUmVncmVzc2lvbiBNb2RlbCAzCm1vZGVsX3BvbHlfbG9nIDwtIGxtKGllZF9teCB+IHBlcmlvZG8rZXhwb3J0YWNpb25lc19teCtlZHVjYWNpb24rbG9nKGlubm92YWNpb24pK0koZGVuc2lkYWRfcG9ibGFjaW9uXjIpK3BpYl9wZXJfY2FwaXRhK2NyaXNpc19maW5hbmNpZXJhLGRhdGE9c3BfZGF0YSkKc3VtbWFyeShtb2RlbF9wb2x5X2xvZykKYGBgCgojIyMgMy4yLiBBY2N1cmFjeSBNZWFzdXJlcyBmb3IgdGhlIE1vZGVsCiMjIyMgRGVzY3JpcHRpb24gb2YgQWNjdXJhY3kgTWVhc3VyZXM6ClRvIGFzc2VzcyB0aGUgcGVyZm9ybWFuY2UgYW5kIHJlbGlhYmlsaXR5IG9mIG91ciByZWdyZXNzaW9uIG1vZGVsLCB3ZSB3aWxsIHVzZSB0aGUgZm9sbG93aW5nIG1ldHJpY3M6CgpSLVNxdWFyZWQ6IFRoaXMgc3RhdGlzdGljIHByb3ZpZGVzIGEgbWVhc3VyZSBvZiBob3cgd2VsbCB0aGUgb2JzZXJ2ZWQgb3V0Y29tZXMgYXJlIHJlcGxpY2F0ZWQgYnkgdGhlIG1vZGVsLiBJdCBleHBsYWlucyB0aGUgcHJvcG9ydGlvbiBvZiB2YXJpYW5jZSBpbiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIHRoYXQncyBleHBsYWluZWQgYnkgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlcy4KUk1TRSAoUm9vdCBNZWFuIFNxdWFyZSBFcnJvcik6IEl0IHNpZ25pZmllcyB0aGUgbW9kZWwncyBwcmVkaWN0aW9uIGVycm9yLiBFc3NlbnRpYWxseSwgaXQgdGVsbHMgdXMgaG93IGNvbmNlbnRyYXRlZCB0aGUgZGF0YSBpcyBhcm91bmQgdGhlIGxpbmUgb2YgYmVzdCBmaXQuCkFJQyAoQWthaWtlIEluZm9ybWF0aW9uIENyaXRlcmlvbik6IFRoaXMgbWVhc3VyZXMgdGhlIGdvb2RuZXNzIG9mIGZpdCBvZiBvdXIgbW9kZWwuIEEgbG93ZXIgQUlDIHZhbHVlIHN1Z2dlc3RzIGEgYmV0dGVyLWZpdHRpbmcgbW9kZWwuCmBgYHtyfQojIFItU3F1YXJlZApyX3NxdWFyZWQgPC0gc3VtbWFyeShtb2RlbF9wb2x5X2xvZykkci5zcXVhcmVkCgojIFJNU0UKcm1zZSA8LSBzcXJ0KG1lYW4obW9kZWxfcG9seV9sb2ckcmVzaWR1YWxzXjIpKQoKIyBBSUMKYWljX3ZhbHVlIDwtIEFJQyhtb2RlbF9wb2x5X2xvZykKCmxpc3QoUl9TcXVhcmVkID0gcl9zcXVhcmVkLCBSTVNFID0gcm1zZSwgQUlDID0gYWljX3ZhbHVlKQpgYGAKCiMjIyAzLjMuIERpYWdub3N0aWMgVGVzdHMKIyMjIyBEZXNjcmlwdGlvbiBvZiBEaWFnbm9zdGljIFRlc3RzOgpQb3N0LXJlZ3Jlc3Npb24gZGlhZ25vc3RpY3MgYXJlIGNydWNpYWwgZm9yIHZhbGlkYXRpbmcgdGhlIGFzc3VtcHRpb25zIG9mIHJlZ3Jlc3Npb24gYW5hbHlzaXMuIFdlJ2xsIGJlIHBlcmZvcm1pbmc6CgpWSUYgKFZhcmlhbmNlIEluZmxhdGlvbiBGYWN0b3IpOiBUbyBjaGVjayBmb3IgbXVsdGljb2xsaW5lYXJpdHkgYW1vbmcgdGhlIHByZWRpY3RvciB2YXJpYWJsZXMuIEEgVklGIGdyZWF0ZXIgdGhhbiA1LTEwIHVzdWFsbHkgc3VnZ2VzdHMgaGlnaCBtdWx0aWNvbGxpbmVhcml0eS4KQnJldXNjaC1QYWdhbiBUZXN0OiBUbyBjaGVjayBmb3IgaGV0ZXJvc2tlZGFzdGljaXR5LiBJZiB0aGUgcC12YWx1ZSBpcyBsZXNzIHRoYW4gYSBjaG9zZW4gYWxwaGEgbGV2ZWwgKGNvbW1vbmx5IDAuMDUpLCBoZXRlcm9za2VkYXN0aWNpdHkgaXMgcHJlc2VudC4KSGlzdG9ncmFtIG9mIFJlc2lkdWFsczogVG8gY2hlY2sgdGhlIG5vcm1hbGl0eSBvZiB0aGUgcmVzaWR1YWxzLiBJZGVhbGx5LCB0aGUgcmVzaWR1YWxzIHNob3VsZCBiZSBub3JtYWxseSBkaXN0cmlidXRlZCBhcm91bmQgemVyby4KCmBgYHtyfQojIFZJRiBmb3IgbXVsdGljb2xsaW5lYXJpdHkKdmlmX3ZhbHVlcyA8LSBjYXI6OnZpZihtb2RlbF9wb2x5X2xvZykKCiMgQnJldXNjaC1QYWdhbiBUZXN0IGZvciBoZXRlcm9za2VkYXN0aWNpdHkKYnBfdGVzdCA8LSBsbXRlc3Q6OmJwdGVzdChtb2RlbF9wb2x5X2xvZykKCiMgSGlzdG9ncmFtIGZvciBub3JtYWxpemF0aW9uIG9mIHJlc2lkdWFscwpoaXN0KG1vZGVsX3BvbHlfbG9nJHJlc2lkdWFscywgbWFpbiA9ICJIaXN0b2dyYW0gb2YgUmVzaWR1YWxzIiwgeGxhYiA9ICJSZXNpZHVhbHMiKQoKIyBQcmludCBSZXN1bHRzCgojIFZJRiBmb3IgbXVsdGljb2xsaW5lYXJpdHkKY2F0KCJWSUYgVmFsdWVzOlxuIikKcHJpbnQodmlmX3ZhbHVlcykKY2F0KCJcbiIpCgojIEJyZXVzY2gtUGFnYW4gVGVzdCBmb3IgaGV0ZXJvc2tlZGFzdGljaXR5CmNhdCgiQnJldXNjaC1QYWdhbiBUZXN0OlxuIikKcHJpbnQoYnBfdGVzdCkKY2F0KCJcbiIpCmBgYAoKIyMgNC4gUHJlZGljdGVkIHZhbHVlcwojIyMjIERlc2NyaXB0aW9uCkluIHRoZSBhbmFseXNpcyBiZWxvdywgd2UnbGwgYmUgdmlzdWFsaXppbmcgdGhlIHByZWRpY3RlZCB2YWx1ZXMgZnJvbSBNb2RlbCAzIGFuZCBldmFsdWF0aW5nIGl0cyBwZXJmb3JtYW5jZSBhZ2FpbnN0IHRoZSBhY3R1YWwgb2JzZXJ2ZWQgdmFsdWVzLgoKYGBge3J9CnByZWRpY3RlZF92YWx1ZXMgPC0gcHJlZGljdChtb2RlbF9wb2x5X2xvZykKCiMgVGhlIGxpc3Qgb2YgcHJlZGljdG9yIHZhcmlhYmxlcyB0byBhbmFseXplCnByZWRpY3Rvcl92YXJpYWJsZXMgPC0gYygicGVyaW9kbyIsICJleHBvcnRhY2lvbmVzX214IiwgImVkdWNhY2lvbiIsICJsb2coaW5ub3ZhY2lvbikgICAgIiwgIkkoZGVuc2lkYWRfcG9ibGFjaW9uXjIpIiwgInBpYl9wZXJfY2FwaXRhIiwgImNyaXNpc19maW5hbmNpZXJhIikKCiMgTG9vcCB0aHJvdWdoIGVhY2ggcHJlZGljdG9yIHZhcmlhYmxlCmZvciAodmFyIGluIHByZWRpY3Rvcl92YXJpYWJsZXMpIHsKICBlZmZlY3RfcGxvdCA8LSBlZmZlY3QodmFyLCBtb2RlbF9wb2x5X2xvZykKICBwbG90KGVmZmVjdF9wbG90LCBtYWluPXBhc3RlKCJFZmZlY3Qgb2YiLCB2YXIpKQp9CmBgYAoKIyMjIyBBY3R1YWwgdnMuIFByZWRpY3RlZCBTY2F0dGVyIFBsb3Q6CgpQb2ludHMgcmVwcmVzZW50IGluZGl2aWR1YWwgb2JzZXJ2YXRpb25zLgoKVGhlIHgtYXhpcyBwb3J0cmF5cyB0aGUgcmVhbCB2YWx1ZXMgb2YgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSAoaWVkX214KSwgd2hpbGUgdGhlIHktYXhpcyBkZXBpY3RzIHRoZSBtb2RlbCdzIHByZWRpY3Rpb25zIGZvciB0aG9zZSBvYnNlcnZhdGlvbnMuCgpUaGUgcmVkIGxpbmUgcmVwcmVzZW50cyBwZXJmZWN0IHByZWRpY3Rpb24sIG1lYW5pbmcgdGhlIG1vZGVsJ3MgcHJlZGljdGlvbiBtYXRjaGVzIHRoZSBhY3R1YWwgdmFsdWUuIFRoZSBjbG9zZXIgdGhlIHBvaW50cyBhcmUgdG8gdGhpcyBsaW5lLCB0aGUgbW9yZSBhY2N1cmF0ZSB0aGUgbW9kZWwncyBwcmVkaWN0aW9ucyBmb3IgdGhvc2Ugb2JzZXJ2YXRpb25zLiBPYnNlcnZhdGlvbnMgdGhhdCBkZXZpYXRlIHNpZ25pZmljYW50bHkgZnJvbSB0aGlzIGxpbmUgaW5kaWNhdGUgYXJlYXMgd2hlcmUgdGhlIG1vZGVsIG1pZ2h0IGJlIHVuZGVyIG9yIG92ZXItcHJlZGljdGluZy4KYGBge3J9CmFjdHVhbF92YWx1ZXMgPC0gc3BfZGF0YSRpZWRfbXgKcGxvdChhY3R1YWxfdmFsdWVzLCBwcmVkaWN0ZWRfdmFsdWVzLCBtYWluPSJNb2RlbCAzOiBBY3R1YWwgdnMuIFByZWRpY3RlZCIsCiAgICAgeGxhYj0iQWN0dWFsIiwgeWxhYj0iUHJlZGljdGVkIiwgcGNoPTE5LCBjb2w9ImJsdWUiKQphYmxpbmUoYT0wLCBiPTEsIGNvbD0icmVkIikKYGBgCgojIyA1LiBBbm5leGVzCgojIyMgRGl2aWRlIERhdGEgaW50byBUcmFpbmluZyBhbmQgVGVzdGluZwpgYGB7cn0KIyMjIFNwbGl0IHRoZSBEYXRhIGluIFRyYWluaW5nIERhdGEgdnMgVGVzdCBEYXRhCiMgTGV0cyByYW5kb21seSBzcGxpdCB0aGUgZGF0YSBpbnRvIHRyYWluIGFuZCB0ZXN0IHNldApzZXQuc2VlZCgxMjMpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMjIyBzZXRzIHRoZSByYW5kb20gc2VlZCBmb3IgcmVwcm9kdWNpYmlsaXR5IG9mIHJlc3VsdHMKdHJhaW5pbmcuc2FtcGxlczwtc3BfZGF0YSRpZWRfbXggJT4lCiAgY3JlYXRlRGF0YVBhcnRpdGlvbihwPTAuNzUsbGlzdD1GQUxTRSkgICAgICAgIyMjIExldHMgY29uc2lkZXIgNzUlIG9mIHRoZSBkYXRhIHRvIGJ1aWxkIGEgcHJlZGljdGl2ZSBtb2RlbAoKdHJhaW4uZGF0YTwtc3BfZGF0YVt0cmFpbmluZy5zYW1wbGVzLCBdICAjIyMgdHJhaW5pbmcgZGF0YSB0byBmaXQgdGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsIAp0ZXN0LmRhdGE8LXNwX2RhdGFbLXRyYWluaW5nLnNhbXBsZXMsIF0gICMjIyB0ZXN0aW5nIGRhdGEgdG8gdGVzdCB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgICAgICAgICAKYGBgCgojIyMgTGFzc28gUmVncmVzc2lvbgpgYGB7ciB3YXJuaW5nPUZBTFNFfQojIExBU1NPIHJlZ3Jlc3Npb24gdmlhIGdsbW5ldCBwYWNrYWdlIGNhbiBvbmx5IHRha2UgbnVtZXJpY2FsIG9ic2VydmF0aW9ucy4gVGhlbiwgdGhlIGRhdGFzZXQgaXMgdHJhbnNmb3JtZWQgdG8gbW9kZWwubWF0cml4KCkgZm9ybWF0LiAKIyBJbmRlcGVuZGVudCB2YXJpYWJsZXMKeDwtbW9kZWwubWF0cml4KGllZF9teCB+IHBlcmlvZG8rZXhwb3J0YWNpb25lc19teCtlZHVjYWNpb24rbG9nKGlubm92YWNpb24pK0koZGVuc2lkYWRfcG9ibGFjaW9uXjIpK3BpYl9wZXJfY2FwaXRhK2NyaXNpc19maW5hbmNpZXJhLHRyYWluLmRhdGEpWywtMV0gIyMjIE9MUyBtb2RlbCBzcGVjaWZpY2F0aW9uCiMgeDwtbW9kZWwubWF0cml4KFdlZWtseV9TYWxlc34uLHRyYWluLmRhdGEpWywtMV0gIyMjIG1hdHJpeCBvZiBpbmRlcGVuZGVudCB2YXJpYWJsZXMgWCdzCnk8LXRyYWluLmRhdGEkaWVkX214ICMjIyBkZXBlbmRlbnQgdmFyaWFibGUgCgojIEluIGVzdGltYXRpbmcgTEFTU08gcmVncmVzc2lvbiBpdCBpcyBpbXBvcnRhbnQgdG8gZGVmaW5lIHRoZSBsYW1iZGEgdGhhdCBtaW5pbWl6ZXMgdGhlIHByZWRpY3Rpb24gZXJyb3IgcmF0ZS4gCiMgQ3Jvc3MtdmFsaWRhdGlvbiBlbnN1cmVzIHRoYXQgZXZlcnkgZGF0YSAvIG9ic2VydmF0aW9uIGZyb20gdGhlIG9yaWdpbmFsIGRhdGFzZXQgKGRhdGFpbnMpIGhhcyBhIGNoYW5jZSBvZiBhcHBlYXJpbmcgaW4gdHJhaW4gYW5kIHRlc3QgZGF0YXNldHMuCiMgRmluZCB0aGUgYmVzdCBsYW1iZGEgdXNpbmcgY3Jvc3MtdmFsaWRhdGlvbi4Kc2V0LnNlZWQoMTIzKSAKY3YubGFzc288LWN2LmdsbW5ldCh4LHksYWxwaGE9MSkgIyBhbHBoYSA9IDEgZm9yIExBU1NPCgojIERpc3BsYXkgdGhlIGJlc3QgbGFtYmRhIHZhbHVlCmN2Lmxhc3NvJGxhbWJkYS5taW4gICAgICAgICAgICAgICAgICAgICAgIyMjIGxhbWJkYTogYSBudW1lcmljIHZhbHVlIGRlZmluaW5nIHRoZSBhbW91bnQgb2Ygc2hyaW5rYWdlLiBXaHkgbWluPyB0aGUgaGlnaGVyIHRoZSB2YWx1ZSBvZiA/PyAsIHRoZSBtb3JlIHBlbmFsaXphdGlvbiB0aGVyZSBpcwoKIyBGaXQgdGhlIGZpbmFsIG1vZGVsIG9uIHRoZSB0cmFpbmluZyBkYXRhCmxhc3NvbW9kZWw8LWdsbW5ldCh4LHksYWxwaGE9MSxsYW1iZGE9Y3YubGFzc28kbGFtYmRhLm1pbikKCiMgRGlzcGxheSByZWdyZXNzaW9uIGNvZWZmaWNpZW50cwpjb2VmKGxhc3NvbW9kZWwpCgojIE1ha2UgcHJlZGljdGlvbnMgb24gdGhlIHRlc3QgZGF0YQp4LnRlc3Q8LW1vZGVsLm1hdHJpeChpZWRfbXggfiBwZXJpb2RvK2V4cG9ydGFjaW9uZXNfbXgrZWR1Y2FjaW9uK2xvZyhpbm5vdmFjaW9uKStJKGRlbnNpZGFkX3BvYmxhY2lvbl4yKStwaWJfcGVyX2NhcGl0YStjcmlzaXNfZmluYW5jaWVyYSx0ZXN0LmRhdGEpWywtMV0gIyMjIE9MUyBtb2RlbCBzcGVjaWZpY2F0aW9uCiMgeC50ZXN0PC1tb2RlbC5tYXRyaXgoV2Vla2x5X1NhbGVzfi4sdGVzdC5kYXRhKVssLTFdCmxhc3NvcHJlZGljdGlvbnMgPC0gbGFzc29tb2RlbCAlPiUgcHJlZGljdCh4LnRlc3QpICU+JSBhcy52ZWN0b3IoKQoKIyBNb2RlbCBBY2N1cmFjeQpkYXRhLmZyYW1lKAogIFJNU0UgPSBSTVNFKGxhc3NvcHJlZGljdGlvbnMsIHRlc3QuZGF0YSRpZWRfbXgpLAogIFJzcXVhcmUgPSBSMihsYXNzb3ByZWRpY3Rpb25zLCB0ZXN0LmRhdGEkaWVkX214KSkKCiMjIyB2aXN1YWxpemluZyBsYXNzbyByZWdyZXNzaW9uIHJlc3VsdHMgCmxic19mdW4gPC0gZnVuY3Rpb24oZml0LCBvZmZzZXRfeD0xLCAuLi4pIHsKICBMIDwtIGxlbmd0aChmaXQkbGFtYmRhKQogIHggPC0gbG9nKGZpdCRsYW1iZGFbTF0pKyBvZmZzZXRfeAogIHkgPC0gZml0JGJldGFbLCBMXQogIGxhYnMgPC0gbmFtZXMoeSkKICB0ZXh0KHgsIHksIGxhYmVscz1sYWJzLCAuLi4pCn0KCmxhc3NvPC1nbG1uZXQoc2NhbGUoeCkseSxhbHBoYT0xKQoKcGxvdChsYXNzbyx4dmFyPSJsYW1iZGEiLGxhYmVsPVQpCmxic19mdW4obGFzc28pCmFibGluZSh2PWN2Lmxhc3NvJGxhbWJkYS5taW4sY29sPSJyZWQiLGx0eT0yKQphYmxpbmUodj1jdi5sYXNzbyRsYW1iZGEuMXNlLGNvbD0iYmx1ZSIsbHR5PTIpCgpgYGAKCiMjIyBSaWRnZSBSZWdyZXNzaW9uCmBgYHtyIHdhcm5pbmc9RkFMU0V9CiMgRmluZCB0aGUgYmVzdCBsYW1iZGEgdXNpbmcgY3Jvc3MtdmFsaWRhdGlvbgpzZXQuc2VlZCgxMjMpICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB4OiBpbmRlcGVuZGVudCB2YXJpYWJsZXMgfCB5OiBkZXBlbmRlbnQgdmFyaWFibGUgCmN2LnJpZGdlIDwtIGN2LmdsbW5ldCh4LHksYWxwaGE9MC4xKSAgICAgICMgYWxwaGEgPSAwIGZvciBSSURHRQoKIyBEaXNwbGF5IHRoZSBiZXN0IGxhbWJkYSB2YWx1ZQpjdi5yaWRnZSRsYW1iZGEubWluICAgICAgICAgICAgICAgICAgICAgIyBsYW1iZGE6IGEgbnVtZXJpYyB2YWx1ZSBkZWZpbmluZyB0aGUgYW1vdW50IG9mIHNocmlua2FnZS4gV2h5IG1pbj8gdGhlIGhpZ2hlciB0aGUgdmFsdWUgb2YgPz8gLCB0aGUgbW9yZSBwZW5hbGl6YXRpb24gdGhlcmUgaXMKCiMgRml0IHRoZSBmaW5hbCBtb2RlbCBvbiB0aGUgdHJhaW5pbmcgZGF0YQpyaWRnZW1vZGVsPC1nbG1uZXQoeCx5LGFscGhhPTAsbGFtYmRhPWN2LnJpZGdlJGxhbWJkYS5taW4pCgojIERpc3BsYXkgcmVncmVzc2lvbiBjb2VmZmljaWVudHMKY29lZihyaWRnZW1vZGVsKQoKIyBNYWtlIHByZWRpY3Rpb25zIG9uIHRoZSB0ZXN0IGRhdGEKeC50ZXN0PC1tb2RlbC5tYXRyaXgoaWVkX214IH4gcGVyaW9kbytleHBvcnRhY2lvbmVzX214K2VkdWNhY2lvbitsb2coaW5ub3ZhY2lvbikrSShkZW5zaWRhZF9wb2JsYWNpb25eMikrcGliX3Blcl9jYXBpdGErY3Jpc2lzX2ZpbmFuY2llcmEsdGVzdC5kYXRhKVssLTFdCnJpZGdlcHJlZGljdGlvbnM8LXJpZGdlbW9kZWwgJT4lIHByZWRpY3QoeC50ZXN0KSAlPiUgYXMudmVjdG9yKCkKCiMgTW9kZWwgQWNjdXJhY3kKZGF0YS5mcmFtZSgKICBSTVNFID0gUk1TRShyaWRnZXByZWRpY3Rpb25zLCB0ZXN0LmRhdGEkaWVkX214KSwKICBSc3F1YXJlID0gUjIocmlkZ2VwcmVkaWN0aW9ucywgdGVzdC5kYXRhJGllZF9teCkKKQoKIyMjIHZpc3VhbGl6aW5nIHJpZGdlIHJlZ3Jlc3Npb24gcmVzdWx0cyAKCnJpZGdlPC1nbG1uZXQoc2NhbGUoeCkseSxhbHBoYT0wKQoKcGxvdChyaWRnZSwgeHZhciA9ICJsYW1iZGEiLCBsYWJlbD1UKQpsYnNfZnVuKHJpZGdlKQphYmxpbmUodj1jdi5yaWRnZSRsYW1iZGEubWluLCBjb2wgPSAicmVkIiwgbHR5PTIpCmFibGluZSh2PWN2LnJpZGdlJGxhbWJkYS4xc2UsIGNvbD0iYmx1ZSIsIGx0eT0yKQoKdGFiIDwtIG1hdHJpeChjKDE3NTg3LDYzMjQsNjMyMiwwLjc3LDAuNzEsMC43MSksIG5jb2w9MiwgYnlyb3c9RkFMU0UpCmNvbG5hbWVzKHRhYikgPC0gYygnUk1TRScsJ1IyJykKcm93bmFtZXModGFiKSA8LSBjKCdMaW5lYXIgUmVncmVzc2lvbicsJ0xhc3NvJywnUmlkZ2UnKQp0YWIgPC0gYXMudGFibGUodGFiKQpgYGAKCg==