Data Exploration

Exercises ~ Week 3

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")  

# 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(
    "Numeric",
    "Numeric",
    "Categorical",
    "Categorical",
    "Categorical"
  ),
  Subtype = c(
    "Discrete",
    "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 Numeric Discrete
2 Student height in cm Numeric Continuous
3 Employee gender (Male / Female) Categorical Nominal
4 Customer satisfaction level: Low, Medium, High Categorical Ordinal
5 Respondent’s favorite color: Red, Blue, Green Categorical 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",
    "External",
    "External",
    "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.

# Create a data frame for Transactions
library(knitr)
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 = factor(c(
  "High",
  "Medium",
  "Low",
  "Medium",
  "Medium",
  "High",
  "Low",
  "High",
  "Low",
  "Medium"
  ),
levels = c("Low","Medium","High"),
ordered = TRUE) 
transactions <-  data.frame (Date, Qty, Price, Product, CustomerTier, stringsAsFactors = FALSE)

# Display the data frame
library(knitr)
kable(transactions, caption = "Data Transactions")
Data Transactions
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
# 2. Identify variable types
library(knitr)
variable_types <- data.frame(
  Variable = c(
    "Date",
    "Qty",
    "Price",
    "Product",
    "CustomerTier"
    ),
  Type = c(
    "Numeric (Discrete)",
    "Numeric (Discrete)",
    "Numeric (Discrete)",
    "Categorical (Nominal)",
    "Categorical (Ordinal)"
    )
)

# Display the data frame
kable(variable_types, caption = "Variable Types in Transactions Data")
Variable Types in Transactions Data
Variable Type
Date Numeric (Discrete)
Qty Numeric (Discrete)
Price Numeric (Discrete)
Product Categorical (Nominal)
CustomerTier Categorical (Ordinal)
# 3. Calculate total revenue
transactions$total = transactions$Qty * transactions$Price
kable(transactions)
Date Qty Price Product CustomerTier total
2025-10-01 2 1000 Laptop High 2000
2025-10-01 5 20 Mouse Medium 100
2025-10-02 1 1000 Laptop Low 1000
2025-10-02 3 30 Keyboard Medium 90
2025-10-03 4 50 Mouse Medium 200
2025-10-03 2 1000 Laptop High 2000
2025-10-04 6 25 Keyboard Low 150
2025-10-04 1 1000 Laptop High 1000
2025-10-05 3 40 Mouse Low 120
2025-10-05 5 10 Keyboard Medium 50
# 4. Compute summary statistic

# a. Total quantity sold for each product
total_Qty = aggregate(Qty ~ Product, data = transactions, sum)
kable(total_Qty, caption = "Total Quantity Sold per Product")
Total Quantity Sold per Product
Product Qty
Keyboard 14
Laptop 6
Mouse 12
# b. total revenue per product
total_revenue = aggregate(total ~ Product, data = transactions, sum)
kable(total_revenue, caption = "Total Revenue per Product")
Total Revenue per Product
Product total
Keyboard 290
Laptop 6000
Mouse 420
# c. Average price per product
avg_price = aggregate(Price ~ Product, data = transactions, mean)
kable(avg_price, caption = "Average Price per Product")
Average Price per Product
Product Price
Keyboard 21.66667
Laptop 1000.00000
Mouse 36.66667
# 5. Visualize the data

# a. barplot showing total quantity sold per product
total_qty = tapply(transactions$Qty, transactions$Product, sum)
barplot(total_qty,
        main = "Total Quantity Sold per Product",
        xlab = "Product",
        ylab = "Total Quantity",
        col = "lightblue")

# b. pie chart showing the proportion of total revenue
total_revenue_tier = tapply(transactions$total, transactions$CustomerTier, sum)
pie(total_revenue_tier,
    main = "Proportion of Total Revenue per Customer Tier",
    col = rainbow(length(total_revenue_tier)))

# 6. Optional challenge

# a. Find which date had the highest total revenue
total_revenue_date <- aggregate(total ~ Date, data = transactions, sum)
total_revenue_date[which.max(total_revenue_date$total), ]
# b. stacked bar chart showing quantity sold per product by customer tier
qty_table = xtabs(Qty ~ Product + CustomerTier, data = transactions)
barplot(qty_table,
        main = "Quantity Sold per Product by Customer Tier",
        xlab = "Product",
        ylab = "Quantity",
        col = c("lightblue", "lightgreen", "pink"))

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).
# 1. Coffee Shop Data
library(knitr)
Date = seq(as.Date("2025-09-01"), as.Date("2025-09-30"), by = "day")    # Date
Coffee_ml = runif(30, min = 1500, max = 4000)             # Continuous / Volume Kopi
Cups_Sold = sample(20:100, 30, replace = TRUE)            # Discrete / Jumlah Kopi
Drink_Type = sample(c(
  "Americano",
  "Cappuccino",
  "Latte",
  "Espresso",
  "Mocha"), 30, replace = TRUE)                           # Nominal / Jenis Kopi
Customer_Satisfaction = factor(
  sample(c(
    "Poor",
    "Fair",
    "Good",
    "Very Good",
    "Excellent"), 30, replace = TRUE),
  levels = c("Poor", "Fair", "Good", "Very Good", "Excellent"),
  ordered = TRUE)                                         # Ordinal / Satisfaction

