Data Exploration

Exercises ~ Week 2

Logo


1 Exercise 1

The following table shows sample information for three students. Each observation represents a single student and includes details such as their unique student ID, name, age, total credits completed, major field of study, and year level.

This dataset demonstrates a mixture of variable types:

  • Nominal: StudentID, Name, Major
  • Numeric: Age (continuous), CreditsCompleted (discrete)
  • Ordinal: YearLevel (Freshman → Senior)
StudentID Name Age CreditsCompleted Major YearLevel
S001 Alice 20 45 Data Sains Sophomore
S002 Budi 21 60 Mathematics Junior
S003 Citra 19 30 Statistics Freshman
# 1. Create vectors for each variable
StudentID <- c("S001", "S002", "S003")       # Nominal / ID
Name <- c("Alice", "Budi", "Citra")          # Nominal / Name
Age <- c(20, 21, 19)                         # Numeric / Continuous
CreditsCompleted <- c(45, 60, 30)            # Numeric / Discrete

# Nominal
Major <- c("Data Sains", "Mathematics", "Statistics")  
1
## [1] 1
# Ordinal
YearLevel <- factor(c("Sophomore", "Junior", "Freshman"),
                    levels = c("Freshman","Sophomore","Junior","Senior"),
                    ordered = TRUE)          

# 2. Combine all vectors into a data frame
students <- data.frame(
  StudentID, Name, Age, CreditsCompleted, Major, YearLevel,
  stringsAsFactors = FALSE
)

# 3. Display the data frame
print(students)
##   StudentID  Name Age CreditsCompleted       Major YearLevel
## 1      S001 Alice  20               45  Data Sains Sophomore
## 2      S002  Budi  21               60 Mathematics    Junior
## 3      S003 Citra  19               30  Statistics  Freshman

2 Exercise 2

Identify Data Types: Determine the type of data for each of the following variables:

# Install knitr package if not already installed
# install.packages("knitr")
library(knitr)

# Create a data frame for Data Types
variables_info <- data.frame(
  No = 1:5,
  Variable = c(
    "Number of vehicles passing through the toll road each day",
    "Student height in cm",
    "Employee gender (Male / Female)",
    "Customer satisfaction level: Low, Medium, High",
    "Respondent's favorite color: Red, Blue, Green"
  ),
  DataType = c(
    "Quantitative",
    "Quantitative",
    "Quantitative",
    "Qualitative",
    "Qualitative"
  ),
  Subtype = c(
    "Diskrete",
    "Continuous",
    "Nominal",
    "Ordinal",
    "Nominal"
  ),
  stringsAsFactors = FALSE
)

# Display the data frame as a neat table
kable(variables_info, 
      caption = "Table of Variables and Data Types")
Table of Variables and Data Types
No Variable DataType Subtype
1 Number of vehicles passing through the toll road each day Quantitative Diskrete
2 Student height in cm Quantitative Continuous
3 Employee gender (Male / Female) Quantitative Nominal
4 Customer satisfaction level: Low, Medium, High Qualitative Ordinal
5 Respondent’s favorite color: Red, Blue, Green Qualitative Nominal

3 Exercise 3

Classify Data Sources: Determine whether the following data comes from internal or external sources, and whether it is structured or unstructured:

# Install DT package if not already installed
# install.packages("DT")
library(DT)

# Create a data frame for data sources 
data_sources <- data.frame(
  No = 1:4,
  DataSource = c(
    "Daily sales transaction data of the company",
    "Weather reports from BMKG",
    "Product reviews on social media",
    "Warehouse inventory reports"
  ),
  Internal_External = c(
    "Internal",
    "Eksternal",
    "Eksternal",
    "Internal"
  ),
  Structured_Unstructured = c(
    "Structured",
    "Structured",
    "Unstructured",
    "Structured"
  ),
  stringsAsFactors = FALSE
)

# Display the data frame as a neat table
datatable(data_sources, 
          caption = "Table of Data Sources",
          rownames = FALSE) # hides the index column

4 Exercise 4

Dataset Structure: Consider the following transaction table:

Date Qty Price Product CustomerTier
2025-10-01 2 1000 Laptop High
2025-10-01 5 20 Mouse Medium
2025-10-02 1 1000 Laptop Low
2025-10-02 3 30 Keyboard Medium
2025-10-03 4 50 Mouse Medium
2025-10-03 2 1000 Laptop High
2025-10-04 6 25 Keyboard Low
2025-10-04 1 1000 Laptop High
2025-10-05 3 40 Mouse Low
2025-10-05 5 10 Keyboard Medium

Your Assignment Instructions: Creating a Transactions Table above in R

  1. Create a data frame in R called transactions containing the data above.

  2. Identify which variables are numeric and which are categorical

  3. Calculate total revenue for each transaction by multiplying Qty × Price and add it as a new column Total.

  4. Compute summary statistics:

    • Total quantity sold for each product
    • Total revenue per product
    • Average price per product
  5. Visualize the data:

    • Create a barplot showing total quantity sold per product.
    • Create a pie chart showing the proportion of total revenue per customer tier.
  6. Optional Challenge:

    • Find which date had the highest total revenue.
    • Create a stacked bar chart showing quantity sold per product by customer tier.

Hints: Use data.frame(), aggregate(), barplot(), pie(), and basic arithmetic operations in R.

4.1 create Data Frame

