From 9d1f0943eabb5ffe5399a5c0384c4d02b68c0c0c Mon Sep 17 00:00:00 2001 From: nfrerebeau Date: Fri, 17 Jan 2025 16:41:01 +0100 Subject: [PATCH] Convert S4 methods to S3 and remove plot() function --- DESCRIPTION | 20 ----- NAMESPACE | 14 +--- R/AllClasses.R | 28 ------- R/AllGenerics.R | 57 --------------- R/ArchaeoCal-internal.R | 23 ++++++ R/ArchaeoCal-package.R | 4 - R/coerce.R | 43 ++++++----- R/mutators.R | 20 +++-- R/oxcal_calibrate.R | 2 +- R/oxcal_execute.R | 34 ++++----- R/oxcal_parse.R | 77 +++++++++++--------- R/plot.R | 105 --------------------------- R/show.R | 25 ------- R/validate.R | 30 -------- R/zzz.R | 2 +- inst/examples/ex-oxcal-calibrate.R | 2 +- inst/examples/ex-oxcal-execute.R | 4 +- inst/tinytest/test-oxcal_configure.R | 2 +- man/OxCalOutput-class.Rd | 31 -------- man/as.data.frame.OxCalResults.Rd | 37 ++++++++++ man/oxcal_calibrate.Rd | 7 +- man/oxcal_execute.Rd | 15 ++-- man/oxcal_install.Rd | 7 +- man/oxcal_parse.Rd | 31 ++++---- man/plot.Rd | 99 ------------------------- vignettes/ArchaeoCal.Rmd | 73 +++++++++---------- vignettes/ArchaeoCal.Rmd.orig | 19 ++--- vignettes/figures/plot-1.png | Bin 47133 -> 0 bytes 28 files changed, 240 insertions(+), 571 deletions(-) delete mode 100644 R/AllClasses.R delete mode 100644 R/AllGenerics.R delete mode 100644 R/plot.R delete mode 100644 R/show.R delete mode 100644 R/validate.R delete mode 100644 man/OxCalOutput-class.Rd create mode 100644 man/as.data.frame.OxCalResults.Rd delete mode 100644 man/plot.Rd delete mode 100644 vignettes/figures/plot-1.png diff --git a/DESCRIPTION b/DESCRIPTION index dbb23c5..3ca1772 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -10,10 +10,6 @@ License: GPL (>= 3) URL: https://archaeostat.github.io/archaeocal/ BugReports: https://github.com/ArchaeoStat/ArchaeoCal/issues Imports: - arkhe (>= 1.9.0), - graphics, - grDevices, - methods, utils, V8 Suggests: @@ -25,19 +21,3 @@ VignetteBuilder: Encoding: UTF-8 Roxygen: list(markdown = TRUE) RoxygenNote: 7.3.2 -Collate: - 'AllClasses.R' - 'AllGenerics.R' - 'ArchaeoCal-internal.R' - 'ArchaeoCal-package.R' - 'coerce.R' - 'mutators.R' - 'oxcal_calibrate.R' - 'oxcal_configure.R' - 'oxcal_execute.R' - 'oxcal_install.R' - 'oxcal_parse.R' - 'plot.R' - 'show.R' - 'validate.R' - 'zzz.R' diff --git a/NAMESPACE b/NAMESPACE index dd9d1a4..14b7785 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,16 +1,10 @@ # Generated by roxygen2: do not edit by hand -S3method(as.data.frame,OxCalOutput) -S3method(plot,OxCalOutput) +S3method(as.data.frame,OxCalResults) +S3method(oxcal_parse,OxCalOutput) +S3method(oxcal_parse,character) export(oxcal_calibrate) export(oxcal_configure) export(oxcal_execute) export(oxcal_install) -exportMethods(oxcal_parse) -exportMethods(plot) -import(arkhe) -importFrom(methods,.valueClassTest) -importFrom(methods,new) -importFrom(methods,setGeneric) -importFrom(methods,setMethod) -importFrom(methods,setValidity) +export(oxcal_parse) diff --git a/R/AllClasses.R b/R/AllClasses.R deleted file mode 100644 index 16c8a4c..0000000 --- a/R/AllClasses.R +++ /dev/null @@ -1,28 +0,0 @@ -# CLASSES DEFINITION AND INITIALIZATION -NULL - -#' OxCal Output -#' -#' An S4 class to represent OxCal output. -#' @param ocd A [`list`] of OxCal data which holds the ranges, probability -#' distributions, etc. for each parameter. -#' @param model A [`list`] of information about the model. -#' @param calib A [`list`] of information about the calibration curve. -#' @section Coerce: -#' In the code snippets below, `x` is an `OxCalOutput` object. -#' \describe{ -#' \item{`as.data.frame(x)`}{Coerces to a [`data.frame`].} -#' } -#' @author N. Frerebeau -#' @family classes -#' @docType class -#' @aliases OxCalOutput-class -#' @keywords internal -.OxCalOutput <- setClass( - Class = "OxCalOutput", - slots = c( - ocd = "list", - model = "list", - calib = "list" - ) -) diff --git a/R/AllGenerics.R b/R/AllGenerics.R deleted file mode 100644 index 881699d..0000000 --- a/R/AllGenerics.R +++ /dev/null @@ -1,57 +0,0 @@ -# GENERIC METHODS -#' @include AllClasses.R -NULL - -#' Read and Parse OxCal Output -#' -#' @param object A [`character`] string naming a JavaScript file which the data -#' are to be read from (or a `list` returned by [oxcal_execute()]). -#' @return An [`OxCalOutput-class`] object. -#' @example inst/examples/ex-oxcal-execute.R -#' @references -#' \url{https://c14.arch.ox.ac.uk/oxcalhelp/hlp_analysis_file.html} -#' @author N. Frerebeau -#' @docType methods -#' @family OxCal tools -#' @aliases oxcal_parse-method -setGeneric( - name = "oxcal_parse", - def = function(object) standardGeneric("oxcal_parse"), - valueClass = "OxCalOutput" -) - -#' Plot OxCal Output -#' -#' @param x An [`OxCalOutput-class`] object. -#' @param likelihood A [`logical`] scalar: should likelihood be drawn? -#' @param posterior A [`logical`] scalar: should posterior distribution be -#' drawn? -#' @param warnings A [`logical`] scalar: should warnings be plotted? -#' @param col.likelihood,col.posterior A [`character`] string specifying the -#' color of the density. -#' @param lty.likelihood,lty.posterior A [`character`] string or [`numeric`] -#' value specifying the line type of the lines. -#' @param main A [`character`] string giving a main title for the plot. -#' @param sub A [`character`] string giving a subtitle for the plot. -#' @param ann A [`logical`] scalar: should the default annotation (title and x, -#' y and z axis labels) appear on the plot? -#' @param axes A [`logical`] scalar: should axes be drawn on the plot? -#' @param frame.plot A [`logical`] scalar: should a box be drawn around the -#' plot? -#' @param panel.first An an `expression` to be evaluated after the plot axes are -#' set up but before any plotting takes place. This can be useful for drawing -#' background grids. -#' @param panel.last An `expression` to be evaluated after plotting has taken -#' place but before the axes, title and box are added. -#' @param ... Other [graphical parameters][graphics::par] may also be passed as -#' arguments to this function. -#' @return -#' `plot()` is called it for its side-effects: it results in a graphic -#' being displayed. Invisibly returns `x`. -#' @example inst/examples/ex-oxcal-calibrate.R -#' @author N. Frerebeau -#' @docType methods -#' @family OxCal tools -#' @name plot -#' @rdname plot -NULL diff --git a/R/ArchaeoCal-internal.R b/R/ArchaeoCal-internal.R index f29c2ce..55dde9a 100644 --- a/R/ArchaeoCal-internal.R +++ b/R/ArchaeoCal-internal.R @@ -1 +1,24 @@ # HELPERS + +#' Default value for NULL +#' +#' Replaces `NULL` with a default value. +#' @param x,y An object. +#' @return If `x` is `NULL`, returns `y`; otherwise returns `x`. +#' @keywords internal +#' @noRd +`%||%` <- function(x, y) { + if (is.null(x)) y else x +} + +# Reexport from base on newer versions of R to avoid conflict messages +if (exists("%||%", envir = baseenv())) { + `%||%` <- get("%||%", envir = baseenv()) +} + +assert_exists <- function(x) { + if (length(x) == 1 && !file.exists(x)) { + stop(sprintf("Could not find %s.", x), call. = FALSE) + } + invisible(x) +} diff --git a/R/ArchaeoCal-package.R b/R/ArchaeoCal-package.R index afba820..b8e9799 100644 --- a/R/ArchaeoCal-package.R +++ b/R/ArchaeoCal-package.R @@ -28,7 +28,3 @@ #' @docType package #' @keywords internal "_PACKAGE" - -#' @import arkhe -#' @importFrom methods new setGeneric setMethod setValidity .valueClassTest -NULL diff --git a/R/coerce.R b/R/coerce.R index d8f3d11..c4a803f 100644 --- a/R/coerce.R +++ b/R/coerce.R @@ -1,22 +1,29 @@ # COERCE -#' @include AllGenerics.R -NULL -# @return A [`data.frame`] with the following columns: -# \describe{ -# \item{`name`}{} -# \item{`operation`}{} -# \item{`type`}{} -# \item{`date`}{} -# \item{`error`}{} -# \item{`agreement`}{} -# \item{`convergence`}{} -# \item{`likelihood`}{} -# \item{`posterior`}{} -# } +#' Coerce to a Data Frame +#' +#' @param x A [`list`] returned by [`oxcal_parse()`]. +#' @param row.names A [`character`] vector giving the row names for the data +#' frame description, or `NULL`. +#' @param optional A [`logical`] scalar. If `FALSE` then the names of the +#' variables in the data frame are checked to ensure that they are +#' syntactically valid variable names and are not duplicated. +#' @param ... Currently not used. +#' @return A [`data.frame`] with the following columns: +#' \describe{ +#' \item{`name`}{} +#' \item{`operation`}{} +#' \item{`type`}{} +#' \item{`date`}{} +#' \item{`error`}{} +#' \item{`agreement`}{} +#' \item{`convergence`}{} +#' \item{`likelihood`}{} +#' \item{`posterior`}{} +#' } #' @export -#' @method as.data.frame OxCalOutput -as.data.frame.OxCalOutput <- function(x, ...) { +as.data.frame.OxCalResults <- function(x, row.names = NULL, + optional = FALSE, ...) { data.frame( name = oxcal_get_names(x), operation = oxcal_get_operation(x), @@ -26,6 +33,8 @@ as.data.frame.OxCalOutput <- function(x, ...) { agreement = oxcal_get_agreement(x), convergence = oxcal_get_convergence(x), likelihood = I(oxcal_density(x, prob = "likelihood")), - posterior = I(oxcal_density(x, prob = "posterior")) + posterior = I(oxcal_density(x, prob = "posterior")), + row.names = row.names, + check.names = !optional ) } diff --git a/R/mutators.R b/R/mutators.R index 1c79b4f..c5c300c 100644 --- a/R/mutators.R +++ b/R/mutators.R @@ -1,11 +1,9 @@ # MUTATORS -#' @include AllGenerics.R -NULL # Helpers ====================================================================== oxcal_range <- function(x, na.rm = TRUE) { r <- vapply( - X = x@ocd, + X = x$ocd, FUN = function(x) { start_like <- x$likelihood$start start_post <- x$posterior$start @@ -27,7 +25,7 @@ oxcal_range <- function(x, na.rm = TRUE) { oxcal_density <- function(x, prob = c("likelihood", "posterior")) { prob <- match.arg(prob, several.ok = FALSE) lapply( - X = x@ocd[-1], + X = x$ocd[-1], FUN = function(x, prob) { years <- seq.int( from = x[[prob]]$start, @@ -43,41 +41,41 @@ oxcal_density <- function(x, prob = c("likelihood", "posterior")) { oxcal_get_names <- function(x) { vapply( - X = x@ocd[-1], + X = x$ocd[-1], FUN = function(x) x$name %||% NA_character_, FUN.VALUE = character(1) ) } oxcal_get_operation <- function(x) { - vapply(X = x@ocd[-1], FUN = `[[`, FUN.VALUE = character(1), i = "op") + vapply(X = x$ocd[-1], FUN = `[[`, FUN.VALUE = character(1), i = "op") } oxcal_get_type <- function(x) { - vapply(X = x@ocd[-1], FUN = `[[`, FUN.VALUE = character(1), i = "type") + vapply(X = x$ocd[-1], FUN = `[[`, FUN.VALUE = character(1), i = "type") } oxcal_get_bp_date <- function(x) { vapply( - X = x@ocd[-1], + X = x$ocd[-1], FUN = function(x) x[["date"]] %||% NA_real_, FUN.VALUE = numeric(1) ) } oxcal_get_bp_error <- function(x) { vapply( - X = x@ocd[-1], + X = x$ocd[-1], FUN = function(x) x[["error"]] %||% NA_real_, FUN.VALUE = numeric(1) ) } oxcal_get_agreement <- function(x) { vapply( - X = x@ocd[-1], + X = x$ocd[-1], FUN = function(x) x$posterior$agreement %||% NA_real_, FUN.VALUE = numeric(1) ) } oxcal_get_convergence <- function(x) { vapply( - X = x@ocd[-1], + X = x$ocd[-1], FUN = function(x) x$posterior$convergence %||% NA_real_, FUN.VALUE = numeric(1) ) diff --git a/R/oxcal_calibrate.R b/R/oxcal_calibrate.R index 3b1ec6f..1cbed40 100644 --- a/R/oxcal_calibrate.R +++ b/R/oxcal_calibrate.R @@ -7,7 +7,7 @@ #' to be calibrated. #' @param curve A [`character`] string specifying the calibration curve to be #' used. -#' @return An [`OxCalOutput-class`] object. +#' @return A [`list`] with class `OxCalResults` (see [oxcal_parse()]). #' @example inst/examples/ex-oxcal-calibrate.R #' @author N. Frerebeau #' @family OxCal tools diff --git a/R/oxcal_execute.R b/R/oxcal_execute.R index e0fee45..8b3ee76 100644 --- a/R/oxcal_execute.R +++ b/R/oxcal_execute.R @@ -4,10 +4,14 @@ #' @param file A [`character`] string naming a file (without extension) to #' write `script` to. Output files will be named after `file` and written to #' the same directory. +#' @param mcmc A [`character`] string giving the name of the output file for +#' the MCMC samples (without extension). It must match the `Name` argument of +#' OxCal's [`MCMC_Sample()`](https://intchron.org/tools/oxcalhelp/hlp_commands.html) +#' function. Only used if `script` contains the `MCMC_Sample()` command. #' @param verbose A [`logical`] scalar: should status updates be displayed? #' @param ... Further parameters to be passed to [system2()]. #' @return -#' A list with the following elements: +#' A [`list`] with class `OxCalOutput` containing the following elements: #' \describe{ #' \item{`oxcal`}{A [`character`] string giving the path to the .oxcal file.} #' \item{`js`}{A [`character`] string giving the path to the .js file.} @@ -21,7 +25,7 @@ #' @author N. Frerebeau #' @family OxCal tools #' @export -oxcal_execute <- function(script, file = NULL, +oxcal_execute <- function(script, file = NULL, mcmc = "MCMC_Sample", verbose = getOption("ArchaeoCal.verbose"), ...) { ## Construct output path if (is.null(file)) { @@ -43,24 +47,20 @@ oxcal_execute <- function(script, file = NULL, out <- oxcal_call(oxcal, ...) if (verbose) cat(out) - output <- list( - oxcal = oxcal, - js = sprintf("%s.js", file), - log = sprintf("%s.log", file), - txt = sprintf("%s.txt", file) - ) - - ## MCMC ? - csv <- sprintf("%s.csv", file) + ## MCMC? + csv <- sprintf("%s.csv", mcmc) csv <- if (file.exists(csv)) csv else character(0) ## Output files - list( - oxcal = oxcal, - js = sprintf("%s.js", file), - log = sprintf("%s.log", file), - txt = sprintf("%s.txt", file), - csv = csv + structure( + list( + oxcal = oxcal, + js = assert_exists(sprintf("%s.js", file)), + log = assert_exists(sprintf("%s.log", file)), + txt = assert_exists(sprintf("%s.txt", file)), + csv = csv + ), + class = "OxCalOutput" ) } diff --git a/R/oxcal_parse.R b/R/oxcal_parse.R index 76b465d..130d483 100644 --- a/R/oxcal_parse.R +++ b/R/oxcal_parse.R @@ -1,43 +1,52 @@ # PARSE OXCAL OUTPUT -#' @include AllGenerics.R -NULL + +#' Read and Parse OxCal Output +#' +#' @param path A [`character`] string naming a JavaScript file which the data +#' are to be read from (or a `list` returned by [oxcal_execute()]). +#' @return +#' A [`list`] with class `OxCalResults` containing the following elements: +#' \describe{ +#' \item{`ocd`}{A [`list`] of OxCal data which holds the ranges, probability +#' distributions, etc. for each parameter.} +#' \item{`model`}{A [`list`] of information about the model.} +#' \item{`calib`}{A [`list`] of information about the calibration curve.} +#' } +#' @example inst/examples/ex-oxcal-execute.R +#' @references +#' \url{https://c14.arch.ox.ac.uk/oxcalhelp/hlp_analysis_file.html} +#' @author N. Frerebeau +#' @family OxCal tools +#' @export +oxcal_parse <- function(path) { + UseMethod("oxcal_parse", path) +} #' @export #' @rdname oxcal_parse -#' @aliases oxcal_parse,list-method -setMethod( - f = "oxcal_parse", - signature = c(object = "list"), - definition = function(object) { - js <- object$js - if (is.null(js)) stop("Could not find the path.", call. = FALSE) - methods::callGeneric(js) +oxcal_parse.OxCalOutput <- function(path) { + js <- path$js + if (is.null(js) || !file.exists(js)) { + stop("Could not find the path.", call. = FALSE) } -) + oxcal_parse(js) +} #' @export #' @rdname oxcal_parse -#' @aliases oxcal_parse,character-method -setMethod( - f = "oxcal_parse", - signature = c(object = "character"), - definition = function(object) { - ox <- V8::v8() - ox$eval("ocd={};") - ox$eval("calib={};") - ox$eval("model={};") - ox$source(object) +oxcal_parse.character <- function(path) { + ox <- V8::v8() + ox$eval("ocd={};") + ox$eval("calib={};") + ox$eval("model={};") + ox$source(path) - ocd <- ox$get("ocd") - model <- ox$get("model") - calib <- ox$get("calib") - - .OxCalOutput( - ocd = ocd, - model = model, - calib = calib - # oxcal = ocd[[1]]$ref, - # curve = calib[[1]]$ref - ) - } -) + structure( + list( + ocd = ox$get("ocd"), + model = ox$get("model"), + calib = ox$get("calib") + ), + class = "OxCalResults" + ) +} diff --git a/R/plot.R b/R/plot.R deleted file mode 100644 index 3d4f9bc..0000000 --- a/R/plot.R +++ /dev/null @@ -1,105 +0,0 @@ -# PLOT -#' @include AllGenerics.R -NULL - -#' @export -#' @method plot OxCalOutput -plot.OxCalOutput <- function(x, likelihood = TRUE, posterior = TRUE, - warnings = TRUE, - col.likelihood = "grey", col.posterior = "blue", - lty.likelihood = "solid", lty.posterior = "dashed", - main = NULL, sub = NULL, ann = graphics::par("ann"), - axes = TRUE, frame.plot = FALSE, - panel.first = NULL, panel.last = NULL, ...) { - ## Drop first element (general information) - ocd <- as.data.frame(x) - ocd <- ocd[ocd$type == "date" | ocd$type == "model", , drop = FALSE] - n <- nrow(ocd) - - ## Graphical parameters - if (length(col.likelihood) != n) - col.likelihood <- rep(col.likelihood, length.out = n) - if (length(col.posterior) != n) - col.posterior <- rep(col.posterior, length.out = n) - fill.likelihood <- grDevices::adjustcolor(col.likelihood, alpha.f = 0.5) - fill.posterior <- grDevices::adjustcolor(col.posterior, alpha.f = 0.5) - - ## Open new window - grDevices::dev.hold() - on.exit(grDevices::dev.flush(), add = TRUE) - graphics::plot.new() - - ## Set plotting coordinates - xlim <- oxcal_range(x, na.rm = TRUE) - ylim <- c(n, -0.5) - graphics::plot.window(xlim = xlim, ylim = ylim) - - ## Evaluate pre-plot expressions - panel.first - - ## Plot - ages <- seq_len(n) - # graphics::abline(h = ages, col = "grey") - for (i in ages) { - if (likelihood) { - d <- ocd$likelihood[[i]] - if (!is.null(d$x)) { - yi <- (d$y - min(d$y)) / max(d$y - min(d$y)) * -1.5 + i - graphics::polygon(d$x, yi, border = NA, col = fill.likelihood[i]) - graphics::lines(d$x, yi, lty = lty.likelihood, col = "black") - } - if (warnings && !is.null(d$warning)) { - graphics::text(x = xlim[1L], y = i, adj = c(0, 0), - labels = d$warning, col = "red") - } - } - if (posterior) { - d <- ocd$posterior[[i]] - if (!is.null(d$x)) { - yi <- (d$y - min(d$y)) / max(d$y - min(d$y)) * -1.5 + i - graphics::polygon(d$x, yi, border = NA, col = fill.posterior[i]) - graphics::lines(d$x, yi, lty = lty.posterior, col = "black") - } - if (warnings && !is.null(d$warning)) { - graphics::text(x = xlim[1L], y = i + 0.5, adj = c(0, 0), - labels = d$warning, col = "red") - } - } - } - if (warnings) { - w <- x@ocd[[1]]$posterior$warning - if (!is.null(w)) { - graphics::mtext(w, side = 3, line = c(1, 0), adj = 0, col = "red") - } - } - - ## Evaluate post-plot and pre-axis expressions - panel.last - - ## Construct Axis - if (axes) { - graphics::axis(side = 1) - graphics::mtext(ocd$name, side = 2, at = ages, las = 2, padj = 0) - } - - ## Plot frame - if (frame.plot) { - graphics::box() - } - - ## Add annotation - if (ann) { - xlab <- "Year CE" - ylab <- NULL - graphics::title(main = main, sub = sub, xlab = xlab, ylab = ylab, ...) - graphics::mtext(text = x@ocd[[1]]$ref, side = 1, line = 3, adj = 1, cex = 0.7) - graphics::mtext(text = x@calib[[1]]$ref, side = 1, line = 4, adj = 1, cex = 0.7) - } - - invisible(x) -} - -#' @export -#' @rdname plot -#' @aliases plot,OxCalOutput,missing-method -setMethod("plot", c(x = "OxCalOutput", y = "missing"), plot.OxCalOutput) diff --git a/R/show.R b/R/show.R deleted file mode 100644 index 588bf9b..0000000 --- a/R/show.R +++ /dev/null @@ -1,25 +0,0 @@ -# SHOW -#' @include AllGenerics.R -NULL - -setMethod( - f = "show", - signature = "OxCalOutput", - definition = function(object) { - com <- vapply( - X = object@ocd[-1], - FUN = function(x) { - like <- paste0(x$likelihood$comment, collapse = "\n") - post <- paste0(x$posterior$comment, collapse = "\n") - c(like, post) - }, - FUN.VALUE = character(2) - ) - sep <- paste0(rep("-", length.out = getOption("width")), collapse = "") - - k <- paste(com, sep, sep = "\n") - cat(k, sep = "\n") - - invisible(object) - } -) diff --git a/R/validate.R b/R/validate.R deleted file mode 100644 index a99f2de..0000000 --- a/R/validate.R +++ /dev/null @@ -1,30 +0,0 @@ -# CLASSES VALIDATION -#' @include AllClasses.R -NULL - -setValidity( - Class = "OxCalOutput", - method = function(object) { - # Get data - ocd <- object@ocd - - for (i in ocd) { - name_warn <- if (is.null(i$name)) i$name else sprintf("%s - ", i$name) - - like_warn <- i$likelihood$warning - if (!is.null(like_warn)) - warning(paste0(name_warn, like_warn), call. = FALSE) - - post_warn <- i$posterior$warning - if (!is.null(post_warn)) - warning(paste0(name_warn, post_warn), call. = FALSE) - } - } -) - -assert_exists <- function(x) { - if (length(x) == 1 && !file.exists(x)) { - stop(sprintf("%s does not exist.", x), call. = FALSE) - } - invisible(x) -} diff --git a/R/zzz.R b/R/zzz.R index 910725a..b554858 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -2,7 +2,7 @@ ## Set package options op <- options() op.ArchaeoCal <- list( - ArchaeoCal.verbose = TRUE, + ArchaeoCal.verbose = interactive(), ArchaeoCal.oxcal = "" ) toset <- !(names(op.ArchaeoCal) %in% names(op)) diff --git a/inst/examples/ex-oxcal-calibrate.R b/inst/examples/ex-oxcal-calibrate.R index 33e95ea..69d4aa1 100644 --- a/inst/examples/ex-oxcal-calibrate.R +++ b/inst/examples/ex-oxcal-calibrate.R @@ -9,5 +9,5 @@ cal <- oxcal_calibrate( errors = c(45, 35) ) -plot(cal) +as.data.frame(cal) } diff --git a/inst/examples/ex-oxcal-execute.R b/inst/examples/ex-oxcal-execute.R index c131d89..836067e 100644 --- a/inst/examples/ex-oxcal-execute.R +++ b/inst/examples/ex-oxcal-execute.R @@ -24,7 +24,5 @@ scr <- 'Plot() out <- oxcal_execute(scr) res <- oxcal_parse(out) -plot(res) -plot(res, likelihood = TRUE, posterior = FALSE) -plot(res, likelihood = FALSE, posterior = TRUE) +as.data.frame(res) } diff --git a/inst/tinytest/test-oxcal_configure.R b/inst/tinytest/test-oxcal_configure.R index 116979e..f80f379 100644 --- a/inst/tinytest/test-oxcal_configure.R +++ b/inst/tinytest/test-oxcal_configure.R @@ -1,4 +1,4 @@ if (at_home()) { ## Check that OxCal configure works properly - expect_error(oxcal_configure(ask = TRUE), "Could not find OxCal") + expect_error(oxcal_configure(install = FALSE), "OxCal was not installed.") } diff --git a/man/OxCalOutput-class.Rd b/man/OxCalOutput-class.Rd deleted file mode 100644 index f195c37..0000000 --- a/man/OxCalOutput-class.Rd +++ /dev/null @@ -1,31 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/AllClasses.R -\docType{class} -\name{OxCalOutput-class} -\alias{OxCalOutput-class} -\alias{.OxCalOutput} -\title{OxCal Output} -\arguments{ -\item{ocd}{A \code{\link{list}} of OxCal data which holds the ranges, probability -distributions, etc. for each parameter.} - -\item{model}{A \code{\link{list}} of information about the model.} - -\item{calib}{A \code{\link{list}} of information about the calibration curve.} -} -\description{ -An S4 class to represent OxCal output. -} -\section{Coerce}{ - -In the code snippets below, \code{x} is an \code{OxCalOutput} object. -\describe{ -\item{\code{as.data.frame(x)}}{Coerces to a \code{\link{data.frame}}.} -} -} - -\author{ -N. Frerebeau -} -\concept{classes} -\keyword{internal} diff --git a/man/as.data.frame.OxCalResults.Rd b/man/as.data.frame.OxCalResults.Rd new file mode 100644 index 0000000..efcdd47 --- /dev/null +++ b/man/as.data.frame.OxCalResults.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/coerce.R +\name{as.data.frame.OxCalResults} +\alias{as.data.frame.OxCalResults} +\title{Coerce to a Data Frame} +\usage{ +\method{as.data.frame}{OxCalResults}(x, row.names = NULL, optional = FALSE, ...) +} +\arguments{ +\item{x}{A \code{\link{list}} returned by \code{\link[=oxcal_parse]{oxcal_parse()}}.} + +\item{row.names}{A \code{\link{character}} vector giving the row names for the data +frame description, or \code{NULL}.} + +\item{optional}{A \code{\link{logical}} scalar. If \code{FALSE} then the names of the +variables in the data frame are checked to ensure that they are +syntactically valid variable names and are not duplicated.} + +\item{...}{Currently not used.} +} +\value{ +A \code{\link{data.frame}} with the following columns: +\describe{ +\item{\code{name}}{} +\item{\code{operation}}{} +\item{\code{type}}{} +\item{\code{date}}{} +\item{\code{error}}{} +\item{\code{agreement}}{} +\item{\code{convergence}}{} +\item{\code{likelihood}}{} +\item{\code{posterior}}{} +} +} +\description{ +Coerce to a Data Frame +} diff --git a/man/oxcal_calibrate.Rd b/man/oxcal_calibrate.Rd index 8f15e5d..3dd7bbb 100644 --- a/man/oxcal_calibrate.Rd +++ b/man/oxcal_calibrate.Rd @@ -19,7 +19,7 @@ to be calibrated.} used.} } \value{ -An \code{\linkS4class{OxCalOutput}} object. +A \code{\link{list}} with class \code{OxCalResults} (see \code{\link[=oxcal_parse]{oxcal_parse()}}). } \description{ 14C Calibration with OxCal @@ -36,7 +36,7 @@ cal <- oxcal_calibrate( errors = c(45, 35) ) -plot(cal) +as.data.frame(cal) } } \seealso{ @@ -44,8 +44,7 @@ Other OxCal tools: \code{\link{oxcal_configure}()}, \code{\link{oxcal_execute}()}, \code{\link{oxcal_install}()}, -\code{\link{oxcal_parse}()}, -\code{\link{plot}()} +\code{\link{oxcal_parse}()} } \author{ N. Frerebeau diff --git a/man/oxcal_execute.Rd b/man/oxcal_execute.Rd index 3df7212..f29bc0e 100644 --- a/man/oxcal_execute.Rd +++ b/man/oxcal_execute.Rd @@ -7,6 +7,7 @@ oxcal_execute( script, file = NULL, + mcmc = "MCMC_Sample", verbose = getOption("ArchaeoCal.verbose"), ... ) @@ -18,12 +19,17 @@ oxcal_execute( write \code{script} to. Output files will be named after \code{file} and written to the same directory.} +\item{mcmc}{A \code{\link{character}} string giving the name of the output file for +the MCMC samples (without extension). It must match the \code{Name} argument of +OxCal's \href{https://intchron.org/tools/oxcalhelp/hlp_commands.html}{\code{MCMC_Sample()}} +function. Only used if \code{script} contains the \code{MCMC_Sample()} command.} + \item{verbose}{A \code{\link{logical}} scalar: should status updates be displayed?} \item{...}{Further parameters to be passed to \code{\link[=system2]{system2()}}.} } \value{ -A list with the following elements: +A \code{\link{list}} with class \code{OxCalOutput} containing the following elements: \describe{ \item{\code{oxcal}}{A \code{\link{character}} string giving the path to the .oxcal file.} \item{\code{js}}{A \code{\link{character}} string giving the path to the .js file.} @@ -62,9 +68,7 @@ scr <- 'Plot() out <- oxcal_execute(scr) res <- oxcal_parse(out) -plot(res) -plot(res, likelihood = TRUE, posterior = FALSE) -plot(res, likelihood = FALSE, posterior = TRUE) +as.data.frame(res) } } \references{ @@ -75,8 +79,7 @@ Other OxCal tools: \code{\link{oxcal_calibrate}()}, \code{\link{oxcal_configure}()}, \code{\link{oxcal_install}()}, -\code{\link{oxcal_parse}()}, -\code{\link{plot}()} +\code{\link{oxcal_parse}()} } \author{ N. Frerebeau diff --git a/man/oxcal_install.Rd b/man/oxcal_install.Rd index 54fe428..a1104c9 100644 --- a/man/oxcal_install.Rd +++ b/man/oxcal_install.Rd @@ -53,9 +53,7 @@ scr <- 'Plot() out <- oxcal_execute(scr) res <- oxcal_parse(out) -plot(res) -plot(res, likelihood = TRUE, posterior = FALSE) -plot(res, likelihood = FALSE, posterior = TRUE) +as.data.frame(res) } } \seealso{ @@ -63,8 +61,7 @@ Other OxCal tools: \code{\link{oxcal_calibrate}()}, \code{\link{oxcal_configure}()}, \code{\link{oxcal_execute}()}, -\code{\link{oxcal_parse}()}, -\code{\link{plot}()} +\code{\link{oxcal_parse}()} } \author{ N. Frerebeau diff --git a/man/oxcal_parse.Rd b/man/oxcal_parse.Rd index 3790d30..2b699d3 100644 --- a/man/oxcal_parse.Rd +++ b/man/oxcal_parse.Rd @@ -1,25 +1,29 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/AllGenerics.R, R/oxcal_parse.R -\docType{methods} +% Please edit documentation in R/oxcal_parse.R \name{oxcal_parse} \alias{oxcal_parse} -\alias{oxcal_parse-method} -\alias{oxcal_parse,list-method} -\alias{oxcal_parse,character-method} +\alias{oxcal_parse.OxCalOutput} +\alias{oxcal_parse.character} \title{Read and Parse OxCal Output} \usage{ -oxcal_parse(object) +oxcal_parse(path) -\S4method{oxcal_parse}{list}(object) +\method{oxcal_parse}{OxCalOutput}(path) -\S4method{oxcal_parse}{character}(object) +\method{oxcal_parse}{character}(path) } \arguments{ -\item{object}{A \code{\link{character}} string naming a JavaScript file which the data +\item{path}{A \code{\link{character}} string naming a JavaScript file which the data are to be read from (or a \code{list} returned by \code{\link[=oxcal_execute]{oxcal_execute()}}).} } \value{ -An \code{\linkS4class{OxCalOutput}} object. +A \code{\link{list}} with class \code{OxCalResults} containing the following elements: +\describe{ +\item{\code{ocd}}{A \code{\link{list}} of OxCal data which holds the ranges, probability +distributions, etc. for each parameter.} +\item{\code{model}}{A \code{\link{list}} of information about the model.} +\item{\code{calib}}{A \code{\link{list}} of information about the calibration curve.} +} } \description{ Read and Parse OxCal Output @@ -51,9 +55,7 @@ scr <- 'Plot() out <- oxcal_execute(scr) res <- oxcal_parse(out) -plot(res) -plot(res, likelihood = TRUE, posterior = FALSE) -plot(res, likelihood = FALSE, posterior = TRUE) +as.data.frame(res) } } \references{ @@ -64,8 +66,7 @@ Other OxCal tools: \code{\link{oxcal_calibrate}()}, \code{\link{oxcal_configure}()}, \code{\link{oxcal_execute}()}, -\code{\link{oxcal_install}()}, -\code{\link{plot}()} +\code{\link{oxcal_install}()} } \author{ N. Frerebeau diff --git a/man/plot.Rd b/man/plot.Rd deleted file mode 100644 index 5cd9d53..0000000 --- a/man/plot.Rd +++ /dev/null @@ -1,99 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/AllGenerics.R, R/plot.R -\docType{methods} -\name{plot} -\alias{plot} -\alias{plot,OxCalOutput,missing-method} -\title{Plot OxCal Output} -\usage{ -\S4method{plot}{OxCalOutput,missing}( - x, - likelihood = TRUE, - posterior = TRUE, - warnings = TRUE, - col.likelihood = "grey", - col.posterior = "blue", - lty.likelihood = "solid", - lty.posterior = "dashed", - main = NULL, - sub = NULL, - ann = graphics::par("ann"), - axes = TRUE, - frame.plot = FALSE, - panel.first = NULL, - panel.last = NULL, - ... -) -} -\arguments{ -\item{x}{An \code{\linkS4class{OxCalOutput}} object.} - -\item{likelihood}{A \code{\link{logical}} scalar: should likelihood be drawn?} - -\item{posterior}{A \code{\link{logical}} scalar: should posterior distribution be -drawn?} - -\item{warnings}{A \code{\link{logical}} scalar: should warnings be plotted?} - -\item{col.likelihood, col.posterior}{A \code{\link{character}} string specifying the -color of the density.} - -\item{lty.likelihood, lty.posterior}{A \code{\link{character}} string or \code{\link{numeric}} -value specifying the line type of the lines.} - -\item{main}{A \code{\link{character}} string giving a main title for the plot.} - -\item{sub}{A \code{\link{character}} string giving a subtitle for the plot.} - -\item{ann}{A \code{\link{logical}} scalar: should the default annotation (title and x, -y and z axis labels) appear on the plot?} - -\item{axes}{A \code{\link{logical}} scalar: should axes be drawn on the plot?} - -\item{frame.plot}{A \code{\link{logical}} scalar: should a box be drawn around the -plot?} - -\item{panel.first}{An an \code{expression} to be evaluated after the plot axes are -set up but before any plotting takes place. This can be useful for drawing -background grids.} - -\item{panel.last}{An \code{expression} to be evaluated after plotting has taken -place but before the axes, title and box are added.} - -\item{...}{Other \link[graphics:par]{graphical parameters} may also be passed as -arguments to this function.} -} -\value{ -\code{plot()} is called it for its side-effects: it results in a graphic -being displayed. Invisibly returns \code{x}. -} -\description{ -Plot OxCal Output -} -\examples{ -\dontrun{ -## Download OxCal -oxcal_configure() - -## Calibrate 14C dates -cal <- oxcal_calibrate( - names = c("X","Y"), - dates = c(5000, 4500), - errors = c(45, 35) -) - -plot(cal) -} -} -\seealso{ -Other OxCal tools: -\code{\link{oxcal_calibrate}()}, -\code{\link{oxcal_configure}()}, -\code{\link{oxcal_execute}()}, -\code{\link{oxcal_install}()}, -\code{\link{oxcal_parse}()} -} -\author{ -N. Frerebeau -} -\concept{OxCal tools} diff --git a/vignettes/ArchaeoCal.Rmd b/vignettes/ArchaeoCal.Rmd index 4ca3a7a..978a790 100644 --- a/vignettes/ArchaeoCal.Rmd +++ b/vignettes/ArchaeoCal.Rmd @@ -1,7 +1,7 @@ --- title: "Introduction to ArchaeoCal" author: "N. Frerebeau" -date: "2023-12-04" +date: "2025-01-17" output: markdown::html_format: options: @@ -16,29 +16,37 @@ vignette: > -This vignette uses data available through the [**ArchaeoData**](https://github.com/ArchaeoStat/ArchaeoData) package which is available in a [separate repository](https://archaeostat.r-universe.dev). **ArchaeoData** provides OxCal [@bronkramsey2009] input models. +This vignette uses data available through the [**ArchaeoData**](https://github.com/ArchaeoStat/ArchaeoData) package which is available in a [separate repository](https://archaeostat.r-universe.dev). +**ArchaeoData** provides OxCal (Bronk Ramsey, 2009) input models. -```r +``` r ## Install the latest version install.packages("ArchaeoData", repos = "https://archaeostat.r-universe.dev") ``` -```r +``` r ## Load package library(ArchaeoCal) ## Download OxCal -oxcal_configure() -#> OxCal binary found at /tmp/RtmpDY8HDa/OxCal/bin/OxCalLinux +oxcal_configure(ask = FALSE) +#> Could not find OxCal binary at /tmp/RtmpCaliqV/OxCal/bin/OxCalLinux +#> Could not find OxCal binary at OxCal +#> Attempting to download OxCal from https://c14.arch.ox.ac.uk/OxCalDistribution.zip. +#> OxCal successfully downloaded and extracted to /tmp/RtmphxBObr/OxCal. +#> OxCal binary found at /tmp/RtmphxBObr/OxCal/bin/OxCalLinux ``` -```r +``` r +## Construct path to file +path <- file.path("oxcal", "ksarakil", "ksarakil.oxcal") +file <- system.file(path, package = "ArchaeoData") + ## Read OxCal script from Bosch et al. 2015 -path <- system.file("oxcal/ksarakil/ksarakil.oxcal", package = "ArchaeoData") -scr <- readLines(path) +scr <- readLines(file) ## Print script # cat(scr, sep = "\n") @@ -50,37 +58,28 @@ out <- oxcal_execute(scr) #> MCMC analysis #> Sort Burn Trial Save Shrink kPasses Done Ok Convergence #> [.] [.] [.] [.] 3.0 10.0 100.0 100.0 -#> [.] [.] [.] [.] 6.0 20.0 100.0 6.8 -#> [.] [.] [.] [.] 12.0 22.2 100.0 14.4 -#> [.] [.] [.] [.] 24.0 22.2 100.0 6.2 -#> [.] [.] [.] [.] 48.0 22.2 100.0 43.2 -#> [.] [.] [.] [.] [.] 96.0 22.2 100.0 64.5 -#> [.] [.] [.] [.] 192.0 22.2 100.0 80.3 -#> [.] [.] [.] [.] 384.0 22.2 100.0 83.2 -#> [.] [.] [.] [.] 768.0 22.2 100.0 70.5 -#> [.] [.] [.] [.] 1152.0 30.0 100.0 95.8 -#> [.] [.] [.] [.] 1536.0 40.0 100.0 85.1 -#> [.] [.] [.] [.] 1920.0 50.0 100.0 85.1 -#> [.] [.] [.] [.] 2304.0 60.0 100.0 85.1 -#> [.] [.] [.] [.] 2688.0 70.0 100.0 85.1 -#> [.] [.] [.] [.] 3072.0 80.0 100.0 85.1 -#> [.] [.] [.] [.] 3456.0 90.0 100.0 85.1 -#> [.] [.] [.] [.] 3840.0 100.0 100.0 82.4 -#> [.] [.] [.] [.] 4224.0 110.0 100.0 82.4 +#> [.] [.] [.] [.] 6.0 20.0 100.0 0.0 +#> [.] [.] [.] [.] 12.0 22.2 100.0 4.7 +#> [.] [.] [.] [.] 24.0 22.2 100.0 25.5 +#> [.] [.] [.] [.] 48.0 22.2 100.0 42.5 +#> [.] [.] [.] [.] [.] 96.0 22.2 100.0 59.4 +#> [.] [.] [.] [.] 192.0 22.2 100.0 5.8 +#> [.] [.] [.] [.] 384.0 22.2 100.0 50.7 +#> [.] [.] [.] [.] 768.0 22.2 100.0 93.6 +#> [.] [.] [.] [.] 1152.0 30.0 100.0 94.4 +#> [.] [.] [.] [.] 1536.0 40.0 100.0 94.4 +#> [.] [.] [.] [.] 1920.0 50.0 100.0 90.0 +#> [.] [.] [.] [.] 2304.0 60.0 100.0 90.0 +#> [.] [.] [.] [.] 2688.0 70.0 100.0 90.0 +#> [.] [.] [.] [.] 3072.0 80.0 100.0 90.0 +#> [.] [.] [.] [.] 3456.0 90.0 100.0 90.0 +#> [.] [.] [.] [.] 3840.0 100.0 100.0 90.0 +#> [.] [.] [.] [.] 4224.0 110.0 100.0 90.0 ## Parse OxCal output res <- oxcal_parse(out) ``` - -```r -par(mar = c(5, 6, 1, 1) + 0.1) -plot(res) -``` - -
-plot of chunk plot -

