Now that we have started working with some spatial statistics, this next unit will help us start building towards spatial regression. Before we can get there, we need to learn one foundational topic in spatial statistics: spatial autocorrelation. One assumption of any regression model is independence. Let’s say we are working with state-level data. If each state represents an independent observation, then no one state influences any other. But is this really ever true?

In Geography, Tobler’s Law states: Everything is related to everything else, but near things are more related than distant things. We might expect, therefore, that neighboring states influence each other. This tends to be the case - if I pick any two states in the South, they are likely to be more related to each other than, say, a Northern state. So my independence assumption is violated - we often call this “Spatial Autocorrelation”. Data with high spatial autocorrelation is data where neighboring geographic units are more related than distant geographic units. In today’s unit, we will practice methods to check for spatial autocorrelation. Later on, we will work on methods to control for this problem in spatial regression.

To illustrate this, let’s load in some data. Suppose I’m a researcher studying poverty in NYC. I have income data at the neighborhood level, and I have created a Poor-index based on the ratio of a household’s income to the poverty level. I then aggregated the number of households with an index value of 1 or below to create my poor count variable. Are impoverished households clustered near each other in NYC? This will help us to learn whether we should concentrate resources in certain areas more than others. Is there spatial inequality alongside economic inequality?


#Reasearch Question - Whats the impact of Crimerate and poverty rate on Unemployment rate.

library(sf)     
library(dplyr)   
library(spData) 
library(ggplot2)
library(ggthemes)
library(spdep)
library(sf)     
library(dplyr)   
library(spData) 
library(ggplot2)
library(ggthemes)
library(spdep)
library(spatialreg)
Warning: package ‘spatialreg’ was built under R version 4.3.3Loading required package: Matrix

Attaching package: ‘spatialreg’

The following objects are masked from ‘package:spdep’:

    get.ClusterOption, get.coresOption,
    get.mcOption, get.VerboseOption,
    get.ZeroPolicyOption, set.ClusterOption,
    set.coresOption, set.mcOption,
    set.VerboseOption, set.ZeroPolicyOption
library(GWmodel)
Warning: package ‘GWmodel’ was built under R version 4.3.3Loading required package: robustbase
Warning: package ‘robustbase’ was built under R version 4.3.3Loading required package: sp
Loading required package: Rcpp
Welcome to GWmodel version 2.3-2.
library(tidyr)

Attaching package: ‘tidyr’

The following objects are masked from ‘package:Matrix’:

    expand, pack, unpack
setwd("C:/Users/Donny/OneDrive/R studio/chicago_airbnb")
Warning: The working directory was changed to C:/Users/Donny/OneDrive/R studio/chicago_airbnb inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
chicago <- st_read("airbnb_chicago 2015.shp")
Reading layer `airbnb_Chicago 2015' from data source 
  `C:\Users\Donny\OneDrive\R studio\chicago_airbnb\airbnb_Chicago 2015.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 77 features and 20 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -87.94011 ymin: 41.64454 xmax: -87.52414 ymax: 42.02304
Geodetic CRS:  WGS 84
ggplot()+
  geom_sf(data = chicago, aes(fill=unemployed))+
  scale_fill_steps(
    name = "Unemployment Rate",
    low = "lightsteelblue1",
    high = "steelblue1",
    n.breaks = 4,
    show.limits = T)+
  theme_void()


chicago_list <- chicago %>% 
  poly2nb(st_geometry(chicago)) %>% 
  nb2listw(zero.policy = TRUE)

moran.plot(chicago$unemployed, 
           chicago_list, 
           zero.policy = TRUE, 
           labels = F,
           xlab = 'Unemployment rate across Chicago',
           ylab = 'Lagged Unemployment rate of neighbors',
                   pch=20)

NA
NA

Since our slope is positive, we have positive autocorrelation, so theres likely to be clustering of neighborhoods with high unemployment rates being near eachother


