library(readxl)
library(here)
library(tidyverse)
library(stringr)
library(naniar)

Data Import

df_simplified<-read_excel(here::here("Nonprofit_Baltimore_Analysis.xlsx"), sheet = 3)
## Warning: Expecting numeric in W4084 / R4084C23: got 'of art'

Information about the data: Here’s an article describing some of the datasets from the IRS 990s. We’re using the Business Master File (BMF). There’s a section titled “Minimum Filing Threshold” that explains a data limitation (and why we’re seeing so many 0’s). See here for more info.

It seems that if there is a value less than 50,000 other than zero, it must mean that the organization decided to submit to the IRS, because otherwise they would be listed as a zero. It is not possible to distinguish a true zero from a zero due to not meeting the threshold of 50,000 and just not submitting. See this guide, page 5 in the “minimum filing threshold” section.

It therefore makes sense to remove zero values and to report this caveat that the data is incomplete because many nonprofits that had assets less than 50,000 are not included.

However for the high vs nonhigh asset we could keep these - because zero values would still be less than the threshold regardless.

Adding to this NA values can be considered less than 50000, as organizations are not required to report an amount if they have less than 50000.

Tidying data and Exploratory Analysis

Asset amount

First let’s check how many zero values there are for asset amounts.

df_simplified %>% filter(ASSET_AMT==0)%>% nrow()
## [1] 1218

Now we will check if there are NA values for asset amounts.

gg_miss_var(df_simplified)

Yes, indeed there are…

NA and zero values likely mean the nonprofit did not need to submit to the IRS. It is impossible to know however, if a zero is actually a true zero. NA values could mean something else.

Thus, we will recode asset amount based on a threshold of greater than or equal to 500,000 as high asset and less than 500,000 (including zero) as not high asset. Note we keep our NA values with this recoding.

df_simplified<-df_simplified %>%
  # modify Asset amount variable to be numeric
  mutate(ASSET_AMT = as.numeric(ASSET_AMT)) %>%
  #create a variable about high asset amount (threshold being $500,000)
  mutate(ASSET_High = case_when(ASSET_AMT  >= 500000 ~ TRUE,
                                ASSET_AMT  < 500000 ~ FALSE))

Here we can see the NA values:

table(df_simplified$ASSET_High, useNA = "always")
## 
## FALSE  TRUE  <NA> 
##  1954   761  1368

Now we will replace NA values with False as well:

 df_simplified <- df_simplified %>%  
  mutate(ASSET_High = replace_na(ASSET_High, FALSE)) #NA values will be coded as not high asset (if no cases match the other two ASSET_AMT statements then code as FALSE) based on the above logic

Check that this worked and that there are no NA values now:

table(df_simplified$ASSET_High, useNA = "always")
## 
## FALSE  TRUE  <NA> 
##  3322   761     0

Now we will convert these to text as another variable and also create a log version of the asset amount to normalize it, as plots and analysis may be easier to interpret if there are many values that are high or low.

 df_simplified<-df_simplified %>%
  mutate(ASSET_High_text = case_when(ASSET_High  == TRUE ~ "High Asset",
                                     ASSET_High  == FALSE ~ "Low Asset")) %>%
  # we will also create new log of asset amount variable
  mutate(ASSET_AMT_log = log(ASSET_AMT))

Neighborhood category

Next we will modify the data to include a variable about the percentage of African American/Black people.

# create new Percent_AA variable by converting
#`Normalized African American Population` variable 
#into a percentage and rounding
 df_simplified<-df_simplified %>%
  mutate(Percent_AA = 
           round(`Normalized African American Population`*100, digits = 1))  %>%

  # create new Majority_AA variable that indicates if Percent_AA is greater than or equal to 50% or not
  mutate(Majority_AA = case_when(
    Percent_AA >= 50 ~ "Yes", 
    Percent_AA <  50 ~ "No")) %>%
  # create a new variable about this in text
   mutate(Neighborhood = case_when(
    Percent_AA >= 50 ~ "Majority\nBlack", 
    Percent_AA <  50 ~ "Majority\nNon-Black")) %>% 
  # make this a factor and order by level appearance in the data
  mutate(Neighborhood = as_factor(Neighborhood),
         Neighborhood = forcats::fct_inorder(Neighborhood))

Quantile data

To group the data by quantiles, we first remove organizations with zero assets because we don’t know if zero values are real. If assets are under 50,000, organizations can report as zero also.

Similarly, NA values could be anything between 0 and less than 50,000. Thus we aren’t sure what those asset amounts are.

 # make a new dataframe without zeros and NA asset amounts
df_simplified_no_zero<-df_simplified %>%
    drop_na(ASSET_AMT) %>% #redundant but shows we are dropping NA values
    filter(ASSET_AMT>0) %>% # ASSET_AMT must be greater than zero
  # get quartiles
    mutate(ASSET_quartile = ntile(ASSET_AMT, 4)) %>%
  # create new quartile variable that specifies quartiles by text
    mutate(ASSET_quartile_text = case_when(ASSET_quartile == 1 ~ "1st_Quartile",
                                           ASSET_quartile == 2 ~ "2nd_Quartile",
                                           ASSET_quartile == 3 ~ "3rd_Quartile",
                                           ASSET_quartile == 4 ~ "4th_Quartile"))

#Now check:
table(df_simplified_no_zero$ASSET_quartile, useNA = "always")
## 
##    1    2    3    4 <NA> 
##  375  374  374  374    0
df_simplified_no_zero%>% group_by(ASSET_quartile_text) %>% summarise(range = range(ASSET_AMT))
## Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in
## dplyr 1.1.0.
## ℹ Please use `reframe()` instead.
## ℹ When switching from `summarise()` to `reframe()`, remember that `reframe()`
##   always returns an ungrouped data frame and adjust accordingly.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `summarise()` has grouped output by 'ASSET_quartile_text'. You can override
## using the `.groups` argument.
## # A tibble: 8 × 2
## # Groups:   ASSET_quartile_text [4]
##   ASSET_quartile_text      range
##   <chr>                    <dbl>
## 1 1st_Quartile                 1
## 2 1st_Quartile             77638
## 3 2nd_Quartile             77996
## 4 2nd_Quartile            528175
## 5 3rd_Quartile            529732
## 6 3rd_Quartile           3783266
## 7 4th_Quartile           3804811
## 8 4th_Quartile        3267270835

Without removal (except NAs)- since these asset amounts might influence quartiles.

df_simplified_no_removal<-df_simplified %>%
    drop_na(ASSET_AMT) %>% #dropping NA values
  # get quartiles
    mutate(ASSET_quartile = ntile(ASSET_AMT, 4)) %>%
  # create new quartile variable that specifies quartiles by text
    mutate(ASSET_quartile_text = case_when(ASSET_quartile == 1 ~ "1st_Quartile",
                                           ASSET_quartile == 2 ~ "2nd_Quartile",
                                           ASSET_quartile == 3 ~ "3rd_Quartile",
                                           ASSET_quartile == 4 ~ "4th_Quartile"))

#Now check:
table(df_simplified_no_removal$ASSET_quartile, useNA = "always")
## 
##    1    2    3    4 <NA> 
##  679  679  679  678    0
df_simplified_no_removal %>% group_by(ASSET_quartile_text) %>% summarise(range = range(ASSET_AMT))
## Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in
## dplyr 1.1.0.
## ℹ Please use `reframe()` instead.
## ℹ When switching from `summarise()` to `reframe()`, remember that `reframe()`
##   always returns an ungrouped data frame and adjust accordingly.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `summarise()` has grouped output by 'ASSET_quartile_text'. You can override
## using the `.groups` argument.
## # A tibble: 8 × 2
## # Groups:   ASSET_quartile_text [4]
##   ASSET_quartile_text      range
##   <chr>                    <dbl>
## 1 1st_Quartile                 0
## 2 1st_Quartile                 0
## 3 2nd_Quartile                 0
## 4 2nd_Quartile              8141
## 5 3rd_Quartile              8251
## 6 3rd_Quartile            735297
## 7 4th_Quartile            738933
## 8 4th_Quartile        3267270835

Turns out this doesn’t really work because the 1st and 2nd quartiles can’t be distinguished as we don’t know if the values of 0 are actually some number below 50,000 and both quartlies have a max of less than 50,000. So we will stick with our removal.

National Taxonomy of Exempt Entities (NTEE) recoding

To provide more information to readers about what the nonprofits do, we will convert the National Taxonomy of Exempt Entities (NTEE) codes based on this and this (see page 15).

df_simplified <-df_simplified %>%
  mutate(NTEE_text = case_when(
    str_starts(NTEE_CD, pattern = "A")~ "Arts", # if NTEE_CD starts with A make new variable value "Arts" etc.
    str_starts(NTEE_CD, pattern = "B") ~ "Education",
    str_starts(NTEE_CD, pattern = "C|D") ~ "Environment/Animals", # if NTEE_CD value starts with C or D make new variable value "Environment/Animals"
    str_starts(NTEE_CD, pattern = "E|F|G|H") ~ "Health",
    str_starts(NTEE_CD, pattern = "I|J|K|L|M|N|O|P") ~ "Human Services",
    str_starts(NTEE_CD, pattern = "Q") ~ "International Affairs",
    str_starts(NTEE_CD, pattern = "R|S|T|U|V|W") ~ "Societal Benefit",
    str_starts(NTEE_CD, pattern = "X") ~ "Religious",
    TRUE ~ "NA")) # this line is redundant as this would happen automatically - but everything else will be NA

Also for the quantile data:

df_simplified_no_zero <-df_simplified_no_zero %>%
  mutate(NTEE_text = case_when(
    str_starts(NTEE_CD, pattern = "A")~ "Arts", # if NTEE_CD starts with A make new variable value "Arts" etc.
    str_starts(NTEE_CD, pattern = "B") ~ "Education",
    str_starts(NTEE_CD, pattern = "C|D") ~ "Environment/Animals", # if NTEE_CD value starts with C or D make new variable value "Environment/Animals"
    str_starts(NTEE_CD, pattern = "E|F|G|H") ~ "Health",
    str_starts(NTEE_CD, pattern = "I|J|K|L|M|N|O|P") ~ "Human Services",
    str_starts(NTEE_CD, pattern = "Q") ~ "International Affairs",
    str_starts(NTEE_CD, pattern = "R|S|T|U|V|W") ~ "Societal Benefit",
    str_starts(NTEE_CD, pattern = "X") ~ "Religous",
    TRUE ~ "NA")) # this line is redundant as this would happen automatically - but everything else will be NA

Visualizations and Analysis

Deeper possible visualizations

First without log normalization figure:

