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(
    "numerik",
    "numerik",
    "kategorikal",
    "kategorikal",
    "kategorikal"
  ),
  Subtype = c(
    "diskrit",
    "kontinu",
    "nomilal",
    "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 numerik diskrit
2 Student height in cm numerik kontinu
3 Employee gender (Male / Female) kategorikal nomilal
4 Customer satisfaction level: Low, Medium, High kategorikal ordinal
5 Respondent’s favorite color: Red, Blue, Green kategorikal 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(
    "terstruktur",
    "terstuktur",
    "tidak terstuktur",
    "terstruktur"
  ),
  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
# Install knitr package if not already installed
# install.packages("knitr")
library(knitr)

# Create a data frame for Transactions
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"
  )              # Numeric / Discrete
Qty = c (2, 5, 1, 3, 4, 2, 6, 1, 3, 5)   # Numeric / Discrete
Price = c (1000, 20, 1000, 30, 50, 1000, 25, 1000, 40, 10)   # Numeric / Discrete

# Nominal
Product = c (
  "Laptop",
  "Mouse",
  "Laptop",
  "Keyboard",
  "Mouse",
  "Laptop",
  "Keyboard",
  "Laptop",
  "Mouse",
  "Keyboard"
  )           # Categorical / Nominal

# Ordinal
CustomerTier = factor(c(
  "High",
  "Medium",
  "Low",
  "Medium",
  "Medium",
  "High",
  "Low",
  "High",
  "Low",
  "Medium"
  ),
levels = c("Low","Medium","High"),
ordered = TRUE) 

# 2. Combine all vectors into a data frame
transactions =  data.frame (Date, Qty, Price, Product, CustomerTier, stringsAsFactors = FALSE)

