Tài liệu khóa Tập huấn giảng viên miền Bắc, Tháng 5/2022.

Code thực hành theo dữ liệu mẫu từ: https://rpubs.com/SayakChakraborty/NewYorkAirBnB_Modelling

Trong dự án này, chúng tôi trình bày về phân tích dữ liệu, trực quan hóa và mô hình hóa dữ liệu Airbnb của New York. Airbnb, Inc. là một công ty trực tuyến về dịch vụ lưu trú, chủ yếu là nhà dân. Công ty không sở hữu bất kỳ danh sách bất động sản nào, cũng như không tổ chức các sự kiện; nó hoạt động như một nhà môi giới, nhận hoa hồng từ mỗi lần đặt chỗ. Doanh thu của Airbnb đến từ khách và chủ nhà của mình: Chủ nhà bị tính phí 3% giá trị đặt phòng, trong khi khách đặt phòng bị tính phí 6% -12% theo giá trị thuê. Thị trường Airbnb đang khá nở rộ ở thành phố New York (NYC), nơi có hơn 48.000 danh sách tính đến tháng 8 năm 2019.

Dữ liệu tải về từ website: https://www.kaggle.com/datasets/dgomonov/new-york-city-airbnb-open-data

Mục đích của bài thực hành là dự đoán các yếu tố ảnh hưởng đến giá của các nhà cho thuê trên website trực tuyến airbnbs xung quanh New York. Phần thực hành bao gồm việc lựa chọn các loại mô hình khác nhau, lựa chọn biến, xét sự phù hợp của mô hình và đi đến mô hình cuối cùng

Chúng tôi thực hiện dự án theo các bước sau:

  • Làm sạch và chuẩn bị dữ liệu
  • Trực quan hóa dữ liệu
  • Mô hình hóa và Kiểm tra mô hình
  • Hoàn thiện mô hình
  • Dự đoán bằng Mô hình cuối cùng (tự tham khảo)

1. Đọc dữ liệu

Nhập dữ liệu và đặt tên là airbnb_data

setwd("D:/TaphuanVIASM2022/Co ban ThaiNguyen_May2022/Project")
airbnb_data <- read.csv("AB_NYC_2019.csv")

Xem một số thống kê mô tả về số liệu

dim(airbnb_data) # 48895  x  16
## [1] 48895    16
head(airbnb_data)
##     id                                             name host_id   host_name
## 1 2539               Clean & quiet apt home by the park    2787        John
## 2 2595                            Skylit Midtown Castle    2845    Jennifer
## 3 3647              THE VILLAGE OF HARLEM....NEW YORK !    4632   Elisabeth
## 4 3831                  Cozy Entire Floor of Brownstone    4869 LisaRoxanne
## 5 5022 Entire Apt: Spacious Studio/Loft by central park    7192       Laura
## 6 5099        Large Cozy 1 BR Apartment In Midtown East    7322       Chris
##   neighbourhood_group neighbourhood latitude longitude       room_type price
## 1            Brooklyn    Kensington 40.64749 -73.97237    Private room   149
## 2           Manhattan       Midtown 40.75362 -73.98377 Entire home/apt   225
## 3           Manhattan        Harlem 40.80902 -73.94190    Private room   150
## 4            Brooklyn  Clinton Hill 40.68514 -73.95976 Entire home/apt    89
## 5           Manhattan   East Harlem 40.79851 -73.94399 Entire home/apt    80
## 6           Manhattan   Murray Hill 40.74767 -73.97500 Entire home/apt   200
##   minimum_nights number_of_reviews last_review reviews_per_month
## 1              1                 9  2018-10-19              0.21
## 2              1                45  2019-05-21              0.38
## 3              3                 0                            NA
## 4              1               270  2019-07-05              4.64
## 5             10                 9  2018-11-19              0.10
## 6              3                74  2019-06-22              0.59
##   calculated_host_listings_count availability_365
## 1                              6              365
## 2                              2              355
## 3                              1              365
## 4                              1              194
## 5                              1                0
## 6                              1              129
names(airbnb_data)
##  [1] "id"                             "name"                          
##  [3] "host_id"                        "host_name"                     
##  [5] "neighbourhood_group"            "neighbourhood"                 
##  [7] "latitude"                       "longitude"                     
##  [9] "room_type"                      "price"                         
## [11] "minimum_nights"                 "number_of_reviews"             
## [13] "last_review"                    "reviews_per_month"             
## [15] "calculated_host_listings_count" "availability_365"

Ý nghĩa của các biến như sau

  • ID Mã căn hộ
  • name: Tên ngắn gọn của căn hộ
  • host_id : Mã chủ nhà
  • host_name: Tên chủ nhà
  • neighbourhood_group: Địa chỉ
  • neighbourhood: Khu vực
  • latitude: vĩ độ
  • longitude: Kinh độ
  • room_type: loại phòng ở
  • price: Giá phòng (đơn vị: Đô la)
  • minimum_nights: Số đêm đặt phòng tối thiểu
  • number_of_reviews
  • last_review
  • reviews_per_month
  • calculated_host_listings_count
  • availability_365

2.Tải một số gói lệnh cho quá trình phân tích

require(tidyverse)

3. Khám phá số liệu

3.1. Kiểm tra dữ liệu khuyết (NA)

Xem cấu trúc số liệu

str(airbnb_data)
## 'data.frame':    48895 obs. of  16 variables:
##  $ id                            : int  2539 2595 3647 3831 5022 5099 5121 5178 5203 5238 ...
##  $ name                          : chr  "Clean & quiet apt home by the park" "Skylit Midtown Castle" "THE VILLAGE OF HARLEM....NEW YORK !" "Cozy Entire Floor of Brownstone" ...
##  $ host_id                       : int  2787 2845 4632 4869 7192 7322 7356 8967 7490 7549 ...
##  $ host_name                     : chr  "John" "Jennifer" "Elisabeth" "LisaRoxanne" ...
##  $ neighbourhood_group           : chr  "Brooklyn" "Manhattan" "Manhattan" "Brooklyn" ...
##  $ neighbourhood                 : chr  "Kensington" "Midtown" "Harlem" "Clinton Hill" ...
##  $ latitude                      : num  40.6 40.8 40.8 40.7 40.8 ...
##  $ longitude                     : num  -74 -74 -73.9 -74 -73.9 ...
##  $ room_type                     : chr  "Private room" "Entire home/apt" "Private room" "Entire home/apt" ...
##  $ price                         : int  149 225 150 89 80 200 60 79 79 150 ...
##  $ minimum_nights                : int  1 1 3 1 10 3 45 2 2 1 ...
##  $ number_of_reviews             : int  9 45 0 270 9 74 49 430 118 160 ...
##  $ last_review                   : chr  "2018-10-19" "2019-05-21" "" "2019-07-05" ...
##  $ reviews_per_month             : num  0.21 0.38 NA 4.64 0.1 0.59 0.4 3.47 0.99 1.33 ...
##  $ calculated_host_listings_count: int  6 2 1 1 1 1 1 1 1 4 ...
##  $ availability_365              : int  365 355 365 194 0 129 0 220 0 188 ...

Kiểm tra dữ liệu khuyết

dim(airbnb_data)
## [1] 48895    16
summary(is.na(airbnb_data))
##      id             name          host_id        host_name      
##  Mode :logical   Mode :logical   Mode :logical   Mode :logical  
##  FALSE:48895     FALSE:48895     FALSE:48895     FALSE:48895    
##                                                                 
##  neighbourhood_group neighbourhood    latitude       longitude      
##  Mode :logical       Mode :logical   Mode :logical   Mode :logical  
##  FALSE:48895         FALSE:48895     FALSE:48895     FALSE:48895    
##                                                                     
##  room_type         price         minimum_nights  number_of_reviews
##  Mode :logical   Mode :logical   Mode :logical   Mode :logical    
##  FALSE:48895     FALSE:48895     FALSE:48895     FALSE:48895      
##                                                                   
##  last_review     reviews_per_month calculated_host_listings_count
##  Mode :logical   Mode :logical     Mode :logical                 
##  FALSE:48895     FALSE:38843       FALSE:48895                   
##                  TRUE :10052                                     
##  availability_365
##  Mode :logical   
##  FALSE:48895     
## 

Một cách đơn giản sau để minh họa dữ liệu khuyết bằng hình vẽ, lệnh dưới này thuộc gói naniar

require(naniar)

naniar::gg_miss_var(airbnb_data) +
  #theme_minimal()+
  labs(y = "Look at all the Missing Values") 

Phân tích cho thấy không có giá trị nào bị thiếu trong tập số liệu, từ biến “reviews_per_month” có 10052 giá trị bị thiếu như phân tích ở trên. Biến trên là 1 biến dự kiến đưa vào trong nghiên cứu nên chúng ta sẽ quyết định xử lý với giá trị khuyết sau.

Do đó, về vấn đề xử lý số liệu sạch, các biến đều được coi là sạch trừ biến “reviews_per_month”. Biến này sẽ cần phải xử lý thêm. Một cách đơn giản nhất để xử lý dữ liệu khuyết là xóa các dữ liệu khuyết, tuy nhiên, tỉ lệ số liệu khuyết là rất lớn (10052/48895 = 20 %). Do đó, trường hợp này chúng ta không xóa các dữ liệu khuyết.

