Required packages

library(readxl)
library(tidyr)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     

Attaching package: ‘tidyr’

The following object is masked _by_ ‘.GlobalEnv’:

    table1
library(dplyr)

Attaching package: ‘dplyr’

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

    filter, lag

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

    intersect, setdiff, setequal, union
library(stringr)
library(car)
Loading required package: carData
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     

Attaching package: ‘car’

The following object is masked from ‘package:dplyr’:

    recode
library(ggplot2)
library(rvest)
Loading required package: xml2

Executive Summary

The data in (.xls) files are not in a desirable state to be joined with any other dataset. Different steps are taken than advised in the notebook but, all the aspects of pre-processing are covered with just different order. Steps were taken for preprocessing:- 1-datasets loaded from Australian Marriage Law Postal Survey 2017 - Participation and subsetted for obtaining two parts LHS for federal divisions and RHS for age brackets. Response data is loaded and processed like a participant. 2-response and participant data are joined with electorates table fetched from the web for adding additional info on state and area of the federal division. 3-with trial and error it was observed before merging participant and response table removal of present NA values in the tables makes further processing easier. 4-Final dataset is created which contains merged participant, response and electorate tables. 5-Required data type conversions are done with the final table. 6-Outlier detection and decision on dealing with outliers are made.

Data describe all columns

The data was taken from Australian Marriage Law Postal Survey, 2017. Source->https://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/1800.02017?OpenDocument

Australian Marriage Law Postal Survey, 2017 was conducted by the Australian Bureau of Statistics. This survey tries to find out people’s views on legalizing same-sex marriage in Australia.

Two excel sheets are being used in the coming tasks:- 1->Australian Marriage Law Postal Survey 2017 - Participation

Australian Marriage Law Postal Survey 2017 - Participation contains information on participants, Distributed over different age bands. A further division by (State/federal division) and gender(male/female)are provided in different sheets.

In this particular script sheet 6 and sheet 7 are going to be used: sheet 6 contains male participants distributed over different age bands (RHS) and federal division(LHS).

sheet 7 contains female participants distributed over different age bands and federal divisions.

male sheet The image is the screenshot of sheet 6. Sheet 6 and 7 are identical in the arrangement.

2->Australian Marriage Law Postal Survey 2017 - Response

Australian Marriage Law Postal Survey 2017 - Response contains information on responses of various participants of the study.

In this analysis sheet, 3 of the data will be used from the Australian Marriage Law Postal Survey 2017 - Response the sheet contains responses of eligible participants and also contains info on non-responding participant and unclear responses over different federal divisions.

female sheet Importing Data Australian Marriage Law Postal Survey 2017 - Participation We are going to load sheet 6 and 7


data=read_excel("data.xls",sheet = 6)
New names:
* `` -> ...2
* `` -> ...3
* `` -> ...4
* `` -> ...5
* `` -> ...6
* … and 12 more problems
data_F=read_excel("data.xls",sheet = 7)
New names:
* `` -> ...2
* `` -> ...3
* `` -> ...4
* `` -> ...5
* `` -> ...6
* … and 12 more problems
head(data)
head(data_F)

a trim is going to be peformed to extract usefule table from the sheet preserving all information

#Breaking problem in 2 parts 

#partA contains federal divisions
partA = data%>%select(contains("Australian Bureau of Statistics"))%>%slice(7:650)
colnames(partA)="area"
#removing all the bold reference of state and only keeping federal division.
partA=partA%>%filter(str_detect(partA$area,pattern = "Divisions|Australia$",negate = TRUE))


#partB#####################################
#partB contains the age group table with all data points

partB = data%>%select(-c(1))%>%slice(5:649)%>%drop_na()

#specifying column name
cols=c("category",
  "18-19",
  "20-24",
  "25-29",
  "30-34",
  "35-39",
  "40-44",
  "45-49",
  "50-54",
  "55-59",
  "60-64",
  "65-69",
  "70-74",
  "75-79",
  "80-84",
  "> 85",
  "Total for Gender")
colnames(partB)=cols
#adding to add a column gender indicating sheet as male after merge with female sheet
#replicating area 3 times to match and fit the category 
#as category contains Total participants,Eligible participants,Participation rate (%) for each federal division
partB=partB%>%mutate(area = rep(partA$area, each=3) ,gender="Male")%>%filter(!grepl("Total", area))

head(partA)
head(partB)
NA

A similar operation will be performed on sheet 7

#part A####################################3

partA_F = data_F%>%select(contains("Australian Bureau of Statistics"))%>%slice(7:650)
colnames(partA_F)="area"
partA_F=partA_F%>%filter(str_detect(partA_F$area,pattern = "Divisions|Australia$",negate = TRUE))

#partB#####################################
partB_F = data_F%>%select(-c(1))%>%slice(5:649)%>%drop_na()

#specifying column name

colnames(partB_F)=cols#using cols from previous sheet specification

partB_F=partB_F%>%mutate(area = rep(partA_F$area, each=3) ,gender="Female")%>%filter(!grepl("Total", area))

head(partA_F)
head(partB_F)

An attempt is made to get the table wilth State with their federal divisions and respective area in sq.km

Here rvest package is used to extract the tables present at the following AEC(Australian Election Comission) which will be combined with participant and respondents table.

current_electorates <- 
  read_html("http://www.aec.gov.au/profiles/") %>%
  rvest::html_nodes("table") %>%
  rvest::html_table() %>%first()%>%select(`Electoral division`, State, `Area (sq km)`)


old_electorates <- 
  read_html("http://www.aec.gov.au/Electorates/abolished.htm") %>%
  rvest::html_nodes("table") %>%
  rvest::html_table() %>%
  first() %>%
  select(`Electoral division` = Division, State)

electorates <- bind_rows(current_electorates, old_electorates)

head(electorates)

One more import is necessary Now, response table of participant will be imported and similar operations like sheet 6 & 7 will be performed. #change name of col

############################################RESPONSE TABLE
response=read_excel("response.xls",sheet = 3)
New names:
* `` -> ...2
* `` -> ...3
* `` -> ...4
* `` -> ...5
* `` -> ...6
* … and 10 more problems
response=response%>%slice(8:182)

col_name = c( "area",
              "Yes",
              "Yes pct",
              "No",
              "No pct",
              "Response Total",
              "Response Total pct",
              "blank",
              "Response clear",
              "Response clear pct",
              "Response not clear(b)",
              "Response not clear(b) pct",
              "Non-responding",
              "Non-responding pct",
              "Eligible Total",
              "Eligible Total pct")


colnames(response)=col_name
response=response%>%select(-blank)%>%filter(!grepl("Total", area))%>%filter(!grepl("Total", area)) %>%drop_na()

Tidy & Manipulate Data I

The quesion we are asking here Is data in tidy format?

The data is not in tidy format. Reason:- age brackets are distributed over columns that directly violate tidy data rules. To make data a tidy df, a gather operation is to be performed to create a column with age brackets as different levels of columns.

partB=partB%>%gather(key="age_group", value = "count",-c("category","area","gender"))
partB_F=partB_F%>%gather(key="age_group", value = "count",-c("category","area","gender"))

head(partB)
dim(partB)
[1] 7200    5
head(partB_F)
dim(partB_F)
[1] 7200    5

Combining both df into one ALL_PARTB

ALL_PARTB=rbind(partB,partB_F)
dim(ALL_PARTB)
[1] 14400     5

Forming one final participant df (with state and area) ALL

ALL<- 
  ALL_PARTB %>%
  left_join(electorates, by = c("area" = "Electoral division"))
head(ALL)
dim(ALL)
[1] 14496     7

repeat the same steps for respondant

response_data <- 
  response%>%
  left_join(electorates, by = c("area" = "Electoral division"))
head(response_data)
dim(response_data)
[1] 151  17

Scan I

There are some inconsistencies present in data which if not handled at this point will engender problems in further analysis. Scanning tables for missing values for a neat join of all tables.

colSums(is.na(ALL))
    category         area       gender    age_group        count        State Area (sq km) 
           0            0            0            0            0          288         1056 

This suggest some error from the electorates table

colSums(is.na(electorates))
Electoral division              State       Area (sq km) 
                 0                  0                 64 

On close obserevation there are some duplicate values with different case settings.

#INVESTIGATION OF ELECTORAL PUSH POSSIBLE PROBLEMS

#some duplicate values were present
electorates=electorates%>%filter(!duplicated(electorates$`Electoral division`))

#vic and vic. problem
electorates$State=lapply(electorates$State,function(x)str_replace(x,pattern = "\\.",replacement = ""))

#converting to lower for uniform grouping
electorates$State=lapply(electorates$State,function(x)tolower(x))

NA’s are present in areas so to decide what to impute on NA’s for better data distribution of data is observed.

#checking the distribultion to decide replacement
x=electorates%>%filter(electorates$State=="vic")
x$`Area (sq km)`=as.numeric(x$`Area (sq km)`)
NAs introduced by coercion
x=x%>%filter(!is.na(x$`Area (sq km)`))
hist(x$`Area (sq km)`)#mean will under represent groups

