Data Exploration

Exercises ~ Week 2

Logo


1 Exercise 1

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

This dataset demonstrates a mixture of variable types:

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

# Nominal
Major <- c("Data Sains", "Mathematics", "Statistics")  

# 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(
    "Continous",
    "continous",
    "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 Continous
2 Student height in cm numeric continous
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.

library(DT)

#transaction
Date <- c("2025-10-01", "2025-10-01", "2025-10-02", "2025-10-02", "2025-10-03", 
          "2025-10-03", "2025-10-04", "2025-10-04", "2025-10-05", "2025-10-05")
Qty <- c(2, 5, 1, 3, 4, 2, 6, 1, 3, 5)
Price <- c(1000, 20, 1000, 30, 50, 1000, 25, 1000, 40, 10)
Product <- c("Laptop", "Mouse", "Laptop", "Keyboard", "Mouse", "Laptop", 
             "Keyboard", "Laptop", "Mouse", "Keyboard")
CustomerTier <- c("High", "Medium", "Low", "Medium", "Medium", "High", 
                  "Low", "High", "Low", "Medium")

# data frame 
transactions <- data.frame(Date, Qty, Price, Product, CustomerTier)

# Display the data frame 
print(transactions)
##          Date Qty Price  Product CustomerTier
## 1  2025-10-01   2  1000   Laptop         High
## 2  2025-10-01   5    20    Mouse       Medium
## 3  2025-10-02   1  1000   Laptop          Low
## 4  2025-10-02   3    30 Keyboard       Medium
## 5  2025-10-03   4    50    Mouse       Medium
## 6  2025-10-03   2  1000   Laptop         High
## 7  2025-10-04   6    25 Keyboard          Low
## 8  2025-10-04   1  1000   Laptop         High
## 9  2025-10-05   3    40    Mouse          Low
## 10 2025-10-05   5    10 Keyboard       Medium
# 3 Total Reveneu
transactions$total <- transactions$Qty * transactions$Price

# view the data frame 
print(transactions)
##          Date Qty Price  Product CustomerTier total
## 1  2025-10-01   2  1000   Laptop         High  2000
## 2  2025-10-01   5    20    Mouse       Medium   100
## 3  2025-10-02   1  1000   Laptop          Low  1000
## 4  2025-10-02   3    30 Keyboard       Medium    90
## 5  2025-10-03   4    50    Mouse       Medium   200
## 6  2025-10-03   2  1000   Laptop         High  2000
## 7  2025-10-04   6    25 Keyboard          Low   150
## 8  2025-10-04   1  1000   Laptop         High  1000
## 9  2025-10-05   3    40    Mouse          Low   120
## 10 2025-10-05   5    10 Keyboard       Medium    50
qty_summary <- aggregate(Qty ~ Product, data = transactions, sum) 
print(qty_summary)
##    Product Qty
## 1 Keyboard  14
## 2   Laptop   6
## 3    Mouse  12
total_summary <- aggregate(total ~ Product, data = transactions, sum) 
print(total_summary)
##    Product total
## 1 Keyboard   290
## 2   Laptop  6000
## 3    Mouse   420
Price_summary <- aggregate(Price ~ Product, data = transactions, mean)
print(Price_summary)
##    Product      Price
## 1 Keyboard   21.66667
## 2   Laptop 1000.00000
## 3    Mouse   36.66667
# Calculate total quantity per product
qty_per_product <- aggregate(Qty ~ Product, data = transactions, sum)

# Create a bar plot 
barplot (qty_per_product$Qty,
         names.arg = qty_per_product$Product, 
         col = "orange", 
         main = "Total Quantity Sold per Product",
         xlab = "Product", ylab = "Quantity Sold")

# Calculate total revenue per CustomerTier
revenue_tier <- aggregate(total ~ CustomerTier, data = transactions, sum) 

# create pie chart 
pie(revenue_tier$tota, 
    labels = revenue_tier$CustomerTier, 
    main = "Proportion of Total Revenue per Customer Tier",
    col = c("red", "orange", "pink"))

# Hitung total revenue per tanggal
revenue_per_date <- aggregate(total ~ Date, data = transactions, sum)

# Lihat hasilnya
print(revenue_per_date)
##         Date total
## 1 2025-10-01  2100
## 2 2025-10-02  1090
## 3 2025-10-03  2200
## 4 2025-10-04  1150
## 5 2025-10-05   170
# Cari tanggal dengan total revenue paling tingi menggunakan max
max_date <- revenue_per_date[which.max(revenue_per_date$total), ]

#lihat hasilnya
print(max_date)
##         Date total
## 3 2025-10-03  2200
library(ggplot2)

# Bikin stacked bar chart
ggplot(transactions, aes(x = reorder(Product, Qty), y = Qty, fill = CustomerTier)) +
  geom_bar(stat = "identity") +
  labs(title = "Quantity Sold per Product by Customer Tier",
       x = "Product",
       y = "Quantity Sold") +
  theme_minimal()

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).
library(DT)

# Data Financial Frame

# column 1: Transaction Date
Date <- seq.Date(from = as.Date("2025-10-01"), by = "day", length.out = 30)

# Column 2: Transaction value (Continuous) — In rupiah
TransactionValue <- c(
  1250000, 980000, 1500000, 2100000, 1850000, 750000, 2400000, 1300000, 1780000, 2220000,
  1950000, 1650000, 1420000, 2550000, 3100000, 2750000, 1980000, 880000, 1750000, 2200000,
  1900000, 2600000, 2450000, 1350000, 1500000, 900000, 1200000, 2750000, 3200000, 2100000
)

# Column 3: Number of items purchased (Discrete)
Items <- c(
  2, 1, 3, 5, 4, 2, 6, 3, 5, 4,
  2, 3, 1, 7, 8, 5, 3, 2, 4, 6,
  5, 7, 8, 3, 4, 1, 2, 7, 9, 5
)

