Report Details

articleID <- "2-10-2014" # insert the article ID code here e.g., "10-3-2015"
reportType <- 'pilot' # specify whether this is the 'pilot' report or 'copilot' report
pilotNames <- "Julian M Siebert" # insert the pilot's name here e.g., "Tom Hardwicke".
copilotNames <- NA # # insert the co-pilot's name here e.g., "Michael Frank".
pilotTTC <- NA # insert the pilot's estimated time to complete (in minutes, it is fine to approximate) e.g., 120
copilotTTC <- 240 # insert the co-pilot's estimated time to complete (in minutes, it is fine to approximate) e.g., 120
pilotStartDate <- as.Date("10/30/19", format = "%m/%d/%y") # insert the piloting start date in US format e.g., as.Date("01/25/18", format = "%m/%d/%y")
copilotStartDate <- NA # insert the co-piloting start date in US format e.g., as.Date("01/25/18", format = "%m/%d/%y")
completionDate <- as.Date("11/03/19", format = "%m/%d/%y") # insert the date of final report completion in US format e.g., as.Date("01/25/18", format = "%m/%d/%y")

Methods summary:

They authors provide descriptive statistics of participants’ ratings of their curiosity about and interest in reflections they made at two points in time; they wrote down the reflections at Time 1, and were exposed to them again at Time 2. Ratings were collected at both times and descriptives (M and SD) for both points in time are presented. The authors further report repeated-measures \(t\)-tests comparing curiosity and interest predicted at Time 1 to actual curiosity and interest experienced at Time 2 (three months later). All values at both times are collapsed across nine individually posed prompts.


Target outcomes:

Quoted from original study:

Table 1 in Zhang et al. (2014) provides descriptive statistics for each measure for Study 1.

Participants’ Time 1 predictions of their curiosity (M = 3.99, SD = 1.32) were lower than their actual curiosity ratings at Time 2, immediately before reading their responses (M = 4.34, SD = 1.25), t(105) = 2.88, p = .005, d = 0.27. Participants also underestimated how interesting they would find their responses. Predictions of interest at Time 1 (M = 3.54, SD = 1.01) were lower than ratings of actual interest experienced at Time 2 (M = 3.82, SD = 0.89), t(105) = 3.10, p = .003, d = 0.29 (Zhang et al., 2014, p. 1852).

All information to reproduce these outcomes is available.


Step 1: Load packages and prepare report object

# load packages
library(tidyverse) # for data munging
library(knitr) # for kable table formating
library(haven) # import and export 'SPSS', 'Stata' and 'SAS' Files
library(readxl) # import excel files
library(ReproReports) # custom reporting functions
# Prepare report object. This will be updated automatically by the reproCheck function each time values are compared
reportObject <- data.frame(dummyRow = TRUE, reportedValue = NA, obtainedValue = NA, valueType = NA, percentageError = NA, comparisonOutcome = NA, eyeballCheck = NA)

Step 2: Load data

Data read into R using read_sav from the haven library.

  original_data <- read_sav("GroupC_2-10-2014/data/Study1_Data.sav")

Step 3: Tidy data

Creating a dataframe to be cleaned, leaving the original intact:

cleaned_data <- original_data

Changing one column name and making minor formatting changes to prepare cleaned_data for converstion into longer format.

colnames(cleaned_data)[colnames(cleaned_data)=="T2_Finished"] <- "Finished"
names(cleaned_data) <- tolower(names(cleaned_data))

Step 4: Run analysis

Filtering the dataframe, only selecting those who completed surveys at both Times 1 and 2.

Pre-processing

analysis_data <- cleaned_data %>%
  filter(finished == 1)
