Full Code of sewardlee337/finreportr for AI

master 81b7cc2f2a12 cached
28 files
39.6 KB
11.4k tokens
1 requests
Download .txt
Repository: sewardlee337/finreportr
Branch: master
Commit: 81b7cc2f2a12
Files: 28
Total size: 39.6 KB

Directory structure:
gitextract_ethd7a8s/

├── .Rbuildignore
├── .gitignore
├── .travis.yml
├── DESCRIPTION
├── LICENSE
├── NAMESPACE
├── R/
│   ├── annual_reports.R
│   ├── backend_utilities.R
│   ├── company_info.R
│   ├── data.R
│   ├── get_balance_sheet.R
│   ├── get_cash_flow.R
│   ├── get_financial.R
│   └── get_income.R
├── README.md
├── data/
│   ├── siccodes.rda
│   └── statecodes.rda
├── finreportr.Rproj
├── man/
│   ├── AnnualReports.Rd
│   ├── CompanyInfo.Rd
│   ├── GetBalanceSheet.Rd
│   ├── GetCashFlow.Rd
│   ├── GetIncome.Rd
│   ├── siccodes.Rd
│   └── statecodes.Rd
├── tests/
│   ├── testthat/
│   │   └── test.R
│   └── testthat.R
└── vignettes/
    └── finreportr.Rmd

================================================
FILE CONTENTS
================================================

================================================
FILE: .Rbuildignore
================================================
^.*\.Rproj$
^\.Rproj\.user$
^\.travis\.yml$
^cran-comments\.md$
^CRAN-RELEASE$


================================================
FILE: .gitignore
================================================
inst/doc
.Rproj.user
.Rhistory
cran-comments.md

================================================
FILE: .travis.yml
================================================
# Sample .travis.yml for R projects

language: r
warnings_are_errors: true
sudo: required


================================================
FILE: DESCRIPTION
================================================
Package: finreportr
Type: Package
Title: Financial Data from U.S. Securities and Exchange Commission
Version: 1.0.4
Date: 2022-01-16
Author: Seward Lee
Maintainer: Seward Lee <sewardlee337@gmail.com>
Description: Download and display company financial data from the U.S. Securities
    and Exchange Commission's EDGAR database. It contains a suite of functions with
    web scraping and XBRL parsing capabilities that allows users to extract data from EDGAR 
    in an automated and scalable manner. See <https://www.sec.gov/edgar/searchedgar/companysearch.html>
    for more information.
Depends: R (>= 2.10)
Imports: xml2,
    dplyr,
    httr,
    rvest,
    XBRL,
    curl
License: MIT + file LICENSE
LazyData: true
URL: https://github.com/sewardlee337/finreportr
BugReports: https://github.com/sewardlee337/finreportr/issues
RoxygenNote: 7.1.0
Suggests: knitr,
    rmarkdown,
    testthat
VignetteBuilder: knitr


================================================
FILE: LICENSE
================================================
YEAR: 2021
COPYRIGHT HOLDER: Seward Lee

================================================
FILE: NAMESPACE
================================================
# Generated by roxygen2: do not edit by hand

export(AnnualReports)
export(CompanyInfo)
export(GetBalanceSheet)
export(GetCashFlow)
export(GetIncome)
import(curl)
import(dplyr)


================================================
FILE: R/annual_reports.R
================================================
#' Acquire listing of company annual reports.
#' 
#' Extracts and displays listing of annual reports filed by a company in a data frame.
#' 
#' @export
#' @import dplyr
#' @param symbol A character vector specifying the stock symbol of the company of interest.
#' @param foreign A logical vector indicating whether the company is domestic or foreign. \code{foreign = FALSE} by default.
#' @examples
#' \dontrun{
#' AnnualReports("TSLA")
#' AnnualReports("BABA", foreign = TRUE)
#' }

AnnualReports <- function(symbol, foreign = FALSE) {
     
     options(stringsAsFactors = FALSE)
     
     if(foreign == FALSE) {
          url <- paste0("http://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=", 
                        symbol, "&type=10-k&dateb=&owner=exclude&count=100")
     } else {
          url <- paste0("http://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=", 
                        symbol, "&type=20-f&dateb=&owner=exclude&count=100")
     }
     
     filings <- xml2::read_html(url)
     
     ##   Generic function to extract info
     ExtractInfo <- function(html.node) {
          info <-
               filings %>%
               rvest::html_nodes(html.node) %>%
               rvest::html_text()
          return(info)
     }
     
     ##   Acquire filing name
     filing.name <- ExtractInfo("#seriesDiv td:nth-child(1)")
     
     ##   Error message for function
     if(length(filing.name) == 0) {
          stop("invalid company symbol or foreign logical")
     }
     
     ##   Acquire filing date
     filing.date <- ExtractInfo(".small+ td")
     
     ##   Acquire accession number
     accession.no.raw <- ExtractInfo(".small")
     
     accession.no <-
          gsub("^.*Acc-no: ", "", accession.no.raw) %>%
          substr(1, 20)
     
     ##   Create dataframe
     info.df <- data.frame(filing.name = filing.name, filing.date = filing.date, 
                           accession.no = accession.no)
     return(info.df)
}

================================================
FILE: R/backend_utilities.R
================================================
#' @import dplyr

################################################################################
#####     Backend Utility: Extract Accession No                            #####
################################################################################


GetAccessionNo <- function(symbol, year, foreign = FALSE) {
     
     ##   This is here to please R CMD check
     filing.year <- NULL
     filing.name <- NULL
     accession.no <- NULL
     
     year.char <- as.character(year)
     
     reports.df <- AnnualReports(symbol, foreign)
     reports.df <-
          mutate(reports.df, filing.year = substr(reports.df$filing.date,1,4) ) %>%
          filter(filing.year == year.char) %>%
          filter(filing.name == "10-K" | filing.name == "20-F")
     
     accession.no.raw <-
          select(reports.df, accession.no) %>%
          as.character()
     
     ##   Error message for function
     if(accession.no.raw == "character(0)") {
          stop("no filings available for given year")
     }
     
     return(accession.no.raw)
}

