Introduction


Research Question:


What are the Top Tech companies to work for? What are the characteristics that make them so?

Overview:



Needless to say, it’s been a turbulent few years. Companies have either risen to the top or fallen off thanks to competing pressures from all sides. Over the course of this class, we discussed a number of companies, I am curious to explore what are the Top Tech Companies and its characteristics. I think it might be very interesting to do our research, so we can ultimately land our dream job.

Motivation:


Coming from a finance background, as a career changer, researching companies would be helpful to help us align with great employers. Also, I really enjoy the data cleaning part, drilling into a lot of information and having that “ah-ha” moment when I can carve out useful insights. I love creating a fabulous dashboard so I will be creating and embedding the Tableau Dashboard to showcase the finding.

Library

library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.2 ──
## ✔ ggplot2 3.4.1     ✔ purrr   1.0.1
## ✔ tibble  3.2.1     ✔ dplyr   1.1.2
## ✔ tidyr   1.2.0     ✔ stringr 1.4.0
## ✔ readr   2.1.2     ✔ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
library(stringr)
library(dplyr)
library(tidyr)
library(rvest)
## 
## Attaching package: 'rvest'
## 
## The following object is masked from 'package:readr':
## 
##     guess_encoding
library(stopwords)
library(kableExtra)
## 
## Attaching package: 'kableExtra'
## 
## The following object is masked from 'package:dplyr':
## 
##     group_rows
library(wordcloud2)

Load Data


Approach


In answering the question above, the following steps was followed:

—Acquire tech stock data.

—Filter for highest value (growth or market cap) companies.

—Verify corresponding company review on Glassdoor (if < 3.5, drop).

—For each company, scrape the “Pros” section of the top 10 reviews.

—Tidy and transform our collection of reviews.

—Visualize most frequent, pertinent verbage via table, barplot, and wordcloud.

—Analyze and export data to Tableau

—Create a Dashboard in Tableau Public and embed the Dashboard into R markdown

—Conclude

Data Souce 1



—-We pulled in (2) different csv files: a list of the Top 100 tech companies and their corresponding market metrics as well as a list of S&P 500 companies (and corresponding sector)


—-From the exploration, it seems that sp_table dataset’s only interesting addition would have been its “Sector” variable, I decide to shift from merging the 2 tables, instead, just explore the tech_table dataset and manually add sector variable.


#Read in csv files
tech_data <- read_csv("https://raw.githubusercontent.com/yinaS1234/data-607/main/project%20final/tech_sector_list.csv")
## Rows: 100 Columns: 9
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): Symbol, Name
## dbl (7): Price, Change, % Change, Volume, Avg Vol, Market Cap (Billions), PE...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
tech_table <- as_tibble(tech_data)
#head(tech_table)

sp_data <- read_csv("https://raw.githubusercontent.com/yinaS1234/data-607/main/project%20final/sp500_list.csv")
## Rows: 505 Columns: 3
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Symbol, Name, Sector
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
sp_table <- as_tibble(sp_data)

#EDA of table --> size, sector --> dataframe of companies
ncol(tech_table)
## [1] 9
nrow(tech_table)
## [1] 100
summary(tech_table)
##     Symbol              Name               Price             Change      
##  Length:100         Length:100         Min.   :   5.12   Min.   :-8.500  
##  Class :character   Class :character   1st Qu.:  72.42   1st Qu.:-0.290  
##  Mode  :character   Mode  :character   Median : 131.42   Median : 0.710  
##                                        Mean   : 181.01   Mean   : 1.048  
##                                        3rd Qu.: 244.68   3rd Qu.: 2.215  
##                                        Max.   :1020.00   Max.   :15.100  
##                                                                          
##     % Change             Volume             Avg Vol         
##  Min.   :-0.029700   Min.   :      483   Min.   :     6552  
##  1st Qu.:-0.001725   1st Qu.:   946206   1st Qu.:  1114250  
##  Median : 0.008050   Median :  1324000   Median :  1853000  
##  Mean   : 0.012525   Mean   :  5939219   Mean   :  6542440  
##  3rd Qu.: 0.019200   3rd Qu.:  3121500   3rd Qu.:  4757250  
##  Max.   : 0.202400   Max.   :127959000   Max.   :150549000  
##                                                             
##  Market Cap (Billions)    PE Ratio     
##  Min.   :  14.60       Min.   :  9.02  
##  1st Qu.:  20.09       1st Qu.: 26.89  
##  Median :  32.08       Median : 33.84  
##  Mean   :  94.60       Mean   : 70.26  
##  3rd Qu.:  75.33       3rd Qu.: 57.59  
##  Max.   :1936.00       Max.   :667.10  
##                        NA's   :26
#filter 1: "% Change"
high_growth <- filter(tech_table, `% Change` > 0.06) #top 3

#filter 2: "Market Cap"
high_val <- filter(tech_table, `Market Cap (Billions)` > 1000) #top 2

#Merge data frames
filtered <- rbind(high_growth, high_val)

#Add "Sector" column - manually keyed in
filtered$Sector <- c("Financial Services", "Big Data", "Semiconductor", "Big Tech", "Big Tech")
filtered
## # A tibble: 5 × 10
##   Symbol Name    Price Change `% Change` Volume `Avg Vol` Market Cap (Billions…¹
##   <chr>  <chr>   <dbl>  <dbl>      <dbl>  <dbl>     <dbl>                  <dbl>
## 1 SQ     Squar… 208.    11.9      0.0609 1.22e7   9772000                   93.8
## 2 PLTR   Palan…  21.0    2.89     0.159  8.38e7  52088000                   39.5
## 3 UMC    Unite…   6.95   1.17     0.202  1.12e7   3153000                   15.8
## 4 AAPL   Apple… 114.    -3.49    -0.0297 1.28e8 150549000                 1936  
## 5 MSFT   Micro… 210.    -0.28    -0.0013 2.57e7  31868000                 1589  
## # ℹ abbreviated name: ¹​`Market Cap (Billions)`
## # ℹ 2 more variables: `PE Ratio` <dbl>, Sector <chr>
write.csv(tech_table, "/Users/linda/Desktop/techtable.csv")
write.csv(filtered, "/Users/linda/Desktop/filteredstock.csv")



From our Top 100 Tech Companies list,we narrow down to 5:

—–Square, Palantir, and United Microelectronics were filtered in as the top 3 highest growth companies

