Descriptive Visualizations

Data Science Programming

Logo

1. Visualizations Combo

1.1 Heatmap

library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.4.3
## Warning: package 'readr' was built under R version 4.4.3
## Warning: package 'purrr' was built under R version 4.4.3
## Warning: package 'forcats' was built under R version 4.4.3
## Warning: package 'lubridate' was built under R version 4.4.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.4     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(ggplot2)
library(readr)

# Baca data
setwd("C:/Users/M Nabil Pratama/Downloads/dsp")
df <- read_csv("Data_Business.csv")
## New names:
## Rows: 500 Columns: 25
## ── Column specification
## ──────────────────────────────────────────────────────── Delimiter: "," chr
## (8): Transaction_ID, Customer_ID, Product_Category, Product_ID, Region... dbl
## (15): ...1, Quantity, Unit_Price, Discount, Delivery_Time, Total_Price,... lgl
## (1): ID_HasPattern date (1): Transaction_Date
## ℹ Use `spec()` to retrieve the full column specification for this data. ℹ
## Specify the column types or set `show_col_types = FALSE` to quiet this message.
## • `` -> `...1`
# Totalin dulu
pivot_df <- df %>%
  group_by(Product_Category, Region) %>%
  summarise(Total_Sales = sum(Total_Price, na.rm = TRUE), .groups = "drop")

# Bikin heatmap-nya
ggplot(pivot_df, aes(x = Region, y = Product_Category, fill = Total_Sales)) +
  geom_tile(color = "white") +
  scale_fill_gradientn(colours = rev(RColorBrewer::brewer.pal(9, "BuPu")),
                       name = "Total Sales (Rp)") +
  geom_text(aes(label = round(Total_Sales, 0)), color = "black", size = 3) +
  labs(title = "🔥 Heatmap Total Sales by Product Category and Region",
       x = "Region", y = "Product Category") +
  theme_minimal(base_size = 12)

2. Relationship

2.1 Scatter Plot

library(ggplot2)
library(readr)

# Load data
setwd("C:/Users/M Nabil Pratama/Downloads/dsp")
df <- read_csv("Data_Business.csv")
## New names:
## Rows: 500 Columns: 25
## ── Column specification
## ──────────────────────────────────────────────────────── Delimiter: "," chr
## (8): Transaction_ID, Customer_ID, Product_Category, Product_ID, Region... dbl
## (15): ...1, Quantity, Unit_Price, Discount, Delivery_Time, Total_Price,... lgl
## (1): ID_HasPattern date (1): Transaction_Date
## ℹ Use `spec()` to retrieve the full column specification for this data. ℹ
## Specify the column types or set `show_col_types = FALSE` to quiet this message.
## • `` -> `...1`
# Plot
ggplot(df, aes(x = Quantity, y = Total_Price)) +
  geom_point(color = "darkorange", fill = "orange", alpha = 0.6, shape = 21, size = 2.5, stroke = 0.3) +
  labs(
    title = "Visualisasi Relasi Quantity & Total Price",
    x = "Jumlah Produk (Quantity)",
    y = "Total Harga (Rp)"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0),
    panel.grid.major = element_line(linetype = "dashed", color = "grey80")
  )

2.2 Bubble Chart

library(ggplot2)
library(readr)
library(dplyr)

# Load data
setwd("C:/Users/M Nabil Pratama/Downloads/dsp")
df <- read_csv("Data_Business.csv")
## New names:
## Rows: 500 Columns: 25
## ── Column specification
## ──────────────────────────────────────────────────────── Delimiter: "," chr
## (8): Transaction_ID, Customer_ID, Product_Category, Product_ID, Region... dbl
## (15): ...1, Quantity, Unit_Price, Discount, Delivery_Time, Total_Price,... lgl
## (1): ID_HasPattern date (1): Transaction_Date
## ℹ Use `spec()` to retrieve the full column specification for this data. ℹ
## Specify the column types or set `show_col_types = FALSE` to quiet this message.
## • `` -> `...1`
# Aggregasi
df_grouped <- df %>%
  group_by(Product_Category, Region) %>%
  summarise(
    Quantity = sum(Quantity),
    Total_Price = sum(Total_Price),
    .groups = 'drop'
  )