analysis_data
## # A tibble: 106 x 107
##    t1_roommate_cur… t1_roommate_int… t1_roommate_sur… t1_roommate_mea…
##           <dbl+lbl>        <dbl+lbl>        <dbl+lbl>        <dbl+lbl>
##  1 NA               NA               NA               NA              
##  2  4 [4-Somewhat]   3 [3]            2 [2]            4 [4-Somewhat] 
##  3  2 [2]            3 [3]            3 [3]            2 [2]          
##  4  3 [3]            2 [2]            3 [3]            1 [1-Not at al…
##  5  2 [2]            1 [1-Not at al…  1 [1-Not at al…  2 [2]          
##  6  3 [3]            3 [3]            3 [3]            3 [3]          
##  7  1 [1-Not at al…  1 [1-Not at al…  1 [1-Not at al…  3 [3]          
##  8  4 [4-Somewhat]   4 [4-Somewhat]   2 [2]            2 [2]          
##  9  2 [2]            2 [2]            2 [2]            2 [2]          
## 10  1 [1-Not at al…  1 [1-Not at al…  1 [1-Not at al…  1 [1-Not at al…
## # … with 96 more rows, and 103 more variables:
## #   t1_social_curious <dbl+lbl>, t1_social_interesting <dbl+lbl>,
## #   t1_social_surprised <dbl+lbl>, t1_social_meaningful <dbl+lbl>,
## #   t1_essay_curious <dbl+lbl>, t1_essay_interesting <dbl+lbl>,
## #   t1_essay_surprised <dbl+lbl>, t1_essay_meaningful <dbl+lbl>,
## #   t1_convo_curious <dbl+lbl>, t1_convo_interesting <dbl+lbl>,
## #   t1_convo_surprised <dbl+lbl>, t1_convo_meaningful <dbl+lbl>,
## #   t1_song_curious <dbl+lbl>, t1_song_interesting <dbl+lbl>,
## #   t1_song_surprised <dbl+lbl>, t1_song_meaningful <dbl+lbl>,
## #   t1_finals_curious <dbl+lbl>, t1_finals_interesting <dbl+lbl>,
## #   t1_finals_surprised <dbl+lbl>, t1_finals_meaningful <dbl+lbl>,
## #   t1_joke_curious <dbl+lbl>, t1_joke_interesting <dbl+lbl>,
## #   t1_joke_surprised <dbl+lbl>, t1_joke_meaningful <dbl+lbl>,
## #   t1_photo_curious <dbl+lbl>, t1_photo_interesting <dbl+lbl>,
## #   t1_photo_surprised <dbl+lbl>, t1_photo_meaningful <dbl+lbl>,
## #   t1_fb_curious <dbl+lbl>, t1_fb_interesting <dbl+lbl>,
## #   t1_fb_surprised <dbl+lbl>, t1_fb_meaningful <dbl+lbl>,
## #   gender <dbl+lbl>, year_born <dbl+lbl>, order <dbl>, finished <dbl>,
## #   t2_roommate_curious <dbl+lbl>, t2_roommate_interesting <dbl+lbl>,
## #   t2_roommate_surprised <dbl+lbl>, t2_roommate_meaningful <dbl+lbl>,
## #   t2_social_curious <dbl+lbl>, t2_social_interesting <dbl+lbl>,
## #   t2_social_surprised <dbl+lbl>, t2_social_meaningful <dbl+lbl>,
## #   t2_essay_curious <dbl+lbl>, t2_essay_interesting <dbl+lbl>,
## #   t2_essay_surprised <dbl+lbl>, t2_essay_meaningful <dbl+lbl>,
## #   t2_convo_curious <dbl+lbl>, t2_convo_interesting <dbl+lbl>,
## #   t2_convo_surprised <dbl+lbl>, t2_convo_meaningful <dbl+lbl>,
## #   t2_song_curious <dbl+lbl>, t2_song_interesting <dbl+lbl>,
## #   t2_song_surprised <dbl+lbl>, t2_song_meaningful <dbl+lbl>,
## #   t2_finals_curious <dbl+lbl>, t2_finals_interesting <dbl+lbl>,
## #   t2_finals_surprised <dbl+lbl>, t2_finals_meaningful <dbl+lbl>,
## #   t2_joke_curious <dbl+lbl>, t2_joke_interesting <dbl+lbl>,
## #   t2_joke_surprised <dbl+lbl>, t2_joke_meaningful <dbl+lbl>,
## #   t2_photo_curious <dbl+lbl>, t2_photo_interesting <dbl+lbl>,
## #   t2_photo_surprised <dbl+lbl>, t2_photo_meaningful <dbl+lbl>,
## #   t2_fb_curious <dbl+lbl>, t2_fb_interesting <dbl+lbl>,
## #   t2_fb_surprised <dbl+lbl>, t2_fb_meaningful <dbl+lbl>,
## #   t1_curious <dbl>, t1_surprised <dbl>, t2_curious <dbl>,
## #   t2_surprised <dbl>, t1_meaningful <dbl>, t2_meaningful <dbl>,
## #   t1_interesting <dbl>, t2_interesting <dbl>, age <dbl>,
## #   t1_roommate_interest_composite <dbl>,
## #   t1_social_interest_composite <dbl>, t1_essay_interest_composite <dbl>,
## #   t1_convo_interest_composite <dbl>, t1_song_interest_composite <dbl>,
## #   t1_finals_interest_composite <dbl>, t1_joke_interest_composite <dbl>,
## #   t1_photo_interest_composite <dbl>, t1_fb_interest_composite <dbl>,
## #   t2_roommate_interest_composite <dbl>,
## #   t2_social_interest_composite <dbl>, t2_essay_interest_composite <dbl>,
## #   t2_convo_interest_composite <dbl>, t2_song_interest_composite <dbl>,
## #   t2_finals_interest_composite <dbl>, t2_joke_interest_composite <dbl>,
## #   t2_photo_interest_composite <dbl>, t2_fb_interest_composite <dbl>,
## #   t1_interest_composite <dbl>, …