#Now we can calculate the "Global Moran's I" for the data
#start with the weights, then give R the corresponding variable
chicago_list %>% 
  moran.test(chicago$unemployed, ., zero.policy = TRUE)

    Moran I test under randomisation

data:  chicago$unemployed  
weights: .    

Moran I statistic standard deviate = 8.035, p-value
= 4.678e-16
alternative hypothesis: greater
sample estimates:
Moran I statistic       Expectation          Variance 
      0.564814885      -0.013157895       0.005174172 

Since we have a Moran’s I statistic of 0.564, and a p-value of< 0.001, our data wasn’t produced by a spatially random process. Since our Moran’s I is somewhat close to 1, this shows a slight correlaton between areas that are near one another and rejects the idea of spatial randomness or independence.

Next, we’ll take a look at Local Indicators of Spatial Autocorrelation (LISA) plots. This will help us to identify clusters of low or high values in the graph, as well as outliers. This uses the Local Moran’s I statistic. Instead of calculating one Moran’s I value for the whole plot (as is the case with the global statistic), the local version calculates a local I for each spatial unit (neighborhood)

model <- chicago %>% 
  mutate(crimerate = num_crimes/population)%>% 
  select(c(unemployed, crimerate,population, geometry)) %>% 
  filter(!population %in% "NA") %>% 
  mutate(population = as.numeric(population))
model
Simple feature collection with 77 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -87.94011 ymin: 41.64454 xmax: -87.52414 ymax: 42.02304
Geodetic CRS:  WGS 84
First 10 features:
   unemployed  crimerate population
1        18.2 0.27486567      18238
2        28.7 0.22068266       5918
3        33.9 0.61335188       2876
4        24.3 0.29258060      21929
5        15.7 0.15206547      17841
6         8.2 0.09292786      39493
7        28.6 0.46368524      11717
8         8.4 0.11802500      25681
9        23.4 0.29192164      25983
10        8.7 0.13058500      54991
                         geometry
