setwd("D:/BTL/BTL XSTK/archive")
Warning: The working directory was changed to D:/BTL/BTL XSTK/archive inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
#Import data:
gpus = read.csv("All_GPUs.csv", header = TRUE)
gpus
# Khởi tạo danh sách các cột cần xóa
columns_to_remove <- c()

# Lặp qua từng cột trong dataframe 'gpus'
for (column in names(gpus)) {
  numCellNAorBlank <- sum(is.na(gpus[[column]]) | gpus[[column]] == "" | gpus[[column]] == "\n- ")
  numCell <- length(gpus[[column]])
  napercentage <- numCellNAorBlank / numCell
  print(paste(column, napercentage))
  # Nếu phần trăm giá trị NA lớn hơn hoặc bằng 0.2, thêm tên cột vào danh sách cần xóa
  if (napercentage >= 0.2) {
    columns_to_remove <- c(columns_to_remove, column)
  }
}
[1] "Architecture 0.0182031708749266"
[1] "Best_Resolution 0.188490898414563"
[1] "Boost_Clock 0.575455079271873"
[1] "Core_Speed 0.266294773928362"
[1] "DVI_Connection 0.220199647680564"
[1] "Dedicated 0.00411039342337052"
[1] "Direct_X 0.00176159718144451"
[1] "DisplayPort_Connection 0.748385202583676"
[1] "HDMI_Connection 0.224016441573693"
[1] "Integrated 0.00411039342337052"
[1] "L2_Cache 0"
[1] "Manufacturer 0"
[1] "Max_Power 0.18349970640047"
[1] "Memory 0.123311802701116"
[1] "Memory_Bandwidth 0.0355255431591309"
[1] "Memory_Bus 0.0182031708749266"
[1] "Memory_Speed 0.0308279506752789"
[1] "Memory_Type 0.0164415736934821"
[1] "Name 0"
[1] "Notebook_GPU 0"
[1] "Open_GL 0.0117439812096301"
[1] "PSU 0.344979448032883"
[1] "Pixel_Rate 0.159718144450969"
[1] "Power_Connector 0.208162066940693"
[1] "Process 0.135936582501468"
[1] "ROPs 0.157956547269524"
[1] "Release_Date 0"
[1] "Release_Price 0.836758661186142"
[1] "Resolution_WxH 0.0572519083969466"
[1] "SLI_Crossfire 0"
[1] "Shader 0.0314151497357604"
[1] "TMUs 0.157956547269524"
[1] "Texture_Rate 0.159718144450969"
[1] "VGA_Connection 0.22254844392249"
print("Các cột bị xóa:")
[1] "Các cột bị xóa:"
print(columns_to_remove)
[1] "Boost_Clock"            "Core_Speed"            
[3] "DVI_Connection"         "DisplayPort_Connection"
[5] "HDMI_Connection"        "PSU"                   
[7] "Power_Connector"        "Release_Price"         
[9] "VGA_Connection"        
# Xóa tất cả các cột trong danh sách cần xóa
lessNA_gpus <- gpus[, !(names(gpus) %in% columns_to_remove)]

# In ra số lượng cột còn lại
print(paste("Số cột còn lại: ", length(names(lessNA_gpus))))
[1] "Số cột còn lại:  25"
#Bỏ một số cột không cần thiết/bị lỗi
rem_cols = c("ROPs", "L2_Cache", "Name", "Integrated", "Resolution_WxH", "Best_Resolution")
lessNA_gpus = lessNA_gpus[, !(names(lessNA_gpus) %in% rem_cols)]
names(lessNA_gpus)
 [1] "Architecture"     "Dedicated"        "Direct_X"        
 [4] "Manufacturer"     "Max_Power"        "Memory"          
 [7] "Memory_Bandwidth" "Memory_Bus"       "Memory_Speed"    
[10] "Memory_Type"      "Notebook_GPU"     "Open_GL"         
[13] "Pixel_Rate"       "Process"          "Release_Date"    
[16] "SLI_Crossfire"    "Shader"           "TMUs"            
[19] "Texture_Rate"    
#Kiểm tra và xóa hàng trùng
duplicate_rows = lessNA_gpus[duplicated(lessNA_gpus),]
non_dup_gpus = unique(lessNA_gpus)
#Chuyển các cột categorical về dạng số
library(dplyr)
# Cài đặt và tải thư viện forcats
# install.packages("forcats")
library(forcats)

non_dup_gpus$Dedicated <- recode(non_dup_gpus$Dedicated, 'Yes' = 1, 'No' = 0)
Warning: Unreplaced values treated as NA as `.x` is not compatible. 
non_dup_gpus$Direct_X <- fct_lump(non_dup_gpus$Direct_X, n = 5, other_level = "Other")
non_dup_gpus$Notebook_GPU <- recode(non_dup_gpus$Notebook_GPU, 'Yes' = 1, 'No' = 0)
non_dup_gpus$SLI_Crossfire <- recode(non_dup_gpus$SLI_Crossfire, 'Yes' = 1, 'No' = 0)
#Xử lý cột Release_Date, chuyển thành cột Release_Year
# Loại bỏ các khoảng trắng và dấu xuống dòng không cần thiết
non_dup_gpus$Release_Date <- trimws(non_dup_gpus$Release_Date)

# Chuyển đổi cột Release_Date thành đối tượng ngày
date_conversion <- as.Date(non_dup_gpus$Release_Date, format="%d-%b-%Y")

# Tìm các hàng có giá trị ngày hợp lệ
valid_dates <- !is.na(date_conversion)

# Giữ lại chỉ các hàng có giá trị ngày hợp lệ
non_dup_gpus <- non_dup_gpus[valid_dates, ]

# Tạo cột Release_Year và chuyển đổi thành số
non_dup_gpus$Release_Year <- as.numeric(format(date_conversion[valid_dates], "%Y"))

# Xóa cột Release_Date
non_dup_gpus$Release_Date <- NULL


# Bỏ đơn vị và chuyển các cột kiểu character thành kiểu số
non_dup_gpus$Max_Power <- as.numeric(gsub(" Watts", "", non_dup_gpus$Max_Power))
non_dup_gpus$Memory <- as.numeric(gsub(" MB", "", non_dup_gpus$Memory))
non_dup_gpus$Memory_Bandwidth <- as.numeric(gsub("GB/sec", "", non_dup_gpus$Memory_Bandwidth))
Warning: NAs introduced by coercion
non_dup_gpus$Memory_Bus <- as.numeric(gsub(" Bit", "", non_dup_gpus$Memory_Bus))
non_dup_gpus$Memory_Speed <- as.numeric(gsub(" MHz", "", non_dup_gpus$Memory_Speed))
non_dup_gpus$Pixel_Rate <- as.numeric(gsub(" GPixel/s", "", non_dup_gpus$Pixel_Rate))
non_dup_gpus$Process <- as.numeric(gsub("nm", "", non_dup_gpus$Process))
non_dup_gpus$TMUs <- as.numeric(non_dup_gpus$TMUs)
non_dup_gpus$Texture_Rate <- as.numeric(gsub(" GTexel/s", "", non_dup_gpus$Texture_Rate))
# Cài đặt và tải các thư viện cần thiết
# install.packages(c(tidyverse"))
library(tidyverse)

