library(tidyverse)
library(openintro)
library(jsonlite)
## Warning: package 'jsonlite' was built under R version 4.4.3
library(stringi)
library(httr)

Overview

APIs are a common source of data, especially in cases where the data could change at any time such as the most recent news. The New York Times provides free access to certain APIs, but require that each developer use their own API key. Today we we will go over the process of procuring and API key and using it to get data which we can use as a dataframe. Then we will attempt to answer the question: which New York Times news sections contain articles with the most words in January 2024?

Load data from API

Retrieve the API key from the environment variables. Using the combined URL, call the NY Times API.

nyt_api_base <- 'https://api.nytimes.com/svc/topstories/v2/'
readRenviron('.env')
nyt_api_key <- Sys.getenv('nyt_api_key')
archive_url <- paste0('https://api.nytimes.com/svc/archive/v1/2024/1.json?api-key=', nyt_api_key)
archive_data <- GET(archive_url)
archive_data
## Response [https://api.nytimes.com/svc/archive/v1/2024/1.json?api-key=VFhCuVrXMz2Ac9azrvtJrlEe7z7L6Geu]
##   Date: 2025-03-31 00:44
##   Status: 200
##   Content-Type: application/json; charset=UTF-8
##   Size: 12.9 MB

Build Dataframe

The raw data from NY Times is supposedly a JSON according to the URL. However, it requires some data wrangling to use. For today’s question, we will want the total word counts for each web page. We will also extract the abstract and URL to help verify the information found. The keys “news_desk” and “section_name” both appear to be categories, so we’ll keep both to check which one provides what we want.

parsed <- content(archive_data, 'parsed')
response_body <- parsed$response$docs
abstracts <- c()
word_counts <- c()
news_desks <- c()
web_urls <- c()
document_types <- c()
sections <- c()

for (entry in response_body) {
  abstract <- entry['abstract']
  abstracts <- append(abstracts, abstract)
  count <- entry['word_count']
  word_counts <- append(word_counts, count)
  news_desk <- entry['news_desk']
  news_desks <- append(news_desks, news_desk)
  web_url <- entry['web_url']
  web_urls <- append(web_urls, web_url)
  document_type <- entry['document_type']
  document_types <- append(document_types, document_type)
  section <- entry['section_name']
  sections <- append(sections, section)
}
nyt_df <- data.frame(
  abstract = unlist(abstracts, use.names = FALSE),
  word_count = unlist(word_counts, use.names = FALSE),
  news_desk = unlist(news_desks, use.names = FALSE),
  web_url = unlist(web_urls, use.names = FALSE),
  document_type = unlist(document_types, use.names = FALSE),
  section = unlist(sections, use.names = FALSE)
)
head(nyt_df)
##                                                                                                                                            abstract
## 1                         The tentative deal for the men’s golf circuits to join forces had a Dec. 31 deadline, but significant questions remained.
## 2                                                                                                       Harry Zheng makes his New York Times debut.
## 3  Iranian-backed Houthi gunmen from Yemen had fired on American helicopters responding to an attack on a commercial ship, American officials said.
## 4                         New Year’s celebrations took place as protesters against the Israel-Hamas war staged demonstrations in Midtown Manhattan.
## 5                                                                                                 Quotation of the Day for Monday, January 1, 2024.
## 6 More than 90 percent of Palestinians in the territory say they have regularly gone without food for a whole day, according to the United Nations.
##   word_count news_desk
## 1        558  Business
## 2        855     Games
## 3       1218   Foreign
## 4        608     Metro
## 5         36   Summary
## 6       1513   Foreign
##                                                                                                                                           web_url
## 1                                                          https://www.nytimes.com/2023/12/31/business/dealbook/pga-tour-saudi-deal-deadline.html
## 2                                                                      https://www.nytimes.com/2023/12/31/crosswords/daily-puzzle-2024-01-01.html
## 3                                                                        https://www.nytimes.com/2023/12/31/world/middleeast/us-houthi-clash.html
## 4                                                                     https://www.nytimes.com/2023/12/31/nyregion/times-square-new-years-eve.html
## 5 https://www.nytimes.com/2023/12/31/pageoneplus/quotation-of-the-day-in-a-jewish-arab-school-an-oasis-from-division-but-not-from-deep-fears.html
## 6                                                                     https://www.nytimes.com/2024/01/01/world/middleeast/gaza-israel-hunger.html
##   document_type            section
## 1       article       Business Day
## 2       article Crosswords & Games
## 3       article              World
## 4       article           New York
## 5       article        Corrections
## 6       article              World

