Author

Source and descriptions of datasets

Ontario Community Health Profiles Partnership (OCHPP)
http://www.ontariohealthprofiles.ca/

Data — LHIN 7 (Toronto Central and City of Toronto) Neighbourhoods, Ontario Sub-Regions and LHINs

We use three datasets:

We quote from the description of the data:

The Registered Persons Database (RPDB) as the source of population
http://www.ontariohealthprofiles.ca/o_documents/aboutTheDataON/RPDB_vs_Census_Oct_26_2018.pdf

Two main population sources

There are two main sources that provide the most reliable estimates of Ontario’s population. For purposes of OCHPP reporting, we use the Registered Persons Database (RPDB) as the source (denominator) for all of our health-related indicators. While another major source for identifying the population (denominator) is Statistics Canada’s Census counts (Census), the OCHPP has determined that the RPDB provides a more consistent measure for the calculation of rates for health indicators and conditions. We explain why and provide examples to illustrate.

RPDB

The RPDB (database) provides basic demographic information about anyone who has ever received an Ontario Health Insurance Plan (OHIP) card. OHIP cards include a unique Health Card Number (HCN) to identify a person’s age, sex and address, including postal code. The postal codes used at ICES come mainly from HCNs. Information from the health card is stored in the RPDB. Health cards are usually renewed every 5 years, a process that helps to ensure that information in the system is periodically refreshed, such as address, for example, should a person move and update the card within that time frame. The system may also be updated more frequently if an individual interacts with the healthcare system between renewal periods. This allows for a more current source of location-based data for health reporting.

Census

Another source of data on where people live can come from Statistics Canada (Stats Can). Stats Can collects data on individuals living in Canada through the Census, a survey conducted every 5 years. Stats Can reports who lives in a given area at one point in time – i.e. based on the information an individual provides when completing the Census

RPDB vs. Census

While at the provincial level, the number of people we identify in the RPDB as living in Ontario does not differ much from Census estimates, differences are more pronounced at smaller areas such as neighbourhoods or local areas. This particular issue is most evident in areas of high migration where we have observed large differences in rates using RPDB vs. the Census in part due to population mobility.
For example, in some areas of Ontario, particularly in larger urban centres, newcomers to the area often settle first “downtown” but over time, may move from downtown to outlying areas. The majority of people who move do not change or update their health card until renewal time so they stay in the RPDB with their original health card information including the address and postal code of their “downtown” address.
The same is true of Census population counts: when someone moves, they are still considered living at their original address and comprise the population of that area until the next Census is taken (every 5 years).

Shapefile for City of Toronto’s 140 neighbourhoods

We now import and process a shapefile for Toronto’s 140 neighbourhoods.

https://www.toronto.ca/city-government/data-research-maps/open-data/open-data-catalogue/#a45bd45a-ede8-730e-1abc-93105b2c439f

http://opendata.toronto.ca/gcc/neighbourhoods_planning_areas_wgs84.zip

Neighbourhoods

Owner: Social Development, Finance & Administration

Currency: June 2014

Neighbourhoods (WGS84)

library(data.table) #fread
library(plyr) #join
library(ggplot2) #ggplot, fortify
library(sp) #used by rgdal
library(rgdal) #readOGR
library(rgeos) #gCentroid
library(scales) #scale_fill_distiller, percent_format
library(ggmap) #theme_nothing
library(Hmisc) #rcorr

Input shapefile

nbds.sh <- readOGR("C:/Users/14165/Desktop/ArcGIS/SHAPEFILES/neighbourhoods_planning_areas_wgs84", "NEIGHBORHOODS_WGS84")
OGR data source with driver: ESRI Shapefile 
Source: "C:\Users\14165\Desktop\ArcGIS\SHAPEFILES\neighbourhoods_planning_areas_wgs84", layer: "NEIGHBORHOODS_WGS84"
with 140 features
It has 2 fields

Add “id” column

nbds.sh@data$id <- as.integer(nbds.sh@data$AREA_S_CD)

Make centroids of each neighbourhood, for placing labels when plotting

nbds.sh.centroids  <- as.data.frame(gCentroid(nbds.sh, byid = TRUE))

Add “id” column

nbds.sh.centroids$id <- nbds.sh@data$id

Shapefile processing

nbds.sh.points = fortify(nbds.sh, region = "id")

nbds.sh.df = join(nbds.sh.points, nbds.sh@data, by = "id")

We are now done with shapefile processing.

We copied selected columns from sheets of the .xls/.xlsx files to new sheets, renamed columns by changing spaces and hyphens to underscores and spelling symbols, and exported these to .csv files.

We shall visualize selected data from these tables on a map. Then we compute correlations.

Primary Care: Enrolment and Continuity of Care 2011/13

1_pc_Continuity_NonRostered_Rostered_Patients_neighb_2013_LHIN_7.xlsx!Continuity_Enrolled_NonEnrolled:

Primary Care: Enrolment and Continuity of Care (Both sexes, Ages 19+) for Toronto Neighbourhoods and Toronto Central LHIN, 2011/12 to 2012/13 (April 1, 2011-March 31, 2013)

Data sources: Population - Ontario Heath Insurance Plan (OHIP) physician claims, Client Agency Provider Enrolment (CAPE) tables, Registered Persons’ Database, Community Health Centre client encounter data.

Population Enrolled: rostered with a Patient Enrolment Model (PEM) or registered with a Community Health Centre (CHC).

Population Non-Enrolled: not rostered with a Patient Enrolment Model (PEM) or registered with a Community Health Centre (CHC).

“id”, “Population_19_plus”, “Enrolled_Population”, “Enrolled_Population_with_No_Visits”, “Enrolled_Population_with_1_or_2_Visits”, “Enrolled_Population_with_3_plus_Visits”, “Non_Enrolled_Population”, “Non_Enrolled_Population_with_No_Visits”, “Non_Enrolled_Population_with_1_or_2_Visits”, “Non_Enrolled_Population_with_3_plus_Visits”, “Total_Population_Enrolled_and_Non_Enrolled”, “Total_Population_with_No_Visits”, “Total_Population_with_1_or_2_Visits”, “Total_Population_with_3_plus_Visits”

1_pc_Continuity_NonRostered_Rostered_Patients_neighb_2013_LHIN_7.csv

patients <- fread("1_pc_Continuity_NonRostered_Rostered_Patients_neighb_2013_LHIN_7.csv")
str(patients)
Classes ‘data.table’ and 'data.frame':  140 obs. of  14 variables:
 $ id                                        : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Population_19_plus                        : int  27552 25140 8548 8497 7834 17733 16996 9076 12298 8922 ...
 $ Enrolled_Population                       : int  20095 17636 5982 6593 5748 13110 13037 6728 8856 6695 ...
 $ Enrolled_Population_with_No_Visits        : int  1030 775 285 356 290 640 655 364 530 405 ...
 $ Enrolled_Population_with_1_or_2_Visits    : int  2145 1723 697 855 735 1492 1632 864 1346 1047 ...
 $ Enrolled_Population_with_3_plus_Visits    : int  16920 15138 5000 5382 4723 10978 10750 5500 6980 5243 ...
 $ Non_Enrolled_Population                   : int  7457 7504 2566 1904 2086 4623 3959 2348 3442 2227 ...
 $ Non_Enrolled_Population_with_No_Visits    : int  1258 1232 411 405 365 900 771 430 652 434 ...
 $ Non_Enrolled_Population_with_1_or_2_Visits: int  1509 1483 485 411 411 1005 862 515 772 552 ...
 $ Non_Enrolled_Population_with_3_plus_Visits: int  4690 4789 1670 1088 1310 2718 2326 1403 2018 1241 ...
 $ Total_Population_Enrolled_and_Non_Enrolled: int  27552 25140 8548 8497 7834 17733 16996 9076 12298 8922 ...
 $ Total_Population_with_No_Visits           : int  2288 2007 696 761 655 1540 1426 794 1182 839 ...
 $ Total_Population_with_1_or_2_Visits       : int  3654 3206 1182 1266 1146 2497 2494 1379 2118 1599 ...
 $ Total_Population_with_3_plus_Visits       : int  21610 19927 6670 6470 6033 13696 13076 6903 8998 6484 ...
 - attr(*, ".internal.selfref")=<externalptr> 

Create ratio columns for selected variables

patients$Ratio_Non_Enrolled_Population <- patients$Non_Enrolled_Population/patients$Population_19_plus

patients$Ratio_Total_Population_with_No_Visits <- patients$Total_Population_with_No_Visits/patients$Population_19_plus

patients$Ratio_Total_Population_with_3_plus_Visits <- patients$Total_Population_with_3_plus_Visits/patients$Population_19_plus

patients_ratios <- patients[,.(id,Ratio_Non_Enrolled_Population,Ratio_Total_Population_with_No_Visits,Ratio_Total_Population_with_3_plus_Visits)]

Ratio_Non_Enrolled_Population

Ratio_Non_Enrolled_Population <- patients_ratios[, .(id,Ratio_Non_Enrolled_Population)]

Ratio_Non_Enrolled_Population.sh <- merge(nbds.sh.df, Ratio_Non_Enrolled_Population, by = "id")

Make graphics object

p.Ratio_Non_Enrolled_Population <- ggplot() +
  geom_polygon(data = Ratio_Non_Enrolled_Population.sh, 
               aes(x = long, y = lat, group = group, fill = Ratio_Non_Enrolled_Population), 
               color = "black", size = 0.2) + 
  coord_map() + 
  scale_fill_distiller(name="Ratio", labels=percent_format(accuracy=1), palette = "PuRd", trans = "reverse", breaks = pretty_breaks(n = 8))+
  theme_nothing(legend = TRUE) + 
  labs(title="Ratio of total population non-enrolled") +
  geom_text(aes(x=x,y=y, group=NULL, label=id), data = nbds.sh.centroids, size = 2)

Plot graphics object

p.Ratio_Non_Enrolled_Population + guides(fill = guide_legend(reverse=TRUE))

Ratio_Total_Population_with_No_Visits

Ratio_Total_Population_with_No_Visits <- patients_ratios[, .(id,Ratio_Total_Population_with_No_Visits)]

Ratio_Total_Population_with_No_Visits.sh <- merge(nbds.sh.df, Ratio_Total_Population_with_No_Visits, by = "id")

