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.

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

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 2433.254 52 Latte Very Good
2025-09-02 1950.821 93 Cappuccino Good
2025-09-03 2164.201 93 Espresso Good
2025-09-04 2171.674 41 Cappuccino Poor
2025-09-05 1619.997 73 Mocha Poor
2025-09-06 3433.387 92 Mocha Fair
2025-09-07 3883.128 99 Americano Poor
2025-09-08 1805.518 66 Latte Good
2025-09-09 2996.276 20 Espresso Good
2025-09-10 1866.226 93 Espresso Poor
2025-09-11 3003.257 42 Espresso Poor
2025-09-12 2511.445 46 Americano Fair
2025-09-13 2181.126 23 Americano Fair
2025-09-14 1949.932 61 Cappuccino Poor
2025-09-15 3096.677 73 Mocha Excellent
2025-09-16 2773.454 62 Espresso Very Good
2025-09-17 2928.137 33 Cappuccino Fair
2025-09-18 2531.876 28 Latte Excellent
2025-09-19 1546.950 44 Americano Excellent
2025-09-20 2117.450 33 Mocha Excellent
2025-09-21 3021.659 90 Latte Good
2025-09-22 3329.366 37 Americano Excellent
2025-09-23 2288.079 88 Americano Fair
2025-09-24 2204.085 25 Mocha Good
2025-09-25 3257.974 21 Espresso Fair
2025-09-26 3986.743 45 Espresso Excellent
2025-09-27 2030.136 63 Latte Fair
2025-09-28 2666.939 24 Americano Fair
2025-09-29 3255.205 43 Mocha Good
2025-09-30 2359.553 87 Mocha Good
# 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. :1547 Min. :20.00 Length:30 Poor :6
1st Qu.:2025-09-08 1st Qu.:2129 1st Qu.:34.00 Class :character Fair :8
Median :2025-09-15 Median :2472 Median :49.00 Mode :character Good :8
Mean :2025-09-15 Mean :2579 Mean :56.33 NA Very Good:2
3rd Qu.:2025-09-22 3rd Qu.:3017 3rd Qu.:83.50 NA Excellent:6
Max. :2025-09-30 Max. :3987 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 7
Cappuccino 4
Espresso 7
Latte 5
Mocha 7
kable(satisfaction_freq, caption = "Frekuensi Kepuasan Pelanggan (Ordinal)")
Frekuensi Kepuasan Pelanggan (Ordinal)
Var1 Freq
Poor 6
Fair 8
Good 8
Very Good 2
Excellent 6
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAzIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6IA0KLSAiTmF5Y2hpbGxhIEFkZWxpYSBaYWhyYWgiDQotICJLaGFmaXphdHVuIE5pc2EiDQotICJBbmdlbGlxdWUgS2l5b3NoaSBMYWtlaXNoYSBCLlUiDQotICJWZXJvbmljYSBMRiBYYXZpZXIiDQotICJOYWtlaXNoYSBBdWxpYSBaYWhyYSIgICAgIyBSZXBsYWNlIHdpdGggeW91ciBmdWxsIG5hbWUNCmRhdGU6ICAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiICMgQXV0byBkaXNwbGF5cyB0aGUgY3VycmVudCBkYXRlDQpvdXRwdXQ6ICAgICAgICAgICAgICAgICAgICAgICAgICMgT3V0cHV0IHNlY3Rpb24gZGVmaW5lcyB0aGUgZm9ybWF0IGFuZCBsYXlvdXQgDQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOiAgICAgICMgaHR0cHM6Ly9naXRodWIuY29tL2p1YmEvcm1kZm9ybWF0cw0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlICAgICAgICAjIEVtYmVkcyBhbGwgcmVzb3VyY2VzIChDU1MsIEpTLCBpbWFnZXMpIA0KICAgIHRodW1ibmFpbHM6IHRydWUgICAgICAgICAgICAjIERpc3BsYXlzIGltYWdlIHRodW1ibmFpbHMgaW4gdGhlIGRvYw0KICAgIGxpZ2h0Ym94OiB0cnVlICAgICAgICAgICAgICAjIEVuYWJsZXMgY2xpY2sgdG8gZW5sYXJnZSBpbWFnZXMNCiAgICBnYWxsZXJ5OiB0cnVlICAgICAgICAgICAgICAgIyBHcm91cHMgaW1hZ2VzIGludG8gYW4gaW50ZXJhY3RpdmUgZ2FsbGVyeQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZSAgICAgICAjIEF1dG9tYXRpY2FsbHkgbnVtYmVycyBhbGwgc2VjdGlvbnMNCiAgICBsaWJfZGlyOiBsaWJzICAgICAgICAgICAgICAgIyBEaXJlY3Rvcnkgd2hlcmUgSmF2YVNjcmlwdC9DU1MgbGlicmFyaWVzDQogICAgZGZfcHJpbnQ6ICJwYWdlZCIgICAgICAgICAgICMgRGlzcGxheXMgZGF0YSBmcmFtZXMgYXMgaW50ZXJhY3RpdmUgcGFnZWQgDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyIgICAgICAgICMgQWxsb3dzIGZvbGRpbmcvdW5mb2xkaW5nIFIgY29kZSBibG9ja3MgDQogICAgY29kZV9kb3dubG9hZDogeWVzICAgICAgICAgICMgQWRkcyBhIGJ1dHRvbiB0byBkb3dubG9hZCBhbGwgUiBjb2RlDQotLS0NCg0KDQo8aW1nIGlkPSJGb3RvIiBzcmM9IkM6L1VzZXJzL25heWNoL09uZURyaXZlL0Rlc2t0b3AvdHVnYXMgc3RhdGlza2EvZm90byBrZWxvbXBva2suanBnP3Jhdz10cnVlIiBhbHQ9IkxvZ28iIHN0eWxlPSJ3aWR0aDoyMDBweDsgZGlzcGxheTogYmxvY2s7IG1hcmdpbjphdXRvOyI+DQoNCi0tLQ0KDQojIyBFeGVyY2lzZSAxDQoNClRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3Mgc2FtcGxlIGluZm9ybWF0aW9uIGZvciB0aHJlZSBzdHVkZW50cy4gRWFjaCBvYnNlcnZhdGlvbiByZXByZXNlbnRzIGEgc2luZ2xlIHN0dWRlbnQgYW5kIGluY2x1ZGVzIGRldGFpbHMgc3VjaCBhcyB0aGVpciB1bmlxdWUgc3R1ZGVudCBJRCwgbmFtZSwgYWdlLCB0b3RhbCBjcmVkaXRzIGNvbXBsZXRlZCwgbWFqb3IgZmllbGQgb2Ygc3R1ZHksIGFuZCB5ZWFyIGxldmVsLiAgDQoNClRoaXMgZGF0YXNldCBkZW1vbnN0cmF0ZXMgYSBtaXh0dXJlIG9mIHZhcmlhYmxlIHR5cGVzOiAgDQoNCi0gKipOb21pbmFsOioqIFN0dWRlbnRJRCwgTmFtZSwgTWFqb3IgIA0KLSAqKk51bWVyaWM6KiogQWdlIChjb250aW51b3VzKSwgQ3JlZGl0c0NvbXBsZXRlZCAoZGlzY3JldGUpICANCi0gKipPcmRpbmFsOioqIFllYXJMZXZlbCAoRnJlc2htYW4g4oaSIFNlbmlvcikgIA0KDQp8IFN0dWRlbnRJRCB8IE5hbWUgICB8IEFnZSB8IENyZWRpdHNDb21wbGV0ZWQgfCBNYWpvciAgICAgICAgICAgIHwgWWVhckxldmVsIHwNCnwtLS0tLS0tLS0tLXwtLS0tLS0tLXwtLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLXwNCnwgUzAwMSAgICAgIHwgQWxpY2UgIHwgMjAgIHwgNDUgICAgICAgICAgICAgIHwgRGF0YSBTYWlucyAgICAgIHwgU29waG9tb3JlIHwNCnwgUzAwMiAgICAgIHwgQnVkaSAgIHwgMjEgIHwgNjAgICAgICAgICAgICAgIHwgTWF0aGVtYXRpY3MgICAgIHwgSnVuaW9yICAgIHwNCnwgUzAwMyAgICAgIHwgQ2l0cmEgIHwgMTkgIHwgMzAgICAgICAgICAgICAgIHwgU3RhdGlzdGljcyAgICAgIHwgRnJlc2htYW4gIHwNCg0KYGBge3J9DQojIDEuIENyZWF0ZSB2ZWN0b3JzIGZvciBlYWNoIHZhcmlhYmxlDQpTdHVkZW50SUQgPC0gYygiUzAwMSIsICJTMDAyIiwgIlMwMDMiKSAgICAgICAjIE5vbWluYWwgLyBJRA0KTmFtZSA8LSBjKCJBbGljZSIsICJCdWRpIiwgIkNpdHJhIikgICAgICAgICAgIyBOb21pbmFsIC8gTmFtZQ0KQWdlIDwtIGMoMjAsIDIxLCAxOSkgICAgICAgICAgICAgICAgICAgICAgICAgIyBOdW1lcmljIC8gQ29udGludW91cw0KQ3JlZGl0c0NvbXBsZXRlZCA8LSBjKDQ1LCA2MCwgMzApICAgICAgICAgICAgIyBOdW1lcmljIC8gRGlzY3JldGUNCg0KIyBOb21pbmFsDQpNYWpvciA8LSBjKCJEYXRhIFNhaW5zIiwgIk1hdGhlbWF0aWNzIiwgIlN0YXRpc3RpY3MiKSAgDQoNCiMgT3JkaW5hbA0KWWVhckxldmVsIDwtIGZhY3RvcihjKCJTb3Bob21vcmUiLCAiSnVuaW9yIiwgIkZyZXNobWFuIiksDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkZyZXNobWFuIiwiU29waG9tb3JlIiwiSnVuaW9yIiwiU2VuaW9yIiksDQogICAgICAgICAgICAgICAgICAgIG9yZGVyZWQgPSBUUlVFKSAgICAgICAgICANCg0KIyAyLiBDb21iaW5lIGFsbCB2ZWN0b3JzIGludG8gYSBkYXRhIGZyYW1lDQpzdHVkZW50cyA8LSBkYXRhLmZyYW1lKA0KICBTdHVkZW50SUQsIE5hbWUsIEFnZSwgQ3JlZGl0c0NvbXBsZXRlZCwgTWFqb3IsIFllYXJMZXZlbCwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgMy4gRGlzcGxheSB0aGUgZGF0YSBmcmFtZQ0KcHJpbnQoc3R1ZGVudHMpDQpgYGANCg0KDQojIyBFeGVyY2lzZSAyDQoNCioqSWRlbnRpZnkgRGF0YSBUeXBlczoqKiBEZXRlcm1pbmUgdGhlIHR5cGUgb2YgZGF0YSBmb3IgZWFjaCBvZiB0aGUgZm9sbG93aW5nIHZhcmlhYmxlczoNCg0KYGBge3J9DQojIEluc3RhbGwga25pdHIgcGFja2FnZSBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCiMgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KbGlicmFyeShrbml0cikNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBEYXRhIFR5cGVzDQp2YXJpYWJsZXNfaW5mbyA8LSBkYXRhLmZyYW1lKA0KICBObyA9IDE6NSwNCiAgVmFyaWFibGUgPSBjKA0KICAgICJOdW1iZXIgb2YgdmVoaWNsZXMgcGFzc2luZyB0aHJvdWdoIHRoZSB0b2xsIHJvYWQgZWFjaCBkYXkiLA0KICAgICJTdHVkZW50IGhlaWdodCBpbiBjbSIsDQogICAgIkVtcGxveWVlIGdlbmRlciAoTWFsZSAvIEZlbWFsZSkiLA0KICAgICJDdXN0b21lciBzYXRpc2ZhY3Rpb24gbGV2ZWw6IExvdywgTWVkaXVtLCBIaWdoIiwNCiAgICAiUmVzcG9uZGVudCdzIGZhdm9yaXRlIGNvbG9yOiBSZWQsIEJsdWUsIEdyZWVuIg0KICApLA0KICBEYXRhVHlwZSA9IGMoDQogICAgIk51bWVyaWMiLA0KICAgICJOdW1lcmljIiwNCiAgICAiQ2F0ZWdvcmljYWwiLA0KICAgICJDYXRlZ29yaWNhbCIsDQogICAgIkNhdGVnb3JpY2FsIg0KICApLA0KICBTdWJ0eXBlID0gYygNCiAgICAiRGlzY3JldGUiLA0KICAgICJDb250aW51b3VzIiwNCiAgICAiTm9taW5hbCIsDQogICAgIk9yZGluYWwiLA0KICAgICJOb21pbmFsIg0KICApLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lIGFzIGEgbmVhdCB0YWJsZQ0Ka2FibGUodmFyaWFibGVzX2luZm8sIA0KICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBWYXJpYWJsZXMgYW5kIERhdGEgVHlwZXMiKQ0KYGBgDQotLS0NCg0KIyMgRXhlcmNpc2UgMw0KDQoqKkNsYXNzaWZ5IERhdGEgU291cmNlczoqKiBEZXRlcm1pbmUgd2hldGhlciB0aGUgZm9sbG93aW5nIGRhdGEgY29tZXMgZnJvbSAqKmludGVybmFsKiogb3IgKipleHRlcm5hbCBzb3VyY2VzKiosIGFuZCB3aGV0aGVyIGl0IGlzICoqc3RydWN0dXJlZCoqIG9yICoqdW5zdHJ1Y3R1cmVkKio6DQoNCmBgYHtyfQ0KIyBJbnN0YWxsIERUIHBhY2thZ2UgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkDQojIGluc3RhbGwucGFja2FnZXMoIkRUIikNCmxpYnJhcnkoRFQpDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgZGF0YSBzb3VyY2VzIA0KZGF0YV9zb3VyY2VzIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMTo0LA0KICBEYXRhU291cmNlID0gYygNCiAgICAiRGFpbHkgc2FsZXMgdHJhbnNhY3Rpb24gZGF0YSBvZiB0aGUgY29tcGFueSIsDQogICAgIldlYXRoZXIgcmVwb3J0cyBmcm9tIEJNS0ciLA0KICAgICJQcm9kdWN0IHJldmlld3Mgb24gc29jaWFsIG1lZGlhIiwNCiAgICAiV2FyZWhvdXNlIGludmVudG9yeSByZXBvcnRzIg0KICApLA0KICBJbnRlcm5hbF9FeHRlcm5hbCA9IGMoDQogICAgIkludGVybmFsIiwNCiAgICAiRXh0ZXJuYWwiLA0KICAgICJFeHRlcm5hbCIsDQogICAgIkludGVybmFsIg0KICApLA0KICBTdHJ1Y3R1cmVkX1Vuc3RydWN0dXJlZCA9IGMoDQogICAgIlN0cnVjdHVyZWQiLA0KICAgICJTdHJ1Y3R1cmVkIiwNCiAgICAiVW5zdHJ1Y3R1cmVkIiwNCiAgICAiU3RydWN0dXJlZCINCiAgKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgRGlzcGxheSB0aGUgZGF0YSBmcmFtZSBhcyBhIG5lYXQgdGFibGUNCmRhdGF0YWJsZShkYXRhX3NvdXJjZXMsIA0KICAgICAgICAgIGNhcHRpb24gPSAiVGFibGUgb2YgRGF0YSBTb3VyY2VzIiwNCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFKSAjIGhpZGVzIHRoZSBpbmRleCBjb2x1bW4NCmBgYA0KDQotLS0NCg0KIyMgRXhlcmNpc2UgNA0KDQoqKkRhdGFzZXQgU3RydWN0dXJlOioqIENvbnNpZGVyIHRoZSBmb2xsb3dpbmcgdHJhbnNhY3Rpb24gdGFibGU6DQoNCnwgRGF0ZSAgICAgICB8IFF0eSB8IFByaWNlIHwgUHJvZHVjdCAgfCBDdXN0b21lclRpZXIgfA0KfC0tLS0tLS0tLS0tLXwtLS0tLXwtLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS18DQp8IDIwMjUtMTAtMDEgfCAyICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wMSB8IDUgICB8IDIwICAgIHwgTW91c2UgICAgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAyIHwgMSAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IExvdyAgICAgICAgICB8DQp8IDIwMjUtMTAtMDIgfCAzICAgfCAzMCAgICB8IEtleWJvYXJkIHwgTWVkaXVtICAgICAgIHwNCnwgMjAyNS0xMC0wMyB8IDQgICB8IDUwICAgIHwgTW91c2UgICAgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAzIHwgMiAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDQgfCA2ICAgfCAyNSAgICB8IEtleWJvYXJkIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wNCB8IDEgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTA1IHwgMyAgIHwgNDAgICAgfCBNb3VzZSAgICB8IExvdyAgICAgICAgICB8DQp8IDIwMjUtMTAtMDUgfCA1ICAgfCAxMCAgICB8IEtleWJvYXJkIHwgTWVkaXVtICAgICAgIHwNCg0KDQoqKllvdXIgQXNzaWdubWVudCBJbnN0cnVjdGlvbnM6KiogQ3JlYXRpbmcgYSBUcmFuc2FjdGlvbnMgVGFibGUgYWJvdmUgaW4gUg0KDQoxLiAqKkNyZWF0ZSBhIGRhdGEgZnJhbWUqKiBpbiBSIGNhbGxlZCBgdHJhbnNhY3Rpb25zYCBjb250YWluaW5nIHRoZSBkYXRhIGFib3ZlLg0KDQoyLiBJZGVudGlmeSB3aGljaCB2YXJpYWJsZXMgYXJlIG51bWVyaWMgYW5kIHdoaWNoIGFyZSBjYXRlZ29yaWNhbA0KDQozLiAqKkNhbGN1bGF0ZSB0b3RhbCByZXZlbnVlKiogZm9yIGVhY2ggdHJhbnNhY3Rpb24gYnkgbXVsdGlwbHlpbmcgYFF0eSDDlyBQcmljZWAgYW5kIGFkZCBpdCBhcyBhIG5ldyBjb2x1bW4gYFRvdGFsYC4NCg0KNC4gKipDb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljcyoqOg0KICAgLSBUb3RhbCBxdWFudGl0eSBzb2xkIGZvciBlYWNoIHByb2R1Y3QNCiAgIC0gVG90YWwgcmV2ZW51ZSBwZXIgcHJvZHVjdA0KICAgLSBBdmVyYWdlIHByaWNlIHBlciBwcm9kdWN0DQoNCjUuICoqVmlzdWFsaXplIHRoZSBkYXRhKio6DQogICAtIENyZWF0ZSBhICoqYmFycGxvdCoqIHNob3dpbmcgdG90YWwgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdC4NCiAgIC0gQ3JlYXRlIGEgKipwaWUgY2hhcnQqKiBzaG93aW5nIHRoZSBwcm9wb3J0aW9uIG9mIHRvdGFsIHJldmVudWUgcGVyIGN1c3RvbWVyIHRpZXIuDQoNCjYuICoqT3B0aW9uYWwgQ2hhbGxlbmdlKio6DQogICAtIEZpbmQgd2hpY2ggKipkYXRlKiogaGFkIHRoZSBoaWdoZXN0IHRvdGFsIHJldmVudWUuDQogICAtIENyZWF0ZSBhICoqc3RhY2tlZCBiYXIgY2hhcnQqKiBzaG93aW5nIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QgYnkgY3VzdG9tZXIgdGllci4NCg0KKipIaW50czoqKiBVc2UgYGRhdGEuZnJhbWUoKWAsIGBhZ2dyZWdhdGUoKWAsIGBiYXJwbG90KClgLCBgcGllKClgLCBhbmQgYmFzaWMgYXJpdGhtZXRpYyBvcGVyYXRpb25zIGluIFIuDQoNCmBgYHtyfQ0KIyBJbnN0YWxsIGtuaXRyIHBhY2thZ2UgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkDQojIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCmxpYnJhcnkoa25pdHIpDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgVHJhbnNhY3Rpb25zDQpEYXRlID0gYyAoDQogICIyMDI1LTEwLTAxIiwgIA0KICAiMjAyNS0xMC0wMSIsIA0KICAiMjAyNS0xMC0wMiIsIA0KICAiMjAyNS0xMC0wMiIsIA0KICAiMjAyNS0xMC0wMyIsIA0KICAiMjAyNS0xMC0wMyIsIA0KICAiMjAyNS0xMC0wNCIsIA0KICAiMjAyNS0xMC0wNCIsIA0KICAiMjAyNS0xMC0wNSIsIA0KICAiMjAyNS0xMC0wNSINCiAgKSAgICAgICAgICAgICAgIyBOdW1lcmljIC8gRGlzY3JldGUNClF0eSA9IGMgKDIsIDUsIDEsIDMsIDQsIDIsIDYsIDEsIDMsIDUpICAgIyBOdW1lcmljIC8gRGlzY3JldGUNClByaWNlID0gYyAoMTAwMCwgMjAsIDEwMDAsIDMwLCA1MCwgMTAwMCwgMjUsIDEwMDAsIDQwLCAxMCkgICAjIE51bWVyaWMgLyBEaXNjcmV0ZQ0KDQojIE5vbWluYWwNClByb2R1Y3QgPSBjICgNCiAgIkxhcHRvcCIsDQogICJNb3VzZSIsDQogICJMYXB0b3AiLA0KICAiS2V5Ym9hcmQiLA0KICAiTW91c2UiLA0KICAiTGFwdG9wIiwNCiAgIktleWJvYXJkIiwNCiAgIkxhcHRvcCIsDQogICJNb3VzZSIsDQogICJLZXlib2FyZCINCiAgKSAgICAgICAgICAgIyBDYXRlZ29yaWNhbCAvIE5vbWluYWwNCg0KIyBPcmRpbmFsDQpDdXN0b21lclRpZXIgPSBmYWN0b3IoYygNCiAgIkhpZ2giLA0KICAiTWVkaXVtIiwNCiAgIkxvdyIsDQogICJNZWRpdW0iLA0KICAiTWVkaXVtIiwNCiAgIkhpZ2giLA0KICAiTG93IiwNCiAgIkhpZ2giLA0KICAiTG93IiwNCiAgIk1lZGl1bSINCiAgKSwNCmxldmVscyA9IGMoIkxvdyIsIk1lZGl1bSIsIkhpZ2giKSwNCm9yZGVyZWQgPSBUUlVFKSANCg0KIyAyLiBDb21iaW5lIGFsbCB2ZWN0b3JzIGludG8gYSBkYXRhIGZyYW1lDQp0cmFuc2FjdGlvbnMgPSAgZGF0YS5mcmFtZSAoRGF0ZSwgUXR5LCBQcmljZSwgUHJvZHVjdCwgQ3VzdG9tZXJUaWVyLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCiMgMy4gRGlzcGxheSB0aGUgZGF0YSBmcmFtZQ0KbGlicmFyeShrbml0cikNCmthYmxlKHRyYW5zYWN0aW9ucykNCg0KYGBgDQoNCmBgYHtyfQ0KIyAyLiBJZGVudGlmeSB2YXJpYWJsZSB0eXBlcw0KbGlicmFyeShrbml0cikNCnZhcmlhYmxlX3R5cGVzIDwtIGRhdGEuZnJhbWUoDQogIFZhcmlhYmxlID0gYygNCiAgICAiRGF0ZSIsDQogICAgIlF0eSIsDQogICAgIlByaWNlIiwNCiAgICAiUHJvZHVjdCIsDQogICAgIkN1c3RvbWVyVGllciINCiAgICApLA0KICBUeXBlID0gYygNCiAgICAiTnVtZXJpYyAoRGlzY3JldGUpIiwNCiAgICAiTnVtZXJpYyAoRGlzY3JldGUpIiwNCiAgICAiTnVtZXJpYyAoRGlzY3JldGUpIiwNCiAgICAiQ2F0ZWdvcmljYWwgKE5vbWluYWwpIiwNCiAgICAiQ2F0ZWdvcmljYWwgKE9yZGluYWwpIg0KICAgICkNCikNCg0KIyBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lDQprYWJsZSh2YXJpYWJsZV90eXBlcywgY2FwdGlvbiA9ICJWYXJpYWJsZSBUeXBlcyBpbiBUcmFuc2FjdGlvbnMgRGF0YSIpDQoNCmBgYA0KDQpgYGB7cn0NCiMgMy4gQ2FsY3VsYXRlIHRvdGFsIHJldmVudWUNCnRyYW5zYWN0aW9ucyR0b3RhbCA9IHRyYW5zYWN0aW9ucyRRdHkgKiB0cmFuc2FjdGlvbnMkUHJpY2UNCmthYmxlKHRyYW5zYWN0aW9ucykNCg0KYGBgDQoNCmBgYHtyfQ0KIyA0LiBDb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljDQoNCiMgYS4gVG90YWwgcXVhbnRpdHkgc29sZCBmb3IgZWFjaCBwcm9kdWN0DQp0b3RhbF9RdHkgPSBhZ2dyZWdhdGUoUXR5IH4gUHJvZHVjdCwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKQ0Ka2FibGUodG90YWxfUXR5LCBjYXB0aW9uID0gIlRvdGFsIFF1YW50aXR5IFNvbGQgcGVyIFByb2R1Y3QiKQ0KDQojIGIuIHRvdGFsIHJldmVudWUgcGVyIHByb2R1Y3QNCnRvdGFsX3JldmVudWUgPSBhZ2dyZWdhdGUodG90YWwgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQprYWJsZSh0b3RhbF9yZXZlbnVlLCBjYXB0aW9uID0gIlRvdGFsIFJldmVudWUgcGVyIFByb2R1Y3QiKQ0KDQojIGMuIEF2ZXJhZ2UgcHJpY2UgcGVyIHByb2R1Y3QNCmF2Z19wcmljZSA9IGFnZ3JlZ2F0ZShQcmljZSB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIG1lYW4pDQprYWJsZShhdmdfcHJpY2UsIGNhcHRpb24gPSAiQXZlcmFnZSBQcmljZSBwZXIgUHJvZHVjdCIpDQoNCmBgYA0KDQpgYGB7cn0NCiMgNS4gVmlzdWFsaXplIHRoZSBkYXRhDQoNCiMgYS4gYmFycGxvdCBzaG93aW5nIHRvdGFsIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QNCnRvdGFsX3F0eSA9IHRhcHBseSh0cmFuc2FjdGlvbnMkUXR5LCB0cmFuc2FjdGlvbnMkUHJvZHVjdCwgc3VtKQ0KYmFycGxvdCh0b3RhbF9xdHksDQogICAgICAgIG1haW4gPSAiVG90YWwgUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCIsDQogICAgICAgIHhsYWIgPSAiUHJvZHVjdCIsDQogICAgICAgIHlsYWIgPSAiVG90YWwgUXVhbnRpdHkiLA0KICAgICAgICBjb2wgPSAibGlnaHRibHVlIikNCg0KIyBiLiBwaWUgY2hhcnQgc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiB0b3RhbCByZXZlbnVlDQp0b3RhbF9yZXZlbnVlX3RpZXIgPSB0YXBwbHkodHJhbnNhY3Rpb25zJHRvdGFsLCB0cmFuc2FjdGlvbnMkQ3VzdG9tZXJUaWVyLCBzdW0pDQpwaWUodG90YWxfcmV2ZW51ZV90aWVyLA0KICAgIG1haW4gPSAiUHJvcG9ydGlvbiBvZiBUb3RhbCBSZXZlbnVlIHBlciBDdXN0b21lciBUaWVyIiwNCiAgICBjb2wgPSByYWluYm93KGxlbmd0aCh0b3RhbF9yZXZlbnVlX3RpZXIpKSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyA2LiBPcHRpb25hbCBjaGFsbGVuZ2UNCg0KIyBhLiBGaW5kIHdoaWNoIGRhdGUgaGFkIHRoZSBoaWdoZXN0IHRvdGFsIHJldmVudWUNCnRvdGFsX3JldmVudWVfZGF0ZSA8LSBhZ2dyZWdhdGUodG90YWwgfiBEYXRlLCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQp0b3RhbF9yZXZlbnVlX2RhdGVbd2hpY2gubWF4KHRvdGFsX3JldmVudWVfZGF0ZSR0b3RhbCksIF0NCg0KDQojIGIuIHN0YWNrZWQgYmFyIGNoYXJ0IHNob3dpbmcgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyDQpxdHlfdGFibGUgPSB4dGFicyhRdHkgfiBQcm9kdWN0ICsgQ3VzdG9tZXJUaWVyLCBkYXRhID0gdHJhbnNhY3Rpb25zKQ0KYmFycGxvdChxdHlfdGFibGUsDQogICAgICAgIG1haW4gPSAiUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCBieSBDdXN0b21lciBUaWVyIiwNCiAgICAgICAgeGxhYiA9ICJQcm9kdWN0IiwNCiAgICAgICAgeWxhYiA9ICJRdWFudGl0eSIsDQogICAgICAgIGNvbCA9IGMoImxpZ2h0Ymx1ZSIsICJsaWdodGdyZWVuIiwgInBpbmsiKSkNCiAgICAgIA0KDQpgYGANCg0KIyMgRXhlcmNpc2UgNQ0KDQoqKkNyZWF0ZSBZb3VyIE93biBEYXRhIEZyYW1lOioqDQoNCioqT2JqZWN0aXZlOioqIENyZWF0ZSBhIGRhdGEgZnJhbWUgaW4gUiB3aXRoICoqMzAgcm93cyoqIGNvbnRhaW5pbmcgYSBtaXggb2YgZGF0YSB0eXBlczogY29udGludW91cywgZGlzY3JldGUsIG5vbWluYWwsIGFuZCBvcmRpbmFsLiAgDQoNCiMjIyBJbnN0cnVjdGlvbnMNCg0KMS4gKipPcGVuIFJTdHVkaW8qKiBvciB0aGUgUiBjb25zb2xlLiAgDQoNCjIuICoqQ3JlYXRlIGEgdmVjdG9yIGZvciBlYWNoIGNvbHVtbioqIGluIHlvdXIgZGF0YSBmcmFtZTogIA0KDQogICAtICoqRGF0ZSoqOiAzMCBkYXRlcyAoY2FuIGJlIHNlcXVlbnRpYWwgb3IgcmFuZG9tIHdpdGhpbiBhIG1vbnRoL3llYXIpICANCiAgIC0gKipDb250aW51b3VzKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIHRha2UgZGVjaW1hbCB2YWx1ZXMgKGUuZy4sIGhlaWdodCwgd2VpZ2h0LCB0ZW1wZXJhdHVyZSkgIA0KICAgLSAqKkRpc2NyZXRlKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIG9ubHkgdGFrZSB3aG9sZSBudW1iZXJzIChlLmcuLCBudW1iZXIgb2YgaXRlbXMsIG51bWJlciBvZiB2ZWhpY2xlcykgIA0KICAgLSAqKk5vbWluYWwqKjogY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggKipubyBvcmRlcioqIChlLmcuLCBjb2xvciwgZ2VuZGVyLCBjaXR5KSAgDQogICAtICoqT3JkaW5hbCoqOiBjYXRlZ29yaWNhbCB2YWx1ZXMgd2l0aCBhICoqZGVmaW5lZCBvcmRlcioqIChlLmcuLCBMb3csIE1lZGl1bSwgSGlnaDsgQmVnaW5uZXIsIEludGVybWVkaWF0ZSwgRXhwZXJ0KSAgDQoNCjMuICoqQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZSoqIGNhbGxlZCBgbXlfZGF0YWAuICANCg0KNC4gKipDaGVjayB5b3VyIGRhdGEgZnJhbWUqKiB1c2luZyBgaGVhZCgpYCBvciBgVmlldygpYCB0byBlbnN1cmUgaXQgaGFzICoqMzAgcm93cyoqIGFuZCB0aGUgY29sdW1ucyBhcmUgY29ycmVjdC4gIA0KDQo1LiAqKk9wdGlvbmFsIHRhc2tzKio6ICANCiAgIC0gU3VtbWFyaXplIGVhY2ggY29sdW1uIHVzaW5nIGBzdW1tYXJ5KClgICANCiAgIC0gQ291bnQgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIGNhdGVnb3J5IGZvciAqKk5vbWluYWwqKiBhbmQgKipPcmRpbmFsKiogY29sdW1ucyB1c2luZyBgdGFibGUoKWAgIA0KDQojIyMgSGludHMNCg0KLSBVc2UgYHNlcS5EYXRlKClgIG9yIGBhcy5EYXRlKClgIHRvIGdlbmVyYXRlIHRoZSBEYXRlIGNvbHVtbi4gIA0KLSBVc2UgYHJ1bmlmKClgIG9yIGBybm9ybSgpYCBmb3IgY29udGludW91cyBudW1lcmljIGRhdGEuICANCi0gVXNlIGBzYW1wbGUoKWAgZm9yIGRpc2NyZXRlLCBub21pbmFsLCBhbmQgb3JkaW5hbCBkYXRhLiAgDQotIEVuc3VyZSB0aGUgKipvcmRpbmFsIHZlY3RvcioqIGlzIGNyZWF0ZWQgd2l0aCBgZmFjdG9yKC4uLiwgbGV2ZWxzID0gYygiTG93IiwiTWVkaXVtIiwiSGlnaCIpLCBvcmRlcmVkID0gVFJVRSlgIChvciBzaW1pbGFyKS4gDQoNCmBgYHtyfQ0KIyAxLiBDb2ZmZWUgU2hvcCBEYXRhDQoNCiMgRGF0ZSAoMzAgaGFyaSBkaSBidWxhbiBTZXB0ZW1iZXIpDQpEYXRlID0gc2VxKGFzLkRhdGUoIjIwMjUtMDktMDEiKSwgYXMuRGF0ZSgiMjAyNS0wOS0zMCIpLCBieSA9ICJkYXkiKQ0KDQojIENvbnRpbnVvdXM6IGp1bWxhaCBtbCBrb3BpIHRlcmp1YWwgcGVyIGhhcmkgKGFjYWsgZGFyaSAxNTAw4oCTNDAwMCBtbCkNCkNvZmZlZV9tbCA9IHJ1bmlmKDMwLCBtaW4gPSAxNTAwLCBtYXggPSA0MDAwKQ0KDQojIERpc2NyZXRlOiBqdW1sYWggY2FuZ2tpciBrb3BpIHRlcmp1YWwgcGVyIGhhcmkgKGFjYWsgMjDigJMxMDApDQpDdXBzX1NvbGQgPSBzYW1wbGUoMjA6MTAwLCAzMCwgcmVwbGFjZSA9IFRSVUUpDQoNCiMgTm9taW5hbDogamVuaXMgbWludW1hbiBrb3BpDQpEcmlua19UeXBlID0gc2FtcGxlKGMoIkFtZXJpY2FubyIsICJDYXBwdWNjaW5vIiwgIkxhdHRlIiwgIkVzcHJlc3NvIiwgIk1vY2hhIiksIDMwLCByZXBsYWNlID0gVFJVRSkNCg0KIyBPcmRpbmFsOiB0aW5na2F0IGtlcHVhc2FuIHBlbGFuZ2dhbg0KQ3VzdG9tZXJfU2F0aXNmYWN0aW9uID0gZmFjdG9yKA0KICBzYW1wbGUoYygiUG9vciIsICJGYWlyIiwgIkdvb2QiLCAiVmVyeSBHb29kIiwgIkV4Y2VsbGVudCIpLCAzMCwgcmVwbGFjZSA9IFRSVUUpLA0KICBsZXZlbHMgPSBjKCJQb29yIiwgIkZhaXIiLCAiR29vZCIsICJWZXJ5IEdvb2QiLCAiRXhjZWxsZW50IiksDQogIG9yZGVyZWQgPSBUUlVFKQ0KDQojIENvbWJpbmUgYWxsIHZlY3RvcnMgaW50byBhIGRhdGEgZnJhbWUNCm15X2RhdGEgPSBkYXRhLmZyYW1lKERhdGUsIENvZmZlZV9tbCwgQ3Vwc19Tb2xkLCBEcmlua19UeXBlLCBDdXN0b21lcl9TYXRpc2ZhY3Rpb24pDQprYWJsZShteV9kYXRhKQ0KDQojIFN1bW1hcnkgZGF0YSAob3BzaW9uYWwpDQpzdW1tYXJ5X2RhdGEgPSBzdW1tYXJ5KG15X2RhdGEpDQprYWJsZShzdW1tYXJ5X2RhdGEpDQoNCiMgRnJla3VlbnNpIEthdGVnb3JpIChub21pbmFsLCBvcmRpbmFsKQ0KbGlicmFyeShrbml0cikNCmRyaW5rX2ZyZXEgPSB0YWJsZShteV9kYXRhJERyaW5rX1R5cGUpDQpzYXRpc2ZhY3Rpb25fZnJlcSA9IHRhYmxlKG15X2RhdGEkQ3VzdG9tZXJfU2F0aXNmYWN0aW9uKQ0KDQprYWJsZShkcmlua19mcmVxLCBjYXB0aW9uID0gIkZyZWt1ZW5zaSBKZW5pcyBNaW51bWFuIChOb21pbmFsKSIpDQprYWJsZShzYXRpc2ZhY3Rpb25fZnJlcSwgY2FwdGlvbiA9ICJGcmVrdWVuc2kgS2VwdWFzYW4gUGVsYW5nZ2FuIChPcmRpbmFsKSIpDQoNCg0KDQoNCg0KDQoNCg0KDQo=