# In ra số dòng dữ liệu khuyết của mỗi cột
colSums(is.na(non_dup_gpus))
    Architecture        Dedicated         Direct_X     Manufacturer 
               0               14                0                0 
       Max_Power           Memory Memory_Bandwidth       Memory_Bus 
             579              337              118               57 
    Memory_Speed      Memory_Type     Notebook_GPU          Open_GL 
              98                0                0               36 
      Pixel_Rate          Process    SLI_Crossfire           Shader 
             503              423                0               83 
            TMUs     Texture_Rate     Release_Year 
             497              503                0 
# Xử lý dữ liệu khuyết trên các cột kiểu số
# Tạo DataFrame gom nhóm theo Manufacturer
grouped_df <- non_dup_gpus %>% group_by(Manufacturer)

# Thay thế N/A bằng trung vị của nhóm
non_dup_gpus <- grouped_df %>% mutate_if(is.numeric, funs(ifelse(is.na(.) | . == "", median(., na.rm = TRUE), .)))
`mutate_if()` ignored the following grouping variables:Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))
# Thay thế 0 bằng trung vị của cột
non_dup_gpus <- non_dup_gpus %>% mutate_if(is.numeric, funs(ifelse(. == 0, median(., na.rm = TRUE), .)))
`mutate_if()` ignored the following grouping variables:Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))
# Xử lý dữ liệu khuyết trên các biến phân loại
# Thay thế N/A bằng giá trị có tần suất xuất hiện cao nhất
non_dup_gpus <- non_dup_gpus %>% mutate_if(is.factor, funs(ifelse(is.na(.) | . == "", names(which.max(table(.))), .)))
`mutate_if()` ignored the following grouping variables:Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))
# Thay thế N/A hoặc rỗng bằng giá trị có tần suất xuất hiện cao nhất
non_dup_gpus <- non_dup_gpus %>% mutate_if(is.character, funs(ifelse(is.na(.) | . == "", names(which.max(table(na.omit(.[. != "" & . != " "])))), .)))
`mutate_if()` ignored the following grouping variables:Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))
# Bỏ đi biến Manufacturer
non_dup_gpus$Manufacturer <- NULL

# Kiểm tra lại số dòng dữ liệu N/A
colSums(is.na(non_dup_gpus) | non_dup_gpus == "")
    Architecture        Dedicated         Direct_X        Max_Power 
               0                0                0                0 
          Memory Memory_Bandwidth       Memory_Bus     Memory_Speed 
               0                0                0                0 
     Memory_Type     Notebook_GPU          Open_GL       Pixel_Rate 
               0                0                0                0 
         Process    SLI_Crossfire           Shader             TMUs 
               0                0                0                0 
    Texture_Rate     Release_Year 
               0                0 
new_gpus = non_dup_gpus
# Cài đặt và tải gói writexl
install.packages('writexl')
Error in install.packages : Updating loaded packages
library(writexl)


# Lưu DataFrame thành file Excel
write_xlsx(new_gpus, 'new_GPUs.xlsx')
#THỐNG KÊ TẢ
#Tính trung bình mẫu
mean<-apply(non_dup_gpus[,c("Memory","Memory_Bandwidth","Memory_Bus","Memory_Speed",
                            "Open_GL", "Pixel_Rate","Shader","TMUs","Texture_Rate",
                            "Release_Year","Direct_X")], 2, mean)
#Tính độ lệch chuẩn
sd<-apply(non_dup_gpus[,c("Memory","Memory_Bandwidth","Memory_Bus","Memory_Speed",
                          "Open_GL", "Pixel_Rate","Shader","TMUs","Texture_Rate",
                          "Release_Year","Direct_X")], 2, sd)
#Tính phân vị 1
Q1<-apply(non_dup_gpus[,c("Memory","Memory_Bandwidth","Memory_Bus","Memory_Speed",
                          "Open_GL", "Pixel_Rate","Shader","TMUs","Texture_Rate",
                          "Release_Year","Direct_X")], 2, quantile, probs = 0.25)
#Tính trung vị
med<-apply(non_dup_gpus[,c("Memory","Memory_Bandwidth","Memory_Bus","Memory_Speed",
                           "Open_GL", "Pixel_Rate","Shader","TMUs","Texture_Rate",
                           "Release_Year","Direct_X")], 2, median)
#Tính phân vị 3
Q3<-apply(non_dup_gpus[,c("Memory","Memory_Bandwidth","Memory_Bus","Memory_Speed",
                          "Open_GL", "Pixel_Rate","Shader","TMUs","Texture_Rate",
                          "Release_Year","Direct_X")], 2, quantile, probs = 0.75)
#Tính giá trị lớn nhất
Max<-apply(non_dup_gpus[,c("Memory","Memory_Bandwidth","Memory_Bus","Memory_Speed",
                           "Open_GL", "Pixel_Rate","Shader","TMUs","Texture_Rate",
                           "Release_Year","Direct_X")], 2, max)
#Tính giá trị nhỏ nhất
Min<-apply(non_dup_gpus[,c("Memory","Memory_Bandwidth","Memory_Bus","Memory_Speed",
                            "Open_GL", "Pixel_Rate","Shader","TMUs","Texture_Rate",
                            "Release_Year","Direct_X")], 2, min)
data.frame(mean, sd, Q1, med, Q3, Max, Min)

#VẼ ĐỒ THJ PHÂN PHỐI CỦA BIẾN Memory_Speed
hist(non_dup_gpus$Memory_Speed, main = "Histogram of Memory_Speed", xlab = "Memory_Speed",
     xlim = c(0,2500), ylim = c(0,600), labels=T, col = "lightblue", border = "darkblue",
     freq = TRUE
)

#VẼ ĐỒ THỊ PHÂN PHỐI CỦA BIẾN Memory_Speed THEO BIẾN Memory
plot(non_dup_gpus$Memory_Speed~non_dup_gpus$Memory,
     main = "Memory_Speed by Memory",
     xlab = "Memory",
     ylab = "Memory_Speed",
     col = "navy"
)
abline(lm(Memory_Speed~Memory,data=non_dup_gpus),col="red3")

#VẼ ĐỒ THỊ PHÂN PHỐI CỦA BIẾN Memory_Speed THEO BIẾN Memory_Bandwidth

plot(non_dup_gpus$Memory_Speed~non_dup_gpus$Memory_Bandwidth,
     main = "Memory_Speed by Memory_Bandwidth",
     xlab = "Memory_Bandwidth",
     ylab = "Memory_Speed",
     col = "darkblue"
)
abline(lm(Memory_Speed~Memory_Bandwidth,data=non_dup_gpus),col="red3")

#VẼ ĐỒ THỊ PHÂN PHỐI CỦA BIẾN Memory_Speed THEO BIẾN Memory_Bus

plot(non_dup_gpus$Memory_Speed~non_dup_gpus$Memory_Bus,
     main = "Memory_Speed by Memory_Bus",
     xlab = "Memory_Bus",
     ylab = "Memory_Speed",
     col = "darkgreen"
)
abline(lm(Memory_Speed~Memory_Bandwidth,data=non_dup_gpus),col="red3")

