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) #untuk tabel yang rapih 
variables_info <- data.frame( 
  No = 1:5, # data yang di tampilkan 1 hingga 5
  
  #c itu Combine. untuk membuat vector (data)
  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"
  ),
  #Mengatur agar data teks (string) tidak otomatis diubah menjadi factor
  stringsAsFactors = FALSE 
)

# Display the data frame as a neat table
kable(variables_info, 
      caption = "Table of Variables and Data Types") #untuk caption (keterangan) yang muncul di atas tabel
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) # package DT(Data Tables) untuk membuat tabel data yang rapih

data_sources <- data.frame(
  No = 1:4, # baris data yang muncul 4 data
  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"
  ),
  
  #Mengatur agar data teks (string) tidak otomatis diubah menjadi factor
  stringsAsFactors = FALSE 
)


datatable(data_sources, 
          caption = "Table of Data Sources", # keterangan untuk di atas tabel
          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)
NO = 1:10
transactions <- data.frame(
  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"),
  #di atas ini Vector (karena datanya tidak memiliki level (text (string)))
  
  # di bawah ini Factor (karena menyimpan data Ordinal(ada levelnya Low - Medium - High)) bukan text (string)
  CustomerTier = c("High", "Medium", "Low", "Medium", "Medium",
                   "High", "Low", "High", "Low", "Medium"),
  
  stringsAsFactors = FALSE #Mengatur agar data teks (string) tidak otomatis diubah menjadi factor
)

# Atur urutan CustomerTier (Low → Medium → High)
transactions$CustomerTier <- factor( # ($) ambil kolom tertentu dari data frame yang bernama transactions
  transactions$CustomerTier,
  levels = c("Low", "Medium", "High"), # untuk menentukan urutan kategori
  ordered = TRUE # memberitahu R bahwa kategori (levels) di dalam faktor tersebut memiliki urutan yang logis
                 # dengan argumen ordered = TRUE R jadi tahu kalau High lebih tinggi dari Medium dan seterusnya
)

# Tambahkan kolom Total = Qty × Price
transactions$Total <- transactions$Qty * transactions$Price 


# Tampilkan tabel interaktif dengan DT
datatable(
  transactions,
  caption = "Table: Transaction Data with Total Revenue",
  rownames = FALSE,
  )
transactions_summary <- aggregate(
  cbind(Qty, Total, Price) ~ Product, # Untuk menggabungkan isi data (value) pada tabel Qty, Total, Price
  data = transactions,
  
  # ini fungsi (function) untuk data di bawahnya (sum = penjumlahan untuk nilai total)
  # (mean = menghitung nilai rata rata)
  FUN = function(x) c(sum = sum(x), avg = mean(x)) 
)


# Bayangin punya lemari besar namanya transactions_summary, 
# di lemari itu ada  4 laci : 1. Product, 2. Qty, 3. Total, 4. Price
transactions_summary <- data.frame(
  Product = transactions_summary$Product,
  
  # Ambil map 'sum' dari laci 'Qty'
  Total_Qty = transactions_summary$Qty[, "sum"],
  
  # Ambil map 'sum' dari laci 'Total'
  Total_Revenue = transactions_summary$Total[, "sum"],
  
  # Ambil map 'avg' dari laci 'Price', lalu bulatkan ke 2 angka desimal
  Avg_Price = round(transactions_summary$Price[, "avg"], 2)
)


#Tampilkan Table Numeric
numeric_table <- transactions[, c("Date", "Qty", "Price", "Total")] # data yang hanya di ambil Date, Qty, Price, Total

datatable(
  numeric_table,
  caption = "Table 2: Numeric Table",
  rownames = FALSE,
  options = list(pageLength = 5) # hanya menampilkan 5 baris data
)
# Tampilkan Table Categorical
categorical_table <- transactions[, c("Date", "Product", "CustomerTier")] # data yang hanya di ambil Date, Product, CustomerTier

datatable(
  categorical_table,
  caption = "Table 3: Categorical Table",
  rownames = FALSE,
  options = list(pageLength = 5) # hanya menampilkan 5 baris data
)
# Tampilkan tabel Summary
datatable(
  transactions_summary,
  caption = "Table 4: Summary Statistics per Product",
  rownames = FALSE,
  options = list(pageLength = 3) # hanya menampilkan 3 baris data
)
# PEMBUATAN BARPLOT

# aggregate itu untuk Mengelompokkan data. jadi pengelompokan data transactions berdasarkan kolom Product, 
qty_per_product <- aggregate(Qty ~ Product, data = transactions, sum) # Qty ~ Product -> kelompokkan Qty menurut Product
# Buat barplot
barplot(
  qty_per_product$Qty,  # tinggi batang sesuai jumlah penjualan
  names.arg = qty_per_product$Product, # nama batang = nama produk
  col = "skyblue", # menampilkan bar warna menjadi biru (skyblue)
  main = "Total Quantity Sold per Product", # Judul barplot
  xlab = "Product", # menunjukkan data sumbu X (Horizontal)
  ylab = "Total Quantity Sold" # menunjukkan data sumbu Y (Vertikal)
  )

# Mengelompokkan data transactions berdasarkan CustomerTier, lalu menjumlahkan nilai Total untuk setiap level pelanggan.
revenue_per_tier <- aggregate(Total ~ CustomerTier, data = transactions, sum) # Total ~ CustomerTier -> kelompokkan Total menurut CustomerTier
# Buat pie chart
pie(
  revenue_per_tier$Total, # nilai total per tier
  labels = revenue_per_tier$CustomerTier, # label tiap potongan pie
  col = c("red", "yellow", "green"), # menampilkan bar warna merah, kuning, hijau.
  main = "Proportion of Total Revenue per Customer Tier" # Judul Pie chart
)

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).
# Install kableExtra package if not already installed
# install.packages("kableExtra")
library(knitr)
library(kableExtra) #library untuk double header di table

# 1. Kolom Date: 30 hari berturut-turut di bulan Oktober 2025
Date <- seq.Date(from = as.Date("2025-10-01"), by = "day", length.out = 30)

# 2. Kolom Weather Temperature
# Menggunakan runif() untuk menghasilkan angka desimal acak antara 15°C dan 35°C
Weather_Temperature <- runif(30, min = 15, max = 35)

# 3. Kolom Number of Green Areas
# Menggunakan sample() untuk menghasilkan angka bulat acak antara 1 - 20
Number_of_Green_Areas <- sample(1:20, 30, replace = TRUE) 

  # 4. Kolom City Name
Cities <- c("New York", "Los Angeles", "Chicago", "Houston", "Phoenix",
            "Philadelphia", "San Antonio", "San Diego", "Dallas", "San Jose")
