From 2b638865e8eed14f34df0657b5b63493f839cd44 Mon Sep 17 00:00:00 2001 From: Howard Baek <50791792+howardbaek@users.noreply.github.com> Date: Mon, 25 Sep 2023 20:42:46 -0700 Subject: [PATCH 1/6] Deleted `get_gs_pptx(url)`, related to issue #121 --- R/gs_png.R | 1 - 1 file changed, 1 deletion(-) diff --git a/R/gs_png.R b/R/gs_png.R index 9366c03..da09bba 100644 --- a/R/gs_png.R +++ b/R/gs_png.R @@ -97,7 +97,6 @@ gs_png_download <- function(url, output_dir = ".", overwrite = TRUE) { include_slide <- function(url, output_dir = knitr::opts_chunk$get("fig.path"), overwrite = TRUE, ...) { - get_gs_pptx(url) outfile <- gs_png_download(url, output_dir, overwrite = overwrite) knitr::include_graphics(outfile, ...) } From 7fc8f5ff1ce30bab74c0cd55720b3f1523d4371f Mon Sep 17 00:00:00 2001 From: Howard Baek <50791792+howardbaek@users.noreply.github.com> Date: Thu, 28 Sep 2023 10:26:31 -0700 Subject: [PATCH 2/6] Change function names: `get_slide_id()` -> `get_presentation_id()`, `get_slide_page()` -> `get_slide_id()` --- NAMESPACE | 3 +- R/gs_png.R | 32 +++++++++++-------- man/get_gs_pptx.Rd | 6 ++-- man/get_gs_slide_pptx.Rd | 22 +++++++++++++ ...get_slide_id.Rd => get_presentation_id.Rd} | 12 +++---- man/gs_png_url.Rd | 10 ++++-- 6 files changed, 58 insertions(+), 27 deletions(-) create mode 100644 man/get_gs_slide_pptx.Rd rename man/{get_slide_id.Rd => get_presentation_id.Rd} (66%) diff --git a/NAMESPACE b/NAMESPACE index 68aaac3..9499c31 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -29,11 +29,12 @@ export(extract_quiz) export(get_bookdown_spec) export(get_chapters) export(get_gs_pptx) +export(get_gs_slide_pptx) export(get_image_from_slide) export(get_image_link_from_slide) export(get_object_id_notes) +export(get_presentation_id) export(get_slide_id) -export(get_slide_page) export(good_quiz_path) export(gs_id_from_slide) export(gs_png_download) diff --git a/R/gs_png.R b/R/gs_png.R index da09bba..0810f60 100644 --- a/R/gs_png.R +++ b/R/gs_png.R @@ -1,4 +1,4 @@ -#' Get Slide ID from URL +#' Get Presentation ID from URL #' #' @param x URL of slide #' @@ -11,8 +11,8 @@ #' "1Tg-GTGnUPduOtZKYuMoelqUNZnUp3vvg_7TtpUPL7e8", #' "/edit#slide=id.g154aa4fae2_0_58" #' ) -#' get_slide_id(x) -get_slide_id <- function(x) { +#' get_presentation_id(x) +get_presentation_id <- function(x) { x <- sub(".*presentation/", "", x) x <- sub("/d/e", "/d", x) # if you publish by accident x <- sub("^(d|e)/", "", x) @@ -35,15 +35,16 @@ get_slide_id <- function(x) { #' "12DPZgPteQBwgal6kSPP58zhPhjZ7QSPZLe3NkA8M3eo/edit", #' "#slide=id.gc8648f14c3_0_397&t=4" #' ) -#' id <- get_slide_id(url) +#' id <- get_presentation_id(url) #' gs_png_url(url) gs_png_url <- function(url) { - id <- get_slide_id(url) - slide_id <- get_slide_page(url) - gs_png_id(id, slide_id) + presentation_id <- get_presentation_id(url) + slide_id <- get_slide_id(url) + gs_png_id(presentation_id, slide_id) } -gs_png_id <- function(id, slide_id) { +# Get URL to download slide as PNG +gs_png_id <- function(presentation_id, slide_id) { if (any(grepl("^id[.]", slide_id))) { warning( "slide ids usually don't have format of id.gc*, ", @@ -52,15 +53,16 @@ gs_png_id <- function(id, slide_id) { } paste0( "https://docs.google.com/presentation/d/", - id, - "/export/png?id=", id, + presentation_id, + "/export/png?id=", presentation_id, "&pageid=", slide_id ) } +#' Extract Slide ID from URL #' @export #' @rdname gs_png_url -get_slide_page <- function(url) { +get_slide_id <- function(url) { parsed <- httr::parse_url(url) slide_id <- parsed$query$pageid if (length(slide_id) == 0 || nchar(slide_id) == 0) { @@ -73,16 +75,17 @@ get_slide_page <- function(url) { slide_id } +#' Download a slide from Google Slides #' @export #' @rdname gs_png_url #' @param output_dir path to output png #' @param overwrite should the slide PNG be overwritten? gs_png_download <- function(url, output_dir = ".", overwrite = TRUE) { - id <- get_slide_id(url) - slide_id <- get_slide_page(url) + presentation_id <- get_presentation_id(url) + slide_id <- get_slide_id(url) url <- gs_png_url(url) dir.create(output_dir, recursive = TRUE, showWarnings = FALSE) - outfile <- file.path(output_dir, paste0(id, "_", slide_id, ".png")) + outfile <- file.path(output_dir, paste0(presentation_id, "_", slide_id, ".png")) if (!file.exists(outfile) || overwrite) { curl::curl_download(url, destfile = outfile, quiet = FALSE) } @@ -97,6 +100,7 @@ gs_png_download <- function(url, output_dir = ".", overwrite = TRUE) { include_slide <- function(url, output_dir = knitr::opts_chunk$get("fig.path"), overwrite = TRUE, ...) { + alt_text <<- # extract alt text from slide outfile <- gs_png_download(url, output_dir, overwrite = overwrite) knitr::include_graphics(outfile, ...) } diff --git a/man/get_gs_pptx.Rd b/man/get_gs_pptx.Rd index fc1c588..16f0e88 100644 --- a/man/get_gs_pptx.Rd +++ b/man/get_gs_pptx.Rd @@ -2,19 +2,19 @@ % Please edit documentation in R/notes_to_fig_alt.R \name{get_gs_pptx} \alias{get_gs_pptx} -\title{Download Google Slides pptx file} +\title{Download Google Slides as PPTX} \usage{ get_gs_pptx(id) } \arguments{ \item{id}{Identifier of Google slides presentation, passed to -\code{\link{get_slide_id}}} +\code{\link{get_presentation_id}}} } \value{ Downloaded file (in temporary directory) } \description{ -Download Google Slides pptx file +Download Google Slides as PPTX } \note{ This downloads presentations if they are public and also try to make diff --git a/man/get_gs_slide_pptx.Rd b/man/get_gs_slide_pptx.Rd new file mode 100644 index 0000000..146b443 --- /dev/null +++ b/man/get_gs_slide_pptx.Rd @@ -0,0 +1,22 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/notes_to_fig_alt.R +\name{get_gs_slide_pptx} +\alias{get_gs_slide_pptx} +\title{Download a slide from Google Slides as PPTX} +\usage{ +get_gs_slide_pptx(url) +} +\arguments{ +\item{id}{Identifier of Google slides presentation, passed to +\code{\link{get_presentation_id}}} +} +\value{ +Downloaded file (in temporary directory) +} +\description{ +Download a slide from Google Slides as PPTX +} +\note{ +This downloads presentations if they are public and also try to make +sure it does not fail on large files +} diff --git a/man/get_slide_id.Rd b/man/get_presentation_id.Rd similarity index 66% rename from man/get_slide_id.Rd rename to man/get_presentation_id.Rd index fc69f90..40d3174 100644 --- a/man/get_slide_id.Rd +++ b/man/get_presentation_id.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/gs_png.R -\name{get_slide_id} -\alias{get_slide_id} -\title{Get Slide ID from URL} +\name{get_presentation_id} +\alias{get_presentation_id} +\title{Get Presentation ID from URL} \usage{ -get_slide_id(x) +get_presentation_id(x) } \arguments{ \item{x}{URL of slide} @@ -13,7 +13,7 @@ get_slide_id(x) A character vector } \description{ -Get Slide ID from URL +Get Presentation ID from URL } \examples{ x <- paste0( @@ -21,5 +21,5 @@ x <- paste0( "1Tg-GTGnUPduOtZKYuMoelqUNZnUp3vvg_7TtpUPL7e8", "/edit#slide=id.g154aa4fae2_0_58" ) -get_slide_id(x) +get_presentation_id(x) } diff --git a/man/gs_png_url.Rd b/man/gs_png_url.Rd index bc7cc10..099635d 100644 --- a/man/gs_png_url.Rd +++ b/man/gs_png_url.Rd @@ -2,14 +2,14 @@ % Please edit documentation in R/gs_png.R \name{gs_png_url} \alias{gs_png_url} -\alias{get_slide_page} +\alias{get_slide_id} \alias{gs_png_download} \alias{include_slide} \title{Get Google Slide PNG URL} \usage{ gs_png_url(url) -get_slide_page(url) +get_slide_id(url) gs_png_download(url, output_dir = ".", overwrite = TRUE) @@ -35,6 +35,10 @@ A character vector of URLs } \description{ Get Google Slide PNG URL + +Extract Slide ID from URL + +Download a slide from Google Slides } \examples{ url <- paste0( @@ -42,6 +46,6 @@ url <- paste0( "12DPZgPteQBwgal6kSPP58zhPhjZ7QSPZLe3NkA8M3eo/edit", "#slide=id.gc8648f14c3_0_397&t=4" ) -id <- get_slide_id(url) +id <- get_presentation_id(url) gs_png_url(url) } From 7eb2a56aa94f0221d6fe009efbacb556f9469a96 Mon Sep 17 00:00:00 2001 From: Howard Baek <50791792+howardbaek@users.noreply.github.com> Date: Thu, 28 Sep 2023 10:27:20 -0700 Subject: [PATCH 3/6] Leftover from previous commit --- R/notes_to_fig_alt.R | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/R/notes_to_fig_alt.R b/R/notes_to_fig_alt.R index 7640f8a..169a430 100644 --- a/R/notes_to_fig_alt.R +++ b/R/notes_to_fig_alt.R @@ -1,7 +1,7 @@ -#' Download Google Slides pptx file +#' Download Google Slides as PPTX #' #' @param id Identifier of Google slides presentation, passed to -#' \code{\link{get_slide_id}} +#' \code{\link{get_presentation_id}} #' #' @note This downloads presentations if they are public and also try to make #' sure it does not fail on large files @@ -9,7 +9,7 @@ #' @export get_gs_pptx <- function(id) { id <- as.character(id) - pres_id <- get_slide_id(id) + pres_id <- get_presentation_id(id) url <- export_url(id = pres_id) pptx_file <- file.path(paste0(pres_id, ".pptx")) @@ -21,7 +21,7 @@ get_gs_pptx <- function(id) { fr_header <- result$headers$`x-frame-options` if (!is.null(fr_header)) { if (all(fr_header == "DENY")) { - warn_them <- TRUE + warn_them <- TRUE } } if (httr::status_code(result) >= 300) { @@ -38,7 +38,7 @@ get_gs_pptx <- function(id) { } if (warn_them) { warning( - paste0( + paste0( "This presentation may not be available, ", "did you turn link sharing on?" ) @@ -48,13 +48,12 @@ get_gs_pptx <- function(id) { pptx_file } - -export_url <- function(id, page_id = NULL, type = "pptx") { +export_url <- function(presentation_id, slide_id = NULL, type = "pptx") { url = paste0( "https://docs.google.com/presentation/d/", - id, "/export/", type, "?id=", id) - if (!is.null(page_id)) { - url = paste0(url, "&pageid=", page_id) + presentation_id, "/export/", type, "?id=", presentation_id) + if (!is.null(slide_id)) { + url = paste0(url, "&pageid=", slide_id) } url } @@ -227,14 +226,14 @@ unzip_pptx <- function(file) { props_dir <- file.path(tdir, "docProps") props_file <- file.path(props_dir, "core.xml") ari_core_file <- system.file("extdata", "docProps", - "core.xml", - package = "ariExtra" + "core.xml", + package = "ariExtra" ) # copy core.xml from ariExtra to props_file if (!dir.exists(props_file)) { dir.create(props_dir, recursive = TRUE) file.copy(ari_core_file, props_file, - overwrite = TRUE + overwrite = TRUE ) } @@ -302,10 +301,10 @@ xml_notes <- function(file, collapse_text = TRUE, xpath = "//a:r//a:t") { #' } extract_object_id = function(slide_url, token = NULL, access_token = NULL, refresh_token = NULL) { # Get Slide ID from URL - id <- get_slide_id(slide_url) + id <- get_presentation_id(slide_url) # Using Slide ID, create url that we'll send to GET get_url <- gsub("{presentationId}", id, - "https://slides.googleapis.com/v1/presentations/{presentationId}", fixed=TRUE) + "https://slides.googleapis.com/v1/presentations/{presentationId}", fixed=TRUE) # if token not provided, fetch token if (is.null(token)) { From 3288bfd009fb94348a45fa04e8b382cd00fd6454 Mon Sep 17 00:00:00 2001 From: Howard Baek <50791792+howardbaek@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:39:56 -0700 Subject: [PATCH 4/6] WIP --- NAMESPACE | 1 - R/gs_png.R | 1 - R/notes_to_fig_alt.R | 53 +++++++++++++++++++++++++++++++++++++--- man/get_gs_slide_pptx.Rd | 22 ----------------- 4 files changed, 50 insertions(+), 27 deletions(-) delete mode 100644 man/get_gs_slide_pptx.Rd diff --git a/NAMESPACE b/NAMESPACE index 9499c31..b85a401 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -29,7 +29,6 @@ export(extract_quiz) export(get_bookdown_spec) export(get_chapters) export(get_gs_pptx) -export(get_gs_slide_pptx) export(get_image_from_slide) export(get_image_link_from_slide) export(get_object_id_notes) diff --git a/R/gs_png.R b/R/gs_png.R index 0810f60..dffa819 100644 --- a/R/gs_png.R +++ b/R/gs_png.R @@ -100,7 +100,6 @@ gs_png_download <- function(url, output_dir = ".", overwrite = TRUE) { include_slide <- function(url, output_dir = knitr::opts_chunk$get("fig.path"), overwrite = TRUE, ...) { - alt_text <<- # extract alt text from slide outfile <- gs_png_download(url, output_dir, overwrite = overwrite) knitr::include_graphics(outfile, ...) } diff --git a/R/notes_to_fig_alt.R b/R/notes_to_fig_alt.R index 169a430..a1f31f7 100644 --- a/R/notes_to_fig_alt.R +++ b/R/notes_to_fig_alt.R @@ -9,10 +9,10 @@ #' @export get_gs_pptx <- function(id) { id <- as.character(id) - pres_id <- get_presentation_id(id) - url <- export_url(id = pres_id) + presentation_id <- get_presentation_id(id) + url <- export_url(presentation_id = presentation_id) - pptx_file <- file.path(paste0(pres_id, ".pptx")) + pptx_file <- file.path(paste0(presentation_id, ".pptx")) # Only download it if it isn't yet present if (!file.exists(pptx_file)) { @@ -48,6 +48,53 @@ get_gs_pptx <- function(id) { pptx_file } + +# WIP: get_gs_slide_pptx() +get_gs_slide_pptx <- function(link) { + link <- as.character(link) + presentation_id <- get_presentation_id(link) + slide_id <- get_slide_id(link) + url <- export_url(presentation_id = presentation_id, slide_id = slide_id) + + pptx_file <- file.path(paste0(presentation_id, slide_id, ".pptx")) + + # Only download it if it isn't yet present + if (!file.exists(pptx_file)) { + result <- httr::GET(url, httr::write_disk(pptx_file)) + warn_them <- FALSE + fr_header <- result$headers$`x-frame-options` + if (!is.null(fr_header)) { + if (all(fr_header == "DENY")) { + warn_them <- TRUE + } + } + if (httr::status_code(result) >= 300) { + warn_them <- TRUE + } + # don't write something if not really a pptx + ctype <- result$headers$`content-type` + if (httr::status_code(result) >= 400 && + !is.null(ctype) && grepl("html", ctype)) { + file.remove(pptx_file) + } + if (grepl("ServiceLogin", result$url)) { + warn_them <- TRUE + } + if (warn_them) { + warning( + paste0( + "This presentation may not be available, ", + "did you turn link sharing on?" + ) + ) + } + } + pptx_file +} + + + + export_url <- function(presentation_id, slide_id = NULL, type = "pptx") { url = paste0( "https://docs.google.com/presentation/d/", diff --git a/man/get_gs_slide_pptx.Rd b/man/get_gs_slide_pptx.Rd deleted file mode 100644 index 146b443..0000000 --- a/man/get_gs_slide_pptx.Rd +++ /dev/null @@ -1,22 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/notes_to_fig_alt.R -\name{get_gs_slide_pptx} -\alias{get_gs_slide_pptx} -\title{Download a slide from Google Slides as PPTX} -\usage{ -get_gs_slide_pptx(url) -} -\arguments{ -\item{id}{Identifier of Google slides presentation, passed to -\code{\link{get_presentation_id}}} -} -\value{ -Downloaded file (in temporary directory) -} -\description{ -Download a slide from Google Slides as PPTX -} -\note{ -This downloads presentations if they are public and also try to make -sure it does not fail on large files -} From 9226487bb2d9e18b0dc6c23357dc9f3189732e9a Mon Sep 17 00:00:00 2001 From: Howard Baek <50791792+howardbaek@users.noreply.github.com> Date: Mon, 2 Oct 2023 15:04:18 -0700 Subject: [PATCH 5/6] alt_text --- R/gs_png.R | 8 ++++++++ R/notes_to_fig_alt.R | 47 -------------------------------------------- 2 files changed, 8 insertions(+), 47 deletions(-) diff --git a/R/gs_png.R b/R/gs_png.R index dffa819..07d90b2 100644 --- a/R/gs_png.R +++ b/R/gs_png.R @@ -100,6 +100,14 @@ gs_png_download <- function(url, output_dir = ".", overwrite = TRUE) { include_slide <- function(url, output_dir = knitr::opts_chunk$get("fig.path"), overwrite = TRUE, ...) { + # Get speaker notes for ALL slides + all_speaker_notes <- get_object_id_notes(url) + + # Get slide speaker notes + slide_id <- get_slide_id(url) + slide_speaker_notes <- all_speaker_notes[all_speaker_notes$id == slide_id, "notes"] + + alt_text <<- slide_speaker_notes outfile <- gs_png_download(url, output_dir, overwrite = overwrite) knitr::include_graphics(outfile, ...) } diff --git a/R/notes_to_fig_alt.R b/R/notes_to_fig_alt.R index a1f31f7..348bb85 100644 --- a/R/notes_to_fig_alt.R +++ b/R/notes_to_fig_alt.R @@ -48,53 +48,6 @@ get_gs_pptx <- function(id) { pptx_file } - -# WIP: get_gs_slide_pptx() -get_gs_slide_pptx <- function(link) { - link <- as.character(link) - presentation_id <- get_presentation_id(link) - slide_id <- get_slide_id(link) - url <- export_url(presentation_id = presentation_id, slide_id = slide_id) - - pptx_file <- file.path(paste0(presentation_id, slide_id, ".pptx")) - - # Only download it if it isn't yet present - if (!file.exists(pptx_file)) { - result <- httr::GET(url, httr::write_disk(pptx_file)) - warn_them <- FALSE - fr_header <- result$headers$`x-frame-options` - if (!is.null(fr_header)) { - if (all(fr_header == "DENY")) { - warn_them <- TRUE - } - } - if (httr::status_code(result) >= 300) { - warn_them <- TRUE - } - # don't write something if not really a pptx - ctype <- result$headers$`content-type` - if (httr::status_code(result) >= 400 && - !is.null(ctype) && grepl("html", ctype)) { - file.remove(pptx_file) - } - if (grepl("ServiceLogin", result$url)) { - warn_them <- TRUE - } - if (warn_them) { - warning( - paste0( - "This presentation may not be available, ", - "did you turn link sharing on?" - ) - ) - } - } - pptx_file -} - - - - export_url <- function(presentation_id, slide_id = NULL, type = "pptx") { url = paste0( "https://docs.google.com/presentation/d/", From 9666dc0cff101f39968af8bcf55b749c05de671d Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Wed, 4 Oct 2023 10:45:09 -0400 Subject: [PATCH 6/6] Fix auth problem --- R/auth.R | 11 +++++++++++ R/data.R | 1 + R/zzz.R | 4 ++-- .../tmp/encrypted_default_user_creds.rds | Bin 564 -> 900 bytes 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/R/auth.R b/R/auth.R index 2b871ef..9ee9a6f 100644 --- a/R/auth.R +++ b/R/auth.R @@ -12,6 +12,7 @@ get_token <- function() { .tokenEnv$Token } + ### Declare all the scopes scopes_list <- c( "https://www.googleapis.com/auth/drive", @@ -123,3 +124,13 @@ app_set_up <- function() { return(list(app = app, endpoint = endpoint)) } + +set_default_creds <- function() { + decrypted <- openssl::aes_cbc_decrypt( + readRDS(encrypt_creds_user_path()), + key = readRDS(key_encrypt_creds_path()) + ) + auth_from_secret(access_token = unserialize(decrypted)$access_token, + refresh_token = unserialize(decrypted)$refresh_token) + +} diff --git a/R/data.R b/R/data.R index 40c1c60..694af31 100644 --- a/R/data.R +++ b/R/data.R @@ -27,3 +27,4 @@ encrypt_creds_user_path <- function() { full.names = TRUE ) } + diff --git a/R/zzz.R b/R/zzz.R index bee70d8..b7068d4 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,3 +1,3 @@ -.onAttach <- function(libname, pkgname) { - packageStartupMessage("Use the authorize() function to begin. This gives the package the proper credentials to run.") +.onLoad <- function(libname, pkgname) { + set_default_creds() } diff --git a/inst/extdata/tmp/encrypted_default_user_creds.rds b/inst/extdata/tmp/encrypted_default_user_creds.rds index bb436e0f2b7c23275755df39be5d47c6daf0a342..60046ec261fa67782f644fe7de67c6eb0c6f4e1f 100644 GIT binary patch delta 890 zcmV-=1BLvw1cV2FABzY80000000RMS1Csn$3IG5A0{{dA0RRI9000001yxi=EjR!G z0vG@Q10YU?PGqI~MbGtzej4%p?#EuoJe*puagG;MJKZU%zkKUJLNDJU_~%siUJq&6 zaFtpAm`}0}noj@o!N^L!SXP<#>OTS7iy5ZFBtZ>{K8ves)kJ_p%4MyH^NM$07rs>h_VNBuGec76tPG( z)m_P&ef@PU6lp@S5X7g+{y#{&JeNr=;~^%^eUU_<)&L+{RVRBP7c=pQt%hn#c;Aq4 zLh6iUr`c_P`VkW)>;G&8B{C6Or%u&0DJq;6=*{-B3hyAV~DfcWazY^(dfkzG-j0X ztFDIuNoNuSbNnT;F%mKU2d}=klJ{^4v=c#stzi%x?bEI777s}on#c~U_zkwH7Bpbe4O@ZpO=1VHKGgLIT4$O=vokN zjfB*HIHckmNfp}d(R8QA4kmnT-m1a!*rM9}4-HK)VM(&7MHfC)843iG0>&Ky^vWWN zjO&8qP{!L;qZM2fDbuXhXfJTwbtmWnE`ReLFx;&ESUSH(?=1=+*XUg{{f_gJE3oT+ zZC$FC^{y>ZW+6Li!+v7%9sxMNh^&sz{6n387Z|&frYPtxU$n_B7~kw`yPgiOa}G=z zlAqNN2us)W`zeG=V(n@W=uun0YO~&c4!R9Rbg~McR!uwg#!^fUGIVd@rTtd6-)h1?aMll}o392wnJF|7cLSx$@4;_0dj Q&;S4c{syXq>TLr602Pp=V*mgE delta 552 zcmV+@0@wY72ebr#ABzY80000000RLX0^u&QXNwr6z zM!PY=dfQ$SZN>pt+VfW?2v8JIaBW`#SXu5OhMLX?lh&oR_!IS*exSK%V)OZN8X4KC&J+JjgGtfeOmvas(1X zmT7^QH>8DsuI$WT#_{{zpjny5suh5A6=X1W;>T2`gqqtQe|6i#ZPtcI(Ou}2|jk_y{$LMq@r@w>WHv1o@rnI^9KU*;VP_<9k{^ip+QPp)!jw zsb;bXzQGWT%)32NYWS~d;7*EWa)BM&g0Yaqn({vu?%(u=%sOOP(S-gqA`2&Pu0lB3-wMuHG2=Cg(zscccS?> qLLKk|&SR5K0~#F8VhrI{yjVnUl3do{PuI=>00928w}grv0ssKWRQtUE