# Combine all vectors into a data frame
my_data = data.frame(Date, Coffee_ml, Cups_Sold, Drink_Type, Customer_Satisfaction)
kable(my_data)
Date Coffee_ml Cups_Sold Drink_Type Customer_Satisfaction
2025-09-01 2119.589 82 Espresso Poor
2025-09-02 1652.511 41 Americano Fair
2025-09-03 3538.228 82 Americano Very Good
2025-09-04 3596.254 75 Espresso Fair
2025-09-05 2717.580 41 Mocha Poor
2025-09-06 2622.993 100 Americano Good
2025-09-07 3579.724 65 Cappuccino Excellent
2025-09-08 2051.191 67 Americano Poor
2025-09-09 3702.286 90 Latte Very Good
2025-09-10 2436.549 74 Espresso Poor
2025-09-11 1800.542 24 Espresso Excellent
2025-09-12 2910.268 36 Cappuccino Very Good
2025-09-13 2582.743 76 Espresso Good
2025-09-14 1640.772 46 Mocha Good
2025-09-15 3080.980 56 Mocha Very Good
2025-09-16 2903.017 35 Espresso Very Good
2025-09-17 2286.498 28 Americano Fair
2025-09-18 3331.012 56 Espresso Fair
2025-09-19 3655.258 83 Americano Good
2025-09-20 2286.588 20 Americano Excellent
2025-09-21 2555.764 63 Cappuccino Poor
2025-09-22 3392.277 49 Espresso Good
2025-09-23 3083.719 40 Espresso Good
2025-09-24 3162.052 93 Mocha Very Good
2025-09-25 3733.539 56 Mocha Good
2025-09-26 3367.869 89 Espresso Excellent
2025-09-27 3921.344 68 Mocha Excellent
2025-09-28 2545.634 86 Mocha Good
2025-09-29 2542.456 100 Americano Fair
2025-09-30 2936.739 97 Americano Very Good
# 2. Summary data (opsional)
summary_data = summary(my_data)
kable(summary_data)
Date Coffee_ml Cups_Sold Drink_Type Customer_Satisfaction
Min. :2025-09-01 Min. :1641 Min. : 20.00 Length:30 Poor :5
1st Qu.:2025-09-08 1st Qu.:2463 1st Qu.: 42.25 Class :character Fair :5
Median :2025-09-15 Median :2907 Median : 66.00 Mode :character Good :8
Mean :2025-09-15 Mean :2858 Mean : 63.93 NA Very Good:7
3rd Qu.:2025-09-22 3rd Qu.:3386 3rd Qu.: 82.75 NA Excellent:5
Max. :2025-09-30 Max. :3921 Max. :100.00 NA NA
# 3. Frekuensi Kategori (nominal, ordinal)
drink_freq = table(my_data$Drink_Type)
satisfaction_freq = table(my_data$Customer_Satisfaction)