Make graphics object

p.Ratio_Total_Population_with_No_Visits <- ggplot() +
  geom_polygon(data = Ratio_Total_Population_with_No_Visits.sh, 
               aes(x = long, y = lat, group = group, fill = Ratio_Total_Population_with_No_Visits), 
               color = "black", size = 0.2) + 
  coord_map() + 
  scale_fill_distiller(name="Ratio", labels=percent_format(accuracy=1), palette = "PuRd", trans = "reverse", breaks = pretty_breaks(n = 8)) + 
  theme_nothing(legend = TRUE) + 
  labs(title="Ratio of total population with no visits") +
  geom_text(aes(x=x,y=y, group=NULL, label=id), data = nbds.sh.centroids, size = 2)

Plot graphics object

p.Ratio_Total_Population_with_No_Visits + guides(fill = guide_legend(reverse=TRUE))

Ratio_Total_Population_with_3_plus_Visits

Ratio_Total_Population_with_3_plus_Visits <- patients_ratios[, .(id,Ratio_Total_Population_with_3_plus_Visits)]

Ratio_Total_Population_with_3_plus_Visits.sh <- merge(nbds.sh.df, Ratio_Total_Population_with_3_plus_Visits, by = "id")

Make graphics object

p.Ratio_Total_Population_with_3_plus_Visits <- ggplot() +
  geom_polygon(data = Ratio_Total_Population_with_3_plus_Visits.sh, 
               aes(x = long, y = lat, group = group, fill = Ratio_Total_Population_with_3_plus_Visits), 
               color = "black", size = 0.2) + 
  coord_map() + 
  scale_fill_distiller(name="Ratio", labels=percent_format(accuracy=1), palette = "Greens", trans = "reverse", breaks = pretty_breaks(n = 8))+
  theme_nothing(legend = TRUE) + 
  labs(title="Ratio of total population with 3+ visits") +
  geom_text(aes(x=x,y=y, group=NULL, label=id), data = nbds.sh.centroids, size = 2)

Plot graphics object

p.Ratio_Total_Population_with_3_plus_Visits + guides(fill = guide_legend(reverse=TRUE))

Adult Health and Disease 2016/17

1_AHD_2017_RPDB_Neighb_LHIN_7.xlsx!Diabetes_Neighb_Toronto:

Demographics - Denominator: Ontario Ministry of Health and Long-Term Care Registered Persons Database (RPDB), population aged 20+ who were alive and living in the Ontario on April 1st, 2016

Numerator: derived from validated, disease registries maintained by the Institute for Clinical Evaluative Sciences (ICES)

1_AHD_2017_RPDB_Neighb_LHIN_7.xlsx!COPD_Neighb_Toronto:

Demographics - Denominator: Ontario Ministry of Health and Long-Term Care Registered Persons Database (RPDB), population aged 35+ who were alive and living in the Ontario on April 1st, 2016

Numerator: derived from validated, disease registries maintained by the Institute for Clinical Evaluative Sciences (ICES)

“id”, “People_with_Diabetes_20_plus”, “Total_Population_2016_RPDB_20_plus”, “Prevalence_per_hundred_Diabetes_20_plus”, “People_with_COPD_35_plus”, “Total_Population_2016_RPDB_35_plus”, “Prevalence_per_hundred_COPD_35_plus”

1_AHD_2017_RPDB_Neighb_LHIN_7.csv

chronic <- fread("1_AHD_2017_RPDB_Neighb_LHIN_7.csv")

chronic$Ratio_People_with_Diabetes_20_plus <- chronic$People_with_Diabetes_20_plus/chronic$Total_Population_2016_RPDB_20_plus

chronic$Ratio_People_with_COPD_35_plus <- chronic$People_with_COPD_35_plus/chronic$Total_Population_2016_RPDB_35_plus

chronic_ratios <- chronic[,.(id,Ratio_People_with_Diabetes_20_plus,Ratio_People_with_COPD_35_plus)]
Ratio_People_with_Diabetes_20_plus <- chronic_ratios[, .(id,Ratio_People_with_Diabetes_20_plus)]

Ratio_People_with_Diabetes_20_plus.sh <- merge(nbds.sh.df, Ratio_People_with_Diabetes_20_plus, by = "id")

Make and plot graphics object

p.Ratio_People_with_Diabetes_20_plus <- ggplot() +
  geom_polygon(data = Ratio_People_with_Diabetes_20_plus.sh, 
               aes(x = long, y = lat, group = group, fill = Ratio_People_with_Diabetes_20_plus), 
               color = "black", size = 0.2) + 
  coord_map() + 
  scale_fill_distiller(name="Ratio", labels=percent_format(accuracy=1), palette = "PuRd", trans = "reverse",
                       breaks = pretty_breaks(n = 8)) + 
  theme_nothing(legend = TRUE)+
  labs(title="Ratio of people with diabetes, 20+") +
  geom_text(aes(x=x,y=y, group=NULL, label=id), data = nbds.sh.centroids, size = 2)

p.Ratio_People_with_Diabetes_20_plus + guides(fill = guide_legend(reverse=TRUE))

Ratio_People_with_COPD_35_plus <- chronic_ratios[, .(id,Ratio_People_with_COPD_35_plus)]

Ratio_People_with_COPD_35_plus.sh <- merge(nbds.sh.df, Ratio_People_with_COPD_35_plus, by = "id")

Make and plot graphics object

p.Ratio_People_with_COPD_35_plus <- ggplot() +
  geom_polygon(data = Ratio_People_with_COPD_35_plus.sh, 
               aes(x = long, y = lat, group = group, fill = Ratio_People_with_COPD_35_plus), 
               color = "black", size = 0.2) + 
  coord_map() + 
  scale_fill_distiller(name="Ratio", labels=percent_format(accuracy=1), palette = "PuRd", trans = "reverse",
                       breaks = pretty_breaks(n = 8))+
  theme_nothing(legend = TRUE) + 
  labs(title="Ratio of people with COPD, 35+") +
  geom_text(aes(x=x,y=y, group=NULL, label=id), data = nbds.sh.centroids, size = 2)

p.Ratio_People_with_COPD_35_plus + guides(fill = guide_legend(reverse=TRUE))

Sexual Health: Chlamydia cases, Gonorrhea cases 2013/16

2_sh_neighb_chlam_gonor_2013-2016_LHIN_7.xlsx!Chlamydia_Male_Female_Tor_neigh:

Number of Chlamydia Cases for Age 15 years and over by Gender (Male, Female), Toronto Neighbourhoods, 2013 to 2016 Calendar Years Combined

Demographics - Denominator: Based on 2011 Census population estimates. (Statistics Canada, 2011 Census of Population).

Numerator: Number of Chlamydia cases for 4 year (2013 to 2016) observation period. Data source: Data as of July 20, 2017, Toronto Public Health integrated Public Health Information System [iPHIS].

  • Average annual rate of Chlamydia cases (/100,000) Males (2013 to 2016), All Ages 15+

  • Average annual rate of Chlamydia cases (/100,000) Females (2013 to 2016), All Ages 15+

“id”, “Chlamydia_cases_male”, “Population_male”, “Chlamydia_cases_female”, “Population_female”

2_sh_neighb_chlam_gonor_2013-2016_LHIN_7.csv

chlamydia <- fread("2_sh_neighb_chlam_gonor_2013-2016_LHIN_7.csv")

chlamydia$Ratio_Chlamydia_cases_male <- chlamydia$Chlamydia_cases_male/chlamydia$Population_male

chlamydia$Ratio_Chlamydia_cases_female <- chlamydia$Chlamydia_cases_female/chlamydia$Population_female

chlamydia_ratios <- chlamydia[,.(id,Ratio_Chlamydia_cases_male,Ratio_Chlamydia_cases_female)]
Ratio_Chlamydia_cases_male <- chlamydia_ratios[, .(id,Ratio_Chlamydia_cases_male)]

Ratio_Chlamydia_cases_male.sh <- merge(nbds.sh.df, Ratio_Chlamydia_cases_male, by = "id")

Make and plot graphics object

p.Ratio_Chlamydia_cases_male <- ggplot() +
  geom_polygon(data = Ratio_Chlamydia_cases_male.sh, 
               aes(x = long, y = lat, group = group, fill = Ratio_Chlamydia_cases_male), 
               color = "black", size = 0.2) + 
  coord_map() + 
  scale_fill_distiller(name="Cases/population", labels=percent_format(accuracy=1), palette = "YlOrBr", trans = "reverse", breaks = pretty_breaks(n = 8)) + 
  theme_nothing(legend = TRUE) + 
  labs(title="Number of male chlamydia cases/male population") +
  geom_text(aes(x=x,y=y, group=NULL, label=id), data = nbds.sh.centroids, size = 2)

p.Ratio_Chlamydia_cases_male + guides(fill = guide_legend(reverse=TRUE))

Correlations

OCHPP_ratios <- merge(merge(patients_ratios, chronic_ratios), chlamydia_ratios)

Structure of data table:

str(OCHPP_ratios)
Classes ‘data.table’ and 'data.frame':  140 obs. of  8 variables:
 $ id                                       : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Ratio_Non_Enrolled_Population            : num  0.271 0.298 0.3 0.224 0.266 ...
 $ Ratio_Total_Population_with_No_Visits    : num  0.083 0.0798 0.0814 0.0896 0.0836 ...
 $ Ratio_Total_Population_with_3_plus_Visits: num  0.784 0.793 0.78 0.761 0.77 ...
 $ Ratio_People_with_Diabetes_20_plus       : num  0.182 0.184 0.177 0.175 0.17 ...
 $ Ratio_People_with_COPD_35_plus           : num  0.0684 0.0658 0.0926 0.1047 0.097 ...
 $ Ratio_Chlamydia_cases_male               : num  0.0199 0.0199 0.0125 0.0114 0.0181 ...
 $ Ratio_Chlamydia_cases_female             : num  0.0232 0.0277 0.023 0.0263 0.0289 ...
 - attr(*, ".internal.selfref")=<externalptr> 
 - attr(*, "sorted")= chr "id"

Drop “id” column

OCHPP_ratios_noid <- OCHPP_ratios[,-c("id")]