# Visualisasi bubble
ggplot(df_grouped, aes(x = Product_Category, y = Quantity)) +
  geom_point(aes(size = Total_Price, fill = Region), shape = 21, alpha = 0.6, color = "grey30", stroke = 0.4) +
  geom_text(aes(label = Product_Category), vjust = 0.5, fontface = "bold", size = 3.5) +
  scale_size_continuous(range = c(5, 20)) +
  scale_fill_brewer(palette = "Pastel1") +
  labs(
    title = "Creative 4D Bubble Chart:\nCategory vs Quantity (Size = Total Price, Color = Region)",
    x = "Product Category",
    y = "Total Quantity",
    size = "Total Price",
    fill = "Region"
  ) +
  theme_minimal(base_size = 12) +
  theme(
    plot.title = element_text(face = "bold"),
    panel.grid.major = element_line(linetype = "dotted", color = "gray80")
  )

2.3 Correlation Matrix

# Load packages
library(ggplot2)
library(reshape2)
## Warning: package 'reshape2' was built under R version 4.4.3
## 
## Attaching package: 'reshape2'
## The following object is masked from 'package:tidyr':
## 
##     smiths
library(scales)
## 
## Attaching package: 'scales'
## The following object is masked from 'package:purrr':
## 
##     discard
## The following object is masked from 'package:readr':
## 
##     col_factor
# Load data
setwd("C:/Users/M Nabil Pratama/Downloads/dsp")
df <- read.csv("Data_Business.csv")

# Compute correlation matrix
cor_matrix <- cor(df[sapply(df, is.numeric)], use = "complete.obs")
## Warning in cor(df[sapply(df, is.numeric)], use = "complete.obs"): the standard
## deviation is zero
# Melt the matrix for ggplot2
cor_melt <- melt(cor_matrix)
colnames(cor_melt) <- c("Var1", "Var2", "Correlation")

# Bubble plot
ggplot(cor_melt, aes(x = Var1, y = Var2, fill = Correlation, size = abs(Correlation))) +
  geom_point(shape = 21, color = "black", alpha = 0.8) +
  geom_text(aes(label = round(Correlation, 2)), size = 3, color = "black", fontface = "bold") +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red", midpoint = 0) +
  scale_size(range = c(1, 15)) +
  theme_minimal(base_size = 12) +
  labs(
    title = "4D Correlation Matrix (Size & Color = Strength)",
    x = "Variable",
    y = "Variable",
    fill = "Correlation",
    size = "Abs(Correlation)"
  ) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid = element_blank()
  )
## Warning: Removed 28 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 28 rows containing missing values or values outside the scale range
## (`geom_text()`).

3. Time Series

3.1 Line Chart

library(ggplot2)
library(dplyr)

# Load data
setwd("C:/Users/M Nabil Pratama/Downloads/dsp")
df <- read.csv("Data_Business.csv")

# Ubah ke format Date
df$Transaction_Date <- as.Date(df$Transaction_Date)

# Agregasi per tanggal
daily_total <- df %>%
  group_by(Transaction_Date) %>%
  summarise(Total_Price = sum(Total_Price))

# Plot line chart
ggplot(daily_total, aes(x = Transaction_Date, y = Total_Price)) +
  geom_line(color = "steelblue", size = 1) +
  geom_point(color = "darkblue") +
  labs(title = "Total Harga per Hari",
       x = "Tanggal", y = "Total Harga") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

3.2 Area Chart

# Load libraries
library(ggplot2)
library(dplyr)
library(readr)