—–Apple and Microsoft were BY FAR the highest value companies in our list (with a Market Cap greater than $1 trillion)

Data Source 2

—Verify corresponding company review on Glassdoor (if < 3.5, drop).

Drop United Microelectronics (with a rating of 2.5) and proceed with just four companies below.

—-Web-scrape reviews.

##APPLE##

#1. Download HTML and convert to XML with read_html()
a <- read_html("https://www.glassdoor.com/Reviews/Apple-Reviews-E1138.htm")
#2. Extract specific nodes with html_nodes()
a_ext <- html_nodes(a,'.v2__EIReviewDetailsV2__fullWidth:nth-child(1) span')
#3. Extract review text from HTML
a_pros <- html_text(a_ext) #collect pros section of 1st 10 reviews

##MICROSOFT##

m <- read_html("https://www.glassdoor.com/Reviews/Microsoft-Reviews-E1651.htm")
m_ext <- html_nodes(m,'.v2__EIReviewDetailsV2__fullWidth:nth-child(1) span')
m_pros <- html_text(m_ext) #collect pros section of 1st 10 reviews

##PALANTIR##

p <- read_html("https://www.glassdoor.com/Reviews/Palantir-Technologies-Reviews-E236375.htm")
p_ext <- html_nodes(p,'.v2__EIReviewDetailsV2__fullWidth:nth-child(1) span')
p_pros <- html_text(p_ext) #collect pros section of 1st 10 reviews

##SQUARE##

s <- read_html("https://www.glassdoor.com/Reviews/Square-Reviews-E422050.htm")
s_ext <- html_nodes(s,'.v2__EIReviewDetailsV2__fullWidth:nth-child(1) span')
s_pros <- html_text(s_ext) #collect pros section of 1st 10 reviews

Data Transformation

Tidy and transform our collection of reviews.

—–merge to create one dataframe

—–handle special character

—–remove white spaces

—–change to lower cases

—–remove stopwords. non-descriptive words

—–remove NAs

—–output to a table

#merge data frames
merged_pros <- rbind(a_pros, m_pros, p_pros, s_pros)

#Tidy text via regular expressions

#Handle special characters and digits
merged_pros <- str_replace_all(merged_pros, "[^[:alnum:]]", " ") #remove non-alpha numeric characters
merged_pros <- str_replace_all(merged_pros, "[!^[:digit:]]", "") #remove digits

#Handle white space
merged_pros <- trimws(merged_pros)
merged_pros <- str_replace_all(merged_pros, "\\s+", " ") #compress whitespace
merged_pros <- str_replace_all(merged_pros, "' '", "','") #' ' ' --> ','

#Remove excess characters and properly split and then re-merge the vector
merged_pros <- str_split(merged_pros, pattern=" ") #convert vector to list at each ,
merged_pros <- unlist(merged_pros) #convert list back to vector
merged_pros <- tolower(merged_pros) #convert list to lowercase

stopwords_regex = paste(stopwords('en'), collapse = '\\b|\\b')
stopwords_regex = paste0('\\b', stopwords_regex, '\\b')
merged_pros = stringr::str_replace_all(merged_pros, stopwords_regex, '')
#Rearrange words into a table format
merged_pros <- as_tibble(merged_pros) #useful?
count1 <- merged_pros %>% count(value, sort = TRUE)

##Drop rows with (perceived) non-pertinent verbage:
refined <- subset(count1, n>=4, select=c(value, n))

#replace ALL non-word, non-descriptive entries as "" and then NA
refined$value <- as.character(refined$value)
refined$value[refined$value == "great"] <- ""
refined$value[refined$value == "good"] <- ""
refined$value[refined$value == "t"] <- ""
refined$value[refined$value == "s"] <- ""
refined$value[refined$value == "can"] <- ""
refined$value[refined$value == "lot"] <- ""
refined$value[refined$value == "amazing"] <- ""
refined$value[refined$value == "ll"] <- ""
refined$value[refined$value == "everyone"] <- ""
refined$value[refined$value == "everything"] <- ""
refined$value[refined$value == "get"] <- ""
refined$value[refined$value == "like"] <- ""
refined$value[refined$value == "palantir"] <- ""
refined$value[refined$value == "square"] <- ""
refined$value[refined$value == "apple"] <- ""
refined$value[refined$value == "ve"] <- ""
refined$value[refined$value == "truly"] <- ""
refined$value[refined$value == "best"] <- ""
refined$value[refined$value == ""] <- NA

#Remove NA entries
refined<-subset(refined, (!is.na(refined[,1])) & (!is.na(refined[,2])))

#output as kable table
refined %>%
  kbl() %>%
  kable_minimal()
value n
work 25
benefits 20
company 20
people 15
culture 12
employees 9
time 9
microsoft 8
opportunities 8
pay 8
life 7
stock 7
compensation 6
development 6
large 6
many 6
outside 6
software 6
career 5
competitive 5
day 5
different 5
employee 5
etc 5
go 5
growth 5
management 5
nice 5
options 5
product 5
working 5
years 5
companies 4
don 4
innovative 4
leadership 4
means 4
much 4
new 4
one 4
opportunity 4
place 4
plan 4
remote 4
smart 4
something 4
team 4
tech 4
use 4
well 4
worked 4
world 4


Statistical Analysis & Visualization


—Visualize most frequent, pertinent verbage via table, barplot, and wordcloud.

#visualize the frequency count
ggplot(refined) +
  geom_bar(aes(reorder(value,n) , y = n, fill=value), stat = "identity", position = "dodge", width = 1) + coord_flip() +
  theme(legend.position = "none") +
  labs( title = "Word Count Frequency", x = "", y = "", fill = "Source")


#word cloud
wordcloud2(data=refined, color = "random-light", backgroundColor = "grey")


write.csv(refined, "/Users/linda/Desktop/refined.csv")


Tableau Public


Hit —open in browser— for full view of the dashboard

Conclusion



Top companies: Apple, Microsoft, Palantir and Square.

—-Terms like “work”, “company”,“opportunities” indicate that these companies offer meaningful work, growth. Employees feel like they’re building toward something greater than themselves.

—-Terms like “people”,”culture“, and”employees” indicate these companies have inclusive culture and that employees of these companies feel a sense of belonging. They feel like they’re a part of something and like their opinion matters.

