Project Description:

In this project, I will work with datasets on movie ratings data of Fandango.com. Fandango is a media company that sells movie tickets online, as well as a provider of television and streaming media information, e.g., through its subsidiaries Flixster, Movies.com, and Rotten Tomatoes.

1. Background

In October 2015, a data journalist named Walt Hickey analyzed movie ratings data and found strong evidence to suggest that Fandango’s rating system was biased and dishonest. He published his analysis in the article - “Be Suspicious Of Online Movie Ratings, Especially Fandango’s” which can be found here: https://fivethirtyeight.com/features/fandango-movies-ratings/.

Fandango displays a 5-star rating system on their website, where the minimum rating is 0 stars and the maximum is 5 stars. Hickey found that there’s a significant discrepancy between the ratings displayed to users and the actual ratings which he was able to find on Fandango. The actual rating was almost always rounded up to the nearest half-star. For instance, a 4.1 movie would be rounded off to 4.5 stars, not to 4 stars.

Fandango’s officials responded that the biased rounding off was caused by a bug in their system rather than being intentional, and they promised to fix the bug as soon as possible. Presumably, this has already happened, although we can’t tell for sure since the actual rating value doesn’t seem to be displayed anymore.

2. Goal

The goal of this project is to analyze data of recent movie ratings on Fandango to find out if there has been any change in Fandango’s rating system after Hickey’s analysis.

3. Data Sources

Here are two sets of movie ratings data sampled:

library(readr)

fandango_before <- read_csv("fandango_score_comparison.csv")
fandango_after <- read_csv("movie_ratings_16_17.csv")
head(fandango_before)
There were 22 warnings (use warnings() to see them)
head(fandango_after)

I. Determining if the samples are representative of the population

If the goal here is to find out if there has been any change after Hickey’s analysis, then ideally we would want to sample all movie ratings at two different periods of time for comparison. Thus, the population of interest for this goal is: all the movie ratings on Fandango.com.

Good news is, the two samples we are working with were taken before and after Hickey’s analysis. However, we still need to make sure the samples are representative of the population of interest, in order to describe the population as precise as possible and minimize the sampling error.

library(dplyr)
# Cleaning dataframes to include only relevant data
fandango_before_cleaned <- fandango_before %>%
  select(FILM, Fandango_Stars, Fandango_Ratingvalue, Fandango_votes, Fandango_Difference)
fandango_after_cleaned <- fandango_after %>%
  select(movie, year, fandango)
head(fandango_before_cleaned)

According to Hickey’article, here are the sampling criteria for Sample #1 (ratings before Hickey’s analysis):

head(fandango_after_cleaned)

According to Dataquest’s GitHub repository, here are the sampling criteria for Sample #2 (ratings after Hickey’s analysis):

Conslusion

Both samples are not random because not all the movies have an equal probability to be selected. The sampling method applied here is purposive sampling, where samples are produced under pre-defined and subjective conditions. Therefore, these two samples are not representative of the population (all movie ratings on Fandango) we want to describe.


II. Adjusting the goal of the analysis and re-examining sample representativeness

Using non-representative samples to describe a population could lead to a wrong conclusion. Moving forward, I am going to slighly adjust the goal of this project to a new goal that is still a fairly good proxy for the initial goal, so that the population of interest changes and the samples we are working with become representative.

We could also collect new data and obtain representative samples here. However, time has passed since Hickey’s analysis and it would be difficult or even impossible to access precise data prior to Hickey’s analysis at this time.


Adjusted Goal

Instead of trying to find out if there has been any change in Fandango’s rating system after Hickey’s analysis, we will try to determine if there is any difference between Fandango’s ratings for popular movies in 2015 and in 2016. If yes, then it could be an indication that Fandango has made changes.

Adjusted Populations of Interest

I will use Hickey’s benchmark of 30 ratings to define “popular” which is reasonable. That being said, a movie is considered “popular” in this case if it has at least 30 ratings.

Sample #1 now becomes representative, since it was randomly selected under the condition of having at lease 30 ratings.

However for Sample #2, it is unclear how the researcher defined “popular”. So it is imperative to check if the movies selected have at lease 30 ratings.


Based on the dataframe of Sample #2 above, there is no such a variable that shows a movie’s rating counts. Moreover, I wasn’t able to find the rating counts on Fandango pages of the movies, because Fandango has replaced the 5-Star Fan Ratings with the Rotten Tomatoes Audience Score in 2019 so now the rating counts are shown on Rottentomatoes.com.

Therefore, I am going to sample 10 observations from Sample #2 and find their rating counts from Rottentomatoes.com.

set.seed(1)
after_sample <- sample_n(fandango_after_cleaned, size = 10)

# Found rating counts of these 10 samples
sample_rating_counts <- tibble(reviews = c(7384, 7259, 7265, 12212, 30271, 281, 13684, 1212, 56851, 9222))

bind_cols(after_sample, sample_rating_counts)

All 10 movies randomly sampled received more than 30 ratings. It is safe to say that movies in Sample #2 are “popular”. Let’s move on.


III. Reshaping dataframes and extracting relevant data

Since now we are only interested in popular movies released in 2015 and 2016, I am going to extract only the relevant data for the following analysis.

library(stringr)
film_name_year <- str_split(fandango_before_cleaned$FILM, "\\(", simplify = TRUE)

fandango_2015 <- fandango_before_cleaned %>%
  mutate(FILM = film_name_year[,1], year = film_name_year[,2]) %>%
  mutate(year = str_sub(year, 1, 4)) %>%
  filter(year == "2015")

head(fandango_2015)
fandango_2016 <- fandango_after_cleaned %>%
  filter(year == "2016")

head(fandango_2016)

IV. Visualizing the frequency distributions to get an overview

First of all, I am going to use Kernel Density Plots to compare the distribution shapes of two samples in order to get a general overview.

library(ggplot2)