transactions <- data.frame( Date = as.Date(c( “2025-10-01”, “2025-10-01”, “2025-10-02”, “2025-10-02”, “2025-10-03”, “2025-10-03”, “2025-10-04”, “2025-10-04”, “2025-10-05”, “2025-10-05” )), Qty = c(2, 5, 1, 3, 4, 2, 6, 1, 3, 5), Price = c(1000, 20, 1000, 30, 50, 1000, 25, 1000, 40, 10), Product = c(“Laptop”, “Mouse”, “Laptop”, “Keyboard”, “Mouse”, “Laptop”, “Keyboard”, “Laptop”, “Mouse”, “Keyboard”), CustomerTier = c(“High”, “Medium”, “Low”, “Medium”, “Medium”, “High”, “Low”, “High”, “Low”, “Medium”), stringsAsFactors = FALSE )

4.2 Identify data types

str(transactions) # look at the structure (numeric vs categorical)

4.3 add a total colum

transactions\(Total <- transactions\)Qty * transactions$Price

4.4 View results

print(transactions)

4.5 Summary Statistics

4.6 Total quantity sold per product

total_qty <- aggregate(Qty ~ Product, data = transactions, sum)

4.6.1 Total revenue per product

total_revenue <- aggregate(Total ~ Product, data = transactions, sum)

4.6.2 Average price per product

avg_price <- aggregate(Price ~ Product, data = transactions, mean)

4.6.3 Tampilkan hasil ringkasan

cat(“=== Total Quantity per Product ===”) print(total_qty) cat(“=== Total Revenue per Product ===”) print(total_revenue) cat(“=== Average Price per Product ===”) print(avg_price)

4.7 Visualization

4.7.1 (a) Barplot - total quantity sold per product

barplot( total_qty\(Qty, names.arg = total_qty\)Product, main = “Total Quantity Sold per Product”, xlab = “Product”, ylab = “Total Quantity”, col = c(“skyblue”, “lightgreen”, “orange”) )

4.7.2 (b) Pie chart - proportion of total revenue per Customer Tier

revenue_tier <- aggregate(Total ~ CustomerTier, data = transactions, sum) pie( revenue_tier\(Total, labels = paste(revenue_tier\)CustomerTier, “-”, revenue_tier$Total), main = “Proportion of Total Revenue per Customer Tier”, col = c(“gold”, “lightblue”, “tomato”) )

4.8 Optional Challenge

4.8.1 (a) Date with highest total revenue

date_revenue <- aggregate(Total ~ Date, data = transactions, sum) max_rev_date <- date_revenue[which.max(date_revenue$Total), ] cat(“dengan total revenue tertinggi:”) print(max_rev_date)

4.8.2 (b) Stacked bar chart: quantity sold per product by customer tier

qty_stack <- aggregate(Qty ~ Product + CustomerTier, data = transactions, sum) qty_matrix <- xtabs(Qty ~ CustomerTier + Product, data = qty_stack) barplot( qty_matrix, beside = FALSE, main = “Quantity Sold per Product by Customer Tier”, xlab = “Product”, ylab = “Quantity Sold”, col = c(“lightblue”, “gold”, “tomato”) ) legend(“topright”, legend = rownames(qty_matrix), fill = c(“lightblue”, “gold”, “tomato”), title = “Customer Tier”)

5 Exercise 5

Create Your Own Data Frame:

Objective: Create a data frame in R with 30 rows containing a mix of data types: continuous, discrete, nominal, and ordinal.

5.1 Instructions

  1. Open RStudio or the R console.

  2. Create a vector for each column in your data frame:

    • Date: 30 dates (can be sequential or random within a month/year)
    • Continuous: numeric values that can take decimal values (e.g., height, weight, temperature)
    • Discrete: numeric values that can only take whole numbers (e.g., number of items, number of vehicles)
    • Nominal: categorical values with no order (e.g., color, gender, city)
    • Ordinal: categorical values with a defined order (e.g., Low, Medium, High; Beginner, Intermediate, Expert)
  3. Combine all vectors into a data frame called my_data.

  4. Check your data frame using head() or View() to ensure it has 30 rows and the columns are correct.

  5. Optional tasks:

    • Summarize each column using summary()
    • Count the frequency of each category for Nominal and Ordinal columns using table()

5.2 Hints

  • Use seq.Date() or as.Date() to generate the Date column.
  • Use runif() or rnorm() for continuous numeric data.
  • Use sample() for discrete, nominal, and ordinal data.
  • Ensure the ordinal vector is created with factor(..., levels = c("Low","Medium","High"), ordered = TRUE) (or similar).

5.3 Create each column

5.4 Date: 30 consecutive dates in October 2025

Date <- seq.Date(from = as.Date(“2025-10-01”), by = “day”, length.out = 30)

5.5 Continuous: for example body temperature data (in °C), use decimals

Continuous <- round(runif(30, min = 35.5, max = 37.5), 1)

5.6 Discrete: e.g number of items sold (whole number)

Discrete <- sample(1:50, 30, replace = TRUE)

5.7 Nominal: e.g cutomer’s city of origin (no order)

Nominal <- sample(c(“Jakarta”, “Bandung”, “Surabaya”, “Medan”, “Bali”), 30, replace = TRUE)

5.8 Ordinal: e.g statisfaction level (there is a sequence)

Ordinal <- factor( sample(c(“Low”, “Medium”, “High”), 30, replace = TRUE), levels = c(“Low”, “Medium”, “High”), ordered = TRUE )

5.9 Combine all into a date frame

my_data <- data.frame(Date, Continuous, Discrete, Nominal, Ordinal)

5.10 Check the data contents

head(my_data) # display the first 6 rows View(my_data) # open in RStudio window (optional)

5.11 (Optional) Data Summary

summary(my_data)

5.12 Calculate frequency categories

cat(“=== Nominal Frequency (City) ===”) print(table(my_data$Nominal))

cat(“=== Ordinal Frequency (Level of Statisfaction) ===”) print(table(my_data$Ordinal))

LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAyIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6IA0KLSAiTS5GaXRyYWggQWlkaWwgSGFyYWhhcCINCi0gIlBhc2thbGlzIEZhcmVsbmF0YSBaYW1hc2kiDQotICJEZW4gWXVhbiBGcmFzc2VrYSINCi0gIkhhbmFmaSBNYWxpayBSaWZhaSINCi0gIlppZGhhbiBBbGZhcmV6aSBBZmRpIiMgUmVwbGFjZSB3aXRoIHlvdXIgZnVsbCBuYW1lDQpkYXRlOiAgImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIiAjIEF1dG8gZGlzcGxheXMgdGhlIGN1cnJlbnQgZGF0ZQ0Kb3V0cHV0OiAgICAgICAgICAgICAgICAgICAgICAgICAjIE91dHB1dCBzZWN0aW9uIGRlZmluZXMgdGhlIGZvcm1hdCBhbmQgbGF5b3V0IA0KICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjogICAgICAjIGh0dHBzOi8vZ2l0aHViLmNvbS9qdWJhL3JtZGZvcm1hdHMNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZSAgICAgICAgIyBFbWJlZHMgYWxsIHJlc291cmNlcyAoQ1NTLCBKUywgaW1hZ2VzKSANCiAgICB0aHVtYm5haWxzOiB0cnVlICAgICAgICAgICAgIyBEaXNwbGF5cyBpbWFnZSB0aHVtYm5haWxzIGluIHRoZSBkb2MNCiAgICBsaWdodGJveDogdHJ1ZSAgICAgICAgICAgICAgIyBFbmFibGVzIGNsaWNrIHRvIGVubGFyZ2UgaW1hZ2VzDQogICAgZ2FsbGVyeTogdHJ1ZSAgICAgICAgICAgICAgICMgR3JvdXBzIGltYWdlcyBpbnRvIGFuIGludGVyYWN0aXZlIGdhbGxlcnkNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUgICAgICAgIyBBdXRvbWF0aWNhbGx5IG51bWJlcnMgYWxsIHNlY3Rpb25zDQogICAgbGliX2RpcjogbGlicyAgICAgICAgICAgICAgICMgRGlyZWN0b3J5IHdoZXJlIEphdmFTY3JpcHQvQ1NTIGxpYnJhcmllcw0KICAgIGRmX3ByaW50OiAicGFnZWQiICAgICAgICAgICAjIERpc3BsYXlzIGRhdGEgZnJhbWVzIGFzIGludGVyYWN0aXZlIHBhZ2VkIA0KICAgIGNvZGVfZm9sZGluZzogInNob3ciICAgICAgICAjIEFsbG93cyBmb2xkaW5nL3VuZm9sZGluZyBSIGNvZGUgYmxvY2tzIA0KICAgIGNvZGVfZG93bmxvYWQ6IHllcyAgICAgICAgICAjIEFkZHMgYSBidXR0b24gdG8gZG93bmxvYWQgYWxsIFIgY29kZQ0KLS0tDQoNCg0KPGltZyBpZD0iRm90byIgc3JjPSJDOlxVc2Vyc1xTcmkgQnVkaXlhbnRpXE9uZURyaXZlXOODieOCreODpeODoeODs+ODiFxEZXNrdG9wXEFpZGlsIEhhcmFoYXBcRm90byBLZWxvbXBvay5qcGVnIiBhbHQ9IkxvZ28iIHN0eWxlPSJ3aWR0aDoyMDBweDsgZGlzcGxheTogYmxvY2s7IG1hcmdpbjogYXV0bzsiPg0KDQotLS0NCg0KIyBFeGVyY2lzZSAxDQoNClRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3Mgc2FtcGxlIGluZm9ybWF0aW9uIGZvciB0aHJlZSBzdHVkZW50cy4gRWFjaCBvYnNlcnZhdGlvbiByZXByZXNlbnRzIGEgc2luZ2xlIHN0dWRlbnQgYW5kIGluY2x1ZGVzIGRldGFpbHMgc3VjaCBhcyB0aGVpciB1bmlxdWUgc3R1ZGVudCBJRCwgbmFtZSwgYWdlLCB0b3RhbCBjcmVkaXRzIGNvbXBsZXRlZCwgbWFqb3IgZmllbGQgb2Ygc3R1ZHksIGFuZCB5ZWFyIGxldmVsLiAgDQoNClRoaXMgZGF0YXNldCBkZW1vbnN0cmF0ZXMgYSBtaXh0dXJlIG9mIHZhcmlhYmxlIHR5cGVzOiAgDQoNCi0gKipOb21pbmFsOioqIFN0dWRlbnRJRCwgTmFtZSwgTWFqb3IgIA0KLSAqKk51bWVyaWM6KiogQWdlIChjb250aW51b3VzKSwgQ3JlZGl0c0NvbXBsZXRlZCAoZGlzY3JldGUpICANCi0gKipPcmRpbmFsOioqIFllYXJMZXZlbCAoRnJlc2htYW4g4oaSIFNlbmlvcikgIA0KDQp8IFN0dWRlbnRJRCB8IE5hbWUgICB8IEFnZSB8IENyZWRpdHNDb21wbGV0ZWQgfCBNYWpvciAgICAgICAgICAgIHwgWWVhckxldmVsIHwNCnwtLS0tLS0tLS0tLXwtLS0tLS0tLXwtLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLXwNCnwgUzAwMSAgICAgIHwgQWxpY2UgIHwgMjAgIHwgNDUgICAgICAgICAgICAgIHwgRGF0YSBTYWlucyAgICAgIHwgU29waG9tb3JlIHwNCnwgUzAwMiAgICAgIHwgQnVkaSAgIHwgMjEgIHwgNjAgICAgICAgICAgICAgIHwgTWF0aGVtYXRpY3MgICAgIHwgSnVuaW9yICAgIHwNCnwgUzAwMyAgICAgIHwgQ2l0cmEgIHwgMTkgIHwgMzAgICAgICAgICAgICAgIHwgU3RhdGlzdGljcyAgICAgIHwgRnJlc2htYW4gIHwNCg0KYGBge3J9DQojIDEuIENyZWF0ZSB2ZWN0b3JzIGZvciBlYWNoIHZhcmlhYmxlDQpTdHVkZW50SUQgPC0gYygiUzAwMSIsICJTMDAyIiwgIlMwMDMiKSAgICAgICAjIE5vbWluYWwgLyBJRA0KTmFtZSA8LSBjKCJBbGljZSIsICJCdWRpIiwgIkNpdHJhIikgICAgICAgICAgIyBOb21pbmFsIC8gTmFtZQ0KQWdlIDwtIGMoMjAsIDIxLCAxOSkgICAgICAgICAgICAgICAgICAgICAgICAgIyBOdW1lcmljIC8gQ29udGludW91cw0KQ3JlZGl0c0NvbXBsZXRlZCA8LSBjKDQ1LCA2MCwgMzApICAgICAgICAgICAgIyBOdW1lcmljIC8gRGlzY3JldGUNCg0KIyBOb21pbmFsDQpNYWpvciA8LSBjKCJEYXRhIFNhaW5zIiwgIk1hdGhlbWF0aWNzIiwgIlN0YXRpc3RpY3MiKSAgDQoxDQojIE9yZGluYWwNClllYXJMZXZlbCA8LSBmYWN0b3IoYygiU29waG9tb3JlIiwgIkp1bmlvciIsICJGcmVzaG1hbiIpLA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJGcmVzaG1hbiIsIlNvcGhvbW9yZSIsIkp1bmlvciIsIlNlbmlvciIpLA0KICAgICAgICAgICAgICAgICAgICBvcmRlcmVkID0gVFJVRSkgICAgICAgICAgDQoNCiMgMi4gQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZQ0Kc3R1ZGVudHMgPC0gZGF0YS5mcmFtZSgNCiAgU3R1ZGVudElELCBOYW1lLCBBZ2UsIENyZWRpdHNDb21wbGV0ZWQsIE1ham9yLCBZZWFyTGV2ZWwsDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIDMuIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCnByaW50KHN0dWRlbnRzKQ0KYGBgDQoNCg0KIyBFeGVyY2lzZSAyDQoNCioqSWRlbnRpZnkgRGF0YSBUeXBlczoqKiBEZXRlcm1pbmUgdGhlIHR5cGUgb2YgZGF0YSBmb3IgZWFjaCBvZiB0aGUgZm9sbG93aW5nIHZhcmlhYmxlczoNCg0KYGBge3J9DQojIEluc3RhbGwga25pdHIgcGFja2FnZSBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCiMgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KbGlicmFyeShrbml0cikNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBEYXRhIFR5cGVzDQp2YXJpYWJsZXNfaW5mbyA8LSBkYXRhLmZyYW1lKA0KICBObyA9IDE6NSwNCiAgVmFyaWFibGUgPSBjKA0KICAgICJOdW1iZXIgb2YgdmVoaWNsZXMgcGFzc2luZyB0aHJvdWdoIHRoZSB0b2xsIHJvYWQgZWFjaCBkYXkiLA0KICAgICJTdHVkZW50IGhlaWdodCBpbiBjbSIsDQogICAgIkVtcGxveWVlIGdlbmRlciAoTWFsZSAvIEZlbWFsZSkiLA0KICAgICJDdXN0b21lciBzYXRpc2ZhY3Rpb24gbGV2ZWw6IExvdywgTWVkaXVtLCBIaWdoIiwNCiAgICAiUmVzcG9uZGVudCdzIGZhdm9yaXRlIGNvbG9yOiBSZWQsIEJsdWUsIEdyZWVuIg0KICApLA0KICBEYXRhVHlwZSA9IGMoDQogICAgIlF1YW50aXRhdGl2ZSIsDQogICAgIlF1YW50aXRhdGl2ZSIsDQogICAgIlF1YW50aXRhdGl2ZSIsDQogICAgIlF1YWxpdGF0aXZlIiwNCiAgICAiUXVhbGl0YXRpdmUiDQogICksDQogIFN1YnR5cGUgPSBjKA0KICAgICJEaXNrcmV0ZSIsDQogICAgIkNvbnRpbnVvdXMiLA0KICAgICJOb21pbmFsIiwNCiAgICAiT3JkaW5hbCIsDQogICAgIk5vbWluYWwiDQogICksDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUgYXMgYSBuZWF0IHRhYmxlDQprYWJsZSh2YXJpYWJsZXNfaW5mbywgDQogICAgICBjYXB0aW9uID0gIlRhYmxlIG9mIFZhcmlhYmxlcyBhbmQgRGF0YSBUeXBlcyIpDQpgYGANCi0tLQ0KDQojIEV4ZXJjaXNlIDMNCg0KKipDbGFzc2lmeSBEYXRhIFNvdXJjZXM6KiogRGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGZvbGxvd2luZyBkYXRhIGNvbWVzIGZyb20gKippbnRlcm5hbCoqIG9yICoqZXh0ZXJuYWwgc291cmNlcyoqLCBhbmQgd2hldGhlciBpdCBpcyAqKnN0cnVjdHVyZWQqKiBvciAqKnVuc3RydWN0dXJlZCoqOg0KDQpgYGB7cn0NCiMgSW5zdGFsbCBEVCBwYWNrYWdlIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZA0KIyBpbnN0YWxsLnBhY2thZ2VzKCJEVCIpDQpsaWJyYXJ5KERUKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIGRhdGEgc291cmNlcyANCmRhdGFfc291cmNlcyA8LSBkYXRhLmZyYW1lKA0KICBObyA9IDE6NCwNCiAgRGF0YVNvdXJjZSA9IGMoDQogICAgIkRhaWx5IHNhbGVzIHRyYW5zYWN0aW9uIGRhdGEgb2YgdGhlIGNvbXBhbnkiLA0KICAgICJXZWF0aGVyIHJlcG9ydHMgZnJvbSBCTUtHIiwNCiAgICAiUHJvZHVjdCByZXZpZXdzIG9uIHNvY2lhbCBtZWRpYSIsDQogICAgIldhcmVob3VzZSBpbnZlbnRvcnkgcmVwb3J0cyINCiAgKSwNCiAgSW50ZXJuYWxfRXh0ZXJuYWwgPSBjKA0KICAgICJJbnRlcm5hbCIsDQogICAgIkVrc3Rlcm5hbCIsDQogICAgIkVrc3Rlcm5hbCIsDQogICAgIkludGVybmFsIg0KICApLA0KICBTdHJ1Y3R1cmVkX1Vuc3RydWN0dXJlZCA9IGMoDQogICAgIlN0cnVjdHVyZWQiLA0KICAgICJTdHJ1Y3R1cmVkIiwNCiAgICAiVW5zdHJ1Y3R1cmVkIiwNCiAgICAiU3RydWN0dXJlZCINCiAgKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgRGlzcGxheSB0aGUgZGF0YSBmcmFtZSBhcyBhIG5lYXQgdGFibGUNCmRhdGF0YWJsZShkYXRhX3NvdXJjZXMsIA0KICAgICAgICAgIGNhcHRpb24gPSAiVGFibGUgb2YgRGF0YSBTb3VyY2VzIiwNCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFKSAjIGhpZGVzIHRoZSBpbmRleCBjb2x1bW4NCmBgYA0KDQotLS0NCg0KIyBFeGVyY2lzZSA0DQoNCioqRGF0YXNldCBTdHJ1Y3R1cmU6KiogQ29uc2lkZXIgdGhlIGZvbGxvd2luZyB0cmFuc2FjdGlvbiB0YWJsZToNCg0KfCBEYXRlICAgICAgIHwgUXR5IHwgUHJpY2UgfCBQcm9kdWN0ICB8IEN1c3RvbWVyVGllciB8DQp8LS0tLS0tLS0tLS0tfC0tLS0tfC0tLS0tLS18LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLXwNCnwgMjAyNS0xMC0wMSB8IDIgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTAxIHwgNSAgIHwgMjAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDIgfCAxICAgfCAxMDAwICB8IExhcHRvcCAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wMiB8IDMgICB8IDMwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAzIHwgNCAgIHwgNTAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDMgfCAyICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wNCB8IDYgICB8IDI1ICAgIHwgS2V5Ym9hcmQgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTA0IHwgMSAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDUgfCAzICAgfCA0MCAgICB8IE1vdXNlICAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wNSB8IDUgICB8IDEwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KDQoNCioqWW91ciBBc3NpZ25tZW50IEluc3RydWN0aW9uczoqKiBDcmVhdGluZyBhIFRyYW5zYWN0aW9ucyBUYWJsZSBhYm92ZSBpbiBSDQoNCjEuICoqQ3JlYXRlIGEgZGF0YSBmcmFtZSoqIGluIFIgY2FsbGVkIGB0cmFuc2FjdGlvbnNgIGNvbnRhaW5pbmcgdGhlIGRhdGEgYWJvdmUuDQoNCjIuIElkZW50aWZ5IHdoaWNoIHZhcmlhYmxlcyBhcmUgbnVtZXJpYyBhbmQgd2hpY2ggYXJlIGNhdGVnb3JpY2FsDQoNCjMuICoqQ2FsY3VsYXRlIHRvdGFsIHJldmVudWUqKiBmb3IgZWFjaCB0cmFuc2FjdGlvbiBieSBtdWx0aXBseWluZyBgUXR5IMOXIFByaWNlYCBhbmQgYWRkIGl0IGFzIGEgbmV3IGNvbHVtbiBgVG90YWxgLg0KDQo0LiAqKkNvbXB1dGUgc3VtbWFyeSBzdGF0aXN0aWNzKio6DQogICAtIFRvdGFsIHF1YW50aXR5IHNvbGQgZm9yIGVhY2ggcHJvZHVjdA0KICAgLSBUb3RhbCByZXZlbnVlIHBlciBwcm9kdWN0DQogICAtIEF2ZXJhZ2UgcHJpY2UgcGVyIHByb2R1Y3QNCg0KNS4gKipWaXN1YWxpemUgdGhlIGRhdGEqKjoNCiAgIC0gQ3JlYXRlIGEgKipiYXJwbG90Kiogc2hvd2luZyB0b3RhbCBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0Lg0KICAgLSBDcmVhdGUgYSAqKnBpZSBjaGFydCoqIHNob3dpbmcgdGhlIHByb3BvcnRpb24gb2YgdG90YWwgcmV2ZW51ZSBwZXIgY3VzdG9tZXIgdGllci4NCg0KNi4gKipPcHRpb25hbCBDaGFsbGVuZ2UqKjoNCiAgIC0gRmluZCB3aGljaCAqKmRhdGUqKiBoYWQgdGhlIGhpZ2hlc3QgdG90YWwgcmV2ZW51ZS4NCiAgIC0gQ3JlYXRlIGEgKipzdGFja2VkIGJhciBjaGFydCoqIHNob3dpbmcgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyLg0KDQoqKkhpbnRzOioqIFVzZSBgZGF0YS5mcmFtZSgpYCwgYGFnZ3JlZ2F0ZSgpYCwgYGJhcnBsb3QoKWAsIGBwaWUoKWAsIGFuZCBiYXNpYyBhcml0aG1ldGljIG9wZXJhdGlvbnMgaW4gUi4NCg0KIyMgIGNyZWF0ZSBEYXRhIEZyYW1lDQoNCnRyYW5zYWN0aW9ucyA8LSBkYXRhLmZyYW1lKA0KICBEYXRlID0gYXMuRGF0ZShjKA0KICAgICIyMDI1LTEwLTAxIiwgIjIwMjUtMTAtMDEiLCAiMjAyNS0xMC0wMiIsICIyMDI1LTEwLTAyIiwgDQogICAgIjIwMjUtMTAtMDMiLCAiMjAyNS0xMC0wMyIsICIyMDI1LTEwLTA0IiwgIjIwMjUtMTAtMDQiLA0KICAgICIyMDI1LTEwLTA1IiwgIjIwMjUtMTAtMDUiDQogICkpLA0KICBRdHkgPSBjKDIsIDUsIDEsIDMsIDQsIDIsIDYsIDEsIDMsIDUpLA0KICBQcmljZSA9IGMoMTAwMCwgMjAsIDEwMDAsIDMwLCA1MCwgMTAwMCwgMjUsIDEwMDAsIDQwLCAxMCksDQogIFByb2R1Y3QgPSBjKCJMYXB0b3AiLCAiTW91c2UiLCAiTGFwdG9wIiwgIktleWJvYXJkIiwgIk1vdXNlIiwNCiAgICAgICAgICAgICAgIkxhcHRvcCIsICJLZXlib2FyZCIsICJMYXB0b3AiLCAiTW91c2UiLCAiS2V5Ym9hcmQiKSwNCiAgQ3VzdG9tZXJUaWVyID0gYygiSGlnaCIsICJNZWRpdW0iLCAiTG93IiwgIk1lZGl1bSIsICJNZWRpdW0iLA0KICAgICAgICAgICAgICAgICAgICJIaWdoIiwgIkxvdyIsICJIaWdoIiwgIkxvdyIsICJNZWRpdW0iKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMjICBJZGVudGlmeSBkYXRhIHR5cGVzDQoNCnN0cih0cmFuc2FjdGlvbnMpICAjIGxvb2sgYXQgdGhlIHN0cnVjdHVyZSAobnVtZXJpYyB2cyBjYXRlZ29yaWNhbCkNCg0KIyMgIGFkZCBhIHRvdGFsIGNvbHVtDQoNCnRyYW5zYWN0aW9ucyRUb3RhbCA8LSB0cmFuc2FjdGlvbnMkUXR5ICogdHJhbnNhY3Rpb25zJFByaWNlDQoNCiMjIFZpZXcgcmVzdWx0cw0KcHJpbnQodHJhbnNhY3Rpb25zKQ0KDQojIyBTdW1tYXJ5IFN0YXRpc3RpY3MNCg0KIyMgVG90YWwgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdA0KdG90YWxfcXR5IDwtIGFnZ3JlZ2F0ZShRdHkgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQoNCiMjIyBUb3RhbCByZXZlbnVlIHBlciBwcm9kdWN0DQp0b3RhbF9yZXZlbnVlIDwtIGFnZ3JlZ2F0ZShUb3RhbCB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkNCg0KIyMjIEF2ZXJhZ2UgcHJpY2UgcGVyIHByb2R1Y3QNCmF2Z19wcmljZSA8LSBhZ2dyZWdhdGUoUHJpY2UgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBtZWFuKQ0KDQojIyMgVGFtcGlsa2FuIGhhc2lsIHJpbmdrYXNhbg0KY2F0KCJcbj09PSBUb3RhbCBRdWFudGl0eSBwZXIgUHJvZHVjdCA9PT1cbiIpDQpwcmludCh0b3RhbF9xdHkpDQpjYXQoIlxuPT09IFRvdGFsIFJldmVudWUgcGVyIFByb2R1Y3QgPT09XG4iKQ0KcHJpbnQodG90YWxfcmV2ZW51ZSkNCmNhdCgiXG49PT0gQXZlcmFnZSBQcmljZSBwZXIgUHJvZHVjdCA9PT1cbiIpDQpwcmludChhdmdfcHJpY2UpDQoNCiMjIFZpc3VhbGl6YXRpb24NCg0KIyMjIChhKSBCYXJwbG90IC0gdG90YWwgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdA0KYmFycGxvdCgNCiAgdG90YWxfcXR5JFF0eSwNCiAgbmFtZXMuYXJnID0gdG90YWxfcXR5JFByb2R1Y3QsDQogIG1haW4gPSAiVG90YWwgUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCIsDQogIHhsYWIgPSAiUHJvZHVjdCIsDQogIHlsYWIgPSAiVG90YWwgUXVhbnRpdHkiLA0KICBjb2wgPSBjKCJza3libHVlIiwgImxpZ2h0Z3JlZW4iLCAib3JhbmdlIikNCikNCg0KIyMjIChiKSBQaWUgY2hhcnQgLSBwcm9wb3J0aW9uIG9mIHRvdGFsIHJldmVudWUgcGVyIEN1c3RvbWVyIFRpZXINCnJldmVudWVfdGllciA8LSBhZ2dyZWdhdGUoVG90YWwgfiBDdXN0b21lclRpZXIsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkNCnBpZSgNCiAgcmV2ZW51ZV90aWVyJFRvdGFsLA0KICBsYWJlbHMgPSBwYXN0ZShyZXZlbnVlX3RpZXIkQ3VzdG9tZXJUaWVyLCAiLSIsIHJldmVudWVfdGllciRUb3RhbCksDQogIG1haW4gPSAiUHJvcG9ydGlvbiBvZiBUb3RhbCBSZXZlbnVlIHBlciBDdXN0b21lciBUaWVyIiwNCiAgY29sID0gYygiZ29sZCIsICJsaWdodGJsdWUiLCAidG9tYXRvIikNCikNCg0KDQojIyBPcHRpb25hbCBDaGFsbGVuZ2UNCg0KIyMjIChhKSBEYXRlIHdpdGggaGlnaGVzdCB0b3RhbCByZXZlbnVlDQpkYXRlX3JldmVudWUgPC0gYWdncmVnYXRlKFRvdGFsIH4gRGF0ZSwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKQ0KbWF4X3Jldl9kYXRlIDwtIGRhdGVfcmV2ZW51ZVt3aGljaC5tYXgoZGF0ZV9yZXZlbnVlJFRvdGFsKSwgXQ0KY2F0KCJcblRhbmdnYWwgZGVuZ2FuIHRvdGFsIHJldmVudWUgdGVydGluZ2dpOlxuIikNCnByaW50KG1heF9yZXZfZGF0ZSkNCg0KIyMjIChiKSBTdGFja2VkIGJhciBjaGFydDogcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyDQpxdHlfc3RhY2sgPC0gYWdncmVnYXRlKFF0eSB+IFByb2R1Y3QgKyBDdXN0b21lclRpZXIsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkNCnF0eV9tYXRyaXggPC0geHRhYnMoUXR5IH4gQ3VzdG9tZXJUaWVyICsgUHJvZHVjdCwgZGF0YSA9IHF0eV9zdGFjaykNCmJhcnBsb3QoDQogIHF0eV9tYXRyaXgsDQogIGJlc2lkZSA9IEZBTFNFLA0KICBtYWluID0gIlF1YW50aXR5IFNvbGQgcGVyIFByb2R1Y3QgYnkgQ3VzdG9tZXIgVGllciIsDQogIHhsYWIgPSAiUHJvZHVjdCIsDQogIHlsYWIgPSAiUXVhbnRpdHkgU29sZCIsDQogIGNvbCA9IGMoImxpZ2h0Ymx1ZSIsICJnb2xkIiwgInRvbWF0byIpDQopDQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gcm93bmFtZXMocXR5X21hdHJpeCksDQogICAgICAgZmlsbCA9IGMoImxpZ2h0Ymx1ZSIsICJnb2xkIiwgInRvbWF0byIpLCB0aXRsZSA9ICJDdXN0b21lciBUaWVyIikNCg0KIyBFeGVyY2lzZSA1DQoNCioqQ3JlYXRlIFlvdXIgT3duIERhdGEgRnJhbWU6KioNCg0KKipPYmplY3RpdmU6KiogQ3JlYXRlIGEgZGF0YSBmcmFtZSBpbiBSIHdpdGggKiozMCByb3dzKiogY29udGFpbmluZyBhIG1peCBvZiBkYXRhIHR5cGVzOiBjb250aW51b3VzLCBkaXNjcmV0ZSwgbm9taW5hbCwgYW5kIG9yZGluYWwuICANCg0KIyMgSW5zdHJ1Y3Rpb25zDQoNCjEuICoqT3BlbiBSU3R1ZGlvKiogb3IgdGhlIFIgY29uc29sZS4gIA0KDQoyLiAqKkNyZWF0ZSBhIHZlY3RvciBmb3IgZWFjaCBjb2x1bW4qKiBpbiB5b3VyIGRhdGEgZnJhbWU6ICANCg0KICAgLSAqKkRhdGUqKjogMzAgZGF0ZXMgKGNhbiBiZSBzZXF1ZW50aWFsIG9yIHJhbmRvbSB3aXRoaW4gYSBtb250aC95ZWFyKSAgDQogICAtICoqQ29udGludW91cyoqOiBudW1lcmljIHZhbHVlcyB0aGF0IGNhbiB0YWtlIGRlY2ltYWwgdmFsdWVzIChlLmcuLCBoZWlnaHQsIHdlaWdodCwgdGVtcGVyYXR1cmUpICANCiAgIC0gKipEaXNjcmV0ZSoqOiBudW1lcmljIHZhbHVlcyB0aGF0IGNhbiBvbmx5IHRha2Ugd2hvbGUgbnVtYmVycyAoZS5nLiwgbnVtYmVyIG9mIGl0ZW1zLCBudW1iZXIgb2YgdmVoaWNsZXMpICANCiAgIC0gKipOb21pbmFsKio6IGNhdGVnb3JpY2FsIHZhbHVlcyB3aXRoICoqbm8gb3JkZXIqKiAoZS5nLiwgY29sb3IsIGdlbmRlciwgY2l0eSkgIA0KICAgLSAqKk9yZGluYWwqKjogY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggYSAqKmRlZmluZWQgb3JkZXIqKiAoZS5nLiwgTG93LCBNZWRpdW0sIEhpZ2g7IEJlZ2lubmVyLCBJbnRlcm1lZGlhdGUsIEV4cGVydCkgIA0KDQozLiAqKkNvbWJpbmUgYWxsIHZlY3RvcnMgaW50byBhIGRhdGEgZnJhbWUqKiBjYWxsZWQgYG15X2RhdGFgLiAgDQoNCjQuICoqQ2hlY2sgeW91ciBkYXRhIGZyYW1lKiogdXNpbmcgYGhlYWQoKWAgb3IgYFZpZXcoKWAgdG8gZW5zdXJlIGl0IGhhcyAqKjMwIHJvd3MqKiBhbmQgdGhlIGNvbHVtbnMgYXJlIGNvcnJlY3QuICANCg0KNS4gKipPcHRpb25hbCB0YXNrcyoqOiAgDQogICAtIFN1bW1hcml6ZSBlYWNoIGNvbHVtbiB1c2luZyBgc3VtbWFyeSgpYCAgDQogICAtIENvdW50IHRoZSBmcmVxdWVuY3kgb2YgZWFjaCBjYXRlZ29yeSBmb3IgKipOb21pbmFsKiogYW5kICoqT3JkaW5hbCoqIGNvbHVtbnMgdXNpbmcgYHRhYmxlKClgICANCg0KIyMgSGludHMNCg0KLSBVc2UgYHNlcS5EYXRlKClgIG9yIGBhcy5EYXRlKClgIHRvIGdlbmVyYXRlIHRoZSBEYXRlIGNvbHVtbi4gIA0KLSBVc2UgYHJ1bmlmKClgIG9yIGBybm9ybSgpYCBmb3IgY29udGludW91cyBudW1lcmljIGRhdGEuICANCi0gVXNlIGBzYW1wbGUoKWAgZm9yIGRpc2NyZXRlLCBub21pbmFsLCBhbmQgb3JkaW5hbCBkYXRhLiAgDQotIEVuc3VyZSB0aGUgKipvcmRpbmFsIHZlY3RvcioqIGlzIGNyZWF0ZWQgd2l0aCBgZmFjdG9yKC4uLiwgbGV2ZWxzID0gYygiTG93IiwiTWVkaXVtIiwiSGlnaCIpLCBvcmRlcmVkID0gVFJVRSlgIChvciBzaW1pbGFyKS4gDQoNCg0KIyMgQ3JlYXRlIGVhY2ggY29sdW1uDQoNCiMjIERhdGU6IDMwIGNvbnNlY3V0aXZlIGRhdGVzIGluIE9jdG9iZXIgMjAyNQ0KRGF0ZSA8LSBzZXEuRGF0ZShmcm9tID0gYXMuRGF0ZSgiMjAyNS0xMC0wMSIpLCANCiAgICAgICAgICAgICAgICAgYnkgPSAiZGF5IiwgDQogICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSAzMCkNCg0KIyMgQ29udGludW91czogZm9yIGV4YW1wbGUgYm9keSB0ZW1wZXJhdHVyZSBkYXRhIChpbiDCsEMpLCB1c2UgZGVjaW1hbHMNCkNvbnRpbnVvdXMgPC0gcm91bmQocnVuaWYoMzAsIG1pbiA9IDM1LjUsIG1heCA9IDM3LjUpLCAxKQ0KDQojIyBEaXNjcmV0ZTogZS5nIG51bWJlciBvZiBpdGVtcyBzb2xkICh3aG9sZSBudW1iZXIpDQpEaXNjcmV0ZSA8LSBzYW1wbGUoMTo1MCwgMzAsIHJlcGxhY2UgPSBUUlVFKQ0KDQojIyBOb21pbmFsOiBlLmcgY3V0b21lcidzIGNpdHkgb2Ygb3JpZ2luIChubyBvcmRlcikNCk5vbWluYWwgPC0gc2FtcGxlKGMoIkpha2FydGEiLCAiQmFuZHVuZyIsICJTdXJhYmF5YSIsICJNZWRhbiIsICJCYWxpIiksDQogICAgICAgICAgICAgICAgICAzMCwgcmVwbGFjZSA9IFRSVUUpDQoNCiMjIE9yZGluYWw6IGUuZyBzdGF0aXNmYWN0aW9uIGxldmVsICh0aGVyZSBpcyBhIHNlcXVlbmNlKQ0KT3JkaW5hbCA8LSBmYWN0b3IoDQogIHNhbXBsZShjKCJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSwgMzAsIHJlcGxhY2UgPSBUUlVFKSwNCiAgbGV2ZWxzID0gYygiTG93IiwgIk1lZGl1bSIsICJIaWdoIiksDQogIG9yZGVyZWQgPSBUUlVFDQopDQoNCg0KIyMgQ29tYmluZSBhbGwgaW50byBhIGRhdGUgZnJhbWUNCg0KbXlfZGF0YSA8LSBkYXRhLmZyYW1lKERhdGUsIENvbnRpbnVvdXMsIERpc2NyZXRlLCBOb21pbmFsLCBPcmRpbmFsKQ0KDQojIyBDaGVjayB0aGUgZGF0YSBjb250ZW50cw0KDQpoZWFkKG15X2RhdGEpICAgIyBkaXNwbGF5IHRoZSBmaXJzdCA2IHJvd3MNClZpZXcobXlfZGF0YSkgICAjIG9wZW4gaW4gUlN0dWRpbyB3aW5kb3cgKG9wdGlvbmFsKQ0KDQoNCiMjIChPcHRpb25hbCkgRGF0YSBTdW1tYXJ5DQoNCnN1bW1hcnkobXlfZGF0YSkNCg0KIyMgQ2FsY3VsYXRlIGZyZXF1ZW5jeSBjYXRlZ29yaWVzIA0KDQpjYXQoIlxuPT09IE5vbWluYWwgRnJlcXVlbmN5ICAoQ2l0eSkgPT09XG4iKQ0KcHJpbnQodGFibGUobXlfZGF0YSROb21pbmFsKSkNCg0KY2F0KCJcbj09PSBPcmRpbmFsIEZyZXF1ZW5jeSAoTGV2ZWwgb2YgU3RhdGlzZmFjdGlvbikgPT09XG4iKQ0KcHJpbnQodGFibGUobXlfZGF0YSRPcmRpbmFsKSkNCg0KDQoNCg0KDQo=