3.2. Khám phá số liệu

Trong phần này, chúng ta thực hiện thống kê mô tả cho một số biến để rõ hơn về đặc điểm số liệu

a. Biến room_type: loại phòng ở

unique(airbnb_data$room_type)
## [1] "Private room"    "Entire home/apt" "Shared room"
summary(airbnb_data$room_type)
##    Length     Class      Mode 
##     48895 character character
table(airbnb_data$room_type)
## 
## Entire home/apt    Private room     Shared room 
##           25409           22326            1160

Chúng ta có thể vẽ 1 biểu đồ cột đơn giản về số lượng các loại phòng ở, có 5 loại khu

data.bar <- table(airbnb_data$room_type)
 barplot (data.bar)

table(airbnb_data$neighbourhood_group)
## 
##         Bronx      Brooklyn     Manhattan        Queens Staten Island 
##          1091         20104         21661          5666           373

Thống kê mô tả theo neighbourhood_group và room_type

data.bar2 <- table(airbnb_data$neighbourhood_group, airbnb_data$room_type)
head(data.bar2)
##                
##                 Entire home/apt Private room Shared room
##   Bronx                     379          652          60
##   Brooklyn                 9559        10132         413
##   Manhattan               13199         7982         480
##   Queens                   2096         3372         198
##   Staten Island             176          188           9
 barplot (data.bar2, main = "Which types of Listings are there in NYC?")

Đồ thị vẽ đẹp hơn thì dùng ggplot2, đầu tiên là đếm số quan sát, sau đó dùng lệnh vẽ hình

property_df <-  airbnb_data %>% 
  group_by(neighbourhood_group, room_type) %>% 
  summarize(Freq = n())
head(property_df)
## # A tibble: 6 x 3
## # Groups:   neighbourhood_group [2]
##   neighbourhood_group room_type        Freq
##   <chr>               <chr>           <int>
## 1 Bronx               Entire home/apt   379
## 2 Bronx               Private room      652
## 3 Bronx               Shared room        60
## 4 Brooklyn            Entire home/apt  9559
## 5 Brooklyn            Private room    10132
## 6 Brooklyn            Shared room       413
ggplot(property_df, aes(x= neighbourhood_group, y = Freq, fill = room_type)) +
  geom_bar(position = "dodge", stat="identity") + 
  xlab("Borough") + ylab ("Count")+
  ggtitle("Which types of Listings are there in NYC?")

Nhận xét về đồ thị hình hộp và phân nhóm như trên như thế nào?

b.Trung bình giá thuê nhà và Neighbourhood Group

Xem thống kê mô tả về giá thuê nhà

summary(airbnb_data$price)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     0.0    69.0   106.0   152.7   175.0 10000.0
table(airbnb_data$neighbourhood_group)
## 
##         Bronx      Brooklyn     Manhattan        Queens Staten Island 
##          1091         20104         21661          5666           373

Xem trung bình cho 1 khu vực

mean(airbnb_data[airbnb_data$neighbourhood_group == "Bronx", "price" ])
## [1] 87.49679

Biểu đồ hộp về giá thuê theo các khu vực như sau, hãy bình luận về biểu đồ hộp này (Lưu ý là có rất nhiều giá trị ngoại lai!!)

boxplot(price ~ neighbourhood_group, data = airbnb_data)

Vẽ đồ thị về giá nhà theo khu vực, thông qua hàm aggregate()

aggregate(price ~ neighbourhood_group, data = airbnb_data, FUN = mean)
##   neighbourhood_group     price
## 1               Bronx  87.49679
## 2            Brooklyn 124.38321
## 3           Manhattan 196.87581
## 4              Queens  99.51765
## 5       Staten Island 114.81233

Sau đó, có thể vẽ biểu đồ hình cột

ag <- aggregate(price ~ neighbourhood_group, data = airbnb_data, FUN = mean)
 barplot (price ~ neighbourhood_group, data = ag )

Sử dụng ggplot2, có thể vẽ 1 hình về trung bình giá nhà theo khu vực

d.ag <- airbnb_data %>% group_by(neighbourhood_group) %>%
  summarise(price = mean(price))

ggplot(d.ag, aes(x=neighbourhood_group, y = price)) +
  geom_bar(position = "dodge", stat="identity", fill = "blue") + 
  ggtitle("Mean Price comparison for each Neighbourhood Group")

c.Tương tự, có thể làm thống kê mô tả của giá nhà theo loại phòng ở

boxplot(price ~ room_type, data = airbnb_data)

So sánh trung bình giá nhà theo loại phòng

ag <- aggregate(price ~ room_type, data = airbnb_data, FUN = mean)
 barplot (price ~ room_type, data = ag )

4. Mô hình dự báo giá nhà

4.1. Đề xuất mô hình

Trong phần tiếp theo, chúng tôi làm mô hình dự báo giá nhà phụ thuộc vào các biến sau

  • neighbourhood_group
  • latitude
  • longitude
  • room_type
  • minimum_nights
  • number_of_reviews
  • reviews_per_month
  • calculated_host_listings_count
  • availability_365

Ngoài ra, các biến còn lại không được đưa vào mô hình hồi quy, cụ thể như sau

Các biến định danh như: id, name, host_id, host_name, neighbourhood,

Các biến last_review là biến theo ngày tháng Biến neighbourhood thì đã sử dụng biến tương tự nhưng có thông tin tổng quát hơn là biến neighbourhood_group.