Descriptive statistics

Below are quotes from the original article (separate chunkgs for curiosity and interest ratings). All results could be reproduced.

Participants’ Time 1 predictions of their curiosity (M = 3.99, SD = 1.32) actual curiosity ratings at Time 2, immediately before read- ing their responses (M = 4.34, SD = 1.25). (Zhang et al., 2014, p. 1852)

# mean curiosity ratings and SDs for Times 1 and 2
# NOTE: alternatively, one could calculate the means from all individual responses,
# but it made more sense to calculate it as the mean of means

mean_curiosity_t1 <- mean(analysis_data$t1_curious)
reportObject <- reproCheck(reportedValue = '3.99', obtainedValue = mean_curiosity_t1, valueType = 'mean')
## [1] "MATCH for mean. The reported value (3.99) and the obtained value (3.99) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."
mean_curiosity_t2 <- mean(analysis_data$t2_curious)
reportObject <- reproCheck(reportedValue = '4.34', obtainedValue = mean_curiosity_t2, valueType = 'mean')
## [1] "MATCH for mean. The reported value (4.34) and the obtained value (4.34) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."
sd_curiosity_t1 <- sd(analysis_data$t1_curious)
reportObject <- reproCheck(reportedValue = '1.32', obtainedValue = sd_curiosity_t1, valueType = 'sd')
## [1] "MATCH for sd. The reported value (1.32) and the obtained value (1.32) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."
sd_curiosity_t2 <- sd(analysis_data$t2_curious)
reportObject <- reproCheck(reportedValue = '1.25', obtainedValue = sd_curiosity_t2, valueType = 'sd')
## [1] "MATCH for sd. The reported value (1.25) and the obtained value (1.25) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."

Predictions of interest at Time 1 (M = 3.54, SD = 1.01) actual interest experienced at Time 2 (M = 3.82, SD = 0.89), (Zhang et al., 2014, p. 1853)

# mean interest ratings and SDs for Times 1 and 2
mean_interest_t1 <- mean(analysis_data$t1_interest_composite)
reportObject <- reproCheck(reportedValue = '3.54', obtainedValue = mean_interest_t1, valueType = 'mean')
## [1] "MATCH for mean. The reported value (3.54) and the obtained value (3.54) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."
mean_interest_t2 <- mean(analysis_data$t2_interest_composite)
reportObject <- reproCheck(reportedValue = '3.82', obtainedValue = mean_interest_t2, valueType = 'mean')
## [1] "MATCH for mean. The reported value (3.82) and the obtained value (3.82) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."
sd_interest_t1 <- sd(analysis_data$t1_interest_composite)
reportObject <- reproCheck(reportedValue = '1.01', obtainedValue = sd_interest_t1, valueType = 'sd')
## [1] "MATCH for sd. The reported value (1.01) and the obtained value (1.01) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."
sd_interest_t2 <- sd(analysis_data$t2_interest_composite)
reportObject <- reproCheck(reportedValue = '0.89', obtainedValue = sd_interest_t2, valueType = 'sd')
## [1] "MATCH for sd. The reported value (0.89) and the obtained value (0.89) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."

Inferential statistics

\(t\)-test comparing curiosity ratings at Times 1 and 2. > Participants’ Time 1 predictions of their curiosity (M = 3.99, SD = 1.32) were lower than their actual curiosity ratings at Time 2, immediately before read- ing their responses (M = 4.34, SD = 1.25), t(105) = 2.88, p = .005, d = 0.27. (Zhang et al., 2014, p. 1852)

