knitr::opts_chunk$set(
    echo = TRUE,
    message = FALSE,
    warning = FALSE
)

Introduction to R for Education Data Analysis and Visualization

1. What is R?

R is a powerful, open-source programming language and environment for statistical computing and graphics. It’s widely used in academia, research, and industry for data analysis, visualization, and machine learning.

Key features of R:

  • Free and open-source - Extensive package ecosystem (over 18,000 packages on CRAN)
  • Strong community support
  • Excellent for data manipulation and visualization
  • Cross-platform compatibility (Windows, Mac, Linux)

History:

  • Inspired by the S programming language (1970s)
  • First released in 1993
  • The “Tidyverse” and Rstudio in the 2010s made it much easier to get started
  • 1/2 primary systems for Data Science (the other being Python)

Why R for Education Data Analysis?

  • Tailored for statistical analysis
  • Reproducible research capabilities
  • Flexibility in data manipulation and visualization
  • Integration with other tools (e.g., databases, web applications, PowerBI)
  • Active community in educational research
# Simple example of an R command
print("Hello, Education Data Analysts!")
[1] "Hello, Education Data Analysts!"

2. R Tools and Packages

2.1 Base R

Using Base R as a calculator

# Basic arithmetic
2 + 5
[1] 7
10 / 3
[1] 3.333333

Explanation: This block demonstrates basic arithmetic operations in R. It shows addition and division. R can be used as a simple calculator.

# Creating a vector
numbers <- c(1, 2, 3, 4, 5)

numbers
[1] 1 2 3 4 5

Explanation: This creates a vector named ‘numbers’ using the c() function, which combines values into a vector. The vector is then displayed.

numbers * 2
[1]  2  4  6  8 10
( numbers/max(numbers) ) * 100
[1]  20  40  60  80 100

Explanation: This shows vector arithmetic. Each element of the ‘numbers’ vector is multiplied by 2 or scaled to percent.

mean(numbers)
[1] 3
median(numbers)
[1] 3
sd(numbers)
[1] 1.581139

Explanation: These are basic statistical functions. mean() calculates the average, median() finds the middle value, and sd() computes the standard deviation of the ‘numbers’ vector.

# Creating a simple function
square <- function(x) {
  return(x^2)
}
square(4)
[1] 16

Explanation: This defines a custom function named ‘square’ that takes an input ‘x’ and returns its square. The function is then called with the argument 4.

# Working with data frames
df <- data.frame(
  name = c("Alice", "Bob", "Charlie"),
  age = c(10, 11, 9),
  score = c(85, 92, 78)
)
print(df)

Explanation: This creates a data frame, a fundamental data structure in R for storing tabular data. It has three columns: name, age, and score. The data frame is then printed.

Note: data frames are typically not entered manually like this, but imported from a file or connection to a database.

summary(df)
     name                age           score     
 Length:3           Min.   : 9.0   Min.   :78.0  
 Class :character   1st Qu.: 9.5   1st Qu.:81.5  
 Mode  :character   Median :10.0   Median :85.0  
                    Mean   :10.0   Mean   :85.0  
                    3rd Qu.:10.5   3rd Qu.:88.5  
                    Max.   :11.0   Max.   :92.0  

Explanation: The summary() function provides a statistical summary of the data frame, including min, max, mean, and median for numeric columns, and frequency for categorical columns.

For public discussion, we often generate synthetic data to run code

# Generate synthetic data
data <- data.frame(
  name = sample(c("Alice", "Bob", "Charlie", "David", "Emma"), 20, replace = TRUE),
  subject = sample(c("Math", "English", "Science", "Math", "English"), 20, replace = TRUE),
  age = sample(9:11, 20, replace = TRUE),
  score = round(rnorm(20, mean = 85, sd = 7))
)

# Display the generated data frame
print(data)

2.2 Tidyverse

Tidyverse is a collection of R packages designed for data science, following consistent design philosophies.

# Load tidyverse
library(tidyverse)
── Attaching core tidyverse packages ───────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ─────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors

2.2.1 dplyr for data manipulation

dplyr provides a grammar of data manipulation, with key verbs like: - filter(): subset rows - select(): choose columns - mutate(): create new variables - arrange(): reorder rows - summarise(): reduce variables to values



# Filter and arrange
data %>%
  filter(score > 80) %>%
  arrange(desc(score))

# Group and summarize
data %>%
  group_by(subject) %>%
  summarise(
    avg_score = mean(score),
    count = n()
  )

# Create new variables
data %>%
  mutate(
    grade = case_when(
      score >= 90 ~ "A",
      score >= 80 ~ "B",
      score >= 70 ~ "C",
      TRUE ~ "D"
    )
  )

2.2.2 ggplot2 for data visualization

ggplot2 is based on the grammar of graphics, allowing you to build complex plots from simple components.

# Basic scatter plot
ggplot(data, aes(x = name, y = score)) +
  geom_point() +
  theme_minimal() +
  labs(title = "Student Scores", x = "Student Name", y = "Score")