Perform Analysis

Put together a summary of the average word count per article and summaries for both news desks and sections.

summary(nyt_df)
##    abstract           word_count       news_desk           web_url         
##  Length:3785        Min.   :    0.0   Length:3785        Length:3785       
##  Class :character   1st Qu.:  492.0   Class :character   Class :character  
##  Mode  :character   Median :  859.0   Mode  :character   Mode  :character  
##                     Mean   :  921.8                                        
##                     3rd Qu.: 1229.0                                        
##                     Max.   :12932.0                                        
##  document_type        section         
##  Length:3785        Length:3785       
##  Class :character   Class :character  
##  Mode  :character   Mode  :character  
##                                       
##                                       
## 
nyt_df %>% filter(news_desk != '') %>% group_by(news_desk) %>% summarise(across(word_count, mean, na.rm = TRUE)) %>% arrange(desc(word_count))
## Warning: There was 1 warning in `summarise()`.
## ℹ In argument: `across(word_count, mean, na.rm = TRUE)`.
## ℹ In group 1: `news_desk = "Arts"`.
## Caused by warning:
## ! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
## Supply arguments directly to `.fns` through an anonymous function instead.
## 
##   # Previously
##   across(a:b, mean, na.rm = TRUE)
## 
##   # Now
##   across(a:b, \(x) mean(x, na.rm = TRUE))
## # A tibble: 59 × 2
##    news_desk                word_count
##    <chr>                         <dbl>
##  1 Magazine                      2399.
##  2 SundayBusiness                1953.
##  3 Headway                       1745.
##  4 SpecialSections               1671 
##  5 Arts&Leisure                  1524.
##  6 TStyle                        1511 
##  7 OpEd                          1491.
##  8 Editorial                     1460 
##  9 NYTNow                        1351.
## 10 Projects and Initiatives      1281 
## # ℹ 49 more rows
nyt_df  %>% group_by(section) %>% summarise(across(word_count, mean, na.rm = TRUE)) %>% arrange(desc(word_count))
## # A tibble: 38 × 2
##    section    word_count
##    <chr>           <dbl>
##  1 Magazine        2399.
##  2 Headway         1745.
##  3 T Magazine      1511 
##  4 Briefing        1342.
##  5 Obituaries      1305.
##  6 Opinion         1290.
##  7 Health          1129.
##  8 Lens            1113 
##  9 Your Money      1113.
## 10 Education       1032 
## # ℹ 28 more rows

According to the summary, the average word count in the full dataset is 921. Magazines are the wordiest news desks and sections at around 2399 words per article. However, there are a number of news desks and sections with 0 word counts. Let’s see if there’s a pattern regarding those.

Continuing with the summaries, we can also group by document type.

nyt_df %>% group_by(document_type) %>% summarise(across(word_count, mean, na.rm = TRUE)) %>% arrange(desc(word_count))
## # A tibble: 2 × 2
##   document_type word_count
##   <chr>              <dbl>
## 1 article             972.
## 2 multimedia            0

According to document_type, some of the media are articles and others are multimedia. Multimedia results always have a word count of 0.

Next, let’s collect mean and median word counts for each news desk and section combination. From what we’ve seen, removing results with 0 word counts should not affect the highest word count totals. We expect (Magazine, Magazine) to be the most common (news desk, section) combination.

combo_df <- nyt_df %>% 
  filter(word_count > 0) %>% 
  group_by(news_desk, section) %>% 
  summarise(mean = mean(word_count, na.rm = TRUE), 
            median = median(word_count, na.rm = TRUE)) %>%   
  arrange(desc(mean))