ggplot(data = fandango_2015,
       aes(x = Fandango_Stars)) +
       geom_density() +
       geom_density(data = fandango_2016, 
                    aes(x = fandango), color = "blue") +
       labs(title = "Comparing Distribution shapes for Fandango's ratings (2015 v.s. 2016)",
           x = "Ratings", y = "Density") +
       scale_x_continuous(breaks = seq(0, 5, by = 0.5), limits = c(0, 5))


V. Generating frequency distribution tables to further explore the distributions

Now I am going to generate frequency distribution tables for further details. Since these two samples have different counts of observations, I will use the relative frequency here instead of the absolute frequency, namely, percentages.

fandango_2015_freq <- fandango_2015 %>% 
  group_by(Fandango_Stars) %>% 
  summarize(Percentage = n() / nrow(fandango_2015) * 100)

print(fandango_2015_freq)

fandango_2016_freq <- fandango_2016 %>% 
  group_by(fandango) %>% 
  summarize(Percentage = n() / nrow(fandango_2016) * 100)

print(fandango_2016_freq)

It is clearly shown that there are significantly lower percentages of ratings between 4.5 - 5.0 stars and higher percentages of ratings below 3.5 - 4.0 stars in 2016 than in 2015.

Now I am going to compare some key summary statistics between two samples to get a more precise picture of the direction of the difference.

library(tidyr)
mode <- function(x) {
        ux <- unique(x)
        ux[which.max(tabulate(match(x, ux)))]
}

freq_summary_2015 <- fandango_2015 %>% 
  summarize(year = "2015",
    mean = mean(Fandango_Stars),
    median = median(Fandango_Stars),
    mode = mode(Fandango_Stars))

freq_summary_2016 <- fandango_2016 %>% 
  summarize(year = "2016",
            mean = mean(fandango),
            median = median(fandango),
            mode = mode(fandango))

summary_stat <- bind_rows(freq_summary_2015, freq_summary_2016)

summary_stat2 <- summary_stat %>% 
  gather(key = "statistic", value = "value", - year)

print(summary_stat2)

ggplot(data = summary_stat2, 
       aes(x = statistic, y = value, fill = year)) +
       geom_bar(stat = "identity", position = "dodge") +
       labs(title = "Comparing Summary Statistics: 2015 v.s. 2016", x = "", y = "Rating Stars") + 
       scale_fill_brewer(palette = "Paired")

summary_stat2 %>%
  filter(statistic == "mean") %>%
  summarize(`Change of Mean` = (value[2] - value[1]) / value[1] *100)

summary_stat2 %>%
  filter(statistic == "mode") %>%
  summarize(`Chang of Mode` = (value[2] - value[1]) / value[1] *100)

All three statistics above point to a conclusion that there is a difference between Fandango’s ratings for popular movies in 2015 (before Hickey’s analysis) and in 2016 (after Hickey’s analysis), and that the movie ratings were lower in 2016 than in 2015.


Summary

I started this project with the goal of finding out if there has been any change in Fandango’s rating system after Hickey’s analysis. However as I was examining the sample representativeness, I discovered that the samples are not representative of the population of interest for the initial goal. Therefore, I adopted an adjusted goal which is a fairly good proxy for the initial goal: to determine if there is any difference between Fandango’s ratings for popular movies in 2015 and in 2016.

So far, the analysis has shown us that there is indeed a difference between Fandango’s ratings for popular movies in 2015 and in 2016, and that the ratings were lower in 2016 than in 2015 on average. On one hand, it could be because the movies released in 2015 were overall “better” than the movies of 2016. On the other hand, it could be because Fandango did make changes to its rating system (for example, fixed the rounding off system). The cause of the difference definitely deserves a further and deeper analysis.

