Setup

library(kableExtra)
library(magrittr)
library(readr)
library(dplyr)
library(tidyr)
library(stringr)
library(forcats)
library(ggplot2)
library(naniar)

Student names, numbers and percentage of contributions

Individual information
Student name Student number Percentage of contribution
Chandangowda Maruvanahalli Shivaramu s4063920 100



Executive Summary

In this report, I present the data pre-processing steps undertaken to clean, prepare and transform two datasets for analysis. The datasets used pertain to university admissions and salary information, which were merged and manipulated to achieve a tidy, comprehensive dataset suitable for further analysis.



Data

Provide explanations here.

Source: I sourced our data from ‘Kaggle’, which is a Google subsidiary and world’s largest data science community. This platform is a home of varied datasets, learning resources for datascience and a hub of challenging competitions etc.,

Dataset_1 details: This dataset contains the details of US colleges/universities admission rates and it’s corresponding SAT and ACT scores required to get an admission. All its attribute details as below:

Dataset_2 details: This dataset contains the details of US colleges/universities avarege salary pay-scale over the period of journey of a individual. All its attribute details as below:

dataframe_1 <- read.csv("/Users/chandangowda/Documents/RMIT Studies/Data Wrangling/Assignment_3/Dataset_1.csv")
dataframe_2 <- read.csv("/Users/chandangowda/Documents/RMIT Studies/Data Wrangling/Assignment_3/Dataset_2.csv")

# Displaying structure and head of both datasets
head(dataframe_1)
str(dataframe_1)
'data.frame':   1085 obs. of  10 variables:
 $ ID            : int  188429 168528 138600 100654 100724 188641 131159 164465 222831 164492 ...
 $ Name          : chr  "Adelphi University" "Adrian College" "Agnes Scott College" "Alabama A & M University" ...
 $ State         : chr  "New York" "Michigan" "Georgia" "Alabama" ...
 $ Applications  : int  16084 2736 1625 6560 5974 6243 19650 13999 3515 2519 ...
 $ Admissions    : int  12459 2079 1135 4697 5854 4193 12594 1224 2463 1835 ...
 $ Admission.Rate: num  0.775 0.76 0.698 0.716 0.98 ...
 $ SATVR75       : int  650 580 NA 520 534 630 730 760 590 NA ...
 $ SATMT75       : int  660 570 NA 510 516 670 710 790 570 NA ...
 $ ACTEN75       : int  31 24 NA 20 22 29 35 35 24 NA ...
 $ ACTMT75       : int  28 26 NA 18 19 27 31 35 24 NA ...
head(dataframe_2)
str(dataframe_2)
'data.frame':   302 obs. of  8 variables:
 $ School.Name                      : chr  "Adelphi University" "American University, Washington D.C." "Amherst College" "Appalachian State University" ...
 $ Region                           : chr  "Northeastern" "Southern" "Northeastern" "Southern" ...
 $ Starting.Median.Salary           : chr  "$40,600.00 " "$45,300.00 " "$54,500.00 " "$40,400.00 " ...
 $ Mid.Career.Median.Salary         : chr  "$79,200.00 " "$90,800.00 " "$107,000.00 " "$69,100.00 " ...
 $ Mid.Career.10th.Percentile.Salary: chr  "$44,200.00 " "$45,200.00 " "N/A" "$37,200.00 " ...
 $ Mid.Career.25th.Percentile.Salary: chr  "$54,800.00 " "$62,400.00 " "$84,900.00 " "$50,400.00 " ...
 $ Mid.Career.75th.Percentile.Salary: chr  "$114,000.00 " "$134,000.00 " "$162,000.00 " "$90,800.00 " ...
 $ Mid.Career.90th.Percentile.Salary: chr  "$160,000.00 " "$169,000.00 " "N/A" "$115,000.00 " ...
# Standardizing university names in both dataframes
dataframe_1 <- dataframe_1 %>%
  mutate(Name = str_to_upper(Name))

dataframe_2 <- dataframe_2 %>%
  mutate(School.Name = str_to_upper(School.Name))

# Merging datasets on standardized School Name
merged_dataframe <- dataframe_1 %>%
  inner_join(dataframe_2, by = c("Name" = "School.Name"))

# Renaming the merged column name as 'University Name'
merged_dataframe <- merged_dataframe %>%
  rename(
    University.Name = Name
  )

# Displaying structure and head of merged data
str(merged_dataframe)
'data.frame':   283 obs. of  17 variables:
 $ ID                               : int  188429 131159 164465 197869 104151 106458 100858 219602 150136 160977 ...
 $ University.Name                  : chr  "ADELPHI UNIVERSITY" "AMERICAN UNIVERSITY, WASHINGTON D.C." "AMHERST COLLEGE" "APPALACHIAN STATE UNIVERSITY" ...
 $ State                            : chr  "New York" "District of Columbia" "Massachusetts" "North Carolina" ...
 $ Applications                     : int  16084 19650 13999 21120 61603 5835 27619 5053 22947 7319 ...
 $ Admissions                       : int  12459 12594 1224 17886 54329 3693 19660 4721 15642 1267 ...
 $ Admission.Rate                   : num  0.7746 0.6409 0.0874 0.8469 0.8819 ...
 $ SATVR75                          : int  650 730 760 650 NA 590 NA NA 610 NA ...
 $ SATMT75                          : int  660 710 790 650 NA 610 NA NA 600 NA ...
 $ ACTEN75                          : int  31 35 35 28 NA 28 NA 24 26 NA ...
 $ ACTMT75                          : int  28 31 35 27 NA 25 NA 23 26 NA ...
 $ Region                           : chr  "Northeastern" "Southern" "Northeastern" "Southern" ...
 $ Starting.Median.Salary           : chr  "$40,600.00 " "$45,300.00 " "$54,500.00 " "$40,400.00 " ...
 $ Mid.Career.Median.Salary         : chr  "$79,200.00 " "$90,800.00 " "$107,000.00 " "$69,100.00 " ...
 $ Mid.Career.10th.Percentile.Salary: chr  "$44,200.00 " "$45,200.00 " "N/A" "$37,200.00 " ...
 $ Mid.Career.25th.Percentile.Salary: chr  "$54,800.00 " "$62,400.00 " "$84,900.00 " "$50,400.00 " ...
 $ Mid.Career.75th.Percentile.Salary: chr  "$114,000.00 " "$134,000.00 " "$162,000.00 " "$90,800.00 " ...
 $ Mid.Career.90th.Percentile.Salary: chr  "$160,000.00 " "$169,000.00 " "N/A" "$115,000.00 " ...
head(merged_dataframe)



Understand

# Summarizing the types of variables
variable_summary <- sapply(merged_dataframe, class)
print("Variable Types:")
[1] "Variable Types:"
print(variable_summary)
                               ID                   University.Name                             State 
                        "integer"                       "character"                       "character" 
                     Applications                        Admissions                    Admission.Rate 
                        "integer"                         "integer"                         "numeric" 
                          SATVR75                           SATMT75                           ACTEN75 
                        "integer"                         "integer"                         "integer" 
                          ACTMT75                            Region            Starting.Median.Salary 
                        "integer"                       "character"                       "character" 
         Mid.Career.Median.Salary Mid.Career.10th.Percentile.Salary Mid.Career.25th.Percentile.Salary 
                      "character"                       "character"                       "character" 
Mid.Career.75th.Percentile.Salary Mid.Career.90th.Percentile.Salary 
                      "character"                       "character" 
# Converting character variables to factors
merged_dataframe <- merged_dataframe %>%
  mutate(University.Name = as.factor(University.Name),
         State = as.factor(State))

# Assuming 'State' is a factor variable that we need to label and order
merged_dataframe <- merged_dataframe %>%
  mutate(State = fct_relevel(State, "California", "Texas", "New York", "Illinois", "Colorado"))

str(merged_dataframe)
'data.frame':   283 obs. of  17 variables:
 $ ID                               : int  188429 131159 164465 197869 104151 106458 100858 219602 150136 160977 ...
 $ University.Name                  : Factor w/ 280 levels "ADELPHI UNIVERSITY",..: 1 2 3 4 5 6 7 8 9 10 ...
 $ State                            : Factor w/ 50 levels "California","Texas",..: 3 12 23 34 8 9 6 43 16 21 ...
 $ Applications                     : int  16084 19650 13999 21120 61603 5835 27619 5053 22947 7319 ...
 $ Admissions                       : int  12459 12594 1224 17886 54329 3693 19660 4721 15642 1267 ...
 $ Admission.Rate                   : num  0.7746 0.6409 0.0874 0.8469 0.8819 ...
 $ SATVR75                          : int  650 730 760 650 NA 590 NA NA 610 NA ...
 $ SATMT75                          : int  660 710 790 650 NA 610 NA NA 600 NA ...
 $ ACTEN75                          : int  31 35 35 28 NA 28 NA 24 26 NA ...
 $ ACTMT75                          : int  28 31 35 27 NA 25 NA 23 26 NA ...
 $ Region                           : chr  "Northeastern" "Southern" "Northeastern" "Southern" ...
 $ Starting.Median.Salary           : chr  "$40,600.00 " "$45,300.00 " "$54,500.00 " "$40,400.00 " ...
 $ Mid.Career.Median.Salary         : chr  "$79,200.00 " "$90,800.00 " "$107,000.00 " "$69,100.00 " ...
 $ Mid.Career.10th.Percentile.Salary: chr  "$44,200.00 " "$45,200.00 " "N/A" "$37,200.00 " ...
 $ Mid.Career.25th.Percentile.Salary: chr  "$54,800.00 " "$62,400.00 " "$84,900.00 " "$50,400.00 " ...
 $ Mid.Career.75th.Percentile.Salary: chr  "$114,000.00 " "$134,000.00 " "$162,000.00 " "$90,800.00 " ...
 $ Mid.Career.90th.Percentile.Salary: chr  "$160,000.00 " "$169,000.00 " "N/A" "$115,000.00 " ...