################################################################################
#####     Backend Utility: Extract Period of Report                        #####
################################################################################


ReportPeriod <- function(symbol, CIK, accession.no, accession.no.raw) {
     
     url <- paste0("https://www.sec.gov/Archives/edgar/data/", CIK, "/", 
                   accession.no, "/", accession.no.raw, "-index.htm")
     search.result <- xml2::read_html(url)
     
     ##   Generic function to extract info
     ExtractInfo <- function(html.node) {
          info <-
               search.result %>%
               rvest::html_nodes(html.node) %>%
               rvest::html_text()
          return(info)
     }
     
     report.period <- ExtractInfo(".formGrouping+ .formGrouping .info:nth-child(2)")
     return(report.period)
}

================================================
FILE: R/company_info.R
================================================
#' Acquire basic company information.
#' 
#' Extracts and displays basic information relating to a given company in a data frame.
#' 
#' @export
#' @import dplyr
#' @param symbol A character vector specifying the stock symbol of the company of interest.
#' @examples
#' \dontrun{
#' CompanyInfo("GOOG")
#' CompanyInfo("TSLA")
#' }

CompanyInfo <- function(symbol) {
     
     options(stringsAsFactors = FALSE)
     
     url <- paste0("https://www.sec.gov/cgi-bin/browse-edgar?CIK=", symbol,
                   "&owner=exclude&action=getcompany&Find=Search")
     search.result <- xml2::read_html(url)
     
     ##   Generic function to extract info
     ExtractInfo <- function(html.node) {
          info <-
               search.result %>%
               rvest::html_nodes(html.node) %>%
               rvest::html_text()
          return(info)
     }
     
     ##   Acquire company name string
     company.name.raw <-
          ExtractInfo(".companyName") %>%
          strsplit(" CIK")
     
     ##   Error message for function
     if(length(company.name.raw) == 0) {
          stop("invalid company symbol")
     }
     
     ##   Parse company name string
     company.name <- company.name.raw[[1]][1]
     
     ##   Acquire CIK number
     CIK.raw <-
          ExtractInfo(".companyName a") %>%
          strsplit(" ")
     
     CIK <- CIK.raw[[1]][1]
     
     ##   Acquire SIC code
     SIC <- ExtractInfo(".identInfo acronym+ a")
     
     ##   Acquire street address
     street.address <- ExtractInfo(".mailer:nth-child(1) .mailerAddress:nth-child(1)")
     
     ##   Acquire city, state, ZIP
     city.state.raw <- ExtractInfo(".mailer:nth-child(1) .mailerAddress+ .mailerAddress")
     city.state <- sub("\\s+$", "", city.state.raw)
     city.state <- gsub("\n", "", city.state)
     
     ##   Fix problems associated with multiple street address lines
     if(length(city.state) == 2){
          street.address <- paste(street.address, city.state[1])
          city.state <- city.state[2]
     }
     
     ##   Acquire fiscal year end
     company.details <-
          ExtractInfo(".identInfo")
     
     fiscal.year.end <-
          gsub("^.*Fiscal Year End: ", "", company.details) %>%
          substr(1,4)
     
     if(fiscal.year.end == "SIC:"){fiscal.year.end <- NA}      ## Fix in case no fiscal year displayed
     
     ##   Acquire state location
     state <-
          gsub("^.*State location: ", "", company.details) %>%
          substr(1,2)
     
     ##   Acquire state of incorporation
     state.inc <-
          gsub("^.*State of Inc.: ", "", company.details) %>%
          substr(1,2)
     
     if(state.inc == "SI"){state.inc <- NA}       ## Fix in case no incorporation year displayed
     
     ##   Create dataframe
     info.df <- data.frame(company = company.name, CIK = CIK, SIC = SIC, 
                           state = state, state.inc = state.inc, 
                           FY.end = fiscal.year.end, 
                           street.address = street.address, city.state = city.state)
     return(info.df)
}

================================================
FILE: R/data.R
================================================
#' Standard Industrial Classification Code List
#' 
#' A dataset containing SIC codes and industries that they represent
#'
#' @format A data frame with 444 rows and 2 variables:
#' \itemize{
#'   \item SIC: Standard Industrial Classification Code
#'   \item industry: Industry Title
#' }
#'  
#' @source \url{https://www.sec.gov/info/edgar/siccodes.htm}
"siccodes"

#' EDGAR State and Country Codes
#' 
#' A dataset containing state and country codes used in the SEC EDGAR database.
#' 
#' @format A data frame with 310 rows and 2 variables:
#'  \itemize{
#'   \item state: State or Country Code
#'   \item state.name: State or Country Name
#' }
#' 
#' @source \url{https://www.sec.gov/edgar/searchedgar/edgarstatecodes.htm}
"statecodes"

================================================
FILE: R/get_balance_sheet.R
================================================
#' Acquire balance sheet.
#' 
#' Extracts and displays balance sheet from the annual report of a given company. 
#' This functionality is only available for queries fo balance sheets that belong to domestic companies. 
#' Note that all data returned by this function comes from the company's Form 10-K, not Form 10-K/A.
#' 
#' @export
#' @param symbol A character vector specifying the stock symbol of the company of interest.
#' @param year A numeric vector specifying the year during which the annual report was filed.
#' @examples 
#' \dontrun{
#' GetBalanceSheet("FB", 2016)
#' }

GetBalanceSheet <- function(symbol, year) {
     
     balance.sheet.descriptions <- c("CONSOLIDATED BALANCE SHEET", 
                                     "CONSOLIDATED BALANCE SHEETS", 
                                     "CONSOLIDATED STATEMENT OF FINANCIAL POSITION", 
                                     "CONSOLIDATED STATEMENTS OF FINANCIAL POSITION",
                                     "BALANCE SHEETS",
                                     "CONSOLIDATED FINANCIAL POSITION")
     
     GetFinancial(balance.sheet.descriptions, symbol, year)
}