## `summarise()` has grouped output by 'news_desk'. You can override using the
## `.groups` argument.
combo_df
## # A tibble: 104 × 4
## # Groups:   news_desk [44]
##    news_desk       section        mean median
##    <chr>           <chr>         <dbl>  <dbl>
##  1 OpEd            Podcasts     10720. 10783 
##  2 SundayBusiness  Technology    2581   2581 
##  3 Magazine        Magazine      2556.  1512.
##  4 SundayBusiness  Business Day  1916.  1560 
##  5 Headway         Headway       1745.  1187 
##  6 SpecialSections Business Day  1671   1671 
##  7 Arts&Leisure    Arts          1630.  1627 
##  8 Arts&Leisure    Theater       1591.  1717 
##  9 Obits           Science       1527   1527 
## 10 TStyle          T Magazine    1511   1526 
## # ℹ 94 more rows

This is a peculiar result considering what we had previously established. The combination (Magazine, Magazine) has a comparable mean to each individual word count from previous analyses. However, the median is far below the mean. Furthermore, (OpEd, Podcasts) has both the highest mean and median by a wide margin. The combination (SundayBusiness, Technology) is another surprise increase.

We can do a check of how OpEd is split to see if there is any irregularity in its results.

nyt_df %>% 
  filter(news_desk %in% c('OpEd', 'SundayBusiness', 'Magazine')) %>% 
  count(news_desk, section) %>% arrange(desc(n))
##        news_desk      section   n
## 1           OpEd      Opinion 250
## 2       Magazine     Magazine  49
## 3 SundayBusiness Business Day  17
## 4           OpEd     Podcasts   4
## 5 SundayBusiness   Technology   1

(OpEd, Opinion) is a far more frequent combination. While this does not change the fact that (OpEd, Podcasts) were on average the wordiest in this dataset, (Magazine, Magazine) articles are far more common to find and are usually going to be long. At a mere single occurrence, (SundayBusiness, Technology) seems to be an exception in our data.

One more eye test we can perform is to try and figure out why (OpEd, Podcasts) were so long. We do not have access to the articles themselves, but with the abstracts that we had collected earlier, we can finally examine them to get a gist of what these piece were about.

nyt_df %>% filter(news_desk == 'OpEd' & section == 'Podcasts') %>% select(abstract)
##                                               abstract
## 1                   Ezra Klein interviews Gloria Mark.
## 2  The Jan. 9, 2023, episode of “The Ezra Klein Show.”
## 3 The Jan. 19, 2023, episode of “The Ezra Klein Show.”
## 4 The Jan. 25, 2024, episode of “The Ezra Klein Show.”

Every result was from someone named Ezra Klein. These pieces appear to be from a podcast, potentially a transcript of everything said. While they are the longest pieces found, they do not seem to be articles in the vein of what we would imagine a New York Times article to be.

Conclusions

We sought to answer the question of which sections in the New York Times from January 2024 were the longest per article. The API, which was protected behind an API key, did not provide the individual articles themselves, but had word counts for every piece the paper featured. However, some pieces turned out to be multimedia which did not have word counts.