head(airbnb_data$last_review)
## [1] "2018-10-19" "2019-05-21" ""           "2019-07-05" "2018-11-19"
## [6] "2019-06-22"
table(airbnb_data$neighbourhood)
## 
##                   Allerton              Arden Heights 
##                         42                          4 
##                   Arrochar                    Arverne 
##                         21                         77 
##                    Astoria                 Bath Beach 
##                        900                         17 
##          Battery Park City                  Bay Ridge 
##                         70                        141 
##                Bay Terrace Bay Terrace, Staten Island 
##                          6                          2 
##                 Baychester                    Bayside 
##                          7                         39 
##                  Bayswater         Bedford-Stuyvesant 
##                         17                       3714 
##               Belle Harbor                  Bellerose 
##                          8                         14 
##                    Belmont                Bensonhurst 
##                         24                         75 
##               Bergen Beach                Boerum Hill 
##                         10                        177 
##               Borough Park               Breezy Point 
##                        136                          3 
##                  Briarwood             Brighton Beach 
##                         56                         75 
##                  Bronxdale           Brooklyn Heights 
##                         19                        154 
##                Brownsville                Bull's Head 
##                         61                          6 
##                   Bushwick            Cambria Heights 
##                       2465                         26 
##                   Canarsie            Carroll Gardens 
##                        147                        233 
##                Castle Hill          Castleton Corners 
##                          9                          4 
##                    Chelsea                  Chinatown 
##                       1113                        368 
##                City Island               Civic Center 
##                         18                         52 
##          Claremont Village               Clason Point 
##                         28                         21 
##                    Clifton               Clinton Hill 
##                         15                        572 
##                 Co-op City                Cobble Hill 
##                          2                         99 
##              College Point                Columbia St 
##                         19                         42 
##                    Concord                  Concourse 
##                         26                         50 
##          Concourse Village               Coney Island 
##                         32                         17 
##                     Corona              Crown Heights 
##                         64                       1564 
##              Cypress Hills           Ditmars Steinway 
##                        135                        309 
##               Dongan Hills                 Douglaston 
##                          7                          8 
##          Downtown Brooklyn                      DUMBO 
##                         83                         36 
##              Dyker Heights              East Elmhurst 
##                         12                        185 
##              East Flatbush                East Harlem 
##                        500                       1117 
##            East Morrisania              East New York 
##                         10                        218 
##               East Village                Eastchester 
##                       1853                         13 
##                   Edenwald                   Edgemere 
##                         13                         11 
##                   Elmhurst                Eltingville 
##                        237                          3 
##               Emerson Hill               Far Rockaway 
##                          5                         29 
##                  Fieldston         Financial District 
##                         12                        744 
##                   Flatbush          Flatiron District 
##                        621                         80 
##                  Flatlands                   Flushing 
##                         83                        426 
##                    Fordham               Forest Hills 
##                         63                        144 
##                Fort Greene              Fort Hamilton 
##                        489                         55 
##             Fort Wadsworth              Fresh Meadows 
##                          1                         32 
##                   Glendale                    Gowanus 
##                         54                        247 
##                   Gramercy               Graniteville 
##                        338                          3 
##                 Grant City                  Gravesend 
##                          6                         68 
##                Great Kills                 Greenpoint 
##                         10                       1115 
##          Greenwich Village                Grymes Hill 
##                        392                          7 
##                     Harlem             Hell's Kitchen 
##                       2658                       1958 
##                 Highbridge                     Hollis 
##                         27                         14 
##                 Holliswood               Howard Beach 
##                          4                         20 
##               Howland Hook                   Huguenot 
##                          2                          3 
##                Hunts Point                     Inwood 
##                         18                        252 
##            Jackson Heights                    Jamaica 
##                        186                        231 
##            Jamaica Estates              Jamaica Hills 
##                         19                          8 
##                 Kensington                Kew Gardens 
##                        175                         32 
##          Kew Gardens Hills                Kingsbridge 
##                         26                         70 
##                   Kips Bay                  Laurelton 
##                        470                         18 
##            Lighthouse Hill               Little Italy 
##                          2                        121 
##                Little Neck           Long Island City 
##                          5                        537 
##                   Longwood            Lower East Side 
##                         62                        911 
##            Manhattan Beach                Marble Hill 
##                          8                         12 
##            Mariners Harbor                    Maspeth 
##                          8                        110 
##                    Melrose             Middle Village 
##                         10                         31 
##              Midland Beach                    Midtown 
##                          6                       1545 
##                    Midwood                 Mill Basin 
##                        109                          4 
##        Morningside Heights             Morris Heights 
##                        346                         17 
##                Morris Park                 Morrisania 
##                         15                         18 
##                 Mott Haven                 Mount Eden 
##                         60                          6 
##                 Mount Hope                Murray Hill 
##                         20                        485 
##                  Navy Yard                   Neponsit 
##                         14                          3 
##               New Brighton                   New Dorp 
##                          5                          1 
##             New Dorp Beach            New Springville 
##                          5                          8 
##                       NoHo                     Nolita 
##                         78                        253 
##            North Riverdale                    Norwood 
##                         10                         31 
##                    Oakwood                  Olinville 
##                          5                          4 
##                 Ozone Park                 Park Slope 
##                         62                        506 
##                Parkchester                 Pelham Bay 
##                         39                         17 
##             Pelham Gardens                Port Morris 
##                         28                         46 
##              Port Richmond               Prince's Bay 
##                          9                          4 
##  Prospect-Lefferts Gardens           Prospect Heights 
##                        535                        357 
##             Queens Village              Randall Manor 
##                         60                         19 
##                   Red Hook                  Rego Park 
##                         79                        106 
##              Richmond Hill               Richmondtown 
##                         94                          1 
##                  Ridgewood                  Riverdale 
##                        423                         11 
##             Rockaway Beach           Roosevelt Island 
##                         56                         77 
##                   Rosebank                   Rosedale 
##                          7                         59 
##                  Rossville              Schuylerville 
##                          1                         13 
##                   Sea Gate             Sheepshead Bay 
##                          7                        164 
##                Shore Acres                Silver Lake 
##                          7                          2 
##                       SoHo                  Soundview 
##                        358                         15 
##                South Beach           South Ozone Park 
##                          8                         40 
##                South Slope        Springfield Gardens 
##                        284                         85 
##             Spuyten Duyvil                 St. Albans 
##                          4                         76 
##                 St. George                  Stapleton 
##                         48                         27 
##            Stuyvesant Town                  Sunnyside 
##                         37                        363 
##                Sunset Park           Theater District 
##                        390                        288 
##                Throgs Neck                  Todt Hill 
##                         24                          4 
##              Tompkinsville                Tottenville 
##                         42                          7 
##                    Tremont                    Tribeca 
##                         11                        177 
##                Two Bridges                  Unionport 
##                         72                          7 
##         University Heights            Upper East Side 
##                         21                       1798 
##            Upper West Side                   Van Nest 
##                       1971                         11 
##               Vinegar Hill                  Wakefield 
##                         34                         50 
##         Washington Heights              West Brighton 
##                        899                         18 
##                 West Farms               West Village 
##                          2                        768 
##         Westchester Square                Westerleigh 
##                         10                          2 
##                 Whitestone             Williamsbridge 
##                         11                         40 
##               Williamsburg                Willowbrook 
##                       3920                          1 
##            Windsor Terrace                  Woodhaven 
##                        157                         88 
##                   Woodlawn                    Woodrow 
##                         11                          1 
##                   Woodside 
##                        235
table(airbnb_data$neighbourhood_group)
## 
##         Bronx      Brooklyn     Manhattan        Queens Staten Island 
##          1091         20104         21661          5666           373

4.2. Hồi quy

Hồi quy mô hình đơn giản, giữa giá nhà và loại phòng, nhận xét về mô hình như thế nào?

airbnb_model_1 <- lm (price ~ room_type, data = airbnb_data)
summary(airbnb_model_1)
## 
## Call:
## lm(formula = price ~ room_type, data = airbnb_data)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -211.8  -59.8  -29.8    9.2 9910.2 
## 
## Coefficients:
##                       Estimate Std. Error t value Pr(>|t|)    
## (Intercept)            211.794      1.456  145.43   <2e-16 ***
## room_typePrivate room -122.013      2.130  -57.30   <2e-16 ***
## room_typeShared room  -141.667      6.970  -20.32   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 232.1 on 48892 degrees of freedom
## Multiple R-squared:  0.06561,    Adjusted R-squared:  0.06558 
## F-statistic:  1717 on 2 and 48892 DF,  p-value: < 2.2e-16

Hồi quy mô hình theo giá nhà và neighbourhood_group, so sánh với mô hình hồi quy airbnb_model_1

airbnb_model_2 <- lm (price ~ room_type + neighbourhood_group , data = airbnb_data)
summary(airbnb_model_2)
## 
## Call:
## lm(formula = price ~ room_type + neighbourhood_group, data = airbnb_data)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -240.9  -63.3  -22.8    9.1 9940.9 
## 
## Coefficients:
##                                  Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                       161.471      7.105  22.725  < 2e-16 ***
## room_typePrivate room            -111.483      2.144 -52.002  < 2e-16 ***
## room_typeShared room             -133.641      6.923 -19.305  < 2e-16 ***
## neighbourhood_groupBrooklyn        21.843      7.163   3.050  0.00229 ** 
## neighbourhood_groupManhattan       79.448      7.164  11.089  < 2e-16 ***
## neighbourhood_groupQueens           9.064      7.611   1.191  0.23369    
## neighbourhood_groupStaten Island   12.756     13.809   0.924  0.35560    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 230.2 on 48888 degrees of freedom
## Multiple R-squared:  0.08159,    Adjusted R-squared:  0.08148 
## F-statistic: 723.9 on 6 and 48888 DF,  p-value: < 2.2e-16

Kiểm tra độ phù hợp của mô hình

Mô hình gồm tất cả các biến: Mô hình không phù hợp!!

plot(airbnb_model_2)

airbnb_model_3 <- lm (price ~ neighbourhood_group + latitude +
                        longitude + room_type + minimum_nights  +
                        number_of_reviews + reviews_per_month +
                        calculated_host_listings_count +
                        availability_365, data = airbnb_data)
summary(airbnb_model_3)
## 
## Call:
## lm(formula = price ~ neighbourhood_group + latitude + longitude + 
##     room_type + minimum_nights + number_of_reviews + reviews_per_month + 
##     calculated_host_listings_count + availability_365, data = airbnb_data)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -210.2  -52.9  -18.2   17.0 9966.7 
## 
## Coefficients:
##                                    Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                      -2.670e+04  2.891e+03  -9.236  < 2e-16 ***
## neighbourhood_groupBrooklyn      -1.686e+01  7.959e+00  -2.118 0.034203 *  
## neighbourhood_groupManhattan      3.337e+01  7.205e+00   4.632 3.64e-06 ***
## neighbourhood_groupQueens         5.137e+00  7.648e+00   0.672 0.501838    
## neighbourhood_groupStaten Island -1.424e+02  1.494e+01  -9.531  < 2e-16 ***
## latitude                         -1.491e+02  2.847e+01  -5.238 1.63e-07 ***
## longitude                        -4.455e+02  3.247e+01 -13.722  < 2e-16 ***
## room_typePrivate room            -1.007e+02  1.954e+00 -51.533  < 2e-16 ***
## room_typeShared room             -1.359e+02  6.520e+00 -20.838  < 2e-16 ***
## minimum_nights                   -2.114e-01  5.513e-02  -3.834 0.000126 ***
## number_of_reviews                -1.955e-01  2.365e-02  -8.267  < 2e-16 ***
## reviews_per_month                 1.261e-01  6.852e-01   0.184 0.854014    
## calculated_host_listings_count   -9.449e-02  3.713e-02  -2.545 0.010928 *  
## availability_365                  1.734e-01  7.750e-03  22.371  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 185 on 38829 degrees of freedom
##   (10052 observations deleted due to missingness)
## Multiple R-squared:  0.1181, Adjusted R-squared:  0.1178 
## F-statistic: 399.8 on 13 and 38829 DF,  p-value: < 2.2e-16

Giải thích hệ số hồi quy và hệ số xác định R^2 trong mô hình trên.

plot(airbnb_model_3)

Mô hình khá xâu!! Nguyên nhân???????????????????????????

Kiểm tra lại biến phụ thuộc price

summary(airbnb_data$price)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##     0.0    69.0   106.0   152.7   175.0 10000.0
plot(airbnb_data$price)

hist(airbnb_data$price)