curiosity_ttest <- t.test(analysis_data$t2_curious, analysis_data$t1_curious, paired=TRUE)
curiosity_ttest
## 
##  Paired t-test
## 
## data:  analysis_data$t2_curious and analysis_data$t1_curious
## t = 2.88, df = 105, p-value = 0.004821
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.1084808 0.5879852
## sample estimates:
## mean of the differences 
##                0.348233
reportObject <- reproCheck(reportedValue = '2.88', obtainedValue = curiosity_ttest$statistic, valueType = 't')
## [1] "MATCH for t. The reported value (2.88) and the obtained value (2.88) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."
reportObject <- reproCheck(reportedValue = '.005', obtainedValue = curiosity_ttest$p.value, valueType = 'p')
## [1] "MATCH for p. The reported value (0.005) and the obtained value (0.005) differed by 0%. Note that the obtained value was rounded to 3 decimal places to match the reported value."

\(t\)-test comparing interest ratings at Times 1 and 2.

Predictions of interest at Time 1 (M = 3.54, SD = 1.01) were lower than ratings of actual interest experienced at Time 2 (M = 3.82, SD = 0.89), t(105) = 3.10, p = .003, d = 0.29 (Zhang et al., 2014, p. 1853)

interest_ttest <- t.test(analysis_data$t2_interest_composite, analysis_data$t1_interest_composite, paired=TRUE)
interest_ttest
## 
##  Paired t-test
## 
## data:  analysis_data$t2_interest_composite and analysis_data$t1_interest_composite
## t = 3.0953, df = 105, p-value = 0.002521
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
##  0.1028612 0.4695408
## sample estimates:
## mean of the differences 
##                0.286201
reportObject <- reproCheck(reportedValue = '3.10', obtainedValue = interest_ttest$statistic, valueType = 't')
## [1] "MATCH for t. The reported value (3.1) and the obtained value (3.1) differed by 0%. Note that the obtained value was rounded to 2 decimal places to match the reported value."
reportObject <- reproCheck(reportedValue = '.003', obtainedValue = interest_ttest$p.value, valueType = 'p')
## [1] "MATCH for p. The reported value (0.003) and the obtained value (0.003) differed by 0%. Note that the obtained value was rounded to 3 decimal places to match the reported value."

Step 5: Conclusion

All results from the orginal paper’s Study 1 were accurately reproduced, no questions remain.

reportObject <- reportObject %>%
  filter(dummyRow == FALSE) %>% # remove the dummy row
  select(-dummyRow) %>% # remove dummy row designation
  mutate(articleID = articleID) %>% # add variables to report 
  select(articleID, everything()) # make articleID first column

# decide on final outcome
if(any(reportObject$comparisonOutcome %in% c("MAJOR_ERROR", "DECISION_ERROR"))){
  finalOutcome <- "Failure"
}else{
  finalOutcome <- "Success"
}

# collate report extra details
reportExtras <- data.frame(articleID, pilotNames, copilotNames, pilotTTC, copilotTTC, pilotStartDate, copilotStartDate, completionDate, finalOutcome)

# save report objects
if(reportType == "pilot"){
  write_csv(reportObject, "pilotReportDetailed.csv")
  write_csv(reportExtras, "pilotReportExtras.csv")
}

if(reportType == "copilot"){
  write_csv(reportObject, "copilotReportDetailed.csv")
  write_csv(reportExtras, "copilotReportExtras.csv")
}

Session information