# Load data (Pastikan file ada di direktori yang benar)
setwd("C:/Users/M Nabil Pratama/Downloads/dsp")
df <- read_csv("Data_Business.csv")
## New names:
## Rows: 500 Columns: 25
## ── Column specification
## ──────────────────────────────────────────────────────── Delimiter: "," chr
## (8): Transaction_ID, Customer_ID, Product_Category, Product_ID, Region... dbl
## (15): ...1, Quantity, Unit_Price, Discount, Delivery_Time, Total_Price,... lgl
## (1): ID_HasPattern date (1): Transaction_Date
## ℹ Use `spec()` to retrieve the full column specification for this data. ℹ
## Specify the column types or set `show_col_types = FALSE` to quiet this message.
## • `` -> `...1`
# Convert Transaction_Date to Date type
df$Transaction_Date <- as.Date(df$Transaction_Date)

# Agregasi total harga per tanggal, kategori, dan region
agg_df <- df %>%
  group_by(Transaction_Date, Product_Category, Region) %>%
  summarise(Total_Price = sum(Total_Price), .groups = 'drop')

# Plot area chart dengan facet per Region
ggplot(agg_df, aes(x = Transaction_Date, y = Total_Price, fill = Product_Category)) +
  geom_area(alpha = 0.8, position = "stack") +
  facet_wrap(~Region, scales = "free_y") +
  labs(
    title = "Area Chart Total Harga per Kategori Produk - Tiap Region",
    x = "Tanggal",
    y = "Total Harga"
  ) +
  theme_minimal(base_size = 12) +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