summary(merged_dataframe)
       ID                                              University.Name           State      Applications   
 Min.   :100751   UNION COLLEGE                                :  3    New York     : 32   Min.   :   261  
 1st Qu.:148494   CALIFORNIA STATE UNIVERSITY, EAST BAY (CSUEB):  2    California   : 25   1st Qu.:  7486  
 Median :187985   ADELPHI UNIVERSITY                           :  1    Massachusetts: 18   Median : 14965  
 Mean   :180612   AMERICAN UNIVERSITY, WASHINGTON D.C.         :  1    Pennsylvania : 15   Mean   : 22572  
 3rd Qu.:213376   AMHERST COLLEGE                              :  1    Texas        : 12   3rd Qu.: 31000  
 Max.   :243744   APPALACHIAN STATE UNIVERSITY                 :  1    Wisconsin    : 12   Max.   :139489  
                  (Other)                                      :274    (Other)      :169                   
   Admissions    Admission.Rate       SATVR75         SATMT75         ACTEN75         ACTMT75     
 Min.   :  217   Min.   :0.03915   Min.   :558.0   Min.   :540.0   Min.   :22.00   Min.   :21.00  
 1st Qu.: 3504   1st Qu.:0.41808   1st Qu.:640.0   1st Qu.:630.0   1st Qu.:27.00   1st Qu.:26.25  
 Median : 7987   Median :0.73850   Median :680.0   Median :680.0   Median :31.50   Median :29.00  
 Mean   :11391   Mean   :0.62864   Mean   :682.2   Mean   :689.6   Mean   :30.71   Mean   :29.16  
 3rd Qu.:16302   3rd Qu.:0.87292   3rd Qu.:730.0   3rd Qu.:755.0   3rd Qu.:35.00   3rd Qu.:32.00  
 Max.   :54329   Max.   :0.99990   Max.   :780.0   Max.   :800.0   Max.   :36.00   Max.   :36.00  
                                   NA's   :76      NA's   :76      NA's   :77      NA's   :77     
    Region          Starting.Median.Salary Mid.Career.Median.Salary Mid.Career.10th.Percentile.Salary
 Length:283         Length:283             Length:283               Length:283                       
 Class :character   Class :character       Class :character         Class :character                 
 Mode  :character   Mode  :character       Mode  :character         Mode  :character                 
                                                                                                     
                                                                                                     
                                                                                                     
                                                                                                     
 Mid.Career.25th.Percentile.Salary Mid.Career.75th.Percentile.Salary Mid.Career.90th.Percentile.Salary
 Length:283                        Length:283                        Length:283                       
 Class :character                  Class :character                  Class :character                 
 Mode  :character                  Mode  :character                  Mode  :character                 
                                                                                                      
                                                                                                      
                                                                                                      
                                                                                                      

Provide explanations here.

In this step, I focused on understanding the structure and attributes of our merged dataset. This involved summarizing the types of variables, checking the summary statistics, and applying appropriate data type conversions to ensure consistency and readiness for analysis.



Tidy & Manipulate Data I

# Removing dollar signs and commas from salary columns and converting to numeric
merged_dataframe <- merged_dataframe %>%
  mutate(across(contains("Salary"), ~ as.numeric(str_remove_all(., "[$,]"))))
Warning: There were 2 warnings in `mutate()`.
The first warning was:
ℹ In argument: `across(contains("Salary"), ~as.numeric(str_remove_all(., "[$,]")))`.
Caused by warning:
! NAs introduced by coercion
ℹ Run ]8;;ide:run:dplyr::last_dplyr_warnings()dplyr::last_dplyr_warnings()]8;; to see the 1 remaining warning.
# Reshaping only the selected salary columns into a long format
tidy_dataframe <- merged_dataframe %>%
  pivot_longer(
    cols = c("Mid.Career.75th.Percentile.Salary", "Mid.Career.90th.Percentile.Salary"),
    names_to = "Higher.Salary.Stage",
    names_prefix = "Mid-Career ",
    values_to = "Higher.Career.Median.Salary"
  )

head(tidy_dataframe)

Provide explanations here.

Datasets did not fully adhere to the principles of tidy dataset due to the presence of salary columns (Mid-Career 75th Percentile Salary and Mid-Career 90th Percentile Salary) which represented similar types of information of an individual who is having higher bar of salary with much experience but were spread across multiple columns. To address this, we needed to reshape these columns into a longer format, ensuring each salary stage and its value are represented in a consistent manner.



Tidy & Manipulate Data II

# Creating the Selectivity variable based on Admission Rate
tidy_dataframe <- tidy_dataframe %>%
  mutate(Selectivity = case_when(
    `Admission.Rate` <= 0.30 ~ "Highly.Selective",
    `Admission.Rate` > 0.30 & `Admission.Rate` <= 0.60 ~ "Selective",
    `Admission.Rate` > 0.60 ~ "Less.Selective",
    TRUE ~ "Unknown"
  ))

# Displaying head of the tidy data with the new variable
head(tidy_dataframe)

Provide explanations here.

In this step, I created a new variable, Selectivity, based on the Admission.Rate of each university. This variable categorizes universities into different levels of selectivity, providing additional insight into the dataset. The creation of the Selectivity variable allows for a more nuanced analysis of how the selectivity of a university might relate to other factors such as salaries.



Scan I

# Scaning for missing values
missing_values <- colSums(is.na(tidy_dataframe))
print("Missing Values:")
[1] "Missing Values:"
print(missing_values)
                               ID                   University.Name                             State 
                                0                                 0                                 0 
                     Applications                        Admissions                    Admission.Rate 
                                0                                 0                                 0 
                          SATVR75                           SATMT75                           ACTEN75 
                              152                               152                               154 
                          ACTMT75                            Region            Starting.Median.Salary 
                              154                                 0                                 0 
         Mid.Career.Median.Salary Mid.Career.10th.Percentile.Salary Mid.Career.25th.Percentile.Salary 
                                0                                86                                 0 
              Higher.Salary.Stage       Higher.Career.Median.Salary                       Selectivity 
                                0                                43                                 0 
# Ploting the missing values
gg_miss_var(tidy_dataframe) + theme_minimal() + ggtitle("Missing Values by Variable")


# Handle missing values
# Here I choose to fill numeric columns with the mean and factor columns with the mode
tidy_dataframe <- tidy_dataframe %>%
  mutate(across(where(is.numeric), ~ ifelse(is.na(.), mean(., na.rm = TRUE), .)),
         across(where(is.factor), ~ ifelse(is.na(.), fct_mode(.), .)))

# Checking if missing values are handled
missing_values_after <- colSums(is.na(tidy_dataframe))
print("Missing Values After Handling:")
[1] "Missing Values After Handling:"
print(missing_values_after)
                               ID                   University.Name                             State 
                                0                                 0                                 0 
                     Applications                        Admissions                    Admission.Rate 
                                0                                 0                                 0 
                          SATVR75                           SATMT75                           ACTEN75 
                                0                                 0                                 0 
                          ACTMT75                            Region            Starting.Median.Salary 
                                0                                 0                                 0 
         Mid.Career.Median.Salary Mid.Career.10th.Percentile.Salary Mid.Career.25th.Percentile.Salary 
                                0                                 0                                 0 
              Higher.Salary.Stage       Higher.Career.Median.Salary                       Selectivity 
                                0                                 0                                 0 
# Handling special values (example: replace Inf with max and -Inf with min)
tidy_dataframe <- tidy_dataframe %>%
  mutate(across(where(is.numeric), ~ ifelse(is.infinite(.), NA, .)))

# Recheck special values after handling
special_values_after <- sapply(tidy_dataframe, function(x) sum(is.nan(x) | is.infinite(x)))
print("Special Values After Handling:")
[1] "Special Values After Handling:"
print(special_values_after)
                               ID                   University.Name                             State 
                                0                                 0                                 0 
                     Applications                        Admissions                    Admission.Rate 
                                0                                 0                                 0 
                          SATVR75                           SATMT75                           ACTEN75 
                                0                                 0                                 0 
                          ACTMT75                            Region            Starting.Median.Salary 
                                0                                 0                                 0 
         Mid.Career.Median.Salary Mid.Career.10th.Percentile.Salary Mid.Career.25th.Percentile.Salary 
                                0                                 0                                 0 
              Higher.Salary.Stage       Higher.Career.Median.Salary                       Selectivity 
                                0                                 0                                 0 
# Check for obvious errors in factor variables (example: unexpected levels)
unexpected_levels <- lapply(tidy_dataframe, function(x) if(is.factor(x)) levels(x))
print("Unexpected Levels:")
[1] "Unexpected Levels:"
print(unexpected_levels)
$ID
NULL

$University.Name
NULL

$State
NULL

$Applications
NULL

$Admissions
NULL

$Admission.Rate
NULL

$SATVR75
NULL

$SATMT75
NULL

$ACTEN75
NULL

$ACTMT75
NULL

$Region
NULL

$Starting.Median.Salary
NULL

$Mid.Career.Median.Salary
NULL

$Mid.Career.10th.Percentile.Salary
NULL

$Mid.Career.25th.Percentile.Salary
NULL

$Higher.Salary.Stage
NULL

$Higher.Career.Median.Salary
NULL

$Selectivity
NULL

Provide explanations here.

In this step, I scanned the dataset for missing values, special values, and obvious errors to ensure data quality and integrity.



Scan II

# Identifying outliers using the IQR method
numeric_cols <- select_if(tidy_dataframe, is.numeric)

# Calculating Q1 (25th percentile) and Q3 (75th percentile) for each numeric column
Q1 <- apply(numeric_cols, 2, quantile, 0.25, na.rm = TRUE)
Q3 <- apply(numeric_cols, 2, quantile, 0.75, na.rm = TRUE)
IQR <- Q3 - Q1

# Defining outliers as values below Q1 - 1.5*IQR or above Q3 + 1.5*IQR
outliers <- numeric_cols %>%
  mutate(across(everything(), ~ (. < (Q1 - 1.5 * IQR)) | (. > (Q3 + 1.5 * IQR))))
Warning: There were 30 warnings in `mutate()`.
The first warning was:
ℹ In argument: `across(...)`.
Caused by warning in `ID < (Q1 - 1.5 * IQR)`:
! longer object length is not a multiple of shorter object length
ℹ Run ]8;;ide:run:dplyr::last_dplyr_warnings()dplyr::last_dplyr_warnings()]8;; to see the 29 remaining warnings.
# Counting of outliers in each column
outliers_count <- colSums(outliers, na.rm = TRUE)
print("Outliers Count:")
[1] "Outliers Count:"
print(outliers_count)
                               ID                   University.Name                             State 
                              489                               434                               390 
                     Applications                        Admissions                    Admission.Rate 
                              457                               485                               376 
                          SATVR75                           SATMT75                           ACTEN75 
                              414                               414                               338 
                          ACTMT75            Starting.Median.Salary          Mid.Career.Median.Salary 
                              338                               380                               426 
Mid.Career.10th.Percentile.Salary Mid.Career.25th.Percentile.Salary       Higher.Career.Median.Salary 
                              383                               361                               475 
# Handling outliers by capping them to the nearest non-outlier value
tidy_dataframe <- tidy_dataframe %>%
  mutate(across(where(is.numeric), ~ ifelse(. < (Q1 - 1.5 * IQR), Q1 - 1.5 * IQR, .))) %>%
  mutate(across(where(is.numeric), ~ ifelse(. > (Q3 + 1.5 * IQR), Q3 + 1.5 * IQR, .)))