df_simplified_no_zero %>% 
ggplot(aes(y = ASSET_AMT, x = Percent_AA)) +
  geom_point() + geom_smooth(method = "loess")
## `geom_smooth()` using formula = 'y ~ x'

We can see that some of the dat points are much higher and this makes it challenging to see the lower data values.

Now let’s look at normalized version.

Overall log Asset amount figure:

df_simplified_no_zero %>% 
ggplot(aes(y = ASSET_AMT_log, x = Percent_AA)) +
  geom_point() + geom_smooth(method = "loess")
## `geom_smooth()` using formula = 'y ~ x'

Quartile plots

Quartiles with log asset data:

df_simplified_no_zero %>% 
ggplot(aes(y = ASSET_AMT_log, x = Percent_AA)) +
  geom_point() + facet_wrap(~ ASSET_quartile_text, scales = "free") +geom_smooth()
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

Look at log asset data for each NTEE type- remember the caveat that there are many organizations that are not included because of NA or zero value ASSET_AMT. However, still we can see that there is a trend towards lower amount of assets for most categories even with this limited data.

df_simplified_no_zero %>%
  ggplot(aes(y = ASSET_AMT_log, x = Neighborhood)) +
  geom_boxplot()+ geom_jitter(width = .08) + 
  facet_wrap(~ NTEE_text, scales = "free_y") + 
  geom_smooth(method = "lm", se=TRUE, aes(group=1))
## `geom_smooth()` using formula = 'y ~ x'

Compare all organizations by neighborhood AA status for log asset data. remember the caveat that there are many organizations that are not included because of NA or zero value ASSET_AMT

df_simplified_no_zero %>%
  ggplot(aes(y = ASSET_AMT_log, x = Neighborhood)) +
  geom_boxplot()+ geom_jitter(width = .08) + geom_smooth(method = "lm", se=TRUE, aes(group=1))
## `geom_smooth()` using formula = 'y ~ x'

Association Tests

summary(glm(data = df_simplified_no_zero, ASSET_AMT ~Percent_AA)) # for every increase in percent AA of the neighborhood there was a 266,249$ decrease in asset amount of the nonprofits in the neighborhood
## 
## Call:
## glm(formula = ASSET_AMT ~ Percent_AA, data = df_simplified_no_zero)
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 29664870    5349712   5.545 3.47e-08 ***
## Percent_AA   -266249     107553  -2.476   0.0134 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 1.84704e+16)
## 
##     Null deviance: 2.7726e+19  on 1496  degrees of freedom
## Residual deviance: 2.7613e+19  on 1495  degrees of freedom
## AIC: 60322
## 
## Number of Fisher Scoring iterations: 2
# there is a less than 5% risk of concluding that an association exists between asset amount a percent AA of neighborhood when there is no actual association.


hist(df_simplified_no_zero$ASSET_AMT_log)

summary(glm(data = df_simplified_no_zero, ASSET_AMT_log~Percent_AA)) # for every increase in percent AA of the neighborhood there was a 266,249$ decrease in asset amount of the nonprofits in the neighborhood
## 
## Call:
## glm(formula = ASSET_AMT_log ~ Percent_AA, data = df_simplified_no_zero)
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 13.632645   0.135946 100.280  < 2e-16 ***
## Percent_AA  -0.018598   0.002733  -6.805 1.46e-11 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for gaussian family taken to be 11.92755)
## 
##     Null deviance: 18384  on 1496  degrees of freedom
## Residual deviance: 17832  on 1495  degrees of freedom
## AIC: 7963.1
## 
## Number of Fisher Scoring iterations: 2
glm(data = df_simplified_no_zero, ASSET_AMT_log ~ Percent_AA) %>% plot(which = 1:3)

#nonparametric test - because the residiuals looked skewed in the above qqplot
cor.test(df_simplified_no_zero$ASSET_AMT, df_simplified_no_zero$Percent_AA, method = "spearman", exact = FALSE)
## 
##  Spearman's rank correlation rho
## 
## data:  df_simplified_no_zero$ASSET_AMT and df_simplified_no_zero$Percent_AA
## S = 641433720, p-value = 1.055e-08
## alternative hypothesis: true rho is not equal to 0
## sample estimates:
##        rho 
## -0.1471965

Look at quartiles with log asset data: remember the caveat that there are many organizations that are not included because of NA or zero value ASSET_AMT

df_simplified_no_zero %>%
  ggplot(aes(y = ASSET_AMT_log, x = Neighborhood)) +
  geom_boxplot()+ geom_jitter(width = .08) + geom_smooth(method = "lm", se=TRUE, aes(group=1)) + facet_wrap(~ASSET_quartile_text, scales = "free_y")
## `geom_smooth()` using formula = 'y ~ x'

First create data to make visualization easier caveat for the data: that there are many organizations that are not included because of NA or zero value ASSET_AMT

quartile_data <-df_simplified_no_zero %>% 
  group_by(ASSET_quartile_text, Neighborhood) %>% 
  count()
quartile_data
## # A tibble: 8 × 3
## # Groups:   ASSET_quartile_text, Neighborhood [8]
##   ASSET_quartile_text Neighborhood              n
##   <chr>               <fct>                 <int>
## 1 1st_Quartile        "Majority\nNon-Black"   217
## 2 1st_Quartile        "Majority\nBlack"       158
## 3 2nd_Quartile        "Majority\nNon-Black"   235
## 4 2nd_Quartile        "Majority\nBlack"       139
## 5 3rd_Quartile        "Majority\nNon-Black"   263
## 6 3rd_Quartile        "Majority\nBlack"       111
## 7 4th_Quartile        "Majority\nNon-Black"   268
## 8 4th_Quartile        "Majority\nBlack"       106

Create percentage variable for each quantile

quartile_data <- quartile_data %>%
  group_by(ASSET_quartile_text) %>% 
  mutate(Percent  = round(n/sum(n)*100)) 
quartile_data
## # A tibble: 8 × 4
## # Groups:   ASSET_quartile_text [4]
##   ASSET_quartile_text Neighborhood              n Percent
##   <chr>               <fct>                 <int>   <dbl>
## 1 1st_Quartile        "Majority\nNon-Black"   217      58
## 2 1st_Quartile        "Majority\nBlack"       158      42
## 3 2nd_Quartile        "Majority\nNon-Black"   235      63
## 4 2nd_Quartile        "Majority\nBlack"       139      37
## 5 3rd_Quartile        "Majority\nNon-Black"   263      70
## 6 3rd_Quartile        "Majority\nBlack"       111      30
## 7 4th_Quartile        "Majority\nNon-Black"   268      72
## 8 4th_Quartile        "Majority\nBlack"       106      28

Visuals…of the above data:

quart_plot <- quartile_data %>% 
  ggplot(aes(x= ASSET_quartile_text, y = Percent,  fill = Neighborhood)) + 
    geom_col(position = position_dodge(width = .9))+
     scale_y_continuous(labels = function(x) paste0(x, "%")) +
     ylim(0,100) +
    scale_fill_grey() +
    theme_linedraw() +
    geom_text(aes(label = paste0(Percent, "%")), position = position_dodge(width = .9), vjust = -.5) 
## Scale for y is already present.
## Adding another scale for y, which will replace the existing scale.
quart_plot + labs(x = "Quartile based on nonprofit asset amount", y = "Percentage of nonprofits in the asset quartile")

this does NOT include all 4,082 organizations

Overall Percentage Plot

First let’s get a count of each - NOTE we are keeping zero values and NA as low asset! The NA neighborhood means there is only one neighborhood that did not fit the categories or have information. We can drop this neighborhood.

df_simplified %>%
  count(ASSET_High_text, Neighborhood)
## # A tibble: 5 × 3
##   ASSET_High_text Neighborhood              n
##   <chr>           <fct>                 <int>
## 1 High Asset      "Majority\nNon-Black"   539
## 2 High Asset      "Majority\nBlack"       222
## 3 Low Asset       "Majority\nNon-Black"  1589
## 4 Low Asset       "Majority\nBlack"      1732
## 5 Low Asset        <NA>                     1
df_simplified <-df_simplified %>%
  drop_na(Neighborhood)

df_simplified %>%
  count(ASSET_High_text, Neighborhood)
## # A tibble: 4 × 3
##   ASSET_High_text Neighborhood              n
##   <chr>           <fct>                 <int>
## 1 High Asset      "Majority\nNon-Black"   539
## 2 High Asset      "Majority\nBlack"       222
## 3 Low Asset       "Majority\nNon-Black"  1589
## 4 Low Asset       "Majority\nBlack"      1732
High_asset_data <-df_simplified %>% 
  group_by(ASSET_High_text, Neighborhood) %>% 
  count() 
High_asset_data
## # A tibble: 4 × 3
## # Groups:   ASSET_High_text, Neighborhood [4]
##   ASSET_High_text Neighborhood              n
##   <chr>           <fct>                 <int>
## 1 High Asset      "Majority\nNon-Black"   539
## 2 High Asset      "Majority\nBlack"       222
## 3 Low Asset       "Majority\nNon-Black"  1589
## 4 Low Asset       "Majority\nBlack"      1732

Create percentage variable for each category:

High_asset_data <- High_asset_data %>%
  group_by(Neighborhood) %>% 
  mutate(Percent_AA_cat = round(n/sum(n)*100)) 
High_asset_data
## # A tibble: 4 × 4
## # Groups:   Neighborhood [2]
##   ASSET_High_text Neighborhood              n Percent_AA_cat
##   <chr>           <fct>                 <int>          <dbl>
## 1 High Asset      "Majority\nNon-Black"   539             25
## 2 High Asset      "Majority\nBlack"       222             11
## 3 Low Asset       "Majority\nNon-Black"  1589             75
## 4 Low Asset       "Majority\nBlack"      1732             89

Visuals…of the above data:

High_asset_data %>% 
  ggplot(aes(x= Neighborhood, y = Percent_AA_cat,  fill = ASSET_High_text)) + 
    geom_col(position = position_dodge(width = .9))+
     scale_y_continuous(labels = function(x) paste0(x, "%")) +
     ylim(0,100) +
    geom_text(aes(label = paste0(Percent_AA_cat, "%")), position = position_dodge(width = .9), vjust = -.5) +
  ylab("Percent of Neighborhood Category") +
  theme_linedraw() +
  scale_fill_grey() +
  theme(legend.title = element_blank())
## Scale for y is already present.
## Adding another scale for y, which will replace the existing scale.

this includes all 4,082 organizations

High vs non asset by category

First create data to make visualization easier

High_asset_data <-df_simplified %>%
  group_by(ASSET_High_text, Neighborhood, NTEE_text) %>% 
  count()