At first glance, news desk and section individually showed that magazine articles were the most verbose with over 2000 words on average. After further analysis, we found that pieces under OpEd and Podcasts were 5 times the word count of magazines. Depending on interpretation, either result can be seen as the answer to our question of the wordiest article. (OpEd, Podcasts) was the longest section of any news desk we found in our data. An honorable mention can be given to (SundayBusiness, Technology) as the lone article in the data had the second highest word count. Finally, magazine articles within the magazine news desk were consistently the longest articles without the caveats of these other sections.

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgOSAtIFdlYiBBUElzIg0KYXV0aG9yOiAiTGF3cmVuY2UgWXUiDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydA0KLS0tDQoNCmBgYHtyIGxvYWQtcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkob3BlbmludHJvKQ0KbGlicmFyeShqc29ubGl0ZSkNCmxpYnJhcnkoc3RyaW5naSkNCmxpYnJhcnkoaHR0cikNCmBgYA0KDQojIyMgT3ZlcnZpZXcNCg0KQVBJcyBhcmUgYSBjb21tb24gc291cmNlIG9mIGRhdGEsIGVzcGVjaWFsbHkgaW4gY2FzZXMgd2hlcmUgdGhlIGRhdGEgY291bGQgY2hhbmdlIGF0IGFueSB0aW1lIHN1Y2ggYXMgdGhlIG1vc3QgcmVjZW50IG5ld3MuIFRoZSBOZXcgWW9yayBUaW1lcyBwcm92aWRlcyBmcmVlIGFjY2VzcyB0byBjZXJ0YWluIEFQSXMsIGJ1dCByZXF1aXJlIHRoYXQgZWFjaCBkZXZlbG9wZXIgdXNlIHRoZWlyIG93biBBUEkga2V5LiBUb2RheSB3ZSB3ZSB3aWxsIGdvIG92ZXIgdGhlIHByb2Nlc3Mgb2YgcHJvY3VyaW5nIGFuZCBBUEkga2V5IGFuZCB1c2luZyBpdCB0byBnZXQgZGF0YSB3aGljaCB3ZSBjYW4gdXNlIGFzIGEgZGF0YWZyYW1lLiBUaGVuIHdlIHdpbGwgYXR0ZW1wdCB0byBhbnN3ZXIgdGhlIHF1ZXN0aW9uOiB3aGljaCBOZXcgWW9yayBUaW1lcyBuZXdzIHNlY3Rpb25zIGNvbnRhaW4gYXJ0aWNsZXMgd2l0aCB0aGUgbW9zdCB3b3JkcyBpbiBKYW51YXJ5IDIwMjQ/DQoNCiMjIyBMb2FkIGRhdGEgZnJvbSBBUEkNCg0KUmV0cmlldmUgdGhlIEFQSSBrZXkgZnJvbSB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzLiBVc2luZyB0aGUgY29tYmluZWQgVVJMLCBjYWxsIHRoZSBOWSBUaW1lcyBBUEkuDQpgYGB7ciBnZXQtbnl0LWRhdGF9DQpueXRfYXBpX2Jhc2UgPC0gJ2h0dHBzOi8vYXBpLm55dGltZXMuY29tL3N2Yy90b3BzdG9yaWVzL3YyLycNCnJlYWRSZW52aXJvbignLmVudicpDQpueXRfYXBpX2tleSA8LSBTeXMuZ2V0ZW52KCdueXRfYXBpX2tleScpDQphcmNoaXZlX3VybCA8LSBwYXN0ZTAoJ2h0dHBzOi8vYXBpLm55dGltZXMuY29tL3N2Yy9hcmNoaXZlL3YxLzIwMjQvMS5qc29uP2FwaS1rZXk9Jywgbnl0X2FwaV9rZXkpDQphcmNoaXZlX2RhdGEgPC0gR0VUKGFyY2hpdmVfdXJsKQ0KYXJjaGl2ZV9kYXRhDQpgYGANCg0KIyMjIEJ1aWxkIERhdGFmcmFtZQ0KDQpUaGUgcmF3IGRhdGEgZnJvbSBOWSBUaW1lcyBpcyBzdXBwb3NlZGx5IGEgSlNPTiBhY2NvcmRpbmcgdG8gdGhlIFVSTC4gSG93ZXZlciwgaXQgcmVxdWlyZXMgc29tZSBkYXRhIHdyYW5nbGluZyB0byB1c2UuIEZvciB0b2RheSdzIHF1ZXN0aW9uLCB3ZSB3aWxsIHdhbnQgdGhlIHRvdGFsIHdvcmQgY291bnRzIGZvciBlYWNoIHdlYiBwYWdlLiBXZSB3aWxsIGFsc28gZXh0cmFjdCB0aGUgYWJzdHJhY3QgYW5kIFVSTCB0byBoZWxwIHZlcmlmeSB0aGUgaW5mb3JtYXRpb24gZm91bmQuIFRoZSBrZXlzICJuZXdzX2Rlc2siIGFuZCAic2VjdGlvbl9uYW1lIiBib3RoIGFwcGVhciB0byBiZSBjYXRlZ29yaWVzLCBzbyB3ZSdsbCBrZWVwIGJvdGggdG8gY2hlY2sgd2hpY2ggb25lIHByb3ZpZGVzIHdoYXQgd2Ugd2FudC4NCg0KYGBge3IgbWFrZS1ueXQtZGZ9DQpwYXJzZWQgPC0gY29udGVudChhcmNoaXZlX2RhdGEsICdwYXJzZWQnKQ0KcmVzcG9uc2VfYm9keSA8LSBwYXJzZWQkcmVzcG9uc2UkZG9jcw0KYWJzdHJhY3RzIDwtIGMoKQ0Kd29yZF9jb3VudHMgPC0gYygpDQpuZXdzX2Rlc2tzIDwtIGMoKQ0Kd2ViX3VybHMgPC0gYygpDQpkb2N1bWVudF90eXBlcyA8LSBjKCkNCnNlY3Rpb25zIDwtIGMoKQ0KDQpmb3IgKGVudHJ5IGluIHJlc3BvbnNlX2JvZHkpIHsNCiAgYWJzdHJhY3QgPC0gZW50cnlbJ2Fic3RyYWN0J10NCiAgYWJzdHJhY3RzIDwtIGFwcGVuZChhYnN0cmFjdHMsIGFic3RyYWN0KQ0KICBjb3VudCA8LSBlbnRyeVsnd29yZF9jb3VudCddDQogIHdvcmRfY291bnRzIDwtIGFwcGVuZCh3b3JkX2NvdW50cywgY291bnQpDQogIG5ld3NfZGVzayA8LSBlbnRyeVsnbmV3c19kZXNrJ10NCiAgbmV3c19kZXNrcyA8LSBhcHBlbmQobmV3c19kZXNrcywgbmV3c19kZXNrKQ0KICB3ZWJfdXJsIDwtIGVudHJ5Wyd3ZWJfdXJsJ10NCiAgd2ViX3VybHMgPC0gYXBwZW5kKHdlYl91cmxzLCB3ZWJfdXJsKQ0KICBkb2N1bWVudF90eXBlIDwtIGVudHJ5Wydkb2N1bWVudF90eXBlJ10NCiAgZG9jdW1lbnRfdHlwZXMgPC0gYXBwZW5kKGRvY3VtZW50X3R5cGVzLCBkb2N1bWVudF90eXBlKQ0KICBzZWN0aW9uIDwtIGVudHJ5WydzZWN0aW9uX25hbWUnXQ0KICBzZWN0aW9ucyA8LSBhcHBlbmQoc2VjdGlvbnMsIHNlY3Rpb24pDQp9DQpueXRfZGYgPC0gZGF0YS5mcmFtZSgNCiAgYWJzdHJhY3QgPSB1bmxpc3QoYWJzdHJhY3RzLCB1c2UubmFtZXMgPSBGQUxTRSksDQogIHdvcmRfY291bnQgPSB1bmxpc3Qod29yZF9jb3VudHMsIHVzZS5uYW1lcyA9IEZBTFNFKSwNCiAgbmV3c19kZXNrID0gdW5saXN0KG5ld3NfZGVza3MsIHVzZS5uYW1lcyA9IEZBTFNFKSwNCiAgd2ViX3VybCA9IHVubGlzdCh3ZWJfdXJscywgdXNlLm5hbWVzID0gRkFMU0UpLA0KICBkb2N1bWVudF90eXBlID0gdW5saXN0KGRvY3VtZW50X3R5cGVzLCB1c2UubmFtZXMgPSBGQUxTRSksDQogIHNlY3Rpb24gPSB1bmxpc3Qoc2VjdGlvbnMsIHVzZS5uYW1lcyA9IEZBTFNFKQ0KKQ0KaGVhZChueXRfZGYpDQpgYGANCg0KIyMjIFBlcmZvcm0gQW5hbHlzaXMNCg0KUHV0IHRvZ2V0aGVyIGEgc3VtbWFyeSBvZiB0aGUgYXZlcmFnZSB3b3JkIGNvdW50IHBlciBhcnRpY2xlIGFuZCBzdW1tYXJpZXMgZm9yIGJvdGggbmV3cyBkZXNrcyBhbmQgc2VjdGlvbnMuDQoNCmBgYHtyIGFuYWx5c2lzfQ0Kc3VtbWFyeShueXRfZGYpDQpueXRfZGYgJT4lIGZpbHRlcihuZXdzX2Rlc2sgIT0gJycpICU+JSBncm91cF9ieShuZXdzX2Rlc2spICU+JSBzdW1tYXJpc2UoYWNyb3NzKHdvcmRfY291bnQsIG1lYW4sIG5hLnJtID0gVFJVRSkpICU+JSBhcnJhbmdlKGRlc2Mod29yZF9jb3VudCkpDQpueXRfZGYgICU+JSBncm91cF9ieShzZWN0aW9uKSAlPiUgc3VtbWFyaXNlKGFjcm9zcyh3b3JkX2NvdW50LCBtZWFuLCBuYS5ybSA9IFRSVUUpKSAlPiUgYXJyYW5nZShkZXNjKHdvcmRfY291bnQpKQ0KYGBgDQoNCkFjY29yZGluZyB0byB0aGUgc3VtbWFyeSwgdGhlIGF2ZXJhZ2Ugd29yZCBjb3VudCBpbiB0aGUgZnVsbCBkYXRhc2V0IGlzIDkyMS4gTWFnYXppbmVzIGFyZSB0aGUgd29yZGllc3QgbmV3cyBkZXNrcyBhbmQgc2VjdGlvbnMgYXQgYXJvdW5kIDIzOTkgd29yZHMgcGVyIGFydGljbGUuIEhvd2V2ZXIsIHRoZXJlIGFyZSBhIG51bWJlciBvZiBuZXdzIGRlc2tzIGFuZCBzZWN0aW9ucyB3aXRoIDAgd29yZCBjb3VudHMuIExldCdzIHNlZSBpZiB0aGVyZSdzIGEgcGF0dGVybiByZWdhcmRpbmcgdGhvc2UuDQoNCkNvbnRpbnVpbmcgd2l0aCB0aGUgc3VtbWFyaWVzLCB3ZSBjYW4gYWxzbyBncm91cCBieSBkb2N1bWVudCB0eXBlLg0KYGBge3IgZG9jLXR5cGV9DQpueXRfZGYgJT4lIGdyb3VwX2J5KGRvY3VtZW50X3R5cGUpICU+JSBzdW1tYXJpc2UoYWNyb3NzKHdvcmRfY291bnQsIG1lYW4sIG5hLnJtID0gVFJVRSkpICU+JSBhcnJhbmdlKGRlc2Mod29yZF9jb3VudCkpDQpgYGANCkFjY29yZGluZyB0byBkb2N1bWVudF90eXBlLCBzb21lIG9mIHRoZSBtZWRpYSBhcmUgYXJ0aWNsZXMgYW5kIG90aGVycyBhcmUgbXVsdGltZWRpYS4gTXVsdGltZWRpYSByZXN1bHRzIGFsd2F5cyBoYXZlIGEgd29yZCBjb3VudCBvZiAwLg0KDQpOZXh0LCBsZXQncyBjb2xsZWN0IG1lYW4gYW5kIG1lZGlhbiB3b3JkIGNvdW50cyBmb3IgZWFjaCBuZXdzIGRlc2sgYW5kIHNlY3Rpb24gY29tYmluYXRpb24uIEZyb20gd2hhdCB3ZSd2ZSBzZWVuLCByZW1vdmluZyByZXN1bHRzIHdpdGggMCB3b3JkIGNvdW50cyBzaG91bGQgbm90IGFmZmVjdCB0aGUgaGlnaGVzdCB3b3JkIGNvdW50IHRvdGFscy4gV2UgZXhwZWN0IChNYWdhemluZSwgTWFnYXppbmUpIHRvIGJlIHRoZSBtb3N0IGNvbW1vbiAobmV3cyBkZXNrLCBzZWN0aW9uKSBjb21iaW5hdGlvbi4NCmBgYHtyfQ0KY29tYm9fZGYgPC0gbnl0X2RmICU+JSANCiAgZmlsdGVyKHdvcmRfY291bnQgPiAwKSAlPiUgDQogIGdyb3VwX2J5KG5ld3NfZGVzaywgc2VjdGlvbikgJT4lIA0KICBzdW1tYXJpc2UobWVhbiA9IG1lYW4od29yZF9jb3VudCwgbmEucm0gPSBUUlVFKSwgDQogICAgICAgICAgICBtZWRpYW4gPSBtZWRpYW4od29yZF9jb3VudCwgbmEucm0gPSBUUlVFKSkgJT4lICAgDQogIGFycmFuZ2UoZGVzYyhtZWFuKSkNCmNvbWJvX2RmDQpgYGANCg0KVGhpcyBpcyBhIHBlY3VsaWFyIHJlc3VsdCBjb25zaWRlcmluZyB3aGF0IHdlIGhhZCBwcmV2aW91c2x5IGVzdGFibGlzaGVkLiBUaGUgY29tYmluYXRpb24gKE1hZ2F6aW5lLCBNYWdhemluZSkgaGFzIGEgY29tcGFyYWJsZSBtZWFuIHRvIGVhY2ggaW5kaXZpZHVhbCB3b3JkIGNvdW50IGZyb20gcHJldmlvdXMgYW5hbHlzZXMuIEhvd2V2ZXIsIHRoZSBtZWRpYW4gaXMgZmFyIGJlbG93IHRoZSBtZWFuLiBGdXJ0aGVybW9yZSwgKE9wRWQsIFBvZGNhc3RzKSBoYXMgYm90aCB0aGUgaGlnaGVzdCBtZWFuIGFuZCBtZWRpYW4gYnkgYSB3aWRlIG1hcmdpbi4gVGhlIGNvbWJpbmF0aW9uIChTdW5kYXlCdXNpbmVzcywgVGVjaG5vbG9neSkgaXMgYW5vdGhlciBzdXJwcmlzZSBpbmNyZWFzZS4gDQoNCldlIGNhbiBkbyBhIGNoZWNrIG9mIGhvdyBPcEVkIGlzIHNwbGl0IHRvIHNlZSBpZiB0aGVyZSBpcyBhbnkgaXJyZWd1bGFyaXR5IGluIGl0cyByZXN1bHRzLg0KYGBge3J9DQpueXRfZGYgJT4lIA0KICBmaWx0ZXIobmV3c19kZXNrICVpbiUgYygnT3BFZCcsICdTdW5kYXlCdXNpbmVzcycsICdNYWdhemluZScpKSAlPiUgDQogIGNvdW50KG5ld3NfZGVzaywgc2VjdGlvbikgJT4lIGFycmFuZ2UoZGVzYyhuKSkNCiAgDQpgYGANCg0KKE9wRWQsIE9waW5pb24pIGlzIGEgZmFyIG1vcmUgZnJlcXVlbnQgY29tYmluYXRpb24uIFdoaWxlIHRoaXMgZG9lcyBub3QgY2hhbmdlIHRoZSBmYWN0IHRoYXQgKE9wRWQsIFBvZGNhc3RzKSB3ZXJlIG9uIGF2ZXJhZ2UgdGhlIHdvcmRpZXN0IGluIHRoaXMgZGF0YXNldCwgKE1hZ2F6aW5lLCBNYWdhemluZSkgYXJ0aWNsZXMgYXJlIGZhciBtb3JlIGNvbW1vbiB0byBmaW5kIGFuZCBhcmUgdXN1YWxseSBnb2luZyB0byBiZSBsb25nLiBBdCBhIG1lcmUgc2luZ2xlIG9jY3VycmVuY2UsIChTdW5kYXlCdXNpbmVzcywgVGVjaG5vbG9neSkgc2VlbXMgdG8gYmUgYW4gZXhjZXB0aW9uIGluIG91ciBkYXRhLg0KDQpPbmUgbW9yZSBleWUgdGVzdCB3ZSBjYW4gcGVyZm9ybSBpcyB0byB0cnkgYW5kIGZpZ3VyZSBvdXQgd2h5IChPcEVkLCBQb2RjYXN0cykgd2VyZSBzbyBsb25nLiBXZSBkbyBub3QgaGF2ZSBhY2Nlc3MgdG8gdGhlIGFydGljbGVzIHRoZW1zZWx2ZXMsIGJ1dCB3aXRoIHRoZSBhYnN0cmFjdHMgdGhhdCB3ZSBoYWQgY29sbGVjdGVkIGVhcmxpZXIsIHdlIGNhbiBmaW5hbGx5IGV4YW1pbmUgdGhlbSB0byBnZXQgYSBnaXN0IG9mIHdoYXQgdGhlc2UgcGllY2Ugd2VyZSBhYm91dC4NCg0KYGBge3J9DQpueXRfZGYgJT4lIGZpbHRlcihuZXdzX2Rlc2sgPT0gJ09wRWQnICYgc2VjdGlvbiA9PSAnUG9kY2FzdHMnKSAlPiUgc2VsZWN0KGFic3RyYWN0KQ0KYGBgDQoNCkV2ZXJ5IHJlc3VsdCB3YXMgZnJvbSBzb21lb25lIG5hbWVkIEV6cmEgS2xlaW4uIFRoZXNlIHBpZWNlcyBhcHBlYXIgdG8gYmUgZnJvbSBhIHBvZGNhc3QsIHBvdGVudGlhbGx5IGEgdHJhbnNjcmlwdCBvZiBldmVyeXRoaW5nIHNhaWQuIFdoaWxlIHRoZXkgYXJlIHRoZSBsb25nZXN0IHBpZWNlcyBmb3VuZCwgdGhleSBkbyBub3Qgc2VlbSB0byBiZSBhcnRpY2xlcyBpbiB0aGUgdmVpbiBvZiB3aGF0IHdlIHdvdWxkIGltYWdpbmUgYSBOZXcgWW9yayBUaW1lcyBhcnRpY2xlIHRvIGJlLiANCg0KIyMjIENvbmNsdXNpb25zDQoNCldlIHNvdWdodCB0byBhbnN3ZXIgdGhlIHF1ZXN0aW9uIG9mIHdoaWNoIHNlY3Rpb25zIGluIHRoZSBOZXcgWW9yayBUaW1lcyBmcm9tIEphbnVhcnkgMjAyNCB3ZXJlIHRoZSBsb25nZXN0IHBlciBhcnRpY2xlLiBUaGUgQVBJLCB3aGljaCB3YXMgcHJvdGVjdGVkIGJlaGluZCBhbiBBUEkga2V5LCBkaWQgbm90IHByb3ZpZGUgdGhlIGluZGl2aWR1YWwgYXJ0aWNsZXMgdGhlbXNlbHZlcywgYnV0IGhhZCB3b3JkIGNvdW50cyBmb3IgZXZlcnkgcGllY2UgdGhlIHBhcGVyIGZlYXR1cmVkLiBIb3dldmVyLCBzb21lIHBpZWNlcyB0dXJuZWQgb3V0IHRvIGJlIG11bHRpbWVkaWEgd2hpY2ggZGlkIG5vdCBoYXZlIHdvcmQgY291bnRzLiANCg0KQXQgZmlyc3QgZ2xhbmNlLCBuZXdzIGRlc2sgYW5kIHNlY3Rpb24gaW5kaXZpZHVhbGx5IHNob3dlZCB0aGF0IG1hZ2F6aW5lIGFydGljbGVzIHdlcmUgdGhlIG1vc3QgdmVyYm9zZSB3aXRoIG92ZXIgMjAwMCB3b3JkcyBvbiBhdmVyYWdlLiBBZnRlciBmdXJ0aGVyIGFuYWx5c2lzLCB3ZSBmb3VuZCB0aGF0IHBpZWNlcyB1bmRlciBPcEVkIGFuZCBQb2RjYXN0cyB3ZXJlIDUgdGltZXMgdGhlIHdvcmQgY291bnQgb2YgbWFnYXppbmVzLiBEZXBlbmRpbmcgb24gaW50ZXJwcmV0YXRpb24sIGVpdGhlciByZXN1bHQgY2FuIGJlIHNlZW4gYXMgdGhlIGFuc3dlciB0byBvdXIgcXVlc3Rpb24gb2YgdGhlIHdvcmRpZXN0IGFydGljbGUuIChPcEVkLCBQb2RjYXN0cykgd2FzIHRoZSBsb25nZXN0IHNlY3Rpb24gb2YgYW55IG5ld3MgZGVzayB3ZSBmb3VuZCBpbiBvdXIgZGF0YS4gQW4gaG9ub3JhYmxlIG1lbnRpb24gY2FuIGJlIGdpdmVuIHRvIChTdW5kYXlCdXNpbmVzcywgVGVjaG5vbG9neSkgYXMgdGhlIGxvbmUgYXJ0aWNsZSBpbiB0aGUgZGF0YSBoYWQgdGhlIHNlY29uZCBoaWdoZXN0IHdvcmQgY291bnQuIEZpbmFsbHksIG1hZ2F6aW5lIGFydGljbGVzIHdpdGhpbiB0aGUgbWFnYXppbmUgbmV3cyBkZXNrIHdlcmUgY29uc2lzdGVudGx5IHRoZSBsb25nZXN0IGFydGljbGVzIHdpdGhvdXQgdGhlIGNhdmVhdHMgb2YgdGhlc2Ugb3RoZXIgc2VjdGlvbnMuDQoNCg0KDQo=