Đồ thị trên cho thấy giá nhà có một số giá trị ngoại lai, do đó, chúng ta loại bỏ 10% giá trị lớn nhất và 10% giá trị nhỏ nhất. Đây là 1 thao tác thường sử dụng khi nghiên cứu về giá tiền. Lưu ý như sau * Có thể loại bỏ ít hơn như 1% top và 1% bottom, loại bỏ bao nhiêu là tùy vào từng số liệu và giá của biến đó. Loại bỏ bao nhiêu thì sẽ viết lại trong báo cáo * Biến giá như trên cũng xử lý tương tự như các biến về tiền như thu nhập, chi tiêu.. * Khi loại bỏ các giá trị lớn nhất và nhỏ nhất là 1 bước của xử lý sạch số liệu, nên quá trình xử lý sạch sẽ kết hợp với quá trình phân tích và làm đi làm lại nhiều lần đến khi tìm được mô hình phù hợp nhất.

4.3. Loại bỏ 10% giá trị lớn nhất và 10% giá trị nhỏ nhất

q90 <- quantile(airbnb_data$price, 0.9)
q10 <- quantile(airbnb_data$price, 0.1)
airbnb_filtered_data <-  airbnb_data[ airbnb_data$price > q10 &  airbnb_data$price < q90, ]
#Code nang cao nhu duoi nay!!
#airbnb_filtered_data <- airbnb_data %>% 
 # filter(price < quantile(airbnb_data$price, 0.9) & price > quantile(airbnb_data$price, 0.1)) %>% 
  #drop_na()

Nhìn lại giá trị price sau khi đã loại bỏ số liệu trên số liệu airbnb_filtered_data.

summary(airbnb_filtered_data$price)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    50.0    75.0   107.0   121.6   155.0   268.0
plot(airbnb_filtered_data$price)

hist(airbnb_filtered_data$price)

4.3. Thực hiện lại mô hình hồi quy trên số liệu mới

airbnb_model_3_new <- lm (price ~ neighbourhood_group + latitude +
                        longitude + room_type + minimum_nights  +
                        number_of_reviews + reviews_per_month +
                        calculated_host_listings_count +
                        availability_365, data = airbnb_filtered_data)
summary(airbnb_model_3_new)
## 
## Call:
## lm(formula = price ~ neighbourhood_group + latitude + longitude + 
##     room_type + minimum_nights + number_of_reviews + reviews_per_month + 
##     calculated_host_listings_count + availability_365, data = airbnb_filtered_data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -119.078  -26.152   -6.408   21.040  213.601 
## 
## Coefficients:
##                                    Estimate Std. Error  t value Pr(>|t|)    
## (Intercept)                      -1.528e+04  7.138e+02  -21.410  < 2e-16 ***
## neighbourhood_groupBrooklyn      -6.278e+00  2.062e+00   -3.044  0.00234 ** 
## neighbourhood_groupManhattan      1.692e+01  1.895e+00    8.933  < 2e-16 ***
## neighbourhood_groupQueens         4.848e+00  1.996e+00    2.429  0.01515 *  
## neighbourhood_groupStaten Island -7.136e+01  3.805e+00  -18.754  < 2e-16 ***
## latitude                         -7.004e+01  6.932e+00  -10.104  < 2e-16 ***
## longitude                        -2.471e+02  8.022e+00  -30.804  < 2e-16 ***
## room_typePrivate room            -6.136e+01  4.705e-01 -130.410  < 2e-16 ***
## room_typeShared room             -7.427e+01  2.157e+00  -34.440  < 2e-16 ***
## minimum_nights                   -1.737e-01  1.277e-02  -13.598  < 2e-16 ***
## number_of_reviews                -2.268e-02  5.675e-03   -3.997 6.43e-05 ***
## reviews_per_month                -1.242e-01  1.675e-01   -0.742  0.45832    
## calculated_host_listings_count    1.152e-01  9.423e-03   12.226  < 2e-16 ***
## availability_365                  4.117e-02  1.925e-03   21.382  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 40.56 on 31543 degrees of freedom
##   (7400 observations deleted due to missingness)
## Multiple R-squared:  0.4458, Adjusted R-squared:  0.4456 
## F-statistic:  1952 on 13 and 31543 DF,  p-value: < 2.2e-16
plot(airbnb_model_3_new)

Vì biến giá là không âm, nên chúng ta có thể sử dụng logarit của price trong mô hình. Đầu tiên, nhìn thống kê mô tả của biến logarit(price)

summary(log(airbnb_filtered_data$price))
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   3.912   4.317   4.673   4.698   5.043   5.591
plot(log(airbnb_filtered_data$price))

hist(log(airbnb_filtered_data$price))

Kiểm tra mô hình hồi quy với log(price) và so sánh với mô hình airbnb_model_3_new

airbnb_model_3_new_log <- lm (log(price) ~ neighbourhood_group + latitude +
                        longitude + room_type + minimum_nights  +
                        number_of_reviews + reviews_per_month +
                        calculated_host_listings_count +
                        availability_365, data = airbnb_filtered_data)
summary(airbnb_model_3_new_log )
## 
## Call:
## lm(formula = log(price) ~ neighbourhood_group + latitude + longitude + 
##     room_type + minimum_nights + number_of_reviews + reviews_per_month + 
##     calculated_host_listings_count + availability_365, data = airbnb_filtered_data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.18736 -0.22499 -0.01509  0.20763  1.67519 
## 
## Coefficients:
##                                    Estimate Std. Error  t value Pr(>|t|)    
## (Intercept)                      -1.311e+02  5.620e+00  -23.336  < 2e-16 ***
## neighbourhood_groupBrooklyn      -4.271e-02  1.624e-02   -2.630  0.00855 ** 
## neighbourhood_groupManhattan      1.515e-01  1.492e-02   10.158  < 2e-16 ***
## neighbourhood_groupQueens         4.487e-02  1.572e-02    2.855  0.00431 ** 
## neighbourhood_groupStaten Island -6.020e-01  2.996e-02  -20.092  < 2e-16 ***
## latitude                         -5.503e-01  5.458e-02  -10.084  < 2e-16 ***
## longitude                        -2.142e+00  6.317e-02  -33.915  < 2e-16 ***
## room_typePrivate room            -5.416e-01  3.705e-03 -146.189  < 2e-16 ***
## room_typeShared room             -6.611e-01  1.698e-02  -38.934  < 2e-16 ***
## minimum_nights                   -1.372e-03  1.006e-04  -13.640  < 2e-16 ***
## number_of_reviews                -7.793e-05  4.468e-05   -1.744  0.08114 .  
## reviews_per_month                -1.962e-03  1.319e-03   -1.488  0.13681    
## calculated_host_listings_count    4.792e-04  7.420e-05    6.458 1.08e-10 ***
## availability_365                  3.333e-04  1.516e-05   21.989  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.3194 on 31543 degrees of freedom
##   (7400 observations deleted due to missingness)
## Multiple R-squared:  0.4955, Adjusted R-squared:  0.4952 
## F-statistic:  2383 on 13 and 31543 DF,  p-value: < 2.2e-16
plot(airbnb_model_3_new_log )

5. Dự báo giá nhà

Phần dự báo giá trị cá thể có thể được thực hiện lệch predict() trong R khi cung cấp đầy đủ các thông tin các biến độc lập.

Với mô hình dự báo tổng quát hơn, thường chia số liệu thành 2 tập (train và test) và thực hiện, chi tiết tham khảo tại: https://rpubs.com/SayakChakraborty/NewYorkAirBnB_Modelling