High_asset_data
## # A tibble: 36 × 4
## # Groups:   ASSET_High_text, Neighborhood, NTEE_text [36]
##    ASSET_High_text Neighborhood          NTEE_text                 n
##    <chr>           <fct>                 <chr>                 <int>
##  1 High Asset      "Majority\nNon-Black" Arts                     34
##  2 High Asset      "Majority\nNon-Black" Education                54
##  3 High Asset      "Majority\nNon-Black" Environment/Animals       9
##  4 High Asset      "Majority\nNon-Black" Health                   65
##  5 High Asset      "Majority\nNon-Black" Human Services           75
##  6 High Asset      "Majority\nNon-Black" International Affairs     4
##  7 High Asset      "Majority\nNon-Black" NA                      174
##  8 High Asset      "Majority\nNon-Black" Religious                 2
##  9 High Asset      "Majority\nNon-Black" Societal Benefit        122
## 10 High Asset      "Majority\nBlack"     Arts                      8
## # ℹ 26 more rows
#Create percentage variable for each category
High_asset_data <- High_asset_data %>%
  group_by(NTEE_text) %>% 
  mutate(Percent_ntee_cat = round(n/sum(n)*100)) 
High_asset_data
## # A tibble: 36 × 5
## # Groups:   NTEE_text [9]
##    ASSET_High_text Neighborhood          NTEE_text            n Percent_ntee_cat
##    <chr>           <fct>                 <chr>            <int>            <dbl>
##  1 High Asset      "Majority\nNon-Black" Arts                34               13
##  2 High Asset      "Majority\nNon-Black" Education           54               18
##  3 High Asset      "Majority\nNon-Black" Environment/Ani…     9               15
##  4 High Asset      "Majority\nNon-Black" Health              65               25
##  5 High Asset      "Majority\nNon-Black" Human Services      75                9
##  6 High Asset      "Majority\nNon-Black" International A…     4                9
##  7 High Asset      "Majority\nNon-Black" NA                 174               13
##  8 High Asset      "Majority\nNon-Black" Religious            2                0
##  9 High Asset      "Majority\nNon-Black" Societal Benefit   122               23
## 10 High Asset      "Majority\nBlack"     Arts                 8                3
## # ℹ 26 more rows

Visuals…of the above data:

High_asset_data %>% 
  ggplot(aes(x= Neighborhood, y = Percent_ntee_cat,  fill = ASSET_High_text)) + 
    geom_col(position = position_dodge(width = .9))+
     scale_y_continuous(labels = function(x) paste0(x, "%")) +
    ylim(0, 100) +
    geom_text(aes(label = paste0(Percent_ntee_cat, "%")), position = position_dodge(width = .9), vjust = -.5) + facet_wrap(~NTEE_text) +
  theme_linedraw() +
  scale_fill_grey() +
  theme(legend.title = element_blank()) +
  ylab("Percentage for each category")

this includes all 4,082 organizations

Count plots/Tables

Different kinds of orgs

library(forcats)
df_simplified %>% group_by(NTEE_text) %>%summarize(count = n()) %>% 
  mutate(NTEE_text = str_replace(string = NTEE_text, pattern = "NA", replacement = "Unclassified")) %>%
 mutate(Percentage = round(count/sum(count)*100, digits = 2)) %>%
  arrange(NTEE_text)
## # A tibble: 9 × 3
##   NTEE_text             count Percentage
##   <chr>                 <int>      <dbl>
## 1 Arts                    255       6.25
## 2 Education               305       7.47
## 3 Environment/Animals      59       1.45
## 4 Health                  264       6.47
## 5 Human Services          814      19.9 
## 6 International Affairs    43       1.05
## 7 Religious               469      11.5 
## 8 Societal Benefit        540      13.2 
## 9 Unclassified           1333      32.7
Total_NTEE <-df_simplified %>% group_by(NTEE_text) %>%summarize(count = n()) %>% 
  mutate(NTEE_text = str_replace(string = NTEE_text, pattern = "NA", replacement = "Unclassified")) %>%
  arrange(NTEE_text)
df_simplified %>% 
  group_by(NTEE_text, Neighborhood) %>%
  summarize(count = n()) %>% 
  mutate(NTEE_text = as_factor(NTEE_text)) %>%
  ggplot(aes(x = fct_reorder(NTEE_text, count, min), y = count , fill = Neighborhood)) + 
  scale_fill_viridis_d() +
  geom_col(position =position_dodge(width = .9))  + 
  ylab ("Number of Organizations") +
  theme_linedraw() +
  theme(axis.text.x = element_text(angle = 60, vjust = .5),
        axis.title.x = element_blank()) +
  scale_fill_grey()
## `summarise()` has grouped output by 'NTEE_text'. You can override using the
## `.groups` argument.
## Scale for fill is already present. Adding another scale for fill, which will
## replace the existing scale.

This includes all 4,082 organizations There was no removal of organizations based on asset amount, just to get a sense of what oganizations are in Baltimore.

plot2 <- df_simplified %>% 
    mutate(NTEE_text = as_factor(NTEE_text),
         NTEE_text = forcats::fct_relevel(NTEE_text, "International Affairs", "Environment/Animals", "Arts", "Religious", "Health","Education", "Societal Benefit", "Human Services", "NA" )) %>%
  group_by(NTEE_text, Neighborhood, ASSET_High_text) %>%
  summarize(count = n()) %>% 
  ggplot(aes(x = NTEE_text, y = count , fill = Neighborhood)) + 
  geom_col(position =position_dodge(width = .9))  + 
  facet_grid(rows = vars(ASSET_High_text)) +
  ylab ("Number of Organizations") +
  theme_linedraw() +
  theme(axis.text.x = element_text(angle = 60, vjust = .5),
        axis.title.x = element_blank()) +
  scale_fill_grey()
## `summarise()` has grouped output by 'NTEE_text', 'Neighborhood'. You can
## override using the `.groups` argument.
plot2

This includes all 4,082 organizations There was no removal of organizations based on asset amount, just to get a sense of what oganizations are in Baltimore.

High Asset Orgs

High_counts <- df_simplified %>% 
    mutate(NTEE_text = as_factor(NTEE_text),
        NTEE_text = forcats::fct_relevel(NTEE_text, "International Affairs", "Environment/Animals", "Arts", "Religious", "Health","Education", "Societal Benefit", "Human Services", "NA" )) %>%
  group_by(NTEE_text, ASSET_High_text) %>%
  summarize(count = n()) %>% filter(ASSET_High_text == "High Asset") %>%
    mutate(NTEE_text = str_replace(string = NTEE_text, pattern = "NA", replacement = "Unclassified"))
## `summarise()` has grouped output by 'NTEE_text'. You can override using the
## `.groups` argument.
full_join(Total_NTEE, High_counts, by = "NTEE_text") %>%
   mutate("Percentage_of_each_code" = round(count.y/count.x *100, digits = 2)) %>%
  arrange(NTEE_text) 
## # A tibble: 9 × 5
##   NTEE_text             count.x ASSET_High_text count.y Percentage_of_each_code
##   <chr>                   <int> <chr>             <int>                   <dbl>
## 1 Arts                      255 High Asset           42                   16.5 
## 2 Education                 305 High Asset           84                   27.5 
## 3 Environment/Animals        59 High Asset           12                   20.3 
## 4 Health                    264 High Asset           97                   36.7 
## 5 Human Services            814 High Asset          152                   18.7 
## 6 International Affairs      43 High Asset            5                   11.6 
## 7 Religious                 469 High Asset            3                    0.64
## 8 Societal Benefit          540 High Asset          155                   28.7 
## 9 Unclassified             1333 High Asset          211                   15.8

Distribution of percent AA

Now to take a look at if 50% African American makes sense. What do the neighborhoods look like?

# get the neighborhood values if no removing rows for nonprofits with NA or zero assets
neighborhood_AAperc <- df_simplified %>% 
 distinct(`neighborhood name`, Percent_AA)

# get the neighborhood values after removing rows for nonprofits with NA or zero assets
neighborhood_AAperc_nozero <- df_simplified_no_zero %>% 
 distinct(`neighborhood name`, Percent_AA)

We can see that there are many neighborhoods that have a more extreme percentage.

# get the neighborhood values if no removing rows for nonprofits with NA or zero assets

neighborhood_AAperc%>% pull(Percent_AA) %>% hist(main = "African American Percentage of Neighborhoods for each nonprofit")

# get the neighborhood values after removing rows for nonprofits with NA or zero assets
neighborhood_AAperc_nozero %>% pull(Percent_AA) %>% hist(main = "African American Percentage of Neighborhoods \n (removed neighborhoods with only zero or NA assets)")