Warning: There were 15 warnings in `mutate()`.
The first warning was:
ℹ In argument: `across(...)`.
Caused by warning in `ID < (Q1 - 1.5 * IQR)`:
! longer object length is not a multiple of shorter object length
ℹ Run ]8;;ide:run:dplyr::last_dplyr_warnings()dplyr::last_dplyr_warnings()]8;; to see the 14 remaining warnings.Warning: There were 15 warnings in `mutate()`.
The first warning was:
ℹ In argument: `across(...)`.
Caused by warning in `ID > (Q3 + 1.5 * IQR)`:
! longer object length is not a multiple of shorter object length
ℹ Run ]8;;ide:run:dplyr::last_dplyr_warnings()dplyr::last_dplyr_warnings()]8;; to see the 14 remaining warnings.
# Verifying the structure after handling outliers
str(tidy_dataframe)
tibble [566 × 18] (S3: tbl_df/tbl/data.frame)
 $ ID                               : num [1:566] 188429 419 88.4 66980.2 35511.5 ...
 $ University.Name                  : num [1:566] 50256 1 2 2 3 ...
 $ State                            : num [1:566] 50256 3 12 12 23 ...
 $ Applications                     : num [1:566] 50256.1 419 88.4 19650 13999 ...
 $ Admissions                       : num [1:566] 50256.1 419 88.4 12594 1224 ...
 $ Admission.Rate                   : num [1:566] 5.03e+04 7.75e-01 6.41e-01 6.41e-01 8.74e-02 ...
 $ SATVR75                          : num [1:566] 50256.1 419 88.4 730 760 ...
 $ SATMT75                          : num [1:566] 50256.1 419 88.4 710 790 ...
 $ ACTEN75                          : num [1:566] 50256 31 35 35 35 ...
 $ ACTMT75                          : num [1:566] 50256 28 31 31 35 ...
 $ Region                           : chr [1:566] "Northeastern" "Northeastern" "Southern" "Southern" ...
 $ Starting.Median.Salary           : num [1:566] 50256.1 419 88.4 45300 35511.5 ...
 $ Mid.Career.Median.Salary         : num [1:566] 79200 419 88.4 66980.2 35511.5 ...
 $ Mid.Career.10th.Percentile.Salary: num [1:566] 50256.1 419 88.4 45200 35511.5 ...
 $ Mid.Career.25th.Percentile.Salary: num [1:566] 54800 419 88.4 62400 35511.5 ...
 $ Higher.Salary.Stage              : chr [1:566] "Mid.Career.75th.Percentile.Salary" "Mid.Career.90th.Percentile.Salary" "Mid.Career.75th.Percentile.Salary" "Mid.Career.90th.Percentile.Salary" ...
 $ Higher.Career.Median.Salary      : num [1:566] 114000 419 88.4 66980.2 35511.5 ...
 $ Selectivity                      : chr [1:566] "Less.Selective" "Less.Selective" "Less.Selective" "Less.Selective" ...

Provide explanations here.

In this step, I scanned the numeric data for outliers to ensure data consistency and integrity.



Transform

# Selecting a "Starting_Salary" variable to transform
variable_to_transform <- tidy_dataframe$Starting.Median.Salary

# Applying log transformation
tidy_dataframe <- tidy_dataframe %>%
  mutate(Starting_Salary_Log = log(Starting.Median.Salary + 1))

# Verifying the structure after transformation
str(tidy_dataframe)
tibble [566 × 19] (S3: tbl_df/tbl/data.frame)
 $ ID                               : num [1:566] 188429 419 88.4 66980.2 35511.5 ...
 $ University.Name                  : num [1:566] 50256 1 2 2 3 ...
 $ State                            : num [1:566] 50256 3 12 12 23 ...
 $ Applications                     : num [1:566] 50256.1 419 88.4 19650 13999 ...
 $ Admissions                       : num [1:566] 50256.1 419 88.4 12594 1224 ...
 $ Admission.Rate                   : num [1:566] 5.03e+04 7.75e-01 6.41e-01 6.41e-01 8.74e-02 ...
 $ SATVR75                          : num [1:566] 50256.1 419 88.4 730 760 ...
 $ SATMT75                          : num [1:566] 50256.1 419 88.4 710 790 ...
 $ ACTEN75                          : num [1:566] 50256 31 35 35 35 ...
 $ ACTMT75                          : num [1:566] 50256 28 31 31 35 ...
 $ Region                           : chr [1:566] "Northeastern" "Northeastern" "Southern" "Southern" ...
 $ Starting.Median.Salary           : num [1:566] 50256.1 419 88.4 45300 35511.5 ...
 $ Mid.Career.Median.Salary         : num [1:566] 79200 419 88.4 66980.2 35511.5 ...
 $ Mid.Career.10th.Percentile.Salary: num [1:566] 50256.1 419 88.4 45200 35511.5 ...
 $ Mid.Career.25th.Percentile.Salary: num [1:566] 54800 419 88.4 62400 35511.5 ...
 $ Higher.Salary.Stage              : chr [1:566] "Mid.Career.75th.Percentile.Salary" "Mid.Career.90th.Percentile.Salary" "Mid.Career.75th.Percentile.Salary" "Mid.Career.90th.Percentile.Salary" ...
 $ Higher.Career.Median.Salary      : num [1:566] 114000 419 88.4 66980.2 35511.5 ...
 $ Selectivity                      : chr [1:566] "Less.Selective" "Less.Selective" "Less.Selective" "Less.Selective" ...
 $ Starting_Salary_Log              : num [1:566] 10.82 6.04 4.49 10.72 10.48 ...
# Originaling distribution
p1 <- ggplot(tidy_dataframe, aes(x = Starting.Median.Salary)) +
  geom_histogram(bins = 30, fill = "red", alpha = 0.7) +
  theme_minimal() +
  ggtitle("Original Starting Salary Distribution")

# Transformeding distribution
p2 <- ggplot(tidy_dataframe, aes(x = Starting_Salary_Log)) +
  geom_histogram(bins = 30, fill = "green", alpha = 0.7) +
  theme_minimal() +
  ggtitle("Log-Transformed Starting Salary Distribution")

print(p1)

print(p2)

Provide explanations here.

In this step, I applied a log transformation to the Starting.Median.Salary variable to address skewness and better understand the distribution of starting salaries.



References

[1] RMIT (2024) Module 4: Tidy and Manipulate: Tidy Data Principles and Manipulating Data, Data Wrangling (Preprocessing). Accessed on: (25 May - 06 Jun)/2024. Link: http://rare-phoenix-161610.appspot.com/secured/Module_04.html

[2] RMIT (2024) Module 5: Scan: Missing Values Data Wrangling (Preprocessing). Accessed on: (25 May - 06 Jun)/2024. Link: http://rare-phoenix-161610.appspot.com/secured/Module_05.html

[3] RMIT (2024) Module 6: Scan: Outliers. Accessed on: (25 May - 06 Jun)/2024. Link: https://rare-phoenix- 161610.appspot.com/secured/Module_06.html

[4] RMIT (2024) Module 7: Scan: Missing Values. Accessed on: (30 May - 06 Jun)/2024. Link: https://rare-phoenix-161610.appspot.com/secured/Module_07.html

[5] QuillBot Website, used for paraphrasing my explanations. Accessed on: (02 Jun - 06 Jun)/2024. URL: https://quillbot.com