boxplot(x$`Area (sq km)`)

The distributin is skewed so using mean to impute NA’s will not be a good decision. Group Median will be used to impute NA in the same group

#will use median

electorates$State=as.character(electorates$State)
electorates$State=as.factor(electorates$State)
electorates$`Area (sq km)`=as.integer(electorates$`Area (sq km)`)
NAs introduced by coercion
electorates=electorates %>% group_by(State) %>%
  mutate(`Area (sq km)`=ifelse(is.na(`Area (sq km)`),median(`Area (sq km)`,na.rm=TRUE),`Area (sq km)`))
colSums(is.na(electorates))
Electoral division              State       Area (sq km) 
                 0                  0                  0 

All NA’s are handled

Some inconsistency was found in area column which was cause of 288 NA values it is handled in next code block.

Join will be attempted again

ALL_PARTB$area[ALL_PARTB$area=="Lingiari(c)"]="Lingiari"
ALL_PARTB$area[ALL_PARTB$area=="Canberra(d)"]="Canberra"
ALL_PARTB$area[ALL_PARTB$area=="Fenner(e)"]="Fenner"

ALL<- 
  ALL_PARTB %>%
  left_join(electorates, by = c("area" = "Electoral division"))

same fore respondant

response$area[response$area=="Lingiari(c)"]="Lingiari"
response$area[response$area=="Canberra(d)"]="Canberra"
response$area[response$area=="Fenner(e)"]="Fenner"


response_data <- 
  response%>%
  left_join(electorates, by = c("area" = "Electoral division"))
colSums(is.na(ALL))
    category         area       gender    age_group        count        State Area (sq km) 
           0            0            0            0            0            0            0 
colSums(is.na(response_data))
                     area                       Yes                   Yes pct                        No 
                        0                         0                         0                         0 
                   No pct            Response Total        Response Total pct            Response clear 
                        0                         0                         0                         0 
       Response clear pct     Response not clear(b) Response not clear(b) pct            Non-responding 
                        0                         0                         0                         0 
       Non-responding pct            Eligible Total        Eligible Total pct                     State 
                        0                         0                         0                         0 
             Area (sq km) 
                        0 

It can be observed NA’s in all columns are eliminated

aa=left_join(ALL,response_data, by = "area")
aa=select(aa,-c(6,7))

Now, obvious incosistencies in the data needed to be checked for 1-Negative values are not possible in any numeric columns in our dataset.As Negative number of peope does not makes sense.

Incos_detect=function(x)
{
  re=which(x<0)
  re
}

test=aa[,c(5,6,7,8,9,10,11,12,14,15)]
lapply(test, function(x) Incos_detect(x))
$count
integer(0)

$Yes
integer(0)

$`Yes pct`
integer(0)

$No
integer(0)

$`No pct`
integer(0)

$`Response Total`
integer(0)

$`Response Total pct`
integer(0)

$`Response clear`
integer(0)

$`Response not clear(b)`
integer(0)

$`Response not clear(b) pct`
integer(0)

final data

head(aa)

Understand

Data types of the final table are explored and appropriate data type conversions are appled wherever is necessary.

glimpse(aa)
Observations: 14,400
Variables: 21
$ category                    <chr> "Total participants", "Eligible participants", "Participation rate (%)", …
$ area                        <chr> "Banks", "Banks", "Banks", "Barton", "Barton", "Barton", "Bennelong", "Be…
$ gender                      <chr> "Male", "Male", "Male", "Male", "Male", "Male", "Male", "Male", "Male", "…
$ age_group                   <chr> "18-19", "18-19", "18-19", "18-19", "18-19", "18-19", "18-19", "18-19", "…
$ count                       <chr> "1102", "1431", "77", "977", "1278", "76.400000000000006", "1177", "1488"…
$ Yes                         <chr> "37736", "37736", "37736", "37153", "37153", "37153", "42943", "42943", "…
$ `Yes pct`                   <chr> "44.899999999999999", "44.899999999999999", "44.899999999999999", "43.600…
$ No                          <chr> "46343", "46343", "46343", "47984", "47984", "47984", "43215", "43215", "…
$ `No pct`                    <chr> "55.100000000000001", "55.100000000000001", "55.100000000000001", "56.399…
$ `Response Total`            <chr> "84079", "84079", "84079", "85137", "85137", "85137", "86158", "86158", "…
$ `Response Total pct`        <chr> "100", "100", "100", "100", "100", "100", "100", "100", "100", "100", "10…
$ `Response clear`            <chr> "84079", "84079", "84079", "85137", "85137", "85137", "86158", "86158", "…
$ `Response clear pct`        <chr> "79.900000000000006", "79.900000000000006", "79.900000000000006", "77.799…
$ `Response not clear(b)`     <chr> "247", "247", "247", "226", "226", "226", "244", "244", "244", "212", "21…
$ `Response not clear(b) pct` <chr> "0.20000000000000001", "0.20000000000000001", "0.20000000000000001", "0.2…
$ `Non-responding`            <chr> "20928", "20928", "20928", "24008", "24008", "24008", "19973", "19973", "…
$ `Non-responding pct`        <chr> "19.899999999999999", "19.899999999999999", "19.899999999999999", "22", "…
$ `Eligible Total`            <chr> "105254", "105254", "105254", "109371", "109371", "109371", "106375", "10…
$ `Eligible Total pct`        <chr> "100", "100", "100", "100", "100", "100", "100", "100", "100", "100", "10…
$ State.y                     <fct> nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw…
$ `Area (sq km).y`            <dbl> 53, 53, 53, 40, 40, 40, 60, 60, 60, 786, 786, 786, 61, 61, 61, 101, 101, …

almost all the numeric values are character type and some factor varibles are also char.

Converting to appropriate types. instead of changing all the char to dbl one by one clubbing of all the columns are performed and converted to dbl.

aa$area=as.factor(aa$area)
aa$age_group=factor(aa$age_group, levels = cols,
               ordered = TRUE)
aa$gender=as.factor(aa$gender)
aa$State.y=as.factor(aa$State.y)
aa$`Area (sq km).y`=as.numeric(aa$`Area (sq km).y`)
#clubbing of supposedly dbl which are char
names=colnames(aa)
names=names[5:19]
aa[,names] = apply(aa[,names], 2, function(x) as.numeric(as.character(x)))

glimpse(aa)
Observations: 14,400
Variables: 21
$ category                    <chr> "Total participants", "Eligible participants", "Participation rate (%)", …
$ area                        <fct> Banks, Banks, Banks, Barton, Barton, Barton, Bennelong, Bennelong, Bennel…
$ gender                      <fct> Male, Male, Male, Male, Male, Male, Male, Male, Male, Male, Male, Male, M…
$ age_group                   <ord> 18-19, 18-19, 18-19, 18-19, 18-19, 18-19, 18-19, 18-19, 18-19, 18-19, 18-…
$ count                       <dbl> 1102.0, 1431.0, 77.0, 977.0, 1278.0, 76.4, 1177.0, 1488.0, 79.1, 1523.0, …
$ Yes                         <dbl> 37736, 37736, 37736, 37153, 37153, 37153, 42943, 42943, 42943, 48471, 484…
$ `Yes pct`                   <dbl> 44.9, 44.9, 44.9, 43.6, 43.6, 43.6, 49.8, 49.8, 49.8, 54.6, 54.6, 54.6, 2…
$ No                          <dbl> 46343, 46343, 46343, 47984, 47984, 47984, 43215, 43215, 43215, 40369, 403…
$ `No pct`                    <dbl> 55.1, 55.1, 55.1, 56.4, 56.4, 56.4, 50.2, 50.2, 50.2, 45.4, 45.4, 45.4, 7…
$ `Response Total`            <dbl> 84079, 84079, 84079, 85137, 85137, 85137, 86158, 86158, 86158, 88840, 888…
$ `Response Total pct`        <dbl> 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100…
$ `Response clear`            <dbl> 84079, 84079, 84079, 85137, 85137, 85137, 86158, 86158, 86158, 88840, 888…
$ `Response clear pct`        <dbl> 79.9, 79.9, 79.9, 77.8, 77.8, 77.8, 81.0, 81.0, 81.0, 84.5, 84.5, 84.5, 7…
$ `Response not clear(b)`     <dbl> 247, 247, 247, 226, 226, 226, 244, 244, 244, 212, 212, 212, 220, 220, 220…
$ `Response not clear(b) pct` <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2…
$ `Non-responding`            <dbl> 20928, 20928, 20928, 24008, 24008, 24008, 19973, 19973, 19973, 16038, 160…
$ `Non-responding pct`        <dbl> 19.9, 19.9, 19.9, 22.0, 22.0, 22.0, 18.8, 18.8, 18.8, 15.3, 15.3, 15.3, 2…
$ `Eligible Total`            <dbl> 105254, 105254, 105254, 109371, 109371, 109371, 106375, 106375, 106375, 1…
$ `Eligible Total pct`        <dbl> 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100…
$ State.y                     <fct> nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw, nsw…
$ `Area (sq km).y`            <dbl> 53, 53, 53, 40, 40, 40, 60, 60, 60, 786, 786, 786, 61, 61, 61, 101, 101, …