kable(drink_freq, caption = "Frekuensi Jenis Minuman (Nominal)")
Frekuensi Jenis Minuman (Nominal)
Var1 Freq
Americano 9
Cappuccino 3
Espresso 10
Latte 1
Mocha 7
kable(satisfaction_freq, caption = "Frekuensi Kepuasan Pelanggan (Ordinal)")
Frekuensi Kepuasan Pelanggan (Ordinal)
Var1 Freq
Poor 5
Fair 5
Good 8
Very Good 7
Excellent 5
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICAgICAjIE1haW4gdGl0bGUgb2YgdGhlIGRvY3VtZW50DQpzdWJ0aXRsZTogIkV4ZXJjaXNlcyB+IFdlZWsgMyIgICAgICAjIFN1YnRpdGxlIG9yIHRvcGljIGZvciB3ZWVrIDMNCmF1dGhvcjogICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgUmVwbGFjZSB3aXRoIHlvdXIgZnVsbCBuYW1lDQotICJBbmdlbGlxdWUgS2l5b3NoaSBMYWtlaXNoYSBCLlUiDQotICJLaGFmaXphdHVuIE5pc2EiIA0KLSAiTmF5Y2hpbGxhIEFkZWxpYSBaYWhyYWgiDQotICJOYWtlaXNoYSBBdWxpYSBaYWhyYSINCi0gIlZlcm9uaWNhIEwgRiBYYXZpZXIiDQpkYXRlOiAgImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIiAjIEF1dG8gZGlzcGxheXMgdGhlIGN1cnJlbnQgZGF0ZQ0Kb3V0cHV0OiAgICAgICAgICAgICAgICAgICAgICAgICAjIE91dHB1dCBzZWN0aW9uIGRlZmluZXMgdGhlIGZvcm1hdCBhbmQgbGF5b3V0IA0KICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjogICAgICAjIGh0dHBzOi8vZ2l0aHViLmNvbS9qdWJhL3JtZGZvcm1hdHMNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZSAgICAgICAgIyBFbWJlZHMgYWxsIHJlc291cmNlcyAoQ1NTLCBKUywgaW1hZ2VzKSANCiAgICB0aHVtYm5haWxzOiB0cnVlICAgICAgICAgICAgIyBEaXNwbGF5cyBpbWFnZSB0aHVtYm5haWxzIGluIHRoZSBkb2MNCiAgICBsaWdodGJveDogdHJ1ZSAgICAgICAgICAgICAgIyBFbmFibGVzIGNsaWNrIHRvIGVubGFyZ2UgaW1hZ2VzDQogICAgZ2FsbGVyeTogdHJ1ZSAgICAgICAgICAgICAgICMgR3JvdXBzIGltYWdlcyBpbnRvIGFuIGludGVyYWN0aXZlIGdhbGxlcnkNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUgICAgICAgIyBBdXRvbWF0aWNhbGx5IG51bWJlcnMgYWxsIHNlY3Rpb25zDQogICAgbGliX2RpcjogbGlicyAgICAgICAgICAgICAgICMgRGlyZWN0b3J5IHdoZXJlIEphdmFTY3JpcHQvQ1NTIGxpYnJhcmllcw0KICAgIGRmX3ByaW50OiAicGFnZWQiICAgICAgICAgICAjIERpc3BsYXlzIGRhdGEgZnJhbWVzIGFzIGludGVyYWN0aXZlIHBhZ2VkIA0KICAgIGNvZGVfZm9sZGluZzogInNob3ciICAgICAgICAjIEFsbG93cyBmb2xkaW5nL3VuZm9sZGluZyBSIGNvZGUgYmxvY2tzIA0KICAgIGNvZGVfZG93bmxvYWQ6IHllcyAgICAgICAgICAjIEFkZHMgYSBidXR0b24gdG8gZG93bmxvYWQgYWxsIFIgY29kZQ0KLS0tDQoNCg0KPGltZyBpZD0iRm90byIgc3JjPSJndXJsc3BpY3QuanBlZz9yYXc9dHJ1ZSIgYWx0PSJMb2dvIiBzdHlsZT0id2lkdGg6MjAwcHg7IGRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87Ij4NCg0KLS0tDQoNCiMjIEV4ZXJjaXNlIDENCg0KVGhlIGZvbGxvd2luZyB0YWJsZSBzaG93cyBzYW1wbGUgaW5mb3JtYXRpb24gZm9yIHRocmVlIHN0dWRlbnRzLiBFYWNoIG9ic2VydmF0aW9uIHJlcHJlc2VudHMgYSBzaW5nbGUgc3R1ZGVudCBhbmQgaW5jbHVkZXMgZGV0YWlscyBzdWNoIGFzIHRoZWlyIHVuaXF1ZSBzdHVkZW50IElELCBuYW1lLCBhZ2UsIHRvdGFsIGNyZWRpdHMgY29tcGxldGVkLCBtYWpvciBmaWVsZCBvZiBzdHVkeSwgYW5kIHllYXIgbGV2ZWwuICANCg0KVGhpcyBkYXRhc2V0IGRlbW9uc3RyYXRlcyBhIG1peHR1cmUgb2YgdmFyaWFibGUgdHlwZXM6ICANCg0KLSAqKk5vbWluYWw6KiogU3R1ZGVudElELCBOYW1lLCBNYWpvciAgDQotICoqTnVtZXJpYzoqKiBBZ2UgKGNvbnRpbnVvdXMpLCBDcmVkaXRzQ29tcGxldGVkIChkaXNjcmV0ZSkgIA0KLSAqKk9yZGluYWw6KiogWWVhckxldmVsIChGcmVzaG1hbiDihpIgU2VuaW9yKSAgDQoNCnwgU3R1ZGVudElEIHwgTmFtZSAgIHwgQWdlIHwgQ3JlZGl0c0NvbXBsZXRlZCB8IE1ham9yICAgICAgICAgICAgfCBZZWFyTGV2ZWwgfA0KfC0tLS0tLS0tLS0tfC0tLS0tLS0tfC0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tfA0KfCBTMDAxICAgICAgfCBBbGljZSAgfCAyMCAgfCA0NSAgICAgICAgICAgICAgfCBEYXRhIFNhaW5zICAgICAgfCBTb3Bob21vcmUgfA0KfCBTMDAyICAgICAgfCBCdWRpICAgfCAyMSAgfCA2MCAgICAgICAgICAgICAgfCBNYXRoZW1hdGljcyAgICAgfCBKdW5pb3IgICAgfA0KfCBTMDAzICAgICAgfCBDaXRyYSAgfCAxOSAgfCAzMCAgICAgICAgICAgICAgfCBTdGF0aXN0aWNzICAgICAgfCBGcmVzaG1hbiAgfA0KDQpgYGB7cn0NCiMgMS4gQ3JlYXRlIHZlY3RvcnMgZm9yIGVhY2ggdmFyaWFibGUNClN0dWRlbnRJRCA8LSBjKCJTMDAxIiwgIlMwMDIiLCAiUzAwMyIpICAgICAgICMgTm9taW5hbCAvIElEDQpOYW1lIDwtIGMoIkFsaWNlIiwgIkJ1ZGkiLCAiQ2l0cmEiKSAgICAgICAgICAjIE5vbWluYWwgLyBOYW1lDQpBZ2UgPC0gYygyMCwgMjEsIDE5KSAgICAgICAgICAgICAgICAgICAgICAgICAjIE51bWVyaWMgLyBDb250aW51b3VzDQpDcmVkaXRzQ29tcGxldGVkIDwtIGMoNDUsIDYwLCAzMCkgICAgICAgICAgICAjIE51bWVyaWMgLyBEaXNjcmV0ZQ0KDQojIE5vbWluYWwNCk1ham9yIDwtIGMoIkRhdGEgU2FpbnMiLCAiTWF0aGVtYXRpY3MiLCAiU3RhdGlzdGljcyIpICANCg0KIyBPcmRpbmFsDQpZZWFyTGV2ZWwgPC0gZmFjdG9yKGMoIlNvcGhvbW9yZSIsICJKdW5pb3IiLCAiRnJlc2htYW4iKSwNCiAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiRnJlc2htYW4iLCJTb3Bob21vcmUiLCJKdW5pb3IiLCJTZW5pb3IiKSwNCiAgICAgICAgICAgICAgICAgICAgb3JkZXJlZCA9IFRSVUUpICAgICAgICAgIA0KDQojIDIuIENvbWJpbmUgYWxsIHZlY3RvcnMgaW50byBhIGRhdGEgZnJhbWUNCnN0dWRlbnRzIDwtIGRhdGEuZnJhbWUoDQogIFN0dWRlbnRJRCwgTmFtZSwgQWdlLCBDcmVkaXRzQ29tcGxldGVkLCBNYWpvciwgWWVhckxldmVsLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyAzLiBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lDQpwcmludChzdHVkZW50cykNCmBgYA0KDQoNCiMjIEV4ZXJjaXNlIDINCg0KKipJZGVudGlmeSBEYXRhIFR5cGVzOioqIERldGVybWluZSB0aGUgdHlwZSBvZiBkYXRhIGZvciBlYWNoIG9mIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOg0KDQpgYGB7cn0NCiMgSW5zdGFsbCBrbml0ciBwYWNrYWdlIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZA0KIyBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQpsaWJyYXJ5KGtuaXRyKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIERhdGEgVHlwZXMNCnZhcmlhYmxlc19pbmZvIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMTo1LA0KICBWYXJpYWJsZSA9IGMoDQogICAgIk51bWJlciBvZiB2ZWhpY2xlcyBwYXNzaW5nIHRocm91Z2ggdGhlIHRvbGwgcm9hZCBlYWNoIGRheSIsDQogICAgIlN0dWRlbnQgaGVpZ2h0IGluIGNtIiwNCiAgICAiRW1wbG95ZWUgZ2VuZGVyIChNYWxlIC8gRmVtYWxlKSIsDQogICAgIkN1c3RvbWVyIHNhdGlzZmFjdGlvbiBsZXZlbDogTG93LCBNZWRpdW0sIEhpZ2giLA0KICAgICJSZXNwb25kZW50J3MgZmF2b3JpdGUgY29sb3I6IFJlZCwgQmx1ZSwgR3JlZW4iDQogICksDQogIERhdGFUeXBlID0gYygNCiAgICAiTnVtZXJpYyIsDQogICAgIk51bWVyaWMiLA0KICAgICJDYXRlZ29yaWNhbCIsDQogICAgIkNhdGVnb3JpY2FsIiwNCiAgICAiQ2F0ZWdvcmljYWwiDQogICksDQogIFN1YnR5cGUgPSBjKA0KICAgICJEaXNjcmV0ZSIsDQogICAgIkNvbnRpbnVvdXMiLA0KICAgICJOb21pbmFsIiwNCiAgICAiT3JkaW5hbCIsDQogICAgIk5vbWluYWwiDQogICksDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUgYXMgYSBuZWF0IHRhYmxlDQprYWJsZSh2YXJpYWJsZXNfaW5mbywgDQogICAgICBjYXB0aW9uID0gIlRhYmxlIG9mIFZhcmlhYmxlcyBhbmQgRGF0YSBUeXBlcyIpDQpgYGANCi0tLQ0KDQojIyBFeGVyY2lzZSAzDQoNCioqQ2xhc3NpZnkgRGF0YSBTb3VyY2VzOioqIERldGVybWluZSB3aGV0aGVyIHRoZSBmb2xsb3dpbmcgZGF0YSBjb21lcyBmcm9tICoqaW50ZXJuYWwqKiBvciAqKmV4dGVybmFsIHNvdXJjZXMqKiwgYW5kIHdoZXRoZXIgaXQgaXMgKipzdHJ1Y3R1cmVkKiogb3IgKip1bnN0cnVjdHVyZWQqKjoNCg0KYGBge3J9DQojIEluc3RhbGwgRFQgcGFja2FnZSBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCiMgaW5zdGFsbC5wYWNrYWdlcygiRFQiKQ0KbGlicmFyeShEVCkNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBkYXRhIHNvdXJjZXMgDQpkYXRhX3NvdXJjZXMgPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjQsDQogIERhdGFTb3VyY2UgPSBjKA0KICAgICJEYWlseSBzYWxlcyB0cmFuc2FjdGlvbiBkYXRhIG9mIHRoZSBjb21wYW55IiwNCiAgICAiV2VhdGhlciByZXBvcnRzIGZyb20gQk1LRyIsDQogICAgIlByb2R1Y3QgcmV2aWV3cyBvbiBzb2NpYWwgbWVkaWEiLA0KICAgICJXYXJlaG91c2UgaW52ZW50b3J5IHJlcG9ydHMiDQogICksDQogIEludGVybmFsX0V4dGVybmFsID0gYygNCiAgICAiSW50ZXJuYWwiLA0KICAgICJFeHRlcm5hbCIsDQogICAgIkV4dGVybmFsIiwNCiAgICAiSW50ZXJuYWwiDQogICksDQogIFN0cnVjdHVyZWRfVW5zdHJ1Y3R1cmVkID0gYygNCiAgICAiU3RydWN0dXJlZCIsDQogICAgIlN0cnVjdHVyZWQiLA0KICAgICJVbnN0cnVjdHVyZWQiLA0KICAgICJTdHJ1Y3R1cmVkIg0KICApLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lIGFzIGEgbmVhdCB0YWJsZQ0KZGF0YXRhYmxlKGRhdGFfc291cmNlcywgDQogICAgICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBEYXRhIFNvdXJjZXMiLA0KICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UpICMgaGlkZXMgdGhlIGluZGV4IGNvbHVtbg0KYGBgDQoNCi0tLQ0KDQojIyBFeGVyY2lzZSA0DQoNCioqRGF0YXNldCBTdHJ1Y3R1cmU6KiogQ29uc2lkZXIgdGhlIGZvbGxvd2luZyB0cmFuc2FjdGlvbiB0YWJsZToNCg0KfCBEYXRlICAgICAgIHwgUXR5IHwgUHJpY2UgfCBQcm9kdWN0ICB8IEN1c3RvbWVyVGllciB8DQp8LS0tLS0tLS0tLS0tfC0tLS0tfC0tLS0tLS18LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLXwNCnwgMjAyNS0xMC0wMSB8IDIgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTAxIHwgNSAgIHwgMjAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDIgfCAxICAgfCAxMDAwICB8IExhcHRvcCAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wMiB8IDMgICB8IDMwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAzIHwgNCAgIHwgNTAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDMgfCAyICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wNCB8IDYgICB8IDI1ICAgIHwgS2V5Ym9hcmQgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTA0IHwgMSAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDUgfCAzICAgfCA0MCAgICB8IE1vdXNlICAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wNSB8IDUgICB8IDEwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KDQoNCioqWW91ciBBc3NpZ25tZW50IEluc3RydWN0aW9uczoqKiBDcmVhdGluZyBhIFRyYW5zYWN0aW9ucyBUYWJsZSBhYm92ZSBpbiBSDQoNCjEuICoqQ3JlYXRlIGEgZGF0YSBmcmFtZSoqIGluIFIgY2FsbGVkIGB0cmFuc2FjdGlvbnNgIGNvbnRhaW5pbmcgdGhlIGRhdGEgYWJvdmUuDQoNCjIuIElkZW50aWZ5IHdoaWNoIHZhcmlhYmxlcyBhcmUgbnVtZXJpYyBhbmQgd2hpY2ggYXJlIGNhdGVnb3JpY2FsDQoNCjMuICoqQ2FsY3VsYXRlIHRvdGFsIHJldmVudWUqKiBmb3IgZWFjaCB0cmFuc2FjdGlvbiBieSBtdWx0aXBseWluZyBgUXR5IMOXIFByaWNlYCBhbmQgYWRkIGl0IGFzIGEgbmV3IGNvbHVtbiBgVG90YWxgLg0KDQo0LiAqKkNvbXB1dGUgc3VtbWFyeSBzdGF0aXN0aWNzKio6DQogICAtIFRvdGFsIHF1YW50aXR5IHNvbGQgZm9yIGVhY2ggcHJvZHVjdA0KICAgLSBUb3RhbCByZXZlbnVlIHBlciBwcm9kdWN0DQogICAtIEF2ZXJhZ2UgcHJpY2UgcGVyIHByb2R1Y3QNCg0KNS4gKipWaXN1YWxpemUgdGhlIGRhdGEqKjoNCiAgIC0gQ3JlYXRlIGEgKipiYXJwbG90Kiogc2hvd2luZyB0b3RhbCBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0Lg0KICAgLSBDcmVhdGUgYSAqKnBpZSBjaGFydCoqIHNob3dpbmcgdGhlIHByb3BvcnRpb24gb2YgdG90YWwgcmV2ZW51ZSBwZXIgY3VzdG9tZXIgdGllci4NCg0KNi4gKipPcHRpb25hbCBDaGFsbGVuZ2UqKjoNCiAgIC0gRmluZCB3aGljaCAqKmRhdGUqKiBoYWQgdGhlIGhpZ2hlc3QgdG90YWwgcmV2ZW51ZS4NCiAgIC0gQ3JlYXRlIGEgKipzdGFja2VkIGJhciBjaGFydCoqIHNob3dpbmcgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyLg0KDQoqKkhpbnRzOioqIFVzZSBgZGF0YS5mcmFtZSgpYCwgYGFnZ3JlZ2F0ZSgpYCwgYGJhcnBsb3QoKWAsIGBwaWUoKWAsIGFuZCBiYXNpYyBhcml0aG1ldGljIG9wZXJhdGlvbnMgaW4gUi4NCg0KYGBge3J9DQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIFRyYW5zYWN0aW9ucw0KbGlicmFyeShrbml0cikNCkRhdGUgPSBjICgNCiAgIjIwMjUtMTAtMDEiLCAgDQogICIyMDI1LTEwLTAxIiwgDQogICIyMDI1LTEwLTAyIiwgDQogICIyMDI1LTEwLTAyIiwgDQogICIyMDI1LTEwLTAzIiwgDQogICIyMDI1LTEwLTAzIiwgDQogICIyMDI1LTEwLTA0IiwgDQogICIyMDI1LTEwLTA0IiwgDQogICIyMDI1LTEwLTA1IiwgDQogICIyMDI1LTEwLTA1Ig0KICApICAgICAgICAgICAgICANClF0eSA9IGMgKDIsIDUsIDEsIDMsIDQsIDIsIDYsIDEsIDMsIDUpICANClByaWNlID0gYyAoMTAwMCwgMjAsIDEwMDAsIDMwLCA1MCwgMTAwMCwgMjUsIDEwMDAsIDQwLCAxMCkgIA0KUHJvZHVjdCA9IGMgKA0KICAiTGFwdG9wIiwNCiAgIk1vdXNlIiwNCiAgIkxhcHRvcCIsDQogICJLZXlib2FyZCIsDQogICJNb3VzZSIsDQogICJMYXB0b3AiLA0KICAiS2V5Ym9hcmQiLA0KICAiTGFwdG9wIiwNCiAgIk1vdXNlIiwNCiAgIktleWJvYXJkIg0KICApICAgICAgICAgDQpDdXN0b21lclRpZXIgPSBmYWN0b3IoYygNCiAgIkhpZ2giLA0KICAiTWVkaXVtIiwNCiAgIkxvdyIsDQogICJNZWRpdW0iLA0KICAiTWVkaXVtIiwNCiAgIkhpZ2giLA0KICAiTG93IiwNCiAgIkhpZ2giLA0KICAiTG93IiwNCiAgIk1lZGl1bSINCiAgKSwNCmxldmVscyA9IGMoIkxvdyIsIk1lZGl1bSIsIkhpZ2giKSwNCm9yZGVyZWQgPSBUUlVFKSANCnRyYW5zYWN0aW9ucyA8LSAgZGF0YS5mcmFtZSAoRGF0ZSwgUXR5LCBQcmljZSwgUHJvZHVjdCwgQ3VzdG9tZXJUaWVyLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCiMgRGlzcGxheSB0aGUgZGF0YSBmcmFtZQ0KbGlicmFyeShrbml0cikNCmthYmxlKHRyYW5zYWN0aW9ucywgY2FwdGlvbiA9ICJEYXRhIFRyYW5zYWN0aW9ucyIpDQpgYGANCg0KYGBge3J9DQojIDIuIElkZW50aWZ5IHZhcmlhYmxlIHR5cGVzDQpsaWJyYXJ5KGtuaXRyKQ0KdmFyaWFibGVfdHlwZXMgPC0gZGF0YS5mcmFtZSgNCiAgVmFyaWFibGUgPSBjKA0KICAgICJEYXRlIiwNCiAgICAiUXR5IiwNCiAgICAiUHJpY2UiLA0KICAgICJQcm9kdWN0IiwNCiAgICAiQ3VzdG9tZXJUaWVyIg0KICAgICksDQogIFR5cGUgPSBjKA0KICAgICJOdW1lcmljIChEaXNjcmV0ZSkiLA0KICAgICJOdW1lcmljIChEaXNjcmV0ZSkiLA0KICAgICJOdW1lcmljIChEaXNjcmV0ZSkiLA0KICAgICJDYXRlZ29yaWNhbCAoTm9taW5hbCkiLA0KICAgICJDYXRlZ29yaWNhbCAoT3JkaW5hbCkiDQogICAgKQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCmthYmxlKHZhcmlhYmxlX3R5cGVzLCBjYXB0aW9uID0gIlZhcmlhYmxlIFR5cGVzIGluIFRyYW5zYWN0aW9ucyBEYXRhIikNCg0KYGBgDQoNCmBgYHtyfQ0KIyAzLiBDYWxjdWxhdGUgdG90YWwgcmV2ZW51ZQ0KdHJhbnNhY3Rpb25zJHRvdGFsID0gdHJhbnNhY3Rpb25zJFF0eSAqIHRyYW5zYWN0aW9ucyRQcmljZQ0Ka2FibGUodHJhbnNhY3Rpb25zKQ0KDQpgYGANCg0KYGBge3J9DQojIDQuIENvbXB1dGUgc3VtbWFyeSBzdGF0aXN0aWMNCg0KIyBhLiBUb3RhbCBxdWFudGl0eSBzb2xkIGZvciBlYWNoIHByb2R1Y3QNCnRvdGFsX1F0eSA9IGFnZ3JlZ2F0ZShRdHkgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQprYWJsZSh0b3RhbF9RdHksIGNhcHRpb24gPSAiVG90YWwgUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCIpDQoNCiMgYi4gdG90YWwgcmV2ZW51ZSBwZXIgcHJvZHVjdA0KdG90YWxfcmV2ZW51ZSA9IGFnZ3JlZ2F0ZSh0b3RhbCB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkNCmthYmxlKHRvdGFsX3JldmVudWUsIGNhcHRpb24gPSAiVG90YWwgUmV2ZW51ZSBwZXIgUHJvZHVjdCIpDQoNCiMgYy4gQXZlcmFnZSBwcmljZSBwZXIgcHJvZHVjdA0KYXZnX3ByaWNlID0gYWdncmVnYXRlKFByaWNlIH4gUHJvZHVjdCwgZGF0YSA9IHRyYW5zYWN0aW9ucywgbWVhbikNCmthYmxlKGF2Z19wcmljZSwgY2FwdGlvbiA9ICJBdmVyYWdlIFByaWNlIHBlciBQcm9kdWN0IikNCg0KYGBgDQoNCmBgYHtyfQ0KIyA1LiBWaXN1YWxpemUgdGhlIGRhdGENCg0KIyBhLiBiYXJwbG90IHNob3dpbmcgdG90YWwgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdA0KdG90YWxfcXR5ID0gdGFwcGx5KHRyYW5zYWN0aW9ucyRRdHksIHRyYW5zYWN0aW9ucyRQcm9kdWN0LCBzdW0pDQpiYXJwbG90KHRvdGFsX3F0eSwNCiAgICAgICAgbWFpbiA9ICJUb3RhbCBRdWFudGl0eSBTb2xkIHBlciBQcm9kdWN0IiwNCiAgICAgICAgeGxhYiA9ICJQcm9kdWN0IiwNCiAgICAgICAgeWxhYiA9ICJUb3RhbCBRdWFudGl0eSIsDQogICAgICAgIGNvbCA9ICJsaWdodGJsdWUiKQ0KDQojIGIuIHBpZSBjaGFydCBzaG93aW5nIHRoZSBwcm9wb3J0aW9uIG9mIHRvdGFsIHJldmVudWUNCnRvdGFsX3JldmVudWVfdGllciA9IHRhcHBseSh0cmFuc2FjdGlvbnMkdG90YWwsIHRyYW5zYWN0aW9ucyRDdXN0b21lclRpZXIsIHN1bSkNCnBpZSh0b3RhbF9yZXZlbnVlX3RpZXIsDQogICAgbWFpbiA9ICJQcm9wb3J0aW9uIG9mIFRvdGFsIFJldmVudWUgcGVyIEN1c3RvbWVyIFRpZXIiLA0KICAgIGNvbCA9IHJhaW5ib3cobGVuZ3RoKHRvdGFsX3JldmVudWVfdGllcikpKQ0KDQpgYGANCg0KYGBge3J9DQojIDYuIE9wdGlvbmFsIGNoYWxsZW5nZQ0KDQojIGEuIEZpbmQgd2hpY2ggZGF0ZSBoYWQgdGhlIGhpZ2hlc3QgdG90YWwgcmV2ZW51ZQ0KdG90YWxfcmV2ZW51ZV9kYXRlIDwtIGFnZ3JlZ2F0ZSh0b3RhbCB+IERhdGUsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkNCnRvdGFsX3JldmVudWVfZGF0ZVt3aGljaC5tYXgodG90YWxfcmV2ZW51ZV9kYXRlJHRvdGFsKSwgXQ0KDQoNCiMgYi4gc3RhY2tlZCBiYXIgY2hhcnQgc2hvd2luZyBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0IGJ5IGN1c3RvbWVyIHRpZXINCnF0eV90YWJsZSA9IHh0YWJzKFF0eSB+IFByb2R1Y3QgKyBDdXN0b21lclRpZXIsIGRhdGEgPSB0cmFuc2FjdGlvbnMpDQpiYXJwbG90KHF0eV90YWJsZSwNCiAgICAgICAgbWFpbiA9ICJRdWFudGl0eSBTb2xkIHBlciBQcm9kdWN0IGJ5IEN1c3RvbWVyIFRpZXIiLA0KICAgICAgICB4bGFiID0gIlByb2R1Y3QiLA0KICAgICAgICB5bGFiID0gIlF1YW50aXR5IiwNCiAgICAgICAgY29sID0gYygibGlnaHRibHVlIiwgImxpZ2h0Z3JlZW4iLCAicGluayIpKQ0KICAgICAgDQpgYGANCg0KIyMgRXhlcmNpc2UgNQ0KDQoqKkNyZWF0ZSBZb3VyIE93biBEYXRhIEZyYW1lOioqDQoNCioqT2JqZWN0aXZlOioqIENyZWF0ZSBhIGRhdGEgZnJhbWUgaW4gUiB3aXRoICoqMzAgcm93cyoqIGNvbnRhaW5pbmcgYSBtaXggb2YgZGF0YSB0eXBlczogY29udGludW91cywgZGlzY3JldGUsIG5vbWluYWwsIGFuZCBvcmRpbmFsLiAgDQoNCiMjIyBJbnN0cnVjdGlvbnMNCg0KMS4gKipPcGVuIFJTdHVkaW8qKiBvciB0aGUgUiBjb25zb2xlLiAgDQoNCjIuICoqQ3JlYXRlIGEgdmVjdG9yIGZvciBlYWNoIGNvbHVtbioqIGluIHlvdXIgZGF0YSBmcmFtZTogIA0KDQogICAtICoqRGF0ZSoqOiAzMCBkYXRlcyAoY2FuIGJlIHNlcXVlbnRpYWwgb3IgcmFuZG9tIHdpdGhpbiBhIG1vbnRoL3llYXIpICANCiAgIC0gKipDb250aW51b3VzKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIHRha2UgZGVjaW1hbCB2YWx1ZXMgKGUuZy4sIGhlaWdodCwgd2VpZ2h0LCB0ZW1wZXJhdHVyZSkgIA0KICAgLSAqKkRpc2NyZXRlKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIG9ubHkgdGFrZSB3aG9sZSBudW1iZXJzIChlLmcuLCBudW1iZXIgb2YgaXRlbXMsIG51bWJlciBvZiB2ZWhpY2xlcykgIA0KICAgLSAqKk5vbWluYWwqKjogY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggKipubyBvcmRlcioqIChlLmcuLCBjb2xvciwgZ2VuZGVyLCBjaXR5KSAgDQogICAtICoqT3JkaW5hbCoqOiBjYXRlZ29yaWNhbCB2YWx1ZXMgd2l0aCBhICoqZGVmaW5lZCBvcmRlcioqIChlLmcuLCBMb3csIE1lZGl1bSwgSGlnaDsgQmVnaW5uZXIsIEludGVybWVkaWF0ZSwgRXhwZXJ0KSAgDQoNCjMuICoqQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZSoqIGNhbGxlZCBgbXlfZGF0YWAuICANCg0KNC4gKipDaGVjayB5b3VyIGRhdGEgZnJhbWUqKiB1c2luZyBgaGVhZCgpYCBvciBgVmlldygpYCB0byBlbnN1cmUgaXQgaGFzICoqMzAgcm93cyoqIGFuZCB0aGUgY29sdW1ucyBhcmUgY29ycmVjdC4gIA0KDQo1LiAqKk9wdGlvbmFsIHRhc2tzKio6ICANCiAgIC0gU3VtbWFyaXplIGVhY2ggY29sdW1uIHVzaW5nIGBzdW1tYXJ5KClgICANCiAgIC0gQ291bnQgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIGNhdGVnb3J5IGZvciAqKk5vbWluYWwqKiBhbmQgKipPcmRpbmFsKiogY29sdW1ucyB1c2luZyBgdGFibGUoKWAgIA0KDQojIyMgSGludHMNCg0KLSBVc2UgYHNlcS5EYXRlKClgIG9yIGBhcy5EYXRlKClgIHRvIGdlbmVyYXRlIHRoZSBEYXRlIGNvbHVtbi4gIA0KLSBVc2UgYHJ1bmlmKClgIG9yIGBybm9ybSgpYCBmb3IgY29udGludW91cyBudW1lcmljIGRhdGEuICANCi0gVXNlIGBzYW1wbGUoKWAgZm9yIGRpc2NyZXRlLCBub21pbmFsLCBhbmQgb3JkaW5hbCBkYXRhLiAgDQotIEVuc3VyZSB0aGUgKipvcmRpbmFsIHZlY3RvcioqIGlzIGNyZWF0ZWQgd2l0aCBgZmFjdG9yKC4uLiwgbGV2ZWxzID0gYygiTG93IiwiTWVkaXVtIiwiSGlnaCIpLCBvcmRlcmVkID0gVFJVRSlgIChvciBzaW1pbGFyKS4gDQoNCg0KYGBge3J9DQojIDEuIENvZmZlZSBTaG9wIERhdGENCmxpYnJhcnkoa25pdHIpDQpEYXRlID0gc2VxKGFzLkRhdGUoIjIwMjUtMDktMDEiKSwgYXMuRGF0ZSgiMjAyNS0wOS0zMCIpLCBieSA9ICJkYXkiKSAgICAjIERhdGUNCkNvZmZlZV9tbCA9IHJ1bmlmKDMwLCBtaW4gPSAxNTAwLCBtYXggPSA0MDAwKSAgICAgICAgICAgICAjIENvbnRpbnVvdXMgLyBWb2x1bWUgS29waQ0KQ3Vwc19Tb2xkID0gc2FtcGxlKDIwOjEwMCwgMzAsIHJlcGxhY2UgPSBUUlVFKSAgICAgICAgICAgICMgRGlzY3JldGUgLyBKdW1sYWggS29waQ0KRHJpbmtfVHlwZSA9IHNhbXBsZShjKA0KICAiQW1lcmljYW5vIiwNCiAgIkNhcHB1Y2Npbm8iLA0KICAiTGF0dGUiLA0KICAiRXNwcmVzc28iLA0KICAiTW9jaGEiKSwgMzAsIHJlcGxhY2UgPSBUUlVFKSAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTm9taW5hbCAvIEplbmlzIEtvcGkNCkN1c3RvbWVyX1NhdGlzZmFjdGlvbiA9IGZhY3RvcigNCiAgc2FtcGxlKGMoDQogICAgIlBvb3IiLA0KICAgICJGYWlyIiwNCiAgICAiR29vZCIsDQogICAgIlZlcnkgR29vZCIsDQogICAgIkV4Y2VsbGVudCIpLCAzMCwgcmVwbGFjZSA9IFRSVUUpLA0KICBsZXZlbHMgPSBjKCJQb29yIiwgIkZhaXIiLCAiR29vZCIsICJWZXJ5IEdvb2QiLCAiRXhjZWxsZW50IiksDQogIG9yZGVyZWQgPSBUUlVFKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBPcmRpbmFsIC8gU2F0aXNmYWN0aW9uDQoNCiMgQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZQ0KbXlfZGF0YSA9IGRhdGEuZnJhbWUoRGF0ZSwgQ29mZmVlX21sLCBDdXBzX1NvbGQsIERyaW5rX1R5cGUsIEN1c3RvbWVyX1NhdGlzZmFjdGlvbikNCmthYmxlKG15X2RhdGEpDQoNCiMgMi4gU3VtbWFyeSBkYXRhIChvcHNpb25hbCkNCnN1bW1hcnlfZGF0YSA9IHN1bW1hcnkobXlfZGF0YSkNCmthYmxlKHN1bW1hcnlfZGF0YSkNCg0KIyAzLiBGcmVrdWVuc2kgS2F0ZWdvcmkgKG5vbWluYWwsIG9yZGluYWwpDQpkcmlua19mcmVxID0gdGFibGUobXlfZGF0YSREcmlua19UeXBlKQ0Kc2F0aXNmYWN0aW9uX2ZyZXEgPSB0YWJsZShteV9kYXRhJEN1c3RvbWVyX1NhdGlzZmFjdGlvbikNCg0Ka2FibGUoZHJpbmtfZnJlcSwgY2FwdGlvbiA9ICJGcmVrdWVuc2kgSmVuaXMgTWludW1hbiAoTm9taW5hbCkiKQ0Ka2FibGUoc2F0aXNmYWN0aW9uX2ZyZXEsIGNhcHRpb24gPSAiRnJla3VlbnNpIEtlcHVhc2FuIFBlbGFuZ2dhbiAoT3JkaW5hbCkiKQ0KDQpgYGANCg0K