Morgan State University
Department of Information Science & Systems
Fall 2024
INSS 615: Data Wrangling for Visualization
Name: Frenandez Lawrence
Due: Dec 1, 2024 (Sunday)
Questions
A. Scrape the College Ranked by Acceptance Rate dataset available at
this link: https://www.oedb.org/rankings/acceptance-rate/#table-rankings
and select the first 9 columns [Rank, School, Student to Faculty Ratio,
Graduation Rate, Retention Rate, Acceptance Rate, Enrollment Rate,
Institutional Aid Rate, and Default Rate] as the dataset for this
assignment. [20 Points]
Hint: There are 6 pages of data, so you may want to use a for loop to
automate the scraping process and combine the data from all 6 pages.
This is just a suggestion—you are free to create the dataset without
automating the web scrapping process.
Solution:
file_path <- "~/Downloads/college_acceptance_data.csv"
# Save the dataset as a CSV file
write.csv(dataset, file = file_path, row.names = FALSE)
# Message to confirm saving
cat("Dataset saved as:", file_path)
Dataset saved as: ~/Downloads/college_acceptance_data.csv
B. You are going to need the dataset created in Question A to answer
the following questions. There are 16 questions each carrying 5
points:
- Replace the missing values “N/A” in the dataset with NA.
Solution:
path = "/Users/frenandezlawrence/Downloads/college_acceptance_data.csv"
data <- read.csv(path)
head(data, n=5)
# Replace "N/A" with NA in the entire dataframe
data_cleaned <- data
data_cleaned[data_cleaned == "N/A"] <- NA
View(data_cleaned)
- Convert percentage columns (e.g., Graduation Rate) to numeric
format.
Solution:
# Load necessary library
library(dplyr)
# Convert percentage columns to numeric
data_cleaned <- data_cleaned %>%
mutate(across(
c(`Graduation.Rate`, `Retention.Rate`, `Acceptance.Rate`, `Enrollment.Rate`, `Institutional.Aid.Rate`, `Default.Rate`),
~ as.numeric(gsub("%", "", .))
))
View(data_cleaned)
- Transform the “Student to Faculty Ratio” column into two separate
numeric columns: Students and Faculty.
Solution:
# Load necessary library
library(dplyr)
library(stringr)
# Extract "Students" and "Faculty" into new columns
data_cleaned <- data_cleaned %>%
mutate(
Students = as.numeric(str_extract(`Student.to.Faculty.Ratio`, "^[0-9]+")),
Faculty = as.numeric(str_extract(`Student.to.Faculty.Ratio`, "[0-9]+$"))
)
View(data_cleaned)
- What is the count of missing values in the “Default Rate” column?
Impute the missing values in the “Default Rate” column with the median
value.
Solution:
missing_count <- sum(is.na(data_cleaned$'Default.Rate'))
print(missing_count)
[1] 0
- Find the average graduation rate for universities ranked in the top
50.
Solution:
# Filter the dataset for top 50 universities
top_50_universities <- data_cleaned %>% filter(Rank <= 50)
# Calculate the average graduation rate
average_graduation_rate <- mean(top_50_universities$`Graduation.Rate`, na.rm = TRUE)
# Display the result
print(average_graduation_rate)
[1] 79.2
- Filter universities with a retention rate above 90% and find the
count of rows in the subset.
Solution:
# Load dplyr
library(dplyr)
# Filter universities with Retention Rate > 90%
high_retention <- data_cleaned %>% filter(`Retention.Rate` > 90)
# Count the rows in the subset
high_retention_count <- nrow(high_retention)
# Display the count
print(high_retention_count)
[1] 300
- Rank universities by enrollment rate in descending order and display
the last 6 rows.
Solution:
# Load dplyr
library(dplyr)
# Rank universities by Enrollment Rate in descending order
ranked_data <- data_cleaned %>% arrange(desc(`Enrollment.Rate`))
# Display the last 6 rows
tail(ranked_data, 6)
NA
- Create a histogram of graduation rates using ggplot2 library.
Solution:
# Load ggplot2
library(ggplot2)
# Create a histogram of Graduation Rates
ggplot(data_cleaned, aes(x = `Graduation.Rate`)) +
geom_histogram(binwidth = 5, fill = "blue", color = "black", alpha = 0.7) +
labs(title = "Histogram of Graduation Rates",
x = "Graduation Rate (%)",
y = "Count") +
theme_minimal()

NA
NA
- Plot a scatterplot between acceptance rate and enrollment rate using
ggplot2 library.
Solution:
# Load ggplot2
library(ggplot2)
# Create a scatterplot
ggplot(data_cleaned, aes(x = `Acceptance.Rate`, y = `Enrollment.Rate`)) +
geom_point(color = "blue", size = 2, alpha = 0.7) +
labs(title = "Scatterplot of Acceptance Rate vs Enrollment Rate",
x = "Acceptance Rate (%)",
y = "Enrollment Rate (%)") +
theme_minimal()