================================================
FILE: R/get_cash_flow.R
================================================
#' Acquire statement of cash flow.
#' 
#' Extracts and displays statement of cash flow from the annual report of a given company. 
#' This functionality is only available for queries of cash flow statements that belong to domestic company. 
#' Note that all data returned by this function comes from the company's Form 10-K, not Form 10-K/A.
#' 
#' @export
#' @param symbol A character vector specifying the stock symbol of the company of interest.
#' @param year A numeric vector specifying the year during which the annual report was filed.
#' @examples 
#' \dontrun{
#' GetCashFlow("FB", 2016)
#' }


GetCashFlow <- function(symbol, year) {
     
     cash.flow.descriptions <- c("CONSOLIDATED STATEMENT OF CASH FLOWS", 
                                 "CONSOLIDATED STATEMENTS OF CASH FLOWS",
                                 "CASH FLOWS STATEMENTS",
                                 "CONSOLIDATED STATEMENT OF CASH FLOW")
     
     GetFinancial(cash.flow.descriptions, symbol, year)
     
}

================================================
FILE: R/get_financial.R
================================================
#' @import dplyr curl

GetFinancial <- function(statement.type, symbol, year) {
     
     ##   This is here to please R CMD check
     description <- NULL
     roleId <- NULL
     labelRole <- NULL
     labelString <- NULL
     unitId <- NULL
     fact <- NULL
     contextId <- NULL
     startDate <- NULL
     endDate <- NULL
     
     ##   Function to acquire Instance Document URL
     GetURL <- function(symbol, year) {
          
          lower.symbol <- tolower(symbol)
          
          accession.no.raw <- GetAccessionNo(symbol, year, foreign = FALSE)
          accession.no <- gsub("-", "" , accession.no.raw)
          
          CIK <- CompanyInfo(symbol)
          CIK <- as.numeric(CIK$CIK)
          
          report.period <- ReportPeriod(symbol, CIK, accession.no, accession.no.raw)
          report.period <- gsub("-", "" , report.period)
          
          inst.url <- paste0("https://www.sec.gov/Archives/edgar/data/", CIK, "/", 
                             accession.no, "/", lower.symbol, "-", report.period, ".xml")
          return(inst.url)
     }
     
     
     ##   Function to download Instance Document
     GetInstFile <- function(url) {
          XBRL::xbrlDoAll(url, cache.dir="XBRLcache", prefix.out ="out", verbose=FALSE)
     }
     
     inst.url <- GetURL(symbol, year)
     
     ##   Check if url exits
     
     check <- tryCatch(is.list(httr::GET(inst.url)), error = function(e) {return(FALSE)})
     if(check == FALSE) {
          stop("no XBRL-format filings detected")
     }
     
     ##   Download Instance Document
     instFile <- GetInstFile(inst.url)
     
     ##   Clear Cache Dir
     file.remove("out_calculations.csv", "out_contexts.csv", "out_definitions.csv", 
                 "out_elements.csv", "out_facts.csv", "out_footnotes.csv", 
                 "out_labels.csv", "out_presentations.csv", "out_roles.csv", "out_units.csv")
     
     unlink("XBRLcache", recursive = TRUE)
     
     ##   Get Role ID from Instance Document
     role.df <- instFile$role %>%
          filter(toupper(description) %in% statement.type)

     role.id <- as.character(role.df$roleId)

     ##   Create statement template from Presentation Linkbase
     statement.skeleton <-
          instFile$presentation %>%
          filter(roleId == role.id)

     rowid <- c(1:nrow(statement.skeleton))
     statement.skeleton <- mutate(statement.skeleton, rowid = rowid)

     ##   Merge with Label Linkbase
     statement <-
          merge(statement.skeleton, instFile$label, by.x = "toElementId", 
                by.y = "elementId") %>%
          filter(labelRole == "http://www.xbrl.org/2003/role/label")

     ##   Merge with Fact Linkbase
     statement <- merge(statement, instFile$fact, by.x = "toElementId", 
                        by.y = "elementId")

     ##   Merge with Context Linkbase
     statement <- merge(statement, instFile$context, by.x = "contextId", 
                        by.y = "contextId") %>%
          arrange(rowid)

     ##   Clean combined table
     statement <- subset(statement, is.na(statement$dimension1))

     clean.statement <- select(statement, labelString, unitId, fact, contextId, 
                               startDate, endDate, rowid)
     clean.statement <- select(clean.statement, -contextId)

     colnames(clean.statement)[1] <- "Metric"
     colnames(clean.statement)[2] <- "Units"
     colnames(clean.statement)[3] <- "Amount"

     clean.statement <- arrange(clean.statement, rowid)
     clean.statement <- select(clean.statement, -rowid)
     return(clean.statement)
}

================================================
FILE: R/get_income.R
================================================
#' Acquire income statement.
#' 
#' Extracts and displays income statement from the annual report of a given company.
#' This functionality is only available for queries of income statements that belong to domestic companies.
#' Note that all data returned by this function comes from the company's 10-K, not 10-K/A.
#' 
#' @export
#' @param symbol A character vector specifying the stock symbol of the company of interest.
#' @param year A numeric vector specifying the year during which the annual report was filed.
#' @examples 
#' \dontrun{
#' GetIncome("FB", 2016)
#' }


GetIncome <- function(symbol, year) {
     
     income.descriptions <- c("CONSOLIDATED STATEMENTS OF INCOME", 
                              "CONSOLIDATED STATEMENT OF INCOME", 
                              "CONSOLIDATED STATEMENTS OF OPERATIONS", 
                              "CONSOLIDATED STATEMENT OF OPERATIONS", 
                              "CONSOLIDATED STATEMENT OF EARNINGS", 
                              "CONSOLIDATED STATEMENTS OF EARNINGS",
                              "INCOME STATEMENTS", 
                              "CONSOLIDATED RESULTS OF OPERATIONS")
     
     GetFinancial(income.descriptions, symbol, year)
}