str(OCHPP_ratios_noid)
Classes ‘data.table’ and 'data.frame':  140 obs. of  7 variables:
 $ Ratio_Non_Enrolled_Population            : num  0.271 0.298 0.3 0.224 0.266 ...
 $ Ratio_Total_Population_with_No_Visits    : num  0.083 0.0798 0.0814 0.0896 0.0836 ...
 $ Ratio_Total_Population_with_3_plus_Visits: num  0.784 0.793 0.78 0.761 0.77 ...
 $ Ratio_People_with_Diabetes_20_plus       : num  0.182 0.184 0.177 0.175 0.17 ...
 $ Ratio_People_with_COPD_35_plus           : num  0.0684 0.0658 0.0926 0.1047 0.097 ...
 $ Ratio_Chlamydia_cases_male               : num  0.0199 0.0199 0.0125 0.0114 0.0181 ...
 $ Ratio_Chlamydia_cases_female             : num  0.0232 0.0277 0.023 0.0263 0.0289 ...
 - attr(*, ".internal.selfref")=<externalptr> 

Compute correlations

rcorr(as.matrix(OCHPP_ratios_noid), type="pearson")
                                          Ratio_Non_Enrolled_Population
Ratio_Non_Enrolled_Population                                      1.00
Ratio_Total_Population_with_No_Visits                              0.45
Ratio_Total_Population_with_3_plus_Visits                         -0.32
Ratio_People_with_Diabetes_20_plus                                -0.12
Ratio_People_with_COPD_35_plus                                     0.14
Ratio_Chlamydia_cases_male                                         0.53
Ratio_Chlamydia_cases_female                                       0.51
                                          Ratio_Total_Population_with_No_Visits
Ratio_Non_Enrolled_Population                                              0.45
Ratio_Total_Population_with_No_Visits                                      1.00
Ratio_Total_Population_with_3_plus_Visits                                 -0.94
Ratio_People_with_Diabetes_20_plus                                        -0.77
Ratio_People_with_COPD_35_plus                                            -0.27
Ratio_Chlamydia_cases_male                                                 0.39
Ratio_Chlamydia_cases_female                                               0.08
                                          Ratio_Total_Population_with_3_plus_Visits
Ratio_Non_Enrolled_Population                                                 -0.32
Ratio_Total_Population_with_No_Visits                                         -0.94
Ratio_Total_Population_with_3_plus_Visits                                      1.00
Ratio_People_with_Diabetes_20_plus                                             0.91
Ratio_People_with_COPD_35_plus                                                 0.34
Ratio_Chlamydia_cases_male                                                    -0.23
Ratio_Chlamydia_cases_female                                                   0.10
                                          Ratio_People_with_Diabetes_20_plus
Ratio_Non_Enrolled_Population                                          -0.12
Ratio_Total_Population_with_No_Visits                                  -0.77
Ratio_Total_Population_with_3_plus_Visits                               0.91
Ratio_People_with_Diabetes_20_plus                                      1.00
Ratio_People_with_COPD_35_plus                                          0.38
Ratio_Chlamydia_cases_male                                             -0.05
Ratio_Chlamydia_cases_female                                            0.31
                                          Ratio_People_with_COPD_35_plus Ratio_Chlamydia_cases_male
Ratio_Non_Enrolled_Population                                       0.14                       0.53
Ratio_Total_Population_with_No_Visits                              -0.27                       0.39
Ratio_Total_Population_with_3_plus_Visits                           0.34                      -0.23
Ratio_People_with_Diabetes_20_plus                                  0.38                      -0.05
Ratio_People_with_COPD_35_plus                                      1.00                       0.13
Ratio_Chlamydia_cases_male                                          0.13                       1.00
Ratio_Chlamydia_cases_female                                        0.23                       0.75
                                          Ratio_Chlamydia_cases_female
Ratio_Non_Enrolled_Population                                     0.51
Ratio_Total_Population_with_No_Visits                             0.08
Ratio_Total_Population_with_3_plus_Visits                         0.10
Ratio_People_with_Diabetes_20_plus                                0.31
Ratio_People_with_COPD_35_plus                                    0.23
Ratio_Chlamydia_cases_male                                        0.75
Ratio_Chlamydia_cases_female                                      1.00

n= 140 


P
                                          Ratio_Non_Enrolled_Population
Ratio_Non_Enrolled_Population                                          
Ratio_Total_Population_with_No_Visits     0.0000                       
Ratio_Total_Population_with_3_plus_Visits 0.0001                       
Ratio_People_with_Diabetes_20_plus        0.1670                       
Ratio_People_with_COPD_35_plus            0.0889                       
Ratio_Chlamydia_cases_male                0.0000                       
Ratio_Chlamydia_cases_female              0.0000                       
                                          Ratio_Total_Population_with_No_Visits
Ratio_Non_Enrolled_Population             0.0000                               
Ratio_Total_Population_with_No_Visits                                          
Ratio_Total_Population_with_3_plus_Visits 0.0000                               
Ratio_People_with_Diabetes_20_plus        0.0000                               
Ratio_People_with_COPD_35_plus            0.0014                               
Ratio_Chlamydia_cases_male                0.0000                               
Ratio_Chlamydia_cases_female              0.3191                               
                                          Ratio_Total_Population_with_3_plus_Visits
Ratio_Non_Enrolled_Population             0.0001                                   
Ratio_Total_Population_with_No_Visits     0.0000                                   
Ratio_Total_Population_with_3_plus_Visits                                          
Ratio_People_with_Diabetes_20_plus        0.0000                                   
Ratio_People_with_COPD_35_plus            0.0000                                   
Ratio_Chlamydia_cases_male                0.0054                                   
Ratio_Chlamydia_cases_female              0.2544                                   
                                          Ratio_People_with_Diabetes_20_plus
Ratio_Non_Enrolled_Population             0.1670                            
Ratio_Total_Population_with_No_Visits     0.0000                            
Ratio_Total_Population_with_3_plus_Visits 0.0000                            
Ratio_People_with_Diabetes_20_plus                                          
Ratio_People_with_COPD_35_plus            0.0000                            
Ratio_Chlamydia_cases_male                0.5450                            
Ratio_Chlamydia_cases_female              0.0002                            
                                          Ratio_People_with_COPD_35_plus Ratio_Chlamydia_cases_male
Ratio_Non_Enrolled_Population             0.0889                         0.0000                    
Ratio_Total_Population_with_No_Visits     0.0014                         0.0000                    
Ratio_Total_Population_with_3_plus_Visits 0.0000                         0.0054                    
Ratio_People_with_Diabetes_20_plus        0.0000                         0.5450                    
Ratio_People_with_COPD_35_plus                                           0.1224                    
Ratio_Chlamydia_cases_male                0.1224                                                   
Ratio_Chlamydia_cases_female              0.0054                         0.0000                    
                                          Ratio_Chlamydia_cases_female
Ratio_Non_Enrolled_Population             0.0000                      
Ratio_Total_Population_with_No_Visits     0.3191                      
Ratio_Total_Population_with_3_plus_Visits 0.2544                      
Ratio_People_with_Diabetes_20_plus        0.0002                      
Ratio_People_with_COPD_35_plus            0.0054                      
Ratio_Chlamydia_cases_male                0.0000                      
Ratio_Chlamydia_cases_female                                          

Linear regression

lm_chlam <- lm(Ratio_Chlamydia_cases_male ~ Ratio_Chlamydia_cases_female, data = OCHPP_ratios_noid)
summary(lm_chlam)

Call:
lm(formula = Ratio_Chlamydia_cases_male ~ Ratio_Chlamydia_cases_female, 
    data = OCHPP_ratios_noid)

Residuals:
       Min         1Q     Median         3Q        Max 
-0.0095561 -0.0027092 -0.0006196  0.0014847  0.0314658 

Coefficients:
                               Estimate Std. Error t value Pr(>|t|)    
(Intercept)                  -0.0003589  0.0012921  -0.278    0.782    
Ratio_Chlamydia_cases_female  0.8114156  0.0611285  13.274   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.005647 on 138 degrees of freedom
Multiple R-squared:  0.5608,    Adjusted R-squared:  0.5576 
F-statistic: 176.2 on 1 and 138 DF,  p-value: < 2.2e-16
plot(lm_chlam)

Choropleth of residuals

str(lm_chlam$residuals)
 Named num [1:140] 0.00145 -0.00222 -0.00587 -0.00956 -0.005 ...
 - attr(*, "names")= chr [1:140] "1" "2" "3" "4" ...

Make dataframe of residuals with “id” column

lm_chlam_df <- data.frame(id = c(1:140), residual = lm_chlam$residuals)
head(lm_chlam_df)
lm_chlam_df.sh <- merge(nbds.sh.df, lm_chlam_df, by = "id")

Make and plot graphics object

p.lm_chlam_df <- ggplot() +
  geom_polygon(data = lm_chlam_df.sh, 
               aes(x = long, y = lat, group = group, fill = residual), 
               color = "black", size = 0.2) + 
  coord_map() + 
  scale_fill_distiller(name="Residuals", palette = "Blues", trans = "reverse", breaks = pretty_breaks(n = 8)) + 
  theme_nothing(legend = TRUE) + 
  labs(title="Residuals of male chlamydia cases ~ female chlamydia cases") +
  geom_text(aes(x=x,y=y, group=NULL, label=id), data = nbds.sh.centroids, size = 2)

p.lm_chlam_df + guides(fill = guide_legend(reverse=TRUE))

