Summary: This will evaluate the median value of a player’s launch angle

The LA50 (50th percentile launch angle) and the mean (average) launch angle are both metrics used to summarize the distribution of launch angles for a player or group of players. Each has its own advantages and can provide different insights: Advantages of LA50 (Median Launch Angle):

Less Sensitive to Outliers: The median, or LA50, is not affected by extreme values as much as the mean. This is particularly useful when a player's data includes a few exceptionally high or low launch angles, which can skew the mean. LA50 provides a more robust measure of the central tendency of the data.

Better Representation of Typical Performance: Since the median represents the middle value, it can give a better sense of a player's typical batted ball profile. For example, if a player has a few high pop-ups or ground balls that are not representative of their usual performance, these outliers won't disproportionately influence the LA50.

Comparing Players with Skewed Distributions: For players with highly skewed distributions of launch angles, the median can provide a more meaningful comparison between players. It helps to understand how often a player is achieving certain types of contact (like line drives) without being skewed by extreme angles.

Advantages of Mean Launch Angle:

Sensitivity to All Data Points: The mean takes into account every launch angle, providing a full-picture summary that reflects all the data. This can be useful in understanding the overall tendency of a player's batted balls, especially if outliers are genuinely reflective of a player's variance in hitting.

Contextual Analysis: The mean is useful when combined with other metrics, such as standard deviation, to analyze the consistency of a player's launch angles. A player with a high mean and low standard deviation may consistently hit balls at advantageous angles.

Predictive Analytics: The mean can sometimes be more informative in predictive models, especially when understanding the potential for certain outcomes (like home runs) that may be influenced by extreme values in launch angle.

Use Case Considerations:

LA50 is particularly useful when you want a stable measure of central tendency that represents a player's typical launch angle without the influence of outliers. It’s helpful in understanding a player's consistency and typical performance.

Mean launch angle is useful for capturing the overall trend and potential variability in a player's batted ball profile, providing a more comprehensive view that includes all data points.

In summary, LA50 provides a reliable measure that can reflect a player’s typical hitting pattern, while the mean offers a broader view that can include the impact of all data points, including outliers. Both metrics are valuable, and the choice between them depends on the specific analysis or question being addressed.

First, let’s load the necessary libraries

library(httr)
library(jsonlite)
library(tidyverse)

Next, let’s fetch event data from the baseball savant API. Let’s create a function which will input a start and end date and return a dataframe with the data from the dat range.


# Function to fetch data from Baseball Savant API
fetch_statcast_data <- function(start_date, end_date) {
  url <- "https://baseballsavant.mlb.com/statcast_search/csv"
  response <- GET(url, query = list(
    start_date = start_date,
    end_date = end_date,
    player_type = "batter",
    type = "events",
    batted_ball_event = "true",
    all = "true"
  ))
  
  content <- content(response, "text")
  df <- read.csv(text = content)
  return(df)
}

Next, let’s define some variables


# Define the date range for the 2024 season
start_date <- "2024-03-28"
end_date <- "2024-10-01"

# Fetch data
data <- fetch_statcast_data(start_date, end_date)


head(data, 5)

Let’s look at the column names:

colnames(data)
 [1] "pitch_type"                      "game_date"                       "release_speed"                  
 [4] "release_pos_x"                   "release_pos_z"                   "player_name"                    
 [7] "batter"                          "pitcher"                         "events"                         