LS0tCnRpdGxlOiAiSW52ZXN0aWdhdGluZyBGYW5kYW5nbyBNb3ZpZSBSYXRpbmdzIEFmdGVyIDIwMTUiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyBQcm9qZWN0IERlc2NyaXB0aW9uOgoKSW4gdGhpcyBwcm9qZWN0LCBJIHdpbGwgd29yayB3aXRoIGRhdGFzZXRzIG9uIG1vdmllIHJhdGluZ3MgZGF0YSBvZiBGYW5kYW5nby5jb20uIEZhbmRhbmdvIGlzIGEgbWVkaWEgY29tcGFueSB0aGF0IHNlbGxzIG1vdmllIHRpY2tldHMgb25saW5lLCBhcyB3ZWxsIGFzIGEgcHJvdmlkZXIgb2YgdGVsZXZpc2lvbiBhbmQgc3RyZWFtaW5nIG1lZGlhIGluZm9ybWF0aW9uLCBlLmcuLCB0aHJvdWdoIGl0cyBzdWJzaWRpYXJpZXMgRmxpeHN0ZXIsIE1vdmllcy5jb20sIGFuZCBSb3R0ZW4gVG9tYXRvZXMuCgoqKjEuIEJhY2tncm91bmQqKgoKSW4gT2N0b2JlciAyMDE1LCBhIGRhdGEgam91cm5hbGlzdCBuYW1lZCBXYWx0IEhpY2tleSBhbmFseXplZCBtb3ZpZSByYXRpbmdzIGRhdGEgYW5kIGZvdW5kIHN0cm9uZyBldmlkZW5jZSB0byBzdWdnZXN0IHRoYXQgRmFuZGFuZ28ncyByYXRpbmcgc3lzdGVtIHdhcyBiaWFzZWQgYW5kIGRpc2hvbmVzdC4gSGUgcHVibGlzaGVkIGhpcyBhbmFseXNpcyBpbiB0aGUgYXJ0aWNsZSAtICJCZSBTdXNwaWNpb3VzIE9mIE9ubGluZSBNb3ZpZSBSYXRpbmdzLCBFc3BlY2lhbGx5IEZhbmRhbmdv4oCZcyIgd2hpY2ggY2FuIGJlIGZvdW5kIGhlcmU6IGh0dHBzOi8vZml2ZXRoaXJ0eWVpZ2h0LmNvbS9mZWF0dXJlcy9mYW5kYW5nby1tb3ZpZXMtcmF0aW5ncy8uCgpGYW5kYW5nbyBkaXNwbGF5cyBhIDUtc3RhciByYXRpbmcgc3lzdGVtIG9uIHRoZWlyIHdlYnNpdGUsIHdoZXJlIHRoZSBtaW5pbXVtIHJhdGluZyBpcyAwIHN0YXJzIGFuZCB0aGUgbWF4aW11bSBpcyA1IHN0YXJzLiBIaWNrZXkgZm91bmQgdGhhdCB0aGVyZSdzIGEgc2lnbmlmaWNhbnQgZGlzY3JlcGFuY3kgYmV0d2VlbiB0aGUgcmF0aW5ncyBkaXNwbGF5ZWQgdG8gdXNlcnMgYW5kIHRoZSBhY3R1YWwgcmF0aW5ncyB3aGljaCBoZSB3YXMgYWJsZSB0byBmaW5kIG9uIEZhbmRhbmdvLiBUaGUgYWN0dWFsIHJhdGluZyB3YXMgYWxtb3N0IGFsd2F5cyByb3VuZGVkIHVwIHRvIHRoZSBuZWFyZXN0IGhhbGYtc3Rhci4gRm9yIGluc3RhbmNlLCBhIDQuMSBtb3ZpZSB3b3VsZCBiZSByb3VuZGVkIG9mZiB0byA0LjUgc3RhcnMsIG5vdCB0byA0IHN0YXJzLgoKRmFuZGFuZ28ncyBvZmZpY2lhbHMgcmVzcG9uZGVkIHRoYXQgdGhlIGJpYXNlZCByb3VuZGluZyBvZmYgd2FzIGNhdXNlZCBieSBhIGJ1ZyBpbiB0aGVpciBzeXN0ZW0gcmF0aGVyIHRoYW4gYmVpbmcgaW50ZW50aW9uYWwsIGFuZCB0aGV5IHByb21pc2VkIHRvIGZpeCB0aGUgYnVnIGFzIHNvb24gYXMgcG9zc2libGUuIFByZXN1bWFibHksIHRoaXMgaGFzIGFscmVhZHkgaGFwcGVuZWQsIGFsdGhvdWdoIHdlIGNhbid0IHRlbGwgZm9yIHN1cmUgc2luY2UgdGhlIGFjdHVhbCByYXRpbmcgdmFsdWUgZG9lc24ndCBzZWVtIHRvIGJlIGRpc3BsYXllZCBhbnltb3JlLgoKKioyLiBHb2FsKioKClRoZSBnb2FsIG9mIHRoaXMgcHJvamVjdCBpcyB0byBhbmFseXplIGRhdGEgb2YgcmVjZW50IG1vdmllIHJhdGluZ3Mgb24gRmFuZGFuZ28gdG8gZmluZCBvdXQgaWYgdGhlcmUgaGFzIGJlZW4gYW55IGNoYW5nZSBpbiBGYW5kYW5nbydzIHJhdGluZyBzeXN0ZW0gYWZ0ZXIgSGlja2V5J3MgYW5hbHlzaXMuCgoqKjMuIERhdGEgU291cmNlcyoqCgpIZXJlIGFyZSB0d28gc2V0cyBvZiBtb3ZpZSByYXRpbmdzIGRhdGEgc2FtcGxlZDoKCiogaHR0cHM6Ly9naXRodWIuY29tL2ZpdmV0aGlydHllaWdodC9kYXRhL3RyZWUvbWFzdGVyL2ZhbmRhbmdvIC0gRGF0YXNldCBjb2xsZWN0ZWQgYnkgV2FsdCBIaWNrZXkgKHB1bGxlZCBvbiBBdWcuIDI0LCAyMDE1KSAKICAtIFRoaXMgc2FtcGxlIHdpbGwgYmUgdXNlZCB0byBhbmFseXplIG1vdmllIHJhdGluZ3MgYmVmb3JlIEhpY2tleSdzIGFuYWx5c2lzCiogaHR0cHM6Ly9naXRodWIuY29tL21pcmNlYWxleC9Nb3ZpZV9yYXRpbmdzXzIwMTZfMTcgLSBEYXRhc2V0IGNvbGxlY3RlZCBieSBEYXRhcXVlc3QgKHB1bGxlZCBvbiBNYXJjaCAyMiwgMjAxNykgCiAgLSBUaGlzIHNhbXBsZSB3aWxsIGJlIHVzZWQgdG8gYW5hbHl6ZSBtb3ZpZSByYXRpbmdzIGFmdGVyIEhpY2tleSdzIGFuYWx5c2lzCgoKYGBge3IgZXZhbD1GQUxTRX0KbGlicmFyeShyZWFkcikKCmZhbmRhbmdvX2JlZm9yZSA8LSByZWFkX2NzdigiZmFuZGFuZ29fc2NvcmVfY29tcGFyaXNvbi5jc3YiKQpmYW5kYW5nb19hZnRlciA8LSByZWFkX2NzdigibW92aWVfcmF0aW5nc18xNl8xNy5jc3YiKQpgYGAKYGBge3J9CmhlYWQoZmFuZGFuZ29fYmVmb3JlKQpoZWFkKGZhbmRhbmdvX2FmdGVyKQpgYGAKCgojIyMgSS4gRGV0ZXJtaW5pbmcgaWYgdGhlIHNhbXBsZXMgYXJlIHJlcHJlc2VudGF0aXZlIG9mIHRoZSBwb3B1bGF0aW9uCgoKSWYgdGhlIGdvYWwgaGVyZSBpcyB0byBmaW5kIG91dCBpZiB0aGVyZSBoYXMgYmVlbiBhbnkgY2hhbmdlIGFmdGVyIEhpY2tleSdzIGFuYWx5c2lzLCB0aGVuIGlkZWFsbHkgd2Ugd291bGQgd2FudCB0byBzYW1wbGUgYWxsIG1vdmllIHJhdGluZ3MgYXQgdHdvIGRpZmZlcmVudCBwZXJpb2RzIG9mIHRpbWUgZm9yIGNvbXBhcmlzb24uIFRodXMsIHRoZSBwb3B1bGF0aW9uIG9mIGludGVyZXN0IGZvciB0aGlzIGdvYWwgaXM6IGFsbCB0aGUgbW92aWUgcmF0aW5ncyBvbiBGYW5kYW5nby5jb20uIAoKR29vZCBuZXdzIGlzLCB0aGUgdHdvIHNhbXBsZXMgd2UgYXJlIHdvcmtpbmcgd2l0aCB3ZXJlIHRha2VuIGJlZm9yZSBhbmQgYWZ0ZXIgSGlja2V5J3MgYW5hbHlzaXMuIEhvd2V2ZXIsIHdlIHN0aWxsIG5lZWQgdG8gbWFrZSBzdXJlIHRoZSBzYW1wbGVzIGFyZSByZXByZXNlbnRhdGl2ZSBvZiB0aGUgcG9wdWxhdGlvbiBvZiBpbnRlcmVzdCwgaW4gb3JkZXIgdG8gZGVzY3JpYmUgdGhlIHBvcHVsYXRpb24gYXMgcHJlY2lzZSBhcyBwb3NzaWJsZSBhbmQgbWluaW1pemUgdGhlIHNhbXBsaW5nIGVycm9yLiAKCmBgYHtyIGV2YWw9RkFMU0V9CgpsaWJyYXJ5KGRwbHlyKQojIENsZWFuaW5nIGRhdGFmcmFtZXMgdG8gaW5jbHVkZSBvbmx5IHJlbGV2YW50IGRhdGEKZmFuZGFuZ29fYmVmb3JlX2NsZWFuZWQgPC0gZmFuZGFuZ29fYmVmb3JlICU+JQogIHNlbGVjdChGSUxNLCBGYW5kYW5nb19TdGFycywgRmFuZGFuZ29fUmF0aW5ndmFsdWUsIEZhbmRhbmdvX3ZvdGVzLCBGYW5kYW5nb19EaWZmZXJlbmNlKQpmYW5kYW5nb19hZnRlcl9jbGVhbmVkIDwtIGZhbmRhbmdvX2FmdGVyICU+JQogIHNlbGVjdChtb3ZpZSwgeWVhciwgZmFuZGFuZ28pCmBgYApgYGB7cn0KaGVhZChmYW5kYW5nb19iZWZvcmVfY2xlYW5lZCkKYGBgCgpBY2NvcmRpbmcgdG8gSGlja2V5J2FydGljbGUsIGhlcmUgYXJlIHRoZSBzYW1wbGluZyBjcml0ZXJpYSBmb3IgU2FtcGxlICMxIChyYXRpbmdzIGJlZm9yZSBIaWNrZXkncyBhbmFseXNpcyk6IAoKKiBUaGUgbW92aWUgaGFkIGF0IGxlYXN0IDMwIGZhbiByZXZpZXdzIG9uIEZhbmRhbmdvLCBhcyBvZiBBdWcuIDI0LCAyMDE1LgoqIFRoZSBtb3ZpZSBoYWQgdGlja2V0cyBvbiBzYWxlIGluIDIwMTUuCgpgYGB7cn0KaGVhZChmYW5kYW5nb19hZnRlcl9jbGVhbmVkKQpgYGAKCkFjY29yZGluZyB0byBEYXRhcXVlc3QncyBHaXRIdWIgcmVwb3NpdG9yeSwgaGVyZSBhcmUgdGhlIHNhbXBsaW5nIGNyaXRlcmlhIGZvciBTYW1wbGUgIzIgKHJhdGluZ3MgYWZ0ZXIgSGlja2V5J3MgYW5hbHlzaXMpOiAKCiogVGhlIG1vdmllIHdhcyAicG9wdWxhciIgYW5kIHJlY2VpdmVkIGEgc2lnbmlmaWNhbnQgbnVtYmVyIG9mIHZvdGVzLgoqIFRoZSBtb3ZpZSB3YXMgcmVsZWFzZWQgaW4gMjAxNiBhbmQgMjAxNy4KCgoqKkNvbnNsdXNpb24qKgoKQm90aCBzYW1wbGVzIGFyZSBub3QgcmFuZG9tIGJlY2F1c2Ugbm90IGFsbCB0aGUgbW92aWVzIGhhdmUgYW4gZXF1YWwgcHJvYmFiaWxpdHkgdG8gYmUgc2VsZWN0ZWQuClRoZSBzYW1wbGluZyBtZXRob2QgYXBwbGllZCBoZXJlIGlzIHB1cnBvc2l2ZSBzYW1wbGluZywgd2hlcmUgc2FtcGxlcyBhcmUgcHJvZHVjZWQgdW5kZXIgcHJlLWRlZmluZWQgYW5kIHN1YmplY3RpdmUgY29uZGl0aW9ucy4KVGhlcmVmb3JlLCB0aGVzZSB0d28gc2FtcGxlcyBhcmUgbm90IHJlcHJlc2VudGF0aXZlIG9mIHRoZSBwb3B1bGF0aW9uIChhbGwgbW92aWUgcmF0aW5ncyBvbiBGYW5kYW5nbykgd2Ugd2FudCB0byBkZXNjcmliZS4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyBJSS4gQWRqdXN0aW5nIHRoZSBnb2FsIG9mIHRoZSBhbmFseXNpcyBhbmQgcmUtZXhhbWluaW5nIHNhbXBsZSByZXByZXNlbnRhdGl2ZW5lc3MKCgpVc2luZyBub24tcmVwcmVzZW50YXRpdmUgc2FtcGxlcyB0byBkZXNjcmliZSBhIHBvcHVsYXRpb24gY291bGQgbGVhZCB0byBhIHdyb25nIGNvbmNsdXNpb24uIE1vdmluZyBmb3J3YXJkLCBJIGFtIGdvaW5nIHRvIHNsaWdobHkgYWRqdXN0IHRoZSBnb2FsIG9mIHRoaXMgcHJvamVjdCB0byBhIG5ldyBnb2FsIHRoYXQgaXMgc3RpbGwgYSBmYWlybHkgZ29vZCBwcm94eSBmb3IgdGhlIGluaXRpYWwgZ29hbCwgc28gdGhhdCB0aGUgcG9wdWxhdGlvbiBvZiBpbnRlcmVzdCBjaGFuZ2VzIGFuZCB0aGUgc2FtcGxlcyB3ZSBhcmUgd29ya2luZyB3aXRoIGJlY29tZSByZXByZXNlbnRhdGl2ZS4KCipXZSBjb3VsZCBhbHNvIGNvbGxlY3QgbmV3IGRhdGEgYW5kIG9idGFpbiByZXByZXNlbnRhdGl2ZSBzYW1wbGVzIGhlcmUuIEhvd2V2ZXIsIHRpbWUgaGFzIHBhc3NlZCBzaW5jZSBIaWNrZXkncyBhbmFseXNpcyBhbmQgaXQgd291bGQgYmUgZGlmZmljdWx0IG9yIGV2ZW4gaW1wb3NzaWJsZSB0byBhY2Nlc3MgcHJlY2lzZSBkYXRhIHByaW9yIHRvIEhpY2tleSdzIGFuYWx5c2lzIGF0IHRoaXMgdGltZS4qCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoqKkFkanVzdGVkIEdvYWwqKgoKSW5zdGVhZCBvZiB0cnlpbmcgdG8gZmluZCBvdXQgaWYgdGhlcmUgaGFzIGJlZW4gYW55IGNoYW5nZSBpbiBGYW5kYW5nbydzIHJhdGluZyBzeXN0ZW0gYWZ0ZXIgSGlja2V5J3MgYW5hbHlzaXMsIHdlIHdpbGwgdHJ5IHRvIGRldGVybWluZSBpZiB0aGVyZSBpcyBhbnkgZGlmZmVyZW5jZSBiZXR3ZWVuIEZhbmRhbmdvJ3MgcmF0aW5ncyBmb3IgcG9wdWxhciBtb3ZpZXMgaW4gMjAxNSBhbmQgaW4gMjAxNi4gSWYgeWVzLCB0aGVuIGl0IGNvdWxkIGJlIGFuIGluZGljYXRpb24gdGhhdCBGYW5kYW5nbyBoYXMgbWFkZSBjaGFuZ2VzLgoKKipBZGp1c3RlZCBQb3B1bGF0aW9ucyBvZiBJbnRlcmVzdCoqCgoqIEFsbCBGYW5kYW5nbydzIHJhdGluZ3MgZm9yIHBvcHVsYXIgbW92aWVzIHJlbGVhc2VkIGluIDIwMTUuCiogQWxsIEZhbmRhbmdvJ3MgcmF0aW5ncyBmb3IgcG9wdWxhciBtb3ZpZXMgcmVsZWFzZWQgaW4gMjAxNi4KCkkgd2lsbCB1c2UgSGlja2V5J3MgYmVuY2htYXJrIG9mIDMwIHJhdGluZ3MgdG8gZGVmaW5lICJwb3B1bGFyIiB3aGljaCBpcyByZWFzb25hYmxlLiBUaGF0IGJlaW5nIHNhaWQsIGEgbW92aWUgaXMgY29uc2lkZXJlZCAicG9wdWxhciIgaW4gdGhpcyBjYXNlIGlmIGl0IGhhcyBhdCBsZWFzdCAzMCByYXRpbmdzLgoKU2FtcGxlICMxIG5vdyBiZWNvbWVzIHJlcHJlc2VudGF0aXZlLCBzaW5jZSBpdCB3YXMgcmFuZG9tbHkgc2VsZWN0ZWQgdW5kZXIgdGhlIGNvbmRpdGlvbiBvZiBoYXZpbmcgYXQgbGVhc2UgMzAgcmF0aW5ncy4KCkhvd2V2ZXIgZm9yIFNhbXBsZSAjMiwgaXQgaXMgdW5jbGVhciBob3cgdGhlIHJlc2VhcmNoZXIgZGVmaW5lZCAicG9wdWxhciIuIFNvIGl0IGlzIGltcGVyYXRpdmUgdG8gY2hlY2sgaWYgdGhlIG1vdmllcyBzZWxlY3RlZCBoYXZlIGF0IGxlYXNlIDMwIHJhdGluZ3MuIAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKQmFzZWQgb24gdGhlIGRhdGFmcmFtZSBvZiBTYW1wbGUgIzIgYWJvdmUsIHRoZXJlIGlzIG5vIHN1Y2ggYSB2YXJpYWJsZSB0aGF0IHNob3dzIGEgbW92aWUncyByYXRpbmcgY291bnRzLiBNb3Jlb3ZlciwgSSB3YXNuJ3QgYWJsZSB0byBmaW5kIHRoZSByYXRpbmcgY291bnRzIG9uIEZhbmRhbmdvIHBhZ2VzIG9mIHRoZSBtb3ZpZXMsIGJlY2F1c2UgRmFuZGFuZ28gaGFzIHJlcGxhY2VkIHRoZSA1LVN0YXIgRmFuIFJhdGluZ3Mgd2l0aCB0aGUgUm90dGVuIFRvbWF0b2VzIEF1ZGllbmNlIFNjb3JlIGluIDIwMTkgc28gbm93IHRoZSByYXRpbmcgY291bnRzIGFyZSBzaG93biBvbiBSb3R0ZW50b21hdG9lcy5jb20uIAoKVGhlcmVmb3JlLCBJIGFtIGdvaW5nIHRvIHNhbXBsZSAxMCBvYnNlcnZhdGlvbnMgZnJvbSBTYW1wbGUgIzIgYW5kIGZpbmQgdGhlaXIgcmF0aW5nIGNvdW50cyBmcm9tIFJvdHRlbnRvbWF0b2VzLmNvbS4KCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRX0Kc2V0LnNlZWQoMSkKYWZ0ZXJfc2FtcGxlIDwtIHNhbXBsZV9uKGZhbmRhbmdvX2FmdGVyX2NsZWFuZWQsIHNpemUgPSAxMCkKCiMgRm91bmQgcmF0aW5nIGNvdW50cyBvZiB0aGVzZSAxMCBzYW1wbGVzCnNhbXBsZV9yYXRpbmdfY291bnRzIDwtIHRpYmJsZShyZXZpZXdzID0gYyg3Mzg0LCA3MjU5LCA3MjY1LCAxMjIxMiwgMzAyNzEsIDI4MSwgMTM2ODQsIDEyMTIsIDU2ODUxLCA5MjIyKSkKCmJpbmRfY29scyhhZnRlcl9zYW1wbGUsIHNhbXBsZV9yYXRpbmdfY291bnRzKQpgYGAKCkFsbCAxMCBtb3ZpZXMgcmFuZG9tbHkgc2FtcGxlZCByZWNlaXZlZCBtb3JlIHRoYW4gMzAgcmF0aW5ncy4gSXQgaXMgc2FmZSB0byBzYXkgdGhhdCBtb3ZpZXMgaW4gU2FtcGxlICMyIGFyZSAicG9wdWxhciIuIExldCdzIG1vdmUgb24uCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoKIyMjIElJSS4gUmVzaGFwaW5nIGRhdGFmcmFtZXMgYW5kIGV4dHJhY3RpbmcgcmVsZXZhbnQgZGF0YQoKU2luY2Ugbm93IHdlIGFyZSBvbmx5IGludGVyZXN0ZWQgaW4gcG9wdWxhciBtb3ZpZXMgcmVsZWFzZWQgaW4gMjAxNSBhbmQgMjAxNiwgSSBhbSBnb2luZyB0byBleHRyYWN0IG9ubHkgdGhlIHJlbGV2YW50IGRhdGEgZm9yIHRoZSBmb2xsb3dpbmcgYW5hbHlzaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpsaWJyYXJ5KHN0cmluZ3IpCmBgYApgYGB7ciBtZXNzYWdlPUZBTFNFfQpmaWxtX25hbWVfeWVhciA8LSBzdHJfc3BsaXQoZmFuZGFuZ29fYmVmb3JlX2NsZWFuZWQkRklMTSwgIlxcKCIsIHNpbXBsaWZ5ID0gVFJVRSkKCmZhbmRhbmdvXzIwMTUgPC0gZmFuZGFuZ29fYmVmb3JlX2NsZWFuZWQgJT4lCiAgbXV0YXRlKEZJTE0gPSBmaWxtX25hbWVfeWVhclssMV0sIHllYXIgPSBmaWxtX25hbWVfeWVhclssMl0pICU+JQogIG11dGF0ZSh5ZWFyID0gc3RyX3N1Yih5ZWFyLCAxLCA0KSkgJT4lCiAgZmlsdGVyKHllYXIgPT0gIjIwMTUiKQoKaGVhZChmYW5kYW5nb18yMDE1KQpgYGAKYGBge3IgbWVzc2FnZSA9IEZBTFNFfQpmYW5kYW5nb18yMDE2IDwtIGZhbmRhbmdvX2FmdGVyX2NsZWFuZWQgJT4lCiAgZmlsdGVyKHllYXIgPT0gIjIwMTYiKQoKaGVhZChmYW5kYW5nb18yMDE2KQpgYGAKCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoKIyMjIElWLiBWaXN1YWxpemluZyB0aGUgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbnMgdG8gZ2V0IGFuIG92ZXJ2aWV3CgpGaXJzdCBvZiBhbGwsIEkgYW0gZ29pbmcgdG8gdXNlIEtlcm5lbCBEZW5zaXR5IFBsb3RzIHRvIGNvbXBhcmUgdGhlIGRpc3RyaWJ1dGlvbiBzaGFwZXMgb2YgdHdvIHNhbXBsZXMgaW4gb3JkZXIgdG8gZ2V0IGEgZ2VuZXJhbCBvdmVydmlldy4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgpnZ3Bsb3QoZGF0YSA9IGZhbmRhbmdvXzIwMTUsCiAgICAgICBhZXMoeCA9IEZhbmRhbmdvX1N0YXJzKSkgKwogICAgICAgZ2VvbV9kZW5zaXR5KCkgKwogICAgICAgZ2VvbV9kZW5zaXR5KGRhdGEgPSBmYW5kYW5nb18yMDE2LCAKICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGZhbmRhbmdvKSwgY29sb3IgPSAiYmx1ZSIpICsKICAgICAgIGxhYnModGl0bGUgPSAiQ29tcGFyaW5nIERpc3RyaWJ1dGlvbiBzaGFwZXMgZm9yIEZhbmRhbmdvJ3MgcmF0aW5ncyAoMjAxNSB2LnMuIDIwMTYpIiwKICAgICAgICAgICB4ID0gIlJhdGluZ3MiLCB5ID0gIkRlbnNpdHkiKSArCiAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDUsIGJ5ID0gMC41KSwgbGltaXRzID0gYygwLCA1KSkKYGBgCgoqIEFzIHdlIGNhbiBzZWUsIGJvdGggZGlzdHJpYnV0aW9ucyBhcmUgc3Ryb25nbHkgbGVmdCBza2V3ZWQsIG1lYW5pbmcgdGhhdCBwb3B1bGFyIG1vdmllcyBvbiBGYW5kYW5nbyBhcmUgbW9zdGx5IGdpdmVuIHF1aXRlIGhpZ2ggcmF0aW5ncyBpbiBnZW5lcmFsLiAKKiBUaGUgZGlzdHJpYnV0aW9uIG9mIEZhbmRhbmdvJ3MgcmF0aW5ncyBpbiAyMDE2IGlzIHNsaWdobHkgc2hpZnRlZCB0byB0aGUgbGVmdCwgY29tcGFyZWQgdG8gdGhlIG9uZSBpbiAyMDE1LCBzdWdnZXN0aW5nIHRoYXQgcG9wdWxhciBtb3ZpZXMgd2VyZSByYXRlZCBzbGlnaHRseSBsb3dlciBpbiAyMDE2IHRoYW4gaW4gMjAxNS4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCgojIyMgVi4gR2VuZXJhdGluZyBmcmVxdWVuY3kgZGlzdHJpYnV0aW9uIHRhYmxlcyB0byBmdXJ0aGVyIGV4cGxvcmUgdGhlIGRpc3RyaWJ1dGlvbnMKCk5vdyBJIGFtIGdvaW5nIHRvIGdlbmVyYXRlIGZyZXF1ZW5jeSBkaXN0cmlidXRpb24gdGFibGVzIGZvciBmdXJ0aGVyIGRldGFpbHMuIFNpbmNlIHRoZXNlIHR3byBzYW1wbGVzIGhhdmUgZGlmZmVyZW50IGNvdW50cyBvZiBvYnNlcnZhdGlvbnMsIEkgd2lsbCB1c2UgdGhlIHJlbGF0aXZlIGZyZXF1ZW5jeSBoZXJlIGluc3RlYWQgb2YgdGhlIGFic29sdXRlIGZyZXF1ZW5jeSwgbmFtZWx5LCBwZXJjZW50YWdlcy4KCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRX0KZmFuZGFuZ29fMjAxNV9mcmVxIDwtIGZhbmRhbmdvXzIwMTUgJT4lIAogIGdyb3VwX2J5KEZhbmRhbmdvX1N0YXJzKSAlPiUgCiAgc3VtbWFyaXplKFBlcmNlbnRhZ2UgPSBuKCkgLyBucm93KGZhbmRhbmdvXzIwMTUpICogMTAwKQoKcHJpbnQoZmFuZGFuZ29fMjAxNV9mcmVxKQoKZmFuZGFuZ29fMjAxNl9mcmVxIDwtIGZhbmRhbmdvXzIwMTYgJT4lIAogIGdyb3VwX2J5KGZhbmRhbmdvKSAlPiUgCiAgc3VtbWFyaXplKFBlcmNlbnRhZ2UgPSBuKCkgLyBucm93KGZhbmRhbmdvXzIwMTYpICogMTAwKQoKcHJpbnQoZmFuZGFuZ29fMjAxNl9mcmVxKQpgYGAKCkl0IGlzIGNsZWFybHkgc2hvd24gdGhhdCB0aGVyZSBhcmUgc2lnbmlmaWNhbnRseSBsb3dlciBwZXJjZW50YWdlcyBvZiByYXRpbmdzIGJldHdlZW4gNC41IC0gNS4wIHN0YXJzIGFuZCBoaWdoZXIgcGVyY2VudGFnZXMgb2YgcmF0aW5ncyBiZWxvdyAzLjUgLSA0LjAgc3RhcnMgaW4gMjAxNiB0aGFuIGluIDIwMTUuIAoKTm93IEkgYW0gZ29pbmcgdG8gY29tcGFyZSBzb21lIGtleSBzdW1tYXJ5IHN0YXRpc3RpY3MgYmV0d2VlbiB0d28gc2FtcGxlcyB0byBnZXQgYSBtb3JlIHByZWNpc2UgcGljdHVyZSBvZiB0aGUgZGlyZWN0aW9uIG9mIHRoZSBkaWZmZXJlbmNlLgoKYGBge3IgZXZhbCA9IEZBTFNFfQpsaWJyYXJ5KHRpZHlyKQpgYGAKYGBge3IgbWVzc2FnZSA9IEZBTFNFfQptb2RlIDwtIGZ1bmN0aW9uKHgpIHsKICAgICAgICB1eCA8LSB1bmlxdWUoeCkKICAgICAgICB1eFt3aGljaC5tYXgodGFidWxhdGUobWF0Y2goeCwgdXgpKSldCn0KCmZyZXFfc3VtbWFyeV8yMDE1IDwtIGZhbmRhbmdvXzIwMTUgJT4lIAogIHN1bW1hcml6ZSh5ZWFyID0gIjIwMTUiLAogICAgbWVhbiA9IG1lYW4oRmFuZGFuZ29fU3RhcnMpLAogICAgbWVkaWFuID0gbWVkaWFuKEZhbmRhbmdvX1N0YXJzKSwKICAgIG1vZGUgPSBtb2RlKEZhbmRhbmdvX1N0YXJzKSkKCmZyZXFfc3VtbWFyeV8yMDE2IDwtIGZhbmRhbmdvXzIwMTYgJT4lIAogIHN1bW1hcml6ZSh5ZWFyID0gIjIwMTYiLAogICAgICAgICAgICBtZWFuID0gbWVhbihmYW5kYW5nbyksCiAgICAgICAgICAgIG1lZGlhbiA9IG1lZGlhbihmYW5kYW5nbyksCiAgICAgICAgICAgIG1vZGUgPSBtb2RlKGZhbmRhbmdvKSkKCnN1bW1hcnlfc3RhdCA8LSBiaW5kX3Jvd3MoZnJlcV9zdW1tYXJ5XzIwMTUsIGZyZXFfc3VtbWFyeV8yMDE2KQoKc3VtbWFyeV9zdGF0MiA8LSBzdW1tYXJ5X3N0YXQgJT4lIAogIGdhdGhlcihrZXkgPSAic3RhdGlzdGljIiwgdmFsdWUgPSAidmFsdWUiLCAtIHllYXIpCgpwcmludChzdW1tYXJ5X3N0YXQyKQoKZ2dwbG90KGRhdGEgPSBzdW1tYXJ5X3N0YXQyLCAKICAgICAgIGFlcyh4ID0gc3RhdGlzdGljLCB5ID0gdmFsdWUsIGZpbGwgPSB5ZWFyKSkgKwogICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogICAgICAgbGFicyh0aXRsZSA9ICJDb21wYXJpbmcgU3VtbWFyeSBTdGF0aXN0aWNzOiAyMDE1IHYucy4gMjAxNiIsIHggPSAiIiwgeSA9ICJSYXRpbmcgU3RhcnMiKSArIAogICAgICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJQYWlyZWQiKQpgYGAKCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRX0Kc3VtbWFyeV9zdGF0MiAlPiUKICBmaWx0ZXIoc3RhdGlzdGljID09ICJtZWFuIikgJT4lCiAgc3VtbWFyaXplKGBDaGFuZ2Ugb2YgTWVhbmAgPSAodmFsdWVbMl0gLSB2YWx1ZVsxXSkgLyB2YWx1ZVsxXSAqMTAwKQoKc3VtbWFyeV9zdGF0MiAlPiUKICBmaWx0ZXIoc3RhdGlzdGljID09ICJtb2RlIikgJT4lCiAgc3VtbWFyaXplKGBDaGFuZyBvZiBNb2RlYCA9ICh2YWx1ZVsyXSAtIHZhbHVlWzFdKSAvIHZhbHVlWzFdICoxMDApCmBgYAoKKiBBbHRob3VnaCB0d28gc2FtcGxlcyBoYXZlIHRoZSBzYW1lIG1lZGlhbiwgaXQgaXMgc2hvd24gdGhhdCBTYW1wbGUgIzEgKHJhdGluZ3MgaW4gMjAxNSkgaGFzIGEgaGlnaGVyIG1lYW4gdGhhbiBTYW1wbGUgIzIgKHJhdGluZ3MgaW4gMjAxNikuCiogVGhlIG1lYW4gb2YgU2FtcGxlICMyIChyYXRpbmdzIGluIDIwMTYpIGRyb3BwZWQgYnkgNC44JSBjb21wYXJlZCB0byBTYW1wbGUgIzEgKHJhdGluZ3MgaW4gMjAxNSkuCiogVGhlIG1vZGUgb2YgU2FtcGxlICMxIChyYXRpbmdzIGluIDIwMTUpIGlzIDExJSBoaWdoZXIgdGhhbiB0aGUgbW9kZSBvZiBTYW1wbGUgIzIgKHJhdGluZ3MgaW4gMjAxNikuCgpBbGwgdGhyZWUgc3RhdGlzdGljcyBhYm92ZSBwb2ludCB0byBhIGNvbmNsdXNpb24gdGhhdCB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgYmV0d2VlbiBGYW5kYW5nbydzIHJhdGluZ3MgZm9yIHBvcHVsYXIgbW92aWVzIGluIDIwMTUgKGJlZm9yZSBIaWNrZXkncyBhbmFseXNpcykgYW5kIGluIDIwMTYgKGFmdGVyIEhpY2tleSdzIGFuYWx5c2lzKSwgYW5kIHRoYXQgdGhlIG1vdmllIHJhdGluZ3Mgd2VyZSBsb3dlciBpbiAyMDE2IHRoYW4gaW4gMjAxNS4KCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMgU3VtbWFyeQoKSSBzdGFydGVkIHRoaXMgcHJvamVjdCB3aXRoIHRoZSBnb2FsIG9mIGZpbmRpbmcgb3V0IGlmIHRoZXJlIGhhcyBiZWVuIGFueSBjaGFuZ2UgaW4gRmFuZGFuZ28ncyByYXRpbmcgc3lzdGVtIGFmdGVyIEhpY2tleSdzIGFuYWx5c2lzLiBIb3dldmVyIGFzIEkgd2FzIGV4YW1pbmluZyB0aGUgc2FtcGxlIHJlcHJlc2VudGF0aXZlbmVzcywgSSBkaXNjb3ZlcmVkIHRoYXQgdGhlIHNhbXBsZXMgYXJlIG5vdCByZXByZXNlbnRhdGl2ZSBvZiB0aGUgcG9wdWxhdGlvbiBvZiBpbnRlcmVzdCBmb3IgdGhlIGluaXRpYWwgZ29hbC4gVGhlcmVmb3JlLCBJIGFkb3B0ZWQgYW4gYWRqdXN0ZWQgZ29hbCB3aGljaCBpcyBhIGZhaXJseSBnb29kIHByb3h5IGZvciB0aGUgaW5pdGlhbCBnb2FsOiB0byBkZXRlcm1pbmUgaWYgdGhlcmUgaXMgYW55IGRpZmZlcmVuY2UgYmV0d2VlbiBGYW5kYW5nbydzIHJhdGluZ3MgZm9yIHBvcHVsYXIgbW92aWVzIGluIDIwMTUgYW5kIGluIDIwMTYuCgpTbyBmYXIsIHRoZSBhbmFseXNpcyBoYXMgc2hvd24gdXMgdGhhdCB0aGVyZSBpcyBpbmRlZWQgYSBkaWZmZXJlbmNlIGJldHdlZW4gRmFuZGFuZ28ncyByYXRpbmdzIGZvciBwb3B1bGFyIG1vdmllcyBpbiAyMDE1IGFuZCBpbiAyMDE2LCBhbmQgdGhhdCB0aGUgcmF0aW5ncyB3ZXJlIGxvd2VyIGluIDIwMTYgdGhhbiBpbiAyMDE1IG9uIGF2ZXJhZ2UuIE9uIG9uZSBoYW5kLCBpdCBjb3VsZCBiZSBiZWNhdXNlIHRoZSBtb3ZpZXMgcmVsZWFzZWQgaW4gMjAxNSB3ZXJlIG92ZXJhbGwgImJldHRlciIgdGhhbiB0aGUgbW92aWVzIG9mIDIwMTYuIE9uIHRoZSBvdGhlciBoYW5kLCBpdCBjb3VsZCBiZSBiZWNhdXNlIEZhbmRhbmdvIGRpZCBtYWtlIGNoYW5nZXMgdG8gaXRzIHJhdGluZyBzeXN0ZW0gKGZvciBleGFtcGxlLCBmaXhlZCB0aGUgcm91bmRpbmcgb2ZmIHN5c3RlbSkuIFRoZSBjYXVzZSBvZiB0aGUgZGlmZmVyZW5jZSBkZWZpbml0ZWx5IGRlc2VydmVzIGEgZnVydGhlciBhbmQgZGVlcGVyIGFuYWx5c2lzLiAKCgo=