LS0tCnRpdGxlOiAiQmFsdGltb3JlIE5vbnByb2ZpdCBBbmFseXNpcyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBzZWxmX2NvbnRhaW5lZDogeWVzCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKLS0tCgoKYGBge3IsIG1lc3NhZ2U9IEZBTFNFfQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KG5hbmlhcikKYGBgCgojIERhdGEgSW1wb3J0CmBgYHtyfQpkZl9zaW1wbGlmaWVkPC1yZWFkX2V4Y2VsKGhlcmU6OmhlcmUoIk5vbnByb2ZpdF9CYWx0aW1vcmVfQW5hbHlzaXMueGxzeCIpLCBzaGVldCA9IDMpCmBgYAoKSW5mb3JtYXRpb24gYWJvdXQgdGhlIGRhdGE6IApIZXJl4oCZcyBhbiBbYXJ0aWNsZV0oaHR0cHM6Ly9uY2NzLnVyYmFuLm9yZy9uY2NzL2RhdGFzZXRzL2JtZi8pIGRlc2NyaWJpbmcgc29tZSBvZiB0aGUgZGF0YXNldHMgZnJvbSB0aGUgSVJTIDk5MHMuIFdl4oCZcmUgdXNpbmcgdGhlIEJ1c2luZXNzIE1hc3RlciBGaWxlIChCTUYpLiAgVGhlcmXigJlzIGEgc2VjdGlvbiB0aXRsZWQg4oCcTWluaW11bSBGaWxpbmcgVGhyZXNob2xk4oCdIHRoYXQgZXhwbGFpbnMgYSBkYXRhIGxpbWl0YXRpb24gKGFuZCB3aHkgd2XigJlyZSBzZWVpbmcgc28gbWFueSAw4oCZcykuIFNlZSBbaGVyZV0oaHR0cHM6Ly93d3cuaXJzLmdvdi9jaGFyaXRpZXMtbm9uLXByb2ZpdHMvZXhlbXB0LW9yZ2FuaXphdGlvbnMtYW5udWFsLXJlcG9ydGluZy1yZXF1aXJlbWVudHMtb3ZlcnZpZXctYW5udWFsLXJldHVybi1maWxpbmctZXhjZXB0aW9ucykgZm9yIG1vcmUgaW5mby4KCkl0IHNlZW1zIHRoYXQgaWYgdGhlcmUgaXMgYSB2YWx1ZSBsZXNzIHRoYW4gNTAsMDAwIG90aGVyIHRoYW4gemVybywgaXQgbXVzdCBtZWFuIHRoYXQgdGhlIG9yZ2FuaXphdGlvbiBkZWNpZGVkIHRvIHN1Ym1pdCB0byB0aGUgSVJTLCBiZWNhdXNlIG90aGVyd2lzZSB0aGV5IHdvdWxkIGJlIGxpc3RlZCBhcyBhIHplcm8uIEl0IGlzIG5vdCBwb3NzaWJsZSB0byBkaXN0aW5ndWlzaCBhIHRydWUgemVybyBmcm9tIGEgemVybyBkdWUgdG8gbm90IG1lZXRpbmcgdGhlIHRocmVzaG9sZCBvZiA1MCwwMDAgYW5kIGp1c3Qgbm90IHN1Ym1pdHRpbmcuIFNlZSBbdGhpcyBndWlkZV0oaHR0cHM6Ly9naXRodWIuY29tL2podWRzbC9CYWx0aW1vcmVfbm9ucHJvZml0c19hc3NldHMvYmxvYi84MDk0MTkxYjg4YmNlZjY1MDNjMTMyYzdjYzczNDA4YzEyZGRjOTE2L0d1aWRlX3RvX1VzaW5nX05DQ1NfRGF0YV8yMDIucGRmKSwgcGFnZSA1IGluIHRoZSAibWluaW11bSBmaWxpbmcgdGhyZXNob2xkIiBzZWN0aW9uLgoKSXQgdGhlcmVmb3JlIG1ha2VzIHNlbnNlIHRvIHJlbW92ZSB6ZXJvIHZhbHVlcyBhbmQgdG8gcmVwb3J0IHRoaXMgY2F2ZWF0IHRoYXQgdGhlIGRhdGEgaXMgaW5jb21wbGV0ZSBiZWNhdXNlIG1hbnkgbm9ucHJvZml0cyB0aGF0IGhhZCBhc3NldHMgbGVzcyB0aGFuIDUwLDAwMCBhcmUgbm90IGluY2x1ZGVkLgoKSG93ZXZlciBmb3IgdGhlIGhpZ2ggdnMgbm9uaGlnaCBhc3NldCB3ZSBjb3VsZCBrZWVwIHRoZXNlIC0gYmVjYXVzZSB6ZXJvIHZhbHVlcyB3b3VsZCBzdGlsbCBiZSBsZXNzIHRoYW4gdGhlIHRocmVzaG9sZCByZWdhcmRsZXNzLgoKQWRkaW5nIHRvIHRoaXMgTkEgdmFsdWVzIGNhbiBiZSBjb25zaWRlcmVkIGxlc3MgdGhhbiA1MDAwMCwgYXMgb3JnYW5pemF0aW9ucyBhcmUgbm90IHJlcXVpcmVkIHRvIHJlcG9ydCBhbiBhbW91bnQgaWYgdGhleSBoYXZlIGxlc3MgdGhhbiA1MDAwMC4KCiMgVGlkeWluZyBkYXRhIGFuZCBFeHBsb3JhdG9yeSBBbmFseXNpcwoKIyMgQXNzZXQgYW1vdW50CgpGaXJzdCBsZXQncyBjaGVjayBob3cgbWFueSB6ZXJvIHZhbHVlcyB0aGVyZSBhcmUgZm9yIGFzc2V0IGFtb3VudHMuCgpgYGB7cn0KZGZfc2ltcGxpZmllZCAlPiUgZmlsdGVyKEFTU0VUX0FNVD09MCklPiUgbnJvdygpCmBgYAoKTm93IHdlIHdpbGwgY2hlY2sgaWYgdGhlcmUgYXJlIGBOQWAgdmFsdWVzIGZvciBhc3NldCBhbW91bnRzLgoKYGBge3IsIGZpZy5oZWlnaHQ9IDh9CmdnX21pc3NfdmFyKGRmX3NpbXBsaWZpZWQpCmBgYAoKWWVzLCBpbmRlZWQgdGhlcmUgYXJlLi4uCgpOQSBhbmQgemVybyB2YWx1ZXMgbGlrZWx5IG1lYW4gdGhlIG5vbnByb2ZpdCBkaWQgbm90IG5lZWQgdG8gc3VibWl0IHRvIHRoZSBJUlMuCkl0IGlzIGltcG9zc2libGUgdG8ga25vdyBob3dldmVyLCBpZiBhIHplcm8gaXMgYWN0dWFsbHkgYSB0cnVlIHplcm8uIE5BIHZhbHVlcyBjb3VsZCBtZWFuIHNvbWV0aGluZyBlbHNlLiAKClRodXMsIHdlIHdpbGwgcmVjb2RlIGFzc2V0IGFtb3VudCBiYXNlZCBvbiBhIHRocmVzaG9sZCBvZiBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gNTAwLDAwMCBhcyBoaWdoIGFzc2V0IGFuZCBsZXNzIHRoYW4gNTAwLDAwMCAoaW5jbHVkaW5nIHplcm8pIGFzIG5vdCBoaWdoIGFzc2V0LgpOb3RlIHdlIGtlZXAgb3VyIE5BIHZhbHVlcyB3aXRoIHRoaXMgcmVjb2RpbmcuCgpgYGB7cn0KCmRmX3NpbXBsaWZpZWQ8LWRmX3NpbXBsaWZpZWQgJT4lCiAgIyBtb2RpZnkgQXNzZXQgYW1vdW50IHZhcmlhYmxlIHRvIGJlIG51bWVyaWMKICBtdXRhdGUoQVNTRVRfQU1UID0gYXMubnVtZXJpYyhBU1NFVF9BTVQpKSAlPiUKICAjY3JlYXRlIGEgdmFyaWFibGUgYWJvdXQgaGlnaCBhc3NldCBhbW91bnQgKHRocmVzaG9sZCBiZWluZyAkNTAwLDAwMCkKICBtdXRhdGUoQVNTRVRfSGlnaCA9IGNhc2Vfd2hlbihBU1NFVF9BTVQgID49IDUwMDAwMCB+IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQVNTRVRfQU1UICA8IDUwMDAwMCB+IEZBTFNFKSkKYGBgCgpIZXJlIHdlIGNhbiBzZWUgdGhlIE5BIHZhbHVlczoKCmBgYHtyfQp0YWJsZShkZl9zaW1wbGlmaWVkJEFTU0VUX0hpZ2gsIHVzZU5BID0gImFsd2F5cyIpCmBgYAoKTm93IHdlIHdpbGwgcmVwbGFjZSBgTkFgIHZhbHVlcyB3aXRoIGBGYWxzZWAgYXMgd2VsbDoKCmBgYHtyfQogZGZfc2ltcGxpZmllZCA8LSBkZl9zaW1wbGlmaWVkICU+JSAgCiAgbXV0YXRlKEFTU0VUX0hpZ2ggPSByZXBsYWNlX25hKEFTU0VUX0hpZ2gsIEZBTFNFKSkgI05BIHZhbHVlcyB3aWxsIGJlIGNvZGVkIGFzIG5vdCBoaWdoIGFzc2V0IChpZiBubyBjYXNlcyBtYXRjaCB0aGUgb3RoZXIgdHdvIEFTU0VUX0FNVCBzdGF0ZW1lbnRzIHRoZW4gY29kZSBhcyBGQUxTRSkgYmFzZWQgb24gdGhlIGFib3ZlIGxvZ2ljCmBgYAoKQ2hlY2sgdGhhdCB0aGlzIHdvcmtlZCBhbmQgdGhhdCB0aGVyZSBhcmUgbm8gTkEgdmFsdWVzIG5vdzoKCmBgYHtyfQp0YWJsZShkZl9zaW1wbGlmaWVkJEFTU0VUX0hpZ2gsIHVzZU5BID0gImFsd2F5cyIpCmBgYAoKTm93IHdlIHdpbGwgY29udmVydCB0aGVzZSB0byB0ZXh0IGFzIGFub3RoZXIgdmFyaWFibGUgYW5kIGFsc28gY3JlYXRlIGEgbG9nIHZlcnNpb24gb2YgdGhlIGFzc2V0IGFtb3VudCB0byBub3JtYWxpemUgaXQsIGFzIHBsb3RzIGFuZCBhbmFseXNpcyBtYXkgYmUgZWFzaWVyIHRvIGludGVycHJldCBpZiB0aGVyZSBhcmUgbWFueSB2YWx1ZXMgdGhhdCBhcmUgaGlnaCBvciBsb3cuCgpgYGB7cn0KIGRmX3NpbXBsaWZpZWQ8LWRmX3NpbXBsaWZpZWQgJT4lCiAgbXV0YXRlKEFTU0VUX0hpZ2hfdGV4dCA9IGNhc2Vfd2hlbihBU1NFVF9IaWdoICA9PSBUUlVFIH4gIkhpZ2ggQXNzZXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQVNTRVRfSGlnaCAgPT0gRkFMU0UgfiAiTG93IEFzc2V0IikpICU+JQogICMgd2Ugd2lsbCBhbHNvIGNyZWF0ZSBuZXcgbG9nIG9mIGFzc2V0IGFtb3VudCB2YXJpYWJsZQogIG11dGF0ZShBU1NFVF9BTVRfbG9nID0gbG9nKEFTU0VUX0FNVCkpCmBgYAoKIyMgTmVpZ2hib3Job29kIGNhdGVnb3J5CgpOZXh0IHdlIHdpbGwgbW9kaWZ5IHRoZSBkYXRhIHRvIGluY2x1ZGUgYSB2YXJpYWJsZSBhYm91dCB0aGUgcGVyY2VudGFnZSBvZiBBZnJpY2FuIEFtZXJpY2FuL0JsYWNrIHBlb3BsZS4KYGBge3J9CiMgY3JlYXRlIG5ldyBQZXJjZW50X0FBIHZhcmlhYmxlIGJ5IGNvbnZlcnRpbmcKI2BOb3JtYWxpemVkIEFmcmljYW4gQW1lcmljYW4gUG9wdWxhdGlvbmAgdmFyaWFibGUgCiNpbnRvIGEgcGVyY2VudGFnZSBhbmQgcm91bmRpbmcKIGRmX3NpbXBsaWZpZWQ8LWRmX3NpbXBsaWZpZWQgJT4lCiAgbXV0YXRlKFBlcmNlbnRfQUEgPSAKICAgICAgICAgICByb3VuZChgTm9ybWFsaXplZCBBZnJpY2FuIEFtZXJpY2FuIFBvcHVsYXRpb25gKjEwMCwgZGlnaXRzID0gMSkpICAlPiUKCiAgIyBjcmVhdGUgbmV3IE1ham9yaXR5X0FBIHZhcmlhYmxlIHRoYXQgaW5kaWNhdGVzIGlmIFBlcmNlbnRfQUEgaXMgZ3JlYXRlciB0aGFuIG9yIGVxdWFsIHRvIDUwJSBvciBub3QKICBtdXRhdGUoTWFqb3JpdHlfQUEgPSBjYXNlX3doZW4oCiAgICBQZXJjZW50X0FBID49IDUwIH4gIlllcyIsIAogICAgUGVyY2VudF9BQSA8ICA1MCB+ICJObyIpKSAlPiUKICAjIGNyZWF0ZSBhIG5ldyB2YXJpYWJsZSBhYm91dCB0aGlzIGluIHRleHQKICAgbXV0YXRlKE5laWdoYm9yaG9vZCA9IGNhc2Vfd2hlbigKICAgIFBlcmNlbnRfQUEgPj0gNTAgfiAiTWFqb3JpdHlcbkJsYWNrIiwgCiAgICBQZXJjZW50X0FBIDwgIDUwIH4gIk1ham9yaXR5XG5Ob24tQmxhY2siKSkgJT4lIAogICMgbWFrZSB0aGlzIGEgZmFjdG9yIGFuZCBvcmRlciBieSBsZXZlbCBhcHBlYXJhbmNlIGluIHRoZSBkYXRhCiAgbXV0YXRlKE5laWdoYm9yaG9vZCA9IGFzX2ZhY3RvcihOZWlnaGJvcmhvb2QpLAogICAgICAgICBOZWlnaGJvcmhvb2QgPSBmb3JjYXRzOjpmY3RfaW5vcmRlcihOZWlnaGJvcmhvb2QpKQpgYGAKCiMjIFF1YW50aWxlIGRhdGEKVG8gZ3JvdXAgdGhlIGRhdGEgYnkgcXVhbnRpbGVzLCB3ZSBmaXJzdCByZW1vdmUgb3JnYW5pemF0aW9ucyB3aXRoIHplcm8gYXNzZXRzIGJlY2F1c2Ugd2UgZG9uJ3Qga25vdyBpZiB6ZXJvIHZhbHVlcyBhcmUgcmVhbC4gSWYgYXNzZXRzIGFyZSB1bmRlciA1MCwwMDAsIG9yZ2FuaXphdGlvbnMgY2FuIHJlcG9ydCBhcyB6ZXJvIGFsc28uCgpTaW1pbGFybHksIE5BIHZhbHVlcyBjb3VsZCBiZSBhbnl0aGluZyBiZXR3ZWVuIDAgYW5kIGxlc3MgdGhhbiA1MCwwMDAuIFRodXMgd2UgYXJlbid0IHN1cmUgd2hhdCB0aG9zZSBhc3NldCBhbW91bnRzIGFyZS4KYGBge3J9CiAjIG1ha2UgYSBuZXcgZGF0YWZyYW1lIHdpdGhvdXQgemVyb3MgYW5kIE5BIGFzc2V0IGFtb3VudHMKZGZfc2ltcGxpZmllZF9ub196ZXJvPC1kZl9zaW1wbGlmaWVkICU+JQogICAgZHJvcF9uYShBU1NFVF9BTVQpICU+JSAjcmVkdW5kYW50IGJ1dCBzaG93cyB3ZSBhcmUgZHJvcHBpbmcgTkEgdmFsdWVzCiAgICBmaWx0ZXIoQVNTRVRfQU1UPjApICU+JSAjIEFTU0VUX0FNVCBtdXN0IGJlIGdyZWF0ZXIgdGhhbiB6ZXJvCiAgIyBnZXQgcXVhcnRpbGVzCiAgICBtdXRhdGUoQVNTRVRfcXVhcnRpbGUgPSBudGlsZShBU1NFVF9BTVQsIDQpKSAlPiUKICAjIGNyZWF0ZSBuZXcgcXVhcnRpbGUgdmFyaWFibGUgdGhhdCBzcGVjaWZpZXMgcXVhcnRpbGVzIGJ5IHRleHQKICAgIG11dGF0ZShBU1NFVF9xdWFydGlsZV90ZXh0ID0gY2FzZV93aGVuKEFTU0VUX3F1YXJ0aWxlID09IDEgfiAiMXN0X1F1YXJ0aWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFTU0VUX3F1YXJ0aWxlID09IDIgfiAiMm5kX1F1YXJ0aWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFTU0VUX3F1YXJ0aWxlID09IDMgfiAiM3JkX1F1YXJ0aWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFTU0VUX3F1YXJ0aWxlID09IDQgfiAiNHRoX1F1YXJ0aWxlIikpCgojTm93IGNoZWNrOgp0YWJsZShkZl9zaW1wbGlmaWVkX25vX3plcm8kQVNTRVRfcXVhcnRpbGUsIHVzZU5BID0gImFsd2F5cyIpCgpkZl9zaW1wbGlmaWVkX25vX3plcm8lPiUgZ3JvdXBfYnkoQVNTRVRfcXVhcnRpbGVfdGV4dCkgJT4lIHN1bW1hcmlzZShyYW5nZSA9IHJhbmdlKEFTU0VUX0FNVCkpCgpgYGAKCgpXaXRob3V0IHJlbW92YWwgKGV4Y2VwdCBOQXMpLSBzaW5jZSB0aGVzZSBhc3NldCBhbW91bnRzIG1pZ2h0IGluZmx1ZW5jZSBxdWFydGlsZXMuIApgYGB7cn0KCmRmX3NpbXBsaWZpZWRfbm9fcmVtb3ZhbDwtZGZfc2ltcGxpZmllZCAlPiUKICAgIGRyb3BfbmEoQVNTRVRfQU1UKSAlPiUgI2Ryb3BwaW5nIE5BIHZhbHVlcwogICMgZ2V0IHF1YXJ0aWxlcwogICAgbXV0YXRlKEFTU0VUX3F1YXJ0aWxlID0gbnRpbGUoQVNTRVRfQU1ULCA0KSkgJT4lCiAgIyBjcmVhdGUgbmV3IHF1YXJ0aWxlIHZhcmlhYmxlIHRoYXQgc3BlY2lmaWVzIHF1YXJ0aWxlcyBieSB0ZXh0CiAgICBtdXRhdGUoQVNTRVRfcXVhcnRpbGVfdGV4dCA9IGNhc2Vfd2hlbihBU1NFVF9xdWFydGlsZSA9PSAxIH4gIjFzdF9RdWFydGlsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBU1NFVF9xdWFydGlsZSA9PSAyIH4gIjJuZF9RdWFydGlsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBU1NFVF9xdWFydGlsZSA9PSAzIH4gIjNyZF9RdWFydGlsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBU1NFVF9xdWFydGlsZSA9PSA0IH4gIjR0aF9RdWFydGlsZSIpKQoKI05vdyBjaGVjazoKdGFibGUoZGZfc2ltcGxpZmllZF9ub19yZW1vdmFsJEFTU0VUX3F1YXJ0aWxlLCB1c2VOQSA9ICJhbHdheXMiKQoKZGZfc2ltcGxpZmllZF9ub19yZW1vdmFsICU+JSBncm91cF9ieShBU1NFVF9xdWFydGlsZV90ZXh0KSAlPiUgc3VtbWFyaXNlKHJhbmdlID0gcmFuZ2UoQVNTRVRfQU1UKSkKYGBgCgpUdXJucyBvdXQgdGhpcyBkb2Vzbid0IHJlYWxseSB3b3JrIGJlY2F1c2UgdGhlIDFzdCBhbmQgMm5kIHF1YXJ0aWxlcyBjYW4ndCBiZSBkaXN0aW5ndWlzaGVkIGFzIHdlIGRvbid0IGtub3cgaWYgdGhlIHZhbHVlcyBvZiAwIGFyZSBhY3R1YWxseSBzb21lIG51bWJlciBiZWxvdyA1MCwwMDAgYW5kIGJvdGggcXVhcnRsaWVzIGhhdmUgYSBtYXggb2YgbGVzcyB0aGFuIDUwLDAwMC4gU28gd2Ugd2lsbCBzdGljayB3aXRoIG91ciByZW1vdmFsLgoKIyMgTmF0aW9uYWwgVGF4b25vbXkgb2YgRXhlbXB0IEVudGl0aWVzIChOVEVFKSByZWNvZGluZwoKVG8gcHJvdmlkZSBtb3JlIGluZm9ybWF0aW9uIHRvIHJlYWRlcnMgYWJvdXQgd2hhdCB0aGUgbm9ucHJvZml0cyBkbywgd2Ugd2lsbCBjb252ZXJ0IHRoZSBOYXRpb25hbCBUYXhvbm9teSBvZiBFeGVtcHQgRW50aXRpZXMgKE5URUUpIGNvZGVzIGJhc2VkIG9uIFt0aGlzXShodHRwczovL3VyYmFuaW5zdGl0dXRlLmdpdGh1Yi5pby9uY2NzLWxlZ2FjeS9udGVlL250ZWUuaHRtbCkgYW5kIFt0aGlzIChzZWUgcGFnZSAxNSldKGh0dHBzOi8vd3d3Lmlycy5nb3YvcHViL2lycy10ZWdlL3A0ODM4LnBkZikuCgpgYGB7cn0KZGZfc2ltcGxpZmllZCA8LWRmX3NpbXBsaWZpZWQgJT4lCiAgbXV0YXRlKE5URUVfdGV4dCA9IGNhc2Vfd2hlbigKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJBIil+ICJBcnRzIiwgIyBpZiBOVEVFX0NEIHN0YXJ0cyB3aXRoIEEgbWFrZSBuZXcgdmFyaWFibGUgdmFsdWUgIkFydHMiIGV0Yy4KICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJCIikgfiAiRWR1Y2F0aW9uIiwKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJDfEQiKSB+ICJFbnZpcm9ubWVudC9BbmltYWxzIiwgIyBpZiBOVEVFX0NEIHZhbHVlIHN0YXJ0cyB3aXRoIEMgb3IgRCBtYWtlIG5ldyB2YXJpYWJsZSB2YWx1ZSAiRW52aXJvbm1lbnQvQW5pbWFscyIKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJFfEZ8R3xIIikgfiAiSGVhbHRoIiwKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJJfEp8S3xMfE18TnxPfFAiKSB+ICJIdW1hbiBTZXJ2aWNlcyIsCiAgICBzdHJfc3RhcnRzKE5URUVfQ0QsIHBhdHRlcm4gPSAiUSIpIH4gIkludGVybmF0aW9uYWwgQWZmYWlycyIsCiAgICBzdHJfc3RhcnRzKE5URUVfQ0QsIHBhdHRlcm4gPSAiUnxTfFR8VXxWfFciKSB+ICJTb2NpZXRhbCBCZW5lZml0IiwKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJYIikgfiAiUmVsaWdpb3VzIiwKICAgIFRSVUUgfiAiTkEiKSkgIyB0aGlzIGxpbmUgaXMgcmVkdW5kYW50IGFzIHRoaXMgd291bGQgaGFwcGVuIGF1dG9tYXRpY2FsbHkgLSBidXQgZXZlcnl0aGluZyBlbHNlIHdpbGwgYmUgTkEKYGBgCgoKQWxzbyBmb3IgdGhlIHF1YW50aWxlIGRhdGE6CmBgYHtyfQpkZl9zaW1wbGlmaWVkX25vX3plcm8gPC1kZl9zaW1wbGlmaWVkX25vX3plcm8gJT4lCiAgbXV0YXRlKE5URUVfdGV4dCA9IGNhc2Vfd2hlbigKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJBIil+ICJBcnRzIiwgIyBpZiBOVEVFX0NEIHN0YXJ0cyB3aXRoIEEgbWFrZSBuZXcgdmFyaWFibGUgdmFsdWUgIkFydHMiIGV0Yy4KICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJCIikgfiAiRWR1Y2F0aW9uIiwKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJDfEQiKSB+ICJFbnZpcm9ubWVudC9BbmltYWxzIiwgIyBpZiBOVEVFX0NEIHZhbHVlIHN0YXJ0cyB3aXRoIEMgb3IgRCBtYWtlIG5ldyB2YXJpYWJsZSB2YWx1ZSAiRW52aXJvbm1lbnQvQW5pbWFscyIKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJFfEZ8R3xIIikgfiAiSGVhbHRoIiwKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJJfEp8S3xMfE18TnxPfFAiKSB+ICJIdW1hbiBTZXJ2aWNlcyIsCiAgICBzdHJfc3RhcnRzKE5URUVfQ0QsIHBhdHRlcm4gPSAiUSIpIH4gIkludGVybmF0aW9uYWwgQWZmYWlycyIsCiAgICBzdHJfc3RhcnRzKE5URUVfQ0QsIHBhdHRlcm4gPSAiUnxTfFR8VXxWfFciKSB+ICJTb2NpZXRhbCBCZW5lZml0IiwKICAgIHN0cl9zdGFydHMoTlRFRV9DRCwgcGF0dGVybiA9ICJYIikgfiAiUmVsaWdvdXMiLAogICAgVFJVRSB+ICJOQSIpKSAjIHRoaXMgbGluZSBpcyByZWR1bmRhbnQgYXMgdGhpcyB3b3VsZCBoYXBwZW4gYXV0b21hdGljYWxseSAtIGJ1dCBldmVyeXRoaW5nIGVsc2Ugd2lsbCBiZSBOQQpgYGAKCgojIFZpc3VhbGl6YXRpb25zIGFuZCBBbmFseXNpcwoKIyMgRGVlcGVyIHBvc3NpYmxlIHZpc3VhbGl6YXRpb25zIAoKRmlyc3Qgd2l0aG91dCBsb2cgbm9ybWFsaXphdGlvbiBmaWd1cmU6CmBgYHtyfQpkZl9zaW1wbGlmaWVkX25vX3plcm8gJT4lIApnZ3Bsb3QoYWVzKHkgPSBBU1NFVF9BTVQsIHggPSBQZXJjZW50X0FBKSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIpCgpgYGAKV2UgY2FuIHNlZSB0aGF0IHNvbWUgb2YgdGhlIGRhdCBwb2ludHMgYXJlIG11Y2ggaGlnaGVyIGFuZCB0aGlzIG1ha2VzIGl0IGNoYWxsZW5naW5nIHRvIHNlZSB0aGUgbG93ZXIgZGF0YSB2YWx1ZXMuIAoKTm93IGxldCdzIGxvb2sgYXQgbm9ybWFsaXplZCB2ZXJzaW9uLgoKT3ZlcmFsbCBsb2cgQXNzZXQgYW1vdW50IGZpZ3VyZToKYGBge3J9CmRmX3NpbXBsaWZpZWRfbm9femVybyAlPiUgCmdncGxvdChhZXMoeSA9IEFTU0VUX0FNVF9sb2csIHggPSBQZXJjZW50X0FBKSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIpCgoKYGBgCgoKCiMjIFF1YXJ0aWxlIHBsb3RzCgoKUXVhcnRpbGVzIHdpdGggbG9nIGFzc2V0IGRhdGE6CmBgYHtyfQpkZl9zaW1wbGlmaWVkX25vX3plcm8gJT4lIApnZ3Bsb3QoYWVzKHkgPSBBU1NFVF9BTVRfbG9nLCB4ID0gUGVyY2VudF9BQSkpICsKICBnZW9tX3BvaW50KCkgKyBmYWNldF93cmFwKH4gQVNTRVRfcXVhcnRpbGVfdGV4dCwgc2NhbGVzID0gImZyZWUiKSArZ2VvbV9zbW9vdGgoKQpgYGAKCgoKCgoKTG9vayBhdCBsb2cgYXNzZXQgZGF0YSBmb3IgZWFjaCBOVEVFIHR5cGUtICoqcmVtZW1iZXIgdGhlIGNhdmVhdCB0aGF0IHRoZXJlIGFyZSBtYW55IG9yZ2FuaXphdGlvbnMgdGhhdCBhcmUgbm90IGluY2x1ZGVkIGJlY2F1c2Ugb2YgTkEgb3IgemVybyB2YWx1ZSBBU1NFVF9BTVQqKi4gSG93ZXZlciwgc3RpbGwgd2UgY2FuIHNlZSB0aGF0IHRoZXJlIGlzIGEgdHJlbmQgdG93YXJkcyBsb3dlciBhbW91bnQgb2YgYXNzZXRzIGZvciBtb3N0IGNhdGVnb3JpZXMgZXZlbiB3aXRoIHRoaXMgbGltaXRlZCBkYXRhLgoKYGBge3J9CmRmX3NpbXBsaWZpZWRfbm9femVybyAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBBU1NFVF9BTVRfbG9nLCB4ID0gTmVpZ2hib3Job29kKSkgKwogIGdlb21fYm94cGxvdCgpKyBnZW9tX2ppdHRlcih3aWR0aCA9IC4wOCkgKyAKICBmYWNldF93cmFwKH4gTlRFRV90ZXh0LCBzY2FsZXMgPSAiZnJlZV95IikgKyAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1UUlVFLCBhZXMoZ3JvdXA9MSkpCmBgYAoKQ29tcGFyZSBhbGwgb3JnYW5pemF0aW9ucyBieSBuZWlnaGJvcmhvb2QgQUEgc3RhdHVzIGZvciBsb2cgYXNzZXQgZGF0YS4gKnJlbWVtYmVyIHRoZSBjYXZlYXQgdGhhdCB0aGVyZSBhcmUgbWFueSBvcmdhbml6YXRpb25zIHRoYXQgYXJlIG5vdCBpbmNsdWRlZCBiZWNhdXNlIG9mIE5BIG9yIHplcm8gdmFsdWUgQVNTRVRfQU1UKgoKYGBge3J9CmRmX3NpbXBsaWZpZWRfbm9femVybyAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBBU1NFVF9BTVRfbG9nLCB4ID0gTmVpZ2hib3Job29kKSkgKwogIGdlb21fYm94cGxvdCgpKyBnZW9tX2ppdHRlcih3aWR0aCA9IC4wOCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1UUlVFLCBhZXMoZ3JvdXA9MSkpCmBgYAoKIyMgQXNzb2NpYXRpb24gVGVzdHMKCmBgYHtyfQoKc3VtbWFyeShnbG0oZGF0YSA9IGRmX3NpbXBsaWZpZWRfbm9femVybywgQVNTRVRfQU1UIH5QZXJjZW50X0FBKSkgIyBmb3IgZXZlcnkgaW5jcmVhc2UgaW4gcGVyY2VudCBBQSBvZiB0aGUgbmVpZ2hib3Job29kIHRoZXJlIHdhcyBhIDI2NiwyNDkkIGRlY3JlYXNlIGluIGFzc2V0IGFtb3VudCBvZiB0aGUgbm9ucHJvZml0cyBpbiB0aGUgbmVpZ2hib3Job29kCiMgdGhlcmUgaXMgYSBsZXNzIHRoYW4gNSUgcmlzayBvZiBjb25jbHVkaW5nIHRoYXQgYW4gYXNzb2NpYXRpb24gZXhpc3RzIGJldHdlZW4gYXNzZXQgYW1vdW50IGEgcGVyY2VudCBBQSBvZiBuZWlnaGJvcmhvb2Qgd2hlbiB0aGVyZSBpcyBubyBhY3R1YWwgYXNzb2NpYXRpb24uCgoKaGlzdChkZl9zaW1wbGlmaWVkX25vX3plcm8kQVNTRVRfQU1UX2xvZykKc3VtbWFyeShnbG0oZGF0YSA9IGRmX3NpbXBsaWZpZWRfbm9femVybywgQVNTRVRfQU1UX2xvZ35QZXJjZW50X0FBKSkgIyBmb3IgZXZlcnkgaW5jcmVhc2UgaW4gcGVyY2VudCBBQSBvZiB0aGUgbmVpZ2hib3Job29kIHRoZXJlIHdhcyBhIDI2NiwyNDkkIGRlY3JlYXNlIGluIGFzc2V0IGFtb3VudCBvZiB0aGUgbm9ucHJvZml0cyBpbiB0aGUgbmVpZ2hib3Job29kCgoKZ2xtKGRhdGEgPSBkZl9zaW1wbGlmaWVkX25vX3plcm8sIEFTU0VUX0FNVF9sb2cgfiBQZXJjZW50X0FBKSAlPiUgcGxvdCh3aGljaCA9IDE6MykKCiNub25wYXJhbWV0cmljIHRlc3QgLSBiZWNhdXNlIHRoZSByZXNpZGl1YWxzIGxvb2tlZCBza2V3ZWQgaW4gdGhlIGFib3ZlIHFxcGxvdApjb3IudGVzdChkZl9zaW1wbGlmaWVkX25vX3plcm8kQVNTRVRfQU1ULCBkZl9zaW1wbGlmaWVkX25vX3plcm8kUGVyY2VudF9BQSwgbWV0aG9kID0gInNwZWFybWFuIiwgZXhhY3QgPSBGQUxTRSkKCmBgYAoKTG9vayBhdCBxdWFydGlsZXMgd2l0aCBsb2cgYXNzZXQgZGF0YToKKnJlbWVtYmVyIHRoZSBjYXZlYXQgdGhhdCB0aGVyZSBhcmUgbWFueSBvcmdhbml6YXRpb25zIHRoYXQgYXJlIG5vdCBpbmNsdWRlZCBiZWNhdXNlIG9mIE5BIG9yIHplcm8gdmFsdWUgQVNTRVRfQU1UKgoKYGBge3J9CmRmX3NpbXBsaWZpZWRfbm9femVybyAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBBU1NFVF9BTVRfbG9nLCB4ID0gTmVpZ2hib3Job29kKSkgKwogIGdlb21fYm94cGxvdCgpKyBnZW9tX2ppdHRlcih3aWR0aCA9IC4wOCkgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZT1UUlVFLCBhZXMoZ3JvdXA9MSkpICsgZmFjZXRfd3JhcCh+QVNTRVRfcXVhcnRpbGVfdGV4dCwgc2NhbGVzID0gImZyZWVfeSIpCgpgYGAKCgoKRmlyc3QgY3JlYXRlIGRhdGEgdG8gbWFrZSB2aXN1YWxpemF0aW9uIGVhc2llcgoqY2F2ZWF0IGZvciB0aGUgZGF0YTogIHRoYXQgdGhlcmUgYXJlIG1hbnkgb3JnYW5pemF0aW9ucyB0aGF0IGFyZSBub3QgaW5jbHVkZWQgYmVjYXVzZSBvZiBOQSBvciB6ZXJvIHZhbHVlIEFTU0VUX0FNVCoKCmBgYHtyfQpxdWFydGlsZV9kYXRhIDwtZGZfc2ltcGxpZmllZF9ub196ZXJvICU+JSAKICBncm91cF9ieShBU1NFVF9xdWFydGlsZV90ZXh0LCBOZWlnaGJvcmhvb2QpICU+JSAKICBjb3VudCgpCnF1YXJ0aWxlX2RhdGEKYGBgCgpDcmVhdGUgcGVyY2VudGFnZSB2YXJpYWJsZSBmb3IgZWFjaCBxdWFudGlsZQpgYGB7cn0KcXVhcnRpbGVfZGF0YSA8LSBxdWFydGlsZV9kYXRhICU+JQogIGdyb3VwX2J5KEFTU0VUX3F1YXJ0aWxlX3RleHQpICU+JSAKICBtdXRhdGUoUGVyY2VudCAgPSByb3VuZChuL3N1bShuKSoxMDApKSAKcXVhcnRpbGVfZGF0YQpgYGAKClZpc3VhbHMuLi5vZiB0aGUgYWJvdmUgZGF0YToKCmBgYHtyfQoKcXVhcnRfcGxvdCA8LSBxdWFydGlsZV9kYXRhICU+JSAKICBnZ3Bsb3QoYWVzKHg9IEFTU0VUX3F1YXJ0aWxlX3RleHQsIHkgPSBQZXJjZW50LCAgZmlsbCA9IE5laWdoYm9yaG9vZCkpICsgCiAgICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjkpKSsKICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgcGFzdGUwKHgsICIlIikpICsKICAgICB5bGltKDAsMTAwKSArCiAgICBzY2FsZV9maWxsX2dyZXkoKSArCiAgICB0aGVtZV9saW5lZHJhdygpICsKICAgIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAoUGVyY2VudCwgIiUiKSksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuOSksIHZqdXN0ID0gLS41KSAKCgpxdWFydF9wbG90ICsgbGFicyh4ID0gIlF1YXJ0aWxlIGJhc2VkIG9uIG5vbnByb2ZpdCBhc3NldCBhbW91bnQiLCB5ID0gIlBlcmNlbnRhZ2Ugb2Ygbm9ucHJvZml0cyBpbiB0aGUgYXNzZXQgcXVhcnRpbGUiKQoKYGBgCgoqKnRoaXMgZG9lcyBOT1QgaW5jbHVkZSBhbGwgNCwwODIgb3JnYW5pemF0aW9ucyoqCgoKIyMgT3ZlcmFsbCBQZXJjZW50YWdlIFBsb3QKCkZpcnN0IGxldCdzIGdldCBhIGNvdW50IG9mIGVhY2ggLSAqKk5PVEUgd2UgYXJlIGtlZXBpbmcgemVybyB2YWx1ZXMgYW5kIE5BIGFzIGxvdyBhc3NldCoqIQpUaGUgTkEgbmVpZ2hib3Job29kIG1lYW5zIHRoZXJlIGlzIG9ubHkgb25lIG5laWdoYm9yaG9vZCB0aGF0IGRpZCBub3QgZml0IHRoZSBjYXRlZ29yaWVzIG9yIGhhdmUgaW5mb3JtYXRpb24uIFdlIGNhbiBkcm9wIHRoaXMgbmVpZ2hib3Job29kLgpgYGB7cn0KZGZfc2ltcGxpZmllZCAlPiUKICBjb3VudChBU1NFVF9IaWdoX3RleHQsIE5laWdoYm9yaG9vZCkKCmRmX3NpbXBsaWZpZWQgPC1kZl9zaW1wbGlmaWVkICU+JQogIGRyb3BfbmEoTmVpZ2hib3Job29kKQoKZGZfc2ltcGxpZmllZCAlPiUKICBjb3VudChBU1NFVF9IaWdoX3RleHQsIE5laWdoYm9yaG9vZCkKYGBgCgoKYGBge3J9CkhpZ2hfYXNzZXRfZGF0YSA8LWRmX3NpbXBsaWZpZWQgJT4lIAogIGdyb3VwX2J5KEFTU0VUX0hpZ2hfdGV4dCwgTmVpZ2hib3Job29kKSAlPiUgCiAgY291bnQoKSAKSGlnaF9hc3NldF9kYXRhCmBgYAoKQ3JlYXRlIHBlcmNlbnRhZ2UgdmFyaWFibGUgZm9yIGVhY2ggY2F0ZWdvcnk6CmBgYHtyfQpIaWdoX2Fzc2V0X2RhdGEgPC0gSGlnaF9hc3NldF9kYXRhICU+JQogIGdyb3VwX2J5KE5laWdoYm9yaG9vZCkgJT4lIAogIG11dGF0ZShQZXJjZW50X0FBX2NhdCA9IHJvdW5kKG4vc3VtKG4pKjEwMCkpIApIaWdoX2Fzc2V0X2RhdGEKYGBgCgpWaXN1YWxzLi4ub2YgdGhlIGFib3ZlIGRhdGE6CgpgYGB7cn0KCkhpZ2hfYXNzZXRfZGF0YSAlPiUgCiAgZ2dwbG90KGFlcyh4PSBOZWlnaGJvcmhvb2QsIHkgPSBQZXJjZW50X0FBX2NhdCwgIGZpbGwgPSBBU1NFVF9IaWdoX3RleHQpKSArIAogICAgZ2VvbV9jb2wocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSkrCiAgICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGZ1bmN0aW9uKHgpIHBhc3RlMCh4LCAiJSIpKSArCiAgICAgeWxpbSgwLDEwMCkgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChQZXJjZW50X0FBX2NhdCwgIiUiKSksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuOSksIHZqdXN0ID0gLS41KSArCiAgeWxhYigiUGVyY2VudCBvZiBOZWlnaGJvcmhvb2QgQ2F0ZWdvcnkiKSArCiAgdGhlbWVfbGluZWRyYXcoKSArCiAgc2NhbGVfZmlsbF9ncmV5KCkgKwogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKYGBgCioqdGhpcyBpbmNsdWRlcyBhbGwgNCwwODIgb3JnYW5pemF0aW9ucyoqCgojIyBIaWdoIHZzIG5vbiBhc3NldCBieSBjYXRlZ29yeQpGaXJzdCBjcmVhdGUgZGF0YSB0byBtYWtlIHZpc3VhbGl6YXRpb24gZWFzaWVyCgpgYGB7cn0KSGlnaF9hc3NldF9kYXRhIDwtZGZfc2ltcGxpZmllZCAlPiUKICBncm91cF9ieShBU1NFVF9IaWdoX3RleHQsIE5laWdoYm9yaG9vZCwgTlRFRV90ZXh0KSAlPiUgCiAgY291bnQoKQpIaWdoX2Fzc2V0X2RhdGEKCiNDcmVhdGUgcGVyY2VudGFnZSB2YXJpYWJsZSBmb3IgZWFjaCBjYXRlZ29yeQpIaWdoX2Fzc2V0X2RhdGEgPC0gSGlnaF9hc3NldF9kYXRhICU+JQogIGdyb3VwX2J5KE5URUVfdGV4dCkgJT4lIAogIG11dGF0ZShQZXJjZW50X250ZWVfY2F0ID0gcm91bmQobi9zdW0obikqMTAwKSkgCkhpZ2hfYXNzZXRfZGF0YQoKCmBgYAoKVmlzdWFscy4uLm9mIHRoZSBhYm92ZSBkYXRhOgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KCkhpZ2hfYXNzZXRfZGF0YSAlPiUgCiAgZ2dwbG90KGFlcyh4PSBOZWlnaGJvcmhvb2QsIHkgPSBQZXJjZW50X250ZWVfY2F0LCAgZmlsbCA9IEFTU0VUX0hpZ2hfdGV4dCkpICsgCiAgICBnZW9tX2NvbChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjkpKSsKICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gZnVuY3Rpb24oeCkgcGFzdGUwKHgsICIlIikpICsKICAgIHlsaW0oMCwgMTAwKSArCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKFBlcmNlbnRfbnRlZV9jYXQsICIlIikpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjkpLCB2anVzdCA9IC0uNSkgKyBmYWNldF93cmFwKH5OVEVFX3RleHQpICsKICB0aGVtZV9saW5lZHJhdygpICsKICBzY2FsZV9maWxsX2dyZXkoKSArCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgeWxhYigiUGVyY2VudGFnZSBmb3IgZWFjaCBjYXRlZ29yeSIpCgpgYGAKCioqdGhpcyBpbmNsdWRlcyBhbGwgNCwwODIgb3JnYW5pemF0aW9ucyoqCgojIyBDb3VudCBwbG90cy9UYWJsZXMKCiMjIyBEaWZmZXJlbnQga2luZHMgb2Ygb3JncwoKYGBge3J9CmxpYnJhcnkoZm9yY2F0cykKZGZfc2ltcGxpZmllZCAlPiUgZ3JvdXBfYnkoTlRFRV90ZXh0KSAlPiVzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JSAKICBtdXRhdGUoTlRFRV90ZXh0ID0gc3RyX3JlcGxhY2Uoc3RyaW5nID0gTlRFRV90ZXh0LCBwYXR0ZXJuID0gIk5BIiwgcmVwbGFjZW1lbnQgPSAiVW5jbGFzc2lmaWVkIikpICU+JQogbXV0YXRlKFBlcmNlbnRhZ2UgPSByb3VuZChjb3VudC9zdW0oY291bnQpKjEwMCwgZGlnaXRzID0gMikpICU+JQogIGFycmFuZ2UoTlRFRV90ZXh0KQoKVG90YWxfTlRFRSA8LWRmX3NpbXBsaWZpZWQgJT4lIGdyb3VwX2J5KE5URUVfdGV4dCkgJT4lc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUgCiAgbXV0YXRlKE5URUVfdGV4dCA9IHN0cl9yZXBsYWNlKHN0cmluZyA9IE5URUVfdGV4dCwgcGF0dGVybiA9ICJOQSIsIHJlcGxhY2VtZW50ID0gIlVuY2xhc3NpZmllZCIpKSAlPiUKICBhcnJhbmdlKE5URUVfdGV4dCkKYGBgCgoKYGBge3J9CmRmX3NpbXBsaWZpZWQgJT4lIAogIGdyb3VwX2J5KE5URUVfdGV4dCwgTmVpZ2hib3Job29kKSAlPiUKICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JSAKICBtdXRhdGUoTlRFRV90ZXh0ID0gYXNfZmFjdG9yKE5URUVfdGV4dCkpICU+JQogIGdncGxvdChhZXMoeCA9IGZjdF9yZW9yZGVyKE5URUVfdGV4dCwgY291bnQsIG1pbiksIHkgPSBjb3VudCAsIGZpbGwgPSBOZWlnaGJvcmhvb2QpKSArIAogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCkgKwogIGdlb21fY29sKHBvc2l0aW9uID1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC45KSkgICsgCiAgeWxhYiAoIk51bWJlciBvZiBPcmdhbml6YXRpb25zIikgKwogIHRoZW1lX2xpbmVkcmF3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNjAsIHZqdXN0ID0gLjUpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2ZpbGxfZ3JleSgpCgoKIApgYGAKCgoqKlRoaXMgaW5jbHVkZXMgYWxsIDQsMDgyIG9yZ2FuaXphdGlvbnMqKiBUaGVyZSB3YXMgbm8gcmVtb3ZhbCBvZiBvcmdhbml6YXRpb25zIGJhc2VkIG9uIGFzc2V0IGFtb3VudCwganVzdCB0byBnZXQgYSBzZW5zZSBvZiB3aGF0IG9nYW5pemF0aW9ucyBhcmUgaW4gQmFsdGltb3JlLgoKCgpgYGB7cn0KCnBsb3QyIDwtIGRmX3NpbXBsaWZpZWQgJT4lIAogICAgbXV0YXRlKE5URUVfdGV4dCA9IGFzX2ZhY3RvcihOVEVFX3RleHQpLAogICAgICAgICBOVEVFX3RleHQgPSBmb3JjYXRzOjpmY3RfcmVsZXZlbChOVEVFX3RleHQsICJJbnRlcm5hdGlvbmFsIEFmZmFpcnMiLCAiRW52aXJvbm1lbnQvQW5pbWFscyIsICJBcnRzIiwgIlJlbGlnaW91cyIsICJIZWFsdGgiLCJFZHVjYXRpb24iLCAiU29jaWV0YWwgQmVuZWZpdCIsICJIdW1hbiBTZXJ2aWNlcyIsICJOQSIgKSkgJT4lCiAgZ3JvdXBfYnkoTlRFRV90ZXh0LCBOZWlnaGJvcmhvb2QsIEFTU0VUX0hpZ2hfdGV4dCkgJT4lCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gTlRFRV90ZXh0LCB5ID0gY291bnQgLCBmaWxsID0gTmVpZ2hib3Job29kKSkgKyAKICBnZW9tX2NvbChwb3NpdGlvbiA9cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuOSkpICArIAogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMoQVNTRVRfSGlnaF90ZXh0KSkgKwogIHlsYWIgKCJOdW1iZXIgb2YgT3JnYW5pemF0aW9ucyIpICsKICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDYwLCB2anVzdCA9IC41KSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCkpICsKICBzY2FsZV9maWxsX2dyZXkoKQogIApwbG90MgoKYGBgCgoKKipUaGlzIGluY2x1ZGVzIGFsbCA0LDA4MiBvcmdhbml6YXRpb25zKiogVGhlcmUgd2FzIG5vIHJlbW92YWwgb2Ygb3JnYW5pemF0aW9ucyBiYXNlZCBvbiBhc3NldCBhbW91bnQsIGp1c3QgdG8gZ2V0IGEgc2Vuc2Ugb2Ygd2hhdCBvZ2FuaXphdGlvbnMgYXJlIGluIEJhbHRpbW9yZS4KCgojIyMgSGlnaCBBc3NldCBPcmdzCgpgYGB7cn0KSGlnaF9jb3VudHMgPC0gZGZfc2ltcGxpZmllZCAlPiUgCiAgICBtdXRhdGUoTlRFRV90ZXh0ID0gYXNfZmFjdG9yKE5URUVfdGV4dCksCiAgICAgICAgTlRFRV90ZXh0ID0gZm9yY2F0czo6ZmN0X3JlbGV2ZWwoTlRFRV90ZXh0LCAiSW50ZXJuYXRpb25hbCBBZmZhaXJzIiwgIkVudmlyb25tZW50L0FuaW1hbHMiLCAiQXJ0cyIsICJSZWxpZ2lvdXMiLCAiSGVhbHRoIiwiRWR1Y2F0aW9uIiwgIlNvY2lldGFsIEJlbmVmaXQiLCAiSHVtYW4gU2VydmljZXMiLCAiTkEiICkpICU+JQogIGdyb3VwX2J5KE5URUVfdGV4dCwgQVNTRVRfSGlnaF90ZXh0KSAlPiUKICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JSBmaWx0ZXIoQVNTRVRfSGlnaF90ZXh0ID09ICJIaWdoIEFzc2V0IikgJT4lCiAgICBtdXRhdGUoTlRFRV90ZXh0ID0gc3RyX3JlcGxhY2Uoc3RyaW5nID0gTlRFRV90ZXh0LCBwYXR0ZXJuID0gIk5BIiwgcmVwbGFjZW1lbnQgPSAiVW5jbGFzc2lmaWVkIikpCgogIApmdWxsX2pvaW4oVG90YWxfTlRFRSwgSGlnaF9jb3VudHMsIGJ5ID0gIk5URUVfdGV4dCIpICU+JQogICBtdXRhdGUoIlBlcmNlbnRhZ2Vfb2ZfZWFjaF9jb2RlIiA9IHJvdW5kKGNvdW50LnkvY291bnQueCAqMTAwLCBkaWdpdHMgPSAyKSkgJT4lCiAgYXJyYW5nZShOVEVFX3RleHQpIApgYGAKCgoKIyMgRGlzdHJpYnV0aW9uIG9mIHBlcmNlbnQgQUEgCgpOb3cgdG8gdGFrZSBhIGxvb2sgYXQgaWYgNTAlIEFmcmljYW4gQW1lcmljYW4gbWFrZXMgc2Vuc2UuIFdoYXQgZG8gdGhlIG5laWdoYm9yaG9vZHMgbG9vayBsaWtlPwoKYGBge3J9CgojIGdldCB0aGUgbmVpZ2hib3Job29kIHZhbHVlcyBpZiBubyByZW1vdmluZyByb3dzIGZvciBub25wcm9maXRzIHdpdGggTkEgb3IgemVybyBhc3NldHMKbmVpZ2hib3Job29kX0FBcGVyYyA8LSBkZl9zaW1wbGlmaWVkICU+JSAKIGRpc3RpbmN0KGBuZWlnaGJvcmhvb2QgbmFtZWAsIFBlcmNlbnRfQUEpCgojIGdldCB0aGUgbmVpZ2hib3Job29kIHZhbHVlcyBhZnRlciByZW1vdmluZyByb3dzIGZvciBub25wcm9maXRzIHdpdGggTkEgb3IgemVybyBhc3NldHMKbmVpZ2hib3Job29kX0FBcGVyY19ub3plcm8gPC0gZGZfc2ltcGxpZmllZF9ub196ZXJvICU+JSAKIGRpc3RpbmN0KGBuZWlnaGJvcmhvb2QgbmFtZWAsIFBlcmNlbnRfQUEpCmBgYAoKCldlIGNhbiBzZWUgdGhhdCB0aGVyZSBhcmUgbWFueSBuZWlnaGJvcmhvb2RzIHRoYXQgaGF2ZSBhIG1vcmUgZXh0cmVtZSBwZXJjZW50YWdlLgoKYGBge3J9CgojIGdldCB0aGUgbmVpZ2hib3Job29kIHZhbHVlcyBpZiBubyByZW1vdmluZyByb3dzIGZvciBub25wcm9maXRzIHdpdGggTkEgb3IgemVybyBhc3NldHMKCm5laWdoYm9yaG9vZF9BQXBlcmMlPiUgcHVsbChQZXJjZW50X0FBKSAlPiUgaGlzdChtYWluID0gIkFmcmljYW4gQW1lcmljYW4gUGVyY2VudGFnZSBvZiBOZWlnaGJvcmhvb2RzIGZvciBlYWNoIG5vbnByb2ZpdCIpCgojIGdldCB0aGUgbmVpZ2hib3Job29kIHZhbHVlcyBhZnRlciByZW1vdmluZyByb3dzIGZvciBub25wcm9maXRzIHdpdGggTkEgb3IgemVybyBhc3NldHMKbmVpZ2hib3Job29kX0FBcGVyY19ub3plcm8gJT4lIHB1bGwoUGVyY2VudF9BQSkgJT4lIGhpc3QobWFpbiA9ICJBZnJpY2FuIEFtZXJpY2FuIFBlcmNlbnRhZ2Ugb2YgTmVpZ2hib3Job29kcyBcbiAocmVtb3ZlZCBuZWlnaGJvcmhvb2RzIHdpdGggb25seSB6ZXJvIG9yIE5BIGFzc2V0cykiKQoKYGBgCgoK