D#VẼ ĐỒ THỊ PHÂN PHỐI CỦA BIẾN Memory_Speed THEO BIẾN Open_GL
function (expr, name) 
.External(C_doD, expr, name)
<bytecode: 0x0000021aacfd50a0>
<environment: namespace:stats>
plot(non_dup_gpus$Memory_Speed~non_dup_gpus$Open_GL,
     main = "Memory_Speed by Open_GL",
     xlab = "Open_GL",
     ylab = "Memory_Speed",
     col = "red4"
)
abline(lm(Memory_Speed~Open_GL,data=non_dup_gpus),col="red3")

#VẼ ĐỒ THỊ PHÂN PHỐI CỦA BIẾN Memory_Speed THEO BIẾN Direct_X

plot(non_dup_gpus$Memory_Speed~non_dup_gpus$Direct_X,
     main = "Memory_Speed by Direct_X",
     xlab = "Direct_X",
     ylab = "Memory_Speed",
     col = "seagreen"
)
abline(lm(Memory_Speed~Direct_X,data=non_dup_gpus),col="red3")

#VẼ ĐỒ THỊ PHÂN PHỐI CỦA BIẾN Memory_Speed THEO BIẾN Release_Year

plot(non_dup_gpus$Memory_Speed~non_dup_gpus$Release_Year,
     main = "Memory_Speed by Release_Year",
     xlab = "Release_Year",
     ylab = "Memory_Speed",
     col = "navy"
)
abline(lm(Memory_Speed~Release_Year,data=non_dup_gpus),col="red3")

###########################1Way-ANOVA#######################################
#Xử lí và lọc dữ liệu#
type_table<-table(non_dup_gpus$Memory_Type)
print(type_table)

   DDR   DDR2   DDR3   DDR4  eDRAM  GDDR2  GDDR3  GDDR4  GDDR5 GDDR5X  HBM-1 
   110     99    593     27      3      4    293      8   1679     46      6 
 HBM-2 
     6 
data_filtered <- non_dup_gpus[non_dup_gpus$Memory_Type %in% names(type_table[type_table > 10]), ]
table(data_filtered$Memory_Type)

   DDR   DDR2   DDR3   DDR4  GDDR3  GDDR5 GDDR5X 
   110     99    593     27    293   1679     46 
#Kiểm tra PP CHuẩn#
qqnorm(non_dup_gpus$Memory_Speed)
qqline(non_dup_gpus$Memory_Speed)

#Kiểm tra tương đồng phuong sai#
bartlett.test(Memory_Speed~Memory_Type,data=data_filtered)

    Bartlett test of homogeneity of variances

data:  Memory_Speed by Memory_Type
Bartlett's K-squared = 833.85, df = 6, p-value < 2.2e-16
#Thực hiện anova#
anova_model1<-aov(Memory_Speed~Memory_Type,data=data_filtered)
summary(anova_model1)
              Df    Sum Sq  Mean Sq F value Pr(>F)    
Memory_Type    6 312350848 52058475   677.2 <2e-16 ***
Residuals   2840 218320676    76873                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#So sánh bội#
TukeyHSD(anova_model1)
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = Memory_Speed ~ Memory_Type, data = data_filtered)

$Memory_Type
                   diff        lwr       upr     p adj
DDR2-DDR      263.73535  150.40808  377.0626 0.0000000
DDR3-DDR      498.17271  413.24895  583.0965 0.0000000
DDR4-DDR      750.34478  574.65063  926.0389 0.0000000
GDDR3-DDR     470.51492  379.04094  561.9889 0.0000000
GDDR5-DDR    1074.24066  993.72901 1154.7523 0.0000000
GDDR5X-DDR   1022.96877  879.33311 1166.6044 0.0000000
DDR3-DDR2     234.43736  145.62297  323.2518 0.0000000
DDR4-DDR2     486.60943  309.00204  664.2168 0.0000000
GDDR3-DDR2    206.77957  111.68256  301.8766 0.0000000
GDDR5-DDR2    810.50531  725.89989  895.1107 0.0000000
GDDR5X-DDR2   759.23342  613.26372  905.2031 0.0000000
DDR4-DDR3     252.17207   91.19580  413.1483 0.0000811
GDDR3-DDR3    -27.65779  -86.07367   30.7581 0.8037118
GDDR5-DDR3    576.06795  536.99046  615.1454 0.0000000
GDDR5X-DDR3   524.79606  399.59171  650.0004 0.0000000
GDDR3-DDR4   -279.82986 -444.35586 -115.3039 0.0000115
GDDR5-DDR4    323.89588  165.20297  482.5888 0.0000000
GDDR5X-DDR4   272.62399   74.29972  470.9483 0.0010074
GDDR5-GDDR3   603.72574  551.93292  655.5186 0.0000000
GDDR5X-GDDR3  552.45385  422.71729  682.1904 0.0000000
GDDR5X-GDDR5  -51.27189 -173.52658   70.9828 0.8795677
################################2WAY ANOVA#########################
#XỬ lý và lọc dữ liệu
year_table<-table(data_filtered$Release_Year)
print(year_table)

1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 
   2    7    5   10   28   28   36   36   76  101  130  107  232  291  478 
2013 2014 2015 2016 2017 
 414  311  288  177   90 
data_filtered2<-data_filtered[data_filtered$Release_Year %in% names(year_table[year_table > 10]), ]
table(data_filtered2$Release_Year)

2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 
  28   28   36   36   76  101  130  107  232  291  478  414  311  288  177 
2017 
  90 
#Kiểm tra sự tương đồng phương sai#
data_filtered2$Release_Year<-as.character(data_filtered2$Release_Year) #chuyển sang char
bartlett.test(Memory_Speed~Release_Year,data=data_filtered2)

    Bartlett test of homogeneity of variances

data:  Memory_Speed by Release_Year
Bartlett's K-squared = 227.11, df = 15, p-value < 2.2e-16
#Thực hiện anova 2 nhân tố#
anova_model2<-aov(Memory_Speed~Memory_Type*Release_Year,data=data_filtered2)
summary(anova_model2)
                           Df    Sum Sq  Mean Sq F value Pr(>F)    
Memory_Type                 6 293160338 48860056 1280.08 <2e-16 ***
Release_Year               15  95723756  6381584  167.19 <2e-16 ***
Memory_Type:Release_Year   37  14919360   403226   10.56 <2e-16 ***
Residuals                2764 105500720    38170                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
## Xay dung mo hinh hoi quy ##
model <- lm(Memory_Speed ~ Memory_Type + Release_Year,data=non_dup_gpus)
summary(model)

Call:
lm(formula = Memory_Speed ~ Memory_Type + Release_Year, data = non_dup_gpus)

Residuals:
     Min       1Q   Median       3Q      Max 