—Terms like “benefits”, “pay”, and “time” indicate that these companies take care of their employees (not just in word but in deed).

Differentiating characteristics: meaningful work, sense of belonging, employer care for employees


Business Application:

Employer

These findings would help employers can tune their mission, culture, and compensation packages to attract higher and higher level employees while employees now have an idea of “what’s out there?”.

JobSeekers

For those uncertain as to what direction to head or what their specialty might be, why not choose a great place to work? That way, at least they have a better chance in enjoying their day-to-day as they gain clarity and experience.

Word spreads, and a long term focus on the right characteristics could pay off handsomely whether for employer or employee.

Reference


  1. Tomas Mantero. Top Tech Companies Stock Price retreived and stored as csv in github https://www.kaggle.com/tomasmantero/top-tech-companies-stock-price?select=Technology+Sector+List.csv\

  2. Glassdoor. Glassdoor webscraped Company Reviews https://www.glassdoor.com/member/home/companies.htm\

LS0tCnRpdGxlOiAiRGF0YSA2MDcgXApGaW5hbCBQcm9qZWN0IgphdXRob3I6ICJ5aW5hIHFpYW8iCmRhdGU6ICIyMDIzLTA0LTI2IgpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydAotLS0KXAoKCgojIEludHJvZHVjdGlvblwKXAoKCgojIyMgUmVzZWFyY2ggUXVlc3Rpb246XApcCgoKCioqV2hhdCBhcmUgdGhlIFRvcCBUZWNoIGNvbXBhbmllcyB0byB3b3JrIGZvcj8gV2hhdCBhcmUgdGhlIGNoYXJhY3RlcmlzdGljcyB0aGF0IG1ha2UgdGhlbSBzbz8gKioKCgoKCiMjIyBPdmVydmlldzpcClwKXAoKCk5lZWRsZXNzIHRvIHNheSwgaXQncyBiZWVuIGEgdHVyYnVsZW50IGZldyB5ZWFycy4gQ29tcGFuaWVzIGhhdmUgZWl0aGVyIHJpc2VuIHRvIHRoZSB0b3Agb3IgZmFsbGVuIG9mZiB0aGFua3MgdG8gY29tcGV0aW5nIHByZXNzdXJlcyBmcm9tIGFsbCBzaWRlcy4gIE92ZXIgdGhlIGNvdXJzZSBvZiB0aGlzIGNsYXNzLCB3ZSBkaXNjdXNzZWQgYSBudW1iZXIgb2YgY29tcGFuaWVzLCBJIGFtIGN1cmlvdXMgdG8gZXhwbG9yZSB3aGF0IGFyZSB0aGUgVG9wIFRlY2ggQ29tcGFuaWVzIGFuZCBpdHMgY2hhcmFjdGVyaXN0aWNzLiBJIHRoaW5rIGl0IG1pZ2h0IGJlIHZlcnkgaW50ZXJlc3RpbmcgdG8gZG8gb3VyIHJlc2VhcmNoLCBzbyB3ZSBjYW4gdWx0aW1hdGVseSBsYW5kIG91ciBkcmVhbSBqb2IuCgoKCiMjIyBNb3RpdmF0aW9uOlwKXAoKCkNvbWluZyBmcm9tIGEgZmluYW5jZSBiYWNrZ3JvdW5kLCBhcyBhIGNhcmVlciBjaGFuZ2VyLCByZXNlYXJjaGluZyBjb21wYW5pZXMgd291bGQgYmUgaGVscGZ1bCB0byBoZWxwIHVzIGFsaWduIHdpdGggZ3JlYXQgZW1wbG95ZXJzLiBBbHNvLCBJIHJlYWxseSBlbmpveSB0aGUgZGF0YSBjbGVhbmluZyBwYXJ0LCBkcmlsbGluZyBpbnRvIGEgbG90IG9mIGluZm9ybWF0aW9uIGFuZCBoYXZpbmcgdGhhdCDigJxhaC1oYeKAnSBtb21lbnQgd2hlbiBJIGNhbiBjYXJ2ZSBvdXQgdXNlZnVsIGluc2lnaHRzLiBJIGxvdmUgY3JlYXRpbmcgYSBmYWJ1bG91cyBkYXNoYm9hcmQgc28gSSB3aWxsIGJlIGNyZWF0aW5nIGFuZCBlbWJlZGRpbmcgdGhlIFRhYmxlYXUgRGFzaGJvYXJkIHRvIHNob3djYXNlIHRoZSBmaW5kaW5nLgoKCgoKIyBMaWJyYXJ5XAoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHJ2ZXN0KQpsaWJyYXJ5KHN0b3B3b3JkcykKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHdvcmRjbG91ZDIpCmBgYAoKIyBMb2FkIERhdGEKClwKCiMjIERhdGEgU291cmNlXApcCgpcCgoqKjEuIGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vdG9tYXNtYW50ZXJvL3RvcC10ZWNoLWNvbXBhbmllcy1zdG9jay1wcmljZT9zZWxlY3Q9VGVjaG5vbG9neStTZWN0b3IrTGlzdC5jc3YqKgoKKioyLiBodHRwczovL3d3dy5nbGFzc2Rvb3IuY29tL21lbWJlci9ob21lL2NvbXBhbmllcy5odG0qKgoKCgojIyBBcHByb2FjaFwKXAoKSW4gYW5zd2VyaW5nIHRoZSBxdWVzdGlvbiBhYm92ZSwgdGhlIGZvbGxvd2luZyBzdGVwcyB3YXMgZm9sbG93ZWQ6CgotLS1BY3F1aXJlIHRlY2ggc3RvY2sgZGF0YS4KCi0tLUZpbHRlciBmb3IgaGlnaGVzdCB2YWx1ZSAoZ3Jvd3RoIG9yIG1hcmtldCBjYXApIGNvbXBhbmllcy4KCi0tLVZlcmlmeSBjb3JyZXNwb25kaW5nIGNvbXBhbnkgcmV2aWV3IG9uIEdsYXNzZG9vciAoaWYgPCAzLjUsIGRyb3ApLgoKLS0tRm9yIGVhY2ggY29tcGFueSwgc2NyYXBlIHRoZSDigJxQcm9z4oCdIHNlY3Rpb24gb2YgdGhlIHRvcCAxMCByZXZpZXdzLgoKLS0tVGlkeSBhbmQgdHJhbnNmb3JtIG91ciBjb2xsZWN0aW9uIG9mIHJldmlld3MuCgotLS1WaXN1YWxpemUgbW9zdCBmcmVxdWVudCwgcGVydGluZW50IHZlcmJhZ2UgdmlhIHRhYmxlLCBiYXJwbG90LCBhbmQgd29yZGNsb3VkLgoKLS0tQW5hbHl6ZSBhbmQgZXhwb3J0IGRhdGEgdG8gVGFibGVhdQoKLS0tQ3JlYXRlIGEgRGFzaGJvYXJkIGluIFRhYmxlYXUgUHVibGljIGFuZCBlbWJlZCB0aGUgRGFzaGJvYXJkIGludG8gUiBtYXJrZG93bgoKLS0tQ29uY2x1ZGUKCgojIyBEYXRhIFNvdWNlIDFcClwKXAoKCgoKLS0tLVdlIHB1bGxlZCBpbiAoMikgZGlmZmVyZW50IGNzdiBmaWxlczogYSBsaXN0IG9mIHRoZSBUb3AgMTAwIHRlY2ggY29tcGFuaWVzIGFuZCB0aGVpciBjb3JyZXNwb25kaW5nIG1hcmtldCBtZXRyaWNzIGFzIHdlbGwgYXMgYSBsaXN0IG9mIFMmUCA1MDAgY29tcGFuaWVzIChhbmQgY29ycmVzcG9uZGluZyBzZWN0b3IpXApcClwKCgoKCi0tLS1Gcm9tIHRoZSBleHBsb3JhdGlvbiwgaXQgc2VlbXMgdGhhdCBzcF90YWJsZSBkYXRhc2V04oCZcyBvbmx5IGludGVyZXN0aW5nIGFkZGl0aW9uIHdvdWxkIGhhdmUgYmVlbiBpdHMg4oCcU2VjdG9y4oCdIHZhcmlhYmxlLCBJIGRlY2lkZSB0byBzaGlmdCBmcm9tIG1lcmdpbmcgdGhlIDIgdGFibGVzLCAgaW5zdGVhZCwganVzdCBleHBsb3JlIHRoZSB0ZWNoX3RhYmxlIGRhdGFzZXQgYW5kIG1hbnVhbGx5IGFkZCBzZWN0b3IgdmFyaWFibGUuXApcClwKCgoKCmBgYHtyfQojUmVhZCBpbiBjc3YgZmlsZXMKdGVjaF9kYXRhIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20veWluYVMxMjM0L2RhdGEtNjA3L21haW4vcHJvamVjdCUyMGZpbmFsL3RlY2hfc2VjdG9yX2xpc3QuY3N2IikKCnRlY2hfdGFibGUgPC0gYXNfdGliYmxlKHRlY2hfZGF0YSkKI2hlYWQodGVjaF90YWJsZSkKCnNwX2RhdGEgPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS95aW5hUzEyMzQvZGF0YS02MDcvbWFpbi9wcm9qZWN0JTIwZmluYWwvc3A1MDBfbGlzdC5jc3YiKQpgYGAKCgpgYGB7cn0KCnNwX3RhYmxlIDwtIGFzX3RpYmJsZShzcF9kYXRhKQoKI0VEQSBvZiB0YWJsZSAtLT4gc2l6ZSwgc2VjdG9yIC0tPiBkYXRhZnJhbWUgb2YgY29tcGFuaWVzCm5jb2wodGVjaF90YWJsZSkKCm5yb3codGVjaF90YWJsZSkKCnN1bW1hcnkodGVjaF90YWJsZSkKCiNmaWx0ZXIgMTogIiUgQ2hhbmdlIgpoaWdoX2dyb3d0aCA8LSBmaWx0ZXIodGVjaF90YWJsZSwgYCUgQ2hhbmdlYCA+IDAuMDYpICN0b3AgMwoKI2ZpbHRlciAyOiAiTWFya2V0IENhcCIKaGlnaF92YWwgPC0gZmlsdGVyKHRlY2hfdGFibGUsIGBNYXJrZXQgQ2FwIChCaWxsaW9ucylgID4gMTAwMCkgI3RvcCAyCgojTWVyZ2UgZGF0YSBmcmFtZXMKZmlsdGVyZWQgPC0gcmJpbmQoaGlnaF9ncm93dGgsIGhpZ2hfdmFsKQoKI0FkZCAiU2VjdG9yIiBjb2x1bW4gLSBtYW51YWxseSBrZXllZCBpbgpmaWx0ZXJlZCRTZWN0b3IgPC0gYygiRmluYW5jaWFsIFNlcnZpY2VzIiwgIkJpZyBEYXRhIiwgIlNlbWljb25kdWN0b3IiLCAiQmlnIFRlY2giLCAiQmlnIFRlY2giKQpmaWx0ZXJlZAoKYGBgCgpgYGB7cn0Kd3JpdGUuY3N2KHRlY2hfdGFibGUsICIvVXNlcnMvbGluZGEvRGVza3RvcC90ZWNodGFibGUuY3N2IikKd3JpdGUuY3N2KGZpbHRlcmVkLCAiL1VzZXJzL2xpbmRhL0Rlc2t0b3AvZmlsdGVyZWRzdG9jay5jc3YiKQpgYGAKClwKXAoKCkZyb20gb3VyIFRvcCAxMDAgVGVjaCBDb21wYW5pZXMgbGlzdCx3ZSAgbmFycm93IGRvd24gdG8gNTpcClwKCgoKCi0tLS0tU3F1YXJlLCBQYWxhbnRpciwgYW5kIFVuaXRlZCBNaWNyb2VsZWN0cm9uaWNzIHdlcmUgZmlsdGVyZWQgaW4gYXMgdGhlIHRvcCAzIGhpZ2hlc3QgZ3Jvd3RoIGNvbXBhbmllcwpcClwKCgoKLS0tLS1BcHBsZSBhbmQgTWljcm9zb2Z0IHdlcmUgIEJZIEZBUiB0aGUgaGlnaGVzdCB2YWx1ZSBjb21wYW5pZXMgaW4gb3VyIGxpc3QgKHdpdGggYSBNYXJrZXQgQ2FwIGdyZWF0ZXIgdGhhbiAkMSB0cmlsbGlvbikKXApcCgoKCgojIyBEYXRhIFNvdXJjZSAyXAoKCgoKLS0tVmVyaWZ5IGNvcnJlc3BvbmRpbmcgY29tcGFueSByZXZpZXcgb24gR2xhc3Nkb29yIChpZiA8IDMuNSwgZHJvcCkuXApcCgpEcm9wIFVuaXRlZCBNaWNyb2VsZWN0cm9uaWNzICh3aXRoIGEgcmF0aW5nIG9mIDIuNSkgYW5kIHByb2NlZWQgd2l0aCBqdXN0IGZvdXIgY29tcGFuaWVzIGJlbG93LiAKCi0tLS1XZWItc2NyYXBlIHJldmlld3MuXAoKCgpgYGB7cn0KIyNBUFBMRSMjCgojMS4gRG93bmxvYWQgSFRNTCBhbmQgY29udmVydCB0byBYTUwgd2l0aCByZWFkX2h0bWwoKQphIDwtIHJlYWRfaHRtbCgiaHR0cHM6Ly93d3cuZ2xhc3Nkb29yLmNvbS9SZXZpZXdzL0FwcGxlLVJldmlld3MtRTExMzguaHRtIikKIzIuIEV4dHJhY3Qgc3BlY2lmaWMgbm9kZXMgd2l0aCBodG1sX25vZGVzKCkKYV9leHQgPC0gaHRtbF9ub2RlcyhhLCcudjJfX0VJUmV2aWV3RGV0YWlsc1YyX19mdWxsV2lkdGg6bnRoLWNoaWxkKDEpIHNwYW4nKQojMy4gRXh0cmFjdCByZXZpZXcgdGV4dCBmcm9tIEhUTUwKYV9wcm9zIDwtIGh0bWxfdGV4dChhX2V4dCkgI2NvbGxlY3QgcHJvcyBzZWN0aW9uIG9mIDFzdCAxMCByZXZpZXdzCgojI01JQ1JPU09GVCMjCgptIDwtIHJlYWRfaHRtbCgiaHR0cHM6Ly93d3cuZ2xhc3Nkb29yLmNvbS9SZXZpZXdzL01pY3Jvc29mdC1SZXZpZXdzLUUxNjUxLmh0bSIpCm1fZXh0IDwtIGh0bWxfbm9kZXMobSwnLnYyX19FSVJldmlld0RldGFpbHNWMl9fZnVsbFdpZHRoOm50aC1jaGlsZCgxKSBzcGFuJykKbV9wcm9zIDwtIGh0bWxfdGV4dChtX2V4dCkgI2NvbGxlY3QgcHJvcyBzZWN0aW9uIG9mIDFzdCAxMCByZXZpZXdzCgojI1BBTEFOVElSIyMKCnAgPC0gcmVhZF9odG1sKCJodHRwczovL3d3dy5nbGFzc2Rvb3IuY29tL1Jldmlld3MvUGFsYW50aXItVGVjaG5vbG9naWVzLVJldmlld3MtRTIzNjM3NS5odG0iKQpwX2V4dCA8LSBodG1sX25vZGVzKHAsJy52Ml9fRUlSZXZpZXdEZXRhaWxzVjJfX2Z1bGxXaWR0aDpudGgtY2hpbGQoMSkgc3BhbicpCnBfcHJvcyA8LSBodG1sX3RleHQocF9leHQpICNjb2xsZWN0IHByb3Mgc2VjdGlvbiBvZiAxc3QgMTAgcmV2aWV3cwoKIyNTUVVBUkUjIwoKcyA8LSByZWFkX2h0bWwoImh0dHBzOi8vd3d3LmdsYXNzZG9vci5jb20vUmV2aWV3cy9TcXVhcmUtUmV2aWV3cy1FNDIyMDUwLmh0bSIpCnNfZXh0IDwtIGh0bWxfbm9kZXMocywnLnYyX19FSVJldmlld0RldGFpbHNWMl9fZnVsbFdpZHRoOm50aC1jaGlsZCgxKSBzcGFuJykKc19wcm9zIDwtIGh0bWxfdGV4dChzX2V4dCkgI2NvbGxlY3QgcHJvcyBzZWN0aW9uIG9mIDFzdCAxMCByZXZpZXdzCmBgYAoKCgojIERhdGEgVHJhbnNmb3JtYXRpb24KCgoKLS0tKipUaWR5IGFuZCB0cmFuc2Zvcm0gb3VyIGNvbGxlY3Rpb24gb2YgcmV2aWV3cyoqLlwKXAoKLS0tLS1tZXJnZSB0byBjcmVhdGUgb25lIGRhdGFmcmFtZVwKXAotLS0tLWhhbmRsZSBzcGVjaWFsIGNoYXJhY3RlclwKXAotLS0tLXJlbW92ZSB3aGl0ZSBzcGFjZXNcClwKLS0tLS1jaGFuZ2UgdG8gbG93ZXIgY2FzZXNcClwKLS0tLS1yZW1vdmUgc3RvcHdvcmRzLiBub24tZGVzY3JpcHRpdmUgd29yZHNcClwKLS0tLS1yZW1vdmUgTkFzXApcCi0tLS0tb3V0cHV0IHRvIGEgdGFibGVcClwKCgpgYGB7cn0KI21lcmdlIGRhdGEgZnJhbWVzCm1lcmdlZF9wcm9zIDwtIHJiaW5kKGFfcHJvcywgbV9wcm9zLCBwX3Byb3MsIHNfcHJvcykKCiNUaWR5IHRleHQgdmlhIHJlZ3VsYXIgZXhwcmVzc2lvbnMKCiNIYW5kbGUgc3BlY2lhbCBjaGFyYWN0ZXJzIGFuZCBkaWdpdHMKbWVyZ2VkX3Byb3MgPC0gc3RyX3JlcGxhY2VfYWxsKG1lcmdlZF9wcm9zLCAiW15bOmFsbnVtOl1dIiwgIiAiKSAjcmVtb3ZlIG5vbi1hbHBoYSBudW1lcmljIGNoYXJhY3RlcnMKbWVyZ2VkX3Byb3MgPC0gc3RyX3JlcGxhY2VfYWxsKG1lcmdlZF9wcm9zLCAiWyFeWzpkaWdpdDpdXSIsICIiKSAjcmVtb3ZlIGRpZ2l0cwoKI0hhbmRsZSB3aGl0ZSBzcGFjZQptZXJnZWRfcHJvcyA8LSB0cmltd3MobWVyZ2VkX3Byb3MpCm1lcmdlZF9wcm9zIDwtIHN0cl9yZXBsYWNlX2FsbChtZXJnZWRfcHJvcywgIlxccysiLCAiICIpICNjb21wcmVzcyB3aGl0ZXNwYWNlCm1lcmdlZF9wcm9zIDwtIHN0cl9yZXBsYWNlX2FsbChtZXJnZWRfcHJvcywgIicgJyIsICInLCciKSAjJyAnICcgLS0+ICcsJwoKI1JlbW92ZSBleGNlc3MgY2hhcmFjdGVycyBhbmQgcHJvcGVybHkgc3BsaXQgYW5kIHRoZW4gcmUtbWVyZ2UgdGhlIHZlY3RvcgptZXJnZWRfcHJvcyA8LSBzdHJfc3BsaXQobWVyZ2VkX3Byb3MsIHBhdHRlcm49IiAiKSAjY29udmVydCB2ZWN0b3IgdG8gbGlzdCBhdCBlYWNoICwKbWVyZ2VkX3Byb3MgPC0gdW5saXN0KG1lcmdlZF9wcm9zKSAjY29udmVydCBsaXN0IGJhY2sgdG8gdmVjdG9yCm1lcmdlZF9wcm9zIDwtIHRvbG93ZXIobWVyZ2VkX3Byb3MpICNjb252ZXJ0IGxpc3QgdG8gbG93ZXJjYXNlCgpzdG9wd29yZHNfcmVnZXggPSBwYXN0ZShzdG9wd29yZHMoJ2VuJyksIGNvbGxhcHNlID0gJ1xcYnxcXGInKQpzdG9wd29yZHNfcmVnZXggPSBwYXN0ZTAoJ1xcYicsIHN0b3B3b3Jkc19yZWdleCwgJ1xcYicpCm1lcmdlZF9wcm9zID0gc3RyaW5ncjo6c3RyX3JlcGxhY2VfYWxsKG1lcmdlZF9wcm9zLCBzdG9wd29yZHNfcmVnZXgsICcnKQoKYGBgCgoKYGBge3J9CgojUmVhcnJhbmdlIHdvcmRzIGludG8gYSB0YWJsZSBmb3JtYXQKbWVyZ2VkX3Byb3MgPC0gYXNfdGliYmxlKG1lcmdlZF9wcm9zKSAjdXNlZnVsPwpjb3VudDEgPC0gbWVyZ2VkX3Byb3MgJT4lIGNvdW50KHZhbHVlLCBzb3J0ID0gVFJVRSkKCiMjRHJvcCByb3dzIHdpdGggKHBlcmNlaXZlZCkgbm9uLXBlcnRpbmVudCB2ZXJiYWdlOgpyZWZpbmVkIDwtIHN1YnNldChjb3VudDEsIG4+PTQsIHNlbGVjdD1jKHZhbHVlLCBuKSkKCiNyZXBsYWNlIEFMTCBub24td29yZCwgbm9uLWRlc2NyaXB0aXZlIGVudHJpZXMgYXMgIiIgYW5kIHRoZW4gTkEKcmVmaW5lZCR2YWx1ZSA8LSBhcy5jaGFyYWN0ZXIocmVmaW5lZCR2YWx1ZSkKcmVmaW5lZCR2YWx1ZVtyZWZpbmVkJHZhbHVlID09ICJncmVhdCJdIDwtICIiCnJlZmluZWQkdmFsdWVbcmVmaW5lZCR2YWx1ZSA9PSAiZ29vZCJdIDwtICIiCnJlZmluZWQkdmFsdWVbcmVmaW5lZCR2YWx1ZSA9PSAidCJdIDwtICIiCnJlZmluZWQkdmFsdWVbcmVmaW5lZCR2YWx1ZSA9PSAicyJdIDwtICIiCnJlZmluZWQkdmFsdWVbcmVmaW5lZCR2YWx1ZSA9PSAiY2FuIl0gPC0gIiIKcmVmaW5lZCR2YWx1ZVtyZWZpbmVkJHZhbHVlID09ICJsb3QiXSA8LSAiIgpyZWZpbmVkJHZhbHVlW3JlZmluZWQkdmFsdWUgPT0gImFtYXppbmciXSA8LSAiIgpyZWZpbmVkJHZhbHVlW3JlZmluZWQkdmFsdWUgPT0gImxsIl0gPC0gIiIKcmVmaW5lZCR2YWx1ZVtyZWZpbmVkJHZhbHVlID09ICJldmVyeW9uZSJdIDwtICIiCnJlZmluZWQkdmFsdWVbcmVmaW5lZCR2YWx1ZSA9PSAiZXZlcnl0aGluZyJdIDwtICIiCnJlZmluZWQkdmFsdWVbcmVmaW5lZCR2YWx1ZSA9PSAiZ2V0Il0gPC0gIiIKcmVmaW5lZCR2YWx1ZVtyZWZpbmVkJHZhbHVlID09ICJsaWtlIl0gPC0gIiIKcmVmaW5lZCR2YWx1ZVtyZWZpbmVkJHZhbHVlID09ICJwYWxhbnRpciJdIDwtICIiCnJlZmluZWQkdmFsdWVbcmVmaW5lZCR2YWx1ZSA9PSAic3F1YXJlIl0gPC0gIiIKcmVmaW5lZCR2YWx1ZVtyZWZpbmVkJHZhbHVlID09ICJhcHBsZSJdIDwtICIiCnJlZmluZWQkdmFsdWVbcmVmaW5lZCR2YWx1ZSA9PSAidmUiXSA8LSAiIgpyZWZpbmVkJHZhbHVlW3JlZmluZWQkdmFsdWUgPT0gInRydWx5Il0gPC0gIiIKcmVmaW5lZCR2YWx1ZVtyZWZpbmVkJHZhbHVlID09ICJiZXN0Il0gPC0gIiIKcmVmaW5lZCR2YWx1ZVtyZWZpbmVkJHZhbHVlID09ICIiXSA8LSBOQQoKI1JlbW92ZSBOQSBlbnRyaWVzCnJlZmluZWQ8LXN1YnNldChyZWZpbmVkLCAoIWlzLm5hKHJlZmluZWRbLDFdKSkgJiAoIWlzLm5hKHJlZmluZWRbLDJdKSkpCgojb3V0cHV0IGFzIGthYmxlIHRhYmxlCnJlZmluZWQgJT4lCiAga2JsKCkgJT4lCiAga2FibGVfbWluaW1hbCgpCmBgYApcCgoKIyBTdGF0aXN0aWNhbCBBbmFseXNpcyAmIFZpc3VhbGl6YXRpb25cClwKCgotLS1WaXN1YWxpemUgbW9zdCBmcmVxdWVudCwgcGVydGluZW50IHZlcmJhZ2UgdmlhIHRhYmxlLCBiYXJwbG90LCBhbmQgd29yZGNsb3VkLlwKXAoKYGBge3J9CiN2aXN1YWxpemUgdGhlIGZyZXF1ZW5jeSBjb3VudApnZ3Bsb3QocmVmaW5lZCkgKwogIGdlb21fYmFyKGFlcyhyZW9yZGVyKHZhbHVlLG4pICwgeSA9IG4sIGZpbGw9dmFsdWUpLCBzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCB3aWR0aCA9IDEpICsgY29vcmRfZmxpcCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBsYWJzKCB0aXRsZSA9ICJXb3JkIENvdW50IEZyZXF1ZW5jeSIsIHggPSAiIiwgeSA9ICIiLCBmaWxsID0gIlNvdXJjZSIpCmBgYApcCgpgYGB7cn0KI3dvcmQgY2xvdWQKd29yZGNsb3VkMihkYXRhPXJlZmluZWQsIGNvbG9yID0gInJhbmRvbS1saWdodCIsIGJhY2tncm91bmRDb2xvciA9ICJncmV5IikKCmBgYApcCgpgYGB7cn0Kd3JpdGUuY3N2KHJlZmluZWQsICIvVXNlcnMvbGluZGEvRGVza3RvcC9yZWZpbmVkLmNzdiIpCmBgYApcCgojIFRhYmxlYXUgUHVibGljXApcCgoqKkhpdCAtLS1vcGVuIGluIGJyb3dzZXItLS0gZm9yIGZ1bGwgdmlldyBvZiB0aGUgZGFzaGJvYXJkKioKCgoKCjxkaXYgY2xhc3M9J3RhYmxlYXVQbGFjZWhvbGRlcicgaWQ9J3ZpejE2ODMyNDg3OTU5OTQnIHN0eWxlPSdwb3NpdGlvbjogcmVsYXRpdmUnPjxub3NjcmlwdD48YSBocmVmPScjJz48aW1nIGFsdD0nRGFzaGJvYXJkIDMgJyBzcmM9J2h0dHBzOiYjNDc7JiM0NztwdWJsaWMudGFibGVhdS5jb20mIzQ3O3N0YXRpYyYjNDc7aW1hZ2VzJiM0NztEYSYjNDc7RGFzaGJvYXJkMDUwNCYjNDc7RGFzaGJvYXJkMyYjNDc7MV9yc3MucG5nJyBzdHlsZT0nYm9yZGVyOiBub25lJyAvPjwvYT48L25vc2NyaXB0PjxvYmplY3QgY2xhc3M9J3RhYmxlYXVWaXonICBzdHlsZT0nZGlzcGxheTpub25lOyc+PHBhcmFtIG5hbWU9J2hvc3RfdXJsJyB2YWx1ZT0naHR0cHMlM0ElMkYlMkZwdWJsaWMudGFibGVhdS5jb20lMkYnIC8+IDxwYXJhbSBuYW1lPSdlbWJlZF9jb2RlX3ZlcnNpb24nIHZhbHVlPSczJyAvPiA8cGFyYW0gbmFtZT0nc2l0ZV9yb290JyB2YWx1ZT0nJyAvPjxwYXJhbSBuYW1lPSduYW1lJyB2YWx1ZT0nRGFzaGJvYXJkMDUwNCYjNDc7RGFzaGJvYXJkMycgLz48cGFyYW0gbmFtZT0ndGFicycgdmFsdWU9J25vJyAvPjxwYXJhbSBuYW1lPSd0b29sYmFyJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdzdGF0aWNfaW1hZ2UnIHZhbHVlPSdodHRwczomIzQ3OyYjNDc7cHVibGljLnRhYmxlYXUuY29tJiM0NztzdGF0aWMmIzQ3O2ltYWdlcyYjNDc7RGEmIzQ3O0Rhc2hib2FyZDA1MDQmIzQ3O0Rhc2hib2FyZDMmIzQ3OzEucG5nJyAvPiA8cGFyYW0gbmFtZT0nYW5pbWF0ZV90cmFuc2l0aW9uJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdkaXNwbGF5X3N0YXRpY19pbWFnZScgdmFsdWU9J3llcycgLz48cGFyYW0gbmFtZT0nZGlzcGxheV9zcGlubmVyJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdkaXNwbGF5X292ZXJsYXknIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2Rpc3BsYXlfY291bnQnIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2xhbmd1YWdlJyB2YWx1ZT0nZW4tVVMnIC8+PC9vYmplY3Q+PC9kaXY+ICAgICAgICAgICAgICAgIAoKYGBge2pzLCBlbWJlZGNvZGUsIGVjaG89RkFMU0V9Cgp2YXIgZGl2RWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2aXoxNjgzMjQ4Nzk1OTk0Jyk7ICAgICAgICAgICAgICAgICAgICB2YXIgdml6RWxlbWVudCA9IGRpdkVsZW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ29iamVjdCcpWzBdOyAgICAgICAgICAgICAgICAgICAgaWYgKCBkaXZFbGVtZW50Lm9mZnNldFdpZHRoID4gODAwICkgeyB2aXpFbGVtZW50LnN0eWxlLndpZHRoPScxMDAwcHgnO3ZpekVsZW1lbnQuc3R5bGUuaGVpZ2h0PSc4MjdweCc7fSBlbHNlIGlmICggZGl2RWxlbWVudC5vZmZzZXRXaWR0aCA+IDUwMCApIHsgdml6RWxlbWVudC5zdHlsZS53aWR0aD0nMTAwMHB4Jzt2aXpFbGVtZW50LnN0eWxlLmhlaWdodD0nODI3cHgnO30gZWxzZSB7IHZpekVsZW1lbnQuc3R5bGUud2lkdGg9JzEwMCUnO3ZpekVsZW1lbnQuc3R5bGUuaGVpZ2h0PScxMzI3cHgnO30gICAgICAgICAgICAgICAgICAgICB2YXIgc2NyaXB0RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpOyAgICAgICAgICAgICAgICAgICAgc2NyaXB0RWxlbWVudC5zcmMgPSAnaHR0cHM6Ly9wdWJsaWMudGFibGVhdS5jb20vamF2YXNjcmlwdHMvYXBpL3Zpel92MS5qcyc7ICAgICAgICAgICAgICAgICAgICB2aXpFbGVtZW50LnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKHNjcmlwdEVsZW1lbnQsIHZpekVsZW1lbnQpOwpgYGAKCgoKCiMgQ29uY2x1c2lvblwKXApcCgoqKlRvcCBjb21wYW5pZXMqKjogQXBwbGUsIE1pY3Jvc29mdCwgUGFsYW50aXIgYW5kIFNxdWFyZS5cClwKCi0tLS1UZXJtcyBsaWtlIOKAnHdvcmvigJ0sIOKAnGNvbXBhbnnigJ0sIm9wcG9ydHVuaXRpZXMiIGluZGljYXRlIHRoYXQgdGhlc2UgY29tcGFuaWVzIG9mZmVyIG1lYW5pbmdmdWwgd29yaywgZ3Jvd3RoLiBFbXBsb3llZXMgZmVlbCBsaWtlIHRoZXnigJlyZSBidWlsZGluZyB0b3dhcmQgc29tZXRoaW5nIGdyZWF0ZXIgdGhhbiB0aGVtc2VsdmVzLlwKXAoKCi0tLS1UZXJtcyBsaWtlIOKAnHBlb3BsZeKAnSzigJ1jdWx0dXJl4oCcLCBhbmTigJ1lbXBsb3llZXMiIGluZGljYXRlIHRoZXNlIGNvbXBhbmllcyBoYXZlIGluY2x1c2l2ZSBjdWx0dXJlIGFuZCB0aGF0IGVtcGxveWVlcyBvZiB0aGVzZSBjb21wYW5pZXMgZmVlbCBhIHNlbnNlIG9mIGJlbG9uZ2luZy4gVGhleSBmZWVsIGxpa2UgdGhleeKAmXJlIGEgcGFydCBvZiBzb21ldGhpbmcgYW5kIGxpa2UgdGhlaXIgb3BpbmlvbiBtYXR0ZXJzLlwKXAoKLS0tVGVybXMgbGlrZSDigJxiZW5lZml0c+KAnSwg4oCccGF54oCdLCBhbmQg4oCcdGltZeKAnSBpbmRpY2F0ZSB0aGF0IHRoZXNlIGNvbXBhbmllcyB0YWtlIGNhcmUgb2YgdGhlaXIgZW1wbG95ZWVzIChub3QganVzdCBpbiB3b3JkIGJ1dCBpbiBkZWVkKS5cClwKCgoqKkRpZmZlcmVudGlhdGluZyBjaGFyYWN0ZXJpc3RpY3MqKjogbWVhbmluZ2Z1bCB3b3JrLCBzZW5zZSBvZiBiZWxvbmdpbmcsIGVtcGxveWVyIGNhcmUgZm9yIGVtcGxveWVlc1wKClwKCgojIyMgQnVzaW5lc3MgQXBwbGljYXRpb246IAoqKkVtcGxveWVyKipcClwKVGhlc2UgZmluZGluZ3Mgd291bGQgaGVscCBlbXBsb3llcnMgY2FuIHR1bmUgdGhlaXIgbWlzc2lvbiwgY3VsdHVyZSwgYW5kIGNvbXBlbnNhdGlvbiBwYWNrYWdlcyB0byBhdHRyYWN0IGhpZ2hlciBhbmQgaGlnaGVyIGxldmVsIGVtcGxveWVlcyB3aGlsZSBlbXBsb3llZXMgbm93IGhhdmUgYW4gaWRlYSBvZiDigJx3aGF04oCZcyBvdXQgdGhlcmU/4oCdLgoKKipKb2JTZWVrZXJzKipcClwKCkZvciB0aG9zZSB1bmNlcnRhaW4gYXMgdG8gd2hhdCBkaXJlY3Rpb24gdG8gaGVhZCBvciB3aGF0IHRoZWlyIHNwZWNpYWx0eSBtaWdodCBiZSwgd2h5IG5vdCBjaG9vc2UgYSBncmVhdCBwbGFjZSB0byB3b3JrPyBUaGF0IHdheSwgYXQgbGVhc3QgdGhleSBoYXZlIGEgYmV0dGVyIGNoYW5jZSBpbiBlbmpveWluZyB0aGVpciBkYXktdG8tZGF5IGFzIHRoZXkgZ2FpbiBjbGFyaXR5IGFuZCBleHBlcmllbmNlLlwKXAoKCldvcmQgc3ByZWFkcywgYW5kIGEgbG9uZyB0ZXJtIGZvY3VzIG9uIHRoZSByaWdodCBjaGFyYWN0ZXJpc3RpY3MgY291bGQgcGF5IG9mZiBoYW5kc29tZWx5IHdoZXRoZXIgZm9yIGVtcGxveWVyIG9yIGVtcGxveWVlLgoKCgojIFJlZmVyZW5jZVwKXAoKCjEuIFRvbWFzIE1hbnRlcm8uIFRvcCBUZWNoIENvbXBhbmllcyBTdG9jayBQcmljZSByZXRyZWl2ZWQgYW5kIHN0b3JlZCBhcyBjc3YgaW4gZ2l0aHViCmh0dHBzOi8vd3d3LmthZ2dsZS5jb20vdG9tYXNtYW50ZXJvL3RvcC10ZWNoLWNvbXBhbmllcy1zdG9jay1wcmljZT9zZWxlY3Q9VGVjaG5vbG9neStTZWN0b3IrTGlzdC5jc3ZcClwKCgoKMi4gR2xhc3Nkb29yLiBHbGFzc2Rvb3Igd2Vic2NyYXBlZCBDb21wYW55IFJldmlld3MgaHR0cHM6Ly93d3cuZ2xhc3Nkb29yLmNvbS9tZW1iZXIvaG9tZS9jb21wYW5pZXMuaHRtXApcCgo=