plot of chunk plot

-
- ## References + +Bronk Ramsey, C. (2009). Bayesian Analysis of Radiocarbon Dates. *Radiocarbon*, 51(1): 337-360. DOI: [10.1017/S0033822200033865(https://doi.org/10.1017/S0033822200033865). diff --git a/vignettes/ArchaeoCal.Rmd.orig b/vignettes/ArchaeoCal.Rmd.orig index b6589a0..c8b795b 100644 --- a/vignettes/ArchaeoCal.Rmd.orig +++ b/vignettes/ArchaeoCal.Rmd.orig @@ -25,7 +25,8 @@ knitr::opts_chunk$set( ) ``` -This vignette uses data available through the [**ArchaeoData**](https://github.com/ArchaeoStat/ArchaeoData) package which is available in a [separate repository](https://archaeostat.r-universe.dev). **ArchaeoData** provides OxCal [@bronkramsey2009] input models. +This vignette uses data available through the [**ArchaeoData**](https://github.com/ArchaeoStat/ArchaeoData) package which is available in a [separate repository](https://archaeostat.r-universe.dev). +**ArchaeoData** provides OxCal (Bronk Ramsey, 2009) input models. ```{r ArchaeoData, eval=FALSE} ## Install the latest version @@ -37,13 +38,16 @@ install.packages("ArchaeoData", repos = "https://archaeostat.r-universe.dev") library(ArchaeoCal) ## Download OxCal -oxcal_configure() +oxcal_configure(ask = FALSE) ``` ```{r excute} +## Construct path to file +path <- file.path("oxcal", "ksarakil", "ksarakil.oxcal") +file <- system.file(path, package = "ArchaeoData") + ## Read OxCal script from Bosch et al. 2015 -path <- system.file("oxcal/ksarakil/ksarakil.oxcal", package = "ArchaeoData") -scr <- readLines(path) +scr <- readLines(file) ## Print script # cat(scr, sep = "\n") @@ -56,9 +60,6 @@ out <- oxcal_execute(scr) res <- oxcal_parse(out) ``` -```{r plot, fig.height=9} -par(mar = c(5, 6, 1, 1) + 0.1) -plot(res) -``` - ## References + +Bronk Ramsey, C. (2009). Bayesian Analysis of Radiocarbon Dates. *Radiocarbon*, 51(1): 337-360. DOI: [10.1017/S0033822200033865(https://doi.org/10.1017/S0033822200033865). diff --git a/vignettes/figures/plot-1.png b/vignettes/figures/plot-1.png deleted file mode 100644 index 926b2b3a1890d18e8514e41f93edb163ea611c50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47133 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 z z2nh$uo&9RGiMKwuGN2yhNSwEAn~~Bf1`Nd20yScE13Mx_f$X>?#>J=u>tN?$@V{yL zt;sy#`k}}hlqp*Ki+*>~5MJorzab}M*05`6hdX`99UzkBqCW<4Afgr^;(p;^QbY+a zTzO-qs|LA6eQ>P@4**ogr>D{0fyA}7wF{N}U)b2J^e~NRv z*MmFg<-<*(yqgFEcXrXNyu=d|ZeQjv$Xpc!HSLxIVj#YwMq+Mqa-rL-X>P~C(8lJs zZ;_J#3lcIw+5$Qt>Dpq8F_HPtE<(V+t)pf;J_^m?CtesA1)5y+J`vb~8swlOH_L z_|$u7_pUIAYIxev9y#8#xk!D>lHv)3XddcvyGrlL?b|5ukE!8r=iy#mLuIFgqn%J|4;wo>9?^j{^n&OML!VK?iInyKXzfkl zYVOy)|COm_N)bZQq-4z0ASy`;WeS7M&sDz|QM7j;h7?mbXGL$izB^jbY zM5X@kpL?HSpXZ$Oob!7A>vg~Ow(VQi`mOJ9U7zWqe`iNfLGH_do-||~kX1Re(RG~j zouzPQ)$iwsL~a8Pk7}Sh1+8ZdfXC5G`bsGvQ!htBbafW4r(?qx)n}I2o#{pKCZMRC zt;_gl)215~vs$dBdRC%MF7bW%Z%0e{4mf*KeiDsk1d^=2n0X-|%&LS_iN6Ug6;3z8 zJ}zGLstJ6J8f-gTWcFrYMHYb=*gLc$Idlt!jzW;uU~pWhrAbw7S& zR@9}H*a63W{rc6Z+Pn|fpR{<0>;Z@Itca}}H{RicApZkO#QS#qOT~}}Po7Y<9}S+@ zYq>L-5kY46I^v{C1DJm8c zaDG9?t{gOC#l03v1v)CQZrgajv*%-D19B@VnZae%6)F_`Dfv-u#D zy7Cql$z+FW#c7S>HkRa%UfYQg2jm583mI)Mn5lgqC97B>rp zO$+-OYf{dKZDDWU+OXq*C>*&lT1J^gqlE9?b4UZ--8+MDUDx->BvLEtDA%d5mhznf zvf0?2p+Z8L?CUETL|$A{4y*uuP+(GyCM5-VU4Gz63xvKG#tNj}`XWU-&y*sJwPSlV z`YiUFR}UXvg2kFc?BeXfC%H+rOr5%VQ|6Is@*+2P#?$?#LCE*HFricm3ie*RcIvOc z#EW*C^$}V7o3%cFWQ|(u(JJ}@j+BK@@0f^KF4!0ouDDw)h#g72%`vmL@wN%nY!{a z+D7CiGDe*BCr;ctaG)0zuIfoykzprO+epbN53;k53&3JF;YLRJdC!&@olE;}B}xg~ zAD5SvnTcO{cFc2{0$*=$PU!A^*O2dr1fP7TchSfu;|<)lZ$IGC02!2*H@kf8+_{H= z1u0B#ILQ3ylBA?UA-1dex^QgN)KppBp-SN(+9i##Zn8M$;^*|30iu*b>4lL7n?G6F z*}bDy;nKkW#WE$PCLpU)+C!s`}SU`OUx`R`b;ugwqOBiu6q>fn}7XshfheKde~I8eA#{urD%(jhg-vB zsqI++hoq4_IcgYo~9 z#E|T@}nG$aqrenq&VsR+z+%pq=>~;q9!YM zy;{)z;+YZZ1n~;C(N(Lo$WfheQb@#=n0NE`ZHTAkiEeQ?dXY~*dD27J*RYWY*w1p! z_>(pwBO@arA;B{q-e(=U==7;JKX?TKVGQBq~IRD~H@1kU}2lQ^6fVfw23#AHulN2)?wm zNEEqx`}Qnza|{HkL8eG(A3u0NZmy7wMBj+b^@EAfdGzZCXp>#;%qjow{rkPr{m1ll z1ta2BJ*eN@ube^%XRI1qXsM@6Q42D4a*EX&H}Qc@oa#vhk>Q*D=kmseKIG`&8Z8$` zJn1{|a@UI!1F{k}eVmJ(&-TxYq7OnXBo~%`Bq;re5zB5l_VdfwURx&72NFo!VGre< zU&aK_)#|QQ|L;X|49U=ux@xD-#@>iiN#ykqu>5VTPR`Zul;Nrr!Ay) zb8)$bfbG`expT*Cd~4UK0u%qpUco&&wGCi(b&{STl+8$5Fi)Vp{rvUomCKjAckWC^ zvb;3<2ijtb8V(_?3d6-<}xYf*Y=(A#-rQpC89g z(1(4rv%4lcIo06101{)vaxM$L`1lcz`L@xGphnvrMepW##;qBUa*>Z|BB)cB2({%EwMXeu}hM+x-yrPE(|Es z&sm_lN$+7GJ21Cvhdp#6$=km_$jGQHy0bTARPzD9^d*ZIV;H1B;j;R<^PZt1Izb}3 zw{F?Ow~luE9u~_V-|>!84G}oYE+zYd!)QnCqf3}KJ9kMM&g0=&3=RoN-t1RjyKZrpp>94i->n|u(Kn_AT1~Oq?u~}mkpf? zPi36=7cGEDWTN&f#LMgU!WAn5Chb>KpZ4PE;tRyo{e68=p-R2-aLLvW5y-;v<55t( z_K@GCNOF!Hke;xm`nX|A^lUM8sN5Lp&;U`vAgDk%IpqX*)fK)PRai$gmJ!kfE6Nd?3T9$;hTgWf{ub|%*-&&*d|J}Ieh z2vs&5jQh`WUpTb~4WfH$|M}Hu*u0?h6u^pFba`36aQ)ZEL zaj|#Syyq_n{LNv550Dn}-02viqa|xp$-m$WsVw^uJjH~Ao;C5Ay`~zR!`(yo-G9UE z{)vbVs9)3Oj|>rV6j^ZiUh!=8YGY_75ef{X0!kS^jo>x%R8oQdgh)I!_>@CH46&#kUq!iBCPw^@es#%iRIPPs$q4MJxU zrbMaHTfdcS8JY)o(GFnK2#>Y%W}p83vw|?qa3t(NzT7&n4+PVZv4<9OHdzqGcQ+Gj zjodn|wJ+W%hqY^6bi%1SKvK-Us*9{0CwJ|jL3eqLhP7NjquiOxO^CBUd;0X;dBJlQ ztmP>d*;lW zvgQv&>I_bd>uvF@y+~7lZE5jNl{ikF+EiB9#=$c(aYJNu^uoo9C%k_xA&Qa$w`Bwb zvMm385uFFz?u@HT{Ny7x%H&Nzui_=)y4k!n+|orFb{l_9Ua4V1;&*4F=AV z-`VWBZJVwv(m#;^<8wa%4&XbbUBtiTj%CfJN#?$)zWzX873Vu&&NSNCaP2lUG+edk zDxzkWkU%k=7dZt-oNb`G$Z-0;b9ty^sPIN0{ALn{Y?qA8Of}|7w%Y#2xE+-+@Z?+3aZ$)}wCj;3y|G37_FMfqn^o_pYBgs`^tB~Y zch;;PQog+oSuI)w-JO3N4J2CK{uAWd*Dl{SC}H8;nCA#^fs-jf`uGW=Vc~~V)I@k^ z4V&ocQB^r(YW~LjVR3SF@e&4brPzY-F9+>^{7|%OPMtot7ZeJHLL@`J>923B2_^tg z$D>2t$C|1+FxY%5^C$5vdJ8e6Qte0-* z{rn@-hbt0b98u5{9QPYG^vSAGlp_9X&Dx=3#{b@J@+_mm?98Czd+uR5c2fIRkZu=X z(7JB~VHP|L74OsgM~iBX@{kCuU?Dxq$$`%MPKYF_wM5+BuhZK%W#&x(#KbX1`%Luw zq!%Z9O!`q1MF;Swh4hlB<0v4P?T%*~#qZUt(h1Hsj*d&wl)a1rW_brArt4IasGzrn z+lVLn@c3vI4GpuI25BE?aXBRH?Je~ZUYPW5G@w;;b8}IU6K|xbq!fAmdan|Ljw#LU?=F0B_z%?wYCr$yd5HjoE(i_yi+~tpIM&?K3uG~tS%Of*RXu_i!#twL$UiEFwxJklh z{(4jesD@^;_ktg(Pv%0w3z$9qm{)Ny2CO zg3z#0VMO{BW}$fA^x%j_+Wa96qC|sC&&KHw`FbJuB_B?FceOe`k14(wHh~rrPu6P)Vh6 z@mvl&Av+}pB}wTH=>@HX(WH0pkFXtu>yPJFQl=lyu`3tvHUtMme3hntP(oDkLZ=40 z3B5oeT`Mi})MTA^r!Sq(-=rJffAHWD<;e$1K5(cP#Hs=az2&`~6&iz2{@=bHZMR#I zKsq)t5JTE1{>~|hNl#YURgW6FomTp}_B0i5=>q`)!aCnISuI%ir=+CF-+*UQi5C^b z8Z^N8*#MW>x14o$cFAxlN%V5+RYbaPwTsGu96NH`{FL;VpVY6ac-W%hFF7)f9yx+} zmXhGekt1ktc%wQVk{f?Aq-E{eF*k0!3_a0msya0B(ZYLet<5+RyANb*y?Xkz=kL-E zBDs)Ei0c2W#Mk||pQAQY({ka8-Iwp)xdYtRz3;=SZ-TKI|J>HCjY{oX>jFH<V}2i91qUEFx*MeK^cAt8tcw~n&9dNU!xzV7Yy>C=NxP5f1!6YL6e zX{>zEqRl_I^2hhV4{}|XE%TD=wnNg_)8m)@XDWgTdU_!vmVkp&C-jz)iNnhS)_!T2 z6uEY!Zu|K7L~ZRW(p-BQ7Afb!gQogizq@zGe)%#?YeUfx0pNcswOBFx6n|#u{CRVN zO7ijmSwI3rU6QIlB25fFJM*~p5U%>af7hZo`xIwdMONo=Ct9^jO(#Hf50{4T@J*M| zA3Hu}SD#g&3v?1^6TSm%qC7kJHT-EhLM4-DA)ES$M4_W!MsFx7NUJV}>K;4xIx^Q% zn-eSEqJitU$HP1D@|XU907VI>`5*p?QjnYncoTl|QAKU7V9wkh#TYmmd!44Q^3fd|4d%`0@5~*EAKVrG5MN z3#QMW%yN!%%+{(u{2Hn_D82Ke+hVdw6EO^H3KNr;NFPPr`);-Uw{S2cs5! z&zppql$b|v$&Ml-8?D)em>9ATx~?i^IMt_!m+>rszbRb_e^FMpskKbMsfiemDlxO%nev+PItA#l-&5~o+g+nj z4G4JR-MJTTeWYUuNBea%VJe4@&s6ee_Z#>0n0jMb|5e`E5;?hnpVqdMnr29Vhg+V* z4H@OQ+rGg$y^N+@d>K2+WlQT&W#v6j+HyyYkPv0x(C*s=Ii(f09$Oo(L4ceM8}Nz~ zv-s*&^xPP+QoG%|rc!`@{M^>49O*pydEkhL(ni2B?av#Dkr!8+zvR)mE$iDAju7bX z1wGEztyxk}MxXiev^8Nzy0MhS^1YX=HYzO1dlqI-NxZZGNWgri-ROTSik-iwfM4X4S<83uwj=7ro^c4m+|S#7jk)`ueLQ?0|NjXavfq<<`?Y`d@Q`7 zxkIq=jq7g?Tbo{PJZ)N|Ak2!oB#?e9?mg^@($>|gK&JmQ%62)qpRu0H8oo7W6>Gagp)P@W(MWL5rb5h@Zd%P)XQDF#9=-4c5aPuYzTs#;ubqi{Zt^P+kvr^F*EtoyK_o0X3zhaLLTd42ZD&Nfb zq5~GMk~}5})TmcoDk}>qgHK;21V%E-S@(;2Z3+4O0M7k>T6>F9HVo9|R6|FG(DnnK^KP_RH*?Ii>H1b?I^=OuPK@Tv6gQq$OAB zTh7gBi*u=5zxjJ|-f*#Rx~tA&*qik6DhNHsI)5_ROYt=8xU@y|tlt+`ymKk!8TFY4 z3#Fm@;`ayc$JQ;XY#jH{wbXqe$+u=kKcfKSpCD6Cx%~Y6vxmRPC16cnsZ{4=xy@VJ zXb+!qjs^Oz%TagpNsjIK2LgX?42vBMKOZH&Pi~-PpD^NG0#l!HP zac$vSA@8YkFaOq(t<3jYQWypKk#F8vqw_J>UNkY>MQ_~BVE`^V=KOpzR%pcL} z)|z{@BgZ~G^}9H`JNn0py*G+BkLB2<^WcEyo?97U*6rnP60MTXo%1nPCc4e0!YcMb z@*8!@3eNhh3PkNVHBd{UAv0MyD04P0(0i@bTSF&Lo%$+0U0+>&^^LjhM5ZIw=$?Uk z!ot6ZH%oC07_Yd!=ld@^=HE+Vje~2z7g2_fy7%+#vg?Cfp%g4E3QO!ewVQnCNkkK^ zc>Z)Agz!{x3lNq91S88zFHSZ@?gY>pM%*e3c6gv>C5H6HU zNN&J@!q>04NqOH&-V}(xTUtyuP9a%mml3l~D#CAs-(|9`t3N;lot`~}3aVf&FaviH7xZ3%-p%~_vM)SsO8hvffDcohE^OVjsfAn)&IYf` zFd?*d6m5n^F=jp>9n0fuE!e1*(g^Dk-yBE zkIOa2#V0BVc1FCaM$}Bg!qx6TBM^KRu2Cq+q)v=p`XxhIL4k z8Poahc^o-)%FN|j^xr=-W>^FJ<>yZ~KpUc7`O{HRBv$^N^nQ$5uy|v= z+KC>JQ1IQ-*g?2fNB_98a9}`4XlRbLCQ!=WOZAlFf(mWM3)sEveH1=oMP>2bF=ZO<{ z#=oXCK;3|=6nYkc1Bw91SSq{YUk=^a_Wje*yLWYsOeaTHuy(;q2|^&I9#>5#NpUO`xj*(7#IA1+zVLpTX*j^VL-9H z;WYO=R4JEqsgw48L;@@>+271QXW%H!MWs?W8C!_Q^k1b zhYtM;a}qA-Blewq7x1B!^DOQ)aV{<3i_<6cea&=%g_h5~Mxd{?x8G)}HAs|F5V+e2 zLF0V5YPd9wA&H-Jzm>QO9I{VOovZHPje^KD}e8|JlvOAsUH7B*|TgP_0@7zgtHlC6`0UhHW4f^c8a$Vh--Er_> z_oLHKqPWB>j2y^0h*O1!g(7!~$0y=`n!QM5G5WyW8gJ12yRp>QUv@hLm4m|vvFjlr zG*-2z*(T#9h1=sx)P8qkc3-S;&o&rzL07Y~>n_XNO)sp-8v5AdM#miaPT1FE*7V&RpgA2D^Xz&WWU=8@}9cmkyly9Hl6G*nK z7!hvXJ?`1ex?nR&EpAFZjSv+c6_Yeg%t!2(^etNW2t}osw*?Ubc?HD?Bg|e@DcL69{!om4mdLO2Ub$ zPFmGLNf=wit9*^Gk_!IONOJSb>!Q`YOpd!IHYK+;CzpDBR+zZK(Xr&&b+_tooTP)} zWVe$M!JZ5XQj#zK_ABk|=9Nbo+yLmjh#%$cMuV=?2h;f0FcHqHu>dCFVx znB9hg0B-@%NCG0Ra<#qwc5zlHnDOt7(bU8aJ!kIR?ZmgS#AiT>5Lp;{^o8`RWk?DS z97w8tg`j8#v@rHGXaImY4t$;%g*Cot7Ge7|L`ZzaoXc_ZITGO}0DSY0lcR_mf}@TE zGt%@>?R4?kBMlawzz_wlWRpWowqcYZFRDa_y6_9@F`?;?bVv4oH zB8?!czOb+mEOOiXhy5Jo6V4F5^-kMF>c@|uYi}`?8ZZvRP?1r2T%(R!dc%hCXM}>q z=$Fmcq5*X8>Fy!Zu`GB%Ru5EA7`6V(sBYbD@eBc5@?xx2xAp4ezuTSPF<5Rgxjgvn z1q{2q&W+58s&C9Jph}tX4U4W#R{-cK_cA()6#Y);F~&nja@u;4Nb~XJNJ&UVsV=C; z{9WhH5hh+Z>o96Zrc{l>Wr*zbHET3(Encz00KxtrnLGLWK>YV_V|@!8j^4{g*)edx zG~u@Yc_nf4Z?mJ>Y6+3t__@nI5O&D8pV&*6s>{j{?2<>gi7%=8ERHgYC>3vkI{Bl! z^bTl&tABiA{IH1=i*jk3&gMSnDp>&(z@QkkU;UdW9qtT@SX_3V3hDLWB%ga! zkpH2OMlf{W;+CQ}v^)B+r$t58U%t4b^C!qcLE$8V9NUNkTG_I5EiGFZT5*e(jekCT za3ElIbcxEMISUs?UrL><+kW-fXWa$G=Cle7HcpAG|?Rb9A}${Px=sxY>m?^w~afVDi?Q<&-C2 zZ34y;$lFF`ynTBUr{mjyUvK=`a>VE0pjy3Jy~)*U<{Ww|A~ml~&;ke~h_ z_u`zGzaT?HHW3w_uXJU(cFjm7B_Z((bBVe62uz=PYrIY-VgD$Ivz0WW%eAGt=0}N@ z{_oXCP`+Hvkp_-^HR+~t<1epWTV|mu%Iy4c(ix`>8weI=70XMhPndxFsjt$z|FR63 z_p|5W)c>XmxrDxnRRkI-*y!#o{hSYhwVySI(0Jz!Yut?9q`4iTQ_QHyfb7P z&Mh!{Dq1)g^r6PeGD=aGFDqd4l$9ksD%B>=0tsi)yT3(Z>B~3zNH^gSXZJClXpBj- znjT2by;kKhp~H8+r`G;#7aQ}MUZ48?Q)T7gkH(qNH2>H`KIjCAhq0aDHKBczob>`8>)c$)ZbbD6(I`vELt|nb16ug5 z1>adG^h4I5VMS%MWIju<8#BOg;K7pvdt6zbw08B@%G^;);@TEm87}BmghDiNSe$&m z0kZ~3j0Ju>qSv z5~ReMnwn^rV?8n*o zjr9%*DP`1b4<9;WG~%9h-daT7G;AR%SrQhG^EZuGAX8KDa4ucyxO%m(G+_$DNJo7h z@>`cX98*)INJzqTu$eOh88<-L8P|JNG%{+lZpkQ&)~qdoSB$EssOUmbL0eJ2^7Q`w zW`7EsMnXidx;C6q$U<<3_Ix@5rcK*P7DoLdV?>A@50Dp_1Iiy_3fR$Pej?4FGO>EL z%{vcJ0e1>_LELn7atAh#n<9{D()*2v9-Z*+G(NwZH@`C~0?LF6H`^xe^x#p5H%w+d zS+MC{dXHBIJAQQAK2@an3^g372xE zV4ebHCy8d&@86q5&PKh#k;Yul(vp&UAY>T&l!M5de1ot7s|r<>5J1tPgQE9d`EYb0 zV2|W$(#!Ct_)e53CVkUyuFD$4A|CIyle|5>EiFHpK7PoZVs(yErsR1Km?1=sefsug z>MJuhs`$cKV=M}IST?&jG9|@u!bw_@<>d>7&Vv}8^0bcm+YT|g9YXbQO;>AkY1_-Z zJVWu9;skAO3nJ1|Q_E>L|0p~0@(2VJX90{yK5Zn5(7gk8GB^|+J1>fF!jf?q3_m|; zau?1xU^9f{Q21+}3d}In4J?SgT|?}0_l?<7PhwZNZYU}U2t0VU!kj~d7<y05%9DLa$uh40<-2zmvj)({q@*YgAAX6jHEQL8&cBH_w)J$E5cQPw z8Azw4`!j32P>B5#wqq&#@1^`T$!#9k?a!!CbrTe7EMBx^iTdDFzpK!g$1G*HkCxHO zCX)QuFS2>MM*KxA(7#CZkMx&Yz;xHd+77$&2fy%X{SPG3e~a&2tYB|nU-by^XRC`# zPm6Q^s@K0veBnRz`VSjB`wJ7p=~KCstqj(RQZ59R2zXELK7EcMb}T4xSic_qU?f6} z<=D%YAtnGA$Nz|N@R}Kk_|Z0Lle7`H`9B2v=?d+f2*uS` z&PVF`iQRU_i3Hiit{+GI4+Q%Zu79II>9UvZ>i7zFp&wb5vM*tYVzpG5L7=M~t8$;`CAEO!#oP^mEQ4^C?0z!mf6 zaca^U$HfX~XwuNB1MIrQke?ABPk06~1jh^&tsfoS4Te?s?Adk8dEdfy;##<(INE|Y znTY%)pYAY@2n=M4F4GD-85+ttvah?%YA5t>t!(W8arXljLx02z`~kGh>lYxK-v9H$;4 z69ol)3Vzb{wYBjmkP$Loyg2OE2?9!N;(!H_Z!i^2zdoFc!GmoFyi%5UP!?}{M#W|X zYBEL}Hzwb{d2_O-l*q(Kw)b|PN_oNs^f=#0k3y8jF5^4DvgGziq@$xplh-kuMhf2K zvm)R5f2_>v)o>Ni>+zG}OtS1EQdSr$2g&wsYi=@|k$W2A9E*ji)?iVlAIUH?gGX5AndZqmFvr_Cp?c&DD6 zsBBsG+(X9UF#ib*L4VyP-PF+JoRKAcr#9`*C($jQ05jQ^d(VkC> zlarG!T&Txmee90jE{Q-bPy!)DUu*pd?&%L@6r_-Hc@axyz*D30fhd4VBTD)lroR+R zXh~yb;@dI6uqQ5`In!=H?7u2Me1g#BQ~rTdurRq1tEn;C)~W`crm;k5T>iFd(c=Gr99jQNksNF3zf{S=d_UHHd>u zJ+(*_xS8*TN(ha=ipmt7w5o4D(>|vSeNs_3a@k!5?LFhpWKbep-0|btl`eE5pg6oB zRx@qlkVfvxKoE<*X4I%BHgQ-TV)55nTjxD{b~Y-ifwWjW+*oe#?+~BA0g)J26kE_~ zkj9}>iNtfHCFF-lS}rL0RQ>S&F)9YJx7m)y)*+G4MRGm(zCLbhB2t?~c0%}o|0yHD zc;V|My}3CF9R#1Xxk#1AuBSgaGa3X9mYG|8r+yoMIs7|>s+QKRvwvP^&S2P%BpXNw z*b-*3hjVi<#C*agU<*@o^Dkdi(B$sAO=5io_)uY%*ixzQ0a#|jr6aBC}5a;cudB8_dS%m`yvo$!`$BkR1vLO`20+#`6K zxp%>v`fc#zCMiT-5fFeCAeVS|P=u06J^c@`H4$GYxhWmj+u9a7_6pn#^E(JJLA9}+ z9`N<`+on6w6t7hliSpEo%z=k5>D%`H$fLsQzAR=Gji#W$Ym0SYB|dr zrz^U`Ph3r~^-)3GoB6mJK$>#hJami?7u_IIfE)`KkR~%vu85WnO^&p9l_5H` zl!N$?e6Lv}7iylN zbsayBBq&>_wy7q2*Q{Fgz96bYijL;MF275KAuoW=gbDFA6Yxc$Gkt=}E@>mYO9|)C zzZj4%+gqKsr4RZEv^_Tl4;5LP&RzIVS|AJoe+WW;2;Ce~6wpY3`wV5OcwyRQY^*R* zDEan?ZQFiP5Pkmii9F0r&$oyY+oM9r305eP)7p3@^yD%}W8?d`OIw=>m+$SlT$HW# zacIMTQd(&d(V7e}iR6xvYKqFr?UWigOFeKi(dePJNpP*|zIwCovsbS|0t06+TBK|L z;7IzTRiEKbiYBc>`P~u6op;u{W1`SFR|=7OR4O8u;z4-zdTYZS23lf7a2k2!!=p{m4Xn z%`o@HW;ws=Dz1f&4M{s`EApRtce&K^f330R^Mk6*UAT#?)=eq@7R*Ma`zW|}?_TSQ zVnO=P@;6amqdA=bFdh2`g{OQjUd#<0r(vaN?cgwT)Q}*7kL~9kdeVjyJN^^puErQuFcSWP$R!W_5{S4AZhkIQ=TFuMe9v=|#b{D_0Wy{Bp}m zE{H@*A19oFT|cyce`oeH%pIY7Fb2MUn>KD_Vqq@O$v$Hn#=4d@-a}aMlkc6mpUj5_ zkuSKpuCMI&&J)~f0X%HxA5AIoNV@auT7<_5^dRS=tD5qs?YOe6@L+oR>W5Y;^*yg@ z&tCBIo3xQYRkSzx#1G1(Zm8=>2al+>InHTf_ zsuxF+1@IX`@}cL??Zh?b7c!9juZg$FpAudd>dPk4MP(mHBe`VJ)p5SjG==?Q4vS_Z0Gw)R?v8Jy_?r&?EzOpLP=dr zG@q@8XDc>Y|9o`S1ncnW_TdJe%X{{dP#h3-;~$cer6ae-XVbMb?w2kx?~(M-uD@@3 z-S?!4WzGYyyRNP&sA|9KQsB-=l(!((Bj9YFeY6_ee$*(YHmzQ>=5=AAkmSUZpaPea zl&p@Z`llZ2;Lhd|Mx(|qYKUlSS>4)la_!plQ#=?saw{=WyFt5CS<>KNMg({t4-I7^ z^WmdMH^0jc;*@{)&W>ckkdQ_ga27V_J-8xirBi&RR<1xYId{&SZ9i)xHRrmW%_!Wp zeASp}8ij(m6|0}LZip9|n}0?J5;wE6sGssL$@6L!;RSEroQR01!Q@o#Y;1t4i$_gQ z%NGZe_p{+_cz6*dL*37nZPS@XJmu%5;XX#GO{bNFSR3f*fGjEtujQ+*DUTSj{&!P* zxZE3y?vF<=Pj+T%%`TMG&Uh&!YpF_wQJ z>C}2`t!Z+BWxz8R{NuGc4P%0JSu<5nDiGZsk~fJCb1HJs*V2$sbXE2IbRG+Zj!rzj zI~A1*tfXhOQy7c-@AYS0vZh_Bw=OEcjs2pH{D76_Cl|F(DGj_DE1_)Mp~L+y2d-V* zw`XdH*OM2?7VVm@Fl|u3qD~se7A!tzIrZFu5iinoPAiJ{*-XxOa&W5s{5i7SPG6h) zW3Y5~W7f$WyPk%Yia960HK$j-cdv1GwNUnT4h~=U;p|yk^8F%LNQ#`x zJu?!qWC4bupub2Z@pszW#!g-Uv~W^5%up=QOpSe`ccr%C;0z?7P2VTadg516)b{;z z3-t7?wWcDmMr+?DT*bs8Ffxt;oTc%rsY%(JQiM>H$}e9=;I%`l#3Wm;Drij7X*jp4r|JH{(coFt^pcVE$;I^ zJ$vqvzU$t6D>72)=yX&Q9&N3Ynriezs?Q;e1u=LXk(Ioo@yd}S&!gRs_YjL|Y!NWl z>va)z2$7a0uOstC`cvjiuptW^0T_`;oV3{L>IxfZhj@ur9!K!iMOz|fJnl%m;nwoB z>zTuXWza~qzT4ZaqaO) z<{g$l?gp$T z<6gn9Ge!dEd2N0Di9NC@s}Q z#!wof0{ZX)o?Y6A(-7Y^P%7^iofonkh31j$S-L7vM+PFES5?>4z!@8`-eH}dZA3^% zQEkslPx3vF-~hunSD2CEQ@UH!O3M1nJn@^WN_~_VIrLZ5CS^6Xy`_^S6!&?T$xj*u zAJ12VG6H;t@8#!v^l<6vPFGO`$6#J+&1}CbrRV*5+JiP>c?82}daId{(Vo&c(Yt=2MZhMVR*G1YFE1mAk3#eVn$Nqck>EcO_6v^;gB01v3iX3lhMYyB-opA^YpY;PYQdXW5&4S?2%v~=E{F#G^!nUifA=QMQ41yJ2@ zqX&vQyo{1<0?4NSN2^IllIe^Yz}s0F86y^515rM4`>Y+8ZbU=`sWXs!HFMFCfI?$s z1nJ;akPr(KRsZc9CNn}eYU}EdQS~+w1{y()2<-3S!)Sq9$?q~5AivREanqk8O7+&s zpz`lui(g}Lt=Co+b$G`6z&lGxL)q^l1xKU7k(EZQz0^P||Z8hn*%lgC-BSHpd5F_{neaqG4_qZeXOEW>MYv;}~ zy?amnGaMBHi9(k7i6{?29GA}6yk*N`D=YZe$UAoyF_rb=$K!nFva&Le729Pw9~jef zX}H$lVZ(B*HG$|&$?CO-{&^7Fkr4d|C<2cm zw~v>glskF0s(J`>O_+jeA=vn)Gav1x8htu!2rq5M1Q!)e)YDr6@nLB>PE|E3K3*>2 zg4pN-@j6(|bzR87t>cJ;MRX9f+XDoF4k*$OynfTjF{25W@T# z09(}81VI})+)tHx74DxUG4n8;(!K425w`A^KJ)D2yGo{5DJ#$I(9Y*`8&XyC5^Y=b zv1oevds@lhgSt&_sT{@He&2L>J81^Aj#YRzy1qJ1!UaxmXb}RdAnbs3d<87p?N>cw zPNZCgxGPw3GDgPAqbcTKaL+vZNVi;oaLB<+yyJHaPB}*dLL?g&8Bha81Sonlov~lHy-YYjNDoyEOik9! zc;f3FJ;64*`l${+_gWkoJ!@V+e`B6)C$E*Zw%17`VD3lttQ?B8;Y)5^B5z+qBd54{ z8G@?--FBK8)H~%`>y9NwlqOre>L&H0DDlpo&x>nCq7R$fds_jfH+*dSxDK0Zalw!| zFn(EqB56Z<9BG7(1aVZ#j~?5cOW*gacMs8?&Rr%++we*4>OGf9@BHCd_4(DX*Y00M zBGZDd?wtG0!{QxD%12S}k}_eC^C84-aR&QGXG%GXM16w=Er64q-I1W6(Jvys_SXXL zZTt4p-DznNvz(xtOVLbb@pV;mrC|97WjV)h@z?t}G+DM8arOlZQs^IlpG z_S$(KY$n)Lwxa*I@xPmV2R%KV+E3)z&hi5h7|cT_otqmy?o zg8d8T2=je{BqfdtY7cSe+Y4 z3k?C9G=SZ*97@KAC}Xse?PEw&_g1qvJ;B$P7=S?zb>Ic2ILUhtJ`lpvhvH z{l<=eVI#nVT=??o)BbBl!`Phd*tJjXq0(eehQoVrl^34{H66P7m7Ly%n9x~aTG}cq zDAIoKbT{Yw^&Owpsm$}>>BKV&=gh$+BzQ&$>S3Gv`JMgSYm{=60fO$oo5tVz&4@OQ zL%qcNsIYpekNno!Sf)I5==ya7$N{NKGqRsFX*GfT0LU<3p^ZJYMP)K=sjaytAjaxRkd@O6;F ze3D3Bk_x63J|i{;2R<+>`U0GIPy~t1Pse5H3@cAAG|?Rmm`SshO`BO__Msd z1w|a5I)j}*YdN&gqd|{4tqHYXtzBaDL`^C3^!Zz}&DS$Td&mVl=c`qmkEDnbhf_cHQ&q(os{=&2w_D{Qj+=tQ__IvukOhM*QYsJ4uQ& ze?%`Fp{BH1q&AS&YtIE#3^#8=W1w_OqBUW>0kIAA1KQer{PdVDBK7D7 zg`2@ca?EIawcK966f*A9DL6PfK4;j$R>fXt8S2ckN1s!=d!|2&p31pS??6sRpMeGh z6r(`6Msl$51CEVaaf;cJHAB=g1p*S00o|PNe=u2|Fp3Jmi5f#SA>!kgLRys9JnjF> zhcPe~UbWx651an{Wh(dhRDWRta!=l&cj~jY8~M^quuZlV^*T!~*!1ZK3>9nj0{7>? zcp+3Pyoqk7p0bU5_3oWv?tcH-ys`cNetJKDx%Q-K-Si5`V++Aq_@~Dk`>+_SHraVPWeS+q=G$ zfK-x-A`Eow_p>Ri3n>%Poc8&&iHeV*ulv`Na)Qf}3bWjNHAD^M1P;n-qfv=>{C#)% zYR5T0z1%K~o&uR-8&k)gF->DYWWEDMUcs$<_w-S*wxq_CLwme^%VtI{D1PA!Qd8R_*!Vz`$KZXU0^^ls~ec*kNMg{*F~2I`;R=c!T_xBmvs(%z;tQ zK2{H$iNy+J_u|FRV!(jFEC}fcU7hhCtyRdcv8QFh zY;|>EgV9L~PC*1L=y1YLoS;M;y7XhM{`jTdLqcXL{{5`msk0>h`~?EPbNX}{L8826 z+6?*)eu30F@8wGmbn3TUF_|7a)@Qfj&xffoW>o}L=)1n}rbS-KTa2S>!5WDlnL736 z^=plxL$O7ST6C>L;pBZ!%OBd`SNNB|QPU&YOq7WQE$G`kZPXFuOTuO$&7h{>+Z_*Y z7Zn@3g5xzmKMu%;{91)l@xxAc;rL^ zFm)uWa6J7#9#8-4^Nc@`a)B&GZYzMB*DA<-`3MooE<1N7!twIkhYndFzt|CO6d7o$ zI!9_;|1aNaq*`Jt8eil{NH3+SAe>6ay=mN*ZwP{D{^*1UC0KZR8dN=EMG+X!z{ab| z$;qe+X3ZLf8aHh2f(1l~{cg#YDC^)ea9143v?LDy0v6>2paNwydI!G@G9L*Q*bUAT z64Do&!Vmxb`$KhI&m*nIS_Og0Bq^W)6mUSF<}+s&bR|L!3W-xTZW^Tp(d}2i#Efd- z>w_+#TH`VUV0nK+u+&fuhlal94Kpk9RW-#IIuo^tQGm--9aP8=`ypUkyF>%+&;x>;>3y2hr&$W zQjg|?g!~uZJ!%mRq=ZH0T4dy86v)h55i9jScncy7K$?ZkJQX^28()U#QuP_Q)$U3v z!;Jzs%ngt}5X+u0o#y%Z@1szSurHAazJC4M^Y`Z!?c24}S&d6Gl+!3U7=avG;FCv= zG|cg15*xN)&o^bqMl89q^o|Rq8lzF;Bz^bp)gLPI=h!6F=kIv4tte7wS*>)WN*JrH z?d0ePbVQgp+qW--4fFB%D{E_YJX&;&_N@cJDJ=X<(%faV4t`%U{Z0zGqtqsNt9ThG znQ~+7OhLzjhlq*loP0A>donc|*#ff8{l;(keM~&?x)&^m9yFn2TF(7`;erF@`j$(_ zk6W3V?xP~xaT5(YQpe2V(BsFi&dMXCX6D+p%=0$*@wIr^$dQMnuU)+=2eNv{6~Fa+ ztk|579QDMMf-y@Qp`+)5VFZ+rJ^16tp?&+x7O%}X(3|gA9EmBfTaO-)Nv9@mJDh6m z{B>;WG;$R<5O4#2W1Unb(8v3q!{JTbS31ii=TN@`5a- z0AQ*&JOzR;{wItcKBtHJffpaBcq3;)l841Ab70P+N5AoM=&blYs~;!C<5}MY{ToxJ zSVER8)&&bd(wf*-S7W$K@vtvjytpZ$=H9o)M)2_R#SdP*;4HYv8G@Y$)D>+c4=7yE z-&0!Y21}PCiFX3VgGyS_`|1G%f3~Yu?Ug1J4=`n_c;$D?$&+{I*eQF%dmxI+`ZZYt zWCMvHI}M0}L+so6)0ZzFlxE>juAul{Jth=jngvlXK%GU)FW3`E;$63HMUBQ~{1@4e zTZZp9PWw6oLLE&Eu^8CIxuD02NN60N+ic8!MZa)m@{duv-hucQ1VdYpATtk@gKuEzBrHwXCSjGpmu((1#H7*Ah{#gakG%~|qU0TF>IZjh^ww0C8 z+G3=hxw2DRIpA&Y-afxa&zU`Ymoy~~E12g-#fIq{)Hkh*!_J*8Y+k&t>1k;w3%2qo zubhK?VNUWlMr_a$QdYoTg2ZD0CS}N)hZ`77pLzVaoRPSBD@qmu$qCy!as;8KvUmKa z3UuCd(rrI0dR*De;CG%hplGJ)Zov$M@CzWB$$HPotfO5Md~S4wj*dkDuuMycj`sbc zi=hwnQN^2;O>PQu7ki*m?>umQu9QD=Ulw!aiOTUhIzv=c(#P*R=g&&w#GWdqKd81W zoTlVnEg@eQhm%Xh-eUJ^TyO%cN}e!P&m z+)+~U`f8LJx@}SzLTeiu!lRZl#|8Dphj;J1-Q9%r7fC63#=8g+p^!V=TvQUMZs0Fh zJv?4VI0HlncoU%9%*m6LMvOSPbv$$-p_}vG@nePz8G;khmk$LJ<05cuRJGlBp4_K#>&+N2(krNsjMt+>J5zkWWkQ7 zTS(cql@AV`DUPHa@bqj02z$K9v6joC^w#c1A`T8|DvLn;E+kK@BIl8074;G6{Vi{PL+VJLO&}PLY0K!73692;g{?z zE;QTlc};eLu3A)8_Q*;g7yrASS08S(#&?j1q2MQ|-7@^A6$^|GsjX}S<5&x{9j9Gq zdPDWasPN2vR}rgcW}YYVswL8fiih2crj5W*()}MLv`S7^j`^Bt+5 ztBPJBV>kE`DbLq)W>GOBk72|b z_t(+sl-idrUYs#=CS^Cl=n8%rG!ac-6KcTS@$g7WN}}`?`YG`0cDo72gLL+i=E(L7 z2nacP^k6`M6N4pz&~_V=joN~ch&z1{BriJg5|6~C%RF@pzbSj8W#V|I z0^V}K7RfzbElndQQ23)AfPMMNJ3iS+g2=g(mBP1URbl3x$4P|1nac~&w2aZxq&;zB z8KcBWfv9~*Szu3$SsZ3l5>=4pGJeSWgZQ{v(bX5QL$n^h2)NB+#A&Fi+TnM?XY9gdRQNm=4s01Ct8c?$ zTo=YJUpYXmG$wT7xN(-?=Qy*D9%br}?|7^C6T7q64jxti(b14yTX0dy8v=}VLiMim zL?=KeJ9ERlhy7~znZ@-$MXisOi9gL@v2o*Qr-x@J4Yysb{bqt~bjs_zpB#EMu7W)FW`oS`oBEZt9`GdY}N+7(Ir5 zS6f{gqT)@3z^zW>vS?91qkXp*YWijLPuN}Su>OF-zT(rzwcqFapH!$B-dwJr;xlWV z!^81@CTkp8CbO+m!cak6kDYdR?Tf!y%+RmgN#DLQcpPwUCEOi$T|yvizHEElH-N{Q zapmgDHEVJR4H$(O_2I8Ll$%dm?u z9A*^eA6Mu5&*R$-tZIMe{P_i>WNvv_@#N6DK3xayaJy6gcH)8Ck#%G$P`Pjt!hQ*p zUs#wbkFO2r?>XFIZ6}djDmF~++vJ~byLw3O8PuyF@271K;Y^U548KV4R`6=HWLi7H jo?9j#epbNnnmvtMG*my`3+I1`L}pVhjIS73@A>}#TqCKz