All the columns are in appropriate data format. With age group as a ordered factor.

Tidy & Manipulate Data II

In this step, all the unnecessary columns of percentage will be removed as they possess only redundant information and can be calculated at any time using mutate function.

#removing percentages
aa=aa%>%select(-c(7,9,11,13,15,17,19))

only after successful NA removal and fixing the data type it was possible to create a varible.

The fabricated column will contain total elegible participant per sq.km of Area

aa=aa%>%mutate(eligible_part_Per_sq.km=`Eligible Total`/`Area (sq km).y`)

Scan II

In this section an analysis for outliers on all the numeric columns is performed. As seen in the previous parts the distribution of the data is not normal so boxplots are used for detecting outliers.

m=aa[,5:15]
ggplot(stack(m), aes(x = ind, y = values))+geom_boxplot()
non-vector columns will be ignored

The scale of y axis is not appropriate for comparision of boxplot with other boxplots. To enable us to compare boxplots a scale shift of y axis might help.

ggplot(stack(m), aes(x = ind, y = values)) +scale_y_log10()+geom_boxplot()
non-vector columns will be ignored

A clear presence of outliers can be seen in almost every column. In further steps, an attempt for the treatment of outliers will be made.

The outliers per function are created to compute the percentage of outlier present in the particular column. This step is necessary as a high percentage of outliers >5% will make us consider other options other than elimination.


outliersper <- function(x){
  length(which(x >  mean(x) + 3 * sd(x) | x < mean(x) - 3 * sd(x))  ) / length(x)
}

out=aa[,c(5,6,7,8,9,10,11,12,14,15)]
out_count=lapply(out, function(x) outliersper(x))
out_count
$count
[1] 0.04083333

$Yes
[1] 0.006666667

$No
[1] 0.006666667

$`Response Total`
[1] 0.02666667

$`Response clear`
[1] 0.02666667

$`Response not clear(b)`
[1] 0

$`Non-responding`
[1] 0.01333333

$`Eligible Total`
[1] 0.04666667

$`Area (sq km).y`
[1] 0.04666667

$eligible_part_Per_sq.km
[1] 0.01333333