1  MULTIPOLYGON (((-87.60914 4...
2  MULTIPOLYGON (((-87.59215 4...
3  MULTIPOLYGON (((-87.6288 41...
4  MULTIPOLYGON (((-87.60671 4...
5  MULTIPOLYGON (((-87.59215 4...
6  MULTIPOLYGON (((-87.67441 4...
7  MULTIPOLYGON (((-87.60604 4...
8  MULTIPOLYGON (((-87.58038 4...
9  MULTIPOLYGON (((-87.57714 4...
10 MULTIPOLYGON (((-87.65456 4...

lm_error <- errorsarlm(population ~ unemployed + crimerate + population,
              data = model,
              listw = chicago_list,
              zero.policy = TRUE, 
              na.action = na.omit)
Warning: the response appeared on the right-hand side and was droppedWarning: problem with term 3 in model.matrix: no columns are assignedWarning: inversion of asymptotic covariance matrix failed for tol.solve = 2.22044604925031e-16 
  reciprocal condition number = 4.33906e-18 - using numerical Hessian.
summary(lm1 <- lm(population ~ crimerate + unemployed, data = model))

Call:
lm(formula = population ~ crimerate + unemployed, data = model)

Residuals:
   Min     1Q Median     3Q    Max 
-31365 -16634  -3391  14017  69637 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  48588.4     5629.7   8.631  8.3e-13 ***
crimerate     7012.6    24592.7   0.285   0.7763    
unemployed    -980.4      456.7  -2.147   0.0351 *  
---
Signif. codes:  
0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 21600 on 74 degrees of freedom
Multiple R-squared:  0.09113,   Adjusted R-squared:  0.06657 
F-statistic:  3.71 on 2 and 74 DF,  p-value: 0.02914
#run the Moran's I test for regression residuals
lm.morantest(lm1, chicago_list)

    Global Moran I for regression residuals

data:  
model: lm(formula = population ~ crimerate +
unemployed, data = model)
weights: chicago_list

Moran I statistic standard deviate = 3.1539,
p-value = 0.0008056
alternative hypothesis: greater
sample estimates:
Observed Moran I      Expectation         Variance 
     0.195748533     -0.026580278      0.004969411 
seResiduals <- rep(0, length(model$population))

resIndex <- lm_error$residuals %>% names() %>% as.integer();

seResiduals[resIndex] <- lm_error$residuals
chicago_list %>%
  moran.test(seResiduals, ., zero.policy = TRUE) 

    Moran I test under randomisation

data:  seResiduals  
weights: .    

Moran I statistic standard deviate = -0.25804,
p-value = 0.6018
alternative hypothesis: greater
sample estimates:
Moran I statistic       Expectation          Variance 
     -0.031597282      -0.013157895       0.005106447 

Now after doing the error model, our P value is much higher and our Morans I is extremely close to 0, which together would indicate that neighboring chicago areas are independent of eachother after the transormation of the dataset.

I chose to do a error model because of the spatial autocorrelation found to be present in the original analysis. My P value was much smaller than 0.001, so it meant that the idea of independence or randmoness between neighboring areas wasn’t really a possibility, which means there was some auto correlation going on. This P value being as small as it was helped me decide that the error model would be a good fit since these models tend to be used when there is spacial correlation.

Unemployment had a negative and statisitcally significant impact on the population, while Crimerate didn’t as much. I was expecting it to be the opposite, where crimerate would have a greater impact on the population but surprisingly it was the other way around.

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KTm93IHRoYXQgd2UgaGF2ZSBzdGFydGVkIHdvcmtpbmcgd2l0aCBzb21lIHNwYXRpYWwgc3RhdGlzdGljcywgdGhpcyBuZXh0IHVuaXQgd2lsbCBoZWxwIHVzIHN0YXJ0IGJ1aWxkaW5nIHRvd2FyZHMgc3BhdGlhbCByZWdyZXNzaW9uLiBCZWZvcmUgd2UgY2FuIGdldCB0aGVyZSwgd2UgbmVlZCB0byBsZWFybiBvbmUgZm91bmRhdGlvbmFsIHRvcGljIGluIHNwYXRpYWwgc3RhdGlzdGljczogc3BhdGlhbCBhdXRvY29ycmVsYXRpb24uIE9uZSBhc3N1bXB0aW9uIG9mIGFueSByZWdyZXNzaW9uIG1vZGVsIGlzIGluZGVwZW5kZW5jZS4gTGV0J3Mgc2F5IHdlIGFyZSB3b3JraW5nIHdpdGggc3RhdGUtbGV2ZWwgZGF0YS4gSWYgZWFjaCBzdGF0ZSByZXByZXNlbnRzIGFuIGluZGVwZW5kZW50IG9ic2VydmF0aW9uLCB0aGVuIG5vIG9uZSBzdGF0ZSBpbmZsdWVuY2VzIGFueSBvdGhlci4gQnV0IGlzIHRoaXMgcmVhbGx5IGV2ZXIgdHJ1ZT8NCg0KSW4gR2VvZ3JhcGh5LCBUb2JsZXIncyBMYXcgc3RhdGVzOiBFdmVyeXRoaW5nIGlzIHJlbGF0ZWQgdG8gZXZlcnl0aGluZyBlbHNlLCBidXQgbmVhciB0aGluZ3MgYXJlIG1vcmUgcmVsYXRlZCB0aGFuIGRpc3RhbnQgdGhpbmdzLiBXZSBtaWdodCBleHBlY3QsIHRoZXJlZm9yZSwgdGhhdCBuZWlnaGJvcmluZyBzdGF0ZXMgaW5mbHVlbmNlIGVhY2ggb3RoZXIuIFRoaXMgdGVuZHMgdG8gYmUgdGhlIGNhc2UgLSBpZiBJIHBpY2sgYW55IHR3byBzdGF0ZXMgaW4gdGhlIFNvdXRoLCB0aGV5IGFyZSBsaWtlbHkgdG8gYmUgbW9yZSByZWxhdGVkIHRvIGVhY2ggb3RoZXIgdGhhbiwgc2F5LCBhIE5vcnRoZXJuIHN0YXRlLiBTbyBteSBpbmRlcGVuZGVuY2UgYXNzdW1wdGlvbiBpcyB2aW9sYXRlZCAtIHdlIG9mdGVuIGNhbGwgdGhpcyAiU3BhdGlhbCBBdXRvY29ycmVsYXRpb24iLiBEYXRhIHdpdGggaGlnaCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpcyBkYXRhIHdoZXJlIG5laWdoYm9yaW5nIGdlb2dyYXBoaWMgdW5pdHMgYXJlIG1vcmUgcmVsYXRlZCB0aGFuIGRpc3RhbnQgZ2VvZ3JhcGhpYyB1bml0cy4gSW4gdG9kYXkncyB1bml0LCB3ZSB3aWxsIHByYWN0aWNlIG1ldGhvZHMgdG8gY2hlY2sgZm9yIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLiBMYXRlciBvbiwgd2Ugd2lsbCB3b3JrIG9uIG1ldGhvZHMgdG8gY29udHJvbCBmb3IgdGhpcyBwcm9ibGVtIGluIHNwYXRpYWwgcmVncmVzc2lvbi4NCg0KVG8gaWxsdXN0cmF0ZSB0aGlzLCBsZXQncyBsb2FkIGluIHNvbWUgZGF0YS4gU3VwcG9zZSBJJ20gYSByZXNlYXJjaGVyIHN0dWR5aW5nIHBvdmVydHkgaW4gTllDLiBJIGhhdmUgaW5jb21lIGRhdGEgYXQgdGhlIG5laWdoYm9yaG9vZCBsZXZlbCwgYW5kIEkgaGF2ZSBjcmVhdGVkIGEgUG9vci1pbmRleCBiYXNlZCBvbiB0aGUgcmF0aW8gb2YgYSBob3VzZWhvbGQncyBpbmNvbWUgdG8gdGhlIHBvdmVydHkgbGV2ZWwuIEkgdGhlbiBhZ2dyZWdhdGVkIHRoZSBudW1iZXIgb2YgaG91c2Vob2xkcyB3aXRoIGFuIGluZGV4IHZhbHVlIG9mIDEgb3IgYmVsb3cgdG8gY3JlYXRlIG15IHBvb3IgY291bnQgdmFyaWFibGUuIEFyZSBpbXBvdmVyaXNoZWQgaG91c2Vob2xkcyBjbHVzdGVyZWQgbmVhciBlYWNoIG90aGVyIGluIE5ZQz8gVGhpcyB3aWxsIGhlbHAgdXMgdG8gbGVhcm4gd2hldGhlciB3ZSBzaG91bGQgY29uY2VudHJhdGUgcmVzb3VyY2VzIGluIGNlcnRhaW4gYXJlYXMgbW9yZSB0aGFuIG90aGVycy4gSXMgdGhlcmUgc3BhdGlhbCBpbmVxdWFsaXR5IGFsb25nc2lkZSBlY29ub21pYyBpbmVxdWFsaXR5Pw0KDQoNCmBgYHtyfQ0KDQojUmVhc2VhcmNoIFF1ZXN0aW9uIC0gV2hhdHMgdGhlIGltcGFjdCBvZiBDcmltZXJhdGUgYW5kIHBvdmVydHkgcmF0ZSBvbiBVbmVtcGxveW1lbnQgcmF0ZS4NCg0KbGlicmFyeShzZikgICAgIA0KbGlicmFyeShkcGx5cikgICANCmxpYnJhcnkoc3BEYXRhKSANCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2d0aGVtZXMpDQpsaWJyYXJ5KHNwZGVwKQ0KbGlicmFyeShzZikgICAgIA0KbGlicmFyeShkcGx5cikgICANCmxpYnJhcnkoc3BEYXRhKSANCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2d0aGVtZXMpDQpsaWJyYXJ5KHNwZGVwKQ0KbGlicmFyeShzcGF0aWFscmVnKQ0KbGlicmFyeShHV21vZGVsKQ0KbGlicmFyeSh0aWR5cikNCnNldHdkKCJDOi9Vc2Vycy9Eb25ueS9PbmVEcml2ZS9SIHN0dWRpby9jaGljYWdvX2FpcmJuYiIpDQpjaGljYWdvIDwtIHN0X3JlYWQoImFpcmJuYl9jaGljYWdvIDIwMTUuc2hwIikNCg0KZ2dwbG90KCkrDQogIGdlb21fc2YoZGF0YSA9IGNoaWNhZ28sIGFlcyhmaWxsPXVuZW1wbG95ZWQpKSsNCiAgc2NhbGVfZmlsbF9zdGVwcygNCiAgICBuYW1lID0gIlVuZW1wbG95bWVudCBSYXRlIiwNCiAgICBsb3cgPSAibGlnaHRzdGVlbGJsdWUxIiwNCiAgICBoaWdoID0gInN0ZWVsYmx1ZTEiLA0KICAgIG4uYnJlYWtzID0gNCwNCiAgICBzaG93LmxpbWl0cyA9IFQpKw0KICB0aGVtZV92b2lkKCkNCg0KY2hpY2Fnb19saXN0IDwtIGNoaWNhZ28gJT4lIA0KICBwb2x5Mm5iKHN0X2dlb21ldHJ5KGNoaWNhZ28pKSAlPiUgDQogIG5iMmxpc3R3KHplcm8ucG9saWN5ID0gVFJVRSkNCg0KYGBgDQoNCmBgYHtyfQ0KDQptb3Jhbi5wbG90KGNoaWNhZ28kdW5lbXBsb3llZCwgDQogICAgICAgICAgIGNoaWNhZ29fbGlzdCwgDQogICAgICAgICAgIHplcm8ucG9saWN5ID0gVFJVRSwgDQogICAgICAgICAgIGxhYmVscyA9IEYsDQogICAgICAgICAgIHhsYWIgPSAnVW5lbXBsb3ltZW50IHJhdGUgYWNyb3NzIENoaWNhZ28nLA0KICAgICAgICAgICB5bGFiID0gJ0xhZ2dlZCBVbmVtcGxveW1lbnQgcmF0ZSBvZiBuZWlnaGJvcnMnLA0KICAgICAgICAgICAgICAgICAgIHBjaD0yMCkNCg0KDQpgYGANClNpbmNlIG91ciBzbG9wZSBpcyBwb3NpdGl2ZSwgd2UgaGF2ZSBwb3NpdGl2ZSBhdXRvY29ycmVsYXRpb24sIHNvIHRoZXJlcyBsaWtlbHkgdG8gYmUgY2x1c3RlcmluZyBvZiBuZWlnaGJvcmhvb2RzIHdpdGggaGlnaCB1bmVtcGxveW1lbnQgcmF0ZXMgYmVpbmcgbmVhciBlYWNob3RoZXINCmBgYHtyfQ0KDQojTm93IHdlIGNhbiBjYWxjdWxhdGUgdGhlICJHbG9iYWwgTW9yYW4ncyBJIiBmb3IgdGhlIGRhdGENCiNzdGFydCB3aXRoIHRoZSB3ZWlnaHRzLCB0aGVuIGdpdmUgUiB0aGUgY29ycmVzcG9uZGluZyB2YXJpYWJsZQ0KY2hpY2Fnb19saXN0ICU+JSANCiAgbW9yYW4udGVzdChjaGljYWdvJHVuZW1wbG95ZWQsIC4sIHplcm8ucG9saWN5ID0gVFJVRSkNCmBgYA0KU2luY2Ugd2UgaGF2ZSBhIE1vcmFuJ3MgSSBzdGF0aXN0aWMgb2YgMC41NjQsIGFuZCBhIHAtdmFsdWUgb2Y8IDAuMDAxLCBvdXIgZGF0YSB3YXNuJ3QgcHJvZHVjZWQgYnkgYSBzcGF0aWFsbHkgcmFuZG9tIHByb2Nlc3MuIFNpbmNlIG91ciBNb3JhbidzIEkgaXMgc29tZXdoYXQgY2xvc2UgdG8gMSwgdGhpcyBzaG93cyBhIHNsaWdodCBjb3JyZWxhdG9uIGJldHdlZW4gYXJlYXMgdGhhdCBhcmUgbmVhciBvbmUgYW5vdGhlciBhbmQgcmVqZWN0cyB0aGUgaWRlYSBvZiBzcGF0aWFsIHJhbmRvbW5lc3Mgb3IgaW5kZXBlbmRlbmNlLg0KDQpOZXh0LCB3ZSdsbCB0YWtlIGEgbG9vayBhdCBMb2NhbCBJbmRpY2F0b3JzIG9mIFNwYXRpYWwgQXV0b2NvcnJlbGF0aW9uIChMSVNBKSBwbG90cy4gVGhpcyB3aWxsIGhlbHAgdXMgdG8gaWRlbnRpZnkgY2x1c3RlcnMgb2YgbG93IG9yIGhpZ2ggdmFsdWVzIGluIHRoZSBncmFwaCwgYXMgd2VsbCBhcyBvdXRsaWVycy4gVGhpcyB1c2VzIHRoZSBMb2NhbCBNb3JhbidzIEkgc3RhdGlzdGljLiBJbnN0ZWFkIG9mIGNhbGN1bGF0aW5nIG9uZSBNb3JhbidzIEkgdmFsdWUgZm9yIHRoZSB3aG9sZSBwbG90IChhcyBpcyB0aGUgY2FzZSB3aXRoIHRoZSBnbG9iYWwgc3RhdGlzdGljKSwgdGhlIGxvY2FsIHZlcnNpb24gY2FsY3VsYXRlcyBhIGxvY2FsIEkgZm9yIGVhY2ggc3BhdGlhbCB1bml0IChuZWlnaGJvcmhvb2QpDQoNCmBgYHtyfQ0KbW9kZWwgPC0gY2hpY2FnbyAlPiUgDQogIG11dGF0ZShjcmltZXJhdGUgPSBudW1fY3JpbWVzL3BvcHVsYXRpb24pJT4lIA0KICBzZWxlY3QoYyh1bmVtcGxveWVkLCBjcmltZXJhdGUscG9wdWxhdGlvbiwgZ2VvbWV0cnkpKSAlPiUgDQogIGZpbHRlcighcG9wdWxhdGlvbiAlaW4lICJOQSIpICU+JSANCiAgbXV0YXRlKHBvcHVsYXRpb24gPSBhcy5udW1lcmljKHBvcHVsYXRpb24pKQ0KbW9kZWwNCg0KYGBgDQpgYGB7cn0NCg0KbG1fZXJyb3IgPC0gZXJyb3JzYXJsbShwb3B1bGF0aW9uIH4gdW5lbXBsb3llZCArIGNyaW1lcmF0ZSArIHBvcHVsYXRpb24sDQogICAgICAgICAgICAgIGRhdGEgPSBtb2RlbCwNCiAgICAgICAgICAgICAgbGlzdHcgPSBjaGljYWdvX2xpc3QsDQogICAgICAgICAgICAgIHplcm8ucG9saWN5ID0gVFJVRSwgDQogICAgICAgICAgICAgIG5hLmFjdGlvbiA9IG5hLm9taXQpDQoNCnN1bW1hcnkobG0xIDwtIGxtKHBvcHVsYXRpb24gfiBjcmltZXJhdGUgKyB1bmVtcGxveWVkLCBkYXRhID0gbW9kZWwpKQ0KDQoNCiNydW4gdGhlIE1vcmFuJ3MgSSB0ZXN0IGZvciByZWdyZXNzaW9uIHJlc2lkdWFscw0KbG0ubW9yYW50ZXN0KGxtMSwgY2hpY2Fnb19saXN0KQ0KDQpgYGANCmBgYHtyfQ0Kc2VSZXNpZHVhbHMgPC0gcmVwKDAsIGxlbmd0aChtb2RlbCRwb3B1bGF0aW9uKSkNCg0KcmVzSW5kZXggPC0gbG1fZXJyb3IkcmVzaWR1YWxzICU+JSBuYW1lcygpICU+JSBhcy5pbnRlZ2VyKCk7DQoNCnNlUmVzaWR1YWxzW3Jlc0luZGV4XSA8LSBsbV9lcnJvciRyZXNpZHVhbHMNCmNoaWNhZ29fbGlzdCAlPiUNCiAgbW9yYW4udGVzdChzZVJlc2lkdWFscywgLiwgemVyby5wb2xpY3kgPSBUUlVFKSANCmBgYA0KTm93IGFmdGVyIGRvaW5nIHRoZSBlcnJvciBtb2RlbCwgb3VyIFAgdmFsdWUgaXMgbXVjaCBoaWdoZXIgYW5kIG91ciBNb3JhbnMgSSBpcyBleHRyZW1lbHkgY2xvc2UgdG8gMCwgd2hpY2ggdG9nZXRoZXIgd291bGQgaW5kaWNhdGUgdGhhdCBuZWlnaGJvcmluZyBjaGljYWdvIGFyZWFzIGFyZSBpbmRlcGVuZGVudCBvZiBlYWNob3RoZXIgYWZ0ZXIgdGhlIHRyYW5zb3JtYXRpb24gb2YgdGhlIGRhdGFzZXQuDQoNCkkgY2hvc2UgdG8gZG8gYSBlcnJvciBtb2RlbCBiZWNhdXNlIG9mIHRoZSBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBmb3VuZCB0byBiZSBwcmVzZW50IGluIHRoZSBvcmlnaW5hbCBhbmFseXNpcy4gTXkgUCB2YWx1ZSB3YXMgbXVjaCBzbWFsbGVyIHRoYW4gMC4wMDEsIHNvIGl0IG1lYW50IHRoYXQgdGhlIGlkZWEgb2YgaW5kZXBlbmRlbmNlIG9yIHJhbmRtb25lc3MgYmV0d2VlbiBuZWlnaGJvcmluZyBhcmVhcyB3YXNuJ3QgcmVhbGx5IGEgcG9zc2liaWxpdHksIHdoaWNoIG1lYW5zIHRoZXJlIHdhcyBzb21lIGF1dG8gY29ycmVsYXRpb24gZ29pbmcgb24uIFRoaXMgUCB2YWx1ZSBiZWluZyBhcyBzbWFsbCBhcyBpdCB3YXMgaGVscGVkIG1lIGRlY2lkZSB0aGF0IHRoZSBlcnJvciBtb2RlbCB3b3VsZCBiZSBhIGdvb2QgZml0IHNpbmNlIHRoZXNlIG1vZGVscyB0ZW5kIHRvIGJlIHVzZWQgd2hlbiB0aGVyZSBpcyBzcGFjaWFsIGNvcnJlbGF0aW9uLg0KDQoNClVuZW1wbG95bWVudCBoYWQgYSBuZWdhdGl2ZSBhbmQgc3RhdGlzaXRjYWxseSBzaWduaWZpY2FudCBpbXBhY3Qgb24gdGhlIHBvcHVsYXRpb24sIHdoaWxlIENyaW1lcmF0ZSBkaWRuJ3QgYXMgbXVjaC4gSSB3YXMgZXhwZWN0aW5nIGl0IHRvIGJlIHRoZSBvcHBvc2l0ZSwgd2hlcmUgY3JpbWVyYXRlIHdvdWxkIGhhdmUgYSBncmVhdGVyIGltcGFjdCBvbiB0aGUgcG9wdWxhdGlvbiBidXQgc3VycHJpc2luZ2x5IGl0IHdhcyB0aGUgb3RoZXIgd2F5IGFyb3VuZC4NCg0KDQo=