-1137.14  -152.60    -6.77   144.76   892.46 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)       -1.637e+05  4.160e+03 -39.351  < 2e-16 ***
Memory_TypeDDR2   -9.522e+01  3.213e+01  -2.963  0.00307 ** 
Memory_TypeDDR3   -2.519e+02  2.992e+01  -8.420  < 2e-16 ***
Memory_TypeDDR4   -2.646e+02  5.427e+01  -4.877 1.14e-06 ***
Memory_TypeeDRAM  -4.236e+02  1.324e+02  -3.200  0.00139 ** 
Memory_TypeGDDR2  -2.215e+02  1.136e+02  -1.951  0.05117 .  
Memory_TypeGDDR3   5.834e+01  2.698e+01   2.163  0.03066 *  
Memory_TypeGDDR4   3.686e+02  8.196e+01   4.497 7.16e-06 ***
Memory_TypeGDDR5   2.328e+02  3.057e+01   7.613 3.61e-14 ***
Memory_TypeGDDR5X -1.164e+02  4.858e+01  -2.397  0.01661 *  
Memory_TypeHBM-1  -8.361e+02  9.677e+01  -8.641  < 2e-16 ***
Memory_TypeHBM-2  -9.453e+02  9.754e+01  -9.692  < 2e-16 ***
Release_Year       8.190e+01  2.077e+00  39.427  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 222.4 on 2861 degrees of freedom
Multiple R-squared:  0.7368,    Adjusted R-squared:  0.7357 
F-statistic: 667.5 on 12 and 2861 DF,  p-value: < 2.2e-16
filtered_non_dup_gpus <- non_dup_gpus[non_dup_gpus$Memory_Type != "GDDR3", ]

model <- lm(Memory_Speed ~ Memory_Type + Release_Year,data=filtered_non_dup_gpus)

summary(model)

Call:
lm(formula = Memory_Speed ~ Memory_Type + Release_Year, data = filtered_non_dup_gpus)

Residuals:
     Min       1Q   Median       3Q      Max 