LS0tDQp0aXRsZTogIkRlc2NyaXB0aXZlIFZpc3VhbGl6YXRpb25zIg0Kc3VidGl0bGU6ICJEYXRhIFNjaWVuY2UgUHJvZ3JhbW1pbmciDQphdXRob3I6ICJNdWhhbW1hZCBOYWJpbCBQcmF0YW1hIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIg0Kb3V0cHV0Og0KICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjoNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIHRodW1ibmFpbHM6IHRydWUNCiAgICBsaWdodGJveDogdHJ1ZQ0KICAgIGdhbGxlcnk6IHRydWUNCiAgICBsaWJfZGlyOiBsaWJzDQogICAgZGZfcHJpbnQ6ICJwYWdlZCINCiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93Ig0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGNzczogInN0eWxlLmNzcyINCi0tLQ0KDQo8aW1nIHNyYz0iQzovVXNlcnMvTSBOYWJpbCBQcmF0YW1hL09uZURyaXZlL1BpY3R1cmVzL1NjcmVlbnNob3RzL0dhbWJhciBXaGF0c0FwcCAyMDI0LTEyLTA2IHB1a3VsIDEzLjMzLjE1X2MzZmQwZmM3LmpwZyIgYWx0PSJMb2dvIiBpZD0iaXNpX25hbWEiIHN0eWxlPSJ3aWR0aDoyMDBweDsgZGlzcGxheTogYmxvY2s7IG1hcmdpbjogYXV0bzsiLz4NCg0KIyAqKjEuIFZpc3VhbGl6YXRpb25zIENvbWJvKioNCiMjICoqMS4xIEhlYXRtYXAqKg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShyZWFkcikNCg0KIyBCYWNhIGRhdGENCnNldHdkKCJDOi9Vc2Vycy9NIE5hYmlsIFByYXRhbWEvRG93bmxvYWRzL2RzcCIpDQpkZiA8LSByZWFkX2NzdigiRGF0YV9CdXNpbmVzcy5jc3YiKQ0KDQojIFRvdGFsaW4gZHVsdQ0KcGl2b3RfZGYgPC0gZGYgJT4lDQogIGdyb3VwX2J5KFByb2R1Y3RfQ2F0ZWdvcnksIFJlZ2lvbikgJT4lDQogIHN1bW1hcmlzZShUb3RhbF9TYWxlcyA9IHN1bShUb3RhbF9QcmljZSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikNCg0KIyBCaWtpbiBoZWF0bWFwLW55YQ0KZ2dwbG90KHBpdm90X2RmLCBhZXMoeCA9IFJlZ2lvbiwgeSA9IFByb2R1Y3RfQ2F0ZWdvcnksIGZpbGwgPSBUb3RhbF9TYWxlcykpICsNCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvdXJzID0gcmV2KFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbCg5LCAiQnVQdSIpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJUb3RhbCBTYWxlcyAoUnApIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoVG90YWxfU2FsZXMsIDApKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMykgKw0KICBsYWJzKHRpdGxlID0gIvCflKUgSGVhdG1hcCBUb3RhbCBTYWxlcyBieSBQcm9kdWN0IENhdGVnb3J5IGFuZCBSZWdpb24iLA0KICAgICAgIHggPSAiUmVnaW9uIiwgeSA9ICJQcm9kdWN0IENhdGVnb3J5IikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKQ0KDQpgYGANCg0KIyAqKjIuIFJlbGF0aW9uc2hpcCoqDQoNCiMjICoqMi4xIFNjYXR0ZXIgUGxvdCoqDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocmVhZHIpDQoNCiMgTG9hZCBkYXRhDQpzZXR3ZCgiQzovVXNlcnMvTSBOYWJpbCBQcmF0YW1hL0Rvd25sb2Fkcy9kc3AiKQ0KZGYgPC0gcmVhZF9jc3YoIkRhdGFfQnVzaW5lc3MuY3N2IikNCg0KIyBQbG90DQpnZ3Bsb3QoZGYsIGFlcyh4ID0gUXVhbnRpdHksIHkgPSBUb3RhbF9QcmljZSkpICsNCiAgZ2VvbV9wb2ludChjb2xvciA9ICJkYXJrb3JhbmdlIiwgZmlsbCA9ICJvcmFuZ2UiLCBhbHBoYSA9IDAuNiwgc2hhcGUgPSAyMSwgc2l6ZSA9IDIuNSwgc3Ryb2tlID0gMC4zKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiVmlzdWFsaXNhc2kgUmVsYXNpIFF1YW50aXR5ICYgVG90YWwgUHJpY2UiLA0KICAgIHggPSAiSnVtbGFoIFByb2R1ayAoUXVhbnRpdHkpIiwNCiAgICB5ID0gIlRvdGFsIEhhcmdhIChScCkiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImdyZXk4MCIpDQogICkNCmBgYA0KDQojIyAqKjIuMiBCdWJibGUgQ2hhcnQqKg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCg0KIyBMb2FkIGRhdGENCnNldHdkKCJDOi9Vc2Vycy9NIE5hYmlsIFByYXRhbWEvRG93bmxvYWRzL2RzcCIpDQpkZiA8LSByZWFkX2NzdigiRGF0YV9CdXNpbmVzcy5jc3YiKQ0KDQojIEFnZ3JlZ2FzaQ0KZGZfZ3JvdXBlZCA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkoUHJvZHVjdF9DYXRlZ29yeSwgUmVnaW9uKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIFF1YW50aXR5ID0gc3VtKFF1YW50aXR5KSwNCiAgICBUb3RhbF9QcmljZSA9IHN1bShUb3RhbF9QcmljZSksDQogICAgLmdyb3VwcyA9ICdkcm9wJw0KICApDQoNCiMgVmlzdWFsaXNhc2kgYnViYmxlDQpnZ3Bsb3QoZGZfZ3JvdXBlZCwgYWVzKHggPSBQcm9kdWN0X0NhdGVnb3J5LCB5ID0gUXVhbnRpdHkpKSArDQogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBUb3RhbF9QcmljZSwgZmlsbCA9IFJlZ2lvbiksIHNoYXBlID0gMjEsIGFscGhhID0gMC42LCBjb2xvciA9ICJncmV5MzAiLCBzdHJva2UgPSAwLjQpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFByb2R1Y3RfQ2F0ZWdvcnkpLCB2anVzdCA9IDAuNSwgZm9udGZhY2UgPSAiYm9sZCIsIHNpemUgPSAzLjUpICsNCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYyg1LCAyMCkpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJQYXN0ZWwxIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkNyZWF0aXZlIDREIEJ1YmJsZSBDaGFydDpcbkNhdGVnb3J5IHZzIFF1YW50aXR5IChTaXplID0gVG90YWwgUHJpY2UsIENvbG9yID0gUmVnaW9uKSIsDQogICAgeCA9ICJQcm9kdWN0IENhdGVnb3J5IiwNCiAgICB5ID0gIlRvdGFsIFF1YW50aXR5IiwNCiAgICBzaXplID0gIlRvdGFsIFByaWNlIiwNCiAgICBmaWxsID0gIlJlZ2lvbiINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gImRvdHRlZCIsIGNvbG9yID0gImdyYXk4MCIpDQogICkNCmBgYA0KDQojIyAyLjMgQ29ycmVsYXRpb24gTWF0cml4DQoNCmBgYHtyfQ0KIyBMb2FkIHBhY2thZ2VzDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShzY2FsZXMpDQoNCiMgTG9hZCBkYXRhDQpzZXR3ZCgiQzovVXNlcnMvTSBOYWJpbCBQcmF0YW1hL0Rvd25sb2Fkcy9kc3AiKQ0KZGYgPC0gcmVhZC5jc3YoIkRhdGFfQnVzaW5lc3MuY3N2IikNCg0KIyBDb21wdXRlIGNvcnJlbGF0aW9uIG1hdHJpeA0KY29yX21hdHJpeCA8LSBjb3IoZGZbc2FwcGx5KGRmLCBpcy5udW1lcmljKV0sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQ0KDQojIE1lbHQgdGhlIG1hdHJpeCBmb3IgZ2dwbG90Mg0KY29yX21lbHQgPC0gbWVsdChjb3JfbWF0cml4KQ0KY29sbmFtZXMoY29yX21lbHQpIDwtIGMoIlZhcjEiLCAiVmFyMiIsICJDb3JyZWxhdGlvbiIpDQoNCiMgQnViYmxlIHBsb3QNCmdncGxvdChjb3JfbWVsdCwgYWVzKHggPSBWYXIxLCB5ID0gVmFyMiwgZmlsbCA9IENvcnJlbGF0aW9uLCBzaXplID0gYWJzKENvcnJlbGF0aW9uKSkpICsNCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC44KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChDb3JyZWxhdGlvbiwgMikpLCBzaXplID0gMywgY29sb3IgPSAiYmxhY2siLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIiwgbWlkcG9pbnQgPSAwKSArDQogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDEsIDE1KSkgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEyKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiNEQgQ29ycmVsYXRpb24gTWF0cml4IChTaXplICYgQ29sb3IgPSBTdHJlbmd0aCkiLA0KICAgIHggPSAiVmFyaWFibGUiLA0KICAgIHkgPSAiVmFyaWFibGUiLA0KICAgIGZpbGwgPSAiQ29ycmVsYXRpb24iLA0KICAgIHNpemUgPSAiQWJzKENvcnJlbGF0aW9uKSINCiAgKSArDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKQ0KICApDQpgYGANCg0KIyAqKjMuIFRpbWUgU2VyaWVzKioNCiMjICoqMy4xIExpbmUgQ2hhcnQqKg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQoNCiMgTG9hZCBkYXRhDQpzZXR3ZCgiQzovVXNlcnMvTSBOYWJpbCBQcmF0YW1hL0Rvd25sb2Fkcy9kc3AiKQ0KZGYgPC0gcmVhZC5jc3YoIkRhdGFfQnVzaW5lc3MuY3N2IikNCg0KIyBVYmFoIGtlIGZvcm1hdCBEYXRlDQpkZiRUcmFuc2FjdGlvbl9EYXRlIDwtIGFzLkRhdGUoZGYkVHJhbnNhY3Rpb25fRGF0ZSkNCg0KIyBBZ3JlZ2FzaSBwZXIgdGFuZ2dhbA0KZGFpbHlfdG90YWwgPC0gZGYgJT4lDQogIGdyb3VwX2J5KFRyYW5zYWN0aW9uX0RhdGUpICU+JQ0KICBzdW1tYXJpc2UoVG90YWxfUHJpY2UgPSBzdW0oVG90YWxfUHJpY2UpKQ0KDQojIFBsb3QgbGluZSBjaGFydA0KZ2dwbG90KGRhaWx5X3RvdGFsLCBhZXMoeCA9IFRyYW5zYWN0aW9uX0RhdGUsIHkgPSBUb3RhbF9QcmljZSkpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gInN0ZWVsYmx1ZSIsIHNpemUgPSAxKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAiZGFya2JsdWUiKSArDQogIGxhYnModGl0bGUgPSAiVG90YWwgSGFyZ2EgcGVyIEhhcmkiLA0KICAgICAgIHggPSAiVGFuZ2dhbCIsIHkgPSAiVG90YWwgSGFyZ2EiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KIyMgKiozLjIgQXJlYSBDaGFydCoqDQoNCmBgYHtyfQ0KIyBMb2FkIGxpYnJhcmllcw0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmVhZHIpDQoNCiMgTG9hZCBkYXRhIChQYXN0aWthbiBmaWxlIGFkYSBkaSBkaXJla3RvcmkgeWFuZyBiZW5hcikNCnNldHdkKCJDOi9Vc2Vycy9NIE5hYmlsIFByYXRhbWEvRG93bmxvYWRzL2RzcCIpDQpkZiA8LSByZWFkX2NzdigiRGF0YV9CdXNpbmVzcy5jc3YiKQ0KDQojIENvbnZlcnQgVHJhbnNhY3Rpb25fRGF0ZSB0byBEYXRlIHR5cGUNCmRmJFRyYW5zYWN0aW9uX0RhdGUgPC0gYXMuRGF0ZShkZiRUcmFuc2FjdGlvbl9EYXRlKQ0KDQojIEFncmVnYXNpIHRvdGFsIGhhcmdhIHBlciB0YW5nZ2FsLCBrYXRlZ29yaSwgZGFuIHJlZ2lvbg0KYWdnX2RmIDwtIGRmICU+JQ0KICBncm91cF9ieShUcmFuc2FjdGlvbl9EYXRlLCBQcm9kdWN0X0NhdGVnb3J5LCBSZWdpb24pICU+JQ0KICBzdW1tYXJpc2UoVG90YWxfUHJpY2UgPSBzdW0oVG90YWxfUHJpY2UpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQojIFBsb3QgYXJlYSBjaGFydCBkZW5nYW4gZmFjZXQgcGVyIFJlZ2lvbg0KZ2dwbG90KGFnZ19kZiwgYWVzKHggPSBUcmFuc2FjdGlvbl9EYXRlLCB5ID0gVG90YWxfUHJpY2UsIGZpbGwgPSBQcm9kdWN0X0NhdGVnb3J5KSkgKw0KICBnZW9tX2FyZWEoYWxwaGEgPSAwLjgsIHBvc2l0aW9uID0gInN0YWNrIikgKw0KICBmYWNldF93cmFwKH5SZWdpb24sIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQXJlYSBDaGFydCBUb3RhbCBIYXJnYSBwZXIgS2F0ZWdvcmkgUHJvZHVrIC0gVGlhcCBSZWdpb24iLA0KICAgIHggPSAiVGFuZ2dhbCIsDQogICAgeSA9ICJUb3RhbCBIYXJnYSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCmBgYA0KDQo=