LS0tCnRpdGxlOiAiRGF0YSBXcmFuZ2xpbmcgKERhdGEgUHJlcHJvY2Vzc2luZykiCmF1dGhvcjogIkNoYW5kYW5nb3dkYSBNYXJ1dmFuYWhhbGxpIFNoaXZhcmFtdSIKc3VidGl0bGU6IFByYWN0aWNhbCBhc3Nlc3NtZW50IDIKZGF0ZTogIjA2LUp1bi0yMDI0IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKLS0tCgojIyAqKlNldHVwKioKCmBgYHtyfQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShmb3JjYXRzKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkobmFuaWFyKQpgYGAKCiMjICoqU3R1ZGVudCBuYW1lcywgbnVtYmVycyBhbmQgcGVyY2VudGFnZSBvZiBjb250cmlidXRpb25zKioKCmBgYHtyLCBlY2hvPUZBTFNFfQpuYTwtIGMoIiBDaGFuZGFuZ293ZGEgTWFydXZhbmFoYWxsaSBTaGl2YXJhbXUiKQpubzwtIGMoIiBzNDA2MzkyMCIpCnBjPC0gYygiMTAwIikKCnM8LSBkYXRhLmZyYW1lKGNiaW5kKG5hLG5vLHBjKSkKY29sbmFtZXMocyk8LSBjKCJTdHVkZW50IG5hbWUiLCAiU3R1ZGVudCBudW1iZXIiLCAiUGVyY2VudGFnZSBvZiBjb250cmlidXRpb24iKQoKcyAlPiUga2JsKGNhcHRpb24gPSAiSW5kaXZpZHVhbCBpbmZvcm1hdGlvbiIpICU+JQogIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IEYsIGh0bWxfZm9udCA9ICJDYW1icmlhIikKCmBgYAoKPGJyPiA8YnI+CgojIyAqKkV4ZWN1dGl2ZSBTdW1tYXJ5KioKCkluIHRoaXMgcmVwb3J0LCBJIHByZXNlbnQgdGhlIGRhdGEgcHJlLXByb2Nlc3Npbmcgc3RlcHMgdW5kZXJ0YWtlbiB0byBjbGVhbiwgcHJlcGFyZSBhbmQgdHJhbnNmb3JtIHR3byBkYXRhc2V0cyBmb3IgYW5hbHlzaXMuIFRoZSBkYXRhc2V0cyB1c2VkIHBlcnRhaW4gdG8gdW5pdmVyc2l0eSBhZG1pc3Npb25zIGFuZCBzYWxhcnkgaW5mb3JtYXRpb24sIHdoaWNoIHdlcmUgbWVyZ2VkIGFuZCBtYW5pcHVsYXRlZCB0byBhY2hpZXZlIGEgdGlkeSwgY29tcHJlaGVuc2l2ZSBkYXRhc2V0IHN1aXRhYmxlIGZvciBmdXJ0aGVyIGFuYWx5c2lzLgoKLSAgIFRoZSBwcmVwcm9jZXNzaW5nIHByb2Nlc3MgYmVnYW4gd2l0aCBkYXRhIGltcG9ydGF0aW9uIGFuZCBhbiBpbml0aWFsIGluc3BlY3Rpb24gdG8gdW5kZXJzdGFuZCB0aGUgc3RydWN0dXJlIGFuZCBjb250ZW50IG9mIHRoZSBkYXRhc2V0cy4gVG8gZ3VhcmFudGVlIGNvbnNpc3RlbmN5IGFjcm9zcyB0aGUgdHdvIGRhdGFzZXRzLCBJIHN0YW5kYXJkaXplZCB0aGUgdW5pdmVyc2l0eSBuYW1lcywgbWFraW5nIGl0IHBvc3NpYmxlIHRvIGFjY3VyYXRlbHkgaW50ZWdyYXRlIHRoZSBkYXRhIGJhc2VkIG9uIHRoZSB1bml2ZXJzaXR5IG5hbWVzLgoKLSAgIEkgdGhlbiBhZGRyZXNzZWQgdGhlIGRpZmZlcmVudCBkYXRhIHR5cGVzIG9mIHRoZSBjb2x1bW5zLCBtYWtpbmcgc3VyZSB0aGUgZm9ybWF0IG9mIHRoZSBudW1lcmljIGNvbHVtbnMgd2FzIHByb3BlciBhbmQgY29udmVydGluZyBwZXJ0aW5lbnQgY29sdW1ucyB0byBmYWN0b3JzIHdoZW4gbmVjZXNzYXJ5LiBUaGlzIGludm9sdmVkIHR1cm5pbmcgdGhlIHNhbGFyeSBjb2x1bW5zIGludG8gbnVtZXJpYyB2YWx1ZXMgYW5kIGRlbGV0aW5nIHRoZSBkb2xsYXIgc2lnbnMgYW5kIGNvbW1hcyBmcm9tIHRoZW0uCgotICAgVG8gZnVydGhlciB0aWR5IHRoZSBkYXRhLCBJIHJlc2hhcGVkIHRoZSBkYXRhc2V0IGJ5IHBpdm90aW5nIHNlbGVjdGVkIHNhbGFyeSBwZXJjZW50aWxlIGNvbHVtbnMgaW50byBhIGxvbmcgZm9ybWF0LCB3aGljaCBmYWNpbGl0YXRlZCBlYXNpZXIgYW5hbHlzaXMgb2Ygc2FsYXJ5IGRpc3RyaWJ1dGlvbnMgYWNyb3NzIGRpZmZlcmVudCBwZXJjZW50aWxlcy4gT24gdGhlIGJhc2lzIG9mIHRoZSBhZG1pc3Npb24gcmF0ZSwgSSBhbHNvIGRldmVsb3BlZCBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgU2VsZWN0aXZpdHksIHdoaWNoIGNsYXNzaWZpZWQgdW5pdmVyc2l0aWVzIGFzICJIaWdobHkgU2VsZWN0aXZlLCIgIlNlbGVjdGl2ZSwiIGFuZCAiTGVzcyBTZWxlY3RpdmUuIgoKLSAgIEkgdGhlbiBwZXJmb3JtZWQgYSBjb21wcmVoZW5zaXZlIHNjYW4gZm9yIG1pc3NpbmcgdmFsdWVzLCBzcGVjaWFsIHZhbHVlcywgYW5kIG9idmlvdXMgZXJyb3JzLiBNaXNzaW5nIG51bWVyaWMgdmFsdWVzIHdlcmUgaGFuZGxlZCBieSBmaWxsaW5nIHRoZW0gd2l0aCB0aGUgbWVhbiBvZiB0aGVpciByZXNwZWN0aXZlIGNvbHVtbnMsIHdoaWxlIG1pc3NpbmcgZmFjdG9yIHZhbHVlcyB3ZXJlIGZpbGxlZCB3aXRoIHRoZSBtb2RlLiBTcGVjaWFsIHZhbHVlcywgc3VjaCBhcyBOYU4gYW5kIEluZiwgd2VyZSBpZGVudGlmaWVkIGFuZCBhcHByb3ByaWF0ZWx5IG1hbmFnZWQuCgotICAgSW4gbnVtZXJpY2FsIGRhdGEsIG91dGxpZXJzIHdlcmUgZm91bmQgdXNpbmcgdGhlIEludGVycXVhcnRpbGUgUmFuZ2UgKElRUikgdGVjaG5pcXVlLiBJbiBvcmRlciB0byBlbnN1cmUgdGhhdCB0aGUgZGF0YSByZW1haW5lZCByb2J1c3QgZm9yIGFuYWx5c2lzIHdpdGhvdXQgYmVpbmcgZGlzdG9ydGVkIGJ5IGV4dHJlbWUgdmFsdWVzLCB0aGVzZSBvdXRsaWVycyB3ZXJlIGFkZHJlc3NlZCBieSBjYXBwaW5nIHRoZW0gdG8gdGhlIG5lYXJlc3Qgbm9uLW91dGxpZXIgdmFsdWVzLgoKLSAgIEZpbmFsbHksIEkgYXBwbGllZCBhIGxvZyB0cmFuc2Zvcm1hdGlvbiB0byB0aGUgU3RhcnRpbmdfU2FsYXJ5IHZhcmlhYmxlIHRvIHJlZHVjZSBza2V3bmVzcyBhbmQgbm9ybWFsaXplIGl0cyBkaXN0cmlidXRpb24sIGVuaGFuY2luZyB0aGUgaW50ZXJwcmV0YWJpbGl0eSBhbmQgdXNhYmlsaXR5IG9mIHRoZSB2YXJpYWJsZSBmb3Igc3Vic2VxdWVudCBhbmFseXNlcy4KCjxicj4gPGJyPgoKIyMgKipEYXRhKioKClByb3ZpZGUgZXhwbGFuYXRpb25zIGhlcmUuCgpTb3VyY2U6IEkgc291cmNlZCBvdXIgZGF0YSBmcm9tICdLYWdnbGUnLCB3aGljaCBpcyBhIEdvb2dsZSBzdWJzaWRpYXJ5IGFuZCB3b3JsZCdzIGxhcmdlc3QgZGF0YSBzY2llbmNlIGNvbW11bml0eS4gVGhpcyBwbGF0Zm9ybSBpcyBhIGhvbWUgb2YgdmFyaWVkIGRhdGFzZXRzLCBsZWFybmluZyByZXNvdXJjZXMgZm9yIGRhdGFzY2llbmNlIGFuZCBhIGh1YiBvZiBjaGFsbGVuZ2luZyBjb21wZXRpdGlvbnMgZXRjLiwKCkRhdGFzZXRfMSBkZXRhaWxzOiBUaGlzIGRhdGFzZXQgY29udGFpbnMgdGhlIGRldGFpbHMgb2YgVVMgY29sbGVnZXMvdW5pdmVyc2l0aWVzIGFkbWlzc2lvbiByYXRlcyBhbmQgaXQncyBjb3JyZXNwb25kaW5nIFNBVCBhbmQgQUNUIHNjb3JlcyByZXF1aXJlZCB0byBnZXQgYW4gYWRtaXNzaW9uLiBBbGwgaXRzIGF0dHJpYnV0ZSBkZXRhaWxzIGFzIGJlbG93OgoKLSAgIElEIC0gVGhpcyBpcyB0aGUgSW50ZWdyYXRlZCBQb3N0c2Vjb25kYXJ5IEVkdWNhdGlvbiBEYXRhIFN5c3RlbSAoSVBFRFMpIHVuaXF1ZSBpZCBmb3IgZWFjaCBjb2xsZWdlL3VuaXZlcnNpdHkuCgotICAgTmFtZSAtIE5hbWUgb2YgdGhlIGNvbGxlZ2UvdW5pdmVyc2l0eS4KCi0gICBTdGF0ZSAtIFN0YXRlIG9mIHRoZSBjb2xsZWdlL3VuaXZlcnNpdHkgd2hlcmUgaXQgaXMgbG9jYXRlZC4KCi0gICBBcHBsaWNhdGlvbnMgLSBOdW1iZXIgb2YgYXBwbGljYW50cyBhcHBsaWVkIGZvciB0aGUgdW5pdmVyc2l0eSBmb3IgYWRtaXNzaW9uLgoKLSAgIEFkbWlzc2lvbnMgLSBOdW1iZXIgb2YgYXBwbGljYW50cyBnb3QgdGhlIHNlYXQvYWRtaXNzaW9uIHRvIHRoZSB1bml2ZXJzaXR5LgoKLSAgIEFkbWlzc2lvbiByYXRlIC0gUmF0ZSBvZiB1bml2ZXJzaXR5IGFjY2VwdGFuY2UuCgotICAgU0FUVlI3NSAtIFNBVCBWZXJiYWwgNzV0aCBwZXJjZW50aWxlIHNjb3JlLgoKLSAgIFNBVE1UNzUgLSBTQVQgTWF0aCA3NXRoIHBlcmNlbnRpbGUgc2NvcmUuCgotICAgQUNURU43NSAtIEFDVCBFbmdsaXNoIDc1dGggcGVyY2VudGlsZSBzY29yZS4KCi0gICBBQ1RNVDc1IC0gQUNUIE1hdGggNzV0aCBwZXJjZW50aWxlIHNjb3JlLgoKRGF0YXNldF8yIGRldGFpbHM6IFRoaXMgZGF0YXNldCBjb250YWlucyB0aGUgZGV0YWlscyBvZiBVUyBjb2xsZWdlcy91bml2ZXJzaXRpZXMgYXZhcmVnZSBzYWxhcnkgcGF5LXNjYWxlIG92ZXIgdGhlIHBlcmlvZCBvZiBqb3VybmV5IG9mIGEgaW5kaXZpZHVhbC4gQWxsIGl0cyBhdHRyaWJ1dGUgZGV0YWlscyBhcyBiZWxvdzoKCi0gICBTY2hvb2wgTmFtZSAtIE5hbWUgb2YgdGhlIGNvbGxlZ2UvdW5pdmVyc2l0eS4KCi0gICBSZWdpb24gLSBSZWdpb24gb2YgdGhlIHVuaXZlcnNpdHkgb24gd2hpY2ggc2lkZSBpdCBtb3N0bHkgY2F0ZWdvcml6ZWQgaW4gdGhlIFVTLiBFeDogQ2FsaWZvcm5pYSByZWdpb24sIFNvdXRoZXJuIHJlZ2lvbiwgTm9ydGhlYXN0ZXJuIHJlZ2lvbiBldGMuLAoKLSAgIFN0YXJ0aW5nIE1lZGlhbiBTYWxhcnkgLSBTdGFydGluZyBhdmVyYWdlIHNhbGFyeSBvZiBhbiBpbmRpdmlkdWFsIHdobyBzdHVkaWVkIGluIHRoYXQgdW5pdmVyc2l0eS4KCi0gICBNaWQtQ2FyZWVyIE1lZGlhbiBTYWxhcnkgLSBDYXJlZXIgbWlkIGF2ZXJhZ2Ugc2FsYXJ5IG9mIGFuIGluZGl2aWR1YWwgd2hvIHN0dWRpZWQgaW4gdGhhdCB1bml2ZXJzaXR5LgoKLSAgIE1pZC1DYXJlZXIgMTB0aCBQZXJjZW50aWxlIFNhbGFyeSAtIENhcmVlciBtaWQgMTB0aCBwZXJjZW50aWxlIGluZGl2aWR1YWxzIHNhbGFyaWVzIHdobyBzdHVkaWVkIGluIHRoYXQgdW5pdmVyc2l0eS4KCi0gICBNaWQtQ2FyZWVyIDI1dGggUGVyY2VudGlsZSBTYWxhcnkgLSBDYXJlZXIgbWlkIDI1dGggcGVyY2VudGlsZSBpbmRpdmlkdWFscyBzYWxhcmllcyB3aG8gc3R1ZGllZCBpbiB0aGF0IHVuaXZlcnNpdHkuCgotICAgTWlkLUNhcmVlciA3NXRoIFBlcmNlbnRpbGUgU2FsYXJ5IC0gQ2FyZWVyIG1pZCA3NXRoIHBlcmNlbnRpbGUgaW5kaXZpZHVhbHMgc2FsYXJpZXMgd2hvIHN0dWRpZWQgaW4gdGhhdCB1bml2ZXJzaXR5LgoKLSAgIE1pZC1DYXJlZXIgOTB0aCBQZXJjZW50aWxlIFNhbGFyeSAtIENhcmVlciBtaWQgOTB0aCBwZXJjZW50aWxlIGluZGl2aWR1YWxzIHNhbGFyaWVzIHdobyBzdHVkaWVkIGluIHRoYXQgdW5pdmVyc2l0eS4KCmBgYHtyfQpkYXRhZnJhbWVfMSA8LSByZWFkLmNzdigiL1VzZXJzL2NoYW5kYW5nb3dkYS9Eb2N1bWVudHMvUk1JVCBTdHVkaWVzL0RhdGEgV3JhbmdsaW5nL0Fzc2lnbm1lbnRfMy9EYXRhc2V0XzEuY3N2IikKZGF0YWZyYW1lXzIgPC0gcmVhZC5jc3YoIi9Vc2Vycy9jaGFuZGFuZ293ZGEvRG9jdW1lbnRzL1JNSVQgU3R1ZGllcy9EYXRhIFdyYW5nbGluZy9Bc3NpZ25tZW50XzMvRGF0YXNldF8yLmNzdiIpCgojIERpc3BsYXlpbmcgc3RydWN0dXJlIGFuZCBoZWFkIG9mIGJvdGggZGF0YXNldHMKaGVhZChkYXRhZnJhbWVfMSkKc3RyKGRhdGFmcmFtZV8xKQoKaGVhZChkYXRhZnJhbWVfMikKc3RyKGRhdGFmcmFtZV8yKQoKIyBTdGFuZGFyZGl6aW5nIHVuaXZlcnNpdHkgbmFtZXMgaW4gYm90aCBkYXRhZnJhbWVzCmRhdGFmcmFtZV8xIDwtIGRhdGFmcmFtZV8xICU+JQogIG11dGF0ZShOYW1lID0gc3RyX3RvX3VwcGVyKE5hbWUpKQoKZGF0YWZyYW1lXzIgPC0gZGF0YWZyYW1lXzIgJT4lCiAgbXV0YXRlKFNjaG9vbC5OYW1lID0gc3RyX3RvX3VwcGVyKFNjaG9vbC5OYW1lKSkKCiMgTWVyZ2luZyBkYXRhc2V0cyBvbiBzdGFuZGFyZGl6ZWQgU2Nob29sIE5hbWUKbWVyZ2VkX2RhdGFmcmFtZSA8LSBkYXRhZnJhbWVfMSAlPiUKICBpbm5lcl9qb2luKGRhdGFmcmFtZV8yLCBieSA9IGMoIk5hbWUiID0gIlNjaG9vbC5OYW1lIikpCgojIFJlbmFtaW5nIHRoZSBtZXJnZWQgY29sdW1uIG5hbWUgYXMgJ1VuaXZlcnNpdHkgTmFtZScKbWVyZ2VkX2RhdGFmcmFtZSA8LSBtZXJnZWRfZGF0YWZyYW1lICU+JQogIHJlbmFtZSgKICAgIFVuaXZlcnNpdHkuTmFtZSA9IE5hbWUKICApCgojIERpc3BsYXlpbmcgc3RydWN0dXJlIGFuZCBoZWFkIG9mIG1lcmdlZCBkYXRhCnN0cihtZXJnZWRfZGF0YWZyYW1lKQpoZWFkKG1lcmdlZF9kYXRhZnJhbWUpCmBgYAoKPGJyPiA8YnI+CgojIyAqKlVuZGVyc3RhbmQqKgoKYGBge3J9CiMgU3VtbWFyaXppbmcgdGhlIHR5cGVzIG9mIHZhcmlhYmxlcwp2YXJpYWJsZV9zdW1tYXJ5IDwtIHNhcHBseShtZXJnZWRfZGF0YWZyYW1lLCBjbGFzcykKcHJpbnQoIlZhcmlhYmxlIFR5cGVzOiIpCnByaW50KHZhcmlhYmxlX3N1bW1hcnkpCgojIENvbnZlcnRpbmcgY2hhcmFjdGVyIHZhcmlhYmxlcyB0byBmYWN0b3JzCm1lcmdlZF9kYXRhZnJhbWUgPC0gbWVyZ2VkX2RhdGFmcmFtZSAlPiUKICBtdXRhdGUoVW5pdmVyc2l0eS5OYW1lID0gYXMuZmFjdG9yKFVuaXZlcnNpdHkuTmFtZSksCiAgICAgICAgIFN0YXRlID0gYXMuZmFjdG9yKFN0YXRlKSkKCiMgQXNzdW1pbmcgJ1N0YXRlJyBpcyBhIGZhY3RvciB2YXJpYWJsZSB0aGF0IHdlIG5lZWQgdG8gbGFiZWwgYW5kIG9yZGVyCm1lcmdlZF9kYXRhZnJhbWUgPC0gbWVyZ2VkX2RhdGFmcmFtZSAlPiUKICBtdXRhdGUoU3RhdGUgPSBmY3RfcmVsZXZlbChTdGF0ZSwgIkNhbGlmb3JuaWEiLCAiVGV4YXMiLCAiTmV3IFlvcmsiLCAiSWxsaW5vaXMiLCAiQ29sb3JhZG8iKSkKCnN0cihtZXJnZWRfZGF0YWZyYW1lKQpzdW1tYXJ5KG1lcmdlZF9kYXRhZnJhbWUpCmBgYAoKUHJvdmlkZSBleHBsYW5hdGlvbnMgaGVyZS4KCkluIHRoaXMgc3RlcCwgSSBmb2N1c2VkIG9uIHVuZGVyc3RhbmRpbmcgdGhlIHN0cnVjdHVyZSBhbmQgYXR0cmlidXRlcyBvZiBvdXIgbWVyZ2VkIGRhdGFzZXQuIFRoaXMgaW52b2x2ZWQgc3VtbWFyaXppbmcgdGhlIHR5cGVzIG9mIHZhcmlhYmxlcywgY2hlY2tpbmcgdGhlIHN1bW1hcnkgc3RhdGlzdGljcywgYW5kIGFwcGx5aW5nIGFwcHJvcHJpYXRlIGRhdGEgdHlwZSBjb252ZXJzaW9ucyB0byBlbnN1cmUgY29uc2lzdGVuY3kgYW5kIHJlYWRpbmVzcyBmb3IgYW5hbHlzaXMuCgotICAgU3VtbWFyaXplIHRoZSBUeXBlcyBvZiBWYXJpYWJsZXMgLSBJIHVzZWQgdGhlIHNhcHBseSBmdW5jdGlvbiB0byBkZXRlcm1pbmUgdGhlIGRhdGEgdHlwZXMgb2YgZWFjaCB2YXJpYWJsZSBpbiB0aGUgbWVyZ2VkX2RhdGFmcmFtZS4gVGhpcyBzdGVwIHdhcyBjcnVjaWFsIHRvIGlkZW50aWZ5IHRoZSB0eXBlcyBvZiB2YXJpYWJsZXMgKG51bWVyaWMsIGNoYXJhY3RlciwgZmFjdG9yLCBldGMuKSBhbmQgZW5zdXJlIHRoYXQgZWFjaCB2YXJpYWJsZSBpcyBhcHByb3ByaWF0ZWx5IGNsYXNzaWZpZWQuCgotICAgQ29udmVydCBDaGFyYWN0ZXIgVmFyaWFibGVzIHRvIEZhY3RvcnMgLSBDaGFyYWN0ZXIgdmFyaWFibGVzLCBwYXJ0aWN1bGFybHkgVW5pdmVyc2l0eS5OYW1lIGFuZCBTdGF0ZSwgd2VyZSBjb252ZXJ0ZWQgdG8gZmFjdG9ycy4gVGhpcyBpcyBhbiBpbXBvcnRhbnQgc3RlcCBmb3IgY2F0ZWdvcmljYWwgZGF0YSwgYXMgaXQgYWxsb3dzIGZvciBtb3JlIGVmZmljaWVudCBzdG9yYWdlIGFuZCBwcm92aWRlcyBtZWFuaW5nZnVsIGxldmVscyBmb3IgYW5hbHlzaXMuCgotICAgTGFiZWwgYW5kIE9yZGVyIEZhY3RvciBMZXZlbHMgLSBJIGFzc3VtZWQgdGhlIFN0YXRlIHZhcmlhYmxlIG5lZWRlZCB0byBiZSBvcmRlcmVkIGZvciBiZXR0ZXIgYW5hbHlzaXMuIFRoZSBmY3RfcmVsZXZlbCBmdW5jdGlvbiBmcm9tIHRoZSBmb3JjYXRzIHBhY2thZ2Ugd2FzIHVzZWQgdG8gcmVvcmRlciB0aGUgbGV2ZWxzIG9mIFN0YXRlIHRvIGEgc3BlY2lmaWVkIG9yZGVyLiBUaGlzIGlzIHVzZWZ1bCBmb3Igb3JkZXJlZCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgd2hlcmUgdGhlIHNlcXVlbmNlIG9mIGxldmVscyBoYXMgYSBtZWFuaW5nZnVsIGludGVycHJldGF0aW9uLgoKPGJyPiA8YnI+CgojIyAqKlRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSSoqCgpgYGB7cn0KIyBSZW1vdmluZyBkb2xsYXIgc2lnbnMgYW5kIGNvbW1hcyBmcm9tIHNhbGFyeSBjb2x1bW5zIGFuZCBjb252ZXJ0aW5nIHRvIG51bWVyaWMKbWVyZ2VkX2RhdGFmcmFtZSA8LSBtZXJnZWRfZGF0YWZyYW1lICU+JQogIG11dGF0ZShhY3Jvc3MoY29udGFpbnMoIlNhbGFyeSIpLCB+IGFzLm51bWVyaWMoc3RyX3JlbW92ZV9hbGwoLiwgIlskLF0iKSkpKQoKIyBSZXNoYXBpbmcgb25seSB0aGUgc2VsZWN0ZWQgc2FsYXJ5IGNvbHVtbnMgaW50byBhIGxvbmcgZm9ybWF0CnRpZHlfZGF0YWZyYW1lIDwtIG1lcmdlZF9kYXRhZnJhbWUgJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IGMoIk1pZC5DYXJlZXIuNzV0aC5QZXJjZW50aWxlLlNhbGFyeSIsICJNaWQuQ2FyZWVyLjkwdGguUGVyY2VudGlsZS5TYWxhcnkiKSwKICAgIG5hbWVzX3RvID0gIkhpZ2hlci5TYWxhcnkuU3RhZ2UiLAogICAgbmFtZXNfcHJlZml4ID0gIk1pZC1DYXJlZXIgIiwKICAgIHZhbHVlc190byA9ICJIaWdoZXIuQ2FyZWVyLk1lZGlhbi5TYWxhcnkiCiAgKQoKaGVhZCh0aWR5X2RhdGFmcmFtZSkKYGBgCgpQcm92aWRlIGV4cGxhbmF0aW9ucyBoZXJlLgoKRGF0YXNldHMgZGlkIG5vdCBmdWxseSBhZGhlcmUgdG8gdGhlIHByaW5jaXBsZXMgb2YgdGlkeSBkYXRhc2V0IGR1ZSB0byB0aGUgcHJlc2VuY2Ugb2Ygc2FsYXJ5IGNvbHVtbnMgKE1pZC1DYXJlZXIgNzV0aCBQZXJjZW50aWxlIFNhbGFyeSBhbmQgTWlkLUNhcmVlciA5MHRoIFBlcmNlbnRpbGUgU2FsYXJ5KSB3aGljaCByZXByZXNlbnRlZCBzaW1pbGFyIHR5cGVzIG9mIGluZm9ybWF0aW9uIG9mIGFuIGluZGl2aWR1YWwgd2hvIGlzIGhhdmluZyBoaWdoZXIgYmFyIG9mIHNhbGFyeSB3aXRoIG11Y2ggZXhwZXJpZW5jZSBidXQgd2VyZSBzcHJlYWQgYWNyb3NzIG11bHRpcGxlIGNvbHVtbnMuIFRvIGFkZHJlc3MgdGhpcywgd2UgbmVlZGVkIHRvIHJlc2hhcGUgdGhlc2UgY29sdW1ucyBpbnRvIGEgbG9uZ2VyIGZvcm1hdCwgZW5zdXJpbmcgZWFjaCBzYWxhcnkgc3RhZ2UgYW5kIGl0cyB2YWx1ZSBhcmUgcmVwcmVzZW50ZWQgaW4gYSBjb25zaXN0ZW50IG1hbm5lci4KCi0gICBSZW1vdmluZyBEb2xsYXIgU2lnbnMgYW5kIENvbW1hcyAtIFRoZSBzYWxhcnkgY29sdW1ucyBpbml0aWFsbHkgY29udGFpbmVkIGRvbGxhciBzaWducyBhbmQgY29tbWFzLCBtYWtpbmcgdGhlbSB1bnN1aXRhYmxlIGZvciBudW1lcmljYWwgb3BlcmF0aW9ucy4gV2UgdXNlZCBtdXRhdGUgd2l0aCBhY3Jvc3MgdG8gcmVtb3ZlIHRoZXNlIGNoYXJhY3RlcnMgYW5kIGNvbnZlcnQgdGhlIGNvbHVtbnMgdG8gbnVtZXJpYy4gVGhpcyBzdGVwIHdhcyBuZWNlc3NhcnkgdG8gZW5zdXJlIHRoYXQgdGhlIHNhbGFyeSBkYXRhIGNvdWxkIGJlIGFjY3VyYXRlbHkgYW5hbHl6ZWQgYW5kIG1hbmlwdWxhdGVkLgoKLSAgIFJlc2hhcGluZyB0aGUgRGF0YSAtIFRoZSBwaXZvdF9sb25nZXIgZnVuY3Rpb24gd2FzIHVzZWQgdG8gdHJhbnNmb3JtIHRoZSB3aWRlIGZvcm1hdCBzYWxhcnkgZGF0YSBpbnRvIGEgbG9uZyBmb3JtYXQuIFRoaXMgcmVzdHJ1Y3R1cmluZyBhbGxvd2VkIHVzIHRvIGNvbmRlbnNlIHRoZSBNaWQtQ2FyZWVyIDc1dGggUGVyY2VudGlsZSBTYWxhcnkgYW5kIE1pZC1DYXJlZXIgOTB0aCBQZXJjZW50aWxlIFNhbGFyeSBjb2x1bW5zIGludG8gYSBzaW5nbGUgSGlnaGVyLkNhcmVlci5NZWRpYW4uU2FsYXJ5IGNvbHVtbi4gQW4gYWRkaXRpb25hbCBIaWdoZXIuU2FsYXJ5LlN0YWdlIGNvbHVtbiB3YXMgY3JlYXRlZCB0byBpbmRpY2F0ZSB0aGUgc3RhZ2Ugb2YgdGhlIHNhbGFyeSAoNzV0aCBvciA5MHRoIHBlcmNlbnRpbGUpLiBUaGlzIHJlc2hhcGluZyBhZGhlcmVzIHRvIHRoZSB0aWR5IGRhdGEgcHJpbmNpcGxlcyBieSBlbnN1cmluZyBlYWNoIHZhcmlhYmxlIGhhcyBpdHMgb3duIGNvbHVtbiwgZWFjaCBvYnNlcnZhdGlvbiBoYXMgaXRzIG93biByb3csIGFuZCBlYWNoIHZhbHVlIGhhcyBpdHMgb3duIGNlbGwuIFRoaXMgbWFrZXMgdGhlIGRhdGFzZXQgbW9yZSBjb21wYWN0IGFuZCBlYXNpZXIgdG8gYW5hbHl6ZS4KCjxicj4gPGJyPgoKIyMgKipUaWR5ICYgTWFuaXB1bGF0ZSBEYXRhIElJKioKCmBgYHtyfQojIENyZWF0aW5nIHRoZSBTZWxlY3Rpdml0eSB2YXJpYWJsZSBiYXNlZCBvbiBBZG1pc3Npb24gUmF0ZQp0aWR5X2RhdGFmcmFtZSA8LSB0aWR5X2RhdGFmcmFtZSAlPiUKICBtdXRhdGUoU2VsZWN0aXZpdHkgPSBjYXNlX3doZW4oCiAgICBgQWRtaXNzaW9uLlJhdGVgIDw9IDAuMzAgfiAiSGlnaGx5LlNlbGVjdGl2ZSIsCiAgICBgQWRtaXNzaW9uLlJhdGVgID4gMC4zMCAmIGBBZG1pc3Npb24uUmF0ZWAgPD0gMC42MCB+ICJTZWxlY3RpdmUiLAogICAgYEFkbWlzc2lvbi5SYXRlYCA+IDAuNjAgfiAiTGVzcy5TZWxlY3RpdmUiLAogICAgVFJVRSB+ICJVbmtub3duIgogICkpCgojIERpc3BsYXlpbmcgaGVhZCBvZiB0aGUgdGlkeSBkYXRhIHdpdGggdGhlIG5ldyB2YXJpYWJsZQpoZWFkKHRpZHlfZGF0YWZyYW1lKQpgYGAKClByb3ZpZGUgZXhwbGFuYXRpb25zIGhlcmUuCgpJbiB0aGlzIHN0ZXAsIEkgY3JlYXRlZCBhIG5ldyB2YXJpYWJsZSwgU2VsZWN0aXZpdHksIGJhc2VkIG9uIHRoZSBBZG1pc3Npb24uUmF0ZSBvZiBlYWNoIHVuaXZlcnNpdHkuIFRoaXMgdmFyaWFibGUgY2F0ZWdvcml6ZXMgdW5pdmVyc2l0aWVzIGludG8gZGlmZmVyZW50IGxldmVscyBvZiBzZWxlY3Rpdml0eSwgcHJvdmlkaW5nIGFkZGl0aW9uYWwgaW5zaWdodCBpbnRvIHRoZSBkYXRhc2V0LiBUaGUgY3JlYXRpb24gb2YgdGhlIFNlbGVjdGl2aXR5IHZhcmlhYmxlIGFsbG93cyBmb3IgYSBtb3JlIG51YW5jZWQgYW5hbHlzaXMgb2YgaG93IHRoZSBzZWxlY3Rpdml0eSBvZiBhIHVuaXZlcnNpdHkgbWlnaHQgcmVsYXRlIHRvIG90aGVyIGZhY3RvcnMgc3VjaCBhcyBzYWxhcmllcy4KCi0gICBDcmVhdGUgdGhlIFNlbGVjdGl2aXR5IFZhcmlhYmxlIC0gSSB1dGlsaXplZCB0aGUgY2FzZV93aGVuIGZ1bmN0aW9uIHdpdGhpbiBtdXRhdGUgdG8gY3JlYXRlIHRoZSBTZWxlY3Rpdml0eSB2YXJpYWJsZSBiYXNlZCBvbiB0aGUgQWRtaXNzaW9uLlJhdGUuIFRoZSBjb25kaXRpb25zIHdlcmUgc2V0IHN1Y2ggdGhhdCB1bml2ZXJzaXRpZXMgd2l0aCBhbiBhZG1pc3Npb24gcmF0ZSBvZiAzMCUgb3IgbGVzcyB3ZXJlIGNhdGVnb3JpemVkIGFzICJIaWdobHkuU2VsZWN0aXZlIiwgdGhvc2Ugd2l0aCBhbiBhZG1pc3Npb24gcmF0ZSBiZXR3ZWVuIDMwJSBhbmQgNjAlIGFzICJTZWxlY3RpdmUiLCBhbmQgdGhvc2Ugd2l0aCBhbiBhZG1pc3Npb24gcmF0ZSBhYm92ZSA2MCUgYXMgIkxlc3MuU2VsZWN0aXZlIi4KCjxicj4gPGJyPgoKIyMgKipTY2FuIEkqKgoKYGBge3J9CiMgU2NhbmluZyBmb3IgbWlzc2luZyB2YWx1ZXMKbWlzc2luZ192YWx1ZXMgPC0gY29sU3Vtcyhpcy5uYSh0aWR5X2RhdGFmcmFtZSkpCnByaW50KCJNaXNzaW5nIFZhbHVlczoiKQpwcmludChtaXNzaW5nX3ZhbHVlcykKCiMgUGxvdGluZyB0aGUgbWlzc2luZyB2YWx1ZXMKZ2dfbWlzc192YXIodGlkeV9kYXRhZnJhbWUpICsgdGhlbWVfbWluaW1hbCgpICsgZ2d0aXRsZSgiTWlzc2luZyBWYWx1ZXMgYnkgVmFyaWFibGUiKQoKIyBIYW5kbGUgbWlzc2luZyB2YWx1ZXMKIyBIZXJlIEkgY2hvb3NlIHRvIGZpbGwgbnVtZXJpYyBjb2x1bW5zIHdpdGggdGhlIG1lYW4gYW5kIGZhY3RvciBjb2x1bW5zIHdpdGggdGhlIG1vZGUKdGlkeV9kYXRhZnJhbWUgPC0gdGlkeV9kYXRhZnJhbWUgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiBpZmVsc2UoaXMubmEoLiksIG1lYW4oLiwgbmEucm0gPSBUUlVFKSwgLikpLAogICAgICAgICBhY3Jvc3Mod2hlcmUoaXMuZmFjdG9yKSwgfiBpZmVsc2UoaXMubmEoLiksIGZjdF9tb2RlKC4pLCAuKSkpCgojIENoZWNraW5nIGlmIG1pc3NpbmcgdmFsdWVzIGFyZSBoYW5kbGVkCm1pc3NpbmdfdmFsdWVzX2FmdGVyIDwtIGNvbFN1bXMoaXMubmEodGlkeV9kYXRhZnJhbWUpKQpwcmludCgiTWlzc2luZyBWYWx1ZXMgQWZ0ZXIgSGFuZGxpbmc6IikKcHJpbnQobWlzc2luZ192YWx1ZXNfYWZ0ZXIpCgojIEhhbmRsaW5nIHNwZWNpYWwgdmFsdWVzIChleGFtcGxlOiByZXBsYWNlIEluZiB3aXRoIG1heCBhbmQgLUluZiB3aXRoIG1pbikKdGlkeV9kYXRhZnJhbWUgPC0gdGlkeV9kYXRhZnJhbWUgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiBpZmVsc2UoaXMuaW5maW5pdGUoLiksIE5BLCAuKSkpCgojIFJlY2hlY2sgc3BlY2lhbCB2YWx1ZXMgYWZ0ZXIgaGFuZGxpbmcKc3BlY2lhbF92YWx1ZXNfYWZ0ZXIgPC0gc2FwcGx5KHRpZHlfZGF0YWZyYW1lLCBmdW5jdGlvbih4KSBzdW0oaXMubmFuKHgpIHwgaXMuaW5maW5pdGUoeCkpKQpwcmludCgiU3BlY2lhbCBWYWx1ZXMgQWZ0ZXIgSGFuZGxpbmc6IikKcHJpbnQoc3BlY2lhbF92YWx1ZXNfYWZ0ZXIpCgojIENoZWNrIGZvciBvYnZpb3VzIGVycm9ycyBpbiBmYWN0b3IgdmFyaWFibGVzIChleGFtcGxlOiB1bmV4cGVjdGVkIGxldmVscykKdW5leHBlY3RlZF9sZXZlbHMgPC0gbGFwcGx5KHRpZHlfZGF0YWZyYW1lLCBmdW5jdGlvbih4KSBpZihpcy5mYWN0b3IoeCkpIGxldmVscyh4KSkKcHJpbnQoIlVuZXhwZWN0ZWQgTGV2ZWxzOiIpCnByaW50KHVuZXhwZWN0ZWRfbGV2ZWxzKQpgYGAKClByb3ZpZGUgZXhwbGFuYXRpb25zIGhlcmUuCgpJbiB0aGlzIHN0ZXAsIEkgc2Nhbm5lZCB0aGUgZGF0YXNldCBmb3IgbWlzc2luZyB2YWx1ZXMsIHNwZWNpYWwgdmFsdWVzLCBhbmQgb2J2aW91cyBlcnJvcnMgdG8gZW5zdXJlIGRhdGEgcXVhbGl0eSBhbmQgaW50ZWdyaXR5LgoKLSAgIFNjYW4gZm9yIE1pc3NpbmcgVmFsdWVzIC0gSSB1c2VkIGNvbFN1bXMoaXMubmEodGlkeV9kYXRhZnJhbWUpKSB0byBpZGVudGlmeSB0aGUgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzIGluIGVhY2ggY29sdW1uLiBUaGlzIHN0ZXAgaGVscHMgaW4gdW5kZXJzdGFuZGluZyB0aGUgZXh0ZW50IG9mIG1pc3NpbmcgZGF0YSB3aXRoaW4gdGhlIGRhdGFzZXQuCgotICAgUGxvdCBNaXNzaW5nIFZhbHVlcyAtIFRvIHZpc3VhbGl6ZSB0aGUgZGlzdHJpYnV0aW9uIG9mIG1pc3NpbmcgdmFsdWVzLCBJIHVzZWQgdGhlIGdnX21pc3NfdmFyIGZ1bmN0aW9uIGZyb20gdGhlIG5hbmlhciBwYWNrYWdlLiBUaGlzIHBsb3QgaGVscHMgaW4gcXVpY2tseSBpZGVudGlmeWluZyB3aGljaCB2YXJpYWJsZXMgaGF2ZSBtaXNzaW5nIGRhdGEuCgotICAgSGFuZGxlIE1pc3NpbmcgVmFsdWVzIC0gSSBjaG9zZSB0byBmaWxsIG1pc3NpbmcgdmFsdWVzIGluIG51bWVyaWMgY29sdW1ucyB3aXRoIHRoZSBtZWFuIG9mIHRoZSByZXNwZWN0aXZlIGNvbHVtbnMsIGFuZCBtaXNzaW5nIHZhbHVlcyBpbiBmYWN0b3IgY29sdW1ucyB3aXRoIHRoZSBtb2RlLiBUaGlzIGFwcHJvYWNoIG1haW50YWlucyB0aGUgZGF0YSBkaXN0cmlidXRpb24gd2hpbGUgYWRkcmVzc2luZyB0aGUgbWlzc2luZyB2YWx1ZXMuCgotICAgSGFuZGxlIFNwZWNpYWwgVmFsdWVzIC0gSSBpZGVudGlmaWVkIGFuZCBoYW5kbGVkIHNwZWNpYWwgdmFsdWVzIChlLmcuLCBJbmYsIC1JbmYpIGJ5IHJlcGxhY2luZyB0aGVtIHdpdGggTkEuIFRoaXMgc3RlcCBlbnN1cmVzIHRoYXQgdGhlc2Ugc3BlY2lhbCB2YWx1ZXMgZG8gbm90IGludGVyZmVyZSB3aXRoIHN1YnNlcXVlbnQgYW5hbHlzZXMuCgotICAgQ2hlY2sgZm9yIE9idmlvdXMgRXJyb3JzIGluIEZhY3RvciBWYXJpYWJsZXMgLSBJIGNoZWNrZWQgZm9yIHVuZXhwZWN0ZWQgbGV2ZWxzIGluIGZhY3RvciB2YXJpYWJsZXMgdG8gaWRlbnRpZnkgYW55IG9idmlvdXMgZXJyb3JzLiBUaGlzIHN0ZXAgaGVscHMgZW5zdXJlIHRoYXQgZmFjdG9yIHZhcmlhYmxlcyBoYXZlIGNvbnNpc3RlbnQgYW5kIGV4cGVjdGVkIGxldmVscy4KCjxicj4gPGJyPgoKIyMgKipTY2FuIElJKioKCmBgYHtyfQojIElkZW50aWZ5aW5nIG91dGxpZXJzIHVzaW5nIHRoZSBJUVIgbWV0aG9kCm51bWVyaWNfY29scyA8LSBzZWxlY3RfaWYodGlkeV9kYXRhZnJhbWUsIGlzLm51bWVyaWMpCgojIENhbGN1bGF0aW5nIFExICgyNXRoIHBlcmNlbnRpbGUpIGFuZCBRMyAoNzV0aCBwZXJjZW50aWxlKSBmb3IgZWFjaCBudW1lcmljIGNvbHVtbgpRMSA8LSBhcHBseShudW1lcmljX2NvbHMsIDIsIHF1YW50aWxlLCAwLjI1LCBuYS5ybSA9IFRSVUUpClEzIDwtIGFwcGx5KG51bWVyaWNfY29scywgMiwgcXVhbnRpbGUsIDAuNzUsIG5hLnJtID0gVFJVRSkKSVFSIDwtIFEzIC0gUTEKCiMgRGVmaW5pbmcgb3V0bGllcnMgYXMgdmFsdWVzIGJlbG93IFExIC0gMS41KklRUiBvciBhYm92ZSBRMyArIDEuNSpJUVIKb3V0bGllcnMgPC0gbnVtZXJpY19jb2xzICU+JQogIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCB+ICguIDwgKFExIC0gMS41ICogSVFSKSkgfCAoLiA+IChRMyArIDEuNSAqIElRUikpKSkKCiMgQ291bnRpbmcgb2Ygb3V0bGllcnMgaW4gZWFjaCBjb2x1bW4Kb3V0bGllcnNfY291bnQgPC0gY29sU3VtcyhvdXRsaWVycywgbmEucm0gPSBUUlVFKQpwcmludCgiT3V0bGllcnMgQ291bnQ6IikKcHJpbnQob3V0bGllcnNfY291bnQpCgojIEhhbmRsaW5nIG91dGxpZXJzIGJ5IGNhcHBpbmcgdGhlbSB0byB0aGUgbmVhcmVzdCBub24tb3V0bGllciB2YWx1ZQp0aWR5X2RhdGFmcmFtZSA8LSB0aWR5X2RhdGFmcmFtZSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCB+IGlmZWxzZSguIDwgKFExIC0gMS41ICogSVFSKSwgUTEgLSAxLjUgKiBJUVIsIC4pKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiBpZmVsc2UoLiA+IChRMyArIDEuNSAqIElRUiksIFEzICsgMS41ICogSVFSLCAuKSkpCgojIFZlcmlmeWluZyB0aGUgc3RydWN0dXJlIGFmdGVyIGhhbmRsaW5nIG91dGxpZXJzCnN0cih0aWR5X2RhdGFmcmFtZSkKYGBgCgpQcm92aWRlIGV4cGxhbmF0aW9ucyBoZXJlLgoKSW4gdGhpcyBzdGVwLCBJIHNjYW5uZWQgdGhlIG51bWVyaWMgZGF0YSBmb3Igb3V0bGllcnMgdG8gZW5zdXJlIGRhdGEgY29uc2lzdGVuY3kgYW5kIGludGVncml0eS4KCi0gICBJZGVudGlmeSBPdXRsaWVycyBVc2luZyB0aGUgSVFSIE1ldGhvZCAtIEkgaWRlbnRpZmllZCBvdXRsaWVycyBpbiB0aGUgbnVtZXJpYyBjb2x1bW5zIHVzaW5nIHRoZSBJbnRlcnF1YXJ0aWxlIFJhbmdlIChJUVIpIG1ldGhvZC4gVGhpcyBtZXRob2QgY2FsY3VsYXRlcyB0aGUgcmFuZ2UgYmV0d2VlbiB0aGUgZmlyc3QgcXVhcnRpbGUgKFExKSBhbmQgdGhlIHRoaXJkIHF1YXJ0aWxlIChRMykgYW5kIGRlZmluZXMgb3V0bGllcnMgYXMgdmFsdWVzIGJlbG93IFExIC0gMS41SVFSIG9yIGFib3ZlIFEzICsgMS41SVFSLiBUaGlzIHJvYnVzdCBtZXRob2QgaXMgZWZmZWN0aXZlIGZvciBpZGVudGlmeWluZyBleHRyZW1lIHZhbHVlcyB3aXRob3V0IGJlaW5nIG92ZXJseSBpbmZsdWVuY2VkIGJ5IHRoZW0uCgotICAgSGFuZGxlIE91dGxpZXJzIGJ5IENhcHBpbmcgLSBUbyBoYW5kbGUgdGhlIGlkZW50aWZpZWQgb3V0bGllcnMsIEkgY2FwcGVkIHRoZW0gdG8gdGhlIG5lYXJlc3Qgbm9uLW91dGxpZXIgdmFsdWVzLiBUaGlzIGFwcHJvYWNoIGhlbHBzIG1pdGlnYXRlIHRoZSBpbXBhY3Qgb2YgZXh0cmVtZSB2YWx1ZXMgb24gb3VyIGFuYWx5c2lzIHdoaWxlIHByZXNlcnZpbmcgdGhlIG92ZXJhbGwgZGF0YSBkaXN0cmlidXRpb24uIEJ5IGNhcHBpbmcgdGhlIG91dGxpZXJzLCBJIGVuc3VyZSB0aGF0IHRoZXkgZG8gbm90IGRpc3Byb3BvcnRpb25hdGVseSBpbmZsdWVuY2UgdGhlIHJlc3VsdHMuCgotICAgVmVyaWZ5IHRoZSBTdHJ1Y3R1cmUgQWZ0ZXIgSGFuZGxpbmcgT3V0bGllcnMgLSBBZnRlciBoYW5kbGluZyB0aGUgb3V0bGllcnMsIEkgdmVyaWZpZWQgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YXNldCB0byBlbnN1cmUgdGhhdCB0aGUgY2hhbmdlcyB3ZXJlIGFwcGxpZWQgY29ycmVjdGx5IGFuZCB0aGUgZGF0YXNldCByZW1haW5lZCBjb25zaXN0ZW50LgoKPGJyPiA8YnI+CgojIyAqKlRyYW5zZm9ybSoqCgpgYGB7cn0KIyBTZWxlY3RpbmcgYSAiU3RhcnRpbmdfU2FsYXJ5IiB2YXJpYWJsZSB0byB0cmFuc2Zvcm0KdmFyaWFibGVfdG9fdHJhbnNmb3JtIDwtIHRpZHlfZGF0YWZyYW1lJFN0YXJ0aW5nLk1lZGlhbi5TYWxhcnkKCiMgQXBwbHlpbmcgbG9nIHRyYW5zZm9ybWF0aW9uCnRpZHlfZGF0YWZyYW1lIDwtIHRpZHlfZGF0YWZyYW1lICU+JQogIG11dGF0ZShTdGFydGluZ19TYWxhcnlfTG9nID0gbG9nKFN0YXJ0aW5nLk1lZGlhbi5TYWxhcnkgKyAxKSkKCiMgVmVyaWZ5aW5nIHRoZSBzdHJ1Y3R1cmUgYWZ0ZXIgdHJhbnNmb3JtYXRpb24Kc3RyKHRpZHlfZGF0YWZyYW1lKQoKIyBPcmlnaW5hbGluZyBkaXN0cmlidXRpb24KcDEgPC0gZ2dwbG90KHRpZHlfZGF0YWZyYW1lLCBhZXMoeCA9IFN0YXJ0aW5nLk1lZGlhbi5TYWxhcnkpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gInJlZCIsIGFscGhhID0gMC43KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBnZ3RpdGxlKCJPcmlnaW5hbCBTdGFydGluZyBTYWxhcnkgRGlzdHJpYnV0aW9uIikKCiMgVHJhbnNmb3JtZWRpbmcgZGlzdHJpYnV0aW9uCnAyIDwtIGdncGxvdCh0aWR5X2RhdGFmcmFtZSwgYWVzKHggPSBTdGFydGluZ19TYWxhcnlfTG9nKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICJncmVlbiIsIGFscGhhID0gMC43KSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBnZ3RpdGxlKCJMb2ctVHJhbnNmb3JtZWQgU3RhcnRpbmcgU2FsYXJ5IERpc3RyaWJ1dGlvbiIpCgpwcmludChwMSkKcHJpbnQocDIpCmBgYAoKUHJvdmlkZSBleHBsYW5hdGlvbnMgaGVyZS4KCkluIHRoaXMgc3RlcCwgSSBhcHBsaWVkIGEgbG9nIHRyYW5zZm9ybWF0aW9uIHRvIHRoZSBTdGFydGluZy5NZWRpYW4uU2FsYXJ5IHZhcmlhYmxlIHRvIGFkZHJlc3Mgc2tld25lc3MgYW5kIGJldHRlciB1bmRlcnN0YW5kIHRoZSBkaXN0cmlidXRpb24gb2Ygc3RhcnRpbmcgc2FsYXJpZXMuCgotICAgU2VsZWN0IGEgVmFyaWFibGUgdG8gVHJhbnNmb3JtIC0gSSBzZWxlY3RlZCBTdGFydGluZy5NZWRpYW4uU2FsYXJ5IGZvciB0cmFuc2Zvcm1hdGlvbiBkdWUgdG8gaXRzIGxpa2VseSByaWdodC1za2V3ZWQgZGlzdHJpYnV0aW9uLiBUcmFuc2Zvcm1pbmcgdGhpcyB2YXJpYWJsZSBoZWxwcyB0byByZWR1Y2Ugc2tld25lc3MgYW5kIHN0YWJpbGl6ZSB2YXJpYW5jZSwgbWFraW5nIGl0IG1vcmUgc3VpdGFibGUgZm9yIGFuYWx5c2lzLgoKLSAgIEFwcGx5IExvZyBUcmFuc2Zvcm1hdGlvbiAtIFRoZSBsb2cgdHJhbnNmb3JtYXRpb24gd2FzIGFwcGxpZWQgdG8gdGhlIFN0YXJ0aW5nLk1lZGlhbi5TYWxhcnkgdmFyaWFibGUgYnkgYWRkaW5nIDEgdG8gZWFjaCB2YWx1ZSBhbmQgdGFraW5nIHRoZSBuYXR1cmFsIGxvZ2FyaXRobS4gVGhpcyBhcHByb2FjaCBoYW5kbGVzIHplcm8gdmFsdWVzIGVmZmVjdGl2ZWx5IGFuZCByZWR1Y2VzIHNrZXduZXNzIGluIHRoZSBkaXN0cmlidXRpb24uCgotICAgVmVyaWZ5IHRoZSBTdHJ1Y3R1cmUgQWZ0ZXIgVHJhbnNmb3JtYXRpb24gLSBJIHZlcmlmaWVkIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGFzZXQgdG8gZW5zdXJlIHRoZSBuZXcgU3RhcnRpbmdfU2FsYXJ5X0xvZyB2YXJpYWJsZSB3YXMgYWRkZWQgY29ycmVjdGx5IGFuZCB0aGUgZGF0YXNldCByZW1haW5lZCBjb25zaXN0ZW50LgoKLSAgIFZpc3VhbGl6ZSB0aGUgT3JpZ2luYWwgYW5kIFRyYW5zZm9ybWVkIERpc3RyaWJ1dGlvbnMgLSBVc2luZyBnZ3Bsb3QyLCBJIHZpc3VhbGl6ZWQgdGhlIG9yaWdpbmFsIGFuZCBsb2ctdHJhbnNmb3JtZWQgZGlzdHJpYnV0aW9ucyBvZiB0aGUgU3RhcnRpbmcuTWVkaWFuLlNhbGFyeS4gVGhlIGhpc3RvZ3JhbXMgc2hvdyBob3cgdGhlIGxvZyB0cmFuc2Zvcm1hdGlvbiByZWR1Y2VkIHNrZXduZXNzIGFuZCBtYWRlIHRoZSBkaXN0cmlidXRpb24gbW9yZSBub3JtYWwuCgo8YnI+IDxicj4KCiMjICoqUmVmZXJlbmNlcyoqCgpbMV0gUk1JVCAoMjAyNCkgTW9kdWxlIDQ6IFRpZHkgYW5kIE1hbmlwdWxhdGU6IFRpZHkgRGF0YSBQcmluY2lwbGVzIGFuZCBNYW5pcHVsYXRpbmcgRGF0YSwgRGF0YSBXcmFuZ2xpbmcgKFByZXByb2Nlc3NpbmcpLiBBY2Nlc3NlZCBvbjogKDI1IE1heSAtIDA2IEp1bikvMjAyNC4gTGluazogPGh0dHA6Ly9yYXJlLXBob2VuaXgtMTYxNjEwLmFwcHNwb3QuY29tL3NlY3VyZWQvTW9kdWxlXzA0Lmh0bWw+CgpbMl0gUk1JVCAoMjAyNCkgTW9kdWxlIDU6IFNjYW46IE1pc3NpbmcgVmFsdWVzIERhdGEgV3JhbmdsaW5nIChQcmVwcm9jZXNzaW5nKS4gQWNjZXNzZWQgb246ICgyNSBNYXkgLSAwNiBKdW4pLzIwMjQuIExpbms6IDxodHRwOi8vcmFyZS1waG9lbml4LTE2MTYxMC5hcHBzcG90LmNvbS9zZWN1cmVkL01vZHVsZV8wNS5odG1sPgoKWzNdIFJNSVQgKDIwMjQpIE1vZHVsZSA2OiBTY2FuOiBPdXRsaWVycy4gQWNjZXNzZWQgb246ICgyNSBNYXkgLSAwNiBKdW4pLzIwMjQuIExpbms6IDxodHRwczovL3JhcmUtcGhvZW5peC0+IDE2MTYxMC5hcHBzcG90LmNvbS9zZWN1cmVkL01vZHVsZV8wNi5odG1sCgpbNF0gUk1JVCAoMjAyNCkgTW9kdWxlIDc6IFNjYW46IE1pc3NpbmcgVmFsdWVzLiBBY2Nlc3NlZCBvbjogKDMwIE1heSAtIDA2IEp1bikvMjAyNC4gTGluazogPGh0dHBzOi8vcmFyZS1waG9lbml4LTE2MTYxMC5hcHBzcG90LmNvbS9zZWN1cmVkL01vZHVsZV8wNy5odG1sPgoKWzVdIFF1aWxsQm90IFdlYnNpdGUsIHVzZWQgZm9yIHBhcmFwaHJhc2luZyBteSBleHBsYW5hdGlvbnMuIEFjY2Vzc2VkIG9uOiAoMDIgSnVuIC0gMDYgSnVuKS8yMDI0LiBVUkw6IDxodHRwczovL3F1aWxsYm90LmNvbT4K