================================================
FILE: README.md
================================================
[![Travis-CI Build Status](https://travis-ci.org/sewardlee337/finreportr.svg?branch=master)](https://travis-ci.org/sewardlee337/finreportr) [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/finreportr)](https://cran.r-project.org/package=finreportr) ![](http://cranlogs.r-pkg.org/badges/grand-total/finreportr) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.192466.svg)](https://doi.org/10.5281/zenodo.192466)
[![status](http://joss.theoj.org/papers/128c974cac2dcf92b673c66f39a2c93e/status.svg)](https://joss.theoj.org/papers/10.21105/joss.00119) 

# finreportr - Financial Data from U.S. Securities and Exchange Commission

* Author/Maintainer: [Seward Lee](https://github.com/sewardlee337)
* License: [MIT](https://opensource.org/licenses/MIT)

## Introduction

A financial analyst's time is valuable – it shouldn't be wasted performing manual data entry. finreportr is a web scraper written in R that allows analysts to query data from the U.S. Securities and Exchange Commission directly from the R console.  It aims to eliminate time wasters from a financial analyst's workflow, such as navigating the SEC EDGAR database, flipping through financial reports, and parsing XBRL-encoded data.

finreportr allows you to fetch data from the SEC and load it into your workspace using the following commands:
* `CompanyInfo()`: returns basic information about a company
* `AnnualReports()`: returns a listing of annual reports filed by a company
* `GetIncome()`: returns the income statement for a given company
* `GetBalanceSheet()`: returns the balance sheet for a given company
* `GetCashFlow()`: returns the cash flow statement for a given company

To install CRAN release version of finreportr:

```
install.packages("finreportr")
```

To install bleeding-edge version from GitHub:

```
devtools::install_github("sewardlee337/finreportr")
```

## CompanyInfo()

`CompanyInfo()` returns the following information about a given company based on its stock ticker symbol:
* Company Name
* [Central Index Key ("CIK")](https://en.wikipedia.org/wiki/Central_Index_Key)
* [Standard  Industrial Classification ("SIC")](https://en.wikipedia.org/wiki/Standard_Industrial_Classification)
* State Location
* State of Incorporation
* Fiscal Year End (ddmm)
* Street Address
* City, State, ZIP

#### Arguments:

`CompanyInfo(symbol)`

where

* `symbol` is a character string that represents the relevant stock ticker symbol.

#### Examples:

```
> CompanyInfo("GOOG")

      company        CIK  SIC state state.inc FY.end            street.address             city.state
1 GOOGLE INC. 0001288776 7370    CA        DE   1231 1600 AMPHITHEATRE PARKWAY MOUNTAIN VIEW CA 94043


> CompanyInfo("FB")

       company        CIK  SIC state state.inc FY.end   street.address          city.state
1 Facebook Inc 0001326801 7370    CA        DE   1231 1601 WILLOW ROAD MENLO PARK CA 94025
```


## AnnualReports()

`AnnualReports()` returns a dataframe that summarizes a given company's annual reports based on its stock ticker symbol. Information returned include:
* Filing Name
* Filing Date
* Accession Number

`AnnualReports()` will return data relating to a company's [Form 10-Ks](https://www.investopedia.com/terms/1/10-k.asp) if the company is domestic, and [Form 20-Fs](https://www.investopedia.com/terms/s/sec-form-20-f.asp) if the company is foreign. 

#### Arguments:

`AnnualReports(symbol, foreign = FALSE)`

where

* `symbol` is a character string that represents the relevant stock ticker symbol.
* `foreign` is a logical indicating whether the company in question is domestic or foreign.  `foreign` is set to `FALSE` by default.

#### Examples:

```
> AnnualReports("GOOG")

   filing.name filing.date         accession.no
1         10-K  2015-02-09 0001288776-15-000008
2         10-K  2014-02-12 0001288776-14-000020
3         10-K  2013-01-29 0001193125-13-028362
4       10-K/A  2012-04-23 0001193125-12-174477
5         10-K  2012-01-26 0001193125-12-025336
6         10-K  2011-02-11 0001193125-11-032930
7         10-K  2010-02-12 0001193125-10-030774
8         10-K  2009-02-13 0001193125-09-029448
9         10-K  2008-02-15 0001193125-08-032690
10        10-K  2007-03-01 0001193125-07-044494
11        10-K  2006-03-16 0001193125-06-056598
12        10-K  2005-03-30 0001193125-05-065298


> AnnualReports("HTHIY", foreign = TRUE)

   filing.name filing.date         accession.no
1       20-F/A  2011-07-21 0001193125-11-192990
2         20-F  2011-06-24 0001193125-11-172867
3       20-F/A  2010-07-29 0001193125-10-169851
4         20-F  2010-06-29 0001193125-10-149406
5         20-F  2009-07-27 0001193125-09-155317
6         20-F  2008-06-20 0001193125-08-137042
7       20-F/A  2008-04-28 0001193125-08-091853
8       20-F/A  2007-11-30 0001193125-07-256746
9         20-F  2007-06-26 0001193125-07-142357
10        20-F  2006-08-07 0001193125-06-163031
11        20-F  2005-08-26 0001193125-05-174960
12        20-F  2004-08-20 0001193125-04-144223
13        20-F  2003-09-30 0001193125-03-056135
14        20-F  2002-09-26 0001145549-02-000252
```

## GetIncome()

`GetIncome()` returns a company's income statement from the annual report of a given filing year as a dataframe.  This functionality is only available for queries of income statements that belong to domestic companies.  Note that all data returned by this function comes from the company's 10-K, not 10-K/A.

#### Arguments:

`GetIncome(symbol, year)`

where

* `symbol` is a character string that represents the relevant stock ticker symbol.
* `year` is the year during which the annual report was filed. *(Note: This is not necessarily identical to the fiscal year for which the annual report was filed)*

#### Example:

```
###   Fetch first 20 lines of Google's income statement in the Form 10-K published in 2016.

> head(GetIncome("GOOG", 2016), 20)

                               Metric Units      Amount  startDate    endDate
1                            Revenues   usd 55519000000 2013-01-01 2013-12-31
2                            Revenues   usd 66001000000 2014-01-01 2014-12-31
3                            Revenues   usd 74989000000 2015-01-01 2015-12-31
4                     Cost of Revenue   usd 21993000000 2013-01-01 2013-12-31
5                     Cost of Revenue   usd 25691000000 2014-01-01 2014-12-31
6                     Cost of Revenue   usd 28164000000 2015-01-01 2015-12-31
7    Research and Development Expense   usd  7137000000 2013-01-01 2013-12-31
8    Research and Development Expense   usd  9832000000 2014-01-01 2014-12-31
9    Research and Development Expense   usd 12282000000 2015-01-01 2015-12-31
10      Selling and Marketing Expense   usd  6554000000 2013-01-01 2013-12-31
11      Selling and Marketing Expense   usd  8131000000 2014-01-01 2014-12-31
12      Selling and Marketing Expense   usd  9047000000 2015-01-01 2015-12-31
13 General and Administrative Expense   usd  4432000000 2013-01-01 2013-12-31
14 General and Administrative Expense   usd  5851000000 2014-01-01 2014-12-31
15 General and Administrative Expense   usd  6136000000 2015-01-01 2015-12-31
16                 Costs and Expenses   usd 40116000000 2013-01-01 2013-12-31
17                 Costs and Expenses   usd 49505000000 2014-01-01 2014-12-31
18                 Costs and Expenses   usd 55629000000 2015-01-01 2015-12-31
19            Operating Income (Loss)   usd 15403000000 2013-01-01 2013-12-31
20            Operating Income (Loss)   usd 16496000000 2014-01-01 2014-12-31
```

## GetBalanceSheet()

`GetBalanceSheet()` returns a company's balance sheet from the annual report of a given filing year as a dataframe. This functionality is only available for queries of balance sheets that belong to domestic companies.  Note that all data returned by this function comes from the company's 10-K, not 10-K/A.

#### Arguments:

`GetBalanceSheet(symbol, year)`

where

* `symbol` is a character string that represents the relevant stock ticker symbol.
* `year` is the year during which the annual report was filed. *(Note: This is not necessarily identical to the fiscal year for which the annual report was filed)*

#### Example:

```
###   Fetch first 20 lines of Google's balance sheet in the Form 10-K published in 2016.

> head(GetBalanceSheet("GOOG", 2016), 20)

                                                       Metric Units      Amount startDate    endDate
1                Cash and Cash Equivalents, at Carrying Value   usd 14778000000      <NA> 2012-12-31
2                Cash and Cash Equivalents, at Carrying Value   usd 18898000000      <NA> 2013-12-31
3                Cash and Cash Equivalents, at Carrying Value   usd 18347000000      <NA> 2014-12-31
4                Cash and Cash Equivalents, at Carrying Value   usd 16549000000      <NA> 2015-12-31
5                      Available-for-sale Securities, Current   usd 46048000000      <NA> 2014-12-31
6                      Available-for-sale Securities, Current   usd 56517000000      <NA> 2015-12-31
7          Cash, Cash Equivalents, and Short-term Investments   usd 64395000000      <NA> 2014-12-31
8          Cash, Cash Equivalents, and Short-term Investments   usd 73066000000      <NA> 2015-12-31
9                           Accounts Receivable, Net, Current   usd  9383000000      <NA> 2014-12-31
10                          Accounts Receivable, Net, Current   usd 11556000000      <NA> 2015-12-31
11             Receivable Under Reverse Repurchase Agreements   usd   875000000      <NA> 2014-12-31
12             Receivable Under Reverse Repurchase Agreements   usd   450000000      <NA> 2015-12-31
13                           Income Taxes Receivable, Current   usd   591000000      <NA> 2014-12-31
14                           Income Taxes Receivable, Current   usd  1903000000      <NA> 2015-12-31
15    Prepaid Revenue Share Expenses And Other Assets Current   usd  3412000000      <NA> 2014-12-31
16    Prepaid Revenue Share Expenses And Other Assets Current   usd  3139000000      <NA> 2015-12-31
17                                            Assets, Current   usd 78656000000      <NA> 2014-12-31
18                                            Assets, Current   usd 90114000000      <NA> 2015-12-31
19 Prepaid Revenue Share Expenses And Other Assets Noncurrent   usd  3187000000      <NA> 2014-12-31
20 Prepaid Revenue Share Expenses And Other Assets Noncurrent   usd  3181000000      <NA> 2015-12-31
```

## GetCashFlow()

`GetCashFlow()` returns a company's statement of cash flow from the annual report of a given filing year as a dataframe. This functionality is only available for queries of cash flow statements that belong to domestic companies.  Note that all data returned by this function comes from the company's 10-K, not 10-K/A.

#### Arguments:

`GetCashFlow(symbol, year)`

where

* `symbol` is a character string that represents the relevant stock ticker symbol.
* `year` is the year during which the annual report was filed. *(Note: This is not necessarily identical to the fiscal year for which the annual report was filed)*

#### Example:

```
###   Fetch first 20 lines of Google's cash flow statement in the Form 10-K published in 2016.

> head(GetCashFlow("GOOG", 2016), 20)

                                                                   Metric Units      Amount  startDate    endDate
1                                Net Income (Loss) Attributable to Parent   usd 12733000000 2013-01-01 2013-12-31
2                                Net Income (Loss) Attributable to Parent   usd 14136000000 2014-01-01 2014-12-31
3                                Net Income (Loss) Attributable to Parent   usd 16348000000 2015-01-01 2015-12-31
4    Depreciation and Impairment on Disposition of Property and Equipment   usd  2781000000 2013-01-01 2013-12-31
5    Depreciation and Impairment on Disposition of Property and Equipment   usd  3523000000 2014-01-01 2014-12-31
6    Depreciation and Impairment on Disposition of Property and Equipment   usd  4132000000 2015-01-01 2015-12-31
7              Amortization and Impairment of Intangible and Other Assets   usd  1158000000 2013-01-01 2013-12-31
8              Amortization and Impairment of Intangible and Other Assets   usd  1456000000 2014-01-01 2014-12-31
9              Amortization and Impairment of Intangible and Other Assets   usd   931000000 2015-01-01 2015-12-31
10                                               Share-based Compensation   usd  3343000000 2013-01-01 2013-12-31
11                                               Share-based Compensation   usd  4279000000 2014-01-01 2014-12-31
12                                               Share-based Compensation   usd  5203000000 2015-01-01 2015-12-31
13 Excess Tax Benefit from Share-based Compensation, Operating Activities   usd   481000000 2013-01-01 2013-12-31
14 Excess Tax Benefit from Share-based Compensation, Operating Activities   usd   648000000 2014-01-01 2014-12-31
15 Excess Tax Benefit from Share-based Compensation, Operating Activities   usd   548000000 2015-01-01 2015-12-31
16                                  Deferred Income Taxes and Tax Credits   usd  -437000000 2013-01-01 2013-12-31
17                                  Deferred Income Taxes and Tax Credits   usd  -104000000 2014-01-01 2014-12-31
18                                  Deferred Income Taxes and Tax Credits   usd  -179000000 2015-01-01 2015-12-31
19     Gain (Loss) on Sale of Business, Including Discontinued Operations   usd   700000000 2013-01-01 2013-12-31
20     Gain (Loss) on Sale of Business, Including Discontinued Operations   usd   740000000 2014-01-01 2014-12-31
```

## Bug Reports and Feedback

Please use the GitHub issue tracker for bug reports, feature request, or general discussions.


================================================
FILE: finreportr.Rproj
================================================
Version: 1.0

RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default

EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 5
Encoding: UTF-8

RnwWeave: Sweave
LaTeX: pdfLaTeX

BuildType: Package
PackageUseDevtools: Yes
PackageInstallArgs: --no-multiarch --with-keep.source
PackageRoxygenize: rd,collate,namespace


================================================
FILE: man/AnnualReports.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/annual_reports.R
\name{AnnualReports}
\alias{AnnualReports}
\title{Acquire listing of company annual reports.}
\usage{
AnnualReports(symbol, foreign = FALSE)
}
\arguments{
\item{symbol}{A character vector specifying the stock symbol of the company of interest.}

\item{foreign}{A logical vector indicating whether the company is domestic or foreign. \code{foreign = FALSE} by default.}
}
\description{
Extracts and displays listing of annual reports filed by a company in a data frame.
}
\examples{
\dontrun{
AnnualReports("TSLA")
AnnualReports("BABA", foreign = TRUE)
}
}


================================================
FILE: man/CompanyInfo.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/company_info.R
\name{CompanyInfo}
\alias{CompanyInfo}
\title{Acquire basic company information.}
\usage{
CompanyInfo(symbol)
}
\arguments{
\item{symbol}{A character vector specifying the stock symbol of the company of interest.}
}
\description{
Extracts and displays basic information relating to a given company in a data frame.
}
\examples{
\dontrun{
CompanyInfo("GOOG")
CompanyInfo("TSLA")
}
}


================================================
FILE: man/GetBalanceSheet.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/get_balance_sheet.R
\name{GetBalanceSheet}
\alias{GetBalanceSheet}
\title{Acquire balance sheet.}
\usage{
GetBalanceSheet(symbol, year)
}
\arguments{
\item{symbol}{A character vector specifying the stock symbol of the company of interest.}

\item{year}{A numeric vector specifying the year during which the annual report was filed.}
}
\description{
Extracts and displays balance sheet from the annual report of a given company. 
This functionality is only available for queries fo balance sheets that belong to domestic companies. 
Note that all data returned by this function comes from the company's Form 10-K, not Form 10-K/A.
}
\examples{
\dontrun{
GetBalanceSheet("FB", 2016)
}
}


================================================
FILE: man/GetCashFlow.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/get_cash_flow.R
\name{GetCashFlow}
\alias{GetCashFlow}
\title{Acquire statement of cash flow.}
\usage{
GetCashFlow(symbol, year)
}
\arguments{
\item{symbol}{A character vector specifying the stock symbol of the company of interest.}

\item{year}{A numeric vector specifying the year during which the annual report was filed.}
}
\description{
Extracts and displays statement of cash flow from the annual report of a given company. 
This functionality is only available for queries of cash flow statements that belong to domestic company. 
Note that all data returned by this function comes from the company's Form 10-K, not Form 10-K/A.
}
\examples{
\dontrun{
GetCashFlow("FB", 2016)
}
}


================================================
FILE: man/GetIncome.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/get_income.R
\name{GetIncome}
\alias{GetIncome}
\title{Acquire income statement.}
\usage{
GetIncome(symbol, year)
}
\arguments{
\item{symbol}{A character vector specifying the stock symbol of the company of interest.}

\item{year}{A numeric vector specifying the year during which the annual report was filed.}
}
\description{
Extracts and displays income statement from the annual report of a given company.
This functionality is only available for queries of income statements that belong to domestic companies.
Note that all data returned by this function comes from the company's 10-K, not 10-K/A.
}
\examples{
\dontrun{
GetIncome("FB", 2016)
}
}


================================================
FILE: man/siccodes.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/data.R
\docType{data}
\name{siccodes}
\alias{siccodes}
\title{Standard Industrial Classification Code List}
\format{
A data frame with 444 rows and 2 variables:
\itemize{
  \item SIC: Standard Industrial Classification Code
  \item industry: Industry Title
}
}
\source{
\url{https://www.sec.gov/info/edgar/siccodes.htm}
}
\usage{
siccodes
}
\description{
A dataset containing SIC codes and industries that they represent
}
\keyword{datasets}


================================================
FILE: man/statecodes.Rd
================================================
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/data.R
\docType{data}
\name{statecodes}
\alias{statecodes}
\title{EDGAR State and Country Codes}
\format{
A data frame with 310 rows and 2 variables:
 \itemize{
  \item state: State or Country Code
  \item state.name: State or Country Name
}
}
\source{
\url{https://www.sec.gov/edgar/searchedgar/edgarstatecodes.htm}
}
\usage{
statecodes
}
\description{
A dataset containing state and country codes used in the SEC EDGAR database.
}
\keyword{datasets}


================================================
FILE: tests/testthat/test.R
================================================
# Test CompanyInfo()

context("Data output dimensions")

skip_on_cran()

test_that("CompanyInfo returning correct dimensions", {
     expect_equal(dim(CompanyInfo("GOOG")), c(1, 8))
     expect_equal(dim(CompanyInfo("TSLA")), c(1, 8))
     expect_equal(dim(CompanyInfo("FB")), c(1, 8))
})

================================================
FILE: tests/testthat.R
================================================
library(testthat)
library(finreportr)

test_check("finreportr")

================================================
FILE: vignettes/finreportr.Rmd
================================================
---
title: "finreportr – Querying Data from the U.S. Securities and Exchange Commission"
author: "Seward Lee"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{finreportr}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

A financial analyst's time is valuable – it shouldn't be wasted on performing manual data entry. **finreportr** is a web scraper written in R that allows analysts to query data from the U.S. Securities and Exchange Commission directly from the R console.  It aims to eliminate time wasters from a financial analyst's workflow, such as navigating the SEC EDGAR database, flipping through financial reports, and parsing XBRL-encoded data.

**finreportr** allows you to fetch data from the SEC and load it into your workspace using the following commands:

* `CompanyInfo()`: returns basic information about a company
* `AnnualReports()`: returns a listing of annual reports filed by a company
* `GetIncome()`: returns the income statement for a given company
* `GetBalanceSheet()`: returns the balance sheet for a given company
* `GetCashFlow()`: returns the cash flow statement for a given company

## Querying Company Information

**finreportr** provides two functions that allow users to acquire background information relating to publicly-listed companies.

The function `CompanyInfo()` returns the following information about a company based on its stock ticker symbol:

* Name
* [Central Index Key ("CIK")](https://en.wikipedia.org/wiki/Central_Index_Key)
* [Standard  Industrial Classification ("SIC")](https://en.wikipedia.org/wiki/Standard_Industrial_Classification)
* State Location
* State of Incorporation
* Fiscal Year End
* Address

For example, suppose we want to do a quick search on Google/Alphabet (symbol: `GOOG`):

```
> CompanyInfo("GOOG")

      company        CIK  SIC state state.inc FY.end            street.address             city.state
1 GOOGLE INC. 0001288776 7370    CA        DE   1231 1600 AMPHITHEATRE PARKWAY MOUNTAIN VIEW CA 94043
```

The function `AnnualReports()` returns a data frame that summarizes a company's annual reports based on its stock ticker symbol. It will return data relating to a company's [Form 10-Ks](https://www.investopedia.com/terms/1/10-k.asp) if the company is domestic, and [Form 20-Fs](https://www.investopedia.com/terms/s/sec-form-20-f.asp) if the company is foreign. 

For example, suppose we want to display the annual reports filed by Facebook (symbol: `FB`):

```
> AnnualReports("FB")

  filing.name filing.date         accession.no
1        10-K  2016-01-28 0001326801-16-000043
2      10-K/A  2015-02-13 0001326801-15-000010
3        10-K  2015-01-29 0001326801-15-000006
4        10-K  2014-01-31 0001326801-14-000007
5        10-K  2013-02-01 0001326801-13-000003
```


## Querying Financial Data

The main benefit of **finreportr** comes from allowing users to download and display financial data without having to manually inspect filings from the SEC EDGAR database. This creates opportunities for users to introduce automation, scalability, and reproducibility to their analysis.

The function `GetIncome()` returns a company's income statement from a given filing year. Suppose we want the income statement of Tesla Motors (symbol: `TSLA`) from the annual report filed in 2015:

```
> head(GetIncome("TSLA", 2015))

                      Metric        Units     Amount  startDate    endDate
1    Sales Revenue Goods Net U_iso4217USD  385699000 2012-01-01 2012-12-31
2    Sales Revenue Goods Net U_iso4217USD 1997786000 2013-01-01 2013-12-31
3    Sales Revenue Goods Net U_iso4217USD 3192723000 2014-01-01 2014-12-31
4 Sales Revenue Services Net U_iso4217USD   27557000 2012-01-01 2012-12-31
5 Sales Revenue Services Net U_iso4217USD   15710000 2013-01-01 2013-12-31
6 Sales Revenue Services Net U_iso4217USD    5633000 2014-01-01 2014-12-31
```

The function `GetBalanceSheet()` returns a company's balance sheet from a given filing year. Suppose we want the balance sheet of Apple (symbol: `AAPL`) from the annual report filed in 2012:

```
> head(GetBalanceSheet("AAPL", 2012))

                                    Metric       Units      Amount startDate    endDate
1 Available For Sale Securities Noncurrent iso4217_USD 55618000000      <NA> 2011-09-24
2 Available For Sale Securities Noncurrent iso4217_USD 92122000000      <NA> 2012-09-29
3         Property Plant And Equipment Net iso4217_USD  7777000000      <NA> 2011-09-24
4         Property Plant And Equipment Net iso4217_USD 15452000000      <NA> 2012-09-29
5                                 Goodwill iso4217_USD   896000000      <NA> 2011-09-24
6                                 Goodwill iso4217_USD  1135000000      <NA> 2012-09-29
```

The function `GetCashFlow()` returns a company's cash flow statement from a given filing year. Suppose we want the cash flow statement of LinkedIn (symbol: `LNKD`) from the annual report filed in 2014:

```
> head(GetCashFlow("LNKD", 2014))

                                                   Metric Units    Amount  startDate    endDate
1                Net Income (Loss) Attributable to Parent   usd  11912000 2011-01-01 2011-12-31
2                Net Income (Loss) Attributable to Parent   usd  21610000 2012-01-01 2012-12-31
3                Net Income (Loss) Attributable to Parent   usd  26769000 2013-01-01 2013-12-31
4 Depreciation, Depletion and Amortization, Nonproduction   usd  43100000 2011-01-01 2011-12-31
5 Depreciation, Depletion and Amortization, Nonproduction   usd  79849000 2012-01-01 2012-12-31
6 Depreciation, Depletion and Amortization, Nonproduction   usd 134516000 2013-01-01 2013-12-31
```
Download .txt
gitextract_ethd7a8s/

├── .Rbuildignore
├── .gitignore
├── .travis.yml
├── DESCRIPTION
├── LICENSE
├── NAMESPACE
├── R/
│   ├── annual_reports.R
│   ├── backend_utilities.R
│   ├── company_info.R
│   ├── data.R
│   ├── get_balance_sheet.R
│   ├── get_cash_flow.R
│   ├── get_financial.R
│   └── get_income.R
├── README.md
├── data/
│   ├── siccodes.rda
│   └── statecodes.rda
├── finreportr.Rproj
├── man/
│   ├── AnnualReports.Rd
│   ├── CompanyInfo.Rd
│   ├── GetBalanceSheet.Rd
│   ├── GetCashFlow.Rd
│   ├── GetIncome.Rd
│   ├── siccodes.Rd
│   └── statecodes.Rd
├── tests/
│   ├── testthat/
│   │   └── test.R
│   └── testthat.R
└── vignettes/
    └── finreportr.Rmd
Condensed preview — 28 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (43K chars).
[
  {
    "path": ".Rbuildignore",
    "chars": 79,
    "preview": "^.*\\.Rproj$\n^\\.Rproj\\.user$\n^\\.travis\\.yml$\n^cran-comments\\.md$\n^CRAN-RELEASE$\n"
  },
  {
    "path": ".gitignore",
    "chars": 47,
    "preview": "inst/doc\n.Rproj.user\n.Rhistory\ncran-comments.md"
  },
  {
    "path": ".travis.yml",
    "chars": 90,
    "preview": "# Sample .travis.yml for R projects\n\nlanguage: r\nwarnings_are_errors: true\nsudo: required\n"
  },
  {
    "path": "DESCRIPTION",
    "chars": 916,
    "preview": "Package: finreportr\nType: Package\nTitle: Financial Data from U.S. Securities and Exchange Commission\nVersion: 1.0.4\nDate"
  },
  {
    "path": "LICENSE",
    "chars": 39,
    "preview": "YEAR: 2021\nCOPYRIGHT HOLDER: Seward Lee"
  },
  {
    "path": "NAMESPACE",
    "chars": 177,
    "preview": "# Generated by roxygen2: do not edit by hand\n\nexport(AnnualReports)\nexport(CompanyInfo)\nexport(GetBalanceSheet)\nexport(G"
  },
  {
    "path": "R/annual_reports.R",
    "chars": 1978,
    "preview": "#' Acquire listing of company annual reports.\n#' \n#' Extracts and displays listing of annual reports filed by a company "
  },
  {
    "path": "R/backend_utilities.R",
    "chars": 1938,
    "preview": "#' @import dplyr\n\n################################################################################\n#####     Backend Uti"
  },
  {
    "path": "R/company_info.R",
    "chars": 3073,
    "preview": "#' Acquire basic company information.\n#' \n#' Extracts and displays basic information relating to a given company in a da"
  },
  {
    "path": "R/data.R",
    "chars": 738,
    "preview": "#' Standard Industrial Classification Code List\n#' \n#' A dataset containing SIC codes and industries that they represent"
  },
  {
    "path": "R/get_balance_sheet.R",
    "chars": 1140,
    "preview": "#' Acquire balance sheet.\n#' \n#' Extracts and displays balance sheet from the annual report of a given company. \n#' This"
  },
  {
    "path": "R/get_cash_flow.R",
    "chars": 997,
    "preview": "#' Acquire statement of cash flow.\n#' \n#' Extracts and displays statement of cash flow from the annual report of a given"
  },
  {
    "path": "R/get_financial.R",
    "chars": 3574,
    "preview": "#' @import dplyr curl\n\nGetFinancial <- function(statement.type, symbol, year) {\n     \n     ##   This is here to please R"
  },
  {
    "path": "R/get_income.R",
    "chars": 1217,
    "preview": "#' Acquire income statement.\n#' \n#' Extracts and displays income statement from the annual report of a given company.\n#'"
  },
  {
    "path": "README.md",
    "chars": 13716,
    "preview": "[![Travis-CI Build Status](https://travis-ci.org/sewardlee337/finreportr.svg?branch=master)](https://travis-ci.org/sewar"
  },
  {
    "path": "finreportr.Rproj",
    "chars": 343,
    "preview": "Version: 1.0\n\nRestoreWorkspace: Default\nSaveWorkspace: Default\nAlwaysSaveHistory: Default\n\nEnableCodeIndexing: Yes\nUseSp"
  },
  {
    "path": "man/AnnualReports.Rd",
    "chars": 651,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/annual_reports.R\n\\name{AnnualReports}\n\\ali"
  },
  {
    "path": "man/CompanyInfo.Rd",
    "chars": 475,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/company_info.R\n\\name{CompanyInfo}\n\\alias{C"
  },
  {
    "path": "man/GetBalanceSheet.Rd",
    "chars": 763,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/get_balance_sheet.R\n\\name{GetBalanceSheet}"
  },
  {
    "path": "man/GetCashFlow.Rd",
    "chars": 765,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/get_cash_flow.R\n\\name{GetCashFlow}\n\\alias{"
  },
  {
    "path": "man/GetIncome.Rd",
    "chars": 729,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/get_income.R\n\\name{GetIncome}\n\\alias{GetIn"
  },
  {
    "path": "man/siccodes.Rd",
    "chars": 520,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/data.R\n\\docType{data}\n\\name{siccodes}\n\\ali"
  },
  {
    "path": "man/statecodes.Rd",
    "chars": 530,
    "preview": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/data.R\n\\docType{data}\n\\name{statecodes}\n\\a"
  },
  {
    "path": "tests/testthat/test.R",
    "chars": 288,
    "preview": "# Test CompanyInfo()\n\ncontext(\"Data output dimensions\")\n\nskip_on_cran()\n\ntest_that(\"CompanyInfo returning correct dimens"
  },
  {
    "path": "tests/testthat.R",
    "chars": 63,
    "preview": "library(testthat)\nlibrary(finreportr)\n\ntest_check(\"finreportr\")"
  },
  {
    "path": "vignettes/finreportr.Rmd",
    "chars": 5678,
    "preview": "---\ntitle: \"finreportr – Querying Data from the U.S. Securities and Exchange Commission\"\nauthor: \"Seward Lee\"\ndate: \"`r "
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the sewardlee337/finreportr GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 28 files (39.6 KB), approximately 11.4k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!