It can be observed that all columns are having an outlier percentage <5% with maximum outlier in Area (sq km).yandEligible Total` followed by count.

The fuction outlier_remov when applied to a column keeps only the data which are not outliers according to Tukays Method of outlier detection

outlier_remov=  function(x){
  aa=aa%>%filter((x <  mean(x) + 1.5 * sd(x) & x > mean(x) - 1.5 * sd(x))) 
  aa
}
#dimention of df before removal of outliers
dim(aa)
[1] 14400    15
after_removal=outlier_remov(aa$count)
dim(after_removal)
[1] 13801    15

all the rows with values outside of the range of Q1-1.5 x IQR to Q3+1.5 x IQR are removed.

boxplot(after_removal$count)

OBSERVATION Even after removing the outliers it can be observed that the outliers of the count column are still present as new outliers are introduced due to the removal of the old one which changed the quartile values.

DECISION FOR OUTLIERS The values of columns are interdependent and removal of outliers is not going to give us any positive effect in cleaning the data.

-One possible reason for many outliers can be outlier observations of the area of the federal district. As a very small or very large area will have extreme stats, for example, a very large federal division will have several participants.

-A decision was made against the removal of outliers or imputation of outliers with mean, median or capping them to the nearest quantile value as any of these will disturb the data and the results from any statistical test done on data will not be reliable.

-If in any case removal of outliers is a must. NA’s can be introduced in the place of outliers. Such a move will keep the original distribution of data.

Discussion Various different analysis is possible from the dataset: -t-test with male and female participant counts. -see if age bracket makes difference, 3 categories (young,mid age,old) can be use to bracket all age groups and then ANOVA test can be use to see if any varience exist across the groups. -regression might be possible area of place and no. of participant as a line(make graph) is there

#TRANSFORM This step is to transform the it could be used for further analysis.

library(forecast)
Registered S3 method overwritten by 'xts':
  method     from
  as.zoo.xts zoo 
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
Registered S3 methods overwritten by 'forecast':
  method             from    
  fitted.fracdiff    fracdiff
  residuals.fracdiff fracdiff
hist(aa$`Area (sq km).y`)

transformed=BoxCox(aa$`Area (sq km).y`,lambda = "auto")
hist(transformed)



LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXMsIDIwMTkiCmF1dGhvcjogIkF5dXNoIFJhbmphbiAtIFMzODAyNTQxIgpzdWJ0aXRsZTogQXNzaWdubWVudCAzCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCgojIyBSZXF1aXJlZCBwYWNrYWdlcyAKCgpgYGB7cn0KbGlicmFyeShyZWFkeGwpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShjYXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShydmVzdCkKYGBgCgoKIyMgRXhlY3V0aXZlIFN1bW1hcnkgCgoKVGhlIGRhdGEgaW4gKC54bHMpIGZpbGVzIGFyZSBub3QgaW4gYSBkZXNpcmFibGUgc3RhdGUgdG8gYmUgam9pbmVkIHdpdGggYW55IG90aGVyIGRhdGFzZXQuIERpZmZlcmVudCBzdGVwcyBhcmUgdGFrZW4gdGhhbiBhZHZpc2VkIGluIHRoZSBub3RlYm9vayBidXQsIGFsbCB0aGUgYXNwZWN0cyBvZiBwcmUtcHJvY2Vzc2luZyBhcmUgY292ZXJlZCB3aXRoIGp1c3QgZGlmZmVyZW50IG9yZGVyLgpTdGVwcyB3ZXJlIHRha2VuIGZvciBwcmVwcm9jZXNzaW5nOi0KMS1kYXRhc2V0cyBsb2FkZWQgZnJvbSBBdXN0cmFsaWFuIE1hcnJpYWdlIExhdyBQb3N0YWwgU3VydmV5IDIwMTcgLSBQYXJ0aWNpcGF0aW9uIGFuZCBzdWJzZXR0ZWQgZm9yIG9idGFpbmluZyB0d28gcGFydHMgTEhTIGZvciBmZWRlcmFsIGRpdmlzaW9ucyBhbmQgUkhTIGZvciBhZ2UgYnJhY2tldHMuIFJlc3BvbnNlIGRhdGEgaXMgbG9hZGVkIGFuZCBwcm9jZXNzZWQgbGlrZSBhIHBhcnRpY2lwYW50LgoyLXJlc3BvbnNlIGFuZCBwYXJ0aWNpcGFudCBkYXRhIGFyZSBqb2luZWQgd2l0aCBlbGVjdG9yYXRlcyB0YWJsZSBmZXRjaGVkIGZyb20gdGhlIHdlYiBmb3IgYWRkaW5nIGFkZGl0aW9uYWwgaW5mbyBvbiBzdGF0ZSBhbmQgYXJlYSBvZiB0aGUgZmVkZXJhbCBkaXZpc2lvbi4KMy13aXRoIHRyaWFsIGFuZCBlcnJvciBpdCB3YXMgb2JzZXJ2ZWQgYmVmb3JlIG1lcmdpbmcgcGFydGljaXBhbnQgYW5kIHJlc3BvbnNlIHRhYmxlIHJlbW92YWwgb2YgcHJlc2VudCBOQSB2YWx1ZXMgaW4gdGhlIHRhYmxlcyBtYWtlcyBmdXJ0aGVyIHByb2Nlc3NpbmcgZWFzaWVyLgo0LUZpbmFsIGRhdGFzZXQgaXMgY3JlYXRlZCB3aGljaCBjb250YWlucyBtZXJnZWQgcGFydGljaXBhbnQsIHJlc3BvbnNlIGFuZCBlbGVjdG9yYXRlIHRhYmxlcy4KNS1SZXF1aXJlZCBkYXRhIHR5cGUgY29udmVyc2lvbnMgYXJlIGRvbmUgd2l0aCB0aGUgZmluYWwgdGFibGUuCjYtT3V0bGllciBkZXRlY3Rpb24gYW5kIGRlY2lzaW9uIG9uIGRlYWxpbmcgd2l0aCBvdXRsaWVycyBhcmUgbWFkZS4KCgojIyBEYXRhIGRlc2NyaWJlIGFsbCBjb2x1bW5zClRoZSBkYXRhIHdhcyB0YWtlbiBmcm9tICAqKkF1c3RyYWxpYW4gTWFycmlhZ2UgTGF3IFBvc3RhbCBTdXJ2ZXksIDIwMTcqKi4KKipTb3VyY2UqKi0+aHR0cHM6Ly93d3cuYWJzLmdvdi5hdS9BVVNTVEFUUy9hYnNALm5zZi9EZXRhaWxzUGFnZS8xODAwLjAyMDE3P09wZW5Eb2N1bWVudAoKQXVzdHJhbGlhbiBNYXJyaWFnZSBMYXcgUG9zdGFsIFN1cnZleSwgMjAxNyAgd2FzIGNvbmR1Y3RlZCBieSB0aGUgQXVzdHJhbGlhbiBCdXJlYXUgb2YgU3RhdGlzdGljcy4gVGhpcyBzdXJ2ZXkgdHJpZXMgdG8gZmluZCBvdXQgcGVvcGxlJ3Mgdmlld3Mgb24gbGVnYWxpemluZyBzYW1lLXNleCBtYXJyaWFnZSBpbiBBdXN0cmFsaWEuCgpUd28gZXhjZWwgc2hlZXRzIGFyZSBiZWluZyB1c2VkIGluIHRoZSBjb21pbmcgdGFza3M6LQoxLT5BdXN0cmFsaWFuIE1hcnJpYWdlIExhdyBQb3N0YWwgU3VydmV5IDIwMTcgLSBQYXJ0aWNpcGF0aW9uIAoKKipBdXN0cmFsaWFuIE1hcnJpYWdlIExhdyBQb3N0YWwgU3VydmV5IDIwMTcgLSBQYXJ0aWNpcGF0aW9uKiogY29udGFpbnMgaW5mb3JtYXRpb24gb24gcGFydGljaXBhbnRzLCBEaXN0cmlidXRlZCBvdmVyIGRpZmZlcmVudCBhZ2UgYmFuZHMuIEEgZnVydGhlciBkaXZpc2lvbiBieSAoU3RhdGUvZmVkZXJhbCBkaXZpc2lvbikgYW5kIGdlbmRlcihtYWxlL2ZlbWFsZSlhcmUgcHJvdmlkZWQgaW4gZGlmZmVyZW50IHNoZWV0cy4gCgpJbiB0aGlzIHBhcnRpY3VsYXIgc2NyaXB0IHNoZWV0IDYgYW5kIHNoZWV0IDcgYXJlIGdvaW5nIHRvIGJlIHVzZWQ6CnNoZWV0IDYgY29udGFpbnMgbWFsZSBwYXJ0aWNpcGFudHMgZGlzdHJpYnV0ZWQgb3ZlciBkaWZmZXJlbnQgYWdlIGJhbmRzIChSSFMpIGFuZCBmZWRlcmFsIGRpdmlzaW9uKExIUykuCgpzaGVldCA3IGNvbnRhaW5zIGZlbWFsZSBwYXJ0aWNpcGFudHMgZGlzdHJpYnV0ZWQgb3ZlciBkaWZmZXJlbnQgYWdlIGJhbmRzIGFuZCBmZWRlcmFsIGRpdmlzaW9ucy4KCiFbbWFsZSBzaGVldF0oMS5wbmcpClRoZSBpbWFnZSBpcyB0aGUgc2NyZWVuc2hvdCBvZiBzaGVldCA2LgpTaGVldCA2IGFuZCA3IGFyZSBpZGVudGljYWwgaW4gdGhlIGFycmFuZ2VtZW50LgoKMi0+QXVzdHJhbGlhbiBNYXJyaWFnZSBMYXcgUG9zdGFsIFN1cnZleSAyMDE3IC0gUmVzcG9uc2UKCioqQXVzdHJhbGlhbiBNYXJyaWFnZSBMYXcgUG9zdGFsIFN1cnZleSAyMDE3IC0gUmVzcG9uc2UqKiBjb250YWlucyBpbmZvcm1hdGlvbiBvbiByZXNwb25zZXMgb2YgdmFyaW91cyBwYXJ0aWNpcGFudHMgb2YgdGhlIHN0dWR5LgoKSW4gdGhpcyBhbmFseXNpcyBzaGVldCwgMyBvZiB0aGUgZGF0YSB3aWxsIGJlIHVzZWQgZnJvbSB0aGUgQXVzdHJhbGlhbiBNYXJyaWFnZSBMYXcgUG9zdGFsIFN1cnZleSAyMDE3IC0gUmVzcG9uc2UKdGhlIHNoZWV0IGNvbnRhaW5zIHJlc3BvbnNlcyBvZiBlbGlnaWJsZSBwYXJ0aWNpcGFudHMgYW5kIGFsc28gY29udGFpbnMgaW5mbyBvbiBub24tcmVzcG9uZGluZyBwYXJ0aWNpcGFudCBhbmQgdW5jbGVhciByZXNwb25zZXMgb3ZlciBkaWZmZXJlbnQgZmVkZXJhbCBkaXZpc2lvbnMuICAKCiFbZmVtYWxlIHNoZWV0XSgyLnBuZykKKkltcG9ydGluZyBEYXRhKgpBdXN0cmFsaWFuIE1hcnJpYWdlIExhdyBQb3N0YWwgU3VydmV5IDIwMTcgLSBQYXJ0aWNpcGF0aW9uCldlIGFyZSBnb2luZyB0byBsb2FkIHNoZWV0IDYgYW5kIDcKYGBge3J9CgpkYXRhPXJlYWRfZXhjZWwoImRhdGEueGxzIixzaGVldCA9IDYpCmRhdGFfRj1yZWFkX2V4Y2VsKCJkYXRhLnhscyIsc2hlZXQgPSA3KQoKaGVhZChkYXRhKQpoZWFkKGRhdGFfRikKYGBgCmEgdHJpbSBpcyBnb2luZyB0byBiZSBwZWZvcm1lZCB0byBleHRyYWN0IHVzZWZ1bGUgdGFibGUgZnJvbSB0aGUgc2hlZXQgcHJlc2VydmluZyBhbGwgaW5mb3JtYXRpb24KCmBgYHtyfQojQnJlYWtpbmcgcHJvYmxlbSBpbiAyIHBhcnRzIAoKI3BhcnRBIGNvbnRhaW5zIGZlZGVyYWwgZGl2aXNpb25zCnBhcnRBID0gZGF0YSU+JXNlbGVjdChjb250YWlucygiQXVzdHJhbGlhbiBCdXJlYXUgb2YgU3RhdGlzdGljcyIpKSU+JXNsaWNlKDc6NjUwKQpjb2xuYW1lcyhwYXJ0QSk9ImFyZWEiCiNyZW1vdmluZyBhbGwgdGhlIGJvbGQgcmVmZXJlbmNlIG9mIHN0YXRlIGFuZCBvbmx5IGtlZXBpbmcgZmVkZXJhbCBkaXZpc2lvbi4KcGFydEE9cGFydEElPiVmaWx0ZXIoc3RyX2RldGVjdChwYXJ0QSRhcmVhLHBhdHRlcm4gPSAiRGl2aXNpb25zfEF1c3RyYWxpYSQiLG5lZ2F0ZSA9IFRSVUUpKQoKCiNwYXJ0QiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKI3BhcnRCIGNvbnRhaW5zIHRoZSBhZ2UgZ3JvdXAgdGFibGUgd2l0aCBhbGwgZGF0YSBwb2ludHMKCnBhcnRCID0gZGF0YSU+JXNlbGVjdCgtYygxKSklPiVzbGljZSg1OjY0OSklPiVkcm9wX25hKCkKCiNzcGVjaWZ5aW5nIGNvbHVtbiBuYW1lCmNvbHM9YygiY2F0ZWdvcnkiLAogICIxOC0xOSIsCiAgIjIwLTI0IiwKICAiMjUtMjkiLAogICIzMC0zNCIsCiAgIjM1LTM5IiwKICAiNDAtNDQiLAogICI0NS00OSIsCiAgIjUwLTU0IiwKICAiNTUtNTkiLAogICI2MC02NCIsCiAgIjY1LTY5IiwKICAiNzAtNzQiLAogICI3NS03OSIsCiAgIjgwLTg0IiwKICAiPiA4NSIsCiAgIlRvdGFsIGZvciBHZW5kZXIiKQpjb2xuYW1lcyhwYXJ0Qik9Y29scwojYWRkaW5nIHRvIGFkZCBhIGNvbHVtbiBnZW5kZXIgaW5kaWNhdGluZyBzaGVldCBhcyBtYWxlIGFmdGVyIG1lcmdlIHdpdGggZmVtYWxlIHNoZWV0CiNyZXBsaWNhdGluZyBhcmVhIDMgdGltZXMgdG8gbWF0Y2ggYW5kIGZpdCB0aGUgY2F0ZWdvcnkgCiNhcyBjYXRlZ29yeSBjb250YWlucyBUb3RhbCBwYXJ0aWNpcGFudHMsRWxpZ2libGUgcGFydGljaXBhbnRzLFBhcnRpY2lwYXRpb24gcmF0ZSAoJSkgZm9yIGVhY2ggZmVkZXJhbCBkaXZpc2lvbgpwYXJ0Qj1wYXJ0QiU+JW11dGF0ZShhcmVhID0gcmVwKHBhcnRBJGFyZWEsIGVhY2g9MykgLGdlbmRlcj0iTWFsZSIpJT4lZmlsdGVyKCFncmVwbCgiVG90YWwiLCBhcmVhKSkKCmhlYWQocGFydEEpCmhlYWQocGFydEIpCgpgYGAKCkEgc2ltaWxhciBvcGVyYXRpb24gd2lsbCBiZSBwZXJmb3JtZWQgb24gc2hlZXQgNwpgYGB7cn0KI3BhcnQgQSMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIzMKCnBhcnRBX0YgPSBkYXRhX0YlPiVzZWxlY3QoY29udGFpbnMoIkF1c3RyYWxpYW4gQnVyZWF1IG9mIFN0YXRpc3RpY3MiKSklPiVzbGljZSg3OjY1MCkKY29sbmFtZXMocGFydEFfRik9ImFyZWEiCnBhcnRBX0Y9cGFydEFfRiU+JWZpbHRlcihzdHJfZGV0ZWN0KHBhcnRBX0YkYXJlYSxwYXR0ZXJuID0gIkRpdmlzaW9uc3xBdXN0cmFsaWEkIixuZWdhdGUgPSBUUlVFKSkKCiNwYXJ0QiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKcGFydEJfRiA9IGRhdGFfRiU+JXNlbGVjdCgtYygxKSklPiVzbGljZSg1OjY0OSklPiVkcm9wX25hKCkKCiNzcGVjaWZ5aW5nIGNvbHVtbiBuYW1lCgpjb2xuYW1lcyhwYXJ0Ql9GKT1jb2xzI3VzaW5nIGNvbHMgZnJvbSBwcmV2aW91cyBzaGVldCBzcGVjaWZpY2F0aW9uCgpwYXJ0Ql9GPXBhcnRCX0YlPiVtdXRhdGUoYXJlYSA9IHJlcChwYXJ0QV9GJGFyZWEsIGVhY2g9MykgLGdlbmRlcj0iRmVtYWxlIiklPiVmaWx0ZXIoIWdyZXBsKCJUb3RhbCIsIGFyZWEpKQoKaGVhZChwYXJ0QV9GKQpoZWFkKHBhcnRCX0YpCmBgYApBbiBhdHRlbXB0IGlzIG1hZGUgdG8gZ2V0IHRoZSB0YWJsZSB3aWx0aCBTdGF0ZSB3aXRoIHRoZWlyIGZlZGVyYWwgZGl2aXNpb25zIGFuZCByZXNwZWN0aXZlIGFyZWEgaW4gc3Eua20KCkhlcmUgcnZlc3QgcGFja2FnZSBpcyB1c2VkIHRvIGV4dHJhY3QgdGhlIHRhYmxlcyBwcmVzZW50IGF0IHRoZSBmb2xsb3dpbmcgQUVDKEF1c3RyYWxpYW4gRWxlY3Rpb24gQ29taXNzaW9uKSB3aGljaCB3aWxsIGJlIGNvbWJpbmVkIHdpdGggcGFydGljaXBhbnQgYW5kIHJlc3BvbmRlbnRzIHRhYmxlLgoKYGBge3J9CmN1cnJlbnRfZWxlY3RvcmF0ZXMgPC0gCiAgcmVhZF9odG1sKCJodHRwOi8vd3d3LmFlYy5nb3YuYXUvcHJvZmlsZXMvIikgJT4lCiAgcnZlc3Q6Omh0bWxfbm9kZXMoInRhYmxlIikgJT4lCiAgcnZlc3Q6Omh0bWxfdGFibGUoKSAlPiVmaXJzdCgpJT4lc2VsZWN0KGBFbGVjdG9yYWwgZGl2aXNpb25gLCBTdGF0ZSwgYEFyZWEgKHNxIGttKWApCgoKb2xkX2VsZWN0b3JhdGVzIDwtIAogIHJlYWRfaHRtbCgiaHR0cDovL3d3dy5hZWMuZ292LmF1L0VsZWN0b3JhdGVzL2Fib2xpc2hlZC5odG0iKSAlPiUKICBydmVzdDo6aHRtbF9ub2RlcygidGFibGUiKSAlPiUKICBydmVzdDo6aHRtbF90YWJsZSgpICU+JQogIGZpcnN0KCkgJT4lCiAgc2VsZWN0KGBFbGVjdG9yYWwgZGl2aXNpb25gID0gRGl2aXNpb24sIFN0YXRlKQoKZWxlY3RvcmF0ZXMgPC0gYmluZF9yb3dzKGN1cnJlbnRfZWxlY3RvcmF0ZXMsIG9sZF9lbGVjdG9yYXRlcykKCmhlYWQoZWxlY3RvcmF0ZXMpCmBgYApPbmUgbW9yZSBpbXBvcnQgaXMgbmVjZXNzYXJ5IApOb3csIHJlc3BvbnNlIHRhYmxlIG9mIHBhcnRpY2lwYW50IHdpbGwgYmUgaW1wb3J0ZWQgYW5kIHNpbWlsYXIgb3BlcmF0aW9ucyBsaWtlIHNoZWV0IDYgJiA3IHdpbGwgYmUgcGVyZm9ybWVkLgojY2hhbmdlIG5hbWUgb2YgY29sCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI1JFU1BPTlNFIFRBQkxFCnJlc3BvbnNlPXJlYWRfZXhjZWwoInJlc3BvbnNlLnhscyIsc2hlZXQgPSAzKQpyZXNwb25zZT1yZXNwb25zZSU+JXNsaWNlKDg6MTgyKQoKY29sX25hbWUgPSBjKCAiYXJlYSIsCiAgICAgICAgICAgICAgIlllcyIsCiAgICAgICAgICAgICAgIlllcyBwY3QiLAogICAgICAgICAgICAgICJObyIsCiAgICAgICAgICAgICAgIk5vIHBjdCIsCiAgICAgICAgICAgICAgIlJlc3BvbnNlIFRvdGFsIiwKICAgICAgICAgICAgICAiUmVzcG9uc2UgVG90YWwgcGN0IiwKICAgICAgICAgICAgICAiYmxhbmsiLAogICAgICAgICAgICAgICJSZXNwb25zZSBjbGVhciIsCiAgICAgICAgICAgICAgIlJlc3BvbnNlIGNsZWFyIHBjdCIsCiAgICAgICAgICAgICAgIlJlc3BvbnNlIG5vdCBjbGVhcihiKSIsCiAgICAgICAgICAgICAgIlJlc3BvbnNlIG5vdCBjbGVhcihiKSBwY3QiLAogICAgICAgICAgICAgICJOb24tcmVzcG9uZGluZyIsCiAgICAgICAgICAgICAgIk5vbi1yZXNwb25kaW5nIHBjdCIsCiAgICAgICAgICAgICAgIkVsaWdpYmxlIFRvdGFsIiwKICAgICAgICAgICAgICAiRWxpZ2libGUgVG90YWwgcGN0IikKCgpjb2xuYW1lcyhyZXNwb25zZSk9Y29sX25hbWUKcmVzcG9uc2U9cmVzcG9uc2UlPiVzZWxlY3QoLWJsYW5rKSU+JWZpbHRlcighZ3JlcGwoIlRvdGFsIiwgYXJlYSkpJT4lZmlsdGVyKCFncmVwbCgiVG90YWwiLCBhcmVhKSkgJT4lZHJvcF9uYSgpCmBgYAoKIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIApUaGUgcXVlc2lvbiB3ZSBhcmUgYXNraW5nIGhlcmUgKipJcyBkYXRhIGluIHRpZHkgZm9ybWF0PyoqCgpUaGUgZGF0YSBpcyBub3QgaW4gdGlkeSBmb3JtYXQuClJlYXNvbjotIGFnZSBicmFja2V0cyBhcmUgZGlzdHJpYnV0ZWQgb3ZlciBjb2x1bW5zIHRoYXQgZGlyZWN0bHkgdmlvbGF0ZSB0aWR5IGRhdGEgcnVsZXMuIFRvIG1ha2UgZGF0YSBhIHRpZHkgZGYsIGEgZ2F0aGVyIG9wZXJhdGlvbiBpcyB0byBiZSBwZXJmb3JtZWQgdG8gY3JlYXRlIGEgY29sdW1uIHdpdGggYWdlIGJyYWNrZXRzIGFzIGRpZmZlcmVudCBsZXZlbHMgb2YgY29sdW1ucy4KCmBgYHtyfQpwYXJ0Qj1wYXJ0QiU+JWdhdGhlcihrZXk9ImFnZV9ncm91cCIsIHZhbHVlID0gImNvdW50IiwtYygiY2F0ZWdvcnkiLCJhcmVhIiwiZ2VuZGVyIikpCnBhcnRCX0Y9cGFydEJfRiU+JWdhdGhlcihrZXk9ImFnZV9ncm91cCIsIHZhbHVlID0gImNvdW50IiwtYygiY2F0ZWdvcnkiLCJhcmVhIiwiZ2VuZGVyIikpCgpoZWFkKHBhcnRCKQpkaW0ocGFydEIpCmhlYWQocGFydEJfRikKZGltKHBhcnRCX0YpCmBgYApDb21iaW5pbmcgYm90aCBkZiBpbnRvIG9uZSBBTExfUEFSVEIKYGBge3J9CkFMTF9QQVJUQj1yYmluZChwYXJ0QixwYXJ0Ql9GKQpkaW0oQUxMX1BBUlRCKQpgYGAKRm9ybWluZyBvbmUgZmluYWwgcGFydGljaXBhbnQgZGYgKHdpdGggc3RhdGUgYW5kIGFyZWEpIEFMTApgYGB7cn0KQUxMPC0gCiAgQUxMX1BBUlRCICU+JQogIGxlZnRfam9pbihlbGVjdG9yYXRlcywgYnkgPSBjKCJhcmVhIiA9ICJFbGVjdG9yYWwgZGl2aXNpb24iKSkKaGVhZChBTEwpCmRpbShBTEwpCmBgYApyZXBlYXQgdGhlIHNhbWUgc3RlcHMgZm9yIHJlc3BvbmRhbnQKYGBge3J9CnJlc3BvbnNlX2RhdGEgPC0gCiAgcmVzcG9uc2UlPiUKICBsZWZ0X2pvaW4oZWxlY3RvcmF0ZXMsIGJ5ID0gYygiYXJlYSIgPSAiRWxlY3RvcmFsIGRpdmlzaW9uIikpCmhlYWQocmVzcG9uc2VfZGF0YSkKZGltKHJlc3BvbnNlX2RhdGEpCmBgYAojIwlTY2FuIEkgCgpUaGVyZSBhcmUgc29tZSBpbmNvbnNpc3RlbmNpZXMgcHJlc2VudCBpbiBkYXRhIHdoaWNoIGlmIG5vdCBoYW5kbGVkIGF0IHRoaXMgcG9pbnQgd2lsbCBlbmdlbmRlciBwcm9ibGVtcyBpbiBmdXJ0aGVyIGFuYWx5c2lzLgpTY2FubmluZyB0YWJsZXMgZm9yIG1pc3NpbmcgdmFsdWVzIGZvciBhIG5lYXQgam9pbiBvZiBhbGwgdGFibGVzLgoKYGBge3J9CmNvbFN1bXMoaXMubmEoQUxMKSkKYGBgClRoaXMgc3VnZ2VzdCBzb21lIGVycm9yIGZyb20gdGhlIGVsZWN0b3JhdGVzIHRhYmxlCmBgYHtyfQpjb2xTdW1zKGlzLm5hKGVsZWN0b3JhdGVzKSkKYGBgCk9uIGNsb3NlIG9ic2VyZXZhdGlvbiB0aGVyZSBhcmUgc29tZSBkdXBsaWNhdGUgdmFsdWVzIHdpdGggZGlmZmVyZW50IGNhc2Ugc2V0dGluZ3MuCmBgYHtyfQojSU5WRVNUSUdBVElPTiBPRiBFTEVDVE9SQUwgUFVTSCBQT1NTSUJMRSBQUk9CTEVNUwoKI3NvbWUgZHVwbGljYXRlIHZhbHVlcyB3ZXJlIHByZXNlbnQKZWxlY3RvcmF0ZXM9ZWxlY3RvcmF0ZXMlPiVmaWx0ZXIoIWR1cGxpY2F0ZWQoZWxlY3RvcmF0ZXMkYEVsZWN0b3JhbCBkaXZpc2lvbmApKQoKI3ZpYyBhbmQgdmljLiBwcm9ibGVtCmVsZWN0b3JhdGVzJFN0YXRlPWxhcHBseShlbGVjdG9yYXRlcyRTdGF0ZSxmdW5jdGlvbih4KXN0cl9yZXBsYWNlKHgscGF0dGVybiA9ICJcXC4iLHJlcGxhY2VtZW50ID0gIiIpKQoKI2NvbnZlcnRpbmcgdG8gbG93ZXIgZm9yIHVuaWZvcm0gZ3JvdXBpbmcKZWxlY3RvcmF0ZXMkU3RhdGU9bGFwcGx5KGVsZWN0b3JhdGVzJFN0YXRlLGZ1bmN0aW9uKHgpdG9sb3dlcih4KSkKYGBgCk5BJ3MgYXJlIHByZXNlbnQgaW4gYXJlYXMgc28gdG8gZGVjaWRlIHdoYXQgdG8gaW1wdXRlIG9uIE5BJ3MgZm9yIGJldHRlciBkYXRhIGRpc3RyaWJ1dGlvbiBvZiBkYXRhIGlzIG9ic2VydmVkLgpgYGB7cn0KI2NoZWNraW5nIHRoZSBkaXN0cmlidWx0aW9uIHRvIGRlY2lkZSByZXBsYWNlbWVudAp4PWVsZWN0b3JhdGVzJT4lZmlsdGVyKGVsZWN0b3JhdGVzJFN0YXRlPT0idmljIikKeCRgQXJlYSAoc3Ega20pYD1hcy5udW1lcmljKHgkYEFyZWEgKHNxIGttKWApCng9eCU+JWZpbHRlcighaXMubmEoeCRgQXJlYSAoc3Ega20pYCkpCmhpc3QoeCRgQXJlYSAoc3Ega20pYCkjbWVhbiB3aWxsIHVuZGVyIHJlcHJlc2VudCBncm91cHMKYm94cGxvdCh4JGBBcmVhIChzcSBrbSlgKQpgYGAKVGhlIGRpc3RyaWJ1dGluIGlzIHNrZXdlZCBzbyB1c2luZyBtZWFuIHRvIGltcHV0ZSBOQSdzIHdpbGwgbm90IGJlIGEgZ29vZCBkZWNpc2lvbi4KR3JvdXAgTWVkaWFuIHdpbGwgYmUgdXNlZCB0byBpbXB1dGUgTkEgaW4gdGhlIHNhbWUgZ3JvdXAKYGBge3J9CiN3aWxsIHVzZSBtZWRpYW4KCmVsZWN0b3JhdGVzJFN0YXRlPWFzLmNoYXJhY3RlcihlbGVjdG9yYXRlcyRTdGF0ZSkKZWxlY3RvcmF0ZXMkU3RhdGU9YXMuZmFjdG9yKGVsZWN0b3JhdGVzJFN0YXRlKQplbGVjdG9yYXRlcyRgQXJlYSAoc3Ega20pYD1hcy5pbnRlZ2VyKGVsZWN0b3JhdGVzJGBBcmVhIChzcSBrbSlgKQoKZWxlY3RvcmF0ZXM9ZWxlY3RvcmF0ZXMgJT4lIGdyb3VwX2J5KFN0YXRlKSAlPiUKICBtdXRhdGUoYEFyZWEgKHNxIGttKWA9aWZlbHNlKGlzLm5hKGBBcmVhIChzcSBrbSlgKSxtZWRpYW4oYEFyZWEgKHNxIGttKWAsbmEucm09VFJVRSksYEFyZWEgKHNxIGttKWApKQpjb2xTdW1zKGlzLm5hKGVsZWN0b3JhdGVzKSkKYGBgCkFsbCBOQSdzIGFyZSBoYW5kbGVkCgpTb21lIGluY29uc2lzdGVuY3kgd2FzIGZvdW5kIGluIGFyZWEgY29sdW1uIHdoaWNoIHdhcyBjYXVzZSBvZiAyODggTkEgdmFsdWVzIGl0IGlzIGhhbmRsZWQgaW4gbmV4dCBjb2RlIGJsb2NrLgoKSm9pbiB3aWxsIGJlIGF0dGVtcHRlZCBhZ2FpbgpgYGB7cn0KQUxMX1BBUlRCJGFyZWFbQUxMX1BBUlRCJGFyZWE9PSJMaW5naWFyaShjKSJdPSJMaW5naWFyaSIKQUxMX1BBUlRCJGFyZWFbQUxMX1BBUlRCJGFyZWE9PSJDYW5iZXJyYShkKSJdPSJDYW5iZXJyYSIKQUxMX1BBUlRCJGFyZWFbQUxMX1BBUlRCJGFyZWE9PSJGZW5uZXIoZSkiXT0iRmVubmVyIgoKQUxMPC0gCiAgQUxMX1BBUlRCICU+JQogIGxlZnRfam9pbihlbGVjdG9yYXRlcywgYnkgPSBjKCJhcmVhIiA9ICJFbGVjdG9yYWwgZGl2aXNpb24iKSkKYGBgCnNhbWUgZm9yZSByZXNwb25kYW50CmBgYHtyfQpyZXNwb25zZSRhcmVhW3Jlc3BvbnNlJGFyZWE9PSJMaW5naWFyaShjKSJdPSJMaW5naWFyaSIKcmVzcG9uc2UkYXJlYVtyZXNwb25zZSRhcmVhPT0iQ2FuYmVycmEoZCkiXT0iQ2FuYmVycmEiCnJlc3BvbnNlJGFyZWFbcmVzcG9uc2UkYXJlYT09IkZlbm5lcihlKSJdPSJGZW5uZXIiCgoKcmVzcG9uc2VfZGF0YSA8LSAKICByZXNwb25zZSU+JQogIGxlZnRfam9pbihlbGVjdG9yYXRlcywgYnkgPSBjKCJhcmVhIiA9ICJFbGVjdG9yYWwgZGl2aXNpb24iKSkKY29sU3Vtcyhpcy5uYShBTEwpKQpjb2xTdW1zKGlzLm5hKHJlc3BvbnNlX2RhdGEpKQpgYGAKSXQgY2FuIGJlIG9ic2VydmVkIE5BJ3MgaW4gYWxsIGNvbHVtbnMgYXJlIGVsaW1pbmF0ZWQKCgpgYGB7cn0KYWE9bGVmdF9qb2luKEFMTCxyZXNwb25zZV9kYXRhLCBieSA9ICJhcmVhIikKYWE9c2VsZWN0KGFhLC1jKDYsNykpCmBgYApOb3csIG9idmlvdXMgaW5jb3Npc3RlbmNpZXMgaW4gdGhlIGRhdGEgbmVlZGVkIHRvIGJlIGNoZWNrZWQgZm9yCjEtTmVnYXRpdmUgdmFsdWVzIGFyZSBub3QgcG9zc2libGUgaW4gYW55IG51bWVyaWMgY29sdW1ucyBpbiBvdXIgZGF0YXNldC5BcyBOZWdhdGl2ZSBudW1iZXIgb2YgcGVvcGUgZG9lcyBub3QgbWFrZXMgc2Vuc2UuIAoKYGBge3J9CkluY29zX2RldGVjdD1mdW5jdGlvbih4KQp7CiAgcmU9d2hpY2goeDwwKQogIHJlCn0KCnRlc3Q9YWFbLGMoNSw2LDcsOCw5LDEwLDExLDEyLDE0LDE1KV0KbGFwcGx5KHRlc3QsIGZ1bmN0aW9uKHgpIEluY29zX2RldGVjdCh4KSkKYGBgCmZpbmFsIGRhdGEKYGBge3J9CmhlYWQoYWEpCmBgYAojIyBVbmRlcnN0YW5kIAoKRGF0YSB0eXBlcyBvZiB0aGUgZmluYWwgdGFibGUgIGFyZSBleHBsb3JlZCBhbmQgYXBwcm9wcmlhdGUgZGF0YSB0eXBlIGNvbnZlcnNpb25zIGFyZSBhcHBsZWQgd2hlcmV2ZXIgaXMgbmVjZXNzYXJ5LgoKYGBge3J9CmdsaW1wc2UoYWEpCmBgYAphbG1vc3QgYWxsIHRoZSBudW1lcmljIHZhbHVlcyBhcmUgY2hhcmFjdGVyIHR5cGUgYW5kIHNvbWUgZmFjdG9yIHZhcmlibGVzIGFyZSBhbHNvIGNoYXIuCgpDb252ZXJ0aW5nIHRvIGFwcHJvcHJpYXRlIHR5cGVzLgppbnN0ZWFkIG9mIGNoYW5naW5nIGFsbCB0aGUgY2hhciB0byBkYmwgb25lIGJ5IG9uZSBjbHViYmluZyBvZiBhbGwgdGhlIGNvbHVtbnMgYXJlIHBlcmZvcm1lZCBhbmQgY29udmVydGVkIHRvIGRibC4gCmBgYHtyfQphYSRhcmVhPWFzLmZhY3RvcihhYSRhcmVhKQphYSRhZ2VfZ3JvdXA9ZmFjdG9yKGFhJGFnZV9ncm91cCwgbGV2ZWxzID0gY29scywKICAgICAgICAgICAgICAgb3JkZXJlZCA9IFRSVUUpCmFhJGdlbmRlcj1hcy5mYWN0b3IoYWEkZ2VuZGVyKQphYSRTdGF0ZS55PWFzLmZhY3RvcihhYSRTdGF0ZS55KQphYSRgQXJlYSAoc3Ega20pLnlgPWFzLm51bWVyaWMoYWEkYEFyZWEgKHNxIGttKS55YCkKI2NsdWJiaW5nIG9mIHN1cHBvc2VkbHkgZGJsIHdoaWNoIGFyZSBjaGFyCm5hbWVzPWNvbG5hbWVzKGFhKQpuYW1lcz1uYW1lc1s1OjE5XQphYVssbmFtZXNdID0gYXBwbHkoYWFbLG5hbWVzXSwgMiwgZnVuY3Rpb24oeCkgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpKQoKZ2xpbXBzZShhYSkKYGBgCkFsbCB0aGUgY29sdW1ucyBhcmUgaW4gYXBwcm9wcmlhdGUgZGF0YSBmb3JtYXQuIFdpdGggYWdlIGdyb3VwIGFzIGEgb3JkZXJlZCBmYWN0b3IuCgojIwlUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIElJIAoKSW4gdGhpcyBzdGVwLCBhbGwgdGhlIHVubmVjZXNzYXJ5IGNvbHVtbnMgb2YgcGVyY2VudGFnZSB3aWxsIGJlIHJlbW92ZWQgYXMgdGhleSBwb3NzZXNzIG9ubHkgcmVkdW5kYW50IGluZm9ybWF0aW9uIGFuZCBjYW4gYmUgY2FsY3VsYXRlZCBhdCBhbnkgdGltZSB1c2luZyBtdXRhdGUgZnVuY3Rpb24uCgpgYGB7cn0KI3JlbW92aW5nIHBlcmNlbnRhZ2VzCmFhPWFhJT4lc2VsZWN0KC1jKDcsOSwxMSwxMywxNSwxNywxOSkpCmBgYAoKb25seSBhZnRlciBzdWNjZXNzZnVsIE5BIHJlbW92YWwgYW5kIGZpeGluZyB0aGUgZGF0YSB0eXBlIGl0IHdhcyBwb3NzaWJsZSB0byBjcmVhdGUgYSB2YXJpYmxlLgoKVGhlIGZhYnJpY2F0ZWQgY29sdW1uIHdpbGwgY29udGFpbiB0b3RhbCBlbGVnaWJsZSBwYXJ0aWNpcGFudCBwZXIgc3Eua20gb2YgQXJlYQpgYGB7cn0KYWE9YWElPiVtdXRhdGUoZWxpZ2libGVfcGFydF9QZXJfc3Eua209YEVsaWdpYmxlIFRvdGFsYC9gQXJlYSAoc3Ega20pLnlgKQpgYGAKCgojIwlTY2FuIElJCgpJbiB0aGlzIHNlY3Rpb24gYW4gYW5hbHlzaXMgZm9yIG91dGxpZXJzIG9uIGFsbCB0aGUgbnVtZXJpYyBjb2x1bW5zIGlzIHBlcmZvcm1lZC4KQXMgc2VlbiBpbiB0aGUgcHJldmlvdXMgcGFydHMgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgZGF0YSBpcyBub3Qgbm9ybWFsIHNvIGJveHBsb3RzIGFyZSB1c2VkIGZvciBkZXRlY3Rpbmcgb3V0bGllcnMuCgpgYGB7cn0KbT1hYVssNToxNV0KZ2dwbG90KHN0YWNrKG0pLCBhZXMoeCA9IGluZCwgeSA9IHZhbHVlcykpK2dlb21fYm94cGxvdCgpCmBgYApUaGUgc2NhbGUgb2YgeSBheGlzIGlzIG5vdCBhcHByb3ByaWF0ZSBmb3IgY29tcGFyaXNpb24gb2YgYm94cGxvdCB3aXRoIG90aGVyIGJveHBsb3RzLiBUbyBlbmFibGUgdXMgdG8gY29tcGFyZSBib3hwbG90cyBhIHNjYWxlIHNoaWZ0IG9mIHkgYXhpcyBtaWdodCBoZWxwLgpgYGB7cn0KZ2dwbG90KHN0YWNrKG0pLCBhZXMoeCA9IGluZCwgeSA9IHZhbHVlcykpICtzY2FsZV95X2xvZzEwKCkrZ2VvbV9ib3hwbG90KCkKYGBgCkEgY2xlYXIgcHJlc2VuY2Ugb2Ygb3V0bGllcnMgY2FuIGJlIHNlZW4gaW4gYWxtb3N0IGV2ZXJ5IGNvbHVtbi4gSW4gZnVydGhlciBzdGVwcywgYW4gYXR0ZW1wdCBmb3IgdGhlIHRyZWF0bWVudCBvZiBvdXRsaWVycyB3aWxsIGJlIG1hZGUuCgpUaGUgb3V0bGllcnMgcGVyIGZ1bmN0aW9uIGFyZSBjcmVhdGVkIHRvIGNvbXB1dGUgdGhlIHBlcmNlbnRhZ2Ugb2Ygb3V0bGllciBwcmVzZW50IGluIHRoZSBwYXJ0aWN1bGFyIGNvbHVtbi4KVGhpcyBzdGVwIGlzIG5lY2Vzc2FyeSBhcyBhIGhpZ2ggcGVyY2VudGFnZSBvZiBvdXRsaWVycyAqKj41JSoqIHdpbGwgbWFrZSB1cyBjb25zaWRlciBvdGhlciBvcHRpb25zIG90aGVyIHRoYW4gZWxpbWluYXRpb24uIApgYGB7cn0KCm91dGxpZXJzcGVyIDwtIGZ1bmN0aW9uKHgpewogIGxlbmd0aCh3aGljaCh4ID4gIG1lYW4oeCkgKyAzICogc2QoeCkgfCB4IDwgbWVhbih4KSAtIDMgKiBzZCh4KSkgICkgLyBsZW5ndGgoeCkKfQoKb3V0PWFhWyxjKDUsNiw3LDgsOSwxMCwxMSwxMiwxNCwxNSldCm91dF9jb3VudD1sYXBwbHkob3V0LCBmdW5jdGlvbih4KSBvdXRsaWVyc3Blcih4KSkKb3V0X2NvdW50CmBgYApJdCBjYW4gYmUgb2JzZXJ2ZWQgdGhhdCBhbGwgY29sdW1ucyBhcmUgaGF2aW5nIGFuIG91dGxpZXIgcGVyY2VudGFnZSA8NSUgd2l0aCBtYXhpbXVtIG91dGxpZXIgaW4gIEFyZWEgKHNxIGttKS55YCBhbmQgYEVsaWdpYmxlIFRvdGFsYCBmb2xsb3dlZCBieSBjb3VudC4KClRoZSBmdWN0aW9uIG91dGxpZXJfcmVtb3Ygd2hlbiBhcHBsaWVkIHRvIGEgY29sdW1uIGtlZXBzIG9ubHkgdGhlIGRhdGEgd2hpY2ggYXJlIG5vdCBvdXRsaWVycyBhY2NvcmRpbmcgdG8gKipUdWtheXMgTWV0aG9kIG9mIG91dGxpZXIgZGV0ZWN0aW9uKioKYGBge3J9Cm91dGxpZXJfcmVtb3Y9ICBmdW5jdGlvbih4KXsKICBhYT1hYSU+JWZpbHRlcigoeCA8ICBtZWFuKHgpICsgMS41ICogc2QoeCkgJiB4ID4gbWVhbih4KSAtIDEuNSAqIHNkKHgpKSkgCiAgYWEKfQojZGltZW50aW9uIG9mIGRmIGJlZm9yZSByZW1vdmFsIG9mIG91dGxpZXJzCmRpbShhYSkKCmFmdGVyX3JlbW92YWw9b3V0bGllcl9yZW1vdihhYSRjb3VudCkKZGltKGFmdGVyX3JlbW92YWwpCmBgYAphbGwgdGhlIHJvd3Mgd2l0aCB2YWx1ZXMgb3V0c2lkZSBvZiB0aGUgcmFuZ2Ugb2YgUTEtMS41IHggSVFSIHRvIFEzKzEuNSB4IElRUiBhcmUgcmVtb3ZlZC4KYGBge3J9CmJveHBsb3QoYWZ0ZXJfcmVtb3ZhbCRjb3VudCkKYGBgCioqT0JTRVJWQVRJT04qKgpFdmVuIGFmdGVyIHJlbW92aW5nIHRoZSBvdXRsaWVycyBpdCBjYW4gYmUgb2JzZXJ2ZWQgdGhhdCB0aGUgb3V0bGllcnMgb2YgdGhlIGNvdW50IGNvbHVtbiBhcmUgc3RpbGwgcHJlc2VudCBhcyBuZXcgb3V0bGllcnMgYXJlIGludHJvZHVjZWQgZHVlIHRvIHRoZSByZW1vdmFsIG9mIHRoZSBvbGQgb25lIHdoaWNoIGNoYW5nZWQgdGhlIHF1YXJ0aWxlIHZhbHVlcy4KCioqREVDSVNJT04gRk9SIE9VVExJRVJTKioKVGhlIHZhbHVlcyBvZiBjb2x1bW5zIGFyZSBpbnRlcmRlcGVuZGVudCBhbmQgcmVtb3ZhbCBvZiBvdXRsaWVycyBpcyBub3QgZ29pbmcgdG8gZ2l2ZSB1cyBhbnkgcG9zaXRpdmUgZWZmZWN0IGluIGNsZWFuaW5nIHRoZSBkYXRhLgoKLU9uZSBwb3NzaWJsZSByZWFzb24gZm9yIG1hbnkgb3V0bGllcnMgY2FuIGJlIG91dGxpZXIgb2JzZXJ2YXRpb25zIG9mIHRoZSBhcmVhIG9mIHRoZSBmZWRlcmFsIGRpc3RyaWN0LiBBcyBhIHZlcnkgc21hbGwgb3IgdmVyeSBsYXJnZSBhcmVhIHdpbGwgaGF2ZSBleHRyZW1lIHN0YXRzLCBmb3IgZXhhbXBsZSwgYSB2ZXJ5IGxhcmdlIGZlZGVyYWwgZGl2aXNpb24gd2lsbCBoYXZlIHNldmVyYWwgcGFydGljaXBhbnRzLgoKLUEgZGVjaXNpb24gd2FzIG1hZGUgYWdhaW5zdCB0aGUgcmVtb3ZhbCBvZiBvdXRsaWVycyBvciBpbXB1dGF0aW9uIG9mIG91dGxpZXJzIHdpdGggbWVhbiwgbWVkaWFuIG9yIGNhcHBpbmcgdGhlbSB0byB0aGUgbmVhcmVzdCBxdWFudGlsZSB2YWx1ZSBhcyBhbnkgb2YgdGhlc2Ugd2lsbCBkaXN0dXJiIHRoZSBkYXRhIGFuZCB0aGUgcmVzdWx0cyBmcm9tIGFueSBzdGF0aXN0aWNhbCB0ZXN0IGRvbmUgb24gZGF0YSB3aWxsIG5vdCBiZSByZWxpYWJsZS4KCi1JZiBpbiBhbnkgY2FzZSByZW1vdmFsIG9mIG91dGxpZXJzIGlzIGEgbXVzdC4gTkEncyBjYW4gYmUgaW50cm9kdWNlZCBpbiB0aGUgcGxhY2Ugb2Ygb3V0bGllcnMuIFN1Y2ggYSBtb3ZlIHdpbGwga2VlcCB0aGUgb3JpZ2luYWwgZGlzdHJpYnV0aW9uIG9mIGRhdGEuCgoqKkRpc2N1c3Npb24qKgpWYXJpb3VzIGRpZmZlcmVudCBhbmFseXNpcyBpcyBwb3NzaWJsZSBmcm9tIHRoZSBkYXRhc2V0OgotdC10ZXN0IHdpdGggbWFsZSBhbmQgZmVtYWxlIHBhcnRpY2lwYW50IGNvdW50cy4KLXNlZSBpZiBhZ2UgYnJhY2tldCBtYWtlcyBkaWZmZXJlbmNlLCAzIGNhdGVnb3JpZXMgKHlvdW5nLG1pZCBhZ2Usb2xkKSBjYW4gYmUgdXNlIHRvIGJyYWNrZXQgYWxsIGFnZSBncm91cHMgYW5kIHRoZW4gQU5PVkEgdGVzdCBjYW4gYmUgdXNlIHRvIHNlZSBpZiBhbnkgdmFyaWVuY2UgZXhpc3QgYWNyb3NzIHRoZSBncm91cHMuCi1yZWdyZXNzaW9uIG1pZ2h0IGJlIHBvc3NpYmxlIGFyZWEgb2YgcGxhY2UgYW5kIG5vLiBvZiBwYXJ0aWNpcGFudCBhcyBhIGxpbmUobWFrZSBncmFwaCkgaXMgdGhlcmUKCiNUUkFOU0ZPUk0KVGhpcyBzdGVwIGlzIHRvIHRyYW5zZm9ybSB0aGUgaXQgY291bGQgYmUgdXNlZCBmb3IgZnVydGhlciBhbmFseXNpcy4KCmBgYHtyfQpsaWJyYXJ5KGZvcmVjYXN0KQpoaXN0KGFhJGBBcmVhIChzcSBrbSkueWApCnRyYW5zZm9ybWVkPUJveENveChhYSRgQXJlYSAoc3Ega20pLnlgLGxhbWJkYSA9ICJhdXRvIikKaGlzdCh0cmFuc2Zvcm1lZCkKYGBgCgo8YnI+Cjxicj4K