This is an analysis of data from from Inside Airbnb.

The data is scraped listings from Airbnb in Lisbon, Portugal.

The data

Short-term rentals have been an issue in many cities across Europe, including Lisbon, the focus of online publication Atlas Lisboa.

I searched for data on short-term rentals in Lisbon and found Inside Airbnb, which scrapes listings from Airbnb, the world’s largest short-term rental platform.

I found data for the city of Lisbon, and decided to explore what it could tell me about short-term rentals in the city.

The data can be found here.

The data dictionary by Inside Airbnb can be found here

This data is licensed under a Creative Commons Attribution 4.0 International License.

df <- read.csv("inside_airbnb_listings.csv") %>% 
  clean_names()

df$price <- gsub("[$,]", "", df$price)
df$price <- as.numeric(df$price)

Filtering

The data includes a lot of information such as host bios and listings descriptions. For this analysis, I am focusing on licencing so start by selecting only the variables I think will be useful.

The data is then filtered by neighbourhood_group_cleansed to only show listings in the city of Lisbon (Lisboa) rather than Greater Lisbon.

lisbon_listings <- df %>% 
  select(id, listing_url, host_id, host_name, neighbourhood_group_cleansed, license, latitude, longitude, room_type, price, minimum_nights) %>% 
  filter(neighbourhood_group_cleansed == "Lisboa")

Next, I filter by license to find listings that self-declare as “exempt”.

I also filter by license to find listings that have no licence listed (which I will refer to as ‘blank’ listings).

Each listing has a unique ID, so I am using these to count individual listings.

exempt_listings <- lisbon_listings %>%
    filter(license == "Exempt")

blank_listings <- lisbon_listings %>%
    filter(license == "")

# Number of listings in Lisbon city 
length(lisbon_listings$id)
## [1] 17428
# Number of listings in Lisbon that self-declared as 'exempt' on Airbnb
length(exempt_listings$id)
## [1] 3698
# Number of listings in Lisbon that left the licence section empty on Airbnb
length(blank_listings$id)
## [1] 669
# Percentage of Lisbon listings that self-declared as 'exempt' on Airbnb
percent((length(exempt_listings$id)/length(lisbon_listings$id)), accuracy = 0.01)
## [1] "21.22%"
# Percentage of Lisbon listings that leave the licence section blank on Airbnb
percent((length(blank_listings$id)/length(lisbon_listings$id)), accuracy = 0.01)
## [1] "3.84%"

We can see that there are 17428 Airbnb listings in Lisbon city and 3698 of those listings declare that they are ‘exempt’ from licencing, and a further 669 have nothing entered in the licence section on Airbnb.

How many are homes?

Next, I want to check how many of those are entire apartment or houses, since it is these rentals that put the most pressure on city housing stock.

Starting with ‘exempt’ listings.

table(exempt_listings$room_type)
## 
## Entire home/apt      Hotel room    Private room     Shared room 
##            2460              18            1219               1
exempt_listings %>% 
    ggplot(aes(room_type))+
  geom_bar()+
  labs(title = "Listings self-reporting as exempt", x = "Room type", y = "# of listings")

exempt_homes <- exempt_listings %>% 
  filter(room_type == "Entire home/apt")

We see that 2460 of those ‘exempt’ listings are entire homes.

Doing the same for blank listings:

table(blank_listings$room_type)
## 
## Entire home/apt      Hotel room    Private room     Shared room 
##             498              16             153               2
blank_listings %>% 
    ggplot(aes(room_type))+
  geom_bar()+
  labs(title = "Blank listings", x = "Room type", y = "# of listings")

blank_homes <- blank_listings %>% 
  filter(room_type == "Entire home/apt")

We can see that 498 of the blank listings are entire homes.

Medium- or short-term rentals?

In Portugal, you can offer your property as a medium-term let (normally a month or more) for students and such.

So next, I look at homes listed on Airbnb by the the minimum number of nights offered to see if this might be a reason for certain exemptions.

ggplotly(exempt_homes %>% 
  filter(minimum_nights < 100) %>% 
  ggplot(aes(minimum_nights))+
  geom_bar(fill = "blue")+
  labs(x = "Minimum Nights", y = "Listings"), 
  dynamicTicks = "y")