# Column 4: Transaction type (Nominal)
TransactionType <- c(
  "Pembelian Tunai", "Transfer Bank", "Kartu Kredit", "Pembelian Tunai", "E-Wallet",
  "Transfer Bank", "Kartu Kredit", "E-Wallet", "Pembelian Tunai", "E-Wallet",
  "Kartu Kredit", "Pembelian Tunai", "Transfer Bank", "E-Wallet", "Kartu Kredit",
  "Pembelian Tunai", "E-Wallet", "Transfer Bank", "Kartu Kredit", "Pembelian Tunai",
  "E-Wallet", "Transfer Bank", "Kartu Kredit", "Pembelian Tunai", "E-Wallet",
  "Kartu Kredit", "Transfer Bank", "Pembelian Tunai", "E-Wallet", "Transfer Bank"
)

# Kolom 5: Customer Tier (Ordinal)
CustomerTier <- factor(
  c(
    "Sedang", "Rendah", "Sedang", "Tinggi", "Sedang", "Rendah", "Tinggi", "Sedang", "Tinggi", "Sedang",
    "Rendah", "Tinggi", "Sedang", "Tinggi", "Tinggi", "Sedang", "Rendah", "Sedang", "Tinggi", "Sedang",
    "Rendah", "Tinggi", "Tinggi", "Rendah", "Sedang", "Rendah", "Sedang", "Tinggi", "Tinggi", "Sedang"
  ),
  levels = c("Rendah", "Sedang", "Tinggi"),
  ordered = TRUE
)

# Combine into a data frame
data_financial <- data.frame(Date, TransactionValue, Items, TransactionType, CustomerTier)

# Display the data frame as a table
print(data_financial)
##          Date TransactionValue Items TransactionType CustomerTier
## 1  2025-10-01          1250000     2 Pembelian Tunai       Sedang
## 2  2025-10-02           980000     1   Transfer Bank       Rendah
## 3  2025-10-03          1500000     3    Kartu Kredit       Sedang
## 4  2025-10-04          2100000     5 Pembelian Tunai       Tinggi
## 5  2025-10-05          1850000     4        E-Wallet       Sedang
## 6  2025-10-06           750000     2   Transfer Bank       Rendah
## 7  2025-10-07          2400000     6    Kartu Kredit       Tinggi
## 8  2025-10-08          1300000     3        E-Wallet       Sedang
## 9  2025-10-09          1780000     5 Pembelian Tunai       Tinggi
## 10 2025-10-10          2220000     4        E-Wallet       Sedang
## 11 2025-10-11          1950000     2    Kartu Kredit       Rendah
## 12 2025-10-12          1650000     3 Pembelian Tunai       Tinggi
## 13 2025-10-13          1420000     1   Transfer Bank       Sedang
## 14 2025-10-14          2550000     7        E-Wallet       Tinggi
## 15 2025-10-15          3100000     8    Kartu Kredit       Tinggi
## 16 2025-10-16          2750000     5 Pembelian Tunai       Sedang
## 17 2025-10-17          1980000     3        E-Wallet       Rendah
## 18 2025-10-18           880000     2   Transfer Bank       Sedang
## 19 2025-10-19          1750000     4    Kartu Kredit       Tinggi
## 20 2025-10-20          2200000     6 Pembelian Tunai       Sedang
## 21 2025-10-21          1900000     5        E-Wallet       Rendah
## 22 2025-10-22          2600000     7   Transfer Bank       Tinggi
## 23 2025-10-23          2450000     8    Kartu Kredit       Tinggi
## 24 2025-10-24          1350000     3 Pembelian Tunai       Rendah
## 25 2025-10-25          1500000     4        E-Wallet       Sedang
## 26 2025-10-26           900000     1    Kartu Kredit       Rendah
## 27 2025-10-27          1200000     2   Transfer Bank       Sedang
## 28 2025-10-28          2750000     7 Pembelian Tunai       Tinggi
## 29 2025-10-29          3200000     9        E-Wallet       Tinggi
## 30 2025-10-30          2100000     5   Transfer Bank       Sedang
# Create a second table for variable type
variables_info <- data.frame(
  No = 1:4,
  variable = c(
    "Transaction Value",
    "Items",
    "Transaction Type",
    "Customer Tier"
),
  DataType = c(
      "Continuous",
      "Discrete",
      "Nominal",
      "Ordinal"
    ),
    stringsAsFactors = FALSE
  )

library(knitr)