[10] "description"                     "spin_dir"                        "spin_rate_deprecated"           
[13] "break_angle_deprecated"          "break_length_deprecated"         "zone"                           
[16] "des"                             "game_type"                       "stand"                          
[19] "p_throws"                        "home_team"                       "away_team"                      
[22] "type"                            "hit_location"                    "bb_type"                        
[25] "balls"                           "strikes"                         "game_year"                      
[28] "pfx_x"                           "pfx_z"                           "plate_x"                        
[31] "plate_z"                         "on_3b"                           "on_2b"                          
[34] "on_1b"                           "outs_when_up"                    "inning"                         
[37] "inning_topbot"                   "hc_x"                            "hc_y"                           
[40] "tfs_deprecated"                  "tfs_zulu_deprecated"             "fielder_2"                      
[43] "umpire"                          "sv_id"                           "vx0"                            
[46] "vy0"                             "vz0"                             "ax"                             
[49] "ay"                              "az"                              "sz_top"                         
[52] "sz_bot"                          "hit_distance_sc"                 "launch_speed"                   
[55] "launch_angle"                    "effective_speed"                 "release_spin_rate"              
[58] "release_extension"               "game_pk"                         "pitcher.1"                      
[61] "fielder_2.1"                     "fielder_3"                       "fielder_4"                      
[64] "fielder_5"                       "fielder_6"                       "fielder_7"                      
[67] "fielder_8"                       "fielder_9"                       "release_pos_y"                  
[70] "estimated_ba_using_speedangle"   "estimated_woba_using_speedangle" "woba_value"                     
[73] "woba_denom"                      "babip_value"                     "iso_value"                      
[76] "launch_speed_angle"              "at_bat_number"                   "pitch_number"                   
[79] "pitch_name"                      "home_score"                      "away_score"                     
[82] "bat_score"                       "fld_score"                       "post_away_score"                
[85] "post_home_score"                 "post_bat_score"                  "post_fld_score"                 
[88] "if_fielding_alignment"           "of_fielding_alignment"           "spin_axis"                      
[91] "delta_home_win_exp"              "delta_run_exp"                   "bat_speed"                      
[94] "swing_length"                   
# Filter out rows without launch angle information
data <- data %>% filter(!is.na(launch_angle))

Now that we have our data, let’s calculate the LA50 for 2024.


# Calculate LA50 for each batter
la50_data <- data %>%
  group_by(player_name) %>%
  summarize(
    LA = mean(launch_angle, na.rm = TRUE),
    LA50 = median(launch_angle, na.rm = TRUE),
    `LA - LA50` = LA - LA50,
  )

# Display the LA50 data
print(la50_data)

the difference between the mean launch angle and the LA50 (median launch angle) can provide valuable insights into a player’s batted ball profile. This difference can highlight aspects of the distribution and consistency of a player’s launch angles. Here’s how this information can be useful: Understanding Skewness in Launch Angle Distribution

Positive Difference (Mean > LA50):
    Implication: If the mean launch angle is greater than the median, this indicates a right-skewed distribution. It means there are some higher-than-average launch angles pulling the mean upward.
    Interpretation: This could suggest that the player occasionally hits high fly balls or pop-ups, which are less frequent but extreme enough to affect the mean. It might indicate a tendency to get under the ball occasionally, leading to more extreme launch angles.

Negative Difference (Mean < LA50):
    Implication: If the mean is less than the median, the distribution is left-skewed. This means there are some lower-than-average launch angles (ground balls or low line drives) that pull the mean down.
    Interpretation: This could indicate a tendency to hit more ground balls, possibly due to a downward swing path or an issue with getting on top of the ball.

Insights into Hitting Consistency and Approach

Large Absolute Difference:
    Implication: A large absolute difference between the mean and median suggests a wide variation in launch angles. The player might have a less consistent approach or be experimenting with different types of contact.
    Interpretation: It could be a sign that the player is versatile but inconsistent, capable of hitting both grounders and fly balls, but not specializing in a specific type of contact.

Small Absolute Difference:
    Implication: A small difference suggests that the player has a more consistent launch angle profile, with fewer outliers affecting the mean.
    Interpretation: This could indicate a stable and consistent hitting approach, which is generally desirable for maintaining a predictable offensive output.

Application in Player Development and Strategy

Adjustment Identification: Coaches can use this metric to identify areas for adjustment. For instance, if a player has a high mean but a lower median, focusing on reducing uppercut swings might help achieve more consistent contact.

Comparative Analysis: Comparing this difference across players can help identify who has more consistent and reliable hitting profiles versus those who might have more volatile outcomes.