There seem to be two clusters.

The majority of exempt homes seem to be operating as regular short-term rentals, with the minimum number of nights listed as a week or less. There is another group that has minimum nights starting around one month, most likely medium-term rentals.

# Entire homes that are offerings short term stays 
short_exempt_homes <- exempt_homes %>%
  filter(minimum_nights >=1, minimum_nights <=7)
  
length(short_exempt_homes$id)
## [1] 1382

We have 1382 homes self-declared as exempt offering stays of 7 days or less.

This is very suspicious, but does not necessarily mean they are illegal.

Next I look at the number of exempt homes offerings stays with minimum number of nights above 28 days but less than the 1 year, which would make a rental permanent.

medium_term <- exempt_homes %>%
  filter(minimum_nights >=28, minimum_nights <365)

length(medium_term$id)
## [1] 1003
percent((length(medium_term$id)/length(exempt_homes$id)), accuracy = 0.01)
## [1] "40.77%"

We can see that these “medium-term rentals” account for more than 40% of exempt homes listed on Airbnb.

What next?

From here, we have a few outcomes to follow up:

  1. One in five Airbnb listings in Lisbon self-declare as exempt
  • The majority of these have no obvious reason for being exempt
  • Around 40% seem to be ‘medium-term’ rentals, which could offer a loophole to new legislation
  1. Almost 4% of listings in Lisbon don’t list any licence at all

The companies are coming in

Next, I am grouping by host ID and host name. Host IDs allow us to differentiate between multiple hosts with the same name.

multi_usrs <- exempt_homes %>% 
  group_by(host_id, host_name) %>% 
  tally(sort = TRUE) 

reactable(multi_usrs)

We can see that two hosts stand out: Blueground and Ukio. * Are these companies? * What business are they operating?

exempt_homes %>% 
  filter(host_name %in% c("Blueground","Ukio")) %>% 
  group_by(host_name) %>% 
  summarise(average_price = mean(price, na.rm = T))
## # A tibble: 2 × 2
##   host_name  average_price
##   <chr>              <dbl>
## 1 Blueground          153.
## 2 Ukio                151.

The average price of listings by Blueground and Ukio is 153EUR and 150EUR, respectively.

Or, the equivalent of 4590EUR and 4500EUR per month (30 days), considerably more than a standard rent in the city.

It’s also interesting to see than many ‘exempt’ hosts have multiple listings.

Doing the same for blank listings:

reactable(blank_homes %>% group_by(host_id, host_name) %>% tally(sort = TRUE))

A few individuals stand out as having multiple listings but no licence listed.

It is important to remember that not having a licence displayed does not mean they don’t have a licence.

It is likely that some of these listings predate the requirement to add a licence.

Map of exempt and “blank” homes in Lisbon

map_df <- lisbon_listings %>%
  filter(license == "Exempt" | license == "") %>% 
  filter(room_type == "Entire home/apt") %>% 
  select(id, license, longitude, latitude, price, host_id, host_name)

pal <- colorFactor(
  palette = c("red", "blue"),
  domain = map_df$license)

map_df %>% 
  leaflet() %>% 
  addTiles() %>% 
  setView(lat = 38.736946, lng = -9.142685, zoom = 12) %>% 
  addCircles(lat = ~latitude, lng = ~longitude,
             color= ~pal(license),
             popup = map_df$name) %>% 
  addLegend(position = "bottomright", 
            colors = c("red", "blue"), 
            labels = c("Blank", "Exempt"))