# 3. Display the data frame
library(knitr)
kable(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"))

  1. 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.
  2. 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.

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

# Date (30 hari di bulan September)
Date = seq(as.Date("2025-09-01"), as.Date("2025-09-30"), by = "day")

# Continuous: jumlah ml kopi terjual per hari (acak dari 1500–4000 ml)
Coffee_ml = runif(30, min = 1500, max = 4000)

# Discrete: jumlah cangkir kopi terjual per hari (acak 20–100)
Cups_Sold = sample(20:100, 30, replace = TRUE)

# Nominal: jenis minuman kopi
Drink_Type = sample(c("Americano", "Cappuccino", "Latte", "Espresso", "Mocha"), 30, replace = TRUE)

# Ordinal: tingkat kepuasan pelanggan
Customer_Satisfaction = factor(
  sample(c("Poor", "Fair", "Good", "Very Good", "Excellent"), 30, replace = TRUE),
  levels = c("Poor", "Fair", "Good", "Very Good", "Excellent"),
  ordered = TRUE)

# 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 3064.949 26 Espresso Excellent
2025-09-02 1610.821 70 Mocha Fair
2025-09-03 1770.798 99 Cappuccino Very Good
2025-09-04 3094.826 92 Espresso Very Good
2025-09-05 1866.469 40 Mocha Excellent
2025-09-06 2054.750 64 Latte Fair
2025-09-07 2436.079 92 Latte Excellent
2025-09-08 2429.349 22 Americano Good
2025-09-09 3086.462 49 Americano Excellent
2025-09-10 2523.109 91 Cappuccino Excellent
2025-09-11 1800.869 63 Espresso Very Good
2025-09-12 1506.859 99 Cappuccino Poor
2025-09-13 2754.235 40 Mocha Very Good
2025-09-14 1774.955 50 Americano Very Good
2025-09-15 2336.350 34 Cappuccino Good
2025-09-16 3263.853 57 Mocha Good
2025-09-17 2013.145 72 Americano Very Good
2025-09-18 3642.700 31 Cappuccino Very Good
2025-09-19 2488.838 26 Latte Fair
2025-09-20 3859.804 78 Espresso Good
2025-09-21 3300.900 82 Mocha Good
2025-09-22 3284.224 22 Cappuccino Fair
2025-09-23 3597.779 91 Latte Fair
2025-09-24 2131.266 29 Latte Good
2025-09-25 2531.294 32 Latte Good
2025-09-26 1587.727 43 Mocha Excellent
2025-09-27 3192.204 88 Latte Fair
2025-09-28 2169.073 83 Latte Poor
2025-09-29 3391.213 44 Americano Excellent
2025-09-30 1531.602 59 Latte Poor
# 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. :1507 Min. :22.00 Length:30 Poor :3
1st Qu.:2025-09-08 1st Qu.:1903 1st Qu.:35.50 Class :character Fair :6
Median :2025-09-15 Median :2462 Median :58.00 Mode :character Good :7
Mean :2025-09-15 Mean :2537 Mean :58.93 NA Very Good:7
3rd Qu.:2025-09-22 3rd Qu.:3168 3rd Qu.:82.75 NA Excellent:7
Max. :2025-09-30 Max. :3860 Max. :99.00 NA NA
# Frekuensi Kategori (nominal, ordinal)
library(knitr)
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 5
Cappuccino 6
Espresso 4
Latte 9
Mocha 6
kable(satisfaction_freq, caption = "Frekuensi Kepuasan Pelanggan (Ordinal)")
Frekuensi Kepuasan Pelanggan (Ordinal)
Var1 Freq
Poor 3
Fair 6
Good 7
Very Good 7
Excellent 7
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAzIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6IA0KLSAiTmFrZWlzaGEgQXVsaWEgWmFocmEiIA0KLSAiQW5nZWxpcXVlIEtpeW9zaGkgTGFrZWlzaGEgQlUiIA0KLSAiS2hhZml6YXR1biBOaXNhIiANCi0gIk5heWNoaWxsYSBBZGVsaWEgWmFocmFoIiANCi0gIlZlcm9uaWNhIE1hcmlhIExGIFhhdmllciIgIyBSZXBsYWNlIHdpdGggeW91ciBmdWxsIG5hbWUNCg0KZGF0ZTogICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCIgIyBBdXRvIGRpc3BsYXlzIHRoZSBjdXJyZW50IGRhdGUNCm91dHB1dDogICAgICAgICAgICAgICAgICAgICAgICAgIyBPdXRwdXQgc2VjdGlvbiBkZWZpbmVzIHRoZSBmb3JtYXQgYW5kIGxheW91dCANCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246ICAgICAgIyBodHRwczovL2dpdGh1Yi5jb20vanViYS9ybWRmb3JtYXRzDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUgICAgICAgICMgRW1iZWRzIGFsbCByZXNvdXJjZXMgKENTUywgSlMsIGltYWdlcykgDQogICAgdGh1bWJuYWlsczogdHJ1ZSAgICAgICAgICAgICMgRGlzcGxheXMgaW1hZ2UgdGh1bWJuYWlscyBpbiB0aGUgZG9jDQogICAgbGlnaHRib3g6IHRydWUgICAgICAgICAgICAgICMgRW5hYmxlcyBjbGljayB0byBlbmxhcmdlIGltYWdlcw0KICAgIGdhbGxlcnk6IHRydWUgICAgICAgICAgICAgICAjIEdyb3VwcyBpbWFnZXMgaW50byBhbiBpbnRlcmFjdGl2ZSBnYWxsZXJ5DQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlICAgICAgICMgQXV0b21hdGljYWxseSBudW1iZXJzIGFsbCBzZWN0aW9ucw0KICAgIGxpYl9kaXI6IGxpYnMgICAgICAgICAgICAgICAjIERpcmVjdG9yeSB3aGVyZSBKYXZhU2NyaXB0L0NTUyBsaWJyYXJpZXMNCiAgICBkZl9wcmludDogInBhZ2VkIiAgICAgICAgICAgIyBEaXNwbGF5cyBkYXRhIGZyYW1lcyBhcyBpbnRlcmFjdGl2ZSBwYWdlZCANCiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93IiAgICAgICAgIyBBbGxvd3MgZm9sZGluZy91bmZvbGRpbmcgUiBjb2RlIGJsb2NrcyANCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMgICAgICAgICAgIyBBZGRzIGEgYnV0dG9uIHRvIGRvd25sb2FkIGFsbCBSIGNvZGUNCi0tLQ0KDQo8aW1nIGlkPSJGb3RvIiBzcmM9IkM6L1VzZXJzL1VTRVIvT25lRHJpdmUvRGVza3RvcC9UdWdhcyBTdGF0aXN0aWthIFIvUmVkIEJsdWUgTW9kZXJuIEFic3RyYWN0IFNjcmFwYm9vayBUZWFtd29yayBNb21lbnQgUGhvdG8gQ29sbGFnZS5wbmc/cmF3PXRydWUiIGFsdD0iTG9nbyIgc3R5bGU9IndpZHRoOjIwMHB4OyBkaXNwbGF5OiBibG9jazsgbWFyZ2luOiBhdXRvOyI+DQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyBFeGVyY2lzZSAxDQoNClRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3Mgc2FtcGxlIGluZm9ybWF0aW9uIGZvciB0aHJlZSBzdHVkZW50cy4gRWFjaCBvYnNlcnZhdGlvbiByZXByZXNlbnRzIGEgc2luZ2xlIHN0dWRlbnQgYW5kIGluY2x1ZGVzIGRldGFpbHMgc3VjaCBhcyB0aGVpciB1bmlxdWUgc3R1ZGVudCBJRCwgbmFtZSwgYWdlLCB0b3RhbCBjcmVkaXRzIGNvbXBsZXRlZCwgbWFqb3IgZmllbGQgb2Ygc3R1ZHksIGFuZCB5ZWFyIGxldmVsLg0KDQpUaGlzIGRhdGFzZXQgZGVtb25zdHJhdGVzIGEgbWl4dHVyZSBvZiB2YXJpYWJsZSB0eXBlczoNCg0KLSAgICoqTm9taW5hbDoqKiBTdHVkZW50SUQsIE5hbWUsIE1ham9yXA0KLSAgICoqTnVtZXJpYzoqKiBBZ2UgKGNvbnRpbnVvdXMpLCBDcmVkaXRzQ29tcGxldGVkIChkaXNjcmV0ZSlcDQotICAgKipPcmRpbmFsOioqIFllYXJMZXZlbCAoRnJlc2htYW4g4oaSIFNlbmlvcikNCg0KfCBTdHVkZW50SUQgfCBOYW1lICB8IEFnZSB8IENyZWRpdHNDb21wbGV0ZWQgfCBNYWpvciAgICAgICB8IFllYXJMZXZlbCB8DQp8LS0tLS0tLS0tLS18LS0tLS0tLXwtLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLXwNCnwgUzAwMSAgICAgIHwgQWxpY2UgfCAyMCAgfCA0NSAgICAgICAgICAgICAgIHwgRGF0YSBTYWlucyAgfCBTb3Bob21vcmUgfA0KfCBTMDAyICAgICAgfCBCdWRpICB8IDIxICB8IDYwICAgICAgICAgICAgICAgfCBNYXRoZW1hdGljcyB8IEp1bmlvciAgICB8DQp8IFMwMDMgICAgICB8IENpdHJhIHwgMTkgIHwgMzAgICAgICAgICAgICAgICB8IFN0YXRpc3RpY3MgIHwgRnJlc2htYW4gIHwNCg0KYGBge3J9DQojIDEuIENyZWF0ZSB2ZWN0b3JzIGZvciBlYWNoIHZhcmlhYmxlDQpTdHVkZW50SUQgPC0gYygiUzAwMSIsICJTMDAyIiwgIlMwMDMiKSAgICAgICAjIE5vbWluYWwgLyBJRA0KTmFtZSA8LSBjKCJBbGljZSIsICJCdWRpIiwgIkNpdHJhIikgICAgICAgICAgIyBOb21pbmFsIC8gTmFtZQ0KQWdlIDwtIGMoMjAsIDIxLCAxOSkgICAgICAgICAgICAgICAgICAgICAgICAgIyBOdW1lcmljIC8gQ29udGludW91cw0KQ3JlZGl0c0NvbXBsZXRlZCA8LSBjKDQ1LCA2MCwgMzApICAgICAgICAgICAgIyBOdW1lcmljIC8gRGlzY3JldGUNCg0KIyBOb21pbmFsDQpNYWpvciA8LSBjKCJEYXRhIFNhaW5zIiwgIk1hdGhlbWF0aWNzIiwgIlN0YXRpc3RpY3MiKSAgDQoNCiMgT3JkaW5hbA0KWWVhckxldmVsIDwtIGZhY3RvcihjKCJTb3Bob21vcmUiLCAiSnVuaW9yIiwgIkZyZXNobWFuIiksDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkZyZXNobWFuIiwiU29waG9tb3JlIiwiSnVuaW9yIiwiU2VuaW9yIiksDQogICAgICAgICAgICAgICAgICAgIG9yZGVyZWQgPSBUUlVFKSAgICAgICAgICANCg0KIyAyLiBDb21iaW5lIGFsbCB2ZWN0b3JzIGludG8gYSBkYXRhIGZyYW1lDQpzdHVkZW50cyA8LSBkYXRhLmZyYW1lKA0KICBTdHVkZW50SUQsIE5hbWUsIEFnZSwgQ3JlZGl0c0NvbXBsZXRlZCwgTWFqb3IsIFllYXJMZXZlbCwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgMy4gRGlzcGxheSB0aGUgZGF0YSBmcmFtZQ0KcHJpbnQoc3R1ZGVudHMpDQpgYGANCg0KIyMgRXhlcmNpc2UgMg0KDQoqKklkZW50aWZ5IERhdGEgVHlwZXM6KiogRGV0ZXJtaW5lIHRoZSB0eXBlIG9mIGRhdGEgZm9yIGVhY2ggb2YgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6DQoNCmBgYHtyfQ0KIyBJbnN0YWxsIGtuaXRyIHBhY2thZ2UgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkDQojIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCmxpYnJhcnkoa25pdHIpDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgRGF0YSBUeXBlcw0KdmFyaWFibGVzX2luZm8gPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjUsDQogIFZhcmlhYmxlID0gYygNCiAgICAiTnVtYmVyIG9mIHZlaGljbGVzIHBhc3NpbmcgdGhyb3VnaCB0aGUgdG9sbCByb2FkIGVhY2ggZGF5IiwNCiAgICAiU3R1ZGVudCBoZWlnaHQgaW4gY20iLA0KICAgICJFbXBsb3llZSBnZW5kZXIgKE1hbGUgLyBGZW1hbGUpIiwNCiAgICAiQ3VzdG9tZXIgc2F0aXNmYWN0aW9uIGxldmVsOiBMb3csIE1lZGl1bSwgSGlnaCIsDQogICAgIlJlc3BvbmRlbnQncyBmYXZvcml0ZSBjb2xvcjogUmVkLCBCbHVlLCBHcmVlbiINCiAgKSwNCiAgRGF0YVR5cGUgPSBjKA0KICAgICJudW1lcmlrIiwNCiAgICAibnVtZXJpayIsDQogICAgImthdGVnb3Jpa2FsIiwNCiAgICAia2F0ZWdvcmlrYWwiLA0KICAgICJrYXRlZ29yaWthbCINCiAgKSwNCiAgU3VidHlwZSA9IGMoDQogICAgImRpc2tyaXQiLA0KICAgICJrb250aW51IiwNCiAgICAibm9taWxhbCIsDQogICAgIm9yZGluYWwiLA0KICAgICJub21pbmFsIg0KICApLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lIGFzIGEgbmVhdCB0YWJsZQ0Ka2FibGUodmFyaWFibGVzX2luZm8sIA0KICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBWYXJpYWJsZXMgYW5kIERhdGEgVHlwZXMiKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyBFeGVyY2lzZSAzDQoNCioqQ2xhc3NpZnkgRGF0YSBTb3VyY2VzOioqIERldGVybWluZSB3aGV0aGVyIHRoZSBmb2xsb3dpbmcgZGF0YSBjb21lcyBmcm9tICoqaW50ZXJuYWwqKiBvciAqKmV4dGVybmFsIHNvdXJjZXMqKiwgYW5kIHdoZXRoZXIgaXQgaXMgKipzdHJ1Y3R1cmVkKiogb3IgKip1bnN0cnVjdHVyZWQqKjoNCg0KYGBge3J9DQojIEluc3RhbGwgRFQgcGFja2FnZSBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCiMgaW5zdGFsbC5wYWNrYWdlcygiRFQiKQ0KbGlicmFyeShEVCkNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBkYXRhIHNvdXJjZXMgDQpkYXRhX3NvdXJjZXMgPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjQsDQogIERhdGFTb3VyY2UgPSBjKA0KICAgICJEYWlseSBzYWxlcyB0cmFuc2FjdGlvbiBkYXRhIG9mIHRoZSBjb21wYW55IiwNCiAgICAiV2VhdGhlciByZXBvcnRzIGZyb20gQk1LRyIsDQogICAgIlByb2R1Y3QgcmV2aWV3cyBvbiBzb2NpYWwgbWVkaWEiLA0KICAgICJXYXJlaG91c2UgaW52ZW50b3J5IHJlcG9ydHMiDQogICksDQogIEludGVybmFsX0V4dGVybmFsID0gYygNCiAgICAiaW50ZXJuYWwiLA0KICAgICJleHRlcm5hbCIsDQogICAgImV4dGVybmFsIiwNCiAgICAiaW50ZXJuYWwiDQogICksDQogIFN0cnVjdHVyZWRfVW5zdHJ1Y3R1cmVkID0gYygNCiAgICAidGVyc3RydWt0dXIiLA0KICAgICJ0ZXJzdHVrdHVyIiwNCiAgICAidGlkYWsgdGVyc3R1a3R1ciIsDQogICAgInRlcnN0cnVrdHVyIg0KICApLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lIGFzIGEgbmVhdCB0YWJsZQ0KZGF0YXRhYmxlKGRhdGFfc291cmNlcywgDQogICAgICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBEYXRhIFNvdXJjZXMiLA0KICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UpICMgaGlkZXMgdGhlIGluZGV4IGNvbHVtbg0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyBFeGVyY2lzZSA0DQoNCioqRGF0YXNldCBTdHJ1Y3R1cmU6KiogQ29uc2lkZXIgdGhlIGZvbGxvd2luZyB0cmFuc2FjdGlvbiB0YWJsZToNCg0KfCBEYXRlICAgICAgIHwgUXR5IHwgUHJpY2UgfCBQcm9kdWN0ICB8IEN1c3RvbWVyVGllciB8DQp8LS0tLS0tLS0tLS0tfC0tLS0tfC0tLS0tLS18LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLXwNCnwgMjAyNS0xMC0wMSB8IDIgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTAxIHwgNSAgIHwgMjAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDIgfCAxICAgfCAxMDAwICB8IExhcHRvcCAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wMiB8IDMgICB8IDMwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAzIHwgNCAgIHwgNTAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDMgfCAyICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wNCB8IDYgICB8IDI1ICAgIHwgS2V5Ym9hcmQgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTA0IHwgMSAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDUgfCAzICAgfCA0MCAgICB8IE1vdXNlICAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wNSB8IDUgICB8IDEwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KDQoqKllvdXIgQXNzaWdubWVudCBJbnN0cnVjdGlvbnM6KiogQ3JlYXRpbmcgYSBUcmFuc2FjdGlvbnMgVGFibGUgYWJvdmUgaW4gUg0KDQoxLiAgKipDcmVhdGUgYSBkYXRhIGZyYW1lKiogaW4gUiBjYWxsZWQgYHRyYW5zYWN0aW9uc2AgY29udGFpbmluZyB0aGUgZGF0YSBhYm92ZS4NCg0KMi4gIElkZW50aWZ5IHdoaWNoIHZhcmlhYmxlcyBhcmUgbnVtZXJpYyBhbmQgd2hpY2ggYXJlIGNhdGVnb3JpY2FsDQoNCjMuICAqKkNhbGN1bGF0ZSB0b3RhbCByZXZlbnVlKiogZm9yIGVhY2ggdHJhbnNhY3Rpb24gYnkgbXVsdGlwbHlpbmcgYFF0eSDDlyBQcmljZWAgYW5kIGFkZCBpdCBhcyBhIG5ldyBjb2x1bW4gYFRvdGFsYC4NCg0KNC4gICoqQ29tcHV0ZSBzdW1tYXJ5IHN0YXRpc3RpY3MqKjoNCg0KICAgIC0gICBUb3RhbCBxdWFudGl0eSBzb2xkIGZvciBlYWNoIHByb2R1Y3QNCiAgICAtICAgVG90YWwgcmV2ZW51ZSBwZXIgcHJvZHVjdA0KICAgIC0gICBBdmVyYWdlIHByaWNlIHBlciBwcm9kdWN0DQpgYGB7cn0NCiMgSW5zdGFsbCBrbml0ciBwYWNrYWdlIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZA0KIyBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQpsaWJyYXJ5KGtuaXRyKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIFRyYW5zYWN0aW9ucw0KRGF0ZSA9IGMgKA0KICAiMjAyNS0xMC0wMSIsICANCiAgIjIwMjUtMTAtMDEiLCANCiAgIjIwMjUtMTAtMDIiLCANCiAgIjIwMjUtMTAtMDIiLCANCiAgIjIwMjUtMTAtMDMiLCANCiAgIjIwMjUtMTAtMDMiLCANCiAgIjIwMjUtMTAtMDQiLCANCiAgIjIwMjUtMTAtMDQiLCANCiAgIjIwMjUtMTAtMDUiLCANCiAgIjIwMjUtMTAtMDUiDQogICkgICAgICAgICAgICAgICMgTnVtZXJpYyAvIERpc2NyZXRlDQpRdHkgPSBjICgyLCA1LCAxLCAzLCA0LCAyLCA2LCAxLCAzLCA1KSAgICMgTnVtZXJpYyAvIERpc2NyZXRlDQpQcmljZSA9IGMgKDEwMDAsIDIwLCAxMDAwLCAzMCwgNTAsIDEwMDAsIDI1LCAxMDAwLCA0MCwgMTApICAgIyBOdW1lcmljIC8gRGlzY3JldGUNCg0KIyBOb21pbmFsDQpQcm9kdWN0ID0gYyAoDQogICJMYXB0b3AiLA0KICAiTW91c2UiLA0KICAiTGFwdG9wIiwNCiAgIktleWJvYXJkIiwNCiAgIk1vdXNlIiwNCiAgIkxhcHRvcCIsDQogICJLZXlib2FyZCIsDQogICJMYXB0b3AiLA0KICAiTW91c2UiLA0KICAiS2V5Ym9hcmQiDQogICkgICAgICAgICAgICMgQ2F0ZWdvcmljYWwgLyBOb21pbmFsDQoNCiMgT3JkaW5hbA0KQ3VzdG9tZXJUaWVyID0gZmFjdG9yKGMoDQogICJIaWdoIiwNCiAgIk1lZGl1bSIsDQogICJMb3ciLA0KICAiTWVkaXVtIiwNCiAgIk1lZGl1bSIsDQogICJIaWdoIiwNCiAgIkxvdyIsDQogICJIaWdoIiwNCiAgIkxvdyIsDQogICJNZWRpdW0iDQogICksDQpsZXZlbHMgPSBjKCJMb3ciLCJNZWRpdW0iLCJIaWdoIiksDQpvcmRlcmVkID0gVFJVRSkgDQoNCiMgMi4gQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZQ0KdHJhbnNhY3Rpb25zID0gIGRhdGEuZnJhbWUgKERhdGUsIFF0eSwgUHJpY2UsIFByb2R1Y3QsIEN1c3RvbWVyVGllciwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIDMuIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCmxpYnJhcnkoa25pdHIpDQprYWJsZSh0cmFuc2FjdGlvbnMpDQpgYGANCg0KYGBge3J9DQojIDIuIElkZW50aWZ5IHZhcmlhYmxlIHR5cGVzDQpsaWJyYXJ5KGtuaXRyKQ0KdmFyaWFibGVfdHlwZXMgPC0gZGF0YS5mcmFtZSgNCiAgVmFyaWFibGUgPSBjKA0KICAgICJEYXRlIiwNCiAgICAiUXR5IiwNCiAgICAiUHJpY2UiLA0KICAgICJQcm9kdWN0IiwNCiAgICAiQ3VzdG9tZXJUaWVyIg0KICAgICksDQogIFR5cGUgPSBjKA0KICAgICJOdW1lcmljIChEaXNjcmV0ZSkiLA0KICAgICJOdW1lcmljIChEaXNjcmV0ZSkiLA0KICAgICJOdW1lcmljIChEaXNjcmV0ZSkiLA0KICAgICJDYXRlZ29yaWNhbCAoTm9taW5hbCkiLA0KICAgICJDYXRlZ29yaWNhbCAoT3JkaW5hbCkiDQogICAgKQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCmthYmxlKHZhcmlhYmxlX3R5cGVzLCBjYXB0aW9uID0gIlZhcmlhYmxlIFR5cGVzIGluIFRyYW5zYWN0aW9ucyBEYXRhIikNCg0KYGBgDQoNCmBgYHtyfQ0KIyAzLiBDYWxjdWxhdGUgdG90YWwgcmV2ZW51ZQ0KdHJhbnNhY3Rpb25zJHRvdGFsID0gdHJhbnNhY3Rpb25zJFF0eSAqIHRyYW5zYWN0aW9ucyRQcmljZQ0Ka2FibGUodHJhbnNhY3Rpb25zKQ0KYGBgDQoNCg0KYGBge3J9DQojIDQuIENvbXB1dGUgc3VtbWFyeSBzdGF0aXN0aWMNCg0KIyBhLiBUb3RhbCBxdWFudGl0eSBzb2xkIGZvciBlYWNoIHByb2R1Y3QNCnRvdGFsX1F0eSA9IGFnZ3JlZ2F0ZShRdHkgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQprYWJsZSh0b3RhbF9RdHksIGNhcHRpb24gPSAiVG90YWwgUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCIpDQoNCiMgYi4gdG90YWwgcmV2ZW51ZSBwZXIgcHJvZHVjdA0KdG90YWxfcmV2ZW51ZSA9IGFnZ3JlZ2F0ZSh0b3RhbCB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkNCmthYmxlKHRvdGFsX3JldmVudWUsIGNhcHRpb24gPSAiVG90YWwgUmV2ZW51ZSBwZXIgUHJvZHVjdCIpDQoNCiMgYy4gQXZlcmFnZSBwcmljZSBwZXIgcHJvZHVjdA0KYXZnX3ByaWNlID0gYWdncmVnYXRlKFByaWNlIH4gUHJvZHVjdCwgZGF0YSA9IHRyYW5zYWN0aW9ucywgbWVhbikNCmthYmxlKGF2Z19wcmljZSwgY2FwdGlvbiA9ICJBdmVyYWdlIFByaWNlIHBlciBQcm9kdWN0IikNCmBgYA0KDQoNCmBgYHtyfQ0KIyA1LiBWaXN1YWxpemUgdGhlIGRhdGENCg0KIyBhLiBiYXJwbG90IHNob3dpbmcgdG90YWwgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdA0KdG90YWxfcXR5ID0gdGFwcGx5KHRyYW5zYWN0aW9ucyRRdHksIHRyYW5zYWN0aW9ucyRQcm9kdWN0LCBzdW0pDQpiYXJwbG90KHRvdGFsX3F0eSwNCiAgICAgICAgbWFpbiA9ICJUb3RhbCBRdWFudGl0eSBTb2xkIHBlciBQcm9kdWN0IiwNCiAgICAgICAgeGxhYiA9ICJQcm9kdWN0IiwNCiAgICAgICAgeWxhYiA9ICJUb3RhbCBRdWFudGl0eSIsDQogICAgICAgIGNvbCA9ICJsaWdodGJsdWUiKQ0KDQojIGIuIHBpZSBjaGFydCBzaG93aW5nIHRoZSBwcm9wb3J0aW9uIG9mIHRvdGFsIHJldmVudWUNCnRvdGFsX3JldmVudWVfdGllciA9IHRhcHBseSh0cmFuc2FjdGlvbnMkdG90YWwsIHRyYW5zYWN0aW9ucyRDdXN0b21lclRpZXIsIHN1bSkNCnBpZSh0b3RhbF9yZXZlbnVlX3RpZXIsDQogICAgbWFpbiA9ICJQcm9wb3J0aW9uIG9mIFRvdGFsIFJldmVudWUgcGVyIEN1c3RvbWVyIFRpZXIiLA0KICAgIGNvbCA9IHJhaW5ib3cobGVuZ3RoKHRvdGFsX3JldmVudWVfdGllcikpKQ0KYGBgDQoNCg0KYGBge3J9DQojIDYuIE9wdGlvbmFsIGNoYWxsZW5nZQ0KDQojIGEuIEZpbmQgd2hpY2ggZGF0ZSBoYWQgdGhlIGhpZ2hlc3QgdG90YWwgcmV2ZW51ZQ0KdG90YWxfcmV2ZW51ZV9kYXRlIDwtIGFnZ3JlZ2F0ZSh0b3RhbCB+IERhdGUsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkNCnRvdGFsX3JldmVudWVfZGF0ZVt3aGljaC5tYXgodG90YWxfcmV2ZW51ZV9kYXRlJHRvdGFsKSwgXQ0KDQoNCiMgYi4gc3RhY2tlZCBiYXIgY2hhcnQgc2hvd2luZyBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0IGJ5IGN1c3RvbWVyIHRpZXINCnF0eV90YWJsZSA9IHh0YWJzKFF0eSB+IFByb2R1Y3QgKyBDdXN0b21lclRpZXIsIGRhdGEgPSB0cmFuc2FjdGlvbnMpDQpiYXJwbG90KHF0eV90YWJsZSwNCiAgICAgICAgbWFpbiA9ICJRdWFudGl0eSBTb2xkIHBlciBQcm9kdWN0IGJ5IEN1c3RvbWVyIFRpZXIiLA0KICAgICAgICB4bGFiID0gIlByb2R1Y3QiLA0KICAgICAgICB5bGFiID0gIlF1YW50aXR5IiwNCiAgICAgICAgY29sID0gYygibGlnaHRibHVlIiwgImxpZ2h0Z3JlZW4iLCAicGluayIpKQ0KYGBgDQoNCg0KNS4gICoqVmlzdWFsaXplIHRoZSBkYXRhKio6DQoNCiAgICAtICAgQ3JlYXRlIGEgKipiYXJwbG90Kiogc2hvd2luZyB0b3RhbCBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0Lg0KICAgIC0gICBDcmVhdGUgYSAqKnBpZSBjaGFydCoqIHNob3dpbmcgdGhlIHByb3BvcnRpb24gb2YgdG90YWwgcmV2ZW51ZSBwZXIgY3VzdG9tZXIgdGllci4NCg0KNi4gICoqT3B0aW9uYWwgQ2hhbGxlbmdlKio6DQoNCiAgICAtICAgRmluZCB3aGljaCAqKmRhdGUqKiBoYWQgdGhlIGhpZ2hlc3QgdG90YWwgcmV2ZW51ZS4NCiAgICAtICAgQ3JlYXRlIGEgKipzdGFja2VkIGJhciBjaGFydCoqIHNob3dpbmcgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyLg0KDQoqKkhpbnRzOioqIFVzZSBgZGF0YS5mcmFtZSgpYCwgYGFnZ3JlZ2F0ZSgpYCwgYGJhcnBsb3QoKWAsIGBwaWUoKWAsIGFuZCBiYXNpYyBhcml0aG1ldGljIG9wZXJhdGlvbnMgaW4gUi4NCg0KDQojIyBFeGVyY2lzZSA1DQoNCioqQ3JlYXRlIFlvdXIgT3duIERhdGEgRnJhbWU6KioNCg0KKipPYmplY3RpdmU6KiogQ3JlYXRlIGEgZGF0YSBmcmFtZSBpbiBSIHdpdGggKiozMCByb3dzKiogY29udGFpbmluZyBhIG1peCBvZiBkYXRhIHR5cGVzOiBjb250aW51b3VzLCBkaXNjcmV0ZSwgbm9taW5hbCwgYW5kIG9yZGluYWwuDQoNCiMjIyBJbnN0cnVjdGlvbnMNCg0KMS4gICoqT3BlbiBSU3R1ZGlvKiogb3IgdGhlIFIgY29uc29sZS4NCg0KMi4gICoqQ3JlYXRlIGEgdmVjdG9yIGZvciBlYWNoIGNvbHVtbioqIGluIHlvdXIgZGF0YSBmcmFtZToNCg0KICAgIC0gICAqKkRhdGUqKjogMzAgZGF0ZXMgKGNhbiBiZSBzZXF1ZW50aWFsIG9yIHJhbmRvbSB3aXRoaW4gYSBtb250aC95ZWFyKVwNCiAgICAtICAgKipDb250aW51b3VzKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIHRha2UgZGVjaW1hbCB2YWx1ZXMgKGUuZy4sIGhlaWdodCwgd2VpZ2h0LCB0ZW1wZXJhdHVyZSlcDQogICAgLSAgICoqRGlzY3JldGUqKjogbnVtZXJpYyB2YWx1ZXMgdGhhdCBjYW4gb25seSB0YWtlIHdob2xlIG51bWJlcnMgKGUuZy4sIG51bWJlciBvZiBpdGVtcywgbnVtYmVyIG9mIHZlaGljbGVzKVwNCiAgICAtICAgKipOb21pbmFsKio6IGNhdGVnb3JpY2FsIHZhbHVlcyB3aXRoICoqbm8gb3JkZXIqKiAoZS5nLiwgY29sb3IsIGdlbmRlciwgY2l0eSlcDQogICAgLSAgICoqT3JkaW5hbCoqOiBjYXRlZ29yaWNhbCB2YWx1ZXMgd2l0aCBhICoqZGVmaW5lZCBvcmRlcioqIChlLmcuLCBMb3csIE1lZGl1bSwgSGlnaDsgQmVnaW5uZXIsIEludGVybWVkaWF0ZSwgRXhwZXJ0KQ0KDQozLiAgKipDb21iaW5lIGFsbCB2ZWN0b3JzIGludG8gYSBkYXRhIGZyYW1lKiogY2FsbGVkIGBteV9kYXRhYC4NCg0KNC4gICoqQ2hlY2sgeW91ciBkYXRhIGZyYW1lKiogdXNpbmcgYGhlYWQoKWAgb3IgYFZpZXcoKWAgdG8gZW5zdXJlIGl0IGhhcyAqKjMwIHJvd3MqKiBhbmQgdGhlIGNvbHVtbnMgYXJlIGNvcnJlY3QuDQoNCjUuICAqKk9wdGlvbmFsIHRhc2tzKio6DQoNCiAgICAtICAgU3VtbWFyaXplIGVhY2ggY29sdW1uIHVzaW5nIGBzdW1tYXJ5KClgXA0KICAgIC0gICBDb3VudCB0aGUgZnJlcXVlbmN5IG9mIGVhY2ggY2F0ZWdvcnkgZm9yICoqTm9taW5hbCoqIGFuZCAqKk9yZGluYWwqKiBjb2x1bW5zIHVzaW5nIGB0YWJsZSgpYA0KDQojIyMgSGludHMNCg0KLSAgIFVzZSBgc2VxLkRhdGUoKWAgb3IgYGFzLkRhdGUoKWAgdG8gZ2VuZXJhdGUgdGhlIERhdGUgY29sdW1uLlwNCi0gICBVc2UgYHJ1bmlmKClgIG9yIGBybm9ybSgpYCBmb3IgY29udGludW91cyBudW1lcmljIGRhdGEuXA0KLSAgIFVzZSBgc2FtcGxlKClgIGZvciBkaXNjcmV0ZSwgbm9taW5hbCwgYW5kIG9yZGluYWwgZGF0YS5cDQotICAgRW5zdXJlIHRoZSAqKm9yZGluYWwgdmVjdG9yKiogaXMgY3JlYXRlZCB3aXRoIGBmYWN0b3IoLi4uLCBsZXZlbHMgPSBjKCJMb3ciLCJNZWRpdW0iLCJIaWdoIiksIG9yZGVyZWQgPSBUUlVFKWAgKG9yIHNpbWlsYXIpLg0KDQpgYGB7cn0NCiMgMS4gQ29mZmVlIFNob3AgRGF0YQ0KDQojIERhdGUgKDMwIGhhcmkgZGkgYnVsYW4gU2VwdGVtYmVyKQ0KRGF0ZSA9IHNlcShhcy5EYXRlKCIyMDI1LTA5LTAxIiksIGFzLkRhdGUoIjIwMjUtMDktMzAiKSwgYnkgPSAiZGF5IikNCg0KIyBDb250aW51b3VzOiBqdW1sYWggbWwga29waSB0ZXJqdWFsIHBlciBoYXJpIChhY2FrIGRhcmkgMTUwMOKAkzQwMDAgbWwpDQpDb2ZmZWVfbWwgPSBydW5pZigzMCwgbWluID0gMTUwMCwgbWF4ID0gNDAwMCkNCg0KIyBEaXNjcmV0ZToganVtbGFoIGNhbmdraXIga29waSB0ZXJqdWFsIHBlciBoYXJpIChhY2FrIDIw4oCTMTAwKQ0KQ3Vwc19Tb2xkID0gc2FtcGxlKDIwOjEwMCwgMzAsIHJlcGxhY2UgPSBUUlVFKQ0KDQojIE5vbWluYWw6IGplbmlzIG1pbnVtYW4ga29waQ0KRHJpbmtfVHlwZSA9IHNhbXBsZShjKCJBbWVyaWNhbm8iLCAiQ2FwcHVjY2lubyIsICJMYXR0ZSIsICJFc3ByZXNzbyIsICJNb2NoYSIpLCAzMCwgcmVwbGFjZSA9IFRSVUUpDQoNCiMgT3JkaW5hbDogdGluZ2thdCBrZXB1YXNhbiBwZWxhbmdnYW4NCkN1c3RvbWVyX1NhdGlzZmFjdGlvbiA9IGZhY3RvcigNCiAgc2FtcGxlKGMoIlBvb3IiLCAiRmFpciIsICJHb29kIiwgIlZlcnkgR29vZCIsICJFeGNlbGxlbnQiKSwgMzAsIHJlcGxhY2UgPSBUUlVFKSwNCiAgbGV2ZWxzID0gYygiUG9vciIsICJGYWlyIiwgIkdvb2QiLCAiVmVyeSBHb29kIiwgIkV4Y2VsbGVudCIpLA0KICBvcmRlcmVkID0gVFJVRSkNCg0KIyBDb21iaW5lIGFsbCB2ZWN0b3JzIGludG8gYSBkYXRhIGZyYW1lDQpteV9kYXRhID0gZGF0YS5mcmFtZShEYXRlLCBDb2ZmZWVfbWwsIEN1cHNfU29sZCwgRHJpbmtfVHlwZSwgQ3VzdG9tZXJfU2F0aXNmYWN0aW9uKQ0Ka2FibGUobXlfZGF0YSkNCg0KIyBTdW1tYXJ5IGRhdGEgKG9wc2lvbmFsKQ0Kc3VtbWFyeV9kYXRhIDwtIHN1bW1hcnkobXlfZGF0YSkNCmthYmxlKHN1bW1hcnlfZGF0YSkNCg0KIyBGcmVrdWVuc2kgS2F0ZWdvcmkgKG5vbWluYWwsIG9yZGluYWwpDQpsaWJyYXJ5KGtuaXRyKQ0KZHJpbmtfZnJlcSA8LSB0YWJsZShteV9kYXRhJERyaW5rX1R5cGUpDQpzYXRpc2ZhY3Rpb25fZnJlcSA8LSB0YWJsZShteV9kYXRhJEN1c3RvbWVyX1NhdGlzZmFjdGlvbikNCg0Ka2FibGUoZHJpbmtfZnJlcSwgY2FwdGlvbiA9ICJGcmVrdWVuc2kgSmVuaXMgTWludW1hbiAoTm9taW5hbCkiKQ0Ka2FibGUoc2F0aXNmYWN0aW9uX2ZyZXEsIGNhcHRpb24gPSAiRnJla3VlbnNpIEtlcHVhc2FuIFBlbGFuZ2dhbiAoT3JkaW5hbCkiKQ0KDQpgYGANCg==