In summary, analyzing the difference between the mean launch angle and LA50 provides a nuanced view of a player’s batted ball tendencies, consistency, and potential areas for improvement. It can reveal underlying issues with a player’s swing mechanics or hitting approach and help tailor coaching strategies to optimize performance.

LS0tDQp0aXRsZTogQ3JlYXRpbmcgYSBMQTUwIG1ldHJpYywgbGlrZSBTdGF0Y2FzdCdzIG5ldyBFVjUwLg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KU3VtbWFyeTogVGhpcyB3aWxsIGV2YWx1YXRlIHRoZSBtZWRpYW4gdmFsdWUgb2YgYSBwbGF5ZXIncyBsYXVuY2ggYW5nbGUNCiANClRoZSBMQTUwICg1MHRoIHBlcmNlbnRpbGUgbGF1bmNoIGFuZ2xlKSBhbmQgdGhlIG1lYW4gKGF2ZXJhZ2UpIGxhdW5jaCBhbmdsZSBhcmUgYm90aCBtZXRyaWNzIHVzZWQgdG8gc3VtbWFyaXplIHRoZSBkaXN0cmlidXRpb24gb2YgbGF1bmNoIGFuZ2xlcyBmb3IgYSBwbGF5ZXIgb3IgZ3JvdXAgb2YgcGxheWVycy4gRWFjaCBoYXMgaXRzIG93biBhZHZhbnRhZ2VzIGFuZCBjYW4gcHJvdmlkZSBkaWZmZXJlbnQgaW5zaWdodHM6DQpBZHZhbnRhZ2VzIG9mIExBNTAgKE1lZGlhbiBMYXVuY2ggQW5nbGUpOg0KDQogICAgTGVzcyBTZW5zaXRpdmUgdG8gT3V0bGllcnM6IFRoZSBtZWRpYW4sIG9yIExBNTAsIGlzIG5vdCBhZmZlY3RlZCBieSBleHRyZW1lIHZhbHVlcyBhcyBtdWNoIGFzIHRoZSBtZWFuLiBUaGlzIGlzIHBhcnRpY3VsYXJseSB1c2VmdWwgd2hlbiBhIHBsYXllcidzIGRhdGEgaW5jbHVkZXMgYSBmZXcgZXhjZXB0aW9uYWxseSBoaWdoIG9yIGxvdyBsYXVuY2ggYW5nbGVzLCB3aGljaCBjYW4gc2tldyB0aGUgbWVhbi4gTEE1MCBwcm92aWRlcyBhIG1vcmUgcm9idXN0IG1lYXN1cmUgb2YgdGhlIGNlbnRyYWwgdGVuZGVuY3kgb2YgdGhlIGRhdGEuDQoNCiAgICBCZXR0ZXIgUmVwcmVzZW50YXRpb24gb2YgVHlwaWNhbCBQZXJmb3JtYW5jZTogU2luY2UgdGhlIG1lZGlhbiByZXByZXNlbnRzIHRoZSBtaWRkbGUgdmFsdWUsIGl0IGNhbiBnaXZlIGEgYmV0dGVyIHNlbnNlIG9mIGEgcGxheWVyJ3MgdHlwaWNhbCBiYXR0ZWQgYmFsbCBwcm9maWxlLiBGb3IgZXhhbXBsZSwgaWYgYSBwbGF5ZXIgaGFzIGEgZmV3IGhpZ2ggcG9wLXVwcyBvciBncm91bmQgYmFsbHMgdGhhdCBhcmUgbm90IHJlcHJlc2VudGF0aXZlIG9mIHRoZWlyIHVzdWFsIHBlcmZvcm1hbmNlLCB0aGVzZSBvdXRsaWVycyB3b24ndCBkaXNwcm9wb3J0aW9uYXRlbHkgaW5mbHVlbmNlIHRoZSBMQTUwLg0KDQogICAgQ29tcGFyaW5nIFBsYXllcnMgd2l0aCBTa2V3ZWQgRGlzdHJpYnV0aW9uczogRm9yIHBsYXllcnMgd2l0aCBoaWdobHkgc2tld2VkIGRpc3RyaWJ1dGlvbnMgb2YgbGF1bmNoIGFuZ2xlcywgdGhlIG1lZGlhbiBjYW4gcHJvdmlkZSBhIG1vcmUgbWVhbmluZ2Z1bCBjb21wYXJpc29uIGJldHdlZW4gcGxheWVycy4gSXQgaGVscHMgdG8gdW5kZXJzdGFuZCBob3cgb2Z0ZW4gYSBwbGF5ZXIgaXMgYWNoaWV2aW5nIGNlcnRhaW4gdHlwZXMgb2YgY29udGFjdCAobGlrZSBsaW5lIGRyaXZlcykgd2l0aG91dCBiZWluZyBza2V3ZWQgYnkgZXh0cmVtZSBhbmdsZXMuDQoNCkFkdmFudGFnZXMgb2YgTWVhbiBMYXVuY2ggQW5nbGU6DQoNCiAgICBTZW5zaXRpdml0eSB0byBBbGwgRGF0YSBQb2ludHM6IFRoZSBtZWFuIHRha2VzIGludG8gYWNjb3VudCBldmVyeSBsYXVuY2ggYW5nbGUsIHByb3ZpZGluZyBhIGZ1bGwtcGljdHVyZSBzdW1tYXJ5IHRoYXQgcmVmbGVjdHMgYWxsIHRoZSBkYXRhLiBUaGlzIGNhbiBiZSB1c2VmdWwgaW4gdW5kZXJzdGFuZGluZyB0aGUgb3ZlcmFsbCB0ZW5kZW5jeSBvZiBhIHBsYXllcidzIGJhdHRlZCBiYWxscywgZXNwZWNpYWxseSBpZiBvdXRsaWVycyBhcmUgZ2VudWluZWx5IHJlZmxlY3RpdmUgb2YgYSBwbGF5ZXIncyB2YXJpYW5jZSBpbiBoaXR0aW5nLg0KDQogICAgQ29udGV4dHVhbCBBbmFseXNpczogVGhlIG1lYW4gaXMgdXNlZnVsIHdoZW4gY29tYmluZWQgd2l0aCBvdGhlciBtZXRyaWNzLCBzdWNoIGFzIHN0YW5kYXJkIGRldmlhdGlvbiwgdG8gYW5hbHl6ZSB0aGUgY29uc2lzdGVuY3kgb2YgYSBwbGF5ZXIncyBsYXVuY2ggYW5nbGVzLiBBIHBsYXllciB3aXRoIGEgaGlnaCBtZWFuIGFuZCBsb3cgc3RhbmRhcmQgZGV2aWF0aW9uIG1heSBjb25zaXN0ZW50bHkgaGl0IGJhbGxzIGF0IGFkdmFudGFnZW91cyBhbmdsZXMuDQoNCiAgICBQcmVkaWN0aXZlIEFuYWx5dGljczogVGhlIG1lYW4gY2FuIHNvbWV0aW1lcyBiZSBtb3JlIGluZm9ybWF0aXZlIGluIHByZWRpY3RpdmUgbW9kZWxzLCBlc3BlY2lhbGx5IHdoZW4gdW5kZXJzdGFuZGluZyB0aGUgcG90ZW50aWFsIGZvciBjZXJ0YWluIG91dGNvbWVzIChsaWtlIGhvbWUgcnVucykgdGhhdCBtYXkgYmUgaW5mbHVlbmNlZCBieSBleHRyZW1lIHZhbHVlcyBpbiBsYXVuY2ggYW5nbGUuDQoNClVzZSBDYXNlIENvbnNpZGVyYXRpb25zOg0KDQogICAgTEE1MCBpcyBwYXJ0aWN1bGFybHkgdXNlZnVsIHdoZW4geW91IHdhbnQgYSBzdGFibGUgbWVhc3VyZSBvZiBjZW50cmFsIHRlbmRlbmN5IHRoYXQgcmVwcmVzZW50cyBhIHBsYXllcidzIHR5cGljYWwgbGF1bmNoIGFuZ2xlIHdpdGhvdXQgdGhlIGluZmx1ZW5jZSBvZiBvdXRsaWVycy4gSXTigJlzIGhlbHBmdWwgaW4gdW5kZXJzdGFuZGluZyBhIHBsYXllcidzIGNvbnNpc3RlbmN5IGFuZCB0eXBpY2FsIHBlcmZvcm1hbmNlLg0KDQogICAgTWVhbiBsYXVuY2ggYW5nbGUgaXMgdXNlZnVsIGZvciBjYXB0dXJpbmcgdGhlIG92ZXJhbGwgdHJlbmQgYW5kIHBvdGVudGlhbCB2YXJpYWJpbGl0eSBpbiBhIHBsYXllcidzIGJhdHRlZCBiYWxsIHByb2ZpbGUsIHByb3ZpZGluZyBhIG1vcmUgY29tcHJlaGVuc2l2ZSB2aWV3IHRoYXQgaW5jbHVkZXMgYWxsIGRhdGEgcG9pbnRzLg0KDQpJbiBzdW1tYXJ5LCBMQTUwIHByb3ZpZGVzIGEgcmVsaWFibGUgbWVhc3VyZSB0aGF0IGNhbiByZWZsZWN0IGEgcGxheWVyJ3MgdHlwaWNhbCBoaXR0aW5nIHBhdHRlcm4sIHdoaWxlIHRoZSBtZWFuIG9mZmVycyBhIGJyb2FkZXIgdmlldyB0aGF0IGNhbiBpbmNsdWRlIHRoZSBpbXBhY3Qgb2YgYWxsIGRhdGEgcG9pbnRzLCBpbmNsdWRpbmcgb3V0bGllcnMuIEJvdGggbWV0cmljcyBhcmUgdmFsdWFibGUsIGFuZCB0aGUgY2hvaWNlIGJldHdlZW4gdGhlbSBkZXBlbmRzIG9uIHRoZSBzcGVjaWZpYyBhbmFseXNpcyBvciBxdWVzdGlvbiBiZWluZyBhZGRyZXNzZWQuDQoNCkZpcnN0LCBsZXQncyBsb2FkIHRoZSBuZWNlc3NhcnkgbGlicmFyaWVzDQpgYGB7cn0NCmxpYnJhcnkoaHR0cikNCmxpYnJhcnkoanNvbmxpdGUpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQpOZXh0LCBsZXQncyBmZXRjaCBldmVudCBkYXRhIGZyb20gdGhlIGJhc2ViYWxsIHNhdmFudCBBUEkuIExldCdzIGNyZWF0ZSBhIGZ1bmN0aW9uIHdoaWNoIHdpbGwgIGlucHV0IGEgc3RhcnQgYW5kIGVuZCBkYXRlIGFuZCByZXR1cm4gYSBkYXRhZnJhbWUgd2l0aCB0aGUgZGF0YSBmcm9tIHRoZSBkYXQgcmFuZ2UuDQpgYGB7cn0NCg0KIyBGdW5jdGlvbiB0byBmZXRjaCBkYXRhIGZyb20gQmFzZWJhbGwgU2F2YW50IEFQSQ0KZmV0Y2hfc3RhdGNhc3RfZGF0YSA8LSBmdW5jdGlvbihzdGFydF9kYXRlLCBlbmRfZGF0ZSkgew0KICB1cmwgPC0gImh0dHBzOi8vYmFzZWJhbGxzYXZhbnQubWxiLmNvbS9zdGF0Y2FzdF9zZWFyY2gvY3N2Ig0KICByZXNwb25zZSA8LSBHRVQodXJsLCBxdWVyeSA9IGxpc3QoDQogICAgc3RhcnRfZGF0ZSA9IHN0YXJ0X2RhdGUsDQogICAgZW5kX2RhdGUgPSBlbmRfZGF0ZSwNCiAgICBwbGF5ZXJfdHlwZSA9ICJiYXR0ZXIiLA0KICAgIHR5cGUgPSAiZXZlbnRzIiwNCiAgICBiYXR0ZWRfYmFsbF9ldmVudCA9ICJ0cnVlIiwNCiAgICBhbGwgPSAidHJ1ZSINCiAgKSkNCiAgDQogIGNvbnRlbnQgPC0gY29udGVudChyZXNwb25zZSwgInRleHQiKQ0KICBkZiA8LSByZWFkLmNzdih0ZXh0ID0gY29udGVudCkNCiAgcmV0dXJuKGRmKQ0KfQ0KYGBgDQoNCk5leHQsIGxldCdzIGRlZmluZSBzb21lIHZhcmlhYmxlcw0KYGBge3J9DQoNCiMgRGVmaW5lIHRoZSBkYXRlIHJhbmdlIGZvciB0aGUgMjAyNCBzZWFzb24NCnN0YXJ0X2RhdGUgPC0gIjIwMjQtMDMtMjgiDQplbmRfZGF0ZSA8LSAiMjAyNC0xMC0wMSINCg0KIyBGZXRjaCBkYXRhDQpkYXRhIDwtIGZldGNoX3N0YXRjYXN0X2RhdGEoc3RhcnRfZGF0ZSwgZW5kX2RhdGUpDQoNCg0KaGVhZChkYXRhLCA1KQ0KYGBgDQoNCkxldCdzIGxvb2sgYXQgdGhlIGNvbHVtbiBuYW1lczoNCmBgYHtyfQ0KY29sbmFtZXMoZGF0YSkNCmBgYA0KDQoNCmBgYHtyfQ0KIyBGaWx0ZXIgb3V0IHJvd3Mgd2l0aG91dCBsYXVuY2ggYW5nbGUgaW5mb3JtYXRpb24NCmRhdGEgPC0gZGF0YSAlPiUgZmlsdGVyKCFpcy5uYShsYXVuY2hfYW5nbGUpKQ0KDQpgYGANCg0KTm93IHRoYXQgd2UgaGF2ZSBvdXIgZGF0YSwgbGV0J3MgY2FsY3VsYXRlIHRoZSBMQTUwIGZvciAyMDI0Lg0KYGBge3J9DQoNCiMgQ2FsY3VsYXRlIExBNTAgZm9yIGVhY2ggYmF0dGVyDQpsYTUwX2RhdGEgPC0gZGF0YSAlPiUNCiAgZ3JvdXBfYnkocGxheWVyX25hbWUpICU+JQ0KICBzdW1tYXJpemUoDQogICAgTEEgPSBtZWFuKGxhdW5jaF9hbmdsZSwgbmEucm0gPSBUUlVFKSwNCiAgICBMQTUwID0gbWVkaWFuKGxhdW5jaF9hbmdsZSwgbmEucm0gPSBUUlVFKSwNCiAgICBgTEEgLSBMQTUwYCA9IExBIC0gTEE1MCwNCiAgKQ0KDQojIERpc3BsYXkgdGhlIExBNTAgZGF0YQ0KcHJpbnQobGE1MF9kYXRhKQ0KYGBgDQoNCnRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1lYW4gbGF1bmNoIGFuZ2xlIGFuZCB0aGUgTEE1MCAobWVkaWFuIGxhdW5jaCBhbmdsZSkgY2FuIHByb3ZpZGUgdmFsdWFibGUgaW5zaWdodHMgaW50byBhIHBsYXllcidzIGJhdHRlZCBiYWxsIHByb2ZpbGUuIFRoaXMgZGlmZmVyZW5jZSBjYW4gaGlnaGxpZ2h0IGFzcGVjdHMgb2YgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgY29uc2lzdGVuY3kgb2YgYSBwbGF5ZXIncyBsYXVuY2ggYW5nbGVzLiBIZXJlJ3MgaG93IHRoaXMgaW5mb3JtYXRpb24gY2FuIGJlIHVzZWZ1bDoNClVuZGVyc3RhbmRpbmcgU2tld25lc3MgaW4gTGF1bmNoIEFuZ2xlIERpc3RyaWJ1dGlvbg0KDQogICAgUG9zaXRpdmUgRGlmZmVyZW5jZSAoTWVhbiA+IExBNTApOg0KICAgICAgICBJbXBsaWNhdGlvbjogSWYgdGhlIG1lYW4gbGF1bmNoIGFuZ2xlIGlzIGdyZWF0ZXIgdGhhbiB0aGUgbWVkaWFuLCB0aGlzIGluZGljYXRlcyBhIHJpZ2h0LXNrZXdlZCBkaXN0cmlidXRpb24uIEl0IG1lYW5zIHRoZXJlIGFyZSBzb21lIGhpZ2hlci10aGFuLWF2ZXJhZ2UgbGF1bmNoIGFuZ2xlcyBwdWxsaW5nIHRoZSBtZWFuIHVwd2FyZC4NCiAgICAgICAgSW50ZXJwcmV0YXRpb246IFRoaXMgY291bGQgc3VnZ2VzdCB0aGF0IHRoZSBwbGF5ZXIgb2NjYXNpb25hbGx5IGhpdHMgaGlnaCBmbHkgYmFsbHMgb3IgcG9wLXVwcywgd2hpY2ggYXJlIGxlc3MgZnJlcXVlbnQgYnV0IGV4dHJlbWUgZW5vdWdoIHRvIGFmZmVjdCB0aGUgbWVhbi4gSXQgbWlnaHQgaW5kaWNhdGUgYSB0ZW5kZW5jeSB0byBnZXQgdW5kZXIgdGhlIGJhbGwgb2NjYXNpb25hbGx5LCBsZWFkaW5nIHRvIG1vcmUgZXh0cmVtZSBsYXVuY2ggYW5nbGVzLg0KDQogICAgTmVnYXRpdmUgRGlmZmVyZW5jZSAoTWVhbiA8IExBNTApOg0KICAgICAgICBJbXBsaWNhdGlvbjogSWYgdGhlIG1lYW4gaXMgbGVzcyB0aGFuIHRoZSBtZWRpYW4sIHRoZSBkaXN0cmlidXRpb24gaXMgbGVmdC1za2V3ZWQuIFRoaXMgbWVhbnMgdGhlcmUgYXJlIHNvbWUgbG93ZXItdGhhbi1hdmVyYWdlIGxhdW5jaCBhbmdsZXMgKGdyb3VuZCBiYWxscyBvciBsb3cgbGluZSBkcml2ZXMpIHRoYXQgcHVsbCB0aGUgbWVhbiBkb3duLg0KICAgICAgICBJbnRlcnByZXRhdGlvbjogVGhpcyBjb3VsZCBpbmRpY2F0ZSBhIHRlbmRlbmN5IHRvIGhpdCBtb3JlIGdyb3VuZCBiYWxscywgcG9zc2libHkgZHVlIHRvIGEgZG93bndhcmQgc3dpbmcgcGF0aCBvciBhbiBpc3N1ZSB3aXRoIGdldHRpbmcgb24gdG9wIG9mIHRoZSBiYWxsLg0KDQpJbnNpZ2h0cyBpbnRvIEhpdHRpbmcgQ29uc2lzdGVuY3kgYW5kIEFwcHJvYWNoDQoNCiAgICBMYXJnZSBBYnNvbHV0ZSBEaWZmZXJlbmNlOg0KICAgICAgICBJbXBsaWNhdGlvbjogQSBsYXJnZSBhYnNvbHV0ZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG1lYW4gYW5kIG1lZGlhbiBzdWdnZXN0cyBhIHdpZGUgdmFyaWF0aW9uIGluIGxhdW5jaCBhbmdsZXMuIFRoZSBwbGF5ZXIgbWlnaHQgaGF2ZSBhIGxlc3MgY29uc2lzdGVudCBhcHByb2FjaCBvciBiZSBleHBlcmltZW50aW5nIHdpdGggZGlmZmVyZW50IHR5cGVzIG9mIGNvbnRhY3QuDQogICAgICAgIEludGVycHJldGF0aW9uOiBJdCBjb3VsZCBiZSBhIHNpZ24gdGhhdCB0aGUgcGxheWVyIGlzIHZlcnNhdGlsZSBidXQgaW5jb25zaXN0ZW50LCBjYXBhYmxlIG9mIGhpdHRpbmcgYm90aCBncm91bmRlcnMgYW5kIGZseSBiYWxscywgYnV0IG5vdCBzcGVjaWFsaXppbmcgaW4gYSBzcGVjaWZpYyB0eXBlIG9mIGNvbnRhY3QuDQoNCiAgICBTbWFsbCBBYnNvbHV0ZSBEaWZmZXJlbmNlOg0KICAgICAgICBJbXBsaWNhdGlvbjogQSBzbWFsbCBkaWZmZXJlbmNlIHN1Z2dlc3RzIHRoYXQgdGhlIHBsYXllciBoYXMgYSBtb3JlIGNvbnNpc3RlbnQgbGF1bmNoIGFuZ2xlIHByb2ZpbGUsIHdpdGggZmV3ZXIgb3V0bGllcnMgYWZmZWN0aW5nIHRoZSBtZWFuLg0KICAgICAgICBJbnRlcnByZXRhdGlvbjogVGhpcyBjb3VsZCBpbmRpY2F0ZSBhIHN0YWJsZSBhbmQgY29uc2lzdGVudCBoaXR0aW5nIGFwcHJvYWNoLCB3aGljaCBpcyBnZW5lcmFsbHkgZGVzaXJhYmxlIGZvciBtYWludGFpbmluZyBhIHByZWRpY3RhYmxlIG9mZmVuc2l2ZSBvdXRwdXQuDQoNCkFwcGxpY2F0aW9uIGluIFBsYXllciBEZXZlbG9wbWVudCBhbmQgU3RyYXRlZ3kNCg0KICAgIEFkanVzdG1lbnQgSWRlbnRpZmljYXRpb246IENvYWNoZXMgY2FuIHVzZSB0aGlzIG1ldHJpYyB0byBpZGVudGlmeSBhcmVhcyBmb3IgYWRqdXN0bWVudC4gRm9yIGluc3RhbmNlLCBpZiBhIHBsYXllciBoYXMgYSBoaWdoIG1lYW4gYnV0IGEgbG93ZXIgbWVkaWFuLCBmb2N1c2luZyBvbiByZWR1Y2luZyB1cHBlcmN1dCBzd2luZ3MgbWlnaHQgaGVscCBhY2hpZXZlIG1vcmUgY29uc2lzdGVudCBjb250YWN0Lg0KDQogICAgQ29tcGFyYXRpdmUgQW5hbHlzaXM6IENvbXBhcmluZyB0aGlzIGRpZmZlcmVuY2UgYWNyb3NzIHBsYXllcnMgY2FuIGhlbHAgaWRlbnRpZnkgd2hvIGhhcyBtb3JlIGNvbnNpc3RlbnQgYW5kIHJlbGlhYmxlIGhpdHRpbmcgcHJvZmlsZXMgdmVyc3VzIHRob3NlIHdobyBtaWdodCBoYXZlIG1vcmUgdm9sYXRpbGUgb3V0Y29tZXMuDQoNCkluIHN1bW1hcnksIGFuYWx5emluZyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBtZWFuIGxhdW5jaCBhbmdsZSBhbmQgTEE1MCBwcm92aWRlcyBhIG51YW5jZWQgdmlldyBvZiBhIHBsYXllcidzIGJhdHRlZCBiYWxsIHRlbmRlbmNpZXMsIGNvbnNpc3RlbmN5LCBhbmQgcG90ZW50aWFsIGFyZWFzIGZvciBpbXByb3ZlbWVudC4gSXQgY2FuIHJldmVhbCB1bmRlcmx5aW5nIGlzc3VlcyB3aXRoIGEgcGxheWVyJ3Mgc3dpbmcgbWVjaGFuaWNzIG9yIGhpdHRpbmcgYXBwcm9hY2ggYW5kIGhlbHAgdGFpbG9yIGNvYWNoaW5nIHN0cmF0ZWdpZXMgdG8gb3B0aW1pemUgcGVyZm9ybWFuY2UuDQoNCg==