LS0tCnRpdGxlOiAiRXhlbXB0IEFpcmJuYiBMaXN0aW5ncyBpbiBMaXNib24iCmF1dGhvcjogIkVkZW4gRmxhaGVydHkiCmRhdGU6ICIyMDI2LTAxLTIwIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogdW5pdGVkCiAgCi0tLQoKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJzY2FsZXMiKQpsaWJyYXJ5KCJsZWFmbGV0IikKbGlicmFyeSgicmVhY3RhYmxlIikKbGlicmFyeSgicGxvdGx5IikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKbGlicmFyeSgiamFuaXRvciIpCmBgYAoKVGhpcyBpcyBhbiBhbmFseXNpcyBvZiBkYXRhIGZyb20gZnJvbSBJbnNpZGUgQWlyYm5iLiAKClRoZSBkYXRhIGlzIHNjcmFwZWQgbGlzdGluZ3MgZnJvbSBBaXJibmIgaW4gTGlzYm9uLCBQb3J0dWdhbC4KCiMjIFRoZSBkYXRhCgpTaG9ydC10ZXJtIHJlbnRhbHMgaGF2ZSBiZWVuIGFuIGlzc3VlIGluIG1hbnkgY2l0aWVzIGFjcm9zcyBFdXJvcGUsIGluY2x1ZGluZyBMaXNib24sIHRoZSBmb2N1cyBvZiBvbmxpbmUgcHVibGljYXRpb24gW0F0bGFzIExpc2JvYV0oaHR0cHM6Ly93d3cuYXRsYXNsaXNib2EuY29tLykuCgpJIHNlYXJjaGVkIGZvciBkYXRhIG9uIHNob3J0LXRlcm0gcmVudGFscyBpbiBMaXNib24gYW5kIGZvdW5kIFtJbnNpZGUgQWlyYm5iXShodHRwczovL2luc2lkZWFpcmJuYi5jb20vKSwgd2hpY2ggc2NyYXBlcyBsaXN0aW5ncyBmcm9tIFtBaXJibmJdKGh0dHBzOi8vYWlyYm5iLmNvbS8pLCB0aGUgd29ybGQncyBsYXJnZXN0IHNob3J0LXRlcm0gcmVudGFsIHBsYXRmb3JtLiAKCkkgZm91bmQgZGF0YSBmb3IgdGhlIGNpdHkgb2YgTGlzYm9uLCBhbmQgZGVjaWRlZCB0byBleHBsb3JlIHdoYXQgaXQgY291bGQgdGVsbCBtZSBhYm91dCBzaG9ydC10ZXJtIHJlbnRhbHMgaW4gdGhlIGNpdHkuIAoKVGhlIGRhdGEgY2FuIGJlIGZvdW5kIFtoZXJlLl0oaHR0cHM6Ly9pbnNpZGVhaXJibmIuY29tL2dldC10aGUtZGF0YS8pCgpUaGUgZGF0YSBkaWN0aW9uYXJ5IGJ5IEluc2lkZSBBaXJibmIgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xaVdDTkpjU3V0WXFwVUxTUUhsTnlHSW5VdkhnMkJvVUdvTlJJR2E2U3pjNC9lZGl0P2dpZD0xMzIyMjg0NTk2I2dpZD0xMzIyMjg0NTk2KQoKVGhpcyBkYXRhIGlzIGxpY2Vuc2VkIHVuZGVyIGEgW0NyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24gNC4wIEludGVybmF0aW9uYWwgTGljZW5zZS5dKGh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LzQuMC8pCgoKYGBge3J9CmRmIDwtIHJlYWQuY3N2KCJpbnNpZGVfYWlyYm5iX2xpc3RpbmdzLmNzdiIpICU+JSAKICBjbGVhbl9uYW1lcygpCgpkZiRwcmljZSA8LSBnc3ViKCJbJCxdIiwgIiIsIGRmJHByaWNlKQpkZiRwcmljZSA8LSBhcy5udW1lcmljKGRmJHByaWNlKQoKYGBgCgoKIyMgRmlsdGVyaW5nIAoKVGhlIGRhdGEgaW5jbHVkZXMgYSBsb3Qgb2YgaW5mb3JtYXRpb24gc3VjaCBhcyBob3N0IGJpb3MgYW5kIGxpc3RpbmdzIGRlc2NyaXB0aW9ucy4gRm9yIHRoaXMgYW5hbHlzaXMsIEkgYW0gZm9jdXNpbmcgb24gbGljZW5jaW5nIHNvIHN0YXJ0IGJ5IHNlbGVjdGluZyBvbmx5IHRoZSB2YXJpYWJsZXMgSSB0aGluayB3aWxsIGJlIHVzZWZ1bC4KClRoZSBkYXRhIGlzIHRoZW4gZmlsdGVyZWQgYnkgKm5laWdoYm91cmhvb2RfZ3JvdXBfY2xlYW5zZWQqIHRvIG9ubHkgc2hvdyBsaXN0aW5ncyBpbiB0aGUgY2l0eSBvZiBMaXNib24gKExpc2JvYSkgcmF0aGVyIHRoYW4gR3JlYXRlciBMaXNib24uCgoKYGBge3J9Cmxpc2Jvbl9saXN0aW5ncyA8LSBkZiAlPiUgCiAgc2VsZWN0KGlkLCBsaXN0aW5nX3VybCwgaG9zdF9pZCwgaG9zdF9uYW1lLCBuZWlnaGJvdXJob29kX2dyb3VwX2NsZWFuc2VkLCBsaWNlbnNlLCBsYXRpdHVkZSwgbG9uZ2l0dWRlLCByb29tX3R5cGUsIHByaWNlLCBtaW5pbXVtX25pZ2h0cykgJT4lIAogIGZpbHRlcihuZWlnaGJvdXJob29kX2dyb3VwX2NsZWFuc2VkID09ICJMaXNib2EiKQpgYGAKCk5leHQsIEkgZmlsdGVyIGJ5ICpsaWNlbnNlKiB0byBmaW5kIGxpc3RpbmdzIHRoYXQgc2VsZi1kZWNsYXJlIGFzICJleGVtcHQiLgoKSSBhbHNvIGZpbHRlciBieSAqbGljZW5zZSogdG8gZmluZCBsaXN0aW5ncyB0aGF0IGhhdmUgbm8gbGljZW5jZSBsaXN0ZWQgKHdoaWNoIEkgd2lsbCByZWZlciB0byBhcyAnYmxhbmsnIGxpc3RpbmdzKS4KCkVhY2ggbGlzdGluZyBoYXMgYSB1bmlxdWUgSUQsIHNvIEkgYW0gdXNpbmcgdGhlc2UgdG8gY291bnQgaW5kaXZpZHVhbCBsaXN0aW5ncy4KCmBgYHtyfQoKZXhlbXB0X2xpc3RpbmdzIDwtIGxpc2Jvbl9saXN0aW5ncyAlPiUKICAgIGZpbHRlcihsaWNlbnNlID09ICJFeGVtcHQiKQoKYmxhbmtfbGlzdGluZ3MgPC0gbGlzYm9uX2xpc3RpbmdzICU+JQogICAgZmlsdGVyKGxpY2Vuc2UgPT0gIiIpCgojIE51bWJlciBvZiBsaXN0aW5ncyBpbiBMaXNib24gY2l0eSAKbGVuZ3RoKGxpc2Jvbl9saXN0aW5ncyRpZCkKCiMgTnVtYmVyIG9mIGxpc3RpbmdzIGluIExpc2JvbiB0aGF0IHNlbGYtZGVjbGFyZWQgYXMgJ2V4ZW1wdCcgb24gQWlyYm5iCmxlbmd0aChleGVtcHRfbGlzdGluZ3MkaWQpCgojIE51bWJlciBvZiBsaXN0aW5ncyBpbiBMaXNib24gdGhhdCBsZWZ0IHRoZSBsaWNlbmNlIHNlY3Rpb24gZW1wdHkgb24gQWlyYm5iCmxlbmd0aChibGFua19saXN0aW5ncyRpZCkKCiMgUGVyY2VudGFnZSBvZiBMaXNib24gbGlzdGluZ3MgdGhhdCBzZWxmLWRlY2xhcmVkIGFzICdleGVtcHQnIG9uIEFpcmJuYgpwZXJjZW50KChsZW5ndGgoZXhlbXB0X2xpc3RpbmdzJGlkKS9sZW5ndGgobGlzYm9uX2xpc3RpbmdzJGlkKSksIGFjY3VyYWN5ID0gMC4wMSkKCiMgUGVyY2VudGFnZSBvZiBMaXNib24gbGlzdGluZ3MgdGhhdCBsZWF2ZSB0aGUgbGljZW5jZSBzZWN0aW9uIGJsYW5rIG9uIEFpcmJuYgpwZXJjZW50KChsZW5ndGgoYmxhbmtfbGlzdGluZ3MkaWQpL2xlbmd0aChsaXNib25fbGlzdGluZ3MkaWQpKSwgYWNjdXJhY3kgPSAwLjAxKQoKYGBgCgoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSAqKjE3NDI4KiogQWlyYm5iIGxpc3RpbmdzIGluIExpc2JvbiBjaXR5IGFuZCAqKjM2OTgqKiBvZiB0aG9zZSBsaXN0aW5ncyBkZWNsYXJlIHRoYXQgdGhleSBhcmUgJ2V4ZW1wdCcgZnJvbSBsaWNlbmNpbmcsIGFuZCBhIGZ1cnRoZXIgKio2NjkqKiBoYXZlIG5vdGhpbmcgZW50ZXJlZCBpbiB0aGUgbGljZW5jZSBzZWN0aW9uIG9uIEFpcmJuYi4gCgojIyBIb3cgbWFueSBhcmUgaG9tZXM/IAoKTmV4dCwgSSB3YW50IHRvIGNoZWNrIGhvdyBtYW55IG9mIHRob3NlIGFyZSBlbnRpcmUgYXBhcnRtZW50IG9yIGhvdXNlcywgc2luY2UgaXQgaXMgdGhlc2UgcmVudGFscyB0aGF0IHB1dCB0aGUgbW9zdCBwcmVzc3VyZSBvbiBjaXR5IGhvdXNpbmcgc3RvY2suCgpTdGFydGluZyB3aXRoICdleGVtcHQnIGxpc3RpbmdzLgoKYGBge3J9Cgp0YWJsZShleGVtcHRfbGlzdGluZ3Mkcm9vbV90eXBlKQoKZXhlbXB0X2xpc3RpbmdzICU+JSAKICAgIGdncGxvdChhZXMocm9vbV90eXBlKSkrCiAgZ2VvbV9iYXIoKSsKICBsYWJzKHRpdGxlID0gIkxpc3RpbmdzIHNlbGYtcmVwb3J0aW5nIGFzIGV4ZW1wdCIsIHggPSAiUm9vbSB0eXBlIiwgeSA9ICIjIG9mIGxpc3RpbmdzIikKCmV4ZW1wdF9ob21lcyA8LSBleGVtcHRfbGlzdGluZ3MgJT4lIAogIGZpbHRlcihyb29tX3R5cGUgPT0gIkVudGlyZSBob21lL2FwdCIpCgpgYGAKCldlIHNlZSB0aGF0ICoqMjQ2MCoqIG9mIHRob3NlICdleGVtcHQnIGxpc3RpbmdzIGFyZSBlbnRpcmUgaG9tZXMuIAoKRG9pbmcgdGhlIHNhbWUgZm9yIGJsYW5rIGxpc3RpbmdzOgoKYGBge3J9CnRhYmxlKGJsYW5rX2xpc3RpbmdzJHJvb21fdHlwZSkKCmJsYW5rX2xpc3RpbmdzICU+JSAKICAgIGdncGxvdChhZXMocm9vbV90eXBlKSkrCiAgZ2VvbV9iYXIoKSsKICBsYWJzKHRpdGxlID0gIkJsYW5rIGxpc3RpbmdzIiwgeCA9ICJSb29tIHR5cGUiLCB5ID0gIiMgb2YgbGlzdGluZ3MiKQoKYmxhbmtfaG9tZXMgPC0gYmxhbmtfbGlzdGluZ3MgJT4lIAogIGZpbHRlcihyb29tX3R5cGUgPT0gIkVudGlyZSBob21lL2FwdCIpCgpgYGAKCldlIGNhbiBzZWUgdGhhdCAqKjQ5OCoqIG9mIHRoZSBibGFuayBsaXN0aW5ncyBhcmUgZW50aXJlIGhvbWVzLiAKCiMjIE1lZGl1bS0gb3Igc2hvcnQtdGVybSByZW50YWxzPwoKSW4gUG9ydHVnYWwsIHlvdSBjYW4gb2ZmZXIgeW91ciBwcm9wZXJ0eSBhcyBhIG1lZGl1bS10ZXJtIGxldCAobm9ybWFsbHkgYSBtb250aCBvciBtb3JlKSBmb3Igc3R1ZGVudHMgYW5kIHN1Y2guCgpTbyBuZXh0LCBJIGxvb2sgYXQgaG9tZXMgbGlzdGVkIG9uIEFpcmJuYiBieSB0aGUgdGhlIG1pbmltdW0gbnVtYmVyIG9mIG5pZ2h0cyBvZmZlcmVkIHRvIHNlZSBpZiB0aGlzIG1pZ2h0IGJlIGEgcmVhc29uIGZvciBjZXJ0YWluIGV4ZW1wdGlvbnMuIAoKYGBge3J9CgpnZ3Bsb3RseShleGVtcHRfaG9tZXMgJT4lIAogIGZpbHRlcihtaW5pbXVtX25pZ2h0cyA8IDEwMCkgJT4lIAogIGdncGxvdChhZXMobWluaW11bV9uaWdodHMpKSsKICBnZW9tX2JhcihmaWxsID0gImJsdWUiKSsKICBsYWJzKHggPSAiTWluaW11bSBOaWdodHMiLCB5ID0gIkxpc3RpbmdzIiksIAogIGR5bmFtaWNUaWNrcyA9ICJ5IikKCmBgYAoKClRoZXJlIHNlZW0gdG8gYmUgdHdvIGNsdXN0ZXJzLgoKVGhlIG1ham9yaXR5IG9mIGV4ZW1wdCBob21lcyBzZWVtIHRvIGJlIG9wZXJhdGluZyBhcyByZWd1bGFyIHNob3J0LXRlcm0gcmVudGFscywgd2l0aCB0aGUgbWluaW11bSBudW1iZXIgb2YgbmlnaHRzIGxpc3RlZCBhcyBhIHdlZWsgb3IgbGVzcy4gClRoZXJlIGlzIGFub3RoZXIgZ3JvdXAgdGhhdCBoYXMgbWluaW11bSBuaWdodHMgc3RhcnRpbmcgYXJvdW5kIG9uZSBtb250aCwgbW9zdCBsaWtlbHkgbWVkaXVtLXRlcm0gcmVudGFscy4gCgpgYGB7cn0KCiMgRW50aXJlIGhvbWVzIHRoYXQgYXJlIG9mZmVyaW5ncyBzaG9ydCB0ZXJtIHN0YXlzIApzaG9ydF9leGVtcHRfaG9tZXMgPC0gZXhlbXB0X2hvbWVzICU+JQogIGZpbHRlcihtaW5pbXVtX25pZ2h0cyA+PTEsIG1pbmltdW1fbmlnaHRzIDw9NykKICAKbGVuZ3RoKHNob3J0X2V4ZW1wdF9ob21lcyRpZCkKCgpgYGAKCldlIGhhdmUgKioxMzgyKiogaG9tZXMgc2VsZi1kZWNsYXJlZCBhcyBleGVtcHQgb2ZmZXJpbmcgc3RheXMgb2YgNyBkYXlzIG9yIGxlc3MuIAoKVGhpcyBpcyB2ZXJ5IHN1c3BpY2lvdXMsIGJ1dCBkb2VzIG5vdCBuZWNlc3NhcmlseSBtZWFuIHRoZXkgYXJlIGlsbGVnYWwuCgpOZXh0IEkgbG9vayBhdCB0aGUgbnVtYmVyIG9mIGV4ZW1wdCBob21lcyBvZmZlcmluZ3Mgc3RheXMgd2l0aCBtaW5pbXVtIG51bWJlciBvZiBuaWdodHMgYWJvdmUgMjggZGF5cyBidXQgbGVzcyB0aGFuIHRoZSAxIHllYXIsIHdoaWNoIHdvdWxkIG1ha2UgYSByZW50YWwgcGVybWFuZW50LgoKCmBgYHtyfQoKbWVkaXVtX3Rlcm0gPC0gZXhlbXB0X2hvbWVzICU+JQogIGZpbHRlcihtaW5pbXVtX25pZ2h0cyA+PTI4LCBtaW5pbXVtX25pZ2h0cyA8MzY1KQoKbGVuZ3RoKG1lZGl1bV90ZXJtJGlkKQoKcGVyY2VudCgobGVuZ3RoKG1lZGl1bV90ZXJtJGlkKS9sZW5ndGgoZXhlbXB0X2hvbWVzJGlkKSksIGFjY3VyYWN5ID0gMC4wMSkKCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXNlICJtZWRpdW0tdGVybSByZW50YWxzIiBhY2NvdW50IGZvciBtb3JlIHRoYW4gKio0MCUgb2YgZXhlbXB0IGhvbWVzIGxpc3RlZCBvbiBBaXJibmIqKi4gCgojIyBXaGF0IG5leHQ/CgpGcm9tIGhlcmUsIHdlIGhhdmUgYSBmZXcgb3V0Y29tZXMgdG8gZm9sbG93IHVwOgoKMS4gT25lIGluIGZpdmUgQWlyYm5iIGxpc3RpbmdzIGluIExpc2JvbiBzZWxmLWRlY2xhcmUgYXMgZXhlbXB0CisgVGhlIG1ham9yaXR5IG9mIHRoZXNlIGhhdmUgbm8gb2J2aW91cyByZWFzb24gZm9yIGJlaW5nIGV4ZW1wdAorIEFyb3VuZCA0MCUgc2VlbSB0byBiZSAnbWVkaXVtLXRlcm0nIHJlbnRhbHMsIHdoaWNoIGNvdWxkIG9mZmVyIGEgbG9vcGhvbGUgdG8gbmV3IGxlZ2lzbGF0aW9uCjIuIEFsbW9zdCA0JSBvZiBsaXN0aW5ncyBpbiBMaXNib24gZG9uJ3QgbGlzdCBhbnkgbGljZW5jZSBhdCBhbGwKCiMjIFRoZSBjb21wYW5pZXMgYXJlIGNvbWluZyBpbgoKTmV4dCwgSSBhbSBncm91cGluZyBieSBob3N0IElEIGFuZCBob3N0IG5hbWUuIEhvc3QgSURzIGFsbG93IHVzIHRvIGRpZmZlcmVudGlhdGUgYmV0d2VlbiBtdWx0aXBsZSBob3N0cyB3aXRoIHRoZSBzYW1lIG5hbWUuIAoKYGBge3J9CgptdWx0aV91c3JzIDwtIGV4ZW1wdF9ob21lcyAlPiUgCiAgZ3JvdXBfYnkoaG9zdF9pZCwgaG9zdF9uYW1lKSAlPiUgCiAgdGFsbHkoc29ydCA9IFRSVUUpIAoKcmVhY3RhYmxlKG11bHRpX3VzcnMpCgpgYGAKCldlIGNhbiBzZWUgdGhhdCB0d28gaG9zdHMgc3RhbmQgb3V0OiBCbHVlZ3JvdW5kIGFuZCBVa2lvLiAKKiBBcmUgdGhlc2UgY29tcGFuaWVzPwoqIFdoYXQgYnVzaW5lc3MgYXJlIHRoZXkgb3BlcmF0aW5nPyAKCmBgYHtyfQpleGVtcHRfaG9tZXMgJT4lIAogIGZpbHRlcihob3N0X25hbWUgJWluJSBjKCJCbHVlZ3JvdW5kIiwiVWtpbyIpKSAlPiUgCiAgZ3JvdXBfYnkoaG9zdF9uYW1lKSAlPiUgCiAgc3VtbWFyaXNlKGF2ZXJhZ2VfcHJpY2UgPSBtZWFuKHByaWNlLCBuYS5ybSA9IFQpKQoKYGBgCgpUaGUgYXZlcmFnZSBwcmljZSBvZiBsaXN0aW5ncyBieSBCbHVlZ3JvdW5kIGFuZCBVa2lvIGlzIDE1M0VVUiBhbmQgMTUwRVVSLCByZXNwZWN0aXZlbHkuCgpPciwgdGhlIGVxdWl2YWxlbnQgb2YgNDU5MEVVUiBhbmQgNDUwMEVVUiBwZXIgbW9udGggKDMwIGRheXMpLCBjb25zaWRlcmFibHkgbW9yZSB0aGFuIGEgc3RhbmRhcmQgcmVudCBpbiB0aGUgY2l0eS4gCgpJdCdzIGFsc28gaW50ZXJlc3RpbmcgdG8gc2VlIHRoYW4gbWFueSAnZXhlbXB0JyBob3N0cyBoYXZlIG11bHRpcGxlIGxpc3RpbmdzLgoKRG9pbmcgdGhlIHNhbWUgZm9yIGJsYW5rIGxpc3RpbmdzOgoKYGBge3J9CnJlYWN0YWJsZShibGFua19ob21lcyAlPiUgZ3JvdXBfYnkoaG9zdF9pZCwgaG9zdF9uYW1lKSAlPiUgdGFsbHkoc29ydCA9IFRSVUUpKQpgYGAKCkEgZmV3IGluZGl2aWR1YWxzIHN0YW5kIG91dCBhcyBoYXZpbmcgbXVsdGlwbGUgbGlzdGluZ3MgYnV0IG5vIGxpY2VuY2UgbGlzdGVkLiAKCioqKkl0IGlzIGltcG9ydGFudCB0byByZW1lbWJlciB0aGF0IG5vdCBoYXZpbmcgYSBsaWNlbmNlIGRpc3BsYXllZCBkb2VzIG5vdCBtZWFuIHRoZXkgZG9uJ3QgaGF2ZSBhIGxpY2VuY2UuKioqCgpJdCBpcyBsaWtlbHkgdGhhdCBzb21lIG9mIHRoZXNlIGxpc3RpbmdzIHByZWRhdGUgdGhlIHJlcXVpcmVtZW50IHRvIGFkZCBhIGxpY2VuY2UuCgojIyBNYXAgb2YgZXhlbXB0IGFuZCAiYmxhbmsiIGhvbWVzIGluIExpc2JvbgoKYGBge3J9CgptYXBfZGYgPC0gbGlzYm9uX2xpc3RpbmdzICU+JQogIGZpbHRlcihsaWNlbnNlID09ICJFeGVtcHQiIHwgbGljZW5zZSA9PSAiIikgJT4lIAogIGZpbHRlcihyb29tX3R5cGUgPT0gIkVudGlyZSBob21lL2FwdCIpICU+JSAKICBzZWxlY3QoaWQsIGxpY2Vuc2UsIGxvbmdpdHVkZSwgbGF0aXR1ZGUsIHByaWNlLCBob3N0X2lkLCBob3N0X25hbWUpCgpwYWwgPC0gY29sb3JGYWN0b3IoCiAgcGFsZXR0ZSA9IGMoInJlZCIsICJibHVlIiksCiAgZG9tYWluID0gbWFwX2RmJGxpY2Vuc2UpCgptYXBfZGYgJT4lIAogIGxlYWZsZXQoKSAlPiUgCiAgYWRkVGlsZXMoKSAlPiUgCiAgc2V0VmlldyhsYXQgPSAzOC43MzY5NDYsIGxuZyA9IC05LjE0MjY4NSwgem9vbSA9IDEyKSAlPiUgCiAgYWRkQ2lyY2xlcyhsYXQgPSB+bGF0aXR1ZGUsIGxuZyA9IH5sb25naXR1ZGUsCiAgICAgICAgICAgICBjb2xvcj0gfnBhbChsaWNlbnNlKSwKICAgICAgICAgICAgIHBvcHVwID0gbWFwX2RmJG5hbWUpICU+JSAKICBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLCAKICAgICAgICAgICAgY29sb3JzID0gYygicmVkIiwgImJsdWUiKSwgCiAgICAgICAgICAgIGxhYmVscyA9IGMoIkJsYW5rIiwgIkV4ZW1wdCIpKQogIApgYGAKCgo=