NA
NA
- Calculate the average default rate by aid rate category (e.g.,
grouped into ranges like 0-20%, 20-40%). Display the categories.
Solution:
# Create Aid Rate categories
data_cleaned$AidRateCategory <- cut(
data_cleaned$`Institutional.Aid.Rate`,
breaks = c(0, 20, 40, 60, 80, 100),
labels = c("0-20%", "20-40%", "40-60%", "60-80%", "80-100%"),
include.lowest = TRUE
)
# Load dplyr
library(dplyr)
# Calculate average default rate by aid rate category
average_default_rate <- data_cleaned %>%
group_by(AidRateCategory) %>%
summarize(AverageDefaultRate = mean(`Default.Rate`, na.rm = TRUE))
# Display the result
print(average_default_rate)
NA
NA
- Normalize the acceptance rate to a scale of 0-1 and save in a new
column “Acceptance Rate Normalized”. Display the first 6 values.
Solution:
library(scales)
Attaching package: ‘scales’
The following object is masked from ‘package:purrr’:
discard
The following object is masked from ‘package:readr’:
col_factor
# Normalize Acceptance Rate to 0-1 scale
data_cleaned$`Acceptance Rate Normalized` <- (data_cleaned$`Acceptance.Rate` - min(data_cleaned$`Acceptance.Rate`, na.rm = TRUE)) /
(max(data_cleaned$`Acceptance.Rate`, na.rm = TRUE) - min(data_cleaned$`Acceptance.Rate`, na.rm = TRUE))
# Display the first 6 values of the normalized column
head(data_cleaned$`Acceptance Rate Normalized`)
[1] 0.0000 0.0238 0.0952 0.1905 0.2143 0.2381
- What is the count of the duplicate entries in the “School” column?
Remove duplicate university entries.
Solution:
# Count duplicate entries in the "School" column
duplicate_count <- sum(duplicated(data_cleaned$School))
print(duplicate_count)
[1] 500
# Load dplyr
library(dplyr)
# Remove duplicate entries based on "School"
data_cleaned <- data_cleaned %>% distinct(School, .keep_all = TRUE)
- Find the correlation between graduation rate and retention rate
(exclude the NAs in both columns).
Solution:
# Calculate the correlation between Graduation Rate and Retention Rate
correlation <- cor(data_cleaned$`Graduation.Rate`, data_cleaned$'Retention.Rate', use = "complete.obs")
# Display the result
print(correlation)
[1] 0.805
- Extract the values in School column into a new variable without
“University” in the string. For example “Rowan University” becomes
“Rowan”
Solution:
# Remove "University" from the School column
#school_names <- gsub(" University", "", data_cleaned$School)
#school_names <- gsub("University of ", "", data_cleaned$School)
# Display the result
#print(head(school_names))
# Load stringr
library(stringr)
# Remove "University" from the School column
school_names <- str_replace(data_cleaned$School, " University", "")
# Display the result
print(head(school_names))
[1] "Harvard" "Yale" "University of Pennsylvania" "Johns Hopkins" "Cornell" "Tufts"
- Count how many universities have “Institute” in their name.
Solution:
# Load stringr
library(stringr)
# Count universities with "Institute" in their name
institute_count <- sum(str_detect(data_cleaned$School, "Institute"))
# Display the count
print(institute_count)
[1] 5
- Export the cleaned and processed dataset to a CSV file.
Solution:
file_path <- "~/Downloads/cleaned_college_acceptance_data.csv"
# Save the dataset as a CSV file
write.csv(dataset, file = file_path, row.names = FALSE)
LS0tCnRpdGxlOiAiSU5TUzYxNSBIb21ld29yayA1IgpvdXRwdXQ6CiAgIyB3b3JkX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKLS0tCgoKKipNb3JnYW4gU3RhdGUgVW5pdmVyc2l0eSoqCgoqKkRlcGFydG1lbnQgb2YgSW5mb3JtYXRpb24gU2NpZW5jZSAmIFN5c3RlbXMqKgoKKipGYWxsIDIwMjQqKgoKKipJTlNTIDYxNTogRGF0YSBXcmFuZ2xpbmcgZm9yIFZpc3VhbGl6YXRpb24qKgoKKipOYW1lOiBGcmVuYW5kZXogTGF3cmVuY2UgKioKCipEdWU6IERlYyAxLCAyMDI0IChTdW5kYXkpKgoKCgpRdWVzdGlvbnMKCgpBLiBTY3JhcGUgdGhlIENvbGxlZ2UgUmFua2VkIGJ5IEFjY2VwdGFuY2UgUmF0ZSBkYXRhc2V0IGF2YWlsYWJsZSBhdCB0aGlzIGxpbms6IGh0dHBzOi8vd3d3Lm9lZGIub3JnL3JhbmtpbmdzL2FjY2VwdGFuY2UtcmF0ZS8jdGFibGUtcmFua2luZ3MgYW5kIHNlbGVjdCB0aGUgZmlyc3QgOSBjb2x1bW5zIFtSYW5rLCBTY2hvb2wsIFN0dWRlbnQgdG8gRmFjdWx0eSBSYXRpbywgR3JhZHVhdGlvbiBSYXRlLCBSZXRlbnRpb24gUmF0ZSwgQWNjZXB0YW5jZSBSYXRlLCBFbnJvbGxtZW50IFJhdGUsIEluc3RpdHV0aW9uYWwgQWlkIFJhdGUsIGFuZCBEZWZhdWx0IFJhdGVdIGFzIHRoZSBkYXRhc2V0IGZvciB0aGlzIGFzc2lnbm1lbnQuIFsyMCBQb2ludHNdCgpIaW50OiBUaGVyZSBhcmUgNiBwYWdlcyBvZiBkYXRhLCBzbyB5b3UgbWF5IHdhbnQgdG8gdXNlIGEgZm9yIGxvb3AgdG8gYXV0b21hdGUgdGhlIHNjcmFwaW5nIHByb2Nlc3MgYW5kIGNvbWJpbmUgdGhlIGRhdGEgZnJvbSBhbGwgNiBwYWdlcy4gVGhpcyBpcyBqdXN0IGEgc3VnZ2VzdGlvbuKAlHlvdSBhcmUgZnJlZSB0byBjcmVhdGUgdGhlIGRhdGFzZXQgd2l0aG91dCBhdXRvbWF0aW5nIHRoZSB3ZWIgc2NyYXBwaW5nIHByb2Nlc3MuCgogCiAgU29sdXRpb246CmBgYHtyfQpsaWJyYXJ5KHJ2ZXN0KSAKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZHBseXIpCgojIERlZmluZSB0aGUgYmFzZSBVUkwgYW5kIGFuIGVtcHR5IGxpc3QgdG8gc3RvcmUgZGF0YQpiYXNlX3VybCA8LSAiaHR0cHM6Ly93d3cub2VkYi5vcmcvcmFua2luZ3MvYWNjZXB0YW5jZS1yYXRlLyN0YWJsZS1yYW5raW5ncyIKYWxsX3BhZ2VzX2RhdGEgPC0gbGlzdCgpCgojIExvb3AgdGhyb3VnaCB0aGUgNiBwYWdlcwpmb3IgKHBhZ2UgaW4gMTo2KSB7CiAgIyBDb25zdHJ1Y3QgdGhlIFVSTCBmb3IgZWFjaCBwYWdlIChhZGp1c3QgaWYgbmVjZXNzYXJ5KQogIHBhZ2VfdXJsIDwtIHBhc3RlMChiYXNlX3VybCwgIj9wYWdlPSIsIHBhZ2UpCiAgCiAgIyBTY3JhcGUgdGhlIHBhZ2UKICBwYWdlX2h0bWwgPC0gcmVhZF9odG1sKHBhZ2VfdXJsKQogIAogICMgRXh0cmFjdCB0aGUgdGFibGUgZnJvbSB0aGUgSFRNTAogIHRhYmxlX25vZGUgPC0gaHRtbF9ub2RlKHBhZ2VfaHRtbCwgInRhYmxlIikKICAKICAjIFJlYWQgdGhlIHRhYmxlIGludG8gYSBkYXRhZnJhbWUKICBpZiAoIWlzLm51bGwodGFibGVfbm9kZSkpIHsKICAgIHBhZ2VfZGF0YSA8LSBodG1sX3RhYmxlKHRhYmxlX25vZGUsIGZpbGwgPSBUUlVFKQogICAgYWxsX3BhZ2VzX2RhdGFbW3BhZ2VdXSA8LSBwYWdlX2RhdGEKICB9IGVsc2UgewogICAgbWVzc2FnZSgiVGFibGUgbm90IGZvdW5kIG9uIHBhZ2U6ICIsIHBhZ2UpCiAgfQp9CgojIENvbWJpbmUgZGF0YSBmcm9tIGFsbCBwYWdlcyBpbnRvIGEgc2luZ2xlIGRhdGFmcmFtZQpkYXRhc2V0IDwtIGJpbmRfcm93cyhhbGxfcGFnZXNfZGF0YSkKCiMgU2VsZWN0IHRoZSBmaXJzdCA5IHJlcXVpcmVkIGNvbHVtbnMKc2VsZWN0ZWRfY29sdW1ucyA8LSBjKAogICJSYW5rIiwgIlNjaG9vbCIsICJTdHVkZW50IHRvIEZhY3VsdHkgUmF0aW8iLCAiR3JhZHVhdGlvbiBSYXRlIiwKICAiUmV0ZW50aW9uIFJhdGUiLCAiQWNjZXB0YW5jZSBSYXRlIiwgIkVucm9sbG1lbnQgUmF0ZSIsIAogICJJbnN0aXR1dGlvbmFsIEFpZCBSYXRlIiwgIkRlZmF1bHQgUmF0ZSIKKQpkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIHNlbGVjdChhbGxfb2Yoc2VsZWN0ZWRfY29sdW1ucykpCgojIFJlcGxhY2UgIk4vQSIgd2l0aCBOQQojZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgfiBuYV9pZigueCwgIk4vQSIpKSkKCiMgRGlzcGxheSB0aGUgY2xlYW5lZCBkYXRhc2V0CnByaW50KGRhdGFzZXQpCgpmaWxlX3BhdGggPC0gIn4vRG93bmxvYWRzL2NvbGxlZ2VfYWNjZXB0YW5jZV9kYXRhLmNzdiIKCiMgU2F2ZSB0aGUgZGF0YXNldCBhcyBhIENTViBmaWxlCndyaXRlLmNzdihkYXRhc2V0LCBmaWxlID0gZmlsZV9wYXRoLCByb3cubmFtZXMgPSBGQUxTRSkKCiMgTWVzc2FnZSB0byBjb25maXJtIHNhdmluZwpjYXQoIkRhdGFzZXQgc2F2ZWQgYXM6IiwgZmlsZV9wYXRoKQoKCiMgbXVsdGlwYWdlIHNjcmFwaW5nIHVzaW5nIGEgZm9yIGxvb3AKCgpgYGAKCkIuIFlvdSBhcmUgZ29pbmcgdG8gbmVlZCB0aGUgZGF0YXNldCBjcmVhdGVkIGluIFF1ZXN0aW9uIEEgdG8gYW5zd2VyIHRoZSBmb2xsb3dpbmcgcXVlc3Rpb25zLiBUaGVyZSBhcmUgMTYgcXVlc3Rpb25zIGVhY2ggY2FycnlpbmcgNSBwb2ludHM6CgoxLiBSZXBsYWNlIHRoZSBtaXNzaW5nIHZhbHVlcyAiTi9BIiBpbiB0aGUgZGF0YXNldCB3aXRoIE5BLgoKCiAgU29sdXRpb246CmBgYHtyfQpwYXRoID0gIi9Vc2Vycy9mcmVuYW5kZXpsYXdyZW5jZS9Eb3dubG9hZHMvY29sbGVnZV9hY2NlcHRhbmNlX2RhdGEuY3N2IgpkYXRhIDwtIHJlYWQuY3N2KHBhdGgpCmhlYWQoZGF0YSwgbj01KQoKIyBSZXBsYWNlICJOL0EiIHdpdGggTkEgaW4gdGhlIGVudGlyZSBkYXRhZnJhbWUKZGF0YV9jbGVhbmVkIDwtIGRhdGEKZGF0YV9jbGVhbmVkW2RhdGFfY2xlYW5lZCA9PSAiTi9BIl0gPC0gTkEKCgpWaWV3KGRhdGFfY2xlYW5lZCkKYGBgCgoyLiBDb252ZXJ0IHBlcmNlbnRhZ2UgY29sdW1ucyAoZS5nLiwgR3JhZHVhdGlvbiBSYXRlKSB0byBudW1lcmljIGZvcm1hdC4KCiAgCiAgU29sdXRpb246CmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcnkKbGlicmFyeShkcGx5cikKCiMgQ29udmVydCBwZXJjZW50YWdlIGNvbHVtbnMgdG8gbnVtZXJpYwpkYXRhX2NsZWFuZWQgPC0gZGF0YV9jbGVhbmVkICU+JQogIG11dGF0ZShhY3Jvc3MoCiAgICBjKCdHcmFkdWF0aW9uLlJhdGUnLCAnUmV0ZW50aW9uLlJhdGUnLCAnQWNjZXB0YW5jZS5SYXRlJywgJ0Vucm9sbG1lbnQuUmF0ZScsICdJbnN0aXR1dGlvbmFsLkFpZC5SYXRlJywgJ0RlZmF1bHQuUmF0ZScpLCAKICAgIH4gYXMubnVtZXJpYyhnc3ViKCIlIiwgIiIsIC4pKQogICkpCgpgYGAKCgozLiBUcmFuc2Zvcm0gdGhlICJTdHVkZW50IHRvIEZhY3VsdHkgUmF0aW8iIGNvbHVtbiBpbnRvIHR3byBzZXBhcmF0ZSBudW1lcmljIGNvbHVtbnM6IFN0dWRlbnRzIGFuZCBGYWN1bHR5LgoKCiAgU29sdXRpb246CmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcnkKbGlicmFyeShkcGx5cikKbGlicmFyeShzdHJpbmdyKQoKIyBFeHRyYWN0ICJTdHVkZW50cyIgYW5kICJGYWN1bHR5IiBpbnRvIG5ldyBjb2x1bW5zCmRhdGFfY2xlYW5lZCA8LSBkYXRhX2NsZWFuZWQgJT4lCiAgbXV0YXRlKAogICAgU3R1ZGVudHMgPSBhcy5udW1lcmljKHN0cl9leHRyYWN0KCdTdHVkZW50LnRvLkZhY3VsdHkuUmF0aW8nLCAiXlswLTldKyIpKSwKICAgIEZhY3VsdHkgPSBhcy5udW1lcmljKHN0cl9leHRyYWN0KCdTdHVkZW50LnRvLkZhY3VsdHkuUmF0aW8nLCAiWzAtOV0rJCIpKQogICkKCmBgYAoKCgoKNC4gV2hhdCBpcyB0aGUgY291bnQgb2YgbWlzc2luZyB2YWx1ZXMgaW4gdGhlICJEZWZhdWx0IFJhdGUiIGNvbHVtbj8gSW1wdXRlIHRoZSBtaXNzaW5nIHZhbHVlcyBpbiB0aGUgIkRlZmF1bHQgUmF0ZSIgY29sdW1uIHdpdGggdGhlIG1lZGlhbiB2YWx1ZS4KCgogIFNvbHV0aW9uOgpgYGB7cn0KIyBDb3VudCB0aGUgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzIGluICJEZWZhdWx0IFJhdGUiCm1pc3NpbmdfY291bnQgPC0gc3VtKGlzLm5hKGRhdGFfY2xlYW5lZCQnRGVmYXVsdC5SYXRlJykpCnByaW50KG1pc3NpbmdfY291bnQpCgojIENhbGN1bGF0ZSB0aGUgbWVkaWFuIG9mIHRoZSAiRGVmYXVsdCBSYXRlIiBjb2x1bW4KbWVkaWFuX2RlZmF1bHRfcmF0ZSA8LSBtZWRpYW4oZGF0YV9jbGVhbmVkJCdEZWZhdWx0LlJhdGUnLCBuYS5ybSA9IFRSVUUpCgojIFJlcGxhY2UgbWlzc2luZyB2YWx1ZXMgd2l0aCB0aGUgbWVkaWFuCmRhdGFfY2xlYW5lZCQnRGVmYXVsdC5SYXRlJ1tpcy5uYShkYXRhX2NsZWFuZWQkJ0RlZmF1bHQuUmF0ZScpXSA8LSBtZWRpYW5fZGVmYXVsdF9yYXRlCgpWaWV3KGRhdGFfY2xlYW5lZCkKYGBgCgoKNS4gRmluZCB0aGUgYXZlcmFnZSBncmFkdWF0aW9uIHJhdGUgZm9yIHVuaXZlcnNpdGllcyByYW5rZWQgaW4gdGhlIHRvcCA1MC4KCgogIFNvbHV0aW9uOgpgYGB7cn0KIyBGaWx0ZXIgdGhlIGRhdGFzZXQgZm9yIHRvcCA1MCB1bml2ZXJzaXRpZXMKdG9wXzUwX3VuaXZlcnNpdGllcyA8LSBkYXRhX2NsZWFuZWQgJT4lIGZpbHRlcihSYW5rIDw9IDUwKQoKIyBDYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgZ3JhZHVhdGlvbiByYXRlCmF2ZXJhZ2VfZ3JhZHVhdGlvbl9yYXRlIDwtIG1lYW4odG9wXzUwX3VuaXZlcnNpdGllcyQnR3JhZHVhdGlvbi5SYXRlJywgbmEucm0gPSBUUlVFKQoKIyBEaXNwbGF5IHRoZSByZXN1bHQKcHJpbnQoYXZlcmFnZV9ncmFkdWF0aW9uX3JhdGUpCgoKYGBgCgoKNi4gRmlsdGVyIHVuaXZlcnNpdGllcyB3aXRoIGEgcmV0ZW50aW9uIHJhdGUgYWJvdmUgOTAlIGFuZCBmaW5kIHRoZSBjb3VudCBvZiByb3dzIGluIHRoZSBzdWJzZXQuCgoKICBTb2x1dGlvbjoKYGBge3J9CiMgTG9hZCBkcGx5cgpsaWJyYXJ5KGRwbHlyKQoKIyBGaWx0ZXIgdW5pdmVyc2l0aWVzIHdpdGggUmV0ZW50aW9uIFJhdGUgPiA5MCUKaGlnaF9yZXRlbnRpb24gPC0gZGF0YV9jbGVhbmVkICU+JSBmaWx0ZXIoJ1JldGVudGlvbi5SYXRlJyA+IDkwKQoKIyBDb3VudCB0aGUgcm93cyBpbiB0aGUgc3Vic2V0CmhpZ2hfcmV0ZW50aW9uX2NvdW50IDwtIG5yb3coaGlnaF9yZXRlbnRpb24pCgojIERpc3BsYXkgdGhlIGNvdW50CnByaW50KGhpZ2hfcmV0ZW50aW9uX2NvdW50KQoKCmBgYAoKCjcuIFJhbmsgdW5pdmVyc2l0aWVzIGJ5IGVucm9sbG1lbnQgcmF0ZSBpbiBkZXNjZW5kaW5nIG9yZGVyIGFuZCBkaXNwbGF5IHRoZSBsYXN0IDYgcm93cy4KCgogIFNvbHV0aW9uOgpgYGB7cn0KIyBMb2FkIGRwbHlyCmxpYnJhcnkoZHBseXIpCgojIFJhbmsgdW5pdmVyc2l0aWVzIGJ5IEVucm9sbG1lbnQgUmF0ZSBpbiBkZXNjZW5kaW5nIG9yZGVyCnJhbmtlZF9kYXRhIDwtIGRhdGFfY2xlYW5lZCAlPiUgYXJyYW5nZShkZXNjKCdFbnJvbGxtZW50LlJhdGUnKSkKCiMgRGlzcGxheSB0aGUgbGFzdCA2IHJvd3MKdGFpbChyYW5rZWRfZGF0YSwgNikKCmBgYAoKCjguIENyZWF0ZSBhIGhpc3RvZ3JhbSBvZiBncmFkdWF0aW9uIHJhdGVzIHVzaW5nIGdncGxvdDIgbGlicmFyeS4KCgogIFNvbHV0aW9uOgpgYGB7cn0KIyBMb2FkIGdncGxvdDIKbGlicmFyeShnZ3Bsb3QyKQoKIyBDcmVhdGUgYSBoaXN0b2dyYW0gb2YgR3JhZHVhdGlvbiBSYXRlcwpnZ3Bsb3QoZGF0YV9jbGVhbmVkLCBhZXMoeCA9ICdHcmFkdWF0aW9uLlJhdGUnKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSwgZmlsbCA9ICJibHVlIiwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNykgKwogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtIG9mIEdyYWR1YXRpb24gUmF0ZXMiLAogICAgICAgeCA9ICJHcmFkdWF0aW9uIFJhdGUgKCUpIiwKICAgICAgIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbWluaW1hbCgpCgoKYGBgCgoKOS4gUGxvdCBhIHNjYXR0ZXJwbG90IGJldHdlZW4gYWNjZXB0YW5jZSByYXRlIGFuZCBlbnJvbGxtZW50IHJhdGUgdXNpbmcgZ2dwbG90MiBsaWJyYXJ5LgoKCiAgU29sdXRpb246CmBgYHtyfQojIExvYWQgZ2dwbG90MgpsaWJyYXJ5KGdncGxvdDIpCgojIENyZWF0ZSBhIHNjYXR0ZXJwbG90CmdncGxvdChkYXRhX2NsZWFuZWQsIGFlcyh4ID0gJ0FjY2VwdGFuY2UuUmF0ZScsIHkgPSAnRW5yb2xsbWVudC5SYXRlJykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gImJsdWUiLCBzaXplID0gMiwgYWxwaGEgPSAwLjcpICsKICBsYWJzKHRpdGxlID0gIlNjYXR0ZXJwbG90IG9mIEFjY2VwdGFuY2UgUmF0ZSB2cyBFbnJvbGxtZW50IFJhdGUiLAogICAgICAgeCA9ICJBY2NlcHRhbmNlIFJhdGUgKCUpIiwKICAgICAgIHkgPSAiRW5yb2xsbWVudCBSYXRlICglKSIpICsKICB0aGVtZV9taW5pbWFsKCkKCgpgYGAKCgoxMC4gQ2FsY3VsYXRlIHRoZSBhdmVyYWdlIGRlZmF1bHQgcmF0ZSBieSBhaWQgcmF0ZSBjYXRlZ29yeSAoZS5nLiwgZ3JvdXBlZCBpbnRvIHJhbmdlcyBsaWtlIDAtMjAlLCAyMC00MCUpLiBEaXNwbGF5IHRoZSBjYXRlZ29yaWVzLgoKCiAgU29sdXRpb246CmBgYHtyfQojIENyZWF0ZSBBaWQgUmF0ZSBjYXRlZ29yaWVzCmRhdGFfY2xlYW5lZCRBaWRSYXRlQ2F0ZWdvcnkgPC0gY3V0KAogIGRhdGFfY2xlYW5lZCQnSW5zdGl0dXRpb25hbC5BaWQuUmF0ZScsCiAgYnJlYWtzID0gYygwLCAyMCwgNDAsIDYwLCA4MCwgMTAwKSwKICBsYWJlbHMgPSBjKCIwLTIwJSIsICIyMC00MCUiLCAiNDAtNjAlIiwgIjYwLTgwJSIsICI4MC0xMDAlIiksCiAgaW5jbHVkZS5sb3dlc3QgPSBUUlVFCikKCiMgTG9hZCBkcGx5cgpsaWJyYXJ5KGRwbHlyKQoKIyBDYWxjdWxhdGUgYXZlcmFnZSBkZWZhdWx0IHJhdGUgYnkgYWlkIHJhdGUgY2F0ZWdvcnkKYXZlcmFnZV9kZWZhdWx0X3JhdGUgPC0gZGF0YV9jbGVhbmVkICU+JQogIGdyb3VwX2J5KEFpZFJhdGVDYXRlZ29yeSkgJT4lCiAgc3VtbWFyaXplKEF2ZXJhZ2VEZWZhdWx0UmF0ZSA9IG1lYW4oJ0RlZmF1bHQuUmF0ZScsIG5hLnJtID0gVFJVRSkpCgojIERpc3BsYXkgdGhlIHJlc3VsdApwcmludChhdmVyYWdlX2RlZmF1bHRfcmF0ZSkKCgpgYGAKCgoKCjExLiBOb3JtYWxpemUgdGhlIGFjY2VwdGFuY2UgcmF0ZSB0byBhIHNjYWxlIG9mIDAtMSBhbmQgc2F2ZSBpbiBhIG5ldyBjb2x1bW4gIkFjY2VwdGFuY2UgUmF0ZSBOb3JtYWxpemVkIi4gRGlzcGxheSB0aGUgZmlyc3QgNiB2YWx1ZXMuCgoKICBTb2x1dGlvbjoKIApgYGB7cn0KbGlicmFyeShzY2FsZXMpCiMgTm9ybWFsaXplIEFjY2VwdGFuY2UgUmF0ZSB0byAwLTEgc2NhbGUKZGF0YV9jbGVhbmVkJGBBY2NlcHRhbmNlIFJhdGUgTm9ybWFsaXplZGAgPC0gKGRhdGFfY2xlYW5lZCQnQWNjZXB0YW5jZS5SYXRlJyAtIG1pbihkYXRhX2NsZWFuZWQkJ0FjY2VwdGFuY2UuUmF0ZScsIG5hLnJtID0gVFJVRSkpIC8gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChtYXgoZGF0YV9jbGVhbmVkJCdBY2NlcHRhbmNlLlJhdGUnLCBuYS5ybSA9IFRSVUUpIC0gbWluKGRhdGFfY2xlYW5lZCQnQWNjZXB0YW5jZS5SYXRlJywgbmEucm0gPSBUUlVFKSkKCiMgRGlzcGxheSB0aGUgZmlyc3QgNiB2YWx1ZXMgb2YgdGhlIG5vcm1hbGl6ZWQgY29sdW1uCmhlYWQoZGF0YV9jbGVhbmVkJCdBY2NlcHRhbmNlIFJhdGUgTm9ybWFsaXplZCcpCgoKYGBgCgoxMi4gV2hhdCBpcyB0aGUgY291bnQgb2YgdGhlIGR1cGxpY2F0ZSBlbnRyaWVzIGluIHRoZSAiU2Nob29sIiBjb2x1bW4/IFJlbW92ZSBkdXBsaWNhdGUgdW5pdmVyc2l0eSBlbnRyaWVzLgoKCiBTb2x1dGlvbjoKCmBgYHtyfQojIENvdW50IGR1cGxpY2F0ZSBlbnRyaWVzIGluIHRoZSAiU2Nob29sIiBjb2x1bW4KZHVwbGljYXRlX2NvdW50IDwtIHN1bShkdXBsaWNhdGVkKGRhdGFfY2xlYW5lZCRTY2hvb2wpKQpwcmludChkdXBsaWNhdGVfY291bnQpCgojIExvYWQgZHBseXIKbGlicmFyeShkcGx5cikKCiMgUmVtb3ZlIGR1cGxpY2F0ZSBlbnRyaWVzIGJhc2VkIG9uICJTY2hvb2wiCmRhdGFfY2xlYW5lZCA8LSBkYXRhX2NsZWFuZWQgJT4lIGRpc3RpbmN0KFNjaG9vbCwgLmtlZXBfYWxsID0gVFJVRSkKCgpgYGAKCgoxMy4gRmluZCB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBncmFkdWF0aW9uIHJhdGUgYW5kIHJldGVudGlvbiByYXRlIChleGNsdWRlIHRoZSBOQXMgaW4gYm90aCBjb2x1bW5zKS4KCgogU29sdXRpb246CgpgYGB7cn0KIyBDYWxjdWxhdGUgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gR3JhZHVhdGlvbiBSYXRlIGFuZCBSZXRlbnRpb24gUmF0ZQpjb3JyZWxhdGlvbiA8LSBjb3IoZGF0YV9jbGVhbmVkJGBHcmFkdWF0aW9uLlJhdGVgLCBkYXRhX2NsZWFuZWQkJ1JldGVudGlvbi5SYXRlJywgdXNlID0gImNvbXBsZXRlLm9icyIpCgojIERpc3BsYXkgdGhlIHJlc3VsdApwcmludChjb3JyZWxhdGlvbikKCgpgYGAKCgoKMTQuIEV4dHJhY3QgdGhlIHZhbHVlcyBpbiBTY2hvb2wgY29sdW1uIGludG8gYSBuZXcgdmFyaWFibGUgd2l0aG91dCAiVW5pdmVyc2l0eSIgaW4gdGhlIHN0cmluZy4gRm9yIGV4YW1wbGUgIlJvd2FuIFVuaXZlcnNpdHkiIGJlY29tZXMgIlJvd2FuIgoKCiBTb2x1dGlvbjoKCmBgYHtyfQojIFJlbW92ZSAiVW5pdmVyc2l0eSIgZnJvbSB0aGUgU2Nob29sIGNvbHVtbgojVGhlIGV4YXBsZSBwcm92aWRlZCB3YXMgZm9yIHNjaG9vbHMgdGhhdCBoYWQgdW5pdmVyc2l0eSBhdCBhcyB0aGUgc2Vjb25kIHBvcnRpb24gb2YgdGhlIHN0cmluZywgaGVuY2UgdGhlIHNvbHV0aW9uIHdhcyB3cml0dGVuIGxpa2UgdGhhdC4gCgojIExvYWQgc3RyaW5ncgpsaWJyYXJ5KHN0cmluZ3IpCgojIFJlbW92ZSAiVW5pdmVyc2l0eSIgZnJvbSB0aGUgU2Nob29sIGNvbHVtbgpzY2hvb2xfbmFtZXMgPC0gc3RyX3JlcGxhY2UoZGF0YV9jbGVhbmVkJFNjaG9vbCwgIiBVbml2ZXJzaXR5IiwgIiIpCgoKIyBEaXNwbGF5IHRoZSByZXN1bHQKcHJpbnQoaGVhZChzY2hvb2xfbmFtZXMpKQoKYGBgCgoKCgoxNS4gQ291bnQgaG93IG1hbnkgdW5pdmVyc2l0aWVzIGhhdmUgIkluc3RpdHV0ZSIgaW4gdGhlaXIgbmFtZS4KCgogU29sdXRpb246CgpgYGB7cn0KIyBMb2FkIHN0cmluZ3IKbGlicmFyeShzdHJpbmdyKQoKIyBDb3VudCB1bml2ZXJzaXRpZXMgd2l0aCAiSW5zdGl0dXRlIiBpbiB0aGVpciBuYW1lCmluc3RpdHV0ZV9jb3VudCA8LSBzdW0oc3RyX2RldGVjdChkYXRhX2NsZWFuZWQkU2Nob29sLCAiSW5zdGl0dXRlIikpCgojIERpc3BsYXkgdGhlIGNvdW50CnByaW50KGluc3RpdHV0ZV9jb3VudCkKCgoKYGBgCgoxNi4gRXhwb3J0IHRoZSBjbGVhbmVkIGFuZCBwcm9jZXNzZWQgZGF0YXNldCB0byBhIENTViBmaWxlLgoKCiBTb2x1dGlvbjoKCmBgYHtyfQpmaWxlX3BhdGggPC0gIn4vRG93bmxvYWRzL2NsZWFuZWRfY29sbGVnZV9hY2NlcHRhbmNlX2RhdGEuY3N2IgoKIyBTYXZlIHRoZSBkYXRhc2V0IGFzIGEgQ1NWIGZpbGUKd3JpdGUuY3N2KGRhdGFzZXQsIGZpbGUgPSBmaWxlX3BhdGgsIHJvdy5uYW1lcyA9IEZBTFNFKQoKCmBgYAoK