# Bar plot with grouping
ggplot(data, aes(x = subject, y = score, fill = subject)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  labs(title = "Scores by Subject", x = "Subject", y = "Score")

# Boxplot with y-axis scaled from 0 to 100
ggplot(data, aes(x = subject, y = score)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "Score Distribution by Subject", x = "Subject", y = "Score") +
  scale_y_continuous(limits = c(50, 100), breaks = seq(50, 100, by = 20))

3. R Environments

3.1 RStudio

RStudio is an integrated development environment (IDE) for R, enhancing productivity and ease of use.

Features: - Code editor with syntax highlighting and auto-completion - Console for immediate code execution - Environment pane for managing objects and data - Plot viewer for visualizations - Help documentation and package management - Project management capabilities - Version control integration (Git)

3.2 R Notebooks

R Notebooks allow for interactive, literate programming, combining code, output, and narrative text.

Benefits: - Reproducible research - Easy sharing of analysis and results - Inline code execution - Multiple output formats (HTML, PDF, Word)

4. Practical Examples for Education Data Analysis

4.1 Another Example Generating Synthetic Student Data

set.seed(123)
student_data <- tibble(
  student_id = 1:200,
  gender = sample(c("Male", "Female"), 200, replace = TRUE),
  grade_level = sample(9:12, 200, replace = TRUE),
  program = sample(c("General", "Honors", "AP"), 200, replace = TRUE, prob = c(0.5, 0.3, 0.2)),
  math_score = rnorm(200, mean = 75, sd = 15),
  reading_score = rnorm(200, mean = 70, sd = 12),
  attendance_rate = rbeta(200, shape1 = 5, shape2 = 1) * 100
)

# View the first few rows
head(student_data)

# Summary statistics
summary(student_data)

4.2 Data Exploration and Visualization

# Distribution of math scores
ggplot(student_data, aes(x = math_score)) +
  geom_histogram(binwidth = 5, fill = "skyblue", color = "black") +
  theme_minimal() +
  labs(title = "Distribution of Math Scores", x = "Math Score", y = "Count")

# Boxplot of reading scores by program
ggplot(student_data, aes(x = program, y = reading_score, fill = program)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "Reading Scores by Program", x = "Program", y = "Reading Score")

# Scatter plot of math vs reading scores
ggplot(student_data, aes(x = math_score, y = reading_score, color = program)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "lm", se = FALSE) +
  theme_minimal() +
  labs(title = "Math vs Reading Scores by Program", x = "Math Score", y = "Reading Score")

4.3 Statistical Analysis

4.3.1 T-test: Comparing Math Scores by Gender

t_test_result <- t.test(math_score ~ gender, data = student_data)
print(t_test_result)

4.3.2 ANOVA: Comparing Reading Scores Across Programs

anova_result <- aov(reading_score ~ program, data = student_data)
summary(anova_result)

4.3.3 Linear Regression: Predicting Math Scores

model <- lm(math_score ~ reading_score + attendance_rate + program, data = student_data)
summary(model)

5. AI for R Code Generation

AI tools can be helpful for generating R code snippets, especially for beginners. However, it’s important to understand the code and verify its correctness.

Benefits:

  • Quick prototyping
  • Learning new functions and packages -Troubleshooting errors
  • Data isn’t exposed

Cautions:

  • Always review and understand generated code
  • Verify results and check for errors
  • Use as a learning tool, not a replacement for understanding

Use a prompt at the beginning of your chat session:

“You are my tutor helping me learn and understand R programming for data analysis and visualization in the education research field. I will be sharing questions, ideas, and code snippets with you and I need you to provide examples and explanations that are detailed and clearly presented for someone just starting out. Don’t provide complex code, or use new packages or functions without explaining them. Be an effective teacher and tutor for learning R, Rstudio, the tidyverse. …”

An effective prompt will avoid it generating large, complex, possibly broken code, and make sure it is explained in a way that you can learn from.

6. Resources for Further Learning

R Project

Posit

Community Resources

7. Next Steps

  • The AERO fall conference will have a topic table on R for education data analysis
  • Interest in future online sessions or meetups?
  • Collaborative projects with other education researchers?

8. Feedback and Future Sessions

I would love to hear your thoughts on this introduction to R and if you’re interested in further sessions. Potential topics for future workshops could include:

  1. Advanced data manipulation with dplyr
  2. Creating publication-quality graphics with ggplot2
  3. Statistical modeling for education research
  4. Machine learning applications in education
  5. Creating interactive dashboards with Shiny

Easiest way to reach me is the #r-sharing group on the DUG slack or email.

LS0tCnRpdGxlOiAiSW50cm9kdWN0aW9uIHRvIFIgZm9yIEVkdWNhdGlvbiBEYXRhIEFuYWx5c2lzIGFuZCBWaXN1YWxpemF0aW9uIgphdXRob3I6ICJKYXNvbiBMb2NrbGluIgpkYXRlOiAiU2VwdGVtYmVyIDI2LCAyMDI0IgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwplZGl0b3Jfb3B0aW9uczogCiAgbWFya2Rvd246IAogICAgd3JhcDogNzIKLS0tCgpgYGB7cn0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAoJZWNobyA9IFRSVUUsCgltZXNzYWdlID0gRkFMU0UsCgl3YXJuaW5nID0gRkFMU0UKKQpgYGAKCiMgSW50cm9kdWN0aW9uIHRvIFIgZm9yIEVkdWNhdGlvbiBEYXRhIEFuYWx5c2lzIGFuZCBWaXN1YWxpemF0aW9uCgojIyAxLiBXaGF0IGlzIFI/CgoqKlIgaXMgYSBwb3dlcmZ1bCoqLCBvcGVuLXNvdXJjZSBwcm9ncmFtbWluZyBsYW5ndWFnZSBhbmQgZW52aXJvbm1lbnQKZm9yIHN0YXRpc3RpY2FsIGNvbXB1dGluZyBhbmQgZ3JhcGhpY3MuIEl0J3Mgd2lkZWx5IHVzZWQgaW4gYWNhZGVtaWEsCnJlc2VhcmNoLCBhbmQgaW5kdXN0cnkgZm9yIGRhdGEgYW5hbHlzaXMsIHZpc3VhbGl6YXRpb24sIGFuZCBtYWNoaW5lCmxlYXJuaW5nLgoKS2V5IGZlYXR1cmVzIG9mIFI6CgotICAgRnJlZSBhbmQgb3Blbi1zb3VyY2UgLSBFeHRlbnNpdmUgcGFja2FnZSBlY29zeXN0ZW0gKG92ZXIgMTgsMDAwCiAgICBwYWNrYWdlcyBvbiBDUkFOKQotICAgU3Ryb25nIGNvbW11bml0eSBzdXBwb3J0Ci0gICBFeGNlbGxlbnQgZm9yIGRhdGEgbWFuaXB1bGF0aW9uIGFuZCB2aXN1YWxpemF0aW9uCi0gICBDcm9zcy1wbGF0Zm9ybSBjb21wYXRpYmlsaXR5IChXaW5kb3dzLCBNYWMsIExpbnV4KQogCgpIaXN0b3J5OgoKLSAgIEluc3BpcmVkIGJ5IHRoZSBTIHByb2dyYW1taW5nIGxhbmd1YWdlICgxOTcwcykKLSAgIEZpcnN0IHJlbGVhc2VkIGluIDE5OTMKLSAgIFRoZSAiVGlkeXZlcnNlIiBhbmQgUnN0dWRpbyBpbiB0aGUgMjAxMHMgbWFkZSBpdCBtdWNoIGVhc2llciB0byBnZXQKICAgIHN0YXJ0ZWQKLSAgIDEvMiBwcmltYXJ5IHN5c3RlbXMgZm9yIERhdGEgU2NpZW5jZSAodGhlIG90aGVyIGJlaW5nIFB5dGhvbikKCldoeSBSIGZvciBFZHVjYXRpb24gRGF0YSBBbmFseXNpcz8KCi0gICBUYWlsb3JlZCBmb3Igc3RhdGlzdGljYWwgYW5hbHlzaXMKLSAgIFJlcHJvZHVjaWJsZSByZXNlYXJjaCBjYXBhYmlsaXRpZXMKLSAgIEZsZXhpYmlsaXR5IGluIGRhdGEgbWFuaXB1bGF0aW9uIGFuZCB2aXN1YWxpemF0aW9uCi0gICBJbnRlZ3JhdGlvbiB3aXRoIG90aGVyIHRvb2xzIChlLmcuLCBkYXRhYmFzZXMsIHdlYiBhcHBsaWNhdGlvbnMsCiAgICBQb3dlckJJKQotICAgQWN0aXZlIGNvbW11bml0eSBpbiBlZHVjYXRpb25hbCByZXNlYXJjaAoKYGBge3J9CiMgU2ltcGxlIGV4YW1wbGUgb2YgYW4gUiBjb21tYW5kCnByaW50KCJIZWxsbywgRWR1Y2F0aW9uIERhdGEgQW5hbHlzdHMhIikKYGBgCgojIyAyLiBSIFRvb2xzIGFuZCBQYWNrYWdlcwoKIyMjIDIuMSBCYXNlIFIKClVzaW5nIEJhc2UgUiBhcyBhIGNhbGN1bGF0b3IKCmBgYHtyfQojIEJhc2ljIGFyaXRobWV0aWMKMiArIDUKMTAgLyAzCmBgYAoKRXhwbGFuYXRpb246IFRoaXMgYmxvY2sgZGVtb25zdHJhdGVzIGJhc2ljIGFyaXRobWV0aWMgb3BlcmF0aW9ucyBpbiBSLgpJdCBzaG93cyBhZGRpdGlvbiBhbmQgZGl2aXNpb24uIFIgY2FuIGJlIHVzZWQgYXMgYSBzaW1wbGUgY2FsY3VsYXRvci4KCmBgYHtyfQojIENyZWF0aW5nIGEgdmVjdG9yCm51bWJlcnMgPC0gYygxLCAyLCAzLCA0LCA1KQoKbnVtYmVycwpgYGAKCkV4cGxhbmF0aW9uOiBUaGlzIGNyZWF0ZXMgYSB2ZWN0b3IgbmFtZWQgJ251bWJlcnMnIHVzaW5nIHRoZSBgYygpYApmdW5jdGlvbiwgd2hpY2ggY29tYmluZXMgdmFsdWVzIGludG8gYSB2ZWN0b3IuIFRoZSB2ZWN0b3IgaXMgdGhlbgpkaXNwbGF5ZWQuCgpgYGB7cn0KbnVtYmVycyAqIDIKKCBudW1iZXJzL21heChudW1iZXJzKSApICogMTAwCmBgYAoKRXhwbGFuYXRpb246IFRoaXMgc2hvd3MgdmVjdG9yIGFyaXRobWV0aWMuIEVhY2ggZWxlbWVudCBvZiB0aGUgJ251bWJlcnMnCnZlY3RvciBpcyBtdWx0aXBsaWVkIGJ5IDIgb3Igc2NhbGVkIHRvIHBlcmNlbnQuCgpgYGB7cn0KbWVhbihudW1iZXJzKQptZWRpYW4obnVtYmVycykKc2QobnVtYmVycykKYGBgCgpFeHBsYW5hdGlvbjogVGhlc2UgYXJlIGJhc2ljIHN0YXRpc3RpY2FsIGZ1bmN0aW9ucy4gYG1lYW4oKWAgY2FsY3VsYXRlcwp0aGUgYXZlcmFnZSwgYG1lZGlhbigpYCBmaW5kcyB0aGUgbWlkZGxlIHZhbHVlLCBhbmQgYHNkKClgIGNvbXB1dGVzIHRoZQpzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlICdudW1iZXJzJyB2ZWN0b3IuCgpgYGB7cn0KIyBDcmVhdGluZyBhIHNpbXBsZSBmdW5jdGlvbgpzcXVhcmUgPC0gZnVuY3Rpb24oeCkgewogIHJldHVybih4XjIpCn0Kc3F1YXJlKDQpCmBgYAoKRXhwbGFuYXRpb246IFRoaXMgZGVmaW5lcyBhIGN1c3RvbSBmdW5jdGlvbiBuYW1lZCAnc3F1YXJlJyB0aGF0IHRha2VzIGFuCmlucHV0ICd4JyBhbmQgcmV0dXJucyBpdHMgc3F1YXJlLiBUaGUgZnVuY3Rpb24gaXMgdGhlbiBjYWxsZWQgd2l0aCB0aGUKYXJndW1lbnQgNC4KCmBgYHtyfQojIFdvcmtpbmcgd2l0aCBkYXRhIGZyYW1lcwpkZiA8LSBkYXRhLmZyYW1lKAogIG5hbWUgPSBjKCJBbGljZSIsICJCb2IiLCAiQ2hhcmxpZSIpLAogIGFnZSA9IGMoMTAsIDExLCA5KSwKICBzY29yZSA9IGMoODUsIDkyLCA3OCkKKQpwcmludChkZikKYGBgCgpFeHBsYW5hdGlvbjogVGhpcyBjcmVhdGVzIGEgZGF0YSBmcmFtZSwgYSBmdW5kYW1lbnRhbCBkYXRhIHN0cnVjdHVyZSBpbgpSIGZvciBzdG9yaW5nIHRhYnVsYXIgZGF0YS4gSXQgaGFzIHRocmVlIGNvbHVtbnM6IG5hbWUsIGFnZSwgYW5kIHNjb3JlLgpUaGUgZGF0YSBmcmFtZSBpcyB0aGVuIHByaW50ZWQuCgpOb3RlOiBkYXRhIGZyYW1lcyBhcmUgdHlwaWNhbGx5IG5vdCBlbnRlcmVkIG1hbnVhbGx5IGxpa2UgdGhpcywgYnV0CmltcG9ydGVkIGZyb20gYSBmaWxlIG9yIGNvbm5lY3Rpb24gdG8gYSBkYXRhYmFzZS4KCmBgYHtyfQpzdW1tYXJ5KGRmKQpgYGAKCkV4cGxhbmF0aW9uOiBUaGUgYHN1bW1hcnkoKWAgZnVuY3Rpb24gcHJvdmlkZXMgYSBzdGF0aXN0aWNhbCBzdW1tYXJ5IG9mCnRoZSBkYXRhIGZyYW1lLCBpbmNsdWRpbmcgbWluLCBtYXgsIG1lYW4sIGFuZCBtZWRpYW4gZm9yIG51bWVyaWMKY29sdW1ucywgYW5kIGZyZXF1ZW5jeSBmb3IgY2F0ZWdvcmljYWwgY29sdW1ucy4KCkZvciBwdWJsaWMgZGlzY3Vzc2lvbiwgd2Ugb2Z0ZW4gZ2VuZXJhdGUgc3ludGhldGljIGRhdGEgdG8gcnVuIGNvZGUKCmBgYHtyfQojIEdlbmVyYXRlIHN5bnRoZXRpYyBkYXRhCmRhdGEgPC0gZGF0YS5mcmFtZSgKICBuYW1lID0gc2FtcGxlKGMoIkFsaWNlIiwgIkJvYiIsICJDaGFybGllIiwgIkRhdmlkIiwgIkVtbWEiKSwgMjAsIHJlcGxhY2UgPSBUUlVFKSwKICBzdWJqZWN0ID0gc2FtcGxlKGMoIk1hdGgiLCAiRW5nbGlzaCIsICJTY2llbmNlIiwgIk1hdGgiLCAiRW5nbGlzaCIpLCAyMCwgcmVwbGFjZSA9IFRSVUUpLAogIGFnZSA9IHNhbXBsZSg5OjExLCAyMCwgcmVwbGFjZSA9IFRSVUUpLAogIHNjb3JlID0gcm91bmQocm5vcm0oMjAsIG1lYW4gPSA4NSwgc2QgPSA3KSkKKQoKIyBEaXNwbGF5IHRoZSBnZW5lcmF0ZWQgZGF0YSBmcmFtZQpwcmludChkYXRhKQpgYGAKCiMjIyAyLjIgVGlkeXZlcnNlCgpUaWR5dmVyc2UgaXMgYSBjb2xsZWN0aW9uIG9mIFIgcGFja2FnZXMgZGVzaWduZWQgZm9yIGRhdGEgc2NpZW5jZSwKZm9sbG93aW5nIGNvbnNpc3RlbnQgZGVzaWduIHBoaWxvc29waGllcy4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgTG9hZCB0aWR5dmVyc2UKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKIyMjIyAyLjIuMSBkcGx5ciBmb3IgZGF0YSBtYW5pcHVsYXRpb24KCmRwbHlyIHByb3ZpZGVzIGEgZ3JhbW1hciBvZiBkYXRhIG1hbmlwdWxhdGlvbiwgd2l0aCBrZXkgdmVyYnMgbGlrZTogLQpmaWx0ZXIoKTogc3Vic2V0IHJvd3MgLSBzZWxlY3QoKTogY2hvb3NlIGNvbHVtbnMgLSBtdXRhdGUoKTogY3JlYXRlIG5ldwp2YXJpYWJsZXMgLSBhcnJhbmdlKCk6IHJlb3JkZXIgcm93cyAtIHN1bW1hcmlzZSgpOiByZWR1Y2UgdmFyaWFibGVzIHRvCnZhbHVlcwoKYGBge3J9CgoKIyBGaWx0ZXIgYW5kIGFycmFuZ2UKZGF0YSAlPiUKICBmaWx0ZXIoc2NvcmUgPiA4MCkgJT4lCiAgYXJyYW5nZShkZXNjKHNjb3JlKSkKCiMgR3JvdXAgYW5kIHN1bW1hcml6ZQpkYXRhICU+JQogIGdyb3VwX2J5KHN1YmplY3QpICU+JQogIHN1bW1hcmlzZSgKICAgIGF2Z19zY29yZSA9IG1lYW4oc2NvcmUpLAogICAgY291bnQgPSBuKCkKICApCgojIENyZWF0ZSBuZXcgdmFyaWFibGVzCmRhdGEgJT4lCiAgbXV0YXRlKAogICAgZ3JhZGUgPSBjYXNlX3doZW4oCiAgICAgIHNjb3JlID49IDkwIH4gIkEiLAogICAgICBzY29yZSA+PSA4MCB+ICJCIiwKICAgICAgc2NvcmUgPj0gNzAgfiAiQyIsCiAgICAgIFRSVUUgfiAiRCIKICAgICkKICApCmBgYAoKIyMjIyAyLjIuMiBnZ3Bsb3QyIGZvciBkYXRhIHZpc3VhbGl6YXRpb24KCmdncGxvdDIgaXMgYmFzZWQgb24gdGhlIGdyYW1tYXIgb2YgZ3JhcGhpY3MsIGFsbG93aW5nIHlvdSB0byBidWlsZApjb21wbGV4IHBsb3RzIGZyb20gc2ltcGxlIGNvbXBvbmVudHMuCgpgYGB7cn0KIyBCYXNpYyBzY2F0dGVyIHBsb3QKZ2dwbG90KGRhdGEsIGFlcyh4ID0gbmFtZSwgeSA9IHNjb3JlKSkgKwogIGdlb21fcG9pbnQoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlN0dWRlbnQgU2NvcmVzIiwgeCA9ICJTdHVkZW50IE5hbWUiLCB5ID0gIlNjb3JlIikKCiMgQmFyIHBsb3Qgd2l0aCBncm91cGluZwpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBzdWJqZWN0LCB5ID0gc2NvcmUsIGZpbGwgPSBzdWJqZWN0KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlNjb3JlcyBieSBTdWJqZWN0IiwgeCA9ICJTdWJqZWN0IiwgeSA9ICJTY29yZSIpCgojIEJveHBsb3Qgd2l0aCB5LWF4aXMgc2NhbGVkIGZyb20gMCB0byAxMDAKZ2dwbG90KGRhdGEsIGFlcyh4ID0gc3ViamVjdCwgeSA9IHNjb3JlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiU2NvcmUgRGlzdHJpYnV0aW9uIGJ5IFN1YmplY3QiLCB4ID0gIlN1YmplY3QiLCB5ID0gIlNjb3JlIikgKwogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDUwLCAxMDApLCBicmVha3MgPSBzZXEoNTAsIDEwMCwgYnkgPSAyMCkpCmBgYAoKIyMgMy4gUiBFbnZpcm9ubWVudHMKCiMjIyAzLjEgUlN0dWRpbwoKUlN0dWRpbyBpcyBhbiBpbnRlZ3JhdGVkIGRldmVsb3BtZW50IGVudmlyb25tZW50IChJREUpIGZvciBSLCBlbmhhbmNpbmcKcHJvZHVjdGl2aXR5IGFuZCBlYXNlIG9mIHVzZS4KCkZlYXR1cmVzOiAtIENvZGUgZWRpdG9yIHdpdGggc3ludGF4IGhpZ2hsaWdodGluZyBhbmQgYXV0by1jb21wbGV0aW9uIC0KQ29uc29sZSBmb3IgaW1tZWRpYXRlIGNvZGUgZXhlY3V0aW9uIC0gRW52aXJvbm1lbnQgcGFuZSBmb3IgbWFuYWdpbmcKb2JqZWN0cyBhbmQgZGF0YSAtIFBsb3Qgdmlld2VyIGZvciB2aXN1YWxpemF0aW9ucyAtIEhlbHAgZG9jdW1lbnRhdGlvbgphbmQgcGFja2FnZSBtYW5hZ2VtZW50IC0gUHJvamVjdCBtYW5hZ2VtZW50IGNhcGFiaWxpdGllcyAtIFZlcnNpb24KY29udHJvbCBpbnRlZ3JhdGlvbiAoR2l0KQoKIyMjIDMuMiBSIE5vdGVib29rcwoKUiBOb3RlYm9va3MgYWxsb3cgZm9yIGludGVyYWN0aXZlLCBsaXRlcmF0ZSBwcm9ncmFtbWluZywgY29tYmluaW5nIGNvZGUsCm91dHB1dCwgYW5kIG5hcnJhdGl2ZSB0ZXh0LgoKQmVuZWZpdHM6IC0gUmVwcm9kdWNpYmxlIHJlc2VhcmNoIC0gRWFzeSBzaGFyaW5nIG9mIGFuYWx5c2lzIGFuZApyZXN1bHRzIC0gSW5saW5lIGNvZGUgZXhlY3V0aW9uIC0gTXVsdGlwbGUgb3V0cHV0IGZvcm1hdHMgKEhUTUwsIFBERiwKV29yZCkKCiMjIDQuIFByYWN0aWNhbCBFeGFtcGxlcyBmb3IgRWR1Y2F0aW9uIERhdGEgQW5hbHlzaXMKCiMjIyA0LjEgQW5vdGhlciBFeGFtcGxlIEdlbmVyYXRpbmcgU3ludGhldGljIFN0dWRlbnQgRGF0YQoKYGBge3J9CnNldC5zZWVkKDEyMykKc3R1ZGVudF9kYXRhIDwtIHRpYmJsZSgKICBzdHVkZW50X2lkID0gMToyMDAsCiAgZ2VuZGVyID0gc2FtcGxlKGMoIk1hbGUiLCAiRmVtYWxlIiksIDIwMCwgcmVwbGFjZSA9IFRSVUUpLAogIGdyYWRlX2xldmVsID0gc2FtcGxlKDk6MTIsIDIwMCwgcmVwbGFjZSA9IFRSVUUpLAogIHByb2dyYW0gPSBzYW1wbGUoYygiR2VuZXJhbCIsICJIb25vcnMiLCAiQVAiKSwgMjAwLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC41LCAwLjMsIDAuMikpLAogIG1hdGhfc2NvcmUgPSBybm9ybSgyMDAsIG1lYW4gPSA3NSwgc2QgPSAxNSksCiAgcmVhZGluZ19zY29yZSA9IHJub3JtKDIwMCwgbWVhbiA9IDcwLCBzZCA9IDEyKSwKICBhdHRlbmRhbmNlX3JhdGUgPSByYmV0YSgyMDAsIHNoYXBlMSA9IDUsIHNoYXBlMiA9IDEpICogMTAwCikKCiMgVmlldyB0aGUgZmlyc3QgZmV3IHJvd3MKaGVhZChzdHVkZW50X2RhdGEpCgojIFN1bW1hcnkgc3RhdGlzdGljcwpzdW1tYXJ5KHN0dWRlbnRfZGF0YSkKYGBgCgojIyMgNC4yIERhdGEgRXhwbG9yYXRpb24gYW5kIFZpc3VhbGl6YXRpb24KCmBgYHtyfQojIERpc3RyaWJ1dGlvbiBvZiBtYXRoIHNjb3JlcwpnZ3Bsb3Qoc3R1ZGVudF9kYXRhLCBhZXMoeCA9IG1hdGhfc2NvcmUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSA1LCBmaWxsID0gInNreWJsdWUiLCBjb2xvciA9ICJibGFjayIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIE1hdGggU2NvcmVzIiwgeCA9ICJNYXRoIFNjb3JlIiwgeSA9ICJDb3VudCIpCgojIEJveHBsb3Qgb2YgcmVhZGluZyBzY29yZXMgYnkgcHJvZ3JhbQpnZ3Bsb3Qoc3R1ZGVudF9kYXRhLCBhZXMoeCA9IHByb2dyYW0sIHkgPSByZWFkaW5nX3Njb3JlLCBmaWxsID0gcHJvZ3JhbSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlID0gIlJlYWRpbmcgU2NvcmVzIGJ5IFByb2dyYW0iLCB4ID0gIlByb2dyYW0iLCB5ID0gIlJlYWRpbmcgU2NvcmUiKQoKIyBTY2F0dGVyIHBsb3Qgb2YgbWF0aCB2cyByZWFkaW5nIHNjb3JlcwpnZ3Bsb3Qoc3R1ZGVudF9kYXRhLCBhZXMoeCA9IG1hdGhfc2NvcmUsIHkgPSByZWFkaW5nX3Njb3JlLCBjb2xvciA9IHByb2dyYW0pKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGUgPSAiTWF0aCB2cyBSZWFkaW5nIFNjb3JlcyBieSBQcm9ncmFtIiwgeCA9ICJNYXRoIFNjb3JlIiwgeSA9ICJSZWFkaW5nIFNjb3JlIikKYGBgCgojIyMgNC4zIFN0YXRpc3RpY2FsIEFuYWx5c2lzCgojIyMjIDQuMy4xIFQtdGVzdDogQ29tcGFyaW5nIE1hdGggU2NvcmVzIGJ5IEdlbmRlcgoKYGBge3J9CnRfdGVzdF9yZXN1bHQgPC0gdC50ZXN0KG1hdGhfc2NvcmUgfiBnZW5kZXIsIGRhdGEgPSBzdHVkZW50X2RhdGEpCnByaW50KHRfdGVzdF9yZXN1bHQpCmBgYAoKIyMjIyA0LjMuMiBBTk9WQTogQ29tcGFyaW5nIFJlYWRpbmcgU2NvcmVzIEFjcm9zcyBQcm9ncmFtcwoKYGBge3J9CmFub3ZhX3Jlc3VsdCA8LSBhb3YocmVhZGluZ19zY29yZSB+IHByb2dyYW0sIGRhdGEgPSBzdHVkZW50X2RhdGEpCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQpgYGAKCiMjIyMgNC4zLjMgTGluZWFyIFJlZ3Jlc3Npb246IFByZWRpY3RpbmcgTWF0aCBTY29yZXMKCmBgYHtyfQptb2RlbCA8LSBsbShtYXRoX3Njb3JlIH4gcmVhZGluZ19zY29yZSArIGF0dGVuZGFuY2VfcmF0ZSArIHByb2dyYW0sIGRhdGEgPSBzdHVkZW50X2RhdGEpCnN1bW1hcnkobW9kZWwpCmBgYAoKIyMgNS4gQUkgZm9yIFIgQ29kZSBHZW5lcmF0aW9uCgpBSSB0b29scyBjYW4gYmUgaGVscGZ1bCBmb3IgZ2VuZXJhdGluZyBSIGNvZGUgc25pcHBldHMsIGVzcGVjaWFsbHkgZm9yCmJlZ2lubmVycy4gSG93ZXZlciwgaXQncyBpbXBvcnRhbnQgdG8gdW5kZXJzdGFuZCB0aGUgY29kZSBhbmQgdmVyaWZ5IGl0cwpjb3JyZWN0bmVzcy4KCkJlbmVmaXRzOiAKCi0gUXVpY2sgcHJvdG90eXBpbmcgCi0gTGVhcm5pbmcgbmV3IGZ1bmN0aW9ucyBhbmQgcGFja2FnZXMgCi1Ucm91Ymxlc2hvb3RpbmcgZXJyb3JzIAotIERhdGEgaXNuJ3QgZXhwb3NlZAoKQ2F1dGlvbnM6IAoKLSBBbHdheXMgcmV2aWV3IGFuZCB1bmRlcnN0YW5kIGdlbmVyYXRlZCBjb2RlIAotIFZlcmlmeSByZXN1bHRzIGFuZCBjaGVjayBmb3IgZXJyb3JzIAotIFVzZSBhcyBhIGxlYXJuaW5nIHRvb2wsIG5vdCBhIHJlcGxhY2VtZW50IGZvciB1bmRlcnN0YW5kaW5nCgojIyMjIFVzZSBhIHByb21wdCBhdCB0aGUgYmVnaW5uaW5nIG9mIHlvdXIgY2hhdCBzZXNzaW9uOgo+ICJZb3UgYXJlIG15IHR1dG9yIGhlbHBpbmcgbWUgbGVhcm4gYW5kIHVuZGVyc3RhbmQgUiBwcm9ncmFtbWluZyBmb3IKPiBkYXRhIGFuYWx5c2lzIGFuZCB2aXN1YWxpemF0aW9uIGluIHRoZSBlZHVjYXRpb24gcmVzZWFyY2ggZmllbGQuIEkKPiB3aWxsIGJlIHNoYXJpbmcgcXVlc3Rpb25zLCBpZGVhcywgYW5kIGNvZGUgc25pcHBldHMgd2l0aCB5b3UgYW5kIEkKPiBuZWVkIHlvdSB0byBwcm92aWRlIGV4YW1wbGVzIGFuZCBleHBsYW5hdGlvbnMgdGhhdCBhcmUgZGV0YWlsZWQgYW5kCj4gY2xlYXJseSBwcmVzZW50ZWQgZm9yIHNvbWVvbmUganVzdCBzdGFydGluZyBvdXQuIERvbid0IHByb3ZpZGUgY29tcGxleAo+IGNvZGUsIG9yIHVzZSBuZXcgcGFja2FnZXMgb3IgZnVuY3Rpb25zIHdpdGhvdXQgZXhwbGFpbmluZyB0aGVtLiBCZSBhbgo+IGVmZmVjdGl2ZSB0ZWFjaGVyIGFuZCB0dXRvciBmb3IgbGVhcm5pbmcgUiwgUnN0dWRpbywgdGhlIHRpZHl2ZXJzZS4KPiAuLi4iCgpBbiBlZmZlY3RpdmUgcHJvbXB0IHdpbGwgYXZvaWQgaXQgZ2VuZXJhdGluZyBsYXJnZSwgY29tcGxleCwgcG9zc2libHkgYnJva2VuIGNvZGUsIGFuZCBtYWtlIHN1cmUgaXQgaXMgZXhwbGFpbmVkIGluIGEgd2F5IHRoYXQgeW91IGNhbiBsZWFybiBmcm9tLgoKIyMgNi4gUmVzb3VyY2VzIGZvciBGdXJ0aGVyIExlYXJuaW5nCgojIyMjIFIgUHJvamVjdAoKLSAgIFtSIFByb2plY3QgSG9tZXBhZ2VdKGh0dHBzOi8vd3d3LnItcHJvamVjdC5vcmcvKSAtIEJhc2UgUiBkb3dubG9hZHMsCiAgICBuZXdzLCBhbmQgbGVhcm5pbmcgcmVzb3VyY2VzCgojIyMjIFBvc2l0CgotICAgW1IgU3R1ZGlvIERlc2t0b3BdKGh0dHBzOi8vcG9zaXQuY28vZG93bmxvYWQvcnN0dWRpby1kZXNrdG9wLykgLQogICAgRmVhdHVyZSByaWNoIGVudmlyb25tZW50IGZvciB3b3JraW5nIHdpdGggZGF0YSBpbiBSCi0gICBbUiBmb3IgRGF0YSBTY2llbmNlXShodHRwczovL3I0ZHMuaGFkLmNvLm56LykgLSBDb21wcmVoZW5zaXZlIG9ubGluZQogICAgYm9vawotICAgW1JTdHVkaW8KICAgIENoZWF0c2hlZXRzXShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS9yZXNvdXJjZXMvY2hlYXRzaGVldHMvKSAtIFF1aWNrCiAgICByZWZlcmVuY2UgZ3VpZGVzCgojIyMjIENvbW11bml0eSBSZXNvdXJjZXMKCi0gICBbUi1ibG9nZ2Vyc10oaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vKSAtIEJsb2cgYWdncmVnYXRvciBmb3IgUgogICAgbmV3cyBhbmQgdHV0b3JpYWxzCi0gICBbU3RhY2sgT3ZlcmZsb3cgLSBSCiAgICB0YWddKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zL3RhZ2dlZC9yKSAtIFEmQSBjb21tdW5pdHkKLSAgIFtyZHJyLmlvIFNuaXBwZXRzXShodHRwczovL3JkcnIuaW8vc25pcHBldHMvKSAtIFRlc3QgUiBjb2RlIHNuaXBwZXRzCiAgICBvbmxpbmUKLSAgIFtDb3Vyc2VyYSAtIFIKICAgIFByb2dyYW1taW5nXShodHRwczovL3d3dy5jb3Vyc2VyYS5vcmcvbGVhcm4vci1wcm9ncmFtbWluZykgLSBPbmxpbmUKICAgIGNvdXJzZQotICAgW0RhdGFDYW1wIC0gSW50cm9kdWN0aW9uIHRvCiAgICBSXShodHRwczovL3d3dy5kYXRhY2FtcC5jb20vY291cnNlcy9mcmVlLWludHJvZHVjdGlvbi10by1yKSAtCiAgICBJbnRlcmFjdGl2ZSBsZWFybmluZyBwbGF0Zm9ybQoKIyMgNy4gTmV4dCBTdGVwcwoKLSAgIFRoZSBBRVJPIGZhbGwgY29uZmVyZW5jZSB3aWxsIGhhdmUgYSB0b3BpYyB0YWJsZSBvbiBSIGZvciBlZHVjYXRpb24KICAgIGRhdGEgYW5hbHlzaXMKLSAgIEludGVyZXN0IGluIGZ1dHVyZSBvbmxpbmUgc2Vzc2lvbnMgb3IgbWVldHVwcz8KLSAgIENvbGxhYm9yYXRpdmUgcHJvamVjdHMgd2l0aCBvdGhlciBlZHVjYXRpb24gcmVzZWFyY2hlcnM/CgojIyA4LiBGZWVkYmFjayBhbmQgRnV0dXJlIFNlc3Npb25zCgpJIHdvdWxkIGxvdmUgdG8gaGVhciB5b3VyIHRob3VnaHRzIG9uIHRoaXMgaW50cm9kdWN0aW9uIHRvIFIgYW5kIGlmCnlvdSdyZSBpbnRlcmVzdGVkIGluIGZ1cnRoZXIgc2Vzc2lvbnMuIFBvdGVudGlhbCB0b3BpY3MgZm9yIGZ1dHVyZQp3b3Jrc2hvcHMgY291bGQgaW5jbHVkZToKCjEuICBBZHZhbmNlZCBkYXRhIG1hbmlwdWxhdGlvbiB3aXRoIGRwbHlyCjIuICBDcmVhdGluZyBwdWJsaWNhdGlvbi1xdWFsaXR5IGdyYXBoaWNzIHdpdGggZ2dwbG90MgozLiAgU3RhdGlzdGljYWwgbW9kZWxpbmcgZm9yIGVkdWNhdGlvbiByZXNlYXJjaAo0LiAgTWFjaGluZSBsZWFybmluZyBhcHBsaWNhdGlvbnMgaW4gZWR1Y2F0aW9uCjUuICBDcmVhdGluZyBpbnRlcmFjdGl2ZSBkYXNoYm9hcmRzIHdpdGggU2hpbnkKCkVhc2llc3Qgd2F5IHRvIHJlYWNoIG1lIGlzIHRoZSAjci1zaGFyaW5nIGdyb3VwIG9uIHRoZSBEVUcgc2xhY2sgb3IKZW1haWwuCg==