LS0tDQp0aXRsZTogIk5ldyBZb3JrIEFpckJuQjogUHJpY2UgUHJlZGljdGlvbiBmb3IgQWlyQm5icyBpbiBOZXcgWW9yayINCmF1dGhvcjogIk5ITCwgVFRILCBOVE4iDQpkYXRlOiAiMTkvMDUvMjAyMiINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgIyBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiAiZmxhdGx5Ig0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFKQ0KYGBgDQoNClTDoGkgbGnhu4d1IGtow7NhIFThuq1wIGh14bqlbiBnaeG6o25nIHZpw6puIG1p4buBbiBC4bqvYywgVGjDoW5nIDUvMjAyMi4NCg0KQ29kZSB0aOG7sWMgaMOgbmggdGhlbyBk4buvIGxp4buHdSBt4bqrdSB04burOiBodHRwczovL3JwdWJzLmNvbS9TYXlha0NoYWtyYWJvcnR5L05ld1lvcmtBaXJCbkJfTW9kZWxsaW5nIA0KDQoNClRyb25nIGThu7Egw6FuIG7DoHksIGNow7puZyB0w7RpIHRyw6xuaCBiw6B5IHbhu4EgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UsIHRy4buxYyBxdWFuIGjDs2EgdsOgIG3DtCBow6xuaCBow7NhIGThu68gbGnhu4d1IEFpcmJuYiBj4bunYSBOZXcgWW9yay4gQWlyYm5iLCBJbmMuIGzDoCBt4buZdCBjw7RuZyB0eSB0cuG7sWMgdHV54bq/biB24buBIGThu4tjaCB24bulIGzGsHUgdHLDuiwgY2jhu6cgeeG6v3UgbMOgIG5ow6AgZMOibi4gQ8O0bmcgdHkga2jDtG5nIHPhu58gaOG7r3UgYuG6pXQga+G7syBkYW5oIHPDoWNoIGLhuqV0IMSR4buZbmcgc+G6o24gbsOgbywgY8WpbmcgbmjGsCBraMO0bmcgdOG7lSBjaOG7qWMgY8OhYyBz4buxIGtp4buHbjsgbsOzIGhv4bqhdCDEkeG7mW5nIG5oxrAgbeG7mXQgbmjDoCBtw7RpIGdp4bubaSwgbmjhuq1uIGhvYSBo4buTbmcgdOG7qyBt4buXaSBs4bqnbiDEkeG6t3QgY2jhu5cuIERvYW5oIHRodSBj4bunYSBBaXJibmIgxJHhur9uIHThu6sga2jDoWNoIHbDoCBjaOG7pyBuaMOgIGPhu6dhIG3DrG5oOiBDaOG7pyBuaMOgIGLhu4sgdMOtbmggcGjDrSAzJSBnacOhIHRy4buLIMSR4bq3dCBwaMOybmcsIHRyb25nIGtoaSBraMOhY2ggxJHhurd0IHBow7JuZyBi4buLIHTDrW5oIHBow60gNiUgLTEyJSB0aGVvIGdpw6EgdHLhu4sgdGh1w6ouIFRo4buLIHRyxrDhu51uZyBBaXJibmIgxJFhbmcga2jDoSBu4bufIHLhu5kg4bufIHRow6BuaCBwaOG7kSBOZXcgWW9yayAoTllDKSwgbsahaSBjw7MgaMahbiA0OC4wMDAgZGFuaCBzw6FjaCB0w61uaCDEkeG6v24gdGjDoW5nIDggbsSDbSAyMDE5Lg0KDQoNCkThu68gbGnhu4d1IHThuqNpIHbhu4EgdOG7qyB3ZWJzaXRlOiBodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL2Rnb21vbm92L25ldy15b3JrLWNpdHktYWlyYm5iLW9wZW4tZGF0YSANCg0KDQpN4bulYyDEkcOtY2ggY+G7p2EgYsOgaSB0aOG7sWMgaMOgbmggbMOgIGThu7EgxJFvw6FuIGPDoWMgeeG6v3UgdOG7kSDhuqNuaCBoxrDhu59uZyDEkeG6v24gZ2nDoSBj4bunYSBjw6FjIG5ow6AgY2hvIHRodcOqIHRyw6puIHdlYnNpdGUgdHLhu7FjIHR1eeG6v24gYWlyYm5icyB4dW5nIHF1YW5oIE5ldyBZb3JrLiBQaOG6p24gdGjhu7FjIGjDoG5oIGJhbyBn4buTbSB2aeG7h2MgbOG7sWEgY2jhu41uIGPDoWMgbG/huqFpIG3DtCBow6xuaCBraMOhYyBuaGF1LCBs4buxYSBjaOG7jW4gYmnhur9uLCB4w6l0IHPhu7EgcGjDuSBo4bujcCBj4bunYSBtw7QgaMOsbmggdsOgIMSRaSDEkeG6v24gbcO0IGjDrG5oIGN14buRaSBjw7luZw0KDQpDaMO6bmcgdMO0aSB0aOG7sWMgaGnhu4duIGThu7Egw6FuIHRoZW8gY8OhYyBixrDhu5tjIHNhdToNCg0KKiBMw6BtIHPhuqFjaCB2w6AgY2h14bqpbiBi4buLIGThu68gbGnhu4d1DQoqICBUcuG7sWMgcXVhbiBow7NhIGThu68gbGnhu4d1DQoqICBNw7QgaMOsbmggaMOzYSB2w6AgS2nhu4NtIHRyYSBtw7QgaMOsbmgNCiogIEhvw6BuIHRoaeG7h24gbcO0IGjDrG5oDQoqICBE4buxIMSRb8OhbiBi4bqxbmcgTcO0IGjDrG5oIGN14buRaSBjw7luZyAodOG7sSB0aGFtIGto4bqjbykNCg0KIyMgMS4gxJDhu41jIGThu68gbGnhu4d1DQoNCg0KTmjhuq1wIGThu68gbGnhu4d1IHbDoCDEkeG6t3QgdMOqbiBsw6AgYWlyYm5iX2RhdGEgDQoNCmBgYHtyfQ0Kc2V0d2QoIkQ6L1RhcGh1YW5WSUFTTTIwMjIvQ28gYmFuIFRoYWlOZ3V5ZW5fTWF5MjAyMi9Qcm9qZWN0IikNCmFpcmJuYl9kYXRhIDwtIHJlYWQuY3N2KCJBQl9OWUNfMjAxOS5jc3YiKQ0KYGBgDQoNClhlbSBt4buZdCBz4buRIHRo4buRbmcga8OqIG3DtCB04bqjIHbhu4Egc+G7kSBsaeG7h3UNCg0KYGBge3J9DQpkaW0oYWlyYm5iX2RhdGEpICMgNDg4OTUgIHggIDE2DQpoZWFkKGFpcmJuYl9kYXRhKQ0KbmFtZXMoYWlyYm5iX2RhdGEpDQoNCmBgYA0KDQoNCsOdIG5naMSpYSBj4bunYSBjw6FjIGJp4bq/biBuaMawIHNhdQ0KDQoqIElEIE3DoyBjxINuIGjhu5kNCiogbmFtZTogVMOqbiBuZ+G6r24gZ+G7jW4gY+G7p2EgY8SDbiBo4buZDQoqIGhvc3RfaWQgOiBNw6MgY2jhu6cgbmjDoA0KKiBob3N0X25hbWU6IFTDqm4gY2jhu6cgbmjDoA0KKiBuZWlnaGJvdXJob29kX2dyb3VwOiDEkOG7i2EgY2jhu4kNCiogbmVpZ2hib3VyaG9vZDogS2h1IHbhu7FjDQoqIGxhdGl0dWRlOiB2xKkgxJHhu5kNCiogbG9uZ2l0dWRlOiBLaW5oIMSR4buZDQoqIHJvb21fdHlwZTogbG/huqFpIHBow7JuZyDhu58NCiogcHJpY2U6IEdpw6EgcGjDsm5nICjEkcahbiB24buLOiDEkMO0IGxhKQ0KKiBtaW5pbXVtX25pZ2h0czogU+G7kSDEkcOqbSDEkeG6t3QgcGjDsm5nIHThu5FpIHRoaeG7g3UgDQoqIG51bWJlcl9vZl9yZXZpZXdzDQoqIGxhc3RfcmV2aWV3IA0KKiByZXZpZXdzX3Blcl9tb250aCANCiogY2FsY3VsYXRlZF9ob3N0X2xpc3RpbmdzX2NvdW50DQoqIGF2YWlsYWJpbGl0eV8zNjUgDQoNCg0KIyMgMi5U4bqjaSBt4buZdCBz4buRIGfDs2kgbOG7h25oIGNobyBxdcOhIHRyw6xuaCBwaMOibiB0w61jaA0KDQpgYGB7cn0NCnJlcXVpcmUodGlkeXZlcnNlKQ0KYGBgDQoNCg0KIyMgMy4gS2jDoW0gcGjDoSBz4buRIGxp4buHdQ0KIyMjIDMuMS4gS2nhu4NtIHRyYSBk4buvIGxp4buHdSBraHV54bq/dCAoTkEpDQoNClhlbSBj4bqldSB0csO6YyBz4buRIGxp4buHdQ0KDQoNCmBgYHtyfQ0Kc3RyKGFpcmJuYl9kYXRhKQ0KYGBgDQoNCktp4buDbSB0cmEgZOG7ryBsaeG7h3Uga2h1eeG6v3QNCmBgYHtyfQ0KZGltKGFpcmJuYl9kYXRhKQ0Kc3VtbWFyeShpcy5uYShhaXJibmJfZGF0YSkpDQpgYGANCg0KTeG7mXQgY8OhY2ggxJHGoW4gZ2nhuqNuIHNhdSDEkeG7gyBtaW5oIGjhu41hIGThu68gbGnhu4d1IGtodXnhur90IGLhurFuZyBow6xuaCB24bq9LCBs4buHbmggZMaw4bubaSBuw6B5IHRodeG7mWMgZ8OzaSBuYW5pYXINCg0KYGBge3J9DQpyZXF1aXJlKG5hbmlhcikNCg0KbmFuaWFyOjpnZ19taXNzX3ZhcihhaXJibmJfZGF0YSkgKw0KICAjdGhlbWVfbWluaW1hbCgpKw0KICBsYWJzKHkgPSAiTG9vayBhdCBhbGwgdGhlIE1pc3NpbmcgVmFsdWVzIikgDQoNCmBgYA0KDQoNClBow6JuIHTDrWNoIGNobyB0aOG6pXkga2jDtG5nIGPDsyBnacOhIHRy4buLIG7DoG8gYuG7iyB0aGnhur91IHRyb25nIHThuq1wIHPhu5EgbGnhu4d1LCB04burIGJp4bq/biAicmV2aWV3c19wZXJfbW9udGgiIGPDsyAxMDA1MiBnacOhIHRy4buLIGLhu4sgdGhp4bq/dSBuaMawIHBow6JuIHTDrWNoIOG7nyB0csOqbi4gQmnhur9uIHRyw6puIGzDoCAxIGJp4bq/biBk4buxIGtp4bq/biDEkcawYSB2w6BvIHRyb25nIG5naGnDqm4gY+G7qXUgbsOqbiBjaMO6bmcgdGEgc+G6vSBxdXnhur90IMSR4buLbmggeOG7rSBsw70gduG7m2kgZ2nDoSB0cuG7iyBraHV54bq/dCBzYXUuIA0KDQpEbyDEkcOzLCB24buBIHbhuqVuIMSR4buBIHjhu60gbMO9IHPhu5EgbGnhu4d1IHPhuqFjaCwgY8OhYyBiaeG6v24gxJHhu4F1IMSRxrDhu6NjIGNvaSBsw6Agc+G6oWNoIHRy4burIGJp4bq/biAicmV2aWV3c19wZXJfbW9udGgiLiBCaeG6v24gbsOgeSBz4bq9IGPhuqduIHBo4bqjaSB44butIGzDvSB0aMOqbS4gTeG7mXQgY8OhY2ggxJHGoW4gZ2nhuqNuIG5o4bqldCDEkeG7gyB44butIGzDvSBk4buvIGxp4buHdSBraHV54bq/dCBsw6AgeMOzYSBjw6FjIGThu68gbGnhu4d1IGtodXnhur90LCB0dXkgbmhpw6puLCB04buJIGzhu4cgc+G7kSBsaeG7h3Uga2h1eeG6v3QgbMOgIHLhuqV0IGzhu5tuICgxMDA1Mi80ODg5NSA9IDIwICUpLiBEbyDEkcOzLCB0csaw4budbmcgaOG7o3AgbsOgeSBjaMO6bmcgdGEga2jDtG5nIHjDs2EgY8OhYyBk4buvIGxp4buHdSBraHV54bq/dC4NCg0KIyMjIDMuMi4gS2jDoW0gcGjDoSBz4buRIGxp4buHdQ0KDQpUcm9uZyBwaOG6p24gbsOgeSwgY2jDum5nIHRhIHRo4buxYyBoaeG7h24gdGjhu5FuZyBrw6ogbcO0IHThuqMgY2hvIG3hu5l0IHPhu5EgYmnhur9uIMSR4buDIHLDtSBoxqFuIHbhu4EgxJHhurdjIMSRaeG7g20gc+G7kSBsaeG7h3UNCg0KIyMjIyBhLiBCaeG6v24gcm9vbV90eXBlOiBsb+G6oWkgcGjDsm5nIOG7nw0KDQpgYGB7cn0NCnVuaXF1ZShhaXJibmJfZGF0YSRyb29tX3R5cGUpDQpzdW1tYXJ5KGFpcmJuYl9kYXRhJHJvb21fdHlwZSkNCnRhYmxlKGFpcmJuYl9kYXRhJHJvb21fdHlwZSkNCmBgYA0KQ2jDum5nIHRhIGPDsyB0aOG7gyB24bq9IDEgYmnhu4N1IMSR4buTIGPhu5l0IMSRxqFuIGdp4bqjbiB24buBIHPhu5EgbMaw4bujbmcgY8OhYyBsb+G6oWkgcGjDsm5nIOG7nywgY8OzIDUgbG/huqFpIGtodQ0KDQpgYGB7cn0NCmRhdGEuYmFyIDwtIHRhYmxlKGFpcmJuYl9kYXRhJHJvb21fdHlwZSkNCiBiYXJwbG90IChkYXRhLmJhcikNCg0KdGFibGUoYWlyYm5iX2RhdGEkbmVpZ2hib3VyaG9vZF9ncm91cCkNCmBgYA0KDQoNClRo4buRbmcga8OqIG3DtCB04bqjIHRoZW8gbmVpZ2hib3VyaG9vZF9ncm91cCB2w6Agcm9vbV90eXBlDQoNCmBgYHtyfQ0KZGF0YS5iYXIyIDwtIHRhYmxlKGFpcmJuYl9kYXRhJG5laWdoYm91cmhvb2RfZ3JvdXAsIGFpcmJuYl9kYXRhJHJvb21fdHlwZSkNCmhlYWQoZGF0YS5iYXIyKQ0KIGJhcnBsb3QgKGRhdGEuYmFyMiwgbWFpbiA9ICJXaGljaCB0eXBlcyBvZiBMaXN0aW5ncyBhcmUgdGhlcmUgaW4gTllDPyIpDQpgYGANCg0KxJDhu5MgdGjhu4sgduG6vSDEkeG6uXAgaMahbiB0aMOsIGTDuW5nIGdncGxvdDIsIMSR4bqndSB0acOqbiBsw6AgxJHhur9tIHPhu5EgcXVhbiBzw6F0LCBzYXUgxJHDsyBkw7luZyBs4buHbmggduG6vSBow6xuaA0KDQpgYGB7cn0NCnByb3BlcnR5X2RmIDwtICBhaXJibmJfZGF0YSAlPiUgDQogIGdyb3VwX2J5KG5laWdoYm91cmhvb2RfZ3JvdXAsIHJvb21fdHlwZSkgJT4lIA0KICBzdW1tYXJpemUoRnJlcSA9IG4oKSkNCmhlYWQocHJvcGVydHlfZGYpDQoNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChwcm9wZXJ0eV9kZiwgYWVzKHg9IG5laWdoYm91cmhvb2RfZ3JvdXAsIHkgPSBGcmVxLCBmaWxsID0gcm9vbV90eXBlKSkgKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQ9ImlkZW50aXR5IikgKyANCiAgeGxhYigiQm9yb3VnaCIpICsgeWxhYiAoIkNvdW50IikrDQogIGdndGl0bGUoIldoaWNoIHR5cGVzIG9mIExpc3RpbmdzIGFyZSB0aGVyZSBpbiBOWUM/IikNCmBgYA0KTmjhuq1uIHjDqXQgduG7gSDEkeG7kyB0aOG7iyBow6xuaCBo4buZcCB2w6AgcGjDom4gbmjDs20gbmjGsCB0csOqbiBuaMawIHRo4bq/IG7DoG8/DQoNCg0KIyMjIyBiLlRydW5nIGLDrG5oIGdpw6EgdGh1w6ogbmjDoCB2w6AgTmVpZ2hib3VyaG9vZCBHcm91cA0KDQpYZW0gdGjhu5FuZyBrw6ogbcO0IHThuqMgduG7gSBnacOhIHRodcOqIG5ow6ANCmBgYHtyfQ0Kc3VtbWFyeShhaXJibmJfZGF0YSRwcmljZSkNCnRhYmxlKGFpcmJuYl9kYXRhJG5laWdoYm91cmhvb2RfZ3JvdXApDQpgYGANCg0KWGVtIHRydW5nIGLDrG5oIGNobyAxIGtodSB24buxYw0KDQpgYGB7cn0NCm1lYW4oYWlyYm5iX2RhdGFbYWlyYm5iX2RhdGEkbmVpZ2hib3VyaG9vZF9ncm91cCA9PSAiQnJvbngiLCAicHJpY2UiIF0pDQpgYGANCg0KQmnhu4N1IMSR4buTIGjhu5lwIHbhu4EgZ2nDoSB0aHXDqiB0aGVvIGPDoWMga2h1IHbhu7FjIG5oxrAgc2F1LCBow6N5IGLDrG5oIGx14bqtbiB24buBIGJp4buDdSDEkeG7kyBo4buZcCBuw6B5IChMxrB1IMO9IGzDoCBjw7MgcuG6pXQgbmhp4buBdSBnacOhIHRy4buLIG5nb+G6oWkgbGFpISEpDQoNCmBgYHtyfQ0KYm94cGxvdChwcmljZSB+IG5laWdoYm91cmhvb2RfZ3JvdXAsIGRhdGEgPSBhaXJibmJfZGF0YSkNCmBgYA0KDQpW4bq9IMSR4buTIHRo4buLIHbhu4EgZ2nDoSBuaMOgIHRoZW8ga2h1IHbhu7FjLCB0aMO0bmcgcXVhIGjDoG0gYWdncmVnYXRlKCkNCg0KYGBge3J9DQphZ2dyZWdhdGUocHJpY2UgfiBuZWlnaGJvdXJob29kX2dyb3VwLCBkYXRhID0gYWlyYm5iX2RhdGEsIEZVTiA9IG1lYW4pDQpgYGANClNhdSDEkcOzLCBjw7MgdGjhu4MgduG6vSBiaeG7g3UgxJHhu5MgaMOsbmggY+G7mXQNCmBgYHtyfQ0KYWcgPC0gYWdncmVnYXRlKHByaWNlIH4gbmVpZ2hib3VyaG9vZF9ncm91cCwgZGF0YSA9IGFpcmJuYl9kYXRhLCBGVU4gPSBtZWFuKQ0KIGJhcnBsb3QgKHByaWNlIH4gbmVpZ2hib3VyaG9vZF9ncm91cCwgZGF0YSA9IGFnICkNCmBgYA0KDQoNClPhu60gZOG7pW5nIGdncGxvdDIsIGPDsyB0aOG7gyB24bq9IDEgaMOsbmggduG7gSB0cnVuZyBiw6xuaCBnacOhIG5ow6AgdGhlbyBraHUgduG7sWMNCg0KYGBge3J9DQpkLmFnIDwtIGFpcmJuYl9kYXRhICU+JSBncm91cF9ieShuZWlnaGJvdXJob29kX2dyb3VwKSAlPiUNCiAgc3VtbWFyaXNlKHByaWNlID0gbWVhbihwcmljZSkpDQoNCmdncGxvdChkLmFnLCBhZXMoeD1uZWlnaGJvdXJob29kX2dyb3VwLCB5ID0gcHJpY2UpKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgc3RhdD0iaWRlbnRpdHkiLCBmaWxsID0gImJsdWUiKSArIA0KICBnZ3RpdGxlKCJNZWFuIFByaWNlIGNvbXBhcmlzb24gZm9yIGVhY2ggTmVpZ2hib3VyaG9vZCBHcm91cCIpDQpgYGANCg0KIyMjIyBjLlTGsMahbmcgdOG7sSwgY8OzIHRo4buDIGzDoG0gdGjhu5FuZyBrw6ogbcO0IHThuqMgY+G7p2EgZ2nDoSBuaMOgIHRoZW8gbG/huqFpIHBow7JuZyDhu58NCg0KYGBge3J9DQpib3hwbG90KHByaWNlIH4gcm9vbV90eXBlLCBkYXRhID0gYWlyYm5iX2RhdGEpDQpgYGANCg0KU28gc8OhbmggdHJ1bmcgYsOsbmggZ2nDoSBuaMOgIHRoZW8gbG/huqFpIHBow7JuZw0KYGBge3J9DQphZyA8LSBhZ2dyZWdhdGUocHJpY2UgfiByb29tX3R5cGUsIGRhdGEgPSBhaXJibmJfZGF0YSwgRlVOID0gbWVhbikNCiBiYXJwbG90IChwcmljZSB+IHJvb21fdHlwZSwgZGF0YSA9IGFnICkNCmBgYA0KDQojIyA0LiBNw7QgaMOsbmggZOG7sSBiw6FvIGdpw6EgbmjDoA0KDQojIyMgNC4xLiDEkOG7gSB4deG6pXQgbcO0IGjDrG5oDQpUcm9uZyBwaOG6p24gdGnhur9wIHRoZW8sIGNow7puZyB0w7RpIGzDoG0gbcO0IGjDrG5oIGThu7EgYsOhbyBnacOhIG5ow6AgcGjhu6UgdGh14buZYyB2w6BvIGPDoWMgYmnhur9uIHNhdQ0KDQoqIG5laWdoYm91cmhvb2RfZ3JvdXANCiogbGF0aXR1ZGUNCiogbG9uZ2l0dWRlDQoqIHJvb21fdHlwZQ0KKiBtaW5pbXVtX25pZ2h0cw0KKiBudW1iZXJfb2ZfcmV2aWV3cw0KKiByZXZpZXdzX3Blcl9tb250aA0KKiBjYWxjdWxhdGVkX2hvc3RfbGlzdGluZ3NfY291bnQNCiogYXZhaWxhYmlsaXR5XzM2NQ0KDQpOZ2/DoGkgcmEsIGPDoWMgYmnhur9uIGPDsm4gbOG6oWkga2jDtG5nIMSRxrDhu6NjIMSRxrBhIHbDoG8gbcO0IGjDrG5oIGjhu5NpIHF1eSwgY+G7pSB0aOG7gyBuaMawIHNhdQ0KDQpDw6FjIGJp4bq/biDEkeG7i25oIGRhbmggbmjGsDogaWQsIG5hbWUsIGhvc3RfaWQsIGhvc3RfbmFtZSwgbmVpZ2hib3VyaG9vZCwgIA0KDQpDw6FjIGJp4bq/biBsYXN0X3JldmlldyBsw6AgYmnhur9uIHRoZW8gbmfDoHkgdGjDoW5nDQpCaeG6v24gbmVpZ2hib3VyaG9vZCB0aMOsIMSRw6Mgc+G7rSBk4bulbmcgYmnhur9uIHTGsMahbmcgdOG7sSBuaMawbmcgY8OzIHRow7RuZyB0aW4gdOG7lW5nIHF1w6F0IGjGoW4gbMOgIGJp4bq/biBuZWlnaGJvdXJob29kX2dyb3VwLg0KDQpgYGB7cn0NCmhlYWQoYWlyYm5iX2RhdGEkbGFzdF9yZXZpZXcpDQp0YWJsZShhaXJibmJfZGF0YSRuZWlnaGJvdXJob29kKQ0KdGFibGUoYWlyYm5iX2RhdGEkbmVpZ2hib3VyaG9vZF9ncm91cCkNCmBgYA0KDQojIyMgNC4yLiBI4buTaSBxdXkNCg0KSOG7k2kgcXV5IG3DtCBow6xuaCDEkcahbiBnaeG6o24sIGdp4buvYSBnacOhIG5ow6AgdsOgIGxv4bqhaSBwaMOybmcsIG5o4bqtbiB4w6l0IHbhu4EgbcO0IGjDrG5oIG5oxrAgdGjhur8gbsOgbz8NCg0KYGBge3J9DQphaXJibmJfbW9kZWxfMSA8LSBsbSAocHJpY2UgfiByb29tX3R5cGUsIGRhdGEgPSBhaXJibmJfZGF0YSkNCnN1bW1hcnkoYWlyYm5iX21vZGVsXzEpDQpgYGANCg0KSOG7k2kgcXV5IG3DtCBow6xuaCB0aGVvIGdpw6EgbmjDoCB2w6AgbmVpZ2hib3VyaG9vZF9ncm91cCwgc28gc8OhbmggduG7m2kgbcO0IGjDrG5oIGjhu5NpIHF1eSAgYWlyYm5iX21vZGVsXzENCmBgYHtyfQ0KYWlyYm5iX21vZGVsXzIgPC0gbG0gKHByaWNlIH4gcm9vbV90eXBlICsgbmVpZ2hib3VyaG9vZF9ncm91cCAsIGRhdGEgPSBhaXJibmJfZGF0YSkNCnN1bW1hcnkoYWlyYm5iX21vZGVsXzIpDQpgYGANCg0KS2nhu4NtIHRyYSDEkeG7mSBwaMO5IGjhu6NwIGPhu6dhIG3DtCBow6xuaA0KDQpNw7QgaMOsbmggZ+G7k20gdOG6pXQgY+G6oyBjw6FjIGJp4bq/bjogTcO0IGjDrG5oIGtow7RuZyBwaMO5IGjhu6NwISENCmBgYHtyfQ0KcGxvdChhaXJibmJfbW9kZWxfMikNCmBgYA0KDQoNCmBgYHtyfQ0KYWlyYm5iX21vZGVsXzMgPC0gbG0gKHByaWNlIH4gbmVpZ2hib3VyaG9vZF9ncm91cCArIGxhdGl0dWRlICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvbmdpdHVkZSArIHJvb21fdHlwZSArIG1pbmltdW1fbmlnaHRzICArDQogICAgICAgICAgICAgICAgICAgICAgICBudW1iZXJfb2ZfcmV2aWV3cyArIHJldmlld3NfcGVyX21vbnRoICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGN1bGF0ZWRfaG9zdF9saXN0aW5nc19jb3VudCArDQogICAgICAgICAgICAgICAgICAgICAgICBhdmFpbGFiaWxpdHlfMzY1LCBkYXRhID0gYWlyYm5iX2RhdGEpDQpzdW1tYXJ5KGFpcmJuYl9tb2RlbF8zKQ0KYGBgDQoNCkdp4bqjaSB0aMOtY2ggaOG7hyBz4buRIGjhu5NpIHF1eSB2w6AgaOG7hyBz4buRIHjDoWMgxJHhu4tuaCBSXjIgdHJvbmcgbcO0IGjDrG5oIHRyw6puLg0KDQoNCmBgYHtyfQ0KcGxvdChhaXJibmJfbW9kZWxfMykNCmBgYA0KDQoNCk3DtCBow6xuaCBraMOhIHjDonUhISBOZ3V5w6puIG5ow6JuPz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/DQoNCktp4buDbSB0cmEgbOG6oWkgYmnhur9uIHBo4bulIHRodeG7mWMgcHJpY2UNCg0KYGBge3J9DQpzdW1tYXJ5KGFpcmJuYl9kYXRhJHByaWNlKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChhaXJibmJfZGF0YSRwcmljZSkNCmhpc3QoYWlyYm5iX2RhdGEkcHJpY2UpDQpgYGANCg0KxJDhu5MgdGjhu4sgdHLDqm4gY2hvIHRo4bqleSBnacOhIG5ow6AgY8OzIG3hu5l0IHPhu5EgZ2nDoSB0cuG7iyBuZ2/huqFpIGxhaSwgZG8gxJHDsywgY2jDum5nIHRhIGxv4bqhaSBi4buPIDEwJSBnacOhIHRy4buLIGzhu5tuIG5o4bqldCB2w6AgMTAlIGdpw6EgdHLhu4sgbmjhu48gbmjhuqV0LiDEkMOieSBsw6AgMSB0aGFvIHTDoWMgdGjGsOG7nW5nIHPhu60gZOG7pW5nIGtoaSBuZ2hpw6puIGPhu6l1IHbhu4EgZ2nDoSB0aeG7gW4uIEzGsHUgw70gbmjGsCBzYXUNCiAqIEPDsyB0aOG7gyBsb+G6oWkgYuG7jyDDrXQgaMahbiBuaMawIDElIHRvcCB2w6AgMSUgYm90dG9tLCBsb+G6oWkgYuG7jyBiYW8gbmhpw6p1IGzDoCB0w7l5IHbDoG8gdOG7q25nIHPhu5EgbGnhu4d1IHbDoCBnacOhIGPhu6dhIGJp4bq/biDEkcOzLiBMb+G6oWkgYuG7jyBiYW8gbmhpw6p1IHRow6wgc+G6vSB2aeG6v3QgbOG6oWkgdHJvbmcgYsOhbyBjw6FvDQogKiBCaeG6v24gZ2nDoSBuaMawIHRyw6puIGPFqW5nIHjhu60gbMO9IHTGsMahbmcgdOG7sSBuaMawIGPDoWMgYmnhur9uIHbhu4EgdGnhu4FuIG5oxrAgdGh1IG5o4bqtcCwgY2hpIHRpw6p1Li4NCiAqIEtoaSBsb+G6oWkgYuG7jyBjw6FjIGdpw6EgdHLhu4sgbOG7m24gbmjhuqV0IHbDoCBuaOG7jyBuaOG6pXQgbMOgIDEgYsaw4bubYyBj4bunYSB44butIGzDvSBz4bqhY2ggc+G7kSBsaeG7h3UsIG7Dqm4gcXXDoSB0csOsbmggeOG7rSBsw70gc+G6oWNoIHPhur0ga+G6v3QgaOG7o3AgduG7m2kgcXXDoSB0csOsbmggcGjDom4gdMOtY2ggdsOgIGzDoG0gxJFpIGzDoG0gbOG6oWkgbmhp4buBdSBs4bqnbiDEkeG6v24ga2hpIHTDrG0gxJHGsOG7o2MgbcO0IGjDrG5oIHBow7kgaOG7o3AgbmjhuqV0Lg0KDQoNCiMjIyA0LjMuIExv4bqhaSBi4buPIDEwJSBnacOhIHRy4buLIGzhu5tuIG5o4bqldCB2w6AgMTAlIGdpw6EgdHLhu4sgbmjhu48gbmjhuqV0DQoNCmBgYHtyfQ0KDQpxOTAgPC0gcXVhbnRpbGUoYWlyYm5iX2RhdGEkcHJpY2UsIDAuOSkNCnExMCA8LSBxdWFudGlsZShhaXJibmJfZGF0YSRwcmljZSwgMC4xKQ0KYWlyYm5iX2ZpbHRlcmVkX2RhdGEgPC0gIGFpcmJuYl9kYXRhWyBhaXJibmJfZGF0YSRwcmljZSA+IHExMCAmICBhaXJibmJfZGF0YSRwcmljZSA8IHE5MCwgXQ0KI0NvZGUgbmFuZyBjYW8gbmh1IGR1b2kgbmF5ISENCiNhaXJibmJfZmlsdGVyZWRfZGF0YSA8LSBhaXJibmJfZGF0YSAlPiUgDQogIyBmaWx0ZXIocHJpY2UgPCBxdWFudGlsZShhaXJibmJfZGF0YSRwcmljZSwgMC45KSAmIHByaWNlID4gcXVhbnRpbGUoYWlyYm5iX2RhdGEkcHJpY2UsIDAuMSkpICU+JSANCiAgI2Ryb3BfbmEoKQ0KYGBgDQoNCk5ow6xuIGzhuqFpIGdpw6EgdHLhu4sgcHJpY2Ugc2F1IGtoaSDEkcOjIGxv4bqhaSBi4buPIHPhu5EgbGnhu4d1IHRyw6puIHPhu5EgbGnhu4d1IGFpcmJuYl9maWx0ZXJlZF9kYXRhLg0KDQoNCmBgYHtyfQ0Kc3VtbWFyeShhaXJibmJfZmlsdGVyZWRfZGF0YSRwcmljZSkNCnBsb3QoYWlyYm5iX2ZpbHRlcmVkX2RhdGEkcHJpY2UpDQpoaXN0KGFpcmJuYl9maWx0ZXJlZF9kYXRhJHByaWNlKQ0KYGBgDQoNCiMjIyA0LjMuIFRo4buxYyBoaeG7h24gbOG6oWkgbcO0IGjDrG5oIGjhu5NpIHF1eSB0csOqbiBz4buRIGxp4buHdSBt4bubaQ0KDQpgYGB7cn0NCmFpcmJuYl9tb2RlbF8zX25ldyA8LSBsbSAocHJpY2UgfiBuZWlnaGJvdXJob29kX2dyb3VwICsgbGF0aXR1ZGUgKw0KICAgICAgICAgICAgICAgICAgICAgICAgbG9uZ2l0dWRlICsgcm9vbV90eXBlICsgbWluaW11bV9uaWdodHMgICsNCiAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcl9vZl9yZXZpZXdzICsgcmV2aWV3c19wZXJfbW9udGggKw0KICAgICAgICAgICAgICAgICAgICAgICAgY2FsY3VsYXRlZF9ob3N0X2xpc3RpbmdzX2NvdW50ICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGF2YWlsYWJpbGl0eV8zNjUsIGRhdGEgPSBhaXJibmJfZmlsdGVyZWRfZGF0YSkNCnN1bW1hcnkoYWlyYm5iX21vZGVsXzNfbmV3KQ0KcGxvdChhaXJibmJfbW9kZWxfM19uZXcpDQpgYGANCg0KVsOsIGJp4bq/biBnacOhIGzDoCBraMO0bmcgw6JtLCBuw6puIGNow7puZyB0YSBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgbG9nYXJpdCBj4bunYSBwcmljZSB0cm9uZyBtw7QgaMOsbmguIMSQ4bqndSB0acOqbiwgbmjDrG4gdGjhu5FuZyBrw6ogbcO0IHThuqMgY+G7p2EgYmnhur9uIGxvZ2FyaXQocHJpY2UpDQoNCmBgYHtyfQ0Kc3VtbWFyeShsb2coYWlyYm5iX2ZpbHRlcmVkX2RhdGEkcHJpY2UpKQ0KcGxvdChsb2coYWlyYm5iX2ZpbHRlcmVkX2RhdGEkcHJpY2UpKQ0KaGlzdChsb2coYWlyYm5iX2ZpbHRlcmVkX2RhdGEkcHJpY2UpKQ0KYGBgDQoNCktp4buDbSB0cmEgbcO0IGjDrG5oIGjhu5NpIHF1eSB24bubaSBsb2cocHJpY2UpIHbDoCBzbyBzw6FuaCB24bubaSBtw7QgaMOsbmggYWlyYm5iX21vZGVsXzNfbmV3DQoNCmBgYHtyfQ0KYWlyYm5iX21vZGVsXzNfbmV3X2xvZyA8LSBsbSAobG9nKHByaWNlKSB+IG5laWdoYm91cmhvb2RfZ3JvdXAgKyBsYXRpdHVkZSArDQogICAgICAgICAgICAgICAgICAgICAgICBsb25naXR1ZGUgKyByb29tX3R5cGUgKyBtaW5pbXVtX25pZ2h0cyAgKw0KICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyX29mX3Jldmlld3MgKyByZXZpZXdzX3Blcl9tb250aCArDQogICAgICAgICAgICAgICAgICAgICAgICBjYWxjdWxhdGVkX2hvc3RfbGlzdGluZ3NfY291bnQgKw0KICAgICAgICAgICAgICAgICAgICAgICAgYXZhaWxhYmlsaXR5XzM2NSwgZGF0YSA9IGFpcmJuYl9maWx0ZXJlZF9kYXRhKQ0Kc3VtbWFyeShhaXJibmJfbW9kZWxfM19uZXdfbG9nICkNCnBsb3QoYWlyYm5iX21vZGVsXzNfbmV3X2xvZyApDQpgYGANCg0KDQojIyA1LiBE4buxIGLDoW8gZ2nDoSBuaMOgDQoNClBo4bqnbiBk4buxIGLDoW8gZ2nDoSB0cuG7iyBjw6EgdGjhu4MgY8OzIHRo4buDIMSRxrDhu6NjIHRo4buxYyBoaeG7h24gbOG7h2NoIHByZWRpY3QoKSB0cm9uZyBSIGtoaSBjdW5nIGPhuqVwIMSR4bqneSDEkeG7pyBjw6FjIHRow7RuZyB0aW4gY8OhYyBiaeG6v24gxJHhu5ljIGzhuq1wLg0KDQpW4bubaSBtw7QgaMOsbmggZOG7sSBiw6FvIHThu5VuZyBxdcOhdCBoxqFuLCB0aMaw4budbmcgY2hpYSBz4buRIGxp4buHdSB0aMOgbmggMiB04bqtcCAodHJhaW4gdsOgIHRlc3QpIHbDoCB0aOG7sWMgaGnhu4duLCBjaGkgdGnhur90IHRoYW0ga2jhuqNvIHThuqFpOiBodHRwczovL3JwdWJzLmNvbS9TYXlha0NoYWtyYWJvcnR5L05ld1lvcmtBaXJCbkJfTW9kZWxsaW5nIA0KDQo=