City_Name <- sample(Cities, 30, replace = TRUE) # untuk memilih nama kota secara acak dari daftar

# 5. Kolom Crime Level
# Menggunakan factor() dengan urutan level dari rendah ke tinggi (Low < Medium < High)
Crime_Level <- factor(
  sample(c("Low", "Medium", "High"), 30, replace = TRUE),
  levels = c("Low", "Medium", "High"),
  ordered = TRUE
)

# Menggabungkan semua kolom menjadi satu data frame bernama my_data
my_data <- data.frame(
  Date = Date,
  Weather_Temperature = Weather_Temperature,
  Number_of_Green_Areas = Number_of_Green_Areas,
  City_Name = City_Name,
  Crime_Level = Crime_Level
)

View(my_data)#melihat semua data

#Untuk menampilkan Kolum Data dan Baris header table
kable(my_data,
        caption = "City Environment & Crime Level Dataset",
        col.names = c("Date", "Air Temperature (°C)", "Number of Green Areas", "City Name", "Crime Level"),
        align = "c") %>%
    add_header_above(c(" " = 1, "Continous" = 1, "Discrete" = 1, "Nominal" = 1, "Ordinal" = 1)
) 
City Environment & Crime Level Dataset
Continous
Discrete
Nominal
Ordinal
Date Air Temperature (°C) Number of Green Areas City Name Crime Level
2025-10-01 26.34752 19 San Antonio Low
2025-10-02 22.10281 16 New York High
2025-10-03 31.71580 9 Phoenix Medium
2025-10-04 15.13374 15 Philadelphia High
2025-10-05 25.78779 18 Los Angeles Medium
2025-10-06 15.85605 17 San Antonio High
2025-10-07 21.96234 20 Houston Low
2025-10-08 25.08193 13 Los Angeles Medium
2025-10-09 18.59004 2 New York Low
2025-10-10 17.11901 3 San Diego High
2025-10-11 16.50570 20 New York High
2025-10-12 15.15755 17 San Antonio Low
2025-10-13 29.76421 8 Dallas Medium
2025-10-14 29.70380 18 Chicago Medium
2025-10-15 30.81624 3 Los Angeles Low
2025-10-16 17.30336 15 Philadelphia Low
2025-10-17 21.18546 3 Chicago Medium
2025-10-18 17.55258 7 San Diego High
2025-10-19 18.58223 5 New York High
2025-10-20 18.63405 6 San Jose Low
2025-10-21 29.39202 5 Los Angeles Low
2025-10-22 21.04285 6 Dallas Medium
2025-10-23 29.68960 9 Dallas High
2025-10-24 19.64592 6 San Jose Low
2025-10-25 24.58204 1 Los Angeles Low
2025-10-26 24.77269 9 Chicago Low
2025-10-27 34.01621 10 Los Angeles Low
2025-10-28 30.63755 20 Los Angeles High
2025-10-29 16.86696 1 San Antonio High
2025-10-30 17.22151 19 Chicago High
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAzIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6DQotICJSZWZhbnRhbnVyIEh1bnN1bCBIYXFpYiINCi0gIkNhaGF5YSBNZWRpbmEgU2VtaWRhbmciDQotICJBZGluZGEgTWFpemEgSXNoZmFoYW5pIg0KLSAiQ2hhbmRyYSBSaXphbCBBbGFtc3lhaCINCi0gIkZpdHlhbmFuZHJhIEF0aGFyIEFkeWFrc2EiICAgIyBSZXBsYWNlIHdpdGggeW91ciBmdWxsIG5hbWUNCmRhdGU6ICAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiICMgQXV0byBkaXNwbGF5cyB0aGUgY3VycmVudCBkYXRlDQpvdXRwdXQ6ICAgICAgICAgICAgICAgICAgICAgICAgICMgT3V0cHV0IHNlY3Rpb24gZGVmaW5lcyB0aGUgZm9ybWF0IGFuZCBsYXlvdXQgDQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOiAgICAgICMgaHR0cHM6Ly9naXRodWIuY29tL2p1YmEvcm1kZm9ybWF0cw0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlICAgICAgICAjIEVtYmVkcyBhbGwgcmVzb3VyY2VzIChDU1MsIEpTLCBpbWFnZXMpIA0KICAgIHRodW1ibmFpbHM6IHRydWUgICAgICAgICAgICAjIERpc3BsYXlzIGltYWdlIHRodW1ibmFpbHMgaW4gdGhlIGRvYw0KICAgIGxpZ2h0Ym94OiB0cnVlICAgICAgICAgICAgICAjIEVuYWJsZXMgY2xpY2sgdG8gZW5sYXJnZSBpbWFnZXMNCiAgICBnYWxsZXJ5OiB0cnVlICAgICAgICAgICAgICAgIyBHcm91cHMgaW1hZ2VzIGludG8gYW4gaW50ZXJhY3RpdmUgZ2FsbGVyeQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZSAgICAgICAjIEF1dG9tYXRpY2FsbHkgbnVtYmVycyBhbGwgc2VjdGlvbnMNCiAgICBsaWJfZGlyOiBsaWJzICAgICAgICAgICAgICAgIyBEaXJlY3Rvcnkgd2hlcmUgSmF2YVNjcmlwdC9DU1MgbGlicmFyaWVzDQogICAgZGZfcHJpbnQ6ICJwYWdlZCIgICAgICAgICAgICMgRGlzcGxheXMgZGF0YSBmcmFtZXMgYXMgaW50ZXJhY3RpdmUgcGFnZWQgDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyIgICAgICAgICMgQWxsb3dzIGZvbGRpbmcvdW5mb2xkaW5nIFIgY29kZSBibG9ja3MgDQogICAgY29kZV9kb3dubG9hZDogeWVzICAgICAgICAgICMgQWRkcyBhIGJ1dHRvbiB0byBkb3dubG9hZCBhbGwgUiBjb2RlDQotLS0NCg0KDQo8aW1nIGlkPSJGb3RvIiBzcmM9Imh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9ZYW5EcmFhL1dlZWszU3RhdGlzdGlrYS9tYWluL0ZPVE9fS0VMT01QT0suanBnIiBhbHQ9IkxvZ28iIHN0eWxlPSJ3aWR0aDoyMDBweDsgZGlzcGxheTogYmxvY2s7IG1hcmdpbjogYXV0bzsiPg0KDQotLS0NCg0KIyMgRXhlcmNpc2UgMQ0KDQpUaGUgZm9sbG93aW5nIHRhYmxlIHNob3dzIHNhbXBsZSBpbmZvcm1hdGlvbiBmb3IgdGhyZWUgc3R1ZGVudHMuIEVhY2ggb2JzZXJ2YXRpb24gcmVwcmVzZW50cyBhIHNpbmdsZSBzdHVkZW50IGFuZCBpbmNsdWRlcyBkZXRhaWxzIHN1Y2ggYXMgdGhlaXIgdW5pcXVlIHN0dWRlbnQgSUQsIG5hbWUsIGFnZSwgdG90YWwgY3JlZGl0cyBjb21wbGV0ZWQsIG1ham9yIGZpZWxkIG9mIHN0dWR5LCBhbmQgeWVhciBsZXZlbC4gIA0KDQpUaGlzIGRhdGFzZXQgZGVtb25zdHJhdGVzIGEgbWl4dHVyZSBvZiB2YXJpYWJsZSB0eXBlczogIA0KDQotICoqTm9taW5hbDoqKiBTdHVkZW50SUQsIE5hbWUsIE1ham9yICANCi0gKipOdW1lcmljOioqIEFnZSAoY29udGludW91cyksIENyZWRpdHNDb21wbGV0ZWQgKGRpc2NyZXRlKSAgDQotICoqT3JkaW5hbDoqKiBZZWFyTGV2ZWwgKEZyZXNobWFuIOKGkiBTZW5pb3IpICANCg0KfCBTdHVkZW50SUQgfCBOYW1lICAgfCBBZ2UgfCBDcmVkaXRzQ29tcGxldGVkIHwgTWFqb3IgICAgICAgICAgICB8IFllYXJMZXZlbCB8DQp8LS0tLS0tLS0tLS18LS0tLS0tLS18LS0tLS18LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18DQp8IFMwMDEgICAgICB8IEFsaWNlICB8IDIwICB8IDQ1ICAgICAgICAgICAgICB8IERhdGEgU2FpbnMgICAgICB8IFNvcGhvbW9yZSB8DQp8IFMwMDIgICAgICB8IEJ1ZGkgICB8IDIxICB8IDYwICAgICAgICAgICAgICB8IE1hdGhlbWF0aWNzICAgICB8IEp1bmlvciAgICB8DQp8IFMwMDMgICAgICB8IENpdHJhICB8IDE5ICB8IDMwICAgICAgICAgICAgICB8IFN0YXRpc3RpY3MgICAgICB8IEZyZXNobWFuICB8DQoNCmBgYHtyfQ0KIyAxLiBDcmVhdGUgdmVjdG9ycyBmb3IgZWFjaCB2YXJpYWJsZQ0KU3R1ZGVudElEIDwtIGMoIlMwMDEiLCAiUzAwMiIsICJTMDAzIikgICAgICAgIyBOb21pbmFsIC8gSUQNCk5hbWUgPC0gYygiQWxpY2UiLCAiQnVkaSIsICJDaXRyYSIpICAgICAgICAgICMgTm9taW5hbCAvIE5hbWUNCkFnZSA8LSBjKDIwLCAyMSwgMTkpICAgICAgICAgICAgICAgICAgICAgICAgICMgTnVtZXJpYyAvIENvbnRpbnVvdXMNCkNyZWRpdHNDb21wbGV0ZWQgPC0gYyg0NSwgNjAsIDMwKSAgICAgICAgICAgICMgTnVtZXJpYyAvIERpc2NyZXRlDQoNCiMgTm9taW5hbA0KTWFqb3IgPC0gYygiRGF0YSBTYWlucyIsICJNYXRoZW1hdGljcyIsICJTdGF0aXN0aWNzIikgIA0KDQojIE9yZGluYWwNClllYXJMZXZlbCA8LSBmYWN0b3IoYygiU29waG9tb3JlIiwgIkp1bmlvciIsICJGcmVzaG1hbiIpLA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJGcmVzaG1hbiIsIlNvcGhvbW9yZSIsIkp1bmlvciIsIlNlbmlvciIpLA0KICAgICAgICAgICAgICAgICAgICBvcmRlcmVkID0gVFJVRSkgICAgICAgICAgDQoNCiMgMi4gQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZQ0Kc3R1ZGVudHMgPC0gZGF0YS5mcmFtZSgNCiAgU3R1ZGVudElELCBOYW1lLCBBZ2UsIENyZWRpdHNDb21wbGV0ZWQsIE1ham9yLCBZZWFyTGV2ZWwsDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIDMuIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCnByaW50KHN0dWRlbnRzKQ0KYGBgDQoNCg0KIyMgRXhlcmNpc2UgMg0KDQoqKklkZW50aWZ5IERhdGEgVHlwZXM6KiogRGV0ZXJtaW5lIHRoZSB0eXBlIG9mIGRhdGEgZm9yIGVhY2ggb2YgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6DQoNCmBgYHtyfQ0KIyBJbnN0YWxsIGtuaXRyIHBhY2thZ2UgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkDQojIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCmxpYnJhcnkoa25pdHIpICN1bnR1ayB0YWJlbCB5YW5nIHJhcGloIA0KdmFyaWFibGVzX2luZm8gPC0gZGF0YS5mcmFtZSggDQogIE5vID0gMTo1LCAjIGRhdGEgeWFuZyBkaSB0YW1waWxrYW4gMSBoaW5nZ2EgNQ0KICANCiAgI2MgaXR1IENvbWJpbmUuIHVudHVrIG1lbWJ1YXQgdmVjdG9yIChkYXRhKQ0KICBWYXJpYWJsZSA9IGMoIA0KICAgICJOdW1iZXIgb2YgdmVoaWNsZXMgcGFzc2luZyB0aHJvdWdoIHRoZSB0b2xsIHJvYWQgZWFjaCBkYXkiLA0KICAgICJTdHVkZW50IGhlaWdodCBpbiBjbSIsDQogICAgIkVtcGxveWVlIGdlbmRlciAoTWFsZSAvIEZlbWFsZSkiLA0KICAgICJDdXN0b21lciBzYXRpc2ZhY3Rpb24gbGV2ZWw6IExvdywgTWVkaXVtLCBIaWdoIiwNCiAgICAiUmVzcG9uZGVudCdzIGZhdm9yaXRlIGNvbG9yOiBSZWQsIEJsdWUsIEdyZWVuIg0KICApLA0KICBEYXRhVHlwZSA9IGMoIA0KICAgICJOdW1lcmljIiwNCiAgICAiTnVtZXJpYyIsDQogICAgIkNhdGVnb3JpY2FsIiwNCiAgICAiQ2F0ZWdvcmljYWwiLA0KICAgICJDYXRlZ29yaWNhbCINCiAgKSwNCiAgU3VidHlwZSA9IGMoDQogICAgIkNvbnRpbm91cyIsDQogICAgIkNvbnRpbm91cyIsDQogICAgIk5vbWluYWwiLA0KICAgICJPcmRpbmFsIiwNCiAgICAiTm9taW5hbCINCiAgKSwNCiAgI01lbmdhdHVyIGFnYXIgZGF0YSB0ZWtzIChzdHJpbmcpIHRpZGFrIG90b21hdGlzIGRpdWJhaCBtZW5qYWRpIGZhY3Rvcg0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UgDQopDQoNCiMgRGlzcGxheSB0aGUgZGF0YSBmcmFtZSBhcyBhIG5lYXQgdGFibGUNCmthYmxlKHZhcmlhYmxlc19pbmZvLCANCiAgICAgIGNhcHRpb24gPSAiVGFibGUgb2YgVmFyaWFibGVzIGFuZCBEYXRhIFR5cGVzIikgI3VudHVrIGNhcHRpb24gKGtldGVyYW5nYW4pIHlhbmcgbXVuY3VsIGRpIGF0YXMgdGFiZWwNCg0KYGBgDQotLS0NCg0KIyMgRXhlcmNpc2UgMw0KDQoqKkNsYXNzaWZ5IERhdGEgU291cmNlczoqKiBEZXRlcm1pbmUgd2hldGhlciB0aGUgZm9sbG93aW5nIGRhdGEgY29tZXMgZnJvbSAqKmludGVybmFsKiogb3IgKipleHRlcm5hbCBzb3VyY2VzKiosIGFuZCB3aGV0aGVyIGl0IGlzICoqc3RydWN0dXJlZCoqIG9yICoqdW5zdHJ1Y3R1cmVkKio6DQoNCmBgYHtyfQ0KIyBJbnN0YWxsIERUIHBhY2thZ2UgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkDQojIGluc3RhbGwucGFja2FnZXMoIkRUIikNCmxpYnJhcnkoRFQpICMgcGFja2FnZSBEVChEYXRhIFRhYmxlcykgdW50dWsgbWVtYnVhdCB0YWJlbCBkYXRhIHlhbmcgcmFwaWgNCg0KZGF0YV9zb3VyY2VzIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMTo0LCAjIGJhcmlzIGRhdGEgeWFuZyBtdW5jdWwgNCBkYXRhDQogIERhdGFTb3VyY2UgPSBjKA0KICAgICJEYWlseSBzYWxlcyB0cmFuc2FjdGlvbiBkYXRhIG9mIHRoZSBjb21wYW55IiwNCiAgICAiV2VhdGhlciByZXBvcnRzIGZyb20gQk1LRyIsDQogICAgIlByb2R1Y3QgcmV2aWV3cyBvbiBzb2NpYWwgbWVkaWEiLA0KICAgICJXYXJlaG91c2UgaW52ZW50b3J5IHJlcG9ydHMiDQogICksDQogIEludGVybmFsX0V4dGVybmFsID0gYygNCiAgICAiSW50ZXJuYWwiLA0KICAgICJFeHRlcm5hbCIsDQogICAgIkV4dGVybmFsIiwNCiAgICAiSW50ZXJuYWwiDQogICksDQogIFN0cnVjdHVyZWRfVW5zdHJ1Y3R1cmVkID0gYygNCiAgICAiU3RydWN0dXJlZCIsDQogICAgInN0cnVjdHVyZWQiLA0KICAgICJVbnN0cnVjdHVyZWQiLA0KICAgICJTdHJ1Y3R1cmVkIg0KICApLA0KICANCiAgI01lbmdhdHVyIGFnYXIgZGF0YSB0ZWtzIChzdHJpbmcpIHRpZGFrIG90b21hdGlzIGRpdWJhaCBtZW5qYWRpIGZhY3Rvcg0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UgDQopDQoNCg0KZGF0YXRhYmxlKGRhdGFfc291cmNlcywgDQogICAgICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBEYXRhIFNvdXJjZXMiLCAjIGtldGVyYW5nYW4gdW50dWsgZGkgYXRhcyB0YWJlbA0KICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UpICMgaGlkZXMgdGhlIGluZGV4IGNvbHVtbg0KYGBgDQoNCi0tLQ0KDQojIyBFeGVyY2lzZSA0DQoNCioqRGF0YXNldCBTdHJ1Y3R1cmU6KiogQ29uc2lkZXIgdGhlIGZvbGxvd2luZyB0cmFuc2FjdGlvbiB0YWJsZToNCg0KfCBEYXRlICAgICAgIHwgUXR5IHwgUHJpY2UgfCBQcm9kdWN0ICB8IEN1c3RvbWVyVGllciB8DQp8LS0tLS0tLS0tLS0tfC0tLS0tfC0tLS0tLS18LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLXwNCnwgMjAyNS0xMC0wMSB8IDIgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTAxIHwgNSAgIHwgMjAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDIgfCAxICAgfCAxMDAwICB8IExhcHRvcCAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wMiB8IDMgICB8IDMwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAzIHwgNCAgIHwgNTAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDMgfCAyICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wNCB8IDYgICB8IDI1ICAgIHwgS2V5Ym9hcmQgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTA0IHwgMSAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDUgfCAzICAgfCA0MCAgICB8IE1vdXNlICAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wNSB8IDUgICB8IDEwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KDQoNCioqWW91ciBBc3NpZ25tZW50IEluc3RydWN0aW9uczoqKiBDcmVhdGluZyBhIFRyYW5zYWN0aW9ucyBUYWJsZSBhYm92ZSBpbiBSDQoNCjEuICoqQ3JlYXRlIGEgZGF0YSBmcmFtZSoqIGluIFIgY2FsbGVkIGB0cmFuc2FjdGlvbnNgIGNvbnRhaW5pbmcgdGhlIGRhdGEgYWJvdmUuDQoNCjIuIElkZW50aWZ5IHdoaWNoIHZhcmlhYmxlcyBhcmUgbnVtZXJpYyBhbmQgd2hpY2ggYXJlIGNhdGVnb3JpY2FsDQoNCjMuICoqQ2FsY3VsYXRlIHRvdGFsIHJldmVudWUqKiBmb3IgZWFjaCB0cmFuc2FjdGlvbiBieSBtdWx0aXBseWluZyBgUXR5IMOXIFByaWNlYCBhbmQgYWRkIGl0IGFzIGEgbmV3IGNvbHVtbiBgVG90YWxgLg0KDQo0LiAqKkNvbXB1dGUgc3VtbWFyeSBzdGF0aXN0aWNzKio6DQogICAtIFRvdGFsIHF1YW50aXR5IHNvbGQgZm9yIGVhY2ggcHJvZHVjdA0KICAgLSBUb3RhbCByZXZlbnVlIHBlciBwcm9kdWN0DQogICAtIEF2ZXJhZ2UgcHJpY2UgcGVyIHByb2R1Y3QNCg0KNS4gKipWaXN1YWxpemUgdGhlIGRhdGEqKjoNCiAgIC0gQ3JlYXRlIGEgKipiYXJwbG90Kiogc2hvd2luZyB0b3RhbCBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0Lg0KICAgLSBDcmVhdGUgYSAqKnBpZSBjaGFydCoqIHNob3dpbmcgdGhlIHByb3BvcnRpb24gb2YgdG90YWwgcmV2ZW51ZSBwZXIgY3VzdG9tZXIgdGllci4NCg0KNi4gKipPcHRpb25hbCBDaGFsbGVuZ2UqKjoNCiAgIC0gRmluZCB3aGljaCAqKmRhdGUqKiBoYWQgdGhlIGhpZ2hlc3QgdG90YWwgcmV2ZW51ZS4NCiAgIC0gQ3JlYXRlIGEgKipzdGFja2VkIGJhciBjaGFydCoqIHNob3dpbmcgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyLg0KDQoqKkhpbnRzOioqIFVzZSBgZGF0YS5mcmFtZSgpYCwgYGFnZ3JlZ2F0ZSgpYCwgYGJhcnBsb3QoKWAsIGBwaWUoKWAsIGFuZCBiYXNpYyBhcml0aG1ldGljIG9wZXJhdGlvbnMgaW4gUi4NCg0KYGBge3J9DQpsaWJyYXJ5KERUKQ0KTk8gPSAxOjEwDQp0cmFuc2FjdGlvbnMgPC0gZGF0YS5mcmFtZSgNCiAgRGF0ZSA9IGMoIjIwMjUtMTAtMDEiLCAiMjAyNS0xMC0wMSIsICIyMDI1LTEwLTAyIiwgIjIwMjUtMTAtMDIiLA0KICAgICAgICAgICAgICAgICAgICIyMDI1LTEwLTAzIiwgIjIwMjUtMTAtMDMiLCAiMjAyNS0xMC0wNCIsICIyMDI1LTEwLTA0IiwgDQogICAgICAgICAgICAgICAgICAgIjIwMjUtMTAtMDUiLCAiMjAyNS0xMC0wNSIpLA0KICBRdHkgPSBjKDIsIDUsIDEsIDMsIDQsIDIsIDYsIDEsIDMsIDUpLA0KICBQcmljZSA9IGMoMTAwMCwgMjAsIDEwMDAsIDMwLCA1MCwgMTAwMCwgMjUsIDEwMDAsIDQwLCAxMCksDQogIFByb2R1Y3QgPSBjKCJMYXB0b3AiLCAiTW91c2UiLCAiTGFwdG9wIiwgIktleWJvYXJkIiwgIk1vdXNlIiwNCiAgICAgICAgICAgICAgIkxhcHRvcCIsICJLZXlib2FyZCIsICJMYXB0b3AiLCAiTW91c2UiLCAiS2V5Ym9hcmQiKSwNCiAgI2RpIGF0YXMgaW5pIFZlY3RvciAoa2FyZW5hIGRhdGFueWEgdGlkYWsgbWVtaWxpa2kgbGV2ZWwgKHRleHQgKHN0cmluZykpKQ0KICANCiAgIyBkaSBiYXdhaCBpbmkgRmFjdG9yIChrYXJlbmEgbWVueWltcGFuIGRhdGEgT3JkaW5hbChhZGEgbGV2ZWxueWEgTG93IC0gTWVkaXVtIC0gSGlnaCkpIGJ1a2FuIHRleHQgKHN0cmluZykNCiAgQ3VzdG9tZXJUaWVyID0gYygiSGlnaCIsICJNZWRpdW0iLCAiTG93IiwgIk1lZGl1bSIsICJNZWRpdW0iLA0KICAgICAgICAgICAgICAgICAgICJIaWdoIiwgIkxvdyIsICJIaWdoIiwgIkxvdyIsICJNZWRpdW0iKSwNCiAgDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSAjTWVuZ2F0dXIgYWdhciBkYXRhIHRla3MgKHN0cmluZykgdGlkYWsgb3RvbWF0aXMgZGl1YmFoIG1lbmphZGkgZmFjdG9yDQopDQoNCiMgQXR1ciB1cnV0YW4gQ3VzdG9tZXJUaWVyIChMb3cg4oaSIE1lZGl1bSDihpIgSGlnaCkNCnRyYW5zYWN0aW9ucyRDdXN0b21lclRpZXIgPC0gZmFjdG9yKCAjICgkKSBhbWJpbCBrb2xvbSB0ZXJ0ZW50dSBkYXJpIGRhdGEgZnJhbWUgeWFuZyBiZXJuYW1hIHRyYW5zYWN0aW9ucw0KICB0cmFuc2FjdGlvbnMkQ3VzdG9tZXJUaWVyLA0KICBsZXZlbHMgPSBjKCJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSwgIyB1bnR1ayBtZW5lbnR1a2FuIHVydXRhbiBrYXRlZ29yaQ0KICBvcmRlcmVkID0gVFJVRSAjIG1lbWJlcml0YWh1IFIgYmFod2Ega2F0ZWdvcmkgKGxldmVscykgZGkgZGFsYW0gZmFrdG9yIHRlcnNlYnV0IG1lbWlsaWtpIHVydXRhbiB5YW5nIGxvZ2lzDQogICAgICAgICAgICAgICAgICMgZGVuZ2FuIGFyZ3VtZW4gb3JkZXJlZCA9IFRSVUUgUiBqYWRpIHRhaHUga2FsYXUgSGlnaCBsZWJpaCB0aW5nZ2kgZGFyaSBNZWRpdW0gZGFuIHNldGVydXNueWENCikNCg0KIyBUYW1iYWhrYW4ga29sb20gVG90YWwgPSBRdHkgw5cgUHJpY2UNCnRyYW5zYWN0aW9ucyRUb3RhbCA8LSB0cmFuc2FjdGlvbnMkUXR5ICogdHJhbnNhY3Rpb25zJFByaWNlIA0KDQoNCiMgVGFtcGlsa2FuIHRhYmVsIGludGVyYWt0aWYgZGVuZ2FuIERUDQpkYXRhdGFibGUoDQogIHRyYW5zYWN0aW9ucywNCiAgY2FwdGlvbiA9ICJUYWJsZTogVHJhbnNhY3Rpb24gRGF0YSB3aXRoIFRvdGFsIFJldmVudWUiLA0KICByb3duYW1lcyA9IEZBTFNFLA0KICApDQoNCnRyYW5zYWN0aW9uc19zdW1tYXJ5IDwtIGFnZ3JlZ2F0ZSgNCiAgY2JpbmQoUXR5LCBUb3RhbCwgUHJpY2UpIH4gUHJvZHVjdCwgIyBVbnR1ayBtZW5nZ2FidW5na2FuIGlzaSBkYXRhICh2YWx1ZSkgcGFkYSB0YWJlbCBRdHksIFRvdGFsLCBQcmljZQ0KICBkYXRhID0gdHJhbnNhY3Rpb25zLA0KICANCiAgIyBpbmkgZnVuZ3NpIChmdW5jdGlvbikgdW50dWsgZGF0YSBkaSBiYXdhaG55YSAoc3VtID0gcGVuanVtbGFoYW4gdW50dWsgbmlsYWkgdG90YWwpDQogICMgKG1lYW4gPSBtZW5naGl0dW5nIG5pbGFpIHJhdGEgcmF0YSkNCiAgRlVOID0gZnVuY3Rpb24oeCkgYyhzdW0gPSBzdW0oeCksIGF2ZyA9IG1lYW4oeCkpIA0KKQ0KDQoNCiMgQmF5YW5naW4gcHVueWEgbGVtYXJpIGJlc2FyIG5hbWFueWEgdHJhbnNhY3Rpb25zX3N1bW1hcnksIA0KIyBkaSBsZW1hcmkgaXR1IGFkYSAgNCBsYWNpIDogMS4gUHJvZHVjdCwgMi4gUXR5LCAzLiBUb3RhbCwgNC4gUHJpY2UNCnRyYW5zYWN0aW9uc19zdW1tYXJ5IDwtIGRhdGEuZnJhbWUoDQogIFByb2R1Y3QgPSB0cmFuc2FjdGlvbnNfc3VtbWFyeSRQcm9kdWN0LA0KICANCiAgIyBBbWJpbCBtYXAgJ3N1bScgZGFyaSBsYWNpICdRdHknDQogIFRvdGFsX1F0eSA9IHRyYW5zYWN0aW9uc19zdW1tYXJ5JFF0eVssICJzdW0iXSwNCiAgDQogICMgQW1iaWwgbWFwICdzdW0nIGRhcmkgbGFjaSAnVG90YWwnDQogIFRvdGFsX1JldmVudWUgPSB0cmFuc2FjdGlvbnNfc3VtbWFyeSRUb3RhbFssICJzdW0iXSwNCiAgDQogICMgQW1iaWwgbWFwICdhdmcnIGRhcmkgbGFjaSAnUHJpY2UnLCBsYWx1IGJ1bGF0a2FuIGtlIDIgYW5na2EgZGVzaW1hbA0KICBBdmdfUHJpY2UgPSByb3VuZCh0cmFuc2FjdGlvbnNfc3VtbWFyeSRQcmljZVssICJhdmciXSwgMikNCikNCg0KDQojVGFtcGlsa2FuIFRhYmxlIE51bWVyaWMNCm51bWVyaWNfdGFibGUgPC0gdHJhbnNhY3Rpb25zWywgYygiRGF0ZSIsICJRdHkiLCAiUHJpY2UiLCAiVG90YWwiKV0gIyBkYXRhIHlhbmcgaGFueWEgZGkgYW1iaWwgRGF0ZSwgUXR5LCBQcmljZSwgVG90YWwNCg0KZGF0YXRhYmxlKA0KICBudW1lcmljX3RhYmxlLA0KICBjYXB0aW9uID0gIlRhYmxlIDI6IE51bWVyaWMgVGFibGUiLA0KICByb3duYW1lcyA9IEZBTFNFLA0KICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSkgIyBoYW55YSBtZW5hbXBpbGthbiA1IGJhcmlzIGRhdGENCikNCg0KIyBUYW1waWxrYW4gVGFibGUgQ2F0ZWdvcmljYWwNCmNhdGVnb3JpY2FsX3RhYmxlIDwtIHRyYW5zYWN0aW9uc1ssIGMoIkRhdGUiLCAiUHJvZHVjdCIsICJDdXN0b21lclRpZXIiKV0gIyBkYXRhIHlhbmcgaGFueWEgZGkgYW1iaWwgRGF0ZSwgUHJvZHVjdCwgQ3VzdG9tZXJUaWVyDQoNCmRhdGF0YWJsZSgNCiAgY2F0ZWdvcmljYWxfdGFibGUsDQogIGNhcHRpb24gPSAiVGFibGUgMzogQ2F0ZWdvcmljYWwgVGFibGUiLA0KICByb3duYW1lcyA9IEZBTFNFLA0KICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSkgIyBoYW55YSBtZW5hbXBpbGthbiA1IGJhcmlzIGRhdGENCikNCg0KIyBUYW1waWxrYW4gdGFiZWwgU3VtbWFyeQ0KZGF0YXRhYmxlKA0KICB0cmFuc2FjdGlvbnNfc3VtbWFyeSwNCiAgY2FwdGlvbiA9ICJUYWJsZSA0OiBTdW1tYXJ5IFN0YXRpc3RpY3MgcGVyIFByb2R1Y3QiLA0KICByb3duYW1lcyA9IEZBTFNFLA0KICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMykgIyBoYW55YSBtZW5hbXBpbGthbiAzIGJhcmlzIGRhdGENCikNCg0KDQojIFBFTUJVQVRBTiBCQVJQTE9UDQoNCiMgYWdncmVnYXRlIGl0dSB1bnR1ayBNZW5nZWxvbXBva2thbiBkYXRhLiBqYWRpIHBlbmdlbG9tcG9rYW4gZGF0YSB0cmFuc2FjdGlvbnMgYmVyZGFzYXJrYW4ga29sb20gUHJvZHVjdCwgDQpxdHlfcGVyX3Byb2R1Y3QgPC0gYWdncmVnYXRlKFF0eSB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkgIyBRdHkgfiBQcm9kdWN0IC0+IGtlbG9tcG9ra2FuIFF0eSBtZW51cnV0IFByb2R1Y3QNCiMgQnVhdCBiYXJwbG90DQpiYXJwbG90KA0KICBxdHlfcGVyX3Byb2R1Y3QkUXR5LCAgIyB0aW5nZ2kgYmF0YW5nIHNlc3VhaSBqdW1sYWggcGVuanVhbGFuDQogIG5hbWVzLmFyZyA9IHF0eV9wZXJfcHJvZHVjdCRQcm9kdWN0LCAjIG5hbWEgYmF0YW5nID0gbmFtYSBwcm9kdWsNCiAgY29sID0gInNreWJsdWUiLCAjIG1lbmFtcGlsa2FuIGJhciB3YXJuYSBtZW5qYWRpIGJpcnUgKHNreWJsdWUpDQogIG1haW4gPSAiVG90YWwgUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCIsICMgSnVkdWwgYmFycGxvdA0KICB4bGFiID0gIlByb2R1Y3QiLCAjIG1lbnVuanVra2FuIGRhdGEgc3VtYnUgWCAoSG9yaXpvbnRhbCkNCiAgeWxhYiA9ICJUb3RhbCBRdWFudGl0eSBTb2xkIiAjIG1lbnVuanVra2FuIGRhdGEgc3VtYnUgWSAoVmVydGlrYWwpDQogICkNCg0KIyBNZW5nZWxvbXBva2thbiBkYXRhIHRyYW5zYWN0aW9ucyBiZXJkYXNhcmthbiBDdXN0b21lclRpZXIsIGxhbHUgbWVuanVtbGFoa2FuIG5pbGFpIFRvdGFsIHVudHVrIHNldGlhcCBsZXZlbCBwZWxhbmdnYW4uDQpyZXZlbnVlX3Blcl90aWVyIDwtIGFnZ3JlZ2F0ZShUb3RhbCB+IEN1c3RvbWVyVGllciwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKSAjIFRvdGFsIH4gQ3VzdG9tZXJUaWVyIC0+IGtlbG9tcG9ra2FuIFRvdGFsIG1lbnVydXQgQ3VzdG9tZXJUaWVyDQojIEJ1YXQgcGllIGNoYXJ0DQpwaWUoDQogIHJldmVudWVfcGVyX3RpZXIkVG90YWwsICMgbmlsYWkgdG90YWwgcGVyIHRpZXINCiAgbGFiZWxzID0gcmV2ZW51ZV9wZXJfdGllciRDdXN0b21lclRpZXIsICMgbGFiZWwgdGlhcCBwb3RvbmdhbiBwaWUNCiAgY29sID0gYygicmVkIiwgInllbGxvdyIsICJncmVlbiIpLCAjIG1lbmFtcGlsa2FuIGJhciB3YXJuYSBtZXJhaCwga3VuaW5nLCBoaWphdS4NCiAgbWFpbiA9ICJQcm9wb3J0aW9uIG9mIFRvdGFsIFJldmVudWUgcGVyIEN1c3RvbWVyIFRpZXIiICMgSnVkdWwgUGllIGNoYXJ0DQopDQoNCmBgYA0KDQojIyBFeGVyY2lzZSA1DQoNCioqQ3JlYXRlIFlvdXIgT3duIERhdGEgRnJhbWU6KioNCg0KKipPYmplY3RpdmU6KiogQ3JlYXRlIGEgZGF0YSBmcmFtZSBpbiBSIHdpdGggKiozMCByb3dzKiogY29udGFpbmluZyBhIG1peCBvZiBkYXRhIHR5cGVzOiBjb250aW51b3VzLCBkaXNjcmV0ZSwgbm9taW5hbCwgYW5kIG9yZGluYWwuICANCg0KIyMjIEluc3RydWN0aW9ucw0KDQoxLiAqKk9wZW4gUlN0dWRpbyoqIG9yIHRoZSBSIGNvbnNvbGUuICANCg0KMi4gKipDcmVhdGUgYSB2ZWN0b3IgZm9yIGVhY2ggY29sdW1uKiogaW4geW91ciBkYXRhIGZyYW1lOiAgDQoNCiAgIC0gKipEYXRlKio6IDMwIGRhdGVzIChjYW4gYmUgc2VxdWVudGlhbCBvciByYW5kb20gd2l0aGluIGEgbW9udGgveWVhcikgIA0KICAgLSAqKkNvbnRpbnVvdXMqKjogbnVtZXJpYyB2YWx1ZXMgdGhhdCBjYW4gdGFrZSBkZWNpbWFsIHZhbHVlcyAoZS5nLiwgaGVpZ2h0LCB3ZWlnaHQsIHRlbXBlcmF0dXJlKSAgDQogICAtICoqRGlzY3JldGUqKjogbnVtZXJpYyB2YWx1ZXMgdGhhdCBjYW4gb25seSB0YWtlIHdob2xlIG51bWJlcnMgKGUuZy4sIG51bWJlciBvZiBpdGVtcywgbnVtYmVyIG9mIHZlaGljbGVzKSAgDQogICAtICoqTm9taW5hbCoqOiBjYXRlZ29yaWNhbCB2YWx1ZXMgd2l0aCAqKm5vIG9yZGVyKiogKGUuZy4sIGNvbG9yLCBnZW5kZXIsIGNpdHkpICANCiAgIC0gKipPcmRpbmFsKio6IGNhdGVnb3JpY2FsIHZhbHVlcyB3aXRoIGEgKipkZWZpbmVkIG9yZGVyKiogKGUuZy4sIExvdywgTWVkaXVtLCBIaWdoOyBCZWdpbm5lciwgSW50ZXJtZWRpYXRlLCBFeHBlcnQpICANCg0KMy4gKipDb21iaW5lIGFsbCB2ZWN0b3JzIGludG8gYSBkYXRhIGZyYW1lKiogY2FsbGVkIGBteV9kYXRhYC4gIA0KDQo0LiAqKkNoZWNrIHlvdXIgZGF0YSBmcmFtZSoqIHVzaW5nIGBoZWFkKClgIG9yIGBWaWV3KClgIHRvIGVuc3VyZSBpdCBoYXMgKiozMCByb3dzKiogYW5kIHRoZSBjb2x1bW5zIGFyZSBjb3JyZWN0LiAgDQoNCjUuICoqT3B0aW9uYWwgdGFza3MqKjogIA0KICAgLSBTdW1tYXJpemUgZWFjaCBjb2x1bW4gdXNpbmcgYHN1bW1hcnkoKWAgIA0KICAgLSBDb3VudCB0aGUgZnJlcXVlbmN5IG9mIGVhY2ggY2F0ZWdvcnkgZm9yICoqTm9taW5hbCoqIGFuZCAqKk9yZGluYWwqKiBjb2x1bW5zIHVzaW5nIGB0YWJsZSgpYCAgDQoNCiMjIyBIaW50cw0KDQotIFVzZSBgc2VxLkRhdGUoKWAgb3IgYGFzLkRhdGUoKWAgdG8gZ2VuZXJhdGUgdGhlIERhdGUgY29sdW1uLiAgDQotIFVzZSBgcnVuaWYoKWAgb3IgYHJub3JtKClgIGZvciBjb250aW51b3VzIG51bWVyaWMgZGF0YS4gIA0KLSBVc2UgYHNhbXBsZSgpYCBmb3IgZGlzY3JldGUsIG5vbWluYWwsIGFuZCBvcmRpbmFsIGRhdGEuICANCi0gRW5zdXJlIHRoZSAqKm9yZGluYWwgdmVjdG9yKiogaXMgY3JlYXRlZCB3aXRoIGBmYWN0b3IoLi4uLCBsZXZlbHMgPSBjKCJMb3ciLCJNZWRpdW0iLCJIaWdoIiksIG9yZGVyZWQgPSBUUlVFKWAgKG9yIHNpbWlsYXIpLiAgDQoNCmBgYHtyfQ0KIyBJbnN0YWxsIGthYmxlRXh0cmEgcGFja2FnZSBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCiMgaW5zdGFsbC5wYWNrYWdlcygia2FibGVFeHRyYSIpDQpsaWJyYXJ5KGtuaXRyKQ0KbGlicmFyeShrYWJsZUV4dHJhKSAjbGlicmFyeSB1bnR1ayBkb3VibGUgaGVhZGVyIGRpIHRhYmxlDQoNCiMgMS4gS29sb20gRGF0ZTogMzAgaGFyaSBiZXJ0dXJ1dC10dXJ1dCBkaSBidWxhbiBPa3RvYmVyIDIwMjUNCkRhdGUgPC0gc2VxLkRhdGUoZnJvbSA9IGFzLkRhdGUoIjIwMjUtMTAtMDEiKSwgYnkgPSAiZGF5IiwgbGVuZ3RoLm91dCA9IDMwKQ0KDQojIDIuIEtvbG9tIFdlYXRoZXIgVGVtcGVyYXR1cmUNCiMgTWVuZ2d1bmFrYW4gcnVuaWYoKSB1bnR1ayBtZW5naGFzaWxrYW4gYW5na2EgZGVzaW1hbCBhY2FrIGFudGFyYSAxNcKwQyBkYW4gMzXCsEMNCldlYXRoZXJfVGVtcGVyYXR1cmUgPC0gcnVuaWYoMzAsIG1pbiA9IDE1LCBtYXggPSAzNSkNCg0KIyAzLiBLb2xvbSBOdW1iZXIgb2YgR3JlZW4gQXJlYXMNCiMgTWVuZ2d1bmFrYW4gc2FtcGxlKCkgdW50dWsgbWVuZ2hhc2lsa2FuIGFuZ2thIGJ1bGF0IGFjYWsgYW50YXJhIDEgLSAyMA0KTnVtYmVyX29mX0dyZWVuX0FyZWFzIDwtIHNhbXBsZSgxOjIwLCAzMCwgcmVwbGFjZSA9IFRSVUUpIA0KDQogICMgNC4gS29sb20gQ2l0eSBOYW1lDQpDaXRpZXMgPC0gYygiTmV3IFlvcmsiLCAiTG9zIEFuZ2VsZXMiLCAiQ2hpY2FnbyIsICJIb3VzdG9uIiwgIlBob2VuaXgiLA0KICAgICAgICAgICAgIlBoaWxhZGVscGhpYSIsICJTYW4gQW50b25pbyIsICJTYW4gRGllZ28iLCAiRGFsbGFzIiwgIlNhbiBKb3NlIikNCkNpdHlfTmFtZSA8LSBzYW1wbGUoQ2l0aWVzLCAzMCwgcmVwbGFjZSA9IFRSVUUpICMgdW50dWsgbWVtaWxpaCBuYW1hIGtvdGEgc2VjYXJhIGFjYWsgZGFyaSBkYWZ0YXINCg0KIyA1LiBLb2xvbSBDcmltZSBMZXZlbA0KIyBNZW5nZ3VuYWthbiBmYWN0b3IoKSBkZW5nYW4gdXJ1dGFuIGxldmVsIGRhcmkgcmVuZGFoIGtlIHRpbmdnaSAoTG93IDwgTWVkaXVtIDwgSGlnaCkNCkNyaW1lX0xldmVsIDwtIGZhY3RvcigNCiAgc2FtcGxlKGMoIkxvdyIsICJNZWRpdW0iLCAiSGlnaCIpLCAzMCwgcmVwbGFjZSA9IFRSVUUpLA0KICBsZXZlbHMgPSBjKCJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSwNCiAgb3JkZXJlZCA9IFRSVUUNCikNCg0KIyBNZW5nZ2FidW5na2FuIHNlbXVhIGtvbG9tIG1lbmphZGkgc2F0dSBkYXRhIGZyYW1lIGJlcm5hbWEgbXlfZGF0YQ0KbXlfZGF0YSA8LSBkYXRhLmZyYW1lKA0KICBEYXRlID0gRGF0ZSwNCiAgV2VhdGhlcl9UZW1wZXJhdHVyZSA9IFdlYXRoZXJfVGVtcGVyYXR1cmUsDQogIE51bWJlcl9vZl9HcmVlbl9BcmVhcyA9IE51bWJlcl9vZl9HcmVlbl9BcmVhcywNCiAgQ2l0eV9OYW1lID0gQ2l0eV9OYW1lLA0KICBDcmltZV9MZXZlbCA9IENyaW1lX0xldmVsDQopDQoNClZpZXcobXlfZGF0YSkjbWVsaWhhdCBzZW11YSBkYXRhDQoNCiNVbnR1ayBtZW5hbXBpbGthbiBLb2x1bSBEYXRhIGRhbiBCYXJpcyBoZWFkZXIgdGFibGUNCmthYmxlKG15X2RhdGEsDQogICAgICAgIGNhcHRpb24gPSAiQ2l0eSBFbnZpcm9ubWVudCAmIENyaW1lIExldmVsIERhdGFzZXQiLA0KICAgICAgICBjb2wubmFtZXMgPSBjKCJEYXRlIiwgIkFpciBUZW1wZXJhdHVyZSAowrBDKSIsICJOdW1iZXIgb2YgR3JlZW4gQXJlYXMiLCAiQ2l0eSBOYW1lIiwgIkNyaW1lIExldmVsIiksDQogICAgICAgIGFsaWduID0gImMiKSAlPiUNCiAgICBhZGRfaGVhZGVyX2Fib3ZlKGMoIiAiID0gMSwgIkNvbnRpbm91cyIgPSAxLCAiRGlzY3JldGUiID0gMSwgIk5vbWluYWwiID0gMSwgIk9yZGluYWwiID0gMSkNCikgDQoNCmBgYA0KDQoNCg0K