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",
    "Structuded",
    "Unstructuded",
    "Structuded"
      ),
  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
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).



``` r
# 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 3179.608 22 Mocha Fair
2025-09-02 2261.069 88 Cappuccino Very Good
2025-09-03 3957.235 70 Latte Excellent
2025-09-04 1837.464 68 Americano Fair
2025-09-05 1602.321 41 Cappuccino Excellent
2025-09-06 1531.665 21 Latte Good
2025-09-07 3221.046 28 Americano Fair
2025-09-08 2625.220 97 Cappuccino Good
2025-09-09 2565.011 68 Latte Good
2025-09-10 3309.117 23 Cappuccino Fair
2025-09-11 2681.909 65 Mocha Fair
2025-09-12 1902.952 62 Mocha Poor
2025-09-13 3371.731 78 Cappuccino Excellent
2025-09-14 3863.962 99 Espresso Poor
2025-09-15 2953.760 91 Americano Good
2025-09-16 2280.910 90 Latte Fair
2025-09-17 3062.806 30 Mocha Excellent
2025-09-18 2437.797 77 Cappuccino Good
2025-09-19 2224.364 85 Espresso Good
2025-09-20 2013.447 75 Americano Very Good
2025-09-21 3899.187 96 Cappuccino Very Good
2025-09-22 2634.276 40 Espresso Excellent
2025-09-23 3609.000 32 Latte Poor
2025-09-24 1735.574 67 Latte Very Good
2025-09-25 1891.297 95 Espresso Fair
2025-09-26 2445.068 38 Americano Poor
2025-09-27 2919.725 88 Latte Good
2025-09-28 2840.019 46 Latte Very Good
2025-09-29 2841.009 25 Latte Excellent
2025-09-30 3426.712 25 Mocha Poor
# 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. :1532 Min. :21.00 Length:30 Poor :5
1st Qu.:2025-09-08 1st Qu.:2234 1st Qu.:33.50 Class :character Fair :7
Median :2025-09-15 Median :2658 Median :67.50 Mode :character Good :7
Mean :2025-09-15 Mean :2704 Mean :61.00 NA Very Good:5
3rd Qu.:2025-09-22 3rd Qu.:3211 3rd Qu.:87.25 NA Excellent:6
Max. :2025-09-30 Max. :3957 Max. :99.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 5
Cappuccino 7
Espresso 4
Latte 9
Mocha 5
kable(satisfaction_freq, caption = "Frekuensi Kepuasan Pelanggan (Ordinal)")
Frekuensi Kepuasan Pelanggan (Ordinal)
Var1 Freq
Poor 5
Fair 7
Good 7
Very Good 5
Excellent 6
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAzIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6IA0KLSAiVmVyb25pY2EgTSBMIEYgWGF2aWVyIiANCi0gIktoYWZpemF0dW4gTmlzYSINCi0gIkFuZ2VsaXF1ZSBLaXlvc2hpIExha2Vpc2hhIEIuVSINCi0gIk5heWNoaWxsYSBBZGVsaWEgWmFocmEiDQotICJOYWtlaXNoYSBBdWxpYSBaYWhyYSIjIFJlcGxhY2Ugd2l0aCB5b3VyIGZ1bGwgbmFtZQ0KZGF0ZTogICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCIgIyBBdXRvIGRpc3BsYXlzIHRoZSBjdXJyZW50IGRhdGUNCm91dHB1dDogICAgICAgICAgICAgICAgICAgICAgICAgIyBPdXRwdXQgc2VjdGlvbiBkZWZpbmVzIHRoZSBmb3JtYXQgYW5kIGxheW91dCANCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246ICAgICAgIyBodHRwczovL2dpdGh1Yi5jb20vanViYS9ybWRmb3JtYXRzDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUgICAgICAgICMgRW1iZWRzIGFsbCByZXNvdXJjZXMgKENTUywgSlMsIGltYWdlcykgDQogICAgdGh1bWJuYWlsczogdHJ1ZSAgICAgICAgICAgICMgRGlzcGxheXMgaW1hZ2UgdGh1bWJuYWlscyBpbiB0aGUgZG9jDQogICAgbGlnaHRib3g6IHRydWUgICAgICAgICAgICAgICMgRW5hYmxlcyBjbGljayB0byBlbmxhcmdlIGltYWdlcw0KICAgIGdhbGxlcnk6IHRydWUgICAgICAgICAgICAgICAjIEdyb3VwcyBpbWFnZXMgaW50byBhbiBpbnRlcmFjdGl2ZSBnYWxsZXJ5DQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlICAgICAgICMgQXV0b21hdGljYWxseSBudW1iZXJzIGFsbCBzZWN0aW9ucw0KICAgIGxpYl9kaXI6IGxpYnMgICAgICAgICAgICAgICAjIERpcmVjdG9yeSB3aGVyZSBKYXZhU2NyaXB0L0NTUyBsaWJyYXJpZXMNCiAgICBkZl9wcmludDogInBhZ2VkIiAgICAgICAgICAgIyBEaXNwbGF5cyBkYXRhIGZyYW1lcyBhcyBpbnRlcmFjdGl2ZSBwYWdlZCANCiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93IiAgICAgICAgIyBBbGxvd3MgZm9sZGluZy91bmZvbGRpbmcgUiBjb2RlIGJsb2NrcyANCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMgICAgICAgICAgIyBBZGRzIGEgYnV0dG9uIHRvIGRvd25sb2FkIGFsbCBSIGNvZGUNCi0tLQ0KDQoNCjxpbWcgaWQ9IkZvdG8iIHNyYz0iZml2ZWd1cmxzLkpQRyIgYWx0PSJMb2dvIiBzdHlsZT0id2lkdGg6MjAwcHg7IGRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87Ij4NCg0KLS0tDQoNCiMjIEV4ZXJjaXNlIDENCg0KVGhlIGZvbGxvd2luZyB0YWJsZSBzaG93cyBzYW1wbGUgaW5mb3JtYXRpb24gZm9yIHRocmVlIHN0dWRlbnRzLiBFYWNoIG9ic2VydmF0aW9uIHJlcHJlc2VudHMgYSBzaW5nbGUgc3R1ZGVudCBhbmQgaW5jbHVkZXMgZGV0YWlscyBzdWNoIGFzIHRoZWlyIHVuaXF1ZSBzdHVkZW50IElELCBuYW1lLCBhZ2UsIHRvdGFsIGNyZWRpdHMgY29tcGxldGVkLCBtYWpvciBmaWVsZCBvZiBzdHVkeSwgYW5kIHllYXIgbGV2ZWwuICANCg0KVGhpcyBkYXRhc2V0IGRlbW9uc3RyYXRlcyBhIG1peHR1cmUgb2YgdmFyaWFibGUgdHlwZXM6ICANCg0KLSAqKk5vbWluYWw6KiogU3R1ZGVudElELCBOYW1lLCBNYWpvciAgDQotICoqTnVtZXJpYzoqKiBBZ2UgKGNvbnRpbnVvdXMpLCBDcmVkaXRzQ29tcGxldGVkIChkaXNjcmV0ZSkgIA0KLSAqKk9yZGluYWw6KiogWWVhckxldmVsIChGcmVzaG1hbiDihpIgU2VuaW9yKSAgDQoNCnwgU3R1ZGVudElEIHwgTmFtZSAgIHwgQWdlIHwgQ3JlZGl0c0NvbXBsZXRlZCB8IE1ham9yICAgICAgICAgICAgfCBZZWFyTGV2ZWwgfA0KfC0tLS0tLS0tLS0tfC0tLS0tLS0tfC0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tfA0KfCBTMDAxICAgICAgfCBBbGljZSAgfCAyMCAgfCA0NSAgICAgICAgICAgICAgfCBEYXRhIFNhaW5zICAgICAgfCBTb3Bob21vcmUgfA0KfCBTMDAyICAgICAgfCBCdWRpICAgfCAyMSAgfCA2MCAgICAgICAgICAgICAgfCBNYXRoZW1hdGljcyAgICAgfCBKdW5pb3IgICAgfA0KfCBTMDAzICAgICAgfCBDaXRyYSAgfCAxOSAgfCAzMCAgICAgICAgICAgICAgfCBTdGF0aXN0aWNzICAgICAgfCBGcmVzaG1hbiAgfA0KDQpgYGB7cn0NCiMgMS4gQ3JlYXRlIHZlY3RvcnMgZm9yIGVhY2ggdmFyaWFibGUNClN0dWRlbnRJRCA8LSBjKCJTMDAxIiwgIlMwMDIiLCAiUzAwMyIpICAgICAgICMgTm9taW5hbCAvIElEDQpOYW1lIDwtIGMoIkFsaWNlIiwgIkJ1ZGkiLCAiQ2l0cmEiKSAgICAgICAgICAjIE5vbWluYWwgLyBOYW1lDQpBZ2UgPC0gYygyMCwgMjEsIDE5KSAgICAgICAgICAgICAgICAgICAgICAgICAjIE51bWVyaWMgLyBDb250aW51b3VzDQpDcmVkaXRzQ29tcGxldGVkIDwtIGMoNDUsIDYwLCAzMCkgICAgICAgICAgICAjIE51bWVyaWMgLyBEaXNjcmV0ZQ0KDQojIE5vbWluYWwNCk1ham9yIDwtIGMoIkRhdGEgU2FpbnMiLCAiTWF0aGVtYXRpY3MiLCAiU3RhdGlzdGljcyIpICANCg0KIyBPcmRpbmFsDQpZZWFyTGV2ZWwgPC0gZmFjdG9yKGMoIlNvcGhvbW9yZSIsICJKdW5pb3IiLCAiRnJlc2htYW4iKSwNCiAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiRnJlc2htYW4iLCJTb3Bob21vcmUiLCJKdW5pb3IiLCJTZW5pb3IiKSwNCiAgICAgICAgICAgICAgICAgICAgb3JkZXJlZCA9IFRSVUUpICAgICAgICAgIA0KDQojIDIuIENvbWJpbmUgYWxsIHZlY3RvcnMgaW50byBhIGRhdGEgZnJhbWUNCnN0dWRlbnRzIDwtIGRhdGEuZnJhbWUoDQogIFN0dWRlbnRJRCwgTmFtZSwgQWdlLCBDcmVkaXRzQ29tcGxldGVkLCBNYWpvciwgWWVhckxldmVsLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyAzLiBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lDQpwcmludChzdHVkZW50cykNCmBgYA0KDQoNCiMjIEV4ZXJjaXNlIDINCg0KKipJZGVudGlmeSBEYXRhIFR5cGVzOioqIERldGVybWluZSB0aGUgdHlwZSBvZiBkYXRhIGZvciBlYWNoIG9mIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOg0KDQpgYGB7cn0NCiMgSW5zdGFsbCBrbml0ciBwYWNrYWdlIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZA0KIyBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQpsaWJyYXJ5KGtuaXRyKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIERhdGEgVHlwZXMNCnZhcmlhYmxlc19pbmZvIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMTo1LA0KICBWYXJpYWJsZSA9IGMoDQogICAgIk51bWJlciBvZiB2ZWhpY2xlcyBwYXNzaW5nIHRocm91Z2ggdGhlIHRvbGwgcm9hZCBlYWNoIGRheSIsDQogICAgIlN0dWRlbnQgaGVpZ2h0IGluIGNtIiwNCiAgICAiRW1wbG95ZWUgZ2VuZGVyIChNYWxlIC8gRmVtYWxlKSIsDQogICAgIkN1c3RvbWVyIHNhdGlzZmFjdGlvbiBsZXZlbDogTG93LCBNZWRpdW0sIEhpZ2giLA0KICAgICJSZXNwb25kZW50J3MgZmF2b3JpdGUgY29sb3I6IFJlZCwgQmx1ZSwgR3JlZW4iDQogICksDQogIERhdGFUeXBlID0gYygNCiAgICAiTnVtZXJpYyIsDQogICAgIk51bWVyaWMiLA0KICAgICJDYXRlZ29yaWNhbCIsDQogICAgIkNhdGVnb3JpY2FsIiwNCiAgICAiQ2F0ZWdvcmljYWwiDQogICksDQogIFN1YnR5cGUgPSBjKA0KICAgICJEaXNjcmV0ZSIsDQogICAgIkNvbnRpbnVvdXMiLA0KICAgICJOb21pbmFsIiwNCiAgICAiT3JkaW5hbCIsDQogICAgIk5vbWluYWwiDQogICksDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUgYXMgYSBuZWF0IHRhYmxlDQprYWJsZSh2YXJpYWJsZXNfaW5mbywgDQogICAgICBjYXB0aW9uID0gIlRhYmxlIG9mIFZhcmlhYmxlcyBhbmQgRGF0YSBUeXBlcyIpDQpgYGANCi0tLQ0KDQojIyBFeGVyY2lzZSAzDQoNCioqQ2xhc3NpZnkgRGF0YSBTb3VyY2VzOioqIERldGVybWluZSB3aGV0aGVyIHRoZSBmb2xsb3dpbmcgZGF0YSBjb21lcyBmcm9tICoqaW50ZXJuYWwqKiBvciAqKmV4dGVybmFsIHNvdXJjZXMqKiwgYW5kIHdoZXRoZXIgaXQgaXMgKipzdHJ1Y3R1cmVkKiogb3IgKip1bnN0cnVjdHVyZWQqKjoNCg0KYGBge3J9DQojIEluc3RhbGwgRFQgcGFja2FnZSBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCiMgaW5zdGFsbC5wYWNrYWdlcygiRFQiKQ0KbGlicmFyeShEVCkNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBkYXRhIHNvdXJjZXMgDQpkYXRhX3NvdXJjZXMgPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjQsDQogIERhdGFTb3VyY2UgPSBjKA0KICAgICJEYWlseSBzYWxlcyB0cmFuc2FjdGlvbiBkYXRhIG9mIHRoZSBjb21wYW55IiwNCiAgICAiV2VhdGhlciByZXBvcnRzIGZyb20gQk1LRyIsDQogICAgIlByb2R1Y3QgcmV2aWV3cyBvbiBzb2NpYWwgbWVkaWEiLA0KICAgICJXYXJlaG91c2UgaW52ZW50b3J5IHJlcG9ydHMiDQogICksDQogIEludGVybmFsX0V4dGVybmFsID0gYygNCiAgICAiSW50ZXJuYWwiLA0KICAgICJFeHRlcm5hbCIsDQogICAgIkV4dGVybmFsIiwNCiAgICAiSW50ZXJuYWwiDQogICksDQogIFN0cnVjdHVyZWRfVW5zdHJ1Y3R1cmVkID0gYygNCiAgICAiU3RydWN0dXJlZCIsDQogICAgIlN0cnVjdHVkZWQiLA0KICAgICJVbnN0cnVjdHVkZWQiLA0KICAgICJTdHJ1Y3R1ZGVkIg0KICAgICAgKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQoNCikNCg0KIyBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lIGFzIGEgbmVhdCB0YWJsZQ0KZGF0YXRhYmxlKGRhdGFfc291cmNlcywgDQogICAgICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBEYXRhIFNvdXJjZXMiLA0KICAgICAgcm93bmFtZXMgPSBGQUxTRSkgIyBoaWRlcyB0aGUgaW5kZXggY29sdW1uDQpgYGANCg0KLS0tDQoNCiMjIEV4ZXJjaXNlIDQNCg0KKipEYXRhc2V0IFN0cnVjdHVyZToqKiBDb25zaWRlciB0aGUgZm9sbG93aW5nIHRyYW5zYWN0aW9uIHRhYmxlOg0KDQp8IERhdGUgICAgICAgfCBRdHkgfCBQcmljZSB8IFByb2R1Y3QgIHwgQ3VzdG9tZXJUaWVyIHwNCnwtLS0tLS0tLS0tLS18LS0tLS18LS0tLS0tLXwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfA0KfCAyMDI1LTEwLTAxIHwgMiAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDEgfCA1ICAgfCAyMCAgICB8IE1vdXNlICAgIHwgTWVkaXVtICAgICAgIHwNCnwgMjAyNS0xMC0wMiB8IDEgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTAyIHwgMyAgIHwgMzAgICAgfCBLZXlib2FyZCB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDMgfCA0ICAgfCA1MCAgICB8IE1vdXNlICAgIHwgTWVkaXVtICAgICAgIHwNCnwgMjAyNS0xMC0wMyB8IDIgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTA0IHwgNiAgIHwgMjUgICAgfCBLZXlib2FyZCB8IExvdyAgICAgICAgICB8DQp8IDIwMjUtMTAtMDQgfCAxICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wNSB8IDMgICB8IDQwICAgIHwgTW91c2UgICAgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTA1IHwgNSAgIHwgMTAgICAgfCBLZXlib2FyZCB8IE1lZGl1bSAgICAgICB8DQoNCg0KKipZb3VyIEFzc2lnbm1lbnQgSW5zdHJ1Y3Rpb25zOioqIENyZWF0aW5nIGEgVHJhbnNhY3Rpb25zIFRhYmxlIGFib3ZlIGluIFINCg0KMS4gKipDcmVhdGUgYSBkYXRhIGZyYW1lKiogaW4gUiBjYWxsZWQgYHRyYW5zYWN0aW9uc2AgY29udGFpbmluZyB0aGUgZGF0YSBhYm92ZS4NCg0KMi4gSWRlbnRpZnkgd2hpY2ggdmFyaWFibGVzIGFyZSBudW1lcmljIGFuZCB3aGljaCBhcmUgY2F0ZWdvcmljYWwNCg0KMy4gKipDYWxjdWxhdGUgdG90YWwgcmV2ZW51ZSoqIGZvciBlYWNoIHRyYW5zYWN0aW9uIGJ5IG11bHRpcGx5aW5nIGBRdHkgw5cgUHJpY2VgIGFuZCBhZGQgaXQgYXMgYSBuZXcgY29sdW1uIGBUb3RhbGAuDQoNCjQuICoqQ29tcHV0ZSBzdW1tYXJ5IHN0YXRpc3RpY3MqKjoNCiAgIC0gVG90YWwgcXVhbnRpdHkgc29sZCBmb3IgZWFjaCBwcm9kdWN0DQogICAtIFRvdGFsIHJldmVudWUgcGVyIHByb2R1Y3QNCiAgIC0gQXZlcmFnZSBwcmljZSBwZXIgcHJvZHVjdA0KDQo1LiAqKlZpc3VhbGl6ZSB0aGUgZGF0YSoqOg0KICAgLSBDcmVhdGUgYSAqKmJhcnBsb3QqKiBzaG93aW5nIHRvdGFsIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QuDQogICAtIENyZWF0ZSBhICoqcGllIGNoYXJ0Kiogc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiB0b3RhbCByZXZlbnVlIHBlciBjdXN0b21lciB0aWVyLg0KDQo2LiAqKk9wdGlvbmFsIENoYWxsZW5nZSoqOg0KICAgLSBGaW5kIHdoaWNoICoqZGF0ZSoqIGhhZCB0aGUgaGlnaGVzdCB0b3RhbCByZXZlbnVlLg0KICAgLSBDcmVhdGUgYSAqKnN0YWNrZWQgYmFyIGNoYXJ0Kiogc2hvd2luZyBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0IGJ5IGN1c3RvbWVyIHRpZXIuDQoNCioqSGludHM6KiogVXNlIGBkYXRhLmZyYW1lKClgLCBgYWdncmVnYXRlKClgLCBgYmFycGxvdCgpYCwgYHBpZSgpYCwgYW5kIGJhc2ljIGFyaXRobWV0aWMgb3BlcmF0aW9ucyBpbiBSLg0KDQpgYGB7cn0NCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgVHJhbnNhY3Rpb25zDQpEYXRlID0gYyAoDQogICIyMDI1LTEwLTAxIiwgIA0KICAiMjAyNS0xMC0wMSIsIA0KICAiMjAyNS0xMC0wMiIsIA0KICAiMjAyNS0xMC0wMiIsIA0KICAiMjAyNS0xMC0wMyIsIA0KICAiMjAyNS0xMC0wMyIsIA0KICAiMjAyNS0xMC0wNCIsIA0KICAiMjAyNS0xMC0wNCIsIA0KICAiMjAyNS0xMC0wNSIsIA0KICAiMjAyNS0xMC0wNSINCiAgKSAgICAgICAgICAgICAgDQpRdHkgPSBjICgyLCA1LCAxLCAzLCA0LCAyLCA2LCAxLCAzLCA1KSAgDQpQcmljZSA9IGMgKDEwMDAsIDIwLCAxMDAwLCAzMCwgNTAsIDEwMDAsIDI1LCAxMDAwLCA0MCwgMTApICANClByb2R1Y3QgPSBjICgNCiAgIkxhcHRvcCIsDQogICJNb3VzZSIsDQogICJMYXB0b3AiLA0KICAiS2V5Ym9hcmQiLA0KICAiTW91c2UiLA0KICAiTGFwdG9wIiwNCiAgIktleWJvYXJkIiwNCiAgIkxhcHRvcCIsDQogICJNb3VzZSIsDQogICJLZXlib2FyZCINCiAgKSAgICAgICAgIA0KQ3VzdG9tZXJUaWVyID0gZmFjdG9yKGMoDQogICJIaWdoIiwNCiAgIk1lZGl1bSIsDQogICJMb3ciLA0KICAiTWVkaXVtIiwNCiAgIk1lZGl1bSIsDQogICJIaWdoIiwNCiAgIkxvdyIsDQogICJIaWdoIiwNCiAgIkxvdyIsDQogICJNZWRpdW0iDQogICksDQpsZXZlbHMgPSBjKCJMb3ciLCJNZWRpdW0iLCJIaWdoIiksDQpvcmRlcmVkID0gVFJVRSkgDQp0cmFuc2FjdGlvbnMgPC0gIGRhdGEuZnJhbWUgKERhdGUsIFF0eSwgUHJpY2UsIFByb2R1Y3QsIEN1c3RvbWVyVGllciwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCmxpYnJhcnkoa25pdHIpDQprYWJsZSh0cmFuc2FjdGlvbnMsIGNhcHRpb24gPSAiRGF0YSBUcmFuc2FjdGlvbnMiKQ0KYGBgDQoNCmBgYHtyfQ0KIyAyLiBJZGVudGlmeSB2YXJpYWJsZSB0eXBlcw0KbGlicmFyeShrbml0cikNCnZhcmlhYmxlX3R5cGVzIDwtIGRhdGEuZnJhbWUoDQogIFZhcmlhYmxlID0gYygNCiAgICAiRGF0ZSIsDQogICAgIlF0eSIsDQogICAgIlByaWNlIiwNCiAgICAiUHJvZHVjdCIsDQogICAgIkN1c3RvbWVyVGllciINCiAgICApLA0KICBUeXBlID0gYygNCiAgICAiTnVtZXJpYyAoRGlzY3JldGUpIiwNCiAgICAiTnVtZXJpYyAoRGlzY3JldGUpIiwNCiAgICAiTnVtZXJpYyAoRGlzY3JldGUpIiwNCiAgICAiQ2F0ZWdvcmljYWwgKE5vbWluYWwpIiwNCiAgICAiQ2F0ZWdvcmljYWwgKE9yZGluYWwpIg0KICAgICkNCikNCg0KIyBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lDQprYWJsZSh2YXJpYWJsZV90eXBlcywgY2FwdGlvbiA9ICJWYXJpYWJsZSBUeXBlcyBpbiBUcmFuc2FjdGlvbnMgRGF0YSIpDQoNCmBgYA0KDQpgYGB7cn0NCiMgMy4gQ2FsY3VsYXRlIHRvdGFsIHJldmVudWUNCnRyYW5zYWN0aW9ucyR0b3RhbCA9IHRyYW5zYWN0aW9ucyRRdHkgKiB0cmFuc2FjdGlvbnMkUHJpY2UNCmthYmxlKHRyYW5zYWN0aW9ucykNCg0KYGBgDQoNCmBgYHtyfQ0KIyA0LiBDb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljDQoNCiMgYS4gVG90YWwgcXVhbnRpdHkgc29sZCBmb3IgZWFjaCBwcm9kdWN0DQp0b3RhbF9RdHkgPSBhZ2dyZWdhdGUoUXR5IH4gUHJvZHVjdCwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKQ0Ka2FibGUodG90YWxfUXR5LCBjYXB0aW9uID0gIlRvdGFsIFF1YW50aXR5IFNvbGQgcGVyIFByb2R1Y3QiKQ0KDQojIGIuIHRvdGFsIHJldmVudWUgcGVyIHByb2R1Y3QNCnRvdGFsX3JldmVudWUgPSBhZ2dyZWdhdGUodG90YWwgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQprYWJsZSh0b3RhbF9yZXZlbnVlLCBjYXB0aW9uID0gIlRvdGFsIFJldmVudWUgcGVyIFByb2R1Y3QiKQ0KDQojIGMuIEF2ZXJhZ2UgcHJpY2UgcGVyIHByb2R1Y3QNCmF2Z19wcmljZSA9IGFnZ3JlZ2F0ZShQcmljZSB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIG1lYW4pDQprYWJsZShhdmdfcHJpY2UsIGNhcHRpb24gPSAiQXZlcmFnZSBQcmljZSBwZXIgUHJvZHVjdCIpDQoNCmBgYA0KDQpgYGB7cn0NCiMgNS4gVmlzdWFsaXplIHRoZSBkYXRhDQoNCiMgYS4gYmFycGxvdCBzaG93aW5nIHRvdGFsIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QNCnRvdGFsX3F0eSA9IHRhcHBseSh0cmFuc2FjdGlvbnMkUXR5LCB0cmFuc2FjdGlvbnMkUHJvZHVjdCwgc3VtKQ0KYmFycGxvdCh0b3RhbF9xdHksDQogICAgICAgIG1haW4gPSAiVG90YWwgUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCIsDQogICAgICAgIHhsYWIgPSAiUHJvZHVjdCIsDQogICAgICAgIHlsYWIgPSAiVG90YWwgUXVhbnRpdHkiLA0KICAgICAgICBjb2wgPSAibGlnaHRibHVlIikNCg0KIyBiLiBwaWUgY2hhcnQgc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiB0b3RhbCByZXZlbnVlDQp0b3RhbF9yZXZlbnVlX3RpZXIgPSB0YXBwbHkodHJhbnNhY3Rpb25zJHRvdGFsLCB0cmFuc2FjdGlvbnMkQ3VzdG9tZXJUaWVyLCBzdW0pDQpwaWUodG90YWxfcmV2ZW51ZV90aWVyLA0KICAgIG1haW4gPSAiUHJvcG9ydGlvbiBvZiBUb3RhbCBSZXZlbnVlIHBlciBDdXN0b21lciBUaWVyIiwNCiAgICBjb2wgPSByYWluYm93KGxlbmd0aCh0b3RhbF9yZXZlbnVlX3RpZXIpKSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyA2LiBPcHRpb25hbCBjaGFsbGVuZ2UNCg0KIyBhLiBGaW5kIHdoaWNoIGRhdGUgaGFkIHRoZSBoaWdoZXN0IHRvdGFsIHJldmVudWUNCnRvdGFsX3JldmVudWVfZGF0ZSA8LSBhZ2dyZWdhdGUodG90YWwgfiBEYXRlLCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQp0b3RhbF9yZXZlbnVlX2RhdGVbd2hpY2gubWF4KHRvdGFsX3JldmVudWVfZGF0ZSR0b3RhbCksIF0NCg0KDQojIGIuIHN0YWNrZWQgYmFyIGNoYXJ0IHNob3dpbmcgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyDQpxdHlfdGFibGUgPSB4dGFicyhRdHkgfiBQcm9kdWN0ICsgQ3VzdG9tZXJUaWVyLCBkYXRhID0gdHJhbnNhY3Rpb25zKQ0KYmFycGxvdChxdHlfdGFibGUsDQogICAgICAgIG1haW4gPSAiUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCBieSBDdXN0b21lciBUaWVyIiwNCiAgICAgICAgeGxhYiA9ICJQcm9kdWN0IiwNCiAgICAgICAgeWxhYiA9ICJRdWFudGl0eSIsDQogICAgICAgIGNvbCA9IGMoImxpZ2h0Ymx1ZSIsICJsaWdodGdyZWVuIiwgInBpbmsiKSkNCiAgICAgIA0KYGBgDQoNCg0KIyMgRXhlcmNpc2UgNQ0KDQoqKkNyZWF0ZSBZb3VyIE93biBEYXRhIEZyYW1lOioqDQoNCioqT2JqZWN0aXZlOioqIENyZWF0ZSBhIGRhdGEgZnJhbWUgaW4gUiB3aXRoICoqMzAgcm93cyoqIGNvbnRhaW5pbmcgYSBtaXggb2YgZGF0YSB0eXBlczogY29udGludW91cywgZGlzY3JldGUsIG5vbWluYWwsIGFuZCBvcmRpbmFsLiAgDQoNCiMjIyBJbnN0cnVjdGlvbnMNCg0KMS4gKipPcGVuIFJTdHVkaW8qKiBvciB0aGUgUiBjb25zb2xlLiAgDQoNCjIuICoqQ3JlYXRlIGEgdmVjdG9yIGZvciBlYWNoIGNvbHVtbioqIGluIHlvdXIgZGF0YSBmcmFtZTogIA0KDQogICAtICoqRGF0ZSoqOiAzMCBkYXRlcyAoY2FuIGJlIHNlcXVlbnRpYWwgb3IgcmFuZG9tIHdpdGhpbiBhIG1vbnRoL3llYXIpICANCiAgIC0gKipDb250aW51b3VzKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIHRha2UgZGVjaW1hbCB2YWx1ZXMgKGUuZy4sIGhlaWdodCwgd2VpZ2h0LCB0ZW1wZXJhdHVyZSkgIA0KICAgLSAqKkRpc2NyZXRlKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIG9ubHkgdGFrZSB3aG9sZSBudW1iZXJzIChlLmcuLCBudW1iZXIgb2YgaXRlbXMsIG51bWJlciBvZiB2ZWhpY2xlcykgIA0KICAgLSAqKk5vbWluYWwqKjogY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggKipubyBvcmRlcioqIChlLmcuLCBjb2xvciwgZ2VuZGVyLCBjaXR5KSAgDQogICAtICoqT3JkaW5hbCoqOiBjYXRlZ29yaWNhbCB2YWx1ZXMgd2l0aCBhICoqZGVmaW5lZCBvcmRlcioqIChlLmcuLCBMb3csIE1lZGl1bSwgSGlnaDsgQmVnaW5uZXIsIEludGVybWVkaWF0ZSwgRXhwZXJ0KSAgDQoNCjMuICoqQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZSoqIGNhbGxlZCBgbXlfZGF0YWAuICANCg0KNC4gKipDaGVjayB5b3VyIGRhdGEgZnJhbWUqKiB1c2luZyBgaGVhZCgpYCBvciBgVmlldygpYCB0byBlbnN1cmUgaXQgaGFzICoqMzAgcm93cyoqIGFuZCB0aGUgY29sdW1ucyBhcmUgY29ycmVjdC4gIA0KDQo1LiAqKk9wdGlvbmFsIHRhc2tzKio6ICANCiAgIC0gU3VtbWFyaXplIGVhY2ggY29sdW1uIHVzaW5nIGBzdW1tYXJ5KClgICANCiAgIC0gQ291bnQgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIGNhdGVnb3J5IGZvciAqKk5vbWluYWwqKiBhbmQgKipPcmRpbmFsKiogY29sdW1ucyB1c2luZyBgdGFibGUoKWAgIA0KDQojIyMgSGludHMNCg0KLSBVc2UgYHNlcS5EYXRlKClgIG9yIGBhcy5EYXRlKClgIHRvIGdlbmVyYXRlIHRoZSBEYXRlIGNvbHVtbi4gIA0KLSBVc2UgYHJ1bmlmKClgIG9yIGBybm9ybSgpYCBmb3IgY29udGludW91cyBudW1lcmljIGRhdGEuICANCi0gVXNlIGBzYW1wbGUoKWAgZm9yIGRpc2NyZXRlLCBub21pbmFsLCBhbmQgb3JkaW5hbCBkYXRhLiAgDQotIEVuc3VyZSB0aGUgKipvcmRpbmFsIHZlY3RvcioqIGlzIGNyZWF0ZWQgd2l0aCBgZmFjdG9yKC4uLiwgbGV2ZWxzID0gYygiTG93IiwiTWVkaXVtIiwiSGlnaCIpLCBvcmRlcmVkID0gVFJVRSlgIChvciBzaW1pbGFyKS4NCg0KYGBgDQoNCg0KYGBge3J9DQojIDEuIENvZmZlZSBTaG9wIERhdGENCmxpYnJhcnkoa25pdHIpDQpEYXRlID0gc2VxKGFzLkRhdGUoIjIwMjUtMDktMDEiKSwgYXMuRGF0ZSgiMjAyNS0wOS0zMCIpLCBieSA9ICJkYXkiKSAgICAjIERhdGUNCkNvZmZlZV9tbCA9IHJ1bmlmKDMwLCBtaW4gPSAxNTAwLCBtYXggPSA0MDAwKSAgICAgICMgQ29udGludW91cyAvIFZvbHVtZSBLb3BpDQpDdXBzX1NvbGQgPSBzYW1wbGUoMjA6MTAwLCAzMCwgcmVwbGFjZSA9IFRSVUUpICAgICAjIERpc2NyZXRlIC8gSnVtbGFoIEtvcGkNCkRyaW5rX1R5cGUgPSBzYW1wbGUoYygNCiAgIkFtZXJpY2FubyIsDQogICJDYXBwdWNjaW5vIiwNCiAgIkxhdHRlIiwNCiAgIkVzcHJlc3NvIiwNCiAgIk1vY2hhIiksIDMwLCByZXBsYWNlID0gVFJVRSkgICAgICAgICAgICAgICAgICAgICMgTm9taW5hbCAvIEplbmlzIEtvcGkNCkN1c3RvbWVyX1NhdGlzZmFjdGlvbiA9IGZhY3RvcigNCiAgc2FtcGxlKGMoDQogICAgIlBvb3IiLA0KICAgICJGYWlyIiwNCiAgICAiR29vZCIsDQogICAgIlZlcnkgR29vZCIsDQogICAgIkV4Y2VsbGVudCIpLCAzMCwgcmVwbGFjZSA9IFRSVUUpLA0KICBsZXZlbHMgPSBjKCJQb29yIiwgIkZhaXIiLCAiR29vZCIsICJWZXJ5IEdvb2QiLCAiRXhjZWxsZW50IiksDQogIG9yZGVyZWQgPSBUUlVFKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIE9yZGluYWwgLyBTYXRpc2ZhY3Rpb24NCg0KIyBDb21iaW5lIGFsbCB2ZWN0b3JzIGludG8gYSBkYXRhIGZyYW1lDQpteV9kYXRhID0gZGF0YS5mcmFtZShEYXRlLCBDb2ZmZWVfbWwsIEN1cHNfU29sZCwgRHJpbmtfVHlwZSwgDQogICAgICAgICAgICAgICAgICAgICBDdXN0b21lcl9TYXRpc2ZhY3Rpb24pDQprYWJsZShteV9kYXRhKQ0KIyAyLiBTdW1tYXJ5IGRhdGEgKG9wc2lvbmFsKQ0Kc3VtbWFyeV9kYXRhID0gc3VtbWFyeShteV9kYXRhKQ0Ka2FibGUoc3VtbWFyeV9kYXRhKQ0KDQojIDMuIEZyZWt1ZW5zaSBLYXRlZ29yaSAobm9taW5hbCwgb3JkaW5hbCkNCmRyaW5rX2ZyZXEgPSB0YWJsZShteV9kYXRhJERyaW5rX1R5cGUpDQpzYXRpc2ZhY3Rpb25fZnJlcSA9IHRhYmxlKG15X2RhdGEkQ3VzdG9tZXJfU2F0aXNmYWN0aW9uKQ0KDQprYWJsZShkcmlua19mcmVxLCBjYXB0aW9uID0gIkZyZWt1ZW5zaSBKZW5pcyBNaW51bWFuIChOb21pbmFsKSIpDQprYWJsZShzYXRpc2ZhY3Rpb25fZnJlcSwgY2FwdGlvbiA9ICJGcmVrdWVuc2kgS2VwdWFzYW4gUGVsYW5nZ2FuIChPcmRpbmFsKSIpDQoNCg0KDQoNCg==