-1149.97  -155.31     0.03   160.53   870.26 

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)    
(Intercept)       -1.722e+05  4.363e+03 -39.477  < 2e-16 ***
Memory_TypeDDR2   -1.139e+02  3.250e+01  -3.505 0.000464 ***
Memory_TypeDDR3   -2.910e+02  3.066e+01  -9.491  < 2e-16 ***
Memory_TypeDDR4   -3.175e+02  5.521e+01  -5.751 9.94e-09 ***
Memory_TypeeDRAM  -4.731e+02  1.336e+02  -3.541 0.000406 ***
Memory_TypeGDDR2  -2.398e+02  1.145e+02  -2.094 0.036339 *  
Memory_TypeGDDR4   3.498e+02  8.267e+01   4.231 2.40e-05 ***
Memory_TypeGDDR5   1.889e+02  3.143e+01   6.010 2.11e-09 ***
Memory_TypeGDDR5X -1.758e+02  4.969e+01  -3.538 0.000411 ***
Memory_TypeHBM-1  -8.892e+02  9.783e+01  -9.089  < 2e-16 ***
Memory_TypeHBM-2  -1.004e+03  9.868e+01 -10.176  < 2e-16 ***
Release_Year       8.617e+01  2.179e+00  39.550  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 224.2 on 2569 degrees of freedom
Multiple R-squared:  0.7357,    Adjusted R-squared:  0.7345 
F-statistic: 649.9 on 11 and 2569 DF,  p-value: < 2.2e-16
op <- par(mfrow=c(2,2)) 
plot(model) 

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCnNldHdkKCJEOi9CVEwvQlRMIFhTVEsvYXJjaGl2ZSIpDQoNCiNJbXBvcnQgZGF0YToNCmdwdXMgPSByZWFkLmNzdigiQWxsX0dQVXMuY3N2IiwgaGVhZGVyID0gVFJVRSkNCmdwdXMNCmBgYA0KDQpgYGB7cn0NCiMgS2jhu59pIHThuqFvIGRhbmggc8OhY2ggY8OhYyBj4buZdCBj4bqnbiB4w7NhDQpjb2x1bW5zX3RvX3JlbW92ZSA8LSBjKCkNCg0KIyBM4bq3cCBxdWEgdOG7q25nIGPhu5l0IHRyb25nIGRhdGFmcmFtZSAnZ3B1cycNCmZvciAoY29sdW1uIGluIG5hbWVzKGdwdXMpKSB7DQogIG51bUNlbGxOQW9yQmxhbmsgPC0gc3VtKGlzLm5hKGdwdXNbW2NvbHVtbl1dKSB8IGdwdXNbW2NvbHVtbl1dID09ICIiIHwgZ3B1c1tbY29sdW1uXV0gPT0gIlxuLSAiKQ0KICBudW1DZWxsIDwtIGxlbmd0aChncHVzW1tjb2x1bW5dXSkNCiAgbmFwZXJjZW50YWdlIDwtIG51bUNlbGxOQW9yQmxhbmsgLyBudW1DZWxsDQogIHByaW50KHBhc3RlKGNvbHVtbiwgbmFwZXJjZW50YWdlKSkNCiAgIyBO4bq/dSBwaOG6p24gdHLEg20gZ2nDoSB0cuG7iyBOQSBs4bubbiBoxqFuIGhv4bq3YyBi4bqxbmcgMC4yLCB0aMOqbSB0w6puIGPhu5l0IHbDoG8gZGFuaCBzw6FjaCBj4bqnbiB4w7NhDQogIGlmIChuYXBlcmNlbnRhZ2UgPj0gMC4yKSB7DQogICAgY29sdW1uc190b19yZW1vdmUgPC0gYyhjb2x1bW5zX3RvX3JlbW92ZSwgY29sdW1uKQ0KICB9DQp9DQpwcmludCgiQ8OhYyBj4buZdCBi4buLIHjDs2E6IikNCnByaW50KGNvbHVtbnNfdG9fcmVtb3ZlKQ0KIyBYw7NhIHThuqV0IGPhuqMgY8OhYyBj4buZdCB0cm9uZyBkYW5oIHPDoWNoIGPhuqduIHjDs2ENCmxlc3NOQV9ncHVzIDwtIGdwdXNbLCAhKG5hbWVzKGdwdXMpICVpbiUgY29sdW1uc190b19yZW1vdmUpXQ0KDQojIEluIHJhIHPhu5EgbMaw4bujbmcgY+G7mXQgY8OybiBs4bqhaQ0KcHJpbnQocGFzdGUoIlPhu5EgY+G7mXQgY8OybiBs4bqhaTogIiwgbGVuZ3RoKG5hbWVzKGxlc3NOQV9ncHVzKSkpKQ0KDQpgYGANCg0KYGBge3J9DQojQuG7jyBt4buZdCBz4buRIGPhu5l0IGtow7RuZyBj4bqnbiB0aGnhur90L2Lhu4sgbOG7l2kNCnJlbV9jb2xzID0gYygiUk9QcyIsICJMMl9DYWNoZSIsICJOYW1lIiwgIkludGVncmF0ZWQiLCAiUmVzb2x1dGlvbl9XeEgiLCAiQmVzdF9SZXNvbHV0aW9uIikNCmxlc3NOQV9ncHVzID0gbGVzc05BX2dwdXNbLCAhKG5hbWVzKGxlc3NOQV9ncHVzKSAlaW4lIHJlbV9jb2xzKV0NCm5hbWVzKGxlc3NOQV9ncHVzKQ0KYGBgDQoNCmBgYHtyfQ0KI0tp4buDbSB0cmEgdsOgIHjDs2EgaMOgbmcgdHLDuW5nDQpkdXBsaWNhdGVfcm93cyA9IGxlc3NOQV9ncHVzW2R1cGxpY2F0ZWQobGVzc05BX2dwdXMpLF0NCm5vbl9kdXBfZ3B1cyA9IHVuaXF1ZShsZXNzTkFfZ3B1cykNCmBgYA0KDQpgYGB7cn0NCiNDaHV54buDbiBjw6FjIGPhu5l0IGNhdGVnb3JpY2FsIHbhu4EgZOG6oW5nIHPhu5ENCmxpYnJhcnkoZHBseXIpDQojIEPDoGkgxJHhurd0IHbDoCB04bqjaSB0aMawIHZp4buHbiBmb3JjYXRzDQojIGluc3RhbGwucGFja2FnZXMoImZvcmNhdHMiKQ0KbGlicmFyeShmb3JjYXRzKQ0KDQpub25fZHVwX2dwdXMkRGVkaWNhdGVkIDwtIHJlY29kZShub25fZHVwX2dwdXMkRGVkaWNhdGVkLCAnWWVzJyA9IDEsICdObycgPSAwKQ0Kbm9uX2R1cF9ncHVzJERpcmVjdF9YIDwtIGZjdF9sdW1wKG5vbl9kdXBfZ3B1cyREaXJlY3RfWCwgbiA9IDUsIG90aGVyX2xldmVsID0gIk90aGVyIikNCm5vbl9kdXBfZ3B1cyROb3RlYm9va19HUFUgPC0gcmVjb2RlKG5vbl9kdXBfZ3B1cyROb3RlYm9va19HUFUsICdZZXMnID0gMSwgJ05vJyA9IDApDQpub25fZHVwX2dwdXMkU0xJX0Nyb3NzZmlyZSA8LSByZWNvZGUobm9uX2R1cF9ncHVzJFNMSV9Dcm9zc2ZpcmUsICdZZXMnID0gMSwgJ05vJyA9IDApDQoNCg0KYGBgDQoNCmBgYHtyfQ0KI1jhu60gbMO9IGPhu5l0IFJlbGVhc2VfRGF0ZSwgY2h1eeG7g24gdGjDoG5oIGPhu5l0IFJlbGVhc2VfWWVhcg0KIyBMb+G6oWkgYuG7jyBjw6FjIGtob+G6o25nIHRy4bqvbmcgdsOgIGThuqV1IHh14buRbmcgZMOybmcga2jDtG5nIGPhuqduIHRoaeG6v3QNCm5vbl9kdXBfZ3B1cyRSZWxlYXNlX0RhdGUgPC0gdHJpbXdzKG5vbl9kdXBfZ3B1cyRSZWxlYXNlX0RhdGUpDQoNCiMgQ2h1eeG7g24gxJHhu5VpIGPhu5l0IFJlbGVhc2VfRGF0ZSB0aMOgbmggxJHhu5FpIHTGsOG7o25nIG5nw6B5DQpkYXRlX2NvbnZlcnNpb24gPC0gYXMuRGF0ZShub25fZHVwX2dwdXMkUmVsZWFzZV9EYXRlLCBmb3JtYXQ9IiVkLSViLSVZIikNCg0KIyBUw6xtIGPDoWMgaMOgbmcgY8OzIGdpw6EgdHLhu4sgbmfDoHkgaOG7o3AgbOG7hw0KdmFsaWRfZGF0ZXMgPC0gIWlzLm5hKGRhdGVfY29udmVyc2lvbikNCg0KIyBHaeG7ryBs4bqhaSBjaOG7iSBjw6FjIGjDoG5nIGPDsyBnacOhIHRy4buLIG5nw6B5IGjhu6NwIGzhu4cNCm5vbl9kdXBfZ3B1cyA8LSBub25fZHVwX2dwdXNbdmFsaWRfZGF0ZXMsIF0NCg0KIyBU4bqhbyBj4buZdCBSZWxlYXNlX1llYXIgdsOgIGNodXnhu4NuIMSR4buVaSB0aMOgbmggc+G7kQ0Kbm9uX2R1cF9ncHVzJFJlbGVhc2VfWWVhciA8LSBhcy5udW1lcmljKGZvcm1hdChkYXRlX2NvbnZlcnNpb25bdmFsaWRfZGF0ZXNdLCAiJVkiKSkNCg0KIyBYw7NhIGPhu5l0IFJlbGVhc2VfRGF0ZQ0Kbm9uX2R1cF9ncHVzJFJlbGVhc2VfRGF0ZSA8LSBOVUxMDQoNCg0KIyBC4buPIMSRxqFuIHbhu4sgdsOgIGNodXnhu4NuIGPDoWMgY+G7mXQga2nhu4N1IGNoYXJhY3RlciB0aMOgbmgga2nhu4N1IHPhu5ENCm5vbl9kdXBfZ3B1cyRNYXhfUG93ZXIgPC0gYXMubnVtZXJpYyhnc3ViKCIgV2F0dHMiLCAiIiwgbm9uX2R1cF9ncHVzJE1heF9Qb3dlcikpDQpub25fZHVwX2dwdXMkTWVtb3J5IDwtIGFzLm51bWVyaWMoZ3N1YigiIE1CIiwgIiIsIG5vbl9kdXBfZ3B1cyRNZW1vcnkpKQ0Kbm9uX2R1cF9ncHVzJE1lbW9yeV9CYW5kd2lkdGggPC0gYXMubnVtZXJpYyhnc3ViKCJHQi9zZWMiLCAiIiwgbm9uX2R1cF9ncHVzJE1lbW9yeV9CYW5kd2lkdGgpKQ0Kbm9uX2R1cF9ncHVzJE1lbW9yeV9CdXMgPC0gYXMubnVtZXJpYyhnc3ViKCIgQml0IiwgIiIsIG5vbl9kdXBfZ3B1cyRNZW1vcnlfQnVzKSkNCm5vbl9kdXBfZ3B1cyRNZW1vcnlfU3BlZWQgPC0gYXMubnVtZXJpYyhnc3ViKCIgTUh6IiwgIiIsIG5vbl9kdXBfZ3B1cyRNZW1vcnlfU3BlZWQpKQ0Kbm9uX2R1cF9ncHVzJFBpeGVsX1JhdGUgPC0gYXMubnVtZXJpYyhnc3ViKCIgR1BpeGVsL3MiLCAiIiwgbm9uX2R1cF9ncHVzJFBpeGVsX1JhdGUpKQ0Kbm9uX2R1cF9ncHVzJFByb2Nlc3MgPC0gYXMubnVtZXJpYyhnc3ViKCJubSIsICIiLCBub25fZHVwX2dwdXMkUHJvY2VzcykpDQpub25fZHVwX2dwdXMkVE1VcyA8LSBhcy5udW1lcmljKG5vbl9kdXBfZ3B1cyRUTVVzKQ0Kbm9uX2R1cF9ncHVzJFRleHR1cmVfUmF0ZSA8LSBhcy5udW1lcmljKGdzdWIoIiBHVGV4ZWwvcyIsICIiLCBub25fZHVwX2dwdXMkVGV4dHVyZV9SYXRlKSkNCmBgYA0KDQpgYGB7cn0NCiMgQ8OgaSDEkeG6t3QgdsOgIHThuqNpIGPDoWMgdGjGsCB2aeG7h24gY+G6p24gdGhp4bq/dA0KIyBpbnN0YWxsLnBhY2thZ2VzKGModGlkeXZlcnNlIikpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KIyBJbiByYSBz4buRIGTDsm5nIGThu68gbGnhu4d1IGtodXnhur90IGPhu6dhIG3hu5dpIGPhu5l0DQpjb2xTdW1zKGlzLm5hKG5vbl9kdXBfZ3B1cykpDQoNCiMgWOG7rSBsw70gZOG7ryBsaeG7h3Uga2h1eeG6v3QgdHLDqm4gY8OhYyBj4buZdCBraeG7g3Ugc+G7kQ0KIyBU4bqhbyBEYXRhRnJhbWUgZ29tIG5ow7NtIHRoZW8gTWFudWZhY3R1cmVyDQpncm91cGVkX2RmIDwtIG5vbl9kdXBfZ3B1cyAlPiUgZ3JvdXBfYnkoTWFudWZhY3R1cmVyKQ0KDQojIFRoYXkgdGjhur8gTi9BIGLhurFuZyB0cnVuZyB24buLIGPhu6dhIG5ow7NtDQpub25fZHVwX2dwdXMgPC0gZ3JvdXBlZF9kZiAlPiUgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZ1bnMoaWZlbHNlKGlzLm5hKC4pIHwgLiA9PSAiIiwgbWVkaWFuKC4sIG5hLnJtID0gVFJVRSksIC4pKSkNCg0KIyBUaGF5IHRo4bq/IDAgYuG6sW5nIHRydW5nIHbhu4sgY+G7p2EgY+G7mXQNCm5vbl9kdXBfZ3B1cyA8LSBub25fZHVwX2dwdXMgJT4lIG11dGF0ZV9pZihpcy5udW1lcmljLCBmdW5zKGlmZWxzZSguID09IDAsIG1lZGlhbiguLCBuYS5ybSA9IFRSVUUpLCAuKSkpDQoNCiMgWOG7rSBsw70gZOG7ryBsaeG7h3Uga2h1eeG6v3QgdHLDqm4gY8OhYyBiaeG6v24gcGjDom4gbG/huqFpDQojIFRoYXkgdGjhur8gTi9BIGLhurFuZyBnacOhIHRy4buLIGPDsyB04bqnbiBzdeG6pXQgeHXhuqV0IGhp4buHbiBjYW8gbmjhuqV0DQpub25fZHVwX2dwdXMgPC0gbm9uX2R1cF9ncHVzICU+JSBtdXRhdGVfaWYoaXMuZmFjdG9yLCBmdW5zKGlmZWxzZShpcy5uYSguKSB8IC4gPT0gIiIsIG5hbWVzKHdoaWNoLm1heCh0YWJsZSguKSkpLCAuKSkpDQoNCiMgVGhheSB0aOG6vyBOL0EgaG/hurdjIHLhu5duZyBi4bqxbmcgZ2nDoSB0cuG7iyBjw7MgdOG6p24gc3XhuqV0IHh14bqldCBoaeG7h24gY2FvIG5o4bqldA0Kbm9uX2R1cF9ncHVzIDwtIG5vbl9kdXBfZ3B1cyAlPiUgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgZnVucyhpZmVsc2UoaXMubmEoLikgfCAuID09ICIiLCBuYW1lcyh3aGljaC5tYXgodGFibGUobmEub21pdCguWy4gIT0gIiIgJiAuICE9ICIgIl0pKSkpLCAuKSkpDQoNCg0KIyBC4buPIMSRaSBiaeG6v24gTWFudWZhY3R1cmVyDQpub25fZHVwX2dwdXMkTWFudWZhY3R1cmVyIDwtIE5VTEwNCg0KIyBLaeG7g20gdHJhIGzhuqFpIHPhu5EgZMOybmcgZOG7ryBsaeG7h3UgTi9BDQpjb2xTdW1zKGlzLm5hKG5vbl9kdXBfZ3B1cykgfCBub25fZHVwX2dwdXMgPT0gIiIpDQoNCmBgYA0KDQpgYGB7cn0NCm5ld19ncHVzID0gbm9uX2R1cF9ncHVzDQojIEPDoGkgxJHhurd0IHbDoCB04bqjaSBnw7NpIHdyaXRleGwNCmluc3RhbGwucGFja2FnZXMoJ3dyaXRleGwnKQ0KbGlicmFyeSh3cml0ZXhsKQ0KDQoNCiMgTMawdSBEYXRhRnJhbWUgdGjDoG5oIGZpbGUgRXhjZWwNCndyaXRlX3hsc3gobmV3X2dwdXMsICduZXdfR1BVcy54bHN4JykNCg0KYGBgDQoNCmBgYHtyfQ0KI1RI4buQTkcgS8OKIFThuqINCiNUw61uaCB0cnVuZyBiw6xuaCBt4bqrdQ0KbWVhbjwtYXBwbHkobm9uX2R1cF9ncHVzWyxjKCJNZW1vcnkiLCJNZW1vcnlfQmFuZHdpZHRoIiwiTWVtb3J5X0J1cyIsIk1lbW9yeV9TcGVlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIk9wZW5fR0wiLCAiUGl4ZWxfUmF0ZSIsIlNoYWRlciIsIlRNVXMiLCJUZXh0dXJlX1JhdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSZWxlYXNlX1llYXIiLCJEaXJlY3RfWCIpXSwgMiwgbWVhbikNCiNUw61uaCDEkeG7mSBs4buHY2ggY2h14bqpbg0Kc2Q8LWFwcGx5KG5vbl9kdXBfZ3B1c1ssYygiTWVtb3J5IiwiTWVtb3J5X0JhbmR3aWR0aCIsIk1lbW9yeV9CdXMiLCJNZW1vcnlfU3BlZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiT3Blbl9HTCIsICJQaXhlbF9SYXRlIiwiU2hhZGVyIiwiVE1VcyIsIlRleHR1cmVfUmF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJSZWxlYXNlX1llYXIiLCJEaXJlY3RfWCIpXSwgMiwgc2QpDQojVMOtbmggcGjDom4gduG7iyAxDQpRMTwtYXBwbHkobm9uX2R1cF9ncHVzWyxjKCJNZW1vcnkiLCJNZW1vcnlfQmFuZHdpZHRoIiwiTWVtb3J5X0J1cyIsIk1lbW9yeV9TcGVlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPcGVuX0dMIiwgIlBpeGVsX1JhdGUiLCJTaGFkZXIiLCJUTVVzIiwiVGV4dHVyZV9SYXRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIlJlbGVhc2VfWWVhciIsIkRpcmVjdF9YIildLCAyLCBxdWFudGlsZSwgcHJvYnMgPSAwLjI1KQ0KI1TDrW5oIHRydW5nIHbhu4sNCm1lZDwtYXBwbHkobm9uX2R1cF9ncHVzWyxjKCJNZW1vcnkiLCJNZW1vcnlfQmFuZHdpZHRoIiwiTWVtb3J5X0J1cyIsIk1lbW9yeV9TcGVlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiT3Blbl9HTCIsICJQaXhlbF9SYXRlIiwiU2hhZGVyIiwiVE1VcyIsIlRleHR1cmVfUmF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiUmVsZWFzZV9ZZWFyIiwiRGlyZWN0X1giKV0sIDIsIG1lZGlhbikNCiNUw61uaCBwaMOibiB24buLIDMNClEzPC1hcHBseShub25fZHVwX2dwdXNbLGMoIk1lbW9yeSIsIk1lbW9yeV9CYW5kd2lkdGgiLCJNZW1vcnlfQnVzIiwiTWVtb3J5X1NwZWVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIk9wZW5fR0wiLCAiUGl4ZWxfUmF0ZSIsIlNoYWRlciIsIlRNVXMiLCJUZXh0dXJlX1JhdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiUmVsZWFzZV9ZZWFyIiwiRGlyZWN0X1giKV0sIDIsIHF1YW50aWxlLCBwcm9icyA9IDAuNzUpDQojVMOtbmggZ2nDoSB0cuG7iyBs4bubbiBuaOG6pXQNCk1heDwtYXBwbHkobm9uX2R1cF9ncHVzWyxjKCJNZW1vcnkiLCJNZW1vcnlfQmFuZHdpZHRoIiwiTWVtb3J5X0J1cyIsIk1lbW9yeV9TcGVlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiT3Blbl9HTCIsICJQaXhlbF9SYXRlIiwiU2hhZGVyIiwiVE1VcyIsIlRleHR1cmVfUmF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiUmVsZWFzZV9ZZWFyIiwiRGlyZWN0X1giKV0sIDIsIG1heCkNCiNUw61uaCBnacOhIHRy4buLIG5o4buPIG5o4bqldA0KTWluPC1hcHBseShub25fZHVwX2dwdXNbLGMoIk1lbW9yeSIsIk1lbW9yeV9CYW5kd2lkdGgiLCJNZW1vcnlfQnVzIiwiTWVtb3J5X1NwZWVkIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiT3Blbl9HTCIsICJQaXhlbF9SYXRlIiwiU2hhZGVyIiwiVE1VcyIsIlRleHR1cmVfUmF0ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlJlbGVhc2VfWWVhciIsIkRpcmVjdF9YIildLCAyLCBtaW4pDQpkYXRhLmZyYW1lKG1lYW4sIHNkLCBRMSwgbWVkLCBRMywgTWF4LCBNaW4pDQoNCiNW4bq8IMSQ4buSIFRISiBQSMOCTiBQSOG7kEkgQ+G7pkEgQknhur5OIE1lbW9yeV9TcGVlZA0KaGlzdChub25fZHVwX2dwdXMkTWVtb3J5X1NwZWVkLCBtYWluID0gIkhpc3RvZ3JhbSBvZiBNZW1vcnlfU3BlZWQiLCB4bGFiID0gIk1lbW9yeV9TcGVlZCIsDQogICAgIHhsaW0gPSBjKDAsMjUwMCksIHlsaW0gPSBjKDAsNjAwKSwgbGFiZWxzPVQsIGNvbCA9ICJsaWdodGJsdWUiLCBib3JkZXIgPSAiZGFya2JsdWUiLA0KICAgICBmcmVxID0gVFJVRQ0KKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiNW4bq8IMSQ4buSIFRI4buKIFBIw4JOIFBI4buQSSBD4bumQSBCSeG6vk4gTWVtb3J5X1NwZWVkIFRIRU8gQknhur5OIE1lbW9yeQ0KcGxvdChub25fZHVwX2dwdXMkTWVtb3J5X1NwZWVkfm5vbl9kdXBfZ3B1cyRNZW1vcnksDQogICAgIG1haW4gPSAiTWVtb3J5X1NwZWVkIGJ5IE1lbW9yeSIsDQogICAgIHhsYWIgPSAiTWVtb3J5IiwNCiAgICAgeWxhYiA9ICJNZW1vcnlfU3BlZWQiLA0KICAgICBjb2wgPSAibmF2eSINCikNCmFibGluZShsbShNZW1vcnlfU3BlZWR+TWVtb3J5LGRhdGE9bm9uX2R1cF9ncHVzKSxjb2w9InJlZDMiKQ0KYGBgDQoNCg0KYGBge3J9DQojVuG6vCDEkOG7kiBUSOG7iiBQSMOCTiBQSOG7kEkgQ+G7pkEgQknhur5OIE1lbW9yeV9TcGVlZCBUSEVPIEJJ4bq+TiBNZW1vcnlfQmFuZHdpZHRoDQoNCnBsb3Qobm9uX2R1cF9ncHVzJE1lbW9yeV9TcGVlZH5ub25fZHVwX2dwdXMkTWVtb3J5X0JhbmR3aWR0aCwNCiAgICAgbWFpbiA9ICJNZW1vcnlfU3BlZWQgYnkgTWVtb3J5X0JhbmR3aWR0aCIsDQogICAgIHhsYWIgPSAiTWVtb3J5X0JhbmR3aWR0aCIsDQogICAgIHlsYWIgPSAiTWVtb3J5X1NwZWVkIiwNCiAgICAgY29sID0gImRhcmtibHVlIg0KKQ0KYWJsaW5lKGxtKE1lbW9yeV9TcGVlZH5NZW1vcnlfQmFuZHdpZHRoLGRhdGE9bm9uX2R1cF9ncHVzKSxjb2w9InJlZDMiKQ0KYGBgDQoNCg0KYGBge3J9DQojVuG6vCDEkOG7kiBUSOG7iiBQSMOCTiBQSOG7kEkgQ+G7pkEgQknhur5OIE1lbW9yeV9TcGVlZCBUSEVPIEJJ4bq+TiBNZW1vcnlfQnVzDQoNCnBsb3Qobm9uX2R1cF9ncHVzJE1lbW9yeV9TcGVlZH5ub25fZHVwX2dwdXMkTWVtb3J5X0J1cywNCiAgICAgbWFpbiA9ICJNZW1vcnlfU3BlZWQgYnkgTWVtb3J5X0J1cyIsDQogICAgIHhsYWIgPSAiTWVtb3J5X0J1cyIsDQogICAgIHlsYWIgPSAiTWVtb3J5X1NwZWVkIiwNCiAgICAgY29sID0gImRhcmtncmVlbiINCikNCmFibGluZShsbShNZW1vcnlfU3BlZWR+TWVtb3J5X0JhbmR3aWR0aCxkYXRhPW5vbl9kdXBfZ3B1cyksY29sPSJyZWQzIikNCg0KYGBgDQoNCg0KYGBge3J9DQpEI1bhurwgxJDhu5IgVEjhu4ogUEjDgk4gUEjhu5BJIEPhu6ZBIEJJ4bq+TiBNZW1vcnlfU3BlZWQgVEhFTyBCSeG6vk4gT3Blbl9HTA0KDQpwbG90KG5vbl9kdXBfZ3B1cyRNZW1vcnlfU3BlZWR+bm9uX2R1cF9ncHVzJE9wZW5fR0wsDQogICAgIG1haW4gPSAiTWVtb3J5X1NwZWVkIGJ5IE9wZW5fR0wiLA0KICAgICB4bGFiID0gIk9wZW5fR0wiLA0KICAgICB5bGFiID0gIk1lbW9yeV9TcGVlZCIsDQogICAgIGNvbCA9ICJyZWQ0Ig0KKQ0KYWJsaW5lKGxtKE1lbW9yeV9TcGVlZH5PcGVuX0dMLGRhdGE9bm9uX2R1cF9ncHVzKSxjb2w9InJlZDMiKQ0KYGBgDQoNCg0KYGBge3J9DQojVuG6vCDEkOG7kiBUSOG7iiBQSMOCTiBQSOG7kEkgQ+G7pkEgQknhur5OIE1lbW9yeV9TcGVlZCBUSEVPIEJJ4bq+TiBEaXJlY3RfWA0KDQpwbG90KG5vbl9kdXBfZ3B1cyRNZW1vcnlfU3BlZWR+bm9uX2R1cF9ncHVzJERpcmVjdF9YLA0KICAgICBtYWluID0gIk1lbW9yeV9TcGVlZCBieSBEaXJlY3RfWCIsDQogICAgIHhsYWIgPSAiRGlyZWN0X1giLA0KICAgICB5bGFiID0gIk1lbW9yeV9TcGVlZCIsDQogICAgIGNvbCA9ICJzZWFncmVlbiINCikNCmFibGluZShsbShNZW1vcnlfU3BlZWR+RGlyZWN0X1gsZGF0YT1ub25fZHVwX2dwdXMpLGNvbD0icmVkMyIpDQpgYGANCg0KDQpgYGB7cn0NCiNW4bq8IMSQ4buSIFRI4buKIFBIw4JOIFBI4buQSSBD4bumQSBCSeG6vk4gTWVtb3J5X1NwZWVkIFRIRU8gQknhur5OIFJlbGVhc2VfWWVhcg0KDQpwbG90KG5vbl9kdXBfZ3B1cyRNZW1vcnlfU3BlZWR+bm9uX2R1cF9ncHVzJFJlbGVhc2VfWWVhciwNCiAgICAgbWFpbiA9ICJNZW1vcnlfU3BlZWQgYnkgUmVsZWFzZV9ZZWFyIiwNCiAgICAgeGxhYiA9ICJSZWxlYXNlX1llYXIiLA0KICAgICB5bGFiID0gIk1lbW9yeV9TcGVlZCIsDQogICAgIGNvbCA9ICJuYXZ5Ig0KKQ0KYWJsaW5lKGxtKE1lbW9yeV9TcGVlZH5SZWxlYXNlX1llYXIsZGF0YT1ub25fZHVwX2dwdXMpLGNvbD0icmVkMyIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjMVdheS1BTk9WQSMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KI1jhu60gbMOtIHbDoCBs4buNYyBk4buvIGxp4buHdSMNCnR5cGVfdGFibGU8LXRhYmxlKG5vbl9kdXBfZ3B1cyRNZW1vcnlfVHlwZSkNCnByaW50KHR5cGVfdGFibGUpDQpkYXRhX2ZpbHRlcmVkIDwtIG5vbl9kdXBfZ3B1c1tub25fZHVwX2dwdXMkTWVtb3J5X1R5cGUgJWluJSBuYW1lcyh0eXBlX3RhYmxlW3R5cGVfdGFibGUgPiAxMF0pLCBdDQp0YWJsZShkYXRhX2ZpbHRlcmVkJE1lbW9yeV9UeXBlKQ0KI0tp4buDbSB0cmEgUFAgQ0h14bqpbiMNCnFxbm9ybShub25fZHVwX2dwdXMkTWVtb3J5X1NwZWVkKQ0KcXFsaW5lKG5vbl9kdXBfZ3B1cyRNZW1vcnlfU3BlZWQpDQojS2nhu4NtIHRyYSB0xrDGoW5nIMSR4buTbmcgcGh1b25nIHNhaSMNCmJhcnRsZXR0LnRlc3QoTWVtb3J5X1NwZWVkfk1lbW9yeV9UeXBlLGRhdGE9ZGF0YV9maWx0ZXJlZCkNCiNUaOG7sWMgaGnhu4duIGFub3ZhIw0KYW5vdmFfbW9kZWwxPC1hb3YoTWVtb3J5X1NwZWVkfk1lbW9yeV9UeXBlLGRhdGE9ZGF0YV9maWx0ZXJlZCkNCnN1bW1hcnkoYW5vdmFfbW9kZWwxKQ0KI1NvIHPDoW5oIGLhu5lpIw0KVHVrZXlIU0QoYW5vdmFfbW9kZWwxKQ0KDQpgYGANCg0KYGBge3J9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIzJXQVkgQU5PVkEjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojWOG7rCBsw70gdsOgIGzhu41jIGThu68gbGnhu4d1DQp5ZWFyX3RhYmxlPC10YWJsZShkYXRhX2ZpbHRlcmVkJFJlbGVhc2VfWWVhcikNCnByaW50KHllYXJfdGFibGUpDQpkYXRhX2ZpbHRlcmVkMjwtZGF0YV9maWx0ZXJlZFtkYXRhX2ZpbHRlcmVkJFJlbGVhc2VfWWVhciAlaW4lIG5hbWVzKHllYXJfdGFibGVbeWVhcl90YWJsZSA+IDEwXSksIF0NCnRhYmxlKGRhdGFfZmlsdGVyZWQyJFJlbGVhc2VfWWVhcikNCiNLaeG7g20gdHJhIHPhu7EgdMawxqFuZyDEkeG7k25nIHBoxrDGoW5nIHNhaSMNCmRhdGFfZmlsdGVyZWQyJFJlbGVhc2VfWWVhcjwtYXMuY2hhcmFjdGVyKGRhdGFfZmlsdGVyZWQyJFJlbGVhc2VfWWVhcikgI2NodXnhu4NuIHNhbmcgY2hhcg0KYmFydGxldHQudGVzdChNZW1vcnlfU3BlZWR+UmVsZWFzZV9ZZWFyLGRhdGE9ZGF0YV9maWx0ZXJlZDIpDQojVGjhu7FjIGhp4buHbiBhbm92YSAyIG5ow6JuIHThu5EjDQphbm92YV9tb2RlbDI8LWFvdihNZW1vcnlfU3BlZWR+TWVtb3J5X1R5cGUqUmVsZWFzZV9ZZWFyLGRhdGE9ZGF0YV9maWx0ZXJlZDIpDQpzdW1tYXJ5KGFub3ZhX21vZGVsMikNCmBgYA0KDQpgYGB7cn0NCiMjIFhheSBkdW5nIG1vIGhpbmggaG9pIHF1eSAjIw0KbW9kZWwgPC0gbG0oTWVtb3J5X1NwZWVkIH4gTWVtb3J5X1R5cGUgKyBSZWxlYXNlX1llYXIsZGF0YT1ub25fZHVwX2dwdXMpDQpzdW1tYXJ5KG1vZGVsKQ0KDQpmaWx0ZXJlZF9ub25fZHVwX2dwdXMgPC0gbm9uX2R1cF9ncHVzW25vbl9kdXBfZ3B1cyRNZW1vcnlfVHlwZSAhPSAiR0REUjMiLCBdDQoNCm1vZGVsIDwtIGxtKE1lbW9yeV9TcGVlZCB+IE1lbW9yeV9UeXBlICsgUmVsZWFzZV9ZZWFyLGRhdGE9ZmlsdGVyZWRfbm9uX2R1cF9ncHVzKQ0KDQpzdW1tYXJ5KG1vZGVsKQ0KDQpvcCA8LSBwYXIobWZyb3c9YygyLDIpKSANCnBsb3QobW9kZWwpIA0KYGBgDQo=