kable(
  variables_info,
  caption = "Table of Variables and Data Types"
)
Table of Variables and Data Types
No variable DataType
1 Transaction Value Continuous
2 Items Discrete
3 Transaction Type Nominal
4 Customer Tier Ordinal
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAyIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6ICJrZWxvbXBvayAzIC0gTmFpZmFoIEVkcmlhIEFydGEoNTIyNTAwNTYpLCBGcml6enkgTGl0aG1lbnN5YWgoNTIyNTAwNjIpLCBMdWx1IE5hamxhIFNhbHNhYmlsYSg1MjI1MDA2OSksIE5haWxhIFN5YWhyYW5pIFB1dHJpKDUyMjUwMDcwKSwgTmkuIE1EIEF1cm9yYSBTZWthcm5pbmdydW0oNTIyNTAwNzIpIg0KZGF0ZTogICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCIgIyBBdXRvIGRpc3BsYXlzIHRoZSBjdXJyZW50IGRhdGUNCm91dHB1dDogICAgICAgICAgICAgICAgICAgICAgICAgIyBPdXRwdXQgc2VjdGlvbiBkZWZpbmVzIHRoZSBmb3JtYXQgYW5kIGxheW91dCANCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246ICAgICAgIyBodHRwczovL2dpdGh1Yi5jb20vanViYS9ybWRmb3JtYXRzDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUgICAgICAgICMgRW1iZWRzIGFsbCByZXNvdXJjZXMgKENTUywgSlMsIGltYWdlcykgDQogICAgdGh1bWJuYWlsczogdHJ1ZSAgICAgICAgICAgICMgRGlzcGxheXMgaW1hZ2UgdGh1bWJuYWlscyBpbiB0aGUgZG9jDQogICAgbGlnaHRib3g6IHRydWUgICAgICAgICAgICAgICMgRW5hYmxlcyBjbGljayB0byBlbmxhcmdlIGltYWdlcw0KICAgIGdhbGxlcnk6IHRydWUgICAgICAgICAgICAgICAjIEdyb3VwcyBpbWFnZXMgaW50byBhbiBpbnRlcmFjdGl2ZSBnYWxsZXJ5DQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlICAgICAgICMgQXV0b21hdGljYWxseSBudW1iZXJzIGFsbCBzZWN0aW9ucw0KICAgIGxpYl9kaXI6IGxpYnMgICAgICAgICAgICAgICAjIERpcmVjdG9yeSB3aGVyZSBKYXZhU2NyaXB0L0NTUyBsaWJyYXJpZXMNCiAgICBkZl9wcmludDogInBhZ2VkIiAgICAgICAgICAgIyBEaXNwbGF5cyBkYXRhIGZyYW1lcyBhcyBpbnRlcmFjdGl2ZSBwYWdlZCANCiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93IiAgICAgICAgIyBBbGxvd3MgZm9sZGluZy91bmZvbGRpbmcgUiBjb2RlIGJsb2NrcyANCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMgICAgICAgICAgIyBBZGRzIGEgYnV0dG9uIHRvIGRvd25sb2FkIGFsbCBSIGNvZGUNCi0tLQ0KDQoNCjxpbWcgaWQ9IkZvdG8iIHNyYz0iaHR0cHM6Ly9naXRodWIuY29tL2RzY2llbmNlbGFicy9pbWFnZXMvYmxvYi9tYXN0ZXIvTG9nb19Ec2NpZW5jZWxhYnNfdjEucG5nP3Jhdz10cnVlIiBhbHQ9IkxvZ28iIHN0eWxlPSJ3aWR0aDoyMDBweDsgZGlzcGxheTogYmxvY2s7IG1hcmdpbjogYXV0bzsiPg0KDQotLS0NCg0KIyMgRXhlcmNpc2UgMQ0KDQpUaGUgZm9sbG93aW5nIHRhYmxlIHNob3dzIHNhbXBsZSBpbmZvcm1hdGlvbiBmb3IgdGhyZWUgc3R1ZGVudHMuIEVhY2ggb2JzZXJ2YXRpb24gcmVwcmVzZW50cyBhIHNpbmdsZSBzdHVkZW50IGFuZCBpbmNsdWRlcyBkZXRhaWxzIHN1Y2ggYXMgdGhlaXIgdW5pcXVlIHN0dWRlbnQgSUQsIG5hbWUsIGFnZSwgdG90YWwgY3JlZGl0cyBjb21wbGV0ZWQsIG1ham9yIGZpZWxkIG9mIHN0dWR5LCBhbmQgeWVhciBsZXZlbC4gIA0KDQpUaGlzIGRhdGFzZXQgZGVtb25zdHJhdGVzIGEgbWl4dHVyZSBvZiB2YXJpYWJsZSB0eXBlczogIA0KDQotICoqTm9taW5hbDoqKiBTdHVkZW50SUQsIE5hbWUsIE1ham9yICANCi0gKipOdW1lcmljOioqIEFnZSAoY29udGludW91cyksIENyZWRpdHNDb21wbGV0ZWQgKGRpc2NyZXRlKSAgDQotICoqT3JkaW5hbDoqKiBZZWFyTGV2ZWwgKEZyZXNobWFuIOKGkiBTZW5pb3IpICANCg0KfCBTdHVkZW50SUQgfCBOYW1lICAgfCBBZ2UgfCBDcmVkaXRzQ29tcGxldGVkIHwgTWFqb3IgICAgICAgICAgICB8IFllYXJMZXZlbCB8DQp8LS0tLS0tLS0tLS18LS0tLS0tLS18LS0tLS18LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18DQp8IFMwMDEgICAgICB8IEFsaWNlICB8IDIwICB8IDQ1ICAgICAgICAgICAgICB8IERhdGEgU2FpbnMgICAgICB8IFNvcGhvbW9yZSB8DQp8IFMwMDIgICAgICB8IEJ1ZGkgICB8IDIxICB8IDYwICAgICAgICAgICAgICB8IE1hdGhlbWF0aWNzICAgICB8IEp1bmlvciAgICB8DQp8IFMwMDMgICAgICB8IENpdHJhICB8IDE5ICB8IDMwICAgICAgICAgICAgICB8IFN0YXRpc3RpY3MgICAgICB8IEZyZXNobWFuICB8DQoNCmBgYHtyfQ0KIyAxLiBDcmVhdGUgdmVjdG9ycyBmb3IgZWFjaCB2YXJpYWJsZQ0KU3R1ZGVudElEIDwtIGMoIlMwMDEiLCAiUzAwMiIsICJTMDAzIikgICAgICAgIyBOb21pbmFsIC8gSUQNCk5hbWUgPC0gYygiQWxpY2UiLCAiQnVkaSIsICJDaXRyYSIpICAgICAgICAgICMgTm9taW5hbCAvIE5hbWUNCkFnZSA8LSBjKDIwLCAyMSwgMTkpICAgICAgICAgICAgICAgICAgICAgICAgICMgTnVtZXJpYyAvIENvbnRpbnVvdXMNCkNyZWRpdHNDb21wbGV0ZWQgPC0gYyg0NSwgNjAsIDMwKSAgICAgICAgICAgICMgTnVtZXJpYyAvIERpc2NyZXRlDQoNCiMgTm9taW5hbA0KTWFqb3IgPC0gYygiRGF0YSBTYWlucyIsICJNYXRoZW1hdGljcyIsICJTdGF0aXN0aWNzIikgIA0KDQojIE9yZGluYWwNClllYXJMZXZlbCA8LSBmYWN0b3IoYygiU29waG9tb3JlIiwgIkp1bmlvciIsICJGcmVzaG1hbiIpLA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJGcmVzaG1hbiIsIlNvcGhvbW9yZSIsIkp1bmlvciIsIlNlbmlvciIpLA0KICAgICAgICAgICAgICAgICAgICBvcmRlcmVkID0gVFJVRSkgICAgICAgICAgDQoNCiMgMi4gQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZQ0Kc3R1ZGVudHMgPC0gZGF0YS5mcmFtZSgNCiAgU3R1ZGVudElELCBOYW1lLCBBZ2UsIENyZWRpdHNDb21wbGV0ZWQsIE1ham9yLCBZZWFyTGV2ZWwsDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIDMuIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCnByaW50KHN0dWRlbnRzKQ0KYGBgDQoNCg0KIyMgRXhlcmNpc2UgMg0KDQoqKklkZW50aWZ5IERhdGEgVHlwZXM6KiogRGV0ZXJtaW5lIHRoZSB0eXBlIG9mIGRhdGEgZm9yIGVhY2ggb2YgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6DQoNCmBgYHtyfQ0KIyBJbnN0YWxsIGtuaXRyIHBhY2thZ2UgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkDQojIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCmxpYnJhcnkoa25pdHIpDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgRGF0YSBUeXBlcw0KdmFyaWFibGVzX2luZm8gPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjUsDQogIFZhcmlhYmxlID0gYygNCiAgICAiTnVtYmVyIG9mIHZlaGljbGVzIHBhc3NpbmcgdGhyb3VnaCB0aGUgdG9sbCByb2FkIGVhY2ggZGF5IiwNCiAgICAiU3R1ZGVudCBoZWlnaHQgaW4gY20iLA0KICAgICJFbXBsb3llZSBnZW5kZXIgKE1hbGUgLyBGZW1hbGUpIiwNCiAgICAiQ3VzdG9tZXIgc2F0aXNmYWN0aW9uIGxldmVsOiBMb3csIE1lZGl1bSwgSGlnaCIsDQogICAgIlJlc3BvbmRlbnQncyBmYXZvcml0ZSBjb2xvcjogUmVkLCBCbHVlLCBHcmVlbiINCiAgKSwNCiAgRGF0YVR5cGUgPSBjKA0KICAgICJOdW1lcmljIiwNCiAgICAibnVtZXJpYyIsDQogICAgIkNhdGVnb3JpY2FsIiwNCiAgICAiQ2F0ZWdvcmljYWwiLA0KICAgICJDYXRlZ29yaWNhbCINCiAgKSwNCiAgU3VidHlwZSA9IGMoDQogICAgIkNvbnRpbm91cyIsDQogICAgImNvbnRpbm91cyIsDQogICAgIk5vbWluYWwiLA0KICAgICJPcmRpbmFsIiwNCiAgICAiTm9taW5hbCINCiAgKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgRGlzcGxheSB0aGUgZGF0YSBmcmFtZSBhcyBhIG5lYXQgdGFibGUNCmthYmxlKHZhcmlhYmxlc19pbmZvLCANCiAgICAgIGNhcHRpb24gPSAiVGFibGUgb2YgVmFyaWFibGVzIGFuZCBEYXRhIFR5cGVzIikNCmBgYA0KLS0tDQoNCiMjIEV4ZXJjaXNlIDMNCg0KKipDbGFzc2lmeSBEYXRhIFNvdXJjZXM6KiogRGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGZvbGxvd2luZyBkYXRhIGNvbWVzIGZyb20gKippbnRlcm5hbCoqIG9yICoqZXh0ZXJuYWwgc291cmNlcyoqLCBhbmQgd2hldGhlciBpdCBpcyAqKnN0cnVjdHVyZWQqKiBvciAqKnVuc3RydWN0dXJlZCoqOg0KDQpgYGB7cn0NCiMgSW5zdGFsbCBEVCBwYWNrYWdlIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZA0KIyBpbnN0YWxsLnBhY2thZ2VzKCJEVCIpDQpsaWJyYXJ5KERUKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIGRhdGEgc291cmNlcyANCmRhdGFfc291cmNlcyA8LSBkYXRhLmZyYW1lKA0KICBObyA9IDE6NCwNCiAgRGF0YVNvdXJjZSA9IGMoDQogICAgIkRhaWx5IHNhbGVzIHRyYW5zYWN0aW9uIGRhdGEgb2YgdGhlIGNvbXBhbnkiLA0KICAgICJXZWF0aGVyIHJlcG9ydHMgZnJvbSBCTUtHIiwNCiAgICAiUHJvZHVjdCByZXZpZXdzIG9uIHNvY2lhbCBtZWRpYSIsDQogICAgIldhcmVob3VzZSBpbnZlbnRvcnkgcmVwb3J0cyINCiAgKSwNCiAgSW50ZXJuYWxfRXh0ZXJuYWwgPSBjKA0KICAgICJJbnRlcm5hbCIsDQogICAgIkV4dGVybmFsIiwNCiAgICAiRXh0ZXJuYWwiLA0KICAgICJJbnRlcm5hbCINCiAgKSwNCiAgU3RydWN0dXJlZF9VbnN0cnVjdHVyZWQgPSBjKA0KICAgICJTdHJ1Y3R1cmVkIiwNCiAgICAiU3RydWN0dXJlZCIsDQogICAgIlVuc3RydWN0dXJlZCIsDQogICAgIlN0cnVjdHVyZWQiDQogICksDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUgYXMgYSBuZWF0IHRhYmxlDQpkYXRhdGFibGUoZGF0YV9zb3VyY2VzLCANCiAgICAgICAgICBjYXB0aW9uID0gIlRhYmxlIG9mIERhdGEgU291cmNlcyIsDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSkgIyBoaWRlcyB0aGUgaW5kZXggY29sdW1uDQpgYGANCg0KLS0tDQoNCiMjIEV4ZXJjaXNlIDQNCg0KKipEYXRhc2V0IFN0cnVjdHVyZToqKiBDb25zaWRlciB0aGUgZm9sbG93aW5nIHRyYW5zYWN0aW9uIHRhYmxlOg0KDQp8IERhdGUgICAgICAgfCBRdHkgfCBQcmljZSB8IFByb2R1Y3QgIHwgQ3VzdG9tZXJUaWVyIHwNCnwtLS0tLS0tLS0tLS18LS0tLS18LS0tLS0tLXwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfA0KfCAyMDI1LTEwLTAxIHwgMiAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDEgfCA1ICAgfCAyMCAgICB8IE1vdXNlICAgIHwgTWVkaXVtICAgICAgIHwNCnwgMjAyNS0xMC0wMiB8IDEgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTAyIHwgMyAgIHwgMzAgICAgfCBLZXlib2FyZCB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDMgfCA0ICAgfCA1MCAgICB8IE1vdXNlICAgIHwgTWVkaXVtICAgICAgIHwNCnwgMjAyNS0xMC0wMyB8IDIgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTA0IHwgNiAgIHwgMjUgICAgfCBLZXlib2FyZCB8IExvdyAgICAgICAgICB8DQp8IDIwMjUtMTAtMDQgfCAxICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wNSB8IDMgICB8IDQwICAgIHwgTW91c2UgICAgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTA1IHwgNSAgIHwgMTAgICAgfCBLZXlib2FyZCB8IE1lZGl1bSAgICAgICB8DQoNCg0KKipZb3VyIEFzc2lnbm1lbnQgSW5zdHJ1Y3Rpb25zOioqIENyZWF0aW5nIGEgVHJhbnNhY3Rpb25zIFRhYmxlIGFib3ZlIGluIFINCg0KMS4gKipDcmVhdGUgYSBkYXRhIGZyYW1lKiogaW4gUiBjYWxsZWQgYHRyYW5zYWN0aW9uc2AgY29udGFpbmluZyB0aGUgZGF0YSBhYm92ZS4NCg0KMi4gSWRlbnRpZnkgd2hpY2ggdmFyaWFibGVzIGFyZSBudW1lcmljIGFuZCB3aGljaCBhcmUgY2F0ZWdvcmljYWwNCg0KMy4gKipDYWxjdWxhdGUgdG90YWwgcmV2ZW51ZSoqIGZvciBlYWNoIHRyYW5zYWN0aW9uIGJ5IG11bHRpcGx5aW5nIGBRdHkgw5cgUHJpY2VgIGFuZCBhZGQgaXQgYXMgYSBuZXcgY29sdW1uIGBUb3RhbGAuDQoNCjQuICoqQ29tcHV0ZSBzdW1tYXJ5IHN0YXRpc3RpY3MqKjoNCiAgIC0gVG90YWwgcXVhbnRpdHkgc29sZCBmb3IgZWFjaCBwcm9kdWN0DQogICAtIFRvdGFsIHJldmVudWUgcGVyIHByb2R1Y3QNCiAgIC0gQXZlcmFnZSBwcmljZSBwZXIgcHJvZHVjdA0KDQo1LiAqKlZpc3VhbGl6ZSB0aGUgZGF0YSoqOg0KICAgLSBDcmVhdGUgYSAqKmJhcnBsb3QqKiBzaG93aW5nIHRvdGFsIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QuDQogICAtIENyZWF0ZSBhICoqcGllIGNoYXJ0Kiogc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiB0b3RhbCByZXZlbnVlIHBlciBjdXN0b21lciB0aWVyLg0KDQo2LiAqKk9wdGlvbmFsIENoYWxsZW5nZSoqOg0KICAgLSBGaW5kIHdoaWNoICoqZGF0ZSoqIGhhZCB0aGUgaGlnaGVzdCB0b3RhbCByZXZlbnVlLg0KICAgLSBDcmVhdGUgYSAqKnN0YWNrZWQgYmFyIGNoYXJ0Kiogc2hvd2luZyBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0IGJ5IGN1c3RvbWVyIHRpZXIuDQoNCioqSGludHM6KiogVXNlIGBkYXRhLmZyYW1lKClgLCBgYWdncmVnYXRlKClgLCBgYmFycGxvdCgpYCwgYHBpZSgpYCwgYW5kIGJhc2ljIGFyaXRobWV0aWMgb3BlcmF0aW9ucyBpbiBSLg0KDQoNCmBgYCB7cn0NCmxpYnJhcnkoRFQpDQoNCiN0cmFuc2FjdGlvbg0KRGF0ZSA8LSBjKCIyMDI1LTEwLTAxIiwgIjIwMjUtMTAtMDEiLCAiMjAyNS0xMC0wMiIsICIyMDI1LTEwLTAyIiwgIjIwMjUtMTAtMDMiLCANCiAgICAgICAgICAiMjAyNS0xMC0wMyIsICIyMDI1LTEwLTA0IiwgIjIwMjUtMTAtMDQiLCAiMjAyNS0xMC0wNSIsICIyMDI1LTEwLTA1IikNClF0eSA8LSBjKDIsIDUsIDEsIDMsIDQsIDIsIDYsIDEsIDMsIDUpDQpQcmljZSA8LSBjKDEwMDAsIDIwLCAxMDAwLCAzMCwgNTAsIDEwMDAsIDI1LCAxMDAwLCA0MCwgMTApDQpQcm9kdWN0IDwtIGMoIkxhcHRvcCIsICJNb3VzZSIsICJMYXB0b3AiLCAiS2V5Ym9hcmQiLCAiTW91c2UiLCAiTGFwdG9wIiwgDQogICAgICAgICAgICAgIktleWJvYXJkIiwgIkxhcHRvcCIsICJNb3VzZSIsICJLZXlib2FyZCIpDQpDdXN0b21lclRpZXIgPC0gYygiSGlnaCIsICJNZWRpdW0iLCAiTG93IiwgIk1lZGl1bSIsICJNZWRpdW0iLCAiSGlnaCIsIA0KICAgICAgICAgICAgICAgICAgIkxvdyIsICJIaWdoIiwgIkxvdyIsICJNZWRpdW0iKQ0KDQojIGRhdGEgZnJhbWUgDQp0cmFuc2FjdGlvbnMgPC0gZGF0YS5mcmFtZShEYXRlLCBRdHksIFByaWNlLCBQcm9kdWN0LCBDdXN0b21lclRpZXIpDQoNCiMgRGlzcGxheSB0aGUgZGF0YSBmcmFtZSANCnByaW50KHRyYW5zYWN0aW9ucykNCg0KIyAzIFRvdGFsIFJldmVuZXUNCnRyYW5zYWN0aW9ucyR0b3RhbCA8LSB0cmFuc2FjdGlvbnMkUXR5ICogdHJhbnNhY3Rpb25zJFByaWNlDQoNCiMgdmlldyB0aGUgZGF0YSBmcmFtZSANCnByaW50KHRyYW5zYWN0aW9ucykNCg0KcXR5X3N1bW1hcnkgPC0gYWdncmVnYXRlKFF0eSB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkgDQpwcmludChxdHlfc3VtbWFyeSkNCnRvdGFsX3N1bW1hcnkgPC0gYWdncmVnYXRlKHRvdGFsIH4gUHJvZHVjdCwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKSANCnByaW50KHRvdGFsX3N1bW1hcnkpDQpQcmljZV9zdW1tYXJ5IDwtIGFnZ3JlZ2F0ZShQcmljZSB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIG1lYW4pDQpwcmludChQcmljZV9zdW1tYXJ5KQ0KDQojIENhbGN1bGF0ZSB0b3RhbCBxdWFudGl0eSBwZXIgcHJvZHVjdA0KcXR5X3Blcl9wcm9kdWN0IDwtIGFnZ3JlZ2F0ZShRdHkgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQoNCiMgQ3JlYXRlIGEgYmFyIHBsb3QgDQpiYXJwbG90IChxdHlfcGVyX3Byb2R1Y3QkUXR5LA0KICAgICAgICAgbmFtZXMuYXJnID0gcXR5X3Blcl9wcm9kdWN0JFByb2R1Y3QsIA0KICAgICAgICAgY29sID0gIm9yYW5nZSIsIA0KICAgICAgICAgbWFpbiA9ICJUb3RhbCBRdWFudGl0eSBTb2xkIHBlciBQcm9kdWN0IiwNCiAgICAgICAgIHhsYWIgPSAiUHJvZHVjdCIsIHlsYWIgPSAiUXVhbnRpdHkgU29sZCIpDQoNCiMgQ2FsY3VsYXRlIHRvdGFsIHJldmVudWUgcGVyIEN1c3RvbWVyVGllcg0KcmV2ZW51ZV90aWVyIDwtIGFnZ3JlZ2F0ZSh0b3RhbCB+IEN1c3RvbWVyVGllciwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKSANCg0KIyBjcmVhdGUgcGllIGNoYXJ0IA0KcGllKHJldmVudWVfdGllciR0b3RhLCANCiAgICBsYWJlbHMgPSByZXZlbnVlX3RpZXIkQ3VzdG9tZXJUaWVyLCANCiAgICBtYWluID0gIlByb3BvcnRpb24gb2YgVG90YWwgUmV2ZW51ZSBwZXIgQ3VzdG9tZXIgVGllciIsDQogICAgY29sID0gYygicmVkIiwgIm9yYW5nZSIsICJwaW5rIikpDQoNCg0KDQojIEhpdHVuZyB0b3RhbCByZXZlbnVlIHBlciB0YW5nZ2FsDQpyZXZlbnVlX3Blcl9kYXRlIDwtIGFnZ3JlZ2F0ZSh0b3RhbCB+IERhdGUsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkNCg0KIyBMaWhhdCBoYXNpbG55YQ0KcHJpbnQocmV2ZW51ZV9wZXJfZGF0ZSkNCg0KIyBDYXJpIHRhbmdnYWwgZGVuZ2FuIHRvdGFsIHJldmVudWUgcGFsaW5nIHRpbmdpIG1lbmdndW5ha2FuIG1heA0KbWF4X2RhdGUgPC0gcmV2ZW51ZV9wZXJfZGF0ZVt3aGljaC5tYXgocmV2ZW51ZV9wZXJfZGF0ZSR0b3RhbCksIF0NCg0KI2xpaGF0IGhhc2lsbnlhDQpwcmludChtYXhfZGF0ZSkNCg0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIEJpa2luIHN0YWNrZWQgYmFyIGNoYXJ0DQpnZ3Bsb3QodHJhbnNhY3Rpb25zLCBhZXMoeCA9IHJlb3JkZXIoUHJvZHVjdCwgUXR5KSwgeSA9IFF0eSwgZmlsbCA9IEN1c3RvbWVyVGllcikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJRdWFudGl0eSBTb2xkIHBlciBQcm9kdWN0IGJ5IEN1c3RvbWVyIFRpZXIiLA0KICAgICAgIHggPSAiUHJvZHVjdCIsDQogICAgICAgeSA9ICJRdWFudGl0eSBTb2xkIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQoNCg0KIyMgRXhlcmNpc2UgNQ0KDQoqKkNyZWF0ZSBZb3VyIE93biBEYXRhIEZyYW1lOioqDQoNCioqT2JqZWN0aXZlOioqIENyZWF0ZSBhIGRhdGEgZnJhbWUgaW4gUiB3aXRoICoqMzAgcm93cyoqIGNvbnRhaW5pbmcgYSBtaXggb2YgZGF0YSB0eXBlczogY29udGludW91cywgZGlzY3JldGUsIG5vbWluYWwsIGFuZCBvcmRpbmFsLiAgDQoNCiMjIyBJbnN0cnVjdGlvbnMNCg0KMS4gKipPcGVuIFJTdHVkaW8qKiBvciB0aGUgUiBjb25zb2xlLiAgDQoNCjIuICoqQ3JlYXRlIGEgdmVjdG9yIGZvciBlYWNoIGNvbHVtbioqIGluIHlvdXIgZGF0YSBmcmFtZTogIA0KDQogICAtICoqRGF0ZSoqOiAzMCBkYXRlcyAoY2FuIGJlIHNlcXVlbnRpYWwgb3IgcmFuZG9tIHdpdGhpbiBhIG1vbnRoL3llYXIpICANCiAgIC0gKipDb250aW51b3VzKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIHRha2UgZGVjaW1hbCB2YWx1ZXMgKGUuZy4sIGhlaWdodCwgd2VpZ2h0LCB0ZW1wZXJhdHVyZSkgIA0KICAgLSAqKkRpc2NyZXRlKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIG9ubHkgdGFrZSB3aG9sZSBudW1iZXJzIChlLmcuLCBudW1iZXIgb2YgaXRlbXMsIG51bWJlciBvZiB2ZWhpY2xlcykgIA0KICAgLSAqKk5vbWluYWwqKjogY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggKipubyBvcmRlcioqIChlLmcuLCBjb2xvciwgZ2VuZGVyLCBjaXR5KSAgDQogICAtICoqT3JkaW5hbCoqOiBjYXRlZ29yaWNhbCB2YWx1ZXMgd2l0aCBhICoqZGVmaW5lZCBvcmRlcioqIChlLmcuLCBMb3csIE1lZGl1bSwgSGlnaDsgQmVnaW5uZXIsIEludGVybWVkaWF0ZSwgRXhwZXJ0KSAgDQoNCjMuICoqQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZSoqIGNhbGxlZCBgbXlfZGF0YWAuICANCg0KNC4gKipDaGVjayB5b3VyIGRhdGEgZnJhbWUqKiB1c2luZyBgaGVhZCgpYCBvciBgVmlldygpYCB0byBlbnN1cmUgaXQgaGFzICoqMzAgcm93cyoqIGFuZCB0aGUgY29sdW1ucyBhcmUgY29ycmVjdC4gIA0KDQo1LiAqKk9wdGlvbmFsIHRhc2tzKio6ICANCiAgIC0gU3VtbWFyaXplIGVhY2ggY29sdW1uIHVzaW5nIGBzdW1tYXJ5KClgICANCiAgIC0gQ291bnQgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIGNhdGVnb3J5IGZvciAqKk5vbWluYWwqKiBhbmQgKipPcmRpbmFsKiogY29sdW1ucyB1c2luZyBgdGFibGUoKWAgIA0KDQojIyMgSGludHMNCg0KLSBVc2UgYHNlcS5EYXRlKClgIG9yIGBhcy5EYXRlKClgIHRvIGdlbmVyYXRlIHRoZSBEYXRlIGNvbHVtbi4gIA0KLSBVc2UgYHJ1bmlmKClgIG9yIGBybm9ybSgpYCBmb3IgY29udGludW91cyBudW1lcmljIGRhdGEuICANCi0gVXNlIGBzYW1wbGUoKWAgZm9yIGRpc2NyZXRlLCBub21pbmFsLCBhbmQgb3JkaW5hbCBkYXRhLiAgDQotIEVuc3VyZSB0aGUgKipvcmRpbmFsIHZlY3RvcioqIGlzIGNyZWF0ZWQgd2l0aCBgZmFjdG9yKC4uLiwgbGV2ZWxzID0gYygiTG93IiwiTWVkaXVtIiwiSGlnaCIpLCBvcmRlcmVkID0gVFJVRSlgIChvciBzaW1pbGFyKS4gIA0KYGBgIHtyfQ0KbGlicmFyeShEVCkNCg0KIyBEYXRhIEZpbmFuY2lhbCBGcmFtZQ0KDQojIGNvbHVtbiAxOiBUcmFuc2FjdGlvbiBEYXRlDQpEYXRlIDwtIHNlcS5EYXRlKGZyb20gPSBhcy5EYXRlKCIyMDI1LTEwLTAxIiksIGJ5ID0gImRheSIsIGxlbmd0aC5vdXQgPSAzMCkNCg0KIyBDb2x1bW4gMjogVHJhbnNhY3Rpb24gdmFsdWUgKENvbnRpbnVvdXMpIOKAlCBJbiBydXBpYWgNClRyYW5zYWN0aW9uVmFsdWUgPC0gYygNCiAgMTI1MDAwMCwgOTgwMDAwLCAxNTAwMDAwLCAyMTAwMDAwLCAxODUwMDAwLCA3NTAwMDAsIDI0MDAwMDAsIDEzMDAwMDAsIDE3ODAwMDAsIDIyMjAwMDAsDQogIDE5NTAwMDAsIDE2NTAwMDAsIDE0MjAwMDAsIDI1NTAwMDAsIDMxMDAwMDAsIDI3NTAwMDAsIDE5ODAwMDAsIDg4MDAwMCwgMTc1MDAwMCwgMjIwMDAwMCwNCiAgMTkwMDAwMCwgMjYwMDAwMCwgMjQ1MDAwMCwgMTM1MDAwMCwgMTUwMDAwMCwgOTAwMDAwLCAxMjAwMDAwLCAyNzUwMDAwLCAzMjAwMDAwLCAyMTAwMDAwDQopDQoNCiMgQ29sdW1uIDM6IE51bWJlciBvZiBpdGVtcyBwdXJjaGFzZWQgKERpc2NyZXRlKQ0KSXRlbXMgPC0gYygNCiAgMiwgMSwgMywgNSwgNCwgMiwgNiwgMywgNSwgNCwNCiAgMiwgMywgMSwgNywgOCwgNSwgMywgMiwgNCwgNiwNCiAgNSwgNywgOCwgMywgNCwgMSwgMiwgNywgOSwgNQ0KKQ0KDQojIENvbHVtbiA0OiBUcmFuc2FjdGlvbiB0eXBlIChOb21pbmFsKQ0KVHJhbnNhY3Rpb25UeXBlIDwtIGMoDQogICJQZW1iZWxpYW4gVHVuYWkiLCAiVHJhbnNmZXIgQmFuayIsICJLYXJ0dSBLcmVkaXQiLCAiUGVtYmVsaWFuIFR1bmFpIiwgIkUtV2FsbGV0IiwNCiAgIlRyYW5zZmVyIEJhbmsiLCAiS2FydHUgS3JlZGl0IiwgIkUtV2FsbGV0IiwgIlBlbWJlbGlhbiBUdW5haSIsICJFLVdhbGxldCIsDQogICJLYXJ0dSBLcmVkaXQiLCAiUGVtYmVsaWFuIFR1bmFpIiwgIlRyYW5zZmVyIEJhbmsiLCAiRS1XYWxsZXQiLCAiS2FydHUgS3JlZGl0IiwNCiAgIlBlbWJlbGlhbiBUdW5haSIsICJFLVdhbGxldCIsICJUcmFuc2ZlciBCYW5rIiwgIkthcnR1IEtyZWRpdCIsICJQZW1iZWxpYW4gVHVuYWkiLA0KICAiRS1XYWxsZXQiLCAiVHJhbnNmZXIgQmFuayIsICJLYXJ0dSBLcmVkaXQiLCAiUGVtYmVsaWFuIFR1bmFpIiwgIkUtV2FsbGV0IiwNCiAgIkthcnR1IEtyZWRpdCIsICJUcmFuc2ZlciBCYW5rIiwgIlBlbWJlbGlhbiBUdW5haSIsICJFLVdhbGxldCIsICJUcmFuc2ZlciBCYW5rIg0KKQ0KDQojIEtvbG9tIDU6IEN1c3RvbWVyIFRpZXIgKE9yZGluYWwpDQpDdXN0b21lclRpZXIgPC0gZmFjdG9yKA0KICBjKA0KICAgICJTZWRhbmciLCAiUmVuZGFoIiwgIlNlZGFuZyIsICJUaW5nZ2kiLCAiU2VkYW5nIiwgIlJlbmRhaCIsICJUaW5nZ2kiLCAiU2VkYW5nIiwgIlRpbmdnaSIsICJTZWRhbmciLA0KICAgICJSZW5kYWgiLCAiVGluZ2dpIiwgIlNlZGFuZyIsICJUaW5nZ2kiLCAiVGluZ2dpIiwgIlNlZGFuZyIsICJSZW5kYWgiLCAiU2VkYW5nIiwgIlRpbmdnaSIsICJTZWRhbmciLA0KICAgICJSZW5kYWgiLCAiVGluZ2dpIiwgIlRpbmdnaSIsICJSZW5kYWgiLCAiU2VkYW5nIiwgIlJlbmRhaCIsICJTZWRhbmciLCAiVGluZ2dpIiwgIlRpbmdnaSIsICJTZWRhbmciDQogICksDQogIGxldmVscyA9IGMoIlJlbmRhaCIsICJTZWRhbmciLCAiVGluZ2dpIiksDQogIG9yZGVyZWQgPSBUUlVFDQopDQoNCiMgQ29tYmluZSBpbnRvIGEgZGF0YSBmcmFtZQ0KZGF0YV9maW5hbmNpYWwgPC0gZGF0YS5mcmFtZShEYXRlLCBUcmFuc2FjdGlvblZhbHVlLCBJdGVtcywgVHJhbnNhY3Rpb25UeXBlLCBDdXN0b21lclRpZXIpDQoNCiMgRGlzcGxheSB0aGUgZGF0YSBmcmFtZSBhcyBhIHRhYmxlDQpwcmludChkYXRhX2ZpbmFuY2lhbCkNCg0KIyBDcmVhdGUgYSBzZWNvbmQgdGFibGUgZm9yIHZhcmlhYmxlIHR5cGUNCnZhcmlhYmxlc19pbmZvIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMTo0LA0KICB2YXJpYWJsZSA9IGMoDQogICAgIlRyYW5zYWN0aW9uIFZhbHVlIiwNCiAgICAiSXRlbXMiLA0KICAgICJUcmFuc2FjdGlvbiBUeXBlIiwNCiAgICAiQ3VzdG9tZXIgVGllciINCiksDQogIERhdGFUeXBlID0gYygNCiAgICAgICJDb250aW51b3VzIiwNCiAgICAgICJEaXNjcmV0ZSIsDQogICAgICAiTm9taW5hbCIsDQogICAgICAiT3JkaW5hbCINCiAgICApLA0KICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KICApDQoNCmxpYnJhcnkoa25pdHIpDQoNCmthYmxlKA0KICB2YXJpYWJsZXNfaW5mbywNCiAgY2FwdGlvbiA9ICJUYWJsZSBvZiBWYXJpYWJsZXMgYW5kIERhdGEgVHlwZXMiDQopDQpgYGANCg0KDQo=