devtools::session_info()
## ─ Session info ──────────────────────────────────────────────────────────
##  setting  value                       
##  version  R version 3.6.1 (2019-07-05)
##  os       macOS Catalina 10.15        
##  system   x86_64, darwin15.6.0        
##  ui       X11                         
##  language (EN)                        
##  collate  en_US.UTF-8                 
##  ctype    en_US.UTF-8                 
##  tz       America/Los_Angeles         
##  date     2019-11-10                  
## 
## ─ Packages ──────────────────────────────────────────────────────────────
##  package      * version date       lib
##  assertthat     0.2.1   2019-03-21 [1]
##  backports      1.1.5   2019-10-02 [1]
##  broom          0.5.2   2019-04-07 [1]
##  callr          3.3.2   2019-09-22 [1]
##  cellranger     1.1.0   2016-07-27 [1]
##  cli            1.1.0   2019-03-19 [1]
##  colorspace     1.4-1   2019-03-18 [1]
##  crayon         1.3.4   2017-09-16 [1]
##  desc           1.2.0   2018-05-01 [1]
##  devtools       2.2.1   2019-09-24 [1]
##  digest         0.6.22  2019-10-21 [1]
##  dplyr        * 0.8.3   2019-07-04 [1]
##  ellipsis       0.3.0   2019-09-20 [1]
##  evaluate       0.14    2019-05-28 [1]
##  fansi          0.4.0   2018-10-05 [1]
##  forcats      * 0.4.0   2019-02-17 [1]
##  fs             1.3.1   2019-05-06 [1]
##  generics       0.0.2   2018-11-29 [1]
##  ggplot2      * 3.2.1   2019-08-10 [1]
##  glue           1.3.1   2019-03-12 [1]
##  gtable         0.3.0   2019-03-25 [1]
##  haven        * 2.1.1   2019-07-04 [1]
##  hms            0.5.2   2019-10-30 [1]
##  htmltools      0.4.0   2019-10-04 [1]
##  httr           1.4.1   2019-08-05 [1]
##  jsonlite       1.6     2018-12-07 [1]
##  knitr        * 1.25    2019-09-18 [1]
##  lattice        0.20-38 2018-11-04 [1]
##  lazyeval       0.2.2   2019-03-15 [1]
##  lifecycle      0.1.0   2019-08-01 [1]
##  lubridate      1.7.4   2018-04-11 [1]
##  magrittr       1.5     2014-11-22 [1]
##  memoise        1.1.0   2017-04-21 [1]
##  modelr         0.1.5   2019-08-08 [1]
##  munsell        0.5.0   2018-06-12 [1]
##  nlme           3.1-141 2019-08-01 [1]
##  pillar         1.4.2   2019-06-29 [1]
##  pkgbuild       1.0.6   2019-10-09 [1]
##  pkgconfig      2.0.3   2019-09-22 [1]
##  pkgload        1.0.2   2018-10-29 [1]
##  prettyunits    1.0.2   2015-07-13 [1]
##  processx       3.4.1   2019-07-18 [1]
##  ps             1.3.0   2018-12-21 [1]
##  purrr        * 0.3.3   2019-10-18 [1]
##  R6             2.4.0   2019-02-14 [1]
##  Rcpp           1.0.2   2019-07-25 [1]
##  readr        * 1.3.1   2018-12-21 [1]
##  readxl       * 1.3.1   2019-03-13 [1]
##  remotes        2.1.0   2019-06-24 [1]
##  ReproReports * 0.1     2019-10-31 [1]
##  rlang          0.4.1   2019-10-24 [1]
##  rmarkdown      1.16    2019-10-01 [1]
##  rprojroot      1.3-2   2018-01-03 [1]
##  rstudioapi     0.10    2019-03-19 [1]
##  rvest          0.3.4   2019-05-15 [1]
##  scales         1.0.0   2018-08-09 [1]
##  sessioninfo    1.1.1   2018-11-05 [1]
##  stringi        1.4.3   2019-03-12 [1]
##  stringr      * 1.4.0   2019-02-10 [1]
##  testthat       2.2.1   2019-07-25 [1]
##  tibble       * 2.1.3   2019-06-06 [1]
##  tidyr        * 1.0.0   2019-09-11 [1]
##  tidyselect     0.2.5   2018-10-11 [1]
##  tidyverse    * 1.2.1   2017-11-14 [1]
##  usethis        1.5.1   2019-07-04 [1]
##  utf8           1.1.4   2018-05-24 [1]
##  vctrs          0.2.0   2019-07-05 [1]
##  withr          2.1.2   2018-03-15 [1]
##  xfun           0.10    2019-10-01 [1]
##  xml2           1.2.2   2019-08-09 [1]
##  yaml           2.2.0   2018-07-25 [1]
##  zeallot        0.1.0   2018-01-28 [1]
##  source                                    
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.1)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.1)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.1)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  Github (TomHardwicke/ReproReports@2ec6f60)
##  CRAN (R 3.6.1)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
##  CRAN (R 3.6.0)                            
## 
## [1] /Library/Frameworks/R.framework/Versions/3.6/Resources/library