LS0tDQp0aXRsZTogIk9DSFBQIFRvcm9udG8gUHVibGljIEhlYWx0aCBEYXRhc2V0cyINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIHRvYzogeWVzDQotLS0NCg0KIyBBdXRob3INCg0KKiBKb3JkYW4gQmVsbA0KKiBKdWx5IDEsIDIwMTkNCiogPGh0dHBzOi8vam9yZGFuYmVsbDIzNTcuZ2l0aHViLmlvL09DSFBQLm5iLmh0bWw+DQoNCiMgU291cmNlIGFuZCBkZXNjcmlwdGlvbnMgb2YgZGF0YXNldHMNCg0KKipPbnRhcmlvIENvbW11bml0eSBIZWFsdGggUHJvZmlsZXMgUGFydG5lcnNoaXAgKE9DSFBQKSoqICAgIA0KPGh0dHA6Ly93d3cub250YXJpb2hlYWx0aHByb2ZpbGVzLmNhLz4NCg0KKipEYXRhIOKAlCBMSElOIDcgKFRvcm9udG8gQ2VudHJhbCBhbmQgQ2l0eSBvZiBUb3JvbnRvKSBOZWlnaGJvdXJob29kcywgT250YXJpbyBTdWItUmVnaW9ucyBhbmQgTEhJTnMqKg0KDQpXZSB1c2UgdGhyZWUgZGF0YXNldHM6DQoNCiogKipQcmltYXJ5IENhcmU6IEVucm9sbWVudCBhbmQgQ29udGludWl0eSBvZiBDYXJlIDIwMTEvMTMqKiAgDQoxX3BjX0NvbnRpbnVpdHlfTm9uUm9zdGVyZWRfUm9zdGVyZWRfUGF0aWVudHNfbmVpZ2hiXzIwMTNfTEhJTl83Lnhsc3gNCiogKipBZHVsdCBIZWFsdGggYW5kIERpc2Vhc2UgMjAxNi8xNyoqICANCjFfQUhEXzIwMTdfUlBEQl9OZWlnaGJfTEhJTl83Lnhsc3gNCiogKipTZXh1YWwgSGVhbHRoOiBDaGxhbXlkaWEgY2FzZXMsIEdvbm9ycmhlYSBjYXNlcyAyMDEzLzE2KiogIA0KMl9zaF9uZWlnaGJfY2hsYW1fZ29ub3JfMjAxMy0yMDE2X0xISU5fNy54bHMNCg0KV2UgcXVvdGUgZnJvbSB0aGUgZGVzY3JpcHRpb24gb2YgdGhlIGRhdGE6DQoNCioqVGhlIFJlZ2lzdGVyZWQgUGVyc29ucyBEYXRhYmFzZSAoUlBEQikgYXMgdGhlIHNvdXJjZSBvZiBwb3B1bGF0aW9uKiogIA0KPGh0dHA6Ly93d3cub250YXJpb2hlYWx0aHByb2ZpbGVzLmNhL29fZG9jdW1lbnRzL2Fib3V0VGhlRGF0YU9OL1JQREJfdnNfQ2Vuc3VzX09jdF8yNl8yMDE4LnBkZj4NCg0KPiAqKlR3byBtYWluIHBvcHVsYXRpb24gc291cmNlcyoqDQo+DQo+VGhlcmUgYXJlIHR3byBtYWluIHNvdXJjZXMgdGhhdCBwcm92aWRlIHRoZSBtb3N0IHJlbGlhYmxlIGVzdGltYXRlcyBvZiBPbnRhcmlvJ3MgcG9wdWxhdGlvbi4gRm9yDQpwdXJwb3NlcyBvZiBPQ0hQUCByZXBvcnRpbmcsIHdlIHVzZSB0aGUgUmVnaXN0ZXJlZCBQZXJzb25zIERhdGFiYXNlIChSUERCKSBhcyB0aGUgc291cmNlDQooZGVub21pbmF0b3IpIGZvciBhbGwgb2Ygb3VyIGhlYWx0aC1yZWxhdGVkIGluZGljYXRvcnMuIFdoaWxlIGFub3RoZXIgbWFqb3Igc291cmNlIGZvciBpZGVudGlmeWluZyB0aGUNCnBvcHVsYXRpb24gKGRlbm9taW5hdG9yKSBpcyBTdGF0aXN0aWNzIENhbmFkYeKAmXMgQ2Vuc3VzIGNvdW50cyAoQ2Vuc3VzKSwgdGhlIE9DSFBQIGhhcyBkZXRlcm1pbmVkIHRoYXQNCnRoZSBSUERCIHByb3ZpZGVzIGEgbW9yZSBjb25zaXN0ZW50IG1lYXN1cmUgZm9yIHRoZSBjYWxjdWxhdGlvbiBvZiByYXRlcyBmb3IgaGVhbHRoIGluZGljYXRvcnMgYW5kDQpjb25kaXRpb25zLiBXZSBleHBsYWluIHdoeSBhbmQgcHJvdmlkZSBleGFtcGxlcyB0byBpbGx1c3RyYXRlLg0KPg0KPiAqKlJQREIqKg0KPg0KPlRoZSBSUERCIChkYXRhYmFzZSkgcHJvdmlkZXMgYmFzaWMgZGVtb2dyYXBoaWMgaW5mb3JtYXRpb24gYWJvdXQgYW55b25lIHdobyBoYXMgZXZlciByZWNlaXZlZCBhbg0KT250YXJpbyBIZWFsdGggSW5zdXJhbmNlIFBsYW4gKE9ISVApIGNhcmQuIE9ISVAgY2FyZHMgaW5jbHVkZSBhIHVuaXF1ZSBIZWFsdGggQ2FyZCBOdW1iZXIgKEhDTikgdG8NCmlkZW50aWZ5IGEgcGVyc29uJ3MgYWdlLCBzZXggYW5kIGFkZHJlc3MsIGluY2x1ZGluZyBwb3N0YWwgY29kZS4gVGhlIHBvc3RhbCBjb2RlcyB1c2VkIGF0IElDRVMgY29tZQ0KbWFpbmx5IGZyb20gSENOcy4gSW5mb3JtYXRpb24gZnJvbSB0aGUgaGVhbHRoIGNhcmQgaXMgc3RvcmVkIGluIHRoZSBSUERCLiBIZWFsdGggY2FyZHMgYXJlIHVzdWFsbHkNCnJlbmV3ZWQgZXZlcnkgNSB5ZWFycywgYSBwcm9jZXNzIHRoYXQgaGVscHMgdG8gZW5zdXJlIHRoYXQgaW5mb3JtYXRpb24gaW4gdGhlIHN5c3RlbSBpcyBwZXJpb2RpY2FsbHkNCnJlZnJlc2hlZCwgc3VjaCBhcyBhZGRyZXNzLCBmb3IgZXhhbXBsZSwgc2hvdWxkIGEgcGVyc29uIG1vdmUgYW5kIHVwZGF0ZSB0aGUgY2FyZCB3aXRoaW4gdGhhdCB0aW1lDQpmcmFtZS4gVGhlIHN5c3RlbSBtYXkgYWxzbyBiZSB1cGRhdGVkIG1vcmUgZnJlcXVlbnRseSBpZiBhbiBpbmRpdmlkdWFsIGludGVyYWN0cyB3aXRoIHRoZSBoZWFsdGhjYXJlDQpzeXN0ZW0gYmV0d2VlbiByZW5ld2FsIHBlcmlvZHMuIFRoaXMgYWxsb3dzIGZvciBhIG1vcmUgY3VycmVudCBzb3VyY2Ugb2YgbG9jYXRpb24tYmFzZWQgZGF0YSBmb3INCmhlYWx0aCByZXBvcnRpbmcuDQo+DQo+ICoqQ2Vuc3VzKioNCj4NCj5Bbm90aGVyIHNvdXJjZSBvZiBkYXRhIG9uIHdoZXJlIHBlb3BsZSBsaXZlIGNhbiBjb21lIGZyb20gU3RhdGlzdGljcyBDYW5hZGEgKFN0YXRzIENhbikuIFN0YXRzIENhbg0KY29sbGVjdHMgZGF0YSBvbiBpbmRpdmlkdWFscyBsaXZpbmcgaW4gQ2FuYWRhIHRocm91Z2ggdGhlIENlbnN1cywgYSBzdXJ2ZXkgY29uZHVjdGVkIGV2ZXJ5IDUgeWVhcnMuIFN0YXRzIENhbg0KcmVwb3J0cyB3aG8gbGl2ZXMgaW4gYSBnaXZlbiBhcmVhIGF0IG9uZSBwb2ludCBpbiB0aW1lIOKAkyBpLmUuIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvbiBhbiBpbmRpdmlkdWFsIHByb3ZpZGVzIHdoZW4NCmNvbXBsZXRpbmcgdGhlIENlbnN1cw0KPg0KPiAqKlJQREIgdnMuIENlbnN1cyoqDQo+DQo+V2hpbGUgYXQgdGhlIHByb3ZpbmNpYWwgbGV2ZWwsIHRoZSBudW1iZXIgb2YgcGVvcGxlIHdlIGlkZW50aWZ5IGluIHRoZSBSUERCIGFzIGxpdmluZyBpbiBPbnRhcmlvIGRvZXMgbm90DQpkaWZmZXIgbXVjaCBmcm9tIENlbnN1cyBlc3RpbWF0ZXMsIGRpZmZlcmVuY2VzIGFyZSBtb3JlIHByb25vdW5jZWQgYXQgc21hbGxlciBhcmVhcyBzdWNoIGFzDQpuZWlnaGJvdXJob29kcyBvciBsb2NhbCBhcmVhcy4gVGhpcyBwYXJ0aWN1bGFyIGlzc3VlIGlzIG1vc3QgZXZpZGVudCBpbiBhcmVhcyBvZiBoaWdoIG1pZ3JhdGlvbiB3aGVyZSB3ZQ0KaGF2ZSBvYnNlcnZlZCBsYXJnZSBkaWZmZXJlbmNlcyBpbiByYXRlcyB1c2luZyBSUERCIHZzLiB0aGUgQ2Vuc3VzIGluIHBhcnQgZHVlIHRvIHBvcHVsYXRpb24gbW9iaWxpdHkuICANCj5Gb3IgZXhhbXBsZSwgaW4gc29tZSBhcmVhcyBvZiBPbnRhcmlvLCBwYXJ0aWN1bGFybHkgaW4gbGFyZ2VyIHVyYmFuIGNlbnRyZXMsIG5ld2NvbWVycyB0byB0aGUgYXJlYSBvZnRlbg0Kc2V0dGxlIGZpcnN0IOKAnGRvd250b3du4oCdIGJ1dCBvdmVyIHRpbWUsIG1heSBtb3ZlIGZyb20gZG93bnRvd24gdG8gb3V0bHlpbmcgYXJlYXMuIFRoZSBtYWpvcml0eSBvZg0KcGVvcGxlIHdobyBtb3ZlIGRvIG5vdCBjaGFuZ2Ugb3IgdXBkYXRlIHRoZWlyIGhlYWx0aCBjYXJkIHVudGlsIHJlbmV3YWwgdGltZSBzbyB0aGV5IHN0YXkgaW4gdGhlIFJQREINCndpdGggdGhlaXIgb3JpZ2luYWwgaGVhbHRoIGNhcmQgaW5mb3JtYXRpb24gaW5jbHVkaW5nIHRoZSBhZGRyZXNzIGFuZCBwb3N0YWwgY29kZSBvZiB0aGVpciDigJxkb3dudG93buKAnQ0KYWRkcmVzcy4gIA0KPlRoZSBzYW1lIGlzIHRydWUgb2YgQ2Vuc3VzIHBvcHVsYXRpb24gY291bnRzOiB3aGVuIHNvbWVvbmUgbW92ZXMsIHRoZXkgYXJlIHN0aWxsIGNvbnNpZGVyZWQgbGl2aW5nIGF0DQp0aGVpciBvcmlnaW5hbCBhZGRyZXNzIGFuZCBjb21wcmlzZSB0aGUgcG9wdWxhdGlvbiBvZiB0aGF0IGFyZWEgdW50aWwgdGhlIG5leHQgQ2Vuc3VzIGlzIHRha2VuIChldmVyeSA1DQp5ZWFycykuDQoNCiMgU2hhcGVmaWxlIGZvciBDaXR5IG9mIFRvcm9udG8ncyAxNDAgbmVpZ2hib3VyaG9vZHMNCg0KV2Ugbm93IGltcG9ydCBhbmQgcHJvY2VzcyBhIHNoYXBlZmlsZSBmb3IgVG9yb250bydzIDE0MCBuZWlnaGJvdXJob29kcy4NCg0KPGh0dHBzOi8vd3d3LnRvcm9udG8uY2EvY2l0eS1nb3Zlcm5tZW50L2RhdGEtcmVzZWFyY2gtbWFwcy9vcGVuLWRhdGEvb3Blbi1kYXRhLWNhdGFsb2d1ZS8jYTQ1YmQ0NWEtZWRlOC03MzBlLTFhYmMtOTMxMDViMmM0MzlmPg0KDQo8aHR0cDovL29wZW5kYXRhLnRvcm9udG8uY2EvZ2NjL25laWdoYm91cmhvb2RzX3BsYW5uaW5nX2FyZWFzX3dnczg0LnppcD4NCg0KKipOZWlnaGJvdXJob29kcyoqDQoNCj4gT3duZXI6IFNvY2lhbCBEZXZlbG9wbWVudCwgRmluYW5jZSAmIEFkbWluaXN0cmF0aW9uDQo+DQo+IEN1cnJlbmN5OiBKdW5lIDIwMTQNCg0KKipOZWlnaGJvdXJob29kcyAoV0dTODQpKioNCg0KYGBge3J9DQpsaWJyYXJ5KGRhdGEudGFibGUpICNmcmVhZA0KbGlicmFyeShwbHlyKSAjam9pbg0KbGlicmFyeShnZ3Bsb3QyKSAjZ2dwbG90LCBmb3J0aWZ5DQpsaWJyYXJ5KHNwKSAjdXNlZCBieSByZ2RhbA0KbGlicmFyeShyZ2RhbCkgI3JlYWRPR1INCmxpYnJhcnkocmdlb3MpICNnQ2VudHJvaWQNCmxpYnJhcnkoc2NhbGVzKSAjc2NhbGVfZmlsbF9kaXN0aWxsZXIsIHBlcmNlbnRfZm9ybWF0DQpsaWJyYXJ5KGdnbWFwKSAjdGhlbWVfbm90aGluZw0KbGlicmFyeShIbWlzYykgI3Jjb3JyDQpgYGANCklucHV0IHNoYXBlZmlsZQ0KYGBge3J9DQpuYmRzLnNoIDwtIHJlYWRPR1IoIkM6L1VzZXJzLzE0MTY1L0Rlc2t0b3AvQXJjR0lTL1NIQVBFRklMRVMvbmVpZ2hib3VyaG9vZHNfcGxhbm5pbmdfYXJlYXNfd2dzODQiLCAiTkVJR0hCT1JIT09EU19XR1M4NCIpDQpgYGANCkFkZCAiaWQiIGNvbHVtbg0KYGBge3J9DQpuYmRzLnNoQGRhdGEkaWQgPC0gYXMuaW50ZWdlcihuYmRzLnNoQGRhdGEkQVJFQV9TX0NEKQ0KYGBgDQpNYWtlIGNlbnRyb2lkcyBvZiBlYWNoIG5laWdoYm91cmhvb2QsIGZvciBwbGFjaW5nIGxhYmVscyB3aGVuIHBsb3R0aW5nDQpgYGB7cn0NCm5iZHMuc2guY2VudHJvaWRzICA8LSBhcy5kYXRhLmZyYW1lKGdDZW50cm9pZChuYmRzLnNoLCBieWlkID0gVFJVRSkpDQpgYGANCkFkZCAiaWQiIGNvbHVtbg0KYGBge3J9DQpuYmRzLnNoLmNlbnRyb2lkcyRpZCA8LSBuYmRzLnNoQGRhdGEkaWQNCmBgYA0KU2hhcGVmaWxlIHByb2Nlc3NpbmcNCmBgYHtyfQ0KbmJkcy5zaC5wb2ludHMgPSBmb3J0aWZ5KG5iZHMuc2gsIHJlZ2lvbiA9ICJpZCIpDQoNCm5iZHMuc2guZGYgPSBqb2luKG5iZHMuc2gucG9pbnRzLCBuYmRzLnNoQGRhdGEsIGJ5ID0gImlkIikNCmBgYA0KV2UgYXJlIG5vdyBkb25lIHdpdGggc2hhcGVmaWxlIHByb2Nlc3NpbmcuDQoNCldlIGNvcGllZCBzZWxlY3RlZCBjb2x1bW5zIGZyb20gc2hlZXRzIG9mIHRoZSAueGxzLy54bHN4IGZpbGVzIHRvIG5ldyBzaGVldHMsIHJlbmFtZWQgY29sdW1ucyBieSBjaGFuZ2luZyBzcGFjZXMgYW5kIGh5cGhlbnMgdG8gdW5kZXJzY29yZXMgYW5kIHNwZWxsaW5nIHN5bWJvbHMsIGFuZCBleHBvcnRlZCB0aGVzZSB0byAuY3N2IGZpbGVzLg0KDQpXZSBzaGFsbCB2aXN1YWxpemUgc2VsZWN0ZWQgZGF0YSBmcm9tIHRoZXNlIHRhYmxlcyBvbiBhIG1hcC4gVGhlbiB3ZSBjb21wdXRlIGNvcnJlbGF0aW9ucy4NCg0KIyBQcmltYXJ5IENhcmU6IEVucm9sbWVudCBhbmQgQ29udGludWl0eSBvZiBDYXJlIDIwMTEvMTMNCg0KMV9wY19Db250aW51aXR5X05vblJvc3RlcmVkX1Jvc3RlcmVkX1BhdGllbnRzX25laWdoYl8yMDEzX0xISU5fNy54bHN4IUNvbnRpbnVpdHlfRW5yb2xsZWRfTm9uRW5yb2xsZWQ6DQoNCj4gUHJpbWFyeSBDYXJlOiBFbnJvbG1lbnQgYW5kIENvbnRpbnVpdHkgb2YgQ2FyZSAoQm90aCBzZXhlcywgQWdlcyAxOSspIGZvciBUb3JvbnRvIE5laWdoYm91cmhvb2RzIGFuZCBUb3JvbnRvIENlbnRyYWwgTEhJTiwgMjAxMS8xMiB0byAyMDEyLzEzIChBcHJpbCAxLCAyMDExLU1hcmNoIDMxLCAyMDEzKQ0KPg0KPiBEYXRhIHNvdXJjZXM6IFBvcHVsYXRpb24gLSBPbnRhcmlvIEhlYXRoIEluc3VyYW5jZSBQbGFuIChPSElQKSBwaHlzaWNpYW4gY2xhaW1zLCBDbGllbnQgQWdlbmN5IFByb3ZpZGVyIEVucm9sbWVudCAoQ0FQRSkgdGFibGVzLCBSZWdpc3RlcmVkIFBlcnNvbnMnIERhdGFiYXNlLCBDb21tdW5pdHkgSGVhbHRoIENlbnRyZSBjbGllbnQgZW5jb3VudGVyIGRhdGEuDQo+DQo+IFBvcHVsYXRpb24gRW5yb2xsZWQ6IHJvc3RlcmVkIHdpdGggYSBQYXRpZW50IEVucm9sbWVudCBNb2RlbCAoUEVNKSBvciByZWdpc3RlcmVkIHdpdGggYSBDb21tdW5pdHkgSGVhbHRoIENlbnRyZSAoQ0hDKS4JDQo+DQo+IFBvcHVsYXRpb24gTm9uLUVucm9sbGVkOiBub3Qgcm9zdGVyZWQgd2l0aCBhIFBhdGllbnQgRW5yb2xtZW50IE1vZGVsIChQRU0pIG9yIHJlZ2lzdGVyZWQgd2l0aCBhIENvbW11bml0eSBIZWFsdGggQ2VudHJlIChDSEMpLgkJCQ0KDQoiaWQiLCAiUG9wdWxhdGlvbl8xOV9wbHVzIiwgIkVucm9sbGVkX1BvcHVsYXRpb24iLCAiRW5yb2xsZWRfUG9wdWxhdGlvbl93aXRoX05vX1Zpc2l0cyIsICJFbnJvbGxlZF9Qb3B1bGF0aW9uX3dpdGhfMV9vcl8yX1Zpc2l0cyIsICJFbnJvbGxlZF9Qb3B1bGF0aW9uX3dpdGhfM19wbHVzX1Zpc2l0cyIsICJOb25fRW5yb2xsZWRfUG9wdWxhdGlvbiIsICJOb25fRW5yb2xsZWRfUG9wdWxhdGlvbl93aXRoX05vX1Zpc2l0cyIsICJOb25fRW5yb2xsZWRfUG9wdWxhdGlvbl93aXRoXzFfb3JfMl9WaXNpdHMiLCAiTm9uX0Vucm9sbGVkX1BvcHVsYXRpb25fd2l0aF8zX3BsdXNfVmlzaXRzIiwgIlRvdGFsX1BvcHVsYXRpb25fRW5yb2xsZWRfYW5kX05vbl9FbnJvbGxlZCIsICJUb3RhbF9Qb3B1bGF0aW9uX3dpdGhfTm9fVmlzaXRzIiwgIlRvdGFsX1BvcHVsYXRpb25fd2l0aF8xX29yXzJfVmlzaXRzIiwgIlRvdGFsX1BvcHVsYXRpb25fd2l0aF8zX3BsdXNfVmlzaXRzIg0KDQoqKjFfcGNfQ29udGludWl0eV9Ob25Sb3N0ZXJlZF9Sb3N0ZXJlZF9QYXRpZW50c19uZWlnaGJfMjAxM19MSElOXzcuY3N2KioNCg0KYGBge3J9DQpwYXRpZW50cyA8LSBmcmVhZCgiMV9wY19Db250aW51aXR5X05vblJvc3RlcmVkX1Jvc3RlcmVkX1BhdGllbnRzX25laWdoYl8yMDEzX0xISU5fNy5jc3YiKQ0KYGBgDQoNCmBgYHtyfQ0Kc3RyKHBhdGllbnRzKQ0KYGBgDQoNCg0KQ3JlYXRlIHJhdGlvIGNvbHVtbnMgZm9yIHNlbGVjdGVkIHZhcmlhYmxlcw0KYGBge3J9DQpwYXRpZW50cyRSYXRpb19Ob25fRW5yb2xsZWRfUG9wdWxhdGlvbiA8LSBwYXRpZW50cyROb25fRW5yb2xsZWRfUG9wdWxhdGlvbi9wYXRpZW50cyRQb3B1bGF0aW9uXzE5X3BsdXMNCg0KcGF0aWVudHMkUmF0aW9fVG90YWxfUG9wdWxhdGlvbl93aXRoX05vX1Zpc2l0cyA8LSBwYXRpZW50cyRUb3RhbF9Qb3B1bGF0aW9uX3dpdGhfTm9fVmlzaXRzL3BhdGllbnRzJFBvcHVsYXRpb25fMTlfcGx1cw0KDQpwYXRpZW50cyRSYXRpb19Ub3RhbF9Qb3B1bGF0aW9uX3dpdGhfM19wbHVzX1Zpc2l0cyA8LSBwYXRpZW50cyRUb3RhbF9Qb3B1bGF0aW9uX3dpdGhfM19wbHVzX1Zpc2l0cy9wYXRpZW50cyRQb3B1bGF0aW9uXzE5X3BsdXMNCg0KcGF0aWVudHNfcmF0aW9zIDwtIHBhdGllbnRzWywuKGlkLFJhdGlvX05vbl9FbnJvbGxlZF9Qb3B1bGF0aW9uLFJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF9Ob19WaXNpdHMsUmF0aW9fVG90YWxfUG9wdWxhdGlvbl93aXRoXzNfcGx1c19WaXNpdHMpXQ0KYGBgDQoNCiMjIFJhdGlvX05vbl9FbnJvbGxlZF9Qb3B1bGF0aW9uDQpgYGB7cn0NClJhdGlvX05vbl9FbnJvbGxlZF9Qb3B1bGF0aW9uIDwtIHBhdGllbnRzX3JhdGlvc1ssIC4oaWQsUmF0aW9fTm9uX0Vucm9sbGVkX1BvcHVsYXRpb24pXQ0KDQpSYXRpb19Ob25fRW5yb2xsZWRfUG9wdWxhdGlvbi5zaCA8LSBtZXJnZShuYmRzLnNoLmRmLCBSYXRpb19Ob25fRW5yb2xsZWRfUG9wdWxhdGlvbiwgYnkgPSAiaWQiKQ0KYGBgDQpNYWtlIGdyYXBoaWNzIG9iamVjdA0KYGBge3J9DQpwLlJhdGlvX05vbl9FbnJvbGxlZF9Qb3B1bGF0aW9uIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBSYXRpb19Ob25fRW5yb2xsZWRfUG9wdWxhdGlvbi5zaCwgDQogICAgICAgICAgICAgICBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBSYXRpb19Ob25fRW5yb2xsZWRfUG9wdWxhdGlvbiksIA0KICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArIA0KICBjb29yZF9tYXAoKSArIA0KICBzY2FsZV9maWxsX2Rpc3RpbGxlcihuYW1lPSJSYXRpbyIsIGxhYmVscz1wZXJjZW50X2Zvcm1hdChhY2N1cmFjeT0xKSwgcGFsZXR0ZSA9ICJQdVJkIiwgdHJhbnMgPSAicmV2ZXJzZSIsIGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDgpKSsNCiAgdGhlbWVfbm90aGluZyhsZWdlbmQgPSBUUlVFKSArIA0KICBsYWJzKHRpdGxlPSJSYXRpbyBvZiB0b3RhbCBwb3B1bGF0aW9uIG5vbi1lbnJvbGxlZCIpICsNCiAgZ2VvbV90ZXh0KGFlcyh4PXgseT15LCBncm91cD1OVUxMLCBsYWJlbD1pZCksIGRhdGEgPSBuYmRzLnNoLmNlbnRyb2lkcywgc2l6ZSA9IDIpDQpgYGANClBsb3QgZ3JhcGhpY3Mgb2JqZWN0DQpgYGB7cn0NCnAuUmF0aW9fTm9uX0Vucm9sbGVkX1BvcHVsYXRpb24gKyBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlPVRSVUUpKQ0KYGBgDQoNCiMjIFJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF9Ob19WaXNpdHMNCmBgYHtyfQ0KUmF0aW9fVG90YWxfUG9wdWxhdGlvbl93aXRoX05vX1Zpc2l0cyA8LSBwYXRpZW50c19yYXRpb3NbLCAuKGlkLFJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF9Ob19WaXNpdHMpXQ0KDQpSYXRpb19Ub3RhbF9Qb3B1bGF0aW9uX3dpdGhfTm9fVmlzaXRzLnNoIDwtIG1lcmdlKG5iZHMuc2guZGYsIFJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF9Ob19WaXNpdHMsIGJ5ID0gImlkIikNCmBgYA0KDQpNYWtlIGdyYXBoaWNzIG9iamVjdA0KYGBge3J9DQpwLlJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF9Ob19WaXNpdHMgPC0gZ2dwbG90KCkgKw0KICBnZW9tX3BvbHlnb24oZGF0YSA9IFJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF9Ob19WaXNpdHMuc2gsIA0KICAgICAgICAgICAgICAgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gUmF0aW9fVG90YWxfUG9wdWxhdGlvbl93aXRoX05vX1Zpc2l0cyksIA0KICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArIA0KICBjb29yZF9tYXAoKSArIA0KICBzY2FsZV9maWxsX2Rpc3RpbGxlcihuYW1lPSJSYXRpbyIsIGxhYmVscz1wZXJjZW50X2Zvcm1hdChhY2N1cmFjeT0xKSwgcGFsZXR0ZSA9ICJQdVJkIiwgdHJhbnMgPSAicmV2ZXJzZSIsIGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDgpKSArIA0KICB0aGVtZV9ub3RoaW5nKGxlZ2VuZCA9IFRSVUUpICsgDQogIGxhYnModGl0bGU9IlJhdGlvIG9mIHRvdGFsIHBvcHVsYXRpb24gd2l0aCBubyB2aXNpdHMiKSArDQogIGdlb21fdGV4dChhZXMoeD14LHk9eSwgZ3JvdXA9TlVMTCwgbGFiZWw9aWQpLCBkYXRhID0gbmJkcy5zaC5jZW50cm9pZHMsIHNpemUgPSAyKQ0KYGBgDQpQbG90IGdyYXBoaWNzIG9iamVjdA0KYGBge3J9DQpwLlJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF9Ob19WaXNpdHMgKyBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlPVRSVUUpKQ0KYGBgDQoNCiMjIFJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF8zX3BsdXNfVmlzaXRzDQpgYGB7cn0NClJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF8zX3BsdXNfVmlzaXRzIDwtIHBhdGllbnRzX3JhdGlvc1ssIC4oaWQsUmF0aW9fVG90YWxfUG9wdWxhdGlvbl93aXRoXzNfcGx1c19WaXNpdHMpXQ0KDQpSYXRpb19Ub3RhbF9Qb3B1bGF0aW9uX3dpdGhfM19wbHVzX1Zpc2l0cy5zaCA8LSBtZXJnZShuYmRzLnNoLmRmLCBSYXRpb19Ub3RhbF9Qb3B1bGF0aW9uX3dpdGhfM19wbHVzX1Zpc2l0cywgYnkgPSAiaWQiKQ0KYGBgDQpNYWtlIGdyYXBoaWNzIG9iamVjdA0KYGBge3J9DQpwLlJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF8zX3BsdXNfVmlzaXRzIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBSYXRpb19Ub3RhbF9Qb3B1bGF0aW9uX3dpdGhfM19wbHVzX1Zpc2l0cy5zaCwgDQogICAgICAgICAgICAgICBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBSYXRpb19Ub3RhbF9Qb3B1bGF0aW9uX3dpdGhfM19wbHVzX1Zpc2l0cyksIA0KICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArIA0KICBjb29yZF9tYXAoKSArIA0KICBzY2FsZV9maWxsX2Rpc3RpbGxlcihuYW1lPSJSYXRpbyIsIGxhYmVscz1wZXJjZW50X2Zvcm1hdChhY2N1cmFjeT0xKSwgcGFsZXR0ZSA9ICJHcmVlbnMiLCB0cmFucyA9ICJyZXZlcnNlIiwgYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gOCkpKw0KICB0aGVtZV9ub3RoaW5nKGxlZ2VuZCA9IFRSVUUpICsgDQogIGxhYnModGl0bGU9IlJhdGlvIG9mIHRvdGFsIHBvcHVsYXRpb24gd2l0aCAzKyB2aXNpdHMiKSArDQogIGdlb21fdGV4dChhZXMoeD14LHk9eSwgZ3JvdXA9TlVMTCwgbGFiZWw9aWQpLCBkYXRhID0gbmJkcy5zaC5jZW50cm9pZHMsIHNpemUgPSAyKQ0KYGBgDQpQbG90IGdyYXBoaWNzIG9iamVjdA0KYGBge3J9DQpwLlJhdGlvX1RvdGFsX1BvcHVsYXRpb25fd2l0aF8zX3BsdXNfVmlzaXRzICsgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZT1UUlVFKSkNCmBgYA0KDQojIEFkdWx0IEhlYWx0aCBhbmQgRGlzZWFzZSAyMDE2LzE3DQoNCjFfQUhEXzIwMTdfUlBEQl9OZWlnaGJfTEhJTl83Lnhsc3ghRGlhYmV0ZXNfTmVpZ2hiX1Rvcm9udG86DQoNCj4gRGVtb2dyYXBoaWNzIC0gRGVub21pbmF0b3I6IE9udGFyaW8gTWluaXN0cnkgb2YgSGVhbHRoIGFuZCBMb25nLVRlcm0gQ2FyZSBSZWdpc3RlcmVkIFBlcnNvbnMgRGF0YWJhc2UgKFJQREIpLCBwb3B1bGF0aW9uIGFnZWQgMjArIHdobyB3ZXJlIGFsaXZlIGFuZCBsaXZpbmcgaW4gdGhlIE9udGFyaW8gb24gQXByaWwgMXN0LCAyMDE2IA0KPg0KPiBOdW1lcmF0b3I6IGRlcml2ZWQgZnJvbSB2YWxpZGF0ZWQsIGRpc2Vhc2UgcmVnaXN0cmllcyBtYWludGFpbmVkIGJ5IHRoZSBJbnN0aXR1dGUgZm9yIENsaW5pY2FsIEV2YWx1YXRpdmUgU2NpZW5jZXMgKElDRVMpDQoNCjFfQUhEXzIwMTdfUlBEQl9OZWlnaGJfTEhJTl83Lnhsc3ghQ09QRF9OZWlnaGJfVG9yb250bzoNCg0KPiBEZW1vZ3JhcGhpY3MgLSBEZW5vbWluYXRvcjogT250YXJpbyBNaW5pc3RyeSBvZiBIZWFsdGggYW5kIExvbmctVGVybSBDYXJlIFJlZ2lzdGVyZWQgUGVyc29ucyBEYXRhYmFzZSAoUlBEQiksIHBvcHVsYXRpb24gYWdlZCAzNSsgd2hvIHdlcmUgYWxpdmUgYW5kIGxpdmluZyBpbiB0aGUgT250YXJpbyBvbiBBcHJpbCAxc3QsIDIwMTYgDQo+DQo+IE51bWVyYXRvcjogZGVyaXZlZCBmcm9tIHZhbGlkYXRlZCwgZGlzZWFzZSByZWdpc3RyaWVzIG1haW50YWluZWQgYnkgdGhlIEluc3RpdHV0ZSBmb3IgQ2xpbmljYWwgRXZhbHVhdGl2ZSBTY2llbmNlcyAoSUNFUykNCg0KImlkIiwgIlBlb3BsZV93aXRoX0RpYWJldGVzXzIwX3BsdXMiLCAiVG90YWxfUG9wdWxhdGlvbl8yMDE2X1JQREJfMjBfcGx1cyIsICJQcmV2YWxlbmNlX3Blcl9odW5kcmVkX0RpYWJldGVzXzIwX3BsdXMiLCAiUGVvcGxlX3dpdGhfQ09QRF8zNV9wbHVzIiwgIlRvdGFsX1BvcHVsYXRpb25fMjAxNl9SUERCXzM1X3BsdXMiLCAiUHJldmFsZW5jZV9wZXJfaHVuZHJlZF9DT1BEXzM1X3BsdXMiDQoNCioqMV9BSERfMjAxN19SUERCX05laWdoYl9MSElOXzcuY3N2KioNCg0KYGBge3J9DQpjaHJvbmljIDwtIGZyZWFkKCIxX0FIRF8yMDE3X1JQREJfTmVpZ2hiX0xISU5fNy5jc3YiKQ0KDQpjaHJvbmljJFJhdGlvX1Blb3BsZV93aXRoX0RpYWJldGVzXzIwX3BsdXMgPC0gY2hyb25pYyRQZW9wbGVfd2l0aF9EaWFiZXRlc18yMF9wbHVzL2Nocm9uaWMkVG90YWxfUG9wdWxhdGlvbl8yMDE2X1JQREJfMjBfcGx1cw0KDQpjaHJvbmljJFJhdGlvX1Blb3BsZV93aXRoX0NPUERfMzVfcGx1cyA8LSBjaHJvbmljJFBlb3BsZV93aXRoX0NPUERfMzVfcGx1cy9jaHJvbmljJFRvdGFsX1BvcHVsYXRpb25fMjAxNl9SUERCXzM1X3BsdXMNCg0KY2hyb25pY19yYXRpb3MgPC0gY2hyb25pY1ssLihpZCxSYXRpb19QZW9wbGVfd2l0aF9EaWFiZXRlc18yMF9wbHVzLFJhdGlvX1Blb3BsZV93aXRoX0NPUERfMzVfcGx1cyldDQpgYGANCg0KYGBge3J9DQpSYXRpb19QZW9wbGVfd2l0aF9EaWFiZXRlc18yMF9wbHVzIDwtIGNocm9uaWNfcmF0aW9zWywgLihpZCxSYXRpb19QZW9wbGVfd2l0aF9EaWFiZXRlc18yMF9wbHVzKV0NCg0KUmF0aW9fUGVvcGxlX3dpdGhfRGlhYmV0ZXNfMjBfcGx1cy5zaCA8LSBtZXJnZShuYmRzLnNoLmRmLCBSYXRpb19QZW9wbGVfd2l0aF9EaWFiZXRlc18yMF9wbHVzLCBieSA9ICJpZCIpDQpgYGANCg0KTWFrZSBhbmQgcGxvdCBncmFwaGljcyBvYmplY3QNCmBgYHtyfQ0KcC5SYXRpb19QZW9wbGVfd2l0aF9EaWFiZXRlc18yMF9wbHVzIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBSYXRpb19QZW9wbGVfd2l0aF9EaWFiZXRlc18yMF9wbHVzLnNoLCANCiAgICAgICAgICAgICAgIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IFJhdGlvX1Blb3BsZV93aXRoX0RpYWJldGVzXzIwX3BsdXMpLCANCiAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMikgKyANCiAgY29vcmRfbWFwKCkgKyANCiAgc2NhbGVfZmlsbF9kaXN0aWxsZXIobmFtZT0iUmF0aW8iLCBsYWJlbHM9cGVyY2VudF9mb3JtYXQoYWNjdXJhY3k9MSksIHBhbGV0dGUgPSAiUHVSZCIsIHRyYW5zID0gInJldmVyc2UiLA0KICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSA4KSkgKyANCiAgdGhlbWVfbm90aGluZyhsZWdlbmQgPSBUUlVFKSsNCiAgbGFicyh0aXRsZT0iUmF0aW8gb2YgcGVvcGxlIHdpdGggZGlhYmV0ZXMsIDIwKyIpICsNCiAgZ2VvbV90ZXh0KGFlcyh4PXgseT15LCBncm91cD1OVUxMLCBsYWJlbD1pZCksIGRhdGEgPSBuYmRzLnNoLmNlbnRyb2lkcywgc2l6ZSA9IDIpDQoNCnAuUmF0aW9fUGVvcGxlX3dpdGhfRGlhYmV0ZXNfMjBfcGx1cyArIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHJldmVyc2U9VFJVRSkpDQpgYGANCg0KYGBge3J9DQpSYXRpb19QZW9wbGVfd2l0aF9DT1BEXzM1X3BsdXMgPC0gY2hyb25pY19yYXRpb3NbLCAuKGlkLFJhdGlvX1Blb3BsZV93aXRoX0NPUERfMzVfcGx1cyldDQoNClJhdGlvX1Blb3BsZV93aXRoX0NPUERfMzVfcGx1cy5zaCA8LSBtZXJnZShuYmRzLnNoLmRmLCBSYXRpb19QZW9wbGVfd2l0aF9DT1BEXzM1X3BsdXMsIGJ5ID0gImlkIikNCmBgYA0KTWFrZSBhbmQgcGxvdCBncmFwaGljcyBvYmplY3QNCmBgYHtyfQ0KcC5SYXRpb19QZW9wbGVfd2l0aF9DT1BEXzM1X3BsdXMgPC0gZ2dwbG90KCkgKw0KICBnZW9tX3BvbHlnb24oZGF0YSA9IFJhdGlvX1Blb3BsZV93aXRoX0NPUERfMzVfcGx1cy5zaCwgDQogICAgICAgICAgICAgICBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBSYXRpb19QZW9wbGVfd2l0aF9DT1BEXzM1X3BsdXMpLCANCiAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMikgKyANCiAgY29vcmRfbWFwKCkgKyANCiAgc2NhbGVfZmlsbF9kaXN0aWxsZXIobmFtZT0iUmF0aW8iLCBsYWJlbHM9cGVyY2VudF9mb3JtYXQoYWNjdXJhY3k9MSksIHBhbGV0dGUgPSAiUHVSZCIsIHRyYW5zID0gInJldmVyc2UiLA0KICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSA4KSkrDQogIHRoZW1lX25vdGhpbmcobGVnZW5kID0gVFJVRSkgKyANCiAgbGFicyh0aXRsZT0iUmF0aW8gb2YgcGVvcGxlIHdpdGggQ09QRCwgMzUrIikgKw0KICBnZW9tX3RleHQoYWVzKHg9eCx5PXksIGdyb3VwPU5VTEwsIGxhYmVsPWlkKSwgZGF0YSA9IG5iZHMuc2guY2VudHJvaWRzLCBzaXplID0gMikNCg0KcC5SYXRpb19QZW9wbGVfd2l0aF9DT1BEXzM1X3BsdXMgKyBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlPVRSVUUpKQ0KYGBgDQoNCiMgU2V4dWFsIEhlYWx0aDogQ2hsYW15ZGlhIGNhc2VzLCBHb25vcnJoZWEgY2FzZXMgMjAxMy8xNg0KDQoyX3NoX25laWdoYl9jaGxhbV9nb25vcl8yMDEzLTIwMTZfTEhJTl83Lnhsc3ghQ2hsYW15ZGlhX01hbGVfRmVtYWxlX1Rvcl9uZWlnaDoNCg0KPiAgTnVtYmVyIG9mIENobGFteWRpYSBDYXNlcyBmb3IgQWdlIDE1IHllYXJzIGFuZCBvdmVyIGJ5IEdlbmRlciAoTWFsZSwgRmVtYWxlKSwgVG9yb250byBOZWlnaGJvdXJob29kcywgMjAxMyB0byAyMDE2IENhbGVuZGFyIFllYXJzIENvbWJpbmVkDQo+DQo+ICBEZW1vZ3JhcGhpY3MgLSBEZW5vbWluYXRvcjogQmFzZWQgb24gMjAxMSBDZW5zdXMgcG9wdWxhdGlvbiBlc3RpbWF0ZXMuIChTdGF0aXN0aWNzIENhbmFkYSwgMjAxMSBDZW5zdXMgb2YgUG9wdWxhdGlvbikuDQo+DQo+ICBOdW1lcmF0b3I6IE51bWJlciBvZiBDaGxhbXlkaWEgY2FzZXMgZm9yIDQgeWVhciAoMjAxMyB0byAyMDE2KSBvYnNlcnZhdGlvbiBwZXJpb2QuICAgICAgICBEYXRhIHNvdXJjZTogRGF0YSBhcyBvZiBKdWx5IDIwLCAyMDE3LCBUb3JvbnRvIFB1YmxpYyBIZWFsdGggaW50ZWdyYXRlZCBQdWJsaWMgSGVhbHRoIEluZm9ybWF0aW9uIFN5c3RlbSBbaVBISVNdLiANCj4NCj4gKiBBdmVyYWdlIGFubnVhbCByYXRlIG9mIENobGFteWRpYSBjYXNlcyAoLzEwMCwwMDApIE1hbGVzICgyMDEzIHRvIDIwMTYpLCBBbGwgQWdlcyAxNSsNCj4NCj4gKiBBdmVyYWdlIGFubnVhbCByYXRlIG9mIENobGFteWRpYSBjYXNlcyAoLzEwMCwwMDApIEZlbWFsZXMgKDIwMTMgdG8gMjAxNiksIEFsbCBBZ2VzIDE1Kw0KDQoiaWQiLCAiQ2hsYW15ZGlhX2Nhc2VzX21hbGUiLCAiUG9wdWxhdGlvbl9tYWxlIiwgIkNobGFteWRpYV9jYXNlc19mZW1hbGUiLCAiUG9wdWxhdGlvbl9mZW1hbGUiDQoNCioqMl9zaF9uZWlnaGJfY2hsYW1fZ29ub3JfMjAxMy0yMDE2X0xISU5fNy5jc3YqKg0KDQpgYGB7cn0NCmNobGFteWRpYSA8LSBmcmVhZCgiMl9zaF9uZWlnaGJfY2hsYW1fZ29ub3JfMjAxMy0yMDE2X0xISU5fNy5jc3YiKQ0KDQpjaGxhbXlkaWEkUmF0aW9fQ2hsYW15ZGlhX2Nhc2VzX21hbGUgPC0gY2hsYW15ZGlhJENobGFteWRpYV9jYXNlc19tYWxlL2NobGFteWRpYSRQb3B1bGF0aW9uX21hbGUNCg0KY2hsYW15ZGlhJFJhdGlvX0NobGFteWRpYV9jYXNlc19mZW1hbGUgPC0gY2hsYW15ZGlhJENobGFteWRpYV9jYXNlc19mZW1hbGUvY2hsYW15ZGlhJFBvcHVsYXRpb25fZmVtYWxlDQoNCmNobGFteWRpYV9yYXRpb3MgPC0gY2hsYW15ZGlhWywuKGlkLFJhdGlvX0NobGFteWRpYV9jYXNlc19tYWxlLFJhdGlvX0NobGFteWRpYV9jYXNlc19mZW1hbGUpXQ0KYGBgDQoNCmBgYHtyfQ0KUmF0aW9fQ2hsYW15ZGlhX2Nhc2VzX21hbGUgPC0gY2hsYW15ZGlhX3JhdGlvc1ssIC4oaWQsUmF0aW9fQ2hsYW15ZGlhX2Nhc2VzX21hbGUpXQ0KDQpSYXRpb19DaGxhbXlkaWFfY2FzZXNfbWFsZS5zaCA8LSBtZXJnZShuYmRzLnNoLmRmLCBSYXRpb19DaGxhbXlkaWFfY2FzZXNfbWFsZSwgYnkgPSAiaWQiKQ0KYGBgDQpNYWtlIGFuZCBwbG90IGdyYXBoaWNzIG9iamVjdA0KYGBge3J9DQpwLlJhdGlvX0NobGFteWRpYV9jYXNlc19tYWxlIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBSYXRpb19DaGxhbXlkaWFfY2FzZXNfbWFsZS5zaCwgDQogICAgICAgICAgICAgICBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBSYXRpb19DaGxhbXlkaWFfY2FzZXNfbWFsZSksIA0KICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArIA0KICBjb29yZF9tYXAoKSArIA0KICBzY2FsZV9maWxsX2Rpc3RpbGxlcihuYW1lPSJDYXNlcy9wb3B1bGF0aW9uIiwgbGFiZWxzPXBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5PTEpLCBwYWxldHRlID0gIllsT3JCciIsIHRyYW5zID0gInJldmVyc2UiLCBicmVha3MgPSBwcmV0dHlfYnJlYWtzKG4gPSA4KSkgKyANCiAgdGhlbWVfbm90aGluZyhsZWdlbmQgPSBUUlVFKSArIA0KICBsYWJzKHRpdGxlPSJOdW1iZXIgb2YgbWFsZSBjaGxhbXlkaWEgY2FzZXMvbWFsZSBwb3B1bGF0aW9uIikgKw0KICBnZW9tX3RleHQoYWVzKHg9eCx5PXksIGdyb3VwPU5VTEwsIGxhYmVsPWlkKSwgZGF0YSA9IG5iZHMuc2guY2VudHJvaWRzLCBzaXplID0gMikNCg0KcC5SYXRpb19DaGxhbXlkaWFfY2FzZXNfbWFsZSArIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHJldmVyc2U9VFJVRSkpDQpgYGANCg0KIyBDb3JyZWxhdGlvbnMNCmBgYHtyfQ0KT0NIUFBfcmF0aW9zIDwtIG1lcmdlKG1lcmdlKHBhdGllbnRzX3JhdGlvcywgY2hyb25pY19yYXRpb3MpLCBjaGxhbXlkaWFfcmF0aW9zKQ0KYGBgDQpTdHJ1Y3R1cmUgb2YgZGF0YSB0YWJsZToNCmBgYHtyfQ0Kc3RyKE9DSFBQX3JhdGlvcykNCmBgYA0KRHJvcCAiaWQiIGNvbHVtbg0KYGBge3J9DQpPQ0hQUF9yYXRpb3Nfbm9pZCA8LSBPQ0hQUF9yYXRpb3NbLC1jKCJpZCIpXQ0KDQpzdHIoT0NIUFBfcmF0aW9zX25vaWQpDQpgYGANCg0KQ29tcHV0ZSBjb3JyZWxhdGlvbnMNCmBgYHtyfQ0KcmNvcnIoYXMubWF0cml4KE9DSFBQX3JhdGlvc19ub2lkKSwgdHlwZT0icGVhcnNvbiIpDQpgYGANCg0KIyMgTGluZWFyIHJlZ3Jlc3Npb24NCmBgYHtyfQ0KbG1fY2hsYW0gPC0gbG0oUmF0aW9fQ2hsYW15ZGlhX2Nhc2VzX21hbGUgfiBSYXRpb19DaGxhbXlkaWFfY2FzZXNfZmVtYWxlLCBkYXRhID0gT0NIUFBfcmF0aW9zX25vaWQpDQpzdW1tYXJ5KGxtX2NobGFtKQ0KYGBgDQoNCg0KYGBge3J9DQpwbG90KGxtX2NobGFtKQ0KYGBgDQoNCiMjIENob3JvcGxldGggb2YgcmVzaWR1YWxzIA0KDQpgYGB7cn0NCnN0cihsbV9jaGxhbSRyZXNpZHVhbHMpDQpgYGANCk1ha2UgZGF0YWZyYW1lIG9mIHJlc2lkdWFscyB3aXRoICJpZCIgY29sdW1uDQpgYGB7cn0NCmxtX2NobGFtX2RmIDwtIGRhdGEuZnJhbWUoaWQgPSBjKDE6MTQwKSwgcmVzaWR1YWwgPSBsbV9jaGxhbSRyZXNpZHVhbHMpDQpoZWFkKGxtX2NobGFtX2RmKQ0KYGBgDQoNCg0KYGBge3J9DQpsbV9jaGxhbV9kZi5zaCA8LSBtZXJnZShuYmRzLnNoLmRmLCBsbV9jaGxhbV9kZiwgYnkgPSAiaWQiKQ0KYGBgDQpNYWtlIGFuZCBwbG90IGdyYXBoaWNzIG9iamVjdA0KYGBge3J9DQpwLmxtX2NobGFtX2RmIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBsbV9jaGxhbV9kZi5zaCwgDQogICAgICAgICAgICAgICBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSByZXNpZHVhbCksIA0KICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArIA0KICBjb29yZF9tYXAoKSArIA0KICBzY2FsZV9maWxsX2Rpc3RpbGxlcihuYW1lPSJSZXNpZHVhbHMiLCBwYWxldHRlID0gIkJsdWVzIiwgdHJhbnMgPSAicmV2ZXJzZSIsIGJyZWFrcyA9IHByZXR0eV9icmVha3MobiA9IDgpKSArIA0KICB0aGVtZV9ub3RoaW5nKGxlZ2VuZCA9IFRSVUUpICsgDQogIGxhYnModGl0bGU9IlJlc2lkdWFscyBvZiBtYWxlIGNobGFteWRpYSBjYXNlcyB+IGZlbWFsZSBjaGxhbXlkaWEgY2FzZXMiKSArDQogIGdlb21fdGV4dChhZXMoeD14LHk9eSwgZ3JvdXA9TlVMTCwgbGFiZWw9aWQpLCBkYXRhID0gbmJkcy5zaC5jZW50cm9pZHMsIHNpemUgPSAyKQ0KDQpwLmxtX2NobGFtX2RmICsgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQocmV2ZXJzZT1UUlVFKSkNCmBgYA==