lintr/0000755000176200001440000000000014753133562011413 5ustar liggesuserslintr/tests/0000755000176200001440000000000014752731051012551 5ustar liggesuserslintr/tests/testthat/0000755000176200001440000000000014753133562014415 5ustar liggesuserslintr/tests/testthat/test-vector_logic_linter.R0000644000176200001440000001436614752731051021557 0ustar liggesuserstest_that("vector_logic_linter skips allowed usages", { linter <- vector_logic_linter() expect_lint("if (TRUE) 5 else if (TRUE) 2", NULL, linter) expect_lint("if (TRUE || FALSE) 1; while (TRUE && FALSE) 2", NULL, linter) # function calls and extractions may aggregate to scalars -- only catch # usages at the highest logical level expect_lint("if (agg_function(x & y)) 1", NULL, linter) expect_lint("if (DT[x | y, cond]) 1", NULL, linter) # don't match potentially OK usages nested within calls expect_lint("if (TRUE && any(TRUE | FALSE)) 4", NULL, linter) # even if the usage is nested in those calls (b/181915948) expect_lint("if (TRUE && any(TRUE | FALSE | TRUE)) 4", NULL, linter) # don't match potentially OK usages in the branch itself lines <- trim_some(" if (TRUE) { x | y } ") expect_lint(lines, NULL, linter) # valid nested usage within aggregator expect_lint("testthat::expect_false(any(TRUE | TRUE))", NULL, linter) }) test_that("vector_logic_linter blocks simple disallowed usages", { linter <- vector_logic_linter() expect_lint("if (TRUE & FALSE) 1", rex::rex("Use `&&` in conditional expressions."), linter) expect_lint("while (TRUE | TRUE) 2", rex::rex("Use `||` in conditional expressions."), linter) }) test_that("vector_logic_linter detects nested conditions", { linter <- vector_logic_linter() expect_lint( "if (TRUE & TRUE || FALSE) 4", list(rex::rex("Use `&&` in conditional expressions."), column_number = 10L), linter ) expect_lint( "if (TRUE && (TRUE | FALSE)) 4", list(rex::rex("Use `||` in conditional expressions."), column_number = 19L), linter ) }) test_that("vector_logic_linter catches usages in expect_true()/expect_false()", { linter <- vector_logic_linter() and_msg <- rex::rex("Use `&&` in conditional expressions.") or_msg <- rex::rex("Use `||` in conditional expressions.") expect_lint("expect_true(TRUE & FALSE)", and_msg, linter) expect_lint("expect_false(TRUE | TRUE)", or_msg, linter) # ditto with namespace qualification expect_lint("testthat::expect_true(TRUE & FALSE)", and_msg, linter) expect_lint("testthat::expect_false(TRUE | TRUE)", or_msg, linter) }) test_that("vector_logic_linter doesn't get mixed up from complex usage", { expect_lint( trim_some(" if (a) { expect_true(ok) x <- 2 a | b } "), NULL, vector_logic_linter() ) }) test_that("vector_logic_linter recognizes some false positves around bitwise &/|", { linter <- vector_logic_linter() expect_lint("if (info & as.raw(12)) { }", NULL, linter) expect_lint("if (as.raw(12) & info) { }", NULL, linter) expect_lint("if (info | as.raw(12)) { }", NULL, linter) expect_lint("if (info & as.octmode('100')) { }", NULL, linter) expect_lint("if (info | as.octmode('011')) { }", NULL, linter) expect_lint("if (info & as.hexmode('100')) { }", NULL, linter) expect_lint("if (info | as.hexmode('011')) { }", NULL, linter) # implicit as.octmode() coercion expect_lint("if (info & '100') { }", NULL, linter) expect_lint("if (info | '011') { }", NULL, linter) expect_lint("if ('011' | info) { }", NULL, linter) # further nesting expect_lint("if ((info & as.raw(12)) == as.raw(12)) { }", NULL, linter) expect_lint("if ((info | as.raw(12)) == as.raw(12)) { }", NULL, linter) expect_lint('if ((mode & "111") != as.octmode("111")) { }', NULL, linter) expect_lint('if ((mode | "111") != as.octmode("111")) { }', NULL, linter) expect_lint('if ((mode & "111") != as.hexmode("111")) { }', NULL, linter) expect_lint('if ((mode | "111") != as.hexmode("111")) { }', NULL, linter) }) test_that("incorrect subset/filter usage is caught", { linter <- vector_logic_linter() and_msg <- rex::rex("Use `&` in subsetting expressions") or_msg <- rex::rex("Use `|` in subsetting expressions") expect_lint("filter(x, y && z)", and_msg, linter) expect_lint("filter(x, y || z)", or_msg, linter) expect_lint("subset(x, y && z)", and_msg, linter) expect_lint("subset(x, y || z)", or_msg, linter) expect_lint("x %>% filter(y && z)", and_msg, linter) expect_lint("filter(x, a & b, c | d, e && f)", list(and_msg, column_number = 27L), linter) }) test_that("native pipe usage is caught in subset/filter logic", { skip_if_not_r_version("4.1.0") expect_lint("x |> filter(y && z)", rex::rex("Use `&` in subsetting"), vector_logic_linter()) }) test_that("subsetting logic handles nesting", { linter <- vector_logic_linter() and_msg <- rex::rex("Use `&` in subsetting expressions") or_msg <- rex::rex("Use `|` in subsetting expressions") expect_lint("filter(x, a & b || c)", or_msg, linter) expect_lint("filter(x, a && b | c)", and_msg, linter) # but not valid usage expect_lint("filter(x, y < mean(y, na.rm = AA && BB))", NULL, linter) expect_lint("subset(x, y < mean(y, na.rm = AA && BB) & y > 0)", NULL, linter) expect_lint("subset(x, y < x[y > 0, drop = AA && BB, y])", NULL, linter) }) test_that("filter() handling is conservative about stats::filter()", { linter <- vector_logic_linter() and_msg <- rex::rex("Use `&` in subsetting expressions") # NB: this should be invalid, filter= is a vector argument expect_lint("stats::filter(x, y && z)", NULL, linter) # The only logical argument to stats::filter(), exclude by keyword expect_lint("filter(x, circular = y && z)", NULL, linter) # But presence of circular= doesn't invalidate lint expect_lint("filter(x, circular = TRUE, y && z)", and_msg, linter) expect_lint("filter(x, y && z, circular = TRUE)", and_msg, linter) expect_lint( trim_some(" filter(x, circular # comment = y && z) "), NULL, linter ) expect_lint( trim_some(" filter(x, circular = # comment y && z) "), NULL, linter ) expect_lint( trim_some(" filter(x, circular # comment = # comment y && z) "), NULL, linter ) }) test_that("lints vectorize", { expect_lint( trim_some("{ if (AA & BB) {} if (CC | DD) {} filter(x, EE && FF) subset(y, GG || HH) }"), list( list(rex::rex("`&&`"), line_number = 2L), list(rex::rex("`||`"), line_number = 3L), list(rex::rex("`&`"), line_number = 4L), list(rex::rex("`|`"), line_number = 5L) ), vector_logic_linter() ) }) lintr/tests/testthat/test-lint_package.R0000644000176200001440000001735314752731051020143 0ustar liggesusers# When called from inside a package: # > lint_package(".") # .. should give the same results as when called from outside the package # with: # > lint_package(path_to_package) # Template packages for use in testing are stored in # tests/testthat/dummy_packages/ # These packages should not have a .lintr file: Hardcoding a .lintr in a # dummy package throws problems during `R CMD check` (they are flagged as # hidden files, but can't be added to RBuildIgnore since they should be # available during `R CMD check` tests) test_that( "`lint_package` does not depend on path to pkg - no excluded files", { withr::local_options(lintr.linter_file = "lintr_test_config") # This dummy package does not have a .lintr file, so no files / lines should # be excluded from analysis pkg_path <- test_path("dummy_packages", "assignmentLinter") expected_lines <- c( # from abc.R "abc = 123", # from jkl.R "jkl = 456", "mno = 789", # from exec/script.R "x = 1:4" ) lints_from_outside <- lint_package( pkg_path, linters = list(assignment_linter()) ) lints_from_pkg_root <- withr::with_dir( pkg_path, lint_package(".", linters = list(assignment_linter()), parse_settings = FALSE) ) lints_from_a_subdir <- withr::with_dir( file.path(pkg_path, "R"), lint_package("..", linters = list(assignment_linter()), parse_settings = FALSE) ) expect_identical( as.data.frame(lints_from_outside)[["line"]], expected_lines ) expect_identical( as.data.frame(lints_from_outside), as.data.frame(lints_from_pkg_root), info = paste( "lint_package() finds the same lints from pkg-root as from outside a pkg", "(no .lintr config present)" ) ) expect_identical( as.data.frame(lints_from_outside), as.data.frame(lints_from_a_subdir), info = paste( "lint_package() finds the same lints from a subdir as from outside a pkg", "(no .lintr config present)" ) ) } ) test_that( "`lint_package` does not depend on path to pkg - with excluded files", { # Since excluded regions can be specified in two ways # list( # filename = line_numbers, # approach 1 # filename # approach 2 # ), # the test checks both approaches pkg_path <- test_path("dummy_packages", "assignmentLinter") # Add a .lintr that excludes the whole of `abc.R` and the first line of # `jkl.R` (and remove it on finishing this test) local_config(pkg_path, "exclusions: list('R/abc.R', 'R/jkl.R' = 1)") expected_lines <- c("mno = 789", "x = 1:4") lints_from_outside <- lint_package( pkg_path, linters = list(assignment_linter()) ) lints_from_pkg_root <- withr::with_dir( pkg_path, lint_package(".", linters = list(assignment_linter())) ) lints_from_a_subdir <- withr::with_dir( file.path(pkg_path, "R"), lint_package(".", linters = list(assignment_linter())) ) lints_from_a_subsubdir <- withr::with_dir( file.path(pkg_path, "tests", "testthat"), lint_package(".", linters = list(assignment_linter())) ) expect_identical( as.data.frame(lints_from_outside)[["line"]], expected_lines ) expect_identical( as.data.frame(lints_from_outside), as.data.frame(lints_from_pkg_root), info = paste( "lint_package() finds the same lints from pkg-root as from outside a pkg", "(.lintr config present)" ) ) expect_identical( as.data.frame(lints_from_outside), as.data.frame(lints_from_a_subdir), info = paste( "lint_package() finds the same lints from a subdir as from outside a pkg", "(.lintr config present)" ) ) expect_identical( as.data.frame(lints_from_outside), as.data.frame(lints_from_a_subsubdir), info = paste( "lint_package() finds the same lints from a sub-subdir as from outside a pkg", "(.lintr config present)" ) ) } ) test_that("lint_package returns early if no package is found", { temp_pkg <- withr::local_tempdir("dir") expect_warning( { l <- lint_package(temp_pkg) }, "Didn't find any R package", fixed = TRUE ) expect_null(l) # ignore a folder named DESCRIPTION, #702 file.copy(test_path("dummy_packages", "desc_dir_pkg"), temp_pkg, recursive = TRUE) expect_warning( lint_package(file.path(temp_pkg, "desc_dir_pkg", "DESCRIPTION", "R")), "Didn't find any R package", fixed = TRUE ) }) test_that("length(path)>1 is not supported", { expect_error(lint_package(letters), "one package at a time", fixed = TRUE) }) test_that( "`lint_package` will use a `.lintr` file in `.github/linters/` directory the same as the package root", { withr::local_options(lintr.linter_file = "lintr_test_config") pkg_path <- test_path("dummy_packages", "github_lintr_file") # First, ensure that the package has lint messages in the absence of a # custom configuration: pkg_lints_before <- withr::with_dir( pkg_path, lint_package(".", linters = list(quotes_linter())) ) expect_identical( as.data.frame(pkg_lints_before)[["line"]], c("'abc'", "'abc'"), "linting the `github_lintr_file` package should fail" ) # In `github/linters`add a `.lintr` file dir.create( path = file.path(pkg_path, ".github", "linters/"), recursive = TRUE ) on.exit(unlink(file.path(pkg_path, ".github"), recursive = TRUE), add = TRUE) local_config( file.path(pkg_path, ".github", "linters"), "linters: linters_with_defaults(quotes_linter(\"'\"))", filename = "lintr_test_config" ) pkg_lints <- withr::with_dir(pkg_path, lint_package(".")) expect_length(pkg_lints, 0L) subdir_lints <- withr::with_dir(pkg_path, lint_dir("tests/testthat")) expect_length(subdir_lints, 0L) } ) test_that("package using .lintr.R config lints correctly", { withr::local_options(lintr.linter_file = "lintr_test_config") r_config_pkg <- test_path("dummy_packages", "RConfig") lints <- as.data.frame(lint_package(r_config_pkg)) expect_identical(unique(basename(lints$filename)), "lint_me.R") expect_identical(lints$linter, c("infix_spaces_linter", "any_duplicated_linter")) # config has bad R syntax expect_error( lint_package(test_path("dummy_packages", "RConfigInvalid")), "Malformed config file (lintr_test_config.R), ensure it is valid R syntax", fixed = TRUE ) # config produces unused variables withr::local_options(lintr.linter_file = "lintr_test_config_extraneous") expect_warning( expect_length(lint_package(r_config_pkg), 2L), "Found unused settings in config file", fixed = TRUE ) # R is preferred if multiple matched configs withr::local_options(lintr.linter_file = "lintr_test_config_conflict") lints <- as.data.frame(lint_package(r_config_pkg)) expect_identical(unique(basename(lints$filename)), "testthat.R") expect_identical(lints$linter, c("expect_null_linter", "trailing_blank_lines_linter")) }) test_that("lintr need not be attached for .lintr.R configs to use lintr functions", { exprs <- paste( 'options(lintr.linter_file = "lintr_test_config")', sprintf('lints <- lintr::lint_package("%s")', test_path("dummy_packages", "RConfig")), # simplify output to be read from stdout 'cat(paste(as.data.frame(lints)$linter, collapse = "|"), "\n", sep = "")', sep = "; " ) if (tolower(Sys.info()[["sysname"]]) == "windows") { rscript <- file.path(R.home("bin"), "Rscript.exe") } else { rscript <- file.path(R.home("bin"), "Rscript") } expect_identical( system2(rscript, c("-e", shQuote(exprs)), stdout = TRUE), "infix_spaces_linter|any_duplicated_linter" ) }) lintr/tests/testthat/test-extraction_operator_linter.R0000644000176200001440000000247114752731051023165 0ustar liggesuserstest_that("extraction_operator_linter generates deprecation warning", { expect_warning( extraction_operator_linter(), rex::rex("Linter extraction_operator_linter was deprecated") ) }) test_that("extraction_operator_linter skips allowed usages", { expect_warning({ linter <- extraction_operator_linter() }) expect_lint("x[[1]]", NULL, linter) expect_lint("x[-1]", NULL, linter) expect_lint("x[1, 'a']", NULL, linter) expect_lint("self$a", NULL, linter) expect_lint(".self $\na", NULL, linter) expect_lint("x[NULL]", NULL, linter) }) test_that("extraction_operator_linter blocks disallowed usages", { expect_warning({ linter <- extraction_operator_linter() }) msg_b <- rex::escape("Use `[[` instead of `[` to extract an element.") msg_d <- rex::escape("Use `[[` instead of `$` to extract an element.") expect_lint("x$a", list(message = msg_d, line_number = 1L, column_number = 2L), linter) expect_lint("x $\na", list(message = msg_d, line_number = 1L, column_number = 3L), linter) expect_lint("x[++ + 3]", list(message = msg_b, line_number = 1L, column_number = 2L), linter) expect_lint( "c(x['a'], x [ 1 ])", list( list(message = msg_b, line_number = 1L, column_number = 4L), list(message = msg_b, line_number = 1L, column_number = 13L) ), linter ) }) lintr/tests/testthat/test-expect_not_linter.R0000644000176200001440000000245114752731051021240 0ustar liggesuserstest_that("expect_not_linter skips allowed usages", { expect_lint("expect_true(x)", NULL, expect_not_linter()) # NB: also applies to tinytest, but it's sufficient to test testthat expect_lint("testthat::expect_true(x)", NULL, expect_not_linter()) expect_lint("expect_false(x)", NULL, expect_not_linter()) expect_lint("testthat::expect_false(x)", NULL, expect_not_linter()) # not a strict ban on ! ## (expect_false(x && y) is the same, but it's not clear which to prefer) expect_lint("expect_true(!x || !y)", NULL, expect_not_linter()) }) test_that("expect_not_linter blocks simple disallowed usages", { linter <- expect_not_linter() lint_msg <- rex::rex("expect_false(x) is better than expect_true(!x), and vice versa.") expect_lint("expect_true(!x)", lint_msg, linter) expect_lint("testthat::expect_true(!x)", lint_msg, linter) expect_lint("expect_false(!foo(x))", lint_msg, linter) expect_lint("testthat::expect_true(!(x && y))", lint_msg, linter) }) test_that("lints vectorize", { lint_msg <- rex::rex("expect_false(x) is better than expect_true(!x), and vice versa.") expect_lint( trim_some("{ expect_true(!x) expect_false(!y) }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), expect_not_linter() ) }) lintr/tests/testthat/test-sarif_output.R0000644000176200001440000000231014752731051020231 0ustar liggesuserstest_that("`sarif_output` produces expected error", { skip_if_not_installed("jsonlite") l <- lint(text = "x = 1", linters = assignment_linter()) expect_error(sarif_output(l), "Package path needs to be a relative path", fixed = TRUE) }) test_that("`sarif_output` writes expected files", { skip_if_not_installed("jsonlite") l <- lint_package( test_path("dummy_packages", "missing_dep"), linters = object_length_linter(), parse_settings = FALSE ) withr::with_tempdir({ sarif_output(l) expect_true(file.exists("lintr_results.sarif")) }) withr::with_tempdir({ sarif_output(l, filename = "myfile.sarif") expect_true(file.exists("myfile.sarif")) }) }) test_that("`sarif_output` produces valid files", { skip_if_not_installed("jsonlite") l <- lint_package( test_path("dummy_packages", "clean"), linters = default_linters, parse_settings = FALSE ) withr::with_tempdir({ sarif <- sarif_output(l) sarif <- jsonlite::fromJSON( "lintr_results.sarif", simplifyVector = TRUE, simplifyDataFrame = FALSE, simplifyMatrix = FALSE ) expect_false(is.null(sarif$runs)) expect_false(is.null(sarif$runs[[1L]]$results)) }) }) lintr/tests/testthat/test-get_source_expressions.R0000644000176200001440000003744614752731051022330 0ustar liggesuserswith_content_to_parse <- function(content, code) { f <- withr::local_tempfile() local({ con <- file(f, open = "w", encoding = "UTF-8") on.exit(close(con)) writeLines(content, con) }) source_expressions <- get_source_expressions(f) content_env <- new.env() content_env$pc <- lapply(source_expressions[["expressions"]], `[[`, "parsed_content") content_env$error <- source_expressions$error eval(substitute(code), envir = content_env) } test_that("tab positions have been corrected", { with_content_to_parse( "1\n\t", expect_length(pc, 2L) ) with_content_to_parse( "TRUE", expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == "TRUE", c("col1", "col2")], use.names = FALSE), c(1L, 4L)) ) with_content_to_parse( "\tTRUE", expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == "TRUE", c("col1", "col2")], use.names = FALSE), c(2L, 5L)) ) with_content_to_parse( "\t\tTRUE", expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == "TRUE", c("col1", "col2")], use.names = FALSE), c(3L, 6L)) ) with_content_to_parse("x\t<-\tTRUE", { expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == "x", c("col1", "col2")], use.names = FALSE), c(1L, 1L)) expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == "<-", c("col1", "col2")], use.names = FALSE), c(3L, 4L)) expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == "TRUE", c("col1", "col2")], use.names = FALSE), c(6L, 9L)) }) with_content_to_parse("\tfunction\t(x)\t{\tprint(pc[\t,1])\t;\t}", { expect_identical( unlist(pc[[1L]][pc[[1L]][["text"]] == "function", c("col1", "col2")], use.names = FALSE), c(2L, 9L) ) expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == "x", c("col1", "col2")], use.names = FALSE), c(12L, 12L)) expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == "print", c("col1", "col2")], use.names = FALSE), c(17L, 21L)) expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == ";", c("col1", "col2")], use.names = FALSE), c(32L, 32L)) expect_identical(unlist(pc[[1L]][pc[[1L]][["text"]] == "}", c("col1", "col2")], use.names = FALSE), c(34L, 34L)) }) with_content_to_parse("# test tab\n\ns <- 'I have \\t a dog'\nrep(\ts, \t3)", { expect_identical( unlist(pc[[2L]][pc[[2L]][["text"]] == "'I have \\t a dog'", c("line1", "col1", "col2")], use.names = FALSE), c(3L, 6L, 22L) ) expect_identical( unlist(pc[[3L]][pc[[3L]][["text"]] == "3", c("line1", "col1", "col2")], use.names = FALSE), c(4L, 10L, 10L) ) }) with_content_to_parse("function(){\nTRUE\n\t}", { expect_identical( unlist(pc[[1L]][1L, c("line1", "col1", "line2", "col2")], use.names = FALSE), c(1L, 1L, 3L, 2L), info = "expression that spans several lines" ) }) }) test_that("Terminal newlines are detected correctly", { content <- "lm(y ~ x)" # NB: need to specify terminal newline explicitly with cat, not writeLines() tmp <- withr::local_tempfile(lines = content) tmp2 <- withr::local_tempfile() cat(content, file = tmp2) expect_true(get_source_expressions(tmp)$expressions[[2L]]$terminal_newline) expect_false(get_source_expressions(tmp2)$expressions[[2L]]$terminal_newline) }) test_that("Multi-byte characters correct columns", { skip_if_not_utf8_locale() with_content_to_parse("`\U2020` <- 1", { # fix_column_numbers corrects the start of <- expect_identical(pc[[1L]]$col1[4L], pc[[1L]]$col1[2L] + 4L) }) }) test_that("Multi-byte character truncated by parser is ignored", { skip_if_not_utf8_locale() # \U2013 is the Unicode character 'en dash', which is # almost identical to a minus sign in monospaced fonts. content <- "y <- x \U2013 42" # message is like ':1:8: unexpected invalid token\n1: ...' with_content_to_parse(content, { base_msg <- conditionMessage(tryCatch(str2lang(content), error = identity)) # Just ensure that the captured message is a substring of the parser error, #2527 expect_true(grepl(error$message, base_msg, fixed = TRUE, useBytes = TRUE)) expect_identical(error$column_number, 8L) }) }) test_that("Can read non UTF-8 file", { file <- test_path("dummy_projects", "project", "cp1252.R") lintr:::read_settings(file) expect_null(get_source_expressions(file)$error) }) test_that("Warns if encoding is misspecified", { file <- test_path("dummy_projects", "project", "cp1252.R") lintr:::read_settings(NULL) the_lint <- lint(filename = file, parse_settings = FALSE)[[1L]] expect_s3_class(the_lint, "lint") lint_msg <- "Invalid multibyte character in parser. Is the encoding correct?" if (!isTRUE(l10n_info()[["UTF-8"]])) { # Prior to R 4.2.0, the Windows parser throws a different error message because the source code is converted to # native encoding. # This results in line 4 becoming <- 42 before the parser sees it. lint_msg <- "unexpected '<'" } expect_identical(the_lint$linter, "error") expect_identical(the_lint$message, lint_msg) expect_identical(the_lint$line_number, 4L) file <- test_path("dummy_projects", "project", "cp1252_parseable.R") lintr:::read_settings(NULL) the_lint <- lint(filename = file, parse_settings = FALSE)[[1L]] expect_s3_class(the_lint, "lint") expect_identical(the_lint$linter, "error") expect_identical(the_lint$message, "Invalid multibyte string. Is the encoding correct?") expect_identical(the_lint$line_number, 1L) }) test_that("Can extract line number from parser errors", { skip_if_not_r_version("4.0.0") # malformed raw string literal at line 2 with_content_to_parse( trim_some(' "ok" R"---a---" '), { expect_identical(error$message, "Malformed raw string literal.") expect_identical(error$line_number, 2L) } ) # invalid \u{xxxx} sequence (line 3) with_content_to_parse( trim_some(' ok ok "\\u{9999" '), { expect_identical(error$message, "Invalid \\u{xxxx} sequence.") expect_identical(error$line_number, 3L) } ) # invalid \u{xxxx} sequence (line 4) with_content_to_parse( trim_some(' ok ok "\\u{9999 '), { # parser erroneously reports line 4 expect_identical(error$message, "Invalid \\u{xxxx} sequence.") expect_identical(error$line_number, 3L) } ) # repeated formal argument 'a' on line 1 with_content_to_parse("function(a, a) {}", { expect_identical(error$message, "Repeated formal argument 'a'.") expect_identical(error$line_number, 1L) }) }) test_that("1- or 2-width octal expressions give the right STR_CONST values", { with_content_to_parse("'\\1'", expect_identical(pc[[1L]][1L, "text"], "'\\1'")) with_content_to_parse('"\\1"', expect_identical(pc[[1L]][1L, "text"], '"\\1"')) # multiple literals with_content_to_parse("'\\1'\n'\\2'", { expect_identical(pc[[1L]][1L, "text"], "'\\1'") expect_identical(pc[[2L]][1L, "text"], "'\\2'") }) # multiple escapes with_content_to_parse("'\\1\\2'", expect_identical(pc[[1L]][1L, "text"], "'\\1\\2'")) # multi-line strings with_content_to_parse("'\n\\1\n'", expect_identical(pc[[1L]][1L, "text"], "'\n\\1\n'")) with_content_to_parse("a <- '\\1\n\\2'", expect_identical(pc[[1L]][5L, "text"], "'\\1\n\\2'")) # mixed-length strings with_content_to_parse("foo('\\1',\n '\n\\2\n')", { expect_identical(pc[[1L]][5L, "text"], "'\\1'") expect_identical(pc[[1L]][8L, "text"], "'\n\\2\n'") }) }) test_that("returned data structure is complete", { lines <- c("line_1", "line_2", "line_3") temp_file <- withr::local_tempfile(lines = lines) lines_with_attr <- setNames(lines, seq_along(lines)) attr(lines_with_attr, "terminal_newline") <- TRUE exprs <- get_source_expressions(temp_file) expect_named(exprs, c("expressions", "error", "lines")) expect_length(exprs$expressions, length(lines) + 1L) for (i in seq_along(lines)) { expr <- exprs$expressions[[i]] expect_named(expr, c( "filename", "line", "column", "lines", "parsed_content", "xml_parsed_content", "xml_find_function_calls", "content" )) expect_identical(expr$filename, temp_file) expect_identical(expr$line, i) expect_identical(expr$column, 1L) expect_identical(expr$lines, setNames(lines[i], i)) expect_identical(nrow(expr$parsed_content), 2L) expect_true(xml2::xml_find_lgl(expr$xml_parsed_content, "count(//SYMBOL) > 0")) expect_identical(expr$content, lines[i]) } full_expr <- exprs$expressions[[length(lines) + 1L]] expect_named(full_expr, c( "filename", "file_lines", "content", "full_parsed_content", "full_xml_parsed_content", "xml_find_function_calls", "terminal_newline" )) expect_identical(full_expr$filename, temp_file) expect_identical(full_expr$file_lines, lines_with_attr) expect_identical(full_expr$content, lines_with_attr) expect_identical(nrow(full_expr$full_parsed_content), 2L * length(lines)) expect_identical( xml2::xml_find_num(full_expr$full_xml_parsed_content, "count(//SYMBOL)"), as.numeric(length(lines)) ) expect_true(full_expr$terminal_newline) expect_null(exprs$error) expect_identical(exprs$lines, lines_with_attr) }) test_that("xml_find_function_calls works as intended", { lines <- c("foo()", "bar()", "foo()", "{ foo(); foo(); bar() }") temp_file <- withr::local_tempfile(lines = lines) exprs <- get_source_expressions(temp_file) expect_length(exprs$expressions[[1L]]$xml_find_function_calls("foo"), 1L) expect_length(exprs$expressions[[1L]]$xml_find_function_calls("bar"), 0L) expect_identical( exprs$expressions[[1L]]$xml_find_function_calls("foo"), xml_find_all(exprs$expressions[[1L]]$xml_parsed_content, "//SYMBOL_FUNCTION_CALL[text() = 'foo']/parent::expr") ) expect_length(exprs$expressions[[2L]]$xml_find_function_calls("foo"), 0L) expect_length(exprs$expressions[[2L]]$xml_find_function_calls("bar"), 1L) expect_length(exprs$expressions[[4L]]$xml_find_function_calls("foo"), 2L) expect_length(exprs$expressions[[4L]]$xml_find_function_calls("bar"), 1L) expect_length(exprs$expressions[[4L]]$xml_find_function_calls(c("foo", "bar")), 3L) # file-level source expression contains all function calls expect_length(exprs$expressions[[5L]]$xml_find_function_calls("foo"), 4L) expect_length(exprs$expressions[[5L]]$xml_find_function_calls("bar"), 2L) expect_length(exprs$expressions[[5L]]$xml_find_function_calls(c("foo", "bar")), 6L) # Also check order is retained: expect_identical( exprs$expressions[[5L]]$xml_find_function_calls(c("foo", "bar")), xml_find_all(exprs$expressions[[5L]]$full_xml_parsed_content, "//SYMBOL_FUNCTION_CALL/parent::expr") ) # Check naming and full cache expect_identical( exprs$expressions[[5L]]$xml_find_function_calls(NULL), exprs$expressions[[5L]]$xml_find_function_calls(c("foo", "bar")) ) expect_named( exprs$expressions[[4L]]$xml_find_function_calls(c("foo", "bar"), keep_names = TRUE), c("foo", "foo", "bar") ) }) test_that("#1262: xml_parsed_content gets returned as missing even if there's no parsed_content", { tempfile <- withr::local_tempfile(lines = '"\\R"') source_expressions <- get_source_expressions(tempfile) expect_null(source_expressions$expressions[[1L]]$full_parsed_content) expect_identical(source_expressions$expressions[[1L]]$full_xml_parsed_content, xml2::xml_missing()) }) test_that("#743, #879, #1406: get_source_expressions works on R files matching a knitr pattern", { # from #743 tempfile <- withr::local_tempfile( lines = trim_some(' create_template <- function(x) { sprintf(" ```{r code} foo <- function(x) x+%d foo(5) ```", x) } ') ) source_expressions <- get_source_expressions(tempfile) expect_null(source_expressions$error) # from #879 tempfile <- withr::local_tempfile( lines = trim_some(' # `r print("7")` function() 2<=3 ') ) source_expressions <- get_source_expressions(tempfile) expect_null(source_expressions$error) # from #1406 tempfile <- withr::local_tempfile() writeLines(c("x <- '", "```{r}", "'"), con = tempfile) source_expressions <- get_source_expressions(tempfile) expect_null(source_expressions$error) }) test_that("Syntax errors in Rmd or qmd don't choke lintr", { tmp <- withr::local_tempfile(lines = c( "```{r}", "if (TRUE) {", " 1", # missing `}` here "if (TRUE) {", "}", "```" )) expect_silent(get_source_expressions(tmp)) }) test_that("Indented Rmd chunks don't cause spurious whitespace lints", { tmp <- withr::local_tempfile(lines = c( "* An enumeration item with code:", "", " ```{r}", ' "properly indented"', " ```", "", "# New section", "", "```{r unindented_chunk}", ' "improperly indented"', "```", "", "# Third section", "", " ```{r staggered}", ' "leftmost code"', ' "further right"', ' "aligned with code gate"', " ```" )) parsed_lines <- get_source_expressions(tmp)$lines expect_identical(parsed_lines[4L], '"properly indented"', ignore_attr = "names") expect_identical(parsed_lines[10L], ' "improperly indented"', ignore_attr = "names") expect_identical(parsed_lines[16L], '"leftmost code"', ignore_attr = "names") expect_identical(parsed_lines[17L], ' "further right"', ignore_attr = "names") expect_identical(parsed_lines[18L], ' "aligned with code gate"', ignore_attr = "names") }) test_that("Reference chunks in Sweave/Rmd are ignored", { example_rnw <- system.file("Sweave", "example-1.Rnw", package = "utils") # ensure such a chunk continues to exist upstream expect_true(any(grepl("^\\s*<<[^>]*>>\\s*$", readLines(example_rnw)))) expect_silent(lint(example_rnw)) }) # NB: this is just a cursory test for linters not to # fail on files where the XML content is xml_missing; # the main linter test files provide more thorough # evidence that things are working as intended. bad_source <- withr::local_tempfile(lines = c("a <- 1L", "b <- 2L")) expressions <- get_source_expressions(bad_source)$expressions # "zap" the xml_parsed_content to be xml_missing -- this gets # around the issue of creating a file that fails to parse now, # but later fails in a different way -> xml not missing. for (ii in seq_along(expressions)) { if ("xml_parsed_content" %in% names(expressions[[ii]])) { expressions[[ii]]$xml_parsed_content <- xml2::xml_missing() } else { expressions[[ii]]$full_xml_parsed_content <- xml2::xml_missing() } } param_df <- expand.grid( linter = available_linters(tags = NULL)$linter, expression_idx = seq_along(expressions), stringsAsFactors = FALSE ) param_df$.test_name <- with(param_df, sprintf("%s on expression %d", linter, expression_idx)) patrick::with_parameters_test_that( "linters pass with xml_missing() content", { if (linter == "backport_linter") { # otherwise we test the trivial linter (#2339) linter <- backport_linter(r_version = "3.6.0") } else { if (linter == "cyclocomp_linter") { skip_if_not_installed("cyclocomp") } linter <- eval(call(linter)) } expression <- expressions[[expression_idx]] is_valid_linter_level <- (is_linter_level(linter, "expression") && is_lint_level(expression, "expression")) || (is_linter_level(linter, "file") && is_lint_level(expression, "file")) if (is_valid_linter_level) { expect_no_warning({ lints <- linter(expression) }) expect_length(lints, 0L) } else { # suppress "empty test" skips expect_true(TRUE) } }, .test_name = param_df$.test_name, linter = param_df$linter, expression_idx = param_df$expression_idx ) test_that("invalid function definition parser failure lints", { expect_lint( "function(a = 1, a = 1) NULL", rex::rex("Repeated formal argument 'a'."), linters = list() ) }) test_that("Disallowed embedded null gives parser failure lint", { expect_lint( "'\\0'", rex::rex("Nul character not allowed."), linters = list() ) }) lintr/tests/testthat/test-assignment_linter.R0000644000176200001440000002725414752731051021250 0ustar liggesuserstest_that("assignment_linter skips allowed usages", { linter <- assignment_linter() expect_lint("blah", NULL, linter) expect_lint("blah <- 1", NULL, linter) expect_lint("blah<-1", NULL, linter) expect_lint("fun(blah=1)", NULL, linter) }) test_that("assignment_linter blocks disallowed usages", { linter <- assignment_linter() lint_msg <- rex::rex("Use one of <-, <<- for assignment, not =.") expect_lint("blah=1", lint_msg, linter) expect_lint("blah = 1", lint_msg, linter) expect_lint("blah = fun(1)", lint_msg, linter) expect_lint("fun((blah = fun(1)))", lint_msg, linter) expect_lint( "blah = fun(1) {", list( lint_msg, c(type = "error", "unexpected") ), linter ) }) test_that("arguments handle <<- and ->/->> correctly", { linter <- assignment_linter() linter_yes_right <- assignment_linter(operator = c("->", "->>")) lint_msg_right <- rex::rex("Replace ->> by assigning to a specific environment") expect_lint("1 -> blah", rex::rex("Use one of <-, <<- for assignment, not ->."), linter) expect_lint("1 ->> blah", lint_msg_right, assignment_linter(operator = "<-")) # <<- is only blocked optionally expect_lint("1 <<- blah", NULL, linter) expect_lint( "1 <<- blah", rex::rex("Replace <<- by assigning to a specific environment"), assignment_linter(operator = "<-") ) # blocking -> can be disabled expect_lint("1 -> blah", NULL, linter_yes_right) expect_lint("1 ->> blah", NULL, linter_yes_right) # we can also differentiate '->' and '->>' expect_lint( "1 ->> blah", lint_msg_right, assignment_linter(operator = c("<-", "->")) ) # when user allows _some_ cascading assignment, advice should not mention the # problems with cascading assignment, but focus on the specific disallowed operator. expect_lint( "1 ->> blah", rex::rex("Use one of <-, <<- for assignment, not ->>."), assignment_linter(operator = c("<-", "<<-")) ) expect_lint( "blah <<- 1", rex::rex("Use one of ->, ->> for assignment, not <<-."), assignment_linter(operator = c("->", "->>")) ) }) test_that("arguments handle trailing assignment operators correctly", { linter_default <- assignment_linter() linter_no_trailing <- assignment_linter(allow_trailing = FALSE) expect_lint("x <- y", NULL, linter_no_trailing) expect_lint("foo(bar = 1)", NULL, linter_no_trailing) expect_lint( trim_some(" foo(bar = 1) "), rex::rex("= should not be trailing at the end of a line."), linter_no_trailing ) expect_lint( trim_some(" x <<- y "), rex::rex("<<- should not be trailing"), linter_no_trailing ) expect_lint( trim_some(" x <<- y "), list( rex::rex("Replace <<- by assigning to a specific environment"), rex::rex("Assignment <<- should not be trailing") ), assignment_linter(operator = "<-", allow_trailing = FALSE) ) expect_lint( trim_some(" x <- #Test y "), rex::rex("<- should not be trailing"), linter_no_trailing ) pipe_left_string <- trim_some(" is_long <- is %>% gather(measure, value, -Species) %>% arrange(-value) ") expect_lint(pipe_left_string, NULL, linter_default) expect_lint(pipe_left_string, rex::rex("<- should not be trailing"), linter_no_trailing) pipe_right_string <- trim_some(" is %>% gather(measure, value, -Species) %>% arrange(-value) -> is_long ") expect_lint(pipe_right_string, rex::rex("Use one of <-, <<- for assignment, not ->"), linter_default) expect_lint( pipe_right_string, list( rex::rex("Use one of <-, <<- for assignment, not ->"), rex::rex("Assignment -> should not be trailing") ), linter_no_trailing ) expect_lint( pipe_right_string, rex::rex("-> should not be trailing"), assignment_linter(operator = "->", allow_trailing = FALSE) ) expect_lint( trim_some(" blah = 42 blh2 <- 54 "), list( list(message = "Use one of <-, <<- for assignment, not =.", line_number = 1L, column_number = 6L), list(message = "Assignment = should not be trailing at the end of a line", line_number = 1L, column_number = 6L), list(message = "Assignment <- should not be trailing at the end of a line", line_number = 3L, column_number = 6L) ), linter_no_trailing ) expect_lint( trim_some(" a = 1 "), "= should not be trailing", assignment_linter(operator = "=", allow_trailing = FALSE) ) }) test_that("allow_trailing interacts correctly with comments in braced expressions", { linter <- assignment_linter(allow_trailing = FALSE) expect_lint( trim_some(" { x <- 1 # blah y <- 2 } "), NULL, linter ) expect_lint( trim_some(" { x <- '#x' y <- '#y' } "), NULL, linter ) expect_lint( trim_some(" { x <- # blah 'x' } "), list(message = "<-", line_number = 2L), linter ) expect_lint( trim_some(" { x <- ' a string with an assignment <- at the end of the line ' } "), NULL, linter ) }) test_that("%<>% throws a lint", { expect_lint("x %<>% sum()", "Avoid the assignment pipe %<>%", assignment_linter()) expect_lint("x %<>% sum()", NULL, assignment_linter(operator = "%<>%")) # interaction with allow_trailing expect_lint( trim_some(" x %<>% sum() "), list( "Avoid the assignment pipe %<>%", "Assignment %<>% should not be trailing" ), assignment_linter(allow_trailing = FALSE) ) }) test_that("multiple lints throw correct messages", { expect_lint( trim_some("{ x <<- 1 y ->> 2 z -> 3 x %<>% as.character() }"), list( list(message = "Replace <<- by assigning to a specific environment", line_number = 2L), list(message = "Replace ->> by assigning to a specific environment", line_number = 3L), list(message = "Use <- for assignment, not ->", line_number = 4L), list(message = "Avoid the assignment pipe %<>%", line_number = 5L) ), assignment_linter(operator = "<-") ) }) test_that("assignment operator can be toggled", { eq_linter <- assignment_linter(operator = "=") any_linter <- assignment_linter(operator = "any") lint_message <- rex("Use = for assignment, not") expect_lint("a = 1", NULL, eq_linter) expect_lint("a = 1", NULL, any_linter) expect_lint("a <- 1", lint_message, eq_linter) expect_lint("a <- 1", NULL, any_linter) expect_lint("a = 1; b <- 2", lint_message, eq_linter) expect_lint("a = 1; b <- 2", NULL, any_linter) expect_lint( trim_some(" foo = function() { a = 1 } "), NULL, eq_linter ) expect_lint( trim_some(" foo = function() { a = 1 } "), NULL, any_linter ) expect_lint( trim_some(" foo = function() { a <- 1 } "), list(lint_message, line_number = 2L), eq_linter ) expect_lint( trim_some(" foo = function() { a <- 1 } "), NULL, any_linter ) expect_lint("if ({a = TRUE}) 1", NULL, eq_linter) expect_lint("if ({a = TRUE}) 1", NULL, any_linter) expect_lint("if (a <- TRUE) 1", NULL, eq_linter) expect_lint("if (a <- TRUE) 1", NULL, any_linter) expect_lint("for (ii in {a = TRUE}) 1", NULL, eq_linter) expect_lint("for (ii in {a = TRUE}) 1", NULL, any_linter) expect_lint("for (ii in a <- TRUE) 1", NULL, eq_linter) expect_lint("for (ii in a <- TRUE) 1", NULL, any_linter) expect_lint( trim_some(" x = 2 y <- 3 "), list( list("Assignment = should not be trailing", line_number = 1L), list("Assignment <- should not be trailing", line_number = 3L) ), assignment_linter(operator = "any", allow_trailing = FALSE) ) }) test_that("multiple lints throw correct messages when both = and <- are allowed", { expect_lint( trim_some("{ x <<- 1 y ->> 2 z -> 3 x %<>% as.character() foo <- 1 bar = 2 }"), list( list(message = "Replace <<- by assigning to a specific environment", line_number = 2L), list(message = "Replace ->> by assigning to a specific environment", line_number = 3L), list(message = "Use one of =, <- for assignment, not ->", line_number = 4L), list(message = "Avoid the assignment pipe %<>%", line_number = 5L) ), assignment_linter(operator = c("=", "<-")) ) }) test_that("multiple lints throw correct messages when = is required", { expect_lint( trim_some("{ x <<- 1 y ->> 2 z -> 3 x %<>% as.character() foo <- 1 bar = 2 }"), list( list(message = "Replace <<- by assigning to a specific environment", line_number = 2L), list(message = "Replace ->> by assigning to a specific environment", line_number = 3L), list(message = "Use = for assignment, not ->", line_number = 4L), list(message = "Avoid the assignment pipe %<>%", line_number = 5L), list(message = "Use = for assignment, not <-", line_number = 6L) ), assignment_linter(operator = "=") ) }) # tests copy-pasted from earlier suite and embellished with warnings; to be removed test_that("Deprecated arguments work & warn as intended", { expect_warning(regexp = "allow_cascading_assign", { linter_no_cascade <- assignment_linter(allow_cascading_assign = FALSE) }) # Positionally-passed argument is hard-deprecated since we changed argument order. expect_error(assignment_linter(FALSE), "allow_cascading_assign") expect_warning(regexp = "allow_right_assign", { linter_yes_right <- assignment_linter(allow_right_assign = TRUE) }) expect_warning(regexp = "allow_right_assign", expect_warning(regexp = "allow_cascading_assign", { linter_no_cascade_yes_right <- assignment_linter(allow_cascading_assign = FALSE, allow_right_assign = TRUE) })) expect_warning(regexp = "allow_cascading_assign", { linter_no_cascade_no_trailing <- assignment_linter(allow_trailing = FALSE, allow_cascading_assign = FALSE) }) expect_warning(regexp = "allow_right_assign", { linter_yes_right_no_trailing <- assignment_linter(allow_right_assign = TRUE, allow_trailing = FALSE) }) expect_warning(regexp = "allow_pipe_assign", { linter_yes_pipe <- assignment_linter(allow_pipe_assign = TRUE) }) expect_lint( "1 <<- blah", rex::rex("Replace <<- by assigning to a specific environment"), linter_no_cascade ) expect_lint("1 -> blah", NULL, linter_yes_right) expect_lint("1 ->> blah", NULL, linter_yes_right) expect_lint( "1 ->> blah", rex::rex("Replace ->> by assigning to a specific environment"), linter_no_cascade_yes_right ) expect_lint( trim_some(" x <<- y "), list( rex::rex("Replace <<- by assigning to a specific environment"), rex::rex("Assignment <<- should not be trailing") ), linter_no_cascade_no_trailing ) expect_lint( trim_some(" is %>% gather(measure, value, -Species) %>% arrange(-value) -> is_long "), rex::rex("-> should not be trailing"), linter_yes_right_no_trailing ) expect_lint("x %<>% sum()", NULL, linter_yes_pipe) expect_lint( trim_some("{ x <<- 1 y ->> 2 z -> 3 x %<>% as.character() }"), list( list(message = "Replace <<- by assigning to a specific environment", line_number = 2L), list(message = "Replace ->> by assigning to a specific environment", line_number = 3L), list(message = "Use <- for assignment, not ->", line_number = 4L), list(message = "Avoid the assignment pipe %<>%", line_number = 5L) ), linter_no_cascade ) }) lintr/tests/testthat/test-paren_body_linter.R0000644000176200001440000000477714752731051021227 0ustar liggesuserstestthat::test_that("paren_body_linter returns correct lints", { linter <- paren_body_linter() lint_msg <- rex::rex("Put a space between a right parenthesis and a body expression.") # No space after the closing parenthesis prompts a lint expect_lint("function()test", lint_msg, linter) expect_lint("print('hello')\nx <- function(x)NULL\nprint('hello')", lint_msg, linter) expect_lint("if (TRUE)test", lint_msg, linter) expect_lint("while (TRUE)test", lint_msg, linter) expect_lint("for (i in seq_along(1))test", lint_msg, linter) # A space after the closing parenthesis does not prompt a lint expect_lint("function() test", NULL, linter) # Symbols after the closing parenthesis of a function call do not prompt a lint expect_lint("head(mtcars)$cyl", NULL, linter) # paren_body_linter returns the correct line number expect_lint( "print('hello')\nx <- function(x)NULL\nprint('hello')", list(line_number = 2L), linter ) expect_lint( "function()test", list( line_number = 1L, column_number = 11L, type = "style", line = "function()test", ranges = list(c(11L, 14L)) ), linter ) # paren_body_linter does not lint when the function body is defined on a new line expect_lint("function()\n test", NULL, linter) # paren_body_linter does not lint comments expect_lint("#function()test", NULL, linter) # multiple lints on the same line expect_lint("function()if(TRUE)while(TRUE)test", list(lint_msg, lint_msg, lint_msg), linter) # No space after the closing parenthesis of an anonymous function prompts a lint skip_if_not_r_version("4.1.0") expect_lint("\\()test", lint_msg, linter) }) test_that("multi-line versions are caught", { linter <- paren_body_linter() lint_msg <- rex::rex("Put a space between a right parenthesis and a body expression.") expect_lint( trim_some(" function(var )x "), lint_msg, linter ) expect_lint( trim_some(" if (cond )x "), lint_msg, linter ) expect_lint( trim_some(" while (cond )x "), lint_msg, linter ) skip_if_not_r_version("4.1.0") expect_lint( trim_some(" \\(var )x "), lint_msg, linter ) }) test_that("function shorthand is handled", { skip_if_not_r_version("4.1.0") linter <- paren_body_linter() lint_msg <- rex::rex("Put a space between a right parenthesis and a body expression.") expect_lint("\\()test", lint_msg, linter) }) lintr/tests/testthat/test-empty_assignment_linter.R0000644000176200001440000000254414752731051022461 0ustar liggesuserstest_that("empty_assignment_linter skips valid usage", { expect_lint("x <- { 3 + 4 }", NULL, empty_assignment_linter()) expect_lint("x <- if (x > 1) { 3 + 4 }", NULL, empty_assignment_linter()) # also triggers assignment_linter expect_lint("x = { 3 + 4 }", NULL, empty_assignment_linter()) }) test_that("empty_assignment_linter blocks disallowed usages", { linter <- empty_assignment_linter() lint_msg <- rex::rex("Assign NULL explicitly or, whenever possible, allocate the empty object") expect_lint("xrep <- {}", lint_msg, linter) # assignment with equal works as well, and white space doesn't matter expect_lint("x = { }", lint_msg, linter) # ditto right assignments expect_lint("{} -> x", lint_msg, linter) expect_lint("{} ->> x", lint_msg, linter) # ditto data.table-style walrus assignments expect_lint("x[, col := {}]", lint_msg, linter) # newlines also don't matter expect_lint("x <- {\n}", lint_msg, linter) # LHS of assignment doesn't matter expect_lint("env$obj <- {}", lint_msg, linter) }) test_that("lints vectorize", { lint_msg <- rex::rex("Assign NULL explicitly or, whenever possible, allocate the empty object") expect_lint( trim_some("{ x <- {} y = {} }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), empty_assignment_linter() ) }) lintr/tests/testthat/test-semicolon_linter.R0000644000176200001440000000607714752731051021070 0ustar liggesuserstest_that("Lint all semicolons", { linter <- semicolon_linter() trail_msg <- rex::rex("Remove trailing semicolons.") comp_msg <- rex::rex("Replace compound semicolons by a newline.") # No semicolon expect_lint("", NULL, linter) expect_lint("a <- 1", NULL, linter) expect_lint("function() {a <- 1}", NULL, linter) expect_lint("a <- \"foo;bar\"", NULL, linter) expect_lint("function() {a <- \"foo;bar\"}", NULL, linter) expect_lint("a <- FALSE # ok; cool!", NULL, linter) expect_lint("function() {\na <- FALSE # ok; cool!\n}", NULL, linter) # Trailing semicolons expect_lint( "a <- 1;", list(message = trail_msg, line_number = 1L, column_number = 7L), linter ) expect_lint( "function(){a <- 1;}", list(message = trail_msg, line_number = 1L, column_number = 18L), linter ) expect_lint( "a <- 1; \n", list(message = trail_msg, line_number = 1L, column_number = 7L), linter ) expect_lint( "function(){a <- 1; \n}", list(message = trail_msg, line_number = 1L, column_number = 18L), linter ) # Compound semicolons expect_lint( "a <- 1;b <- 2", list(message = comp_msg, line_number = 1L, column_number = 7L), linter ) expect_lint( "function() {a <- 1;b <- 2}\n", list(message = comp_msg, line_number = 1L, column_number = 19L), linter ) expect_lint( "foo <-\n 1 ; foo <- 1.23", list(message = comp_msg, line_number = 2L, column_number = 6L), linter ) expect_lint( "function(){\nfoo <-\n 1 ; foo <- 1.23\n}", list(message = comp_msg, line_number = 3L, column_number = 6L), linter ) # Multiple, mixed semicolons", { expect_lint( "a <- 1 ; b <- 2;\nc <- 3;", list( list(message = comp_msg, line_number = 1L, column_number = 8L), list(message = trail_msg, line_number = 1L, column_number = 16L), list(message = trail_msg, line_number = 2L, column_number = 7L) ), linter ) expect_lint( "function() { a <- 1 ; b <- 2;\nc <- 3;}", list( list(message = comp_msg, line_number = 1L, column_number = 21L), list(message = trail_msg, line_number = 1L, column_number = 29L), list(message = trail_msg, line_number = 2L, column_number = 7L) ), linter ) }) test_that("Compound semicolons only", { linter <- semicolon_linter(allow_trailing = TRUE) expect_lint("a <- 1;", NULL, linter) expect_lint("function(){a <- 1;}", NULL, linter) expect_lint("a <- 1; \n", NULL, linter) expect_lint("function(){a <- 1; \n}", NULL, linter) }) test_that("Trailing semicolons only", { linter <- semicolon_linter(allow_compound = TRUE) expect_lint("a <- 1;b <- 2", NULL, linter) expect_lint("function() {a <- 1;b <- 2}\n", NULL, linter) expect_lint("f <-\n 1 ;f <- 1.23", NULL, linter) expect_lint("function(){\nf <-\n 1 ;f <- 1.23\n}", NULL, linter) }) test_that("Compound semicolons only", { expect_error( lint(text = "a <- 1;", linters = semicolon_linter(allow_trailing = TRUE, allow_compound = TRUE)), "At least one of `allow_compound` or `allow_trailing` must be `FALSE`", fixed = TRUE ) }) lintr/tests/testthat/test-expect_length_linter.R0000644000176200001440000000346114752731051021723 0ustar liggesuserstest_that("expect_length_linter skips allowed usages", { linter <- expect_length_linter() expect_lint("expect_equal(nrow(x), 4L)", NULL, linter) # NB: also applies to tinytest, but it's sufficient to test testthat expect_lint("testthat::expect_equal(nrow(x), 4L)", NULL, linter) # only check the first argument. yoda tests in the second argument will be # missed, but there are legitimate uses of length() in argument 2 expect_lint("expect_equal(nrow(x), length(y))", NULL, linter) # expect_length() doesn't have info= or label= arguments expect_lint("expect_equal(length(x), n, info = 'x should have size n')", NULL, linter) expect_lint("expect_equal(length(x), n, label = 'x size')", NULL, linter) expect_lint("expect_equal(length(x), n, expected.label = 'target size')", NULL, linter) }) test_that("expect_length_linter blocks simple disallowed usages", { linter <- expect_length_linter() lint_msg <- rex::rex("expect_length(x, n) is better than expect_equal(length(x), n)") expect_lint("expect_equal(length(x), 2L)", lint_msg, linter) expect_lint("testthat::expect_equal(length(DF), length(old))", lint_msg, linter) # yoda test cases expect_lint("expect_equal(2, length(x))", lint_msg, linter) expect_lint("expect_equal(2L, length(x))", lint_msg, linter) }) test_that("expect_length_linter blocks expect_identical usage as well", { expect_lint( "expect_identical(length(x), 2L)", rex::rex("expect_length(x, n) is better than expect_identical(length(x), n)"), expect_length_linter() ) }) test_that("lints vectorize", { expect_lint( trim_some("{ expect_equal(length(x), n) expect_identical(length(x), n) }"), list( list("expect_equal", line_number = 2L), list("expect_identical", line_number = 3L) ), expect_length_linter() ) }) lintr/tests/testthat/test-comparison_negation_linter.R0000644000176200001440000000334514752731051023131 0ustar liggesuserstest_that("comparison_negation_linter skips allowed usages", { linter <- comparison_negation_linter() # doesn't apply to joint statements expect_lint("!(x == y | y == z)", NULL, linter) # don't force de Morgan's laws expect_lint("!(x & y)", NULL, linter) # naive xpath will include !foo(x) cases expect_lint("!any(x > y)", NULL, linter) # ditto for tidyeval cases expect_lint("!!target == 1 ~ 'target'", NULL, linter) # ditto for !x[f == g] expect_lint("!passes.test[stage == 1]", NULL, linter) }) local({ linter <- comparison_negation_linter() comparators <- c("==", "!=", ">=", ">", "<=", "<") inverses <- c("!=", "==", "<", "<=", ">", ">=") patrick::with_parameters_test_that( "comparison_negation_linter blocks simple disallowed usages", { expect_lint( sprintf("!(x %s y)", comparator), rex::rex(sprintf("Use x %s y, not !(x %s y)", inverse, comparator)), linter ) expect_lint( sprintf("!x %s y", comparator), rex::rex(sprintf("Use x %s y, not !(x %s y)", inverse, comparator)), linter ) }, .test_name = comparators, comparator = comparators, inverse = inverses ) }) test_that("comparison_negation_linter catches plain ! (no parens) + call", { # Earlier logic would find the wrong node due to expr in length() expect_lint( "!length(x) > 0", rex::rex("Use x <= y, not !(x > y)"), comparison_negation_linter() ) }) test_that("Lints vectorize", { expect_lint( trim_some("{ !(x > y) !x == y }"), list( list(rex::rex("Use x <= y, not !(x > y)."), line_number = 2L), list(rex::rex("Use x != y, not !(x == y)."), line_number = 3L) ), comparison_negation_linter() ) }) lintr/tests/testthat/test-exclusions.R0000644000176200001440000001204214752731051017704 0ustar liggesuserstest_that("it excludes properly", { withr::local_options( lintr.exclude = "#TeSt_NoLiNt", lintr.exclude_start = "#TeSt_NoLiNt_StArT", lintr.exclude_end = "#TeSt_NoLiNt_EnD" ) lintr:::read_settings(NULL) t1 <- lint("exclusions-test", parse_settings = FALSE) expect_length(t1, 8L) t2 <- lint("exclusions-test", exclusions = list("exclusions-test" = 4L), parse_settings = FALSE) expect_length(t2, 7L) t3 <- lint("exclusions-test", exclusions = list("exclusions-test"), parse_settings = FALSE) expect_length(t3, 0L) cache_path <- file.path(tempdir(), "lintr_cache") clear_cache("exclusions-test", cache_path) for (info in sprintf("caching: pass %s", 1L:4L)) { t4 <- lint("exclusions-test", cache = cache_path, parse_settings = FALSE) expect_identical(length(t4), 8L, info = info) } }) test_that("it doesn't fail when encountering misspecified encodings", { withr::local_options( lintr.exclude = "#TeSt_NoLiNt", lintr.exclude_start = "#TeSt_NoLiNt_StArT", lintr.exclude_end = "#TeSt_NoLiNt_EnD" ) lintr:::read_settings(NULL) expect_length(lintr:::parse_exclusions("dummy_projects/project/cp1252.R"), 0L) }) test_that("it gives the expected error message when there is only one start but no end", { lintr:::read_settings(NULL) expect_error( lintr:::parse_exclusions("dummy_projects/project/one_start_no_end.R"), "has 1 range start (line 3) and 0 range ends", fixed = TRUE ) }) test_that("it gives the expected error message when there is mismatch between multiple starts and ends", { lintr:::read_settings(NULL) expect_error( lintr:::parse_exclusions("dummy_projects/project/mismatched_starts_ends.R"), "has 3 range starts (lines 3, 7, 11) and 2 range ends (lines 1, 9)", fixed = TRUE ) }) test_that("partial matching works for exclusions but warns if no linter found", { lintr:::read_settings(NULL) expect_warning( expect_warning( expect_warning( expect_lint( file = "dummy_projects/project/partially_matched_exclusions.R", checks = rex::rex("semicolons"), parse_settings = FALSE ), rex::rex("Could not find linter named ", anything, "s") ), rex::rex("Could not find linter named ", anything, "bogus_linter") ), rex::rex("Could not find linters named ", anything, "hocus_pocus", anything, "bogus") ) }) test_that("#1413: lint_dir properly excludes files", { withr::local_options(lintr.linter_file = "lintr_test_config") tmp <- withr::local_tempdir() writeLines( trim_some(" linters: linters_with_defaults( line_length_linter(10) ) exclusions: list( 'bad.R' = list( 1, # global exclusions are unnamed line_length_linter = 4:6 ) ) "), file.path(tmp, "lintr_test_config") ) writeLines( trim_some(" tmp = 'value' # comment # long comment # long comment # long comment # comment "), file.path(tmp, "bad.R") ) expect_length(lint(file.path(tmp, "bad.R")), 0L) expect_length(lint_dir(tmp), 0L) }) test_that("#1442: is_excluded_files works if no global exclusions are specified", { withr::local_options(lintr.linter_file = "lintr_test_config") tmp <- withr::local_tempdir() writeLines( trim_some(" linters: linters_with_defaults( line_length_linter(10) ) exclusions: list( 'bad.R' = list( line_length_linter = 4:6 ) ) "), file.path(tmp, "lintr_test_config") ) writeLines( trim_some(" tmp = 'value' # comment # long comment # long comment # long comment # comment "), file.path(tmp, "bad.R") ) # 3 lints: assignment_linter(), quotes_linter() and line_length_linter() expect_lint( file = file.path(tmp, "bad.R"), checks = list( list(linter = "assignment_linter", line_number = 1L), list(linter = "quotes_linter", line_number = 1L), list(linter = "line_length_linter", line_number = 1L) ) ) expect_length(lint_dir(tmp), 3L) }) test_that("next-line exclusion works", { withr::local_options( lintr.exclude = "# NL", lintr.exclude_next = "# NLN", lintr.exclude_linter = default_settings$exclude_linter ) linter <- assignment_linter() # blanket exclusion works expect_lint( trim_some(" # NLN x = 1 "), NULL, linter ) # specific exclusion works expect_lint( trim_some(" # NLN: assignment_linter. x = 1 "), NULL, linter ) expect_lint( trim_some(" # NLN: assignment. x = 1 "), NULL, linter ) expect_lint( trim_some(" # NLN: line_length_linter. x = 1 "), rex::rex("Use one of <-, <<- for assignment, not =."), list(linter, line_length_linter()) ) # interaction with plain nolint expect_lint( trim_some(" x = 1 # NLN: assignment_linter. x = 2 "), list(rex::rex("Use one of <-, <<- for assignment, not =."), line_number = 1L), linter ) }) lintr/tests/testthat/test-undesirable_operator_linter.R0000644000176200001440000000525014752731051023300 0ustar liggesuserstest_that("linter returns correct linting", { linter <- undesirable_operator_linter(op = c("$" = "As an alternative, use the `[[` accessor.", "<<-" = NA)) msg_assign <- rex::escape("Avoid undesirable operator `<<-`.") msg_dollar <- rex::escape("Avoid undesirable operator `$`. As an alternative, use the `[[` accessor.") expect_lint("x <- foo:::getObj()", NULL, linter) expect_lint("cat(\"10$\")", NULL, linter) expect_lint( "a <<- log(10)", list(message = msg_assign, line_number = 1L, column_number = 3L), linter ) expect_lint( "data$parsed == c(1, 2)", list(message = msg_dollar, line_number = 1L, column_number = 5L), linter ) }) test_that("undesirable_operator_linter handles '=' consistently", { linter <- undesirable_operator_linter(op = c("=" = "As an alternative, use '<-'")) expect_lint("a = 2L", rex::rex("Avoid undesirable operator `=`."), linter) expect_lint("lm(data = mtcars)", NULL, linter) expect_lint("function(a = 1) { }", NULL, linter) }) test_that("undesirable_operator_linter handles infixes correctly", { linter <- undesirable_operator_linter(list("%oo%" = NA)) expect_lint("a %oo% b", rex::rex("Avoid undesirable operator `%oo%`."), linter) expect_lint("a %00% b", NULL, linter) # somewhat special case: %% is in infix_metadata expect_lint( "foo(x %% y, x %/% y)", rex::rex("Avoid undesirable operator `%%`."), undesirable_operator_linter(list("%%" = NA)) ) }) test_that("undesirable_operator_linter vectorizes messages", { expect_lint( "x <<- c(pkg:::foo, bar %oo% baz)", list( rex::rex("Avoid undesirable operator `<<-`. It assigns"), rex::rex("Avoid undesirable operator `:::`. It accesses"), rex::rex("Avoid undesirable operator `%oo%`.", end) ), undesirable_operator_linter(modify_defaults(default_undesirable_operators, "%oo%" = NA)) ) }) test_that("invalid inputs fail correctly", { error_msg <- "`op` should be a non-empty named character vector" expect_error( undesirable_operator_linter("***"), error_msg, fixed = TRUE ) expect_error( undesirable_operator_linter(c("***" = NA, NA)), error_msg, fixed = TRUE ) expect_error( undesirable_operator_linter(op = NULL), error_msg, fixed = TRUE ) expect_error( undesirable_operator_linter(op = character(0L)), error_msg, fixed = TRUE ) expect_error( undesirable_operator_linter(c("***" = NA)), 'Did not recognize any valid operators in request for: "***"', fixed = TRUE ) expect_error( undesirable_operator_linter(c("***" = NA, "///" = NA)), 'Did not recognize any valid operators in request for: "***" and "///"', fixed = TRUE ) }) lintr/tests/testthat/knitr_extended_formats/0000755000176200001440000000000014752731051021153 5ustar liggesuserslintr/tests/testthat/knitr_extended_formats/tufte.Rmd0000644000176200001440000000014114752731051022742 0ustar liggesusers--- output: tufte::tufte_html --- ```{marginfigure} "Hi" - X ``` ```{r} a = 1 ``` lintr/tests/testthat/knitr_extended_formats/bookdown.Rmd0000644000176200001440000000040314752731051023436 0ustar liggesusers--- documentclass: book output: bookdown::html_document2 --- # Examples ```{definition} The characteristic function of a random variable $X$ is defined by $$\varphi _{X}(t)=\operatorname {E} \left[e^{itX}\right], \; t\in\mathcal{R}$$ ``` ```{r} a = 1 ``` lintr/tests/testthat/test-trailing_whitespace_linter.R0000644000176200001440000000343114752731051023114 0ustar liggesuserstest_that("returns the correct linting", { linter <- trailing_whitespace_linter() lint_msg <- rex::rex("Remove trailing whitespace.") expect_lint("blah", NULL, linter) expect_lint( "blah <- 1 ", list(message = lint_msg, column_number = 10L), linter ) expect_lint("blah <- 1 \n'hi'", lint_msg, linter) expect_lint( "blah <- 1\n'hi'\na <- 2 ", list(message = lint_msg, line_number = 3L), linter ) }) test_that("also handles completely empty lines per allow_empty_lines argument", { linter <- trailing_whitespace_linter() lint_msg <- rex::rex("Remove trailing whitespace.") expect_lint( "blah <- 1\n \n'hi'\na <- 2", list(message = lint_msg, line_number = 2L), linter ) expect_lint( "blah <- 1 ", list(message = lint_msg, column_number = 10L), trailing_whitespace_linter(allow_empty_lines = TRUE) ) expect_lint( "blah <- 1\n \n'hi'\na <- 2", NULL, trailing_whitespace_linter(allow_empty_lines = TRUE) ) }) test_that("also handles trailing whitespace in string constants", { linter <- trailing_whitespace_linter() lint_msg <- rex::rex("Remove trailing whitespace.") expect_lint("blah <- ' \n \n'", NULL, linter) # Don't exclude past the end of string expect_lint( "blah <- ' \n \n' ", list(message = lint_msg, line_number = 3L), linter ) # can be enabled with allow_in_strings = FALSE expect_lint( "blah <- ' \n \n'", list(message = lint_msg, line_number = 1L), trailing_whitespace_linter(allow_empty_lines = TRUE, allow_in_strings = FALSE) ) expect_lint( "blah <- ' \n \n'", list( list(message = lint_msg, line_number = 1L), list(message = lint_msg, line_number = 2L) ), trailing_whitespace_linter(allow_in_strings = FALSE) ) }) lintr/tests/testthat/test-nested_pipe_linter.R0000644000176200001440000000700514752731051021367 0ustar liggesuserstest_that("nested_pipe_linter skips allowed usages", { linter <- nested_pipe_linter() expect_lint("a %>% b() %>% c()", NULL, linter) expect_lint( trim_some(" foo <- function(x) { out <- a %>% b() return(out) } "), NULL, linter ) # pipes fitting on one line can be ignored expect_lint( "bind_rows(a %>% select(b), c %>% select(b))", NULL, linter ) # switch outputs are OK expect_lint("switch(x, a = x %>% foo())", NULL, linter) # final position is an output position expect_lint("switch(x, a = x, x %>% foo())", NULL, linter) # inline switch inputs are not linted expect_lint( trim_some(" switch( x %>% foo(), a = x ) "), NULL, linter ) }) patrick::with_parameters_test_that( "allow_outer_calls defaults are ignored by default", expect_lint( trim_some(sprintf(outer_call, fmt = " %s( x %%>%% foo() ) ")), NULL, nested_pipe_linter() ), .test_name = c("try", "tryCatch", "withCallingHandlers"), outer_call = c("try", "tryCatch", "withCallingHandlers") ) test_that("nested_pipe_linter blocks simple disallowed usages", { linter <- nested_pipe_linter() linter_inline <- nested_pipe_linter(allow_inline = FALSE) lint_msg <- rex::rex("Don't nest pipes inside other calls.") expect_lint( "bind_rows(a %>% select(b), c %>% select(b))", list(lint_msg, lint_msg), linter_inline ) expect_lint( trim_some(" print( a %>% filter(b > c) ) "), lint_msg, linter ) # switch inputs are linted expect_lint( trim_some(" switch( x %>% foo(), a = x ) "), lint_msg, linter ) expect_lint( trim_some(" switch( x %>% foo(), a = x ) "), lint_msg, linter_inline ) }) test_that("allow_outer_calls= argument works", { expect_lint( trim_some(" try( x %>% foo() ) "), rex::rex("Don't nest pipes inside other calls."), nested_pipe_linter(allow_outer_calls = character()) ) expect_lint( trim_some(" print( x %>% foo() ) "), NULL, nested_pipe_linter(allow_outer_calls = "print") ) }) test_that("Native pipes are handled as well", { skip_if_not_r_version("4.1.0") linter <- nested_pipe_linter() linter_inline <- nested_pipe_linter(allow_inline = FALSE) lint_msg <- rex::rex("Don't nest pipes inside other calls.") expect_lint( "bind_rows(a |> select(b), c |> select(b))", NULL, linter ) expect_lint( "bind_rows(a |> select(b), c |> select(b))", list(lint_msg, lint_msg), linter_inline ) expect_lint( trim_some(" print( a |> filter(b > c) ) "), lint_msg, linter ) }) test_that("lints vectorize", { lint_msg <- rex::rex("Don't nest pipes inside other calls.") lines <- trim_some("{ bind_rows( a %>% select(b), c %>% select(d), e %>% select(f) %>% filter(g > 0), h %>% filter(i < 0) ) }") expect_lint( lines, list( list(lint_msg, line_number = 4L), list(lint_msg, line_number = 6L) ), nested_pipe_linter() ) expect_lint( lines, list( list(lint_msg, line_number = 3L), list(lint_msg, line_number = 4L), list(lint_msg, line_number = 6L), list(lint_msg, line_number = 9L) ), nested_pipe_linter(allow_inline = FALSE) ) }) lintr/tests/testthat/test-consecutive_assertion_linter.R0000644000176200001440000000554114752731051023511 0ustar liggesuserstest_that("consecutive_assertion_linter skips allowed usages", { linter <- consecutive_assertion_linter() expect_lint("stopifnot(x)", NULL, linter) expect_lint("stopifnot(x, y, z)", NULL, linter) # intervening expression expect_lint("stopifnot(x); y; stopifnot(z)", NULL, linter) # inline or potentially with gaps don't matter expect_lint( trim_some(" stopifnot(x) y stopifnot(z) "), NULL, linter ) }) test_that("consecutive_assertion_linter blocks simple disallowed usages", { linter <- consecutive_assertion_linter() lint_msg <- rex::rex("Unify consecutive calls to stopifnot().") # one test of inline usage expect_lint( "stopifnot(x); stopifnot(y)", lint_msg, linter ) expect_lint( trim_some(" stopifnot(x) stopifnot(y, z) "), lint_msg, linter ) expect_lint( trim_some(" stopifnot(x) stopifnot(y) "), lint_msg, linter ) expect_lint( trim_some(" stopifnot(x) # a comment on y stopifnot(y) "), lint_msg, linter ) }) test_that("assert_that usages are handled correctly too", { linter <- consecutive_assertion_linter() lint_msg <- rex::rex("Unify consecutive calls to assert_that().") expect_lint("assert_that(x)", NULL, linter) expect_lint("assertthat::assert_that(x, y, z)", NULL, linter) # if msg= is used, can't necessarily combine lines <- trim_some(" assert_that(x, msg = 'bad x') assert_that(y, msg = 'bad y') ") expect_lint(lines, NULL, linter) # one test of inline usage expect_lint( "assert_that(x); assert_that(y)", lint_msg, linter ) lines_gap <- trim_some(" assert_that(x) assertthat::assert_that(y, z) ") expect_lint(lines_gap, lint_msg, linter) }) test_that("Mixing test functions is fine", { expect_lint( trim_some(" assert_that(x) stopifnot(y) "), NULL, consecutive_assertion_linter() ) }) test_that("lints vectorize", { expect_lint( trim_some("{ stopifnot(A) stopifnot(B) assert_that(C) assert_that(D) }"), list( list("stopifnot", line_number = 2L), list("assert_that", line_number = 4L) ), consecutive_assertion_linter() ) }) test_that("old name consecutive_stopifnot_linter() is deprecated", { expect_warning( { old_linter <- consecutive_stopifnot_linter() }, "Use consecutive_assertion_linter instead", fixed = TRUE ) expect_lint("stopifnot(x); y; stopifnot(z)", NULL, old_linter) expect_lint("stopifnot(x); stopifnot(y)", "Unify consecutive calls", old_linter) }) test_that("interceding = assignments aren't linted", { expect_lint( trim_some("{ stopifnot(A) x = 1 stopifnot(B) assert_that(C) z = 3 assert_that(D) }"), NULL, consecutive_assertion_linter() ) }) lintr/tests/testthat/test-lint.R0000644000176200001440000001531614752731051016465 0ustar liggesusers# The lints for a given file should be the same regardless of the working # directory test_that("lint() results do not depend on the working directory", { # Helper function: run assignment_linter on a given file lint_assignments <- function(filename) { lint(filename, linters = list(assignment_linter())) } # a dummy package for use in the test pkg_path <- test_path("dummy_packages", "assignmentLinter") # put a .lintr in the package root that excludes the first line of `R/jkl.R` local_config(pkg_path, "exclusions: list('R/jkl.R' = 1)") # linting the `R/jkl.R` should identify the following assignment lint on the # second line of the file expected_lines <- "mno = 789" # lint the file from: # - outside the package # - at the package root # - in the package's R/ directory lints_from_outside <- lint_assignments( file.path(pkg_path, "R", "jkl.R") ) lints_from_pkg_root <- withr::with_dir( pkg_path, lint_assignments(file.path("R", "jkl.R")) ) lints_from_a_subdir <- withr::with_dir( file.path(pkg_path, "R"), lint_assignments("jkl.R") ) expect_identical( as.data.frame(lints_from_pkg_root)[["line"]], expected_lines ) expect_identical( as.data.frame(lints_from_outside), as.data.frame(lints_from_pkg_root) ) expect_identical( as.data.frame(lints_from_a_subdir), as.data.frame(lints_from_pkg_root) ) }) # The lints for a given file should be the same regardless of where the .lintr # file is positioned (file-exclusions in the .lintr should be relative to the # directory containing the .lintr) test_that("lint() results do not depend on the position of the .lintr", { # .lintr config files for lint(filepath) are looked for in: # - the same directory as filepath # - the project directory # - the user's home directory lint_with_config <- function(config_dir, config_string, filename) { local_config(config_dir, config_string) lint(filename, linters = assignment_linter()) } # a dummy package for use in the test pkg_path <- test_path("dummy_packages", "assignmentLinter") # we lint the file /R/jkl.R using the pkg-root as working directory # and # - 1) a .lintr config in the package root, # - 2) a .lintr config in the source directory R/ # The second line of jkl.R contains the following assignment lint: expected_lines <- "mno = 789" lints_with_config_at_pkg_root <- withr::with_dir( pkg_path, lint_with_config( config_dir = ".", config_string = "exclusions: list('R/jkl.R' = 1)", filename = file.path("R", "jkl.R") ) ) lints_with_config_in_r_dir <- withr::with_dir( pkg_path, lint_with_config( config_dir = "R", config_string = "exclusions: list('jkl.R' = 1)", filename = file.path("R", "jkl.R") ) ) expect_identical( as.data.frame(lints_with_config_at_pkg_root)[["line"]], expected_lines ) expect_identical( as.data.frame(lints_with_config_at_pkg_root), as.data.frame(lints_with_config_in_r_dir), info = paste( "lints for a source file should be independent of whether the .lintr", "file is in the project-root or the source-file-directory" ) ) }) test_that("lint uses linter names", { expect_lint( "a = 2", list(linter = "bla"), linters = list(bla = assignment_linter()), parse_settings = FALSE ) }) test_that("lint() results from file or text should be consistent", { linters <- list(assignment_linter(), infix_spaces_linter()) lines <- c("x<-1", "x+1") file <- withr::local_tempfile(lines = lines) text <- paste(lines, collapse = "\n") file <- normalize_path(file) lint_from_file <- lint(file, linters = linters) lint_from_lines <- lint(linters = linters, text = lines) lint_from_text <- lint(linters = linters, text = text) # Remove file before linting to ensure that lint works and do not # assume that file exists when both filename and text are supplied. expect_identical(unlink(file), 0L) lint_from_text2 <- lint(file, linters = linters, text = text) expect_length(lint_from_file, 2L) expect_length(lint_from_lines, 2L) expect_length(lint_from_text, 2L) expect_length(lint_from_text2, 2L) expect_identical(lint_from_file, lint_from_text2) for (i in seq_along(lint_from_lines)) { lint_from_file[[i]]$filename <- "" lint_from_lines[[i]]$filename <- "" lint_from_text[[i]]$filename <- "" } expect_identical(lint_from_file, lint_from_lines) expect_identical(lint_from_file, lint_from_text) }) test_that("exclusions work with custom linter names", { expect_lint( "a = 2 # nolint: bla.", NULL, linters = list(bla = assignment_linter()), parse_settings = FALSE ) }) test_that("old compatibility usage errors", { expect_error( expect_lint( "a == NA", "Use is.na", linters = equals_na_linter ), regexp = "Passing linters as variables", fixed = TRUE ) expect_error( expect_lint( "a = 42", "Use <-", linters = assignment_linter ), regexp = "Passing linters as variables", fixed = TRUE ) # Also within `linters_with_defaults()` (#1725) expect_error( expect_lint( "a = 42", "Use <-", linters = linters_with_defaults(assignment_linter) ), regexp = "Passing linters as variables", fixed = TRUE ) expect_error( expect_lint( "a == NA", "Use is.na", linters = unclass(equals_na_linter()) ), regexp = "The use of linters of class 'function'", fixed = TRUE ) # Trigger compatibility in auto_names() expect_error( expect_lint( "a == NA", "Use is.na", linters = list(unclass(equals_na_linter())) ), "The use of linters of class 'function'", fixed = TRUE ) expect_error( lint("a <- 1\n", linters = function(two, arguments) NULL), regexp = "The use of linters of class 'function'", fixed = TRUE ) expect_error( lint("a <- 1\n", linters = "equals_na_linter"), regexp = "Expected `linters()` to be a function of class ", fixed = TRUE ) }) test_that("Linters throwing an error give a helpful error", { tmp_file <- withr::local_tempfile(lines = "a <- 1") lintr_error_msg <- "a broken linter" linter <- function() Linter(function(source_expression) cli_abort(lintr_error_msg)) # NB: Some systems/setups may use e.g. symlinked files when creating under tempfile(); # we don't care much about that, so just check basename() expect_error(lint(tmp_file, linter()), lintr_error_msg, fixed = TRUE) expect_error(lint(tmp_file, list(broken_linter = linter())), lintr_error_msg, fixed = TRUE) }) test_that("typo in argument name gives helpful error", { expect_error(lint("xxx", litners = identity), "Found unknown arguments in `...`: `litners`") }) lintr/tests/testthat/test-is_numeric_linter.R0000644000176200001440000000557414752731051021236 0ustar liggesuserstest_that("is_numeric_linter skips allowed usages involving ||", { linter <- is_numeric_linter() expect_lint("is.numeric(x) || is.integer(y)", NULL, linter) # x is used, but not identically expect_lint("is.numeric(x) || is.integer(foo(x))", NULL, linter) # not totally crazy, e.g. if input accepts a vector or a list expect_lint("is.numeric(x) || is.integer(x[[1]])", NULL, linter) }) test_that("is_numeric_linter skips allowed usages involving %in%", { linter <- is_numeric_linter() # false positives for class(x) %in% c('integer', 'numeric') style expect_lint("class(x) %in% 1:10", NULL, linter) expect_lint("class(x) %in% 'numeric'", NULL, linter) expect_lint("class(x) %in% c('numeric', 'integer', 'factor')", NULL, linter) expect_lint("class(x) %in% c('numeric', 'integer', y)", NULL, linter) }) test_that("is_numeric_linter blocks disallowed usages involving ||", { linter <- is_numeric_linter() lint_msg <- rex::rex("Use `is.numeric(x)` instead of the equivalent `is.numeric(x) || is.integer(x)`.") expect_lint("is.numeric(x) || is.integer(x)", lint_msg, linter) # order doesn't matter expect_lint("is.integer(x) || is.numeric(x)", lint_msg, linter) # identical expressions match too expect_lint("is.integer(DT$x) || is.numeric(DT$x)", lint_msg, linter) # line breaks don't matter lines <- trim_some(" if ( is.integer(x) || is.numeric(x) ) TRUE ") expect_lint(lines, lint_msg, linter) # caught when nesting expect_lint("all(y > 5) && (is.integer(x) || is.numeric(x))", lint_msg, linter) # implicit nesting expect_lint("is.integer(x) || is.numeric(x) || is.logical(x)", lint_msg, linter) }) test_that("is_numeric_linter blocks disallowed usages involving %in%", { linter <- is_numeric_linter() lint_msg <- rex::rex('Use is.numeric(x) instead of class(x) %in% c("integer", "numeric")') expect_lint("class(x) %in% c('integer', 'numeric')", lint_msg, linter) expect_lint('class(x) %in% c("numeric", "integer")', lint_msg, linter) }) test_that("raw strings are handled properly when testing in class", { skip_if_not_r_version("4.0.0") linter <- is_numeric_linter() lint_msg <- rex::rex('Use is.numeric(x) instead of class(x) %in% c("integer", "numeric")') expect_lint("class(x) %in% c(R'(numeric)', 'integer', 'factor')", NULL, linter) expect_lint("class(x) %in% c('numeric', R'--(integer)--', y)", NULL, linter) expect_lint("class(x) %in% c(R'(integer)', 'numeric')", lint_msg, linter) expect_lint('class(x) %in% c("numeric", R"--[integer]--")', lint_msg, linter) }) test_that("lints vectorize", { expect_lint( trim_some("{ is.numeric(x) || is.integer(x) class(x) %in% c('integer', 'numeric') }"), list( list(rex::rex("`is.numeric(x) || is.integer(x)`"), line_number = 2L), list(rex::rex('class(x) %in% c("integer", "numeric")'), line_number = 3L) ), is_numeric_linter() ) }) lintr/tests/testthat/test-expect_s4_class_linter.R0000644000176200001440000000256114752731051022155 0ustar liggesuserstest_that("expect_s4_class_linter skips allowed usages", { linter <- expect_s4_class_linter() # expect_s4_class doesn't have an inverted version expect_lint("expect_true(!is(x, 'class'))", NULL, linter) # NB: also applies to tinytest, but it's sufficient to test testthat expect_lint("testthat::expect_s3_class(!is(x, 'class'))", NULL, linter) # expect_s4_class() doesn't have info= or label= arguments expect_lint("expect_true(is(x, 'SpatialPoly'), info = 'x should be SpatialPoly')", NULL, linter) expect_lint("expect_true(is(x, 'SpatialPoly'), label = 'x inheritance')", NULL, linter) }) test_that("expect_s4_class blocks simple disallowed usages", { linter <- expect_s4_class_linter() lint_msg <- rex::rex("expect_s4_class(x, k) is better than expect_true(is(x, k))") expect_lint("expect_true(is(x, 'data.frame'))", lint_msg, linter) # namespace qualification is irrelevant expect_lint("testthat::expect_true(methods::is(x, 'SpatialPolygonsDataFrame'))", lint_msg, linter) }) test_that("lints vectorize", { lint_msg <- rex::rex("expect_s4_class(x, k) is better than expect_true(is(x, k))") expect_lint( trim_some("{ expect_true(is(x, 'data.frame')) expect_true(is(x, 'SpatialPolygonsDataFrame')) }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), expect_s4_class_linter() ) }) lintr/tests/testthat/test-outer_negation_linter.R0000644000176200001440000000346114752731051022114 0ustar liggesuserstest_that("outer_negation_linter skips allowed usages", { linter <- outer_negation_linter() expect_lint("x <- any(y)", NULL, linter) expect_lint("y <- all(z)", NULL, linter) # extended usage of any is not covered expect_lint("any(!a & b)", NULL, linter) expect_lint("all(a | !b)", NULL, linter) expect_lint("any(a, b)", NULL, linter) expect_lint("all(b, c)", NULL, linter) expect_lint("any(!a, b)", NULL, linter) expect_lint("all(a, !b)", NULL, linter) expect_lint("any(a, !b, na.rm = TRUE)", NULL, linter) # ditto when na.rm is passed quoted expect_lint("any(a, !b, 'na.rm' = TRUE)", NULL, linter) }) test_that("outer_negation_linter blocks simple disallowed usages", { linter <- outer_negation_linter() not_all_msg <- rex::rex("!all(x) is better than any(!x)") not_any_msg <- rex::rex("!any(x) is better than all(!x)") expect_lint("any(!x)", not_all_msg, linter) expect_lint("all(!foo(x))", not_any_msg, linter) # na.rm doesn't change the recommendation expect_lint("any(!x, na.rm = TRUE)", not_all_msg, linter) # also catch nested usage expect_lint("all(!(x + y))", not_any_msg, linter) # catch when all inputs are negated expect_lint("any(!x, !y)", not_all_msg, linter) expect_lint("all(!x, !y, na.rm = TRUE)", not_any_msg, linter) }) test_that("outer_negation_linter doesn't trigger on empty calls", { linter <- outer_negation_linter() # minimal version of issue expect_lint("any()", NULL, linter) # closer to what was is practically relevant, as another regression test expect_lint("x %>% any()", NULL, linter) }) test_that("lints vectorize", { expect_lint( trim_some("{ any(!x) all(!y) }"), list( list(rex::rex("!all(x)"), line_number = 2L), list(rex::rex("!any(x)"), line_number = 3L) ), outer_negation_linter() ) }) lintr/tests/testthat/test-pipe_call_linter.R0000644000176200001440000000374214752731051021024 0ustar liggesuserstest_that("pipe_call_linter skips allowed usages", { linter <- pipe_call_linter() expect_lint("a %>% foo()", NULL, linter) expect_lint("a %>% foo(x)", NULL, linter) expect_lint("b %>% { foo(., ., .) }", NULL, linter) expect_lint("a %>% foo() %>% bar()", NULL, linter) # ensure it works across lines too lines <- trim_some(" a %>% foo() %>% bar() ") expect_lint(lines, NULL, linter) # symbol extraction is OK (don't force extract2(), e.g.) expect_lint("a %>% .$y %>% mean()", NULL, linter) # more complicated expressions don't pick up on nested symbols lines <- trim_some(" x %>% { tmp <- . bla <- foo %>% unrelated_stuff(tmp) my_combination_fun(tmp, bla) } ") expect_lint(lines, NULL, linter) # extraction pipe uses RHS symbols expect_lint("a %$% b", NULL, linter) }) test_that("pipe_call_linter blocks simple disallowed usages", { expect_lint( "x %>% foo", "Use explicit calls in magrittr pipes", pipe_call_linter() ) expect_lint( "x %>% foo() %>% bar", "Use explicit calls in magrittr pipes", pipe_call_linter() ) expect_lint( "x %>% foo %>% bar()", "Use explicit calls in magrittr pipes", pipe_call_linter() ) lines <- trim_some(" a %>% foo %>% bar() ") expect_lint( lines, "Use explicit calls in magrittr pipes", pipe_call_linter() ) }) local({ pipes <- pipes(exclude = c("%$%", "|>")) linter <- pipe_call_linter() patrick::with_parameters_test_that( "All pipe operators are caught", { expect_lint(sprintf("a %s foo()", pipe), NULL, linter) expect_lint(sprintf("a %s foo", pipe), sprintf("`a %s foo`", pipe), linter) }, pipe = pipes, .test_name = names(pipes) ) }) test_that("Multiple lints give custom messages", { expect_lint( trim_some(" a %>% b c %T>% d "), list( list(message = "%>%", line_number = 1L), list(message = "%T>%", line_number = 2L) ), pipe_call_linter() ) }) lintr/tests/testthat/test-which_grepl_linter.R0000644000176200001440000000160214752731051021360 0ustar liggesuserstest_that("which_grepl_linter skips allowed usages", { # this _could_ be combined as p1|p2, but often it's cleaner to read this way expect_lint("which(grepl(p1, x) | grepl(p2, x))", NULL, which_grepl_linter()) }) test_that("which_grepl_linter blocks simple disallowed usages", { linter <- which_grepl_linter() lint_msg <- rex::rex("grep(pattern, x) is better than which(grepl(pattern, x)).") expect_lint("which(grepl('^a', x))", lint_msg, linter) # options also don't matter (grep has more arguments: value, invert) expect_lint("which(grepl('^a', x, perl = TRUE, fixed = TRUE))", lint_msg, linter) expect_lint( trim_some('{ which(x) grepl(y) which(grepl("pt1", x)) which(grepl("pt2", y)) }'), list( list(lint_msg, line_number = 4L, column_number = 3L), list(lint_msg, line_number = 5L, column_number = 3L) ), linter ) }) lintr/tests/testthat/test-spaces_inside_linter.R0000644000176200001440000001204514752731051021701 0ustar liggesuserstest_that("spaces_inside_linter skips allowed usages", { linter <- spaces_inside_linter() expect_lint("blah", NULL, linter) expect_lint("print(blah)", NULL, linter) expect_lint("base::print(blah)", NULL, linter) expect_lint("a[, ]", NULL, linter) expect_lint("a[1]", NULL, linter) expect_lint("fun(\na[1]\n )", NULL, linter) expect_lint("a(, )", NULL, linter) expect_lint("a(,)", NULL, linter) expect_lint("a(1)", NULL, linter) expect_lint('"a( 1 )"', NULL, linter) # trailing comments are OK (#636) expect_lint( trim_some(" or( #code x, y ) "), NULL, linter ) expect_lint( trim_some(" fun( # this is another comment a = 42, # because 42 is always the answer b = Inf ) "), NULL, linter ) }) test_that("spaces_inside_linter blocks diallowed usages", { linter <- spaces_inside_linter() expect_lint( "a[1 ]", list( message = "Do not place spaces before square brackets", line_number = 1L, column_number = 4L, type = "style" ), linter ) expect_lint( "a[[1 ]]", list( message = "Do not place spaces before square brackets", line_number = 1L, column_number = 5L, type = "style" ), linter ) expect_lint( "\n\na[ 1]", list( message = "Do not place spaces after square brackets", line_number = 3L, column_number = 3L, type = "style" ), linter ) expect_lint( "a[ 1 ]", list( list( message = "Do not place spaces after square brackets", line_number = 1L, column_number = 3L, type = "style" ), list( message = "Do not place spaces before square brackets", line_number = 1L, column_number = 5L, type = "style" ) ), linter ) expect_lint( "a(1 )", list( message = "Do not place spaces before parentheses", line_number = 1L, column_number = 4L, type = "style" ), linter ) expect_lint( "a[[ 1]]", list( message = "Do not place spaces after square brackets", line_number = 1L, column_number = 4L, type = "style" ), linter ) expect_lint( "a( 1)", list( message = "Do not place spaces after parentheses", line_number = 1L, column_number = 3L, type = "style" ), linter ) expect_lint( "x[[ 1L ]]", list( list( message = "Do not place spaces after square brackets", line_number = 1L, column_number = 4L, type = "style" ), list( message = "Do not place spaces before square brackets", line_number = 1L, column_number = 7L, type = "style" ) ), linter ) expect_lint( "a( 1 )", list( list( message = "Do not place spaces after parentheses", line_number = 1L, column_number = 3L, type = "style" ), list( message = "Do not place spaces before parentheses", line_number = 1L, column_number = 5L, type = "style" ) ), linter ) # range covers all whitespace expect_lint( "a( blah )", list( list( message = "Do not place spaces after parentheses", line_number = 1L, column_number = 3L, ranges = list(c(3L, 4L)), type = "style" ), list( message = "Do not place spaces before parentheses", line_number = 1L, column_number = 9L, ranges = list(c(9L, 10L)), type = "style" ) ), linter ) }) test_that("multi-line expressions have good markers", { expect_lint( trim_some(" ( x | y ) "), list( list(line_number = 1L, ranges = list(c(2L, 2L)), message = "Do not place spaces after parentheses"), list(line_number = 2L, ranges = list(c(4L, 4L)), message = "Do not place spaces before parentheses") ), spaces_inside_linter() ) }) test_that("spaces_inside_linter blocks disallowed usages with a pipe", { skip_if_not_r_version("4.1.0") linter <- spaces_inside_linter() expect_lint( "letters[1:3] %>% paste0( )", list( list( message = "Do not place spaces after parentheses", line_number = 1L, column_number = 25L, type = "style" ), list( message = "Do not place spaces before parentheses", line_number = 1L, column_number = 25L, type = "style" ) ), linter ) expect_lint( "letters[1:3] |> paste0( )", list( list( message = "Do not place spaces after parentheses", line_number = 1L, column_number = 24L, type = "style" ), list( message = "Do not place spaces before parentheses", line_number = 1L, column_number = 24L, type = "style" ) ), linter ) }) test_that("terminal missing keyword arguments are OK", { expect_lint("alist(missing_arg = )", NULL, spaces_inside_linter()) }) lintr/tests/testthat/test-brace_linter.R0000644000176200001440000002603714752731051020152 0ustar liggesuserstest_that("brace_linter lints braces correctly", { open_curly_msg <- rex::rex( "Opening curly braces should never go on their own line" ) closed_curly_msg <- rex::rex( "Closing curly-braces should always be on their own line, ", "unless they are followed by an else." ) linter <- brace_linter() expect_lint("blah", NULL, linter) expect_lint("a <- function() {\n}", NULL, linter) expect_lint("a <- function() { \n}", NULL, linter) expect_lint("a <- function() { 1 }", list(open_curly_msg, closed_curly_msg), linter) # allowed by allow_single_line expect_lint("a <- function() { 1 }", NULL, brace_linter(allow_single_line = TRUE)) expect_lint( trim_some(" a <- if(1) { 1} else { 2 } "), closed_curly_msg, linter ) expect_lint( trim_some(" a <- if(1) { 1 } else { 2} "), closed_curly_msg, linter ) expect_lint( trim_some(" a <- if(1) { 1} else { 2} "), list( closed_curly_msg, closed_curly_msg ), linter ) # }) is allowed expect_lint("eval(bquote({\n...\n}))", NULL, linter) # }] is too expect_lint("df[, {\n...\n}]", NULL, linter) # }, is allowed expect_lint( trim_some(" fun({ statements }, param)"), NULL, linter ) expect_lint( trim_some(" fun(function(a) { statements }, param)"), NULL, linter ) # ,<\n>{ is allowed expect_lint( trim_some(" switch( x, 'a' = do_something(x), 'b' = do_another(x), { do_first(x) do_second(x) } ) "), NULL, linter ) # a comment before ,<\n>{ is allowed expect_lint( trim_some(" switch( x, 'a' = do_something(x), 'b' = do_another(x), # comment { do_first(x) do_second(x) } ) "), NULL, linter ) # a comment before <\n>{ is allowed expect_lint( trim_some(" switch(stat, o = { x <- 0.01 }, # else { x <- 2 } ) "), NULL, linter ) expect_lint( trim_some(" fun( 'This is very very very long text.', { message('This is the code.') message('It\\'s stupid, but proves my point.') } ) "), NULL, linter ) # (\n{ is allowed optionally expect_lint( trim_some(" tryCatch( { print(1) }, error = function(err) { } ) "), NULL, linter ) # {{ }} is allowed expect_lint("{{ x }}", NULL, linter) expect_lint( trim_some(" pkg_name <- function(path = find_package()) { if (is.null(path)) { return(NULL) } else { read.dcf(file.path(path, \"DESCRIPTION\"), fields = \"Package\")[1] } } "), NULL, linter ) expect_lint( "a <- function() # comment { 1 }", open_curly_msg, linter ) expect_lint("a <- function()\n{\n 1 \n}", open_curly_msg, linter) expect_lint("a <- function()\n {\n 1 \n}", open_curly_msg, linter) expect_lint("a <- function()\n\t{\n 1 \n}", open_curly_msg, linter) # trailing comments are allowed expect_lint( trim_some(' if ("P" != "NP") { # what most people expect print("Cryptomania is possible") } '), NULL, linter ) }) test_that("brace_linter lints spaces before open braces", { linter <- brace_linter() lint_msg <- rex::rex("There should be a space before an opening curly brace.") expect_lint( "blah <- function(){\n}", list( message = lint_msg, column_number = 19L ), linter ) expect_lint( "\nblah <- function(){\n\n\n}", list( message = lint_msg, column_number = 19L ), linter ) # should also lint if/else expect_lint( "a <- if (a){\n} else{\n}", list( list(message = lint_msg, line_number = 1L, column_number = 12L), list(message = lint_msg, line_number = 2L, column_number = 7L) ), linter ) # should lint repeat{ expect_lint( "repeat{\nblah\n}", list(message = lint_msg, line_number = 1L, column_number = 7L), linter ) # should ignore strings and comments, as in regexes: expect_lint("grepl('(iss){2}', 'Mississippi')", NULL, linter) expect_lint( "x <- 123 # don't flag (paren){brace} if inside a comment", NULL, linter ) # should not be thrown when the brace lies on subsequent line expect_lint( trim_some(" x <- function() {2} "), list( rex::rex("Opening curly braces should never go on their own line"), rex::rex("Closing curly-braces should always be on their own line") ), # , but not lint_msg linter ) }) test_that("brace_linter lints else correctly", { linter <- brace_linter() expect_lint("if (TRUE) 1 else 2", NULL, linter) expect_lint("if (TRUE) 1", NULL, linter) lines_brace <- trim_some(" if (TRUE) { 1 } else { 2 } ") expect_lint(lines_brace, NULL, linter) # such usage is also not allowed by the style guide, but test anyway lines_unbrace <- trim_some(" foo <- function(x) { if (TRUE) 1 else 2 } ") expect_lint(lines_unbrace, NULL, linter) lines <- trim_some(" foo <- function(x) { if (x) { 1 } else { 2 } } ") expect_lint( lines, rex::rex("`else` should come on the same line as the previous `}`."), linter ) }) test_that("brace_linter lints function expressions correctly", { linter <- brace_linter() expect_lint("function(x) 4", NULL, linter) lines <- trim_some(" function(x) { x + 4 } ") expect_lint(lines, NULL, linter) lines <- trim_some(" function(x) x+4 ") expect_lint( lines, rex::rex("Use curly braces for any function spanning multiple lines."), linter ) }) test_that("brace_linter lints if/else matching braces correctly", { linter <- brace_linter() expect_lint("if (TRUE) 1 else 2", NULL, linter) expect_lint("if (TRUE) 1", NULL, linter) lines_brace <- trim_some(" if (TRUE) { 1 } else { 2 } ") expect_lint(lines_brace, NULL, linter) # such usage is also not allowed by the style guide, but test anyway lines_unbrace <- trim_some(" foo <- function(x) { if (TRUE) 1 else 2 } ") expect_lint(lines_unbrace, NULL, linter) # else if is OK lines_else_if <- trim_some(" if (x) { 1 } else if (y) { 2 } else { 3 } ") expect_lint(lines_else_if, NULL, linter) lines_if <- trim_some(" foo <- function(x) { if (x) { 1 } else 2 } ") expect_lint( lines_if, rex::rex("Either both or neither branch in `if`/`else` should use curly braces."), linter ) lines_else <- trim_some(" foo <- function(x) { if (x) 1 else { 2 } } ") expect_lint( lines_else, rex::rex("Either both or neither branch in `if`/`else` should use curly braces."), linter ) }) # Keep up to date with https://github.com/tidyverse/style/issues/191 test_that("empty brace expressions are always allowed inline", { expect_lint("while (FALSE) {}", NULL, brace_linter()) expect_lint("while (FALSE) { }", NULL, brace_linter()) # only applies when `{` is "attached" to the preceding token on the same line expect_lint("while (FALSE)\n{}", rex::rex("Opening curly braces"), brace_linter()) expect_lint("while (FALSE)\n{ }", rex::rex("Opening curly braces"), brace_linter()) expect_lint("while (FALSE) {}", NULL, brace_linter(allow_single_line = TRUE)) expect_lint("while (FALSE) { }", NULL, brace_linter(allow_single_line = TRUE)) }) test_that("formula syntax is linted properly", { linter <- brace_linter() lint_msg_open <- rex::rex("Opening curly braces should never go on their own line") lint_msg_closed <- rex::rex("Closing curly-braces should always be on their own line") expect_lint( trim_some(" map( .x = 1:4, .f = ~ { .x + 1 } )"), NULL, linter ) expect_lint( trim_some(" map( .x = 1:4, .f = ~ {.x + 1} )"), list( list(message = lint_msg_open, line_number = 3L, column_number = 10L), list(message = lint_msg_closed, line_number = 3L, column_number = 17L) ), linter ) expect_lint( trim_some(" map( .x = 1:4, .f = ~ { .x + 1 } )"), list( list(message = lint_msg_open, line_number = 3L, column_number = 10L) ), linter ) expect_lint( trim_some(" map( .x = 1:4, .f = ~ { .x + 1} )"), list( list(message = lint_msg_closed, line_number = 4L, column_number = 17L) ), linter ) }) test_that("code with pipes is handled correctly", { linter <- brace_linter() lint_msg_open <- rex::rex("Opening curly braces should never go on their own line") lint_msg_closed <- rex::rex("Closing curly-braces should always be on their own line") expect_lint( trim_some(" out <- lapply(stuff, function(i) { do_something(i) }) %>% unlist "), NULL, linter ) expect_lint( trim_some(" 1:4 %!>% { sum(.) } "), NULL, linter ) # %>%\n{ is allowed expect_lint( trim_some(" 1:4 %T>% { sum(.) } "), NULL, linter ) expect_lint( trim_some(" xx %<>% { sum(.) } "), list( list(message = lint_msg_open, line_number = 1L, column_number = 9L) ), linter ) expect_lint( trim_some(" x %>% { uvwxyz } "), list( list(message = lint_msg_closed, line_number = 3L, column_number = 12L) ), linter ) expect_lint( trim_some(" 1:4 %>% { sum(.) } "), list( list(message = lint_msg_closed, line_number = 2L, column_number = 12L) ), linter ) expect_lint( "1:4 %>% { sum(.) }", list( list(message = lint_msg_open, line_number = 1L, column_number = 9L), list(message = lint_msg_closed, line_number = 1L, column_number = 18L) ), linter ) skip_if_not_r_version("4.1.0") expect_lint( trim_some(" out <- lapply(stuff, function(i) { do_something(i) }) |> unlist() "), NULL, linter ) expect_lint( "local({ 1:4 |> sum() })", list( list(message = lint_msg_open, line_number = 1L, column_number = 7L) ), linter ) }) test_that("function shorthand is treated like 'full' function", { skip_if_not_r_version("4.1.0") linter <- brace_linter() expect_lint("a <- \\() { \n}", NULL, linter) expect_lint( trim_some(" x <- \\() {2} "), list( rex::rex("Opening curly braces should never go on their own line"), rex::rex("Closing curly-braces should always be on their own line") ), linter ) }) lintr/tests/testthat/test-package_hooks_linter.R0000644000176200001440000002036614752731051021673 0ustar liggesuserstest_that("package_hooks_linter skips allowed usages of packageStartupMessage() & library.dynam()", { linter <- package_hooks_linter() # allowed in .onAttach, not .onLoad expect_lint(".onAttach <- function(lib, pkg) packageStartupMessage('hi')", NULL, linter) # allowed in .onLoad, not .onAttach expect_lint(".onLoad <- function(lib, pkg) library.dynam()", NULL, linter) }) test_that("package_hooks_linter blocks simple disallowed usages of packageStartupMessage() & library.dynam()", { linter <- package_hooks_linter() # inline version expect_lint( ".onLoad <- function(lib, pkg) packageStartupMessage('hi')", rex::rex("Put packageStartupMessage() calls in .onAttach()"), linter ) # multiline version expect_lint( trim_some(" .onAttach <- function(libname, pkgname) { library.dynam() } "), rex::rex("Put library.dynam() calls in .onLoad, not .onAttach()."), linter ) # found at deeper nesting too expect_lint( trim_some(" .onLoad <- function(libname, pkgname) { foo(bar(baz(packageStartupMessage('hi')))) } "), rex::rex("Put packageStartupMessage() calls in .onAttach()"), linter ) }) test_that("package_hooks_linter blocks simple disallowed usages of other blocked messaging functions", { linter <- package_hooks_linter() # inline version expect_lint( ".onLoad <- function(lib, pkg) cat('hi')", rex::rex("Don't use cat() in .onLoad()"), linter ) # multiline version expect_lint( trim_some(" .onAttach <- function(libname, pkgname) { writeLines('hi') } "), rex::rex("Don't use writeLines() in .onAttach()"), linter ) expect_lint( trim_some(" .onLoad <- function(libname, pkgname) { print('hi') } "), rex::rex("Don't use print() in .onLoad()"), linter ) # found at deeper nesting too expect_lint( trim_some(" .onAttach <- function(libname, pkgname) { foo(bar(baz(message('hi')))) } "), rex::rex("Don't use message() in .onAttach()"), linter ) }) test_that("package_hooks_linter skips valid .onLoad() and .onAttach() arguments", { linter <- package_hooks_linter() expect_lint(".onAttach <- function(lib, pkg) { }", NULL, linter) expect_lint(".onLoad <- function(lib, pkg) { }", NULL, linter) # args only need to start with those characters expect_lint(".onAttach <- function(libname, pkgpath) { }", NULL, linter) expect_lint(".onLoad <- function(libXXXX, pkgYYYY) { }", NULL, linter) }) test_that("package_hooks_linter blocks invalid .onLoad() / .onAttach() arguments", { linter <- package_hooks_linter() onload_msg <- rex::rex(".onLoad() should take two arguments") expect_lint( ".onAttach <- function(xxx, pkg) { }", rex::rex(".onAttach() should take two arguments"), linter ) expect_lint(".onLoad <- function(lib, yyy) { }", onload_msg, linter) # only one lint if both are wrong expect_lint(".onLoad <- function(xxx, yyy) { }", onload_msg, linter) # exactly two arguments required. # NB: QC.R allows ... arguments to be passed, but disallow this flexibility in the linter. expect_lint(".onLoad <- function() { }", onload_msg, linter) expect_lint(".onLoad <- function(lib) { }", onload_msg, linter) expect_lint(".onLoad <- function(lib, pkg, third) { }", onload_msg, linter) expect_lint(".onLoad <- function(lib, ...) { }", onload_msg, linter) }) test_that("package_hooks_linter skips valid namespace loading", { linter <- package_hooks_linter() expect_lint(".onAttach <- function(lib, pkg) { requireNamespace('foo') }", NULL, linter) expect_lint(".onLoad <- function(lib, pkg) { requireNamespace('foo') }", NULL, linter) }) test_that("package_hooks_linter blocks attaching namespaces", { linter <- package_hooks_linter() expect_lint( ".onAttach <- function(lib, pkg) { require(foo) }", rex::rex("Don't alter the search() path in .onAttach() by calling require()."), linter ) expect_lint( ".onLoad <- function(lib, pkg) { library(foo) }", rex::rex("Don't alter the search() path in .onLoad() by calling library()."), linter ) expect_lint( ".onLoad <- function(lib, pkg) { installed.packages() }", rex::rex("Don't slow down package load by running installed.packages() in .onLoad()."), linter ) # find at further nesting too expect_lint( ".onAttach <- function(lib, pkg) { a(b(c(require(foo)))) }", rex::rex("Don't alter the search() path in .onAttach() by calling require()."), linter ) expect_lint( ".onLoad <- function(lib, pkg) { d(e(f(library(foo)))) }", rex::rex("Don't alter the search() path in .onLoad() by calling library()."), linter ) expect_lint( ".onLoad <- function(lib, pkg) { g(h(i(installed.packages()))) }", rex::rex("Don't slow down package load by running installed.packages() in .onLoad()."), linter ) # also find when used as names expect_lint( ".onAttach <- function(lib, pkg) { sapply(c('a', 'b', 'c'), require, character.only = TRUE) }", rex::rex("Don't alter the search() path in .onAttach() by calling require()."), linter ) expect_lint( ".onAttach <- function(lib, pkg) { lapply(c('a', 'b', 'c'), library, character.only = TRUE) }", rex::rex("Don't alter the search() path in .onAttach() by calling library()"), linter ) }) test_that("package_hooks_linter skips valid .onDetach() and .Last.lib()", { linter <- package_hooks_linter() expect_lint(".onDetach <- function(lib) { }", NULL, linter) expect_lint(".onDetach <- function(libname) { }", NULL, linter) expect_lint(".Last.lib <- function(lib) { }", NULL, linter) expect_lint(".Last.lib <- function(libname) { }", NULL, linter) }) test_that("package_hooks_linter catches usage of library.dynam.unload()", { linter <- package_hooks_linter() expect_lint( ".onDetach <- function(lib) { library.dynam.unload() }", rex::rex("Use library.dynam.unload() calls in .onUnload(), not .onDetach()."), linter ) expect_lint( ".Last.lib <- function(lib) { library.dynam.unload() }", rex::rex("Use library.dynam.unload() calls in .onUnload(), not .Last.lib()."), linter ) # expected usage is in .onUnload expect_lint( ".onUnload <- function(lib) { library.dynam.unload() }", NULL, linter ) }) test_that("package_hooks_linter detects bad argument names in .onDetach()/.Last.lib()", { linter <- package_hooks_linter() lint_msg_part <- " should take one argument starting with 'lib'" expect_lint( ".onDetach <- function(xxx) { }", rex::rex(".onDetach()", lint_msg_part), linter ) expect_lint( ".Last.lib <- function(yyy) { }", rex::rex(".Last.lib()", lint_msg_part), linter ) # exactly one argument required. # NB: QC.R allows ... arguments to be passed, but disallow this flexibility in the linter. expect_lint( ".onDetach <- function() { }", rex::rex(".onDetach()", lint_msg_part), linter ) expect_lint( ".Last.lib <- function(lib, pkg) { }", rex::rex(".Last.lib()", lint_msg_part), linter ) expect_lint( ".onDetach <- function(...) { }", rex::rex(".onDetach()", lint_msg_part), linter ) }) test_that("function shorthand is handled", { skip_if_not_r_version("4.1.0") linter <- package_hooks_linter() expect_lint( ".onLoad <- \\(lib, pkg) packageStartupMessage('hi')", rex::rex("Put packageStartupMessage() calls in .onAttach()"), linter ) expect_lint( ".onAttach <- \\(xxx, pkg) { }", rex::rex(".onAttach() should take two arguments"), linter ) expect_lint( ".onAttach <- \\(lib, pkg) { require(foo) }", rex::rex("Don't alter the search() path in .onAttach() by calling require()."), linter ) expect_lint( ".onDetach <- \\(lib) { library.dynam.unload() }", rex::rex("Use library.dynam.unload() calls in .onUnload(), not .onDetach()."), linter ) expect_lint( ".onDetach <- \\(xxx) { }", rex::rex(".onDetach() should take one argument starting with 'lib'."), linter ) }) test_that("lints vectorize", { expect_lint( trim_some("{ .onLoad <- function(xxx, yyy) { } .onAttach <- function(aaa, bbb) { } }"), list( list(".onLoad", line_number = 2L), list(".onAttach", line_number = 3L) ), package_hooks_linter() ) }) lintr/tests/testthat/test-rep_len_linter.R0000644000176200001440000000356214752731051020520 0ustar liggesuserstest_that("rep_len_linter skips allowed usages", { linter <- rep_len_linter() # only catch length.out usages expect_lint("rep(x, y)", NULL, linter) expect_lint("rep(1:10, 2)", NULL, linter) expect_lint("rep(1:10, 10:1)", NULL, linter) # usage of each is not compatible with rep_len; see ?rep. expect_lint("rep(x, each = 4, length.out = 50)", NULL, linter) # each is implicitly the 4th positional argument. a very strange usage # (because length.out is ignored), but doesn't hurt to catch it expect_lint("rep(a, b, length.out = c, d)", NULL, linter) # ditto for implicit length.out= expect_lint("rep(a, b, c, d)", NULL, linter) }) test_that("rep_len_linter blocks simple disallowed usages", { linter <- rep_len_linter() lint_msg <- rex::rex("Use rep_len(x, n) instead of rep(x, length.out = n).") # only catch length.out usages expect_lint("rep(x, length.out = 4L)", lint_msg, linter) # implicit times= argument; length.out has priority over times= (see ?rep), # so we still lint since it's as if times= is not supplied. # (notice here that the base behavior is odd -- one might expect output like # head(rep(1:10, 10:1), 50), but instead we get rep(1:10, length.out = 50)) expect_lint("rep(1:10, 10:1, length.out = 50)", lint_msg, linter) # ditto for explicit times= argument expect_lint("rep(1:10, times = 10:1, length.out = 50)", lint_msg, linter) # implicit usage in third argument expect_lint("rep(1:10, 10:1, 50)", lint_msg, linter) }) test_that("vectorized lints work", { lint_msg <- rex::rex("Use rep_len(x, n) instead of rep(x, length.out = n).") expect_lint( trim_some("{ rep(x, y) rep(1:10, length.out = 50) rep(x, each = 4, length.out = 50) rep(x, length.out = 50) }"), list( list(lint_msg, line_number = 3L), list(lint_msg, line_number = 5L) ), rep_len_linter() ) }) lintr/tests/testthat/test-nrow_subset_linter.R0000644000176200001440000000273214752731051021444 0ustar liggesuserstest_that("nrow_subset_linter skips allowed usage", { linter <- nrow_subset_linter() expect_lint("nrow(foo(subset(x, y == z)))", NULL, linter) expect_lint("with(x, sum(y == z))", NULL, linter) }) test_that("nrow_subset_linter blocks subset() cases", { expect_lint( "nrow(subset(x, y == z))", rex::rex("Use arithmetic to count the number of rows satisfying a condition"), nrow_subset_linter() ) }) test_that("nrow_subset_linter blocks filter() cases", { expect_lint( "nrow(filter(x, y == z))", rex::rex("Use arithmetic to count the number of rows satisfying a condition"), nrow_subset_linter() ) }) test_that("lints vectorize", { lint_msg <- rex::rex("Use arithmetic to count the number of rows satisfying a condition") expect_lint( trim_some("{ nrow(subset(x, y == z)) subset(x) %>% transform(m = 2) nrow(subset(a, b == c)) x %>% filter(y == z) %>% nrow() }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 4L), list(lint_msg, line_number = 5L) ), nrow_subset_linter() ) }) test_that("linter is pipeline-aware", { linter <- nrow_subset_linter() lint_msg <- "Use arithmetic to count the number of rows satisfying a condition" expect_lint("x %>% subset(y == z) %>% nrow()", lint_msg, linter) expect_lint("filter(x, y == z) %>% nrow()", lint_msg, linter) skip_if_not_r_version("4.1.0") expect_lint("x |> subset(y == z) |> nrow()", lint_msg, linter) }) lintr/tests/testthat/test-nonportable_path_linter.R0000644000176200001440000000372214752731051022431 0ustar liggesuserstest_that("nonportable_path_linter skips allowed usages", { linter <- nonportable_path_linter(lax = FALSE) # various strings non_path_strings <- c( "foo", "https://cran.r-project.org/web/packages/lintr/", encodeString("hello\nthere!") ) for (path in non_path_strings) { expect_lint(single_quote(path), NULL, linter) expect_lint(double_quote(path), NULL, linter) } expect_lint("\"'/foo'\"", NULL, linter) # nested quotes # system root root_path_strings <- c("/", "~", "c:", ".") for (path in root_path_strings) { expect_lint(single_quote(path), NULL, linter) expect_lint(double_quote(path), NULL, linter) } }) test_that("nonportable_path_linter blocks disallowed usages", { linter <- nonportable_path_linter(lax = FALSE) lint_msg <- rex::escape("Use file.path() to construct portable file paths.") # paths with (back)slashes slash_path_strings <- c( "~/", "c:/", encodeString("D:\\"), "../", "/foo", "foo/", "foo/bar", encodeString("foo\\bar"), "/as:df", encodeString("/a\nsdf") ) for (path in slash_path_strings) { expect_lint(single_quote(path), lint_msg, linter) expect_lint(double_quote(path), lint_msg, linter) } }) test_that("nonportable_path_linter's lax argument works", { # lax mode: no check for strings that are likely not paths (too short or with special characters) linter <- nonportable_path_linter(lax = TRUE) unlikely_path_strings <- c( "/foo", encodeString("/a\nsdf/bar"), "/as:df/bar" ) for (path in unlikely_path_strings) { expect_lint(single_quote(path), NULL, linter) expect_lint(double_quote(path), NULL, linter) } }) test_that("lints vectorize", { lint_msg <- rex::escape("Use file.path() to construct portable file paths.") expect_lint( trim_some("{ '~/' 'C:/' }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), nonportable_path_linter(lax = FALSE) ) }) lintr/tests/testthat/test-Lint-builder.R0000644000176200001440000000201414752731051020040 0ustar liggesuserstest_that("Lint() errors on invalid input", { dummy_line <- "abc" expect_error( Lint("dummy.R", line = dummy_line, column_number = NA_integer_), "`column_number` must be an integer between 0 and 4 (`nchar(line) + 1`)", fixed = TRUE ) expect_error( Lint("dummy.R", line = dummy_line, line_number = 0L), "`line_number` must be a positive integer", fixed = TRUE ) expect_error( Lint("dummy.R", ranges = c(1L, 3L)), "`ranges` must be `NULL` or a list", fixed = TRUE ) expect_error( Lint("dummy.R", ranges = list(1L)), "`ranges` must only contain integer vectors of length 2 without `NA`s.", fixed = TRUE ) expect_error( Lint("dummy.R", ranges = list(c(1L, NA_integer_))), "`ranges` must only contain integer vectors of length 2 without `NA`s.", fixed = TRUE ) expect_error( Lint("dummy.R", line = dummy_line, ranges = list(c(1L, 2L), c(1L, 5L))), "`ranges` must satisfy 0 <= range[1L] <= range[2L] <= 4 (nchar(line) + 1).", fixed = TRUE ) }) lintr/tests/testthat/test-indentation_linter.R0000644000176200001440000003541614752731051021413 0ustar liggesuserstest_that("indentation linter flags unindented expressions", { linter <- indentation_linter(indent = 2L) expect_lint( trim_some(" lapply(1:10, function(i) { i %% 2 }) "), NULL, linter ) expect_lint( trim_some(" lapply(1:10, function(i) { i %% 2 # indentation is only 1 character }) "), "Indentation", linter ) expect_lint( trim_some(" lapply(1:10, function(i) { # indentation is only 1 character i %% 2 }) "), "Indentation", linter ) # no double-block indents even if the indentation-starting tokens are immediately next to each other expect_lint( trim_some(" local({ # no lint }) local({ # must lint }) "), list(line_number = 6L, message = "Indentation"), linter ) expect_lint( trim_some(" lapply(1:10, function(i) { i %% 2 }) "), NULL, indentation_linter(indent = 4L) ) expect_lint( trim_some(" lapply(1:10, function(i) { i %% 2 # indentation is only 2 characters }) "), "Indentation", indentation_linter(indent = 4L) ) # ugly code, but still correctly indented expect_lint( trim_some(" list( 1, 2) "), NULL, linter ) # comments do not trigger hanging indent rule expect_lint( trim_some(" list( # comment ok ) "), NULL, linter ) # comments do not suppress block indents (#1751) expect_lint( trim_some(" a <- # comment 42L "), NULL, linter ) # assignment triggers indent expect_lint( trim_some(" a <- expr( 42 ) "), NULL, linter ) expect_lint( trim_some(" if (cond) code if (cond) code else code2 if (cond) { code } else code if (cond) { code } else { code } "), NULL, linter ) }) test_that("indentation linter flags improper closing curly braces", { linter <- indentation_linter(indent = 2L) expect_lint( trim_some(" lapply(1:10, function(i) { { i %% 2 } }) "), NULL, linter ) expect_lint( trim_some(" lapply(1:10, function(i) { i %% 2 } # closing curly doesn't return to parent indentation ) "), "Indentation", linter ) }) test_that("function argument indentation works in tidyverse-style", { linter <- indentation_linter() expect_lint( trim_some(" function(a = 1L, b = 2L) { a + b } "), NULL, linter ) # new style (#1754) expect_lint( trim_some(" function( a = 1L, b = 2L) { a + b } "), NULL, linter ) expect_lint( trim_some(" function( a = 1L, b = 2L) { a + b } "), "Indentation should be 4", linter ) # Hanging is only allowed if there is an argument next to "(" expect_lint( trim_some(" function( a = 1L, b = 2L) { a + b } "), "Indentation should be 4", linter ) # Block is only allowed if there is no argument next to ")" expect_lint( trim_some(" function( a = 1L, b = 2L) { a + b } "), "Indentation should be 4", linter ) expect_lint( trim_some(" function( a = 1L, b = 2L ) { a + b } "), NULL, linter ) # anchor is correctly found with assignments as well expect_lint( trim_some(" test <- function(a = 1L, b = 2L) { a + b } "), NULL, linter ) expect_lint( trim_some(" function(a = 1L, b = 2L) { a + b } "), "Hanging", linter ) # This is a case for brace_linter expect_lint( trim_some(" function(a = 1L, b = 2L) { a + b } "), NULL, linter ) }) test_that("function argument indentation works in always-hanging-style", { linter <- indentation_linter(hanging_indent_style = "always") expect_lint( trim_some(" function(a = 1L, b = 2L) { a + b } "), NULL, linter ) expect_lint( trim_some(" function( a = 1L, b = 2L) { a + b } "), "Hanging", linter ) expect_lint( trim_some(" function( a = 1L, b = 2L) { a + b } "), NULL, linter ) # Block is only allowed if there is no argument next to ")" expect_lint( trim_some(" function( a = 1L, b = 2L) { a + b } "), "Hanging", linter ) expect_lint( trim_some(" function( a = 1L, b = 2L ) { a + b } "), NULL, linter ) # anchor is correctly found with assignments as well expect_lint( trim_some(" test <- function(a = 1L, b = 2L) { a + b } "), NULL, linter ) expect_lint( trim_some(" function(a = 1L, b = 2L) { a + b } "), "Hanging", linter ) # This is a case for brace_linter expect_lint( trim_some(" function(a = 1L, b = 2L) { a + b } "), NULL, linter ) }) test_that("indentation with operators works", { linter <- indentation_linter() expect_lint( trim_some(" a %>% b() "), NULL, linter ) expect_lint( trim_some(" (a + b + c) / (d + e + f) / (g + h + i) "), NULL, linter ) expect_lint( trim_some(" a %>% b() "), "Indentation", linter ) expect_lint( trim_some(" a + b() "), "Indentation", linter ) expect_lint( trim_some(" abc$ def$ ghi "), NULL, linter ) }) test_that("indentation with bracket works", { linter <- indentation_linter() expect_lint( trim_some(" dt[ , col := 42L ][ , ok ] bla[hanging, also_ok] "), NULL, linter ) expect_lint( trim_some(" abc[[ 'elem' ]] def[[a, b]] "), NULL, linter ) }) test_that("indentation works with control flow statements", { linter <- indentation_linter() expect_lint( trim_some(" if (TRUE) { do_something } else { do_other_thing } "), NULL, linter ) expect_lint( trim_some(" while (1 > 2) { do_something } "), "Indentation", linter ) expect_lint( trim_some(" if (FALSE) { do_something } else { do_other_thing } "), "Indentation", linter ) }) test_that("indentation lint messages are dynamic", { linter <- indentation_linter() expect_lint( trim_some(" local({ # should be 2 }) "), rex::rex("Indentation should be 2 spaces but is 4 spaces."), linter ) expect_lint( trim_some(" fun( 3) # should be 4 "), rex::rex("Hanging indent should be 4 spaces but is 2 spaces."), linter ) }) test_that("indentation within string constants is ignored", { expect_lint( trim_some(" x <- ' an indented string ' "), NULL, indentation_linter() ) expect_lint( trim_some(" x <- ' an indented string with 3 spaces indentation ' "), NULL, indentation_linter() ) }) test_that("combined hanging and block indent works", { linter <- indentation_linter() expect_lint( trim_some(" func(hang, and, block( combined )) "), NULL, linter ) expect_lint( trim_some(" func(ha, func2(ab, block( indented ))) "), NULL, linter ) expect_lint( trim_some(" func(func2( a = 42 )) "), NULL, linter ) # Adapted from cli R/ansi.R L231-234 expect_lint( trim_some(" stopifnot(is.character(style) && length(style) == 1 || is_rgb_matrix(style) && ncol(style) == 1, is.logical(bg) && length(bg) == 1, is.numeric(colors) && length(colors) == 1) "), NULL, linter ) # Adapted from cli inst/scripts/up.R L26-37 expect_lint( trim_some(" http_head(url, ...)$ then(function(res) { if (res$status_code < 300) { cli_alert_success() } else { cli_alert_danger() } })$ catch(error = function(err) { e <- if (grepl('timed out', err$message)) 'timed out' else 'error' cli_alert_danger() }) "), NULL, linter ) }) test_that("hanging_indent_stlye works", { code_block_multi_line <- "map(x, f,\n extra_arg = 42\n)" code_hanging_multi_line <- "map(x, f,\n extra_arg = 42\n)" code_block_same_line <- "map(x, f,\n extra_arg = 42)" code_hanging_same_line <- "map(x, f,\n extra_arg = 42)" tidy_linter <- indentation_linter() hanging_linter <- indentation_linter(hanging_indent_style = "always") non_hanging_linter <- indentation_linter(hanging_indent_style = "never") expect_lint(code_block_multi_line, NULL, tidy_linter) expect_lint(code_block_multi_line, "Hanging indent", hanging_linter) expect_lint(code_block_multi_line, NULL, non_hanging_linter) expect_lint(code_hanging_multi_line, "Indent", tidy_linter) expect_lint(code_hanging_multi_line, NULL, hanging_linter) expect_lint(code_hanging_multi_line, "Indent", non_hanging_linter) expect_lint(code_block_same_line, "Hanging indent", tidy_linter) expect_lint(code_block_same_line, "Hanging indent", hanging_linter) expect_lint(code_block_same_line, NULL, non_hanging_linter) expect_lint(code_hanging_same_line, NULL, tidy_linter) expect_lint(code_hanging_same_line, NULL, hanging_linter) expect_lint(code_hanging_same_line, "Indent", non_hanging_linter) # regression test for #1898 expect_lint( trim_some(" outer_fun(inner_fun(x, one_indent = 42L )) "), NULL, tidy_linter ) expect_lint( trim_some(" outer_fun(inner_fun(x, # this is first arg one_indent = 42L # this is second arg )) "), NULL, tidy_linter ) expect_lint( trim_some(" outer_fun(inner_fun( x, one_indent = 42L )) "), NULL, tidy_linter ) expect_lint( trim_some(" outer_fun( inner_fun( x, one_indent = 42L ) ) "), NULL, tidy_linter ) }) test_that("assignment_as_infix works", { # test function call restorator and LEFT_ASSIGN suppressor code_infix <- trim_some(" ok_code <- var1 + f( var2 + var3 ) + var4 ") # test that innermost ancestor token decides the indentation code_infix_2 <- trim_some(" lapply(x, function(e) { temp_var <- e + 42 } ) ") # test brace restorator code_infix_3 <- trim_some(" ok_code <- if (condition) { a + b } else { c + d } + e ") # test EQ_ASSIGN, EQ_SUB and EQ_FORMALS suppressors code_infix_4 <- trim_some(" # EQ_ASSIGN ok_code = a + b # EQ_SUB f( a = b + c ) # EQ_FORMALS f <- function( a = b + c ) { NULL } ") code_no_infix <- trim_some(" ok_code <- var1 + f( var2 + var3 ) + var4 ") tidy_linter <- indentation_linter() no_infix_linter <- indentation_linter(assignment_as_infix = FALSE) expect_lint(code_infix, NULL, tidy_linter) expect_lint(code_infix_2, NULL, tidy_linter) expect_lint(code_infix_3, NULL, tidy_linter) expect_lint(code_infix_4, NULL, tidy_linter) expect_lint(code_no_infix, rex::rex("Indentation should be 2 spaces but is 4 spaces."), tidy_linter) expect_lint(code_infix, rex::rex("Indentation should be 4 spaces but is 2 spaces."), no_infix_linter) expect_lint(code_infix_2, rex::rex("Indentation should be 8 spaces but is 6 spaces."), no_infix_linter) expect_lint(code_infix_3, rex::rex("Indentation should be 4 spaces but is 2 spaces."), no_infix_linter) expect_lint(code_infix_4, list( list(line_number = 4L, rex::rex("Indentation should be 4 spaces but is 2 spaces.")), list(line_number = 10L, rex::rex("Indentation should be 6 spaces but is 4 spaces.")), list(line_number = 17L, rex::rex("Indentation should be 6 spaces but is 4 spaces.")) ), no_infix_linter) expect_lint(code_no_infix, NULL, no_infix_linter) }) test_that("consecutive same-level lints are suppressed", { bad_code <- trim_some(" ok_code <- 42 wrong_hanging <- fun(a, b, c, d, e %>% f()) wrong_block <- function() { a + b c + d if (a == 24) boo } wrong_hanging_args <- function(a = 1, b = 2, c = 3, d = 4, e = 5, f = 6) { a + b + c + d + e + f } ") expect_lint( bad_code, list( list(line_number = 4L, message = "Hanging indent"), list(line_number = 8L, message = "Indentation"), list(line_number = 15L, message = "Hanging indent") ), indentation_linter() ) }) test_that("native pipe is supported", { skip_if_not_r_version("4.1.0") linter <- indentation_linter() expect_lint( trim_some(" a |> foo() "), NULL, linter ) expect_lint( trim_some(" b <- a |> foo() "), NULL, linter ) }) test_that("it doesn't error on invalid code", { # Part of #1427 expect_lint("function() {)", list(linter = "error", message = rex::rex("unexpected ')'")), indentation_linter()) }) test_that("function shorthand is handled", { skip_if_not_r_version("4.1.0") linter <- indentation_linter() expect_lint( trim_some(" lapply(1:10, \\(i) { i %% 2 }) "), NULL, linter ) expect_lint( trim_some(" lapply(1:10, \\(i) { i %% 2 # indentation is only 1 character }) "), "Indentation", linter ) expect_lint( trim_some(" \\( a = 1L, b = 2L) { a + b } "), NULL, linter ) }) test_that("lint metadata works for 0-space case", { expect_lint( trim_some(" if (TRUE) { FALSE } "), list(ranges = list(1L:2L)), indentation_linter() ) }) lintr/tests/testthat/test-make_linter_from_xpath.R0000644000176200001440000000254714752731051022242 0ustar liggesuserstest_that("basic usage works", { linter <- make_linter_from_xpath("//NUM_CONST", "Number") expect_type(linter, "closure") expect_lint("1", list("Number", type = "warning"), linter()) expect_lint("'a'", "Letter", make_linter_from_xpath("//STR_CONST", "Letter")()) expect_lint("'a'", "Letter", make_linter_from_xpath("//STR_CONST", "Letter", level = "file")()) expect_lint("'a'", list("Letter", type = "style"), make_linter_from_xpath("//STR_CONST", "Letter", type = "style")()) }) test_that("input validation works", { expect_error( make_linter_from_xpath("//NUM_CONST", "Number", type = "x"), 'one of "warning", "style", "error"', fixed = TRUE ) expect_error( make_linter_from_xpath("//NUM_CONST", "Number", level = "x"), 'one of "expression", "file"', fixed = TRUE ) err_msg <- if (getRversion() < "4.0.0") "is.character(xpath)" else "xpath should be a character string" expect_error(make_linter_from_xpath(FALSE), err_msg, fixed = TRUE) expect_error(make_linter_from_xpath(letters), err_msg, fixed = TRUE) expect_error(make_linter_from_xpath(NA_character_), err_msg, fixed = TRUE) expect_error(make_linter_from_xpath(character()), err_msg, fixed = TRUE) err_msg <- if (getRversion() < "4.0.0") "!missing(lint_message)" else "lint_message is required" expect_error(make_linter_from_xpath(""), err_msg, fixed = TRUE) }) lintr/tests/testthat/test-condition_message_linter.R0000644000176200001440000001146514752731051022567 0ustar liggesuserstest_that("condition_message_linter skips allowed usages", { linter <- condition_message_linter() expect_lint("stop('a string', 'another')", NULL, linter) expect_lint("warning('a string', 'another')", NULL, linter) expect_lint("message('a string', 'another')", NULL, linter) # extracted calls likely don't obey base::stop() semantics expect_lint("ctx$stop(paste('a', 'b'))", NULL, linter) expect_lint("ctx@stop(paste('a', 'b'))", NULL, linter) # sprintf is OK -- gettextf() enforcement is left to other linters expect_lint("stop(sprintf('A %s!', 'string'))", NULL, linter) # get multiple sep= in one expression expect_lint( trim_some(" tryCatch( foo(x), error = function(e) stop(paste(a, b, sep = '-')), warning = function(w) warning(paste(a, b, sep = '--')), ) "), NULL, linter ) }) skip_if_not_installed("tibble") patrick::with_parameters_test_that( "paste/paste0 allowed by condition_message_linter when using other seps and/or collapse", expect_lint( sprintf("%s(%s(x, %s = '%s'))", condition, fun, parameter, arg), NULL, condition_message_linter() ), .cases = tibble::tribble( ~.test_name, ~condition, ~fun, ~parameter, ~arg, "stop, paste and collapse = ''", "stop", "paste", "collapse", "", "warning, paste and collapse = '\n'", "warning", "paste", "collapse", "\n", "message, paste and collapse = '|'", "message", "paste", "collapse", "|", "stop, paste0 and collapse = ''", "stop", "paste0", "collapse", "", "warning, paste0 and collapse = '\n'", "warning", "paste0", "collapse", "\n", "message, paste0 and collapse = '|'", "message", "paste0", "collapse", "|", "stop, paste and sep = '-'", "stop", "paste", "sep", "-", "warning, paste and sep = '\n'", "warning", "paste", "sep", "\n", "message, paste and sep = '|'", "message", "paste", "sep", "|" ) ) test_that("condition_message_linter blocks simple disallowed usages", { expect_lint( "stop(paste('a string', 'another'))", rex::rex("Don't use paste to build stop strings."), condition_message_linter() ) expect_lint( "warning(paste0('a string ', 'another'))", rex::rex("Don't use paste0 to build warning strings."), condition_message_linter() ) # `sep` argument allowed, but only if it is different from default expect_lint( "stop(paste(x, sep = ' '))", rex::rex("Don't use paste to build stop strings."), condition_message_linter() ) # not thrown off by named arguments expect_lint( "stop(paste('a', 'b'), call. = FALSE)", rex::rex("Don't use paste to build stop strings."), condition_message_linter() ) expect_lint( "warning(paste0('a', 'b'), immediate. = TRUE)", rex::rex("Don't use paste0 to build warning strings."), condition_message_linter() ) expect_lint( trim_some(" tryCatch( foo(x), error = function(e) stop(paste(a, b)), warning = function(w) warning(paste(a, b, sep = '--')), ) "), rex::rex("Don't use paste to build stop strings."), condition_message_linter() ) # one with no sep, one with linted sep expect_lint( trim_some(" tryCatch( foo(x), error = function(e) stop(paste(a, b)), warning = function(w) warning(paste(a, b, sep = '')), ) "), list( list(message = rex::rex("Don't use paste to build stop strings."), line_number = 3L), list(message = rex::rex("Don't use paste to build warning strings"), line_number = 4L) ), condition_message_linter() ) }) test_that("packageStartupMessage usages are also matched", { expect_lint( "packageStartupMessage(paste('a string', 'another'))", rex::rex("Don't use paste to build packageStartupMessage strings."), condition_message_linter() ) expect_lint( "packageStartupMessage(paste0('a string ', 'another'))", rex::rex("Don't use paste0 to build packageStartupMessage strings."), condition_message_linter() ) }) test_that("R>=4.0.0 raw strings are handled", { skip_if_not_r_version("4.0.0") expect_lint( "warning(paste(a, b, sep = R'( )'))", rex::rex("Don't use paste to build warning strings."), condition_message_linter() ) expect_lint( "warning(paste(a, b, sep = R'---[ ]---'))", rex::rex("Don't use paste to build warning strings."), condition_message_linter() ) }) test_that("message vectorization works", { expect_lint( trim_some(" foo <- function() { warning(paste('uh oh!', 'spaghettios')) stop(paste0('look out ', 'below!')) } "), list( rex::rex("Don't use paste to build warning strings"), rex::rex("Don't use paste0 to build stop strings") ), condition_message_linter() ) }) lintr/tests/testthat/test-xml_nodes_to_lints.R0000644000176200001440000001202714752731051021416 0ustar liggesuserstest_that("it creates basic lints", { code <- "before %+% after" tmpfile <- withr::local_tempfile(lines = code) expr <- get_source_expressions(tmpfile)$expressions[[2L]] xml <- expr$full_xml_parsed_content node <- xml2::xml_find_first(xml, "//SPECIAL") l <- xml_nodes_to_lints( xml = node, source_expression = expr, lint_message = "lint_msg", type = "warning" ) expect_s3_class(l, "lint") expect_identical(l$filename, tmpfile) expect_identical(l$line_number, 1L) expect_identical(l$column_number, as.integer(xml2::xml_attr(node, "col1"))) expect_identical(l$type, "warning") expect_identical(l$message, "lint_msg") expect_identical(l$line, code) expect_identical(l$ranges, list(as.integer(c(xml2::xml_attr(node, "col1"), xml2::xml_attr(node, "col2"))))) # location XPaths work l_before_col <- xml_nodes_to_lints( xml = node, source_expression = expr, lint_message = "lint_msg", column_number_xpath = "number(./preceding-sibling::*[1]/@col2 + 1)", range_start_xpath = "number(./preceding-sibling::*[1]/@col1)", range_end_xpath = "number(./following-sibling::*[1]/@col2)" ) expect_identical(l_before_col$column_number, nchar("before") + 1L) expect_identical(l_before_col$ranges, list(c(1L, nchar(code)))) # Vectorization works ll <- xml_nodes_to_lints( xml = xml2::xml_find_all(xml, "//expr"), source_expression = expr, lint_message = "lint_msg" ) expect_s3_class(ll, "lints") expect_length(ll, 3L) expect_s3_class(ll[[1L]], "lint") # Also for plain lists of xml_nodes, usually obtained by c(nodeset_a, nodeset_b) ll_unclassed <- xml_nodes_to_lints( xml = unclass(xml2::xml_find_all(xml, "//expr")), source_expression = expr, lint_message = "lint_msg" ) expect_s3_class(ll_unclassed, "lints") expect_length(ll_unclassed, 3L) expect_s3_class(ll_unclassed[[1L]], "lint") # lint_message as a vector ll_msgvec <- xml_nodes_to_lints( xml = xml2::xml_find_all(xml, "//SYMBOL"), source_expression = expr, lint_message = letters[1L:2L] ) expect_identical(ll_msgvec[[1L]]$message, "a") expect_identical(ll_msgvec[[2L]]$message, "b") }) test_that("it handles multi-line lints correctly", { code <- c("before %+%", " after") tmpfile <- withr::local_tempfile(lines = code) expr <- get_source_expressions(tmpfile)$expressions[[2L]] xml <- expr$full_xml_parsed_content node <- xml2::xml_find_first(xml, "/exprlist/expr") l <- xml_nodes_to_lints( xml = node, source_expression = expr, lint_message = "lint_msg" ) expect_s3_class(l, "lint") expect_identical(l$filename, tmpfile) expect_identical(l$line_number, 1L) expect_identical(l$column_number, as.integer(xml2::xml_attr(node, "col1"))) expect_identical(l$type, "style") expect_identical(l$message, "lint_msg") expect_identical(l$line, code[[1L]]) expect_identical(l$ranges, list(as.integer(c(xml2::xml_attr(node, "col1"), nchar(code[1L]))))) }) test_that("it doesn't produce invalid lints", { # Part of #1427 code <- "before %+% after" tmpfile <- withr::local_tempfile(lines = code) expr <- get_source_expressions(tmpfile)$expressions[[2L]] xml <- expr$full_xml_parsed_content node <- xml2::xml_find_first(xml, "//SPECIAL") # We can produce invalid location xpaths by requiring any non-existent node xp_column_number <- "number(./preceding-sibling::*[1]/@col2 + 1)" xp_range_start <- "number(./preceding-sibling::*[1]/@col1)" xp_range_end <- "number(./following-sibling::*[1]/@col2)" xp_invalid <- "number(./DOES-NOT-EXIST/@col1)" expect_warning( { lints1 <- xml_nodes_to_lints( xml = node, source_expression = expr, lint_message = "lint_msg", column_number_xpath = xp_column_number, range_start_xpath = xp_invalid, range_end_xpath = xp_range_end ) }, "Defaulting to start of line", fixed = TRUE ) expect_identical(lints1[["column_number"]], nchar("before") + 1L) expect_identical(lints1[["ranges"]], list(c(1L, nchar(code)))) expect_warning( { lints2 <- xml_nodes_to_lints( xml = node, source_expression = expr, lint_message = "lint_msg", column_number_xpath = xp_column_number, range_start_xpath = xp_range_start, range_end_xpath = xp_invalid ) }, "Defaulting to width 1", fixed = TRUE ) expect_identical(lints2[["column_number"]], nchar("before") + 1L) expect_identical(lints2[["ranges"]], list(c(1L, 1L))) expect_warning( { lints3 <- xml_nodes_to_lints( xml = node, source_expression = expr, lint_message = "lint_msg", column_number_xpath = xp_invalid, range_start_xpath = xp_range_start, range_end_xpath = xp_range_end ) }, "Defaulting to start of range", fixed = TRUE ) expect_identical(lints3[["column_number"]], 1L) expect_identical(lints3[["ranges"]], list(c(1L, nchar(code)))) }) test_that("erroneous input errors", { expect_error(xml_nodes_to_lints(1L), "Expected an ", fixed = TRUE) }) lintr/tests/testthat/test-boolean_arithmetic_linter.R0000644000176200001440000000270214752731051022717 0ustar liggesuserstest_that("boolean_arithmetic_linter doesn't block allowed usages", { linter <- boolean_arithmetic_linter() expect_lint("!any(x == y)", NULL, linter) expect_lint("!any(grepl(pattern, x))", NULL, linter) }) test_that("boolean_arithmetic_linter requires use of any() or !any()", { linter <- boolean_arithmetic_linter() lint_msg <- rex::rex("Use any() to express logical aggregations.") expect_lint("length(which(x == y)) == 0", lint_msg, linter) # anything passed to which() can be assumed to be logical expect_lint("length(which(is_treatment)) == 0L", lint_msg, linter) # regex version expect_lint("length(grep(pattern, x)) == 0", lint_msg, linter) # sum version expect_lint("sum(x == y) == 0L", lint_msg, linter) expect_lint("sum(grepl(pattern, x)) == 0", lint_msg, linter) # non-== comparisons expect_lint("length(which(x == y)) > 0L", lint_msg, linter) expect_lint("length(which(is_treatment)) < 1", lint_msg, linter) expect_lint("length(grep(pattern, x)) >= 1L", lint_msg, linter) expect_lint("sum(x == y) != 0", lint_msg, linter) expect_lint("sum(grepl(pattern, x)) > 0L", lint_msg, linter) }) test_that("lints vectorize", { lint_msg <- rex::rex("Use any() to express logical aggregations.") expect_lint( trim_some("{ length(which(x == y)) > 0L sum(x == y) != 0 }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), boolean_arithmetic_linter() ) }) lintr/tests/testthat/test-unnecessary_placeholder_linter.R0000644000176200001440000000305414752731051023771 0ustar liggesuserslinter <- unnecessary_placeholder_linter() pipes <- pipes(exclude = "|>") patrick::with_parameters_test_that( "unnecessary_placeholder_linter skips allowed usages", { # . used in position other than first --> ok expect_lint(sprintf("x %s foo(y, .)", pipe), NULL, linter) # ditto for nested usage expect_lint(sprintf("x %s foo(y, bar(.))", pipe), NULL, linter) # . used twice --> ok expect_lint(sprintf("x %s foo(., .)", pipe), NULL, linter) # . used as a keyword argument --> ok expect_lint(sprintf("x %s foo(arg = .)", pipe), NULL, linter) # . used inside a scope --> ok expect_lint(sprintf("x %s { foo(arg = .) }", pipe), NULL, linter) }, .test_name = names(pipes), pipe = pipes ) patrick::with_parameters_test_that( "unnecessary_placeholder_linter blocks simple disallowed usages", { expect_lint( sprintf("x %s sum(.)", pipe), rex::rex("Don't use the placeholder (`.`) when it's not needed"), unnecessary_placeholder_linter() ) expect_lint( sprintf("x %s y(.) %s sum()", pipe, pipe), rex::rex("Don't use the placeholder (`.`) when it's not needed"), unnecessary_placeholder_linter() ) }, .test_name = names(pipes), pipe = pipes ) test_that("lints vectorize", { lint_msg <- rex::rex("Don't use the placeholder (`.`) when it's not needed") expect_lint( trim_some("{ x %>% foo(.) y %T>% bar(.) }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), unnecessary_placeholder_linter() ) }) lintr/tests/testthat/test-fixed_regex_linter.R0000644000176200001440000003536514752731051021373 0ustar liggesuserstest_that("fixed_regex_linter skips allowed usages", { linter <- fixed_regex_linter() expect_lint("gsub('^x', '', y)", NULL, linter) expect_lint("grep('x$', '', y)", NULL, linter) expect_lint("sub('[a-zA-Z]', '', y)", NULL, linter) expect_lint("grepl(fmt, y)", NULL, linter) expect_lint(R"{regexec('\\s', '', y)}", NULL, linter) expect_lint("grep('a(?=b)', x, perl = TRUE)", NULL, linter) expect_lint("grep('0+1', x, perl = TRUE)", NULL, linter) expect_lint("grep('1*2', x)", NULL, linter) expect_lint("grep('a|b', x)", NULL, linter) expect_lint(R"{grep('\\[|\\]', x)}", NULL, linter) # if fixed=TRUE is already set, regex patterns don't matter expect_lint(R"{gsub('\\.', '', y, fixed = TRUE)}", NULL, linter) # ignore.case=TRUE implies regex interpretation expect_lint("gsub('abcdefg', '', y, ignore.case = TRUE)", NULL, linter) # char classes starting with [] might contain other characters -> not fixed expect_lint("sub('[][]', '', y)", NULL, linter) expect_lint("sub('[][ ]', '', y)", NULL, linter) expect_lint("sub('[],[]', '', y)", NULL, linter) # wrapper functions don't throw expect_lint("gregexpr(pattern = pattern, data, perl = TRUE, ...)", NULL, linter) }) test_that("fixed_regex_linter blocks simple disallowed usages", { linter <- fixed_regex_linter() lint_msg <- rex::rex("This regular expression is static") expect_lint(R"{gsub('\\.', '', x)}", lint_msg, linter) expect_lint("grepl('abcdefg', x)", lint_msg, linter) expect_lint("gregexpr('a-z', y)", lint_msg, linter) expect_lint(R"{regexec('\\$', x)}", lint_msg, linter) expect_lint("grep('\n', x)", lint_msg, linter) # naming the argument doesn't matter (if it's still used positionally) expect_lint("gregexpr(pattern = 'a-z', y)", lint_msg, linter) }) patrick::with_parameters_test_that( "fixed_regex_linter is robust to unrecognized escapes error for {char}", { expect_lint( sprintf(R"{grep('\\%s', x)}", char), rex::rex("This regular expression is static"), fixed_regex_linter() ) expect_lint( sprintf(R"{strsplit('a%sb', '\\%s')}", char, char), rex::rex("This regular expression is static"), fixed_regex_linter() ) }, char = c( "^", "$", "{", "}", "(", ")", ".", "*", "+", "?", "|", "[", "]", R"(\\)", "<", ">", "=", ":", ";", "/", "_", "-", "!", "@", "#", "%", "&", "~" ) ) test_that("fixed_regex_linter catches regex like [.] or [$]", { linter <- fixed_regex_linter() lint_msg <- rex::rex("This regular expression is static") expect_lint("grep('[.]', x)", lint_msg, linter) expect_lint("grepl('a[*]b', x)", lint_msg, linter) # also catch char classes for [ and ] expect_lint("gregexpr('[]]', x)", lint_msg, linter) }) test_that("fixed_regex_linter catches null calls to strsplit as well", { linter <- fixed_regex_linter() expect_lint("strsplit(x, '^x')", NULL, linter) expect_lint(R"{strsplit(x, '\\s')}", NULL, linter) expect_lint("strsplit(x, 'a(?=b)', perl = TRUE)", NULL, linter) expect_lint("strsplit(x, '0+1', perl = TRUE)", NULL, linter) expect_lint("strsplit(x, 'a|b')", NULL, linter) expect_lint("tstrsplit(x, '1*2')", NULL, linter) expect_lint("tstrsplit(x, '[a-zA-Z]')", NULL, linter) expect_lint("tstrsplit(x, fmt)", NULL, linter) # if fixed=TRUE is already set, regex patterns don't matter expect_lint(R"{strsplit(x, '\\.', fixed = TRUE)}", NULL, linter) expect_lint(R"{strsplit(x, '\\.', fixed = T)}", NULL, linter) }) test_that("fixed_regex_linter catches calls to strsplit as well", { linter <- fixed_regex_linter() lint_msg <- rex::rex("This regular expression is static") expect_lint(R"{strsplit(x, '\\.')}", lint_msg, linter) expect_lint("strsplit(x, '[.]')", lint_msg, linter) expect_lint("tstrsplit(x, 'abcdefg')", lint_msg, linter) }) test_that("fixed_regex_linter is more exact about distinguishing \\s from \\:", { linter <- fixed_regex_linter() lint_msg <- rex::rex("This regular expression is static") expect_lint(R"{grep('\\s', '', x)}", NULL, linter) expect_lint(R"{grep('\\:', '', x)}", lint_msg, linter) }) ## tests for stringr functions test_that("fixed_regex_linter skips allowed stringr usages", { linter <- fixed_regex_linter() expect_lint("str_replace(y, '[a-zA-Z]', '')", NULL, linter) expect_lint("str_replace_all(y, '^x', '')", NULL, linter) expect_lint("str_detect(y, fmt)", NULL, linter) expect_lint(R"{str_extract(y, '\\s')}", NULL, linter) expect_lint(R"{str_extract_all(y, '\\s')}", NULL, linter) expect_lint("str_which(x, '1*2')", NULL, linter) # if fixed() is already set, regex patterns don't matter expect_lint(R"{str_replace(y, fixed('\\.'), '')}", NULL, linter) # namespace qualification doesn't matter expect_lint("stringr::str_replace(y, stringr::fixed('abcdefg'), '')", NULL, linter) }) test_that("fixed_regex_linter blocks simple disallowed usages of stringr functions", { linter <- fixed_regex_linter() lint_msg <- rex::rex("This regular expression is static") expect_lint(R"{str_replace_all(x, '\\.', '')}", lint_msg, linter) expect_lint("str_detect(x, 'abcdefg')", lint_msg, linter) expect_lint("str_locate(y, 'a-z')", lint_msg, linter) expect_lint(R"{str_subset(x, '\\$')}", lint_msg, linter) expect_lint("str_which(x, '\n')", lint_msg, linter) # named, positional arguments are still caught expect_lint("str_locate(y, pattern = 'a-z')", lint_msg, linter) # nor do other named arguments throw things off expect_lint(R"{str_starts(x, '\\.', negate = TRUE)}", lint_msg, linter) }) test_that("fixed_regex_linter catches calls to str_split as well", { linter <- fixed_regex_linter() lint_msg <- rex::rex("This regular expression is static") expect_lint("str_split(x, '^x')", NULL, linter) expect_lint("str_split(x, fmt)", NULL, linter) # if fixed() is already set, regex patterns don't matter expect_lint(R"{str_split(x, fixed('\\.'))}", NULL, linter) expect_lint(R"{str_split(x, '\\.')}", lint_msg, linter) expect_lint("str_split(x, '[.]')", lint_msg, linter) }) test_that("str_replace_all's multi-replacement version is handled", { linter <- fixed_regex_linter() # While each of the replacements is fixed, and this _could_ in principle be replaced by # a pipeline where each step does one of the replacements and fixed() is used, this is overkill. # Instead, ensure that no lint is returned for this case expect_lint('str_replace_all(x, c("one" = "1", "two" = "2", "three" = "3"))', NULL, linter) expect_lint('grepl(c("a" = "b"), x)', NULL, linter) }) test_that("1- or 2-width octal escape sequences are handled", { linter <- fixed_regex_linter() lint_msg <- rex::rex("This regular expression is static") expect_lint('strsplit(x, "\\1")', lint_msg, linter) }) test_that("one-character character classes with escaped characters are caught", { linter <- fixed_regex_linter() lint_msg <- rex::rex("This regular expression is static") expect_lint(R"{gsub('[\n]', '', x)}", lint_msg, linter) expect_lint(R"{gsub('[\"]', '', x)}", lint_msg, linter) expect_lint(R'{gsub("\\<", "x", x, perl = TRUE)}', lint_msg, linter) expect_lint(R"{str_split(x, '[\1]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\12]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\123]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\xa]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\x32]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\uF]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\u01]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\u012]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\u0123]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\U8]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\U1d4d7]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\u{1}]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\U{F7D5}]')}", lint_msg, linter) expect_lint(R"{str_split(x, '[\U{1D4D7}]')}", lint_msg, linter) }) test_that("bracketed unicode escapes are caught", { linter <- fixed_regex_linter() lint_msg <- rex::rex("This regular expression is static") expect_lint('gsub("\\u{A0}", " ", out, useBytes = TRUE)', lint_msg, linter) expect_lint('gsub("abc\\U{A0DEF}ghi", " ", out, useBytes = TRUE)', lint_msg, linter) expect_lint('gsub("\\u{A0}\\U{0001d4d7}", " ", out, useBytes = TRUE)', lint_msg, linter) }) test_that("escaped characters are handled correctly", { linter <- fixed_regex_linter() expect_lint(R"{gsub('\n+', '', sql)}", NULL, linter) expect_lint('gsub("\\n{2,}", "\n", D)', NULL, linter) expect_lint(R'{gsub("[\r\n]", "", x)}', NULL, linter) expect_lint(R'{gsub("\n $", "", y)}', NULL, linter) expect_lint(R'{gsub("```\n*```r*\n*", "", x)}', NULL, linter) expect_lint('strsplit(x, "(;|\n)")', NULL, linter) expect_lint(R'{strsplit(x, "(;|\n)")}', NULL, linter) expect_lint(R'{grepl("[\\W]", x, perl = TRUE)}', NULL, linter) expect_lint(R'{grepl("[\\W]", x)}', NULL, linter) }) # make sure the logic is properly vectorized test_that("single expression with multiple regexes is OK", { expect_lint('c(grep("^a", x), grep("b$", x))', NULL, fixed_regex_linter()) }) test_that("fixed replacements vectorize and recognize str_detect", { linter <- fixed_regex_linter() # properly vectorized expect_lint( trim_some(R"({ grepl('abcdefg', x) grepl('a[.]\\.b\n', x) })"), list( list(rex::rex('Use "abcdefg" with fixed = TRUE'), line_number = 2L), list(rex::rex('Use "a..b\\n" with fixed = TRUE'), line_number = 3L) ), linter ) # stringr hint works expect_lint( "str_detect(x, 'abc')", rex::rex('Use stringr::fixed("abc") as the pattern'), linter ) }) test_that("fixed replacement is correct with UTF-8", { skip_if( .Platform$OS.type == "windows" && !hasName(R.Version(), "crt"), message = "UTF-8 support is required" ) expect_lint( "grepl('[\\U{1D4D7}]', x)", rex::rex('Use "\U1D4D7" with fixed = TRUE'), fixed_regex_linter() ) }) #' Generate a string with a non-printable Unicode entry robust to test environment #' #' Non-printable unicode behaves wildly different with `encodeString()` #' across R versions and platforms. Nonetheless, all of these expressions #' are valid replacements. #' @noRd robust_non_printable_unicode <- function() { if (getRversion() < "4.1.0") { "abc\\U000a0defghi" } else if (.Platform$OS.type == "windows") { "abc\U{0a0def}ghi" } else { "abc\\U{0a0def}ghi" } } # styler: off local({ .cases <- tibble::tribble( ~.test_name, ~regex_expr, ~fixed_expr, "[.]", "[.]", ".", '[\\\"]', R'([\"])', '\\"', "[]]", "[]]", "]", R"(\\.)", R"(\\.)", ".", R"(\\:)", R"(\\:)", ":", R"(\\<)", R"(\\<)", "<", R"(\\$)", R"(\\$)", "$", R"([\1])", R"([\1])", R"(\001)", R"(\1)", R"(\1)", R"(\001)", R"([\12])", R"([\12])", R"(\n)", R"([\123])", R"([\123])", "S", "a[*]b", "a[*]b", "a*b", "abcdefg", "abcdefg", "abcdefg", "abc\\U{A0DEF}ghi", "abc\\U{A0DEF}ghi", robust_non_printable_unicode(), "a-z", "a-z", "a-z", R"([\n])", R"([\n])", R"(\n)", R"(\n)", "\n", R"(\n)", R"([\u01])", R"([\u01])", R"(\001)", R"([\u012])", R"([\u012])", R"(\022)", R"([\u0123])", R"([\u0123])", "\u0123", R"([\u{1}])", R"([\u{1}])", R"(\001)", R"([\U1d4d7])", R"([\U1d4d7])", "\U1D4D7", R"([\U{1D4D7}])", R"([\U{1D4D7}])", "\U1D4D7", R"([\U8])", R"([\U8])", R"(\b)", R"(\u{A0})", R"(\u{A0})", "\uA0", R"(\u{A0}\U{0001d4d7})", R"(\u{A0}\U{0001d4d7})", "\uA0\U1D4D7", R"([\uF])", R"([\uF])", R"(\017)", R"([\U{F7D5}])", R"([\U{F7D5}])", "\UF7D5", R"([\x32])", R"([\x32])", "2", R"([\xa])", R"([\xa])", R"(\n)" ) if (.Platform$OS.type == "windows" && !hasName(R.Version(), "crt")) { skip_cases <- c( # These require UTF-8 support "abc\\U{A0DEF}ghi", "[\\U1d4d7]", "[\\U{1D4D7}]", "\\u{A0}\\U{0001d4d7}", # R version-specific difference in output message on Windows (probably r80051) if (getRversion() == "4.0.4") "[\\U{F7D5}]" ) } else { skip_cases <- character() } patrick::with_parameters_test_that( "fixed replacements of {regex_expr} with {fixed_expr} is correct", { # TODO(google/patrick#19): handle this more cleanly by skipping up-front skip_if( regex_expr %in% skip_cases, sprintf("regex '%s' is not supported on this system", regex_expr) ) expect_lint( sprintf("grepl('%s', x)", regex_expr), rex::rex(sprintf('Use "%s" with fixed = TRUE', fixed_expr)), fixed_regex_linter() ) }, .cases = .cases ) }) # styler: on test_that("'unescaped' regex can optionally be skipped", { linter <- fixed_regex_linter(allow_unescaped = TRUE) expect_lint("grepl('a', x)", NULL, linter) expect_lint("str_detect(x, 'a')", NULL, linter) expect_lint("grepl('[$]', x)", rex::rex('Use "$" with fixed = TRUE'), linter) }) local({ pipes <- pipes(exclude = c("%$%", "%T>%")) patrick::with_parameters_test_that( "linter is pipe-aware", { linter <- fixed_regex_linter() lint_msg <- "This regular expression is static" expect_lint(paste("x", pipe, "grepl(pattern = 'a')"), lint_msg, linter) expect_lint(paste("x", pipe, "grepl(pattern = '^a')"), NULL, linter) expect_lint(paste("x", pipe, "grepl(pattern = 'a', fixed = TRUE)"), NULL, linter) expect_lint(paste("x", pipe, "str_detect('a')"), lint_msg, linter) expect_lint(paste("x", pipe, "str_detect('^a')"), NULL, linter) expect_lint(paste("x", pipe, "str_detect(fixed('a'))"), NULL, linter) expect_lint(paste("x", pipe, "gsub(pattern = 'a', replacement = '')"), lint_msg, linter) expect_lint(paste("x", pipe, "gsub(pattern = '^a', replacement = '')"), NULL, linter) expect_lint(paste("x", pipe, "gsub(pattern = 'a', replacement = '', fixed = TRUE)"), NULL, linter) expect_lint(paste("x", pipe, "str_replace('a', '')"), lint_msg, linter) expect_lint(paste("x", pipe, "str_replace('^a', '')"), NULL, linter) expect_lint(paste("x", pipe, "str_replace(fixed('a'), '')"), NULL, linter) }, pipe = pipes, .test_name = names(pipes) ) }) lintr/tests/testthat/test-any_duplicated_linter.R0000644000176200001440000000615514752731051022062 0ustar liggesuserstest_that("any_duplicated_linter skips allowed usages", { linter <- any_duplicated_linter() expect_lint("x <- any(y)", NULL, linter) expect_lint("y <- duplicated(z)", NULL, linter) # extended usage of any is not covered expect_lint("any(duplicated(y), b)", NULL, linter) expect_lint("any(b, duplicated(y))", NULL, linter) }) test_that("any_duplicated_linter blocks simple disallowed usages", { linter <- any_duplicated_linter() lint_msg <- rex::rex("anyDuplicated(x, ...) > 0 is better") expect_lint("any(duplicated(x))", lint_msg, linter) expect_lint("any(duplicated(foo(x)))", lint_msg, linter) # na.rm doesn't really matter for this since duplicated can't return NA expect_lint("any(duplicated(x), na.rm = TRUE)", lint_msg, linter) # also catch nested usage expect_lint("foo(any(duplicated(x)))", lint_msg, linter) }) test_that("any_duplicated_linter catches length(unique()) equivalencies too", { linter <- any_duplicated_linter() lint_msg_x <- rex::rex("anyDuplicated(x) == 0L is better than length(unique(x)) == length(x)") lint_msg_df <- rex::rex("anyDuplicated(DF$col) == 0L is better than length(unique(DF$col)) == nrow(DF)") # non-matches ## different variable expect_lint("length(unique(x)) == length(y)", NULL, linter) ## different table expect_lint("length(unique(DF$x)) == nrow(DT)", NULL, linter) expect_lint("length(unique(l1$DF$x)) == nrow(l2$DF)", NULL, linter) # lintable usage expect_lint("length(unique(x)) == length(x)", lint_msg_x, linter) # argument order doesn't matter expect_lint("length(x) == length(unique(x))", lint_msg_x, linter) # nrow-style equivalency expect_lint("nrow(DF) == length(unique(DF$col))", lint_msg_df, linter) expect_lint("nrow(DF) == length(unique(DF[['col']]))", lint_msg_df, linter) # match with nesting too expect_lint("nrow(l$DF) == length(unique(l$DF[['col']]))", lint_msg_df, linter) # !=, <, and > usages are all alternative ways of writing a test for dupes # technically, the direction of > / < matter, but writing # length(unique(x)) > length(x) doesn't seem like it would ever happen. expect_lint("length(unique(x)) != length(x)", lint_msg_x, linter) expect_lint("length(unique(x)) < length(x)", lint_msg_x, linter) expect_lint("length(x) > length(unique(x))", lint_msg_x, linter) }) test_that("any_duplicated_linter catches expression with two types of lint", { linter <- any_duplicated_linter() lint_msg <- rex::rex("anyDuplicated(DF$col) == 0L is better than length(unique(DF$col)) == nrow(DF)") expect_lint( trim_some("{ any(duplicated(x)) length(unique(DF$col)) == nrow(DF) }"), list( list(rex::rex("anyDuplicated(x, ...) > 0 is better"), line_number = 2L), list(lint_msg, line_number = 3L) ), linter ) # ditto for different messages within the length(unique()) tests expect_lint( trim_some("{ length(unique(x)) == length(x) length(unique(DF$col)) == nrow(DF) }"), list( list(rex::rex("anyDuplicated(x) == 0L is better than length(unique(x)) == length(x)"), line_number = 2L), list(lint_msg, line_number = 3L) ), linter ) }) lintr/tests/testthat/test-function_argument_linter.R0000644000176200001440000000761614752731051022627 0ustar liggesuserstest_that("function_argument_linter skips allowed usages", { linter <- function_argument_linter() expect_lint("function(x, y = 1, z = 2) {}", NULL, linter) expect_lint("function(x, y, z = 1) {}", NULL, linter) # ... handled correctly expect_lint("function(x, y, z = 1, ...) {}", NULL, linter) expect_lint("function(x, y, ..., z = 1) {}", NULL, linter) }) test_that("function_argument_linter blocks disallowed usages", { linter <- function_argument_linter() lint_msg <- rex::rex("Arguments without defaults should come before arguments with defaults.") expect_lint("function(x, y = 1, z) {}", list(message = lint_msg, column_number = 20L), linter) expect_lint("function(x, y = 1, z, w = 2) {}", list(message = lint_msg, column_number = 20L), linter) expect_lint("function(x, y, z = 1, ..., w) {}", list(message = lint_msg, column_number = 28L), linter) # Multi-line also works expect_lint( trim_some(" function(x, y = 1, z) { } "), list(message = lint_msg, line_number = 3L), linter ) expect_lint( trim_some(" function(x, y # comment for distraction = 1, z, w = 2) { } "), list(message = lint_msg, line_number = 4L), linter ) expect_lint( trim_some(" function(x, y = 1, z = 2) { } "), NULL, linter ) }) test_that("function_argument_linter also lints lambda expressions", { skip_if_not_r_version("4.1.0") linter <- function_argument_linter() lint_msg <- rex::rex("Arguments without defaults should come before arguments with defaults.") expect_lint("\\(x, y = 1, z) {}", list(message = lint_msg, column_number = 13L), linter) expect_lint("\\(x, y = 1, z, w = 2) {}", list(message = lint_msg, column_number = 13L), linter) expect_lint("\\(x, y = 1, z = 2) {}", NULL, linter) expect_lint("\\(x, y, z = 1) {}", NULL, linter) }) test_that("Use of missing() is reported in the lint message", { linter <- function_argument_linter() simple_msg <- "Arguments without defaults should come before arguments with defaults." expect_lint( trim_some(" function(x, y = 1, z) { if (missing(z)) { z <- 2 } } "), rex::rex(simple_msg, anything, "missing()"), linter ) expect_lint( trim_some(" function(x, y = 1, z) { if (y > 1) { if (missing(z)) { z <- 2 } } } "), rex::rex(simple_msg, anything, "missing()"), linter ) # inline function expect_lint( "function(x = 2, y) if (missing(y)) x else y", rex::rex(simple_msg, anything, "missing()"), linter ) # missing() used for a different argument expect_lint( trim_some(" function(x, y = 1, z) { if (missing(x)) { z <- 2 } } "), rex::rex(simple_msg, end), linter ) # missing() used in the signature (not quite the same, and easier to spot) expect_lint( trim_some(" function(x = 1, y, z = missing(y)) { x } "), rex::rex(simple_msg, end), linter ) }) test_that("multiple lints give correct message", { simple_msg <- "Arguments without defaults should come before arguments with defaults." expect_lint( trim_some("{ function(x, y = 1, z) { x } function(x, y = 1, z) { if (missing(z)) { z <- 2 } } function(x, y = 1, z, w) { if (missing(z)) { z <- 2 } } }"), list( list(rex::rex(simple_msg, end), line_number = 2L), list(rex::rex(simple_msg, anything, "missing()"), line_number = 5L), list(rex::rex(simple_msg, anything, "missing()"), line_number = 10L, column_number = 22L), list(rex::rex(simple_msg, end), line_number = 10L, column_number = 25L) ), function_argument_linter() ) }) lintr/tests/testthat/test-for_loop_index_linter.R0000644000176200001440000000246014752731051022076 0ustar liggesuserstest_that("for_loop_index_linter skips allowed usages", { linter <- for_loop_index_linter() expect_lint("for (xi in x) {}", NULL, linter) # this is OK, so not every symbol is problematic expect_lint("for (col in DF$col) {}", NULL, linter) expect_lint("for (col in S4@col) {}", NULL, linter) expect_lint("for (col in DT[, col]) {}", NULL, linter) # make sure symbol check is scoped expect_lint( trim_some(" { for (i in 1:10) { 42L } i <- 7L } "), NULL, linter ) }) test_that("for_loop_index_linter blocks simple disallowed usages", { linter <- for_loop_index_linter() lint_msg <- "Don't re-use any sequence symbols as the index symbol in a for loop" expect_lint("for (x in x) {}", lint_msg, linter) # these also overwrite a variable in calling scope expect_lint("for (x in foo(x)) {}", lint_msg, linter) # arbitrary nesting expect_lint("for (x in foo(bar(y, baz(2, x)))) {}", lint_msg, linter) }) test_that("lints vectorize", { lint_msg <- "Don't re-use any sequence symbols as the index symbol in a for loop" expect_lint( trim_some("{ for (x in x) {} for (y in y) {} }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), for_loop_index_linter() ) }) lintr/tests/testthat/test-sort_linter.R0000644000176200001440000000705514752731051020064 0ustar liggesuserstest_that("sort_linter skips allowed usages", { linter <- sort_linter() expect_lint("order(y)", NULL, linter) expect_lint("y[order(x)]", NULL, linter) # If another function is intercalated, don't fail expect_lint("x[c(order(x))]", NULL, linter) expect_lint("x[order(y, x)]", NULL, linter) expect_lint("x[order(x, y)]", NULL, linter) # pretty sure this never makes sense, but test anyway expect_lint("x[order(y, na.last = x)]", NULL, linter) }) test_that("sort_linter blocks simple disallowed usages", { linter <- sort_linter() lint_message <- rex::rex("sort(", anything, ") is better than") expect_lint("x[order(x)]", lint_message, linter) # Works with extra args in order() expect_lint("x[order(x, decreasing = TRUE)]", lint_message, linter) # ...even in disorder expect_lint("x[order(decreasing = TRUE, x)]", lint_message, linter) }) test_that("sort_linter produces customized warning message", { linter <- sort_linter() expect_lint( "y[order(y)]", rex::rex("sort(y, na.last = TRUE) is better than y[order(y)]."), linter ) # We capture the correct variable symbol expect_lint( "y + x[order(x)]", rex::rex("sort(x, na.last = TRUE) is better than x[order(x)]."), linter ) # Default na.last = TRUE is overwritten if na.last is already provided expect_lint( "x[order(x, na.last = FALSE)]", rex::rex("sort(x, na.last = FALSE) is better than x[order(x, na.last = FALSE)]."), linter ) expect_lint( "x[order(x, decreasing = FALSE)]", rex::rex("sort(x, decreasing = FALSE, na.last = TRUE) is better than x[order(x, decreasing = FALSE)]."), linter ) expect_lint( "f()[order(f())]", rex::rex("sort(f(), na.last = TRUE) is better than f()[order(f())]"), linter ) }) test_that("sort_linter works with multiple lints in a single expression", { linter <- sort_linter() expect_lint( "c( x[order(x)], y[order(y, decreasing = TRUE, na.last = FALSE)] )", list( rex::rex("sort(x, na.last = TRUE) is better than x[order(x)]."), rex::rex( "sort(y, decreasing = TRUE, na.last = FALSE)", anything, "y[order(y, decreasing = TRUE, na.last = FALSE)]." ) ), linter ) }) test_that("sort_linter skips usages calling sort arguments", { linter <- sort_linter() # any arguments to sort --> not compatible expect_lint("sort(x, decreasing = TRUE) == x", NULL, linter) expect_lint("sort(x, na.last = TRUE) != x", NULL, linter) expect_lint("sort(x, method_arg = TRUE) == x", NULL, linter) }) test_that("sort_linter skips when inputs don't match", { linter <- sort_linter() expect_lint("sort(x) == y", NULL, linter) expect_lint("sort(x) == foo(x)", NULL, linter) expect_lint("sort(foo(x)) == x", NULL, linter) }) test_that("sort_linter blocks simple disallowed usages", { linter <- sort_linter() unsorted_msg <- rex::rex("Use is.unsorted(x) to test the unsortedness of a vector.") sorted_msg <- rex::rex("Use !is.unsorted(x) to test the sortedness of a vector.") expect_lint("sort(x) == x", sorted_msg, linter) # argument order doesn't matter expect_lint("x == sort(x)", sorted_msg, linter) # inverted version expect_lint("sort(x) != x", unsorted_msg, linter) # expression matching expect_lint("sort(foo(x)) == foo(x)", sorted_msg, linter) }) test_that("lints vectorize", { expect_lint( trim_some("{ x == sort(x) y[order(y)] }"), list( list(rex::rex("is.unsorted(x)"), line_number = 2L), list(rex::rex("sort(y"), line_number = 3L) ), sort_linter() ) }) lintr/tests/testthat/test-numeric_leading_zero_linter.R0000644000176200001440000000254614752731051023261 0ustar liggesuserstest_that("numeric_leading_zero_linter skips allowed usages", { linter <- numeric_leading_zero_linter() expect_lint("a <- 0.1", NULL, linter) expect_lint("b <- -0.2", NULL, linter) expect_lint("c <- 3.0", NULL, linter) expect_lint("d <- 4L", NULL, linter) expect_lint("e <- TRUE", NULL, linter) expect_lint("f <- 0.5e6", NULL, linter) expect_lint("g <- 0x78", NULL, linter) expect_lint("h <- 0.9 + 0.1i", NULL, linter) expect_lint("h <- 0.9+0.1i", NULL, linter) expect_lint("h <- 0.9 - 0.1i", NULL, linter) expect_lint("i <- 2L + 3.4i", NULL, linter) }) test_that("numeric_leading_zero_linter blocks simple disallowed usages", { linter <- numeric_leading_zero_linter() lint_msg <- rex::rex("Include the leading zero for fractional numeric constants.") expect_lint("a <- .1", lint_msg, linter) expect_lint("b <- -.2", lint_msg, linter) expect_lint("c <- .3 + 4.5i", lint_msg, linter) expect_lint("d <- 6.7 + .8i", lint_msg, linter) expect_lint("d <- 6.7+.8i", lint_msg, linter) expect_lint("e <- .9e10", lint_msg, linter) }) test_that("lints vectorize", { lint_msg <- rex::rex("Include the leading zero for fractional numeric constants.") expect_lint( trim_some("{ .1 -.2 }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), numeric_leading_zero_linter() ) }) lintr/tests/testthat/test-lintr-package.R0000644000176200001440000000074714752731051020242 0ustar liggesuserstest_that("All linter help files have examples", { help_db <- safe_load_help_db() linter_db <- help_db[endsWith(names(help_db), "_linter.Rd")] rd_has_examples <- function(rd) any(vapply(rd, attr, "Rd_tag", FUN.VALUE = character(1L)) == "\\examples") linter_has_examples <- vapply(linter_db, rd_has_examples, logical(1L)) for (ii in seq_along(linter_has_examples)) { expect_true(linter_has_examples[ii], label = paste("Linter", names(linter_db)[ii], "has examples")) } }) lintr/tests/testthat/test-commented_code_linter.R0000644000176200001440000000614514752731051022041 0ustar liggesuserstest_that("commented_code_linter skips allowed usages", { linter <- commented_code_linter() expect_lint("blah", NULL, linter) expect_lint("#' blah <- 1", NULL, linter) expect_lint("a <- 1\n# comment without code", NULL, linter) expect_lint("a <- 1\n## whatever", NULL, linter) expect_lint("TRUE", NULL, linter) expect_lint("#' @examples", NULL, linter) expect_lint("#' foo(1) # list(1)", NULL, linter) # comment in roxygen block ignored expect_lint("1+1 # gives 2", NULL, linter) expect_lint("# Non-existent:", NULL, linter) expect_lint("# 1-a", NULL, linter) # "-" removed from code operators expect_lint('1+1 # for example cat("123")', NULL, linter) # regression test for #451 expect_lint("c('#a#' = 1)", NULL, linter) }) test_that("commented_code_linter blocks disallowed usages", { lint_msg <- rex::rex("Remove commented code.") linter <- commented_code_linter() expect_lint("# blah <- 1", lint_msg, linter) expect_lint( "bleurgh <- fun_call(1) # other_call()", list(message = lint_msg, column_number = 26L), linter ) expect_lint( " #blah <- 1", list(message = lint_msg, column_number = 3L), linter ) # Regression test for #742, line number and comment number don't match up expect_lint( trim_some(" # non-code comment line_without_comment <- 42L #blah <- 1 "), list(message = lint_msg, line_number = 3L, column_number = 3L), linter ) expect_lint( trim_some(" d <- t.test( x = dplyr::starwars$height, # var.equal = TRUE, conf.level = .99, mu = 175 ) "), list(message = lint_msg, line_number = 3L), linter ) expect_lint( trim_some(" d <- t.test( x = dplyr::starwars$height #, var.equal = TRUE , conf.level = .99 , mu = 175 ) "), list(message = lint_msg, line_number = 3L), linter ) expect_lint("1+1 # cat('123')", lint_msg, linter) expect_lint("#expect_ftype(1e-12 , t)", lint_msg, linter) }) test_that("commented_code_linter can detect operators in comments and lint correctly", { linter <- commented_code_linter() lint_msg <- rex::rex("Remove commented code.") test_ops <- c( "+", "=", "==", "!=", "<=", ">=", "<-", "<<-", "<", ">", "->", "->>", "%%", "/", "^", "*", "**", "|", "||", "&", "&&", "%>%", "%anything%" ) for (op in test_ops) { expect_lint(paste("i", op, "1", collapse = ""), NULL, linter) expect_lint(paste("# something like i", op, "1", collapse = ""), NULL, linter) expect_lint(paste("# i", op, "1", collapse = ""), lint_msg, linter) } }) test_that("commented_code_linter can detect operators in comments and lint correctly", { skip_if_not_r_version("4.1.0") expect_lint( "# 1:3 |> sum()", rex::rex("Remove commented code."), commented_code_linter() ) }) test_that("commented_code_linter can detect commented code ending with pipes", { linter <- commented_code_linter() lint_msg <- rex::rex("Remove commented code.") expect_lint("# f() %>%", lint_msg, linter) skip_if_not_r_version("4.1.0") expect_lint("# f() |>", lint_msg, linter) }) lintr/tests/testthat/test-linter_tags.R0000644000176200001440000002213514752731051020027 0ustar liggesuserstest_that("input validation for available_linters works as expected", { expect_error(available_linters(1L), "`packages` must be a vector.") expect_error(available_linters(tags = 1L), "`tags` must be a vector.") expect_error(available_linters(exclude_tags = 1L), "`exclude_tags` must be a vector.") }) test_that("validate_linter_db works as expected", { df_empty <- data.frame() expect_warning( lintr:::validate_linter_db(df_empty, "mypkg"), 'must contain the columns "linter" and "tags"', fixed = TRUE ) expect_false(suppressWarnings(lintr:::validate_linter_db(df_empty, "mypkg"))) df <- data.frame(linter = "absolute_path_linter", tags = "robustness") expect_true(lintr:::validate_linter_db(df, "mypkg")) }) test_that("available_linters returns a data frame", { avail <- available_linters() avail2 <- available_linters(c("lintr", "not-a-package")) empty <- available_linters("not-a-package") expect_s3_class(avail, "data.frame") expect_identical(avail, avail2) expect_identical(nrow(empty), 0L) expect_named(avail, c("linter", "package", "tags")) expect_type(avail[["linter"]], "character") expect_type(avail[["package"]], "character") expect_type(avail[["tags"]], "list") expect_type(avail[["tags"]][[1L]], "character") }) test_that("available_tags returns a character vector", { tags <- available_tags() tags2 <- available_tags(c("lintr", "not-a-package")) empty <- available_tags("not-a-package") expect_type(tags, "character") expect_identical(tags, tags2) expect_length(empty, 0L) expect_true(all(available_linters()$tags[[1L]] %in% tags)) expect_true(all(unlist(available_linters()$tags) %in% tags)) expect_identical(anyDuplicated(tags), 0L) expect_identical(lintr:::platform_independent_order(tags), seq_along(tags)) }) test_that("default_linters and default tag match up", { avail <- available_linters() tagged_default <- avail[["linter"]][vapply(avail[["tags"]], function(tags) "default" %in% tags, logical(1L))] expect_identical(tagged_default, names(default_linters)) }) test_that("warnings occur only for deprecated linters", { expect_silent(linters_with_tags(tags = NULL)) num_deprecated_linters <- nrow(available_linters(tags = "deprecated", exclude_tags = NULL)) deprecation_warns_seen <- 0L outer_env <- environment() expect_silent({ withCallingHandlers( linters_with_tags(tags = "deprecated", exclude_tags = NULL), warning = function(w) { if (grepl("was deprecated", conditionMessage(w), fixed = TRUE)) { outer_env$deprecation_warns_seen <- outer_env$deprecation_warns_seen + 1L invokeRestart("muffleWarning") } else { w } } ) }) expect_identical(deprecation_warns_seen, num_deprecated_linters) }) test_that("available_linters matches the set of linters available from lintr", { lintr_db <- available_linters(exclude_tags = NULL) defunct_linters <- subset(read.csv(system.file("lintr", "linters.csv", package = "lintr"), as.is = TRUE), tags == "defunct")$linter ignore <- c("is_linter", defunct_linters) linters_in_namespace <- setdiff(ls(asNamespace("lintr"), pattern = "_linter$"), ignore) # ensure that the contents of inst/lintr/linters.csv covers all _linter objects in our namespace expect_identical(sort(lintr_db$linter), sort(linters_in_namespace)) # ensure that all _linter objects in our namespace are also exported exported_linters <- setdiff(grep("_linter$", getNamespaceExports("lintr"), value = TRUE), ignore) expect_identical(sort(linters_in_namespace), sort(exported_linters)) }) test_that("rownames for available_linters data frame doesn't have missing entries", { lintr_db <- available_linters() expect_identical( tail(rownames(lintr_db), 1L), as.character(nrow(lintr_db)) ) lintr_db2 <- available_linters(exclude_tags = NULL) expect_identical( tail(rownames(lintr_db2), 1L), as.character(nrow(lintr_db2)) ) }) # See the roxygen helpers in R/linter_tags.R for the code used to generate the docs. # This test helps ensure the documentation is up to date with the available_linters() database test_that("lintr help files are up to date", { help_db <- safe_load_help_db() lintr_db <- available_linters(exclude_tags = NULL) lintr_db$package <- NULL lintr_db$tags <- lapply(lintr_db$tags, function(x) if ("deprecated" %in% x) "deprecated" else sort(x)) lintr_db <- lintr_db[order(lintr_db$linter), ] expect_true("linters.Rd" %in% names(help_db), info = "?linters exists") # NB: objects in help_env are class Rd, see ?as.character.Rd (part of 'tools') rd_as_string <- function(rd) paste(as.character(rd), collapse = "") # Get a character string with the contents of ?linters linter_help_text <- rd_as_string(help_db$linters.Rd) # Test three things about ?linters # (1) the complete list of linters and tags matches that in available_linters() # (2) the tabulation of tags & corresponding count of linters matches that in available_linters() # (3) the 'configurable' tag applies if and only if the linter has parameters # Extract linters & associated tags from ?linters text # Rd markup for items looks like \item{\code{\link{...}} (tags: ...)} # [1] [2] # [1]: linter name; [2]: associated tags help_linters <- rex::re_matches( linter_help_text, rex::rex( "\\item{\\code{\\link{", capture(some_of(letter, number, "_", "."), name = "linter"), "}} (tags: ", capture(some_of(letter, "_", ",", " "), name = "tags"), ")}" ), global = TRUE )[[1L]] help_linters$tags <- lapply(strsplit(help_linters$tags, ", ", fixed = TRUE), sort) help_linters <- help_linters[order(help_linters$linter), ] # (1) the complete list of linters and tags matches that in available_linters() expect_identical( help_linters, # deprecated linters are excluded from this page lintr_db[!vapply(lintr_db$tags, identical, "deprecated", FUN.VALUE = NA), ], info = "Database implied by ?linters is the same as is available_linters()", ignore_attr = "row.names" ) # Counts of tags from available_linters() # NB: as.data.frame.table returns stringsAsFactors=TRUE default in R>4 db_tag_table <- as.data.frame( table(tag = unlist(lintr_db$tags)), responseName = "n_linters", stringsAsFactors = FALSE ) # In ?linters, entries in the enumeration of tags look like # \item{\link[=${TAG}_linters]{${TAG}} (${N_LINTERS_WITH_TAG} linters)} help_tag_table <- rex::re_matches( linter_help_text, rex::rex( "\\item{\\link[=", capture(some_of(letter, "_"), name = "tag_page"), "_linters]{", capture(some_of(letter, "_"), name = "tag"), "} (", capture(numbers, name = "n_linters"), " linters)}" ), global = TRUE )[[1L]] # consistency/sanity check expect_identical(help_tag_table$tag_page, help_tag_table$tag) help_tag_table$tag_page <- NULL help_tag_table$n_linters <- as.integer(help_tag_table$n_linters) # (2) the tabulation of tags & corresponding count of linters matches that in available_linters() expect_identical( help_tag_table[order(help_tag_table$tag), ], db_tag_table[order(db_tag_table$tag), ], ignore_attr = "row.names", info = "Tags and corresponding counts in ?linters is the same as in available_linters()" ) # Now test an analogue to (1) from above for each tag's help page for (tag in db_tag_table$tag) { expect_true(paste0(tag, "_linters.Rd") %in% names(help_db), info = paste0("?", tag, "_linters exists")) tag_help <- help_db[[paste0(tag, "_linters.Rd")]] tag_help_text <- rd_as_string(tag_help) # linters listed in ?${TAG}_linter help_tag_linters <- rex::re_matches( tag_help_text, rex::rex("\\item{\\code{\\link{", capture(some_of(letter, number, "_", "."), name = "linter"), "}}}"), global = TRUE )[[1L]] # those entries in available_linters() with the current tag db_linter_has_tag <- vapply(lintr_db$tags, function(linter_tag) any(tag %in% linter_tag), logical(1L)) expected <- lintr_db$linter[db_linter_has_tag] expect_identical( sort(help_tag_linters$linter), sort(expected), info = paste0("?", tag, "_linters lists all linters with that tag in available_linters()") ) } # (3) the 'configurable' tag applies if and only if the linter has parameters has_args <- 0L < lengths(Map( function(linter, tags) if ("deprecated" %in% tags) NULL else formals(match.fun(linter)), lintr_db$linter, lintr_db$tags )) has_configurable_tag <- vapply(lintr_db$tags, function(tags) "configurable" %in% tags, logical(1L)) expect_identical(has_configurable_tag, unname(has_args)) }) test_that("available_linters gives precedence to included tags", { expect_true("style" %in% unlist(available_linters(tags = "style", exclude_tags = "style")$tags)) # also for the default case expect_identical( available_linters(tags = "deprecated"), available_linters(tags = "deprecated", exclude_tags = NULL) ) }) test_that("all linters have at least one tag", { expect_true(all(lengths(available_linters()$tags) > 0L)) }) lintr/tests/testthat/test-object_name_linter.R0000644000176200001440000003141014752731051021333 0ustar liggesusers# styler: off test_that("styles are correctly identified", { do_style_check <- function(nms) lapply(unname(style_regexes), lintr:::check_style, nms = nms) # symbl UpC lowC snake SNAKE dot alllow ALLUP expect_identical(do_style_check("x"), list(FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE)) expect_identical(do_style_check(".x"), list(FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE)) expect_identical(do_style_check("X"), list(FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE)) expect_identical(do_style_check("x."), list(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("X."), list(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("x_"), list(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("X_"), list(FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("xy"), list(FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE)) expect_identical(do_style_check("xY"), list(FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("Xy"), list(FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("XY"), list(FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE)) expect_identical(do_style_check("x1"), list(FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE)) expect_identical(do_style_check("X1"), list(FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE)) expect_identical(do_style_check("x_y"), list(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("X_Y"), list(FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("X.Y"), list(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("x_2"), list(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("X_2"), list(FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("x.2"), list(FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE)) expect_identical(do_style_check("X.2"), list(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)) # symbl UpC lowC snake SNAKE dot alllow ALLUP expect_identical(do_style_check("IHave1Cat"), list(FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("iHave1Cat"), list(FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("i_have_1_cat"), list(FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("I_HAVE_1_CAT"), list(FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("i.have.1.cat"), list(FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE)) expect_identical(do_style_check("ihave1cat"), list(FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE)) expect_identical(do_style_check("IHAVE1CAT"), list(FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, TRUE)) expect_identical(do_style_check("I.HAVE_ONECAT"), list(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("."), list(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)) expect_identical(do_style_check("%^%"), list(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE)) }) # styler: on test_that("linter ignores some objects", { # names for which style check is ignored expect_lint("`%X%` <- t", NULL, object_name_linter("SNAKE_CASE")) # operator expect_lint("`%x%` <- t", NULL, object_name_linter("snake_case")) # operator expect_lint("`t.test` <- t", NULL, object_name_linter("UPPERCASE")) # std pkg expect_lint(".Deprecated('x')", NULL, object_name_linter("lowercase")) # std pkg expect_lint("print.foo <- t", NULL, object_name_linter("CamelCase")) # S3 generic expect_lint("names.foo <- t", NULL, object_name_linter("CamelCase")) # int generic expect_lint("sapply(x,f,USE.NAMES=T)", NULL, object_name_linter("snake_case")) # defined elsewhere expect_lint(".onLoad <- function(...) TRUE", NULL, object_name_linter("snake_case")) # namespace hooks, #500 expect_lint(".First <- function(...) TRUE", NULL, object_name_linter("snake_case")) # namespace hooks expect_lint("`%++%` <- `+`", NULL, object_name_linter("symbols")) # all-symbol operator expect_lint("`%<-%` <- `+`", NULL, object_name_linter("symbols")) # all-symbol operator #495 # S3 group generic, #1841 expect_lint( "`==.snake_case` <- function(a, b) unclass(a) == unclass(b)", NULL, object_name_linter("snake_case") ) }) test_that("linter returns correct linting", { lint_msg <- "Variable and function name style should match camelCase." linter <- object_name_linter("camelCase") expect_lint("myObject <- 123", NULL, linter) expect_lint("`myObject` <- 123", NULL, linter) expect_lint("my.confused_NAME <- 1;", list(message = lint_msg, line_number = 1L, column_number = 1L), linter) expect_lint("1 ->> read.data.frame;", list(message = lint_msg, line_number = 1L, column_number = 7L), linter) expect_lint( "object_name_linter <- function(...) {}", list(message = lint_msg, line_number = 1L, column_number = 1L), linter ) expect_lint( "Z = sapply('function', function(x=function(x){1}, b.a.z=F, ...){identity(b.a.z)}, USE.NAMES=TRUE)", list( list(message = lint_msg, line_number = 1L, column_number = 1L), list(message = lint_msg, line_number = 1L, column_number = 51L) ), linter ) expect_lint("blah", NULL, linter) expect_lint("invokeRestartInteractively", NULL, linter) expect_lint("camelCase", NULL, linter) expect_lint("camelCase()", NULL, linter) expect_lint("pack::camelCase", NULL, linter) expect_lint("pack:::camelCase", NULL, linter) expect_lint("a(camelCase = 1)", NULL, linter) expect_lint("a$b <- 1", NULL, linter) }) test_that("linter accepts vector of styles", { lint_msg <- "Variable and function name style should match camelCase or dotted.case." linter <- object_name_linter(styles = c("camelCase", "dotted.case")) expect_lint( "var.one <- 1\nvarTwo <- 2\nvar_three <- 3", list(message = lint_msg, line_number = 3L, column_number = 1L), linter ) }) test_that("dollar subsetting only lints the first expression", { # Regression test for #582 linter <- object_name_linter() lint_msg <- rex::rex("Variable and function name style should match snake_case or symbols.") expect_lint("my_var$MY_COL <- 42L", NULL, linter) expect_lint("MY_VAR$MY_COL <- 42L", lint_msg, linter) expect_lint("my_var@MY_SUB <- 42L", NULL, linter) expect_lint("MY_VAR@MY_SUB <- 42L", lint_msg, linter) }) patrick::with_parameters_test_that( "nested extraction only lints on the first symbol", expect_lint( sprintf("%s%sMY_SUB%sMY_COL <- 42L", if (should_lint) "MY_VAR" else "my_var", op1, op2), if (should_lint) rex::rex("Variable and function name style should match snake_case or symbols."), object_name_linter() ), .cases = within( expand.grid(should_lint = c(TRUE, FALSE), op1 = c("$", "@"), op2 = c("$", "@"), stringsAsFactors = FALSE), { .test_name <- sprintf("(should lint? %s, op1=%s, op2=%s)", should_lint, op1, op2) } ) ) test_that("assignment targets of compound lhs are correctly identified", { linter <- object_name_linter() lint_msg <- "Variable and function name style should match snake_case or symbols." # (recursive) [, $, and [[ subsetting expect_lint("good_name[badName] <- badName2", NULL, linter) expect_lint("good_name[1L][badName] <- badName2", NULL, linter) expect_lint("good_name[[badName]] <- badName2", NULL, linter) expect_lint("good_name[[1L]][[badName]] <- badName2", NULL, linter) expect_lint("good_name[[fun(badName)]] <- badName2", NULL, linter) expect_lint("good_name[[badName]]$badName2 <- badName3", NULL, linter) expect_lint("good_name$badName[[badName2]][badName3]$badName4 <- badName5", NULL, linter) expect_lint("badName[badName] <- badName2", lint_msg, linter) expect_lint("badName[1L][badName] <- badName2", lint_msg, linter) expect_lint("badName[[badName]] <- badName2", lint_msg, linter) expect_lint("badName[[1L]][[badName]] <- badName2", lint_msg, linter) expect_lint("badName[[fun(badName)]] <- badName2", lint_msg, linter) expect_lint("badName[[badName]]$badName2 <- badName3", lint_msg, linter) expect_lint("badName$badName[[badName2]][badName3]$badName4 <- badName5", lint_msg, linter) # setters expect_lint("setter(badName) <- good_name", lint_msg, linter) expect_lint("setter(good_name[[badName]]) <- good_name2", NULL, linter) # quotation expect_lint("\"good_name\" <- 42", NULL, linter) expect_lint("\"badName\" <- 42", lint_msg, linter) expect_lint("'good_name' <- 42", NULL, linter) expect_lint("'badName' <- 42", lint_msg, linter) expect_lint("`good_name` <- 42", NULL, linter) expect_lint("`badName` <- 42", lint_msg, linter) # subsetting with quotation expect_lint("good_name$\"badName\" <- 42", NULL, linter) expect_lint("good_name$'badName' <- 42", NULL, linter) expect_lint("badName$\"good_name\" <- 42", lint_msg, linter) expect_lint("badName$'good_name' <- 42", lint_msg, linter) expect_lint("`badName`$\"good_name\" <- 42", lint_msg, linter) expect_lint("`badName`$'good_name' <- 42", lint_msg, linter) }) test_that("object_name_linter won't fail if an imported namespace is unavailable", { expect_length( lint_package(test_path("dummy_packages", "missing_dep"), linters = object_name_linter(), parse_settings = FALSE), 3L ) }) test_that("object_name_linter supports custom regexes", { # disables default styles linter <- object_name_linter( regexes = c(shinyModule = rex::rex(start, lower, zero_or_more(alnum), "UI" %or% "Server", end)) ) msg <- rex::rex("Variable and function name style should match shinyModule.") linter2 <- object_name_linter( styles = c("snake_case", "symbols"), regexes = c(shinyModule = rex::rex(start, lower, zero_or_more(alnum), "UI" %or% "Server", end)) ) msg2 <- rex::rex("Variable and function name style should match snake_case, symbols or shinyModule.") # Can't allow 0 styles expect_error( object_name_linter(NULL), rex::rex("At least one style must be specified using `styles` or `regexes`.") ) expect_lint( trim_some(' snake_case <- 42L "%+%" <- function(...) ..1 + ..2 myModuleUI <- function(id) { # blah } myModuleServer <- function(id) { # blah } myBadName <- 20L '), list( list(line_number = 1L, message = msg), list(line_number = 2L, message = msg), # argument "id" is linted if we only allow shinyModule names list(line_number = 4L, column_number = 24L, message = msg), list(line_number = 8L, column_number = 28L, message = msg), list(line_number = 12L, message = msg) ), linter ) expect_lint( trim_some(' snake_case <- 42L "%+%" <- function(...) ..1 + ..2 myModuleUI <- function(id) { # blah } myModuleServer <- function(id) { # blah } myBadName <- 20L '), list(line_number = 12L, message = msg2), linter2 ) # Default regex naming works expect_lint( trim_some(" a <- 42L b <- 1L c <- 2L "), list(line_number = 3L, message = rex::rex("Variable and function name style should match /^a$/ or /^b$/.")), object_name_linter(regexes = c("^a$", "^b$")) ) expect_lint( trim_some(" a <- 42L b <- 1L c <- 2L "), list(line_number = 3L, message = rex::rex("Variable and function name style should match a or /^b$/.")), object_name_linter(regexes = c(a = "^a$", "^b$")) ) }) test_that("complex LHS of := doesn't cause false positive", { # "_l" would be included under previous logic which tried ancestor::expr[ASSIGN] for STR_CONST, # but only parent::expr[ASSIGN] is needed for strings. expect_lint('dplyr::mutate(df, !!paste0(v, "_l") := df$a * 2)', NULL, object_name_linter()) }) test_that("function shorthand also lints", { skip_if_not_r_version("4.1.0") expect_lint("aBc <- \\() NULL", "function name style", object_name_linter()) }) test_that("capture groups in style are fine", { expect_lint("a <- 1\nab <- 2", NULL, object_name_linter(regexes = c(capture = "^(a)"))) expect_lint("ab <- 1\nabc <- 2", NULL, object_name_linter(regexes = c(capture = "^(a)(b)"))) }) test_that("rlang name injection is handled", { linter <- object_name_linter() expect_lint('tibble("{name}" := 2)', NULL, linter) expect_lint('x %>% mutate("{name}" := 2)', NULL, linter) expect_lint('DT[, "{name}" := 2]', "style should match snake_case", linter) }) lintr/tests/testthat/test-todo_comment_linter.R0000644000176200001440000000327114752731051021560 0ustar liggesuserstest_that("returns the correct linting", { linter <- todo_comment_linter() lint_msg <- rex::rex("Remove TODO comments.") expect_lint('a <- "you#need#to#fixme"', NULL, linter) expect_lint("# something todo", NULL, linter) expect_lint( "cat(x) ### fixme", list(message = lint_msg, line_number = 1L, column_number = 8L), linter ) expect_lint( "x <- \"1.0\n2.0 #FIXME\n3 #TODO 4\"; y <- 2; z <- 3 # todo later", list(message = lint_msg, line_number = 3L, column_number = 28L), linter ) expect_lint( trim_some(" function() { # TODO function() { # fixme } } "), list( list(message = lint_msg, line_number = 2L, column_number = 3L), list(message = lint_msg, line_number = 4L, column_number = 5L) ), linter ) }) test_that("except_regex= excludes valid TODO", { linter <- todo_comment_linter(except_regex = "TODO\\(#[0-9]+\\):") lint_msg <- rex::rex("Remove TODO comments.") expect_lint("foo() # TODO(#1234): Deprecate foo.", NULL, linter) # Non-excepted lints expect_lint( trim_some(" foo() # TODO() bar() # TODO(#567): Deprecate bar. "), list(lint_msg, line_number = 1L), linter ) # Only TODO() is excepted mixed_lines <- trim_some(" foo() # TODO(#1234): Deprecate foo. bar() # fixme(#567): Deprecate bar. ") expect_lint(mixed_lines, list(lint_msg, line_number = 2L), linter) expect_lint( mixed_lines, NULL, todo_comment_linter(except_regex = c("TODO\\(#[0-9]+\\):", "fixme\\(#[0-9]+\\):")) ) # ignore captured groups expect_lint( "# TODO(a)", NULL, todo_comment_linter(except_regex = "TODO\\((a|abc)\\)") ) }) lintr/tests/testthat/test-with_id.R0000644000176200001440000000116414752731051017142 0ustar liggesuserstest_that("with_id works as expected", { source_expression <- get_source_expressions("tmp.R", "a <- 42L")$expressions[[1L]] ref <- with_id( source_expression = source_expression, ids_with_token(source_expression = source_expression, value = "expr") ) expect_identical(ref, source_expression$parsed_content[c(1L, 3L, 6L), ]) expect_identical(ref$token, rep_len("expr", nrow(ref))) # deprecated argument expect_error( with_id( source_file = source_expression, id = ids_with_token(source_expression = source_expression, value = "expr") ), "Argument source_file was deprecated" ) }) lintr/tests/testthat/test-function_left_parentheses_linter.R0000644000176200001440000001176014752731051024333 0ustar liggesuserstest_that("function_left_parentheses_linter skips allowed usages", { linter <- function_left_parentheses_linter() expect_lint("blah", NULL, linter) expect_lint("print(blah)", NULL, linter) expect_lint('"print"(blah)', NULL, linter) expect_lint("base::print(blah)", NULL, linter) expect_lint('base::"print"(blah)', NULL, linter) expect_lint("base::print(blah, fun(1))", NULL, linter) expect_lint("blah <- function(blah) { }", NULL, linter) expect_lint("(1 + 1)", NULL, linter) expect_lint("( (1 + 1) )", NULL, linter) expect_lint("if (blah) { }", NULL, linter) expect_lint("for (i in j) { }", NULL, linter) expect_lint("1 * (1 + 1)", NULL, linter) expect_lint("!(1 == 1)", NULL, linter) expect_lint("(2 - 1):(3 - 1)", NULL, linter) expect_lint("c(1, 2, 3)[(2 - 1)]", NULL, linter) expect_lint("list(1, 2, 3)[[(2 - 1)]]", NULL, linter) expect_lint("range(10)[(2 - 1):(10 - 1)]", NULL, linter) expect_lint("function(){function(){}}()()", NULL, linter) expect_lint("c(function(){})[1]()", NULL, linter) expect_lint("function(x) (mean(x) + 3)", NULL, linter) expect_lint("\"blah (1)\"", NULL, linter) }) test_that("function_left_parentheses_linter blocks disallowed usages", { linter <- function_left_parentheses_linter() fun_lint_msg <- rex::rex("Remove spaces before the left parenthesis in a function definition.") call_lint_msg <- rex::rex("Remove spaces before the left parenthesis in a function call.") expect_lint("blah (1)", call_lint_msg, linter) expect_lint("base::print (blah)", call_lint_msg, linter) expect_lint("base::print(blah, f (1))", call_lint_msg, linter) expect_lint("`+` (1, 1)", call_lint_msg, linter) expect_lint("test <- function (x) { }", fun_lint_msg, linter) expect_lint( "blah (1)", list(message = call_lint_msg, column_number = 5L, ranges = list(c(5L, 6L))), linter ) expect_lint( "test <- function (x) { }", list(message = fun_lint_msg, column_number = 17L, ranges = list(c(17L, 18L))), linter ) }) test_that("multi-line cases are handled correctly", { linter <- function_left_parentheses_linter() call_lint_msg <- rex::rex("Left parenthesis should be on the same line as the function's symbol.") fun_lint_msg <- rex::rex("Left parenthesis should be on the same line as the 'function' symbol.") expect_lint( trim_some(" foo <- function ( param ) { param + 1 } "), fun_lint_msg, linter ) # edge case where '(' is in the right place on the wrong line expect_lint( trim_some(" foo <- function ( param ) { param + 1 } "), fun_lint_msg, linter ) # ditto for function calls expect_lint( trim_some(" if ( y > sum ( x ) ) { TRUE } "), call_lint_msg, linter ) expect_lint( trim_some(" if ( y > sum ( x ) ) { TRUE } "), call_lint_msg, linter ) }) test_that("multi-lint case works", { expect_lint( trim_some(" if ( y > sum ( x ) && z > mean ( x ) && a > sd (x) && b > var (x) ) { TRUE } "), list( list( message = "Left parenthesis should be on the same line as the function's symbol.", line_number = 2L, ranges = list(c(7L, 9L)) ), list( message = "Left parenthesis should be on the same line as the function's symbol.", line_number = 6L, ranges = list(c(7L, 10L)) ), list( message = "Remove spaces before the left parenthesis in a function call.", line_number = 10L, ranges = list(c(9L, 9L)) ), list( message = "Remove spaces before the left parenthesis in a function call.", line_number = 11L, ranges = list(10L:11L) ) ), function_left_parentheses_linter() ) }) test_that("it doesn't produce invalid lints", { # Part of #1427 expect_no_warning( expect_lint( "function() {)", list(linter = "error"), function_left_parentheses_linter() ) ) }) test_that("newline in character string doesn't trigger false positive (#1963)", { linter <- function_left_parentheses_linter() expect_lint('foo("\n")$bar()', NULL, linter) # also corrected the lint metadata for similar cases expect_lint( trim_some(' ( foo(" ")$bar () ) '), # attach to 'b' in '$bar' list(line_number = 3L, column_number = 6L), linter ) }) test_that("shorthand functions are handled", { skip_if_not_r_version("4.1.0") linter <- function_left_parentheses_linter() fun_lint_msg <- rex::rex("Remove spaces before the left parenthesis in a function definition.") expect_lint("blah <- \\(blah) { }", NULL, linter) expect_lint("\\(){\\(){}}()()", NULL, linter) expect_lint("test <- \\ (x) { }", fun_lint_msg, linter) }) lintr/tests/testthat/test-undesirable_function_linter.R0000644000176200001440000000537114752731051023276 0ustar liggesuserstest_that("linter returns correct linting", { linter <- undesirable_function_linter(fun = c(return = NA, log10 = "use log()")) msg_return <- rex::rex('Avoid undesirable function "return".', end) msg_log10 <- rex::rex('Avoid undesirable function "log10". As an alternative, use log().') expect_lint("x <- options()", NULL, linter) expect_lint("cat(\"Try to return\")", NULL, linter) expect_lint("lapply(x, log10)", list(message = msg_log10, line_number = 1L, column_number = 11L), linter) expect_lint("return()", list(message = msg_return, line_number = 1L, column_number = 1L), linter) expect_lint( trim_some(" function(x) { print(options()) y <- log10(x) return(y) }"), list( list(message = msg_log10, line_number = 3L, column_number = 8L), list(message = msg_return, line_number = 4L, column_number = 3L) ), linter ) # regression test for #1050 expect_lint("df$return <- 1", NULL, linter) expect_lint("df@return <- 1", NULL, linter) }) test_that("it's possible to NOT lint symbols", { linter <- undesirable_function_linter( fun = c(dir = NA, log10 = "use log()"), symbol_is_undesirable = FALSE ) expect_lint("dir <- 'path/to/a/directory'", NULL, linter) expect_lint("lapply(x, log10)", NULL, linter) }) test_that("undesirable_function_linter doesn't lint library and require calls", { linter <- undesirable_function_linter(fun = c(foo = NA)) expect_lint("test::foo()", "undesirable", linter) expect_lint("foo::test()", NULL, linter) expect_lint("library(foo)", NULL, linter) expect_lint("require(foo)", NULL, linter) linter <- undesirable_function_linter(fun = c(foo = NA, bar = NA)) expect_lint("library(foo)", NULL, linter) linter <- undesirable_function_linter(fun = c(foo = NA, bar = NA), symbol_is_undesirable = FALSE) expect_lint("library(foo)", NULL, linter) }) # regression test for #866 test_that("Line numbers are extracted correctly", { lines <- c(rep(letters, 10L), "tmp <- tempdir()") expect_lint(paste(lines, collapse = "\n"), "undesirable", undesirable_function_linter(c(tempdir = NA))) }) test_that("invalid inputs fail correctly", { error_msg <- "`fun` should be a non-empty named character vector" expect_error( undesirable_function_linter("***"), error_msg, fixed = TRUE ) expect_error( undesirable_function_linter(c("***" = NA, NA)), error_msg, fixed = TRUE ) expect_error( undesirable_function_linter(fun = NULL), error_msg, fixed = TRUE ) expect_error( undesirable_function_linter(fun = character(0L)), error_msg, fixed = TRUE ) expect_error( undesirable_function_linter(symbol_is_undesirable = 1.0), "is.logical(symbol_is_undesirable) is not TRUE", fixed = TRUE ) }) lintr/tests/testthat/test-pipe_return_linter.R0000644000176200001440000000270014752731051021421 0ustar liggesuserstest_that("pipe_return_linter skips allowed usages", { linter <- pipe_return_linter() normal_pipe_lines <- trim_some(" x %>% filter(str > 5) %>% summarize(str = sum(str)) ") expect_lint(normal_pipe_lines, NULL, linter) normal_function_lines <- trim_some(" pipeline <- function(x) { out <- x %>% filter(str > 5) %>% summarize(str = sum(str)) return(out) } ") expect_lint(normal_function_lines, NULL, linter) nested_return_lines <- trim_some(" pipeline <- function(x) { x_squared <- x %>% sapply(function(xi) { return(xi ** 2) }) return(x_squared) } ") expect_lint(nested_return_lines, NULL, linter) }) test_that("pipe_return_linter blocks simple disallowed usages", { lines <- trim_some(" pipeline <- function(x) { out <- x %>% filter(str > 5) %>% summarize(str = sum(str)) %>% return() } ") expect_lint( lines, rex::rex("Avoid return() as the final step of a magrittr pipeline"), pipe_return_linter() ) }) test_that("lints vectorize", { lint_msg <- rex::rex("Avoid return() as the final step of a magrittr pipeline") expect_lint( trim_some("{ function(x) { x %>% return() } function(y) { y %>% return() } }"), list( list(lint_msg, line_number = 3L), list(lint_msg, line_number = 6L) ), pipe_return_linter() ) }) lintr/tests/testthat/test-expect_named_linter.R0000644000176200001440000000322714752731051021526 0ustar liggesuserstest_that("expect_named_linter skips allowed usages", { linter <- expect_named_linter() # colnames(), rownames(), and dimnames() tests are not equivalent expect_lint("expect_equal(colnames(x), 'a')", NULL, linter) expect_lint("expect_equal(rownames(x), 'a')", NULL, linter) expect_lint("expect_equal(dimnames(x), 'a')", NULL, linter) expect_lint("expect_equal(nrow(x), 4L)", NULL, linter) # NB: also applies to tinytest, but it's sufficient to test testthat expect_lint("testthat::expect_equal(nrow(x), 4L)", NULL, linter) # only check the first argument. yoda tests in the second argument will be # missed, but there are legitimate uses of names() in argument 2 expect_lint("expect_equal(colnames(x), names(y))", NULL, linter) }) test_that("expect_named_linter blocks simple disallowed usages", { linter <- expect_named_linter() lint_msg <- rex::rex("expect_named(x, n) is better than expect_equal(names(x), n)") expect_lint("expect_equal(names(x), 'a')", lint_msg, linter) expect_lint("testthat::expect_equal(names(DF), names(old))", lint_msg, linter) expect_lint("expect_equal('a', names(x))", lint_msg, linter) }) test_that("expect_named_linter blocks expect_identical usage as well", { expect_lint( "expect_identical(names(x), 'a')", rex::rex("expect_named(x, n) is better than expect_identical(names(x), n)"), expect_named_linter() ) }) test_that("lints vectorize", { expect_lint( trim_some("{ expect_equal(names(x), nm) expect_identical(names(x), nm) }"), list( list("expect_equal", line_number = 2L), list("expect_identical", line_number = 3L) ), expect_named_linter() ) }) lintr/tests/testthat/test-stopifnot_all_linter.R0000644000176200001440000000157214752731051021750 0ustar liggesuserstest_that("stopifnot_all_linter skips allowed usages", { expect_lint("stopifnot(all(x) || any(y))", NULL, stopifnot_all_linter()) }) test_that("stopifnot_all_linter blocks simple disallowed usages", { linter <- stopifnot_all_linter() lint_msg <- rex::rex("stopifnot(x) runs all() 'under the hood'") expect_lint("stopifnot(all(A))", list(lint_msg, column_number = 11L), linter) expect_lint("stopifnot(x, y, all(z))", list(lint_msg, column_number = 17L), linter) expect_lint( trim_some("{ stopifnot(all(x), all(y), all(z) ) stopifnot(a > 0, b < 0, all(c == 0)) }"), list( list(lint_msg, line_number = 2L, column_number = 13L), list(lint_msg, line_number = 2L, column_number = 21L), list(lint_msg, line_number = 3L, column_number = 5L), list(lint_msg, line_number = 5L, column_number = 27L) ), linter ) }) lintr/tests/testthat/test-whitespace_linter.R0000644000176200001440000000332214752731051021222 0ustar liggesuserstest_that("whitespace_linter skips allowed usages", { linter <- whitespace_linter() expect_lint("blah", NULL, linter) expect_lint(" blah", NULL, linter) expect_lint(" blah", NULL, linter) expect_lint("#\tblah", NULL, linter) }) test_that("whitespace_linter skips allowed tab usages inside strings", { linter <- whitespace_linter() expect_lint( 'lint_msg <- "dont flag tabs if\tthey are inside a string."', NULL, linter ) expect_lint( 'lint_msg <- "dont flag tabs if\n\tthey are inside multiline strings."', NULL, linter ) }) test_that("whitespace_linter blocks disallowed usages", { linter <- whitespace_linter() lint_msg <- rex::rex("Use spaces to indent, not tabs.") expect_lint( "\tblah", list(message = lint_msg, line_number = 1L, column_number = 1L, ranges = list(c(1L, 1L))), linter ) expect_lint( "\n\t\t\tblah", list(message = lint_msg, line_number = 2L, column_number = 1L), linter ) }) test_that("whitespace_linter blocks disallowed usages with a pipe", { skip_if_not_r_version("4.1.0") linter <- whitespace_linter() lint_msg <- rex::rex("Use spaces to indent, not tabs.") expect_lint( "a %>%\n\tb()", list(message = lint_msg, line_number = 2L, column_number = 1L, ranges = list(c(1L, 1L))), linter ) expect_lint( "a |>\n\tb()", list(message = lint_msg, line_number = 2L, column_number = 1L, ranges = list(c(1L, 1L))), linter ) }) test_that("no_tab_linter id deprecated", { expect_warning( { old_linter <- no_tab_linter() }, "Use whitespace_linter instead", fixed = TRUE ) expect_lint(" f(a, b, c)", NULL, old_linter) expect_lint("\tf(a, b, c)", "not tabs", old_linter) }) lintr/tests/testthat/test-ci.R0000644000176200001440000000416714752731051016114 0ustar liggesuserstest_that("GitHub Actions functionality works", { withr::local_envvar(list(GITHUB_ACTIONS = "true", IN_PKGDOWN = "false")) withr::local_options(lintr.rstudio_source_markers = FALSE) tmp <- withr::local_tempfile(lines = "x <- 1:nrow(y)") l <- lint(tmp) expect_output(print(l), "::warning file", fixed = TRUE) }) test_that("GitHub Actions functionality works in a subdirectory", { pkg_path <- test_path("dummy_packages", "assignmentLinter") withr::local_envvar(list(GITHUB_ACTIONS = "true")) withr::local_options(lintr.rstudio_source_markers = FALSE, lintr.github_annotation_project_dir = pkg_path) l <- lint_package( pkg_path, linters = list(assignment_linter()), parse_settings = FALSE ) expect_output( print(l), paste0("::warning file=", file.path(pkg_path, "R(/|\\\\)abc\\.R")) ) }) patrick::with_parameters_test_that( "GitHub Actions - error on lint works", { withr::local_envvar(list(GITHUB_ACTIONS = "true", IN_PKGDOWN = "", LINTR_ERROR_ON_LINT = env_var_value)) withr::local_options(lintr.rstudio_source_markers = FALSE) tmp <- withr::local_tempfile(lines = "x <- 1:nrow(y)") l <- lint(tmp) local_mocked_bindings(quit = function(...) cat("Tried to quit.\n")) expect_output(print(l), "::warning file", fixed = TRUE) }, env_var_value = list("T", "true") ) patrick::with_parameters_test_that( "GitHub Actions - env var for error on lint is converted to logical", { withr::local_envvar(list(GITHUB_ACTIONS = "true", LINTR_ERROR_ON_LINT = env_var_value)) withr::local_options(lintr.rstudio_source_markers = FALSE) tmp <- withr::local_tempfile(lines = "x <- 1:nrow(y)") l <- lint(tmp) expect_output(print(l), "::warning file", fixed = TRUE) }, env_var_value = list("", "F", NA, NULL) ) test_that("GitHub Actions log is skipped in pkgdown websites", { withr::local_envvar(list(GITHUB_ACTIONS = "true", IN_PKGDOWN = "true")) withr::local_options(lintr.rstudio_source_markers = FALSE) tmp <- withr::local_tempfile(lines = "x <- 1:nrow(y)") l <- lint(tmp, linters = seq_linter()) expect_output(print(l), "warning: [seq_linter]", fixed = TRUE) }) lintr/tests/testthat/test-nzchar_linter.R0000644000176200001440000000553114752731051020357 0ustar liggesuserstest_that("nzchar_linter skips allowed usages", { linter <- nzchar_linter() expect_lint("if (any(nzchar(x))) TRUE", NULL, linter) expect_lint("letters == 'a'", NULL, linter) expect_lint("which(nchar(x) == 4)", NULL, linter) expect_lint("which(nchar(x) != 2)", NULL, linter) }) test_that("nzchar_linter skips as appropriate for other nchar args", { linter <- nzchar_linter() # using type="width" can lead to 0-width strings that are counted as # nzchar, c.f. nchar("\u200b", type="width"), so don't lint this. # type="bytes" should be >= the value for the default (type="chars") expect_lint("nchar(x, type='width') == 0L", NULL, linter) expect_lint("nchar(x, allowNA=TRUE) == 0L", NULL, linter) # nzchar also has keepNA argument so a drop-in switch is easy expect_lint( "nchar(x, keepNA=TRUE) == 0", rex::rex("Use !nzchar(x) instead of nchar(x) == 0"), linter ) }) test_that("nzchar_linter blocks simple disallowed usages", { linter <- nzchar_linter() lint_msg_quote <- rex::rex('Use !nzchar(x) instead of x == ""') lint_msg_nchar <- rex::rex("Use nzchar() instead of comparing nchar(x) to 0") expect_lint("which(x == '')", lint_msg_quote, linter) expect_lint("any(nchar(x) >= 0)", rex::rex("nchar(x) >= 0 is always true, maybe you want nzchar(x)?"), linter) expect_lint("all(nchar(x) == 0L)", rex::rex("Use !nzchar(x) instead of nchar(x) == 0"), linter) expect_lint("sum(0.0 < nchar(x))", rex::rex("Use nzchar(x) instead of nchar(x) > 0"), linter) }) test_that("nzchar_linter skips comparison to '' in if/while statements", { linter <- nzchar_linter() lint_msg_quote <- rex::rex('Use !nzchar(x) instead of x == ""') lint_msg_nchar <- rex::rex("Use nzchar(x) instead of nchar(x) > 0") # still lint nchar() comparisons expect_lint("if (nchar(x) > 0) TRUE", lint_msg_nchar, linter) expect_lint('if (x == "") TRUE', NULL, linter) expect_lint('while (x == "") TRUE', NULL, linter) # nested versions, a la nesting issues with vector_logic_linter expect_lint('if (TRUE || (x == "" && FALSE)) TRUE', NULL, linter) expect_lint('if (TRUE && x == "" && FALSE) TRUE', NULL, linter) expect_lint('if (any(x == "")) TRUE', lint_msg_quote, linter) expect_lint('if (TRUE || any(x == "" | FALSE)) TRUE', lint_msg_quote, linter) expect_lint('foo(if (x == "") y else z)', NULL, linter) }) test_that("multiple lints are generated correctly", { expect_lint( trim_some("{ a == '' '' < b nchar(c) != 0 0.0 > nchar(d) }"), list( list(rex::rex('Use !nzchar(x) instead of x == ""'), line_number = 2L), list(rex::rex('Use nzchar(x) instead of x > ""'), line_number = 3L), list(rex::rex("Use nzchar(x) instead of nchar(x) != 0."), line_number = 4L), list(rex::rex("nchar(x) < 0 is always false, maybe you want !nzchar(x)?"), line_number = 5L) ), nzchar_linter() ) }) lintr/tests/testthat/test-object_usage_linter.R0000644000176200001440000004233514752731051021527 0ustar liggesuserstest_that("returns the correct linting", { linter <- object_usage_linter() local_var_msg <- rex::rex("local variable", anything, "assigned but may not be used") expect_lint("blah", NULL, linter) expect_lint( trim_some(" function() { a <- 1 a } "), NULL, linter ) expect_lint( trim_some(" fun <- function(x) { fun(1) } fun2 <- function(x) { fun2(2) } "), NULL, linter ) expect_lint( trim_some(" fun <- function() { a <- 1 } "), local_var_msg, linter ) expect_lint( trim_some(" fun <- function() { a <- 1 1 } "), local_var_msg, linter ) expect_lint( trim_some(" fun <- function() { a <- 1 } "), local_var_msg, linter ) # same, using = for assignment expect_lint( trim_some(" fun = function() { a = 1 } "), local_var_msg, linter ) expect_lint( trim_some(" fun <- function() { a2 <- 1 a3 } "), list( local_var_msg, rex::rex("no visible binding for global variable ", anything) ), linter ) expect_lint( trim_some(" fun <- function() { fnu(1) } "), rex::rex("no visible global function definition for ", anything), linter ) # earlier we used n(1) but this might conflict with dplyr::n(), # so switch to use an obscure symbol expect_lint( trim_some(" fun <- function(x) { `__lintr_obj`(1) } "), rex::rex("no visible global function definition for ", anything), linter ) # setMethod and assign also checked expect_lint( trim_some(" assign('fun', function() { a <- 1 1 }) "), local_var_msg, linter ) expect_lint( trim_some(" setMethod('plot', 'numeric', function() { a <- 1 1 }) "), local_var_msg, linter ) }) test_that("replace_functions_stripped", { expect_lint( trim_some(" fun <- function(x) { `__lintr_obj`(x) = 1 } "), rex::rex("no visible global function definition for ", anything), object_usage_linter() ) expect_lint( trim_some(" fun <- function(x) { `__lintr_obj`(x) <- 1 } "), rex::rex("no visible global function definition for ", anything), object_usage_linter() ) }) test_that("eval errors are ignored", { expect_lint( trim_some(' setMethod("[[<-", c("stampedEnv", "character", "missing"), function(x) { x }) '), NULL, object_usage_linter() ) }) test_that("calls with top level function definitions are ignored", { expect_lint( 'tryCatch("foo", error = function(e) e)', NULL, object_usage_linter() ) }) test_that("object-usage line-numbers are relative to start-of-file", { expect_lint( trim_some(" a <- function(y) { y ** 2 } b <- function() { x } "), list(line_number = 5L), object_usage_linter() ) }) test_that("used symbols are detected correctly", { # From #666 expect_lint( trim_some(' foo <- data.frame(0) foo$bar <- 1 zero <- function() { file.info("/dev/null")$size } message(zero()) '), NULL, object_usage_linter() ) expect_lint( trim_some(" foo$bar <- 1 zero <- function() { foo } message(zero()) "), list("foo"), object_usage_linter() ) # Also test deeper nesting expect_lint( trim_some(' foo <- list(0) foo$bar$baz$goo <- 1 zero <- function() { file.info("/dev/null")$size foo$bar foo$bar$baz foo$bar$baz$goo } message(zero()) '), NULL, object_usage_linter() ) # Test alternative assignment and access methods expect_lint( trim_some(' foo <- list(0) foo[["bar"]][["baz"]][["goo"]] <- 1 zero <- function() { file.info("/dev/null")$size foo$bar foo$bar$baz foo$bar$baz$goo foo[["bar"]] foo[[c("bar", "baz")]] foo[["bar"]]$baz$goo } message(zero()) '), NULL, object_usage_linter() ) # regression #1322 expect_silent(expect_lint("assign('x', 42)", NULL, object_usage_linter())) }) test_that("object_usage_linter finds lints spanning multiple lines", { # Regression test for #507 expect_lint( trim_some(" foo <- function() { if (unknown_function()) NULL if (unknown_function()) { NULL } } "), list( list(message = "unknown_function", line_number = 2L), list(message = "unknown_function", line_number = 4L) ), object_usage_linter() ) # Linted symbol is not on the first line of the usage warning expect_lint( trim_some(" foo <- function(x) { with( x, unknown_symbol ) } "), list(message = "unknown_symbol", line_number = 4L, column_number = 5L), object_usage_linter(skip_with = FALSE) ) # Even ugly names are found expect_lint( trim_some(" foo <- function(x) { with( x, `\u2019regex_kill` ) } "), list(line_number = 4L, column_number = 5L), object_usage_linter(skip_with = FALSE) ) }) test_that("global variable detection works", { old_globals <- utils::globalVariables(package = globalenv()) utils::globalVariables("global_function", package = globalenv()) on.exit(utils::globalVariables(old_globals, package = globalenv(), add = FALSE)) expect_lint( trim_some(" foo <- function() { if (global_function()) NULL if (global_function()) { NULL } } "), NULL, object_usage_linter() ) }) test_that("package detection works", { expect_length( lint_package(test_path("dummy_packages", "package"), linters = object_usage_linter(), parse_settings = FALSE), 10L ) }) test_that("robust against errors", { expect_lint( 'assign("x", unknown_function)', NULL, object_usage_linter() ) }) test_that("interprets glue expressions", { linter <- object_usage_linter() expect_lint(trim_some(" fun <- function() { local_var <- 42 glue::glue('The answer is {local_var}.') } "), NULL, linter) # no need for namespace-qualification expect_lint(trim_some(" glue <- glue::glue # imitate this being an @import fun <- function() { local_var <- 42 glue('The answer is {local_var}.') } "), NULL, linter) # multiple variables in different interpolations expect_lint(trim_some(" fun <- function() { local_key <- 'a' local_value <- 123 glue::glue('Key-value pair: {local_key}={local_value}.') } "), NULL, linter) # multiple variables in single interpolation expect_lint(trim_some(" fun <- function() { local_str1 <- 'a' local_str2 <- 'b' glue::glue('With our powers combined: {paste(local_str1, local_str2)}.') } "), NULL, linter) # Check non-standard .open and .close expect_lint(trim_some(" fun <- function() { local_var <- 42 glue::glue('The answer is $[local_var].', .open = '$[', .close = ']') } "), NULL, linter) # Steer clear of custom .transformer and .envir constructs expect_lint(trim_some(" fun <- function() { local_var <- 42 glue::glue('The answer is {local_var}.', .transformer = glue::identity_transformer) } "), "local_var", linter) expect_lint(trim_some(" fun <- function() { local_var <- 42 e <- new.env() glue::glue('The answer is {local_var}.', .envir = e) } "), "local_var", linter) # unused is caught, glue-used is not expect_lint(trim_some(" fun <- function() { local_var <- 42 unused_var <- 3 glue::glue('The answer is {local_var}.') } "), "unused_var", linter) # glue-only is caught with option off expect_lint(trim_some(" fun <- function() { local_var <- 42 glue::glue('The answer is {local_var}.') } "), "local_var", object_usage_linter(interpret_glue = FALSE)) # call in glue is caught expect_lint( trim_some(" fun <- function() { local_call <- identity local_unused_call <- identity glue::glue('{local_call(1)}') } "), "local_unused_call", linter ) # ditto infix operator expect_lint(trim_some(" glue <- glue::glue # imitate this being an @import foo <- function() { `%++%` <- `+` glue('{x %++% y}') } "), NULL, linter) }) test_that("errors/edge cases in glue syntax don't fail lint()", { linter <- object_usage_linter() # no lint & no error, despite glue error expect_warning( expect_lint( trim_some(" fun <- function() { a <- 2 a + 1 glue::glue('The answer is {a') } "), NULL, linter ), "Evaluating glue expression.*failed: Expecting '\\}'.*Please ensure correct glue syntax" ) # generates a lint because the "usage" inside glue() is not detected expect_warning( expect_lint( trim_some(" fun <- function() { a <- 2 glue::glue('The answer is {a') } "), "local variable 'a'", linter ), "Evaluating glue expression.*failed: Expecting '\\}'" ) # complete {...}, but syntax error in code -> ignore expect_lint( trim_some(" fun <- function() { a <- 2 glue::glue('The answer is {a + }') } "), "local variable 'a'", linter ) # empty glue expression {} expect_lint( trim_some(" fun <- function() { a <- 2 glue::glue('The answer is {}: {a}') } "), NULL, linter ) # comment inside glue range (#1919) expect_lint( trim_some(" fun <- function() { a <- 2 glue::glue( 'The answer is {}: {a}' # show the answer ) } "), NULL, linter ) }) test_that("backtick'd names in glue are handled", { expect_lint( trim_some(" fun <- function() { `w` <- 2 x <- 3 y <- -4 `\\`y` <- 4 z <- -5 `z\\`` <- 5 glue::glue('{w}{`x`}{y}{z}') } "), list( rex::rex("local variable '`y'"), rex::rex("local variable 'z`'") ), object_usage_linter() ) }) # reported as #1088 test_that("definitions below top level are ignored (for now)", { expect_lint( trim_some(" local({ x <- 1 f <- function() { x } }) "), NULL, object_usage_linter() ) }) # reported as #1127 test_that("package imports are detected if present in file", { skip_if("package:xml2" %in% search()) expect_lint( trim_some(" dog <- function(url) { a <- read_xml(url) a } "), rex::rex("no visible global function definition for ", anything, "read_xml"), object_usage_linter() ) expect_lint( trim_some(" library(xml2) dog <- function(url) { a <- read_xml(url) a } "), NULL, object_usage_linter() ) }) test_that("fallback works", { expect_lint( trim_some(" f <- function() { `non_existing_assign<-`(1, 2) } "), list( message = rex::rex("no visible global function definition for ", anything, "non_existing_assign<-"), line_number = 2L, column_number = 3L ), object_usage_linter() ) }) test_that("unknown infix operators give good lint metadata", { expect_lint( trim_some(" foo <- function(x) { x %unknown-operator% 1 } "), list( message = rex::rex("no visible global function definition for '%unknown-operator%'"), line_number = 2L, column_number = 5L ), object_usage_linter() ) skip_if(any(c("package:rlang", "package:data.table") %in% search())) expect_lint( trim_some(' foo <- function(x) { x[, "new_col" := 2L] } '), list( message = rex::rex("no visible global function definition for ':='"), line_number = 2L, column_number = 17L ), object_usage_linter() ) }) test_that("respects `skip_with` argument for `with()` expressions", { f <- withr::local_tempfile( lines = c( "test_fun <- function(df) {", " with(df, first_var + second_var)", "}" ) ) expect_length(lint(f, object_usage_linter(skip_with = TRUE)), 0L) expect_length(lint(f, object_usage_linter(skip_with = FALSE)), 2L) }) test_that("missing libraries don't cause issue", { expect_lint( trim_some(" library(a.a.a.z.z.z) foo <- function() { a <- 1 a } "), NULL, object_usage_linter() ) }) test_that("messages without a quoted name are caught", { # regression test for #1714 expect_lint( trim_some(" foo <- function() { a <- ... a } "), list( message = "... may be used in an incorrect context", line_number = 2L ), object_usage_linter() ) }) # See #1914 test_that("symbols in formulas aren't treated as 'undefined global'", { expect_lint( trim_some(" foo <- function(x) { lm( y ~ z, data = x[!is.na(y)] ) } "), list( message = "no visible binding for global variable 'y'", line_number = 4L, column_number = 21L ), object_usage_linter() ) # neither on the RHS expect_lint( trim_some(" foo <- function(x) { lm( z ~ y, data = x[!is.na(y)] ) } "), list( message = "no visible binding for global variable 'y'", line_number = 4L, column_number = 21L ), object_usage_linter() ) # nor in nested expressions expect_lint( trim_some(" foo <- function(x) { lm( log(log(y)) ~ z, data = x[!is.na(y)] ) } "), list( message = "no visible binding for global variable 'y'", line_number = 4L, column_number = 21L ), object_usage_linter() ) # nor as a call # NB: I wanted this to be s(), as in mgcv::s(), but that # doesn't work in this test suite because it resolves to # rex::s() since we attach that in testthat.R expect_lint( trim_some(" foo <- function(x) { lm( y(w) ~ z, data = x[!is.na(y)] ) } "), list( message = "no visible binding for global variable 'y'", line_number = 4L, column_number = 21L ), object_usage_linter() ) }) test_that("NSE-ish symbols after $/@ are ignored as sources for lints", { linter <- object_usage_linter() lint_msg <- "no visible binding for global variable 'column'" expect_lint( trim_some(" foo <- function(x) { ggplot2::ggplot( x[!is.na(x$column), ], ggplot2::aes(x = column, fill = factor(x$grp)) ) } "), list(lint_msg, line_number = 4L, column_number = 22L), linter ) expect_lint( trim_some(" foo <- function(x) { ggplot2::ggplot( x[!is.na(x@column), ], ggplot2::aes(x = column, fill = factor(x$grp)) ) } "), list(lint_msg, line_number = 4L, column_number = 22L), linter ) }) test_that("functional lambda definitions are also caught", { skip_if_not_r_version("4.1.0") expect_lint( trim_some(" fun <- \\() { a <- 1 } "), rex::rex("local variable", anything, "assigned but may not be used"), object_usage_linter() ) }) test_that("messages without location info are repaired", { linter <- object_usage_linter() global_function_msg <- rex::rex("no visible global function definition for", anything) global_variable_msg <- rex::rex("no visible binding for global variable", anything) local_variable_msg <- rex::rex("local variable", anything, "assigned but may not be used") # regression test for #1986 expect_lint( "foo <- function() no_fun()", list(global_function_msg, line_number = 1L, column_number = 19L), linter ) expect_lint( "foo <- function(a = no_fun()) a", list(global_function_msg, line_number = 1L, column_number = 21L), linter ) expect_lint( "foo <- function() no_global", list(global_variable_msg, line_number = 1L, column_number = 19L), linter ) expect_lint( "foo <- function() unused_local <- 42L", list(local_variable_msg, line_number = 1L, column_number = 19L), linter ) # More complex case with two lints and missing location info expect_lint( trim_some(" foo <- function() a <- bar() "), list( list(local_variable_msg, line_number = 1L, column_number = 19L), list(global_function_msg, line_number = 2L, column_number = 3L) ), linter ) }) test_that("globals in scripts are found regardless of assignment operator", { linter <- object_usage_linter() expect_lint( trim_some(" library(dplyr) global_const_eq = 5 global_const_la <- 6 7 -> global_const_ra examplefunction <- function(df) { df %>% select(dist) %>% mutate(power = global_const_eq + global_const_ra + global_const_la) } "), NULL, linter ) }) lintr/tests/testthat/test-unnecessary_nesting_linter.R0000644000176200001440000002762214752731051023165 0ustar liggesuserstest_that("unnecessary_nesting_linter skips allowed usages", { linter <- unnecessary_nesting_linter() # parallel stops() and return()s are OK expect_lint( trim_some(" if (A) { stop() } else { stop() } "), NULL, linter ) expect_lint( trim_some(" if (A) { return() } else { return() } "), NULL, linter ) }) test_that("Multiple if/else statements don't require unnesting", { # with further branches, reducing nesting might be less readable expect_lint( trim_some(" if (x == 'a') { stop() } else if (x == 'b') { do_b() } else { stop() } "), NULL, unnecessary_nesting_linter() ) }) test_that("else-less if statements don't lint", { expect_lint( trim_some(" if (x == 4) { msg <- 'failed' stop(msg) } "), NULL, unnecessary_nesting_linter() ) }) test_that("non-terminal expressions are not considered for the logic", { expect_lint( trim_some(" if (x == 4) { x <- 5 return(x) } else { return(x) } "), NULL, unnecessary_nesting_linter() ) }) test_that("parallels in further nesting are skipped", { expect_lint( trim_some(" if (length(bucket) > 1) { return(age) } else { age <- age / 2 if (grepl('[0-9]', age)) { return(age) } else { return('unknown') } } "), NULL, unnecessary_nesting_linter() ) }) test_that("unnecessary_nesting_linter blocks if/else with one exit branch", { linter <- unnecessary_nesting_linter() lint_msg <- rex::rex("Reduce the nesting of this if/else statement by unnesting the portion") expect_lint( trim_some(" if (A) { stop() } else { B } "), lint_msg, linter ) expect_lint( trim_some(" if (A) { return() } else { B } "), lint_msg, linter ) # also find exits in the later branch expect_lint( trim_some(" if (A) { B } else { stop() } "), lint_msg, linter ) expect_lint( trim_some(" if (A) { B } else { return() } "), lint_msg, linter ) stop_warning_lines <- trim_some(" if (A) { stop('An error') } else { warning('A warning') } ") expect_lint(stop_warning_lines, lint_msg, linter) # Optionally consider 'warning' as an exit call --> no lint expect_lint(stop_warning_lines, NULL, unnecessary_nesting_linter(branch_exit_calls = "warning")) }) test_that("unnecessary_nesting_linter skips one-line functions", { linter <- unnecessary_nesting_linter() expect_lint( trim_some(" foo <- function(x) { return(x) } "), NULL, linter ) # purrr anonymous functions also get skipped expect_lint( trim_some(" purrr::map(x, ~ { .x }) "), NULL, linter ) }) test_that("unnecessary_nesting_linter skips one-expression for loops", { linter <- unnecessary_nesting_linter() expect_lint( trim_some(" for (i in 1:10) { print(i) } "), NULL, linter ) # also for extended control flow functionality from packages expect_lint( trim_some(" foreach (i = 1:10) %dopar% { print(i) } "), NULL, linter ) }) test_that("unnecessary_nesting_linter skips one-expression if and else clauses", { expect_lint( trim_some(" if (TRUE) { x } else { y } "), NULL, unnecessary_nesting_linter() ) }) test_that("unnecessary_nesting_linter skips one-expression while loops", { expect_lint( trim_some(" while (x < 10) { x <- x + 1 } "), NULL, unnecessary_nesting_linter() ) }) test_that("unnecessary_nesting_linter skips one-expression repeat loops", { expect_lint( trim_some(" repeat { x <- x + 1 } "), NULL, unnecessary_nesting_linter() ) }) test_that("unnecessary_nesting_linter skips one-expression assignments by default", { expect_lint( trim_some(" { x <- foo() } "), NULL, unnecessary_nesting_linter() ) }) test_that("unnecessary_nesting_linter passes for multi-line braced expressions", { expect_lint( trim_some(" tryCatch( { foo(x) bar(x) }, error = identity ) "), NULL, unnecessary_nesting_linter() ) }) test_that("unnecessary_nesting_linter skips if unbracing won't reduce nesting", { linter <- unnecessary_nesting_linter() expect_lint( trim_some(" test_that('this works', { expect_true(TRUE) }) "), NULL, linter ) expect_lint( trim_some(" DT[, { plot(x, y) }] "), NULL, linter ) expect_lint( trim_some(" DT[, x := { foo(x, y) }] "), NULL, linter ) # NB: styler would re-style these anyway expect_lint( trim_some(" tryCatch({ foo() }, error = identity) "), NULL, linter ) expect_lint( trim_some(" DT[{ n <- .N - 1 x[n] < y[n] }, j = TRUE, by = x] "), NULL, linter ) }) test_that("rlang's double-brace operator is skipped", { expect_lint( "rename(DF, col = {{ val }})", NULL, unnecessary_nesting_linter() ) }) test_that("unnecessary_nesting_linter blocks one-expression braced expressions", { expect_lint( trim_some(" tryToCatch( { foo(x) }, error = identity ) "), rex::rex("Reduce the nesting of this statement by removing the braces {}."), unnecessary_nesting_linter() ) }) test_that("unnecessary_nesting_linter allow_assignment= argument works", { expect_lint( trim_some(" tryToCatch( { idx <- foo(x) }, error = identity ) "), rex::rex("Reduce the nesting of this statement by removing the braces {}."), unnecessary_nesting_linter(allow_assignment = FALSE) ) }) test_that("lints vectorize", { lint_msg <- rex::rex("Reduce the nesting of this if/else") expect_lint( trim_some("{ if (A) { stop('no') } else { 0 } if (B) { stop('really no') } else { 1 } }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 7L) ), unnecessary_nesting_linter() ) }) test_that("unnecessary_nesting_linter skips allowed usages", { linter <- unnecessary_nesting_linter() expect_lint( trim_some(" if (x && y) { 1L } "), NULL, linter ) expect_lint( trim_some(" for (x in 1:3) { if (x && y) { 1L } } "), NULL, linter ) expect_lint( trim_some(" if (x) { 1L } else if (y) { 2L } "), NULL, linter ) expect_lint( trim_some(" if (x) { 1L } else { 2L if (y) { 3L } } "), NULL, linter ) expect_lint( trim_some(" if (if (x) TRUE else FALSE) { 1L } "), NULL, linter ) expect_lint( trim_some(" if (x) { y <- x + 1L if (y) { 1L } } "), NULL, linter ) expect_lint( trim_some(" if ((x && y) || (if (x) TRUE else FALSE)) { 1L } "), NULL, linter ) # if there is any additional code between the inner and outer scopes, no lint expect_lint( trim_some(" if (x && a) { y <- x + 1L if (y || b) { 1L } } "), NULL, linter ) expect_lint( trim_some(" if (x) { if (y) { 1L } y <- x + 1L } "), NULL, linter ) expect_lint( trim_some(" if (x) { y <- x + 1L if (y) { 1L } y <- x } "), NULL, linter ) expect_lint( trim_some(" if (x) { y <- x + 1L { if (y) { 1L } } } "), NULL, linter ) expect_lint( trim_some(" if (x) { { y <- x + 1L if (y) { 1L } } } "), NULL, linter ) expect_lint( trim_some(" if (x) { { if (y) { 1L } } y <- x + 1L } "), NULL, linter ) expect_lint( trim_some(" if (x) { { y <- x + 1L { if (y) { 1L } } } } "), NULL, linter ) }) test_that("unnecessary_nesting_linter blocks disallowed usages", { lint_message <- rex::rex("Don't use nested `if` statements") linter <- unnecessary_nesting_linter() expect_lint( trim_some(" if (x) { if (y) { 1L } } "), lint_message, linter ) expect_lint( trim_some(" if (x) { if (y) 1L } "), lint_message, linter ) expect_lint( trim_some(" if (x && a) { if (y || b) { 1L } } "), lint_message, linter ) expect_lint( trim_some(" if (if (x) TRUE else FALSE) { if (y) { 1L } } "), lint_message, linter ) expect_lint( "if (x) if (y) 1L", lint_message, linter ) expect_lint( trim_some(" for (x in 1:3) { if (x) if (y) 1L } "), lint_message, linter ) expect_lint( trim_some(" if (x) { if (y) { if (z) { 1L } } } "), list( list(message = lint_message, line_number = 2L, column_number = 3L), list(message = lint_message, line_number = 3L, column_number = 5L) ), linter ) }) test_that("else that can drop braces is found", { linter <- unnecessary_nesting_linter() lint_msg <- rex::rex("Simplify this condition by using 'else if' instead of 'else { if.") expect_lint( trim_some(" if (A) { 1 } else { if (B) { 2 } else { 3 } } "), list(lint_msg, line_number = 4L), linter ) expect_lint( trim_some(" if (A) { 1 } else if (B) { 2 } else { if (C) { 3 } else { 4 } } "), list(lint_msg, line_number = 6L), linter ) expect_lint( trim_some(" if (A) { 1 } else { if (B) { 2 } else { if (C) { 3 } else { 4 } } } "), list( list(lint_msg, line_number = 4L), list(lint_msg, line_number = 7L) ), linter ) }) patrick::with_parameters_test_that( "default allowed functions are skipped", expect_lint(sprintf("%s(x, {y}, z)", call), NULL, unnecessary_nesting_linter()), call = c( "test_that", "with_parameters_test_that", "switch", "try", "tryCatch", "withCallingHandlers", "quote", "bquote", "expression", "substitute", "observe", "observeEvent", "reactive", "renderCachedPlot", "renderDataTable", "renderImage", "renderPlot", "renderPrint", "renderTable", "renderText", "renderUI" ) ) test_that("allow_functions= works", { linter_default <- unnecessary_nesting_linter() linter_foo <- unnecessary_nesting_linter(allow_functions = "foo") expect_lint("foo(x, {y}, z)", "Reduce the nesting of this statement", linter_default) expect_lint("foo(x, {y}, z)", NULL, linter_foo) expect_lint("test_that('a', {y})", NULL, linter_default) expect_lint("that_that('b', {y})", NULL, linter_foo) }) lintr/tests/testthat/test-length_levels_linter.R0000644000176200001440000000122714752731051021723 0ustar liggesuserstest_that("length_levels_linter skips allowed usages", { expect_lint("length(c(levels(x), 'a'))", NULL, length_levels_linter()) }) test_that("length_levels_linter blocks simple disallowed usages", { expect_lint( "2:length(levels(x))", rex::rex("nlevels(x) is better than length(levels(x))."), length_levels_linter() ) }) test_that("lints vectorize", { lint_msg <- rex::rex("nlevels(x) is better than length(levels(x)).") expect_lint( trim_some("{ length(levels(x)) length(levels(y)) }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), length_levels_linter() ) }) lintr/tests/testthat/test-redundant_ifelse_linter.R0000644000176200001440000001076614752731051022413 0ustar liggesuserstest_that("redundant_ifelse_linter skips allowed usages", { linter <- redundant_ifelse_linter() expect_lint("ifelse(x > 5, 0, 2)", NULL, linter) expect_lint("ifelse(x > 5, TRUE, NA)", NULL, linter) expect_lint("ifelse(x > 5, FALSE, NA)", NULL, linter) expect_lint("ifelse(x > 5, TRUE, TRUE)", NULL, linter) expect_lint("ifelse(x > 5, 0L, 2L)", NULL, linter) expect_lint("ifelse(x > 5, 0L, 10L)", NULL, linter) }) test_that("redundant_ifelse_linter blocks simple disallowed usages", { linter <- redundant_ifelse_linter() expect_lint( "ifelse(x > 5, TRUE, FALSE)", rex::rex("Just use the logical condition (or its negation) directly"), linter ) expect_lint( "ifelse(x > 5, FALSE, TRUE)", rex::rex("Just use the logical condition (or its negation) directly"), linter ) # other ifelse equivalents from common packages expect_lint( "if_else(x > 5, TRUE, FALSE)", rex::rex("Just use the logical condition (or its negation) directly"), linter ) expect_lint( "fifelse(x > 5, FALSE, TRUE)", rex::rex("Just use the logical condition (or its negation) directly"), linter ) }) test_that("redundant_ifelse_linter blocks usages equivalent to as.numeric, optionally", { linter <- redundant_ifelse_linter() expect_lint( "ifelse(x > 5, 1L, 0L)", rex::rex("Prefer as.integer(x) to ifelse(x, 1L, 0L)"), linter ) expect_lint( "ifelse(x > 5, 0L, 1L)", rex::rex("Prefer as.integer(!x) to ifelse(x, 0L, 1L)"), linter ) expect_lint( "ifelse(x > 5, 1, 0)", rex::rex("Prefer as.numeric(x) to ifelse(x, 1, 0)"), linter ) expect_lint( "ifelse(x > 5, 0, 1)", rex::rex("Prefer as.numeric(!x) to ifelse(x, 0, 1)"), linter ) # mixing int and num expect_lint( "ifelse(x > 5, 0, 1L)", rex::rex("Prefer as.numeric(!x) to ifelse(x, 0, 1L)"), linter ) expect_lint( "ifelse(x > 5, 0L, 1)", rex::rex("Prefer as.numeric(!x) to ifelse(x, 0L, 1)"), linter ) expect_lint( "ifelse(x > 5, 1, 0L)", rex::rex("Prefer as.numeric(x) to ifelse(x, 1, 0L)"), linter ) expect_lint( "ifelse(x > 5, 1L, 0)", rex::rex("Prefer as.numeric(x) to ifelse(x, 1L, 0)"), linter ) # data.table/dplyr equivalents expect_lint( "dplyr::if_else(x > 5, 1L, 0L)", rex::rex("Prefer as.integer(x) to if_else(x, 1L, 0L)"), linter ) expect_lint( "data.table::fifelse(x > 5, 0L, 1L)", rex::rex("Prefer as.integer(!x) to fifelse(x, 0L, 1L)"), linter ) expect_lint( "if_else(x > 5, 1, 0)", rex::rex("Prefer as.numeric(x) to if_else(x, 1, 0)"), linter ) expect_lint( "fifelse(x > 5, 0, 1)", rex::rex("Prefer as.numeric(!x) to fifelse(x, 0, 1)"), linter ) }) test_that("allow10 works as intended", { linter <- redundant_ifelse_linter(allow10 = TRUE) expect_lint("ifelse(x > 5, 1L, 0L)", NULL, linter) expect_lint("ifelse(x > 5, 0L, 1L)", NULL, linter) expect_lint("ifelse(x > 5, 1, 0)", NULL, linter) expect_lint("ifelse(x > 5, 0, 1)", NULL, linter) expect_lint("dplyr::if_else(x > 5, 1L, 0L)", NULL, linter) expect_lint("data.table::fifelse(x > 5, 0L, 1L)", NULL, linter) expect_lint("if_else(x > 5, 1, 0)", NULL, linter) expect_lint("fifelse(x > 5, 0, 1)", NULL, linter) }) test_that("ifelse(missing = ) gives correct lints", { linter <- redundant_ifelse_linter() expect_lint("if_else(x > 5, TRUE, FALSE, NA)", rex::rex("Just use the logical condition"), linter) expect_lint("if_else(x > 5, TRUE, FALSE, TRUE)", NULL, linter) expect_lint("if_else(x > 5, TRUE, FALSE, 5L)", NULL, linter) expect_lint("if_else(x > 5, 1L, 0L, NA_integer_)", rex::rex("Prefer as.integer(x)"), linter) expect_lint("if_else(x > 5, 1L, 0L, 2L)", NULL, linter) expect_lint("if_else(x > 5, 1L, 0L, 5)", NULL, linter) expect_lint("if_else(x > 5, 1, 0, NA_real_)", rex::rex("Prefer as.numeric(x)"), linter) expect_lint("if_else(x > 5, 1, 0, 2)", NULL, linter) expect_lint("if_else(x > 5, 1, 0, '5')", NULL, linter) # TRUE/FALSE must be found in yes/no, not missing= expect_lint("if_else(x > 5, 'a', TRUE, FALSE)", NULL, linter) expect_lint("if_else(x > 5, 'a', 0L, 1L)", NULL, linter) expect_lint("if_else(x > 5, 'a', 1, 0)", NULL, linter) }) test_that("lints vectorize", { expect_lint( trim_some("{ ifelse(x > 0, TRUE, FALSE) fifelse(y == 0, 1, 0) }"), list( list("Just use the logical condition", line_number = 2L), list(rex::rex("refer as.numeric(x)"), line_number = 3L) ), redundant_ifelse_linter() ) }) lintr/tests/testthat/test-expect_identical_linter.R0000644000176200001440000000601514752731051022374 0ustar liggesuserstest_that("expect_identical_linter skips allowed usages", { linter <- expect_identical_linter() # expect_type doesn't have an inverted version expect_lint("expect_true(identical(x, y) || identical(y, z))", NULL, linter) # NB: also applies to tinytest, but it's sufficient to test testthat expect_lint("testthat::expect_true(identical(x, y) || identical(y, z))", NULL, linter) # expect_equal calls with explicit tolerance= are OK expect_lint("expect_equal(x, y, tolerance = 1e-6)", NULL, linter) # ditto if the argument is passed quoted expect_lint("expect_equal(x, y, 'tolerance' = 1e-6)", NULL, linter) # ditto for check.attributes = FALSE expect_lint("expect_equal(x, y, check.attributes = FALSE)", NULL, linter) }) test_that("expect_identical_linter blocks simple disallowed usages", { linter <- expect_identical_linter() lint_msg <- rex::rex("Use expect_identical(x, y) by default; resort to expect_equal() only when needed") expect_lint("expect_equal(x, y)", lint_msg, linter) # different usage to redirect to expect_identical expect_lint("expect_true(identical(x, y))", lint_msg, linter) }) test_that("expect_identical_linter skips cases likely testing numeric equality", { linter <- expect_identical_linter() lint_msg <- rex::rex("Use expect_identical(x, y) by default; resort to expect_equal() only when needed") expect_lint("expect_equal(x, 1.034)", NULL, linter) expect_lint("expect_equal(x, -1.034)", NULL, linter) expect_lint("expect_equal(x, c(-1.034))", NULL, linter) expect_lint("expect_equal(x, -c(1.034))", NULL, linter) expect_lint("expect_equal(x, c(1.01, 1.02))", NULL, linter) # whole numbers with explicit decimals are OK, even in mixed scenarios expect_lint("expect_equal(x, c(1.0, 2))", NULL, linter) # plain numbers are still caught, however expect_lint("expect_equal(x, 1L)", lint_msg, linter) expect_lint("expect_equal(x, 1)", lint_msg, linter) # NB: TRUE is a NUM_CONST so we want test matching it, even though this test is # also a violation of expect_true_false_linter() expect_lint("expect_equal(x, TRUE)", lint_msg, linter) expect_lint("expect_equal(x, 1.01 - y)", lint_msg, linter) expect_lint("expect_equal(x, foo() - 0.01)", lint_msg, linter) }) test_that("expect_identical_linter skips 3e cases needing expect_equal", { expect_lint("expect_equal(x, y, ignore_attr = 'names')", NULL, expect_identical_linter()) }) # this arose where a helper function was wrapping expect_equal() and # some of the "allowed" arguments were being passed --> false positive test_that("expect_identical_linter skips calls using ...", { expect_lint("expect_equal(x, y, ...)", NULL, expect_identical_linter()) }) test_that("lints vectorize", { lint_msg <- rex::rex("Use expect_identical(x, y) by default; resort to expect_equal() only when needed") expect_lint( trim_some("{ expect_equal(x, 1) expect_true(identical(x, y)) }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), expect_identical_linter() ) }) lintr/tests/testthat/test-function_return_linter.R0000644000176200001440000000352514752731051022317 0ustar liggesuserstest_that("function_return_linter skips allowed usages", { lines_simple <- trim_some(" foo <- function(x) { x <- x + 1 return(x) } ") expect_lint(lines_simple, NULL, function_return_linter()) # arguably an expression as complicated as this should also be assigned, # but for now that's out of the scope of this linter lines_subassignment <- trim_some(" foo <- function(x) { return(x[, { col <- col + 1 .(grp, col) }]) } ") expect_lint(lines_subassignment, NULL, function_return_linter()) }) test_that("function_return_linter blocks simple disallowed usages", { linter <- function_return_linter() lint_msg <- rex::rex("Move the assignment outside of the return() clause") expect_lint( trim_some(" foo <- function(x) { return(x <- x + 1) } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function(x) { return(x <<- x + 1) } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function(x) { return(x + 1 ->> x) } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function(x) { return(x + 1 -> x) } "), lint_msg, linter ) side_effect_lines <- expect_lint( trim_some(" e <- new.env() foo <- function(x) { return(e$val <- x + 1) } "), lint_msg, linter ) }) test_that("lints vectorize", { linter <- function_return_linter() lint_msg <- rex::rex("Move the assignment outside of the return() clause") expect_lint( trim_some("{ function() { return(x <- 1) } function() { return(y <- 2) } }"), list( list(lint_msg, line_number = 3L), list(lint_msg, line_number = 6L) ), function_return_linter() ) }) lintr/tests/testthat/test-pipe_consistency_linter.R0000644000176200001440000001035514752731051022450 0ustar liggesuserstest_that("pipe_consistency skips allowed usage", { skip_if_not_r_version("4.1.0") linter <- pipe_consistency_linter() expect_lint("1:3 %>% mean() %>% as.character()", NULL, linter) expect_lint("1:3 |> mean() |> as.character()", NULL, linter) # With no pipes expect_lint("x <- 1:5", NULL, linter) # Across multiple lines expect_lint( trim_some(" 1:3 %>% mean() %>% as.character() "), NULL, linter ) }) test_that("pipe_consistency lints inconsistent usage", { skip_if_not_r_version("4.1.0") linter <- pipe_consistency_linter() expected_msg <- rex::rex("Stick to one pipe operator; found 1 instances of %>% and 1 instances of |>.") expect_lint( "1:3 |> mean() %>% as.character()", list( list(message = expected_msg, line_number = 1L, column_number = 5L), list(message = expected_msg, line_number = 1L, column_number = 15L) ), linter ) expect_lint( "1:3 %>% mean() |> as.character()", list( list(message = expected_msg, line_number = 1L, column_number = 5L), list(message = expected_msg, line_number = 1L, column_number = 16L) ), linter ) expect_lint( trim_some(" 1:3 %>% mean() |> as.character() "), list( list(message = expected_msg, line_number = 1L, column_number = 5L), list(message = expected_msg, line_number = 2L, column_number = 10L) ), linter ) expected_msg_multi <- rex::rex("Stick to one pipe operator; found 1 instances of %>% and 2 instances of |>.") expect_lint( "1:3 |> sort() |> mean() %>% as.character()", list( list(message = expected_msg_multi, line_number = 1L, column_number = 5L), list(message = expected_msg_multi, line_number = 1L, column_number = 15L), list(message = expected_msg_multi, line_number = 1L, column_number = 25L) ), linter ) }) test_that("pipe_consistency_linter works with |> argument", { skip_if_not_r_version("4.1.0") linter <- pipe_consistency_linter(pipe = "|>") expected_message <- rex::rex("Use the |> pipe operator instead of the %>% pipe operator.") expect_lint( trim_some(" 1:3 %>% mean() %>% as.character() "), list( list(message = expected_message, line_number = 1L, column_number = 5L), list(message = expected_message, line_number = 2L, column_number = 10L) ), linter ) expect_lint( trim_some(" 1:3 |> mean() %>% as.character() "), list(message = expected_message, line_number = 2L, column_number = 10L), linter ) expect_lint( "1:3 |> mean() |> as.character()", NULL, linter ) expect_lint( trim_some(" 1:3 |> mean() %>% as.character() "), list(message = expected_message, line_number = 2L, column_number = 10L), linter ) }) test_that("pipe_consistency_linter works with %>% argument", { skip_if_not_r_version("4.1.0") linter <- pipe_consistency_linter(pipe = "%>%") expected_message <- rex::rex("Use the %>% pipe operator instead of the |> pipe operator.") expect_lint( "1:3 |> mean() |> as.character()", list( list(message = expected_message, line_number = 1L, column_number = 5L), list(message = expected_message, line_number = 1L, column_number = 15L) ), linter ) expect_lint( "1:3 %>% mean() |> as.character()", list(message = expected_message, line_number = 1L, column_number = 16L), linter ) expect_lint( "1:3 %>% mean() %>% as.character()", NULL, linter ) expect_lint( trim_some(" 1:3 %>% mean() |> as.character() "), list(message = expected_message, line_number = 2L, column_number = 10L), linter ) }) test_that("pipe_consistency_linter works with other magrittr pipes", { skip_if_not_r_version("4.1.0") linter <- pipe_consistency_linter() expected_message <- rex::rex("Stick to one pipe operator; found 1 instances of %>% and 1 instances of |>.") expect_lint("1:3 %>% mean() %T% print()", NULL, linter) expect_lint( "1:3 |> mean() %T>% print()", list( list(message = expected_message, line_number = 1L, column_number = 5L), list(message = expected_message, line_number = 1L, column_number = 15L) ), linter ) }) lintr/tests/testthat/test-string_boundary_linter.R0000644000176200001440000001501414752731051022300 0ustar liggesuserstest_that("string_boundary_linter skips allowed grepl() usages", { linter <- string_boundary_linter() # no known start/end anchor --> no lint expect_lint("grepl(p1, x)", NULL, linter) # no start/end anchor --> no lint expect_lint("grepl('abc', x)", NULL, linter) # regex pattern --> no lint expect_lint("grepl('^[a-z]', x)", NULL, linter) expect_lint("grepl('[a-z]$', x)", NULL, linter) # ignore.case --> no lint expect_lint("grepl('^abc', x, ignore.case = TRUE)", NULL, linter) expect_lint("grepl('^abc', x, ignore.case = ignore.case)", NULL, linter) # fixed --> no lint expect_lint("grepl('^abc', x, fixed = TRUE)", NULL, linter) expect_lint("grepl('^abc', x, fixed = fixed)", NULL, linter) }) test_that("string_boundary_linter skips allowed str_detect() usages", { linter <- string_boundary_linter() # no known start/end anchor --> no lint expect_lint("str_detect(x, p1)", NULL, linter) # no start/end anchor --> no lint expect_lint("str_detect(x, 'abc')", NULL, linter) # regex pattern --> no lint expect_lint("str_detect(x, '^[a-z]')", NULL, linter) expect_lint("str_detect(x, '[a-z]$')", NULL, linter) }) test_that("string_boundary_linter skips allowed substr()/substring() usages", { linter <- string_boundary_linter() # no comparison operator --> no lint expect_lint("substr(x, start, end)", NULL, linter) # unknown indices --> no lint expect_lint("substr(x, start, end) == 'a'", NULL, linter) expect_lint("substring(x, start, end) == 'a'", NULL, linter) # using foo(nchar(.)) expect_lint("substring(x, nchar(x) - 4, nchar(x) - 1) == 'abc'", NULL, linter) # using nchar(), but not of the input expect_lint("substring(x, nchar(y) - 4, nchar(y)) == 'abcd'", NULL, linter) # using x in nchar(), but on foo(input) expect_lint("substring(x, nchar(foo(x)) - 4, nchar(foo(x))) == 'abcd'", NULL, linter) # _close_ to equivalent, but not so in general -- e.g. # substring(s <- "abcdefg", 2L) == "efg" is not TRUE, but endsWith(s, "efg") # is. And if `s` contains strings of varying lengths, there's no equivalent. expect_lint("substring(x, 2L)", NULL, linter) }) test_that("string_boundary_linter blocks simple disallowed grepl() usages", { linter <- string_boundary_linter() starts_message <- rex::rex("Use !is.na(x) & startsWith(x, string) to detect a fixed initial substring,") ends_message <- rex::rex("Use !is.na(x) & endsWith(x, string) to detect a fixed terminal substring,") expect_lint("grepl('^a', x)", starts_message, linter) # non-trivially equivalent (but still same as startsWith()) expect_lint("grepl('^[.]', x)", starts_message, linter) expect_lint("grepl('a$', x)", ends_message, linter) # also get negation for free expect_lint("!grepl('a$', x)", ends_message, linter) # perl = TRUE doesn't matter expect_lint("grepl('^a', x, perl = TRUE)", starts_message, linter) # explicit FALSE (i.e., an explicit default) is ignored expect_lint("grepl('^a', x, fixed = FALSE)", starts_message, linter) expect_lint("grepl('^a', x, fixed = F)", starts_message, linter) }) test_that("string_boundary_linter blocks simple disallowed str_detect() usages", { linter <- string_boundary_linter() expect_lint( "str_detect(x, '^a')", rex::rex("Use startsWith() to detect a fixed initial substring."), linter ) expect_lint( "str_detect(x, 'a$')", rex::rex("Use endsWith() to detect a fixed terminal substring."), linter ) }) test_that("string_boundary_linter blocks disallowed substr()/substring() usage", { linter <- string_boundary_linter() starts_message <- rex::rex("Use startsWith() to detect an initial substring.") ends_message <- rex::rex("Use endsWith() to detect a terminal substring.") expect_lint("substr(x, 1L, 2L) == 'ab'", starts_message, linter) # end doesn't matter, just anchoring to 1L expect_lint("substr(x, 1L, end) == 'ab'", starts_message, linter) expect_lint("substring(x, nchar(x) - 4L, nchar(x)) == 'abcde'", ends_message, linter) # start doesn't matter, just anchoring to nchar(x) expect_lint("substring(x, start, nchar(x)) == 'abcde'", ends_message, linter) # more complicated expressions expect_lint("substring(colnames(x), start, nchar(colnames(x))) == 'abc'", ends_message, linter) }) test_that("plain ^ or $ are skipped", { linter <- string_boundary_linter() expect_lint('grepl("^", x)', NULL, linter) expect_lint('grepl("$", x)', NULL, linter) }) test_that("substr inverted tests are caught as well", { linter <- string_boundary_linter() expect_lint( "substr(x, 1L, 2L) != 'ab'", rex::rex("Use startsWith() to detect an initial substring."), linter ) expect_lint( "substring(x, nchar(x) - 4L, nchar(x)) != 'abcde'", rex::rex("Use endsWith() to detect a terminal substring."), linter ) }) test_that("R>=4 raw strings are detected", { linter <- string_boundary_linter() skip_if_not_r_version("4.0.0") expect_lint('grepl(R"(^.{3})", x)', NULL, linter) expect_lint( 'grepl(R"(^abc)", x)', rex::rex("Use !is.na(x) & startsWith(x, string) to detect a fixed initial substring,"), linter ) }) test_that("grepl() can optionally be ignored", { linter <- string_boundary_linter(allow_grepl = TRUE) expect_lint("grepl('^abc', x)", NULL, linter) expect_lint("grepl('xyz$', x)", NULL, linter) }) test_that("whole-string regex recommends ==, not {starts,ends}With()", { linter <- string_boundary_linter() lint_msg <- rex::rex("Use == to check for an exact string match.") expect_lint("grepl('^abc$', x)", lint_msg, linter) expect_lint("grepl('^a\\\\.b$', x)", lint_msg, linter) expect_lint("str_detect(x, '^abc$')", lint_msg, linter) expect_lint("str_detect(x, '^a[.]b$')", lint_msg, linter) }) test_that("vectorization + metadata work as intended", { expect_lint( trim_some("{ substring(a, 1, 3) == 'abc' substring(b, nchar(b) - 3, nchar(b)) == 'defg' substr(c, 1, 3) == 'hij' substr(d, nchar(d) - 3, nchar(d)) == 'klmn' grepl('^abc', e) grepl('abc$', f) grepl('^abc$', g) str_detect(h, '^abc') str_detect(i, 'abc$') str_detect(j, '^abc$') }"), list( list("startsWith", line_number = 2L), list("endsWith", line_number = 3L), list("startsWith", line_number = 4L), list("endsWith", line_number = 5L), list("startsWith", line_number = 6L), list("endsWith", line_number = 7L), list("==", line_number = 8L), list("startsWith", line_number = 9L), list("endsWith", line_number = 10L), list("==", line_number = 11L) ), string_boundary_linter() ) }) lintr/tests/testthat/helper.R0000644000176200001440000000532214752731051016015 0ustar liggesusers# Helpers for lintr tests single_quote <- function(x) paste0("'", x, "'") double_quote <- function(x) paste0('"', x, '"') #' Trim some leading whitespace #' #' Trim `num` characters from the start of every line in `x`, or auto-detect to remove the maximum number whitespace #' from all lines while preserving relative indentation #' #' @param x a string containing newlines #' @param num number of characters to strip from the start of each line. #' `NULL` will auto-detect this based on the minimum number of leading spaces greater than one. #' #' @return A modified version of `x` with `num` characters removed from the start of every line and with a possible #' leading and trailing blank line removed. #' #' @examples #' my_var <- local({ #' out <- trim_some(" #' This will be the content #' of the file where #' only the following line #' is indented by two spaces. #' ") #' }) #' #' stopifnot(identical( #' my_var, #' "This will be the content\nof the file where\nonly the following line\n is indented by two spaces." #' )) trim_some <- function(x, num = NULL) { x <- rex::re_substitutes( x, rex::rex(list(start, any_blanks, newline) %or% list(newline, any_blanks, end)), replacement = "", global = TRUE ) if (is.null(num)) { ms <- rex::re_matches(x, "^\\s+", locations = TRUE, global = TRUE, options = "multi-line")[[1L]] num <- min(ms$end - ms$start) + 1L } rex::re_substitutes(x, rex::rex(start, n_times(any, num)), "", global = TRUE, options = "multi-line") } local_config <- function(config_dir, contents, filename = ".lintr", .local_envir = parent.frame()) { config_path <- file.path(config_dir, filename) writeLines(contents, config_path) withr::defer(unlink(config_path), envir = .local_envir) config_path } skip_if_not_r_version <- function(min_version) { if (getRversion() < min_version) { testthat::skip(paste("R version at least", min_version, "is required")) } } skip_if_not_utf8_locale <- function() { testthat::skip_if_not(l10n_info()[["UTF-8"]], "Not a UTF-8 locale") } safe_load_help_db <- function() { help_db <- tryCatch(tools::Rd_db("lintr"), error = function(e) NULL) # e.g. in dev under pkgload::load_all() if (length(help_db) == 0L) { help_db <- tryCatch(tools::Rd_db(dir = testthat::test_path("..", "..")), error = function(e) NULL) testthat::skip_if_not(length(help_db) > 0L, message = "Package help corrupted or not installed") } help_db } pipes <- function(exclude = NULL) { if (getRversion() < "4.1.0") exclude <- unique(c(exclude, "|>")) all_pipes <- c( standard = "%>%", greedy = "%!>%", tee = "%T>%", assignment = "%<>%", extraction = "%$%", native = "|>" ) all_pipes[!all_pipes %in% exclude] } lintr/tests/testthat/test-T_and_F_symbol_linter.R0000644000176200001440000000350214752731051021745 0ustar liggesuserstest_that("T_and_F_symbol_linter skips allowed usages", { linter <- T_and_F_symbol_linter() expect_lint("FALSE", NULL, linter) expect_lint("TRUE", NULL, linter) expect_lint("x <- \"TRUE a vs FALSE b\"", NULL, linter) }) test_that("T_and_F_symbol_linter blocks disallowed usages", { linter <- T_and_F_symbol_linter() msg_true <- "Use TRUE instead of the symbol T." msg_false <- "Use FALSE instead of the symbol F." msg_variable_true <- "Don't use T as a variable name, as it can break code relying on T being TRUE." msg_variable_false <- "Don't use F as a variable name, as it can break code relying on F being FALSE." expect_lint("T", list(message = msg_true, line_number = 1L, column_number = 2L), linter) expect_lint("F", list(message = msg_false, line_number = 1L, column_number = 2L), linter) expect_lint("T = 42", list(message = msg_variable_true, line_number = 1L, column_number = 2L), linter) expect_lint("F = 42", list(message = msg_variable_false, line_number = 1L, column_number = 2L), linter) expect_lint( "for (i in 1:10) {x <- c(T, TRUE, F, FALSE)}", list( list(message = msg_true, line_number = 1L, column_number = 26L), list(message = msg_false, line_number = 1L, column_number = 35L) ), linter ) expect_lint("DF$bool <- T", msg_true, linter) expect_lint("S4@bool <- T", msg_true, linter) expect_lint("sum(x, na.rm = T)", msg_true, linter) # Regression test for #657 expect_lint( trim_some(" x <- list( T = 42L, F = 21L ) x$F <- 42L y@T <- 84L T <- \"foo\" F = \"foo2\" \"foo3\" -> T "), list( list(message = msg_variable_true, line_number = 9L), list(message = msg_variable_false, line_number = 10L), list(message = msg_variable_true, line_number = 11L) ), linter ) }) lintr/tests/testthat/test-object_length_linter.R0000644000176200001440000000442214752731051021677 0ustar liggesuserstest_that("returns the correct linting", { linter <- object_length_linter() lint_msg <- rex::rex("Variable and function names should not be longer than 30 characters.") expect_lint("blah", NULL, linter) expect_lint("very_very_very_very_long_variable_names_are_not_ideal <- 1", lint_msg, linter) expect_lint( "very_very_very_very_long_variable_names_are_not_ideal <<- 'foo'", rex::rex("Variable and function names should not be longer than 40 characters."), object_length_linter(length = 40L) ) }) # Regression tests for #871 test_that("lints S3 generics correctly", { linter <- object_length_linter() lint_msg <- rex::rex("Variable and function names should not be longer than 30 characters.") expect_lint("print.very_very_long_class_name <- 1", NULL, linter) expect_lint("print.very_very_very_very_long_class_name <- 1", lint_msg, linter) expect_lint( trim_some(" very_very_very_long_generic_name <- function(x, ...) { UseMethod(\"very_very_very_long_generic_name\") } very_very_very_long_generic_name.short_class <- function(x, ...) { 42L } very_very_very_long_generic_name.very_very_very_very_long_class_name <- function(x, ...) { 2L } "), list( list(line_number = 1L), list(line_number = 9L) ), linter ) }) test_that("object_length_linter won't fail if an imported namespace is unavailable", { expect_length( lint_package( test_path("dummy_packages", "missing_dep"), linters = object_length_linter(), parse_settings = FALSE ), 3L ) }) test_that("object_length_linter won't fail if dependency has no exports", { expect_length( lint_package( test_path("dummy_packages", "no_export_dep"), linters = object_length_linter(), parse_settings = FALSE ), 1L ) }) test_that("function shorthand is caught", { skip_if_not_r_version("4.1.0") expect_lint( "abcdefghijklm <- \\() NULL", "function names", object_length_linter(length = 10L) ) }) test_that("rlang name injection is handled", { linter <- object_length_linter(length = 10L) expect_lint("tibble('{foo() |> bar() |> baz()}' := TRUE)", NULL, linter) expect_lint("DT[, 'a_very_long_name' := FALSE]", "names should not be longer than 10 characters", linter) }) lintr/tests/testthat/test-paste_linter.R0000644000176200001440000002370414752731051020210 0ustar liggesuserstest_that("paste_linter skips allowed usages for sep=''", { linter <- paste_linter() expect_lint("paste('a', 'b', 'c')", NULL, linter) expect_lint("paste('a', 'b', 'c', sep = ',')", NULL, linter) expect_lint("paste('a', 'b', collapse = '')", NULL, linter) expect_lint("cat(paste('a', 'b'), sep = '')", NULL, linter) expect_lint("sep <- ''; paste('a', sep)", NULL, linter) expect_lint("paste(sep = ',', '', 'a')", NULL, linter) expect_lint("paste0('a', 'b', 'c')", NULL, linter) }) test_that("paste_linter blocks simple disallowed usages for sep=''", { expect_lint( "paste(sep = '', 'a', 'b')", rex::rex('paste0(...) is better than paste(..., sep = "").'), paste_linter() ) expect_lint( "paste('a', 'b', sep = '')", rex::rex('paste0(...) is better than paste(..., sep = "").'), paste_linter() ) }) test_that("paste_linter skips allowed usages for collapse=', '", { linter <- paste_linter() expect_lint("paste('a', 'b', 'c')", NULL, linter) expect_lint("paste(x, sep = ', ')", NULL, linter) expect_lint("paste(x, collapse = ',')", NULL, linter) expect_lint("paste(foo(x), collapse = '/')", NULL, linter) # harder to catch statically expect_lint("collapse <- ', '; paste(x, collapse = collapse)", NULL, linter) # paste(..., sep=sep, collapse=", ") is not a trivial swap to toString expect_lint("paste(x, y, sep = '.', collapse = ', ')", NULL, linter) # any call involving ...length() > 1 will implicitly use the default sep expect_lint("paste(x, y, collapse = ', ')", NULL, linter) expect_lint("paste0(x, y, collapse = ', ')", NULL, linter) expect_lint("toString(x)", NULL, linter) # string match of ", " is OK -- lint only _exact_ match expect_lint('paste(x, collapse = ", \n")', NULL, linter) }) test_that("paste_linter blocks simple disallowed usages for collapse=', '", { expect_lint( "paste(collapse = ', ', x)", rex::rex('toString(.) is more expressive than paste(., collapse = ", ")'), paste_linter() ) }) test_that("paste_linter respects non-default arguments", { expect_lint("paste(sep = '', 'a', 'b')", NULL, paste_linter(allow_empty_sep = TRUE)) expect_lint("paste('a', 'b', sep = '')", NULL, paste_linter(allow_empty_sep = TRUE)) expect_lint("paste(collapse = ', ', x)", NULL, paste_linter(allow_to_string = TRUE)) }) test_that("paste_linter works for raw strings", { skip_if_not_r_version("4.0.0") expect_lint("paste(a, b, sep = R'(xyz)')", NULL, paste_linter()) expect_lint( 'paste(a, b, sep = R"---[]---")', rex::rex('paste0(...) is better than paste(..., sep = "").'), paste_linter() ) expect_lint("paste(x, collapse = R'(,,)')", NULL, paste_linter()) expect_lint( 'paste(c(a, b, c), collapse = R"-{, }-")', rex::rex('toString(.) is more expressive than paste(., collapse = ", ")'), paste_linter() ) }) test_that("paste_linter catches use of paste0 with sep=", { expect_lint( "paste0(x, y, sep = '')", rex::rex("sep= is not a formal argument to paste0();"), paste_linter() ) }) test_that("paste_linter skips allowed usages for strrep()", { linter <- paste_linter() expect_lint("paste(x, collapse = '')", NULL, linter) expect_lint("paste(rep('*', 10), collapse = '+')", NULL, linter) expect_lint("paste(rep(c('a', 'b'), 2), collapse = '')", NULL, linter) expect_lint("paste0(rep('a', 2), 'b', collapse = '')", NULL, linter) # no collapse expect_lint("paste(rep('*', 10))", NULL, linter) # combined before aggregating expect_lint("paste(rep('*', 10), rep('x', 10), collapse = '')", NULL, linter) }) test_that("paste_linter blocks simple disallowed usages", { expect_lint( "paste(rep('#', width), collapse='')", rex::rex("strrep(x, times) is better than paste"), paste_linter() ) }) test_that("paste_linter skips allowed usages for file paths", { linter <- paste_linter() expect_lint("paste('a', 'b', 'c')", NULL, linter) expect_lint("paste('a', 'b', 'c', sep = ',')", NULL, linter) expect_lint("paste('a', 'b', collapse = '/')", NULL, linter) expect_lint("cat(paste('a', 'b'), sep = '/')", NULL, linter) expect_lint("sep <- '/'; paste('a', sep)", NULL, linter) expect_lint("paste(sep = ',', '/', 'a')", NULL, linter) # paste(..., sep='/', collapse=collapse) is not a trivial swap to file.path expect_lint("paste(x, y, sep = '/', collapse = ':')", NULL, linter) expect_lint("file.path('a', 'b', 'c')", NULL, linter) # testing the sep starts with / is not enough expect_lint("paste('a', 'b', sep = '//')", NULL, linter) }) test_that("paste_linter blocks simple disallowed usages for file paths", { linter <- paste_linter() lint_msg <- rex::rex("Construct file paths with file.path(...) instead of") expect_lint("paste(sep = '/', 'a', 'b')", lint_msg, linter) expect_lint("paste('a', 'b', sep = '/')", lint_msg, linter) }) test_that("paste_linter ignores non-path cases with paste0", { linter <- paste_linter() expect_lint("paste0(x, y)", NULL, linter) expect_lint("paste0('abc', 'def')", NULL, linter) expect_lint("paste0('/abc', 'def/')", NULL, linter) expect_lint("paste0(x, 'def/')", NULL, linter) expect_lint("paste0('/abc', y)", NULL, linter) expect_lint("paste0(foo(x), y)", NULL, linter) expect_lint("paste0(foo(x), 'def')", NULL, linter) # these might be a different lint (as.character instead, e.g.) but not here expect_lint("paste0(x)", NULL, linter) expect_lint("paste0('a')", NULL, linter) expect_lint("paste0('a', 1)", NULL, linter) }) test_that("paste_linter detects paths built with '/' and paste0", { linter <- paste_linter() lint_msg <- rex::rex("Construct file paths with file.path(...) instead of") expect_lint("paste0(x, '/', y)", lint_msg, linter) expect_lint("paste0(x, '/', y, '/', z)", lint_msg, linter) expect_lint("paste0(x, '/abc/', 'def/', y)", lint_msg, linter) expect_lint("paste0(foo(x), '/abc/', 'def/', bar(y))", lint_msg, linter) }) test_that("paste_linter skips initial/terminal '/' and repeated '/' for paths", { linter <- paste_linter() expect_lint("paste0('/', x)", NULL, linter) expect_lint("paste0(x, '/')", NULL, linter) expect_lint("paste0(x, '//hey/', y)", NULL, linter) expect_lint("paste0(x, '/hey//', y)", NULL, linter) }) test_that("paste_linter doesn't skip all initial/terminal '/' for paths", { linter <- paste_linter() lint_msg <- rex::rex("Construct file paths with file.path(...) instead of") expect_lint('paste0("/abc/", "def")', lint_msg, linter) expect_lint('paste0("abc/", "def/")', lint_msg, linter) }) test_that("multiple path lints are generated correctly", { linter <- paste_linter() expect_lint( trim_some("{ paste(x, y, sep = '/') paste0(x, '/', y) }"), list( rex::rex('paste(..., sep = "/")'), rex::rex('paste0(x, "/", y, "/", z)') ), linter ) # check vectorization of multiple paste0 file paths expect_lint( trim_some('{ paste0(x, y) paste0("a/", x, y, "/b") paste0("a", "b") paste0("a", x) paste0(a, "x") paste0("a/", NA_character_, "/b") paste0("a/", "b") paste0("a/", "bcd//efg", "/h") paste0("/", a) paste0(a, "/") }'), list(message = rex::rex("Construct file paths with file.path(...)"), line_number = 8L), linter ) }) test_that("allow_file_path argument works", { expect_lint("paste(x, y, sep = '/')", NULL, paste_linter(allow_file_path = "always")) }) test_that("URLs are ignored by default, linted optionally", { linter <- paste_linter() linter_url <- paste_linter(allow_file_path = "never") expect_lint("paste0('http://site.com/', x)", NULL, linter) expect_lint("paste0('http://site.com/', x)", rex::rex("Construct file paths with file.path(...)"), linter_url) }) test_that("raw strings are detected in file path logic", { skip_if_not_r_version("4.0.0") linter <- paste_linter() lint_msg <- rex::rex("Construct file paths with file.path(...) instead of ") expect_lint("paste0(x, R'{abc}', y)", NULL, linter) expect_lint("paste0(x, R'{/abc/}', y)", lint_msg, linter) expect_lint("paste(x, y, sep = R'{//}')", NULL, linter) expect_lint("paste(x, y, sep = R'{/}')", lint_msg, linter) }) test_that("paste0(collapse=...) is caught", { linter <- paste_linter() lint_msg <- rex::rex("Use paste(), not paste0(), to collapse a character vector when sep= is not used.") expect_lint("paste(x, collapse = '')", NULL, linter) expect_lint("paste0(a, b, collapse = '')", NULL, linter) # pass-through can pass any number of arguments expect_lint("paste0(..., collapse = '')", NULL, linter) expect_lint("paste0(x, collapse = '')", lint_msg, linter) expect_lint("paste0(x, collapse = 'xxx')", lint_msg, linter) expect_lint("paste0(foo(x, y, z), collapse = '')", lint_msg, linter) }) local({ linter <- paste_linter() lint_msg <- rex::rex("Use paste(), not paste0(), to collapse a character vector when sep= is not used.") pipes <- pipes() patrick::with_parameters_test_that( "paste0(collapse=...) is caught in pipes", { expect_lint(sprintf('x %s paste0(y, collapse = "")', pipe), NULL, linter) expect_lint(sprintf('x %s paste0(collapse = "")', pipe), lint_msg, linter) }, pipe = pipes, .test_name = pipes ) }) test_that("paste0(collapse=...) cases interacting with other rules are handled", { linter <- paste_linter() lint_msg <- rex::rex("Use paste(), not paste0(), to collapse a character vector when sep= is not used.") # multiple lints when collapse= happens to be ", " expect_lint( "paste0(foo(x), collapse = ', ')", list(rex::rex('toString(.) is more expressive than paste(., collapse = ", ")'), lint_msg), linter ) expect_lint("paste0(foo(x), collapse = ', ')", lint_msg, paste_linter(allow_to_string = TRUE)) expect_lint( "paste0(rep('*', 20L), collapse='')", list(rex::rex("strrep(x, times) is better than paste"), lint_msg), linter ) # paste0(..., collapse=collapse) not directly mapped to file.path expect_lint("paste0(x, collapse = '/')", lint_msg, linter) expect_lint("paste0(x, y, collapse = '/')", NULL, linter) }) lintr/tests/testthat/test-settings.R0000644000176200001440000002371414752731051017360 0ustar liggesuserstest_that("it uses default settings if none provided", { lintr:::read_settings(NULL) lapply(ls(settings), function(setting) { expect_identical(settings[[setting]], default_settings[[setting]]) }) }) test_that("it uses option settings if provided", { withr::local_options(list(lintr.exclude = "test")) lintr:::read_settings(NULL) expect_identical(settings$exclude, "test") }) test_that("it uses config settings in same directory if provided", { test_dir <- tempdir() file <- withr::local_tempfile(tmpdir = test_dir) local_config(test_dir, 'exclude: "test"') lintr:::read_settings(file) lapply(setdiff(ls(settings), "exclude"), function(setting) { expect_identical(settings[[setting]], default_settings[[setting]]) }) expect_identical(settings$exclude, "test") }) test_that("it uses config home directory settings if provided", { path <- withr::local_tempdir() home_path <- withr::local_tempdir() file <- withr::local_tempfile(tmpdir = path) local_config(home_path, 'exclude: "test"') withr::with_envvar(c(HOME = home_path), lintr:::read_settings(file)) lapply(setdiff(ls(settings), "exclude"), function(setting) { expect_identical(settings[[setting]], default_settings[[setting]]) }) expect_identical(settings$exclude, "test") }) test_that("it uses system config directory settings if provided", { path <- withr::local_tempdir() config_parent_path <- withr::local_tempdir("config") config_path <- file.path(config_parent_path, "R", "lintr") dir.create(config_path, recursive = TRUE) file <- withr::local_tempfile(tmpdir = path) local_config(config_path, 'exclude: "test"', filename = "config") withr::with_envvar(c(R_USER_CONFIG_DIR = config_parent_path), lintr:::read_settings(file)) lapply(setdiff(ls(settings), "exclude"), function(setting) { expect_identical(settings[[setting]], default_settings[[setting]]) }) expect_identical(settings$exclude, "test") }) test_that("read_config_file() warns if the config file does not end in a newline", { .lintr <- withr::local_tempfile() withr::local_options(lintr.linter_file = .lintr) withr::local_dir(withr::local_tempdir()) # cat() not writeLines() to ensure no trailing \n cat("linters: linters_with_defaults(brace_linter = NULL)", file = .lintr) writeLines("a <- 1", "aaa.R") expect_warning(lint_dir(), "Warning encountered while loading config", fixed = TRUE) }) test_that("it gives informative errors if the config file contains errors", { .lintr <- withr::local_tempfile(lines = c( "linters: linters_with_defaults(", " brace_linter = NULL,", " )" )) withr::local_options(lintr.linter_file = .lintr) withr::local_dir(withr::local_tempdir()) writeLines("a <- 1", "aaa.R") expect_error(lint_dir(), "Error from config setting `linters`", fixed = TRUE) }) test_that("rot utility works as intended", { expect_identical(lintr:::rot(letters), c(letters[14L:26L], LETTERS[1L:13L])) }) # fixing #774 test_that("linters_with_defaults doesn't break on very long input", { expect_named( linters_with_defaults( defaults = list(), lintr::undesirable_function_linter(c( detach = paste( "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ) )) ), "undesirable_function_linter" ) }) test_that("it has a smart default for encodings", { lintr:::read_settings(NULL) expect_identical(settings$encoding, "UTF-8") proj_file <- test_path("dummy_projects", "project", "cp1252.R") pkg_file <- test_path("dummy_packages", "cp1252", "R", "cp1252.R") expect_identical( normalize_path(find_rproj_at(find_package(proj_file, allow_rproj = TRUE))), normalize_path(test_path("dummy_projects", "project", "project.Rproj")) ) expect_identical( normalize_path(find_package(pkg_file)), normalize_path(test_path("dummy_packages", "cp1252")) ) expect_identical(lintr:::find_default_encoding(proj_file), "ISO8859-1") expect_identical(lintr:::find_default_encoding(pkg_file), "ISO8859-1") lintr:::read_settings(proj_file) expect_identical(settings$encoding, "ISO8859-1") lintr:::read_settings(pkg_file) expect_identical(settings$encoding, "ISO8859-1") }) test_that("validate_config_file() detects improperly-formed settings", { .lintr <- withr::local_tempfile() withr::local_options(lintr.linter_file = .lintr) withr::local_dir(withr::local_tempdir()) writeLines("asdf: 1", .lintr) expect_warning(lint_dir(), "Found unused settings in config", fixed = TRUE) writeLines("a=1", "aaa.R") writeLines(c('exclusions: list("aaa.R")', "asdf: 1"), .lintr) expect_warning(lint_dir(), "Found unused settings in config", fixed = TRUE) encoding_error_msg <- "Setting `encoding` should be a character string" writeLines("encoding: FALSE", .lintr) expect_error(lint_dir(), encoding_error_msg, fixed = TRUE) writeLines("encoding: NA_character_", .lintr) expect_error(lint_dir(), encoding_error_msg, fixed = TRUE) writeLines('encoding: c("a", "b")', .lintr) expect_error(lint_dir(), encoding_error_msg, fixed = TRUE) exclude_error_msg <- "Setting `exclude` should be a single regular expression" writeLines("exclude: FALSE", .lintr) expect_error(lint_dir(), exclude_error_msg, fixed = TRUE) writeLines(c('exclusions: list("aaa.R")', "exclude: FALSE"), .lintr) expect_error(lint_dir(), exclude_error_msg, fixed = TRUE) writeLines('exclude: "("', .lintr) expect_error(lint_dir(), exclude_error_msg, fixed = TRUE) writeLines("linters: list(1)", .lintr) expect_error(lint_dir(), "Setting `linters` should be a list of linters", fixed = TRUE) writeLines("linters: list(assignment_linter(), 1)", .lintr) expect_error(lint_dir(), "Setting `linters` should be a list of linters", fixed = TRUE) name_exclusion_error_msg <- "Unnamed entries of setting `exclusions` should be strings" writeLines("exclusions: list(1L)", .lintr) expect_error(lint_dir(), name_exclusion_error_msg, fixed = TRUE) writeLines('exclusions: list("aaa.R", 1L)', .lintr) expect_error(lint_dir(), name_exclusion_error_msg, fixed = TRUE) writeLines("exclusions: list(letters)", .lintr) expect_error(lint_dir(), name_exclusion_error_msg, fixed = TRUE) writeLines("exclusions: list(NA_character_)", .lintr) expect_error(lint_dir(), name_exclusion_error_msg, fixed = TRUE) exclusion_error_msg <- "Named entries of setting `exclusions` should designate line numbers" writeLines('exclusions: list(aaa.R = "abc")', .lintr) expect_error(lint_dir(), exclusion_error_msg, fixed = TRUE) writeLines("exclusions: list(aaa.R = NA_integer_)", .lintr) expect_error(lint_dir(), exclusion_error_msg, fixed = TRUE) writeLines('exclusions: list(aaa.R = list("abc"))', .lintr) expect_error(lint_dir(), exclusion_error_msg, fixed = TRUE) writeLines("exclusions: list(aaa.R = list(NA_integer_))", .lintr) expect_error(lint_dir(), exclusion_error_msg, fixed = TRUE) writeLines('exclusions: list(aaa.R = list(assignment_linter = "abc"))', .lintr) expect_error(lint_dir(), exclusion_error_msg, fixed = TRUE) writeLines("exclusions: list(aaa.R = list(assignment_linter = NA_integer_))", .lintr) expect_error(lint_dir(), exclusion_error_msg, fixed = TRUE) }) test_that("exclusions can be a character vector", { withr::local_dir(withr::local_tempdir()) # exclusions are relative to dirname(.lintr), so must create it here .lintr <- withr::local_tempfile(tmpdir = getwd()) withr::local_options(lintr.linter_file = .lintr) writeLines('exclusions: "aaa.R"', .lintr) writeLines("a<-1", "aaa.R") writeLines("b<-1", "bbb.R") expect_length(lint_dir(linters = infix_spaces_linter()), 1L) writeLines('exclusions: c("aaa.R", "bbb.R")', .lintr) expect_length(lint_dir(linters = infix_spaces_linter()), 0L) }) test_that("lines Inf means 'all lines'", { withr::local_dir(withr::local_tempdir()) # exclusions are relative to dirname(.lintr), so must create it here .lintr <- withr::local_tempfile(tmpdir = getwd()) withr::local_options(lintr.linter_file = .lintr) writeLines("exclusions: list(aaa.R = Inf)", .lintr) writeLines("a<-1", "aaa.R") expect_length(lint_dir(linters = infix_spaces_linter()), 0L) writeLines("exclusions: list(aaa.R = list(infix_spaces_linter = Inf))", .lintr) # exclude infix_spaces_linter, include assignment_linter() writeLines("a=1", "aaa.R") expect_length(lint_dir(linters = list(assignment_linter(), infix_spaces_linter())), 1L) }) test_that("read_config_file() bubbles up warnings helpfully, without erroring (#2253)", { .lintr <- withr::local_tempfile(lines = 'linters: list(backport_linter("2.0.0"))') withr::local_options(lintr.linter_file = .lintr) withr::local_dir(withr::local_tempdir()) writeLines("a <- 1", "aaa.R") expect_warning( lint_dir(), 'Depending on an R version older than "3.0.0" is not recommended' ) }) test_that("perl-only regular expressions are accepted in config", { .lintr <- withr::local_tempfile(lines = 'exclude: "# (?<=a)b"') withr::local_options(lintr.linter_file = .lintr) withr::local_dir(withr::local_tempdir()) writeLines("a <- 1", "aaa.R") expect_silent(lint("aaa.R")) }) test_that("settings can be put in a sub-directory", { withr::local_dir(withr::local_tempdir()) dir.create(".settings") .lintr <- ".settings/.lintr.R" writeLines("linters <- list(line_length_linter(10L))", .lintr) dir.create("R") writeLines("abcdefghijklmnopqrstuvwxyz=1", "R/a.R") writeLines(c("Package: foo", "Version: 0.1"), "DESCRIPTION") withr::local_options(lintr.linter_file = .lintr) expect_length(lint_package(), 1L) }) lintr/tests/testthat/test-cyclocomp_linter.R0000644000176200001440000000225514752731051021062 0ustar liggesuserstest_that("returns the correct linting", { skip_if_not_installed("cyclocomp") cc_linter_1 <- cyclocomp_linter(1L) cc_linter_2 <- cyclocomp_linter(2L) lint_msg <- rex::rex("Reduce the cyclomatic complexity of this function") expect_lint("if (TRUE) 1 else 2", NULL, cc_linter_2) expect_lint("if (TRUE) 1 else 2", lint_msg, cc_linter_1) expect_lint( "function(x) {not parsing}", "unexpected symbol", cc_linter_2 ) complex_lines <- trim_some(" complexity <- function(x) { if (x > 0.0) { if (x > 10.0) { if (x > 20.0) { x <- x / 2.0 } else { return(x) } } else { return(x) } } else { if (x < -10.0) { if (x < -20.0) { x <- x * 2.0 } else { return(x) } } else { return(x) } } x } ") expect_lint(complex_lines, lint_msg, cc_linter_2) expect_lint( complex_lines, list(rex::rex("Reduce the cyclomatic complexity of this function from 10 to at most 2."), line_number = 1L), cc_linter_2 ) expect_lint(complex_lines, NULL, cyclocomp_linter(10L)) }) lintr/tests/testthat/test-unnecessary_concatenation_linter.R0000644000176200001440000000764314752731051024344 0ustar liggesuserstest_that("unnecessary_concatenation_linter skips allowed usages", { linter <- unnecessary_concatenation_linter() expect_lint("c(x)", NULL, linter) expect_lint("c(1, 2)", NULL, linter) expect_lint("c(x, recursive = TRUE)", NULL, linter) expect_lint("c(1, recursive = FALSE)", NULL, linter) expect_lint("lapply(1, c)", NULL, linter) expect_lint("c(a = 1)", NULL, linter) expect_lint("c('a' = 1)", NULL, linter) }) test_that("unnecessary_concatenation_linter blocks disallowed usages", { linter <- unnecessary_concatenation_linter() msg_c <- rex::rex("Remove unnecessary c() of a constant.") msg_e <- rex::rex("Replace unnecessary c() by NULL or, whenever possible, vector()") expect_lint( "c()", list(message = msg_e, line_number = 1L, column_number = 1L), linter ) expect_lint( "c(NULL)", list(message = msg_c, line_number = 1L, column_number = 1L), linter ) expect_lint( "c(1)", list(message = msg_c, line_number = 1L, column_number = 1L), linter ) expect_lint( "c (\n'a' )", list(message = msg_c, line_number = 1L, column_number = 1L), linter ) expect_lint( "c(y, c('c('),\nc())", list( list(message = msg_c, line_number = 1L, column_number = 6L), list(message = msg_e, line_number = 2L, column_number = 1L) ), linter ) }) local({ pipes <- pipes(exclude = "%$%") linter <- unnecessary_concatenation_linter() const_msg <- rex::rex("Remove unnecessary c() of a constant.") no_arg_msg <- rex::rex("Replace unnecessary c() by NULL or, whenever possible, vector()") patrick::with_parameters_test_that( "Correctly handles concatenation within magrittr pipes", { expect_lint(sprintf('"a" %s c("b")', pipe), NULL, linter) expect_lint(sprintf('"a" %s c()', pipe), const_msg, linter) expect_lint(sprintf('"a" %s list("b", c())', pipe), no_arg_msg, linter) }, pipe = pipes, .test_name = names(pipes) ) }) test_that("symbolic expressions are allowed, except by request", { linter <- unnecessary_concatenation_linter() linter_strict <- unnecessary_concatenation_linter(allow_single_expression = FALSE) lint_msg <- rex::rex("Remove unnecessary c() of a constant expression.") expect_lint("c(alpha / 2)", NULL, linter) expect_lint("c(paste0('.', 1:2))", NULL, linter) expect_lint("c(DF[cond > 1, col])", NULL, linter) # allow_single_expression = FALSE turns both into lints expect_lint("c(alpha / 2)", lint_msg, linter_strict) expect_lint("c(paste0('.', 1:2))", lint_msg, linter_strict) expect_lint("c(DF[cond > 1, col])", lint_msg, linter_strict) }) test_that("sequences with : are linted whenever a constant is involved", { linter <- unnecessary_concatenation_linter() linter_strict <- unnecessary_concatenation_linter(allow_single_expression = FALSE) const_msg <- rex::rex("Remove unnecessary c() of a constant.") expr_msg <- rex::rex("Remove unnecessary c() of a constant expression.") expect_lint("c(1:10)", const_msg, linter) expect_lint("c(1:sum(x))", const_msg, linter) # this is slightly different if a,b are factors, in which case : does # something like interaction expect_lint("c(a:b)", NULL, linter) expect_lint("c(a:b)", expr_msg, linter_strict) expect_lint("c(a:foo(b))", NULL, linter) expect_lint("c(a:foo(b))", expr_msg, linter_strict) }) test_that("c(...) does not lint under !allow_single_expression", { expect_lint("c(...)", NULL, unnecessary_concatenation_linter(allow_single_expression = FALSE)) }) test_that("invalid allow_single_expression argument produce informative error messages", { expect_error( expect_lint("c()", NULL, unnecessary_concatenation_linter(allow_single_expression = 1.0)), rex::rex("is.logical(allow_single_expression) is not TRUE") ) expect_error( expect_lint("c()", NULL, unnecessary_concatenation_linter(allow_single_expression = c(TRUE, FALSE))), rex::rex("length(allow_single_expression) == 1L is not TRUE") ) }) lintr/tests/testthat/default_linter_testcode.R0000644000176200001440000000174414752731051021435 0ustar liggesusers# Each of the default linters should throw at least one lint on this file # assignment # function_left_parentheses # brace_linter # commas # paren_brace f = function (x,y = 1){} # return_linter g <- function(x) { return(x + 1) } # commented_code # some <- commented("out code") # equals_na # brace_linter # indentation # infix_spaces # line_length # object_length # object_name # object_usage # open_curly # T_and_F_symbol someComplicatedFunctionWithALongCamelCaseName <- function(x) { y <- 1 if (1 > 2 && 2 > 3 && 3 > 4 && 4 > 5 && 5*10 > 6 && 5 > 6 && 6 > 7 && x == NA) {T} else F } # vector_logic if (1 & 2) FALSE else TRUE # function_brace my_metric <- function(x) sum(x) + prod(x) # no_tab # pipe_continuation # seq_linter # spaces_inside # indentation x <- 1:10 x[ 2] 1:length(x) %>% lapply(function(x) x*2) %>% head() # single_quotes message('single_quotes') # spaces_left_parentheses # trailing_whitespace # semicolon x <- 42; y <- 2 +(1:10) # trailing_blank_lines lintr/tests/testthat/test-if_not_else_linter.R0000644000176200001440000000527314752731051021363 0ustar liggesuserstest_that("if_not_else_linter skips allowed usages", { linter <- if_not_else_linter() # simple if/else statement is fine expect_lint("if (A) x else y", NULL, linter) # not plain negation --> OK expect_lint("if (!A || B) x else y", NULL, linter) # no else clause --> OK expect_lint("if (!A) x", NULL, linter) # nested statements are also OK expect_lint("if (!A) x else if (B) y", NULL, linter) expect_lint("if (!A) x else if (B) y else z", NULL, linter) expect_lint("if (A) x else if (B) y else if (!C) z", NULL, linter) # ! picked up in the evaluation statements is skipped expect_lint("if (A) !x else y", NULL, linter) expect_lint("if (A) x else !y", NULL, linter) }) test_that("if_not_else_linter blocks simple disallowed usages", { linter <- if_not_else_linter() lint_msg <- rex::rex("Prefer `if (A) x else y`") expect_lint("if (!A) x else y", lint_msg, linter) expect_lint("if (!A) x else if (!B) y else z", lint_msg, linter) # ditto for more complicated expressions where ! is still the outer operator expect_lint("if (!x %in% 1:10) y else z", lint_msg, linter) }) patrick::with_parameters_test_that( "if_not_else_linter blocks usages in ifelse() and friends as well", { linter <- if_not_else_linter() expect_lint(sprintf("%s(!A | B, x, y)", ifelse_fun), NULL, linter) expect_lint(sprintf("%s(A, !x, y)", ifelse_fun), NULL, linter) expect_lint( sprintf("%s(!A, x, y)", ifelse_fun), sprintf("Prefer `%s[(]A, x, y[)]` to the less-readable", ifelse_fun), linter ) # particularly relevant for if_else() expect_lint(sprintf("%s(!!A, x, y)", ifelse_fun), NULL, linter) }, .test_name = c("ifelse", "fifelse", "if_else"), ifelse_fun = c("ifelse", "fifelse", "if_else") ) test_that("if_not_else_linter skips negated calls to is.null & similar", { linter <- if_not_else_linter() expect_lint("if (!is.null(x)) x else y", NULL, linter) expect_lint("if (!is.na(x)) x else y", NULL, linter) expect_lint("if (!missing(x)) x else y", NULL, linter) expect_lint("ifelse(!is.na(x), x, y)", NULL, linter) }) test_that("multiple lints are generated correctly", { expect_lint( trim_some("{ if (!A) x else B ifelse(!A, x, y) fifelse(!A, x, y) if_else(!A, x, y) }"), list( rex::rex("Prefer `if (A) x else y`"), "Prefer `ifelse", "Prefer `fifelse", "Prefer `if_else" ), if_not_else_linter() ) }) test_that("exceptions= argument works", { expect_lint( "if (!is.null(x)) x else y", rex::rex("Prefer `if (A) x else y`"), if_not_else_linter(exceptions = character()) ) expect_lint("if (!foo(x)) y else z", NULL, if_not_else_linter(exceptions = "foo")) }) lintr/tests/testthat/dummy_packages/0000755000176200001440000000000014752731051017402 5ustar liggesuserslintr/tests/testthat/dummy_packages/RConfig/0000755000176200001440000000000014752731051020731 5ustar liggesuserslintr/tests/testthat/dummy_packages/RConfig/tests/0000755000176200001440000000000014752731051022073 5ustar liggesuserslintr/tests/testthat/dummy_packages/RConfig/tests/testthat.R0000644000176200001440000000044614752731051024062 0ustar liggesusers# This file is in 'exclusions' & nothing lints under R config. # Under DCF config, '# SKIP_LINT' is the exclusion & this line won't lint 1+1 # SKIP_LINT # This is included as a linter in the DCF, thus this should lint expect_equal(foo(x), NULL) # trailing blank line next will lint under DCF lintr/tests/testthat/dummy_packages/RConfig/lintr_test_config_extraneous.R0000644000176200001440000000055514752731051027052 0ustar liggesusers# here are some extraneous variables that are not part of the config directly non_default_linter <- any_duplicated_linter() attr(non_default_linter, "name") <- "any_duplicated_linter" excluded_files <- "tests/testthat.R" linters <- linters_with_defaults( non_default_linter, assignment_linter = NULL ) exclude <- "# NOLINT" exclusions <- list(excluded_files) lintr/tests/testthat/dummy_packages/RConfig/R/0000755000176200001440000000000014752731051021132 5ustar liggesuserslintr/tests/testthat/dummy_packages/RConfig/R/lint_me.R0000644000176200001440000000045414752731051022707 0ustar liggesusers# config excludes assignment_linter() so this doesn't lint a = 1 # default config includes infix_spaces_linter() so this lints b=a + 2 # config extends defaults with any_duplicated_linter() so this lints any(duplicated(b)) # custom exclude setting is also picked up so this doesn't lint 1+1 # NOLINT lintr/tests/testthat/dummy_packages/RConfig/lintr_test_config.R0000644000176200001440000000022714752731051024571 0ustar liggesuserslinters <- linters_with_defaults( any_duplicated_linter(), assignment_linter = NULL ) exclude <- "# NOLINT" exclusions <- list("tests/testthat.R") lintr/tests/testthat/dummy_packages/RConfig/lintr_test_config_conflict0000644000176200001440000000022714752731051026252 0ustar liggesuserslinters: linters_with_defaults( any_duplicated_linter(), assignment_linter = NULL ) exclude: "# NOLINT" exclusions: list("tests/testthat.R") lintr/tests/testthat/dummy_packages/RConfig/lintr_test_config_conflict.R0000644000176200001440000000022214752731051026445 0ustar liggesuserslinters <- linters_with_defaults( expect_null_linter(), assignment_linter = NULL ) exclude <- "# SKIP_LINT" exclusions <- list("R/lint_me.R") lintr/tests/testthat/dummy_packages/RConfig/DESCRIPTION0000644000176200001440000000004114752731051022432 0ustar liggesusersPackage: RConfig Version: 0.0.1 lintr/tests/testthat/dummy_packages/package/0000755000176200001440000000000014752763366021013 5ustar liggesuserslintr/tests/testthat/dummy_packages/package/R/0000755000176200001440000000000014752731051021176 5ustar liggesuserslintr/tests/testthat/dummy_packages/package/R/default_linter_testcode.R0000644000176200001440000000144614752731051026221 0ustar liggesusers# Each of the default linters should throw at least one lint on this file # assignment # function_left_parentheses # closed_curly # commas # paren_brace f = function (x,y = 1){} # commented_code # some <- commented("out code") # cyclocomp # equals_na # infix_spaces # line_length # object_length # object_name # object_usage # open_curly # T_and_F_symbol someComplicatedFunctionWithALongCamelCaseName <- function(x) { y <- 1 if (1 > 2 && 2 > 3 && 3 > 4 && 4 > 5 && 5*10 > 6 && 5 > 6 && 6 > 7 && x == NA) {T} else {F} } # no_tab # pipe_continuation # seq_linter # spaces_inside x <- 1:10 x[ 2] 1:length(x) %>% lapply(function(x) x*2) %>% head() # single_quotes message('single_quotes') # spaces_left_parentheses # trailing_whitespace # semicolon x <- 42; y <- 2 +(1:10) # trailing_blank_lines lintr/tests/testthat/dummy_packages/package/exec/0000755000176200001440000000000014752731051021721 5ustar liggesuserslintr/tests/testthat/dummy_packages/package/exec/script.R0000644000176200001440000000024214752731051023346 0ustar liggesusers# Each of the default linters should throw at least one lint for assignment_linter or object_name_linter on this file x = 1:4 res <- lapply(x, function(y) y + 1) lintr/tests/testthat/dummy_packages/package/lintr_test_config0000644000176200001440000000004114752731051024427 0ustar liggesuserslinters: linters_with_defaults() lintr/tests/testthat/dummy_packages/package/vignettes/0000755000176200001440000000000014752731051023005 5ustar liggesuserslintr/tests/testthat/dummy_packages/package/vignettes/test.Rhtml0000644000176200001440000000154014752731051024774 0ustar liggesusers Test

Test

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

Test

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. lintr/tests/testthat/dummy_packages/package/vignettes/test.Qmd0000644000176200001440000000262114752731051024430 0ustar liggesusers# Test # Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} a = 1 ``` Test ==== Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} b <- function(x) { d = 1 } ``` ```{r engine="python"} a=[] a[0]=1 ``` ``` Plain code blocks can be written after three or more backticks - R Markdown: The Definitive Guide. Xie, Allaire and Grolemund (2.5.2) ``` ```r # This is a non-evaluated block of R code for formatting in markdown. # It should not be linted abc = 123 ``` ```cpp // Some C++ code for formatting by markdown ``` Calls to a non-R knitr-engine using {engine_name} syntax. ```{python} # Python that looks like R a = list() b = {2} print(a) ``` ```{python} # Python that's definitely not R a = [] a.append(2) print(a) ``` The following are only supported by Quarto and shouldn't lint either. ```{.r} 1+1 ``` ```{{r}} 1+1 ``` ```{.python} # Python that's definitely not R a = [] a.append(2) print(a) ``` lintr/tests/testthat/dummy_packages/package/vignettes/test.Rrst0000644000176200001440000000134014752731051024636 0ustar liggesusersTest ==== Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. .. {r rst-example} a = 1 .. .. Test ---- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. .. {r} b <- function(x) { d = 1 } .. .. .. {r engine = "python"} a=[] a[0]=1 .. .. lintr/tests/testthat/dummy_packages/package/vignettes/test.Rnw0000644000176200001440000000142514752731051024456 0ustar liggesusers\documentclass{article} \usepackage{mathpazo} \begin{document} \title{Test} Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. <>= a = 1 @ \subtitle{Test} Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. <<>>= b <- function(x) { d = 1 } @ <>= a=[] a[0]=1 @ lintr/tests/testthat/dummy_packages/package/vignettes/test.Rtxt0000644000176200001440000000140114752731051024643 0ustar liggesusers= Test = Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. //begin.rcode a = 1 //end.rcode Test ==== Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. //begin.rcode trailing b <- function(x) { d = 1 } //end.rcode //begin.rcode engine="python" a=[] a[0]=1 //end.rcode lintr/tests/testthat/dummy_packages/package/vignettes/test.Rtex0000644000176200001440000000151714752731051024634 0ustar liggesusers\documentclass{article} \usepackage{graphicx} \title{Test} Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. %% begin.rcode % a = 1 %% end.rcode \subtitle{Test} Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. %% begin.rcode test_chunk % b <- function(x) { % d = 1 % } % %% end.rcode %% begin.rcode engine="python" % a=[] % % a[0]=1 %% end.rcode lintr/tests/testthat/dummy_packages/package/vignettes/test.Rmd0000644000176200001440000000205314752731051024430 0ustar liggesusers# Test # Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} a = 1 ``` Test ==== Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} b <- function(x) { d = 1 } ``` ```{r engine="python"} a=[] a[0]=1 ``` ``` Plain code blocks can be written after three or more backticks - R Markdown: The Definitive Guide. Xie, Allaire and Grolemund (2.5.2) ``` Calls to a non-R knitr-engine using {engine_name} syntax. ```{python} # Python that looks like R a = list() b = {2} print(a) ``` ```{python} # Python that's definitely not R a = [] a.append(2) print(a) ``` lintr/tests/testthat/dummy_packages/package/NAMESPACE0000644000176200001440000000015614752731051022216 0ustar liggesusers# Generated by roxygen2: fake comment so roxygen2 overwrites silently. exportPattern("^[^\\.]") import(lintr) lintr/tests/testthat/dummy_packages/package/package.Rproj0000644000176200001440000000047014752731051023407 0ustar liggesusersVersion: 1.0 RestoreWorkspace: No SaveWorkspace: No AlwaysSaveHistory: Default EnableCodeIndexing: Yes Encoding: UTF-8 AutoAppendNewline: Yes StripTrailingWhitespace: Yes BuildType: Package PackageUseDevtools: Yes PackageInstallArgs: --no-multiarch --with-keep.source PackageRoxygenize: rd,collate,namespace lintr/tests/testthat/dummy_packages/package/data-raw/0000755000176200001440000000000014752731051022475 5ustar liggesuserslintr/tests/testthat/dummy_packages/package/data-raw/default_linter_testcode.R0000644000176200001440000000144614752731051027520 0ustar liggesusers# Each of the default linters should throw at least one lint on this file # assignment # function_left_parentheses # closed_curly # commas # paren_brace f = function (x,y = 1){} # commented_code # some <- commented("out code") # cyclocomp # equals_na # infix_spaces # line_length # object_length # object_name # object_usage # open_curly # T_and_F_symbol someComplicatedFunctionWithALongCamelCaseName <- function(x) { y <- 1 if (1 > 2 && 2 > 3 && 3 > 4 && 4 > 5 && 5*10 > 6 && 5 > 6 && 6 > 7 && x == NA) {T} else {F} } # no_tab # pipe_continuation # seq_linter # spaces_inside x <- 1:10 x[ 2] 1:length(x) %>% lapply(function(x) x*2) %>% head() # single_quotes message('single_quotes') # spaces_left_parentheses # trailing_whitespace # semicolon x <- 42; y <- 2 +(1:10) # trailing_blank_lines lintr/tests/testthat/dummy_packages/package/inst/0000755000176200001440000000000014752731051021752 5ustar liggesuserslintr/tests/testthat/dummy_packages/package/inst/data-raw/0000755000176200001440000000000014752731051023452 5ustar liggesuserslintr/tests/testthat/dummy_packages/package/inst/data-raw/default_linter_testcode.R0000644000176200001440000000144614752731051030475 0ustar liggesusers# Each of the default linters should throw at least one lint on this file # assignment # function_left_parentheses # closed_curly # commas # paren_brace f = function (x,y = 1){} # commented_code # some <- commented("out code") # cyclocomp # equals_na # infix_spaces # line_length # object_length # object_name # object_usage # open_curly # T_and_F_symbol someComplicatedFunctionWithALongCamelCaseName <- function(x) { y <- 1 if (1 > 2 && 2 > 3 && 3 > 4 && 4 > 5 && 5*10 > 6 && 5 > 6 && 6 > 7 && x == NA) {T} else {F} } # no_tab # pipe_continuation # seq_linter # spaces_inside x <- 1:10 x[ 2] 1:length(x) %>% lapply(function(x) x*2) %>% head() # single_quotes message('single_quotes') # spaces_left_parentheses # trailing_whitespace # semicolon x <- 42; y <- 2 +(1:10) # trailing_blank_lines lintr/tests/testthat/dummy_packages/package/DESCRIPTION0000644000176200001440000000067514752731051022513 0ustar liggesusersPackage: package Title: What the Package Does (One Line, Title Case) Version: 0.0.0.9000 Authors@R: person(given = "First", family = "Last", role = c("aut", "cre"), email = "first.last@example.com", comment = c(ORCID = "YOUR-ORCID-ID")) Description: What the package does (one paragraph). License: What license it uses Encoding: UTF-8 Imports: lintr LazyData: true Roxygen: list(markdown = TRUE) lintr/tests/testthat/dummy_packages/clean/0000755000176200001440000000000014753133562020470 5ustar liggesuserslintr/tests/testthat/dummy_packages/clean/R/0000755000176200001440000000000014752731051020665 5ustar liggesuserslintr/tests/testthat/dummy_packages/clean/R/default_linter_testcode.R0000644000176200001440000000007714752731051025707 0ustar liggesusersf <- function(x, y = 1) x + y message("hello") y <- 2 + (1:10) lintr/tests/testthat/dummy_packages/clean/R/clean_generics.R0000644000176200001440000000140614752731051023752 0ustar liggesusers# Regression test for #737 via expecting clean to be lint-free #' drink_me #' @description empty #' #' @export drink_me <- function(x, ...) { UseMethod("drink_me") } #' drink_me for most things #' @export drink_me.default <- function(x, ...) { 1 } #' drink_me for lists #' @export drink_me.list <- function(x, ...) { NULL } #' drink_me for data.frames #' @export drink_me.data.frame <- function(x, ...) { NULL } #' head on my_s3_object #' @importFrom utils head #' @export head.my_s3_object <- function(x, ...) { NULL } #' assign names for my_custom_class #' @export `names<-.my_custom_class` <- function(x, value) { NULL } #' Defined S3 generic in R/eat_me.R #' Tests #1808 #' @export eat_me.liiiiiiiiiiiiiiiiiiiiiiiiiiist <- function(x, ...) { NULL } lintr/tests/testthat/dummy_packages/clean/R/eat_me.R0000644000176200001440000000014514752731051022242 0ustar liggesusers#' eat_me #' @description empty #' #' @export eat_me <- function(x, ...) { UseMethod("drink_me") } lintr/tests/testthat/dummy_packages/clean/lintr_test_config0000644000176200001440000000005214752731051024120 0ustar liggesusersexclusions: "R/default_linter_testcode.R" lintr/tests/testthat/dummy_packages/clean/NAMESPACE0000644000176200001440000000044614752731051021707 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("names<-",my_custom_class) S3method(drink_me,data.frame) S3method(drink_me,default) S3method(drink_me,list) S3method(eat_me,liiiiiiiiiiiiiiiiiiiiiiiiiiist) S3method(head,my_s3_object) export(drink_me) export(eat_me) importFrom(utils,head) lintr/tests/testthat/dummy_packages/clean/DESCRIPTION0000644000176200001440000000006114752731051022167 0ustar liggesusersPackage: clean Version: 0.0.1 RoxygenNote: 7.2.2 lintr/tests/testthat/dummy_packages/github_lintr_file/0000755000176200001440000000000014752731051023073 5ustar liggesuserslintr/tests/testthat/dummy_packages/github_lintr_file/tests/0000755000176200001440000000000014752731051024235 5ustar liggesuserslintr/tests/testthat/dummy_packages/github_lintr_file/tests/testthat/0000755000176200001440000000000014753133562026101 5ustar liggesuserslintr/tests/testthat/dummy_packages/github_lintr_file/tests/testthat/test-abc.R0000644000176200001440000000000614752731051027716 0ustar liggesusers'abc' lintr/tests/testthat/dummy_packages/github_lintr_file/tests/testthat.R0000644000176200001440000000007514752731051026222 0ustar liggesuserslibrary(testthat) test_check('github_lintr_file') # nolint lintr/tests/testthat/dummy_packages/github_lintr_file/R/0000755000176200001440000000000014752731051023274 5ustar liggesuserslintr/tests/testthat/dummy_packages/github_lintr_file/R/abc.R0000644000176200001440000000000614752731051024140 0ustar liggesusers'abc' lintr/tests/testthat/dummy_packages/github_lintr_file/NAMESPACE0000644000176200001440000000003714752731051024312 0ustar liggesusersexportPattern("^[[:alpha:]]+") lintr/tests/testthat/dummy_packages/github_lintr_file/DESCRIPTION0000644000176200001440000000044114752731051024600 0ustar liggesusersPackage: assignmentLinter Type: Package Title: What the package does (short line) Version: 1.0 Date: 2019-12-17 Author: Who wrote it Maintainer: Who to complain to Description: More about what it does (maybe more than one line) License: What license is it under? lintr/tests/testthat/dummy_packages/desc_dir_pkg/0000755000176200001440000000000014752731051022017 5ustar liggesuserslintr/tests/testthat/dummy_packages/desc_dir_pkg/DESCRIPTION/0000755000176200001440000000000014752731051023602 5ustar liggesuserslintr/tests/testthat/dummy_packages/desc_dir_pkg/DESCRIPTION/R/0000755000176200001440000000000014752731051024003 5ustar liggesuserslintr/tests/testthat/dummy_packages/desc_dir_pkg/DESCRIPTION/R/foo.R0000644000176200001440000000000714752731051024706 0ustar liggesusersx <- 4 lintr/tests/testthat/dummy_packages/RConfigInvalid/0000755000176200001440000000000014752731051022240 5ustar liggesuserslintr/tests/testthat/dummy_packages/RConfigInvalid/R/0000755000176200001440000000000014752731051022441 5ustar liggesuserslintr/tests/testthat/dummy_packages/RConfigInvalid/R/lint_me.R0000644000176200001440000000000714752731051024210 0ustar liggesusersa <- 1 lintr/tests/testthat/dummy_packages/RConfigInvalid/lintr_test_config.R0000644000176200001440000000002714752731051026076 0ustar liggesusers# invalid R syntax 1 + lintr/tests/testthat/dummy_packages/RConfigInvalid/DESCRIPTION0000644000176200001440000000005014752731051023741 0ustar liggesusersPackage: RConfigInvalid Version: 0.0.1 lintr/tests/testthat/dummy_packages/no_export_dep/0000755000176200001440000000000014752731051022247 5ustar liggesuserslintr/tests/testthat/dummy_packages/no_export_dep/R/0000755000176200001440000000000014752731051022450 5ustar liggesuserslintr/tests/testthat/dummy_packages/no_export_dep/R/foo.R0000644000176200001440000000010414752731051023351 0ustar liggesusersfoo <- function() { a_really_really_long_local_object_name <- 1 } lintr/tests/testthat/dummy_packages/no_export_dep/NAMESPACE0000644000176200001440000000002114752731051023457 0ustar liggesusersimport(datasets) lintr/tests/testthat/dummy_packages/no_export_dep/DESCRIPTION0000644000176200001440000000006514752731051023756 0ustar liggesusersPackage: downstream Version: 0.0.1 Imports: datasets lintr/tests/testthat/dummy_packages/assignmentLinter/0000755000176200001440000000000014752731051022730 5ustar liggesuserslintr/tests/testthat/dummy_packages/assignmentLinter/tests/0000755000176200001440000000000014752731051024072 5ustar liggesuserslintr/tests/testthat/dummy_packages/assignmentLinter/tests/testthat/0000755000176200001440000000000014753133562025736 5ustar liggesuserslintr/tests/testthat/dummy_packages/assignmentLinter/tests/testthat/test-abc.R0000644000176200001440000000006414752731051027557 0ustar liggesuserstest_that("test abc", { expect_equal(2 * 2, 4) }) lintr/tests/testthat/dummy_packages/assignmentLinter/tests/testthat.R0000644000176200001440000000011414752731051026051 0ustar liggesuserslibrary(testthat) library(assignmentLinter) test_check("assignmentLinter") lintr/tests/testthat/dummy_packages/assignmentLinter/R/0000755000176200001440000000000014752731051023131 5ustar liggesuserslintr/tests/testthat/dummy_packages/assignmentLinter/R/abc.R0000644000176200001440000000002514752731051023776 0ustar liggesusersabc = 123 ghi <- 456 lintr/tests/testthat/dummy_packages/assignmentLinter/R/jkl.R0000644000176200001440000000002414752731051024030 0ustar liggesusersjkl = 456 mno = 789 lintr/tests/testthat/dummy_packages/assignmentLinter/exec/0000755000176200001440000000000014752731051023654 5ustar liggesuserslintr/tests/testthat/dummy_packages/assignmentLinter/exec/script.R0000644000176200001440000000014114752731051025277 0ustar liggesusers# lint errors should be included in test-lint_package.R x = 1:4 res<- lapply(x, function(y) y+1) lintr/tests/testthat/dummy_packages/assignmentLinter/NAMESPACE0000644000176200001440000000003714752731051024147 0ustar liggesusersexportPattern("^[[:alpha:]]+") lintr/tests/testthat/dummy_packages/assignmentLinter/DESCRIPTION0000644000176200001440000000053714752731051024443 0ustar liggesusersPackage: assignmentLinter Type: Package Title: What the package does (short line) Version: 1.0 Date: 2019-12-17 Author: Who wrote it Maintainer: Who to complain to Description: More about what it does (maybe more than one line) License: What license is it under? Suggests: testthat (>= 3.0.0) Config/testthat/edition: 3 lintr/tests/testthat/dummy_packages/cp1252/0000755000176200001440000000000014752763366020334 5ustar liggesuserslintr/tests/testthat/dummy_packages/cp1252/R/0000755000176200001440000000000014752731051020517 5ustar liggesuserslintr/tests/testthat/dummy_packages/cp1252/R/cp1252.R0000644000176200001440000000011414752731051021552 0ustar liggesusers# This file is encoded in Cp-1252 # Comment containing non-ASCII ä ü <- 42 lintr/tests/testthat/dummy_packages/cp1252/cp1252.Rproj0000644000176200001440000000055014752731051022250 0ustar liggesusersVersion: 1.0 RestoreWorkspace: Default SaveWorkspace: Default AlwaysSaveHistory: Default EnableCodeIndexing: Yes UseSpacesForTab: Yes NumSpacesForTab: 2 Encoding: ISO8859-1 RnwWeave: Sweave LaTeX: pdfLaTeX AutoAppendNewline: Yes StripTrailingWhitespace: Yes BuildType: Package PackageUseDevtools: Yes PackageInstallArgs: --no-multiarch --with-keep.source lintr/tests/testthat/dummy_packages/cp1252/NAMESPACE0000644000176200001440000000003714752731051021535 0ustar liggesusersexportPattern("^[[:alpha:]]+") lintr/tests/testthat/dummy_packages/cp1252/DESCRIPTION0000644000176200001440000000061714752731051022030 0ustar liggesusersPackage: cp1252 Type: Package Title: What the Package Does (Title Case) Version: 0.1.0 Author: Who wrote it Maintainer: The package maintainer Description: More about what it does (maybe more than one line) Use four spaces when indenting paragraphs within the Description. License: What license is it under? Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) lintr/tests/testthat/dummy_packages/clean_subdir/0000755000176200001440000000000014752731051022034 5ustar liggesuserslintr/tests/testthat/dummy_packages/clean_subdir/lintr_test_config0000644000176200001440000000005214752731051025470 0ustar liggesusersexclusions: "R/default_linter_testcode.R" lintr/tests/testthat/dummy_packages/clean_subdir/r/0000755000176200001440000000000014752731051022275 5ustar liggesuserslintr/tests/testthat/dummy_packages/clean_subdir/r/R/0000755000176200001440000000000014752731051022476 5ustar liggesuserslintr/tests/testthat/dummy_packages/clean_subdir/r/R/default_linter_testcode.R0000644000176200001440000000007714752731051027520 0ustar liggesusersf <- function(x, y = 1) x + y message("hello") y <- 2 + (1:10) lintr/tests/testthat/dummy_packages/clean_subdir/r/R/imported_methods.R0000644000176200001440000000012114752731051026161 0ustar liggesusers#' head on my_s3_object #' @export head.my_s3_object <- function(x, ...) { 1 } lintr/tests/testthat/dummy_packages/clean_subdir/r/NAMESPACE0000644000176200001440000000002714752731051023513 0ustar liggesusersimportFrom(utils,head) lintr/tests/testthat/dummy_packages/clean_subdir/r/DESCRIPTION0000644000176200001440000000003614752731051024002 0ustar liggesusersPackage: clean Version: 0.0.1 lintr/tests/testthat/dummy_packages/missing_dep/0000755000176200001440000000000014752731051021703 5ustar liggesuserslintr/tests/testthat/dummy_packages/missing_dep/R/0000755000176200001440000000000014752731051022104 5ustar liggesuserslintr/tests/testthat/dummy_packages/missing_dep/R/foo.R0000644000176200001440000000057614752731051023022 0ustar liggesusersdownstream <- function(x) { a_really_really_long_local_object_name <- 1 aSilLLyObjEctNaME <- 2 myFancyUpstream::upstreams_really_long_imported_object_name() myFancyUpstream::uPStreams_SilLY.objecT.Name() } # importFrom() functions in unknown namespace a_veritably_dilettantish_function.my_class <- function(x, ...) x sPoNgEbOb_cAsE.FuNcTiOn.my_class <- function(x, ...) x lintr/tests/testthat/dummy_packages/missing_dep/NAMESPACE0000644000176200001440000000023514752731051023122 0ustar liggesusersimport(myFancyUpstream) importFrom(aGemOfAPackage, a_veritably_dilettantish_function, sPoNgEbOb_cAsE.FuNcTiOn) export(downstream) lintr/tests/testthat/dummy_packages/missing_dep/DESCRIPTION0000644000176200001440000000007414752731051023412 0ustar liggesusersPackage: downstream Version: 0.0.1 Imports: myFancyUpstream lintr/tests/testthat/test-parse_exclusions.R0000644000176200001440000000757214752731051021112 0ustar liggesuserswithr::local_options(list( lintr.exclude = "#TeSt_NoLiNt", lintr.exclude_start = "#TeSt_NoLiNt_StArT", lintr.exclude_end = "#TeSt_NoLiNt_EnD" )) test_that("it returns an empty list if there are no exclusions", { lintr:::read_settings(NULL) t1 <- withr::local_tempfile(lines = trim_some(" this is a test ")) expect_identical(lintr:::parse_exclusions(t1), list()) }) test_that("it returns the line if one line is excluded", { lintr:::read_settings(NULL) t1 <- withr::local_tempfile(lines = trim_some(" this is #TeSt_NoLiNt a test ")) expect_identical(lintr:::parse_exclusions(t1), list(2L)) t2 <- withr::local_tempfile(lines = trim_some(" this is #TeSt_NoLiNt a test #TeSt_NoLiNt ")) expect_identical(lintr:::parse_exclusions(t2), list(c(2L, 4L))) }) test_that("it supports specific linter exclusions", { lintr:::read_settings(NULL) t1 <- withr::local_tempfile(lines = trim_some(" this is #TeSt_NoLiNt: my_linter. a test ")) expect_identical(lintr:::parse_exclusions(t1), list(my_linter = 2L)) t2 <- withr::local_tempfile(lines = trim_some(" this is #TeSt_NoLiNt: my_linter. a test #TeSt_NoLiNt: my_linter2. ")) expect_identical(lintr:::parse_exclusions(t2), list(my_linter = 2L, my_linter2 = 4L)) t3 <- withr::local_tempfile(lines = trim_some(" this is #TeSt_NoLiNt: my_linter. another useful #TeSt_NoLiNt: my_linter. test testing #TeSt_NoLiNt: my_linter2. ")) expect_identical(lintr:::parse_exclusions(t3), list(my_linter = c(2L, 4L), my_linter2 = 6L)) }) test_that("it supports multiple linter exclusions", { t1 <- withr::local_tempfile(lines = trim_some(" this #TeSt_NoLiNt is #TeSt_NoLiNt: a, b. a thorough #TeSt_NoLiNt_StArT: a, b, c. test #TeSt_NoLiNt of #TeSt_NoLiNt_EnD all features #TeSt_NoLiNt_StArT a, b, c interleaved #TeSt_NoLiNt a, b with each #TeSt_NoLiNt_EnD other ")) expect_identical(lintr:::parse_exclusions(t1), list( a = c(2L, 4L:6L), b = c(2L, 4L:6L), c = 4L:6L, c(1L, 5L, 8L:11L) )) }) test_that("it supports overlapping exclusion ranges", { t1 <- withr::local_tempfile(lines = trim_some(" this #TeSt_NoLiNt_StArT: a. is a #TeSt_NoLiNt_StArT: b. test with #TeSt_NoLiNt_EnD overlapping #TeSt_NoLiNt_EnD ranges ")) expect_identical(lintr:::parse_exclusions(t1), list( a = 1L:5L, b = 3L:6L )) }) test_that("it returns all lines between start and end", { lintr:::read_settings(NULL) t1 <- withr::local_tempfile(lines = trim_some(" this #TeSt_NoLiNt_StArT is a #TeSt_NoLiNt_EnD test ")) expect_identical(lintr:::parse_exclusions(t1), list(c(1L, 2L, 3L))) t2 <- withr::local_tempfile(lines = trim_some(" this #TeSt_NoLiNt_StArT is a #TeSt_NoLiNt_EnD test of the #TeSt_NoLiNt_StArT emergency #TeSt_NoLiNt_EnD broadcast system ")) expect_identical(lintr:::parse_exclusions(t2), list(c(1L, 2L, 3L, 6L, 7L))) }) test_that("it ignores exclude coverage lines within start and end", { lintr:::read_settings(NULL) t1 <- withr::local_tempfile(lines = c( "this #TeSt_NoLiNt_StArT", "is #TeSt_NoLiNt", "a #TeSt_NoLiNt_EnD", "test" )) expect_identical(lintr:::parse_exclusions(t1), list(c(1L, 2L, 3L))) }) test_that("it throws an error if start and end are unpaired", { lintr:::read_settings(NULL) error_msg_stem <- "Equal number of line starts and ends expected for exclusion from linting" t1 <- withr::local_tempfile(lines = trim_some(" this #TeSt_NoLiNt_StArT is #TeSt_NoLiNt a test ")) expect_error(lintr:::parse_exclusions(t1), error_msg_stem) t2 <- withr::local_tempfile(lines = trim_some(" this #TeSt_NoLiNt_StArT is #TeSt_NoLiNt_EnD a #TeSt_NoLiNt_EnD test ")) expect_error(lintr:::parse_exclusions(t2), error_msg_stem) }) lintr/tests/testthat/test-commas_linter.R0000644000176200001440000000744014752731051020352 0ustar liggesuserstest_that("returns the correct linting (with default parameters)", { linter <- commas_linter() msg_after <- rex::rex("Put a space after a comma.") msg_before <- rex::rex("Remove spaces before a comma.") expect_lint("blah", NULL, linter) expect_lint("fun(1, 1)", NULL, linter) expect_lint("fun(1,\n 1)", NULL, linter) expect_lint("fun(1,\n1)", NULL, linter) expect_lint("fun(1\n,\n1)", NULL, linter) expect_lint("fun(1\n ,\n1)", NULL, linter) expect_lint("fun(1\n,1)", msg_after, linter) expect_lint("fun(1,1)", msg_after, linter) expect_lint("\nfun(1,1)", msg_after, linter) expect_lint("a(1,)", msg_after, linter) expect_lint("a[1,]", msg_after, linter) expect_lint("a[[1,]]", msg_after, linter) expect_lint( "fun(1 ,1)", list( list(msg_before, column_number = 6L), list(msg_after, column_number = 8L) ), linter ) expect_lint("\"fun(1 ,1)\"", NULL, linter) expect_lint("a[1, , 2]", NULL, linter) expect_lint("a[1, , 2, , 3]", NULL, linter) expect_lint("switch(op, x = foo, y = bar)", NULL, linter) expect_lint("switch(op, x = , y = bar)", NULL, linter) expect_lint("switch(op, \"x\" = , y = bar)", NULL, linter) expect_lint("switch(op, x = ,\ny = bar)", NULL, linter) expect_lint("switch(op, x = foo , y = bar)", msg_before, linter) expect_lint("switch(op, x = foo , y = bar)", msg_before, linter) expect_lint("switch(op , x = foo, y = bar)", msg_before, linter) expect_lint("switch(op, x = foo, y = bar(a = 4 , b = 5))", msg_before, linter) expect_lint("fun(op, x = foo , y = switch(bar, a = 4, b = 5))", msg_before, linter) expect_lint( trim_some(" switch(op , x = foo,y = bar ) "), list( list(msg_before, line_number = 1L), list(msg_after, line_number = 2L) ), linter ) expect_lint( "fun(op ,bar)", list( list(message = msg_before, column_number = 7L, ranges = list(c(7L, 10L))), list(message = msg_after, column_number = 12L, ranges = list(c(12L, 12L))) ), linter ) }) test_that("returns the correct linting (with 'allow_trailing' set)", { linter <- commas_linter(allow_trailing = TRUE) msg_after <- rex::rex("Put a space after a comma.") msg_before <- rex::rex("Remove spaces before a comma.") expect_lint("blah", NULL, linter) expect_lint("fun(1, 1)", NULL, linter) expect_lint("fun(1,\n 1)", NULL, linter) expect_lint("fun(1,\n1)", NULL, linter) expect_lint("fun(1\n,\n1)", NULL, linter) expect_lint("fun(1\n ,\n1)", NULL, linter) expect_lint("a[1,]", NULL, linter) expect_lint("a(1,)", NULL, linter) expect_lint("fun(1\n,1)", msg_after, linter) expect_lint("fun(1,1)", msg_after, linter) expect_lint("\nfun(1,1)", msg_after, linter) expect_lint( "fun(1 ,1)", list( msg_before, msg_after ), linter ) expect_lint("\"fun(1 ,1)\"", NULL, linter) expect_lint("a[1, , 2]", NULL, linter) expect_lint("a[1, , 2, , 3]", NULL, linter) expect_lint("a[[1,]]", NULL, linter) expect_lint("switch(op, x = foo, y = bar)", NULL, linter) expect_lint("switch(op, x = , y = bar)", NULL, linter) expect_lint("switch(op, \"x\" = , y = bar)", NULL, linter) expect_lint("switch(op, x = ,\ny = bar)", NULL, linter) expect_lint("switch(op, x = foo , y = bar)", msg_before, linter) expect_lint("switch(op, x = foo , y = bar)", msg_before, linter) expect_lint("switch(op , x = foo, y = bar)", msg_before, linter) expect_lint("switch(op, x = foo, y = bar(a = 4 , b = 5))", msg_before, linter) expect_lint("fun(op, x = foo , y = switch(bar, a = 4, b = 5))", msg_before, linter) expect_lint( "fun(op ,bar)", list( list(message = msg_before, column_number = 7L, ranges = list(c(7L, 10L))), list(message = msg_after, column_number = 12L, ranges = list(c(12L, 12L))) ), linter ) }) lintr/tests/testthat/test-use_lintr.R0000644000176200001440000000204314752731051017514 0ustar liggesuserstest_that("use_lintr works as expected", { tmp <- withr::local_tempdir() lintr_file <- use_lintr(path = tmp) expect_true(file.exists(lintr_file)) # check that newly created file is in the root directory expect_identical( normalize_path(lintr_file), file.path(normalize_path(tmp), ".lintr") ) # can't generate if a .lintr already exists expect_error(use_lintr(path = tmp), "Found an existing configuration") # check that `read_settings()` works with the generated file # this can be checked by checking lintr runs successfully lints <- lint_dir(tmp) expect_length(lints, 0L) }) test_that("use_lintr with type = full also works", { tmp <- withr::local_tempdir() # type = "full" also works with read_settings() lintr_file <- use_lintr(path = tmp, type = "full") expect_true(file.exists(lintr_file)) # check that newly created file is in the root directory expect_identical( normalize_path(lintr_file), file.path(normalize_path(tmp), ".lintr") ) lints <- lint_dir(tmp) expect_length(lints, 0L) }) lintr/tests/testthat/test-missing_package_linter.R0000644000176200001440000000361414752731051022216 0ustar liggesuserstest_that("missing_package_linter skips allowed usages", { linter <- missing_package_linter() expect_lint("library(stats)", NULL, linter) expect_lint('library("stats")', NULL, linter) expect_lint("library('stats')", NULL, linter) expect_lint("library(`stats`)", NULL, linter) expect_lint("library(stats, quietly)", NULL, linter) expect_lint("library(stats, quietly = TRUE)", NULL, linter) expect_lint("require(stats)", NULL, linter) expect_lint("require(stats, quietly = TRUE)", NULL, linter) expect_lint('loadNamespace("stats")', NULL, linter) expect_lint('requireNamespace("stats")', NULL, linter) }) test_that("missing_package_linter blocks disallowed usages", { linter <- missing_package_linter() lint_msg <- rex::rex("Package 'statts' is not installed.") expect_lint("require(statts)", lint_msg, linter) expect_lint("library(statts, quietly = TRUE)", lint_msg, linter) expect_lint("library(statts, quietly = TRUE)", lint_msg, linter) expect_lint('loadNamespace("statts")', lint_msg, linter) expect_lint('requireNamespace("statts")', lint_msg, linter) expect_lint( trim_some(" library(utils) library(statts) "), list(lint_msg, line_number = 2L, line = "library(statts)"), linter ) }) test_that("loadNamespace and requireNamespace allow plain symbols", { linter <- missing_package_linter() expect_lint("loadNamespace(mypkg)", NULL, linter) expect_lint("requireNamespace(mypkg)", NULL, linter) }) test_that("character.only=TRUE case is handled", { linter <- missing_package_linter() expect_lint("library(statts, character.only = TRUE)", NULL, linter) expect_lint("require(statts, character.only = TRUE)", NULL, linter) expect_lint('library("stats", character.only = TRUE)', NULL, linter) expect_lint( 'library("statts", character.only = TRUE)', rex::rex("Package 'statts' is not installed."), missing_package_linter() ) }) lintr/tests/testthat/test-equals_na_linter.R0000644000176200001440000000550714752731051021045 0ustar liggesuserstest_that("equals_na_linter skips allowed usages", { linter <- equals_na_linter() expect_lint("blah", NULL, linter) expect_lint(" blah", NULL, linter) expect_lint(" blah", NULL, linter) expect_lint("x=NA", NULL, linter) expect_lint("x = NaN", NULL, linter) expect_lint("x = NA_real_", NULL, linter) expect_lint("is.na(x)", NULL, linter) expect_lint("is.nan(x)", NULL, linter) expect_lint("x[!is.na(x)]", NULL, linter) # equals_na_linter should ignore strings and comments expect_lint("is.na(x) # do not flag x == NA if inside a comment", NULL, linter) expect_lint("lint_msg <- 'do not flag x == NA if inside a string'", NULL, linter) # nested NAs are okay expect_lint("x==f(1, ignore = NA)", NULL, linter) # this should be covered by any_is_na_linter() expect_lint("NA %in% x", NULL, linter) }) skip_if_not_installed("tibble") patrick::with_parameters_test_that( "equals_na_linter blocks disallowed usages for all combinations of operators and types of NAs", expect_lint( paste("x", operation, type_na), rex::rex("Use is.na() instead of x ", operation, " NA"), equals_na_linter() ), .cases = tibble::tribble( ~.test_name, ~operation, ~type_na, "equality, logical NA", "==", "NA", "equality, integer NA", "==", "NA_integer_", "equality, real NA", "==", "NA_real_", "equality, complex NA", "==", "NA_complex_", "equality, character NA", "==", "NA_character_", "containment, logical NA", "%in%", "NA", "containment, integer NA", "%in%", "NA_integer_", "containment, real NA", "%in%", "NA_real_", "containment, complex NA", "%in%", "NA_complex_", "containment, character NA", "%in%", "NA_character_", "inequality, logical NA", "!=", "NA", "inequality, integer NA", "!=", "NA_integer_", "inequality, real NA", "!=", "NA_real_", "inequality, complex NA", "!=", "NA_complex_", "inequality, character NA", "!=", "NA_character_" ) ) test_that("equals_na_linter blocks disallowed usages in edge cases", { linter <- equals_na_linter() lint_msg_part <- "Use is.na() instead of x " # missing spaces around operators expect_lint( "x==NA", list(message = rex::rex(lint_msg_part, "== NA"), line_number = 1L, column_number = 1L), linter ) expect_lint( "x!=NA", list(message = rex::rex(lint_msg_part, "!= NA"), line_number = 1L, column_number = 1L), linter ) # order doesn't matter expect_lint( "NA == x", list(message = rex::rex(lint_msg_part, "== NA"), line_number = 1L, column_number = 1L), linter ) # correct line number for multiline code expect_lint( "x ==\nNA", list(line_number = 1L, column_number = 1L, ranges = list(c(1L, 4L))), linter ) }) lintr/tests/testthat/test-sample_int_linter.R0000644000176200001440000000665614752731051021236 0ustar liggesuserstest_that("sample_int_linter skips allowed usages", { linter <- sample_int_linter() expect_lint("sample(n, m)", NULL, linter) expect_lint("sample(n, m, TRUE)", NULL, linter) expect_lint("sample(n, m, prob = 1:n/n)", NULL, linter) expect_lint("sample(foo(x), m, TRUE)", NULL, linter) expect_lint("sample(n, replace = TRUE)", NULL, linter) expect_lint("sample(10:1, m)", NULL, linter) }) test_that("sample_int_linter blocks simple disallowed usages", { linter <- sample_int_linter() lint_msg <- rex::rex("sample.int(n, m, ...) is preferable to sample(1:n, m, ...).") expect_lint("sample(1:10, 2)", lint_msg, linter) # also matches literal integer expect_lint("sample(1L:10L, 2)", lint_msg, linter) expect_lint("sample(1:n, 2)", lint_msg, linter) expect_lint("sample(1:k, replace = TRUE)", lint_msg, linter) expect_lint("sample(1:foo(x), prob = bar(x))", lint_msg, linter) }) test_that("sample_int_linter blocks sample(seq_len(n), ...) as well", { expect_lint( "sample(seq_len(10), 2)", rex::rex("sample.int(n, m, ...) is preferable to sample(seq_len(n), m, ...)."), sample_int_linter() ) }) test_that("sample_int_linter blocks sample(seq(n)) and sample(seq(1, ...))", { linter <- sample_int_linter() lint_msg <- rex::rex("sample.int(n, m, ...) is preferable to sample(seq(n), m, ...).") expect_lint("sample(seq(n), 5)", lint_msg, linter) expect_lint("sample(seq(1, 10), 5)", lint_msg, linter) expect_lint("sample(seq(1, 10, by = 1), 5)", lint_msg, linter) expect_lint("sample(seq(1L, 10, by = 1L), 5)", lint_msg, linter) # lint doesn't apply when by= is used (except when set to literal 1) expect_lint("sample(seq(1, 10, by = 2), 5)", NULL, linter) expect_lint("sample(seq(1, 10, by = n), 5)", NULL, linter) }) test_that("sample_int_linter catches literal integer/numeric in the first arg", { linter <- sample_int_linter() lint_msg <- rex::rex("sample.int(n, m, ...) is preferable to sample(n, m, ...).") expect_lint("sample(10L, 4)", lint_msg, linter) expect_lint("sample(10, 5)", lint_msg, linter) }) test_that("sample_int_linter skips TRUE or FALSE in the first argument", { linter <- sample_int_linter() expect_lint("sample(replace = TRUE, letters)", NULL, linter) expect_lint("sample(replace = FALSE, letters)", NULL, linter) }) test_that("sample_int_linter skips x$sample() usage", { linter <- sample_int_linter() lint_msg <- rex::rex("sample.int(n, m, ...) is preferable to sample(n, m, ...).") expect_lint("foo$sample(1L)", NULL, linter) expect_lint("foo$sample(1:10)", NULL, linter) expect_lint("foo$sample(seq_len(10L))", NULL, linter) # ditto for '@' slot extraction expect_lint("foo@sample(1L)", NULL, linter) # however, base::sample qualification is still caught expect_lint("base::sample(10L)", lint_msg, linter) # but also, not everything "below" a $ extraction is skipped expect_lint("foo$bar(sample(10L))", lint_msg, linter) }) test_that("multiple lints are generated correctly", { expect_lint( trim_some("{ sample(1:10, 2) sample(10, 2) sample(seq_len(10), 2) sample(seq(10), 2) }"), list( list(rex::rex("sample(1:n"), line_number = 2L, column_number = 3L), list(rex::rex("sample(n"), line_number = 3L, column_number = 3L), list(rex::rex("sample(seq_len(n)"), line_number = 4L, column_number = 3L), list(rex::rex("sample(seq(n)"), line_number = 5L, column_number = 3L) ), sample_int_linter() ) }) lintr/tests/testthat/test-unreachable_code_linter.R0000644000176200001440000003545414752731051022344 0ustar liggesuserstest_that("unreachable_code_linter works in simple function", { lines <- trim_some(" foo <- function(bar) { return(bar) } ") expect_lint(lines, NULL, unreachable_code_linter()) }) test_that("unreachable_code_linter works in sub expressions", { linter <- unreachable_code_linter() msg <- rex::rex("Remove code and comments coming after return() or stop()") lines <- trim_some(" foo <- function(bar) { if (bar) { return(bar) # Test comment while (bar) { return(bar) 5 + 3 repeat { return(bar) # Test comment } } } else if (bla) { # test return(5) # Test 2 } else { return(bar) # Test comment for(i in 1:3) { return(bar) 5 + 4 } } return(bar) 5 + 1 } ") expect_lint( lines, list( list(line_number = 4L, message = msg), list(line_number = 7L, message = msg), list(line_number = 10L, message = msg), list(line_number = 16L, message = msg), list(line_number = 19L, message = msg), list(line_number = 22L, message = msg), list(line_number = 26L, message = msg) ), linter ) lines <- trim_some(" foo <- function(bar) { if (bar) { return(bar) # Test comment } while (bar) { return(bar) # 5 + 3 } repeat { return(bar) # Test comment } } ") expect_lint(lines, NULL, linter) lines <- trim_some(" foo <- function(bar) { if (bar) { return(bar); x <- 2 } else { return(bar); x <- 3 } while (bar) { return(bar); 5 + 3 } repeat { return(bar); test() } for(i in 1:3) { return(bar); 5 + 4 } } ") expect_lint( lines, list( list(line_number = 3L, message = msg), list(line_number = 5L, message = msg), list(line_number = 8L, message = msg), list(line_number = 11L, message = msg), list(line_number = 14L, message = msg) ), linter ) }) test_that("unreachable_code_linter works with next and break in sub expressions", { linter <- unreachable_code_linter() msg <- rex::rex("Remove code and comments coming after `next` or `break`") lines <- trim_some(" foo <- function(bar) { if (bar) { next # Test comment while (bar) { break 5 + 3 repeat { next # Test comment } } } else { next # test for(i in 1:3) { break 5 + 4 } } } ") expect_lint( lines, list( list(line_number = 4L, message = msg), list(line_number = 7L, message = msg), list(line_number = 10L, message = msg), list(line_number = 15L, message = msg), list(line_number = 18L, message = msg) ), linter ) lines <- trim_some(" foo <- function(bar) { if (bar) { break # Test comment } else { next # Test comment } while (bar) { next # 5 + 3 } repeat { next # Test comment } for(i in 1:3) { break # 5 + 4 } } ") expect_lint(lines, NULL, linter) lines <- trim_some(" foo <- function(bar) { if (bar) { next; x <- 2 } else { break; x <- 3 } while (bar) { break; 5 + 3 } repeat { next; test() } for(i in 1:3) { break; 5 + 4 } } ") expect_lint( lines, list( list(line_number = 3L, message = msg), list(line_number = 5L, message = msg), list(line_number = 8L, message = msg), list(line_number = 11L, message = msg), list(line_number = 14L, message = msg) ), linter ) }) test_that("unreachable_code_linter ignores expressions that aren't functions", { expect_lint("x + 1", NULL, unreachable_code_linter()) }) test_that("unreachable_code_linter ignores anonymous/inline functions", { expect_lint("lapply(rnorm(10), function(x) x + 1)", NULL, unreachable_code_linter()) }) test_that("unreachable_code_linter passes on multi-line functions", { lines <- trim_some(" oo <- function(x) { y <- x + 1 return(y) } ") expect_lint(lines, NULL, unreachable_code_linter()) }) test_that("unreachable_code_linter ignores comments on the same expression", { lines <- trim_some(" foo <- function(x) { return( y^2 ) # y^3 } ") expect_lint(lines, NULL, unreachable_code_linter()) }) test_that("unreachable_code_linter ignores comments on the same line", { lines <- trim_some(" foo <- function(x) { return(y^2) # y^3 } ") expect_lint(lines, NULL, unreachable_code_linter()) }) test_that("unreachable_code_linter identifies simple unreachable code", { lines <- trim_some(" foo <- function(bar) { return(bar) x + 3 } ") # testing the correct expression is linted (the first culprit line) expect_lint( lines, list( line_number = 3L, message = rex::rex("Remove code and comments coming after return() or stop()") ), unreachable_code_linter() ) }) test_that("unreachable_code_linter finds unreachable comments", { lines <- trim_some(" foo <- function(x) { y <- x + 1 return(y^2) # y^3 } ") expect_lint( lines, rex::rex("Remove code and comments coming after return() or stop()"), unreachable_code_linter() ) }) test_that("unreachable_code_linter finds expressions in the same line", { msg <- rex::rex("Remove code and comments coming after return() or stop()") linter <- unreachable_code_linter() lines <- trim_some(" foo <- function(x) { return( y^2 ); 3 + 1 } ") expect_lint(lines, msg, linter) lines <- trim_some(" foo <- function(x) { return(y^2); 3 + 1 } ") expect_lint(lines, msg, linter) lines <- trim_some(" foo <- function(x) { return(y^2); 3 + 1 # Test } ") expect_lint(lines, msg, linter) }) test_that("unreachable_code_linter finds expressions and comments after comment in return line", { msg <- rex::rex("Remove code and comments coming after return() or stop()") linter <- unreachable_code_linter() lines <- trim_some(" foo <- function(x) { return(y^2) #Test comment #Test comment 2 } ") expect_lint(lines, msg, linter) lines <- trim_some(" foo <- function(x) { return(y^2) # Test 3 + 1 } ") expect_lint(lines, msg, linter) }) test_that("unreachable_code_linter finds a double return", { lines <- trim_some(" foo <- function(x) { return(y^2) return(y^3) } ") expect_lint( lines, rex::rex("Remove code and comments coming after return() or stop()"), unreachable_code_linter() ) }) test_that("unreachable_code_linter finds code after stop()", { lines <- trim_some(" foo <- function(x) { y <- x + 1 stop(y^2) # y^3 } ") expect_lint( lines, rex::rex("Remove code and comments coming after return() or stop()"), unreachable_code_linter() ) }) test_that("unreachable_code_linter ignores code after foo$stop(), which might be stopping a subprocess, for example", { linter <- unreachable_code_linter() expect_lint( trim_some(" foo <- function(x) { bar <- get_process() bar$stop() TRUE } "), NULL, linter ) expect_lint( trim_some(" foo <- function(x) { bar <- get_process() bar@stop() TRUE } "), NULL, linter ) }) test_that("unreachable_code_linter ignores terminal nolint end comments", { linter <- unreachable_code_linter() withr::local_options(list( lintr.exclude_start = "#\\s*TestNoLintStart", lintr.exclude_end = "#\\s*TestNoLintEnd" )) expect_lint( trim_some(" foo <- function() { do_something # TestNoLintStart: one_linter. a = 42 return(a) # TestNoLintEnd } "), NULL, list(linter, one_linter = assignment_linter()) ) expect_lint( trim_some(" foo <- function() { do_something # TestNoLintStart: one_linter. a = 42 next # TestNoLintEnd } "), NULL, linter ) }) test_that("unreachable_code_linter identifies unreachable code in conditional loops", { linter <- unreachable_code_linter() msg <- rex::rex("Remove code inside a conditional loop with a deterministically false condition.") lines <- trim_some(" foo <- function(bar) { if (FALSE) { x <- 3 } x + 3 } ") expect_lint(lines, list(line_number = 2L, message = msg), linter) lines <- trim_some(" foo <- function(bar) { if (FALSE) { # Unlinted comment x <- 3 } x + 3 } ") expect_lint(lines, list(line_number = 2L, message = msg), linter) lines <- trim_some(" foo <- function(bar) { if (bla) { x <- 3 } else if (FALSE) { # Unlinted comment y <- 3 } x + 3 } ") expect_lint(lines, list(line_number = 4L, message = msg), linter) lines <- trim_some(" foo <- function(bar) { while (FALSE) { x <- 3 } x + 3 } ") expect_lint(lines, list(line_number = 2L, message = msg), linter) lines <- trim_some(" foo <- function(bar) { while (FALSE) { # Unlinted comment x <- 3 } x + 3 } ") expect_lint(lines, list(line_number = 2L, message = msg), linter) lines <- "while (FALSE) x <- 3" expect_lint( lines, list(line_number = 1L, ranges = list(c(1L, 20L)), message = msg), linter ) lines <- "if (FALSE) x <- 3 # Test comment" expect_lint( lines, list(line_number = 1L, ranges = list(c(1L, 17L)), message = msg), linter ) }) test_that("unreachable_code_linter identifies unreachable code in conditional loops", { linter <- unreachable_code_linter() msg <- rex::rex("Remove code inside an else block after a deterministically true condition.") lines <- trim_some(" foo <- function(bar) { if (TRUE) { x <- 3 } else { # Unlinted comment x + 3 } } ") expect_lint(lines, list(line_number = 6L, message = msg), linter) lines <- trim_some(" foo <- function(bar) { if (TRUE) { x <- 3 } else if (bar) { # Unlinted comment x + 3 } } ") expect_lint(lines, list(line_number = 4L, message = msg), linter) expect_lint( "if (TRUE) x <- 3 else if (bar) x + 3", list(line_number = 1L, ranges = list(c(23L, 36L)), message = msg), linter ) }) test_that("unreachable_code_linter identifies unreachable code in mixed conditional loops", { linter <- unreachable_code_linter() false_msg <- rex::rex("Remove code inside a conditional loop with a deterministically false condition.") true_msg <- rex::rex("Remove code inside an else block after a deterministically true condition.") expect_lint( trim_some(" function (bla) { if (FALSE) { code + 4 } while (FALSE) { code == 3 } if (TRUE) { } else { code + bla } stop('.') code <- 1 } "), list( list(false_msg, line_number = 2L), list(false_msg, line_number = 5L), list(true_msg, line_number = 10L), list(rex::rex("Remove code and comments coming after return() or stop()."), line_number = 13L) ), linter ) expect_lint( "if (FALSE) x <- 3 else if (TRUE) x + 3 else x + 4", list( list(false_msg, line_number = 1L, ranges = list(c(1L, 49L))), list( rex::rex("Remove code inside an else block after a deterministically true condition."), line_number = 1L, ranges = list(c(45L, 49L)) ) ), linter ) }) test_that("function shorthand is handled", { skip_if_not_r_version("4.1.0") expect_lint( trim_some(" foo <- \\(bar) { return(bar) x + 3 } "), list( line_number = 3L, message = rex::rex("Remove code and comments coming after return() or stop()") ), unreachable_code_linter() ) }) test_that("Do not lint inline else after stop", { expect_lint("if (x > 3L) stop() else x + 3", NULL, unreachable_code_linter()) }) test_that("Do not lint inline else after stop in inline function", { linter <- unreachable_code_linter() expect_lint("function(x) if (x > 3L) stop() else x + 3", NULL, linter) expect_lint("function(x) if (x > 3L) { stop() } else {x + 3}", NULL, linter) }) test_that("Do not lint inline else after stop in inline lambda function", { skip_if_not_r_version("4.1.0") linter <- unreachable_code_linter() expect_lint("\\(x) if (x > 3L) stop() else x + 3", NULL, linter) expect_lint("\\(x){ if (x > 3L) stop() else x + 3 }", NULL, linter) }) test_that("allow_comment_regex= works", { withr::local_options(c(lintr.exclude_end = "#\\s*TestNoLintEnd")) linter_covr <- unreachable_code_linter() linter_xxxx <- unreachable_code_linter(allow_comment_regex = "#.*xxxx") linter_x1x2 <- unreachable_code_linter(allow_comment_regex = c("#x", "#y")) expect_lint( trim_some(" function() { return(1) # nocov end } "), NULL, linter_covr ) expect_lint( trim_some(" function() { return(1) # TestNoLintEnd # nocov end } "), NULL, linter_covr ) expect_lint( trim_some(" function() { return(1) # ABCDxxxx } "), NULL, linter_xxxx ) expect_lint( trim_some(" function() { return(1) # TestNoLintEnd # ABCDxxxx } "), NULL, linter_xxxx ) expect_lint( trim_some(" function() { return(1) #x } "), NULL, linter_x1x2 ) expect_lint( trim_some(" function() { return(1) #xABC #yDEF } "), NULL, linter_x1x2 ) # might contain capture groups, #2678 expect_lint( trim_some(" function() { stop('a') # a # ab } "), NULL, unreachable_code_linter(allow_comment_regex = "#\\s*(a|ab|abc)") ) }) test_that("allow_comment_regex= obeys covr's custom exclusion when set", { withr::local_options(c( lintr.exclude_end = "#\\s*TestNoLintEnd", covr.exclude_end = "#\\s*TestNoCovEnd" )) linter_covr <- unreachable_code_linter() expect_lint( trim_some(" function() { return(1) # TestNoCovEnd } "), NULL, linter_covr ) expect_lint( trim_some(" function() { return(1) # TestNoLintEnd # TestNoCovEnd } "), NULL, linter_covr ) }) lintr/tests/testthat/test-list_comparison_linter.R0000644000176200001440000000202614752731051022273 0ustar liggesuserstest_that("list_comparison_linter skips allowed usages", { expect_lint("sapply(x, sum) > 10", NULL, list_comparison_linter()) }) local({ linter <- list_comparison_linter() lint_msg <- rex::rex("a list(), is being coerced for comparison") cases <- expand.grid( list_mapper = c("lapply", "map", "Map", ".mapply"), comparator = c("==", "!=", ">=", "<=", ">", "<") ) cases$.test_name <- with(cases, paste(list_mapper, comparator)) patrick::with_parameters_test_that( "list_comparison_linter blocks simple disallowed usages", expect_lint(sprintf("%s(x, sum) %s 10", list_mapper, comparator), lint_msg, linter), .cases = cases ) }) test_that("list_comparison_linter vectorizes", { expect_lint( trim_some("{ sapply(x, sum) > 10 .mapply(`+`, list(1:10, 1:10), NULL) == 2 lapply(x, sum) < 5 }"), list( list(rex::rex(".mapply()", anything, "`==`"), line_number = 3L), list(rex::rex("lapply()", anything, "`<`"), line_number = 4L) ), list_comparison_linter() ) }) lintr/tests/testthat/test-backport_linter.R0000644000176200001440000000470214752735601020703 0ustar liggesuserstest_that("backport_linter produces error when R version misspecified", { expect_error( lint(text = "numToBits(2)", linters = backport_linter(420L)), "`r_version` must be an R version number" ) }) test_that("backport_linter detects backwards-incompatibility", { # default should be current R version; all of these are included on our dependency expect_lint(".getNamespaceInfo(dir.exists(lapply(x, toTitleCase)))", NULL, backport_linter()) expect_lint(".getNamespaceInfo(dir.exists(lapply(x, toTitleCase)))", NULL, backport_linter("release")) expect_lint(".getNamespaceInfo(dir.exists(lapply(x, toTitleCase)))", NULL, backport_linter("devel")) expect_lint( "numToBits(2)", rex::rex("numToBits (R 4.1.0) is not available for dependency R >= 4.0.0."), backport_linter("4.0.0") ) # symbols as well as calls expect_lint( "lapply(1:10, numToBits)", rex::rex("numToBits (R 4.1.0) is not available for dependency R >= 4.0.0."), backport_linter("4.0.0") ) expect_lint( trim_some(" trimws( ...names() ) "), list( list(rex::rex("trimws (R 3.2.0) is not available for dependency R >= 3.0.0."), line_number = 1L), list(rex::rex("...names (R 4.1.0) is not available for dependency R >= 3.0.0."), line_number = 2L) ), backport_linter("3.0.0") ) # oldrel specification expect_lint( "R_compiled_by()", rex::rex("R_compiled_by (R 4.3.0) is not available for dependency R >= 4.2.3."), backport_linter("oldrel") ) expect_error( backport_linter("oldrel-99"), "`r_version` is not valid" ) expect_lint( "numToBits(2)", rex::rex("numToBits (R 4.1.0) is not available for dependency R >= 4.0.5."), backport_linter("oldrel-3") ) # no interference from namespace-qualification (even of base functions) expect_lint( "base::numToBits(2)", rex::rex("numToBits (R 4.1.0) is not available for dependency R >= 4.0.5."), backport_linter("oldrel-3") ) # except is honored expect_lint( trim_some(" numToBits(2) R_user_dir('mypkg') "), NULL, backport_linter("3.0.0", except = c("numToBits", "R_user_dir")) ) }) test_that("backport_linter generates expected warnings", { tmp <- withr::local_tempfile(lines = "x <- x + 1") expect_warning( { l <- lint(tmp, backport_linter("2.0.0")) }, 'version older than "3.0.0"', fixed = TRUE ) expect_identical(l, lint(tmp, backport_linter("3.0.0"))) }) lintr/tests/testthat/test-terminal_close_linter.R0000644000176200001440000000301714752731051022067 0ustar liggesuserstest_that("terminal_close_linter skips allowed cases", { linter <- terminal_close_linter() lines <- trim_some(" foo <- function(bar) { tmp <- tempfile() on.exit(close(tmp)) writeLines(bar, tmp) return(invisible()) } ") expect_lint(lines, NULL, linter) lines <- trim_some(" foo <- function(bar) { close <- bar + 1 return(close) } ") expect_lint(lines, NULL, linter) lines <- trim_some(" foo <- function(bar) { close <- bar + 1 close } ") expect_lint(lines, NULL, linter) }) test_that("terminal_close_linter blocks simple cases", { linter <- terminal_close_linter() lint_msg <- rex::rex("Use on.exit(close(x)) to close connections") expect_lint( trim_some(" foo <- function(bar) { tmp <- tempfile() writeLines(bar, tmp) return(close(tmp)) } "), list(lint_msg, line_number = 4L, column_number = 3L), linter ) expect_lint( trim_some(" foo <- function(bar) { tmp <- tempfile() writeLines(bar, tmp) close(tmp) } "), list(lint_msg, line_number = 4L, column_number = 3L), linter ) # When multiple terminations happen, only lint the one expect_lint( trim_some(" foo <- function(bar) { tmp1 <- tempfile() tmp2 <- tempfile() writeLines(bar, tmp1) writeLines(bar, tmp2) close(tmp1) close(tmp2) } "), list(lint_msg, line_number = 7L, column_number = 3L), linter ) }) lintr/tests/testthat/knitr_malformed/0000755000176200001440000000000014752731051017566 5ustar liggesuserslintr/tests/testthat/knitr_malformed/incomplete_r_block.qmd0000644000176200001440000000115114752731051024121 0ustar liggesusers# Test # Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} a = 1 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. lintr/tests/testthat/knitr_malformed/incomplete_r_block.Rmd0000644000176200001440000000115114752731051024062 0ustar liggesusers# Test # Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} a = 1 Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. lintr/tests/testthat/test-implicit_assignment_linter.R0000644000176200001440000002562514752731051023142 0ustar liggesuserstest_that("implicit_assignment_linter skips allowed usages", { linter <- implicit_assignment_linter() expect_lint("x <- 1L", NULL, linter) expect_lint("1L -> x", NULL, linter) expect_lint("x <<- 1L", NULL, linter) expect_lint("1L ->> x", NULL, linter) expect_lint("y <- if (is.null(x)) z else x", NULL, linter) expect_lint("for (x in 1:10) x <- x + 1", NULL, linter) expect_lint("abc <- mean(1:4)", NULL, linter) expect_lint("mean(1:4) -> abc", NULL, linter) expect_lint( trim_some(" x <- 1:4 mean(x)"), NULL, linter ) expect_lint( trim_some(" x <- 1L if (x) TRUE"), NULL, linter ) expect_lint( trim_some(" 0L -> abc while (abc) { FALSE }"), NULL, linter ) expect_lint( trim_some(" if (x > 20L) { x <- x / 2.0 }"), NULL, linter ) expect_lint( trim_some(" i <- 1 while (i < 6L) { print(i) i <- i + 1 }"), NULL, linter ) expect_lint( trim_some(" foo <- function(x) { x <- x + 1 return(x) }"), NULL, linter ) expect_lint( trim_some(" f <- function() { p <- g() p <- if (is.null(p)) x else p }"), NULL, linter ) expect_lint( trim_some(" map( .x = 1:4, .f = ~ { x <- .x + 1 x } )"), NULL, linter ) expect_lint( trim_some(" lapply(1:4, function(x) { x <- x + 1 x })"), NULL, linter ) skip_if_not_r_version("4.1.0") expect_lint( trim_some(" map(1:4, \\(x) { x <- x + 1 x })"), NULL, linter ) }) test_that("implicit_assignment_linter respects except argument", { expect_lint( "local({ a <- 1L })", NULL, implicit_assignment_linter(except = NULL) ) expect_lint( "local({ a <- 1L })", NULL, implicit_assignment_linter(except = character(0L)) ) expect_lint( "local(a <- 1L)", rex::rex("Avoid implicit assignments in function calls."), implicit_assignment_linter(except = character(0L)) ) expect_lint( "local(a <- 1L)", rex::rex("Avoid implicit assignments in function calls."), implicit_assignment_linter(except = NULL) ) expect_lint( "local(a <- 1L)", NULL, implicit_assignment_linter(except = "local") ) }) test_that("implicit_assignment_linter skips allowed usages with braces", { linter <- implicit_assignment_linter(except = character(0L)) expect_lint( trim_some(" foo({ a <- 1L }) "), NULL, linter ) expect_lint( trim_some(" output <- capture.output({ x <- f() }) "), NULL, linter ) expect_lint( trim_some(" quote({ a <- 1L }) "), NULL, linter ) expect_lint( trim_some(" bquote({ a <- 1L }) "), NULL, linter ) expect_lint( trim_some(" expression({ a <- 1L }) "), NULL, linter ) expect_lint( trim_some(" local({ a <- 1L }) "), NULL, linter ) }) test_that("implicit_assignment_linter makes exceptions for functions that capture side-effects", { linter <- implicit_assignment_linter() expect_lint( trim_some(" test_that('my test', { a <- 1L expect_equal(a, 1L) })"), NULL, linter ) # rlang expect_lint("expr(a <- 1L)", NULL, linter) expect_lint("quo(a <- 1L)", NULL, linter) expect_lint("quos(a <- 1L)", NULL, linter) }) test_that("implicit_assignment_linter blocks disallowed usages in simple conditional statements", { lint_message <- rex::rex("Avoid implicit assignments in function calls.") linter <- implicit_assignment_linter() expect_lint("if (x <- 1L) TRUE", lint_message, linter) expect_lint("if (1L -> x) TRUE", lint_message, linter) expect_lint("if (x <<- 1L) TRUE", lint_message, linter) expect_lint("if (1L ->> x) TRUE", lint_message, linter) expect_lint("while (x <- 0L) FALSE", lint_message, linter) expect_lint("while (0L -> x) FALSE", lint_message, linter) expect_lint("for (x in y <- 1:10) print(x)", lint_message, linter) expect_lint("for (x in 1:10 -> y) print(x)", lint_message, linter) }) test_that("implicit_assignment_linter blocks disallowed usages in nested conditional statements", { lint_message <- rex::rex("Avoid implicit assignments in function calls.") linter <- implicit_assignment_linter() expect_lint( trim_some(" while (x <- 1L) { if (0L -> y) FALSE }"), list( list(message = lint_message, line_number = 1L, column_number = 8L), list(message = lint_message, line_number = 2L, column_number = 7L) ), linter ) expect_lint( trim_some(" for (x in y <- 1:10) { if (0L -> y) print(x) }"), list( list(message = lint_message, line_number = 1L, column_number = 11L), list(message = lint_message, line_number = 2L, column_number = 7L) ), linter ) }) test_that("implicit_assignment_linter blocks disallowed usages in function calls", { lint_message <- rex::rex("Avoid implicit assignments in function calls.") linter <- implicit_assignment_linter() expect_lint("mean(x <- 1:4)", lint_message, linter) expect_lint( "mean(x <- (y <- 1:3) + 1L)", list(list(column_number = 6L), list(column_number = 12L)), linter ) expect_lint("y <- median(x <- 1:4)", lint_message, linter) expect_lint("lapply(x, function(x) return(x <- x + 1))", lint_message, linter) expect_lint("map(x, function(x) return(x <- x + 1))", lint_message, linter) expect_lint("expect_warning(out <- f(-1))", lint_message, linter) expect_lint("expect_message(out <- f(-1))", lint_message, linter) expect_lint("expect_error(out <- f(-1))", lint_message, linter) expect_lint("expect_condition(out <- f(-1))", lint_message, linter) expect_lint( trim_some(" foo <- function(x) { return(x <- x + 1) }"), lint_message, linter ) expect_lint( trim_some(" foo <- function(x) { if (x <- 1L) x <- 2L return(x <- x + 1) }"), list( list(message = lint_message, line_number = 2L, column_number = 7L), list(message = lint_message, line_number = 3L, column_number = 10L) ), linter ) expect_lint( trim_some(" map( .x = 1:4, .f = ~ .x + 1 -> x )"), lint_message, linter ) expect_lint( trim_some(" map( .x = 1:4, .f = ~ (x <- .x + 1) )"), lint_message, linter ) expect_lint( "foo(a <- 1, b <- 2, c <- 3)", list(list(column_number = 5L), list(column_number = 13L), list(column_number = 21L)), linter ) }) test_that("implicit_assignment_linter works as expected with pipes and walrus operator", { linter <- implicit_assignment_linter() expect_lint("data %>% mutate(a := b)", NULL, linter) expect_lint("dt %>% .[, z := x + y]", NULL, linter) expect_lint("data %<>% mutate(a := b)", NULL, linter) expect_lint("DT[i, x := i]", NULL, linter) skip_if_not_r_version("4.1.0") expect_lint("data |> mutate(a := b)", NULL, linter) }) test_that("parenthetical assignments are caught", { expect_lint( "if (A && (B <- foo())) { }", rex::rex("Avoid implicit assignments in function calls."), implicit_assignment_linter() ) }) test_that("allow_lazy lets lazy assignments through", { linter <- implicit_assignment_linter(allow_lazy = TRUE) lint_message <- rex::rex("Avoid implicit assignments in function calls.") expect_lint("A && (B <- foo(A))", NULL, linter) # || also admits laziness expect_lint("A || (B <- foo(A))", NULL, linter) # & and |, however, do not expect_lint("A & (B <- foo(A))", lint_message, linter) expect_lint("A | (B <- foo(A))", lint_message, linter) expect_lint("A && foo(bar(idx <- baz()))", NULL, linter) # LHS _is_ linted expect_lint("(A <- foo()) && B", lint_message, linter) # however we skip on _any_ RHS (even if it's later an LHS) # test on all &&/|| combinations to stress test operator precedence expect_lint("A && (B <- foo(A)) && C", NULL, linter) expect_lint("A && (B <- foo(A)) || C", NULL, linter) expect_lint("A || (B <- foo(A)) && C", NULL, linter) expect_lint("A || (B <- foo(A)) || C", NULL, linter) # &&/|| elsewhere in the tree don't matter expect_lint( trim_some(" A && B foo(C <- bar()) "), lint_message, linter ) }) test_that("allow_scoped skips scoped assignments", { linter <- implicit_assignment_linter(allow_scoped = TRUE) lint_message <- rex::rex("Avoid implicit assignments in function calls.") expect_lint( trim_some(" if (any(idx <- x < 0)) { stop('negative elements: ', toString(which(idx))) } "), NULL, linter ) expect_lint( trim_some(" if (any(idx <- x < 0)) { stop('negative elements: ', toString(which(idx))) } print(idx) "), lint_message, linter ) # only applies to the branch condition itself -- within the branch, still lint expect_lint( trim_some(" if (TRUE) { foo(idx <- bar()) } "), lint_message, linter ) expect_lint( trim_some(" obj <- letters while ((n <- length(obj)) > 0) obj <- obj[-n] "), NULL, linter ) expect_lint( trim_some(" obj <- letters while ((n <- length(obj)) > 0) obj <- obj[-n] if (TRUE) { print(n) } "), lint_message, linter ) # outside of branching, doesn't matter expect_lint("foo(idx <- bar()); baz()", lint_message, linter) expect_lint("foo(x, idx <- bar()); baz()", lint_message, linter) }) test_that("interaction of allow_lazy and allow_scoped", { linter <- implicit_assignment_linter(allow_scoped = TRUE, allow_lazy = TRUE) expect_lint( trim_some(" if (any(idx <- foo()) && BB) { stop('Invalid foo() output: ', toString(idx)) } "), NULL, linter ) expect_lint( trim_some(" if (any(idx <- foo()) && BB) { stop('Invalid foo() output: ', toString(idx)) } print(format(idx)) "), rex::rex("Avoid implicit assignments in function calls."), linter ) expect_lint( trim_some(" if (AA && any(idx <- foo())) { stop('Invalid foo() output: ', toString(idx)) } print(format(idx)) # NB: bad code! idx may not exist. "), NULL, linter ) }) test_that("call-less '(' mentions avoiding implicit printing", { linter <- implicit_assignment_linter() implicit_msg <- rex::rex("Avoid implicit assignments in function calls.") print_msg <- rex::rex("Call print() explicitly instead of relying on implicit printing behavior via '('.") expect_lint("(a <- foo())", print_msg, linter) # only for top-level assignments; withAutoprint() ignored expect_lint("for (xi in x) (z <- foo(xi))", implicit_msg, linter) # mixed messages expect_lint( trim_some(" (a <- foo()) bar(z <- baz(a)) "), list(print_msg, implicit_msg), linter ) }) lintr/tests/testthat/test-repeat_linter.R0000644000176200001440000000163314752731051020351 0ustar liggesuserstest_that("test repeat_linter", { linter <- repeat_linter() msg <- rex::rex("Use 'repeat' instead of 'while (TRUE)' for infinite loops.") expect_lint("repeat { }", NULL, linter) expect_lint("while (FALSE) { }", NULL, linter) expect_lint("while (i < 5) { }", NULL, linter) expect_lint("while (j < 5) TRUE", NULL, linter) expect_lint("while (TRUE && j < 5) { ... }", NULL, linter) expect_lint("while (TRUE) { }", msg, linter) expect_lint("for (i in 1:10) { while (TRUE) { if (i == 5) { break } } }", msg, linter) expect_lint("while (TRUE) { while (TRUE) { } }", list(msg, msg), linter) expect_lint( trim_some("{ while (TRUE) { } while (TRUE) { } }"), list( list(message = msg, line_number = 2L, column_number = 3L, ranges = list(c(3L, 14L))), list(message = msg, line_number = 4L, column_number = 3L, ranges = list(c(3L, 14L))) ), linter ) }) lintr/tests/testthat/lints0000644000176200001440000005374314752731051015501 0ustar liggesusers[R/AES.R:30:34:](https://github.com///blob//R/AES.R#L30) *style:* **Put spaces around all infix operators.** ```r for (i in seq_len(len/16)) { ~^~ ``` [R/AES.R:31:26:](https://github.com///blob//R/AES.R#L31) *style:* **Put spaces around all infix operators.** ```r ind <- (i-1)*16 + 1:16 ~^~ ``` [R/AES.R:31:29:](https://github.com///blob//R/AES.R#L31) *style:* **Put spaces around all infix operators.** ```r ind <- (i-1)*16 + 1:16 ~^~ ``` [R/AES.R:39:29:](https://github.com///blob//R/AES.R#L39) *style:* **Put spaces around all infix operators.** ```r result <- raw(16*blocks) ~^~ ``` [R/AES.R:42:26:](https://github.com///blob//R/AES.R#L42) *style:* **Put spaces around all infix operators.** ```r result[16*(i-1)+1:16] <- IV ~^~ ``` [R/AES.R:42:27:](https://github.com///blob//R/AES.R#L42) *style:* **Place a space before left parenthesis, except in a function call.** ```r result[16*(i-1)+1:16] <- IV ^ ``` [R/AES.R:42:29:](https://github.com///blob//R/AES.R#L42) *style:* **Put spaces around all infix operators.** ```r result[16*(i-1)+1:16] <- IV ~^~ ``` [R/AES.R:42:32:](https://github.com///blob//R/AES.R#L42) *style:* **Put spaces around all infix operators.** ```r result[16*(i-1)+1:16] <- IV ~^~ ``` [R/AES.R:64:34:](https://github.com///blob//R/AES.R#L64) *style:* **Put spaces around all infix operators.** ```r for (i in seq_len(len/16)) { ~^~ ``` [R/AES.R:65:26:](https://github.com///blob//R/AES.R#L65) *style:* **Put spaces around all infix operators.** ```r ind <- (i-1)*16 + 1:16 ~^~ ``` [R/AES.R:65:29:](https://github.com///blob//R/AES.R#L65) *style:* **Put spaces around all infix operators.** ```r ind <- (i-1)*16 + 1:16 ~^~ ``` [R/AES.R:72:1:](https://github.com///blob//R/AES.R#L72) *style:* **Trailing whitespace is superfluous.** ```r ^~~~~~~~ ``` [R/AES.R:89:1:](https://github.com///blob//R/AES.R#L89) *style:* **Trailing blank lines are superfluous.** ```r ^ ``` [R/digest.R:54:1:](https://github.com///blob//R/digest.R#L54) *style:* **lines should not be more than 80 characters.** ```r stop("Argument object must be of type character or raw vector if serialize is FALSE") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [R/digest.R:71:27:](https://github.com///blob//R/digest.R#L71) *style:* **Put spaces around all infix operators.** ```r algoint <- algoint+100 ~^~ ``` [R/hmac.R:4:15:](https://github.com///blob//R/hmac.R#L4) *style:* **Only use double-quotes.** ```r UseMethod('makeRaw') ^~~~~~~~~ ``` [R/hmac.R:13:33:](https://github.com///blob//R/hmac.R#L13) *style:* **Opening curly braces should never go on their own line and should always be followed by a new line.** ```r function(i) { substr(x, i, i + 1) }) ^ ``` [R/hmac.R:13:55:](https://github.com///blob//R/hmac.R#L13) *style:* **Closing curly-braces should always be on their own line, unless it's followed by an else.** ```r function(i) { substr(x, i, i + 1) }) ^ ``` [R/hmac.R:29:20:](https://github.com///blob//R/hmac.R#L29) *style:* **Trailing whitespace is superfluous.** ```r blocksize <- 64 ^ ``` [R/hmac.R:33:31:](https://github.com///blob//R/hmac.R#L33) *style:* **Opening curly braces should never go on their own line and should always be followed by a new line.** ```r if(length(k) > blocksize) {# not while() ^ ``` [R/hmac.R:33:45:](https://github.com///blob//R/hmac.R#L33) *style:* **Trailing whitespace is superfluous.** ```r if(length(k) > blocksize) {# not while() ^ ``` [R/hmac.R:34:11:](https://github.com///blob//R/hmac.R#L34) *style:* **Put spaces around all infix operators.** ```r k <-digest(k, algo=algo, serialize=FALSE,raw=TRUE) ^~~ ``` [R/hmac.R:47:5:](https://github.com///blob//R/hmac.R#L47) *style:* **Words within variable and function names should be separated by '_' rather than '.'.** ```r i.xored.key <- xor(padded.key, makeRaw(0x36)) ^~~~~~~~~~~ ``` [R/hmac.R:48:34:](https://github.com///blob//R/hmac.R#L48) *style:* **Words within variable and function names should be separated by '_' rather than '.'.** ```r character.digest <- digest(c(i.xored.key, makeRaw(object)), ^~~~~~~~~~~ ``` [R/hmac.R:51:5:](https://github.com///blob//R/hmac.R#L51) *style:* **Words within variable and function names should be separated by '_' rather than '.'.** ```r o.xored.key <- xor(padded.key, makeRaw(0x5c)) ^~~~~~~~~~~ ``` [R/hmac.R:52:1:](https://github.com///blob//R/hmac.R#L52) *style:* **lines should not be more than 80 characters.** ```r result <- digest(c(o.xored.key, raw.digest), algo=algo, serialize=serialize, ...) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [R/hmac.R:52:24:](https://github.com///blob//R/hmac.R#L52) *style:* **Words within variable and function names should be separated by '_' rather than '.'.** ```r result <- digest(c(o.xored.key, raw.digest), algo=algo, serialize=serialize, ...) ^~~~~~~~~~~ ``` [tests/AESTest.R:8:1:](https://github.com///blob//tests/AESTest.R#L8) *style:* **Variable and function names should be all lowercase.** ```r hextextToRaw <- function(text) { ^~~~~~~~~~~~ ``` [tests/AESTest.R:9:1:](https://github.com///blob//tests/AESTest.R#L9) *style:* **lines should not be more than 80 characters.** ```r vals <- matrix(as.integer(as.hexmode(strsplit(text, "")[[1]])), ncol=2, byrow=TRUE) ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/AESTest.R:14:20:](https://github.com///blob//tests/AESTest.R#L14) *style:* **Variable and function names should be all lowercase.** ```r plaintext <- hextextToRaw("00112233445566778899aabbccddeeff") ^~~~~~~~~~~~ ``` [tests/AESTest.R:16:20:](https://github.com///blob//tests/AESTest.R#L16) *style:* **Variable and function names should be all lowercase.** ```r aes128key <- hextextToRaw("000102030405060708090a0b0c0d0e0f") ^~~~~~~~~~~~ ``` [tests/AESTest.R:17:20:](https://github.com///blob//tests/AESTest.R#L17) *style:* **Variable and function names should be all lowercase.** ```r aes128output <- hextextToRaw("69c4e0d86a7b0430d8cdb78070b4c55a") ^~~~~~~~~~~~ ``` [tests/AESTest.R:24:1:](https://github.com///blob//tests/AESTest.R#L24) *style:* **lines should not be more than 80 characters.** ```r aes192key <- hextextToRaw("000102030405060708090a0b0c0d0e0f1011121314151617") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/AESTest.R:24:20:](https://github.com///blob//tests/AESTest.R#L24) *style:* **Variable and function names should be all lowercase.** ```r aes192key <- hextextToRaw("000102030405060708090a0b0c0d0e0f1011121314151617") ^~~~~~~~~~~~ ``` [tests/AESTest.R:25:20:](https://github.com///blob//tests/AESTest.R#L25) *style:* **Variable and function names should be all lowercase.** ```r aes192output <- hextextToRaw("dda97ca4864cdfe06eaf70a0ec0d7191") ^~~~~~~~~~~~ ``` [tests/AESTest.R:32:1:](https://github.com///blob//tests/AESTest.R#L32) *style:* **lines should not be more than 80 characters.** ```r aes256key <- hextextToRaw("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/AESTest.R:32:20:](https://github.com///blob//tests/AESTest.R#L32) *style:* **Variable and function names should be all lowercase.** ```r aes256key <- hextextToRaw("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f") ^~~~~~~~~~~~ ``` [tests/AESTest.R:33:21:](https://github.com///blob//tests/AESTest.R#L33) *style:* **Variable and function names should be all lowercase.** ```r aes256output <- hextextToRaw("8ea2b7ca516745bfeafc49904b496089") ^~~~~~~~~~~~ ``` [tests/AESTest.R:42:14:](https://github.com///blob//tests/AESTest.R#L42) *style:* **Variable and function names should be all lowercase.** ```r plaintext <- hextextToRaw(paste("6bc1bee22e409f96e93d7e117393172a", ^~~~~~~~~~~~ ``` [tests/AESTest.R:46:8:](https://github.com///blob//tests/AESTest.R#L46) *style:* **Variable and function names should be all lowercase.** ```r key <- hextextToRaw("2b7e151628aed2a6abf7158809cf4f3c") ^~~~~~~~~~~~ ``` [tests/AESTest.R:48:17:](https://github.com///blob//tests/AESTest.R#L48) *style:* **Variable and function names should be all lowercase.** ```r ecb128output <- hextextToRaw(paste("3ad77bb40d7a3660a89ecaf32466ef97", ^~~~~~~~~~~~ ``` [tests/AESTest.R:58:17:](https://github.com///blob//tests/AESTest.R#L58) *style:* **Variable and function names should be all lowercase.** ```r cbc128output <- hextextToRaw(paste("7649abac8119b246cee98e9b12e9197d", ^~~~~~~~~~~~ ``` [tests/AESTest.R:62:7:](https://github.com///blob//tests/AESTest.R#L62) *style:* **Variable and function names should be all lowercase.** ```r iv <- hextextToRaw("000102030405060708090a0b0c0d0e0f") ^~~~~~~~~~~~ ``` [tests/AESTest.R:70:17:](https://github.com///blob//tests/AESTest.R#L70) *style:* **Variable and function names should be all lowercase.** ```r ctr128output <- hextextToRaw(paste("874d6191b620e3261bef6864990db6ce", ^~~~~~~~~~~~ ``` [tests/AESTest.R:74:7:](https://github.com///blob//tests/AESTest.R#L74) *style:* **Variable and function names should be all lowercase.** ```r iv <- hextextToRaw("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") ^~~~~~~~~~~~ ``` [tests/digestTest.R:67:13:](https://github.com///blob//tests/digestTest.R#L67) *style:* **Put spaces around all infix operators.** ```r sha512Input <-c( ^~~ ``` [tests/digestTest.R:72:1:](https://github.com///blob//tests/digestTest.R#L72) *style:* **lines should not be more than 80 characters.** ```r "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/digestTest.R:73:1:](https://github.com///blob//tests/digestTest.R#L73) *style:* **lines should not be more than 80 characters.** ```r "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:7:17:](https://github.com///blob//tests/hmacTest.R#L7) *style:* **Only use double-quotes.** ```r current <- hmac('Jefe', 'what do ya want for nothing?', "md5") ^~~~~~ ``` [tests/hmacTest.R:7:25:](https://github.com///blob//tests/hmacTest.R#L7) *style:* **Only use double-quotes.** ```r current <- hmac('Jefe', 'what do ya want for nothing?', "md5") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:8:11:](https://github.com///blob//tests/hmacTest.R#L8) *style:* **Only use double-quotes.** ```r target <- '750c783e6ab0b503eaa86e310a5db738' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:12:17:](https://github.com///blob//tests/hmacTest.R#L12) *style:* **Only use double-quotes.** ```r current <- hmac('Jefe', 'what do ya want for nothing?', "md5") ^~~~~~ ``` [tests/hmacTest.R:12:25:](https://github.com///blob//tests/hmacTest.R#L12) *style:* **Only use double-quotes.** ```r current <- hmac('Jefe', 'what do ya want for nothing?', "md5") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:13:11:](https://github.com///blob//tests/hmacTest.R#L13) *style:* **Only use double-quotes.** ```r target <- '750c783e6ab0b503eaa86e310a5db738' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:17:32:](https://github.com///blob//tests/hmacTest.R#L17) *style:* **Only use double-quotes.** ```r current <- hmac(rep(0x0b, 16), 'Hi There', "md5") ^~~~~~~~~~ ``` [tests/hmacTest.R:18:11:](https://github.com///blob//tests/hmacTest.R#L18) *style:* **Only use double-quotes.** ```r target <- '9294727a3638bb1c13f48ef8158bfc9d' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:23:11:](https://github.com///blob//tests/hmacTest.R#L23) *style:* **Only use double-quotes.** ```r target <- '56be34521d144c88dbb8c733f0e8b3f6' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:29:1:](https://github.com///blob//tests/hmacTest.R#L29) *style:* **lines should not be more than 80 characters.** ```r current <- hmac('ThisKeyIsLongerThan64BytesAndThereforeLongerThanTheHashDigestByFour', 'what do ya want for nothing?', "md5") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:29:17:](https://github.com///blob//tests/hmacTest.R#L29) *style:* **Only use double-quotes.** ```r current <- hmac('ThisKeyIsLongerThan64BytesAndThereforeLongerThanTheHashDigestByFour', 'what do ya want for nothing?', "md5") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:29:88:](https://github.com///blob//tests/hmacTest.R#L29) *style:* **Only use double-quotes.** ```r current <- hmac('ThisKeyIsLongerThan64BytesAndThereforeLongerThanTheHashDigestByFour', 'what do ya want for nothing?', "md5") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:30:11:](https://github.com///blob//tests/hmacTest.R#L30) *style:* **Only use double-quotes.** ```r target <- '109af8ddd9cccbf8927d354da8be892b' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:36:17:](https://github.com///blob//tests/hmacTest.R#L36) *style:* **Only use double-quotes.** ```r current <- hmac('Jefe', 'what do ya want for nothing?', "sha1") ^~~~~~ ``` [tests/hmacTest.R:36:25:](https://github.com///blob//tests/hmacTest.R#L36) *style:* **Only use double-quotes.** ```r current <- hmac('Jefe', 'what do ya want for nothing?', "sha1") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:37:11:](https://github.com///blob//tests/hmacTest.R#L37) *style:* **Only use double-quotes.** ```r target <- 'effcdf6ae5eb2fa2d27416d5f184df9c259a7c79' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:41:32:](https://github.com///blob//tests/hmacTest.R#L41) *style:* **Only use double-quotes.** ```r current <- hmac(rep(0x0b, 16), 'Hi There', "sha1") ^~~~~~~~~~ ``` [tests/hmacTest.R:42:11:](https://github.com///blob//tests/hmacTest.R#L42) *style:* **Only use double-quotes.** ```r target <- '675b0b3a1b4ddf4e124872da6c2f632bfed957e9' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:47:11:](https://github.com///blob//tests/hmacTest.R#L47) *style:* **Only use double-quotes.** ```r target <- 'd730594d167e35d5956fd8003d0db3d3f46dc7bb' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:52:17:](https://github.com///blob//tests/hmacTest.R#L52) *style:* **Only use double-quotes.** ```r current <- hmac('key', 'The quick brown fox jumps over the lazy dog', 'sha256') ^~~~~ ``` [tests/hmacTest.R:52:24:](https://github.com///blob//tests/hmacTest.R#L52) *style:* **Only use double-quotes.** ```r current <- hmac('key', 'The quick brown fox jumps over the lazy dog', 'sha256') ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:52:71:](https://github.com///blob//tests/hmacTest.R#L52) *style:* **Only use double-quotes.** ```r current <- hmac('key', 'The quick brown fox jumps over the lazy dog', 'sha256') ^~~~~~~~ ``` [tests/hmacTest.R:53:11:](https://github.com///blob//tests/hmacTest.R#L53) *style:* **Only use double-quotes.** ```r target <- 'f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:63:17:](https://github.com///blob//tests/hmacTest.R#L63) *style:* **Only use double-quotes.** ```r current <- hmac('Jefe', 'what do ya want for nothing?', "sha512") ^~~~~~ ``` [tests/hmacTest.R:63:25:](https://github.com///blob//tests/hmacTest.R#L63) *style:* **Only use double-quotes.** ```r current <- hmac('Jefe', 'what do ya want for nothing?', "sha512") ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:64:1:](https://github.com///blob//tests/hmacTest.R#L64) *style:* **lines should not be more than 80 characters.** ```r target <- '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:64:11:](https://github.com///blob//tests/hmacTest.R#L64) *style:* **Only use double-quotes.** ```r target <- '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:68:17:](https://github.com///blob//tests/hmacTest.R#L68) *style:* **Only use double-quotes.** ```r current <- hmac('love', 'message', 'sha512') ^~~~~~ ``` [tests/hmacTest.R:68:25:](https://github.com///blob//tests/hmacTest.R#L68) *style:* **Only use double-quotes.** ```r current <- hmac('love', 'message', 'sha512') ^~~~~~~~~ ``` [tests/hmacTest.R:68:36:](https://github.com///blob//tests/hmacTest.R#L68) *style:* **Only use double-quotes.** ```r current <- hmac('love', 'message', 'sha512') ^~~~~~~~ ``` [tests/hmacTest.R:69:1:](https://github.com///blob//tests/hmacTest.R#L69) *style:* **lines should not be more than 80 characters.** ```r target <- 'f955821b3f6161673eb20985c677e3dc101860cafef3321ee31641acad9fcd85d9c7d3481ed3e4e1f4fa7af41d7e6ea9606d51e9bc7205d0091a4ee87d90fb9c' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:69:11:](https://github.com///blob//tests/hmacTest.R#L69) *style:* **Only use double-quotes.** ```r target <- 'f955821b3f6161673eb20985c677e3dc101860cafef3321ee31641acad9fcd85d9c7d3481ed3e4e1f4fa7af41d7e6ea9606d51e9bc7205d0091a4ee87d90fb9c' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:74:1:](https://github.com///blob//tests/hmacTest.R#L74) *style:* **lines should not be more than 80 characters.** ```r current <- hmac('verylongkeyinfactlongerthanthedigestandthereforehashedbyitselfonlyifwegettothislengthsoonpleasepleasebutiddoesnotlooksoogoodahthereweare', 'message', 'sha512') ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:74:17:](https://github.com///blob//tests/hmacTest.R#L74) *style:* **Only use double-quotes.** ```r current <- hmac('verylongkeyinfactlongerthanthedigestandthereforehashedbyitselfonlyifwegettothislengthsoonpleasepleasebutiddoesnotlooksoogoodahthereweare', 'message', 'sha512') ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:74:157:](https://github.com///blob//tests/hmacTest.R#L74) *style:* **Only use double-quotes.** ```r current <- hmac('verylongkeyinfactlongerthanthedigestandthereforehashedbyitselfonlyifwegettothislengthsoonpleasepleasebutiddoesnotlooksoogoodahthereweare', 'message', 'sha512') ^~~~~~~~~ ``` [tests/hmacTest.R:74:168:](https://github.com///blob//tests/hmacTest.R#L74) *style:* **Only use double-quotes.** ```r current <- hmac('verylongkeyinfactlongerthanthedigestandthereforehashedbyitselfonlyifwegettothislengthsoonpleasepleasebutiddoesnotlooksoogoodahthereweare', 'message', 'sha512') ^~~~~~~~ ``` [tests/hmacTest.R:75:1:](https://github.com///blob//tests/hmacTest.R#L75) *style:* **lines should not be more than 80 characters.** ```r target <- '54b274484a8b8a371c8ae898f453d37c90d488b0c88c89dd705de06b18263d50c28069f1f778c8a997a61a4d53a06bc8e8719ad11a553c49140bb93a4636882e' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:75:11:](https://github.com///blob//tests/hmacTest.R#L75) *style:* **Only use double-quotes.** ```r target <- '54b274484a8b8a371c8ae898f453d37c90d488b0c88c89dd705de06b18263d50c28069f1f778c8a997a61a4d53a06bc8e8719ad11a553c49140bb93a4636882e' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``` [tests/hmacTest.R:78:1:](https://github.com///blob//tests/hmacTest.R#L78) *style:* **Trailing blank lines are superfluous.** ```r ^ ``` lintr/tests/testthat/test-redundant_equals_linter.R0000644000176200001440000000227514752731051022432 0ustar liggesuserstest_that("redundant_equals_linter skips allowed usages", { # comparisons to non-logical constants expect_lint("x == 1", NULL, redundant_equals_linter()) # comparison to TRUE as a string expect_lint("x != 'TRUE'", NULL, redundant_equals_linter()) }) test_that("multiple lints return correct custom messages", { expect_lint( trim_some(" list( x == TRUE, y != TRUE ) "), list( list("Using == on a logical vector", line_number = 2L), list("Using != on a logical vector", line_number = 3L) ), redundant_equals_linter() ) }) test_that("Order doesn't matter", { expect_lint("TRUE == x", rex::rex("Using == on a logical vector is redundant."), redundant_equals_linter()) }) patrick::with_parameters_test_that( "redundant_equals_linter blocks simple disallowed usages", { lint_msg <- rex::rex(paste("Using", op, "on a logical vector is redundant.")) code <- paste("x", op, bool) expect_lint(code, lint_msg, redundant_equals_linter()) }, .cases = tibble::tribble( ~.test_name, ~op, ~bool, "==, TRUE", "==", "TRUE", "==, FALSE", "==", "FALSE", "!=, TRUE", "!=", "TRUE", "!=, FALSE", "!=", "FALSE" ) ) lintr/tests/testthat/test-with.R0000644000176200001440000001120214752731051016460 0ustar liggesuserstest_that("modify_defaults produces error with missing or incorrect defaults", { expect_error( modify_defaults(), "`defaults` is a required argument, but is missing", fixed = TRUE ) expect_error( modify_defaults("assignment_linter"), "`defaults` must be a named list", fixed = TRUE ) }) test_that("linters_with_tags produces error with incorrect tags", { expect_error(linters_with_tags(1L:4L), "`tags` must be a character vector, or `NULL`", fixed = TRUE) }) test_that("linters_with_defaults works as expected with unnamed args", { # assignment_linter is in defaults, so output doesn't change expect_named(linters_with_defaults(assignment_linter), names(linters_with_defaults())) }) test_that("linters_with_defaults warns on unused NULLs", { expect_warning(linters_with_defaults(not_a_default = NULL), rex::rex("which is not in `defaults`.")) expect_warning( linters_with_defaults(not_a_default = NULL, also_not_default = NULL), rex::rex("which are not in `defaults`.") ) }) test_that("linters_with_tags() verifies the output of available_linters()", { local_mocked_bindings( available_linters = function(...) { data.frame(linter = c("fake_linter", "very_fake_linter"), package = "lintr", tags = "") } ) expect_error( linters_with_tags(NULL), "Can't find linters `fake_linter()` and `very_fake_linter()`", fixed = TRUE ) }) test_that("all default linters are tagged default", { expect_named(linters_with_defaults(), available_linters(tags = "default")$linter) # covr modifies package functions causing differing deparse() results even for identical anonymous functions. # This happens because default_linters is generated at build time and thus not modifiable by covr, whereas # linters_with_tags() constructs the linters at runtime. skip_on_covr() expect_identical(linters_with_tags("default"), linters_with_defaults()) expect_length(linters_with_tags(NULL, exclude_tags = available_tags()), 0L) # Check that above test also trips on default arguments. skip_if_not_r_version("4.1.0") # Desired all.equal behavior only available in >= 4.1 expect_identical( all.equal(linters_with_tags("default"), linters_with_defaults(line_length_linter(120L))), c( 'Component "line_length_linter": Component "general_msg": 1 string mismatch', 'Component "line_length_linter": Component "length": Mean relative difference: 0.5' ) ) }) test_that("can instantiate all linters without arguments", { all_linters <- linters_with_tags(tags = NULL) expect_type(all_linters, "list") expect_length(all_linters, nrow(available_linters())) really_all_linters <- suppressWarnings(linters_with_tags(tags = NULL, exclude_tags = NULL)) expect_type(really_all_linters, "list") expect_length(really_all_linters, nrow(available_linters(exclude_tags = NULL))) }) test_that("with_defaults is fully deprecated", { expect_error( with_defaults(), rex::rex("Use linters_with_defaults or modify_defaults instead.") ) }) test_that("modify_defaults works", { my_default <- list(a = 1L, b = 2L, c = 3L) expect_identical(modify_defaults(defaults = my_default), my_default) expect_identical(modify_defaults(defaults = my_default, a = 2L), list(a = 2L, b = 2L, c = 3L)) expect_identical(modify_defaults(defaults = my_default, c = NULL), list(a = 1L, b = 2L)) # auto-sorts expect_identical(modify_defaults(defaults = list(b = 2L, a = 1L), c = 3L), my_default) }) test_that("linters_with_defaults(default = .) is supported with a deprecation warning", { expect_warning( { linters <- linters_with_defaults(default = list(), whitespace_linter()) }, "`default` is not an argument" ) expect_named(linters, "whitespace_linter") # the same warning is not triggered in modify_defaults expect_silent({ linters <- modify_defaults(defaults = list(), default = list(), whitespace_linter()) }) expect_named(linters, c("default", "whitespace_linter")) # if default= is explicitly provided alongside defaults=, assume that was intentional default <- Linter(function(.) list()) expect_silent({ linters <- linters_with_defaults(defaults = list(), default = default) }) expect_named(linters, "default") }) test_that("all_linters contains all available linters", { all_linters <- all_linters(packages = "lintr") expect_identical(linters_with_tags(NULL, packages = "lintr"), all_linters) expect_length(all_linters, nrow(available_linters())) }) test_that("all_linters respects ellipsis argument", { expect_identical( linters_with_tags(tags = NULL, implicit_integer_linter = NULL), all_linters(packages = "lintr", implicit_integer_linter = NULL) ) }) lintr/tests/testthat/test-ids_with_token.R0000644000176200001440000000077014752731051020527 0ustar liggesuserstest_that("ids_with_token works as expected", { source_expression <- get_source_expressions("tmp.R", "a <- 42L")$expressions[[1L]] ref <- ids_with_token(source_expression = source_expression, value = "expr") expect_identical(ref, c(1L, 3L, 6L)) expect_identical(source_expression$parsed_content$token[ref], rep_len("expr", length(ref))) # deprecated argument expect_error( ids_with_token(source_file = source_expression, value = "expr"), "Argument source_file was deprecated" ) }) lintr/tests/testthat/test-expect_type_linter.R0000644000176200001440000000533214752731051021422 0ustar liggesuserstest_that("expect_type_linter skips allowed usages", { linter <- expect_type_linter() # expect_type doesn't have an inverted version expect_lint("expect_true(!is.numeric(x))", NULL, linter) # NB: also applies to tinytest, but it's sufficient to test testthat expect_lint("testthat::expect_true(!is.numeric(x))", NULL, linter) # other is. calls are not suitable for expect_type in particular expect_lint("expect_true(is.data.frame(x))", NULL, linter) # expect_type(x, ...) cannot be cleanly used here: expect_lint("expect_true(typeof(x) %in% c('builtin', 'closure'))", NULL, linter) # expect_type() doesn't have info= or label= arguments expect_lint("expect_equal(typeof(x), t, info = 'x should have type t')", NULL, linter) expect_lint("expect_equal(typeof(x), t, label = 'x type')", NULL, linter) expect_lint("expect_equal(typeof(x), t, expected.label = 'type')", NULL, linter) expect_lint("expect_true(is.double(x), info = 'x should be double')", NULL, linter) }) test_that("expect_type_linter blocks simple disallowed usages", { linter <- expect_type_linter() expect_lint( "expect_equal(typeof(x), 'double')", rex::rex("expect_type(x, t) is better than expect_equal(typeof(x), t)"), linter ) # expect_identical is treated the same as expect_equal expect_lint( "testthat::expect_identical(typeof(x), 'language')", rex::rex("expect_type(x, t) is better than expect_identical(typeof(x), t)"), linter ) # different equivalent usage expect_lint( "expect_true(is.complex(foo(x)))", rex::rex("expect_type(x, t) is better than expect_true(is.(x))"), linter ) # yoda test with clear expect_type replacement expect_lint( "expect_equal('integer', typeof(x))", rex::rex("expect_type(x, t) is better than expect_equal(typeof(x), t)"), linter ) }) local({ # test for lint errors appropriately raised for all is. calls is_types <- c( "raw", "logical", "integer", "double", "complex", "character", "list", "numeric", "function", "primitive", "environment", "pairlist", "promise", "language", "call", "name", "symbol", "expression" ) patrick::with_parameters_test_that( "expect_type_linter catches expect_true(is.)", expect_lint( sprintf("expect_true(is.%s(x))", is_type), rex::rex("expect_type(x, t) is better than expect_true(is.(x))"), expect_type_linter() ), .test_name = is_types, is_type = is_types ) }) test_that("lints vectorize", { expect_lint( trim_some("{ expect_true(is.integer(x)) expect_equal(typeof(x), 'double') }"), list( list("expect_true", line_number = 2L), list("expect_equal", line_number = 3L) ), expect_type_linter() ) }) lintr/tests/testthat/test-conjunct_test_linter.R0000644000176200001440000001306114752731051021751 0ustar liggesuserstest_that("conjunct_test_linter skips allowed usages of expect_true", { expect_lint("expect_true(x)", NULL, conjunct_test_linter()) expect_lint("testthat::expect_true(x, y, z)", NULL, conjunct_test_linter()) # more complicated expression expect_lint("expect_true(x || (y && z))", NULL, conjunct_test_linter()) # the same by operator precedence, though not obvious a priori expect_lint("expect_true(x || y && z)", NULL, conjunct_test_linter()) expect_lint("expect_true(x && y || z)", NULL, conjunct_test_linter()) }) test_that("conjunct_test_linter skips allowed usages of expect_true", { expect_lint("expect_false(x)", NULL, conjunct_test_linter()) expect_lint("testthat::expect_false(x, y, z)", NULL, conjunct_test_linter()) # more complicated expression # (NB: xx && yy || zz and xx || yy && zz both parse with || first) expect_lint("expect_false(x && (y || z))", NULL, conjunct_test_linter()) }) test_that("conjunct_test_linter blocks && conditions with expect_true()", { linter <- conjunct_test_linter() lint_msg <- rex::rex("Write multiple expectations like expect_true(A) and expect_true(B) instead of expect_true(A && B)") expect_lint("expect_true(x && y)", lint_msg, linter) expect_lint("expect_true(x && y && z)", lint_msg, linter) }) test_that("conjunct_test_linter blocks || conditions with expect_false()", { linter <- conjunct_test_linter() lint_msg <- rex::rex("Write multiple expectations like expect_false(A) and expect_false(B) instead of expect_false(A || B)") expect_lint("expect_false(x || y)", lint_msg, linter) expect_lint("expect_false(x || y || z)", lint_msg, linter) # these lint because `||` is always outer by operator precedence expect_lint("expect_false(x || y && z)", lint_msg, linter) expect_lint("expect_false(x && y || z)", lint_msg, linter) }) test_that("conjunct_test_linter skips allowed stopifnot() and assert_that() usages", { linter <- conjunct_test_linter() expect_lint("stopifnot(x)", NULL, linter) expect_lint("assert_that(x, y, z)", NULL, linter) # more complicated expression expect_lint("stopifnot(x || (y && z))", NULL, linter) # the same by operator precedence, though not obvious a priori expect_lint("stopifnot(x || y && z)", NULL, linter) expect_lint("assertthat::assert_that(x && y || z)", NULL, linter) }) test_that("conjunct_test_linter blocks simple disallowed usages of stopifnot() and assert_that()", { linter <- conjunct_test_linter() lint_msg <- function(fun) rex::rex("Write multiple conditions like ", fun, "(A, B) instead of ", fun, "(A && B)") expect_lint("stopifnot(x && y)", lint_msg("stopifnot"), linter) expect_lint("stopifnot(x && y && z)", lint_msg("stopifnot"), linter) # assert_that() versions expect_lint("assert_that(x && y)", lint_msg("assert_that"), linter) expect_lint("assertthat::assert_that(x && y && z)", lint_msg("assert_that"), linter) }) test_that("conjunct_test_linter's allow_named_stopifnot argument works", { # allowed by default expect_lint( "stopifnot('x must be a logical scalar' = length(x) == 1 && is.logical(x) && !is.na(x))", NULL, conjunct_test_linter() ) expect_lint( "stopifnot('x is a logical scalar' = length(x) == 1 && is.logical(x) && !is.na(x))", rex::rex("Write multiple conditions like stopifnot(A, B)"), conjunct_test_linter(allow_named_stopifnot = FALSE) ) }) test_that("conjunct_test_linter skips allowed usages", { linter <- conjunct_test_linter() expect_lint("dplyr::filter(DF, A, B)", NULL, linter) expect_lint("dplyr::filter(DF, !(A & B))", NULL, linter) # | is the "top-level" operator here expect_lint("dplyr::filter(DF, A & B | C)", NULL, linter) expect_lint("dplyr::filter(DF, A | B & C)", NULL, linter) }) test_that("conjunct_test_linter blocks simple disallowed usages", { linter <- conjunct_test_linter() lint_msg <- rex::rex("Use dplyr::filter(DF, A, B) instead of dplyr::filter(DF, A & B)") expect_lint("dplyr::filter(DF, A & B)", lint_msg, linter) expect_lint("dplyr::filter(DF, A & B & C)", lint_msg, linter) # more common usage, in pipes expect_lint("DF %>% dplyr::filter(A & B)", lint_msg, linter) }) test_that("conjunct_test_linter respects its allow_filter argument", { linter_always <- conjunct_test_linter(allow_filter = "always") linter_dplyr <- conjunct_test_linter(allow_filter = "not_dplyr") lint_msg <- rex::rex("Use dplyr::filter(DF, A, B) instead of dplyr::filter(DF, A & B)") expect_lint("dplyr::filter(DF, A & B)", NULL, linter_always) expect_lint("dplyr::filter(DF, A & B & C)", NULL, linter_always) expect_lint("DF %>% dplyr::filter(A & B)", NULL, linter_always) expect_lint("dplyr::filter(DF, A & B)", lint_msg, linter_dplyr) expect_lint("dplyr::filter(DF, A & B & C)", lint_msg, linter_dplyr) expect_lint("DF %>% dplyr::filter(A & B)", lint_msg, linter_dplyr) expect_lint("filter(DF, A & B)", NULL, linter_dplyr) expect_lint("filter(DF, A & B & C)", NULL, linter_dplyr) expect_lint("DF %>% filter(A & B)", NULL, linter_dplyr) }) test_that("filter() is assumed to be dplyr::filter() by default, unless o/w specified", { linter <- conjunct_test_linter() expect_lint("stats::filter(A & B)", NULL, linter) expect_lint("ns::filter(A & B)", NULL, linter) expect_lint( "DF %>% filter(A & B)", rex::rex("Use dplyr::filter(DF, A, B) instead of dplyr::filter(DF, A & B)"), linter ) }) test_that("lints vectorize", { expect_lint( trim_some("{ stopifnot(A && B) filter(DF, A & B) }"), list( list("stopifnot", line_number = 2L), list("filter", line_number = 3L) ), conjunct_test_linter() ) }) lintr/tests/testthat/test-expect_s3_class_linter.R0000644000176200001440000000633714752731051022161 0ustar liggesuserstest_that("expect_s3_class_linter skips allowed usages", { linter <- expect_s3_class_linter() # expect_s3_class doesn't have an inverted version expect_lint("expect_true(!inherits(x, 'class'))", NULL, linter) # NB: also applies to tinytest, but it's sufficient to test testthat expect_lint("testthat::expect_true(!inherits(x, 'class'))", NULL, linter) # other is. calls are not suitable for expect_s3_class in particular expect_lint("expect_true(is.na(x))", NULL, linter) # case where expect_s3_class() *could* be used but we don't enforce expect_lint("expect_true(is.data.table(x))", NULL, linter) # expect_s3_class() doesn't have info= or label= arguments expect_lint("expect_equal(class(x), k, info = 'x should have class k')", NULL, linter) expect_lint("expect_equal(class(x), k, label = 'x class')", NULL, linter) expect_lint("expect_equal(class(x), k, expected.label = 'target class')", NULL, linter) expect_lint("expect_true(is.data.frame(x), info = 'x should be a data.frame')", NULL, linter) }) test_that("expect_s3_class_linter blocks simple disallowed usages", { linter <- expect_s3_class_linter() expect_lint( "expect_equal(class(x), 'data.frame')", rex::rex("expect_s3_class(x, k) is better than expect_equal(class(x), k)"), linter ) # works when testing against a sequence of classes too expect_lint( "expect_equal(class(x), c('data.table', 'data.frame'))", rex::rex("expect_s3_class(x, k) is better than expect_equal(class(x), k)"), linter ) # expect_identical is treated the same as expect_equal expect_lint( "testthat::expect_identical(class(x), 'lm')", rex::rex("expect_s3_class(x, k) is better than expect_identical(class(x), k)"), linter ) # yoda test with string literal in first arg also caught expect_lint( "expect_equal('data.frame', class(x))", rex::rex("expect_s3_class(x, k) is better than expect_equal(class(x), k)"), linter ) # different equivalent usages expect_lint( "expect_true(is.table(foo(x)))", rex::rex("expect_s3_class(x, k) is better than expect_true(is.(x))"), linter ) expect_lint( "expect_true(inherits(x, 'table'))", rex::rex("expect_s3_class(x, k) is better than expect_true(is.(x))"), linter ) }) local({ # test for lint errors appropriately raised for all is. calls is_classes <- c( "data.frame", "factor", "numeric_version", "ordered", "package_version", "qr", "table", "relistable", "raster", "tclObj", "tkwin", "grob", "unit", "mts", "stepfun", "ts", "tskernel" ) patrick::with_parameters_test_that( "expect_true(is.) is caught", expect_lint( sprintf("expect_true(is.%s(x))", is_class), rex::rex("expect_s3_class(x, k) is better than expect_true(is.(x))"), expect_s3_class_linter() ), .test_name = is_classes, is_class = is_classes ) }) test_that("lints vectorize", { expect_lint( trim_some("{ expect_true(is.factor(x)) expect_true(inherits(x, k)) expect_equal(class(x), k) }"), list( list(rex::rex("is."), line_number = 2L), list(rex::rex("is."), line_number = 3L), list("expect_equal", line_number = 4L) ), expect_s3_class_linter() ) }) lintr/tests/testthat/test-inner_combine_linter.R0000644000176200001440000001107014752731051021674 0ustar liggesuserstest_that("inner_combine_linter lints a false positive-ish usage", { # By default as.POSIXct.character picks up the format to apply from # the first element and, since it succeeds, applies that to the remaining # timestamps. Whereas when run individually, it won't succeed until # the correct format is matched for each input. Nevertheless, it is # still preferable to vectorize the call, while being sure to use a # consistent format for the inputs. In this case, the correct equivalent # call is as.POSIXct(c("2021-01-01 00:00:00", "2021-01-01 01:00:00")). expect_lint( "c(as.POSIXct('2021-01-01'), as.POSIXct('2021-01-01 01:00:00'))", rex::rex("Combine inputs to vectorized functions first"), inner_combine_linter() ) }) local({ vector_funs <- c( "as.Date", "as.POSIXct", "as.POSIXlt", "sin", "cos", "tan", "sinpi", "cospi", "tanpi", "asin", "acos", "atan", "log", "logb", "log2", "log10", "log1p", "exp", "expm1", "sqrt", "abs", "ymd", "ydm", "mdy", "myd", "dmy", "dym", "yq", "ym", "my", "ymd_hms", "ymd_hm", "ymd_h", "dmy_hms", "dmy_hm", "dmy_h", "mdy_hms", "mdy_hm", "mdy_h", "ydm_hms", "ydm_hm", "ydm_h", NULL ) patrick::with_parameters_test_that( "inner_combine_linter blocks simple vectorized calls:", expect_lint( sprintf("c(%1$s(x), %1$s(y))", vector_fun), rex::rex("Combine inputs to vectorized functions first"), inner_combine_linter() ), .test_name = vector_funs, vector_fun = vector_funs ) }) patrick::with_parameters_test_that( "inner_combine_linter blocks as.Date with identical passed arguments:", expect_lint( sprintf("c(as.Date(x, %1$s), as.Date(y, %1$s))", arg), rex::rex("Combine inputs to vectorized functions first"), inner_combine_linter() ), .test_name = c("format", "origin", "tz", "tryFormats", "non-literal", "quoted arg name"), arg = c("format = '%F'", "origin = '1900-01-01'", "tz = 'Asia/Jakarta'", "tryFormats = '%F'", "tz = tz", "'tz' = tz") ) patrick::with_parameters_test_that( "inner_combine_linter blocks as.POSIXct with identical passed arguments:", expect_lint( sprintf("c(as.POSIXct(x, %1$s), as.POSIXct(y, %1$s))", arg), rex::rex("Combine inputs to vectorized functions first"), inner_combine_linter() ), .test_name = c("format", "origin", "tz", "non-literal"), arg = c("format = '%F'", "origin = '1900-01-01'", "tz = 'UTC'", "tz = tz") ) test_that("inner_combine_linter is order-agnostic for matching arguments", { expect_lint( "c(as.Date(x, format = f, tz = t), as.Date(y, tz = t, format = f))", rex::rex("Combine inputs to vectorized functions first"), inner_combine_linter() ) }) test_that("c() with ...length()=1 is OK", { expect_lint("c(exp())", NULL, inner_combine_linter()) }) skip_if_not_installed("tibble") patrick::with_parameters_test_that( "inner_combine_linter skips allowed usages:", expect_lint(expr, NULL, inner_combine_linter()), .cases = tibble::tribble( ~.test_name, ~expr, "simple sin()", "x <- sin(1:10)", "mixed sin()+cos()", "y <- c(sin(1:10), cos(2:20))", "present/absent vector function", "c(log(x), 0.5)", "absent/present vector function", "c(0.5, log(x))", "mismatched arg (Date)", "c(as.Date(x, format = '%y'), as.Date(y, format = '%m'))", "present/absent arg (Date)", "c(as.Date(x, format = '%y'), as.Date(y))", "absent/present arg (Date)", "c(as.Date(x), as.Date(y, format = '%y'))", "matched value, not arg (Date)", "c(as.Date(x, format = '%y'), as.Date(y, tz = '%y'))", "mismatched arg (POSIXct)", "c(as.POSIXct(x, format = '%y'), as.POSIXct(y, format = '%m'))", "present/absent arg (POSIXct)", "c(as.POSIXct(x, format = '%y'), as.POSIXct(y))", "mismatched arg (log)", "c(log(x, base = 4), log(y, base = 5))", "present/absent arg (log)", "c(log(x, base = 4), log(y))" # TODO(#2486): Reactivate these. # "unknown Date method argument", "c(as.Date(x, zoo = zzz), as.Date(y, zoo = zzz))", # "known+unknown Date argument", "c(as.Date(x, format = '%y', zoo = zzz), as.Date(y, format = '%y', zoo = zzz))", # "unknown POSIXct method argument", "c(as.POSIXct(x, zoo = zzz), as.POSIXct(y, zoo = zzz))", ) ) test_that("lints vectorize", { lint_msg <- rex::rex("Combine inputs to vectorized functions first") expect_lint( trim_some("{ c(sin(x), sin(y)) c(log(x), log(y)) }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), inner_combine_linter() ) }) lintr/tests/testthat/test-methods.R0000644000176200001440000001520014752731051017152 0ustar liggesuserstest_that("it returns the input if less than the max", { expect_identical(lintr:::trim_output(character()), character()) expect_identical(lintr:::trim_output("test", max = 10L), "test") }) test_that("it returns the input trimmed strictly to max if no lints found", { expect_identical(lintr:::trim_output("testing a longer non_lint string", max = 7L), "testing") }) test_that("it returns the input trimmed to the last full lint if one exists within the max", { t1 <- readChar(test_path("lints"), file.size(test_path("lints"))) if (.Platform$OS.type == "windows") { # Magic numbers expect newlines to be 1 character t1 <- gsub("\r\n", "\n", t1, fixed = TRUE) } expect_identical(lintr:::trim_output(t1, max = 200L), substr(t1, 1L, 195L)) expect_identical(lintr:::trim_output(t1, max = 400L), substr(t1, 1L, 380L)) expect_identical(lintr:::trim_output(t1, max = 2000L), substr(t1, 1L, 1930L)) }) test_that("as.data.frame.lints", { l1 <- Lint( "dummy.R", line_number = 1L, type = "style", message = "", line = "" ) # A minimum lint expect_s3_class(l1, "lint") expect_type(l1, "list") # A larger lint l2 <- Lint( "dummy.R", line_number = 2L, column_number = 6L, type = "error", message = "Under no circumstances is the use of foobar allowed.", line = "a <- 1", ranges = list(c(1L, 2L), c(6L, 7L)) ) expect_s3_class(l2, "lint") expect_error( Lint("dummy.R", linter = "deprecated"), regexp = "deprecated", fixed = TRUE ) # Convert lints to data.frame lints <- list(l1, l2) class(lints) <- "lints" df <- as.data.frame(lints) expect_s3_class(df, "data.frame") exp <- data.frame( filename = "dummy.R", line_number = c(1L, 2L), column_number = c(1L, 6L), type = c("style", "error"), message = c("", "Under no circumstances is the use of foobar allowed."), line = c("", "a <- 1"), linter = NA_character_ # These are assigned in lint() now. ) expect_identical(df, exp) }) test_that("summary.lints() works (no lints)", { no_lints <- lint("x <- 1\n", linters = assignment_linter()) no_lint_summary <- summary(no_lints) expect_s3_class(no_lint_summary, "data.frame") expect_identical(nrow(no_lint_summary), 0L) }) test_that("summary.lints() works (lints found)", { has_lints <- lint("x = 1\n", linters = assignment_linter()) has_lint_summary <- summary(has_lints) expect_s3_class(has_lint_summary, "data.frame") expect_identical(nrow(has_lint_summary), 1L) expect_gt(has_lint_summary$style, 0L) expect_identical(has_lint_summary$warning, 0L) expect_identical(has_lint_summary$error, 0L) }) test_that("print.lint works", { # don't treat \t as width-1, #528 l <- Lint( filename = "tmp", line_number = 1L, column_number = 3L, type = "warning", message = "this is a lint", line = c(`1` = "\t\t1:length(x)"), ranges = list(c(3L, 3L)) ) expect_output(print(l), " 1:length(x)", fixed = TRUE) }) test_that("print.lint works with empty lints", { withr::local_options(list(lintr.rstudio_source_markers = FALSE)) l <- lint(text = "1L") expect_message(print(l), "No lints found", fixed = TRUE) }) test_that("print.lint works for inline data, even in RStudio", { l <- lint("x = 1\n") # Make sure lints print to console. # The full output is: # # > :1:3: style: Use <-, not =, for assignment. # > x = 1 # > ^ withr::with_options( list(lintr.rstudio_source_markers = FALSE), expect_output(print(l), "not =") ) skip_if_not_installed("rstudioapi") local_mocked_bindings( hasFun = function(...) FALSE, .package = "rstudioapi" ) withr::with_options( list(lintr.rstudio_source_markers = TRUE), expect_output(print(l), "not =") ) }) test_that("print.lints works", { withr::local_options(lintr.rstudio_source_markers = FALSE) tmp <- withr::local_tempfile() stopifnot(file.create(tmp)) expect_invisible(print(lint(tmp))) }) test_that("split.lint works as intended", { tmp <- withr::local_tempfile(lines = c("1:nrow(x)", "1:ncol(x)")) l <- lint(tmp, seq_linter()) expect_true(all(vapply(split(l), inherits, logical(1L), "lints"))) }) test_that("within.list is dispatched", { l <- lint(text = "a=1\nb=2", linters = infix_spaces_linter()) expect_silent({ # nolint next: implicit_assignment_linter. Workaround is pretty horrid. l <- lapply(l, within, line_number <- line_number + 1L) }) expect_identical(vapply(l, `[[`, integer(1L), "line_number"), 2L:3L) }) test_that("as_tibble.list is _not_ dispatched directly", { skip_if_not_installed("tibble") lints <- lint(text = "a = 1", linters = assignment_linter()) expect_identical(nrow(tibble::as_tibble(lints)), 1L) }) test_that("as.data.table.list is _not_ dispatched directly", { skip_if_not_installed("data.table") lints <- lint(text = "a = 1", linters = assignment_linter()) expect_identical(nrow(data.table::as.data.table(lints)), 1L) }) local({ # avoid impact of CLI mark-up on strwrap output. # (testthat, or cli, already do so, but force it explicitly here for emphasis) withr::local_options(c(cli.num_colors = 0L)) # force "default" print method even on GHA withr::local_envvar(c(GITHUB_ACTIONS = NA)) test_linter <- make_linter_from_xpath("*[1]", lint_message = "The quick brown fox jumps over the lazy dog.") lints <- lint(text = "a", linters = test_linter()) lint <- lints[[1L]] widths <- c(10L, 20L, 40L, 80L) test_names <- paste0(": width = ", widths) patrick::with_parameters_test_that( "print.lint, print.lints support optional message wrapping", { expect_snapshot(print(lints, width = width)) withr::with_options(c(lintr.format_width = width), { expect_snapshot(print(lints)) }) }, .test_name = test_names, width = widths ) wrapped_strings <- c( "[test_linter]\n The\n quick\n brown\n fox\n jumps\n over\n the\n lazy\n dog.", "[test_linter]\n The quick brown\n fox jumps over\n the lazy dog.", "[test_linter] The\n quick brown fox jumps over the lazy\n dog.", "[test_linter] The quick brown fox jumps over the lazy dog." ) patrick::with_parameters_test_that( "format.lint, format.lints support optional message wrapping", { expect_match(format(lint, width = width), wrapped_string, fixed = TRUE) expect_match(format(lints, width = width), wrapped_string, fixed = TRUE) withr::with_options(c(lintr.format_width = width), { expect_match(format(lint), wrapped_string, fixed = TRUE) expect_match(format(lints), wrapped_string, fixed = TRUE) }) }, .test_name = test_names, width = widths, wrapped_string = wrapped_strings ) }) lintr/tests/testthat/exclusions-test0000644000176200001440000000043114752731051017503 0ustar liggesusersa <- function() { x = 1 #TeSt_NoLiNt b = 2 c = 3 #TeSt_NoLiNt_StArT b + 1 d = 4 e = 5 #TeSt_NoLiNt_EnD f = 6 f + 1 a.b = 42 #TeSt_NoLiNt: assignment_linter. #TeSt_NoLiNt_StArT: assignment_linter, object_name_linter. a.b.c = 33 F = T #TeSt_NoLiNt_EnD } lintr/tests/testthat/test-checkstyle_output.R0000644000176200001440000000160614752731051021272 0ustar liggesuserstest_that("return lint report as checkstyle xml", { lints <- list( Lint( filename = "test_file", line_number = 1L, column_number = 2L, type = "error", line = "a line", message = "foo" ), Lint( filename = "test_file", line_number = 2L, column_number = 1L, type = "style", line = "another line", message = "bar" ), Lint( filename = "test_file2", line_number = 1L, column_number = 1L, type = "warning", line = "yet another line", message = "baz" ) ) class(lints) <- "lints" tmp <- withr::local_tempfile() checkstyle_output(lints, tmp) # The second line is the checkstyle version, so we ignore it during the # check, so we don't have to update the version every release. expect_identical(readLines(tmp)[-2L], readLines(test_path("checkstyle.xml"))[-2L]) }) lintr/tests/testthat/test-infix_spaces_linter.R0000644000176200001440000001577214752731051021555 0ustar liggesuserstest_that("returns the correct linting", { ops <- c( "+", "-", "~", "=", "==", "!=", "<=", ">=", "<-", ":=", "<<-", "<", ">", "->", "->>", "%%", "/", "*", "|", "||", "&", "&&", "%>%", "%Anything%", "%+%", NULL ) linter <- infix_spaces_linter() lint_msg <- rex::rex("Put spaces around all infix operators.") expect_lint("blah", NULL, linter) for (op in ops) { expect_lint(paste0("1 ", op, " 2"), NULL, linter) expect_lint(paste0("1 ", op, "\n2"), NULL, linter) expect_lint(paste0("1 ", op, "\n 2"), NULL, linter) expect_lint(paste0("1", op, "2"), lint_msg, linter) # unary plus and minus can have no space before them if (!op %in% ops[1L:2L]) { expect_lint(paste0("1 ", op, "2"), lint_msg, linter) } expect_lint(paste0("1", op, " 2"), lint_msg, linter) } expect_lint("b <- 2E+4", NULL, linter) expect_lint("a <- 1e-3", NULL, linter) expect_lint("a[-1]", NULL, linter) expect_lint("a[-1 + 1]", NULL, linter) expect_lint("a[1 + -1]", NULL, linter) expect_lint("fun(a=1)", lint_msg, linter) }) test_that("The three `=` are all linted", { linter <- infix_spaces_linter() lint_msg <- rex::rex("Put spaces around all infix operators.") # EQ_ASSIGN in the parse data expect_lint("a=1", lint_msg, linter) # EQ_FORMALS in the parse data expect_lint("foo <- function(x=1) {}", lint_msg, linter) # EQ_SUB in the parse data expect_lint("foo(x=1)", lint_msg, linter) }) test_that("exclude_operators works", { lint_msg <- rex::rex("Put spaces around all infix operators.") expect_lint("a+b", NULL, infix_spaces_linter(exclude_operators = "+")) expect_lint( trim_some(" a+b a-b "), NULL, infix_spaces_linter(exclude_operators = c("+", "-")) ) # operators match on text, not hidden node expect_lint("a<<-1", lint_msg, infix_spaces_linter(exclude_operators = "<-")) expect_lint("a<<-1", NULL, infix_spaces_linter(exclude_operators = "<<-")) expect_lint("a:=1", lint_msg, infix_spaces_linter(exclude_operators = "<-")) expect_lint("a:=1", NULL, infix_spaces_linter(exclude_operators = ":=")) expect_lint("a->>1", lint_msg, infix_spaces_linter(exclude_operators = "->")) expect_lint("a->>1", NULL, infix_spaces_linter(exclude_operators = "->>")) expect_lint("a%any%1", NULL, infix_spaces_linter(exclude_operators = "%%")) expect_lint("function(a=1) { }", NULL, infix_spaces_linter(exclude_operators = "=")) expect_lint("foo(a=1)", NULL, infix_spaces_linter(exclude_operators = "=")) }) # more tests specifically for assignment test_that("assignment cases return the correct linting", { linter <- infix_spaces_linter() lint_msg <- rex::rex("Put spaces around all infix operators.") expect_lint("fun(blah = 1)", NULL, linter) expect_lint("blah <- 1", NULL, linter) expect_lint("blah = 1", NULL, linter) expect_lint("\"my = variable\" <- 42.0", NULL, linter) expect_lint("if (0 < 1) x <- 42L", NULL, linter) expect_lint( trim_some(" if (0 < 1) { x <- 42L }"), NULL, linter ) expect_lint("my = bad = variable = name <- 2.0", NULL, linter) expect_lint("blah<- 1", lint_msg, linter) expect_lint("blah <-1", lint_msg, linter) expect_lint("blah= 1", lint_msg, linter) expect_lint("blah =1", lint_msg, linter) }) test_that("infix_spaces_linter can allow >1 spaces optionally", { linter <- infix_spaces_linter(allow_multiple_spaces = FALSE) lint_msg <- rex::rex("Put exactly one space on each side of infix operators.") expect_lint("x ~ 1", lint_msg, linter) expect_lint("x - 1", lint_msg, linter) expect_lint("x / 1", lint_msg, linter) }) test_that("exception for box::use()", { linter <- infix_spaces_linter() expect_lint("box::use(a/b)", NULL, linter) expect_lint("box::use(./a/b)", NULL, linter) expect_lint( trim_some(" box::use( a, a/b, ../a, alias = a/b/c[xyz = abc, ...], ) "), NULL, linter ) }) test_that("multi-line, multi-expression case is caught", { expect_lint( trim_some(" x + y+ z "), rex::rex("Put spaces around all infix operators."), infix_spaces_linter() ) }) test_that("Rules around missing arguments are respected", { linter <- infix_spaces_linter() lint_msg <- rex::rex("Put spaces around all infix operators.") expect_lint("switch(a = , b = 2)", NULL, linter) expect_lint("alist(missing_arg = )", NULL, linter) expect_lint("switch(a =, b = 2)", lint_msg, linter) expect_lint("alist(missing_arg =)", lint_msg, linter) }) test_that("native pipe is supported", { skip_if_not_r_version("4.1.0") linter <- infix_spaces_linter() expect_lint("a |> foo()", NULL, linter) expect_lint("a|>foo()", rex::rex("Put spaces around all infix operators."), linter) }) test_that("mixed unary & binary operators aren't mis-lint", { expect_lint( "-1-1", list( message = rex::rex("Put spaces around all infix operators."), column_number = 3L ), infix_spaces_linter() ) }) test_that("parse tags are accepted by exclude_operators", { expect_lint("sum(x, na.rm=TRUE)", NULL, infix_spaces_linter(exclude_operators = "EQ_SUB")) expect_lint("function(x, na.rm=TRUE) { }", NULL, infix_spaces_linter(exclude_operators = "EQ_FORMALS")) expect_lint("x=1", NULL, infix_spaces_linter(exclude_operators = "EQ_ASSIGN")) # uses parse_tag expect_lint("1+1", NULL, infix_spaces_linter(exclude_operators = "'+'")) # mixing text <- "x=function(a=foo(bar=1)) { }" col_assign <- list(column_number = 2L) col_formals <- list(column_number = 13L) col_sub <- list(column_number = 21L) expect_lint(text, NULL, infix_spaces_linter(exclude_operators = c("EQ_SUB", "EQ_FORMALS", "EQ_ASSIGN"))) expect_lint(text, col_assign, infix_spaces_linter(exclude_operators = c("EQ_SUB", "EQ_FORMALS"))) expect_lint(text, col_formals, infix_spaces_linter(exclude_operators = c("EQ_SUB", "EQ_ASSIGN"))) expect_lint(text, col_sub, infix_spaces_linter(exclude_operators = c("EQ_FORMALS", "EQ_ASSIGN"))) expect_lint(text, list(col_assign, col_formals), infix_spaces_linter(exclude_operators = "EQ_SUB")) expect_lint(text, list(col_assign, col_sub), infix_spaces_linter(exclude_operators = "EQ_FORMALS")) expect_lint(text, list(col_formals, col_sub), infix_spaces_linter(exclude_operators = "EQ_ASSIGN")) }) test_that("lints vectorize", { lint_msg <- rex::rex("Put spaces around all infix operators.") expect_lint( trim_some("{ a<-1 1/2 b<-c<-2 d+e+f+g/3 }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L), list(lint_msg, line_number = 4L, column_number = 4L), list(lint_msg, line_number = 4L, column_number = 7L), list(lint_msg, line_number = 5L, column_number = 4L), list(lint_msg, line_number = 5L, column_number = 6L), list(lint_msg, line_number = 5L, column_number = 8L), list(lint_msg, line_number = 5L, column_number = 10L) ), infix_spaces_linter() ) }) lintr/tests/testthat/test-sprintf_linter.R0000644000176200001440000001122514752731051020554 0ustar liggesuserspatrick::with_parameters_test_that( "sprintf_linter skips allowed usages", { linter <- sprintf_linter() # NB: using paste0, not sprintf, to avoid escaping '%d' in sprint fmt= expect_lint(paste0(call_name, "('hello')"), NULL, linter) expect_lint(paste0(call_name, "('hello %d', 1)"), NULL, linter) expect_lint(paste0(call_name, "('hello %d', x)"), NULL, linter) expect_lint(paste0(call_name, "('hello %d', x + 1)"), NULL, linter) expect_lint(paste0(call_name, "('hello %d', f(x))"), NULL, linter) expect_lint(paste0(call_name, "('hello %1$s %1$s', x)"), NULL, linter) expect_lint(paste0(call_name, "('hello %1$s %1$s %2$d', x, y)"), NULL, linter) expect_lint(paste0(call_name, "('hello %1$s %1$s %2$d %3$s', x, y, 1.5)"), NULL, linter) }, .test_name = c("sprintf", "gettextf"), call_name = c("sprintf", "gettextf") ) patrick::with_parameters_test_that( "sprintf_linter blocks disallowed usages", { linter <- sprintf_linter() unused_arg_msg <- if (getRversion() >= "4.1.0") "one argument not used by format" else NULL expect_lint(paste0(call_name, "('hello', 1)"), unused_arg_msg, linter) expect_lint( paste0(call_name, "('hello %d', 'a')"), rex::rex("invalid format '%d'; use format %s for character objects"), linter ) expect_lint( paste0(call_name, "('hello %d', 1.5)"), rex::rex("invalid format '%d'; use format %f, %e, %g or %a for numeric objects"), linter ) expect_lint( paste0(call_name, "('hello %d',)"), rex::rex("argument is missing, with no default"), linter ) expect_lint(paste0(call_name, "('hello %1$s %s', 'a', 'b')"), unused_arg_msg, linter) expect_lint(paste0(call_name, "('hello %1$s %1$s', x, y)"), unused_arg_msg, linter) expect_lint( paste0(call_name, "('hello %1$s %1$s %3$d', x, y)"), rex::rex("reference to non-existent argument 3"), linter ) expect_lint( paste0(call_name, "('hello %1$s %1$s %2$d %3$d', x, y, 1.5)"), rex::rex("invalid format '%d'; use format %f, %e, %g or %a for numeric objects"), linter ) }, .test_name = c("sprintf", "gettextf"), call_name = c("sprintf", "gettextf") ) test_that("edge cases are detected correctly", { linter <- sprintf_linter() # works with multi-line sprintf and comments expect_lint( trim_some(" sprintf( 'test fmt %s', # this is a comment 2 ) "), NULL, linter ) # dots expect_lint("sprintf('%d %d, %d', id, ...)", NULL, linter) # TODO(#1265) extend ... detection to at least test for too many arguments. # named argument fmt expect_lint("sprintf(x, fmt = 'hello %1$s %1$s')", NULL, linter) expect_lint( "sprintf(x, fmt = 'hello %1$s %1$s %3$d', y)", list(message = rex::rex("reference to non-existent argument 3")), linter ) # #2131: xml2lang stripped necessary whitespace expect_lint("sprintf('%s', if (A) '' else y)", NULL, linter) }) local({ linter <- sprintf_linter() unused_fmt_msg <- "too few arguments" unused_arg_msg <- "one argument not used by format" pipes <- pipes(exclude = "%$%") patrick::with_parameters_test_that( "piping into sprintf works", { expect_lint(paste("x", pipe, "sprintf(fmt = '%s')"), NULL, linter) # no fmt= specified -> this is just 'sprintf("%s", "%s%s")', which won't lint expect_lint(paste('"%s"', pipe, 'sprintf("%s%s")'), NULL, linter) expect_lint(paste("x", pipe, "sprintf(fmt = '%s%s')"), unused_fmt_msg, linter) # Cannot evaluate statically --> skip expect_lint(paste("x", pipe, 'sprintf("a")'), NULL, linter) # Nested pipes expect_lint( paste("'%%sb'", pipe, "sprintf('%s')", pipe, "sprintf('a')"), if (getRversion() >= "4.1.0") list(column_number = nchar(paste("'%%sb'", pipe, "x")), message = unused_arg_msg), linter ) expect_lint( paste("x", pipe, 'sprintf(fmt = "%s")', pipe, 'sprintf(fmt = "%s%s")'), list(column_number = nchar(paste("x", pipe, 'sprintf(fmt = "%s")', pipe, "x")), message = unused_fmt_msg), linter ) expect_lint( paste("x", pipe, 'sprintf(fmt = "%s%s")', pipe, 'sprintf(fmt = "%s")'), list(column_number = nchar(paste("x", pipe, "x")), message = unused_fmt_msg), linter ) }, pipe = pipes, .test_name = names(pipes) ) }) test_that("lints vectorize", { skip_if_not_r_version("4.1.0") expect_lint( trim_some("{ sprintf('%s', a, b) sprintf('%s%s', a) }"), list( list("one argument not used by format", line_number = 2L), list("too few arguments", line_number = 3L) ), sprintf_linter() ) }) lintr/tests/testthat/test-duplicate_argument_linter.R0000644000176200001440000001143714752731051022750 0ustar liggesuserstest_that("duplicate_argument_linter doesn't block allowed usages", { linter <- duplicate_argument_linter() expect_lint("fun(arg = 1)", NULL, linter) expect_lint("fun('arg' = 1)", NULL, linter) expect_lint("fun(`arg` = 1)", NULL, linter) expect_lint("'fun'(arg = 1)", NULL, linter) expect_lint("(function(x, y) x + y)(x = 1)", NULL, linter) expect_lint("dt[i = 1]", NULL, linter) }) test_that("duplicate_argument_linter blocks disallowed usages", { linter <- duplicate_argument_linter() lint_msg <- rex::rex("Avoid duplicate arguments in function calls.") expect_lint("fun(arg = 1, arg = 2)", lint_msg, linter) expect_lint("fun(arg = 1, 'arg' = 2)", lint_msg, linter) expect_lint("fun(arg = 1, `arg` = 2)", lint_msg, linter) expect_lint("'fun'(arg = 1, arg = 2)", lint_msg, linter) expect_lint("(function(x, y) x + y)(x = 1, x = 2)", lint_msg, linter) expect_lint("dt[i = 1, i = 2]", lint_msg, linter) expect_lint( trim_some(" list( var = 1, var = 2 ) "), lint_msg, linter ) }) test_that("duplicate_argument_linter respects except argument", { linter_list <- duplicate_argument_linter(except = "list") linter_all <- duplicate_argument_linter(except = character()) expect_lint( "list( var = 1, var = 2 )", NULL, linter_list ) expect_lint( "(function(x, y) x + y)(x = 1) list(var = 1, var = 2)", NULL, linter_list ) expect_lint( "fun(` ` = 1, ` ` = 2)", rex::rex("Avoid duplicate arguments in function calls."), linter_all ) expect_lint( "function(arg = 1, arg = 1) {}", rex::rex("Repeated formal argument 'arg'."), linter_all ) }) test_that("doesn't lint duplicated arguments in allowed functions", { linter <- duplicate_argument_linter() expect_lint( "x %>% dplyr::mutate( col = a + b, col = col + d )", NULL, linter ) expect_lint( "x %>% dplyr::transmute( col = a + b, col = col / 2.5 )", NULL, linter ) skip_if_not_r_version("4.1.0") expect_lint( "x |> dplyr::mutate( col = col |> str_replace('t', '') |> str_replace('\\\\s+$', 'xxx') )", NULL, linter ) }) test_that("interceding comments don't trip up logic", { linter <- duplicate_argument_linter() lint_msg <- rex::rex("Avoid duplicate arguments") # comment before the EQ_SUB # actually this case "just works" even before #2402 since # get_r_string() returns NA for both argument names expect_lint( trim_some(" fun( arg # xxx = 1, arg # yyy = 2 ) "), list(lint_msg, line_number = 4L), linter ) expect_lint( trim_some(" fun( arg # xxx = 1, arg = 2 ) "), list(lint_msg, line_number = 4L), linter ) expect_lint( trim_some(" fun( arg = 1, arg # yyy = 2 ) "), list(lint_msg, line_number = 3L), linter ) # comment after the EQ_SUB expect_lint( trim_some(" fun( arg = # xxx 1, arg = # yyy 2 ) "), list(lint_msg, line_number = 4L), linter ) expect_lint( trim_some(" fun( arg = # xxx 1, arg = 2 ) "), list(lint_msg, line_number = 4L), linter ) expect_lint( trim_some(" fun( arg = 1, arg = # yyy 2 ) "), list(lint_msg, line_number = 3L), linter ) # comment after the arg value expect_lint( trim_some(" fun( arg = 1 # xxx , arg = 2 # yyy ) "), list(lint_msg, line_number = 4L), linter ) expect_lint( trim_some(" fun( arg = 1 # xxx , arg = 2 ) "), list(lint_msg, line_number = 4L), linter ) expect_lint( trim_some(" fun( arg = 1, arg = 2 # yyy ) "), list(lint_msg, line_number = 3L), linter ) # comment after the OP-COMMA expect_lint( trim_some(" fun( arg = 1, # xxx arg = 2 # yyy ) "), list(lint_msg, line_number = 3L), linter ) expect_lint( trim_some(" fun( arg = 1, # xxx arg = 2 ) "), list(lint_msg, line_number = 3L), linter ) }) test_that("lints vectorize", { lint_msg <- rex::rex("Avoid duplicate arguments") expect_lint( trim_some("{ c(a = 1, a = 2, a = 3) list(b = 1, b = 2, b = 3) }"), list( list(lint_msg, line_number = 2L, column_number = 12L), list(lint_msg, line_number = 2L, column_number = 19L), list(lint_msg, line_number = 3L, column_number = 15L), list(lint_msg, line_number = 3L, column_number = 22L) ), duplicate_argument_linter() ) }) lintr/tests/testthat/test-trailing_blank_lines_linter.R0000644000176200001440000000733214752731051023245 0ustar liggesuserstest_that("trailing_blank_lines_linter doesn't block allowed usages", { linter <- trailing_blank_lines_linter() expect_lint("blah", NULL, linter) expect_lint("blah <- 1 ", NULL, linter) expect_lint("blah <- 1\nblah", NULL, linter) expect_lint("blah <- 1\nblah\n \n blah", NULL, linter) tmp <- withr::local_tempfile(lines = "lm(y ~ x)") expect_lint(file = tmp, checks = NULL, linters = linter) }) test_that("trailing_blank_lines_linter detects disallowed usages", { linter <- trailing_blank_lines_linter() lint_msg <- rex::rex("Remove trailing blank lines.") expect_lint("blah <- 1\n", lint_msg, linter) expect_lint("blah <- 1\n ", lint_msg, linter) expect_lint("blah <- 1\n \n ", list(lint_msg, lint_msg), linter) expect_lint("blah <- 1\n\n", list(lint_msg, lint_msg), linter) expect_lint("blah <- 1\n\t\n", list(lint_msg, lint_msg), linter) # Construct a test file without terminal newline # cf. test-get_source_expressions.R tmp2 <- withr::local_tempfile() cat("lm(y ~ x)", file = tmp2) expect_lint( file = tmp2, checks = list( message = rex::rex("Add a terminal newline."), line_number = 1L, column_number = 10L ), linters = linter ) }) test_that("trailing_blank_lines_linter detects missing terminal newlines in Rmd/qmd docs", { linter <- trailing_blank_lines_linter() lint_msg <- rex::rex("Add a terminal newline") tmp3 <- withr::local_tempfile(fileext = ".Rmd") cat( trim_some( '--- title: "Some file" --- ```{r} abc = 123 ``` ```{r child="some-file.Rmd"} ```' ), file = tmp3 ) expect_lint( file = tmp3, # We can't get 4 here because the line is NA-masked in get_source_expressions(), so no line length info exists. checks = list(lint_msg, line_number = 10L, column_number = 1L), linters = linter ) # Construct an Rmd file without R code (#1415) tmp4 <- withr::local_tempfile(fileext = ".Rmd") cat( trim_some( '--- title: "Some file" --- No code and no terminal newline' ), file = tmp4 ) expect_lint( file = tmp4, # We can't get 4 here because the line is NA-masked in get_source_expressions(), so no line length info exists. checks = list(lint_msg, line_number = 5L, column_number = 1L), linters = linter ) # Construct a qmd file without terminal newline tmp5 <- withr::local_tempfile(fileext = ".qmd") cat( trim_some( '--- title: "Some file" --- ```{r} abc = 123 ``` ```{r child="some-file.qmd"} ```' ), file = tmp5 ) expect_lint( file = tmp5, # We can't get 4 here because the line is NA-masked in get_source_expressions(), so no line length info exists. checks = list(lint_msg, line_number = 10L, column_number = 1L), linters = linter ) }) test_that("blank lines in knitr chunks produce lints", { linter <- trailing_blank_lines_linter() lint_msg <- rex::rex("Remove trailing blank lines.") tmp6 <- withr::local_tempfile( fileext = ".Rmd", lines = trim_some( '--- title: "Some file" --- ```{r} abc = 123 ``` \n' ) ) expect_lint( file = tmp6, checks = list(lint_msg, line_number = 7L, column_number = 1L), linters = linter ) tmp7 <- withr::local_tempfile( fileext = ".qmd", lines = trim_some( '--- title: "Some file" --- ```{r} abc = 123 ``` \n' ) ) expect_lint( file = tmp7, checks = list( list(lint_msg, line_number = 7L, column_number = 1L), list(lint_msg, line_number = 8L, column_number = 1L), list(lint_msg, line_number = 9L, column_number = 1L) ), linters = linter ) }) lintr/tests/testthat/test-expect_null_linter.R0000644000176200001440000000341614752731051021414 0ustar liggesuserstest_that("expect_null_linter skips allowed usages", { linter <- expect_null_linter() # NB: this usage should be expect_false(), but this linter should # nevertheless apply (e.g. for maintainers not using expect_not_linter) expect_lint("expect_true(!is.null(x))", NULL, linter) # NB: also applies to tinytest, but it's sufficient to test testthat expect_lint("testthat::expect_true(!is.null(x))", NULL, linter) # length-0 could be NULL, but could be integer() or list(), so let it pass expect_lint("expect_length(x, 0L)", NULL, linter) # no false positive for is.null() at the wrong positional argument expect_lint("expect_true(x, is.null(y))", NULL, linter) }) test_that("expect_null_linter blocks simple disallowed usages", { linter <- expect_null_linter() expect_lint( "expect_equal(x, NULL)", rex::rex("expect_null(x) is better than expect_equal(x, NULL)"), linter ) # expect_identical is treated the same as expect_equal expect_lint( "testthat::expect_identical(x, NULL)", rex::rex("expect_null(x) is better than expect_identical(x, NULL)"), linter ) # reverse order lints the same expect_lint( "expect_equal(NULL, x)", rex::rex("expect_null(x) is better than expect_equal(x, NULL)"), linter ) # different equivalent usage expect_lint( "expect_true(is.null(foo(x)))", rex::rex("expect_null(x) is better than expect_true(is.null(x))"), linter ) }) test_that("lints vectorize", { expect_lint( trim_some("{ expect_equal(x, NULL) expect_identical(x, NULL) expect_true(is.null(x)) }"), list( list("expect_equal", line_number = 2L), list("expect_identical", line_number = 3L), list("expect_true", line_number = 4L) ), expect_null_linter() ) }) lintr/tests/testthat/test-is_lint_level.R0000644000176200001440000000044014752731051020337 0ustar liggesuserstest_that("is_lint_level works", { pc <- list(parsed_content = 1L) expect_true(is_lint_level(pc, "expression")) expect_false(is_lint_level(pc, "file")) names(pc) <- "full_parsed_content" expect_true(is_lint_level(pc, "file")) expect_false(is_lint_level(pc, "expression")) }) lintr/tests/testthat/test-unnecessary_nested_if_linter.R0000644000176200001440000000725014752731051023451 0ustar liggesuserstest_that("unnecessary_nested_if_linter generates deprecation warning", { expect_warning( unnecessary_nested_if_linter(), rex::rex("unnecessary_nested_if_linter was deprecated", anything, "Use unnecessary_nesting_linter") ) }) test_that("unnecessary_nested_if_linter skips allowed usages", { expect_warning({ linter <- unnecessary_nested_if_linter() }) expect_lint( trim_some(" if (x && y) { 1L }"), NULL, linter ) expect_lint( trim_some(" for (x in 1:3) { if (x && y) { 1L } }"), NULL, linter ) expect_lint( trim_some(" if (x) { 1L } else if (y) { 2L }"), NULL, linter ) expect_lint( trim_some(" if (x) { 1L } else { if (y) { 2L } }"), NULL, linter ) expect_lint( trim_some(" if (if (x) TRUE else FALSE) { 1L }"), NULL, linter ) expect_lint( trim_some(" if (x) { y <- x + 1L if (y) { 1L } }"), NULL, linter ) expect_lint( trim_some(" if ((x && y) || (if (x) TRUE else FALSE)) { 1L }"), NULL, linter ) # if there is any additional code between the inner and outer scopes, no lint expect_lint( trim_some(" if (x && a) { y <- x + 1L if (y || b) { 1L } }"), NULL, linter ) expect_lint( trim_some(" if (x) { if (y) { 1L } y <- x + 1L }"), NULL, linter ) expect_lint( trim_some(" if (x) { y <- x + 1L if (y) { 1L } y <- x }"), NULL, linter ) expect_lint( trim_some(" if (x) { y <- x + 1L { if (y) { 1L } } }"), NULL, linter ) expect_lint( trim_some(" if (x) { { y <- x + 1L if (y) { 1L } } }"), NULL, linter ) expect_lint( trim_some(" if (x) { { if (y) { 1L } } y <- x + 1L }"), NULL, linter ) expect_lint( trim_some(" if (x) { { y <- x + 1L { if (y) { 1L } } } }"), NULL, linter ) }) test_that("unnecessary_nested_if_linter blocks disallowed usages", { lint_message <- rex::rex("Don't use nested `if` statements") expect_warning({ linter <- unnecessary_nested_if_linter() }) expect_lint( trim_some(" if (x) { if (y) { 1L } }"), lint_message, linter ) expect_lint( trim_some(" if (x) { if (y) 1L }"), lint_message, linter ) expect_lint( trim_some(" if (x && a) { if (y || b) { 1L } }"), lint_message, linter ) expect_lint( trim_some(" if (if (x) TRUE else FALSE) { if (y) { 1L } }"), lint_message, linter ) expect_lint( "if (x) if (y) 1L", lint_message, linter ) expect_lint( trim_some(" for (x in 1:3) { if (x) if (y) 1L }"), lint_message, linter ) expect_lint( trim_some(" if (x) { if (y) { if (z) { 1L } } }"), list( list(message = lint_message, line_number = 2L, column_number = 3L), list(message = lint_message, line_number = 3L, column_number = 5L) ), linter ) }) lintr/tests/testthat/test-knitr_formats.R0000644000176200001440000001211714752731051020375 0ustar liggesusersregexes <- list( assign = rex::rex("Use one of <-, <<- for assignment, not =."), local_var = rex::rex("local variable"), quotes = rex::rex("Only use double-quotes."), trailing = rex::rex("Remove trailing blank lines."), trailws = rex::rex("Remove trailing whitespace."), indent = rex::rex("Indentation should be") ) test_that("it handles dir", { file_pattern <- rex::rex(".R", one_of("html", "md", "nw", "rst", "tex", "txt")) lints <- lint_dir(path = "knitr_formats", pattern = file_pattern, parse_settings = FALSE) # For every file there should be at least 1 lint expect_identical( sort(unique(names(lints))), sort(list.files(test_path("knitr_formats"), pattern = file_pattern)) ) }) test_that("it handles markdown", { expect_lint( file = test_path("knitr_formats", "test.Rmd"), checks = list( list(regexes[["assign"]], line_number = 9L), list(regexes[["local_var"]], line_number = 22L), list(regexes[["assign"]], line_number = 22L), list(regexes[["trailing"]], line_number = 24L) ), linters = default_linters, parse_settings = FALSE ) }) test_that("it handles quarto", { expect_lint( file = test_path("knitr_formats", "test.qmd"), checks = list( list(regexes[["assign"]], line_number = 9L), list(regexes[["local_var"]], line_number = 22L), list(regexes[["assign"]], line_number = 22L), list(regexes[["trailing"]], line_number = 24L) ), linters = default_linters, parse_settings = FALSE ) }) test_that("it handles Sweave", { expect_lint( file = test_path("knitr_formats", "test.Rnw"), checks = list( list(regexes[["assign"]], line_number = 12L), list(regexes[["local_var"]], line_number = 24L), list(regexes[["assign"]], line_number = 24L), list(regexes[["trailing"]], line_number = 26L) ), linters = default_linters, parse_settings = FALSE ) }) test_that("it handles reStructuredText", { expect_lint( file = test_path("knitr_formats", "test.Rrst"), checks = list( list(regexes[["assign"]], line_number = 10L), list(regexes[["local_var"]], line_number = 23L), list(regexes[["assign"]], line_number = 23L), list(regexes[["trailing"]], line_number = 25L) ), linters = default_linters, parse_settings = FALSE ) }) test_that("it handles HTML", { expect_lint( file = test_path("knitr_formats", "test.Rhtml"), checks = list( list(regexes[["assign"]], line_number = 15L), list(regexes[["local_var"]], line_number = 27L), list(regexes[["assign"]], line_number = 27L), list(regexes[["trailing"]], line_number = 29L) ), linters = default_linters, parse_settings = FALSE ) }) test_that("it handles tex", { expect_lint( file = test_path("knitr_formats", "test.Rtex"), checks = list( list(regexes[["indent"]], line_number = 11L), list(regexes[["assign"]], line_number = 11L), list(regexes[["indent"]], line_number = 22L), list(regexes[["local_var"]], line_number = 23L), list(regexes[["assign"]], line_number = 23L), list(regexes[["trailing"]], line_number = 25L), list(regexes[["trailws"]], line_number = 25L) ), linters = default_linters, parse_settings = FALSE ) }) test_that("it handles asciidoc", { expect_lint( file = test_path("knitr_formats", "test.Rtxt"), checks = list( list(regexes[["assign"]], line_number = 9L), list(regexes[["local_var"]], line_number = 22L), list(regexes[["assign"]], line_number = 22L), list(regexes[["trailing"]], line_number = 24L) ), linters = default_linters, parse_settings = FALSE ) }) test_that("it does _not_ handle brew", { expect_lint("'<% a %>'\n", checks = list( regexes[["quotes"]], regexes[["trailing"]] ), default_linters ) }) test_that("it does _not_ error with inline \\Sexpr", { expect_lint( "#' text \\Sexpr{1 + 1} more text", NULL, default_linters ) }) test_that("it does lint .Rmd or .qmd file with malformed input", { expect_lint( file = test_path("knitr_malformed", "incomplete_r_block.Rmd"), checks = "Missing chunk end", linters = default_linters, parse_settings = FALSE ) expect_lint( file = test_path("knitr_malformed", "incomplete_r_block.qmd"), checks = "Missing chunk end", linters = default_linters, parse_settings = FALSE ) contents <- c( trim_some(" ```{r chunk} lm(x ~ y) # some text ``` bash some_script.sh ``` "), trim_some(" ```{r chunk-1} code <- 42 # A heading Some text ```{r chunk-2} some_more_code <- 42 ``` "), trim_some(" ```{r chunk-1} code <- 42 ``` # A heading Some text ```{r chunk-2} some_more_code <- 42 ") ) expected <- list( NULL, # This test case would require parsing all chunk fences, not just r chunks. "maybe starting at line 1", "maybe starting at line 8" ) for (i in seq_along(contents)) { expect_lint(contents[[i]], expected[[i]], linters = list()) } }) lintr/tests/testthat/test-pipe_continuation_linter.R0000644000176200001440000001034414752731051022617 0ustar liggesuserstest_that("pipe-continuation correctly handles stand-alone expressions", { linter <- pipe_continuation_linter() lint_msg <- rex::rex("Put a space before `%>%` and a new line after it,") # Expressions without pipes are ignored expect_lint("blah", NULL, linter) # Pipe expressions on a single line are ignored expect_lint("foo %>% bar() %>% baz()", NULL, linter) # Pipe expressions spanning multiple lines with each expression on a line are ignored expect_lint( trim_some(" foo %>% bar() %>% baz() "), NULL, linter ) # Pipe expressions with multiple expression on a line are linted expect_lint( trim_some(" foo %>% bar() %>% baz() "), lint_msg, linter ) expect_lint( trim_some(" foo %>% bar() %>% baz() %>% qux() "), lint_msg, linter ) }) test_that("pipe-continuation linter correctly handles nesting", { linter <- pipe_continuation_linter() lint_msg <- rex::rex("Put a space before `%>%` and a new line after it,") expect_lint( trim_some(" my_fun <- function(){ a %>% b() %>% c() } "), list(list(message = lint_msg, line_number = 2L)), linter ) expect_lint( trim_some(" my_fun <- function(){ a %>% b() %>% c() } "), list(list(message = lint_msg, line_number = 3L)), linter ) # but no lints here expect_lint( trim_some(" 1:4 %>% { (.) %>% sum() } "), NULL, linter ) }) test_that("pipe-continuation linter handles native pipe", { skip_if_not_r_version("4.1.0") linter <- pipe_continuation_linter() lint_msg_native <- rex::rex("Put a space before `|>` and a new line after it,") lint_msg_magrittr <- rex::rex("Put a space before `%>%` and a new line after it,") expect_lint("foo |> bar() |> baz()", NULL, linter) expect_lint( trim_some(" foo |> bar() |> baz() "), NULL, linter ) expect_lint( trim_some(" foo |> bar() |> baz() "), lint_msg_native, linter ) # mixing pipes expect_lint( trim_some(" foo %>% bar() |> baz() "), lint_msg_native, linter ) expect_lint( trim_some(" foo |> bar() %>% baz() "), lint_msg_magrittr, linter ) expect_lint( trim_some(" list( foo |> bar() |> baz(), foo %>% bar() %>% baz() ) "), list( lint_msg_native, lint_msg_magrittr ), linter ) }) local({ linter <- pipe_continuation_linter() .cases <- tibble::tribble( ~code_string, ~.test_name, trim_some(" my_fun <- function() { a %>% b() } "), "two on one line", trim_some(" my_fun <- function() { a %>% b() %>% c() } "), "three on one line", trim_some(" with( diamonds, x %>% head(10) %>% tail(5) ) "), "three inside with()", trim_some(" test_that('blah', { test_data <- diamonds %>% head(10) %>% tail(5) }) "), "three inside test_that()", trim_some(" { x <- a %>% b %>% c y <- c %>% b %>% a } "), "two different single-line pipelines", trim_some(" my_fun <- function() { a %>% b() %>% c() } "), "at most one pipe-character per line" ) patrick::with_parameters_test_that( "valid nesting is handled", # nolint next: unnecessary_nesting_linter. TODO(#2334): Remove this nolint. { expect_lint(code_string, NULL, linter) }, .cases = .cases ) }) local({ linter <- pipe_continuation_linter() pipes <- pipes() cases <- expand.grid(pipe1 = pipes, pipe2 = pipes, stringsAsFactors = FALSE) cases <- within(cases, { .test_name <- sprintf("(%s, %s)", pipe1, pipe2) }) patrick::with_parameters_test_that( "Various pipes are linted correctly", expect_lint( sprintf("a %s b() %s\n c()", pipe1, pipe2), rex::rex(sprintf("Put a space before `%s` and a new line after it", pipe2)), linter ), .cases = cases ) }) lintr/tests/testthat/test-make_linter_from_regex.R0000644000176200001440000000032714752731051022222 0ustar liggesuserstest_that("test make_linter_from_regex works", { linter <- lintr:::make_linter_from_regex("-", "style", "Silly lint.")() expect_lint("a <- 2L", "Silly lint.", linter) expect_lint("a = '2-3'", NULL, linter) }) lintr/tests/testthat/test-consecutive_mutate_linter.R0000644000176200001440000001004314752731051022772 0ustar liggesuserstest_that("consecutive_mutate_linter skips allowed usages", { linter <- consecutive_mutate_linter() expect_lint("DF %>% mutate(x = 1)", NULL, linter) # intervening expression expect_lint("DF %>% mutate(x = 1) %>% filter(x > 2) %>% mutate(y = 2)", NULL, linter) # pipeline starts with mutate() expect_lint("mutate(DF, x = 1) %>% arrange(y) %>% mutate(z = 2)", NULL, linter) # new dplyr: .keep and .by arguments are ignored expect_lint("DF %>% mutate(a = 1) %>% mutate(a = a / sum(a), .by = b)", NULL, linter) expect_lint("DF %>% mutate(a = 1) %>% mutate(a = b, .keep = 'none')", NULL, linter) expect_lint("DF %>% mutate(a = a / sum(a), .by = b) %>% mutate(c = 1)", NULL, linter) expect_lint("DF %>% mutate(a = 1, .keep = 'none') %>% mutate(a = a + 1)", NULL, linter) }) patrick::with_parameters_test_that( "consecutive_mutate_linter skips files loading SQL backends", { linter <- consecutive_mutate_linter(invalid_backends = backend) expect_lint( trim_some(glue::glue(" library({backend}) DF %>% mutate(a = a + 1) %>% mutate(b = a - 2) ")), NULL, linter ) expect_lint( trim_some(glue::glue(" require('{backend}') DF %>% mutate(a = a + 1) %>% mutate(b = a - 2) ")), NULL, linter ) expect_lint( trim_some(glue(" conn %>% tbl({backend}::sql('SELECT 1 AS x')) %>% mutate(a = x + 1) %>% mutate(b = a + 1) ")), NULL, linter ) expect_lint( trim_some(glue(" conn %>% tbl({backend}:::sql('SELECT 1 AS x')) %>% mutate(a = x + 1) %>% mutate(b = a + 1) ")), NULL, linter ) expect_lint( trim_some(glue(" #' @import {backend} NULL DF %>% mutate(a = a + 1) %>% mutate(b = a - 2) ")), NULL, linter ) expect_lint( trim_some(glue(" #' @importFrom {backend} sql NULL conn %>% tbl(sql('SELECT 1 AS x')) %>% mutate(a = x + 1) %>% mutate(b = a + 1) ")), NULL, linter ) }, .test_name = c("dbplyr", "custom.backend"), backend = c("dbplyr", "custom.backend") ) test_that("consecutive_mutate_linter blocks simple disallowed usages", { linter <- consecutive_mutate_linter() lint_msg <- rex::rex("Unify consecutive calls to mutate().") # one test of inline usage expect_lint("DF %>% mutate(a = 1) %>% mutate(b = 2)", lint_msg, linter) expect_lint( trim_some(" DF %>% mutate(a = 1) %>% mutate(b = 2) "), lint_msg, linter ) expect_lint( trim_some(" DF %>% dplyr::mutate(a = 1) %>% dplyr::mutate(b = 2) "), lint_msg, linter ) expect_lint( trim_some(" DF %>% mutate(a = 1) %>% # a comment on b mutate(b = 2) "), lint_msg, linter ) # mutate to open pipeline followed by mutate expect_lint("mutate(DF, x = 1) %>% mutate(x = 2)", lint_msg, linter) }) test_that("'parallel' calls are not linted", { linter <- consecutive_mutate_linter() expect_lint("foo(mutate(DF1, x = 1), mutate(DF2, y = 2))", NULL, linter) expect_lint("foo(DF1 %>% mutate(x = 1), DF2 %>% mutate(y = 2))", NULL, linter) expect_lint("DF1 %>% mutate(x = 1) %>% inner_join(DF2 %>% mutate(y = 2))", NULL, linter) }) test_that("native pipe is linted", { skip_if_not_r_version("4.1.0") linter <- consecutive_mutate_linter() lint_msg <- rex::rex("Unify consecutive calls to mutate().") expect_lint("DF |> mutate(a = 1) |> mutate(b = 2)", lint_msg, linter) # Ditto mixed pipes expect_lint("DF %>% mutate(a = 1) |> mutate(b = 2)", lint_msg, linter) }) test_that("lints vectorize", { lint_msg <- rex::rex("Unify consecutive calls to mutate().") expect_lint( trim_some(" DF %>% mutate(a = 1) %>% mutate(b = 2) %>% mutate(c = 3) "), list( list(lint_msg, line_number = 3L), list(lint_msg, line_number = 4L) ), consecutive_mutate_linter() ) }) lintr/tests/testthat/knitr_formats/0000755000176200001440000000000014752731051017273 5ustar liggesuserslintr/tests/testthat/knitr_formats/test.Rhtml0000644000176200001440000000154014752731051021262 0ustar liggesusers Test

Test

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.

Test

Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. lintr/tests/testthat/knitr_formats/test.Rrst0000644000176200001440000000134014752731051021124 0ustar liggesusersTest ==== Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. .. {r rst-example} a = 1 .. .. Test ---- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. .. {r} b <- function(x) { d = 1 } .. .. .. {r engine = "python"} a=[] a[0]=1 .. .. lintr/tests/testthat/knitr_formats/test.qmd0000644000176200001440000000262114752731051020756 0ustar liggesusers# Test # Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} a = 1 ``` Test ==== Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} b <- function(x) { d = 1 } ``` ```{r engine="python"} a=[] a[0]=1 ``` ``` Plain code blocks can be written after three or more backticks - R Markdown: The Definitive Guide. Xie, Allaire and Grolemund (2.5.2) ``` ```r # This is a non-evaluated block of R code for formatting in markdown. # It should not be linted abc = 123 ``` ```cpp // Some C++ code for formatting by markdown ``` Calls to a non-R knitr-engine using {engine_name} syntax. ```{python} # Python that looks like R a = list() b = {2} print(a) ``` ```{python} # Python that's definitely not R a = [] a.append(2) print(a) ``` The following are only supported by Quarto and shouldn't lint either. ```{.r} 1+1 ``` ```{{r}} 1+1 ``` ```{.python} # Python that's definitely not R a = [] a.append(2) print(a) ``` lintr/tests/testthat/knitr_formats/test.Rnw0000644000176200001440000000142514752731051020744 0ustar liggesusers\documentclass{article} \usepackage{mathpazo} \begin{document} \title{Test} Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. <>= a = 1 @ \subtitle{Test} Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. <<>>= b <- function(x) { d = 1 } @ <>= a=[] a[0]=1 @ lintr/tests/testthat/knitr_formats/test.Rtxt0000644000176200001440000000140114752731051021131 0ustar liggesusers= Test = Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. //begin.rcode a = 1 //end.rcode Test ==== Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. //begin.rcode trailing b <- function(x) { d = 1 } //end.rcode //begin.rcode engine="python" a=[] a[0]=1 //end.rcode lintr/tests/testthat/knitr_formats/test.Rtex0000644000176200001440000000151714752731051021122 0ustar liggesusers\documentclass{article} \usepackage{graphicx} \title{Test} Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. %% begin.rcode % a = 1 %% end.rcode \subtitle{Test} Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. %% begin.rcode test_chunk % b <- function(x) { % d = 1 % } % %% end.rcode %% begin.rcode engine="python" % a=[] % % a[0]=1 %% end.rcode lintr/tests/testthat/knitr_formats/test.Rmd0000644000176200001440000000233014752731051020714 0ustar liggesusers# Test # Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} a = 1 ``` Test ==== Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. ```{r} b <- function(x) { d = 1 } ``` ```{r engine="python"} a=[] a[0]=1 ``` ``` Plain code blocks can be written after three or more backticks - R Markdown: The Definitive Guide. Xie, Allaire and Grolemund (2.5.2) ``` ```r # This is a non-evaluated block of R code for formatting in markdown. # It should not be linted abc = 123 ``` ```cpp // Some C++ code for formatting by markdown ``` Calls to a non-R knitr-engine using {engine_name} syntax. ```{python} # Python that looks like R a = list() b = {2} print(a) ``` ```{python} # Python that's definitely not R a = [] a.append(2) print(a) ``` lintr/tests/testthat/test-knitr_extended_formats.R0000644000176200001440000000150214752731051022251 0ustar liggesuserstest_that("marginfigure engine from tufte package doesn't cause problems", { skip_if_not_installed("tufte", minimum_version = "0.12.4") # for rstudio/tufte#117 loadNamespace("tufte") # to register additional engines expect_lint( file = test_path("knitr_extended_formats", "tufte.Rmd"), checks = list(rex::rex("Use one of <-, <<- for assignment, not =."), line_number = 11L), default_linters, parse_settings = FALSE ) }) test_that("engines from bookdown package cause no problems", { skip_if_not_installed("bookdown") loadNamespace("bookdown") # to register additional engines expect_lint( file = test_path("knitr_extended_formats", "bookdown.Rmd"), checks = list(rex::rex("Use one of <-, <<- for assignment, not =."), line_number = 14L), default_linters, parse_settings = FALSE ) }) lintr/tests/testthat/test-xp_utils.R0000644000176200001440000000157514752731051017370 0ustar liggesuserstest_that("xp_call_name works", { xml_from_code <- function(str) { xml2::read_xml(xmlparsedata::xml_parse_data(parse(text = str, keep.source = TRUE))) } xml <- xml_from_code("sum(1:10)") expect_identical(xp_call_name(xml, depth = 2L), "sum") expect_identical(xp_call_name(xml2::xml_find_first(xml, "expr")), "sum") xml <- xml_from_code(c("sum(1:10)", "sd(1:10)")) expect_identical(xp_call_name(xml, depth = 2L, condition = "text() = 'sum'"), "sum") }) test_that("xp_call_name input validation works", { expect_error(xp_call_name(2L), "`expr` must be an ", fixed = TRUE) xml <- xml2::read_xml("") expect_error(xp_call_name(xml, depth = -1L), "depth >= 0", fixed = TRUE) expect_error(xp_call_name(xml, depth = "1"), "is.numeric(depth)", fixed = TRUE) expect_error(xp_call_name(xml, condition = 1L), "is.character(condition)", fixed = TRUE) }) lintr/tests/testthat/test-return_linter.R0000644000176200001440000011045014752731051020406 0ustar liggesuserstest_that("Lint return on end of function", { expect_lint( trim_some(" function() { return(1) # Test 3 + 4 } "), list( line_number = 4L, message = rex::rex("All functions must have an explicit return()."), type = "warning" ), return_linter(return_style = "explicit") ) expect_lint( trim_some(" function() { return(1) } "), list( line_number = 2L, message = rex::rex("Use implicit return behavior; explicit return() is not needed."), type = "style" ), return_linter() ) }) test_that("Lint return on end of lambda function", { skip_if_not_r_version("4.1.0") expect_lint( trim_some(" \\(bar) { 5L + 3L } "), list( line_number = 2L, message = rex::rex("All functions must have an explicit return().") ), return_linter(return_style = "explicit") ) expect_lint( trim_some(" \\(bar) { 5L + 3L return(1) } "), list( line_number = 3L, message = rex::rex("Use implicit return behavior; explicit return() is not needed.") ), return_linter() ) }) test_that("Do not lint if/else statements (with return) on end of function", { linter <- return_linter(return_style = "explicit") expect_lint( trim_some(" function() { if (x) { return(4) } else if (y) { return(5) } else { return(6) } } "), NULL, linter ) }) test_that("Lint control statements (without return) on end of function", { linter <- return_linter(return_style = "explicit") lint_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" function() { while (x > 4) { cat(4) if (x < 4) { return(x) } } } "), list(lint_msg, line_number = 2L), linter ) expect_lint( trim_some(" function() { repeat { cat(4) } } "), list(lint_msg, line_number = 2L), linter ) expect_lint( trim_some(" function() { for (i in 1:10) { cat(4) if (i > 11) { return(x) } } } "), list(lint_msg, line_number = 2L), linter ) expect_lint( trim_some(" function() { if (x == 2L){ return(e) } else if (x == 3L) { cat(f) } } "), list(lint_msg, line_number = 5L), linter ) }) test_that("Do not lint stop on end of function", { expect_lint( trim_some(" function() { # Test 3 + 4 stop(1) } "), NULL, return_linter(return_style = "explicit") ) expect_lint( trim_some(" function() { stop(1) } "), NULL, return_linter() ) }) test_that("return_linter works in simple function", { expect_lint( trim_some(" foo <- function(bar) { return(bar) } "), NULL, return_linter(return_style = "explicit") ) }) test_that("return_linter works for using stop() instead of returning", { linter <- return_linter(return_style = "explicit") expect_lint( trim_some(" foo <- function(bar) { stop('bad') } "), NULL, linter ) }) test_that("return_linter ignores expressions that aren't functions", { expect_lint("x + 1", NULL, return_linter(return_style = "explicit")) }) test_that("return_linter ignores anonymous/inline functions", { expect_lint("lapply(rnorm(10), function(x) x + 1)", NULL, return_linter(return_style = "explicit")) }) test_that("return_linter ignores if statements outside of functions", { expect_lint( trim_some(" if (TRUE) { TRUE } else { FALSE } "), NULL, return_linter(return_style = "explicit") ) }) test_that("return_linter passes on multi-line functions", { expect_lint( trim_some(" foo <- function(x) { y <- x + 1 return(y) } "), NULL, return_linter(return_style = "explicit") ) }) test_that("return_linter identifies a simple missing return", { expect_lint( trim_some(" foo <- function(bar) { bar } "), rex::rex("All functions must have an explicit return()."), return_linter(return_style = "explicit") ) }) test_that("return_linter finds a missing return in a 2+ line function", { expect_lint( trim_some(" foo <- function(x) { y <- x + 1 y^2 } "), rex::rex("All functions must have an explicit return()."), return_linter(return_style = "explicit") ) }) test_that("return_linter finds a missing return despite early returns", { expect_lint( trim_some(" foo <- function(x) { if (TRUE) return(TRUE) x <- 1 + 1 x } "), rex::rex("All functions must have an explicit return()."), return_linter(return_style = "explicit") ) }) test_that("return_linter finds multiple missing returns in branches", { lint_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function() { if (TRUE) { TRUE } else { FALSE } } "), list( list(lint_msg, line_number = 3L), list(lint_msg, line_number = 5L) ), return_linter(return_style = "explicit") ) }) test_that("return_linter works regardless of braces in final if case", { linter <- return_linter(return_style = "explicit") expect_lint( trim_some(" foo <- function() { if (TRUE) TRUE } "), rex::rex("All functions must have an explicit return()."), linter ) expect_lint( trim_some(" foo <- function() { if (TRUE) return(TRUE) } "), NULL, linter ) }) test_that("return_linter finds missing return in one branch of an if", { linter <- return_linter(return_style = "explicit") lint_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function() { if (TRUE) { return(TRUE) } else { FALSE } } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function() { if (TRUE) { TRUE } else { return(FALSE) } } "), lint_msg, linter ) }) test_that("return_linter works in nested if statements", { linter <- return_linter(return_style = "explicit") expect_lint( trim_some(" foo <- function() { if (TRUE) { return(TRUE) } else if (nzchar('a')) { return(TRUE) } else { return(FALSE) } } "), NULL, linter ) expect_lint( trim_some(" foo <- function() { if (TRUE) { if (nzchar('a')) { TRUE } } else { return(FALSE) } } "), rex::rex("All functions must have an explicit return()."), linter ) }) test_that("return_linter works in multi-line nested if statements", { linter <- return_linter(return_style = "explicit") expect_lint( trim_some(" foo <- function() { if (TRUE) { if (nzchar('a')) { y <- 1 + 1 y } } else { return(FALSE) } } "), rex::rex("All functions must have an explicit return()."), linter ) expect_lint( trim_some(" foo <- function() { if (TRUE) { if (nzchar('a')) { y <- 1 + 1 return(y) } } else { return(FALSE) } } "), NULL, linter ) }) test_that("return_linter works for final for loops as well", { linter <- return_linter(return_style = "explicit") lint_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function() { for (i in seq_len(10)) { if (i %% 2 == 0) { y <- 1 + 1 return(y) } } } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function() { for (i in seq_len(10)) { if (i %% 2 == 0) { y <- 1 + 1 } } } "), lint_msg, linter ) }) test_that("return_linter works for function factories", { linter <- return_linter(return_style = "explicit") lint_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function(x) { function () { return(x + 1) } } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function(x) { function () { x + 1 } } "), list(lint_msg, lint_msg), linter ) }) test_that("return_linter allows return()-less Rcpp wrappers", { expect_lint( trim_some(" ReadCapacitorAsList <- function(file) { .Call(R_ReadCapacitorAsList, file) } "), NULL, return_linter(return_style = "explicit") ) }) test_that("return_linter allows return()-less namespace hook calls", { expect_lint( trim_some(" .onLoad <- function(libname, pkgname) { do_setup() } "), NULL, return_linter(return_style = "explicit") ) }) test_that("return_linter correctly handles pipes", { linter <- return_linter(return_style = "explicit") expect_lint( trim_some(" foo <- function(x) { x %>% return() } "), NULL, linter ) expect_lint( trim_some(" foo <- function(x) { x %>% mean() %>% return() } "), NULL, linter ) expect_lint( trim_some(" foo <- function(x) { y <- rnorm(length(x)) x %>% cbind(y) %>% return() } "), NULL, linter ) }) test_that("return_linter handles pipes in control flow", { linter <- return_linter(return_style = "explicit") lint_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function(x) { if (TRUE) { return(invisible()) } else { x %>% return() } } "), NULL, linter ) expect_lint( trim_some(" foo <- function(x) { for (i in seq_len(10)) { x %>% mean() } } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function(x) { if (TRUE) { x %>% mean() } else { return(TRUE) } } "), lint_msg, linter ) }) test_that("return_linter passes on q() or quit() calls", { expect_lint( trim_some(" foo <- function(x) { if (TRUE) { q('n') } else { quit('n') } } "), NULL, return_linter(return_style = "explicit") ) }) test_that("return_functions= argument works", { linter <- return_linter(return_style = "explicit", return_functions = "LOG") expect_lint( trim_some(" foo <- function(bar) { LOG('INFO', 'bad') } "), NULL, linter ) expect_lint( trim_some(" foo <- function(bar) { logging::LOG('INFO', 'bad') } "), NULL, linter ) }) test_that("except= argument works", { expect_lint( trim_some(" foo <- function(bar) { 5 + 3 } "), NULL, return_linter(return_style = "explicit", except = "foo") ) }) test_that("except_regex= argument works", { linter <- return_linter(return_style = "explicit", except_regex = "^Test") expect_lint( trim_some(" TestSummary <- function() { context <- foo(72643424) expected <- data.frame(a = 2) checkEquals(expected, bar(context)) } "), NULL, linter ) expect_lint( trim_some(" TestMyPackage <- function() { checkMyCustomComparator(x, y) } "), NULL, linter ) expect_lint( trim_some(" TestOuter <- function() { actual <- lapply( input, function(x) { no_return() } ) TestInner <- function() { no_return() } checkEquals(TestInner(), actual) } "), list(rex::rex("All functions must have an explicit return()."), line_number = 5L), linter ) # capture group doesn't cause issues, #2678 expect_lint( trim_some(" TestFun <- function() { non_return() } AssertFun <- function() { non_return() } "), NULL, return_linter(return_style = "explicit", except_regex = "^(Test|Assert)") ) }) test_that("except= and except_regex= combination works", { expect_lint( trim_some(" foo <- function() { no_return() } bar <- function() { no_return() } abaz <- function() { no_return() } bbaz <- function() { no_return() } "), NULL, return_linter(return_style = "explicit", except = c("foo", "bar"), except_regex = "baz$") ) }) test_that("return_linter skips brace-wrapped inline functions", { expect_lint("function(x) { sum(x) }", NULL, return_linter(return_style = "explicit")) }) test_that("return_linter skips common S4 method functions", { linter <- return_linter(return_style = "explicit") expect_lint( trim_some(" setGeneric( 'ReadCircuitsPBAsDataTable', function(pbMessageList) { standardGeneric('ReadCircuitsPBAsDataTable') } ) "), NULL, linter ) expect_lint( trim_some(" setMethod('initialize', 'CircuitsTopology', function(.Object, ...) { callNextMethod(.Object, ...) }) "), NULL, linter ) }) test_that("return_functions= is not affected by namespace qualification", { linter <- return_linter(return_style = "explicit", return_functions = "abort") expect_lint( trim_some(" foo <- function(bar) { abort('bad') } "), NULL, linter ) expect_lint( trim_some(" foo <- function(bar) { rlang::abort('bad') } "), NULL, linter ) }) test_that("return_linter skips invokeRestart(), tryInvokeRestart()", { linter <- return_linter(return_style = "explicit") expect_lint( trim_some(" warning = function(w) { warn <<- append(warn, conditionMessage(w)) invokeRestart('muffleWarning') } "), NULL, linter ) expect_lint( trim_some(" custom_warning = function(w) { warn <<- append(warn, conditionMessage(w)) tryInvokeRestart('muffleCustom_warning') } "), NULL, linter ) }) # NB: x |> return() is blocked by the parser, so no need to test that. test_that("Native pipes are handled correctly", { skip_if_not_r_version("4.1.0") linter <- return_linter(return_style = "explicit") lint_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function(x) { for (i in seq_len(10)) { x |> mean() } } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function(x) { if (TRUE) { x |> mean() } else { return(TRUE) } } "), lint_msg, linter ) }) test_that("return_linter works for final while/repeat loops as well", { linter <- return_linter(return_style = "explicit") lint_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function(x) { while (x > 0) { if (x %% 2 == 0) { return(x) } x <- x + sample(10, 1) } } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function(x) { repeat { if (x == 0) { return(x) } x <- x - sign(x) } } "), lint_msg, linter ) }) test_that("return_linter lints `message`, `warning` and `stopifnot`", { linter <- return_linter(return_style = "explicit") lint_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function(bar) { stopifnot(bar == 'd') } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function(bar) { message('test') } "), lint_msg, linter ) expect_lint( trim_some(" foo <- function(bar) { warning(test) } "), lint_msg, linter ) }) test_that("return_linter handles arbitrarily nested terminal statements", { implicit_linter <- return_linter() implicit_msg <- rex::rex("Use implicit return behavior; explicit return() is not needed.") explicit_linter <- return_linter(return_style = "explicit") explicit_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function(x) { if (x < 0) { if (x == -1) { return(TRUE) } if (x > -10) { NA } else { FALSE } } else if (x == 0) { TRUE } else { y <- x**2 if (y > 10) { z <- sin(y) if (z > 0) { FALSE } else { NA } } else { TRUE } } } "), NULL, implicit_linter ) expect_lint( trim_some(" foo <- function(x) { if (x < 0) { if (x == -1) { return(TRUE) } if (x > -10) { return(NA) } else { return(FALSE) } } else if (x == 0) { return(TRUE) } else { y <- x**2 if (y > 10) { z <- sin(y) if (z > 0) { return(FALSE) } else { return(NA) } } else { return(TRUE) } } } "), NULL, explicit_linter ) mixed_lines <- trim_some(" foo <- function(x) { if (x < 0) { if (x == -1) { return(TRUE) } if (x > -10) { return(NA) } else { FALSE } } else if (x == 0) { return(TRUE) } else { y <- x**2 if (y > 10) { z <- sin(y) if (z > 0) { FALSE } else { return(NA) } } else { TRUE } } } ") expect_lint( mixed_lines, list( list(implicit_msg, line_number = 7L), list(implicit_msg, line_number = 12L), list(implicit_msg, line_number = 20L) ), implicit_linter ) expect_lint( mixed_lines, list( list(explicit_msg, line_number = 9L), list(explicit_msg, line_number = 18L), list(explicit_msg, line_number = 23L) ), explicit_linter ) }) test_that("explicit returns in control flow are linted correctly", { linter <- return_linter() lint_msg <- rex::rex("Use implicit return behavior") expect_lint( trim_some(" foo <- function(bar) { if (TRUE) { return(bar) } else { return(NULL) } } "), list(lint_msg, lint_msg), linter ) expect_lint( trim_some(" foo <- function() { if (TRUE) { if (TRUE) { return(1) } 2 } else { 3 } } "), NULL, linter ) }) # inspired by grid:::draw.all # https://github.com/r-devel/r-svn/blob/eeff859e427b2399f1474427a531365d2672f52f/src/library/grid/R/grob.R#L1940 test_that("logic is robust to absence of '{'", { linter <- return_linter() expect_lint( trim_some(" foo <- function() { if (TRUE) # comment is a neighbor of 'if' FALSE } "), NULL, linter ) expect_lint( trim_some(" foo <- function() { if (TRUE) FALSE else # cannot rely on 'else' expr being e.g. 7th NA } "), NULL, linter ) expect_lint( trim_some(" foo <- function() { if (TRUE) { FALSE } else # cannot rely on 'else' expr being e.g. 7th NA } "), NULL, linter ) }) test_that("logic is robust to terminal comments under '{'", { implicit_linter <- return_linter() implicit_msg <- rex::rex("Use implicit return behavior; explicit return() is not needed.") explicit_linter <- return_linter(return_style = "explicit") explicit_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" foo <- function() { return(TRUE) # comment } "), implicit_msg, implicit_linter ) expect_lint( trim_some(" foo <- function() { return(TRUE) # comment } "), NULL, explicit_linter ) expect_lint( trim_some(" foo <- function() { TRUE # comment } "), explicit_msg, explicit_linter ) }) test_that("terminal = assignment is not an error", { # key is this is not an node expect_lint( trim_some(" foo <- function() { a = 1 } "), NULL, return_linter() ) }) test_that("empty terminal '{' expression is handled correctly", { implicit_linter <- return_linter() implicit_msg <- rex::rex("Use implicit return behavior; explicit return() is not needed.") explicit_linter <- return_linter(return_style = "explicit") explicit_msg <- rex::rex("All functions must have an explicit return().") empty_inline <- "foo <- function() { }" expect_lint(empty_inline, NULL, implicit_linter) expect_lint(empty_inline, NULL, explicit_linter) empty_multiline <- trim_some(" foo <- function() { } ") expect_lint(empty_multiline, NULL, implicit_linter) expect_lint(empty_multiline, NULL, explicit_linter) empty_comment <- trim_some(" foo <- function() { # this line intentionally left blank } ") expect_lint(empty_comment, NULL, implicit_linter) expect_lint(empty_comment, NULL, explicit_linter) empty_if_implicit <- trim_some(" foo <- function() { if (TRUE) { } else { FALSE } } ") expect_lint(empty_if_implicit, NULL, implicit_linter) expect_lint( empty_if_implicit, list( list(explicit_msg, line_number = 2L), list(explicit_msg, line_number = 4L) ), explicit_linter ) empty_else_implicit <- trim_some(" foo <- function() { if (TRUE) { FALSE } else { } } ") expect_lint(empty_else_implicit, NULL, implicit_linter) expect_lint( empty_else_implicit, list( list(explicit_msg, line_number = 3L), list(explicit_msg, line_number = 4L) ), explicit_linter ) empty_if_explicit <- trim_some(" foo <- function() { if (TRUE) { } else { return(FALSE) } } ") expect_lint(empty_if_explicit, list(implicit_msg, line_number = 4L), implicit_linter) expect_lint(empty_if_explicit, list(explicit_msg, line_number = 2L), explicit_linter) empty_else_explicit <- trim_some(" foo <- function() { if (TRUE) { return(FALSE) } else { } } ") expect_lint(empty_else_explicit, list(implicit_msg, line_number = 3L), implicit_linter) expect_lint(empty_else_explicit, list(explicit_msg, line_number = 4L), explicit_linter) empty_if_else <- trim_some(" foo <- function() { if (TRUE) { } else { } } ") expect_lint(empty_if_else, NULL, implicit_linter) expect_lint( empty_if_else, list( list(explicit_msg, line_number = 2L), list(explicit_msg, line_number = 3L) ), explicit_linter ) weird <- trim_some(" foo <- function() { if (TRUE) {{{{ 0 }}}} else { { return(1) } } } ") expect_lint(weird, list(implicit_msg, line_number = 5L), implicit_linter) expect_lint(weird, list(explicit_msg, line_number = 3L), explicit_linter) }) test_that("non-if returns are skipped under allow_implicit_else = FALSE", { expect_lint( trim_some(" foo <- function(bar) { bar } "), NULL, return_linter(allow_implicit_else = FALSE) ) }) test_that("if/else don't throw a lint under allow_implicit_else = FALSE", { expect_lint( trim_some(" foo <- function(bar) { if (TRUE) { bar } else { NULL } } "), NULL, return_linter(allow_implicit_else = FALSE) ) }) test_that("implicit else outside a function doesn't lint under allow_implicit_else = FALSE", { expect_lint("if(TRUE) TRUE", NULL, return_linter(allow_implicit_else = FALSE)) }) test_that("allow_implicit_else = FALSE identifies a simple implicit else", { expect_lint( trim_some(" foo <- function(bar) { if (TRUE) { bar } } "), rex::rex("All functions with terminal if statements must have a corresponding terminal else clause"), return_linter(allow_implicit_else = FALSE) ) }) test_that("allow_implicit_else = FALSE finds implicit else with nested if+else", { lint_msg <- rex::rex("All functions with terminal if statements must have a corresponding terminal else clause") expect_lint( trim_some(" foo <- function() { if (TRUE) { if (TRUE) { FALSE } else { TRUE } } } "), lint_msg, return_linter(allow_implicit_else = FALSE) ) expect_lint( trim_some(" foo <- function() { if (TRUE) { if (TRUE) { return(FALSE) } else { return(TRUE) } } } "), lint_msg, return_linter(return_style = "explicit", allow_implicit_else = FALSE) ) }) test_that("allow_implicit_else = FALSE works on anonymous/inline functions", { expect_lint( "lapply(rnorm(10), function(x) if (TRUE) x + 1)", rex::rex("All functions with terminal if statements must"), return_linter(allow_implicit_else = FALSE) ) }) test_that("side-effect functions like .onLoad ignore the lack of explicit else under allow_implicit_else = FALSE", { expect_lint( trim_some(" .onAttach <- function(libname, pkgname) { if (TRUE) foo() } "), NULL, return_linter(allow_implicit_else = FALSE) ) expect_lint( trim_some(" .onAttach <- function(libname, pkgname) { if (TRUE) return(foo()) } "), NULL, return_linter(return_style = "explicit", allow_implicit_else = FALSE) ) }) test_that("implicit else lint has the correct metadata", { linter <- return_linter(return_style = "explicit", allow_implicit_else = FALSE) lint_msg <- "All functions with terminal if statements" expect_lint( trim_some(" foo <- function(x, y = 3) { if (x) { return(x) } } "), list(lint_msg, line_number = 2L), linter ) expect_lint( trim_some("{ foo <- function(x, y = 3) { if (x) { return(x) } } bar <- function(x, y = 3) { if (x) { return(x) } } baz <- function(x, y = 3) { if (x) return(x) } }"), list( list(lint_msg, line_number = 3L), list(lint_msg, line_number = 9L), list(lint_msg, line_number = 15L) ), linter ) }) test_that("Correct lints thrown when lacking explicit return and explicit else", { linter <- return_linter(return_style = "explicit", allow_implicit_else = FALSE) explicit_return_msg <- rex::rex("All functions must have an explicit return().") implicit_else_msg <- rex::rex("All functions with terminal if statements") expect_lint( trim_some(" foo <- function(x, y = 3) { if (x) { x } } "), list( list(implicit_else_msg, line_number = 2L), list(explicit_return_msg, line_number = 3L) ), linter ) expect_lint( trim_some(" function(x, y) { if (x) { 1 } else if (y) { 2 } } "), list( list(explicit_return_msg, line_number = 3L), list(implicit_else_msg, line_number = 4L), list(explicit_return_msg, line_number = 5L) ), linter ) }) test_that("Mixing exempted functions doesn't miss lints", { # in the current implementation, a local copy of 'params' is # edited in a loop; this test ensures that behavior continues to be correct expect_lint( trim_some("{ foo <- function() { 1 } bar <- function() { if (TRUE) { return(2) } } baz <- function() { if (TRUE) { 3 } } }"), list( list("Use implicit return behavior", line_number = 8L), list("All functions with terminal if statements", line_number = 13L) ), return_linter(allow_implicit_else = FALSE, except = "bar") ) }) test_that("= assignments are handled correctly", { implicit_linter <- return_linter(allow_implicit_else = FALSE) implicit_msg <- rex::rex("All functions with terminal if statements") explicit_linter <- return_linter(return_style = "explicit") explicit_msg <- rex::rex("All functions must have an explicit return().") expect_lint( trim_some(" .onLoad = function() { 1 } "), NULL, explicit_linter ) expect_lint( trim_some(" .onLoad = function() { if (TRUE) 1 } "), NULL, implicit_linter ) expect_lint( trim_some(" foo = function() { 1 } "), explicit_msg, explicit_linter ) expect_lint( trim_some(" foo = function() { if (TRUE) 1 } "), implicit_msg, implicit_linter ) }) test_that("terminal switch() is handled correctly", { implicit_linter <- return_linter() implicit_msg <- rex::rex("Use implicit return behavior; explicit return() is not needed.") explicit_linter <- return_linter(return_style = "explicit") explicit_msg <- rex::rex("All functions must have an explicit return().") no_return_lines <- trim_some(" foo <- function(x) { switch(x, a = 1, b = 2 ) } ") expect_lint(no_return_lines, NULL, implicit_linter) expect_lint(no_return_lines, list(explicit_msg, explicit_msg), explicit_linter) outer_return_lines <- trim_some(" foo <- function(x) { return(switch(x, a = 1, b = 2 )) } ") expect_lint(outer_return_lines, implicit_msg, implicit_linter) expect_lint(outer_return_lines, NULL, explicit_linter) partial_return_lines <- trim_some(" foo <- function(x) { switch(x, a = return(1), b = 2 ) } ") expect_lint(partial_return_lines, implicit_msg, implicit_linter) expect_lint(partial_return_lines, explicit_msg, explicit_linter) all_return_lines <- trim_some(" foo <- function(x) { switch(x, a = return(1), b = return(2) ) } ") expect_lint(all_return_lines, list(implicit_msg, implicit_msg), implicit_linter) expect_lint(all_return_lines, NULL, explicit_linter) default_all_return_lines <- trim_some(" foo <- function(x) { switch(x, a = return(1), return(2) ) } ") expect_lint(default_all_return_lines, list(implicit_msg, implicit_msg), implicit_linter) expect_lint(default_all_return_lines, NULL, explicit_linter) default_no_return_lines <- trim_some(" foo <- function(x) { switch(x, a = 1, 2 ) } ") expect_lint(default_no_return_lines, NULL, implicit_linter) expect_lint(default_no_return_lines, list(explicit_msg, explicit_msg), explicit_linter) no_return_braced_lines <- trim_some(" foo <- function(x) { switch(x, a = { 1 2 3 4 }, b = { 5 6 7 } ) } ") expect_lint(no_return_braced_lines, NULL, implicit_linter) expect_lint( no_return_braced_lines, list( list(explicit_msg, line_number = 7L), list(explicit_msg, line_number = 12L) ), explicit_linter ) all_return_braced_lines <- trim_some(" foo <- function(x) { switch(x, a = { 1 2 3 return(4) }, b = { 5 6 return(7) } ) } ") expect_lint( all_return_braced_lines, list( list(implicit_msg, line_number = 7L), list(implicit_msg, line_number = 12L) ), implicit_linter ) expect_lint(all_return_braced_lines, NULL, explicit_linter) early_return_braced_lines <- trim_some(" foo <- function(x) { switch(x, a = { 1 if (TRUE) { return(2) } 3 4 }, b = { 5 6 7 } ) } ") expect_lint(early_return_braced_lines, NULL, implicit_linter) expect_lint( early_return_braced_lines, list( list(explicit_msg, line_number = 9L), list(explicit_msg, line_number = 14L) ), explicit_linter ) if_no_return_braced_lines <- trim_some(" foo <- function(x) { switch(x, a = { 1 if (TRUE) { 2 } else { 3 } }, b = { 5 6 7 } ) } ") expect_lint(if_no_return_braced_lines, NULL, implicit_linter) expect_lint( if_no_return_braced_lines, list( list(explicit_msg, line_number = 6L), list(explicit_msg, line_number = 8L), list(explicit_msg, line_number = 14L) ), explicit_linter ) if_return_braced_lines <- trim_some(" foo <- function(x) { switch(x, a = { 1 if (TRUE) { return(2) } else { return(3) } }, b = { 5 6 return(7) } ) } ") expect_lint( if_return_braced_lines, list( list(implicit_msg, line_number = 6L), list(implicit_msg, line_number = 8L), list(implicit_msg, line_number = 14L) ), implicit_linter ) expect_lint(if_return_braced_lines, NULL, explicit_linter) ok_exit_lines <- trim_some(" foo <- function(x) { switch(x, a = .Call(a_routine, x), b = .Call(b_routine, x), stop('invalid') ) } ") expect_lint(ok_exit_lines, NULL, implicit_linter) expect_lint(ok_exit_lines, NULL, explicit_linter) }) test_that("switch() default statements interact with allow_implicit_else", { implicit_linter <- return_linter(allow_implicit_else = FALSE) explicit_linter <- return_linter(allow_implicit_else = FALSE, return_style = "explicit") implicit_msg <- rex::rex("Use implicit return behavior; explicit return() is not needed.") explicit_msg <- rex::rex("All functions must have an explicit return().") implicit_switch_msg <- rex::rex("All functions with terminal switch statements") implicit_else_msg <- rex::rex("All functions with terminal if statements") no_default_lines <- trim_some(" foo <- function(x) { switch(x, a = 1, b = 2 ) } ") expect_lint(no_default_lines, list(implicit_switch_msg, line_number = 2L), implicit_linter) expect_lint(no_default_lines, list(implicit_switch_msg, explicit_msg, explicit_msg), explicit_linter) ifelse_default_lines <- trim_some(" foo <- function(x) { switch(x, a = 1, b = 2, if (x != 'c') { 3 } else { 4 } ) } ") expect_lint(ifelse_default_lines, NULL, implicit_linter) expect_lint(ifelse_default_lines, list(explicit_msg, explicit_msg, explicit_msg, explicit_msg), explicit_linter) if_no_else_default_lines <- trim_some(" foo <- function(x) { switch(x, a = 1, b = 2, if (x != 'c') { 3 } ) } ") expect_lint(if_no_else_default_lines, list(implicit_else_msg, line_number = 5L), implicit_linter) expect_lint( if_no_else_default_lines, list( list(explicit_msg, line_number = 3L), list(explicit_msg, line_number = 4L), list(implicit_else_msg, line_number = 5L), list(explicit_msg, line_number = 6L) ), explicit_linter ) }) lintr/tests/testthat/checkstyle.xml0000644000176200001440000000054214752731051017272 0ustar liggesusers lintr/tests/testthat/_snaps/0000755000176200001440000000000014752731051015674 5ustar liggesuserslintr/tests/testthat/_snaps/methods.md0000644000176200001440000000352014752731051017661 0ustar liggesusers# print.lint, print.lints support optional message wrapping : width = 10 Code print(lints, width = width) Output :1:1: warning: [test_linter] The quick brown fox jumps over the lazy dog. a ^ --- Code print(lints) Output :1:1: warning: [test_linter] The quick brown fox jumps over the lazy dog. a ^ # print.lint, print.lints support optional message wrapping : width = 20 Code print(lints, width = width) Output :1:1: warning: [test_linter] The quick brown fox jumps over the lazy dog. a ^ --- Code print(lints) Output :1:1: warning: [test_linter] The quick brown fox jumps over the lazy dog. a ^ # print.lint, print.lints support optional message wrapping : width = 40 Code print(lints, width = width) Output :1:1: warning: [test_linter] The quick brown fox jumps over the lazy dog. a ^ --- Code print(lints) Output :1:1: warning: [test_linter] The quick brown fox jumps over the lazy dog. a ^ # print.lint, print.lints support optional message wrapping : width = 80 Code print(lints, width = width) Output :1:1: warning: [test_linter] The quick brown fox jumps over the lazy dog. a ^ --- Code print(lints) Output :1:1: warning: [test_linter] The quick brown fox jumps over the lazy dog. a ^ lintr/tests/testthat/test-any_is_na_linter.R0000644000176200001440000000330414752731051021026 0ustar liggesuserstest_that("any_is_na_linter skips allowed usages", { linter <- any_is_na_linter() expect_lint("x <- any(y)", NULL, linter) expect_lint("y <- is.na(z)", NULL, linter) # extended usage of ... arguments to any is not covered expect_lint("any(is.na(y), b)", NULL, linter) expect_lint("any(b, is.na(y))", NULL, linter) # negation shouldn't list expect_lint("any(!is.na(x))", NULL, linter) expect_lint("any(!is.na(foo(x)))", NULL, linter) }) test_that("any_is_na_linter blocks simple disallowed usages", { linter <- any_is_na_linter() lint_message <- rex::rex("anyNA(x) is better than any(is.na(x)).") expect_lint("any(is.na(x))", lint_message, linter) expect_lint("any(is.na(foo(x)))", lint_message, linter) # na.rm doesn't really matter for this since is.na can't return NA expect_lint("any(is.na(x), na.rm = TRUE)", lint_message, linter) # also catch nested usage expect_lint("foo(any(is.na(x)))", lint_message, linter) }) test_that("NA %in% x is also found", { linter <- any_is_na_linter() lint_message <- rex::rex("anyNA(x) is better than NA %in% x.") expect_lint("NA %in% x", lint_message, linter) expect_lint("NA_real_ %in% x", lint_message, linter) expect_lint("NA_not_a_sentinel_ %in% x", NULL, linter) }) test_that("lints vectorize", { any_message <- rex::rex("any(is.na(x))") in_message <- rex::rex("NA %in% x") expect_lint( trim_some("{ any(is.na(foo(x))) any(is.na(y), na.rm = TRUE) NA %in% a NA_complex_ %in% b }"), list( list(any_message, line_number = 2L), list(any_message, line_number = 3L), list(in_message, line_number = 4L), list(in_message, line_number = 5L) ), any_is_na_linter() ) }) lintr/tests/testthat/test-unnecessary_lambda_linter.R0000644000176200001440000002057614752731051022737 0ustar liggesuserstest_that("unnecessary_lambda_linter skips allowed usages", { linter <- unnecessary_lambda_linter() expect_lint("lapply(DF, sum)", NULL, linter) expect_lint("apply(M, 1, sum, na.rm = TRUE)", NULL, linter) # the first argument may be ... or have a cumbersome name, so an anonymous # function may be preferable (e.g. this is often the case for grep() calls) expect_lint("sapply(x, function(xi) foo(1, xi))", NULL, linter) expect_lint("sapply(x, function(xi) return(foo(1, xi)))", NULL, linter) # if the argument is re-used, that's also a no-go expect_lint("dendrapply(x, function(xi) foo(xi, xi))", NULL, linter) # at any nesting level expect_lint("parLapply(cl, x, function(xi) foo(xi, 2, bar(baz(xi))))", NULL, linter) # multi-expression case expect_lint("lapply(x, function(xi) { print(xi); xi^2 })", NULL, linter) # multi-expression, multi-line cases expect_lint( trim_some(" lapply(x, function(xi) { print(xi); xi^2 }) "), NULL, linter ) expect_lint( trim_some(" lapply(x, function(xi) { print(xi) xi^2 }) "), NULL, linter ) # This _could_ be lapply(x, `%in%`, tbl), but don't force infix into lambda expect_lint("lapply(x, function(xi) xi %in% tbl)", NULL, linter) # This one could not expect_lint("lapply(x, function(xi) tbl %in% xi)", NULL, linter) # would require multiple lapply() loops expect_lint("lapply(x, function(xi) foo(bar(xi)))", NULL, linter) expect_lint("lapply(x, function(xi) return(foo(bar(xi))))", NULL, linter) # extractions, #2231 expect_lint("lapply(l, function(x) rle(x)$values)", NULL, linter) expect_lint('lapply(l, function(x) rle(x)["values"])', NULL, linter) expect_lint('lapply(l, function(x) rle(x)[["values"]])', NULL, linter) expect_lint("lapply(l, function(x) rle(x)@values)", NULL, linter) # return() extractions, #2258 expect_lint("lapply(l, function(x) return(foo(x)$bar))", NULL, linter) expect_lint('lapply(l, function(x) return(rle(x)["values"]))', NULL, linter) expect_lint('lapply(l, function(x) return(rle(x)[["values"]]))', NULL, linter) expect_lint("lapply(l, function(x) return(rle(x)@values))", NULL, linter) # Other operators, #2247 expect_lint("lapply(l, function(x) foo(x) - 1)", NULL, linter) expect_lint("lapply(l, function(x) foo(x) * 2)", NULL, linter) expect_lint("lapply(l, function(x) foo(x) ^ 3)", NULL, linter) expect_lint("lapply(l, function(x) foo(x) %% 4)", NULL, linter) # Don't include other lambdas, #2249 expect_lint( trim_some('{ lapply(x, function(e) sprintf("%o", e)) lapply(y, function(e) paste(strlpad(e, "0", width))) }'), NULL, linter ) # only call is on RHS of operator, #2310 expect_lint("lapply(l, function(x) 'a' %in% names(x))", NULL, linter) expect_lint("lapply(l, function(x = 1) 'a' %in% names(x))", NULL, linter) }) test_that("unnecessary_lambda_linter skips allowed inner comparisons", { linter <- unnecessary_lambda_linter() # lapply returns a list, so not the same, though as.list is probably # a better choice expect_lint("lapply(x, function(xi) foo(xi) == 2)", NULL, linter) # this _may_ return a matrix, though outer is probably a better choice if so expect_lint("sapply(x, function(xi) foo(xi) == y)", NULL, linter) # only lint "plain" calls that can be replaced by eliminating the lambda expect_lint("sapply(x, function(xi) sum(abs(xi)) == 0)", NULL, linter) }) test_that("unnecessary_lambda_linter blocks simple disallowed usage", { linter <- unnecessary_lambda_linter() expect_lint( "lapply(DF, function(x) sum(x))", rex::rex("Pass sum directly as a symbol to lapply()"), linter ) expect_lint( "lapply(DF, function(x) return(sum(x)))", rex::rex("Pass sum directly as a symbol to lapply()"), linter ) expect_lint( "rapply(l, function(x) is.data.frame(x))", rex::rex("Pass is.data.frame directly as a symbol to rapply()"), linter ) expect_lint( "eapply(env, function(x) sum(x, na.rm = TRUE))", rex::rex("Pass sum directly as a symbol to eapply()"), linter ) expect_lint( "eapply(env, function(x) return(sum(x, na.rm = TRUE)))", rex::rex("Pass sum directly as a symbol to eapply()"), linter ) }) test_that("unnecessary_lambda_linter blocks simple disallowed usages", { linter <- unnecessary_lambda_linter() linter_allow <- unnecessary_lambda_linter(allow_comparison = TRUE) lint_msg <- rex::rex("Compare to a constant after calling sapply() to get", anything, "sapply(x, foo)") expect_lint("sapply(x, function(xi) foo(xi) == 2)", lint_msg, linter) expect_lint("sapply(x, function(xi) foo(xi) == 'a')", lint_msg, linter) expect_lint("sapply(x, function(xi) foo(xi) == 1 + 2i)", lint_msg, linter) expect_lint("sapply(x, function(xi) foo(xi) == 2)", NULL, linter_allow) expect_lint("sapply(x, function(xi) foo(xi) == 'a')", NULL, linter_allow) expect_lint("sapply(x, function(xi) foo(xi) == 1 + 2i)", NULL, linter_allow) # vapply counts as well # NB: we ignore the FUN.VALUE argument, for now expect_lint( "vapply(x, function(xi) foo(xi) == 2, logical(1L))", rex::rex("Compare to a constant after calling vapply()", anything, "vapply(x, foo, FUN.VALUE = )"), linter ) }) test_that("unnecessary_lambda_linter blocks other comparators as well", { linter <- unnecessary_lambda_linter() linter_allow <- unnecessary_lambda_linter(allow_comparison = TRUE) lint_msg <- rex::rex("Compare to a constant after calling sapply() to get") expect_lint("sapply(x, function(xi) foo(xi) >= 2)", lint_msg, linter) expect_lint("sapply(x, function(xi) foo(xi) != 'a')", lint_msg, linter) expect_lint("sapply(x, function(xi) foo(xi) < 1 + 2i)", lint_msg, linter) expect_lint("sapply(x, function(xi) foo(xi) >= 2)", NULL, linter_allow) expect_lint("sapply(x, function(xi) foo(xi) != 'a')", NULL, linter_allow) expect_lint("sapply(x, function(xi) foo(xi) < 1 + 2i)", NULL, linter_allow) }) test_that("unnecessary_lambda_linter doesn't apply to keyword args", { expect_lint("lapply(x, function(xi) data.frame(nm = xi))", NULL, unnecessary_lambda_linter()) expect_lint("lapply(x, function(xi) return(data.frame(nm = xi)))", NULL, unnecessary_lambda_linter()) }) test_that("purrr-style anonymous functions are also caught", { linter <- unnecessary_lambda_linter() expect_lint("purrr::map(x, ~.x)", NULL, linter) expect_lint("purrr::map_df(x, ~lm(y, .x))", NULL, linter) expect_lint("map_dbl(x, ~foo(bar = .x))", NULL, linter) expect_lint( "purrr::map(x, ~foo(.x))", rex::rex("Pass foo directly as a symbol to map()"), linter ) expect_lint( "purrr::map_int(x, ~foo(.x, y))", rex::rex("Pass foo directly as a symbol to map_int()"), linter ) expect_lint( "purrr::map_vec(x, ~foo(.x, y))", rex::rex("Pass foo directly as a symbol to map_vec()"), linter ) }) test_that("cases with braces are caught", { linter <- unnecessary_lambda_linter() lint_msg <- rex::rex("Pass print directly as a symbol to lapply()") expect_lint( "lapply(x, function(xi) { print(xi) })", lint_msg, linter ) expect_lint( trim_some(" lapply(x, function(xi) { print(xi) }) "), lint_msg, linter ) expect_lint( "lapply(x, function(xi) { return(print(xi)) })", lint_msg, linter ) expect_lint( trim_some(" lapply(x, function(xi) { print(xi) }) "), lint_msg, linter ) expect_lint( trim_some(" lapply(x, function(xi) { return(print(xi)) }) "), lint_msg, linter ) expect_lint( trim_some(" lapply(x, function(xi) { print(xi) xi }) "), NULL, linter ) # false positives like #2231, #2247 are avoided with braces too expect_lint("lapply(x, function(xi) { foo(xi)$bar })", NULL, linter) expect_lint("lapply(x, function(xi) { foo(xi) - 1 })", NULL, linter) }) test_that("function shorthand is handled", { skip_if_not_r_version("4.1.0") expect_lint( "lapply(DF, \\(x) sum(x))", rex::rex("Pass sum directly as a symbol to lapply()"), unnecessary_lambda_linter() ) }) test_that("lints vectorize", { expect_lint( trim_some("{ sapply(x, function(xi) sd(xi)) lapply(y, function(yi) { sum(yi) }) }"), list( list("sd", line_number = 2L), list("sum", line_number = 3L) ), unnecessary_lambda_linter() ) }) lintr/tests/testthat/test-routine_registration_linter.R0000644000176200001440000000143614752731051023351 0ustar liggesuserspatrick::with_parameters_test_that( "lints correctly", { linter <- routine_registration_linter() expect_lint(sprintf("%s(ROUTINE, 1)", caller), NULL, linter) expect_lint( sprintf("%s('ROUTINE', PACKAGE = 'foo')", caller), "Register your native code routines with useDynLib", linter ) }, .test_name = c(".C", ".Call", ".External", ".Fortran"), caller = c(".C", ".Call", ".External", ".Fortran") ) test_that("lints vectorize", { lint_msg <- "Register your native code routines with useDynLib" expect_lint( trim_some("{ .C('ROUTINE', PACKAGE = 'foo') .External('POUTINE', PACKAGE = 'bar') }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), routine_registration_linter() ) }) lintr/tests/testthat/test-system_file_linter.R0000644000176200001440000000173014752731051021412 0ustar liggesuserstest_that("system_file_linter skips allowed usages", { linter <- system_file_linter() expect_lint("system.file('a', 'b', 'c')", NULL, linter) expect_lint("file.path('a', 'b', 'c')", NULL, linter) }) test_that("system_file_linter blocks simple disallowed usages", { linter <- system_file_linter() lint_msg <- rex::rex("Use the `...` argument of system.file() to expand paths") expect_lint("system.file(file.path('path', 'to', 'data'), package = 'foo')", lint_msg, linter) expect_lint("file.path(system.file(package = 'foo'), 'path', 'to', 'data')", lint_msg, linter) }) test_that("lints vectorize", { lint_msg <- rex::rex("Use the `...` argument of system.file() to expand paths") expect_lint( trim_some("{ file.path(system.file(package = 'foo'), 'bar') system.file(file.path('bar', 'data'), package = 'foo') }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), system_file_linter() ) }) lintr/tests/testthat/test-if_switch_linter.R0000644000176200001440000003053414752731051021052 0ustar liggesuserstest_that("if_switch_linter skips allowed usages", { linter <- if_switch_linter() # don't apply to simple if/else statements expect_lint("if (x == 'a') 1 else 2", NULL, linter) # don't apply to non-character conditions # (NB: switch _could_ be used for integral input, but this # interface is IMO a bit clunky / opaque) expect_lint("if (x == 1) 1 else 2", NULL, linter) # this also has a switch equivalent, but we don't both handling such # complicated cases expect_lint("if (x == 'a') 1 else if (x != 'b') 2 else 3", NULL, linter) # multiple variables involved --> no clean change expect_lint("if (x == 'a') 1 else if (y == 'b') 2 else 3", NULL, linter) # multiple conditions --> no clean change expect_lint("if (is.character(x) && x == 'a') 1 else if (x == 'b') 2 else 3", NULL, linter) # simple cases with two conditions might be more natural # without switch(); require at least three branches to trigger a lint expect_lint("if (x == 'a') 1 else if (x == 'b') 2", NULL, linter) # still no third if() clause expect_lint("if (x == 'a') 1 else if (x == 'b') 2 else 3", NULL, linter) }) test_that("if_switch_linter blocks simple disallowed usages", { linter <- if_switch_linter() lint_msg <- rex::rex("Prefer switch() statements over repeated if/else equality tests") # anything with >= 2 equality statements is deemed switch()-worthy expect_lint("if (x == 'a') 1 else if (x == 'b') 2 else if (x == 'c') 3", lint_msg, linter) # expressions are also OK expect_lint("if (foo(x) == 'a') 1 else if (foo(x) == 'b') 2 else if (foo(x) == 'c') 3", lint_msg, linter) }) test_that("if_switch_linter handles further nested if/else correctly", { linter <- if_switch_linter() # ensure that nested if() doesn't generate multiple lints; expect_lint( "if (x == 'a') 1 else if (x == 'b') 2 else if (x == 'c') 3 else if (x == 'd') 4", rex::rex("Prefer switch() statements over repeated if/else equality tests"), linter ) # related to previous test -- if the first condition is non-`==`, the # whole if/else chain is "tainted" / non-switch()-recommended. # (technically, switch can work here, but the semantics are opaque) expect_lint( "if (x %in% c('a', 'e', 'f')) 1 else if (x == 'b') 2 else if (x == 'c') 3 else if (x == 'd') 4", NULL, linter ) }) test_that("multiple lints have right metadata", { lint_msg <- rex::rex("Prefer switch() statements over repeated if/else equality tests") expect_lint( trim_some("{ if (x == 'a') { do_a() } else if (x == 'b') { do_b() } else if (x == 'c') { do_c() } if (y == 'A') { do_A() } else if (y == 'B') { do_B() } else if (y == 'C') { do_C() } }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 9L) ), if_switch_linter() ) }) test_that("max_branch_lines= and max_branch_expressions= arguments work", { max_lines2_linter <- if_switch_linter(max_branch_lines = 2L) max_lines4_linter <- if_switch_linter(max_branch_lines = 4L) max_expr2_linter <- if_switch_linter(max_branch_expressions = 2L) max_expr4_linter <- if_switch_linter(max_branch_expressions = 4L) lint_msg <- rex::rex("Prefer switch() statements over repeated if/else equality tests") one_per_branch_lines <- trim_some(" if (x == 'a') { 1 } else if (x == 'b') { 2 } else if (x == 'c') { 3 } ") expect_lint(one_per_branch_lines, lint_msg, max_lines2_linter) expect_lint(one_per_branch_lines, lint_msg, max_lines4_linter) expect_lint(one_per_branch_lines, lint_msg, max_expr2_linter) expect_lint(one_per_branch_lines, lint_msg, max_expr4_linter) two_per_branch_lines <- trim_some(" if (x == 'a') { 1 2 } else if (x == 'b') { 3 4 } else if (x == 'c') { 5 6 } ") expect_lint(two_per_branch_lines, lint_msg, max_lines2_linter) expect_lint(two_per_branch_lines, lint_msg, max_lines4_linter) expect_lint(two_per_branch_lines, lint_msg, max_expr2_linter) expect_lint(two_per_branch_lines, lint_msg, max_expr4_linter) three_per_branch_lines <- trim_some(" if (x == 'a') { 1 2 3 } else if (x == 'b') { 4 5 6 } else if (x == 'c') { 7 8 9 } ") expect_lint(three_per_branch_lines, NULL, max_lines2_linter) expect_lint(three_per_branch_lines, lint_msg, max_lines4_linter) expect_lint(three_per_branch_lines, NULL, max_expr2_linter) expect_lint(three_per_branch_lines, lint_msg, max_expr4_linter) five_per_branch_lines <- trim_some(" if (x == 'a') { 1 2 3 4 5 } else if (x == 'b') { 6 7 8 9 10 } else if (x == 'c') { 11 12 13 14 15 } ") expect_lint(five_per_branch_lines, NULL, max_lines2_linter) expect_lint(five_per_branch_lines, NULL, max_lines4_linter) expect_lint(five_per_branch_lines, NULL, max_expr2_linter) expect_lint(five_per_branch_lines, NULL, max_expr4_linter) five_lines_three_expr_lines <- trim_some(" if (x == 'a') { 1 2 foo( x ) } else if (x == 'b') { 6 7 bar( y ) } else if (x == 'c') { 11 12 baz( z ) } ") expect_lint(five_lines_three_expr_lines, NULL, max_lines2_linter) expect_lint(five_lines_three_expr_lines, NULL, max_lines4_linter) expect_lint(five_lines_three_expr_lines, NULL, max_expr2_linter) expect_lint( five_lines_three_expr_lines, list(lint_msg, line_number = 1L), max_expr4_linter ) five_expr_three_lines_lines <- trim_some(" if (x == 'a') { 1 2 3; 4; 5 } else if (x == 'b') { 6 7 8; 9; 10 } else if (x == 'c') { 11 12 13; 14; 15 } ") expect_lint(five_expr_three_lines_lines, NULL, max_lines2_linter) expect_lint( five_expr_three_lines_lines, list(lint_msg, line_number = 1L), max_lines4_linter ) expect_lint(five_expr_three_lines_lines, NULL, max_expr2_linter) expect_lint(five_expr_three_lines_lines, NULL, max_expr4_linter) }) test_that("max_branch_lines= and max_branch_expressions= block over-complex switch() too", { max_lines2_linter <- if_switch_linter(max_branch_lines = 2L) max_lines4_linter <- if_switch_linter(max_branch_lines = 4L) max_expr2_linter <- if_switch_linter(max_branch_expressions = 2L) max_expr4_linter <- if_switch_linter(max_branch_expressions = 4L) lint_msg <- rex::rex("Prefer repeated if/else statements over overly-complicated switch() statements.") one_per_branch_lines <- trim_some(" switch(x, a = { 1 }, b = { 2 }, c = { 3 } ) ") expect_lint(one_per_branch_lines, NULL, max_lines2_linter) expect_lint(one_per_branch_lines, NULL, max_lines4_linter) expect_lint(one_per_branch_lines, NULL, max_expr2_linter) expect_lint(one_per_branch_lines, NULL, max_expr4_linter) two_per_branch_lines <- trim_some(" switch(x, a = { 1 2 }, b = { 3 4 }, c = { 5 6 } ) ") expect_lint(two_per_branch_lines, NULL, max_lines2_linter) expect_lint(two_per_branch_lines, NULL, max_lines4_linter) expect_lint(two_per_branch_lines, NULL, max_expr2_linter) expect_lint(two_per_branch_lines, NULL, max_expr4_linter) three_per_branch_lines <- trim_some(" switch(x, a = { 1 2 3 }, b = { 4 5 6 }, c = { 7 8 9 } ) ") expect_lint( three_per_branch_lines, list(lint_msg, line_number = 1L), max_lines2_linter ) expect_lint(three_per_branch_lines, NULL, max_lines4_linter) expect_lint( three_per_branch_lines, list(lint_msg, line_number = 1L), max_expr2_linter ) expect_lint(three_per_branch_lines, NULL, max_expr4_linter) five_per_branch_lines <- trim_some(" switch(x, a = { 1 2 3 4 5 }, b = { 6 7 8 9 10 }, c = { 11 12 13 14 15 } ) ") expect_lint(five_per_branch_lines, lint_msg, max_lines2_linter) expect_lint(five_per_branch_lines, lint_msg, max_lines4_linter) expect_lint(five_per_branch_lines, lint_msg, max_expr2_linter) expect_lint(five_per_branch_lines, lint_msg, max_expr4_linter) five_lines_three_expr_lines <- trim_some(" switch(x, a = { 1 2 foo( x ) }, b = { 6 7 bar( y ) }, c = { 11 12 baz( z ) } ) ") expect_lint(five_lines_three_expr_lines, lint_msg, max_lines2_linter) expect_lint(five_lines_three_expr_lines, lint_msg, max_lines4_linter) expect_lint(five_lines_three_expr_lines, lint_msg, max_expr2_linter) expect_lint(five_lines_three_expr_lines, NULL, max_expr4_linter) five_expr_three_lines_lines <- trim_some(" switch(x, a = { 1 2 3; 4; 5 }, b = { 6 7 8; 9; 10 }, c = { 11 12 13; 14; 15 } ) ") expect_lint(five_expr_three_lines_lines, lint_msg, max_lines2_linter) expect_lint(five_expr_three_lines_lines, NULL, max_lines4_linter) expect_lint(five_expr_three_lines_lines, lint_msg, max_expr2_linter) expect_lint(five_expr_three_lines_lines, lint_msg, max_expr4_linter) }) test_that("max_branch_lines= and max_branch_expressions= interact correctly", { linter <- if_switch_linter(max_branch_lines = 5L, max_branch_expressions = 3L) lint_msg <- rex::rex("Prefer switch() statements over repeated if/else equality tests") expect_lint( trim_some(" if (x == 'a') { 1 } else if (x == 'b') { 2 } else if (x == 'c') { 3 } "), lint_msg, linter ) expect_lint( trim_some(" if (x == 'a') { foo( x1, x2, x3, x4 ) } else if (x == 'b') { 2 } else if (x == 'c') { 3 } "), NULL, linter ) expect_lint( trim_some(" if (x == 'a') { 1; 2; 3; 4 } else if (x == 'b') { 5 } else if (x == 'c') { 6 } "), NULL, linter ) }) test_that("max_branch_lines= and max_branch_expressions= work for a terminal 'else' branch", { max_lines2_linter <- if_switch_linter(max_branch_lines = 2L) max_expr2_linter <- if_switch_linter(max_branch_expressions = 2L) lint_msg <- rex::rex("Prefer repeated if/else statements over overly-complicated switch() statements.") else_long_lines <- trim_some(" if (x == 'a') { 1 } else if (x == 'b') { 2 } else if (x == 'c') { 3 } else { 4 5 6 } ") expect_lint(else_long_lines, NULL, max_lines2_linter) expect_lint(else_long_lines, NULL, max_expr2_linter) default_long_lines <- trim_some(" switch(x, a = { 1 }, b = { 2 }, c = { 3 }, { 4 5 6 } ) ") expect_lint(default_long_lines, lint_msg, max_lines2_linter) expect_lint(default_long_lines, lint_msg, max_expr2_linter) }) test_that("max_branch_lines= and max_branch_expressions= are guided by the most complex branch", { max_lines2_linter <- if_switch_linter(max_branch_lines = 2L) max_expr2_linter <- if_switch_linter(max_branch_expressions = 2L) lint_msg <- rex::rex("Prefer repeated if/else statements over overly-complicated switch() statements.") # no lint if _any_ branch is too complex if_else_one_branch_lines <- trim_some(" if (x == 'a') { 1 } else if (x == 'b') { 2 } else if (x == 'c') { 3 4 5 } ") expect_lint(if_else_one_branch_lines, NULL, max_lines2_linter) expect_lint(if_else_one_branch_lines, NULL, max_expr2_linter) # lint if _any_ branch is too complex switch_one_branch_lines <- trim_some(" switch(x, a = { 1 }, b = { 2 }, c = { 3 4 5 } ) ") expect_lint(switch_one_branch_lines, lint_msg, max_lines2_linter) expect_lint(switch_one_branch_lines, lint_msg, max_expr2_linter) }) lintr/tests/testthat/test-length_test_linter.R0000644000176200001440000000254314752731051021412 0ustar liggesuserstest_that("skips allowed usages", { linter <- length_test_linter() expect_lint("length(x) > 0", NULL, linter) expect_lint("length(DF[key == val, cols])", NULL, linter) }) test_that("blocks simple disallowed usages", { linter <- length_test_linter() lint_msg_stub <- rex::rex("Checking the length of a logical vector is likely a mistake. Did you mean ") expect_lint("length(x == 0)", rex::rex(lint_msg_stub, "`length(x) == 0`?"), linter) expect_lint("length(x == y)", rex::rex(lint_msg_stub, "`length(x) == y`?"), linter) expect_lint("length(x + y == 2)", rex::rex(lint_msg_stub, "`length(x+y) == 2`?"), linter) }) local({ ops <- c(lt = "<", lte = "<=", gt = ">", gte = ">=", eq = "==", neq = "!=") linter <- length_test_linter() lint_msg_stub <- rex::rex("Checking the length of a logical vector is likely a mistake. Did you mean ") patrick::with_parameters_test_that( "all logical operators detected", expect_lint( paste("length(x", op, "y)"), rex::rex("`length(x) ", op, " y`?"), linter ), op = ops, .test_name = names(ops) ) }) test_that("lints vectorize", { expect_lint( trim_some("{ length(x == y) length(y == z) }"), list( list(rex::rex("length(x) == y"), line_number = 2L), list(rex::rex("length(y) == z"), line_number = 3L) ), length_test_linter() ) }) lintr/tests/testthat/test-expect_comparison_linter.R0000644000176200001440000000345214752731051022614 0ustar liggesuserstest_that("expect_comparison_linter skips allowed usages", { linter <- expect_comparison_linter() # there's no expect_ne() for this operator expect_lint("expect_true(x != y)", NULL, linter) # NB: also applies to tinytest, but it's sufficient to test testthat expect_lint("testthat::expect_true(x != y)", NULL, linter) # multiple comparisons are OK expect_lint("expect_true(x > y || x > z)", NULL, linter) # expect_gt() and friends don't have an info= argument expect_lint("expect_true(x > y, info = 'x is bigger than y yo')", NULL, linter) # expect_true() used incorrectly, and as executed the first argument is not a lint expect_lint("expect_true(is.count(n_draws), n_draws > 1)", NULL, linter) }) test_that("expect_comparison_linter blocks simple disallowed usages", { linter <- expect_comparison_linter() expect_lint( "expect_true(x > y)", rex::rex("expect_gt(x, y) is better than expect_true(x > y)."), linter ) # namespace qualification is irrelevant expect_lint( "testthat::expect_true(x < y)", rex::rex("expect_lt(x, y) is better than expect_true(x < y)."), linter ) expect_lint( "expect_true(foo(x) >= y[[2]])", rex::rex("expect_gte(x, y) is better than expect_true(x >= y)."), linter ) expect_lint( "expect_true(x <= y)", rex::rex("expect_lte(x, y) is better than expect_true(x <= y)."), linter ) expect_lint( "expect_true(x == (y == 2))", rex::rex("expect_identical(x, y) is better than expect_true(x == y)."), linter ) }) test_that("lints vectorize", { expect_lint( trim_some("{ expect_true(x < y) expect_true(y > z) }"), list( list(rex::rex("expect_lt("), line_number = 2L), list(rex::rex("expect_gt("), line_number = 3L) ), expect_comparison_linter() ) }) lintr/tests/testthat/test-seq_linter.R0000644000176200001440000001004314752731051017654 0ustar liggesuserstest_that("other : expressions are fine", { linter <- seq_linter() expect_lint("1:10", NULL, linter) expect_lint("2:length(x)", NULL, linter) expect_lint("1:(length(x) || 1)", NULL, linter) }) test_that("seq_len(...) or seq_along(...) expressions are fine", { linter <- seq_linter() expect_lint("seq_len(x)", NULL, linter) expect_lint("seq_along(x)", NULL, linter) expect_lint("seq(2, length(x))", NULL, linter) expect_lint("seq(length(x), 2)", NULL, linter) }) test_that("finds seq(...) expressions", { linter <- seq_linter() lint_msg <- function(want, got) rex::rex("Use ", want, " instead of ", got) expect_lint( "seq(length(x))", lint_msg("seq_along(...)", "seq(length(...))"), linter ) expect_lint( "seq(nrow(x))", lint_msg("seq_len(nrow(...))", "seq(nrow(...))"), linter ) expect_lint( "rev(seq(length(x)))", lint_msg("seq_along(...)", "seq(length(...))"), linter ) expect_lint( "rev(seq(nrow(x)))", lint_msg("seq_len(nrow(...))", "seq(nrow(...))"), linter ) }) test_that("finds 1:length(...) expressions", { linter <- seq_linter() lint_msg <- function(want, got) rex::rex("Use ", want, " instead of ", got) expect_lint( "1:length(x)", lint_msg("seq_along(...)", "1:length(...)"), linter ) expect_lint( "1:nrow(x)", lint_msg("seq_len(nrow(...))", "1:nrow(...)"), linter ) expect_lint( "1:ncol(x)", lint_msg("seq_len(ncol(...))", "1:ncol(...)"), linter ) expect_lint( "1:NROW(x)", lint_msg("seq_len(NROW(...))", "1:NROW(...)"), linter ) expect_lint( "1:NCOL(x)", lint_msg("seq_len(NCOL(...))", "1:NCOL(...)"), linter ) expect_lint( "1:dim(x)[1L]", lint_msg("seq_len(dim(...)[1L])", "1:dim(...)[1L]"), linter ) expect_lint( "1L:dim(x)[[1]]", rex::rex("Use seq_len", anything, "dim(...)"), linter ) expect_lint( "mutate(x, .id = 1:n())", lint_msg("seq_len(n())", "1:n(),"), linter ) expect_lint( "x[, .id := 1:.N]", lint_msg("seq_len(.N)", "1:.N,"), linter ) }) test_that("1L is also bad", { expect_lint( "1L:length(x)", rex::rex("seq_along", anything, "1L:length(...)"), seq_linter() ) }) test_that("reverse seq is ok", { linter <- seq_linter() expect_lint("rev(seq_along(x))", NULL, linter) expect_lint("rev(seq_len(nrow(x)))", NULL, linter) expect_lint( "length(x):1", rex::rex("rev(seq_along(...))", anything, "length(...):1"), linter ) }) test_that("Message vectorization works for multiple lints", { linter <- seq_linter() expect_lint( trim_some("{ 1:length(x) 1:nrow(y) }"), list( list(rex::rex("seq_along(...)", anything, "1:length(...)"), line_number = 2L), list(rex::rex("seq_len(nrow(...))", anything, "1:nrow(...)"), line_number = 3L) ), linter ) expect_lint( trim_some("{ seq(length(x)) 1:nrow(y) }"), list( list(rex::rex("seq_along(...)", anything, "seq(length(...))"), line_number = 2L), list(rex::rex("seq_len(nrow(...))", anything, "1:nrow(...)"), line_number = 3L) ), linter ) expect_lint( trim_some("{ seq(length(x)) seq(nrow(y)) }"), list( list(rex::rex("seq_along(...)", anything, "seq(length(...))"), line_number = 2L), list(rex::rex("seq_len(nrow(...))", anything, "seq(nrow(...))"), line_number = 3L) ), linter ) expect_lint( trim_some("{ 1:NROW(x) seq(NCOL(y)) }"), list( list(rex::rex("seq_len(NROW(...))", anything, "1:NROW(...)"), line_number = 2L), list(rex::rex("seq_len(NCOL(...))", anything, "seq(NCOL(...))"), line_number = 3L) ), linter ) }) test_that("Message recommends rev() correctly", { linter <- seq_linter() expect_lint(".N:1", rex::rex("Use rev(seq_len(.N))"), linter) expect_lint("n():1", rex::rex("Use rev(seq_len(n()))"), linter) expect_lint("nrow(x):1", rex::rex("Use rev(seq_len(nrow(...)))"), linter) expect_lint("length(x):1", rex::rex("Use rev(seq_along(...))"), linter) }) lintr/tests/testthat/test-normalize_exclusions.R0000644000176200001440000001111514752731051021764 0ustar liggesuserswithr::local_options(list( lintr.exclude = "#TeSt_NoLiNt", lintr.exclude_start = "#TeSt_NoLiNt_StArT", lintr.exclude_end = "#TeSt_NoLiNt_EnD" )) a <- withr::local_tempfile() b <- withr::local_tempfile() c <- withr::local_tempfile(tmpdir = ".") file.create(a, b, c) a <- normalize_path(a) b <- normalize_path(b) c <- normalize_path(c) test_that("it merges two NULL or empty objects as an empty list", { expect_identical(lintr:::normalize_exclusions(c(NULL, NULL)), list()) expect_identical(lintr:::normalize_exclusions(c(NULL, list())), list()) expect_identical(lintr:::normalize_exclusions(c(list(), NULL)), list()) expect_identical(lintr:::normalize_exclusions(c(list(), list())), list()) }) test_that("it returns the object if the other is NULL", { t1 <- list() t1[[a]] <- list(1L:10L) expect_identical(lintr:::normalize_exclusions(c(t1, NULL)), t1) expect_identical(lintr:::normalize_exclusions(c(NULL, t1)), t1) }) test_that("it returns the union of two non-overlapping lists", { t1 <- list() t1[[a]] <- list(1L:10L) t2 <- list() t2[[a]] <- list(20L:30L) res <- list() res[[a]] <- list(c(1L:10L, 20L:30L)) expect_identical(lintr:::normalize_exclusions(c(t1, t2)), res) }) test_that("it works with named lists", { t1 <- list() t1[[a]] <- list(1L:10L, my_linter = 1L:20L) t2 <- list() t2[[a]] <- list(11L:15L, my_linter = 21L:25L) res <- list() res[[a]] <- list(1L:15L, my_linter = 1L:25L) expect_identical(lintr:::normalize_exclusions(c(t1, t2)), res) }) test_that("it returns the union of two overlapping lists", { t1 <- list() t1[[a]] <- list(1L:10L) t2 <- list() t2[[a]] <- list(5L:15L) res <- list() res[[a]] <- list(1L:15L) expect_identical(lintr:::normalize_exclusions(c(t1, t2)), res) }) test_that("it adds names if needed", { t1 <- list() t1[[a]] <- list(1L:10L) t2 <- list() t2[[b]] <- list(5L:15L) res <- list() res[[a]] <- list(1L:10L) res[[b]] <- list(5L:15L) expect_identical(lintr:::normalize_exclusions(c(t1, t2)), res) }) test_that("it handles full file exclusions", { res <- list() res[[a]] <- list(Inf) expect_identical(lintr:::normalize_exclusions(list(a)), res) t1 <- list() t1[[1L]] <- a t1[[b]] <- 1L res <- list() res[[a]] <- list(Inf) res[[b]] <- list(1L) expect_identical(lintr:::normalize_exclusions(t1), res) }) test_that("it handles redundant lines", { t1 <- list() t1[[a]] <- list(c(1L, 1L, 1L:10L)) res <- list() res[[a]] <- list(1L:10L) expect_identical(lintr:::normalize_exclusions(t1), res) t1 <- list() t1[[a]] <- list(c(1L, 1L, 1L:10L)) t1[[b]] <- list(1L:10L) res <- list() res[[a]] <- list(1L:10L) res[[b]] <- list(1L:10L) expect_identical(lintr:::normalize_exclusions(t1), res) }) test_that("it handles redundant linters", { t1 <- list() # nolint next: duplicate_argument_linter. t1[[a]] <- list(c(1L, 1L, 1L:10L), my_linter = c(1L, 1L, 1L, 2L), my_linter = 3L) res <- list() res[[a]] <- list(1L:10L, my_linter = 1L:3L) expect_identical(lintr:::normalize_exclusions(t1), res) t1 <- list() t1[[a]] <- list(c(1L, 1L, 1L:10L), my_linter = c(1L, 1L, 1L, 2L)) # nolint next: duplicate_argument_linter. t1[[b]] <- list(1L:10L, my_linter = 1L:10L, my_linter = 11L:20L) res <- list() res[[a]] <- list(1L:10L, my_linter = 1L:2L) res[[b]] <- list(1L:10L, my_linter = 1L:20L) expect_identical(lintr:::normalize_exclusions(t1), res) }) test_that("it handles redundant files", { t1 <- list(1L:10L, 10L:20L) names(t1) <- c(a, a) res <- list() res[[a]] <- list(1L:20L) expect_identical(lintr:::normalize_exclusions(t1), res) }) test_that("it normalizes file paths, removing non-existing files", { t1 <- list() t1[[a]] <- 1L:10L t2 <- list() t2[["notafile"]] <- 5L:15L t3 <- list() t3[[c]] <- 5L:15L res <- list() res[[a]] <- list(1L:10L) res[[c]] <- list(5L:15L) expect_identical(lintr:::normalize_exclusions(c(t1, t2, t3)), res) res <- list() res[[a]] <- list(1L:10L) res[["notafile"]] <- list(5L:15L) res[[c]] <- list(5L:15L) expect_identical(lintr:::normalize_exclusions(c(t1, t2, t3), normalize_path = FALSE), res) }) test_that("it errors for invalid specifications", { msg_full_files <- "Full file exclusions must be vectors of length 1." expect_error(lintr:::normalize_exclusions(2L), msg_full_files) expect_error(lintr:::normalize_exclusions(list("a.R", 2L)), msg_full_files) expect_error(lintr:::normalize_exclusions(list(a.R = Inf, 2L)), msg_full_files) msg_full_lines <- "Full line exclusions must be or vectors." expect_error(lintr:::normalize_exclusions(list(a.R = "Inf")), msg_full_lines) }) lintr/tests/testthat/test-print_linter.R0000644000176200001440000000177314752731051020232 0ustar liggesuserstest_that("print_linter skips allowed usages", { linter <- print_linter() expect_lint("print(x)", NULL, linter) expect_lint("print(foo(x))", NULL, linter) }) test_that("print_linter blocks disallowed usages", { linter <- print_linter() lint_msg <- rex::rex("Use cat() instead of print() logging messages. Use message() in cases calling for a signalled condition.") expect_lint('print("hi")', lint_msg, linter) # basic known-character functions expect_lint('print(paste(x, "b", y))', lint_msg, linter) expect_lint('print(paste0(x, "c", y))', lint_msg, linter) expect_lint('print(sprintf("a %s", x))', lint_msg, linter) # vectorization, metadata expect_lint( trim_some("{ print('a') print(paste('x', y)) print(z) print(sprintf('%s', b)) }"), list( list(lint_msg, line_number = 2L, column_number = 3L), list(lint_msg, line_number = 3L, column_number = 3L), list(lint_msg, line_number = 5L, column_number = 3L) ), linter ) }) lintr/tests/testthat/test-cache.R0000644000176200001440000003021214752731051016552 0ustar liggesusers# Fixtures fixtures <- list() fixtures$retrieve_lint <- function() { file_name <- "R/test.R" lines <- c("foobar1", "foobar2", "foobar3") lints <- list( Lint(file_name, 1L, line = "foobar1"), Lint(file_name, 2L, line = "foobar2"), Lint(file_name, 3L, line = "foobar3") ) expr <- list(content = paste(collapse = "\n", lines)) list( lines = lines, linters = list(), lints = lints, expr = expr ) } # Run tests with a temporary cache directory, so we don't leave files behind # after running withr::local_options(lintr.cache_directory = withr::local_tempdir()) # Helper functions fhash <- function(filename) { digest::digest(filename, algo = "sha1") } # Tests # `clear_cache` test_that("clear_cache deletes the file if a file is given", { local_mocked_bindings( read_settings = function(...) invisible(...), unlink = function(...) list(...) ) e1 <- new.env(parent = emptyenv()) d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) want <- list(file.path(d1, fhash("R/test.R")), recursive = TRUE) expect_identical(clear_cache(f1, d1), want) expect_identical(clear_cache(file = f1, path = d1), want) }) test_that("clear_cache deletes the directory if no file is given", { local_mocked_bindings( read_settings = function(...) invisible(...), unlink = function(...) list(...) ) expect_identical(clear_cache(file = NULL, path = "."), list(".", recursive = TRUE)) }) # `load_cache` test_that("load_cache loads the saved file in a new empty environment", { e1 <- new.env(parent = emptyenv()) e1[["x"]] <- "foobar" d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) e2 <- lintr:::load_cache(file = f1, path = d1) expect_identical(e2, e1) }) test_that("load_cache returns an empty environment if no cache file exists", { e1 <- new.env(parent = emptyenv()) d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" f2 <- "test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) e2 <- lintr:::load_cache(file = f2, path = d1) expect_identical(e2, e1) }) test_that("load_cache returns an empty environment if reading cache file fails", { e1 <- new.env(parent = emptyenv()) e1[["x"]] <- "foobar" d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) cache_f1 <- file.path(d1, fhash(f1)) writeLines(character(), cache_f1) expect_warning( { e2 <- lintr:::load_cache(file = f1, path = d1) }, "Could not load cache file" ) saveRDS(e1, cache_f1) expect_warning( { e3 <- lintr:::load_cache(file = f1, path = d1) }, "Could not load cache file" ) expect_identical(ls(e2), character()) expect_identical(ls(e3), character()) }) # `save_cache` test_that("save_cache creates a directory if needed", { e1 <- new.env(parent = emptyenv()) d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" expect_false(file.exists(d1)) expect_false(file.exists(file.path(d1, fhash(f1)))) lintr:::save_cache(cache = e1, file = f1, path = d1) expect_true(file.exists(d1)) expect_true(file.info(d1)$isdir) expect_true(file.exists(file.path(d1, fhash(f1)))) }) test_that("save_cache uses unambiguous cache file names", { e1 <- new.env(parent = emptyenv()) d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" f2 <- "test.R" expect_false(file.exists(file.path(d1, fhash(f1)))) expect_false(file.exists(file.path(d1, fhash(f2)))) lintr:::save_cache(cache = e1, file = f1, path = d1) lintr:::save_cache(cache = e1, file = f2, path = d1) expect_true(fhash(f1) != fhash(f2)) expect_true(file.exists(file.path(d1, fhash(f1)))) expect_true(file.exists(file.path(d1, fhash(f2)))) }) test_that("save_cache saves all non-hidden objects from the environment", { e1 <- new.env(parent = emptyenv()) e1$t1 <- 1L e1$t2 <- 2L d1 <- withr::local_tempfile(pattern = "lintr_cache_") f1 <- "R/test.R" lintr:::save_cache(cache = e1, file = f1, path = d1) e2 <- new.env(parent = emptyenv()) load(file = file.path(d1, fhash(f1)), envir = e2) expect_identical(e2, e1) }) # `cache_file` test_that("cache_file generates the same cache with different lints", { e1 <- new.env(parent = emptyenv()) f1 <- withr::local_tempfile(lines = "foobar") lintr:::cache_file(e1, f1, list(), list()) lintr:::cache_file(e1, f1, list(), list(1L)) expect_length(ls(e1), 1L) }) test_that("cache_file generates different caches for different linters", { e1 <- new.env(parent = emptyenv()) f1 <- withr::local_tempfile(lines = "foobar") lintr:::cache_file(e1, f1, list(), list()) lintr:::cache_file(e1, f1, list(1L), list()) expect_length(ls(e1), 2L) }) # `retrieve_file` test_that("retrieve_file returns NULL if there is no cached result", { e1 <- new.env(parent = emptyenv()) f1 <- withr::local_tempfile(lines = "foobar") expect_null(lintr:::retrieve_file(e1, f1, list())) }) test_that("retrieve_file returns the cached result if found", { e1 <- new.env(parent = emptyenv()) f1 <- withr::local_tempfile(lines = "foobar") lintr:::cache_file(e1, f1, list(), list("foobar")) expect_identical(lintr:::retrieve_file(e1, f1, list()), list("foobar")) }) # `cache_lint` test_that("cache_lint generates the same cache with different lints", { e1 <- new.env(parent = emptyenv()) t1 <- list(content = "test") lintr:::cache_lint(e1, t1, list(), list()) lintr:::cache_lint(e1, t1, list(), list(1L)) expect_length(ls(e1), 1L) }) test_that("cache_lint generates different caches for different linters", { e1 <- new.env(parent = emptyenv()) t1 <- list(content = "test") lintr:::cache_lint(e1, t1, list(), list()) lintr:::cache_lint(e1, t1, list(1L), list()) expect_length(ls(e1), 2L) }) # `retrieve_lint` test_that("retrieve_lint returns the same lints if nothing has changed", { test_data <- fixtures$retrieve_lint() e1 <- new.env(parent = emptyenv()) lintr:::cache_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lints = test_data[["lints"]] ) t1 <- lintr:::retrieve_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lines = test_data[["lines"]] ) expect_identical(t1, test_data[["lints"]]) }) test_that( "retrieve_lint returns the same lints with fixed line numbers if lines added above", { test_data <- fixtures$retrieve_lint() e1 <- new.env(parent = emptyenv()) lines1 <- test_data[["lines"]] lines2 <- c("", lines1) lints <- test_data[["lints"]] lintr:::cache_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lints = lints ) t1 <- lintr:::retrieve_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lines = lines2 ) expect_identical(t1[[1L]]$line_number, lints[[1L]]$line_number + 1L) expect_identical(t1[[2L]]$line_number, lints[[2L]]$line_number + 1L) expect_identical(t1[[3L]]$line_number, lints[[3L]]$line_number + 1L) } ) test_that("retrieve_lint returns the same lints with lines added below", { test_data <- fixtures$retrieve_lint() e1 <- new.env(parent = emptyenv()) lines1 <- test_data[["lines"]] lines2 <- c(lines1, "") lintr:::cache_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lints = test_data[["lints"]] ) t1 <- lintr:::retrieve_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lines = lines2 ) expect_identical(t1, test_data[["lints"]]) }) test_that( "retrieve_lint returns the same lints with fixed line numbers if lines added between", { test_data <- fixtures$retrieve_lint() e1 <- new.env(parent = emptyenv()) lines1 <- test_data[["lines"]] lines2 <- c(lines1[1L], "", lines1[2L:3L], "") lints1 <- test_data[["lints"]] lintr:::cache_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lints = lints1 ) t1 <- lintr:::retrieve_lint( cache = e1, expr = test_data[["expr"]], linter = test_data[["linters"]], lines = lines2 ) expect_identical(t1[[1L]]$line_number, lints1[[1L]]$line_number) expect_identical(t1[[2L]]$line_number, lints1[[2L]]$line_number + 1L) expect_identical(t1[[3L]]$line_number, lints1[[3L]]$line_number + 1L) } ) # `has_lint` test_that("has_lint returns FALSE if there is no cached result", { e1 <- new.env(parent = emptyenv()) t1 <- list(content = "foobar") expect_false(lintr:::has_lint(e1, t1, list())) }) test_that("has_lint returns TRUE if there is a cached result", { e1 <- new.env(parent = emptyenv()) t1 <- list(content = "foobar") lintr:::cache_lint(e1, t1, list(), list()) expect_true(lintr:::has_lint(e1, t1, list())) }) test_that("has_lint distinguishes global expressions from line expression with same content", { e1 <- new.env(parent = emptyenv()) same_content <- "foobar" line_expr <- list(content = same_content, parsed_content = data.frame()) lintr:::cache_lint(e1, line_expr, list(), list()) global_expr <- list(content = same_content, file_lines = character()) expect_false(lintr:::has_lint(e1, global_expr, list())) }) # `find_new_line` test_that("find_new_line returns the same if the line is the same", { t1 <- c( "foobar1", "foobar2", "foobar3" ) expect_identical(lintr:::find_new_line(1L, "foobar1", t1), 1L) expect_identical(lintr:::find_new_line(2L, "foobar2", t1), 2L) expect_identical(lintr:::find_new_line(3L, "foobar3", t1), 3L) }) test_that("find_new_line returns the correct line if it is before the current line", { t1 <- c( "foobar1", "foobar2", "foobar3" ) expect_identical(lintr:::find_new_line(1L, "foobar1", t1), 1L) expect_identical(lintr:::find_new_line(2L, "foobar1", t1), 1L) expect_identical(lintr:::find_new_line(3L, "foobar1", t1), 1L) }) test_that("find_new_line returns the correct line if it is after the current line", { t1 <- c( "foobar1", "foobar2", "foobar3" ) expect_identical(lintr:::find_new_line(1L, "foobar3", t1), 3L) expect_identical(lintr:::find_new_line(2L, "foobar3", t1), 3L) expect_identical(lintr:::find_new_line(3L, "foobar3", t1), 3L) }) # test_that("lint with cache uses the provided relative cache directory", { path <- withr::local_tempdir("my_cache_dir") linter <- assignment_linter() # create the cache expect_lint("a <- 1", NULL, linter, cache = path) expect_true(dir.exists(path)) expect_length(list.files(file.path(path)), 1L) # read the cache expect_lint("a <- 1", NULL, linter, cache = path) expect_true(dir.exists(path)) }) test_that("it works outside of a package", { linter <- assignment_linter() local_mocked_bindings(find_package = function(...) NULL) path <- withr::local_tempfile(pattern = "my_cache_dir_") expect_false(dir.exists(path)) expect_lint("a <- 1", NULL, linter, cache = path) expect_true(dir.exists(path)) expect_length(list.files(path), 1L) expect_lint("a <- 1", NULL, linter, cache = path) expect_true(dir.exists(path)) }) test_that("cache = TRUE workflow works", { # Need a test structure with a safe to load .lintr withr::local_dir(file.path("dummy_packages", "package")) withr::local_options(lintr.linter_file = "lintr_test_config") files <- normalize_path(list.files(recursive = TRUE, full.names = TRUE)) # Manually clear cache (that function is exported) for (f in files) { clear_cache(file = f) } l1 <- lint_package(cache = TRUE) l2 <- lint_package(cache = TRUE) expect_identical(l1, l2) }) test_that("cache = TRUE works with nolint", { linters <- list(infix_spaces_linter()) file <- withr::local_tempfile() writeLines("1+1\n", file) expect_length(lint(file, linters, cache = TRUE), 1L) writeLines("1+1 # nolint\n", file) expect_length(lint(file, linters, cache = TRUE), 0L) writeLines("1+1\n", file) expect_length(lint(file, linters, cache = TRUE), 1L) writeLines("1+1 # nolint\n", file) expect_length(lint(file, linters, cache = TRUE), 0L) }) lintr/tests/testthat/test-class_equals_linter.R0000644000176200001440000000430014752731051021542 0ustar liggesuserstest_that("class_equals_linter skips allowed usages", { linter <- class_equals_linter() expect_lint("class(x) <- 'character'", NULL, linter) expect_lint("class(x) = 'character'", NULL, linter) # proper way to test exact class expect_lint("identical(class(x), c('glue', 'character'))", NULL, linter) expect_lint("is_lm <- inherits(x, 'lm')", NULL, linter) }) test_that("class_equals_linter blocks simple disallowed usages", { linter <- class_equals_linter() lint_msg <- rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes") expect_lint("if (class(x) == 'character') stop('no')", lint_msg, linter) expect_lint("is_regression <- class(x) == 'lm'", lint_msg, linter) expect_lint("is_regression <- 'lm' == class(x)", lint_msg, linter) }) test_that("class_equals_linter blocks usage of %in% for checking class", { linter <- class_equals_linter() lint_msg <- rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes") expect_lint("if ('character' %in% class(x)) stop('no')", lint_msg, linter) expect_lint("if (class(x) %in% 'character') stop('no')", lint_msg, linter) }) test_that("class_equals_linter blocks class(x) != 'klass'", { expect_lint( "if (class(x) != 'character') TRUE", rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes"), class_equals_linter() ) }) # as seen, e.g. in base R test_that("class_equals_linter skips usage for subsetting", { linter <- class_equals_linter() expect_lint("class(x)[class(x) == 'foo']", NULL, linter) # but not further nesting expect_lint( "x[if (class(x) == 'foo') 1 else 2]", rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes"), linter ) }) test_that("lints vectorize", { lint_msg <- rex::rex("Use inherits(x, 'class-name'), is. for S3 classes, or is(x, 'S4Class') for S4 classes") expect_lint( trim_some("{ 'character' %in% class(x) class(x) == 'character' }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), class_equals_linter() ) }) lintr/tests/testthat/test-error.R0000644000176200001440000000347514752731051016653 0ustar liggesuserstest_that("returns the correct linting", { msg_escape_char <- rex::rex("is an unrecognized escape in character string") expect_lint('"\\R"', msg_escape_char) expect_lint('"\\A"', msg_escape_char) expect_lint('"\\z"', msg_escape_char) placeholder_linter <- function(...) NULL class(placeholder_linter) <- "linter" attr(placeholder_linter, "name") <- "null" expect_lint( "a <- 1 function() { b", rex::rex("unexpected end of input"), placeholder_linter ) linter <- equals_na_linter() expect_lint("x=", rex::rex("unexpected end of input"), linter) expect_lint("x += 1", rex::rex("unexpected '='"), linter) expect_lint("{x = }", rex::rex("unexpected '}'"), linter) expect_lint("x = ;", rex::rex("unexpected ';'"), linter) # no parsing error is expected for the equals-assignment in this code expect_lint("purrr::partial(list, 1, ... = , 2)", NULL, linter) # trigger error with base only, and extract it to match against # what comes out from expect_lint. get_base_message <- function(e) { rex::re_substitutes( data = conditionMessage(e), pattern = rex::rex( list(start, ":", any_digits, ":", any_digits, ": ") %or% list(newline, anything, newline, anything, end) ), replacement = "", global = TRUE ) } expected_message <- tryCatch(parse(text = "\\"), error = get_base_message) expect_lint("\\", rex::rex(expected_message)) msg_zero_length_var <- rex::rex("attempt to use zero-length variable name") expect_lint("``", msg_zero_length_var) expect_lint("``()", msg_zero_length_var) expect_lint("''()", msg_zero_length_var) expect_lint('""()', msg_zero_length_var) expect_lint("fun(''=42)", msg_zero_length_var) expect_lint('fun(""=42)', msg_zero_length_var) expect_lint('fun(a=1,""=42)', msg_zero_length_var) }) lintr/tests/testthat/test-expect_true_false_linter.R0000644000176200001440000000217414752731051022573 0ustar liggesuserstest_that("expect_true_false_linter skips allowed usages", { # expect_true is a scalar test; testing logical vectors with expect_equal is OK expect_lint("expect_equal(x, c(TRUE, FALSE))", NULL, expect_true_false_linter()) }) test_that("expect_true_false_linter blocks simple disallowed usages", { linter <- expect_true_false_linter() expect_lint( "expect_equal(foo(x), TRUE)", rex::rex("expect_true(x) is better than expect_equal(x, TRUE)"), linter ) # expect_identical is treated the same as expect_equal expect_lint( "testthat::expect_identical(x, FALSE)", rex::rex("expect_false(x) is better than expect_identical(x, FALSE)"), linter ) # also caught when TRUE/FALSE is the first argument expect_lint( "expect_equal(TRUE, foo(x))", rex::rex("expect_true(x) is better than expect_equal(x, TRUE)"), linter ) }) test_that("lints vectorize", { expect_lint( trim_some("{ expect_equal(x, TRUE) expect_equal(x, FALSE) }"), list( list("expect_true", line_number = 2L), list("expect_false", line_number = 3L) ), expect_true_false_linter() ) }) lintr/tests/testthat/test-condition_call_linter.R0000644000176200001440000000310314752731051022044 0ustar liggesuserstest_that("condition_call_linter skips allowed usages", { linter <- condition_call_linter() expect_lint("stop('test', call. = FALSE)", NULL, linter) # works even with multiple arguments expect_lint("stop('this is a', 'test', call. = FALSE)", NULL, linter) linter <- condition_call_linter(display_call = TRUE) expect_lint("stop('test', call. = TRUE)", NULL, linter) linter <- condition_call_linter(display_call = NA) expect_lint("stop('test', call. = TRUE)", NULL, linter) expect_lint("stop('test', call. = FALSE)", NULL, linter) }) patrick::with_parameters_test_that( "condition_call_linter blocks disallowed usages", { linter <- condition_call_linter() lint_message <- rex::rex(call_name, anything, "not to display the call") expect_lint(paste0(call_name, "('test')"), lint_message, linter) expect_lint(paste0(call_name, "('test', call. = TRUE)"), lint_message, linter) linter <- condition_call_linter(display_call = TRUE) lint_message <- rex::rex(call_name, anything, "to display the call") expect_lint(paste0(call_name, "('test', call. = FALSE)"), lint_message, linter) linter <- condition_call_linter(display_call = NA) lint_message <- rex::rex("explicit value", anything, call_name) expect_lint(paste0(call_name, "('test')"), lint_message, linter) }, call_name = c("stop", "warning") ) test_that("lints vectorize", { expect_lint( trim_some("{ stop(e) warning(w) }"), list( list("stop", line_number = 2L), list("warning", line_number = 3L) ), condition_call_linter() ) }) lintr/tests/testthat/test-implicit_integer_linter.R0000644000176200001440000000721614752731051022423 0ustar liggesusers# styler: off skip_if_not_installed("tibble") local({ # Note: cases indicated by "*" are whole numbers, but don't lint because the user has # effectively declared "this is a double" much as adding '.0' is otherwise accepted. cases <- tibble::tribble( ~num_value_str, ~lint_msg, "Inf", "", "NaN", "", "TRUE", "", "FALSE", "", "NA", "", "NA_character_", "", "2.000", "", "2.", "", "2L", "", "2.0", "", "2.1", "", "2", "2L or 2.0", "1e3", "1000L or 1000.0", "1e3L", "", "1.0e3L", "", "1.2e3", "", # * ( = 1200) "1.2e-3", "", "1e-3", "", "1e-33", "", "1.2e0", "", "0x1p+0", "", # * ( = 1) "0x1.ecp+6L", "", "0x1.ecp+6", "", # * ( = 123) "0x1.ec66666666666p+6", "", "8i", "", "8.0i", "" ) # for convenience of coercing these to string (since tribble doesn't support auto-conversion) int_max <- .Machine[["integer.max"]] # largest number that R can represent as an integer cases_int_max <- tibble::tribble( ~num_value_str, ~lint_msg, -int_max - 1.0, "", -int_max, sprintf("%1$dL or %1$d.0", -int_max), int_max, sprintf("%1$dL or %1$d.0", int_max), int_max + 1.0, "" ) cases_int_max$num_value_str <- as.character(cases_int_max$num_value_str) cases <- rbind(cases, cases_int_max) linter <- implicit_integer_linter() patrick::with_parameters_test_that( "single numerical constants are properly identified ", expect_lint(num_value_str, if (nzchar(lint_msg)) lint_msg, linter), .cases = cases ) }) # styler: on test_that("linter returns the correct linting", { linter <- implicit_integer_linter() lint_msg <- rex::rex("Use 1L or 1.0 to avoid implicit integers.") expect_lint("x <<- 1L", NULL, linter) expect_lint("1.0/-Inf -> y", NULL, linter) expect_lint( "y <- 1+i", list(message = lint_msg, line_number = 1L, column_number = 7L), linter ) expect_lint( "z <- 1e5", list(message = rex::rex("100000L or 100000.0"), line_number = 1L, column_number = 9L), linter ) expect_lint( "cat(1:n)", list(message = lint_msg, line_number = 1L, column_number = 6L), linter ) expect_lint( "552^9", list( list(message = rex::rex("552L or 552.0"), line_number = 1L, column_number = 4L), list(message = rex::rex("9L or 9.0"), line_number = 1L, column_number = 6L) ), linter ) }) skip_if_not_installed("tibble") patrick::with_parameters_test_that( "numbers in a:b input are optionally not linted", expect_lint( paste0(left, ":", right), if (n_lints > 0L) rep(list(rex::rex("Use 1L or 1.0")), n_lints), implicit_integer_linter(allow_colon = allow_colon) ), .cases = tibble::tribble( ~left, ~right, ~n_lints, ~allow_colon, ~.test_name, "1", "1", 2L, FALSE, "1:1, !allow_colon", "1", "1", 0L, TRUE, "1:1, allow_colon", "1", "1L", 1L, FALSE, "1:1L, !allow_colon", "1", "1L", 0L, TRUE, "1:1L, allow_colon", "1L", "1", 1L, FALSE, "1L:1, !allow_colon", "1L", "1", 0L, TRUE, "1L:1, allow_colon", "1L", "1L", 0L, FALSE, "1L:1L, !allow_colon", "1L", "1L", 0L, TRUE, "1L:1L, allow_colon" ) ) lintr/tests/testthat/test-object_overwrite_linter.R0000644000176200001440000001100314752731051022435 0ustar liggesuserstest_that("object_overwrite_linter skips allowed usages", { linter <- object_overwrite_linter() expect_lint("function() DT <- data.frame(a = 1)", NULL, linter) # don't block names subassigned e.g. as columns or list elements expect_lint("function() x$sd <- sd(rnorm(100))", NULL, linter) # These virtual names are ignored to slightly reduce the search space expect_lint("function() .__C__logical <- TRUE", NULL, linter) }) test_that("object_overwrite_linter blocks simple disallowed usages", { linter <- object_overwrite_linter() expect_lint( "foo <- function() data <- mtcars", rex::rex("'data' is an exported object from package 'utils'."), linter ) expect_lint( trim_some(" foo <- function() { sigma <- sd(rnorm(100)) } "), rex::rex("'sigma' is an exported object from package 'stats'."), linter ) # base and graphics both export 'plot' (in recent R); ensure this is no issue plot_pkg <- environmentName(environment(plot)) expect_lint( "function() plot <- 1", rex::rex("'plot' is an exported object from package '", plot_pkg, "'."), linter ) # not just the top level of the function expect_lint( trim_some(" foo <- function() { if (TRUE) { sigma <- sd(rnorm(100)) } else { all <- FALSE } } "), list( rex::rex("'sigma' is an exported object from package 'stats'."), rex::rex("'all' is an exported object from package 'base'.") ), linter ) }) test_that("Non-syntactic names are matched & linted (#2346)", { linter <- object_overwrite_linter() lint_msg <- rex::rex("'+' is an exported object from package 'base'.") expect_lint( trim_some(" foo <- function() { `+` <- 2L } "), lint_msg, linter ) expect_lint( trim_some(' foo <- function() { "+" <- 2L } '), lint_msg, linter ) expect_lint( trim_some(" foo <- function() { '+' <- 2L } "), lint_msg, linter ) }) test_that("object_overwrite_linter skips any name assigned at the top level", { linter <- object_overwrite_linter() expect_lint("data <- mtcars", NULL, linter) expect_lint("sigma <- sd(rnorm(100))", NULL, linter) }) test_that("object_overwrite_linter skips argument names", { linter <- object_overwrite_linter() expect_lint("foo <- function(data) data <- data + 1", NULL, linter) expect_lint( trim_some(" bar <- function(a, b, c, sigma) { sigma <- a * b * c ^ sigma } "), NULL, linter ) }) test_that("object_overwrite_linter skips data.table assignments with :=", { expect_lint("foo <- function() x[, title := 4]", NULL, object_overwrite_linter()) }) test_that("object_overwrite_linter optionally accepts package names", { expect_lint("function() data <- 1", NULL, object_overwrite_linter(packages = "base")) expect_lint( "function() lint <- TRUE", rex::rex("'lint' is an exported object from package 'lintr'."), object_overwrite_linter(packages = "lintr") ) }) test_that("non-<- assignments are detected", { linter <- object_overwrite_linter() lint_msg <- rex::rex("'sum' is an exported object from package 'base'.") expect_lint("function(x) sum(x) -> sum", lint_msg, linter) expect_lint("function(x) sum <<- sum(x)", lint_msg, linter) expect_lint("function(x) sum(x) ->> sum", lint_msg, linter) expect_lint("function(x) sum = sum(x)", lint_msg, linter) }) test_that("shorthand lambda is detected", { skip_if_not_r_version("4.1.0") expect_lint("\\() data <- 1", "'data' is an exported object", object_overwrite_linter()) }) test_that("allow_names= works to ignore certain symbols", { expect_lint("function() data <- 1", NULL, object_overwrite_linter(allow_names = "data")) }) test_that("lints vectorize", { lines <- trim_some("{ foo <- function() { data <- 1 var <- 2 } bar <- function(data) { data <- data + 3 sum <- 4 } }") expect_lint( lines, list( list(rex::rex("'data' is an exported object from package 'utils'."), line_number = 3L), list(rex::rex("'var' is an exported object from package 'stats'."), line_number = 4L), list(rex::rex("'sum' is an exported object from package 'base'."), line_number = 8L) ), object_overwrite_linter() ) expect_lint( lines, list(rex::rex("'var' is an exported object from package 'stats'."), line_number = 4L), object_overwrite_linter(packages = c("stats", "base"), allow_names = "sum") ) }) lintr/tests/testthat/test-namespace_linter.R0000644000176200001440000000531714752731051021030 0ustar liggesuserstest_that("namespace_linter skips allowed usages", { linter <- namespace_linter() expect_lint("stats::sd", NULL, linter) expect_lint("stats::sd(c(1,2,3))", NULL, linter) expect_lint('"stats"::sd(c(1,2,3))', NULL, linter) expect_lint('stats::"sd"(c(1,2,3))', NULL, linter) expect_lint("stats::`sd`(c(1,2,3))", NULL, linter) expect_lint("datasets::mtcars", NULL, linter) expect_lint("stats:::print.formula", NULL, linter) expect_lint('"stats":::print.formula', NULL, linter) }) test_that("namespace_linter respects check_exports and check_nonexports arguments", { expect_lint("stats::ssd(c(1,2,3))", NULL, namespace_linter(check_exports = FALSE)) expect_lint("stats:::ssd(c(1,2,3))", NULL, namespace_linter(check_nonexports = FALSE)) expect_lint("stats:::ssd(c(1,2,3))", NULL, namespace_linter(check_exports = FALSE, check_nonexports = FALSE)) }) test_that("namespace_linter can work with backticked symbols", { skip_if_not_installed("rlang") linter <- namespace_linter() expect_lint("rlang::`%||%`", NULL, linter) expect_lint("rlang::`%||%`()", NULL, linter) expect_lint("rlang::'%||%'", NULL, linter) expect_lint("rlang::'%||%'()", NULL, linter) expect_lint('rlang::"%||%"', NULL, linter) expect_lint('rlang::"%||%"()', NULL, linter) expect_lint("rlang::`%>%`", "'%>%' is not exported from {rlang}.", linter) expect_lint("rlang::'%>%'()", "'%>%' is not exported from {rlang}.", linter) expect_lint('rlang::"%>%"()', "'%>%' is not exported from {rlang}.", linter) }) test_that("namespace_linter blocks disallowed usages", { linter <- namespace_linter() expect_lint( "statts::sd(c(1,2,3))", rex::rex("Package 'statts' is not installed."), linter ) expect_lint( "stats::ssd(c(1,2,3))", rex::rex("'ssd' is not exported from {stats}"), linter ) expect_lint( "stats:::sd(c(1,2,3))", rex::rex("Don't use `:::` to access sd, which is exported from stats."), linter ) expect_lint( "statts:::sd(c(1,2,3))", rex::rex("Package 'statts' is not installed."), linter ) expect_lint( "stats:::sdd(c(1,2,3))", rex::rex("'sdd' does not exist in {stats}"), linter ) expect_lint( trim_some(" stats::sd(c(1,2,3)) stats::sdd(c(1,2,3)) "), list(line = "stats::sdd(c(1,2,3))"), linter ) }) test_that("lints vectorize", { expect_lint( trim_some("{ statts::sd(c(1,2,3)) stats::ssd(c(1,2,3)) stats:::sd(c(1,2,3)) }"), list( list(rex::rex("Package 'statts' is not installed."), line_number = 2L), list(rex::rex("'ssd' is not exported from {stats}"), line_number = 3L), list(rex::rex("Don't use `:::` to access sd"), line_number = 4L) ), namespace_linter() ) }) lintr/tests/testthat/test-matrix_apply_linter.R0000644000176200001440000000565614752731051021613 0ustar liggesuserstest_that("matrix_apply_linter skips allowed usages", { linter <- matrix_apply_linter() expect_lint("apply(x, 1, prod)", NULL, linter) expect_lint("apply(x, 1, function(i) sum(i[i > 0]))", NULL, linter) # sum as FUN argument expect_lint("apply(x, 1, f, sum)", NULL, linter) # mean() with named arguments other than na.rm is skipped because they are not # implemented in colMeans() or rowMeans() expect_lint("apply(x, 1, mean, trim = 0.2)", NULL, linter) }) test_that("matrix_apply_linter is not implemented for complex MARGIN values", { linter <- matrix_apply_linter() # Could be implemented at some point expect_lint("apply(x, seq(2, 4), sum)", NULL, linter) # No equivalent expect_lint("apply(x, c(2, 4), sum)", NULL, linter) # Beyond the scope of static analysis expect_lint("apply(x, m, sum)", NULL, linter) expect_lint("apply(x, 1 + 2:4, sum)", NULL, linter) }) test_that("matrix_apply_linter simple disallowed usages", { linter <- matrix_apply_linter() lint_message <- rex::rex("rowSums(x)") expect_lint("apply(x, 1, sum)", lint_message, linter) expect_lint("apply(x, MARGIN = 1, FUN = sum)", lint_message, linter) expect_lint("apply(x, 1L, sum)", lint_message, linter) expect_lint("apply(x, 1:4, sum)", rex::rex("rowSums(x, dims = 4)"), linter) expect_lint("apply(x, 2, sum)", rex::rex("rowSums(colSums(x))"), linter) expect_lint("apply(x, 2:4, sum)", rex::rex("rowSums(colSums(x), dims = 3)"), linter) lint_message <- rex::rex("rowMeans") expect_lint("apply(x, 1, mean)", lint_message, linter) expect_lint("apply(x, MARGIN = 1, FUN = mean)", lint_message, linter) # Works with extra args in mean() expect_lint("apply(x, 1, mean, na.rm = TRUE)", lint_message, linter) lint_message <- rex::rex("colMeans") expect_lint("apply(x, 2, mean)", lint_message, linter) expect_lint("apply(x, 2:4, mean)", lint_message, linter) }) test_that("matrix_apply_linter recommendation includes na.rm if present in original call", { linter <- matrix_apply_linter() lint_message <- rex::rex("na.rm = TRUE") expect_lint("apply(x, 1, sum, na.rm = TRUE)", lint_message, linter) expect_lint("apply(x, 2, sum, na.rm = TRUE)", lint_message, linter) expect_lint("apply(x, 1, mean, na.rm = TRUE)", lint_message, linter) expect_lint("apply(x, 2, mean, na.rm = TRUE)", lint_message, linter) lint_message <- rex::rex("rowSums(x)") expect_lint("apply(x, 1, sum)", lint_message, linter) lint_message <- rex::rex("na.rm = foo") expect_lint("apply(x, 1, sum, na.rm = foo)", lint_message, linter) }) test_that("matrix_apply_linter works with multiple lints in a single expression", { linter <- matrix_apply_linter() expect_lint( trim_some("{ apply(x, 1, sum) apply(y, 2:4, mean, na.rm = TRUE) }"), list( list(rex::rex("rowSums(x)"), line_number = 2L), list(rex::rex("rowMeans(colMeans(y, na.rm = TRUE), dims = 3)"), line_number = 3L) ), linter ) }) lintr/tests/testthat/test-regex_subset_linter.R0000644000176200001440000000360014752731051021564 0ustar liggesuserstest_that("regex_subset_linter skips allowed usages", { expect_lint("y[grepl(ptn, x)]", NULL, regex_subset_linter()) expect_lint("x[grepl(ptn, foo(x))]", NULL, regex_subset_linter()) }) test_that("regex_subset_linter blocks simple disallowed usages", { linter <- regex_subset_linter() lint_msg <- rex::rex("Prefer grep(pattern, x, ..., value = TRUE)") expect_lint("x[grep(ptn, x)]", lint_msg, linter) expect_lint("names(y)[grepl(ptn, names(y), perl = TRUE)]", lint_msg, linter) expect_lint("names(foo(y))[grepl(ptn, names(foo(y)), fixed = TRUE)]", lint_msg, linter) }) test_that("regex_subset_linter skips grep/grepl subassignment", { linter <- regex_subset_linter() expect_lint("x[grep(ptn, x)] <- ''", NULL, linter) expect_lint("x[grepl(ptn, x)] <- ''", NULL, linter) expect_lint("x[grep(ptn, x, perl = TRUE)] = ''", NULL, linter) expect_lint("'' -> x[grep(ptn, x, ignore.case = TRUE)] = ''", NULL, linter) }) test_that("regex_subset_linter skips allowed usages for stringr equivalents", { linter <- regex_subset_linter() expect_lint("y[str_detect(x, ptn)]", NULL, linter) expect_lint("x[str_detect(foo(x), ptn)]", NULL, linter) expect_lint("x[str_detect(x, ptn)] <- ''", NULL, linter) expect_lint("x[str_detect(x, ptn)] <- ''", NULL, linter) }) test_that("regex_subset_linter blocks disallowed usages for stringr equivalents", { linter <- regex_subset_linter() lint_msg <- rex::rex("Prefer stringr::str_subset(x, pattern) over") expect_lint("x[str_which(x, ptn)]", lint_msg, linter) expect_lint("names(y)[str_detect(names(y), ptn, negate = TRUE)]", lint_msg, linter) }) test_that("lints vectorize", { expect_lint( trim_some("{ x[grep(ptn, x)] y[str_detect(y, ptn)] }"), list( list(rex::rex("Prefer grep"), line_number = 2L), list(rex::rex("Prefer stringr::str_subset"), line_number = 3L) ), regex_subset_linter() ) }) lintr/tests/testthat/test-nested_ifelse_linter.R0000644000176200001440000000400414752731051021675 0ustar liggesuserstest_that("nested_ifelse_linter skips allowed usages", { linter <- nested_ifelse_linter() expect_lint("if (TRUE) 1 else 2", NULL, linter) expect_lint("if (TRUE) 1 else if (TRUE) 2 else 3", NULL, linter) expect_lint("ifelse(runif(10) > .2, 4, 6)", NULL, linter) # don't block suggested alternatives expect_lint("fcase(l1, v1, l2, v2)", NULL, linter) expect_lint("case_when(l1 ~ v1, l2 ~ v2)", NULL, linter) }) test_that("nested_ifelse_linter blocks simple disallowed usages", { expect_lint( "ifelse(l1, v1, ifelse(l2, v2, v3))", rex::rex("Don't use nested ifelse() calls"), nested_ifelse_linter() ) expect_lint( "ifelse(l1, ifelse(l2, v1, v2), v3)", rex::rex("Don't use nested ifelse() calls"), nested_ifelse_linter() ) }) test_that("nested_ifelse_linter also catches dplyr::if_else", { expect_lint( "if_else(l1, v1, if_else(l2, v2, v3))", rex::rex("Don't use nested if_else() calls"), nested_ifelse_linter() ) expect_lint( "dplyr::if_else(l1, dplyr::if_else(l2, v1, v2), v3)", rex::rex("Don't use nested if_else() calls"), nested_ifelse_linter() ) }) test_that("nested_ifelse_linter also catches data.table::fifelse", { expect_lint( "fifelse(l1, v1, fifelse(l2, v2, v3))", rex::rex("Don't use nested fifelse() calls"), nested_ifelse_linter() ) expect_lint( "data.table::fifelse(l1, v1, data.table::fifelse(l2, v2, v3))", rex::rex("Don't use nested fifelse() calls"), nested_ifelse_linter() ) # not sure why anyone would do this, but the readability still argument holds expect_lint( "data.table::fifelse(l1, dplyr::if_else(l2, v1, v2), v3)", rex::rex("Don't use nested if_else() calls"), nested_ifelse_linter() ) }) test_that("lints vectorize", { expect_lint( trim_some("{ ifelse(x < 0, ifelse(x == 0, 0, 1), -1) fifelse(y < 0, fifelse(y == 0, 0, 1), -1) }"), list( list("ifelse", line_number = 2L), list("fifelse", line_number = 3L) ), nested_ifelse_linter() ) }) lintr/tests/testthat/test-lint_dir.R0000644000176200001440000000746214752731051017326 0ustar liggesuserstest_that("lint all files in a directory", { # NB: not using .lintr in the test packages because # R CMD check doesn't like hidden files in any subdirectory withr::local_options(lintr.linter_file = "lintr_test_config") the_dir <- test_path("dummy_packages", "package", "vignettes") files <- list.files(the_dir) lints <- lint_dir(the_dir, parse_settings = FALSE) linted_files <- unique(names(lints)) expect_s3_class(lints, "lints") expect_identical(sort(linted_files), sort(files)) }) test_that("lint all relevant directories in a package", { withr::local_options(lintr.linter_file = "lintr_test_config") the_pkg <- test_path("dummy_packages", "package") files <- setdiff( list.files(the_pkg, recursive = TRUE), c("package.Rproj", "DESCRIPTION", "NAMESPACE", "lintr_test_config") ) lintr:::read_settings(NULL) lints <- lint_package(the_pkg, parse_settings = FALSE) linted_files <- unique(names(lints)) # lintr paths contain backslash on windows, list.files uses forward slash. linted_files <- gsub("\\", "/", linted_files, fixed = TRUE) expect_s3_class(lints, "lints") expect_identical(sort(linted_files), sort(files)) # Code coverage is not detected for default_linters. # We want to ensure that object_name_linter uses namespace_imports correctly. # assignment_linter is needed to cause a lint in all vignettes. linters <- list(assignment_linter(), object_name_linter()) lintr:::read_settings(NULL) lints <- lint_package(the_pkg, linters = linters, parse_settings = FALSE) linted_files <- unique(names(lints)) # lintr paths contain backslash on windows, list.files uses forward slash. linted_files <- gsub("\\", "/", linted_files, fixed = TRUE) expect_s3_class(lints, "lints") expect_identical(sort(linted_files), sort(files)) }) test_that("respects directory exclusions", { the_dir <- withr::local_tempdir() the_excluded_dir <- file.path(the_dir, "exclude-me") dir.create(the_excluded_dir) defaults_path <- test_path("default_linter_testcode.R") file.copy(defaults_path, the_dir) file.copy(defaults_path, the_excluded_dir) file.copy(defaults_path, file.path(the_excluded_dir, "bad2.R")) lints <- lint_dir(the_dir, exclusions = "exclude-me") linted_files <- unique(names(lints)) expect_length(linted_files, 1L) expect_identical(linted_files, "default_linter_testcode.R") lints_norm <- lint_dir(the_dir, exclusions = "exclude-me", relative_path = FALSE) linted_files <- unique(names(lints_norm)) expect_length(linted_files, 1L) expect_identical(linted_files, normalize_path(file.path(the_dir, "default_linter_testcode.R"))) }) test_that("respect directory exclusions from settings", { the_dir <- withr::local_tempdir() the_excluded_dir <- file.path(the_dir, "exclude-me") dir.create(the_excluded_dir) defaults_path <- test_path("default_linter_testcode.R") file.copy(defaults_path, the_dir) file.copy(defaults_path, the_excluded_dir) file.copy(defaults_path, file.path(the_excluded_dir, "bad2.R")) cat("exclusions:\n 'exclude-me'\n", file = file.path(the_dir, ".lintr")) lints <- lint_dir(the_dir) linted_files <- unique(names(lints)) expect_length(linted_files, 1L) }) test_that("lint_dir works with specific linters without specifying other arguments", { withr::local_options(lintr.linter_file = "lintr_test_config") the_dir <- test_path("dummy_packages", "package", "vignettes") expect_length(lint_dir(the_dir, assignment_linter(), parse_settings = FALSE), 14L) expect_length(lint_dir(the_dir, commented_code_linter(), parse_settings = FALSE), 0L) }) test_that("typo in argument name gives helpful error", { expect_error(lint_dir(litners = identity), "Found unknown arguments in `...`: `litners`") }) test_that("linting empty directory passes", { expect_length(lint_dir(withr::local_tempdir(), any_duplicated_linter()), 0L) }) lintr/tests/testthat/test-expect_lint.R0000644000176200001440000000660614752731051020037 0ustar liggesusers# testthat's expect_success() and expect_failure() can only handle the first expectation and are # thus less than ideal to test expect_lint(), which can process multiple lints. If you want to test # for failure, always put the lint check or lint field that must fail first. linter <- assignment_linter() lint_msg <- "Use one of <-, <<- for assignment, not =" test_that("no checks", { expect_success(expect_no_lint("a", linter)) expect_success(expect_no_lint("a=1", list())) expect_failure(expect_no_lint("a=1", linter)) }) test_that("single check", { expect_failure(expect_lint(character(), lint_msg, linter)) expect_failure(expect_lint("", lint_msg, linter)) expect_success(expect_lint(content = "a=1", checks = lint_msg, linters = linter)) expect_success(expect_lint("a=1", lint_msg, linter)) expect_failure(expect_lint("a=1", "asdf", linter)) expect_success(expect_lint("a=1", c(message = lint_msg), linter)) expect_failure(expect_lint("a=1", c(message = NULL), linter)) expect_success(expect_lint("a=1", c(message = lint_msg, line_number = 1L), linter)) expect_failure(expect_lint("a=1", c(line_number = 2L, message = lint_msg), linter)) expect_error(expect_lint("a=1", c(message = lint_msg, lineXXX = 1L), linter), "Check 1 has an invalid field: lineXXX") expect_failure(expect_lint("foo ()", list(ranges = list(c(2L, 2L))), function_left_parentheses_linter())) expect_success(expect_lint("\t1", list(ranges = list(c(1L, 1L))), whitespace_linter())) expect_success(expect_lint("a=1", list(message = lint_msg, line_number = 1L), linter)) expect_failure(expect_lint("a=1", list(2L, lint_msg), linter)) expect_success(expect_lint("1:nrow(x)", "(nrow)", seq_linter())) }) test_that("multiple checks", { expect_success( expect_lint(file = "exclusions-test", checks = as.list(rep(lint_msg, 9L)), linters = linter, parse_settings = FALSE) ) expect_success(expect_lint("a=1; b=2", list(lint_msg, lint_msg), linter)) expect_success(expect_lint("a=1; b=2", list(c(message = lint_msg), c(message = lint_msg)), linter)) expect_success(expect_lint("a=1; b=2", list(c(line_number = 1L), c(linter = "assignment_linter")), linter)) expect_success(expect_lint("a=1; b=2", list(lint_msg, c(line = "a=1; b=2", type = "warning")), linter)) expect_success(expect_lint("a=1\nb=2", list(c(line_number = 1L), c(line_number = 2L)), linter)) expect_failure(expect_lint("a=1\nb=2", list(c(line_number = 2L), c(line_number = 2L)), linter)) expect_success(expect_lint("a=1; b=2", list(list(line_number = 1L), list(line_number = 2L)), linter)) expect_failure(expect_lint("a=1; b=2", list(list(line_number = 2L), list(line_number = 2L)), linter)) expect_success( expect_lint("\t1\n\t2", list("tabs", list(column_number = 1L, ranges = list(c(1L, 1L)))), whitespace_linter()) ) }) test_that("expect_lint_free works", { withr::local_options( lintr.rstudio_source_markers = FALSE, lintr.linter_file = "lintr_test_config" ) withr::local_envvar(c(NOT_CRAN = "true", R_COVR = "false")) expect_lint_free(test_path("dummy_packages", "clean")) expect_lint_free(test_path("dummy_packages", "clean_subdir", "r")) expect_failure(expect_lint_free(test_path("dummy_packages", "package"))) }) test_that("expect_lint doesn't change language", { withr::with_envvar(c(LANGUAGE = "mr"), { expect_success(expect_lint("a=1", lint_msg, linter)) expect_identical(Sys.getenv("LANGUAGE"), "mr") }) }) lintr/tests/testthat/test-scalar_in_linter.R0000644000176200001440000000362014752731051021022 0ustar liggesuserstest_that("scalar_in_linter skips allowed usages", { linter <- scalar_in_linter() expect_lint("x %in% y", NULL, linter) expect_lint("y %in% c('a', 'b')", NULL, linter) expect_lint("c('a', 'b') %in% x", NULL, linter) expect_lint("z %in% 1:3", NULL, linter) # scalars on LHS are fine (often used as `"col" %in% names(DF)`) expect_lint("3L %in% x", NULL, linter) # this should be is.na(x), but it more directly uses the "always TRUE/FALSE, _not_ NA" # aspect of %in%, so we delegate linting here to equals_na_linter() expect_lint("x %in% NA", NULL, linter) expect_lint("x %in% NA_character_", NULL, linter) }) test_that("scalar_in_linter blocks simple disallowed usages", { linter <- scalar_in_linter(in_operators = c("%chin%", "%notin%")) lint_msg <- rex::rex("Use comparison operators (e.g. ==, !=, etc.) to match length-1 scalars instead of") expect_lint("x %in% 1", lint_msg, linter) expect_lint("x %chin% 'a'", lint_msg, linter) expect_lint("x %notin% 1", lint_msg, linter) }) test_that("scalar_in_linter blocks or skips based on configuration", { linter_default <- scalar_in_linter() linter_config <- scalar_in_linter(in_operators = "%notin%") lint_msg <- rex::rex("Use comparison operators (e.g. ==, !=, etc.) to match length-1 scalars instead of") # default expect_lint("x %in% 1", lint_msg, linter_default) expect_lint("x %notin% 1", NULL, linter_default) expect_lint("x %notin% y", NULL, linter_default) # configured expect_lint("x %in% 1", lint_msg, linter_config) expect_lint("x %notin% 1", lint_msg, linter_config) expect_lint("x %notin% y", NULL, linter_config) }) test_that("multiple lints are generated correctly", { linter <- scalar_in_linter(in_operators = "%chin%") expect_lint( trim_some('{ x %in% 1 y %chin% "a" }'), list( list("%in%", line_number = 2L), list("%chin%", line_number = 3L) ), linter ) }) lintr/tests/testthat/test-missing_argument_linter.R0000644000176200001440000001026114752731051022441 0ustar liggesuserstest_that("missing_argument_linter skips allowed usages", { linter <- missing_argument_linter() expect_lint("fun(x, a = 1)", NULL, linter) expect_lint("fun(x = 1, a = 1)", NULL, linter) expect_lint("dt[, 1]", NULL, linter) expect_lint("dt[, 'col']", NULL, linter) expect_lint("array[, , 1]", NULL, linter) expect_lint("switch(a =, b =, c = 1, 0)", NULL, linter) expect_lint("alist(a =, b =, c = 1, 0)", NULL, linter) expect_lint("pairlist(path = quote(expr = ))", NULL, linter) #1889 # always allow this missing usage expect_lint("foo()", NULL, linter) expect_lint("test(a =, b =, c = 1, 0)", NULL, missing_argument_linter("test")) }) test_that("missing_argument_linter blocks disallowed usages", { linter <- missing_argument_linter() lint_msg1 <- rex::rex("Missing argument 1 in function call.") lint_msg2 <- rex::rex("Missing argument 2 in function call.") lint_msg3 <- rex::rex("Missing argument 3 in function call.") lint_msga <- rex::rex("Missing argument 'a' in function call.") expect_lint("fun(, a = 1)", lint_msg1, linter) expect_lint( "f <- function(x, y) x\nf(, y = 1)\n", list(lint_msg1, line = "f(, y = 1)"), linter ) expect_lint("fun(a = 1,, b = 2)", lint_msg2, linter) expect_lint("fun(b = 1, a =)", lint_msga, linter) expect_lint("fun(a = 1,)", lint_msg2, linter) expect_lint("fun(a = )", lint_msga, linter) expect_lint( trim_some(" list( a = 1, b = 2, ) "), lint_msg3, linter ) expect_lint("stats::median(1:10, a =)", lint_msga, linter) expect_lint("env$get(1:10, a =)", lint_msga, linter) # Fixes https://github.com/r-lib/lintr/issues/906 # Comments should be ignored so that missing arguments could be # properly identified in these cases. expect_lint( trim_some(" fun( 1, 2, # comment ) "), lint_msg3, linter ) expect_lint( trim_some(" fun( # comment , 1 ) "), lint_msg1, linter ) expect_lint( trim_some(" fun( a = # comment , 1 ) "), lint_msga, linter ) }) test_that("except list can be empty", { linter <- missing_argument_linter(character()) lint_msg <- rex::rex("Missing argument 'a' in function call.") expect_lint("switch(a =, b = 1, 0)", lint_msg, linter) expect_lint("alist(a =)", lint_msg, linter) }) test_that("allow_trailing can allow trailing empty args also for non-excepted functions", { linter <- missing_argument_linter(allow_trailing = TRUE) expect_lint("fun(a = 1,)", NULL, linter) expect_lint( trim_some(" fun( a = 1, # comment ) "), NULL, linter ) # ... but not if the final argument is named expect_lint( "fun(a = 1, b = )", rex::rex("Missing argument 'b' in function call."), linter ) }) test_that("lints vectorize", { linter <- missing_argument_linter() linter_trailing <- missing_argument_linter(allow_trailing = TRUE) lint_msg <- rex::rex("Missing argument in function call.") expect_lint( "foo(,,)", list( list("Missing argument 1", column_number = 5L), list("Missing argument 2", column_number = 6L), list("Missing argument 3", column_number = 7L) ), linter ) expect_lint( "foo(,,)", list( list("Missing argument 1", column_number = 5L), list("Missing argument 2", column_number = 6L) ), linter_trailing ) expect_lint( "foo(a =,,)", list( list("Missing argument 'a'", column_number = 7L), list("Missing argument 2", column_number = 9L), list("Missing argument 3", column_number = 10L) ), linter ) expect_lint( "foo(a =,,)", list( list("Missing argument 'a'", column_number = 7L), list("Missing argument 2", column_number = 9L) ), linter_trailing ) expect_lint( trim_some("{ foo(1,) bar(,2) }"), list( list("Missing argument 2", line_number = 2L), list("Missing argument 1", line_number = 3L) ), linter ) expect_lint( trim_some("{ foo(1,) bar(,2) }"), list("Missing argument 1", line_number = 3L), linter_trailing ) }) lintr/tests/testthat/test-spaces_left_parentheses_linter.R0000644000176200001440000001002014752731051023750 0ustar liggesuserstest_that("spaces_left_parentheses_linter skips allowed usages", { linter <- spaces_left_parentheses_linter() expect_lint("blah", NULL, linter) expect_lint("print(blah)", NULL, linter) expect_lint("base::print(blah)", NULL, linter) expect_lint("base::print(blah, fun(1))", NULL, linter) expect_lint("blah <- function(blah) { }", NULL, linter) expect_lint("(1 + 1)", NULL, linter) expect_lint("(1 + 1)", NULL, linter) expect_lint("( (1 + 1) )", NULL, linter) expect_lint("if (blah) { }", NULL, linter) expect_lint("for (i in j) { }", NULL, linter) expect_lint("1 * (1 + 1)", NULL, linter) expect_lint("!(1 == 1)", NULL, linter) expect_lint("(2 - 1):(3 - 1)", NULL, linter) expect_lint("c(1, 2, 3)[(2 - 1)]", NULL, linter) expect_lint("list(1, 2, 3)[[(2 - 1)]]", NULL, linter) expect_lint("range(10)[(2 - 1):(10 - 1)]", NULL, linter) expect_lint("function(){function(){}}()()", NULL, linter) expect_lint("c(function(){})[1]()", NULL, linter) expect_lint("\"test <- function(x) { if(1 + 1) 'hi' }\"", NULL, linter) expect_lint("res <- c((mat - 1L) %*% combs + 1L)", NULL, linter) expect_lint("if (!(foo && bar || baz)) { foo }", NULL, linter) expect_lint("x^(y + z)", NULL, linter) expect_lint("x**(y + z)", NULL, linter) expect_lint("a <- -(b)", NULL, linter) expect_lint("(3^(3 + 2))", NULL, linter) expect_lint("-(!!!symb)", NULL, linter) expect_lint("'[[<-.data.frame'(object, y)", NULL, linter) expect_lint("object@data@get('input')", NULL, linter) expect_lint("x <- ~(. + y)", NULL, linter) # the internal newline is required to trigger the lint expect_lint("if (x > 1)\n x <- x[-(i)]", NULL, linter) # these don't violate the linter, even if they are strange coding practice expect_lint("for (ii in 1:10) next()", NULL, linter) expect_lint("for (ii in 1:10) break()", NULL, linter) }) test_that("spaces_left_parentheses_linter blocks disallowed usages", { linter <- spaces_left_parentheses_linter() lint_msg <- rex::rex("Place a space before left parenthesis, except in a function call.") expect_lint("if(blah) { }", lint_msg, linter) expect_lint("for(i in j) { }", lint_msg, linter) expect_lint("1*(1 + 1)", lint_msg, linter) expect_lint("test <- function(x) { if(1 + 1) 'hi' }", lint_msg, linter) expect_lint("test <- function(x) { if(`+`(1, 1)) 'hi' }", lint_msg, linter) # more complicated cases for parse tree expect_lint("y1<-(abs(yn)>90)*1", lint_msg, linter) expect_lint("c(a,(a+b))", lint_msg, linter) expect_lint("if (x>y) 1 else(2)", lint_msg, linter) expect_lint("y~(x+z)", lint_msg, linter) expect_lint("if (x>y) {(x+y) / (x-y)}", lint_msg, linter) expect_lint("for (ii in(1:10)) { }", lint_msg, linter) expect_lint("x = 1;(x + 2)*3", lint_msg, linter) expect_lint("foo <- function(x=(1+2)) { }", lint_msg, linter) }) test_that("doesn't produce a warning", { # this contains a function with nested if-statements where the conditional includes a unary minus. # This specific constellation with another if-statement at the same nesting level on the other enclosing if-branch # caused a warning in spaces_left_parentheses_linter (e.g. 84bc3a is broken) complex_lines <- trim_some(" complexity <- function(x) { if (x > 0.0) { if (x > 10.0) { if (x > 20.0) { x <- x / 2.0 } else { return(x) } } else { return(x) } } else { if (x < -10.0) { if (x < -20.0) { x <- x * 2.0 } else { return(x) } } else { return(x) } } x } ") expect_no_warning(lint(text = complex_lines, linters = spaces_left_parentheses_linter())) }) test_that("lints vectorize", { lint_msg <- rex::rex("Place a space before left parenthesis, except in a function call.") expect_lint( trim_some("{ y1<-(abs(yn)>90)*1 for(i in j) { } }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), spaces_left_parentheses_linter() ) }) lintr/tests/testthat/test-one_call_pipe_linter.R0000644000176200001440000000636614752731051021672 0ustar liggesuserstest_that("one_call_pipe_linter skips allowed usages", { linter <- one_call_pipe_linter() # two pipe steps is OK expect_lint("x %>% foo() %>% bar()", NULL, linter) # call in first step --> OK expect_lint("foo(x) %>% bar()", NULL, linter) # both calls in second step --> OK expect_lint("x %>% foo(bar(.))", NULL, linter) # assignment pipe is exempted expect_lint("x %<>% as.character()", NULL, linter) }) test_that("one_call_pipe_linter blocks simple disallowed usages", { linter <- one_call_pipe_linter() lint_msg <- rex::rex("Avoid pipe %>% for expressions with only a single call.") expect_lint("x %>% foo()", lint_msg, linter) # new lines don't matter expect_lint("x %>%\n foo()", lint_msg, linter) # nested case expect_lint("x %>% inner_join(y %>% filter(is_treatment))", lint_msg, linter) }) test_that("one_call_pipe_linter skips data.table chains", { linter <- one_call_pipe_linter() lint_msg <- rex::rex("Avoid pipe %>% for expressions with only a single call.") expect_lint("DT[x > 5, sum(y), by = keys] %>% .[, .SD[1], by = key1]", NULL, linter) # lint here: instead of a pipe, use DT[x > 5, sum(y), by = keys] expect_lint("DT %>% .[x > 5, sum(y), by = keys]", lint_msg, linter) # ditto for [[ expect_lint("DT %>% rowSums() %>% .[[idx]]", NULL, linter) expect_lint("DT %>% .[[idx]]", lint_msg, linter) }) test_that("one_call_pipe_linter treats all pipes equally", { linter <- one_call_pipe_linter() lint_msg_part <- " for expressions with only a single call." expect_lint("foo %>% bar() %$% col", NULL, linter) expect_lint("x %T>% foo()", rex::rex("%T>%", lint_msg_part), linter) expect_lint("x %$%\n foo", rex::rex("%$%", lint_msg_part), linter) expect_lint( 'data %>% filter(type == "console") %$% obscured_id %>% unique()', NULL, linter ) }) test_that("multiple lints are generated correctly", { expect_lint( trim_some("{ a %>% b() c %$% d e %T>% f() }"), list( list(rex::rex("pipe %>%"), line_number = 2L), list(rex::rex("pipe %$%"), line_number = 3L), list(rex::rex("pipe %T>%"), line_number = 4L) ), one_call_pipe_linter() ) }) test_that("Native pipes are handled as well", { skip_if_not_r_version("4.1.0") linter <- one_call_pipe_linter() expect_lint( "x |> foo()", rex::rex("Avoid pipe |> for expressions with only a single call."), linter ) # mixed pipes expect_lint("x |> foo() %>% bar()", NULL, linter) expect_lint("x %>% foo() |> bar()", NULL, linter) expect_lint( trim_some("{ a %>% b() c |> d() }"), list( list(message = "pipe %>%"), list(message = "pipe |>") ), linter ) }) test_that("one_call_pipe_linter skips data.table chains with native pipe", { skip_if_not_r_version("4.3.0") linter <- one_call_pipe_linter() lint_msg <- rex::rex("Avoid pipe |> for expressions with only a single call.") expect_lint("DT[x > 5, sum(y), by = keys] |> _[, .SD[1], by = key1]", NULL, linter) # lint here: instead of a pipe, use DT[x > 5, sum(y), by = keys] expect_lint("DT |> _[x > 5, sum(y), by = keys]", lint_msg, linter) # ditto for [[ expect_lint("DT |> rowSums() |> _[[idx]]", NULL, linter) expect_lint("DT |> _[[idx]]", lint_msg, linter) }) lintr/tests/testthat/test-unused_import_linter.R0000644000176200001440000000554514752731051021774 0ustar liggesuserstest_that("unused_import_linter lints as expected", { linter <- unused_import_linter() expect_lint("library(dplyr)\ntibble(a = 1)", NULL, linter) # SYMBOL_FUNCTION_CALL usage is detected expect_lint("library(tidyverse)\ntibble(a = 1)", NULL, linter) # SYMBOL usage is detected expect_lint("library(dplyr)\ndo.call(tibble, args = list(a = 1))", NULL, linter) # SPECIAL usage is detected expect_lint("library(magrittr)\n1:3 %>% mean()", NULL, linter) # dataset is detected expect_lint("library(dplyr)\nstarwars", NULL, linter) expect_lint("library(datasets)\nstate.center", NULL, linter) # Missing packages are ignored expect_lint("library(not.a.package)\ntibble(a = 1)", NULL, linter) # SYMBOL calls with character.only = TRUE are ignored, even if the argument is a package name expect_lint("library(dplyr, character.only = TRUE)\n1 + 1", NULL, linter) lint_msg <- rex::rex("Package 'dplyr' is attached but never used") msg_ns <- rex::rex("Don't attach package 'dplyr', which is only used by namespace.") expect_lint("library(dplyr)\n1 + 1", lint_msg, linter) expect_lint("require(dplyr)\n1 + 1", lint_msg, linter) expect_lint("library('dplyr')\n1 + 1", lint_msg, linter) expect_lint("library('dplyr', character.only = TRUE)\n1 + 1", lint_msg, linter) # ignore namespaced usages by default, but provide custom lint message expect_lint("library(dplyr)\ndplyr::tibble(a = 1)", msg_ns, linter) expect_lint("library(dplyr)\ndplyr::tibble(a = 1)", NULL, unused_import_linter(allow_ns_usage = TRUE)) # ignore packages in except_packages expect_lint("library(data.table)\n1 + 1", NULL, linter) expect_lint("library(dplyr)\n1 + 1", NULL, unused_import_linter(except_packages = "dplyr")) }) test_that("unused_import_linter handles message vectorization", { skip_if_not_installed("crayon") expect_lint( trim_some(" library(crayon) library(xmlparsedata) xmlparsedata::xml_parse_data(parse(text = 'a')) "), list( list(rex::rex("Package 'crayon' is attached but never used."), line_number = 1L), list(rex::rex("Don't attach package 'xmlparsedata', which is only used by namespace"), line_number = 2L) ), unused_import_linter() ) }) test_that("unused_import_linter lints packages with exports like pkg::pkg", { # glue::glue is an export, so don't get thrown off by the 'glue' symbol in library() expect_lint( trim_some(" library(glue) 1 + 1 "), rex::rex("Package 'glue' is attached but never used."), unused_import_linter() ) }) test_that("glue usages are seen", { lint_msg <- rex::rex("Package 'xmlparsedata' is attached but never used.") lines <- trim_some(" library(glue) library(xmlparsedata) glue('{ xml_parse_data() }') ") expect_lint(lines, NULL, unused_import_linter()) expect_lint(lines, lint_msg, unused_import_linter(interpret_glue = FALSE)) }) lintr/tests/testthat/test-yoda_test_linter.R0000644000176200001440000000417714752731051021072 0ustar liggesuserstest_that("yoda_test_linter skips allowed usages", { linter <- yoda_test_linter() expect_lint("expect_equal(x, 2)", NULL, linter) # namespace qualification doesn't matter expect_lint("testthat::expect_identical(x, 'a')", NULL, linter) # two variables can't be distinguished which is expected/actual (without # playing quixotic games trying to parse that out from variable names) expect_lint("expect_equal(x, y)", NULL, linter) }) test_that("yoda_test_linter blocks simple disallowed usages", { linter <- yoda_test_linter() lint_msg <- rex::rex("Compare objects in tests in the order 'actual', 'expected', not the reverse.") expect_lint("expect_equal(2, x)", lint_msg, linter) expect_lint("testthat::expect_identical('a', x)", lint_msg, linter) expect_lint("expect_setequal(2, x)", lint_msg, linter) # complex literals are slightly odd expect_lint("expect_equal(2 + 1i, x)", lint_msg, linter) }) test_that("yoda_test_linter ignores strings in $ expressions", { linter <- yoda_test_linter() # the "key" here shows up at the same level of the parse tree as plain "key" normally would expect_lint('expect_equal(x$"key", 2)', NULL, linter) expect_lint('expect_equal(x@"key", 2)', NULL, linter) }) # if we only inspect the first argument & ignore context, get false positives local({ pipes <- pipes(exclude = c("%<>%", "%$%")) linter <- yoda_test_linter() patrick::with_parameters_test_that( "yoda_test_linter ignores usage in pipelines", expect_lint(sprintf("foo() %s expect_identical(2)", pipe), NULL, linter), pipe = pipes, .test_name = names(pipes) ) }) test_that("yoda_test_linter throws a special message for placeholder tests", { expect_lint( "expect_equal(1, 1)", rex::rex("Avoid storing placeholder tests like expect_equal(1, 1)"), yoda_test_linter() ) }) test_that("lints vectorize", { expect_lint( trim_some("{ expect_equal(1, 1) expect_equal(2, foo(x)) }"), list( list("Avoid storing placeholder tests", line_number = 2L), list("Compare objects in tests in the order 'actual', 'expected'", line_number = 3L) ), yoda_test_linter() ) }) lintr/tests/testthat/test-literal_coercion_linter.R0000644000176200001440000001176114752731051022411 0ustar liggesuserstest_that("literal_coercion_linter skips allowed usages", { linter <- literal_coercion_linter() # naive xpath includes the "_f0" here as a literal expect_lint('as.numeric(x$"_f0")', NULL, linter) expect_lint('as.numeric(x@"_f0")', NULL, linter) # only examine the first method for as. methods expect_lint("as.character(as.Date(x), '%Y%m%d')", NULL, linter) # we are as yet agnostic on whether to prefer literals over coerced vectors expect_lint("as.integer(c(1, 2, 3))", NULL, linter) # even more ambiguous for character vectors like here, where quotes are much # more awkward to type than a sequence of numbers expect_lint("as.character(c(1, 2, 3))", NULL, linter) # not possible to declare raw literals expect_lint("as.raw(c(1, 2, 3))", NULL, linter) # also not taking a stand on as.complex(0) vs. 0 + 0i expect_lint("as.complex(0)", NULL, linter) # ditto for as.integer(1e6) vs. 1000000L expect_lint("as.integer(1e6)", NULL, linter) # ditto for as.numeric(1:3) vs. c(1, 2, 3) expect_lint("as.numeric(1:3)", NULL, linter) }) test_that("literal_coercion_linter skips allowed rlang usages", { linter <- literal_coercion_linter() expect_lint("int(1, 2.0, 3)", NULL, linter) expect_lint("chr('e', 'ab', 'xyz')", NULL, linter) expect_lint("lgl(0, 1)", NULL, linter) expect_lint("lgl(0L, 1)", NULL, linter) expect_lint("dbl(1.2, 1e5, 3L, 2E4)", NULL, linter) # make sure using namespace (`rlang::`) doesn't create problems expect_lint("rlang::int(1, 2, 3)", NULL, linter) # even if scalar, carve out exceptions for the following expect_lint("int(1.0e6)", NULL, linter) }) test_that("literal_coercion_linter skips quoted keyword arguments", { expect_lint("as.numeric(foo('a' = 1))", NULL, literal_coercion_linter()) }) test_that("no warnings surfaced by running coercion", { linter <- literal_coercion_linter() expect_no_warning( expect_lint("as.integer('a')", "Use NA_integer_", linter) ) expect_no_warning( expect_lint("as.integer(2147483648)", "Use NA_integer_", linter) ) }) skip_if_not_installed("tibble") patrick::with_parameters_test_that( "literal_coercion_linter blocks simple disallowed usages", expect_lint( sprintf("as.%s(%s)", out_type, input), lint_msg, literal_coercion_linter() ), .cases = tibble::tribble( ~.test_name, ~out_type, ~input, ~lint_msg, "lgl, from int", "logical", "1L", rex::rex("Use TRUE instead of as.logical(1L)"), "lgl, from num", "logical", "1", rex::rex("Use TRUE instead of as.logical(1)"), "lgl, from chr", "logical", '"true"', rex::rex('Use TRUE instead of as.logical("true")'), "int, from num", "integer", "1", rex::rex("Use 1L instead of as.integer(1)"), "num, from num", "numeric", "1", rex::rex("Use 1 instead of as.numeric(1)"), "dbl, from num", "double", "1", rex::rex("Use 1 instead of as.double(1)"), "chr, from num", "character", "1", rex::rex('Use "1" instead of as.character(1)'), "chr, from chr", "character", '"e"', rex::rex('Use "e" instead of as.character("e")'), "chr, from chr", "character", '"E"', rex::rex('Use "E" instead of as.character("E")'), # affirmatively lint as.(NA) should be NA__ "int, from NA", "integer", "NA", rex::rex("Use NA_integer_ instead of as.integer(NA)"), "num, from NA", "numeric", "NA", rex::rex("Use NA_real_ instead of as.numeric(NA)"), "dbl, from NA", "double", "NA", rex::rex("Use NA_real_ instead of as.double(NA)"), "chr, from NA", "character", "NA", rex::rex("Use NA_character_ instead of as.character(NA)") ) ) skip_if_not_installed("rlang") test_that("multiple lints return custom messages", { expect_lint( trim_some("{ as.integer(1) lgl(1L) }"), list( list(rex::rex("Use 1L instead of as.integer(1)"), line_number = 2L), list(rex::rex("Use TRUE instead of lgl(1L)"), line_number = 3L) ), literal_coercion_linter() ) }) patrick::with_parameters_test_that( "literal_coercion_linter blocks rlang disallowed usages", expect_lint( sprintf("%s(%s)", out_type, input), lint_msg, literal_coercion_linter() ), # even if `as.character(1)` works, `chr(1)` doesn't, so no corresponding test case .cases = tibble::tribble( ~.test_name, ~out_type, ~input, ~lint_msg, "rlang::lgl", "lgl", "1L", rex::rex("Use TRUE instead of lgl(1L)"), "rlang::lgl[ns]", "rlang::lgl", "1L", rex::rex("Use TRUE instead of rlang::lgl(1L)"), "rlang::int", "int", "1.0", rex::rex("Use 1L instead of int(1.0)"), "rlang::dbl", "dbl", "1L", rex::rex("Use 1 instead of dbl(1L)"), "rlang::chr", "chr", '"e"', rex::rex('Use "e" instead of chr("e")'), "rlang::chr", "chr", '"E"', rex::rex('Use "E" instead of chr("E")') ) ) test_that("literal_coercion_linter blocks scalar rlang list2 construction", { expect_lint( "int(1, )", rex::rex("Use 1L instead of int(1,)"), literal_coercion_linter() ) }) lintr/tests/testthat/test-defaults.R0000644000176200001440000000300214752731051017313 0ustar liggesuserstest_that("linters", { # non-empty named list of functions x <- default_linters expect_type(x, "list") expect_gt(length(x), 0L) expect_true(all(nzchar(names(x)))) expect_true(all(vapply(x, inherits, logical(1L), "linter"))) expect_true(all(vapply(x, is.function, logical(1L)))) }) test_that("undesirable functions and operators", { # non-empty named list of NAs and character strings vars <- list( all_undesirable_functions, default_undesirable_functions, all_undesirable_operators, default_undesirable_operators ) for (x in vars) { expect_type(x, "list") expect_gt(length(x), 0L) expect_true(all(nzchar(names(x)))) expect_true(all(vapply(x, function(x) is.na(x) || is.character(x), logical(1L)))) expect_true(all(lengths(x) == 1L)) } }) test_that("settings", { # non-empty named list x <- default_settings expect_type(default_settings, "list") expect_gt(length(default_settings), 0L) expect_true(all(nzchar(names(default_settings)))) }) patrick::with_parameters_test_that( "all default linters throw lints with their name on 'default_linter_testcode.R'", { lints <- lint( test_path("default_linter_testcode.R"), linters = default_linters[[linter_name]], parse_settings = FALSE ) lint_df <- as.data.frame(lints) expect_gt(nrow(lint_df), 0L) reported_linter_name <- lint_df[["linter"]][1L] expect_identical(reported_linter_name, linter_name) }, linter_name = names(default_linters), .test_name = names(default_linters) ) lintr/tests/testthat/dummy_projects/0000755000176200001440000000000014752731051017455 5ustar liggesuserslintr/tests/testthat/dummy_projects/project/0000755000176200001440000000000014752731051021123 5ustar liggesuserslintr/tests/testthat/dummy_projects/project/partially_matched_exclusions.R0000644000176200001440000000040014752731051027202 0ustar liggesusers# nolint start: assign. a = 2 # nolint end # nolint start: s. warn (and lint) because of non-unique identifier x <- 42; y <- 2 # nolint end # nolint start: bogus_linter. warn because of nonexistent identifier # nolint end # nolint: hocus_pocus, bogus. lintr/tests/testthat/dummy_projects/project/default_linter_testcode.R0000644000176200001440000000143214752731051026141 0ustar liggesusers# Each of the default linters should throw at least one lint on this file # assignment # function_left_parentheses # closed_curly # commas # paren_brace f = function (x,y = 1){} # commented_code # some <- commented("out code") # equals_na # infix_spaces # line_length # object_length # object_name # object_usage # open_curly # T_and_F_symbol someComplicatedFunctionWithALongCamelCaseName <- function(x) { y <- 1 if (1 > 2 && 2 > 3 && 3 > 4 && 4 > 5 && 5*10 > 6 && 5 > 6 && 6 > 7 && x == NA) {T} else {F} } # no_tab # pipe_continuation # seq_linter # spaces_inside x <- 1:10 x[ 2] 1:length(x) %>% lapply(function(x) x*2) %>% head() # single_quotes message('single_quotes') # spaces_left_parentheses # trailing_whitespace # semicolon x <- 42; y <- 2 +(1:10) # trailing_blank_lines lintr/tests/testthat/dummy_projects/project/mismatched_starts_ends.R0000644000176200001440000000011614752731051025773 0ustar liggesusers#nolint end #nolint start c(1,2) #nolint start #nolint end #nolint start lintr/tests/testthat/dummy_projects/project/one_start_no_end.R0000644000176200001440000000003014752731051024557 0ustar liggesusers #nolint start c(1,2) lintr/tests/testthat/dummy_projects/project/cp1252.R0000644000176200001440000000011414752731051022156 0ustar liggesusers# This file is encoded in Cp-1252 # Comment containing non-ASCII ä ü <- 42 lintr/tests/testthat/dummy_projects/project/project.Rproj0000644000176200001440000000040614752731051023607 0ustar liggesusersVersion: 1.0 RestoreWorkspace: Default SaveWorkspace: Default AlwaysSaveHistory: Default EnableCodeIndexing: Yes UseSpacesForTab: Yes NumSpacesForTab: 2 Encoding: ISO8859-1 RnwWeave: Sweave LaTeX: pdfLaTeX AutoAppendNewline: Yes StripTrailingWhitespace: Yes lintr/tests/testthat/dummy_projects/project/cp1252_parseable.R0000644000176200001440000000011414752731051024174 0ustar liggesusers# This file is encoded in Cp-1252 # Comment containing non-ASCII ä a <- 42 lintr/tests/testthat/test-unneeded_concatenation_linter.R0000644000176200001440000000031514752731051023561 0ustar liggesuserstest_that("unneeded_concatenation_linter generates deprecation warning", { expect_warning( unneeded_concatenation_linter(), rex::rex("Linter unneeded_concatenation_linter was deprecated") ) }) lintr/tests/testthat/test-library_call_linter.R0000644000176200001440000002576714752731051021546 0ustar liggesuserstest_that("library_call_linter skips allowed usages", { linter <- library_call_linter() expect_lint( trim_some(" library(dplyr) print('test') "), NULL, linter ) expect_lint("print('test')", NULL, linter ) expect_lint( trim_some(" # comment library(dplyr) "), NULL, linter ) expect_lint( trim_some(" print('test') # library(dplyr) "), NULL, linter ) expect_lint( trim_some(" suppressPackageStartupMessages({ library(dplyr) library(knitr) }) "), NULL, linter ) }) test_that("library_call_linter warns on disallowed usages", { linter <- library_call_linter() lint_message <- rex::rex("Move all library calls to the top of the script.") expect_lint( trim_some(" library(dplyr) print('test') library(tidyr) "), lint_message, linter ) expect_lint( trim_some(" library(dplyr) print('test') library(tidyr) library(purrr) "), list( list(lint_message, line_number = 3L, column_number = 1L), list(lint_message, line_number = 4L, column_number = 1L) ), linter ) expect_lint( trim_some(" library(dplyr) print('test') print('test') library(tidyr) "), lint_message, linter ) expect_lint( trim_some(" library(dplyr) print('test') library(tidyr) print('test') "), lint_message, linter ) expect_lint( trim_some(" library(dplyr) print('test') library(tidyr) print('test') library(purrr) "), list( list(lint_message, line_number = 3L, column_number = 1L), list(lint_message, line_number = 5L, column_number = 1L) ), linter ) expect_lint( trim_some(" library(dplyr) print('test') suppressMessages(library('lubridate', character.only = TRUE)) suppressMessages(library(tidyr)) print('test') "), list( list(rex::rex("Unify consecutive calls to suppressMessages()"), line_number = 3L), list(lint_message, line_number = 3L), list(rex::rex("Use symbols in library calls to avoid the need for 'character.only'"), line_number = 3L), list(lint_message, line_number = 4L) ), linter ) }) test_that("require() treated the same as library()", { linter <- library_call_linter() lint_message_library <- rex::rex("Move all library calls to the top of the script.") lint_message_require <- rex::rex("Move all require calls to the top of the script.") expect_lint( trim_some(" library(dplyr) require(tidyr) "), NULL, linter ) expect_lint( trim_some(" library(dplyr) print(letters) require(tidyr) "), list(lint_message_require, line_number = 3L), linter ) expect_lint( trim_some(" library(dplyr) print(letters) library(dbplyr) require(tidyr) "), list( list(lint_message_library, line_number = 3L), list(lint_message_require, line_number = 4L) ), linter ) }) test_that("allow_preamble applies as intended", { linter_preamble <- library_call_linter(allow_preamble = TRUE) linter_no_preamble <- library_call_linter(allow_preamble = FALSE) lint_msg <- rex::rex("Move all library calls to the top of the script.") lines <- trim_some(" opts_chunk$set(eval = FALSE) library(dplyr) library(knitr) print(letters) ") expect_lint(lines, NULL, linter_preamble) expect_lint(lines, list(list(line_number = 2L), list(line_number = 3L)), linter_no_preamble) lines <- trim_some(" opts_chunk$set(eval = FALSE) suppressPackageStartupMessages({ library(dplyr) library(knitr) }) print(letters) ") expect_lint(lines, NULL, linter_preamble) expect_lint(lines, list(list(line_number = 3L), list(line_number = 4L)), linter_no_preamble) lines <- trim_some(" opts_chunk$set(eval = FALSE) suppressPackageStartupMessages(library(dplyr)) library(knitr) print(letters) ") expect_lint(lines, NULL, linter_preamble) expect_lint(lines, list(list(line_number = 2L), list(line_number = 3L)), linter_no_preamble) lines <- trim_some(" opts_chunk$set(eval = FALSE) library(dplyr) suppressPackageStartupMessages(library(knitr)) print(letters) ") expect_lint(lines, NULL, linter_preamble) expect_lint(lines, list(list(line_number = 2L), list(line_number = 3L)), linter_no_preamble) lines <- trim_some(" fun() library(moreFun) oops() ") expect_lint(lines, NULL, linter_preamble) expect_lint(lines, lint_msg, linter_no_preamble) }) test_that("skips allowed usages of library()/character.only=TRUE", { linter <- library_call_linter() expect_lint("library(data.table)", NULL, linter) expect_lint("function(pkg) library(pkg, character.only = TRUE)", NULL, linter) expect_lint("function(pkgs) sapply(pkgs, require, character.only = TRUE)", NULL, linter) }) test_that("blocks disallowed usages of strings in library()/require()", { linter <- library_call_linter() char_only_msg <- rex::rex("Use symbols in library calls", anything, "character.only") direct_stub <- "Call library() directly, not vectorized with " expect_lint( 'library("data.table")', rex::rex("Use symbols, not strings, in library calls."), linter ) expect_lint('library("data.table", character.only = TRUE)', char_only_msg, linter) expect_lint('suppressWarnings(library("data.table", character.only = TRUE))', char_only_msg, linter) expect_lint( "do.call(library, list(data.table))", rex::rex(direct_stub, "do.call()"), linter ) expect_lint( 'do.call("library", list(data.table))', rex::rex(direct_stub, "do.call()"), linter ) expect_lint( 'lapply("data.table", library, character.only = TRUE)', rex::rex(direct_stub, "lapply()"), linter ) expect_lint( 'purr::map("data.table", library, character.only = TRUE)', rex::rex(direct_stub, "map()"), linter ) }) test_that("character.only=TRUE is caught in *apply functions passed as strings", { linter <- library_call_linter() lib_msg <- rex::rex("Call library() directly, not vectorized with sapply()") req_msg <- rex::rex("Call require() directly, not vectorized with sapply()") expect_lint("sapply(pkgs, 'library', character.only = TRUE)", lib_msg, linter) expect_lint('sapply(pkgs, "library", character.only = TRUE)', lib_msg, linter) expect_lint("sapply(pkgs, 'require', character.only = TRUE)", req_msg, linter) expect_lint('sapply(pkgs, "require", character.only = TRUE)', req_msg, linter) }) test_that("character.only=TRUE is caught with multiple-line source", { expect_lint( trim_some(' suppressWarnings(library( "data.table", character.only = TRUE )) '), rex::rex("Use symbols in library calls", anything, "character.only"), library_call_linter() ) }) test_that("character.only=TRUE is caught inside purrr::walk as well", { expect_lint( 'purr::walk("data.table", library, character.only = TRUE)', rex::rex("Call library() directly, not vectorized with walk()"), library_call_linter() ) }) test_that("multiple lints are generated correctly", { expect_lint( trim_some('{ library("dplyr", character.only = TRUE) print("not a library call") require("gfile") sapply(pkg_list, "library", character.only = TRUE) purrr::walk(extra_list, require, character.only = TRUE) }'), list( list(message = rex::rex("library calls", anything, "character.only")), list(message = rex::rex("Move all require calls to the top of the script.")), list(message = "symbols, not strings, in require calls"), list(message = rex::rex("library() directly", anything, "vectorized with sapply()")), list(message = rex::rex("require() directly", anything, "vectorized with walk()")) ), library_call_linter() ) }) patrick::with_parameters_test_that( "library_call_linter skips allowed usages", { linter <- library_call_linter() expect_lint(sprintf("%s(x)", call), NULL, linter) expect_lint(sprintf("%s(x, y, z)", call), NULL, linter) # intervening expression expect_lint(sprintf("%1$s(x); y; %1$s(z)", call), NULL, linter) # inline or potentially with gaps don't matter expect_lint( trim_some(glue::glue(" {call}(x) y stopifnot(z) ")), NULL, linter ) # only suppressing calls with library() expect_lint( trim_some(glue::glue(" {call}(x) {call}(y) ")), NULL, linter ) }, .test_name = c("suppressMessages", "suppressPackageStartupMessages"), call = c("suppressMessages", "suppressPackageStartupMessages") ) patrick::with_parameters_test_that( "library_call_linter blocks simple disallowed usages", { linter <- library_call_linter() lint_msg <- sprintf("Unify consecutive calls to %s\\(\\)\\.", call) # one test of inline usage expect_lint(sprintf("%1$s(library(x)); %1$s(library(y))", call), lint_msg, linter) expect_lint( trim_some(glue::glue(" {call}(library(x)) {call}(library(y)) ")), lint_msg, linter ) expect_lint( trim_some(glue::glue(" {call}(require(x)) {call}(require(y)) ")), lint_msg, linter ) expect_lint( trim_some(glue::glue(" {call}(library(x)) # a comment on y {call}(library(y)) ")), lint_msg, linter ) }, .test_name = c("suppressMessages", "suppressPackageStartupMessages"), call = c("suppressMessages", "suppressPackageStartupMessages") ) test_that("Namespace differences are detected", { linter <- library_call_linter() # totally different namespaces expect_lint( "ns::suppressMessages(library(x)); base::suppressMessages(library(y))", NULL, linter ) # one namespaced, one not expect_lint( "ns::suppressMessages(library(x)); suppressMessages(library(y))", NULL, linter ) }) test_that("Consecutive calls to different blocked calls is OK", { expect_lint( "suppressPackageStartupMessages(library(x)); suppressMessages(library(y))", NULL, library_call_linter() ) }) test_that("Multiple violations across different calls are caught", { linter <- library_call_linter() expect_lint( trim_some(" suppressPackageStartupMessages(library(x)) suppressPackageStartupMessages(library(x)) suppressMessages(library(x)) suppressMessages(library(x)) "), list( "Unify consecutive calls to suppressPackageStartupMessages", "Unify consecutive calls to suppressMessages" ), linter ) expect_lint( trim_some(" suppressMessages(library(A)) suppressPackageStartupMessages(library(A)) suppressMessages(library(A)) suppressPackageStartupMessages(library(A)) suppressPackageStartupMessages(library(A)) "), list("Unify consecutive calls to suppressPackageStartupMessages", line_number = 4L), linter ) }) lintr/tests/testthat/test-strings_as_factors_linter.R0000644000176200001440000000753714752731051022777 0ustar liggesuserstest_that("strings_as_factors_linter skips allowed usages", { linter <- strings_as_factors_linter() expect_lint("data.frame(1:3)", NULL, linter) expect_lint("data.frame(x = 1:3)", NULL, linter) expect_lint("data.frame(x = 'a', stringsAsFactors = TRUE)", NULL, linter) expect_lint("data.frame(x = 'a', stringsAsFactors = FALSE)", NULL, linter) expect_lint("data.frame(x = c('a', 'b'), stringsAsFactors = FALSE)", NULL, linter) # strings in argument names to c() don't get linted expect_lint("data.frame(x = c('a b' = 1L, 'b c' = 2L))", NULL, linter) # characters supplied to row.names are not affected expect_lint("data.frame(x = 1:3, row.names = c('a', 'b', 'c'))", NULL, linter) # ambiguous cases passes expect_lint("data.frame(x = c(xx, 'a'))", NULL, linter) expect_lint("data.frame(x = c(foo(y), 'a'))", NULL, linter) }) test_that("strings_as_factors_linter blocks simple disallowed usages", { linter <- strings_as_factors_linter() lint_msg <- "Supply an explicit value for stringsAsFactors for this code" expect_lint("data.frame('a')", lint_msg, linter) expect_lint("data.frame(c('a', 'b'))", lint_msg, linter) expect_lint("data.frame(x = 1:5, y = 'b')", lint_msg, linter) expect_lint("data.frame(x = 1:5, y, z = 'b')", lint_msg, linter) # catch row.names when combined with a character vector expect_lint("data.frame(x = c('c', 'd', 'e'), row.names = c('a', 'b', 'c'))", lint_msg, linter) expect_lint("data.frame(row.names = c('c', 'd', 'e'), x = c('a', 'b', 'c'))", lint_msg, linter) # when everything is a literal, type promotion means the column is character expect_lint("data.frame(x = c(TRUE, 'a'))", lint_msg, linter) }) test_that("strings_as_factors_linters catches rep(char) usages", { linter <- strings_as_factors_linter() lint_msg <- "Supply an explicit value for stringsAsFactors for this code" expect_lint("data.frame(rep('a', 10L))", lint_msg, linter) expect_lint("data.frame(rep(c('a', 'b'), 10L))", lint_msg, linter) # literal char, not mixed or non-char expect_lint("data.frame(rep(1L, 10L))", NULL, linter) expect_lint("data.frame(rep(c(x, 'a'), 10L))", NULL, linter) # however, type promotion of literals is caught expect_lint("data.frame(rep(c(TRUE, 'a'), 10L))", lint_msg, linter) }) test_that("strings_as_factors_linter catches character(), as.character() usages", { linter <- strings_as_factors_linter() lint_msg <- "Supply an explicit value for stringsAsFactors for this code" expect_lint("data.frame(a = character())", lint_msg, linter) expect_lint("data.frame(a = character(1L))", lint_msg, linter) expect_lint("data.frame(a = as.character(x))", lint_msg, linter) # but not for row.names expect_lint("data.frame(a = 1:10, row.names = as.character(1:10))", NULL, linter) }) test_that("strings_as_factors_linter catches more functions with string output", { linter <- strings_as_factors_linter() lint_msg <- "Supply an explicit value for stringsAsFactors for this code" expect_lint("data.frame(a = paste(1, 2, 3))", lint_msg, linter) expect_lint("data.frame(a = sprintf('%d', 1:10))", lint_msg, linter) expect_lint("data.frame(a = format(x, just = 'right'))", lint_msg, linter) expect_lint("data.frame(a = formatC(x, format = '%d'))", lint_msg, linter) expect_lint("data.frame(a = prettyNum(x, big.mark = ','))", lint_msg, linter) expect_lint("data.frame(a = toString(x))", lint_msg, linter) expect_lint("data.frame(a = encodeString(x))", lint_msg, linter) # but not for row.names expect_lint("data.frame(a = 1:10, row.names = paste(1:10))", NULL, linter) }) test_that("lints vectorize", { lint_msg <- "Supply an explicit value for stringsAsFactors for this code" expect_lint( trim_some("{ data.frame('a') data.frame('b') }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), strings_as_factors_linter() ) }) lintr/tests/testthat/test-quotes_linter.R0000644000176200001440000000471214752731051020412 0ustar liggesuserstest_that("quotes_linter skips allowed usages", { linter <- quotes_linter() expect_lint("blah", NULL, linter) expect_lint('"blah"', NULL, linter) expect_lint('"\'blah"', NULL, linter) expect_lint('"blah\'"', NULL, linter) expect_lint('"\'blah\'"', NULL, linter) expect_lint("'\"'", NULL, linter) expect_lint("'\"blah\"'", NULL, linter) }) test_that("quotes_linter blocks disallowed usages", { linter <- quotes_linter() lint_msg <- rex::rex("Only use double-quotes.") expect_lint("'blah'", lint_msg, linter) expect_lint("fun('blah')", lint_msg, linter) expect_lint("{'blah'}", lint_msg, linter) expect_lint( " x = 'test '", list(message = lint_msg, ranges = list(c(9L, 13L))), linter ) }) # NB: repeat of above tests with (mostly) opposite results test_that("quotes_linter skips allowed usages of delimiter='", { linter <- quotes_linter(delimiter = "'") expect_lint("blah", NULL, linter) expect_lint('"\'blah"', NULL, linter) expect_lint('"blah\'"', NULL, linter) expect_lint('"\'blah\'"', NULL, linter) expect_lint("'\"'", NULL, linter) expect_lint("'\"blah\"'", NULL, linter) expect_lint("'blah'", NULL, linter) expect_lint("fun('blah')", NULL, linter) expect_lint("{'blah'}", NULL, linter) }) test_that("quotes_linter blocks disallowed usages of delimiter='", { linter <- quotes_linter(delimiter = "'") lint_msg <- rex::rex("Only use single-quotes.") expect_lint('"blah"', lint_msg, linter) expect_lint( ' x = "test "', list(message = lint_msg, ranges = list(c(9L, 13L))), linter ) }) test_that("handles R>=4.0.0 strings", { skip_if_not_r_version("4.0.0") linter <- quotes_linter() expect_lint('R"(hello \'\' there)"', NULL, linter) expect_lint("R'( whoops )'", rex::rex("Only use double-quotes."), linter) expect_lint("R'---[ daisy ]---'", rex::rex("Only use double-quotes."), linter) expect_lint("r'(\")'", NULL, linter) }) test_that("single_quotes_linter is deprecated", { expect_warning( { old_linter <- single_quotes_linter() }, "Use quotes_linter instead", fixed = TRUE ) expect_lint('"blah"', NULL, old_linter) expect_lint("'blah'", "Only use double-quotes", old_linter) }) test_that("lints vectorize", { lint_msg <- rex::rex("Only use double-quotes.") expect_lint( trim_some("{ 'abc' 'def' }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), quotes_linter() ) }) lintr/tests/testthat/test-line_length_linter.R0000644000176200001440000000277414752731051021370 0ustar liggesuserstest_that("line_length_linter skips allowed usages", { linter <- line_length_linter(80L) expect_lint("blah", NULL, linter) expect_lint(strrep("x", 80L), NULL, linter) }) test_that("line_length_linter blocks disallowed usages", { linter <- line_length_linter(80L) lint_msg <- rex::rex("Lines should not be more than 80 characters. This line is 81 characters.") expect_lint( strrep("x", 81L), list( message = lint_msg, column_number = 81L ), linter ) expect_lint( paste(rep(strrep("x", 81L), 2L), collapse = "\n"), list( list( message = lint_msg, line_number = 1L, column_number = 81L ), list( message = lint_msg, line_number = 2L, column_number = 81L ) ), linter ) linter <- line_length_linter(20L) lint_msg <- rex::rex("Lines should not be more than 20 characters. This line is 22 characters.") expect_lint(strrep("a", 20L), NULL, linter) expect_lint( strrep("a", 22L), list( message = lint_msg, column_number = 21L ), linter ) # Don't duplicate lints expect_length( lint( "x <- 2 # ------------\n", linters = linter, parse_settings = FALSE ), 1L ) }) test_that("Multiple lints give custom messages", { expect_lint( trim_some("{ abcdefg hijklmnop }"), list( list("9 characters", line_number = 2L), list("11 characters", line_number = 3L) ), line_length_linter(5L) ) }) lintr/tests/testthat/test-keyword_quote_linter.R0000644000176200001440000001407114752731051021772 0ustar liggesuserstest_that("keyword_quote_linter skips allowed usages", { linter <- keyword_quote_linter() # main use case: c() expect_lint("x <- c(1, 2, 4, 5)", NULL, linter) expect_lint("x <- c(a = 1, 2)", NULL, linter) expect_lint("x <- c(a = 1, b = 2)", NULL, linter) expect_lint("y <- c(`a b` = 1, `c d` = 2)", NULL, linter) expect_lint('y <- c("a b" = 1, "c d" = 2)', NULL, linter) expect_lint("z <- c('a b' = 1, c = 2)", NULL, linter) # don't catch strings as arguments expect_lint('c(A = "a")', NULL, linter) # don't catch unnamed arguments expect_lint('c(1, 2, "a")', NULL, linter) # don't get thrown off by missing arguments expect_lint("alist(`a b` =)", NULL, linter) # other use cases: switch() and list() expect_lint("list(a = 1, b = list(c = 2))", NULL, linter) expect_lint("list(`a b` = 1, c = 2:6)", NULL, linter) expect_lint("switch(x, a = 1, b = 2)", NULL, linter) expect_lint( "switch(x, `a b` = 1, c = 2:6)", NULL, linter ) }) test_that("keyword_quote_linter blocks simple disallowed usages", { linter <- keyword_quote_linter() lint_msg <- "Only quote named arguments to functions" expect_lint('c("a" = 1, b = 2)', lint_msg, linter) expect_lint( "c('a' = 1, 'b' = 2)", list(lint_msg, lint_msg), linter ) expect_lint( "c(`a` = 1, b = list(`c` = 2))", list(lint_msg, lint_msg), linter ) # missing argument is caught expect_lint("alist(`a` = )", lint_msg, linter) expect_lint( "switch(x, `a` = c('b' = list(\"c\" = 1)))", list(lint_msg, lint_msg, lint_msg), linter ) }) test_that("keyword_quote_linter skips quoting on reserved words", { linter <- keyword_quote_linter() expect_lint("c(`next` = 1, `while` = 2)", NULL, linter) expect_lint("switch(x, `for` = 3, `TRUE` = 4)", NULL, linter) expect_lint("list('NA' = 5, 'Inf' = 6)", NULL, linter) }) test_that("keyword_quote_linter works on more common functions", { linter <- keyword_quote_linter() lint_msg <- "Only quote named arguments to functions" expect_lint("data.frame('a' = 1)", lint_msg, linter) expect_lint("data.table('a' = 1)", lint_msg, linter) expect_lint("data.table::data.table('a' = 1)", lint_msg, linter) expect_lint("rbind('a' = 1)", lint_msg, linter) expect_lint("cbind('a' = 1)", lint_msg, linter) }) test_that("keyword_quote_linter finds blocked usages in any function call", { expect_lint( "foo('a' = 1)", rex::rex("Only quote named arguments to functions"), keyword_quote_linter() ) }) test_that("keyword_quote_linter blocks quoted assignment targets", { linter <- keyword_quote_linter() backtick_msg <- rex::rex("Use backticks to create non-syntactic names, not quotes.") assign_msg <- "Only quote targets of assignment if necessary" expect_lint('"foo bar" <- 1', backtick_msg, linter) expect_lint("'foo bar' = 1", backtick_msg, linter) # valid choice: use backticks expect_lint("`foo bar` = 1", NULL, linter) expect_lint('"foo" <- 1', assign_msg, linter) expect_lint("'foo' = 1", assign_msg, linter) expect_lint("`foo` = 1", assign_msg, linter) # don't include data.table assignments expect_lint('DT[, "a" := 1]', NULL, linter) expect_lint("DT[, 'a' := 1]", NULL, linter) expect_lint("DT[, `a` := 1]", NULL, linter) # include common use cases: [<-/$ methods and infixes expect_lint('"$.my_class" <- function(x, key) { }', backtick_msg, linter) expect_lint("'Setter[<-.my_class' = function(x, idx, value) { }", backtick_msg, linter) expect_lint('"%nin%" <- function(x, table) !x %in% table', backtick_msg, linter) # right assignment expect_lint('1 -> "foo"', assign_msg, linter) expect_lint("1 -> foo", NULL, linter) expect_lint('1 -> "a b"', backtick_msg, linter) }) test_that("keyword_quote_linter blocks quoted $, @ extractions", { linter <- keyword_quote_linter() backtick_msg <- rex::rex("Use backticks to create non-syntactic names, not quotes.") dollar_msg <- rex::rex("Only quote targets of extraction with $ if necessary") at_msg <- rex::rex("Only quote targets of extraction with @ if necessary") expect_lint('x$"foo bar" <- 1', backtick_msg, linter) expect_lint("x$'foo bar' = 1", backtick_msg, linter) expect_lint('x@"foo bar" <- 1', backtick_msg, linter) expect_lint("x@'foo bar' = 1", backtick_msg, linter) # valid choice: non-syntactic name with backticks expect_lint("x@`foo bar` <- 1", NULL, linter) expect_lint("x@`foo bar` = 1", NULL, linter) expect_lint('x$"foo" <- 1', dollar_msg, linter) expect_lint("x$'foo' = 1", dollar_msg, linter) expect_lint('x@"foo" <- 1', at_msg, linter) expect_lint("x@'foo' = 1", at_msg, linter) expect_lint("x@`foo` <- 1", at_msg, linter) expect_lint("x@`foo` = 1", at_msg, linter) }) test_that("multiple lints are generated correctly", { linter <- keyword_quote_linter() expect_lint( trim_some('{ foo("a" = 1) "b" <- 2 x$"c" y@"d" }'), list( "Only quote named arguments", "Only quote targets of assignment", "Only quote targets of extraction with \\$", "Only quote targets of extraction with @" ), linter ) # multiple flavors of assignment lints expect_lint( trim_some('{ "a" <- 1 "a b" <- 1 `a` <- 1 `a b` <- 1 }'), list( "Only quote targets of assignment if necessary", "Use backticks to create non-syntactic names, not quotes", "Only quote targets of assignment if necessary" ), linter ) # multiple flavors of extraction lints expect_lint( trim_some('{ x$"a" x$"a b" <- 1 x$`a` <- 1 x$`a b` <- 1 y@"a" y@"a b" <- 1 y@`a` <- 1 y@`a b` <- 1 }'), list( rex::rex("Only quote targets of extraction with $ if necessary"), rex::rex("Use backticks to create non-syntactic names, not quotes."), rex::rex("Only quote targets of extraction with $ if necessary"), rex::rex("Only quote targets of extraction with @ if necessary"), rex::rex("Use backticks to create non-syntactic names, not quotes."), rex::rex("Only quote targets of extraction with @ if necessary") ), linter ) }) lintr/tests/testthat/test-rstudio_markers.R0000644000176200001440000000752514752731051020737 0ustar liggesuserstest_that("it returns markers which match lints", { skip_if_not_installed("rstudioapi") local_mocked_bindings( callFun = function(...) list(...), executeCommand = function(...) NULL, .package = "rstudioapi" ) lint1 <- list(Lint( filename = "test_file", line_number = 1L, column_number = 2L, type = "error", line = "a line", message = "hi" )) class(lint1) <- "lints" lint1[[1L]]$linter <- "linter_name" marker1 <- rstudio_source_markers(lint1) expect_identical(marker1$name, "lintr") expect_identical(marker1$markers[[1L]]$type, lint1[[1L]]$type) expect_identical(marker1$markers[[1L]]$file, lint1[[1L]]$filename) expect_identical(marker1$markers[[1L]]$line, lint1[[1L]]$line_number) expect_identical(marker1$markers[[1L]]$column, lint1[[1L]]$column_number) expect_identical(marker1$markers[[1L]]$message, paste0("[", lint1[[1L]]$linter, "] ", lint1[[1L]]$message)) lint2 <- list( Lint( filename = "test_file", line_number = 1L, column_number = 2L, type = "error", line = "a line", message = "hi" ), Lint( filename = "test_file2", line_number = 10L, column_number = 1L, type = "warning", message = "test a message" ) ) class(lint2) <- "lints" lint2[[1L]]$linter <- "linter_name" lint2[[2L]]$linter <- "linter_name" marker2 <- rstudio_source_markers(lint2) expect_identical(marker2$name, "lintr") expect_identical(marker2$markers[[1L]]$type, lint2[[1L]]$type) expect_identical(marker2$markers[[1L]]$file, lint2[[1L]]$filename) expect_identical(marker2$markers[[1L]]$line, lint2[[1L]]$line_number) expect_identical(marker2$markers[[1L]]$column, lint2[[1L]]$column_number) expect_identical(marker2$markers[[1L]]$message, paste0("[", lint2[[1L]]$linter, "] ", lint2[[1L]]$message)) }) test_that("it prepends the package path if it exists", { skip_if_not_installed("rstudioapi") local_mocked_bindings( callFun = function(...) list(...), executeCommand = function(...) NULL, .package = "rstudioapi" ) lint3 <- list(Lint( filename = "test_file", line_number = 1L, column_number = 2L, type = "error", line = "a line", message = "hi" )) class(lint3) <- "lints" attr(lint3, "path") <- "test" lint3[[1L]]$linter <- "linter_name" marker3 <- rstudio_source_markers(lint3) expect_identical(marker3$name, "lintr") expect_identical(marker3$basePath, "test") expect_identical(marker3$markers[[1L]]$type, lint3[[1L]]$type) expect_identical(marker3$markers[[1L]]$file, file.path("test", lint3[[1L]]$filename)) expect_identical(marker3$markers[[1L]]$line, lint3[[1L]]$line_number) expect_identical(marker3$markers[[1L]]$column, lint3[[1L]]$column_number) expect_identical(marker3$markers[[1L]]$message, paste0("[", lint3[[1L]]$linter, "] ", lint3[[1L]]$message)) }) test_that("it returns an empty list of markers if there are no lints", { skip_if_not_installed("rstudioapi") local_mocked_bindings( callFun = function(...) list(...), executeCommand = function(...) NULL, .package = "rstudioapi" ) lint4 <- `class<-`(list(), "lints") marker4 <- rstudio_source_markers(lint4) expect_identical(marker4$name, "lintr") expect_identical(marker4$markers, list()) }) test_that("rstudio_source_markers apply to print within rstudio", { withr::local_options(lintr.rstudio_source_markers = TRUE) tmp <- withr::local_tempfile(lines = "1:ncol(x)") empty <- withr::local_tempfile(lines = character(0L)) skip_if_not_installed("rstudioapi") local_mocked_bindings( hasFun = function(...) TRUE, .package = "rstudioapi" ) local_mocked_bindings(rstudio_source_markers = function(x) cat("matched\n")) l <- lint(tmp, seq_linter()) expect_output(print(l), "matched", fixed = TRUE) l <- lint(empty, seq_linter()) expect_output(print(l), "matched", fixed = TRUE) }) lintr/tests/testthat/test-lengths_linter.R0000644000176200001440000000401714752731051020534 0ustar liggesuserstest_that("lengths_linter skips allowed usages", { linter <- lengths_linter() expect_lint("length(x)", NULL, linter) expect_lint("function(x) length(x) + 1L", NULL, linter) expect_lint("vapply(x, fun, integer(length(y)))", NULL, linter) expect_lint("sapply(x, sqrt, simplify = length(x))", NULL, linter) # TODO(#1570): also throw a lint here, and for map(x, length) expect_lint("lapply(x, length)", NULL, linter) }) test_that("lengths_linter blocks simple disallowed base usages", { linter <- lengths_linter() lint_msg <- rex::rex("Use lengths() to find the length of each element in a list.") expect_lint("sapply(x, length)", lint_msg, linter) expect_lint("sapply(x, FUN = length)", lint_msg, linter) expect_lint("sapply(FUN = length, x)", lint_msg, linter) expect_lint("vapply(x, length, integer(1L))", lint_msg, linter) }) test_that("lengths_linter blocks simple disallowed purrr usages", { linter <- lengths_linter() lint_msg <- rex::rex("Use lengths() to find the length of each element in a list.") expect_lint("purrr::map_dbl(x, length)", lint_msg, linter) expect_lint("map_dbl(x, .f = length)", lint_msg, linter) expect_lint("map_dbl(.f = length, x)", lint_msg, linter) expect_lint("map_int(x, length)", lint_msg, linter) }) test_that("lengths_linter blocks simple disallowed usages with pipes", { skip_if_not_r_version("4.1.0") linter <- lengths_linter() lint_msg <- rex::rex("Use lengths() to find the length of each element in a list.") expect_lint("x |> sapply(length)", lint_msg, linter) expect_lint("x %>% sapply(length)", lint_msg, linter) expect_lint("x |> map_int(length)", lint_msg, linter) expect_lint("x %>% map_int(length)", lint_msg, linter) }) test_that("lints vectorize", { lint_msg <- rex::rex("Use lengths() to find the length of each element in a list.") expect_lint( trim_some("{ sapply(x, length) map_int(x, length) }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L) ), lengths_linter() ) }) lintr/tests/testthat/test-absolute_path_linter.R0000644000176200001440000001240214752731051021717 0ustar liggesusers# styler: off test_that("is_root_path", { f <- lintr:::is_root_path x <- character() y <- logical() expect_identical(f(x), y) x <- c("", "foo", "http://rseek.org/", "./", " /", "/foo", "'/'") y <- c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) expect_identical(f(x), y) x <- c("/", "//") y <- c(TRUE, FALSE) expect_identical(f(x), y) x <- c("~", "~/", "~//", "~bob2", "~foo_bar/") y <- c(TRUE, TRUE, TRUE, TRUE, TRUE) expect_identical(f(x), y) x <- c("c:", "C:\\", "D:/", "C:\\\\", "D://") y <- c(TRUE, TRUE, TRUE, FALSE, FALSE) expect_identical(f(x), y) x <- c("\\\\", "\\\\localhost", "\\\\localhost\\") y <- c(TRUE, TRUE, TRUE) expect_identical(f(x), y) }) test_that("is_absolute_path", { f <- lintr:::is_absolute_path x <- character() y <- logical() expect_identical(f(x), y) x <- c("/", "//", "/foo", "/foo/") y <- c(TRUE, FALSE, TRUE, TRUE) expect_identical(f(x), y) x <- c("~", "~/foo", "~/foo/", "~'") y <- c(TRUE, TRUE, TRUE, FALSE) expect_identical(f(x), y) x <- c("c:", "C:\\foo\\", "C:/foo/") y <- c(TRUE, TRUE, TRUE) expect_identical(f(x), y) x <- c("\\\\", "\\\\localhost", "\\\\localhost\\c$", "\\\\localhost\\c$\\foo") y <- c(TRUE, TRUE, TRUE, TRUE) expect_identical(f(x), y) }) test_that("is_relative_path", { f <- lintr:::is_relative_path x <- character() y <- logical() expect_identical(f(x), y) x <- c("/", "c:\\", "~/", "foo", "http://rseek.org/", "'./'") y <- c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) expect_identical(f(x), y) x <- c("/foo", "foo/", "foo/bar", "foo//bar", "./foo", "../foo") y <- c(FALSE, TRUE, TRUE, TRUE, TRUE, TRUE) expect_identical(f(x), y) x <- c("\\\\", "\\foo", "foo\\", "foo\\bar", ".\\foo", "..\\foo", ".", "..", "../") y <- c(FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE) expect_identical(f(x), y) }) test_that("is_path", { f <- lintr:::is_path x <- character() y <- logical() expect_identical(f(x), y) x <- c("", "foo", "http://rseek.org/", "foo\nbar", "'foo/bar'", "'/'") y <- c(FALSE, FALSE, FALSE, FALSE, FALSE, FALSE) expect_identical(f(x), y) x <- c("c:", "..", "foo/bar", "foo\\bar", "~", "\\\\localhost") y <- c(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE) expect_identical(f(x), y) }) test_that("is_valid_path", { f <- lintr:::is_valid_path x <- character() y <- logical() expect_identical(f(x), y) x <- c("C:/asdf", "C:/asd*f", "a\\s:df", "a\\\nsdf") y <- c(TRUE, FALSE, FALSE, FALSE) expect_identical(f(x), y) x <- c("C:/asdf", "C:/asd*f", "a\\s:df", "a\\\nsdf") y <- c(TRUE, FALSE, FALSE, FALSE) expect_identical(f(x, lax = TRUE), y) x <- c("/asdf", "/asd*f", "/as:df", "/a\nsdf") y <- c(TRUE, TRUE, TRUE, TRUE) expect_identical(f(x), y) x <- c("/asdf", "/asd*f", "/as:df", "/a\nsdf") y <- c(TRUE, FALSE, FALSE, FALSE) expect_identical(f(x, lax = TRUE), y) }) test_that("is_long_path", { f <- lintr:::is_long_path x <- character() y <- logical() expect_identical(f(x), y) x <- c("foo/", "/foo", "n/a", "Z:\\foo", "foo/bar", "~/foo", "../foo") y <- c(FALSE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE) expect_identical(f(x), y) }) # styler: on test_that("returns the correct linting", { lint_msg <- rex::escape("Do not use absolute paths.") # strict mode linter <- absolute_path_linter(lax = FALSE) non_absolute_path_strings <- c( "..", "./blah", encodeString("blah\\file.txt") ) for (path in non_absolute_path_strings) { expect_lint(single_quote(path), NULL, linter) expect_lint(double_quote(path), NULL, linter) } expect_lint("\"'/'\"", NULL, linter) # nested quotes absolute_path_strings <- c( "/", "/blah/file.txt", encodeString("d:\\"), "E:/blah/file.txt", encodeString("\\\\"), encodeString("\\\\server\\path"), "~", "~james.hester/blah/file.txt", encodeString("/a\nsdf"), "/as:df" ) for (path in absolute_path_strings) { expect_lint(single_quote(path), lint_msg, linter) expect_lint(double_quote(path), lint_msg, linter) } # lax mode: no check for strings that are likely not paths (too short or with special characters) linter <- absolute_path_linter(lax = TRUE) unlikely_path_strings <- c( "/", encodeString("/a\nsdf/bar"), "/as:df/bar" ) for (path in unlikely_path_strings) { expect_lint(single_quote(path), NULL, linter) expect_lint(double_quote(path), NULL, linter) } }) test_that("raw strings are handled correctly", { skip_if_not_r_version("4.0.0") expect_lint('R"(./blah)"', NULL, absolute_path_linter(lax = FALSE)) expect_lint( "R'--[/blah/file.txt]--'", rex::rex("Do not use absolute paths."), absolute_path_linter(lax = FALSE) ) }) test_that("lints vectorize", { lint_msg <- rex::rex("Do not use absolute paths.") expect_lint( trim_some("{ '/' '/blah/file.txt' 'abcdefg' '~' }"), list( list(lint_msg, line_number = 2L), list(lint_msg, line_number = 3L), list(lint_msg, line_number = 5L) ), absolute_path_linter(lax = FALSE) ) }) lintr/tests/testthat/test-ifelse_censor_linter.R0000644000176200001440000000361514752731051021713 0ustar liggesuserstest_that("ifelse_censor_linter skips allowed usages", { linter <- ifelse_censor_linter() expect_lint("ifelse(x == 2, x, y)", NULL, linter) expect_lint("ifelse(x > 2, x, y)", NULL, linter) }) test_that("ifelse_censor_linter blocks simple disallowed usages", { linter <- ifelse_censor_linter() expect_lint( "ifelse(x < 0, 0, x)", rex::rex("pmax(x, y) is preferable to ifelse(x < y, y, x)"), linter ) # other equivalents to base::ifelse() expect_lint( "if_else(x < 0, 0, x)", rex::rex("pmax(x, y) is preferable to if_else(x < y, y, x)"), linter ) expect_lint( "fifelse(x < 0, 0, x)", rex::rex("pmax(x, y) is preferable to fifelse(x < y, y, x)"), linter ) # other equivalents for censoring expect_lint( "ifelse(x <= 0, 0, x)", rex::rex("pmax(x, y) is preferable to ifelse(x <= y, y, x)"), linter ) expect_lint( "ifelse(x > 0, x, 0)", rex::rex("pmax(x, y) is preferable to ifelse(x > y, x, y)"), linter ) expect_lint( "ifelse(x >= 0, x, 0)", rex::rex("pmax(x, y) is preferable to ifelse(x >= y, x, y)"), linter ) # pairwise min/max (similar to censoring) expect_lint( "ifelse(x < y, x, y)", rex::rex("pmin(x, y) is preferable to ifelse(x < y, x, y)"), linter ) expect_lint( "ifelse(x >= y, y, x)", rex::rex("pmin(x, y) is preferable to ifelse(x >= y, y, x)"), linter ) # more complicated expression still matches lines <- trim_some(" ifelse(2 + p + 104 + 1 > ncols, ncols, 2 + p + 104 + 1 ) ") expect_lint( lines, rex::rex("pmin(x, y) is preferable to ifelse(x > y, y, x)"), linter ) }) test_that("lints vectorize", { expect_lint( trim_some("{ ifelse(x >= y, y, x) ifelse(x >= 0, x, 0) }"), list( list("pmin", line_number = 2L), list("pmax", line_number = 3L) ), ifelse_censor_linter() ) }) lintr/tests/testthat.R0000644000176200001440000000024714752731051014537 0ustar liggesuserslibrary(testthat) library(lintr) # suppress printing environment name (noisy) invisible({ loadNamespace("patrick") loadNamespace("withr") }) test_check("lintr") lintr/MD50000644000176200001440000011322114753133562011723 0ustar liggesusers822d352eaa553a20ceb702f8f506992f *DESCRIPTION c1c87d33a58f9b257f3c3099b6889177 *LICENSE 77dc1d594aa41962754cddc57803900d *NAMESPACE 7e69c5879d26d04aabfa1c0025ae5389 *NEWS.md 68e8916d69e0550d36f4d9061452c384 *R/AAA.R 1a32aa69ee1bf9c6d736174a4ac34f03 *R/T_and_F_symbol_linter.R b7fde7b2e685cb6e9705b5a1c0b4ad81 *R/absolute_path_linter.R e893f543fa5befb68f4406bca0cd7eb1 *R/actions.R b8aa78fe5094bb65c6cb0d5676a603a5 *R/addins.R 9e9eefa65d78a7aeee00b520c0168902 *R/any_duplicated_linter.R fe1e3f03483c8af474589c7f42b6fa79 *R/any_is_na_linter.R bc51d87e59339909179c1c65ef4737f9 *R/assignment_linter.R 4041e5be595c2d2d1f546973a3ace968 *R/backport_linter.R 82273273a3c616211166ae6012feab5f *R/boolean_arithmetic_linter.R 5a1c510365e3bc7ebb3df8c4b00bd680 *R/brace_linter.R 28befc550edd8c050153488dd888eaf1 *R/cache.R 069899073f41544778c5370d7ee3466c *R/class_equals_linter.R 1f7f04059d77b87690f85bf2427ac079 *R/commas_linter.R 402313ce8885277798ba8d97c75b3e71 *R/commented_code_linter.R 920e560f154a92ad0c3e11a28c2f5420 *R/comparison_negation_linter.R bcc3959507f1b54dd981178a313d63e1 *R/condition_call_linter.R 3932ca60e0c6de11783e615d9a8d15d4 *R/condition_message_linter.R 7f1c54550116c85280614bfd4681e544 *R/conjunct_test_linter.R 1fdfe54a4ef26229f2b287a591fca1de *R/consecutive_assertion_linter.R ffc751c6b92fc849a078fb767d7e22ce *R/consecutive_mutate_linter.R 1a004bbc771e40412f09bbd704c439f8 *R/cyclocomp_linter.R deafb9e16f1a98027ce6fa6239c8e4e2 *R/declared_functions.R 62679c0fab3c0cfecc0052b4512e53ae *R/deprecated.R 9f8ab0eaff3b6748d451907ac4da54f6 *R/duplicate_argument_linter.R 2b688ed88194182fab2bf7f0b0eace9d *R/empty_assignment_linter.R a7a257b228fe1d22e6c5fc781ee137c6 *R/equals_na_linter.R dca5e354641ae4d629794032c99039ff *R/exclude.R acb8f23d983952c83fd220ad19e2f794 *R/expect_comparison_linter.R 04ab9f4616cc2a96bad55169b85b89d5 *R/expect_identical_linter.R 9a1c06b74e7e9619c939cc4441312a40 *R/expect_length_linter.R 5a7de9b6d9af39d092de4bb67c75efc1 *R/expect_lint.R e6bf26f492c1552f29bb41826992406e *R/expect_named_linter.R e74ca0ee40d55ef03b4665da4c7834b9 *R/expect_not_linter.R e11b825458bb19a4c6492135cae51ac0 *R/expect_null_linter.R e383f0de14a2e40a1b5563e562e011e7 *R/expect_s3_class_linter.R 34f5561a61fb9b81e125c5529d14ebbb *R/expect_s4_class_linter.R 71b98670252a495a9188258de0332922 *R/expect_true_false_linter.R 719c700035e854617ecded1fb8a83bb0 *R/expect_type_linter.R 34f665dad13b242cfa952ceba91d99c5 *R/extract.R 1d63ce8ca5504d79ff683d3a65535556 *R/fixed_regex_linter.R 7452790eb222cdcce12ebbcaeb92554d *R/for_loop_index_linter.R 72090e2f80f31a5bd60080445d9189b9 *R/function_argument_linter.R 29e8d9199b0935781cbab54300ac61e3 *R/function_left_parentheses_linter.R 1109cfb1fefb9cf991becb290cc8f55b *R/function_return_linter.R 300e0efae3ea322a6a666514e88ccd72 *R/get_source_expressions.R 57624e4bc2009ad72493fd939fb27d8f *R/ids_with_token.R 57b704a545dda25c17265e8d435696f3 *R/if_not_else_linter.R c42e8bc9b5adebe3bf0fade3658f78cf *R/if_switch_linter.R a33772c4d46ac0c6f6ee8ddce9cc4b15 *R/ifelse_censor_linter.R 2995cc22c577e3a84fd1fd3516aad338 *R/implicit_assignment_linter.R ba687f470668fc810cdb7e42df502d23 *R/implicit_integer_linter.R 99a145ff0d35311ead158cfe36dba5f3 *R/indentation_linter.R 98d914f273a8c12fc53ef0829921722f *R/infix_spaces_linter.R a4666fffa7b91e9e8ef56ff7346532df *R/inner_combine_linter.R 9b51980c2403f8134be721f6d52ac4d9 *R/is_lint_level.R 44cc720ec9a2bc9d12f1e6b92d6d6e75 *R/is_numeric_linter.R 135265013efba3759a8c8386f9286fe7 *R/keyword_quote_linter.R 79cf11bfebadf79edf28b468d396eaf3 *R/length_levels_linter.R f72d063b47e9f0b52de219fadeef28a1 *R/length_test_linter.R 2276488894891dafffd66f52b11c6c6d *R/lengths_linter.R 303492d32e0022eed34bd531d294412c *R/library_call_linter.R 6b9f2d62a190390896f2ca83f2c9b328 *R/line_length_linter.R 7e5b244959e621a2cae7553c045267b6 *R/lint.R a53cd6406d7b6adfe1e258817a71b0e3 *R/linter_tag_docs.R eb399bd363aeec97a703fae8e0327956 *R/linter_tags.R c4f25aab22f734fcd76dd853b076ec56 *R/lintr-deprecated.R d3eb37f595d20f6a873bd3724d1bffe3 *R/lintr-package.R 1b94d6b51cec5fce83ce45e82f9c197e *R/list_comparison_linter.R d12c1dabbead14aa74c9d39205163b2f *R/literal_coercion_linter.R 0c029ec3f23099ca2644cce1c16e9ebd *R/make_linter_from_regex.R 15d467f20fbf7a90e36497013f18d38a *R/make_linter_from_xpath.R 36e3d3ac799000bf375f7f85bdbba736 *R/matrix_apply_linter.R 3dfb1c9552321ac3ac4322c39bcce149 *R/methods.R dd18363d49049ea9da4048128dec274d *R/missing_argument_linter.R 94f37511d6b48a4d7a33086fece2c929 *R/missing_package_linter.R 33e29a8c1124ab2943e1128791080ad5 *R/namespace.R 29cf109605875ff5601f6d0c02fa026f *R/namespace_linter.R 26b42725d0b42b903f542ae1009cdce5 *R/nested_ifelse_linter.R 6d62f9ef98b8971b5cb031d9d72b0996 *R/nested_pipe_linter.R 28c206e7ba0d8762e70f5328b79cc695 *R/nonportable_path_linter.R b4c030f250ad5223fa60313b31f72859 *R/nrow_subset_linter.R e557ed00ac6fa8052aa4fff06142c636 *R/numeric_leading_zero_linter.R eeb4399a384ee4f733ff34ed010db220 *R/nzchar_linter.R 92740f48ed61c423951ffba1f577cae5 *R/object_length_linter.R 9dab0fde4711d7e367c5b5b1f02916f8 *R/object_name_linter.R eda7ac62663d04b7532ef8da977fde5a *R/object_overwrite_linter.R 55a38c15368148486a01d08a39e80682 *R/object_usage_linter.R 50ecf15e5ce4562483cb6436382b3bfe *R/one_call_pipe_linter.R 0027028fd78846cbfd574e833ff8ba67 *R/outer_negation_linter.R f85c35ea524594dc8a3e080ca437e8a9 *R/package_hooks_linter.R e3cf03e65d49e69a1a1bb1fa31cbb487 *R/paren_body_linter.R af770599803ff454dba643ebea974b29 *R/paste_linter.R 79da0c19f6ef5af78ee5d95d5a676f74 *R/path_utils.R 0b2160d7ddc6c9989299ba73764e34d6 *R/pipe_call_linter.R 0db3044190da81f2c3d63ec82adaea65 *R/pipe_consistency_linter.R c5e0df69a05372b304998f50c10f9a9a *R/pipe_continuation_linter.R 67421c29aef77cf4b7a3b0977c11d058 *R/pipe_return_linter.R c2d3f6ec7563cef215265931a33e09d9 *R/print_linter.R d6dd85987a1bcb237eef21b725633195 *R/quotes_linter.R 22d5eac27f725e12ae201ec22ae5b4eb *R/redundant_equals_linter.R 472c89942e310e067d435bdb9699883c *R/redundant_ifelse_linter.R ed34a39b7914f7ee761b9b4c3d8c1775 *R/regex_subset_linter.R 470dd2fcb235e1d26471d5ac954744e3 *R/rep_len_linter.R 7582353a144a40220da71f76bb80c7e8 *R/repeat_linter.R 6fb7990af57617553b3f46ab5fbf74bf *R/return_linter.R 679a58f6cc4ccda784d5f0a9a78bf138 *R/routine_registration_linter.R f5bc4a9b9ba9b32bced0345d90b3346a *R/sample_int_linter.R 6e56dde0b9a10fb02654efd7f9fec1da *R/scalar_in_linter.R 171599eab74e92c2c8392db9b01006e3 *R/semicolon_linter.R 2ae14c8ba7702e99680295bebcc24374 *R/seq_linter.R 86501ff7372c476f149458c0c6c2c0b7 *R/settings.R f22520b29d4b4269a48223a2777439f1 *R/settings_utils.R 090986a8bf37e68ec2cb539c02e34036 *R/shared_constants.R 4e415c5b5d0e2ecc33adb1e11d3ff97c *R/sort_linter.R 7cb685e3cf2d5437a635182d1fd072dc *R/source_utils.R 20e68ab84a0bf8a9f6e9ebc26ec123c7 *R/spaces_inside_linter.R 1fecfdb8c8c47d157d2084f5fa0d52e4 *R/spaces_left_parentheses_linter.R f4eb5031f1fa394d920893386206d24d *R/sprintf_linter.R 40cfba6d751e2cf698978b970504e24d *R/stopifnot_all_linter.R fba8f19efb64d46c472916bc66e25465 *R/string_boundary_linter.R cd904bf8d1a3852b738a5a455628e1c1 *R/strings_as_factors_linter.R 4cef5ccb76f13ba72f49031e9c9e9bfb *R/system_file_linter.R 94221945cec53316edf487895c0e2736 *R/terminal_close_linter.R 7b37c3144d3b1c8af12b9c965bc26386 *R/todo_comment_linter.R a1ac46110ccb2bfe9b9139937b604bdc *R/trailing_blank_lines_linter.R 79d127d5d77740a388746067fa597a74 *R/trailing_whitespace_linter.R 6c8cb6c7814624b9f8542eb3c7139765 *R/tree_utils.R 469ee80e15a170d05f0de088697a0d89 *R/undesirable_function_linter.R f7d12b14488e7a29fb49e7ec7d135155 *R/undesirable_operator_linter.R 1d0358ec528acd19e60015ed544082c0 *R/unnecessary_concatenation_linter.R 4264776ba38879b9250dc791a9fa799a *R/unnecessary_lambda_linter.R e4b74bd89cc00ade6878dbdcc46511e9 *R/unnecessary_nesting_linter.R be3721cf99d541fb03126eeb7005ecd4 *R/unnecessary_placeholder_linter.R b1c68a02f1f871f1fa629f1a3376cc1c *R/unreachable_code_linter.R 30c42f8462784aedc97fdc1a3c4d225d *R/unused_import_linter.R 154e04f58fb6cf44617fd0993795b51a *R/use_lintr.R b6cc10b9fc43c9f42cc397f3fdbff459 *R/utils.R 9d7cf7cff6e2ff91969d25bfc5f734c1 *R/vector_logic_linter.R 21547355b0ad6bff80ac9cc21e024fed *R/which_grepl_linter.R 402e8486a9f9109fe1ec9d72dd0925d6 *R/whitespace_linter.R 6db5a9d4ff5d8c1288f9450a19beba00 *R/with.R d943eacec09bf19a32bd31faa7057769 *R/with_id.R eca343b6bdfbe6962ca56ee7285407d1 *R/xml_nodes_to_lints.R 0b48a0a3d2d1eadad9aed2548161c956 *R/xml_utils.R 66860df502d13b538a6577a6026f78f3 *R/xp_utils.R ba8bd3ba5b3360761d1501cb61becf2b *R/yoda_test_linter.R 5c7dd69c11a0961d0f5f57effabe4d7f *R/zzz.R 3a7ffffa2c5f97bb46e935e3ab8978c6 *README.md eebb69b7379d922f3d405b26407024d0 *build/stage23.rdb cdbbd2d7a3a9dc56ca094f8b12b52d2d *build/vignette.rds f9cd2360a90a89a0f4847c664bce4050 *inst/WORDLIST 5e270ae6034b339c2a13d20a5f7d2dec *inst/doc/continuous-integration.R 8c98d0a750f8d35b83025425c1ad9693 *inst/doc/continuous-integration.Rmd 5a6bdf3fede6d057ee11e11bbe6417a6 *inst/doc/continuous-integration.html da7ec31e0adac4da81a7ec86b7c439c6 *inst/doc/creating_linters.Rmd 6b269b234561be6ebd8f4e005bb8c4af *inst/doc/creating_linters.html 217947520a60dfbe342d51207149891c *inst/doc/editors.R 79b71c06f968aec2a875be4969f034e4 *inst/doc/editors.Rmd 0e325a384052b13bcc318bb7f98120bf *inst/doc/editors.html a5aafae3ba4b960d281181104dfb59ac *inst/doc/lintr.R 7ffb922d893f8a9d257011aaaa35a1bd *inst/doc/lintr.Rmd bdda4f6281e7b9ada6a7fcf4cb3a8078 *inst/doc/lintr.html 99e2dcf364f1a17436a52bac9e87e84a *inst/example/bad.R 6f515ea057170dc538df138369b0c3c7 *inst/extdata/sarif-template.json 43925d2a8a4772afda86f2d964ff34a8 *inst/lintr/linters.csv 4bfa1cd4531477ebc1ba01acdecb4d33 *inst/rstudio/addins.dcf 8b4d64c345bab131574d9b68861be1c1 *inst/syntastic/lintr.vim 974bcc3ec591a4e137312b3877108f61 *man/Linter.Rd f469f022dfba16d64238378c6aa1351e *man/T_and_F_symbol_linter.Rd 853eb5c20074fa522f3293b29333f5e5 *man/absolute_path_linter.Rd 44a3390ec2bc020198264cc5ac9e7ebe *man/all_linters.Rd 8ac2ecd2142ba77377796280fe696ee7 *man/any_duplicated_linter.Rd 81723ce2cfc9157fa5067c19bde05c59 *man/any_is_na_linter.Rd d7845d115774b4632b4360f38c3e6cc2 *man/assignment_linter.Rd 08099ab4c14f0274a66d3efb993ed0dc *man/available_linters.Rd fc40d61e9349b7baf7d0ef3636ca4df3 *man/backport_linter.Rd b8105cc29543e5c703bb8750b7f2b99c *man/best_practices_linters.Rd ef5ed3c4baa6aa512b8261675ecb30b9 *man/boolean_arithmetic_linter.Rd 53fb472d643bc00059ba3a5e8c345111 *man/brace_linter.Rd 6b1bb38ef6923fe98d2518a57e1ab9f9 *man/checkstyle_output.Rd 1514cd47ae0934ee3ff6d2b3dc940fa9 *man/class_equals_linter.Rd ab3200819a810d785390dc805fea4429 *man/clear_cache.Rd 162a396d6fa9bdcfa2eec0c623ceb3d4 *man/commas_linter.Rd 29b234afae2453fc9671fb4882840c3e *man/commented_code_linter.Rd 57eed76b2087c837e39f721f45228988 *man/common_mistakes_linters.Rd e0f4e0b899746008dec3fbc181ba6763 *man/comparison_negation_linter.Rd f8fc2d39d7e19e29c26c6237e5291efd *man/condition_call_linter.Rd d342fd5e07c6c09ce094dc3242b813b5 *man/condition_message_linter.Rd b5824bbbfcb2467b899ba4c4c4daf120 *man/configurable_linters.Rd 21cac62e77b8cf3084d96e6ca6a63840 *man/conjunct_test_linter.Rd bb3d0775f67e7e11190f1822f222f3fa *man/consecutive_assertion_linter.Rd d3b9bc679949256a945d04526f45269e *man/consecutive_mutate_linter.Rd ae9ee2f2819de3c5b02ae8ac7f1771de *man/consistency_linters.Rd 6a1650b1ca64f3a46a465b54342a2d7c *man/correctness_linters.Rd 891da922a4f37fbc45600e760a2397c5 *man/cyclocomp_linter.Rd 47268a54c92c25ac1b56e92962614b5c *man/default_linters.Rd 4d9348e997547e8542f918bcbbd19d49 *man/default_settings.Rd daf9ceeb1341d47ebcb59325b78482af *man/default_undesirable_functions.Rd 18b11ac33b38888974a97c6e7c2392f2 *man/deprecated_linters.Rd e46b77da4b5d76763d456bf5fcc14ebb *man/duplicate_argument_linter.Rd 7cc1aacae0675a10812324fd8d265f7a *man/efficiency_linters.Rd 053bfd358f4ebb322f0584745fe1a2dc *man/empty_assignment_linter.Rd d3fab73fdc2bb5df82d598bd23fb110b *man/equals_na_linter.Rd 3be3635deeb13641375080e9599c1ff5 *man/exclude.Rd 94051500fa96c86bd7dd4e9b66b09121 *man/executing_linters.Rd fa7d9613cde22cefcc451fb7baca3b35 *man/expect_comparison_linter.Rd 8376df4ca9455aed1fe1b3f95ebc54fe *man/expect_identical_linter.Rd d651d862fced0b2fa6f784dedb20a3a2 *man/expect_length_linter.Rd a556f2e94aaa5761986e04b555c8b487 *man/expect_lint.Rd 47bba6185083883e8dd9d02d644cca4a *man/expect_lint_free.Rd 15cdbd081729d359896d7555fa4dc8ac *man/expect_named_linter.Rd 57f8842de58c61f11dfc690dc1f1d097 *man/expect_not_linter.Rd c622d08bb7e3e338f13ffa39795102bb *man/expect_null_linter.Rd 9399ae2745289d595ccbee024d5011c5 *man/expect_s3_class_linter.Rd af02b24e756edb4c11c9f3936f874d28 *man/expect_s4_class_linter.Rd 40bae057da5e2e65364f6914d3eba8f1 *man/expect_true_false_linter.Rd c47af3e9397a0fccf48c2a9a4b488df6 *man/expect_type_linter.Rd 9e1674c355416c5123fbd7caf59f7e90 *man/figures/demo.gif dc004f1acc104ece5f01cc537d242fae *man/fixed_regex_linter.Rd 420b1e957c1b6a0499ab354717243578 *man/for_loop_index_linter.Rd ccf6c6e60110b0191d602986fcdca8d0 *man/function_argument_linter.Rd 15d0084ebd9798326c6015def0192dd9 *man/function_left_parentheses_linter.Rd d2a67fc30a7db23eef1007bc63d9e772 *man/function_return_linter.Rd 3e1d89549bc1ff464e2dfc122ea2522c *man/get_r_string.Rd b3b3584f39882393a9b75746a4b83c47 *man/get_source_expressions.Rd 904b0967240b595e27a8660ade908aef *man/ids_with_token.Rd 41ec2a66ce0f43f57d9f799e01b43ebf *man/if_not_else_linter.Rd fb38bf8408697c600a5f4ac4e1f5dcb4 *man/if_switch_linter.Rd fca8e4340b30b480de0d1a32ccdba253 *man/ifelse_censor_linter.Rd 78a5db9fb7d25337f344234a95ead0e7 *man/implicit_assignment_linter.Rd ce3c6e1dca99c36cbd2ea97bb5738b5b *man/implicit_integer_linter.Rd 58deffd23f30acfdc543c990be0d9eb1 *man/indentation_linter.Rd 3b8211065fa6ed4ce9cee277656dcf13 *man/infix_spaces_linter.Rd 92f058695aaee6d0895efc70b1c68645 *man/inner_combine_linter.Rd a2935a70cf28a975ec8ad04be9cbe06f *man/is_lint_level.Rd 172d23f4e36eeaf917e3f7d1e9be7162 *man/is_numeric_linter.Rd 6934ff905dc5d5e461eb819a93170d9b *man/keyword_quote_linter.Rd 226c797456f0383884e2af419006a5c5 *man/length_levels_linter.Rd ab248aeb32ae8333fd1e8958586aede5 *man/length_test_linter.Rd 2a674616b6af294d01b5437cbb5f0672 *man/lengths_linter.Rd 44941af4b9b38352c66a21ba17ac0219 *man/library_call_linter.Rd a6e5442a6ad487732b03c81e6a452329 *man/line_length_linter.Rd 7e65203707e985c9a8f6f178376933dd *man/lint-s3.Rd 7441d76eda0fef98f6edb9c3ccd69d61 *man/lint.Rd f93dfb67b16c9c25c08a1a2419e919b0 *man/linters.Rd 6c8ed9809762227510517abf9138915a *man/linters_with_defaults.Rd 6594f54d4a36589e98e68ef7ad7ccd16 *man/linters_with_tags.Rd 188945f6760a372888e587053d28780a *man/lintr-deprecated.Rd 440d6a4909d908f8773dd521b3fe0d5a *man/lintr-package.Rd 72d72f5c5fa4e217d2412f79a5059d9b *man/list_comparison_linter.Rd 9653060007f3ea1d0adfb6a4df80e8c3 *man/literal_coercion_linter.Rd b5cb809d2d46c8956bd94aeb3852fca4 *man/make_linter_from_xpath.Rd 056b36cc16cabb85cea9984e06b1ce0b *man/matrix_apply_linter.Rd c879319b4810b5960ef8b02d510e98a5 *man/missing_argument_linter.Rd f5451e230bcd931f579e5f8ee000dc98 *man/missing_package_linter.Rd 37a3ecc2d045faa6a198ab79dfaf4b8d *man/modify_defaults.Rd 4e67d67b2488b9f1b6796a9857c97669 *man/namespace_linter.Rd 9fedf31c9262d271ed46c7a240f2d686 *man/nested_ifelse_linter.Rd 33c64c7941732832bb37ecbe44beab8a *man/nested_pipe_linter.Rd e28b685ec18443910933bf3f3be04081 *man/nonportable_path_linter.Rd 4af5840531b973046aaaeb2e2c65ff2d *man/normalize_exclusions.Rd 707311036d00244007fcceb2fcedaf8b *man/nrow_subset_linter.Rd 152303cb47153cd52492db05bcd69064 *man/numeric_leading_zero_linter.Rd 751d9e91f9e4f80d85022613823c82d9 *man/nzchar_linter.Rd 8a349a0b89e6a1fd92b2ef4130df9e1e *man/object_length_linter.Rd 36dcae2f6d9f78f6417a8ff881162552 *man/object_name_linter.Rd ac4214b88d7935a937e1b3a10d894ee5 *man/object_overwrite_linter.Rd 3c420658f57754f4dd6d2edd6eab3359 *man/object_usage_linter.Rd 61d0c54e4f9222f6d4a7740cccb4a29b *man/one_call_pipe_linter.Rd d0bb58d87e46e3b26fc68c2c8d217321 *man/outer_negation_linter.Rd fd6c00d85b50b4f51ed6b0326245f2fb *man/package_development_linters.Rd 6baa8b010184c44e3766b52c2c9f2da2 *man/package_hooks_linter.Rd 6288eacba5c41c7f35f9a3c2066673cd *man/paren_body_linter.Rd 58dc43f6efe38875fbaa3f247f8d8481 *man/parse_exclusions.Rd 24694526bf903edc942db95e53ce237e *man/paste_linter.Rd c44b47c40357bfd98434796ac7fbaf61 *man/pipe_call_linter.Rd 6faf7b62bc371f20f49d930c8ade1a63 *man/pipe_consistency_linter.Rd ed406b3297b64eaf5bd4403431f5897d *man/pipe_continuation_linter.Rd 6c48f39a24be12666464fb3909129e88 *man/pipe_return_linter.Rd f4c44d4526652bc2d923cfbe144c577e *man/pkg_testthat_linters.Rd 79ccffc14775436d35142d7aae1f674e *man/print_linter.Rd 3c13c489a19a6928bac8ece207d54733 *man/quotes_linter.Rd 057fbc586fe7e5750153aa0c794605cb *man/read_settings.Rd 69241f3292b8f76eceb20b8f3aa2b285 *man/readability_linters.Rd 3285fa223ad1b2b36fc7ae2e08789d52 *man/redundant_equals_linter.Rd 0c8ae3933a06817197595d2b9206781e *man/redundant_ifelse_linter.Rd 568fcaf854941d1794926362e4594c51 *man/regex_linters.Rd 6087811951ef083d36218541422ac966 *man/regex_subset_linter.Rd 6974a7a9b91c394f6d0b3c38d1cc2ed7 *man/rep_len_linter.Rd 18b1d05a113267fa9d3c5320e856aa42 *man/repeat_linter.Rd 91d3c67d9ce099d25e087bce30e4f6e8 *man/return_linter.Rd 3e5740bebf81c6bb58872bbd218082bc *man/robustness_linters.Rd 31542647d63a182fa5b1c2264cf63eea *man/routine_registration_linter.Rd d7042af66b4d22e55424455c6ee2b908 *man/sample_int_linter.Rd ccef70b8eee150be011d950bf65fda7a *man/sarif_output.Rd ef79459f0f322234f0a5f4ebdecba499 *man/scalar_in_linter.Rd c1e7a754a8a9e44286e5445c3fe3447a *man/semicolon_linter.Rd 8f27a0fd79888b2082cd7fabaa101ccb *man/seq_linter.Rd f20cb94256a81112e5066a13fba4924f *man/sort_linter.Rd 2018483d18081ccee090a330b292e63c *man/spaces_inside_linter.Rd d164dd87f5b2b10dd9fb563132dd2822 *man/spaces_left_parentheses_linter.Rd 98f0bafe788f9f3566594c950c5d5186 *man/sprintf_linter.Rd 0fd3f60572da7fa9eb65786f316c536d *man/stopifnot_all_linter.Rd 913729f1657aa596947023d8d4690146 *man/string_boundary_linter.Rd e6ff99f4c58968b51d6311423a992979 *man/strings_as_factors_linter.Rd 07712e61c1819c950656fd57afee62d5 *man/style_linters.Rd db3decd3a0a1f280f4773ebb3117018e *man/system_file_linter.Rd 3a4e9ec98ac67c611946a493686c954a *man/terminal_close_linter.Rd 79168aac1ae689442e39e610279a18ba *man/tidy_design_linters.Rd 134e8cb8d1921a09790593ac80c9f4a7 *man/todo_comment_linter.Rd 222d4ce8e87f9be70039196fe15505ab *man/trailing_blank_lines_linter.Rd 283fe4b6547d0bebe6a7fe62e318bf19 *man/trailing_whitespace_linter.Rd fade1c983f40a8ae0020b273e3a502de *man/undesirable_function_linter.Rd 69d9bedc05813e687a5c92dd7df91adb *man/undesirable_operator_linter.Rd 9a389186117e6f68bdb42949c5bde772 *man/unnecessary_concatenation_linter.Rd 8194b3fc0efe1b47b9b5a61d5d86ca6f *man/unnecessary_lambda_linter.Rd 27bce1e767d4e9b5946bcaa52917256c *man/unnecessary_nesting_linter.Rd 33d79693da4413a9404a49198f2efeb8 *man/unnecessary_placeholder_linter.Rd c1078269591d36968070ee279396366a *man/unreachable_code_linter.Rd e32eff9bde6e05b3b3e56c8ff14e123b *man/unused_import_linter.Rd 0ff4ff9cb98f7e2f039e58cca35d447b *man/use_lintr.Rd 724380dcbea050567a97ad85957c0331 *man/vector_logic_linter.Rd d2be432290e0143eb4c41c5989521df1 *man/which_grepl_linter.Rd 9aab6b22558ae3665eeef7ad57cd50e4 *man/whitespace_linter.Rd b38c6aaf1218f5f020e50a676830dc96 *man/xml_nodes_to_lints.Rd b43e46607943efae86448b4fca494786 *man/xp_call_name.Rd 3cd4f66d5f3e73560571a19b735c85f3 *man/yoda_test_linter.Rd cd0784aeed7386695d7553d17ef4c340 *tests/testthat.R 77756276fe9b63c2b325230259ee982d *tests/testthat/_snaps/methods.md 26d15b1f61ca44e70148edc81254d441 *tests/testthat/checkstyle.xml 69d02ff2ae9e704834c79d52818f44fb *tests/testthat/default_linter_testcode.R aaed27820d9ea879bd76df3ff4751bd9 *tests/testthat/dummy_packages/RConfig/DESCRIPTION 8c7c02352670449350b4d1bdef021768 *tests/testthat/dummy_packages/RConfig/R/lint_me.R b29540a2f21f8192c776b7c363a98379 *tests/testthat/dummy_packages/RConfig/lintr_test_config.R 21dbf7f39cbf41256fbf18e254f99a7d *tests/testthat/dummy_packages/RConfig/lintr_test_config_conflict 19646a96b4ad2271c1c0b1a29c02353f *tests/testthat/dummy_packages/RConfig/lintr_test_config_conflict.R 8320d1ad1f6cac28bee45881e8979290 *tests/testthat/dummy_packages/RConfig/lintr_test_config_extraneous.R bfa2bf7f8a8b8e53c02fbafa848bf076 *tests/testthat/dummy_packages/RConfig/tests/testthat.R 6839e5cac8d2ad6beef39fc461e4b028 *tests/testthat/dummy_packages/RConfigInvalid/DESCRIPTION 26813d0f7f8e272af05102662163c53b *tests/testthat/dummy_packages/RConfigInvalid/R/lint_me.R c3ce8bfe939aab9148629f67b79a8847 *tests/testthat/dummy_packages/RConfigInvalid/lintr_test_config.R b64bf1efeb5e911288ecd23887b3bfd6 *tests/testthat/dummy_packages/assignmentLinter/DESCRIPTION 8b54e5a89fbda3af5e077053d40bec76 *tests/testthat/dummy_packages/assignmentLinter/NAMESPACE 3ae082cb6fd2047c7ccaa6e08c71838c *tests/testthat/dummy_packages/assignmentLinter/R/abc.R adb6f9135ff547493ee5bef6e5aa6ad0 *tests/testthat/dummy_packages/assignmentLinter/R/jkl.R 6a9d3d5c14bb032d2ec02d3685093b56 *tests/testthat/dummy_packages/assignmentLinter/exec/script.R 78a21cb50559555815798f6c2bc9884a *tests/testthat/dummy_packages/assignmentLinter/tests/testthat.R f6dcb71f287240b7e28dcaceb13942b9 *tests/testthat/dummy_packages/assignmentLinter/tests/testthat/test-abc.R fb24a4e2f1f9627c3908b83bfa3970f9 *tests/testthat/dummy_packages/clean/DESCRIPTION 4868f6d5a7fb6dbf050df0a5bf2cbc53 *tests/testthat/dummy_packages/clean/NAMESPACE c5dde05e81ae3cca126311141e85bab7 *tests/testthat/dummy_packages/clean/R/clean_generics.R c4fbf9794416b9abfbfd9494a9fde0ed *tests/testthat/dummy_packages/clean/R/default_linter_testcode.R 035388fd16a4b82cdd37efbceeaf47f2 *tests/testthat/dummy_packages/clean/R/eat_me.R 4c61569079b46263ca9b09d41d360086 *tests/testthat/dummy_packages/clean/lintr_test_config 4c61569079b46263ca9b09d41d360086 *tests/testthat/dummy_packages/clean_subdir/lintr_test_config c9239a50affa8bff3b03273f421bc254 *tests/testthat/dummy_packages/clean_subdir/r/DESCRIPTION 6b01f49f6db592a0ff9d92e399d242c3 *tests/testthat/dummy_packages/clean_subdir/r/NAMESPACE c4fbf9794416b9abfbfd9494a9fde0ed *tests/testthat/dummy_packages/clean_subdir/r/R/default_linter_testcode.R 74655ea81ee2a9c5db45d5f6c57e07da *tests/testthat/dummy_packages/clean_subdir/r/R/imported_methods.R d287dd2446cdf35da5530ae99bb312f3 *tests/testthat/dummy_packages/cp1252/DESCRIPTION 8b54e5a89fbda3af5e077053d40bec76 *tests/testthat/dummy_packages/cp1252/NAMESPACE fa310f3f657122643ad3b020f755d415 *tests/testthat/dummy_packages/cp1252/R/cp1252.R 9c202a90ee3e421e55821643ccb7210f *tests/testthat/dummy_packages/cp1252/cp1252.Rproj 863ab39602c4002968c7978b77ed0a49 *tests/testthat/dummy_packages/desc_dir_pkg/DESCRIPTION/R/foo.R 2cf4b050b4ec4d6a9a10b60cd1c2515e *tests/testthat/dummy_packages/github_lintr_file/DESCRIPTION 8b54e5a89fbda3af5e077053d40bec76 *tests/testthat/dummy_packages/github_lintr_file/NAMESPACE 387ce1901b5304468abb91bbfcf3a31e *tests/testthat/dummy_packages/github_lintr_file/R/abc.R 3116b9cb6e55dbc52682ffe45521933c *tests/testthat/dummy_packages/github_lintr_file/tests/testthat.R 387ce1901b5304468abb91bbfcf3a31e *tests/testthat/dummy_packages/github_lintr_file/tests/testthat/test-abc.R 5fa5a362fe0926b3763a9d676c023b02 *tests/testthat/dummy_packages/missing_dep/DESCRIPTION 21b783bc993c520768c42c81d1a31aa1 *tests/testthat/dummy_packages/missing_dep/NAMESPACE ee665b88f1a4bd01eeedf1cd9b7f17fc *tests/testthat/dummy_packages/missing_dep/R/foo.R 347aa60736542d22f771cd3a915a2e20 *tests/testthat/dummy_packages/no_export_dep/DESCRIPTION ac0b9e0144a121b592555541bc124458 *tests/testthat/dummy_packages/no_export_dep/NAMESPACE 1e1dff52d75c5815c8877535cb0aab48 *tests/testthat/dummy_packages/no_export_dep/R/foo.R 4e4ece613a3cab8b7960c27fbbcbc0d5 *tests/testthat/dummy_packages/package/DESCRIPTION 53a143d3ff54cf4db5a4ffd57e848364 *tests/testthat/dummy_packages/package/NAMESPACE 23d3b4a21d5a8c89cc2bead0d25d6391 *tests/testthat/dummy_packages/package/R/default_linter_testcode.R 23d3b4a21d5a8c89cc2bead0d25d6391 *tests/testthat/dummy_packages/package/data-raw/default_linter_testcode.R 84c672fd8da1f137384cdda85fd36ccd *tests/testthat/dummy_packages/package/exec/script.R 23d3b4a21d5a8c89cc2bead0d25d6391 *tests/testthat/dummy_packages/package/inst/data-raw/default_linter_testcode.R d1c3e86a77bba5f384b5279bb9bd7086 *tests/testthat/dummy_packages/package/lintr_test_config a22ea92b08e06a4bbbb38cfd5693e080 *tests/testthat/dummy_packages/package/package.Rproj 944ac51d76c95bd11df93d252b7c009e *tests/testthat/dummy_packages/package/vignettes/test.Qmd b4ecb1ec1dbb7d7c629c578cbebcce5a *tests/testthat/dummy_packages/package/vignettes/test.Rhtml 1885ebd2d20240bb193f44b6b8e30765 *tests/testthat/dummy_packages/package/vignettes/test.Rmd c37efc49e0294190561047a63ba49607 *tests/testthat/dummy_packages/package/vignettes/test.Rnw 93db4dc8ed588c87ff94566b00e6891e *tests/testthat/dummy_packages/package/vignettes/test.Rrst 4ecc24216384c642ab5abbbc7537a907 *tests/testthat/dummy_packages/package/vignettes/test.Rtex 52a1f46b64423940155df41059342c51 *tests/testthat/dummy_packages/package/vignettes/test.Rtxt fa310f3f657122643ad3b020f755d415 *tests/testthat/dummy_projects/project/cp1252.R fa09e2c168d037d278f62d9c476ed416 *tests/testthat/dummy_projects/project/cp1252_parseable.R 316d42ff77cac012181a47896caa653b *tests/testthat/dummy_projects/project/default_linter_testcode.R 9aee4ffbb277a4e6613bdba74fe61e06 *tests/testthat/dummy_projects/project/mismatched_starts_ends.R 3f932aa4067f423825a53dd6eb0bda87 *tests/testthat/dummy_projects/project/one_start_no_end.R cee103d26493854043b9fc3357e23dec *tests/testthat/dummy_projects/project/partially_matched_exclusions.R f823822886b798e97fdb6d693323cb56 *tests/testthat/dummy_projects/project/project.Rproj d1bf27337e9d99679909f450d930c5cf *tests/testthat/exclusions-test c58bd3fff9c9496927c0d588bd2f21bd *tests/testthat/helper.R 8b63d69e1187cc4725c41da250164940 *tests/testthat/knitr_extended_formats/bookdown.Rmd c244da997cbdd2a7d0d73eef2c9b5d4a *tests/testthat/knitr_extended_formats/tufte.Rmd b4ecb1ec1dbb7d7c629c578cbebcce5a *tests/testthat/knitr_formats/test.Rhtml ea73828bc2e38386950d7f9425dfe2ea *tests/testthat/knitr_formats/test.Rmd c37efc49e0294190561047a63ba49607 *tests/testthat/knitr_formats/test.Rnw 93db4dc8ed588c87ff94566b00e6891e *tests/testthat/knitr_formats/test.Rrst 4ecc24216384c642ab5abbbc7537a907 *tests/testthat/knitr_formats/test.Rtex 52a1f46b64423940155df41059342c51 *tests/testthat/knitr_formats/test.Rtxt 944ac51d76c95bd11df93d252b7c009e *tests/testthat/knitr_formats/test.qmd d006c5b4e5ddac8fcb4696e9939d7c36 *tests/testthat/knitr_malformed/incomplete_r_block.Rmd d006c5b4e5ddac8fcb4696e9939d7c36 *tests/testthat/knitr_malformed/incomplete_r_block.qmd 5cc611f6b1e16a64dfffae5bcff2e704 *tests/testthat/lints 4c84c9f4da09ea17c02b4ea38af162bc *tests/testthat/test-Lint-builder.R cd78bfbb40f6b80ec585318df78e80b4 *tests/testthat/test-T_and_F_symbol_linter.R c35cb90aed4bd7d74d2576c5d4700d9f *tests/testthat/test-absolute_path_linter.R 2e3a23b5f84322825b30e9701f5ca347 *tests/testthat/test-any_duplicated_linter.R ae081bf5c9a210df4e936b673d0cd72e *tests/testthat/test-any_is_na_linter.R 274f1b1cad5ee4aa8de53c0c526e7b63 *tests/testthat/test-assignment_linter.R 5cb98e0bc4c7692ba9d8d723924813a3 *tests/testthat/test-backport_linter.R 9e7164e8c0e8961a6d552aaf4f8b1cd4 *tests/testthat/test-boolean_arithmetic_linter.R 8766edeee91e847bdeb176d2abaffdef *tests/testthat/test-brace_linter.R 436e8c778119a3b014f3a0a5ec64e853 *tests/testthat/test-cache.R 9fd5ddbfc33b3950968db2b966abc387 *tests/testthat/test-checkstyle_output.R 022893cece1482d05cff404371356646 *tests/testthat/test-ci.R 66992dc74937e82c7911c702799f5612 *tests/testthat/test-class_equals_linter.R 589e3b4ba11ccd93d79f0ec4b785b20c *tests/testthat/test-commas_linter.R e652a39cfce77ccf03122ce868d08fec *tests/testthat/test-commented_code_linter.R 544f6dc27eb66355551c7e0ccc6cf6e1 *tests/testthat/test-comparison_negation_linter.R 31c268c86afa105a9a7cbcb3266d15cd *tests/testthat/test-condition_call_linter.R bc50f8dfa91bba83f4c48bfcd82b2c11 *tests/testthat/test-condition_message_linter.R 5b8f58045fa24cf047f39be398793f89 *tests/testthat/test-conjunct_test_linter.R 78fa457b6a019f650acb5a6135c3fe05 *tests/testthat/test-consecutive_assertion_linter.R 80d08ed3fcabc9e284173054e6e6de66 *tests/testthat/test-consecutive_mutate_linter.R 197bf919574150b4ab2dc7f4f7562c17 *tests/testthat/test-cyclocomp_linter.R fe349544048e412d5daa91570c3ac797 *tests/testthat/test-defaults.R 9ae02461a3f8d036c5da45c5996f8a98 *tests/testthat/test-duplicate_argument_linter.R 363c87c32829e5868c5adb0550cf3fb1 *tests/testthat/test-empty_assignment_linter.R 88518b5dc2bf0c5fe32c0060e197f2f0 *tests/testthat/test-equals_na_linter.R e5eac50c38bc15a50fd5042bcec62829 *tests/testthat/test-error.R 82ef5450899e5d65b3410ab92f13e894 *tests/testthat/test-exclusions.R d729500087d65ca80f06a4e07fe3eb57 *tests/testthat/test-expect_comparison_linter.R ae7c7ed038d05a3910bf583896b76fb5 *tests/testthat/test-expect_identical_linter.R ab59c9af183b43dae3fac851cc25adc6 *tests/testthat/test-expect_length_linter.R 3b778fec534d98179fb739b993fcb00c *tests/testthat/test-expect_lint.R e59ae7fb8c163d94b3c806e4448c29be *tests/testthat/test-expect_named_linter.R dbbe9e111a223ec5c377f112e2799850 *tests/testthat/test-expect_not_linter.R 6a0493c0407fdb55655c076bb0f16a41 *tests/testthat/test-expect_null_linter.R dadc2b2ea706ada00cfef407a3effdb0 *tests/testthat/test-expect_s3_class_linter.R 79fa6bf5c58828876910991d67bcb5cb *tests/testthat/test-expect_s4_class_linter.R 386a540879205d75e5d06613996a5245 *tests/testthat/test-expect_true_false_linter.R cc1738c8f79957df326f2be0da926c0b *tests/testthat/test-expect_type_linter.R 4dec755e36a42f099fb3db1c552c3aad *tests/testthat/test-extraction_operator_linter.R e721d8510e0bf04f85ae23223ed29e8d *tests/testthat/test-fixed_regex_linter.R 8bfcdf81e16e478be10ca554e0d41059 *tests/testthat/test-for_loop_index_linter.R cf909ccea303beb52fbaa5ae2fd85e10 *tests/testthat/test-function_argument_linter.R 1c83773033bbb88702a3f4fcadb7c010 *tests/testthat/test-function_left_parentheses_linter.R 6748e8638a38c0c6d7ce64c2314d5980 *tests/testthat/test-function_return_linter.R 038d6f5957ac80ec0a714ea7ad4fd303 *tests/testthat/test-get_source_expressions.R ac96814091d9e73faef083e7d763de2e *tests/testthat/test-ids_with_token.R c61466149f1b12ae34dc6239d45c13d4 *tests/testthat/test-if_not_else_linter.R 0128bda009eaa14d86492405a9029db5 *tests/testthat/test-if_switch_linter.R fbe7faa1e65ef991bb892ffe58b15bc7 *tests/testthat/test-ifelse_censor_linter.R 950f1a2141e907cb41c24c05e80a57d5 *tests/testthat/test-implicit_assignment_linter.R 7e8762dad4a3e6be6d1484b2a7d871a6 *tests/testthat/test-implicit_integer_linter.R bc6a0b7db5c57ff846d4572a670fed3d *tests/testthat/test-indentation_linter.R e9cfe8af801d9fcd90698312b2ffe4ad *tests/testthat/test-infix_spaces_linter.R 25a5167b3314daa9bf04a19f810574e2 *tests/testthat/test-inner_combine_linter.R af61184ddcec5e080e002b9526773e49 *tests/testthat/test-is_lint_level.R c5f61097f426a122304acc3d5cdc8c1a *tests/testthat/test-is_numeric_linter.R 64fdf71e27b6c61199d2f4d3e5b3a702 *tests/testthat/test-keyword_quote_linter.R c3c375e3d15eb89bf9f6ae9023d34d20 *tests/testthat/test-knitr_extended_formats.R 17a0e813ff7d1c1547b875aaf7bb0d40 *tests/testthat/test-knitr_formats.R b780f0f70a7d1b0dcd51d91076771944 *tests/testthat/test-length_levels_linter.R 7ae4b9e2d497fe4aacb8d5b90d615248 *tests/testthat/test-length_test_linter.R 95550563f5f55736938331067dcf65c9 *tests/testthat/test-lengths_linter.R 1799bd49b7fbf6c041244f420b15a9a7 *tests/testthat/test-library_call_linter.R b396e7c3981e2ae291834717ce9b41cf *tests/testthat/test-line_length_linter.R 33fb5a1cb3d2fa8b1447ef5fb5adb08c *tests/testthat/test-lint.R 00b8328e984d9836784b48066ab1ede3 *tests/testthat/test-lint_dir.R 71f31fb58ec44eebba811bf94bca961b *tests/testthat/test-lint_package.R 759ef84fb3004509cbae645185e04239 *tests/testthat/test-linter_tags.R 3bbeedf3639495c6d5ec20ba434995b4 *tests/testthat/test-lintr-package.R 70b9be5504c3c116202c27d63fa51c72 *tests/testthat/test-list_comparison_linter.R b9f241308c8086ed4ccd6a39ae775f16 *tests/testthat/test-literal_coercion_linter.R a5f72271eefd5c9791da697fc075bdb9 *tests/testthat/test-make_linter_from_regex.R b07789d0333e7ac997174fd8fb82bca5 *tests/testthat/test-make_linter_from_xpath.R 3042afd9cb7e75ca872460da2a619da8 *tests/testthat/test-matrix_apply_linter.R f1be830ff3a1eafde40f9a47b936b176 *tests/testthat/test-methods.R f96367ca9dd3fd5e4593bb3222f8e2ab *tests/testthat/test-missing_argument_linter.R f2c993f0e685c1c5676deb4a2a8bec6d *tests/testthat/test-missing_package_linter.R 1f851aa02bb148df6b7db3205e4d4604 *tests/testthat/test-namespace_linter.R 07954d619e0f0d883f9a8a297e215463 *tests/testthat/test-nested_ifelse_linter.R 0c636c2e70923aac8ca41d5ea77918c1 *tests/testthat/test-nested_pipe_linter.R e63b8ba31b2799399400f3e757d0fd3e *tests/testthat/test-nonportable_path_linter.R c74bc4de6f6222ef8e6ff6340bc16358 *tests/testthat/test-normalize_exclusions.R fb9561356969c7850bdaa87232e213eb *tests/testthat/test-nrow_subset_linter.R 9add4742358952d1649e53b012cf8140 *tests/testthat/test-numeric_leading_zero_linter.R 6ae2d95e775c8197308ea83eb67d109a *tests/testthat/test-nzchar_linter.R 0c806b4c6071bea384c78df23752ae6d *tests/testthat/test-object_length_linter.R a82d5ef79f4e601d7ff7f2ebbfc778a7 *tests/testthat/test-object_name_linter.R 3ebc972eb6ddd4f14cbec55452a8c5fa *tests/testthat/test-object_overwrite_linter.R 278ba2e5c09c1e1ec1c4d6b7cba84da5 *tests/testthat/test-object_usage_linter.R 910c0ba452cd5014a1243dc91b43d048 *tests/testthat/test-one_call_pipe_linter.R e29c0984273b7f68e854710e47717828 *tests/testthat/test-outer_negation_linter.R 479f9f2ea5c479a0c1b3e5cd6019707a *tests/testthat/test-package_hooks_linter.R 59ba1db344e1620a4ef3c507dc16416f *tests/testthat/test-paren_body_linter.R b4aa1f5a7429106f3dac880c35e61cb5 *tests/testthat/test-parse_exclusions.R 53450fd3641517212f1cf15212ab2a3e *tests/testthat/test-paste_linter.R 24d16293067a9102a0d86927a62029a4 *tests/testthat/test-pipe_call_linter.R 8e2c2b848fa81e6bacf80c8f39bb09a8 *tests/testthat/test-pipe_consistency_linter.R c031ee6676a5cd4da6993b6f62039fbd *tests/testthat/test-pipe_continuation_linter.R d799f177513425b0a7d04034d7e9a226 *tests/testthat/test-pipe_return_linter.R 906f6c822f0b7ead1d86dc8c2dfb62e7 *tests/testthat/test-print_linter.R 1c2dfd697df608e43ec903941d924b84 *tests/testthat/test-quotes_linter.R 16c3635fcb602efd7e8e0f43054b7d9c *tests/testthat/test-redundant_equals_linter.R 69d4aded007616e765e2f2d3b54d8355 *tests/testthat/test-redundant_ifelse_linter.R 926ce9f70fb2e0745bc9c1e8c693c29f *tests/testthat/test-regex_subset_linter.R 17de558310063c649023699f3693eae4 *tests/testthat/test-rep_len_linter.R b43b41e81391c1425f3bc2ef6d3f7560 *tests/testthat/test-repeat_linter.R ac2e12663a62ef129b19ef46f868e91f *tests/testthat/test-return_linter.R 9a2e7cf9d9f82976c5fe5b55a7d7d97f *tests/testthat/test-routine_registration_linter.R 354148a809dd0ec5ddf11a839592c7bd *tests/testthat/test-rstudio_markers.R ad2664106c7529882157f0a1e6464fa1 *tests/testthat/test-sample_int_linter.R d219ab739fc8f3977131d69ef9797fc1 *tests/testthat/test-sarif_output.R 769772840c56ffec4e53a732411216cf *tests/testthat/test-scalar_in_linter.R a73059c589d17e740f96dc493661e444 *tests/testthat/test-semicolon_linter.R 0722bab3d2d867f80387b5375e245118 *tests/testthat/test-seq_linter.R c244e9002762d83169f6eadba3d71430 *tests/testthat/test-settings.R 8c6b7eebefadb32e0c2e11eaeac1b64f *tests/testthat/test-sort_linter.R ace3439cb54cd0960f77bc3bf48b21a1 *tests/testthat/test-spaces_inside_linter.R 42d138a7db8b4b93741917e666719b36 *tests/testthat/test-spaces_left_parentheses_linter.R f233d1307b1f755da8986a3ef39be092 *tests/testthat/test-sprintf_linter.R c52e07e7ae29debba4a4ce00bac4b0c6 *tests/testthat/test-stopifnot_all_linter.R 0d1f094df6706f250c2f81484f91fe99 *tests/testthat/test-string_boundary_linter.R 208c3404f13e2e4126f174adb4b17356 *tests/testthat/test-strings_as_factors_linter.R 5966a8de03759c23263a11236ac2ebb1 *tests/testthat/test-system_file_linter.R a9e68e32f9ce4d6ba0442f7d6afb2543 *tests/testthat/test-terminal_close_linter.R a2f06780abbba3a3ebb31fcbf851f244 *tests/testthat/test-todo_comment_linter.R fc8ef623877438bde342a0c29e7c8d31 *tests/testthat/test-trailing_blank_lines_linter.R d8b1370cbf6ec16a3ab3d431f3e4957a *tests/testthat/test-trailing_whitespace_linter.R 159c4c1e9fd1ca36f08ccdd674ca9c3a *tests/testthat/test-undesirable_function_linter.R c9da7b0336d47c1003ba7b7eedd6faad *tests/testthat/test-undesirable_operator_linter.R 3e44a8d04143b57df3959b18c2baabaa *tests/testthat/test-unnecessary_concatenation_linter.R 52cd7b60776cc3da7163071d166ed6b3 *tests/testthat/test-unnecessary_lambda_linter.R 441c20c171fabd333248e80245d85e14 *tests/testthat/test-unnecessary_nested_if_linter.R 60352095c0fe4e659879d51f6331349e *tests/testthat/test-unnecessary_nesting_linter.R f84fb5a9e1f032e58b76db2ddd03d487 *tests/testthat/test-unnecessary_placeholder_linter.R 0e7dd5e1a86666a96f238782a2b3081c *tests/testthat/test-unneeded_concatenation_linter.R b84ee7be73f3485004f1207b95bee19d *tests/testthat/test-unreachable_code_linter.R 3abf7ec0feaca1ec03887be7b6810656 *tests/testthat/test-unused_import_linter.R 0765dfa37447dfe88daea048dd18098f *tests/testthat/test-use_lintr.R e070372bedc6d205863d601155c8ffa6 *tests/testthat/test-vector_logic_linter.R 503324c144a12c263ce00aa00fbe0c56 *tests/testthat/test-which_grepl_linter.R 206b5b7fe86cd25b931ca1832266cdc2 *tests/testthat/test-whitespace_linter.R c8ceb37b2291925f37366d208d4fbae7 *tests/testthat/test-with.R e9f51139a6e01966822dd500dbf2f8c4 *tests/testthat/test-with_id.R 0e8d26ad850e0e2030452980a13245fe *tests/testthat/test-xml_nodes_to_lints.R 27882d2096e2260d614b39e0951e06d6 *tests/testthat/test-xp_utils.R eea72e9643a48cdf1ac7894d428fce42 *tests/testthat/test-yoda_test_linter.R a0ad092a8b252ffc3e939ab0f9cbb665 *vignettes/atom.png 8c98d0a750f8d35b83025425c1ad9693 *vignettes/continuous-integration.Rmd da7ec31e0adac4da81a7ec86b7c439c6 *vignettes/creating_linters.Rmd 79b71c06f968aec2a875be4969f034e4 *vignettes/editors.Rmd a0e9aec3dc3cda3a9436bbb9312ecd0d *vignettes/emacs-still.gif 7ffb922d893f8a9d257011aaaa35a1bd *vignettes/lintr.Rmd c65b3525f3ac2d3f825a443a18500dff *vignettes/rstudio.png c2e39f07dbe4df2f901ed095d6658ecb *vignettes/sublime-still.gif aa43e719e7e82fa8f132b34827391d82 *vignettes/vim-syntastic-still.gif 32bdb35e5ff7098c72c66f21c92b75ae *vignettes/vscode.png lintr/R/0000755000176200001440000000000014752734540011616 5ustar liggesuserslintr/R/implicit_assignment_linter.R0000644000176200001440000001010014752731051017342 0ustar liggesusers#' Avoid implicit assignment in function calls #' #' Assigning inside function calls makes the code difficult to read, and should #' be avoided, except for functions that capture side-effects (e.g. [capture.output()]). #' #' @param except A character vector of functions to be excluded from linting. #' @param allow_lazy logical, default `FALSE`. If `TRUE`, assignments that only #' trigger conditionally (e.g. in the RHS of `&&` or `||` expressions) are skipped. #' @param allow_scoped Logical, default `FALSE`. If `TRUE`, "scoped assignments", #' where the object is assigned in the statement beginning a branch and used only #' within that branch, are skipped. #' #' @examples #' # will produce lints #' lint( #' text = "if (x <- 1L) TRUE", #' linters = implicit_assignment_linter() #' ) #' #' lint( #' text = "mean(x <- 1:4)", #' linters = implicit_assignment_linter() #' ) #' #' # okay #' lines <- "x <- 1L\nif (x) TRUE" #' writeLines(lines) #' lint( #' text = lines, #' linters = implicit_assignment_linter() #' ) #' #' lines <- "x <- 1:4\nmean(x)" #' writeLines(lines) #' lint( #' text = lines, #' linters = implicit_assignment_linter() #' ) #' #' lint( #' text = "A && (B <- foo(A))", #' linters = implicit_assignment_linter(allow_lazy = TRUE) #' ) #' #' lines <- c( #' "if (any(idx <- x < 0)) {", #' " stop('negative elements: ', toString(which(idx)))", #' "}" #' ) #' writeLines(lines) #' lint( #' text = lines, #' linters = implicit_assignment_linter(allow_scoped = TRUE) #' ) #' #' @evalRd rd_tags("implicit_assignment_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' #' @export implicit_assignment_linter <- function(except = c("bquote", "expression", "expr", "quo", "quos", "quote"), allow_lazy = FALSE, allow_scoped = FALSE) { stopifnot(is.null(except) || is.character(except)) if (length(except) > 0L) { exceptions <- xp_text_in_table(except) xpath_exceptions <- glue("SYMBOL_FUNCTION_CALL[ not({exceptions}) ]") } else { xpath_exceptions <- "SYMBOL_FUNCTION_CALL" } # The walrus operator `:=` is also `LEFT_ASSIGN`, but is not a relevant operator # to be considered for the present linter. assignments <- paste( "//LEFT_ASSIGN[text() != ':=']", "//RIGHT_ASSIGN", sep = " | " ) # NB: Also used, essentially, in assignment_linter. Keep in sync. xpath <- glue(" ({assignments}) /parent::expr[ preceding-sibling::*[2][self::IF or self::WHILE] or parent::forcond or preceding-sibling::expr/{xpath_exceptions} or parent::expr/*[1][self::OP-LEFT-PAREN] ] ") if (allow_lazy) { xpath <- paste0(xpath, "[not(ancestor::expr/preceding-sibling::*[self::AND2 or self::OR2])]") } if (allow_scoped) { # force 2nd preceding to ensure we're in the loop condition, not the loop expression in_branch_cond <- "ancestor::expr[preceding-sibling::*[2][self::IF or self::WHILE]]" xpath <- paste0( xpath, # _if_ we're in an IF/WHILE branch, lint if the assigned SYMBOL appears anywhere later on. glue("[not({in_branch_cond}) or expr[1]/SYMBOL = {in_branch_cond}/parent::expr/following::SYMBOL]") ) } implicit_message <- paste( "Avoid implicit assignments in function calls.", "For example, instead of `if (x <- 1L) { ... }`, write `x <- 1L; if (x) { ... }`." ) print_message <- "Call print() explicitly instead of relying on implicit printing behavior via '('." Linter(linter_level = "file", function(source_expression) { # need the full file to also catch usages at the top level xml <- source_expression$full_xml_parsed_content bad_expr <- xml_find_all(xml, xpath) print_only <- !is.na(xml_find_first(bad_expr, "parent::expr[parent::exprlist and *[1][self::OP-LEFT-PAREN]]")) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = ifelse(print_only, print_message, implicit_message), type = "warning" ) }) } lintr/R/declared_functions.R0000644000176200001440000000071114752731051015565 0ustar liggesusersdeclared_s3_generics <- function(x) { xpath <- paste0( # Top level expression which "/exprlist/expr", # Assigns to a symbol "[./LEFT_ASSIGN|EQ_ASSIGN]", "[./expr[FUNCTION or OP-LAMBDA]]", "[./expr/SYMBOL]", # Is a S3 Generic (contains call to UseMethod) "[.//SYMBOL_FUNCTION_CALL[text()='UseMethod']]", # Retrieve assigned name of the function "/expr/SYMBOL/text()" ) as.character(xml_find_all(x, xpath)) } lintr/R/lengths_linter.R0000644000176200001440000000176614752731051014766 0ustar liggesusers#' Require usage of `lengths()` where possible #' #' [lengths()] is a function that was added to base R in version 3.2.0 to #' get the length of each element of a list. It is equivalent to #' `sapply(x, length)`, but faster and more readable. #' #' @examples #' # will produce lints #' lint( #' text = "sapply(x, length)", #' linters = lengths_linter() #' ) #' #' lint( #' text = "vapply(x, length, integer(1L))", #' linters = lengths_linter() #' ) #' #' lint( #' text = "purrr::map_int(x, length)", #' linters = lengths_linter() #' ) #' #' # okay #' lint( #' text = "lengths(x)", #' linters = lengths_linter() #' ) #' #' @evalRd rd_tags("lengths_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export lengths_linter <- make_linter_from_function_xpath( function_names = c("sapply", "vapply", "map_int", "map_dbl"), xpath = "parent::expr[expr/SYMBOL[text() = 'length']]", lint_message = "Use lengths() to find the length of each element in a list." ) lintr/R/library_call_linter.R0000644000176200001440000001676614752731051015767 0ustar liggesusers#' Library call linter #' #' This linter covers several rules related to [library()] calls: #' #' - Enforce such calls to all be at the top of the script. #' - Block usage of argument `character.only`, in particular #' for loading packages in a loop. #' - Block consecutive calls to `suppressMessages(library(.))` #' in favor of using [suppressMessages()] only once to suppress #' messages from all `library()` calls. Ditto [suppressPackageStartupMessages()]. #' #' @param allow_preamble Logical, default `TRUE`. If `FALSE`, #' no code is allowed to precede the first `library()` call, #' otherwise some setup code is allowed, but all `library()` #' calls must follow consecutively after the first one. #' @examples #' # will produce lints #' #' code <- "library(dplyr)\nprint('test')\nlibrary(tidyr)" #' writeLines(code) #' lint( #' text = code, #' linters = library_call_linter() #' ) #' #' lint( #' text = "library('dplyr', character.only = TRUE)", #' linters = library_call_linter() #' ) #' #' code <- paste( #' "pkg <- c('dplyr', 'tibble')", #' "sapply(pkg, library, character.only = TRUE)", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = library_call_linter() #' ) #' #' code <- "suppressMessages(library(dplyr))\nsuppressMessages(library(tidyr))" #' writeLines(code) #' lint( #' text = code, #' linters = library_call_linter() #' ) #' #' # okay #' code <- "library(dplyr)\nprint('test')" #' writeLines(code) #' lint( #' text = code, #' linters = library_call_linter() #' ) #' #' code <- "# comment\nlibrary(dplyr)" #' lint( #' text = code, #' linters = library_call_linter() #' ) #' #' code <- paste( #' "foo <- function(pkg) {", #' " sapply(pkg, library, character.only = TRUE)", #' "}", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = library_call_linter() #' ) #' #' code <- "suppressMessages({\n library(dplyr)\n library(tidyr)\n})" #' writeLines(code) #' lint( #' text = code, #' linters = library_call_linter() #' ) #' #' @evalRd rd_tags("library_call_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export library_call_linter <- function(allow_preamble = TRUE) { attach_calls <- c("library", "require") attach_call_cond <- xp_text_in_table(attach_calls) suppress_call_cond <- xp_text_in_table(c("suppressMessages", "suppressPackageStartupMessages")) unsuppressed_call_cond <- glue("not( {xp_or(attach_call_cond, suppress_call_cond)} )") if (allow_preamble) { unsuppressed_call_cond <- xp_and( unsuppressed_call_cond, glue("@line1 > //SYMBOL_FUNCTION_CALL[{ attach_call_cond }][1]/@line1") ) } upfront_call_xpath <- glue(" //SYMBOL_FUNCTION_CALL[{ attach_call_cond }][last()] /preceding::expr /SYMBOL_FUNCTION_CALL[{ unsuppressed_call_cond }][last()] /following::expr[SYMBOL_FUNCTION_CALL[{ attach_call_cond }]] /parent::expr ") # STR_CONST: block library|require("..."), i.e., supplying a string literal # ancestor::expr[FUNCTION]: Skip usages inside functions a la {knitr} char_only_direct_xpath <- glue(" //SYMBOL_FUNCTION_CALL[{attach_call_cond}] /parent::expr /parent::expr[ expr[2][STR_CONST] or ( SYMBOL_SUB[text() = 'character.only'] and not(ancestor::expr[FUNCTION]) ) ] ") bad_indirect_funs <- c("do.call", "lapply", "sapply", "map", "walk") call_symbol_cond <- glue("SYMBOL[{attach_call_cond}] or STR_CONST") char_only_indirect_xpath <- glue(" //SYMBOL_FUNCTION_CALL[{ xp_text_in_table(bad_indirect_funs) }] /parent::expr /parent::expr[ not(ancestor::expr[FUNCTION]) and expr[{ call_symbol_cond }] ] ") call_symbol_path <- glue("./expr[{call_symbol_cond}]") attach_expr_cond <- glue("expr[expr/SYMBOL_FUNCTION_CALL[{attach_call_cond}]]") # Use `calls` in the first condition, not in the second, to prevent, e.g., # the first call matching calls[1] but the second matching calls[2]. # That is, ensure that calls[i] only matches a following call to calls[i]. # match on the expr, not the SYMBOL_FUNCTION_CALL, to ensure # namespace-qualified calls only match if the namespaces do. consecutive_suppress_xpath <- glue(" //SYMBOL_FUNCTION_CALL[{ suppress_call_cond }] /parent::expr /parent::expr[ expr[SYMBOL_FUNCTION_CALL[{ suppress_call_cond }]] = following-sibling::expr[1][{attach_expr_cond}]/expr and {attach_expr_cond} ] ") Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content upfront_call_expr <- xml_find_all(xml, upfront_call_xpath) upfront_call_name <- xp_call_name(upfront_call_expr) upfront_call_lints <- xml_nodes_to_lints( upfront_call_expr, source_expression = source_expression, lint_message = sprintf("Move all %s calls to the top of the script.", upfront_call_name), type = "warning" ) char_only_direct_expr <- xml_find_all(xml, char_only_direct_xpath) char_only_direct_calls <- xp_call_name(char_only_direct_expr) character_only <- xml_find_first(char_only_direct_expr, "./SYMBOL_SUB[text() = 'character.only']") char_only_direct_msg_fmt <- ifelse( is.na(character_only), "Use symbols, not strings, in %s calls.", "Use symbols in %s calls to avoid the need for 'character.only'." ) char_only_direct_msg <- sprintf(as.character(char_only_direct_msg_fmt), char_only_direct_calls) char_only_direct_lints <- xml_nodes_to_lints( char_only_direct_expr, source_expression = source_expression, lint_message = char_only_direct_msg, type = "warning" ) char_only_indirect_expr <- xml_find_all(xml, char_only_indirect_xpath) char_only_indirect_lib_calls <- vapply( char_only_indirect_expr, function(expr) { calls <- get_r_string(xml_find_all(expr, call_symbol_path)) calls <- calls[calls %in% attach_calls] if (length(calls) == 1L) calls else NA_character_ }, character(1L) ) # For STR_CONST entries, the XPath doesn't check the string value -- we use # get_r_string() here to do that filter more robustly. is_attach_call <- !is.na(char_only_indirect_lib_calls) char_only_indirect_expr <- char_only_indirect_expr[is_attach_call] char_only_indirect_lib_calls <- char_only_indirect_lib_calls[is_attach_call] char_only_indirect_loop_calls <- xp_call_name(char_only_indirect_expr) char_only_indirect_msg <- sprintf( "Call %s() directly, not vectorized with %s().", char_only_indirect_lib_calls, char_only_indirect_loop_calls ) char_only_indirect_lints <- xml_nodes_to_lints( char_only_indirect_expr, source_expression = source_expression, lint_message = char_only_indirect_msg, type = "warning" ) consecutive_suppress_expr <- xml_find_all(xml, consecutive_suppress_xpath) consecutive_suppress_call_text <- xp_call_name(consecutive_suppress_expr) consecutive_suppress_message <- glue( "Unify consecutive calls to {consecutive_suppress_call_text}(). ", "You can do so by writing all of the calls in one braced expression ", "like {consecutive_suppress_call_text}({{...}})." ) consecutive_suppress_lints <- xml_nodes_to_lints( consecutive_suppress_expr, source_expression = source_expression, lint_message = consecutive_suppress_message, type = "warning" ) c(upfront_call_lints, char_only_direct_lints, char_only_indirect_lints, consecutive_suppress_lints) }) } lintr/R/missing_argument_linter.R0000644000176200001440000000441214752731051016664 0ustar liggesusers#' Missing argument linter #' #' Check for missing arguments in function calls (e.g. `stats::median(1:10, )`). #' #' @param except a character vector of function names as exceptions. #' @param allow_trailing always allow trailing empty arguments? #' #' @examples #' # will produce lints #' lint( #' text = 'tibble(x = "a", )', #' linters = missing_argument_linter() #' ) #' #' # okay #' lint( #' text = 'tibble(x = "a")', #' linters = missing_argument_linter() #' ) #' #' lint( #' text = 'tibble(x = "a", )', #' linters = missing_argument_linter(except = "tibble") #' ) #' #' lint( #' text = 'tibble(x = "a", )', #' linters = missing_argument_linter(allow_trailing = TRUE) #' ) #' #' @evalRd rd_tags("missing_argument_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export missing_argument_linter <- function(except = c("alist", "quote", "switch"), allow_trailing = FALSE) { conds <- c( "self::OP-COMMA[preceding-sibling::*[not(self::COMMENT)][1][self::OP-LEFT-PAREN or self::OP-COMMA]]", "self::EQ_SUB[following-sibling::*[not(self::COMMENT)][1][self::OP-RIGHT-PAREN or self::OP-COMMA]]" ) if (!allow_trailing) { conds <- c(conds, "self::OP-RIGHT-PAREN[preceding-sibling::*[not(self::COMMENT)][1][self::OP-LEFT-PAREN or self::OP-COMMA]]" ) } # require >3 children to exclude foo(), which is xpath <- glue(" parent::expr[count(*) > 3] /*[{xp_or(conds)}] ") Linter(linter_level = "file", function(source_expression) { xml_targets <- source_expression$xml_find_function_calls(NULL, keep_names = TRUE) xml_targets <- xml_targets[!names(xml_targets) %in% except] missing_args <- xml_find_all(xml_targets, xpath) named_idx <- xml_name(missing_args) == "EQ_SUB" arg_id <- character(length(missing_args)) arg_id[named_idx] <- sQuote(xml_find_chr(missing_args[named_idx], "string(preceding-sibling::SYMBOL_SUB[1])"), "'") # TODO(#2452): use xml_find_int() instead arg_id[!named_idx] <- xml_find_num(missing_args[!named_idx], "count(preceding-sibling::OP-COMMA)") + 1.0 xml_nodes_to_lints( missing_args, source_expression = source_expression, lint_message = sprintf("Missing argument %s in function call.", arg_id) ) }) } lintr/R/cache.R0000644000176200001440000000776214752731051013012 0ustar liggesusers#' Clear the lintr cache #' #' @param file filename whose cache to clear. If you pass `NULL`, it will delete all of the caches. #' @param path directory to store caches. Reads option 'lintr.cache_directory' as the default. #' @return 0 for success, 1 for failure, invisibly. #' @export clear_cache <- function(file = NULL, path = NULL) { if (is.null(path)) { # Only retrieve settings if `path` isn't specified. # Otherwise, other settings may inadvertently be loaded, such as exclusions. read_settings(file) path <- settings$cache_directory } if (!is.null(file)) { path <- get_cache_file_path(file, path) } unlink(path, recursive = TRUE) } define_cache_path <- function(cache) { if (isTRUE(cache)) { settings$cache_directory } else if (is.character(cache)) { cache } else { character() } } define_cache_key <- function(filename, inline_data, lines) { if (inline_data) list(content = get_content(lines), TRUE) else filename } get_cache_file_path <- function(file, path) { # this assumes that a normalized absolute file path was given file.path(path, digest::digest(file, algo = "sha1")) } load_cache <- function(file, path = NULL) { if (is.null(path) || length(path) == 0L) { return() } env <- new.env(parent = emptyenv()) file <- get_cache_file_path(file, path) if (file.exists(file)) { tryCatch( load(file = file, envir = env), warning = function(w) { invokeRestart("muffleWarning") }, error = function(e) { cli_warn( "Could not load cache file {.file {file}}:", parent = e ) } ) } # else nothing to do for source file that has no cache env } save_cache <- function(cache, file, path = NULL) { if (is.null(cache)) { return() } if (!file.exists(path)) { dir.create(path, recursive = TRUE) } save(file = get_cache_file_path(file, path), envir = cache, list = ls(envir = cache)) } cache_file <- function(cache, filename, linters, lints) { if (is.null(cache)) { return() } assign( envir = cache, x = digest_content(linters, filename), value = lints, inherits = FALSE ) } retrieve_file <- function(cache, filename, linters) { if (is.null(cache)) { return(NULL) } mget( envir = cache, x = digest_content(linters, filename), mode = "list", inherits = FALSE, ifnotfound = list(NULL) )[[1L]] } cache_lint <- function(cache, expr, linter, lints) { if (is.null(cache)) { return() } assign( envir = cache, x = digest_content(linter, expr), value = lints, inherits = FALSE ) } retrieve_lint <- function(cache, expr, linter, lines) { lints <- get( envir = cache, x = digest_content(linter, expr), mode = "list", inherits = FALSE ) for (i in seq_along(lints)) { new_line_number <- find_new_line( lints[[i]]$line_number, unname(lints[[i]]$line), lines ) if (is.na(new_line_number)) { return(NULL) } lints[[i]]$line_number <- new_line_number } cache_lint(cache, expr, linter, lints) lints } has_lint <- function(cache, expr, linter) { if (is.null(cache)) { return(FALSE) } exists( envir = cache, x = digest_content(linter, expr), mode = "list", inherits = FALSE ) } digest_content <- function(linters, obj) { content <- if (is.list(obj)) { # assume an expression (global expression if obj$parsed_content is lacking) list(linters, obj$content, is.null(obj$parsed_content)) } else { # assume a filename list(linters, readLines(obj)) } digest::digest(content, algo = "sha1") } find_new_line <- function(line_number, line, lines) { if (lines[line_number] %==% line) { return(line_number) } width <- 1L while (width <= length(lines)) { low <- line_number - width if (low > 0L && lines[low] %==% line) { return(low) } high <- line_number + width if (high <= length(lines) && lines[high] %==% line) { return(high) } width <- width + 1L } NA } lintr/R/commas_linter.R0000644000176200001440000000557414752731051014602 0ustar liggesusers#' Commas linter #' #' Check that all commas are followed by spaces, but do not have spaces before them. #' #' @param allow_trailing If `TRUE`, the linter allows a comma to be followed #' directly by a closing bracket without a space. #' #' @examples #' # will produce lints #' lint( #' text = "switch(op , x = foo, y = bar)", #' linters = commas_linter() #' ) #' #' lint( #' text = "mean(x,trim = 0.2,na.rm = TRUE)", #' linters = commas_linter() #' ) #' #' lint( #' text = "x[ ,, drop=TRUE]", #' linters = commas_linter() #' ) #' #' lint( #' text = "x[1,]", #' linters = commas_linter() #' ) #' #' # okay #' lint( #' text = "switch(op, x = foo, y = bar)", #' linters = commas_linter() #' ) #' #' lint( #' text = "switch(op, x = , y = bar)", #' linters = commas_linter() #' ) #' #' lint( #' text = "mean(x, trim = 0.2, na.rm = TRUE)", #' linters = commas_linter() #' ) #' #' lint( #' text = "a[1, , 2, , 3]", #' linters = commas_linter() #' ) #' #' lint( #' text = "x[1,]", #' linters = commas_linter(allow_trailing = TRUE) #' ) #' #' @evalRd rd_tags("commas_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export commas_linter <- function(allow_trailing = FALSE) { # conditions are in carefully-chosen order for performance -- # an expression like c(a,b,c,....) with many elements can have # a huge number of preceding-siblings and the performance of # preceding-sibling::*[1][not(self::OP-COMMA)] is terrible. # This approach exits early on most nodes ('and' condition) # to avoid this. See #1340. xpath_before <- " //OP-COMMA[ @col1 != preceding-sibling::*[1]/@col2 + 1 and @line1 = preceding-sibling::*[1]/@line1 and not(preceding-sibling::*[1][self::OP-COMMA or self::EQ_SUB]) ]" xpath_after <- paste0( "//OP-COMMA[@line1 = following-sibling::*[1]/@line1 and @col1 = following-sibling::*[1]/@col1 - 1 ", if (allow_trailing) "and not(following-sibling::*[1][self::OP-RIGHT-BRACKET or self::RBB or self::OP-RIGHT-PAREN])", "]" ) Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content before_lints <- xml_nodes_to_lints( xml_find_all(xml, xpath_before), source_expression = source_expression, lint_message = "Remove spaces before a comma.", range_start_xpath = "number(./preceding-sibling::*[1]/@col2 + 1)", # start after preceding expression range_end_xpath = "number(./@col1 - 1)" # end before comma ) after_lints <- xml_nodes_to_lints( xml_find_all(xml, xpath_after), source_expression = source_expression, lint_message = "Put a space after a comma.", range_start_xpath = "number(./@col2 + 1)", # start and end after comma range_end_xpath = "number(./@col2 + 1)" ) c(before_lints, after_lints) }) } lintr/R/pipe_consistency_linter.R0000644000176200001440000000452114752731051016670 0ustar liggesusers#' Pipe consistency linter #' #' Check that pipe operators are used consistently by file, or optionally #' specify one valid pipe operator. #' #' @param pipe Which pipe operator is valid (either `"%>%"` or `"|>"`). By default #' (`"auto"`), the linter has no preference but will check that each file uses #' only one type of pipe operator. #' #' @examples #' # will produce lints #' lint( #' text = "1:3 |> mean() %>% as.character()", #' linters = pipe_consistency_linter() #' ) #' #' lint( #' text = "1:3 %>% mean() %>% as.character()", #' linters = pipe_consistency_linter("|>") #' ) #' #' # okay #' lint( #' text = "1:3 %>% mean() %>% as.character()", #' linters = pipe_consistency_linter() #' ) #' #' lint( #' text = "1:3 |> mean() |> as.character()", #' linters = pipe_consistency_linter() #' ) #' @evalRd rd_tags("pipe_consistency_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export pipe_consistency_linter <- function(pipe = c("auto", "%>%", "|>")) { pipe <- match.arg(pipe) xpath_magrittr <- glue("//SPECIAL[{ xp_text_in_table(magrittr_pipes) }]") xpath_native <- "//PIPE" Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content match_magrittr <- xml_find_all(xml, xpath_magrittr) match_native <- xml_find_all(xml, xpath_native) n_magrittr <- length(match_magrittr) n_native <- length(match_native) if (pipe == "auto" && n_magrittr > 0L && n_native > 0L) { xml_nodes_to_lints( xml = c(match_magrittr, match_native), source_expression = source_expression, lint_message = glue( "Stick to one pipe operator; found {n_magrittr} instances of %>% and {n_native} instances of |>." ), type = "style" ) } else if (pipe == "%>%" && n_native > 0L) { xml_nodes_to_lints( xml = match_native, source_expression = source_expression, lint_message = "Use the %>% pipe operator instead of the |> pipe operator.", type = "style" ) } else if (pipe == "|>" && n_magrittr > 0L) { xml_nodes_to_lints( xml = match_magrittr, source_expression = source_expression, lint_message = "Use the |> pipe operator instead of the %>% pipe operator.", type = "style" ) } else { list() } }) } lintr/R/expect_comparison_linter.R0000644000176200001440000000431214752731051017032 0ustar liggesusers#' Require usage of `expect_gt(x, y)` over `expect_true(x > y)` (and similar) #' #' [testthat::expect_gt()], [testthat::expect_gte()], [testthat::expect_lt()], #' [testthat::expect_lte()], and [testthat::expect_equal()] exist specifically #' for testing comparisons between two objects. [testthat::expect_true()] can #' also be used for such tests, but it is better to use the tailored function #' instead. #' #' @examples #' # will produce lints #' lint( #' text = "expect_true(x > y)", #' linters = expect_comparison_linter() #' ) #' #' lint( #' text = "expect_true(x <= y)", #' linters = expect_comparison_linter() #' ) #' #' lint( #' text = "expect_true(x == (y == 2))", #' linters = expect_comparison_linter() #' ) #' #' # okay #' lint( #' text = "expect_gt(x, y)", #' linters = expect_comparison_linter() #' ) #' #' lint( #' text = "expect_lte(x, y)", #' linters = expect_comparison_linter() #' ) #' #' lint( #' text = "expect_identical(x, y == 2)", #' linters = expect_comparison_linter() #' ) #' #' lint( #' text = "expect_true(x < y | x > y^2)", #' linters = expect_comparison_linter() #' ) #' #' @evalRd rd_tags("expect_comparison_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export expect_comparison_linter <- function() { # != doesn't have a clean replacement comparator_nodes <- setdiff(infix_metadata$xml_tag[infix_metadata$comparator], "NE") xpath <- glue(" following-sibling::expr[1][ {xp_or(comparator_nodes)} ] /parent::expr[not(SYMBOL_SUB[text() = 'info'])] ") comparator_expectation_map <- c( `>` = "expect_gt", `>=` = "expect_gte", `<` = "expect_lt", `<=` = "expect_lte", `==` = "expect_identical" ) Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls("expect_true") bad_expr <- xml_find_all(xml_calls, xpath) comparator <- xml_find_chr(bad_expr, "string(expr[2]/*[2])") expectation <- comparator_expectation_map[comparator] lint_message <- sprintf("%s(x, y) is better than expect_true(x %s y).", expectation, comparator) xml_nodes_to_lints(bad_expr, source_expression, lint_message = lint_message, type = "warning") }) } lintr/R/sort_linter.R0000644000176200001440000001103214752731051014274 0ustar liggesusers#' Check for common mistakes around sorting vectors #' #' This linter checks for some common mistakes when using [order()] or [sort()]. #' #' First, it requires usage of `sort()` over `.[order(.)]`. #' #' [sort()] is the dedicated option to sort a list or vector. It is more legible #' and around twice as fast as `.[order(.)]`, with the gap in performance #' growing with the vector size. #' #' Second, it requires usage of [is.unsorted()] over equivalents using `sort()`. #' #' The base function `is.unsorted()` exists to test the sortedness of a vector. #' Prefer it to inefficient and less-readable equivalents like #' `x != sort(x)`. The same goes for checking `x == sort(x)` -- use #' `!is.unsorted(x)` instead. #' #' Moreover, use of `x == sort(x)` can be risky because [sort()] drops missing #' elements by default, meaning `==` might end up trying to compare vectors #' of differing lengths. #' #' @examples #' # will produce lints #' lint( #' text = "x[order(x)]", #' linters = sort_linter() #' ) #' #' lint( #' text = "x[order(x, decreasing = TRUE)]", #' linters = sort_linter() #' ) #' #' lint( #' text = "sort(x) == x", #' linters = sort_linter() #' ) #' #' # okay #' lint( #' text = "x[sample(order(x))]", #' linters = sort_linter() #' ) #' #' lint( #' text = "y[order(x)]", #' linters = sort_linter() #' ) #' #' lint( #' text = "sort(x, decreasing = TRUE) == x", #' linters = sort_linter() #' ) #' #' # If you are sorting several objects based on the order of one of them, such #' # as: #' x <- sample(1:26) #' y <- letters #' newx <- x[order(x)] #' newy <- y[order(x)] #' # This will be flagged by the linter. However, in this very specific case, #' # it would be clearer and more efficient to run order() once and assign it #' # to an object, rather than mix and match order() and sort() #' index <- order(x) #' newx <- x[index] #' newy <- y[index] #' #' @evalRd rd_tags("sort_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export sort_linter <- function() { non_keyword_arg <- "expr[not(preceding-sibling::*[1][self::EQ_SUB])]" order_xpath <- glue(" //OP-LEFT-BRACKET /following-sibling::expr[1][ expr[1][ SYMBOL_FUNCTION_CALL[text() = 'order'] and count(following-sibling::{non_keyword_arg}) = 1 and following-sibling::{non_keyword_arg} = parent::expr[1]/parent::expr[1]/expr[1] ] ] ") sorted_xpath <- " parent::expr[not(SYMBOL_SUB)] /parent::expr[ (EQ or NE) and expr/expr = expr ] " arguments_xpath <- ".//SYMBOL_SUB[text() = 'method' or text() = 'decreasing' or text() = 'na.last']" arg_values_xpath <- glue("{arguments_xpath}/following-sibling::expr[1]") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content order_expr <- xml_find_all(xml, order_xpath) variable <- xml_text(xml_find_first( order_expr, ".//SYMBOL_FUNCTION_CALL[text() = 'order']/parent::expr[1]/following-sibling::expr[1]" )) orig_call <- sprintf("%s[%s]", variable, get_r_string(order_expr)) # Reconstruct new argument call for each expression separately arguments <- vapply(order_expr, function(e) { arg_names <- xml_text(xml_find_all(e, arguments_xpath)) arg_values <- xml_text(xml_find_all(e, arg_values_xpath)) if (!"na.last" %in% arg_names) { arg_names <- c(arg_names, "na.last") arg_values <- c(arg_values, "TRUE") } paste(arg_names, "=", arg_values, collapse = ", ") }, character(1L)) new_call <- sprintf("sort(%s, %s)", variable, arguments) order_lints <- xml_nodes_to_lints( order_expr, source_expression = source_expression, lint_message = paste0( new_call, " is better than ", orig_call, ". ", "Note that it's always preferable to save the output of order() for the same variable ", "as a local variable than to re-compute it." ), type = "warning" ) xml_calls <- source_expression$xml_find_function_calls("sort") sorted_expr <- xml_find_all(xml_calls, sorted_xpath) sorted_op <- xml_text(xml_find_first(sorted_expr, "*[2]")) lint_message <- ifelse( sorted_op == "==", "Use !is.unsorted(x) to test the sortedness of a vector.", "Use is.unsorted(x) to test the unsortedness of a vector." ) sorted_lints <- xml_nodes_to_lints( sorted_expr, source_expression = source_expression, lint_message = lint_message, type = "warning" ) c(order_lints, sorted_lints) }) } lintr/R/comparison_negation_linter.R0000644000176200001440000000504714752731051017354 0ustar liggesusers#' Block usages like !(x == y) where a direct relational operator is appropriate #' #' `!(x == y)` is more readably expressed as `x != y`. The same is true of #' other negations of simple comparisons like `!(x > y)` and `!(x <= y)`. #' #' @examples #' # will produce lints #' lint( #' text = "!x == 2", #' linters = comparison_negation_linter() #' ) #' #' lint( #' text = "!(x > 2)", #' linters = comparison_negation_linter() #' ) #' #' # okay #' lint( #' text = "!(x == 2 & y > 2)", #' linters = comparison_negation_linter() #' ) #' #' lint( #' text = "!(x & y)", #' linters = comparison_negation_linter() #' ) #' #' lint( #' text = "x != 2", #' linters = comparison_negation_linter() #' ) #' #' @evalRd rd_tags("comparison_negation_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export comparison_negation_linter <- function() { comparators <- infix_metadata$xml_tag[infix_metadata$comparator] comparator_inverses <- c(EQ = "!=", NE = "==", GE = "<", LE = ">", GT = "<=", LT = ">=") # outline # - match ! # - avoid false positives like `!!x > y` # + two conditions: one for the "outer" ! and one for the "inner" ! # - avoid false positives like !any(x > y) # - avoid false positives like !x[f == g] # - make sure to catch both !(x == y) and !x == y xpath <- glue(" //OP-EXCLAMATION /parent::expr[ not(parent::expr[OP-EXCLAMATION]) and expr[ not(expr[SYMBOL_FUNCTION_CALL] or OP-EXCLAMATION or OP-LEFT-BRACKET) and ( expr[ {xp_or(comparators)} ] or {xp_or(comparators)} ) ] ] ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) comparator_node <- xml_find_first(bad_expr, "expr/expr/*[2]") comparator_name <- xml_name(comparator_node) # "typical" case is assumed to be !(x == y), so try that first, and back # up to the less nested case. there may be a cleaner way to do this... unnested <- !comparator_name %in% names(comparator_inverses) comparator_node[unnested] <- xml_find_first(bad_expr[unnested], "expr/*[2]") comparator_name[unnested] <- xml_name(comparator_node[unnested]) comparator_text <- xml_text(comparator_node) inverse <- comparator_inverses[comparator_name] xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = glue("Use x {inverse} y, not !(x {comparator_text} y)."), type = "warning" ) }) } lintr/R/expect_length_linter.R0000644000176200001440000000266714752731051016154 0ustar liggesusers#' Require usage of `expect_length(x, n)` over `expect_equal(length(x), n)` #' #' [testthat::expect_length()] exists specifically for testing the [length()] of #' an object. [testthat::expect_equal()] can also be used for such tests, #' but it is better to use the tailored function instead. #' #' @examples #' # will produce lints #' lint( #' text = "expect_equal(length(x), 2L)", #' linters = expect_length_linter() #' ) #' #' # okay #' lint( #' text = "expect_length(x, 2L)", #' linters = expect_length_linter() #' ) #' #' @evalRd rd_tags("expect_length_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export expect_length_linter <- function() { # TODO(#2465): also catch expect_true(length(x) == 1) xpath <- sprintf(" following-sibling::expr[ expr[1][SYMBOL_FUNCTION_CALL[text() = 'length']] and (position() = 1 or preceding-sibling::expr[NUM_CONST]) ] /parent::expr[not(SYMBOL_SUB[text() = 'info' or contains(text(), 'label')])] ") Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(c("expect_equal", "expect_identical")) bad_expr <- xml_find_all(xml_calls, xpath) matched_function <- xp_call_name(bad_expr) lint_message <- sprintf("expect_length(x, n) is better than %s(length(x), n)", matched_function) xml_nodes_to_lints(bad_expr, source_expression, lint_message, type = "warning") }) } lintr/R/for_loop_index_linter.R0000644000176200001440000000212014752731051016311 0ustar liggesusers#' Block usage of for loops directly overwriting the indexing variable #' #' `for (x in x)` is a poor choice of indexing variable. This overwrites #' `x` in the calling scope and is confusing to read. #' #' @examples #' # will produce lints #' lint( #' text = "for (x in x) { TRUE }", #' linters = for_loop_index_linter() #' ) #' #' lint( #' text = "for (x in foo(x, y)) { TRUE }", #' linters = for_loop_index_linter() #' ) #' #' # okay #' lint( #' text = "for (xi in x) { TRUE }", #' linters = for_loop_index_linter() #' ) #' #' lint( #' text = "for (col in DF$col) { TRUE }", #' linters = for_loop_index_linter() #' ) #' #' @evalRd rd_tags("for_loop_index_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export for_loop_index_linter <- make_linter_from_xpath( xpath = " //forcond /SYMBOL[text() = following-sibling::expr //SYMBOL[not(parent::expr[OP-DOLLAR or OP-AT or preceding-sibling::OP-LEFT-BRACKET])] /text() ] ", lint_message = "Don't re-use any sequence symbols as the index symbol in a for loop." ) lintr/R/expect_named_linter.R0000644000176200001440000000301014752731051015736 0ustar liggesusers#' Require usage of `expect_named(x, n)` over `expect_equal(names(x), n)` #' #' [testthat::expect_named()] exists specifically for testing the [names()] of #' an object. [testthat::expect_equal()] can also be used for such tests, #' but it is better to use the tailored function instead. #' #' @examples #' # will produce lints #' lint( #' text = 'expect_equal(names(x), "a")', #' linters = expect_named_linter() #' ) #' #' # okay #' lint( #' text = 'expect_named(x, "a")', #' linters = expect_named_linter() #' ) #' #' lint( #' text = 'expect_equal(colnames(x), "a")', #' linters = expect_named_linter() #' ) #' #' lint( #' text = 'expect_equal(dimnames(x), "a")', #' linters = expect_named_linter() #' ) #' #' @evalRd rd_tags("expect_named_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export expect_named_linter <- function() { xpath <- " following-sibling::expr[ expr[1][SYMBOL_FUNCTION_CALL[text() = 'names']] and (position() = 1 or preceding-sibling::expr[STR_CONST]) ] /parent::expr " Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(c("expect_equal", "expect_identical")) bad_expr <- xml_find_all(xml_calls, xpath) matched_function <- xp_call_name(bad_expr) lint_message <- sprintf("expect_named(x, n) is better than %s(names(x), n)", matched_function) xml_nodes_to_lints(bad_expr, source_expression = source_expression, lint_message, type = "warning") }) } lintr/R/unnecessary_lambda_linter.R0000644000176200001440000001761114752731051017155 0ustar liggesusers#' Block usage of anonymous functions in iteration functions when unnecessary #' #' Using an anonymous function in, e.g., [lapply()] is not always necessary, #' e.g. `lapply(DF, sum)` is the same as `lapply(DF, function(x) sum(x))` and #' the former is more readable. #' #' Cases like `lapply(x, \(xi) grep("ptn", xi))` are excluded because, though #' the anonymous function _can_ be avoided, doing so is not always more #' readable. #' #' @param allow_comparison Logical, default `FALSE`. If `TRUE`, lambdas like #' `function(x) foo(x) == 2`, where `foo` can be extracted to the "mapping" #' function and `==` vectorized instead of called repeatedly, are linted. #' #' @examples #' # will produce lints #' lint( #' text = "lapply(list(1:3, 2:4), function(xi) sum(xi))", #' linters = unnecessary_lambda_linter() #' ) #' #' lint( #' text = "sapply(x, function(xi) xi == 2)", #' linters = unnecessary_lambda_linter() #' ) #' #' lint( #' text = "sapply(x, function(xi) sum(xi) > 0)", #' linters = unnecessary_lambda_linter() #' ) #' #' # okay #' lint( #' text = "lapply(list(1:3, 2:4), sum)", #' linters = unnecessary_lambda_linter() #' ) #' #' lint( #' text = 'lapply(x, function(xi) grep("ptn", xi))', #' linters = unnecessary_lambda_linter() #' ) #' #' lint( #' text = "lapply(x, function(xi) data.frame(col = xi))", #' linters = unnecessary_lambda_linter() #' ) #' #' lint( #' text = "sapply(x, function(xi) xi == 2)", #' linters = unnecessary_lambda_linter(allow_comparison = TRUE) #' ) #' #' lint( #' text = "sapply(x, function(xi) sum(xi) > 0)", #' linters = unnecessary_lambda_linter(allow_comparison = TRUE) #' ) #' #' lint( #' text = "sapply(x, function(xi) sum(abs(xi)) > 10)", #' linters = unnecessary_lambda_linter() #' ) #' #' lint( #' text = "sapply(x, sum) > 0", #' linters = unnecessary_lambda_linter() #' ) #' #' @evalRd rd_tags("unnecessary_lambda_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export unnecessary_lambda_linter <- function(allow_comparison = FALSE) { # include any base function like those where FUN is an argument # and ... follows positionally directly afterwards (with ... # being passed on to FUN). That excludes functions like # Filter/Reduce (which don't accept ...), as well as functions # like sweep() (where check.margin comes between FUN and ..., # and thus would need to be supplied in order to replicate # positional arguments). Technically, these latter could # be part of the linter logic (e.g., detect if the anonymous # call is using positional or keyword arguments -- we can # throw a lint for sweep() lambdas where the following arguments # are all named) but for now it seems like overkill. apply_funs <- c( "lapply", "sapply", "vapply", "apply", "tapply", "rapply", "eapply", "dendrapply", "mapply", "by", "outer", "mclapply", "mcmapply", "parApply", "parCapply", "parLapply", "parLapplyLB", "parRapply", "parSapply", "parSapplyLB", "pvec", purrr_mappers ) # OP-PLUS: condition for complex literal, e.g. 0+2i. # NB: this includes 0+3 and TRUE+FALSE, which are also fine. inner_comparison_xpath <- glue(" parent::expr /expr[FUNCTION] /expr[ ({ xp_or(infix_metadata$xml_tag[infix_metadata$comparator]) }) and expr[ expr/SYMBOL_FUNCTION_CALL and expr/SYMBOL ] and expr[ NUM_CONST or STR_CONST or (OP-PLUS and count(expr/NUM_CONST) = 2) ] ] ") # outline: # 1. match one of the identified mappers # 2. match an anonymous function that can be "symbol-ized" # a. it's a one-variable function [TODO(#2477): relax this] # b. the function is a single call # c. that call's _first_ argument is just the function argument (a SYMBOL) # - and it has to be passed positionally (not as a keyword) # d. the function argument doesn't appear elsewhere in the call default_fun_xpath <- glue(" following-sibling::expr[(FUNCTION or OP-LAMBDA) and count(SYMBOL_FORMALS) = 1] /expr[last()][ count(.//SYMBOL[self::* = preceding::SYMBOL_FORMALS[1]]) = 1 and count(.//SYMBOL_FUNCTION_CALL[text() != 'return']) = 1 and preceding-sibling::SYMBOL_FORMALS = .//expr[ position() = 2 and preceding-sibling::expr/SYMBOL_FUNCTION_CALL and not(preceding-sibling::*[1][self::EQ_SUB]) and not(parent::expr[ preceding-sibling::expr[not(SYMBOL_FUNCTION_CALL)] or following-sibling::*[not(self::OP-RIGHT-PAREN or self::OP-RIGHT-BRACE)] ]) ]/SYMBOL ] /parent::expr ") # purrr-style inline formulas-as-functions, e.g. ~foo(.x) # logic is basically the same as that above, except we need # 1. a formula (OP-TILDE) # 2. the lone argument marker `.x` or `.` purrr_symbol <- "SYMBOL[text() = '.x' or text() = '.']" purrr_fun_xpath <- glue(" following-sibling::expr[ OP-TILDE and expr[OP-LEFT-PAREN/following-sibling::expr[1][not(preceding-sibling::*[2][self::SYMBOL_SUB])]/{purrr_symbol}] and not(expr/OP-LEFT-PAREN/following-sibling::expr[position() > 1]//{purrr_symbol}) ]") # path to calling function symbol from the matched expressions fun_xpath <- "./parent::expr/expr/SYMBOL_FUNCTION_CALL" # path to the symbol of the simpler function that avoids a lambda symbol_xpath <- "expr[last()]//expr[SYMBOL_FUNCTION_CALL[text() != 'return']]" Linter(linter_level = "expression", function(source_expression) { default_calls <- source_expression$xml_find_function_calls(apply_funs) default_fun_expr <- xml_find_all(default_calls, default_fun_xpath) # TODO(#2478): Give a specific recommendation in the message. default_call_fun <- xml_text(xml_find_first(default_fun_expr, fun_xpath)) default_symbol <- xml_text(xml_find_first(default_fun_expr, symbol_xpath)) default_fun_lints <- xml_nodes_to_lints( default_fun_expr, source_expression = source_expression, lint_message = paste0( "Pass ", default_symbol, " directly as a symbol to ", default_call_fun, "() ", "instead of wrapping it in an unnecessary anonymous function. ", "For example, prefer lapply(DF, sum) to lapply(DF, function(x) sum(x))." ), type = "warning" ) inner_comparison_lints <- NULL if (!allow_comparison) { sapply_vapply_calls <- source_expression$xml_find_function_calls(c("sapply", "vapply")) inner_comparison_expr <- xml_find_all(sapply_vapply_calls, inner_comparison_xpath) mapper <- xp_call_name(xml_find_first(inner_comparison_expr, "parent::expr/parent::expr")) if (length(mapper) > 0L) fun_value <- if (mapper == "sapply") "" else ", FUN.VALUE = " inner_comparison_lints <- xml_nodes_to_lints( inner_comparison_expr, source_expression = source_expression, lint_message = sprintf( paste( "Compare to a constant after calling %1$s() to get the full benefits of vectorization.", "Prefer %1$s(x, foo%2$s) == 2 over %1$s(x, function(xi) foo(xi) == 2, logical(1L))." ), mapper, fun_value ), type = "warning" ) } purrr_calls <- source_expression$xml_find_function_calls(purrr_mappers) purrr_fun_expr <- xml_find_all(purrr_calls, purrr_fun_xpath) purrr_call_fun <- xml_text(xml_find_first(purrr_fun_expr, fun_xpath)) purrr_symbol <- xml_text(xml_find_first(purrr_fun_expr, symbol_xpath)) purrr_fun_lints <- xml_nodes_to_lints( purrr_fun_expr, source_expression = source_expression, lint_message = paste0( "Pass ", purrr_symbol, " directly as a symbol to ", purrr_call_fun, "() ", "instead of wrapping it in an unnecessary anonymous function. ", "For example, prefer purrr::map(DF, sum) to purrr::map(DF, ~sum(.x))." ), type = "warning" ) c(default_fun_lints, inner_comparison_lints, purrr_fun_lints) }) } lintr/R/ids_with_token.R0000644000176200001440000000312614752731051014747 0ustar liggesusers#' Get parsed IDs by token #' #' Gets the source IDs (row indices) corresponding to given token. #' #' @param source_expression A list of source expressions, the result of a call to [get_source_expressions()], #' for the desired filename. #' @param value Character. String corresponding to the token to search for. #' For example: #' #' * "SYMBOL" #' * "FUNCTION" #' * "EQ_FORMALS" #' * "$" #' * "(" #' #' @param fun For additional flexibility, a function to search for in #' the `token` column of `parsed_content`. Typically `==` or `%in%`. #' @param source_file (DEPRECATED) Same as `source_expression`. Will be removed. #' #' @examples #' tmp <- tempfile() #' writeLines(c("x <- 1", "y <- x + 1"), tmp) #' source_exprs <- get_source_expressions(tmp) #' ids_with_token(source_exprs$expressions[[1L]], value = "SYMBOL") #' with_id(source_exprs$expressions[[1L]], 2L) #' unlink(tmp) #' #' @return `ids_with_token`: The indices of the `parsed_content` data frame #' entry of the list of source expressions. Indices correspond to the #' *rows* where `fun` evaluates to `TRUE` for the `value` in the *token* column. #' @export ids_with_token <- function(source_expression, value, fun = `==`, source_file = NULL) { if (!missing(source_file)) { lintr_deprecated( what = "source_file", alternative = "source_expression", version = "3.0.0", type = "Argument", signal = "stop" ) } if (!is_lint_level(source_expression, "expression")) { return(integer()) } loc <- which(fun(source_expression$parsed_content$token, value)) if (loc %==% integer()) { return(integer()) } loc } lintr/R/missing_package_linter.R0000644000176200001440000000363314752731051016441 0ustar liggesusers#' Missing package linter #' #' Check for missing packages in `library()`, `require()`, `loadNamespace()`, and `requireNamespace()` calls. #' #' @examples #' # will produce lints #' lint( #' text = "library(xyzxyz)", #' linters = missing_package_linter() #' ) #' #' # okay #' lint( #' text = "library(stats)", #' linters = missing_package_linter() #' ) #' #' @evalRd rd_tags("missing_package_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export missing_package_linter <- function() { library_require_xpath <- " parent::expr[ expr[2][STR_CONST] or ( expr[2][SYMBOL] and not( SYMBOL_SUB[text() = 'character.only'] /following-sibling::expr[1] /NUM_CONST[text() = 'TRUE' or text() = 'T'] ) ) ]" load_require_namespace_xpath <- " following-sibling::expr[1][STR_CONST] /parent::expr " Linter(linter_level = "file", function(source_expression) { library_require_calls <- source_expression$xml_find_function_calls(c("library", "require")) load_require_namespace_calls <- source_expression$xml_find_function_calls(c("loadNamespace", "requireNamespace")) pkg_calls <- combine_nodesets( xml_find_all(library_require_calls, library_require_xpath), xml_find_all(load_require_namespace_calls, load_require_namespace_xpath) ) pkg_names <- get_r_string(xml_find_all( pkg_calls, "OP-LEFT-PAREN[1]/following-sibling::expr[1][SYMBOL | STR_CONST]" )) # run here, not in the factory, to allow for run- vs. "compile"-time differences in available packages installed_packges <- .packages(all.available = TRUE) missing_pkgs <- !(pkg_names %in% installed_packges) xml_nodes_to_lints( pkg_calls[missing_pkgs], source_expression = source_expression, lint_message = sprintf("Package '%s' is not installed.", pkg_names[missing_pkgs]), type = "warning" ) }) } lintr/R/expect_lint.R0000644000176200001440000001235014752731051014252 0ustar liggesusers#' Lint expectation #' #' These are expectation functions to test specified linters on sample code in the `testthat` testing framework. #' * `expect_lint` asserts that specified lints are generated. #' * `expect_no_lint` asserts that no lints are generated. #' #' @param content a character vector for the file content to be linted, each vector element representing a line of #' text. #' @param checks checks to be performed: #' \describe{ #' \item{NULL}{check that no lints are returned.} #' \item{single string or regex object}{check that the single lint returned has a matching message.} #' \item{named list}{check that the single lint returned has fields that match. Accepted fields are the same as those #' taken by [Lint()].} #' \item{list of named lists}{for each of the multiple lints returned, check that it matches the checks in the #' corresponding named list (as described in the point above).} #' } #' Named vectors are also accepted instead of named lists, but this is a compatibility feature that #' is not recommended for new code. #' @param ... arguments passed to [lint()], e.g. the linters or cache to use. #' @param file if not `NULL`, read content from the specified file rather than from `content`. #' @param language temporarily override Rs `LANGUAGE` envvar, controlling localization of base R error messages. #' This makes testing them reproducible on all systems irrespective of their native R language setting. #' @return `NULL`, invisibly. #' @examples #' # no expected lint #' expect_no_lint("a", trailing_blank_lines_linter()) #' #' # one expected lint #' expect_lint("a\n", "trailing blank", trailing_blank_lines_linter()) #' expect_lint("a\n", list(message = "trailing blank", line_number = 2), trailing_blank_lines_linter()) #' #' # several expected lints #' expect_lint("a\n\n", list("trailing blank", "trailing blank"), trailing_blank_lines_linter()) #' expect_lint( #' "a\n\n", #' list( #' list(message = "trailing blank", line_number = 2), #' list(message = "trailing blank", line_number = 3) #' ), #' trailing_blank_lines_linter() #' ) #' @export expect_lint <- function(content, checks, ..., file = NULL, language = "en") { if (!requireNamespace("testthat", quietly = TRUE)) { # nocov start cli_abort( # nolint next: line_length_linter. "{.fun expect_lint} and {.fun expect_no_lint} are designed to work within the {.pkg testthat} testing framework, which is not installed." ) # nocov end } old_lang <- set_lang(language) on.exit(reset_lang(old_lang)) if (is.null(file)) { file <- tempfile() on.exit(unlink(file), add = TRUE) local({ con <- base::file(file, encoding = "UTF-8") on.exit(close(con)) writeLines(content, con = con, sep = "\n") }) } lints <- lint(file, ...) n_lints <- length(lints) lint_str <- if (n_lints) paste(c("", lints), collapse = "\n") else "" wrong_number_fmt <- "got %d lints instead of %d%s" if (is.null(checks)) { msg <- sprintf(wrong_number_fmt, n_lints, length(checks), lint_str) return(testthat::expect(n_lints %==% 0L, msg)) } if (!is.list(checks) || !is.null(names(checks))) { # vector or named list checks <- list(checks) } checks[] <- lapply(checks, fix_names, "message") if (n_lints != length(checks)) { msg <- sprintf(wrong_number_fmt, n_lints, length(checks), lint_str) return(testthat::expect(FALSE, msg)) } local({ itr <- 0L # keep 'linter' as a field even if we remove the deprecated argument from Lint() in the future lint_fields <- unique(c(names(formals(Lint)), "linter")) Map( function(lint, check) { itr <<- itr + 1L lapply(names(check), function(field) { if (!field %in% lint_fields) { cli_abort(c( x = "Check {.val {itr}} has an invalid field: {.field {field}}.", i = "Valid fields are: {.field {lint_fields}}." )) } check <- check[[field]] value <- lint[[field]] msg <- sprintf( "check #%d: %s %s did not match %s", itr, field, deparse(value), deparse(check) ) # deparse ensures that NULL, list(), etc are handled gracefully ok <- if (field == "message") { re_matches_logical(value, check) } else { isTRUE(all.equal(value, check)) } testthat::expect(ok, msg) }) }, lints, checks ) }) invisible(NULL) } #' @rdname expect_lint #' @export expect_no_lint <- function(content, ..., file = NULL, language = "en") { expect_lint(content, NULL, ..., file = file, language = language) } #' Test that the package is lint free #' #' This function is a thin wrapper around lint_package that simply tests there are no #' lints in the package. It can be used to ensure that your tests fail if the package #' contains lints. #' #' @param ... arguments passed to [lint_package()] #' @export expect_lint_free <- function(...) { testthat::skip_on_cran() testthat::skip_on_covr() lints <- lint_package(...) has_lints <- length(lints) > 0L lint_output <- NULL if (has_lints) { lint_output <- format(lints) } result <- testthat::expect( !has_lints, paste0("Not lint free\n", lint_output) ) invisible(result) } lintr/R/get_source_expressions.R0000644000176200001440000005727614752731051016555 0ustar liggesusers#' Parsed sourced file from a filename #' #' This object is given as input to each linter. #' #' @details #' The file is read using the `encoding` setting. #' This setting is found by taking the first valid result from the following locations #' #' 1. The `encoding` key from the usual lintr configuration settings. #' 2. The `Encoding` field from a Package `DESCRIPTION` file in a parent directory. #' 3. The `Encoding` field from an R Project `.Rproj` file in a parent directory. #' 4. `"UTF-8"` as a fallback. #' #' @param filename the file to be parsed. #' @param lines a character vector of lines. #' If `NULL`, then `filename` will be read. #' @return A `list` with three components: #' \describe{ #' \item{expressions}{a `list` of #' `n+1` objects. The first `n` elements correspond to each expression in #' `filename`, and consist of a list of 8 elements: #' \itemize{ #' \item{`filename` (`character`) the name of the file.} #' \item{`line` (`integer`) the line in the file where this expression begins.} #' \item{`column` (`integer`) the column in the file where this expression begins.} #' \item{`lines` (named `character`) vector of all lines spanned by this #' expression, named with the corresponding line numbers.} #' \item{`parsed_content` (`data.frame`) as given by [utils::getParseData()] for this expression.} #' \item{`xml_parsed_content` (`xml_document`) the XML parse tree of this expression as given by #' [xmlparsedata::xml_parse_data()].} #' \item{`content` (`character`) the same as `lines` as a single string (not split across lines).} #' \item{`xml_find_function_calls(function_names)` (`function`) a function that returns all `SYMBOL_FUNCTION_CALL` #' XML nodes from `xml_parsed_content` with specified function names.} #' } #' #' The final element of `expressions` is a list corresponding to the full file #' consisting of 7 elements: #' \itemize{ #' \item{`filename` (`character`) the name of this file.} #' \item{`file_lines` (`character`) the [readLines()] output for this file.} #' \item{`content` (`character`) for .R files, the same as `file_lines`; #' for .Rmd or .qmd scripts, this is the extracted R source code (as text).} #' \item{`full_parsed_content` (`data.frame`) as given by #' [utils::getParseData()] for the full content.} #' \item{`full_xml_parsed_content` (`xml_document`) the XML parse tree of all #' expressions as given by [xmlparsedata::xml_parse_data()].} #' \item{`terminal_newline` (`logical`) records whether `filename` has a terminal #' newline (as determined by [readLines()] producing a corresponding warning).} #' \item{`xml_find_function_calls(function_names)` (`function`) a function that returns all `SYMBOL_FUNCTION_CALL` #' XML nodes from `full_xml_parsed_content` with specified function names.} #' } #' } #' \item{error}{A `Lint` object describing any parsing error.} #' \item{lines}{The [readLines()] output for this file.} #' } #' #' @examples #' tmp <- tempfile() #' writeLines(c("x <- 1", "y <- x + 1"), tmp) #' get_source_expressions(tmp) #' unlink(tmp) #' @export get_source_expressions <- function(filename, lines = NULL) { source_expression <- srcfile(filename, encoding = settings$encoding) # Ensure English locale for terminal newline and zero-length variable warning messages old_lang <- set_lang("en") on.exit(reset_lang(old_lang)) source_expression$lines <- if (is.null(lines)) { read_lines(filename) } else { lines } # Only regard explicit attribute terminal_newline=FALSE as FALSE and all other cases (e.g. NULL or TRUE) as TRUE. terminal_newline <- !isFALSE(attr(source_expression$lines, "terminal_newline", exact = TRUE)) e <- NULL source_expression$lines <- extract_r_source( filename = source_expression$filename, lines = source_expression$lines, error = function(e) lint_rmd_error(e, source_expression) ) names(source_expression$lines) <- seq_along(source_expression$lines) source_expression$content <- get_content(source_expression$lines) parsed_content <- get_source_expression(source_expression, error = function(e) lint_parse_error(e, source_expression)) if (is_lint(e) && (is.na(e$line) || !nzchar(e$line) || e$message == "unexpected end of input")) { # Don't create expression list if it's unreliable (invalid encoding or unhandled parse error) expressions <- list() } else { top_level_map <- generate_top_level_map(parsed_content) xml_parsed_content <- safe_parse_to_xml(parsed_content) expressions <- lapply( X = top_level_expressions(parsed_content), FUN = get_single_source_expression, parsed_content, source_expression, filename, top_level_map ) if (!is.null(xml_parsed_content) && !is.na(xml_parsed_content)) { expression_xmls <- lapply( xml_find_all(xml_parsed_content, "/exprlist/*"), function(top_level_expr) xml2::xml_add_parent(xml2::xml_new_root(top_level_expr), "exprlist") ) for (i in seq_along(expressions)) { expressions[[i]]$xml_parsed_content <- expression_xmls[[i]] expressions[[i]]$xml_find_function_calls <- build_xml_find_function_calls(expression_xmls[[i]]) } } # add global expression expressions[[length(expressions) + 1L]] <- list( filename = filename, file_lines = source_expression$lines, content = source_expression$lines, full_parsed_content = parsed_content, full_xml_parsed_content = xml_parsed_content, xml_find_function_calls = build_xml_find_function_calls(xml_parsed_content), terminal_newline = terminal_newline ) } list(expressions = expressions, error = e, lines = source_expression$lines) } lint_parse_error <- function(e, source_expression) { # R >= 4.3.0 if (inherits(e, "parseError")) { return(lint_parse_error_r43(e, source_expression)) } message_info <- re_matches( e$message, rex( except_some_of(":"), ":", capture(name = "line", digits), ":", capture(name = "column", digits), ":", space, capture(name = "message", anything), "\n" ) ) if (!is.na(message_info$line)) { return(lint_parse_error_r42(message_info, source_expression)) } # an error that does not use R_ParseErrorMsg lint_parse_error_nonstandard(e, source_expression) } #' Ensure a string is valid for printing #' #' Helper to ensure a valid string is provided as line where necessary. #' Handles two cases: #' #' 1. NA lines, as generated by running outside of code blocks in Rmd documents #' 2. invalid string lines, as generated by invalid encoding settings #' #' [nchar()] can detect both cases: 1. returns `NA_integer_`, 2. errors #' #' @param line Possibly misencoded or NA line #' #' @return `line` if it's a valid non-NA string, otherwise an empty string. #' #' @noRd fixup_line <- function(line) { nchars <- tryCatch(nchar(line, type = "chars"), error = function(e) NA_integer_) if (is.na(nchars)) { "" } else { line } } #' Convert an R >= 4.3.0 classed parseError with metadata into a lint #' #' @param e A parse error of class `parseError` generated by R >= 4.3.0 #' @param source_expression The source expression that generated the parse error #' #' @return A [Lint()] based on the metadata attached to `e`. #' #' @noRd lint_parse_error_r43 <- function(e, source_expression) { msg <- re_substitutes(e$message, rex(" (", except_some_of(")"), ")", end), "") line_number <- e$lineno column <- e$colno substr(msg, 1L, 1L) <- toupper(substr(msg, 1L, 1L)) msg <- paste0(msg, ".") if (inherits(e, "invalidMBCS")) { msg <- paste(msg, "Is the encoding correct?") } if (column == 0L) { line_number <- line_number - 1L } if (line_number < 1L || line_number > length(source_expression$lines)) { # Safely handle invalid location info line_number <- 1L column <- 1L } line <- fixup_line(source_expression$lines[[line_number]]) if (column == 0L || column > nchar(line) + 1L) { column <- nchar(line) + 1L } Lint( filename = source_expression$filename, line_number = line_number, column_number = column, type = "error", message = msg, line = line ) } #' Convert a R < 4.3.0 standard parse error message into a lint #' #' @param message_info Match of the structured parse error message regex, matched in [lint_parse_error()] #' @param source_expression The source expression that generated the parse error #' #' @return A [Lint()] based on text mining of the error message captured by `message_info`, #' #' @noRd lint_parse_error_r42 <- function(message_info, source_expression) { line_number <- as.integer(message_info$line) column_number <- as.integer(message_info$column) # If the column number is zero it means the error really occurred at the # end of the previous line if (column_number %==% 0L) { line_number <- line_number - 1L line <- fixup_line(source_expression$lines[[line_number]]) column_number <- nchar(line) + 1L } else { line <- fixup_line(source_expression$lines[[line_number]]) } Lint( filename = source_expression$filename, line_number = line_number, column_number = column_number, type = "error", message = message_info$message, line = line ) } #' Convert a R < 4.3.0 non-standard parse error message into a lint #' #' Uses a hand-crafted regex and some heuristics to find location information, falling back to Line 1, Column 1 if all #' attempts fail. #' #' @param e A parse error that doesn't fit the standard `message_info` regex used for most parse errors in R < 4.3.0 #' @param source_expression The source expression that generated the parse error #' #' @return A [Lint()] based on trying to extract information from the error message of `e`. #' #' @noRd lint_parse_error_nonstandard <- function(e, source_expression) { if (grepl("invalid multibyte character in parser at line", e$message, fixed = TRUE)) { # nocov start: platform-specific l <- as.integer(re_matches( e$message, rex("invalid multibyte character in parser at line ", capture(name = "line", digits)) )$line) # Invalid encoding in source code return( Lint( filename = source_expression$filename, line_number = l, column_number = 1L, type = "error", message = "Invalid multibyte character in parser. Is the encoding correct?", line = fixup_line(source_expression$lines[[l]]) ) ) # nocov end } else if (grepl("invalid multibyte string, element", e$message, fixed = TRUE)) { # Invalid encoding, will break even re_matches() below, so we need to handle this first. return( Lint( filename = source_expression$filename, line_number = 1L, column_number = 1L, type = "error", message = "Invalid multibyte string. Is the encoding correct?", line = "" ) ) } else if (grepl("repeated formal argument", e$message, fixed = TRUE)) { # nocov start: only throws on certain versions; tested on L389 matches <- re_matches( e$message, rex( "repeated formal argument '", capture(name = "symbol", anything), "' on line ", capture(name = "line", digits) ) ) sym <- matches$symbol l <- as.integer(matches$line) # Repeated formal argument 'sym' on line l return( Lint( filename = source_expression$filename, line_number = l, column_number = 1L, type = "error", message = sprintf("Repeated formal argument '%s'.", sym), line = fixup_line(source_expression$lines[[l]]) ) ) # nocov end } # Hand-crafted regex to parse all error messages generated by the R parser code for R < 4.3. # The error messages can be found in src/main/gram.c and src/main/character.c in the R code. # This code produces a list of all possible error messages: # # nolint start: commented_code_linter. # parser_files <- c("src/main/gram.c", "src/main/character.c") # # lines <- unlist(lapply( # file.path("https://raw.githubusercontent.com/wch/r-source/trunk", parser_files), # readLines # )) # error_calls <- grep("error(_(", lines, fixed = TRUE, value = TRUE) # error_formats <- trimws(gsub("^.*error\\(_\\(\"(.+)\".+", "\\1", error_calls)) # error_formats <- unique(error_formats) # nolint end parse_error_rx <- rex( start, capture(anything, name = "msg_1"), or(" at ", " on ", " ("), "line ", capture(digits, name = "line"), maybe(")"), capture(anything, name = "msg_2"), end ) if (grepl(parse_error_rx, e$message, perl = TRUE)) { # nocov start: only throws on certain versions. Tested on L396: Nul character not allowed rx_match <- re_matches( e$message, parse_error_rx ) l <- as.integer(rx_match$line) # Sometimes the parser "line" runs one past the last line l <- pmin(l, length(source_expression$lines)) msg <- paste0(rx_match$msg_1, if (nzchar(rx_match$msg_2)) " ", rx_match$msg_2, ".") substr(msg, 1L, 1L) <- toupper(substr(msg, 1L, 1L)) return( Lint( filename = source_expression$filename, line_number = l, column_number = 1L, type = "error", message = msg, line = source_expression$lines[[l]] ) ) # nocov end } message_info <- re_matches( e$message, rex( single_quotes, capture(name = "name", anything), single_quotes, anything, double_quotes, capture(name = "starting", anything), double_quotes ) ) loc <- re_matches(source_expression$content, rex(message_info$starting), locations = TRUE) line_location <- loc[!is.na(loc$start) & !is.na(loc$end), ] if (nrow(line_location) == 0L) { if (grepl("attempt to use zero-length variable name", e$message, fixed = TRUE)) { # empty symbol: ``, ``(), ''(), ""(), fun(''=42), fun(""=42), fun(a=1,""=42) loc <- re_matches( source_expression$content, rex( "``" %or% list(or("''", '""'), any_spaces, "(") %or% list(or("(", ","), any_spaces, or("''", '""'), any_spaces, "=") ), options = "multi-line", locations = TRUE ) loc <- loc[!is.na(loc$start) & !is.na(loc$end), ] if (nrow(loc) > 0L) { line_location <- loc[1L, ] } } else { # nocov start return( Lint( filename = source_expression$filename, line_number = 1L, column_number = 1L, type = "error", message = e$message, line = "" ) ) # nocov end } } newline_locs <- get_newline_locs(source_expression$content) line_number <- which(newline_locs >= line_location$start)[1L] - 1L column_number <- line_location$start - newline_locs[line_number] Lint( filename = source_expression$filename, line_number = line_number, column_number = column_number, type = "error", message = e$message, line = source_expression$lines[[line_number]] ) } lint_rmd_error <- function(e, source_expression) { message_info <- re_matches( e$message, rex( except_some_of(":"), ":", capture(name = "line", digits), ":", capture(name = "column", digits), ":", space, capture(name = "message", anything), "\n" ) ) line_number <- as.integer(message_info$line) column_number <- as.integer(message_info$column) Lint( filename = source_expression$filename, line_number = line_number, column_number = column_number, type = "error", message = message_info$message, line = source_expression$lines[line_number] ) } get_single_source_expression <- function(loc, parsed_content, source_expression, filename, top_level_map) { line_nums <- parsed_content$line1[loc]:parsed_content$line2[loc] expr_lines <- source_expression$lines[line_nums] names(expr_lines) <- line_nums content <- get_content(source_expression$lines, parsed_content[loc, ]) id <- parsed_content$id[loc] pc <- parsed_content[which(top_level_map == id), ] list( filename = filename, line = parsed_content[loc, "line1"], column = parsed_content[loc, "col1"], lines = expr_lines, parsed_content = pc, xml_parsed_content = xml2::xml_missing(), # Placeholder for xml_find_function_calls, if needed (e.g. on R <= 4.0.5 with input source "\\") xml_find_function_calls = build_xml_find_function_calls(xml2::xml_missing()), content = content ) } get_source_expression <- function(source_expression, error = identity) { parse_error <- FALSE parsed_content <- tryCatch( parse( text = source_expression$content, srcfile = source_expression, keep.source = TRUE ), error = error ) if (is_error(parsed_content) || is_lint(parsed_content)) { assign("e", parsed_content, envir = parent.frame()) parse_error <- TRUE } # Triggers an error if the lines contain invalid characters. parsed_content <- tryCatch( nchar(source_expression$content, type = "chars"), error = error ) if (is_error(parsed_content) || is_lint(parsed_content)) { # Let parse errors take precedence over encoding problems if (!parse_error) assign("e", parsed_content, envir = parent.frame()) return() # parsed_content is unreliable if encoding is invalid } source_expression$parsed_content <- parsed_content fix_octal_escapes(fix_eq_assigns(fix_tab_indentations(source_expression)), source_expression$lines) } get_newline_locs <- function(x) { newline_search <- re_matches(x, rex("\n"), locations = TRUE, global = TRUE)[[1L]]$start c( 0L, if (!is.na(newline_search[1L])) newline_search, nchar(x) + 1L ) } # Fix column numbers when there are tabs # getParseData() counts 1 tab as a variable number of spaces instead of one: # https://github.com/wch/r-source/blame/e7401b68ab0e032fce3e376aaca9a5431619b2b4/src/main/gram.y#L512 # The number of spaces is so that the code is brought to the next 8-character indentation level e.g.: # "1\t;" --> "1 ;" # "12\t;" --> "12 ;" # "123\t;" --> "123 ;" # "1234\t;" --> "1234 ;" # "12345\t;" --> "12345 ;" # "123456\t;" --> "123456 ;" # "1234567\t;" --> "1234567 ;" # "12345678\t;" --> "12345678 ;" # "123456789\t;" --> "123456789 ;" # "1234567890\t;" --> "1234567890 ;" fix_tab_indentations <- function(source_expression) { parse_data <- getParseData(source_expression) if (is.null(parse_data)) { return(NULL) } tab_cols <- gregexpr("\t", source_expression[["lines"]], fixed = TRUE) names(tab_cols) <- seq_along(tab_cols) matched_lines <- vapply(tab_cols, function(line_match) !is.na(line_match[1L]) && line_match[1L] > 0L, logical(1L)) if (!any(matched_lines)) { return(parse_data) } tab_cols <- tab_cols[matched_lines] fix_columns <- c("line1", "line2", "col1", "col2") parse_data[, fix_columns] <- fix_tab_columns(parse_data[, fix_columns], tab_cols) parse_data } fix_tab_columns <- function(parse_content, tab_cols) { dat <- cbind( c(parse_content$line1, parse_content$line2), c(parse_content$col1, parse_content$col2) ) lines <- as.integer(names(tab_cols)) for (i in seq_along(tab_cols)) { is_curr_line <- dat[, 1L] == lines[[i]] if (!any(is_curr_line)) { next } tab_col <- tab_cols[[i]] line_tab_offsets <- tab_offsets(tab_col) for (j in seq_along(tab_col)) { is_line_to_change <- is_curr_line & dat[, 2L] > tab_col[[j]] if (any(is_line_to_change)) { dat[is_line_to_change, 2L] <- dat[is_line_to_change, 2L] - line_tab_offsets[[j]] } } } dat } tab_offsets <- function(tab_columns) { cum_offset <- 0L vapply( tab_columns - 1L, function(tab_idx) { # nolint next: object_overwrite_linter. 'offset' is a perfect name here. offset <- 7L - (tab_idx + cum_offset) %% 8L # using a tab width of 8 characters cum_offset <<- cum_offset + offset offset }, integer(1L), USE.NAMES = FALSE ) } # This function wraps equal assign expressions in a parent expression so they # are the same as the corresponding <- expression fix_eq_assigns <- function(pc) { if (is.null(pc) || any(c("equal_assign", "expr_or_assign_or_help") %in% pc$token)) { return(pc) } eq_assign_locs <- which(pc$token == "EQ_ASSIGN") # check whether the equal-assignment is the final entry if (length(eq_assign_locs) == 0L || tail(eq_assign_locs, 1L) == nrow(pc)) { return(pc) } prev_locs <- vapply(eq_assign_locs, prev_with_parent, pc = pc, integer(1L)) next_locs <- vapply(eq_assign_locs, next_with_parent, pc = pc, integer(1L)) expr_locs <- prev_locs != lag(next_locs) expr_locs[is.na(expr_locs)] <- TRUE id_itr <- max(pc$id) true_locs <- which(expr_locs) n_expr <- length(true_locs) supplemental_content <- data.frame( line1 = integer(n_expr), col1 = integer(n_expr), line2 = integer(n_expr), col2 = integer(n_expr), id = integer(n_expr), parent = integer(n_expr), token = character(n_expr), terminal = logical(n_expr), text = character(n_expr) ) for (i in seq_len(n_expr)) { start_loc <- true_locs[i] end_loc <- true_locs[i] prev_loc <- prev_locs[start_loc] next_loc <- next_locs[end_loc] id_itr <- id_itr + 1L supplemental_content[i, ] <- list( pc[prev_loc, "line1"], pc[prev_loc, "col1"], pc[next_loc, "line2"], pc[next_loc, "col2"], id_itr, pc[eq_assign_locs[true_locs[i]], "parent"], "expr", # R now uses "equal_assign" FALSE, "" ) new_parent_locs <- c( prev_locs[start_loc:end_loc], eq_assign_locs[start_loc:end_loc], next_locs[start_loc:end_loc], next_loc ) pc[new_parent_locs, "parent"] <- id_itr } rownames(supplemental_content) <- supplemental_content$id res <- rbind(pc, supplemental_content) res[order(res$line1, res$col1, res$line2, res$col2, res$id), ] } step_with_parent <- function(pc, loc, offset) { id <- pc$id[loc] parent_id <- pc$parent[loc] with_parent <- pc[pc$parent == parent_id, ] with_parent <- with_parent[order(with_parent$line1, with_parent$col1, with_parent$line2, with_parent$col2), ] loc <- which(with_parent$id == id) which(pc$id == with_parent$id[loc + offset]) } prev_with_parent <- function(pc, loc) step_with_parent(pc, loc, offset = -1L) next_with_parent <- function(pc, loc) step_with_parent(pc, loc, offset = 1L) top_level_expressions <- function(pc) { if (is.null(pc)) { return(integer(0L)) } which(pc$parent <= 0L) } # workaround for bad parse data bug for octal escapes # https://bugs.r-project.org/show_bug.cgi?id=18323 fix_octal_escapes <- function(pc, lines) { # subset first to prevent using nchar() on MBCS input is_str_const <- pc$token == "STR_CONST" str_const <- pc[is_str_const, ] str_const_mismatch <- str_const$col2 - str_const$col1 != nchar(str_const$text) - 1L if (!any(str_const_mismatch)) { return(pc) } str_const <- str_const[str_const_mismatch, ] out <- character(nrow(str_const)) single_line <- str_const$line1 == str_const$line2 out[single_line] <- substr( lines[str_const$line1[single_line]], str_const$col1[single_line], str_const$col2[single_line] ) for (ii in which(!single_line)) { out[ii] <- paste( c( substring(lines[str_const$line1[ii]], str_const$col1[ii]), if (str_const$line1[ii] < str_const$line2[ii] - 1L) { lines[(str_const$line1[ii] + 1L):(str_const$line2[ii] - 1L)] }, substr(lines[str_const$line2[ii]], 1L, str_const$col2[ii]) ), collapse = "\n" ) } pc$text[is_str_const][str_const_mismatch] <- out pc } lintr/R/absolute_path_linter.R0000644000176200001440000000200014752731051016132 0ustar liggesusers#' Absolute path linter #' #' Check that no absolute paths are used (e.g. "/var", "C:\\System", "~/docs"). #' #' @param lax Less stringent linting, leading to fewer false positives. #' If `TRUE`, only lint path strings, which #' #' * contain at least two path elements, with one having at least two characters and #' * contain only alphanumeric chars (including UTF-8), spaces, and win32-allowed punctuation #' #' @examples #' # will produce lints #' lint( #' text = 'R"--[/blah/file.txt]--"', #' linters = absolute_path_linter() #' ) #' #' # okay #' lint( #' text = 'R"(./blah)"', #' linters = absolute_path_linter() #' ) #' #' @evalRd rd_tags("absolute_path_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - [nonportable_path_linter()] #' @export absolute_path_linter <- function(lax = TRUE) { path_linter_factory( path_function = function(path) { is_absolute_path(path) && is_valid_long_path(path, lax) }, message = "Do not use absolute paths." ) } lintr/R/commented_code_linter.R0000644000176200001440000000534214752731051016261 0ustar liggesusers#' Commented code linter #' #' Check that there is no commented code outside roxygen blocks. #' #' @examples #' # will produce lints #' lint( #' text = "# x <- 1", #' linters = commented_code_linter() #' ) #' #' lint( #' text = "x <- f() # g()", #' linters = commented_code_linter() #' ) #' #' lint( #' text = "x + y # + z[1, 2]", #' linters = commented_code_linter() #' ) #' #' # okay #' lint( #' text = "x <- 1; x <- f(); x + y", #' linters = commented_code_linter() #' ) #' #' lint( #' text = "#' x <- 1", #' linters = commented_code_linter() #' ) #' #' @evalRd rd_tags("commented_code_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export commented_code_linter <- function() { ops <- list( "+", # "-", "=", "==", "!=", "<=", ">=", "<-", "<<-", "<", ">", "->", "->>", "%%", "/", "^", "*", "**", "|", "||", "&", "&&", rex("%", except_any_of("%"), "%") ) code_candidate_regex <- rex( some_of("#"), any_spaces, capture( name = "code", anything, or( some_of("{}[]"), # code-like parentheses or(ops), # any operator group(graphs, "(", anything, ")"), # a function call group("!", alphas) # a negation ), anything ) ) Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content all_comment_nodes <- xml_find_all(xml, "//COMMENT") all_comments <- xml_text(all_comment_nodes) code_candidates <- re_matches(all_comments, code_candidate_regex, global = FALSE, locations = TRUE) extracted_code <- code_candidates[, "code"] # ignore trailing ',' or pipes ('|>', '%>%') when testing for parsability extracted_code <- re_substitutes(extracted_code, rex(or(",", "|>", "%>%"), any_spaces, end), "") extracted_code <- re_substitutes(extracted_code, rex(start, any_spaces, ","), "") is_parsable <- which(vapply(extracted_code, parsable, logical(1L))) lint_list <- xml_nodes_to_lints( all_comment_nodes[is_parsable], source_expression = source_expression, lint_message = "Remove commented code." ) # Location info needs updating for (i in seq_along(lint_list)) { rng <- lint_list[[i]]$ranges[[1L]] rng[2L] <- rng[1L] + code_candidates[is_parsable[i], "code.end"] - 1L rng[1L] <- rng[1L] + code_candidates[is_parsable[i], "code.start"] - 1L lint_list[[i]]$column_number <- rng[1L] lint_list[[i]]$ranges <- list(rng) } lint_list }) } # is given text parsable parsable <- function(x) { if (anyNA(x)) { return(FALSE) } res <- try_silently(parse(text = x)) !inherits(res, "try-error") } lintr/R/undesirable_operator_linter.R0000644000176200001440000000547114752731051017527 0ustar liggesusers#' Undesirable operator linter #' #' Report the use of undesirable operators, e.g. \code{\link[base:ns-dblcolon]{:::}} or #' [`<<-`][base::assignOps] and suggest an alternative. #' #' @param op Named character vector. `names(op)` correspond to undesirable operators, #' while the values give a description of why the operator is undesirable. #' If `NA`, no additional information is given in the lint message. Defaults to #' [default_undesirable_operators]. To make small customizations to this list, #' use [modify_defaults()]. #' #' @examples #' # defaults for which functions are considered undesirable #' names(default_undesirable_operators) #' #' # will produce lints #' lint( #' text = "a <<- log(10)", #' linters = undesirable_operator_linter() #' ) #' #' lint( #' text = "mtcars$wt", #' linters = undesirable_operator_linter(op = c("$" = "As an alternative, use the `[[` accessor.")) #' ) #' #' # okay #' lint( #' text = "a <- log(10)", #' linters = undesirable_operator_linter() #' ) #' lint( #' text = 'mtcars[["wt"]]', #' linters = undesirable_operator_linter(op = c("$" = NA)) #' ) #' #' lint( #' text = 'mtcars[["wt"]]', #' linters = undesirable_operator_linter(op = c("$" = "As an alternative, use the `[[` accessor.")) #' ) #' #' @evalRd rd_tags("undesirable_operator_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export undesirable_operator_linter <- function(op = default_undesirable_operators) { if (is.null(names(op)) || !all(nzchar(names(op))) || length(op) == 0L) { cli_abort(c( x = "{.arg op} should be a non-empty named character vector.", i = "Use missing elements to indicate default messages." )) } # infix must be handled individually below; non-assignment `=` are always OK operator_nodes <- infix_metadata$xml_tag_exact[ infix_metadata$string_value %in% setdiff(names(op), "%%") & !infix_metadata$xml_tag %in% c("EQ_SUB", "EQ_FORMALS") ] is_infix <- startsWith(names(op), "%") if (any(is_infix)) { operator_nodes <- c(operator_nodes, sprintf("SPECIAL[text() = '%s']", names(op)[is_infix])) } if (length(operator_nodes) == 0L) { cli_abort("Did not recognize any valid operators in request for: {.str {names(op)}}") } xpath <- paste(paste0("//", operator_nodes), collapse = " | ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_op <- xml_find_all(xml, xpath) operator <- xml_text(bad_op) lint_message <- sprintf("Avoid undesirable operator `%s`.", operator) alternative <- op[operator] has_alternative <- !is.na(alternative) lint_message[has_alternative] <- paste(lint_message[has_alternative], alternative[has_alternative]) xml_nodes_to_lints(bad_op, source_expression, lint_message, type = "warning") }) } lintr/R/unused_import_linter.R0000644000176200001440000001074314752731051016212 0ustar liggesusers#' Check that imported packages are actually used #' #' @inheritParams object_usage_linter #' @param allow_ns_usage Suppress lints for packages only used via namespace. #' This is `FALSE` by default because `pkg::fun()` doesn't require `library(pkg)`. #' You can use [requireNamespace("pkg")][requireNamespace()] to ensure a package is #' installed without attaching it. #' @param except_packages Character vector of packages that are ignored. #' These are usually attached for their side effects. #' #' @examples #' # will produce lints #' code_lines <- "library(dplyr)\n1 + 1" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unused_import_linter() #' ) #' #' code_lines <- "library(dplyr)\ndplyr::tibble(a = 1)" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unused_import_linter() #' ) #' #' # okay #' code_lines <- "library(dplyr)\ntibble(a = 1)" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unused_import_linter() #' ) #' #' code_lines <- "library(dplyr)\ndplyr::tibble(a = 1)" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unused_import_linter(allow_ns_usage = TRUE) #' ) #' #' @evalRd rd_tags("unused_import_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export unused_import_linter <- function(allow_ns_usage = FALSE, except_packages = c("bit64", "data.table", "tidyverse"), interpret_glue = TRUE) { # Get dataset names lazy-loaded by imported packages get_datasets <- function(pkg) { results <- utils::data(package = pkg)$results items <- results[, "Item"] # e.g. 'state.abb (state)' in 'datasets' gsub("\\s*\\([^)]*\\)$", "", items) } import_xpath <- " parent::expr[ expr[2][STR_CONST] or not(SYMBOL_SUB[ text() = 'character.only' and following-sibling::expr[1][NUM_CONST[text() = 'TRUE'] or SYMBOL[text() = 'T']] ]) ]" xp_used_functions <- "SYMBOL_FUNCTION_CALL[not(preceding-sibling::NS_GET)]" xp_used_symbols <- paste( "//SYMBOL[not( parent::expr/preceding-sibling::expr[last()]/SYMBOL_FUNCTION_CALL[text() = 'library' or text() = 'require'] )]", "//SPECIAL", sep = " | " ) Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content library_calls <- source_expression$xml_find_function_calls(c("library", "require")) all_calls <- source_expression$xml_find_function_calls(NULL) import_exprs <- xml_find_all(library_calls, import_xpath) if (length(import_exprs) == 0L) { return(list()) } imported_pkgs <- xml_find_chr(import_exprs, "string(expr[STR_CONST|SYMBOL])") # as.character(parse(...)) returns one entry per expression imported_pkgs <- as.character(parse(text = imported_pkgs, keep.source = FALSE)) used_symbols <- unique(c( xml_text(xml_find_all(all_calls, xp_used_functions)), xml_text(xml_find_all(xml, xp_used_symbols)), extract_glued_symbols(xml, interpret_glue = interpret_glue) )) is_used <- vapply( imported_pkgs, function(pkg) { # Skip excepted packages and packages that are not installed if (pkg %in% except_packages || !requireNamespace(pkg, quietly = TRUE)) { return(TRUE) } package_exports <- getNamespaceExports(pkg) # functions dataset_exports <- get_datasets(pkg) # datasets any(package_exports %in% used_symbols) || any(dataset_exports %in% used_symbols) }, logical(1L) ) # TODO(#2480): Only call //SYMBOL_PACKAGE once. is_ns_used <- vapply( imported_pkgs, function(pkg) { ns_usage <- xml_find_first(xml, paste0("//SYMBOL_PACKAGE[text() = '", pkg, "']")) !identical(ns_usage, xml2::xml_missing()) }, logical(1L) ) is_unused <- !is_used if (allow_ns_usage) { is_unused[is_ns_used] <- FALSE } import_exprs <- import_exprs[is_unused] unused_packages <- get_r_string(import_exprs, xpath = "expr[STR_CONST | SYMBOL]") lint_message <- ifelse( is_ns_used[is_unused][unused_packages], paste0( "Don't attach package '", unused_packages, "', which is only used by namespace. ", "Check that it is installed using loadNamespace() instead." ), paste0("Package '", unused_packages, "' is attached but never used.") ) xml_nodes_to_lints(import_exprs, source_expression, lint_message, type = "warning") }) } lintr/R/rep_len_linter.R0000644000176200001440000000204614752731051014736 0ustar liggesusers#' Require usage of rep_len(x, n) over rep(x, length.out = n) #' #' `rep(x, length.out = n)` calls `rep_len(x, n)` "under the hood". The latter #' is thus more direct and equally readable. #' #' @examples #' # will produce lints #' lint( #' text = "rep(1:3, length.out = 10)", #' linters = rep_len_linter() #' ) #' #' # okay #' lint( #' text = "rep_len(1:3, 10)", #' linters = rep_len_linter() #' ) #' #' lint( #' text = "rep(1:3, each = 2L, length.out = 10L)", #' linters = rep_len_linter() #' ) #' #' @evalRd rd_tags("rep_len_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export rep_len_linter <- make_linter_from_function_xpath( function_names = "rep", # count(expr) is for cases using positional matching; see ?rep. xpath = " parent::expr[ ( SYMBOL_SUB[text() = 'length.out'] or (not(SYMBOL_SUB) and count(expr) = 4) ) and not(SYMBOL_SUB[text() = 'each'] or count(expr) = 5) ] ", lint_message = "Use rep_len(x, n) instead of rep(x, length.out = n)." ) lintr/R/vector_logic_linter.R0000644000176200001440000001050514752731051015770 0ustar liggesusers#' Enforce usage of scalar logical operators in conditional statements #' #' Usage of `&` in conditional statements is error-prone and inefficient. #' `condition` in `if (condition) expr` must always be of length 1, in which #' case `&&` is to be preferred. Ditto for `|` vs. `||`. #' #' This linter covers inputs to `if()` and `while()` conditions and to #' [testthat::expect_true()] and [testthat::expect_false()]. #' #' Note that because `&` and `|` are generics, it is possible that #' `&&` / `||` are not perfect substitutes because `&` is doing #' method dispatch in an incompatible way. #' #' Moreover, be wary of code that may have side effects, most commonly #' assignments. Consider `if ((a <- foo(x)) | (b <- bar(y))) { ... }` #' vs. `if ((a <- foo(x)) || (b <- bar(y))) { ... }`. Because `||` exits #' early, if `a` is `TRUE`, the second condition will never be evaluated #' and `b` will not be assigned. Such usage is not allowed by the Tidyverse #' style guide, and the code can easily be refactored by pulling the #' assignment outside the condition, so using `||` is still preferable. #' #' @examples #' # will produce lints #' lint( #' text = "if (TRUE & FALSE) 1", #' linters = vector_logic_linter() #' ) #' #' lint( #' text = "if (TRUE && (TRUE | FALSE)) 4", #' linters = vector_logic_linter() #' ) #' #' lint( #' text = "filter(x, A && B)", #' linters = vector_logic_linter() #' ) #' #' # okay #' lint( #' text = "if (TRUE && FALSE) 1", #' linters = vector_logic_linter() #' ) #' #' lint( #' text = "if (TRUE && (TRUE || FALSE)) 4", #' linters = vector_logic_linter() #' ) #' #' lint( #' text = "filter(x, A & B)", #' linters = vector_logic_linter() #' ) #' #' @evalRd rd_tags("vector_logic_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export vector_logic_linter <- function() { # ensures the expr is in the cond part of `if/while (cond) expr` -- # if on the XML parse tree is structured like # # | # # ... # <- loop condition # # ... # <- evaluation; includes BRACEs if present # # (here & below is optional) # ... # # we _don't_ want to match anything on the second expr, hence this condition_xpath <- " (//AND | //OR)[ ancestor::expr[ not(preceding-sibling::OP-RIGHT-PAREN) and preceding-sibling::*[ self::IF or self::WHILE or self::expr[SYMBOL_FUNCTION_CALL[text() = 'expect_true' or text() = 'expect_false']] ] ] and not(ancestor::expr[ preceding-sibling::expr[last()][SYMBOL_FUNCTION_CALL[not(text() = 'expect_true' or text() = 'expect_false')]] or preceding-sibling::OP-LEFT-BRACKET ]) and not(parent::expr/expr[ STR_CONST or expr/SYMBOL_FUNCTION_CALL[text() = 'as.raw' or text() = 'as.octmode' or text() = 'as.hexmode'] ]) ] " subset_xpath <- " self::*[not(SYMBOL_PACKAGE[text() = 'stats'])] /parent::expr //expr[ (AND2 or OR2) and not(preceding-sibling::expr[last()]/SYMBOL_FUNCTION_CALL[not(text() = 'subset' or text() = 'filter')]) and not(preceding-sibling::OP-LEFT-BRACKET) and not(preceding-sibling::*[not(self::COMMENT)][2][self::SYMBOL_SUB and text() = 'circular']) ] /*[2] " Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content xml_call <- source_expression$xml_find_function_calls(c("subset", "filter")) condition_expr <- xml_find_all(xml, condition_xpath) condition_op <- xml_text(condition_expr) condition_lints <- xml_nodes_to_lints( condition_expr, source_expression = source_expression, lint_message = sprintf("Use `%s` in conditional expressions.", strrep(condition_op, 2L)), type = "warning" ) subset_expr <- xml_find_all(xml_call, subset_xpath) subset_op <- xml_text(subset_expr) subset_lints <- xml_nodes_to_lints( subset_expr, source_expression = source_expression, lint_message = sprintf("Use `%s` in subsetting expressions.", substr(subset_op, 1L, 1L)), type = "warning" ) c(condition_lints, subset_lints) }) } lintr/R/use_lintr.R0000644000176200001440000000324614752731051013744 0ustar liggesusers#' Use lintr in your project #' #' Create a minimal lintr config file as a starting point for customization #' #' @param path Path to project root, where a `.lintr` file should be created. #' If the `.lintr` file already exists, an error will be thrown. #' @param type What kind of configuration to create? #' #' * `tidyverse` creates a minimal lintr config, based on the default linters ([linters_with_defaults()]). #' These are suitable for following [the tidyverse style guide](https://style.tidyverse.org/). #' * `full` creates a lintr config using all available linters via [all_linters()]. #' #' @return Path to the generated configuration, invisibly. #' #' @export #' @seealso `vignette("lintr")` for detailed introduction to using and configuring lintr. #' @examples #' if (FALSE) { #' # use the default set of linters #' lintr::use_lintr() #' # or try all linters #' lintr::use_lintr(type = "full") #' #' # then #' lintr::lint_dir() #' } use_lintr <- function(path = ".", type = c("tidyverse", "full")) { config_file <- normalize_path(file.path(path, lintr_option("linter_file")), mustWork = FALSE) if (file.exists(config_file)) { cli_abort("Found an existing configuration file at {.file {config_file}}.") } type <- match.arg(type) the_config <- switch( type, tidyverse = list( linters = 'linters_with_defaults() # see vignette("lintr")', encoding = '"UTF-8"' ), full = list( linters = 'all_linters(packages = "lintr") # see vignette("lintr")', encoding = '"UTF-8"', exclusions = 'list("renv", "packrat") # see ?lintr::exclude' ) ) write.dcf(the_config, config_file, width = Inf) invisible(config_file) } lintr/R/make_linter_from_regex.R0000644000176200001440000000465614752731051016455 0ustar liggesusersmake_linter_from_regex <- function(regex, lint_type, lint_msg) { function() { Linter(linter_level = "file", function(source_expression) { all_matches <- re_matches( source_expression[["file_lines"]], regex, locations = TRUE, global = FALSE ) all_matches <- all_matches[!is.na(all_matches$start), ] all_matches$line_number <- as.integer(rownames(all_matches)) matches_by_row <- split(all_matches, seq_len(nrow(all_matches))) lints <- lapply(matches_by_row, function(.match) { if (is_match_covered(.match, source_expression)) { return() } Lint( filename = source_expression[["filename"]], line_number = .match$line_number, type = lint_type, message = lint_msg, line = source_expression[["file_lines"]][[rownames(.match)]], ranges = list(c(.match$start, .match$end)) ) }) lints[lengths(lints) > 0L] }) } } #' Determine if a regex match is covered by an expression in a source_expression #' #' @param match The position where a regex match was observed. #' It must have the following elements: `"start"`, `"end"`, and `"line_number"`. #' @param source_expression A source_expression. #' @param token_type Restrict analysis to tokens of this type, for example, #' with `token_type = "STR_CONST"` you can check that a regex match occurs #' within a string. #' @noRd is_match_covered <- function(match, source_expression, token_type = "STR_CONST") { line_number <- match$line_number pc <- source_expression[["full_parsed_content"]] if (!is.null(token_type)) { pc <- pc[pc[["token"]] == token_type, ] } covering_rows <- pc[["line1"]] <= line_number & pc[["line2"]] >= line_number pc_cover <- pc[covering_rows, ] any_single_line_covers <- function() { x <- pc_cover[pc_cover[["line1"]] == pc_cover[["line2"]], ] any( x[["col1"]] <= match[["start"]] & x[["col2"]] >= match[["end"]] ) } any_multi_line_covers <- function() { x <- pc_cover[pc_cover[["line1"]] < pc_cover[["line2"]], ] any( (x[["line1"]] < line_number & x[["line2"]] > line_number) | (x[["line1"]] == line_number & x[["col1"]] <= match[["start"]]) | (x[["line2"]] == line_number & x[["col2"]] >= match[["end"]]) ) } any_single_line_covers() || any_multi_line_covers() } lintr/R/xml_nodes_to_lints.R0000644000176200001440000001010114752731051015627 0ustar liggesusers#' Convert an XML node or nodeset into a Lint #' #' Convenience function for converting nodes matched by XPath-based #' linter logic into a [Lint()] object to return. #' #' @details #' The location XPaths, `column_number_xpath`, `range_start_xpath` and `range_end_xpath` are evaluated using #' [xml2::xml_find_num()] and will usually be of the form `"number(./relative/xpath)"`. #' Note that the location line number cannot be changed and lints spanning multiple lines will ignore `range_end_xpath`. #' `column_number_xpath` and `range_start_xpath` are assumed to always refer to locations on the starting line of the #' `xml` node. #' #' @inheritParams lint-s3 #' @param xml An `xml_node` object (to generate one `Lint`) or an #' `xml_nodeset` object (to generate several `Lint`s), e.g. as returned by #' [xml2::xml_find_all()] or [xml2::xml_find_first()] or a #' list of `xml_node` objects. #' @param source_expression A source expression object, e.g. as #' returned typically by [lint()], or more generally #' by [get_source_expressions()]. #' @param lint_message The message to be included as the `message` #' to the `Lint` object. If `lint_message` is a character vector the same length as `xml`, #' the `i`-th lint will be given the `i`-th message. #' @param column_number_xpath XPath expression to return the column number location of the lint. #' Defaults to the start of the range matched by `range_start_xpath`. See details for more information. #' @param range_start_xpath XPath expression to return the range start location of the lint. #' Defaults to the start of the expression matched by `xml`. See details for more information. #' @param range_end_xpath XPath expression to return the range end location of the lint. #' Defaults to the end of the expression matched by `xml`. See details for more information. #' #' @return For `xml_node`s, a `lint`. For `xml_nodeset`s, `lints` (a list of `lint`s). #' @export xml_nodes_to_lints <- function(xml, source_expression, lint_message, type = c("style", "warning", "error"), column_number_xpath = range_start_xpath, range_start_xpath = "number(./@col1)", range_end_xpath = "number(./@col2)") { if (length(xml) == 0L) { return(list()) } if (is_nodeset_like(xml)) { lints <- .mapply( xml_nodes_to_lints, dots = list(xml = xml, lint_message = lint_message), MoreArgs = list( source_expression = source_expression, type = type, column_number_xpath = column_number_xpath, range_start_xpath = range_start_xpath, range_end_xpath = range_end_xpath ) ) class(lints) <- "lints" return(lints) } else if (!is_node(xml)) { cli_abort(c( x = "Expected an {.cls xml_nodeset}, a {.cls list} of xml_nodes, or an {.cls xml_node}.", i = "Instead got {.obj_type_friendly {xml}}." )) } type <- match.arg(type, c("style", "warning", "error")) line1 <- xml_attr(xml, "line1") col1 <- xp_find_location(xml, range_start_xpath) if (is.na(col1)) { cli_warn(c( x = "Could not find range start for lint.", i = "Defaulting to start of line." )) col1 <- 1L } lines <- source_expression[["lines"]] if (is.null(lines)) lines <- source_expression[["file_lines"]] if (xml_attr(xml, "line2") == line1) { col2 <- xp_find_location(xml, range_end_xpath) if (is.na(col2)) { cli_warn(c( x = "Could not find range end for lint.", i = "Defaulting to width 1." )) col2 <- col1 } } else { col2 <- nchar(lines[[line1]]) } column_number <- xp_find_location(xml, column_number_xpath) if (is.na(column_number)) { cli_warn(c( x = "Could not find location for lint.", i = "Defaulting to start of range." )) column_number <- col1 } Lint( filename = source_expression$filename, line_number = as.integer(line1), column_number = column_number, type = type, message = lint_message, line = lines[[line1]], ranges = list(c(col1, col2)) ) } lintr/R/namespace.R0000644000176200001440000000532614752731051013675 0ustar liggesusers# Parse namespace files and return imports exports, methods namespace_imports <- function(path = find_package(".")) { namespace_data <- tryCatch( parseNamespaceFile(basename(path), package.lib = file.path(path, "..")), error = function(e) NULL ) if (length(namespace_data$imports) == 0L) { return(empty_namespace_data()) } do.call(rbind, lapply(namespace_data$imports, safe_get_exports)) } # this loads the namespaces, but is the easiest way to do it # test package availability to avoid failing out as in #1360 # typically, users are running this on their own package directories and thus # will have the namespace dependencies installed, but we can't guarantee this. safe_get_exports <- function(ns) { # check package exists for both import(x) and importFrom(x, y) usages if (!requireNamespace(ns[[1L]], quietly = TRUE)) { return(empty_namespace_data()) } # importFrom directives appear as list(ns, imported_funs) if (length(ns) > 1L) { return(data.frame(pkg = ns[[1L]], fun = ns[[2L]])) } # relevant only if there are any exported objects fun <- getNamespaceExports(ns) if (length(fun) > 0L) { data.frame(pkg = ns, fun = fun) } } empty_namespace_data <- function() { data.frame(pkg = character(), fun = character()) } # filter namespace_imports() for S3 generics # this loads all imported namespaces imported_s3_generics <- function(ns_imports) { # `NROW()` for the `NULL` case of 0-export dependencies (cf. #1503) is_generic <- vapply( seq_len(NROW(ns_imports)), function(i) { fun_obj <- get(ns_imports$fun[i], envir = asNamespace(ns_imports$pkg[i])) is.function(fun_obj) && is_s3_generic(fun_obj) }, logical(1L) ) ns_imports[is_generic, ] } exported_s3_generics <- function(path = find_package(".")) { namespace_data <- tryCatch( parseNamespaceFile(basename(path), package.lib = file.path(path, "..")), error = function(e) NULL ) if (length(namespace_data$S3methods) == 0L || nrow(namespace_data$S3methods) == 0L) { return(empty_namespace_data()) } data.frame(pkg = basename(path), fun = unique(namespace_data$S3methods[, 1L])) } is_s3_generic <- function(fun) { # Inspired by `utils::isS3stdGeneric`, though it will detect functions that # have `useMethod()` in places other than the first expression. bdexpr <- body(fun) while (is.call(bdexpr) && bdexpr[[1L]] == "{") bdexpr <- bdexpr[[length(bdexpr)]] ret <- is.call(bdexpr) && identical(bdexpr[[1L]], as.name("UseMethod")) if (ret) { names(ret) <- bdexpr[[2L]] } ret } .base_s3_generics <- unique(c( names(.knownS3Generics), .S3_methods_table[, 1L], # Contains S3 generic groups, see ?base::groupGeneric and src/library/base/R/zzz.R ls(.GenericArgsEnv) )) lintr/R/todo_comment_linter.R0000644000176200001440000000406314752731051016002 0ustar liggesusers#' TODO comment linter #' #' Check that the source contains no TODO comments (case-insensitive). #' #' @param todo Vector of case-insensitive strings that identify TODO comments. #' @param except_regex Vector of case-sensitive regular expressions that identify #' _valid_ TODO comments. #' #' @examples #' # will produce lints #' lint( #' text = "x + y # TOODOO", #' linters = todo_comment_linter(todo = "toodoo") #' ) #' #' lint( #' text = "pi <- 1.0 # FIIXMEE", #' linters = todo_comment_linter(todo = "fiixmee") #' ) #' #' lint( #' text = "x <- TRUE # TOODOO(#1234): Fix this hack.", #' linters = todo_comment_linter() #' ) #' #' # okay #' lint( #' text = "x + y # my informative comment", #' linters = todo_comment_linter() #' ) #' #' lint( #' text = "pi <- 3.14", #' linters = todo_comment_linter() #' ) #' #' lint( #' text = "x <- TRUE", #' linters = todo_comment_linter() #' ) #' #' lint( #' text = "x <- TRUE # TODO(#1234): Fix this hack.", #' linters = todo_comment_linter(except_regex = "TODO\\(#[0-9]+\\):") #' ) #' #' @evalRd rd_tags("todo_comment_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export todo_comment_linter <- function(todo = c("todo", "fixme"), except_regex = NULL) { todo_comment_regex <- rex(one_or_more("#"), any_spaces, or(todo)) valid_todo_regex <- if (!is.null(except_regex)) paste0("#+", rex::shortcuts$any_spaces, "(?:", paste(except_regex, collapse = "|"), ")") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content comment_expr <- xml_find_all(xml, "//COMMENT") comment_text <- xml_text(comment_expr) invalid_todo <- re_matches_logical(comment_text, todo_comment_regex, ignore.case = TRUE) if (!is.null(valid_todo_regex)) { invalid_todo <- invalid_todo & !re_matches_logical(comment_text, valid_todo_regex) } xml_nodes_to_lints( comment_expr[invalid_todo], source_expression = source_expression, lint_message = "Remove TODO comments.", type = "style" ) }) } lintr/R/boolean_arithmetic_linter.R0000644000176200001440000000417714752731051017151 0ustar liggesusers#' Require usage of boolean operators over equivalent arithmetic #' #' `length(which(x == y)) == 0` is the same as `!any(x == y)`, but the latter #' is more readable and more efficient. #' #' @examples #' # will produce lints #' lint( #' text = "length(which(x == y)) == 0L", #' linters = boolean_arithmetic_linter() #' ) #' #' lint( #' text = "sum(grepl(pattern, x)) == 0", #' linters = boolean_arithmetic_linter() #' ) #' #' # okay #' lint( #' text = "!any(x == y)", #' linters = boolean_arithmetic_linter() #' ) #' #' lint( #' text = "!any(grepl(pattern, x))", #' linters = boolean_arithmetic_linter() #' ) #' #' @evalRd rd_tags("boolean_arithmetic_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export boolean_arithmetic_linter <- function() { # TODO(#1580): sum() cases x %in% y, A [&|] B, !A, is.na/is.nan/is.finite/is.infinite/is.element # TODO(#1581): extend to include all()-alike expressions zero_expr <- "(EQ or NE or GT or LE) and expr[NUM_CONST[text() = '0' or text() = '0L']]" one_expr <- "(LT or GE) and expr[NUM_CONST[text() = '1' or text() = '1L']]" length_xpath <- glue(" parent::expr /parent::expr[ expr[SYMBOL_FUNCTION_CALL[text() = 'length']] and parent::expr[ ({zero_expr}) or ({one_expr})] ] ") sum_xpath <- glue(" parent::expr[ expr[ expr[SYMBOL_FUNCTION_CALL[text() = 'grepl']] or (EQ or NE or GT or LT or GE or LE) ] and parent::expr[ ({zero_expr}) or ({one_expr})] ]") Linter(linter_level = "expression", function(source_expression) { length_calls <- source_expression$xml_find_function_calls(c("which", "grep")) sum_calls <- source_expression$xml_find_function_calls("sum") any_expr <- c( xml_find_all(length_calls, length_xpath), xml_find_all(sum_calls, sum_xpath) ) xml_nodes_to_lints( any_expr, source_expression = source_expression, # TODO(#2464): customize this? lint_message = paste( "Use any() to express logical aggregations.", "For example, replace length(which(x == y)) == 0 with !any(x == y)." ), type = "warning" ) }) } lintr/R/duplicate_argument_linter.R0000644000176200001440000000427114752731051017170 0ustar liggesusers#' Duplicate argument linter #' #' Check for duplicate arguments in function calls. Some cases are run-time errors #' (e.g. `mean(x = 1:5, x = 2:3)`), otherwise this linter is used to discourage #' explicitly providing duplicate names to objects (e.g. `c(a = 1, a = 2)`). #' Duplicate-named objects are hard to work with programmatically and #' should typically be avoided. #' #' @param except A character vector of function names as exceptions. Defaults to #' functions that allow sequential updates to variables, currently `dplyr::mutate()` #' and `dplyr::transmute()`. #' #' @examples #' # will produce lints #' lint( #' text = "list(x = 1, x = 2)", #' linters = duplicate_argument_linter() #' ) #' #' lint( #' text = "fun(arg = 1, arg = 2)", #' linters = duplicate_argument_linter() #' ) #' #' # okay #' lint( #' text = "list(x = 1, x = 2)", #' linters = duplicate_argument_linter(except = "list") #' ) #' #' lint( #' text = "df %>% dplyr::mutate(x = a + b, x = x + d)", #' linters = duplicate_argument_linter() #' ) #' #' @evalRd rd_tags("duplicate_argument_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export duplicate_argument_linter <- function(except = c("mutate", "transmute")) { # NB: approach checking for duplicates in XPath is hard because of # quoted names, e.g. foo(a = 1, `a` = 2), so compute duplicates in R xpath_call_with_args <- glue(" //EQ_SUB[not( preceding-sibling::expr/SYMBOL_FUNCTION_CALL[{ xp_text_in_table(except) }] )] /parent::expr[count(EQ_SUB) > 1] ") xpath_arg_name <- "./EQ_SUB/preceding-sibling::*[not(self::COMMENT)][1]" Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content call_expr <- xml_find_all(xml, xpath_call_with_args) bad_expr <- lapply( call_expr, function(expr) { arg_expr <- xml_find_all(expr, xpath_arg_name) arg_expr[duplicated(get_r_string(arg_expr))] } ) xml_nodes_to_lints( unlist(bad_expr, recursive = FALSE), source_expression = source_expression, lint_message = "Avoid duplicate arguments in function calls.", type = "warning" ) }) } lintr/R/deprecated.R0000644000176200001440000000127614752731051014041 0ustar liggesusers#' Deprecated functions #' #' Functions that have been deprecated and replaced by newer ones. They will be removed in an #' upcoming version of \pkg{lintr} and should thus not be used anymore. #' @noRd NULL lintr_deprecated <- function(what, alternative = NULL, version = NULL, type = "Function", signal = c("warning", "stop")) { signal <- match.arg(signal) signal <- match.fun(signal) msg <- c( c(type, " ", what, " was deprecated"), if (length(version) > 0L) c(" in lintr version ", version), ". ", if (length(alternative) > 0L) c("Use ", alternative, " instead.") ) msg <- paste(msg, collapse = "") signal(msg, call. = FALSE, domain = NA) } lintr/R/function_return_linter.R0000644000176200001440000000311314752731051016532 0ustar liggesusers#' Lint common mistakes/style issues cropping up from return statements #' #' `return(x <- ...)` is either distracting (because `x` is ignored), or #' confusing (because assigning to `x` has some side effect that is muddled #' by the dual-purpose expression). #' #' @examples #' # will produce lints #' lint( #' text = "foo <- function(x) return(y <- x + 1)", #' linters = function_return_linter() #' ) #' #' lint( #' text = "foo <- function(x) return(x <<- x + 1)", #' linters = function_return_linter() #' ) #' #' writeLines("e <- new.env() \nfoo <- function(x) return(e$val <- x + 1)") #' lint( #' text = "e <- new.env() \nfoo <- function(x) return(e$val <- x + 1)", #' linters = function_return_linter() #' ) #' #' # okay #' lint( #' text = "foo <- function(x) return(x + 1)", #' linters = function_return_linter() #' ) #' #' code_lines <- " #' foo <- function(x) { #' x <<- x + 1 #' return(x) #' } #' " #' lint( #' text = code_lines, #' linters = function_return_linter() #' ) #' #' code_lines <- " #' e <- new.env() #' foo <- function(x) { #' e$val <- x + 1 #' return(e$val) #' } #' " #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = function_return_linter() #' ) #' #' @evalRd rd_tags("function_return_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export function_return_linter <- make_linter_from_function_xpath( function_names = "return", xpath = "parent::expr/expr[LEFT_ASSIGN or RIGHT_ASSIGN]", lint_message = "Move the assignment outside of the return() clause, or skip assignment altogether." ) lintr/R/ifelse_censor_linter.R0000644000176200001440000000406414752731051016134 0ustar liggesusers#' Block usage of `ifelse()` where `pmin()` or `pmax()` is more appropriate #' #' `ifelse(x > M, M, x)` is the same as `pmin(x, M)`, but harder #' to read and requires several passes over the vector. #' #' The same goes for other similar ways to censor a vector, e.g. #' `ifelse(x <= M, x, M)` is `pmin(x, M)`, #' `ifelse(x < m, m, x)` is `pmax(x, m)`, and #' `ifelse(x >= m, x, m)` is `pmax(x, m)`. #' #' @examples #' # will produce lints #' lint( #' text = "ifelse(5:1 < pi, 5:1, pi)", #' linters = ifelse_censor_linter() #' ) #' #' lint( #' text = "ifelse(x > 0, x, 0)", #' linters = ifelse_censor_linter() #' ) #' #' # okay #' lint( #' text = "pmin(5:1, pi)", #' linters = ifelse_censor_linter() #' ) #' #' lint( #' text = "pmax(x, 0)", #' linters = ifelse_censor_linter() #' ) #' #' @evalRd rd_tags("ifelse_censor_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export ifelse_censor_linter <- function() { xpath <- glue(" following-sibling::expr[ (LT or GT or LE or GE) and expr[1] = following-sibling::expr and expr[2] = following-sibling::expr ] /parent::expr ") Linter(linter_level = "expression", function(source_expression) { ifelse_calls <- source_expression$xml_find_function_calls(ifelse_funs) bad_expr <- xml_find_all(ifelse_calls, xpath) matched_call <- xp_call_name(bad_expr) operator <- xml_find_chr(bad_expr, "string(expr[2]/*[2])") match_first <- !is.na(xml_find_first(bad_expr, "expr[2][expr[1] = following-sibling::expr[1]]")) optimizer <- ifelse((operator %in% c("<", "<=")) == match_first, "pmin", "pmax") first_var <- rep_len("x", length(match_first)) second_var <- rep_len("y", length(match_first)) first_var[!match_first] <- "y" second_var[!match_first] <- "x" xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = sprintf( "%s(x, y) is preferable to %s(x %s y, %s, %s).", optimizer, matched_call, operator, first_var, second_var ), type = "warning" ) }) } lintr/R/print_linter.R0000644000176200001440000000271314752731051014447 0ustar liggesusers#' Block usage of print() for logging #' #' The default print method for character vectors is appropriate for interactively inspecting objects, #' not for logging messages. Thus checked-in usage like `print(paste('Data has', nrow(DF), 'rows.'))` #' is better served by using [cat()], e.g. `cat(sprintf('Data has %d rows.\n', nrow(DF)))` (noting that #' using `cat()` entails supplying your own line returns, and that [glue::glue()] might be preferable #' to [sprintf()] for constructing templated strings). Lastly, note that [message()] differs slightly #' from `cat()` in that it prints to `stderr` by default, not `stdout`, but is still a good option #' to consider for logging purposes. #' #' @examples #' # will produce lints #' lint( #' text = "print('a')", #' linters = print_linter() #' ) #' #' lint( #' text = "print(paste(x, 'y'))", #' linters = print_linter() #' ) #' #' # okay #' lint( #' text = "print(x)", #' linters = print_linter() #' ) #' #' @evalRd rd_tags("print_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export print_linter <- make_linter_from_function_xpath( function_names = "print", xpath = " parent::expr[expr[2][ STR_CONST or expr/SYMBOL_FUNCTION_CALL[ text() = 'paste' or text() = 'paste0' or text() = 'sprintf' ] ]] ", lint_message = "Use cat() instead of print() logging messages. Use message() in cases calling for a signalled condition." ) lintr/R/whitespace_linter.R0000644000176200001440000000165514752731051015453 0ustar liggesusers#' Whitespace linter #' #' Check that the correct character is used for indentation. #' #' Currently, only supports linting in the presence of tabs. #' #' Much ink has been spilled on this topic, and we encourage you to check #' out references for more information. #' #' @include make_linter_from_regex.R #' #' @examples #' # will produce lints #' lint( #' text = "\tx", #' linters = whitespace_linter() #' ) #' #' # okay #' lint( #' text = " x", #' linters = whitespace_linter() #' ) #' #' @evalRd rd_tags("whitespace_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' #' @references #' - https://www.jwz.org/doc/tabs-vs-spaces.html #' - https://blog.codinghorror.com/death-to-the-space-infidels/ #' @export whitespace_linter <- make_linter_from_regex( regex = rex(start, zero_or_more(regex("\\s")), one_or_more("\t")), lint_type = "style", lint_msg = "Use spaces to indent, not tabs." ) lintr/R/nrow_subset_linter.R0000644000176200001440000000341014752731051015660 0ustar liggesusers#' Block usage of `nrow(subset(x, .))` #' #' Using `nrow(subset(x, condition))` to count the instances where `condition` #' applies inefficiently requires doing a full subset of `x` just to #' count the number of rows in the resulting subset. #' There are a number of equivalent expressions that don't require the full #' subset, e.g. `with(x, sum(condition))` (or, more generically, #' `with(x, sum(condition, na.rm = TRUE))`). #' #' @examples #' # will produce lints #' lint( #' text = "nrow(subset(x, is_treatment))", #' linters = nrow_subset_linter() #' ) #' #' lint( #' text = "nrow(filter(x, is_treatment))", #' linters = nrow_subset_linter() #' ) #' #' lint( #' text = "x %>% filter(x, is_treatment) %>% nrow()", #' linters = nrow_subset_linter() #' ) #' #' # okay #' lint( #' text = "with(x, sum(is_treatment, na.rm = TRUE))", #' linters = nrow_subset_linter() #' ) #' #' @evalRd rd_tags("nrow_subset_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @include shared_constants.R #' @export nrow_subset_linter <- make_linter_from_function_xpath( function_names = c("subset", "filter"), xpath = glue(" parent::expr /parent::expr[ expr/SYMBOL_FUNCTION_CALL[text() = 'nrow'] or (self::expr | parent::expr)[ (PIPE or SPECIAL[{ xp_text_in_table(setdiff(magrittr_pipes, c('%$%', '%<>%'))) }]) and expr/expr/SYMBOL_FUNCTION_CALL[text() = 'nrow'] ] ] "), lint_message = paste( "Use arithmetic to count the number of rows satisfying a condition,", "rather than fully subsetting the data.frame and counting the resulting rows.", "For example, replace nrow(subset(x, is_treatment)) with sum(x$is_treatment).", "NB: use na.rm = TRUE if `is_treatment` has missing values." ) ) lintr/R/repeat_linter.R0000644000176200001440000000170014752731051014566 0ustar liggesusers#' Repeat linter #' #' Check that `while (TRUE)` is not used for infinite loops. #' #' @examples #' # will produce lints #' lint( #' text = "while (TRUE) { }", #' linters = repeat_linter() #' ) #' #' #' # okay #' lint( #' text = "repeat { }", #' linters = repeat_linter() #' ) #' #' @evalRd rd_tags("repeat_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export repeat_linter <- function() { xpath <- "//WHILE[following-sibling::expr[1]/NUM_CONST[text() = 'TRUE']]" Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content lints <- xml_find_all(xml, xpath) xml_nodes_to_lints( lints, source_expression = source_expression, lint_message = "Use 'repeat' instead of 'while (TRUE)' for infinite loops.", range_start_xpath = "number(./@col1)", range_end_xpath = "number(./following-sibling::*[3]/@col2)" ) }) } lintr/R/unnecessary_concatenation_linter.R0000644000176200001440000001000014752731051020543 0ustar liggesusers#' Unneeded concatenation linter #' #' Check that the [c()] function is not used without arguments nor with a single constant. #' #' @param allow_single_expression Logical, default `TRUE`. If `FALSE`, one-expression #' usages of `c()` are always linted, e.g. `c(x)` and `c(matrix(...))`. In some such #' cases, `c()` is being used for its side-effect of stripping non-name attributes; #' it is usually preferable to use the more readable [as.vector()] instead. #' [as.vector()] is not always preferable, for example with environments #' (especially, `R6` objects), in which case `list()` is the better alternative. #' #' @examples #' # will produce lints #' lint( #' text = "x <- c()", #' linters = unnecessary_concatenation_linter() #' ) #' #' lint( #' text = "x <- c(TRUE)", #' linters = unnecessary_concatenation_linter() #' ) #' #' lint( #' text = "x <- c(1.5 + 2.5)", #' linters = unnecessary_concatenation_linter(allow_single_expression = FALSE) #' ) #' #' # okay #' lint( #' text = "x <- NULL", #' linters = unnecessary_concatenation_linter() #' ) #' #' # In case the intent here was to seed a vector of known size #' lint( #' text = "x <- integer(4L)", #' linters = unnecessary_concatenation_linter() #' ) #' #' lint( #' text = "x <- TRUE", #' linters = unnecessary_concatenation_linter() #' ) #' #' lint( #' text = "x <- c(1.5 + 2.5)", #' linters = unnecessary_concatenation_linter(allow_single_expression = TRUE) #' ) #' #' @evalRd rd_tags("unnecessary_concatenation_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export unnecessary_concatenation_linter <- function(allow_single_expression = TRUE) { # nolint: object_length_linter. stopifnot( is.logical(allow_single_expression), length(allow_single_expression) == 1L ) msg_empty <- "Replace unnecessary c() by NULL or, whenever possible, vector() seeded with the correct type and/or length." msg_const <- "Remove unnecessary c() of a constant." non_constant_cond <- "SYMBOL or (expr and not(OP-COLON and count(expr[SYMBOL or expr]) != 2))" pipes <- setdiff(magrittr_pipes, "%$%") to_pipe_xpath <- glue(" ./preceding-sibling::*[1][ self::PIPE or self::SPECIAL[{ xp_text_in_table(pipes) }] ] ") if (allow_single_expression) { zero_arg_cond <- glue("count(expr) = 1 and not( {to_pipe_xpath} / preceding-sibling::expr[ {non_constant_cond} ])") one_arg_cond <- glue("count(expr) = 2 and not(expr[2][ {non_constant_cond} ])") } else { zero_arg_cond <- glue("count(expr) = 1 and not( {to_pipe_xpath} )") one_arg_cond <- "count(expr) = 2 and not(expr[2]/SYMBOL[text() = '...'])" path_to_non_constant <- glue("./expr[2][ {non_constant_cond} ]") msg_const_expr <- paste( "Remove unnecessary c() of a constant expression.", "Replace with as.vector() if c() is used to strip attributes, e.g. in converting an array to a vector." ) } call_xpath <- glue(" parent::expr[ not(EQ_SUB) and ( {xp_or(zero_arg_cond, one_arg_cond)} ) ]") num_args_xpath <- "count(./expr) - 1" Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls("c") c_calls <- xml_find_all(xml_calls, call_xpath) # bump count(args) by 1 if inside a pipeline num_args <- as.integer(xml_find_num(c_calls, num_args_xpath)) + as.integer(!is.na(xml_find_first(c_calls, to_pipe_xpath))) # NB: the xpath guarantees num_args is 0, 1, or 2. 2 comes # in "a" %>% c("b"). # TODO(#2476): Push this logic back into the XPath. is_unneeded <- num_args <= 1L c_calls <- c_calls[is_unneeded] num_args <- num_args[is_unneeded] msg <- ifelse(num_args == 0L, msg_empty, msg_const) if (!allow_single_expression) { is_single_expression <- !is.na(xml_find_first(c_calls, path_to_non_constant)) msg[is_single_expression] <- msg_const_expr } xml_nodes_to_lints( c_calls, source_expression = source_expression, lint_message = msg ) }) } lintr/R/if_switch_linter.R0000644000176200001440000001445614752731051015301 0ustar liggesusers#' Require usage of switch() over repeated if/else blocks #' #' [switch()] statements in R are used to delegate behavior based #' on the value of some input scalar string, e.g. #' `switch(x, a = 1, b = 3, c = 7, d = 8)` will be one of #' `1`, `3`, `7`, or `8`, depending on the value of `x`. #' #' This can also be accomplished by repeated `if`/`else` statements like #' so: `if (x == "a") 1 else if (x == "b") 2 else if (x == "c") 7 else 8` #' (implicitly, the last `else` assumes x only takes 4 possible values), #' but this is more cluttered and slower (note that `switch()` takes the same #' time to evaluate regardless of the value of `x`, and is faster even #' when `x` takes the first value (here `a`), and that the `if`/`else` #' approach is roughly linear in the number of conditions that need to #' be evaluated, here up to 3 times). #' #' @param max_branch_lines,max_branch_expressions Integer, default 0 indicates "no maximum". #' If set any `if`/`else if`/.../`else` chain where any branch occupies more than #' this number of lines (resp. expressions) will not be linted. The conjugate #' applies to `switch()` statements -- if these parameters are set, any `switch()` #' statement with any overly-complicated branches will be linted. See examples. #' #' @examples #' # will produce lints #' lint( #' text = "if (x == 'a') 1 else if (x == 'b') 2 else 3", #' linters = if_switch_linter() #' ) #' #' code <- paste( #' "if (x == 'a') {", #' " 1", #' "} else if (x == 'b') {", #' " 2", #' "} else if (x == 'c') {", #' " y <- x", #' " z <- sqrt(match(y, letters))", #' " z", #' "}", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = if_switch_linter() #' ) #' #' code <- paste( #' "if (x == 'a') {", #' " 1", #' "} else if (x == 'b') {", #' " 2", #' "} else if (x == 'c') {", #' " y <- x", #' " z <- sqrt(", #' " match(y, letters)", #' " )", #' " z", #' "}", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = if_switch_linter() #' ) #' #' code <- paste( #' "switch(x,", #' " a = {", #' " 1", #' " 2", #' " 3", #' " },", #' " b = {", #' " 1", #' " 2", #' " }", #' ")", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = if_switch_linter(max_branch_lines = 2L) #' ) #' #' # okay #' lint( #' text = "switch(x, a = 1, b = 2, 3)", #' linters = if_switch_linter() #' ) #' #' # switch() version not as clear #' lint( #' text = "if (x == 'a') 1 else if (x == 'b' & y == 2) 2 else 3", #' linters = if_switch_linter() #' ) #' #' code <- paste( #' "if (x == 'a') {", #' " 1", #' "} else if (x == 'b') {", #' " 2", #' "} else if (x == 'c') {", #' " y <- x", #' " z <- sqrt(match(y, letters))", #' " z", #' "}", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = if_switch_linter(max_branch_lines = 2L) #' ) #' #' code <- paste( #' "if (x == 'a') {", #' " 1", #' "} else if (x == 'b') {", #' " 2", #' "} else if (x == 'c') {", #' " y <- x", #' " z <- sqrt(", #' " match(y, letters)", #' " )", #' " z", #' "}", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = if_switch_linter(max_branch_expressions = 2L) #' ) #' #' code <- paste( #' "switch(x,", #' " a = {", #' " 1", #' " 2", #' " 3", #' " },", #' " b = {", #' " 1", #' " 2", #' " }", #' ")", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = if_switch_linter(max_branch_lines = 3L) #' ) #' #' @evalRd rd_tags("if_switch_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export if_switch_linter <- function(max_branch_lines = 0L, max_branch_expressions = 0L) { equal_str_cond <- "expr[1][EQ and expr/STR_CONST]" if (max_branch_lines > 0L || max_branch_expressions > 0L) { complexity_cond <- xp_or(c( if (max_branch_lines > 0L) paste("OP-RIGHT-BRACE/@line2 - OP-LEFT-BRACE/@line1 > 1 +", max_branch_lines), if (max_branch_expressions > 0L) paste("count(expr) >", max_branch_expressions) )) branch_expr_cond <- xp_and(c( xp_or( # if (x) { } ... xp_and("preceding-sibling::IF", "position() = 2"), # if (x) { ... } else { } xp_and("preceding-sibling::ELSE", "not(IF)") ), complexity_cond )) max_lines_cond <- glue(".//expr[{branch_expr_cond}]") switch_xpath <- glue(" parent::expr[expr[ position() > 2 and {complexity_cond} ]]") } else { max_lines_cond <- "false" switch_xpath <- NULL } # NB: IF AND {...} AND ELSE/... implies >= 3 equality conditions are present # .//expr/IF/...: the expr in `==` that's _not_ the STR_CONST # not(preceding::IF): prevent nested matches which might be incorrect globally # not(. != .): don't match if there are _any_ expr which _don't_ match the top # expr if_xpath <- glue(" //IF /parent::expr[ not(preceding-sibling::IF) and {equal_str_cond} and ELSE/following-sibling::expr[ IF and {equal_str_cond} and ELSE/following-sibling::expr[IF and {equal_str_cond}] ] and not( .//expr/IF/following-sibling::{equal_str_cond}/expr[not(STR_CONST)] != expr[1][EQ]/expr[not(STR_CONST)] ) and not({ max_lines_cond }) ] ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, if_xpath) lints <- xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = paste( "Prefer switch() statements over repeated if/else equality tests,", "e.g., switch(x, a = 1, b = 2) over", 'if (x == "a") 1 else if (x == "b") 2.' ), type = "warning" ) if (!is.null(switch_xpath)) { xml_calls <- source_expression$xml_find_function_calls("switch") switch_expr <- xml_find_all(xml_calls, switch_xpath) lints <- c(lints, xml_nodes_to_lints( switch_expr, source_expression = source_expression, lint_message = "Prefer repeated if/else statements over overly-complicated switch() statements.", type = "warning" )) } lints }) } lintr/R/make_linter_from_xpath.R0000644000176200001440000000514214752731051016456 0ustar liggesusers#' Create a linter from an XPath #' #' @inheritParams xml_nodes_to_lints #' @inheritParams is_lint_level #' @param xpath Character string, an XPath identifying R code to lint. #' For `make_linter_from_function_xpath()`, the XPath is relative to the `parent::expr` of the #' `SYMBOL_FUNCTION_CALL` nodes of the selected functions. #' See [xmlparsedata::xml_parse_data()] and [get_source_expressions()]. #' #' @examples #' number_linter <- make_linter_from_xpath("//NUM_CONST", "This is a number.") #' lint(text = "1 + 2", linters = number_linter()) #' @export make_linter_from_xpath <- function(xpath, lint_message, type = c("warning", "style", "error"), level = c("expression", "file")) { type <- match.arg(type) level <- match.arg(level) stopifnot( "xpath should be a character string" = is.character(xpath) && length(xpath) == 1L && !is.na(xpath), "lint_message is required" = !missing(lint_message) ) xml_key <- if (level == "expression") "xml_parsed_content" else "full_xml_parsed_content" function() { Linter(linter_level = level, function(source_expression) { xml <- source_expression[[xml_key]] expr <- xml_find_all(xml, xpath) xml_nodes_to_lints( expr, source_expression = source_expression, lint_message = lint_message, type = type ) }) } } #' @rdname make_linter_from_xpath #' @param function_names Character vector, names of functions whose calls to examine.. #' @export # nolint next: object_length. make_linter_from_function_xpath <- function(function_names, xpath, lint_message, type = c("warning", "style", "error"), level = c("expression", "file")) { type <- match.arg(type) level <- match.arg(level) stopifnot( "function_names should be a character vector" = is.character(function_names) && length(function_names) > 0L, "xpath should be a character string" = is.character(xpath) && length(xpath) == 1L && !is.na(xpath), "lint_message is required" = !missing(lint_message) ) function() { Linter(linter_level = level, function(source_expression) { call_xml <- source_expression$xml_find_function_calls(function_names) expr <- xml_find_all(call_xml, xpath) xml_nodes_to_lints( expr, source_expression = source_expression, lint_message = lint_message, type = type ) }) } } lintr/R/sprintf_linter.R0000644000176200001440000000745114752731051015004 0ustar liggesusers#' Require correct `sprintf()` calls #' #' Check for an inconsistent number of arguments or arguments with incompatible types (for literal arguments) in #' [sprintf()] calls. #' #' [gettextf()] calls are also included, since `gettextf()` is a thin wrapper around `sprintf()`. #' #' @examples #' # will produce lints #' lint( #' text = 'sprintf("hello %s %s %d", x, y)', #' linters = sprintf_linter() #' ) #' #' # okay #' lint( #' text = 'sprintf("hello %s %s %d", x, y, z)', #' linters = sprintf_linter() #' ) #' #' lint( #' text = 'sprintf("hello %s %s %d", x, y, ...)', #' linters = sprintf_linter() #' ) #' #' @evalRd rd_tags("sprintf_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export sprintf_linter <- function() { call_xpath <- " parent::expr[ ( OP-LEFT-PAREN/following-sibling::expr[1]/STR_CONST or SYMBOL_SUB[text() = 'fmt']/following-sibling::expr[1]/STR_CONST ) and not(expr/SYMBOL[text() = '...']) ]" pipes <- setdiff(magrittr_pipes, "%$%") in_pipe_xpath <- glue("self::expr[ preceding-sibling::*[1][self::PIPE or self::SPECIAL[{ xp_text_in_table(pipes) }]] and ( preceding-sibling::*[2]/STR_CONST or SYMBOL_SUB[text() = 'fmt']/following-sibling::expr[1]/STR_CONST ) ]") is_missing <- function(x) is.symbol(x) && !nzchar(x) # Zap sprintf() call to contain only constants # # Set all extra arguments to 0L if they aren't a constant # # @param parsed_expr A parsed `sprintf()` call # # @return A `sprintf()` call with all non-constants replaced by `0L` # (which is compatible with all sprintf format specifiers) zap_extra_args <- function(parsed_expr) { if ("fmt" %in% names(parsed_expr)) { fmt_loc <- which(names(parsed_expr) == "fmt") } else { fmt_loc <- 2L } if (length(parsed_expr) >= 3L) { for (i in setdiff(seq_along(parsed_expr), c(1L, fmt_loc))) { if (!is_missing(parsed_expr[[i]]) && !is.atomic(parsed_expr[[i]])) { parsed_expr[[i]] <- 0L } } } parsed_expr } # Anticipate warnings of a sprintf() call # # Try running a static sprintf() call to determine whether it will produce warnings or errors due to format # misspecification # # @param xml An XML node representing a `sprintf()` call (i.e. the `` node containing the call) # # @return A string, either `NA_character_` or the text of generated errors and warnings from the `sprintf()` call when # replacing all dynamic components by 0, which is compatible with all format specifiers. capture_sprintf_warning <- function(xml) { parsed_expr <- xml2lang(xml) # convert x %>% sprintf(...) to sprintf(x, ...) if (length(xml_find_first(xml, in_pipe_xpath)) > 0L) { arg_names <- names(parsed_expr) arg_idx <- 2L:length(parsed_expr) parsed_expr[arg_idx + 1L] <- parsed_expr[arg_idx] names(parsed_expr)[arg_idx + 1L] <- arg_names[arg_idx] parsed_expr[[2L]] <- xml2lang(xml_find_first(xml, "preceding-sibling::*[2]")) names(parsed_expr)[2L] <- "" } parsed_expr <- zap_extra_args(parsed_expr) res <- tryCatch(eval(parsed_expr, envir = baseenv()), warning = identity, error = identity) if (inherits(res, "condition")) { conditionMessage(res) } else { NA_character_ } } Linter(linter_level = "file", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(c("sprintf", "gettextf")) sprintf_calls <- xml_find_all(xml_calls, call_xpath) sprintf_warning <- vapply(sprintf_calls, capture_sprintf_warning, character(1L)) has_warning <- !is.na(sprintf_warning) xml_nodes_to_lints( sprintf_calls[has_warning], source_expression = source_expression, lint_message = sprintf_warning[has_warning], type = "warning" ) }) } lintr/R/settings_utils.R0000644000176200001440000000562314752731051015021 0ustar liggesusershas_description <- function(path) { desc_info <- file.info(file.path(path, "DESCRIPTION")) !is.na(desc_info$size) && desc_info$size > 0.0 && !desc_info$isdir } has_rproj <- function(path) { length(Sys.glob(file.path(path, "*.Rproj"))) > 0L } find_package <- function(path, allow_rproj = FALSE, max_depth = 2L) { path <- normalize_path(path, mustWork = !allow_rproj) if (allow_rproj) { found <- function(path) has_description(path) || has_rproj(path) } else { found <- function(path) has_description(path) } depth <- max_depth while (!found(path)) { path <- dirname(path) if (is_root(path) || depth <= 0L) { return(NULL) } depth <- depth - 1L } path } find_rproj_at <- function(path) { head(Sys.glob(file.path(path, "*.Rproj")), n = 1L) } is_root <- function(path) { identical(path, dirname(path)) } is_directory <- function(filename) isTRUE(file.info(filename)$isdir) #' Return the first of a vector of files that exists. #' #' Avoid running 'expensive' [file.exists()] for the full vector, #' since typically the first entries will lead to early exit. #' TODO(#2204): check if the implementation should be simpler #' @noRd first_exists <- function(files) { for (file in files) { if (file.exists(file)) { return(file) } } NULL } find_config <- function(filename) { if (is.null(filename)) { return(NULL) } linter_file <- lintr_option("linter_file") ## if users changed lintr.linter_file, return immediately. if (is_absolute_path(linter_file) && file.exists(linter_file)) { return(linter_file) } path <- if (is_directory(filename)) { filename } else { dirname(filename) } path <- normalize_path(path, mustWork = FALSE) # NB: This vector specifies a priority order for where to find the configs, # i.e. the first location where a config exists is chosen and configs which # may exist in subsequent directories are ignored file_locations <- c( # Local (incl. parent) directories find_local_config(path, linter_file), # User directory # cf: rstudio@bc9b6a5 SessionRSConnect.R#L32 file.path(Sys.getenv("HOME", unset = "~"), linter_file), # Next check for a global config file file.path(R_user_dir("lintr", which = "config"), "config") ) first_exists(file_locations) } find_local_config <- function(path, config_file) { # R config gets precedence configs_to_check <- c(paste0(config_file, ".R"), config_file) repeat { guesses_in_dir <- c( file.path(path, configs_to_check), file.path(path, ".github", "linters", configs_to_check) ) found <- first_exists(guesses_in_dir) if (!is.null(found)) { return(found) } path <- dirname(path) if (is_root(path)) { return(character()) } } } pkg_name <- function(path = find_package()) { if (is.null(path)) { return(NULL) } read.dcf(file.path(path, "DESCRIPTION"), fields = "Package")[1L] } lintr/R/expect_null_linter.R0000644000176200001440000000422614752731051015636 0ustar liggesusers#' Require usage of `expect_null` for checking `NULL` #' #' Require usage of `expect_null(x)` over `expect_equal(x, NULL)` and similar #' usages. #' #' [testthat::expect_null()] exists specifically for testing for `NULL` objects. #' [testthat::expect_equal()], [testthat::expect_identical()], and #' [testthat::expect_true()] can also be used for such tests, #' but it is better to use the tailored function instead. #' #' @examples #' # will produce lints #' lint( #' text = "expect_equal(x, NULL)", #' linters = expect_null_linter() #' ) #' #' lint( #' text = "expect_identical(x, NULL)", #' linters = expect_null_linter() #' ) #' #' lint( #' text = "expect_true(is.null(x))", #' linters = expect_null_linter() #' ) #' #' #' # okay #' lint( #' text = "expect_null(x)", #' linters = expect_null_linter() #' ) #' #' @evalRd rd_tags("expect_null_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export expect_null_linter <- function() { # two cases two match: # (1) expect_{equal,identical}(x, NULL) (or NULL, x) # (2) expect_true(is.null(x)) expect_equal_identical_xpath <- " following-sibling::expr[position() <= 2 and NULL_CONST] /parent::expr " expect_true_xpath <- " following-sibling::expr[1][expr[1]/SYMBOL_FUNCTION_CALL[text() = 'is.null']] /parent::expr " Linter(linter_level = "expression", function(source_expression) { expect_equal_identical_calls <- source_expression$xml_find_function_calls(c("expect_equal", "expect_identical")) expect_true_calls <- source_expression$xml_find_function_calls("expect_true") bad_expr <- combine_nodesets( xml_find_all(expect_equal_identical_calls, expect_equal_identical_xpath), xml_find_all(expect_true_calls, expect_true_xpath) ) matched_function <- xp_call_name(bad_expr) msg <- ifelse( matched_function %in% c("expect_equal", "expect_identical"), sprintf("expect_null(x) is better than %s(x, NULL)", matched_function), "expect_null(x) is better than expect_true(is.null(x))" ) xml_nodes_to_lints( bad_expr, source_expression, lint_message = msg, type = "warning" ) }) } lintr/R/fixed_regex_linter.R0000644000176200001440000001250414752731051015603 0ustar liggesusers#' Require usage of `fixed=TRUE` in regular expressions where appropriate #' #' Invoking a regular expression engine is overkill for cases when the search #' pattern only involves static patterns. #' #' NB: for `stringr` functions, that means wrapping the pattern in `stringr::fixed()`. #' #' NB: this linter is likely not able to distinguish every possible case when #' a fixed regular expression is preferable, rather it seeks to identify #' likely cases. It should _never_ report false positives, however; please #' report false positives as an error. #' #' @param allow_unescaped Logical, default `FALSE`. If `TRUE`, only patterns that #' require regex escapes (e.g. `"\\$"` or `"[$]"`) will be linted. See examples. #' @examples #' # will produce lints #' code_lines <- 'gsub("\\\\.", "", x)' #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = fixed_regex_linter() #' ) #' #' lint( #' text = 'grepl("a[*]b", x)', #' linters = fixed_regex_linter() #' ) #' #' lint( #' text = 'grepl("a[*]b", x)', #' linters = fixed_regex_linter(allow_unescaped = TRUE) #' ) #' #' code_lines <- 'stringr::str_subset(x, "\\\\$")' #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = fixed_regex_linter() #' ) #' #' lint( #' text = 'grepl("Munich", address)', #' linters = fixed_regex_linter() #' ) #' #' # okay #' code_lines <- 'gsub("\\\\.", "", x, fixed = TRUE)' #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = fixed_regex_linter() #' ) #' #' lint( #' text = 'grepl("a*b", x, fixed = TRUE)', #' linters = fixed_regex_linter() #' ) #' #' lint( #' text = 'stringr::str_subset(x, stringr::fixed("$"))', #' linters = fixed_regex_linter() #' ) #' #' lint( #' text = 'grepl("Munich", address, fixed = TRUE)', #' linters = fixed_regex_linter() #' ) #' #' lint( #' text = 'grepl("Munich", address)', #' linters = fixed_regex_linter(allow_unescaped = TRUE) #' ) #' #' @evalRd rd_tags("fixed_regex_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export fixed_regex_linter <- function(allow_unescaped = FALSE) { # regular expression pattern is the first argument pos_1_regex_funs <- c( "grep", "gsub", "sub", "regexec", "grepl", "regexpr", "gregexpr" ) # regular expression pattern is the second argument pos_2_regex_funs <- c( # base functions. "strsplit", # data.table functions. "tstrsplit", # stringr functions. # even though the user action is different # (setting fixed=TRUE vs. wrapping stringr::fixed()), # detection of the lint is the same "str_count", "str_detect", "str_ends", "str_extract", "str_extract_all", "str_locate", "str_locate_all", "str_match", "str_match_all", "str_remove", "str_remove_all", "str_replace", "str_replace_all", "str_split", "str_starts", "str_subset", "str_view", "str_view_all", "str_which" ) pipes <- setdiff(magrittr_pipes, c("%$%", "%T>%")) in_pipe_cond <- glue(" parent::expr/preceding-sibling::SPECIAL[{ xp_text_in_table(pipes) }] | parent::expr/preceding-sibling::PIPE ") # NB: strsplit doesn't have an ignore.case argument # NB: we intentionally exclude cases like gsub(x, c("a" = "b")), where "b" is fixed pos_1_xpath <- glue(" self::*[ not(following-sibling::SYMBOL_SUB[ (text() = 'fixed' or text() = 'ignore.case') and following-sibling::expr[1][NUM_CONST[text() = 'TRUE'] or SYMBOL[text() = 'T']] ]) ] /following-sibling::expr[ ( position() = 1 and STR_CONST and not(EQ_SUB) and not({ in_pipe_cond }) ) or ( STR_CONST and preceding-sibling::*[2][self::SYMBOL_SUB/text() = 'pattern'] ) ] ") pos_2_xpath <- glue(" self::*[ not(following-sibling::SYMBOL_SUB[ text() = 'fixed' and following-sibling::expr[1][NUM_CONST[text() = 'TRUE'] or SYMBOL[text() = 'T']] ]) ] /following-sibling::expr[ position() = 2 - count({ in_pipe_cond }) and STR_CONST and not(EQ_SUB) ] ") Linter(linter_level = "expression", function(source_expression) { pos_1_calls <- source_expression$xml_find_function_calls(pos_1_regex_funs) pos_2_calls <- source_expression$xml_find_function_calls(pos_2_regex_funs) patterns <- combine_nodesets( xml_find_all(pos_1_calls, pos_1_xpath), xml_find_all(pos_2_calls, pos_2_xpath) ) pattern_strings <- get_r_string(patterns) is_static <- is_not_regex(pattern_strings, allow_unescaped) patterns <- patterns[is_static] pattern_strings <- pattern_strings[is_static] fixed_equivalent <- encodeString(get_fixed_string(pattern_strings), quote = '"', justify = "none") call_name <- xml_find_chr(patterns, "string(preceding-sibling::expr[last()]/SYMBOL_FUNCTION_CALL)") is_stringr <- startsWith(call_name, "str_") replacement_suggestion <- ifelse( is_stringr, sprintf("stringr::fixed(%s) as the pattern", fixed_equivalent), sprintf("%s with fixed = TRUE", fixed_equivalent) ) msg <- paste( "Use", replacement_suggestion, "here. This regular expression is static, i.e.,", "its matches can be expressed as a fixed substring expression, which is faster to compute." ) xml_nodes_to_lints( patterns, source_expression = source_expression, lint_message = msg, type = "warning" ) }) } lintr/R/AAA.R0000644000176200001440000000172314752731051012320 0ustar liggesusers#' @include utils.R #' @include xp_utils.R #' @include make_linter_from_xpath.R NULL #' Available linters #' @name linters #' #' @description A variety of linters are available in \pkg{lintr}. The most popular ones are readily #' accessible through [default_linters()]. #' #' Within a [lint()] function call, the linters in use are initialized with the provided #' arguments and fed with the source file (provided by [get_source_expressions()]). #' #' A data frame of all available linters can be retrieved using [available_linters()]. #' Documentation for linters is structured into tags to allow for easier discovery; #' see also [available_tags()]. #' #' @evalRd rd_taglist() #' @evalRd rd_linterlist() NULL # need to register rex shortcuts as globals to avoid CRAN check errors rex::register_shortcuts("lintr") globalVariables( c( "line1", "col1", "line2", "col2", # columns of parsed_content "id", "parent", "token", "terminal", "text" # ditto ), "lintr" ) lintr/R/function_argument_linter.R0000644000176200001440000000431314752731051017040 0ustar liggesusers#' Function argument linter #' #' @description #' Check that arguments with defaults come last in all function declarations, #' as per the tidyverse design guide. #' #' Changing the argument order can be a breaking change. An alternative to changing the argument order #' is to instead set the default for such arguments to `NULL`. #' #' @examples #' # will produce lints #' lint( #' text = "function(y = 1, z = 2, x) {}", #' linters = function_argument_linter() #' ) #' #' lint( #' text = "function(x, y, z = 1, ..., w) {}", #' linters = function_argument_linter() #' ) #' #' # okay #' lint( #' text = "function(x, y = 1, z = 2) {}", #' linters = function_argument_linter() #' ) #' #' lint( #' text = "function(x, y, w, z = 1, ...) {}", #' linters = function_argument_linter() #' ) #' #' lint( #' text = "function(y = 1, z = 2, x = NULL) {}", #' linters = function_argument_linter() #' ) #' #' lint( #' text = "function(x, y, z = 1, ..., w = NULL) {}", #' linters = function_argument_linter() #' ) #' #' @evalRd rd_tags("function_argument_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export function_argument_linter <- function() { xpath <- " (//FUNCTION | //OP-LAMBDA) /following-sibling::EQ_FORMALS[1] /following-sibling::SYMBOL_FORMALS[ text() != '...' and not(following-sibling::*[not(self::COMMENT)][1][self::EQ_FORMALS]) ] " used_in_missing_xpath <- " text() = following-sibling::expr[last()]//expr[expr/SYMBOL_FUNCTION_CALL[text() = 'missing']]/expr[2]/SYMBOL/text() " Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) uses_missing <- xml_find_lgl(bad_expr, used_in_missing_xpath) missing_note <- ifelse(uses_missing, " Consider setting the default to NULL and using is.null() instead of using missing()", "") xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = paste0("Arguments without defaults should come before arguments with defaults.", missing_note), type = "style" ) }) } lintr/R/T_and_F_symbol_linter.R0000644000176200001440000000426014752731051016171 0ustar liggesusers#' `T` and `F` symbol linter #' #' Although they can be synonyms, avoid the symbols `T` and `F`, and use `TRUE` and `FALSE`, respectively, instead. #' `T` and `F` are not reserved keywords and can be assigned to any other values. #' #' @examples #' # will produce lints #' lint( #' text = "x <- T; y <- F", #' linters = T_and_F_symbol_linter() #' ) #' #' lint( #' text = "T = 1.2; F = 2.4", #' linters = T_and_F_symbol_linter() #' ) #' #' # okay #' lint( #' text = "x <- c(TRUE, FALSE)", #' linters = T_and_F_symbol_linter() #' ) #' #' lint( #' text = "t = 1.2; f = 2.4", #' linters = T_and_F_symbol_linter() #' ) #' #' @evalRd rd_tags("T_and_F_symbol_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export T_and_F_symbol_linter <- function() { # nolint: object_name. symbol_xpath <- "//SYMBOL[ (text() = 'T' or text() = 'F') and not(parent::expr[OP-DOLLAR or OP-AT]) ]" assignment_xpath <- "parent::expr[following-sibling::LEFT_ASSIGN or preceding-sibling::RIGHT_ASSIGN or following-sibling::EQ_ASSIGN]" usage_xpath <- sprintf("%s[not(%s)]", symbol_xpath, assignment_xpath) assignment_xpath <- sprintf("%s[%s]", symbol_xpath, assignment_xpath) replacement_map <- c(T = "TRUE", F = "FALSE") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_usage <- xml_find_all(xml, usage_xpath) bad_assignment <- xml_find_all(xml, assignment_xpath) make_lints <- function(expr, fmt) { symbol <- xml_text(expr) lint_message <- sprintf(fmt, replacement_map[symbol], symbol) xml_nodes_to_lints( xml = expr, source_expression = source_expression, lint_message = lint_message, type = "style", column_number_xpath = "number(./@col2 + 1)", # mark at end range_end_xpath = "number(./@col2 + 1)" # end after T/F for easy fixing ) } c( make_lints(bad_usage, "Use %s instead of the symbol %s."), make_lints(bad_assignment, "Don't use %2$s as a variable name, as it can break code relying on %2$s being %1$s.") ) }) } lintr/R/unreachable_code_linter.R0000644000176200001440000001355514752731051016564 0ustar liggesusers#' Block unreachable code and comments following return statements #' #' Code after e.g. a [return()] or [stop()] #' or in deterministically false conditional loops like `if (FALSE)` can't be reached; #' typically this is vestigial code left after refactoring or sandboxing code, which #' is fine for exploration, but shouldn't ultimately be checked in. Comments #' meant for posterity should be placed *before* the final `return()`. #' #' @param allow_comment_regex Character vector of regular expressions which identify #' comments to exclude when finding unreachable terminal comments. By default, this #' includes the default "skip region" end marker for `{covr}` #' (option "covr.exclude_end", or `"# nocov end"` if unset). #' The end marker for `{lintr}` (`settings$exclude_end`) is always included. #' Note that the regexes should include the initial comment character `#`. #' #' @examples #' # will produce lints #' code_lines <- "f <- function() {\n return(1 + 1)\n 2 + 2\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unreachable_code_linter() #' ) #' #' code_lines <- "if (FALSE) {\n 2 + 2\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unreachable_code_linter() #' ) #' #' code_lines <- "while (FALSE) {\n 2 + 2\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unreachable_code_linter() #' ) #' #' code_lines <- "f <- function() {\n return(1)\n # end skip\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unreachable_code_linter() #' ) #' #' # okay #' code_lines <- "f <- function() {\n return(1 + 1)\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unreachable_code_linter() #' ) #' #' code_lines <- "if (foo) {\n 2 + 2\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unreachable_code_linter() #' ) #' #' code_lines <- "while (foo) {\n 2 + 2\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unreachable_code_linter() #' ) #' #' code_lines <- "f <- function() {\n return(1)\n # end skip\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = unreachable_code_linter(allow_comment_regex = "# end skip") #' ) #' #' @evalRd rd_tags("unreachable_code_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export unreachable_code_linter <- function(allow_comment_regex = getOption("covr.exclude_end", "# nocov end")) { expr_after_control <- " (//REPEAT | //ELSE | //FOR)/following-sibling::expr[1] | (//IF | //WHILE)/following-sibling::expr[2] " # NB: use not(OP-DOLLAR) to prevent matching process$stop(), #1051 xpath_return_stop <- glue(" ( {expr_after_control} | (//FUNCTION | //OP-LAMBDA)[following-sibling::expr[1]/*[1][self::OP-LEFT-BRACE]]/following-sibling::expr[1] ) /expr[expr[1][ not(OP-DOLLAR or OP-AT) and SYMBOL_FUNCTION_CALL[text() = 'return' or text() = 'stop'] ]] /following-sibling::*[ not(self::OP-RIGHT-BRACE or self::OP-SEMICOLON) and (not(self::COMMENT) or @line2 > preceding-sibling::*[1]/@line2) ][1] ") xpath_next_break <- glue(" ({expr_after_control}) /expr[NEXT or BREAK] /following-sibling::*[ not(self::OP-RIGHT-BRACE or self::OP-SEMICOLON) and (not(self::COMMENT) or @line2 > preceding-sibling::*[1]/@line2) ][1] ") xpath_if_while <- " (//WHILE | //IF)[following-sibling::expr[1]/NUM_CONST[text() = 'FALSE']] /parent::expr " xpath_else <- " //IF[following-sibling::expr[1]/NUM_CONST[text() = 'TRUE']] /following-sibling::ELSE/following-sibling::expr[1] " handle_inline_conditions <- function(expr) { expr <- lapply( expr, function(x) { if (xml_name(xml2::xml_child(x)) == "OP-LEFT-BRACE") { xml_find_first(x, "expr") } else { x } } ) expr[vapply(expr, xml2::xml_length, integer(1L)) != 0L] } drop_valid_comments <- function(expr, valid_comment_re) { is_valid_comment <- xml2::xml_name(expr) == "COMMENT" & re_matches_logical(xml_text(expr), valid_comment_re) expr[!is_valid_comment] } Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content # run here because 'settings$exclude_end' may not be set correctly at "compile time". # also build with '|', not rex::rex(or(.)), the latter which will double-escape the regex. allow_comment_regex <- paste(union(allow_comment_regex, settings$exclude_end), collapse = "|") expr_return_stop <- xml_find_all(xml, xpath_return_stop) lints_return_stop <- xml_nodes_to_lints( drop_valid_comments(expr_return_stop, allow_comment_regex), source_expression = source_expression, lint_message = "Remove code and comments coming after return() or stop().", type = "warning" ) expr_next_break <- xml_find_all(xml, xpath_next_break) lints_next_break <- xml_nodes_to_lints( drop_valid_comments(expr_next_break, allow_comment_regex), source_expression = source_expression, lint_message = "Remove code and comments coming after `next` or `break`.", type = "warning" ) expr_if_while <- handle_inline_conditions(xml_find_all(xml, xpath_if_while)) lints_if_while <- xml_nodes_to_lints( expr_if_while, source_expression = source_expression, lint_message = "Remove code inside a conditional loop with a deterministically false condition.", type = "warning" ) expr_else <- handle_inline_conditions(xml_find_all(xml, xpath_else)) lints_else <- xml_nodes_to_lints( expr_else, source_expression = source_expression, lint_message = "Remove code inside an else block after a deterministically true condition.", type = "warning" ) c(lints_return_stop, lints_next_break, lints_if_while, lints_else) }) } lintr/R/paste_linter.R0000644000176200001440000002632614752731051014435 0ustar liggesusers#' Raise lints for several common poor usages of `paste()` #' #' @description #' #' The following issues are linted by default by this linter #' (see arguments for which can be de-activated optionally): #' #' 1. Block usage of [paste()] with `sep = ""`. [paste0()] is a faster, more concise alternative. #' 2. Block usage of `paste()` or `paste0()` with `collapse = ", "`. [toString()] is a direct #' wrapper for this, and alternatives like [glue::glue_collapse()] might give better messages for humans. #' 3. Block usage of `paste0()` that supplies `sep=` -- this is not a formal argument to `paste0`, and #' is likely to be a mistake. #' 4. Block usage of `paste()` / `paste0()` combined with [rep()] that could be replaced by #' [strrep()]. `strrep()` can handle the task of building a block of repeated strings #' (e.g. often used to build "horizontal lines" for messages). This is both more readable and #' skips the (likely small) overhead of putting two strings into the global string cache when only one is needed. #' #' Only target scalar usages -- `strrep` can handle more complicated cases (e.g. `strrep(letters, 26:1)`, #' but those aren't as easily translated from a `paste(collapse=)` call. #' #' @evalRd rd_tags("paste_linter") #' @param allow_empty_sep Logical, default `FALSE`. If `TRUE`, usage of #' `paste()` with `sep = ""` is not linted. #' @param allow_to_string Logical, default `FALSE`. If `TRUE`, usage of #' `paste()` and `paste0()` with `collapse = ", "` is not linted. #' @param allow_file_path String, one of `"never"`, `"double_slash"`, or `"always"`; `"double_slash"` by default. #' If `"never"`, usage of `paste()` and `paste0()` to construct file paths is not linted. If `"double_slash"`, #' strings containing consecutive forward slashes will not lint. The main use case here is for URLs -- "paths" like #' `"https://"` will not induce lints, since constructing them with `file.path()` might be deemed unnatural. #' Lastly, if `"always"`, strings with consecutive forward slashes will also lint. Note that `"//"` is never linted #' when it comes at the beginning or end of the input, to avoid requiring empty inputs like #' `file.path("", ...)` or `file.path(..., "")`. #' #' @examples #' # will produce lints #' lint( #' text = 'paste("a", "b", sep = "")', #' linters = paste_linter() #' ) #' #' lint( #' text = 'paste(c("a", "b"), collapse = ", ")', #' linters = paste_linter() #' ) #' #' lint( #' text = 'paste0(c("a", "b"), sep = " ")', #' linters = paste_linter() #' ) #' #' lint( #' text = 'paste0(rep("*", 10L), collapse = "")', #' linters = paste_linter() #' ) #' #' lint( #' text = 'paste0("http://site.com/", path)', #' linters = paste_linter(allow_file_path = "never") #' ) #' #' lint( #' text = 'paste0(x, collapse = "")', #' linters = paste_linter() #' ) #' #' # okay #' lint( #' text = 'paste0("a", "b")', #' linters = paste_linter() #' ) #' #' lint( #' text = 'paste("a", "b", sep = "")', #' linters = paste_linter(allow_empty_sep = TRUE) #' ) #' #' lint( #' text = 'toString(c("a", "b"))', #' linters = paste_linter() #' ) #' #' lint( #' text = 'paste(c("a", "b"), collapse = ", ")', #' linters = paste_linter(allow_to_string = TRUE) #' ) #' #' lint( #' text = 'paste(c("a", "b"))', #' linters = paste_linter() #' ) #' #' lint( #' text = 'strrep("*", 10L)', #' linters = paste_linter() #' ) #' #' lint( #' text = 'paste0(year, "/", month, "/", day)', #' linters = paste_linter(allow_file_path = "always") #' ) #' #' lint( #' text = 'paste0("http://site.com/", path)', #' linters = paste_linter() #' ) #' #' lint( #' text = 'paste(x, collapse = "")', #' linters = paste_linter() #' ) #' #' @seealso [linters] for a complete list of linters available in lintr. #' @export paste_linter <- function(allow_empty_sep = FALSE, allow_to_string = FALSE, allow_file_path = c("double_slash", "always", "never")) { allow_file_path <- match.arg(allow_file_path) check_file_paths <- allow_file_path %in% c("double_slash", "never") paste_sep_xpath <- " following-sibling::SYMBOL_SUB[text() = 'sep' and following-sibling::expr[1][STR_CONST]] /parent::expr " to_string_xpath <- " parent::expr[ count(expr) = 3 and SYMBOL_SUB[text() = 'collapse']/following-sibling::expr[1][STR_CONST] ]" paste0_sep_xpath <- " following-sibling::SYMBOL_SUB[text() = 'sep'] /parent::expr " paste_strrep_xpath <- " self::*[ count(following-sibling::expr) = 2 and following-sibling::expr[1][expr[1][SYMBOL_FUNCTION_CALL[text() = 'rep']] and expr[2][STR_CONST]] and following-sibling::SYMBOL_SUB[text() = 'collapse'] ] /parent::expr " # Type II: paste0(x, "/", y, "/", z) # NB: some conditions require evaluating the R string, only a few can be done in pure XPath. See below. paste0_file_path_xpath <- xp_strip_comments(" parent::expr[ (: exclude paste0(x) :) count(expr) > 2 (: An expression matching _any_ of these conditions is _not_ a file path :) and not( (: Any numeric input :) expr/NUM_CONST (: A call using collapse= :) or SYMBOL_SUB[text() = 'collapse'] (: Consecutive non-strings like paste0(x, y) :) or expr[(SYMBOL or expr) and following-sibling::expr[1][SYMBOL or expr]] ) ]") empty_paste_note <- 'Note that paste() converts empty inputs to "", whereas file.path() leaves it empty.' paste0_collapse_xpath <- glue::glue(" parent::expr[ SYMBOL_SUB[text() = 'collapse'] and count(expr) = 3 - count(preceding-sibling::*[self::PIPE or self::SPECIAL[{ xp_text_in_table(magrittr_pipes) }]]) and not(expr/SYMBOL[text() = '...']) ]") Linter(linter_level = "expression", function(source_expression) { paste_calls <- source_expression$xml_find_function_calls("paste") paste0_calls <- source_expression$xml_find_function_calls("paste0") both_calls <- combine_nodesets(paste_calls, paste0_calls) optional_lints <- list() # Both of these look for paste(..., sep = "..."), differing in which 'sep' is linted, # so run the expensive XPath search/R parse only once if (!allow_empty_sep || check_file_paths) { paste_sep_expr <- xml_find_all(paste_calls, paste_sep_xpath) paste_sep_value <- get_r_string(paste_sep_expr, xpath = "./SYMBOL_SUB[text() = 'sep']/following-sibling::expr[1]") } if (!allow_empty_sep) { optional_lints <- c(optional_lints, xml_nodes_to_lints( paste_sep_expr[!nzchar(paste_sep_value)], source_expression = source_expression, lint_message = 'paste0(...) is better than paste(..., sep = "").', type = "warning" )) } if (!allow_to_string) { # 3 expr: the function call, the argument, and collapse= to_string_expr <- xml_find_all(both_calls, to_string_xpath) collapse_value <- get_r_string( to_string_expr, xpath = "./SYMBOL_SUB[text() = 'collapse']/following-sibling::expr[1]" ) optional_lints <- c(optional_lints, xml_nodes_to_lints( to_string_expr[collapse_value == ", "], source_expression = source_expression, lint_message = paste( 'toString(.) is more expressive than paste(., collapse = ", ").', "Note also glue::glue_collapse() and and::and()", "for constructing human-readable / translation-friendly lists" ), type = "warning" )) } paste0_sep_expr <- xml_find_all(paste0_calls, paste0_sep_xpath) paste0_sep_lints <- xml_nodes_to_lints( paste0_sep_expr, source_expression = source_expression, lint_message = "sep= is not a formal argument to paste0(); did you mean to use paste(), or collapse=?", type = "warning" ) paste_strrep_expr <- xml_find_all(both_calls, paste_strrep_xpath) collapse_arg <- get_r_string(paste_strrep_expr, "SYMBOL_SUB/following-sibling::expr[1]/STR_CONST") paste_strrep_expr <- paste_strrep_expr[!nzchar(collapse_arg)] paste_call <- xp_call_name(paste_strrep_expr) paste_strrep_lints <- xml_nodes_to_lints( paste_strrep_expr, source_expression = source_expression, lint_message = sprintf('strrep(x, times) is better than %s(rep(x, times), collapse = "").', paste_call), type = "warning" ) paste0_collapse_expr <- xml_find_all(paste0_calls, paste0_collapse_xpath) paste0_collapse_lints <- xml_nodes_to_lints( paste0_collapse_expr, source_expression = source_expression, lint_message = "Use paste(), not paste0(), to collapse a character vector when sep= is not used.", type = "warning" ) if (check_file_paths) { paste_sep_slash_expr <- paste_sep_expr[paste_sep_value == "/"] optional_lints <- c(optional_lints, xml_nodes_to_lints( # in addition to paste(..., sep = "/") we ensure collapse= is not present paste_sep_slash_expr[is.na(xml_find_first(paste_sep_slash_expr, "./SYMBOL_SUB[text() = 'collapse']"))], source_expression = source_expression, lint_message = paste( 'Construct file paths with file.path(...) instead of paste(..., sep = "/").', 'If you are using paste(sep = "/") to construct a date,', "consider using format() or lubridate helpers instead.", empty_paste_note ), type = "warning" )) paste0_file_path_expr <- xml_find_all(paste0_calls, paste0_file_path_xpath) is_file_path <- !vapply(paste0_file_path_expr, check_is_not_file_path, logical(1L), allow_file_path = allow_file_path) optional_lints <- c(optional_lints, xml_nodes_to_lints( paste0_file_path_expr[is_file_path], source_expression = source_expression, lint_message = paste( 'Construct file paths with file.path(...) instead of paste0(x, "/", y, "/", z).', empty_paste_note ), type = "warning" )) } c(optional_lints, paste0_sep_lints, paste_strrep_lints, paste0_collapse_lints) }) } check_is_not_file_path <- function(expr, allow_file_path) { arguments <- xml_find_all(expr, "expr[position() > 1]") is_string <- !is.na(xml_find_first(arguments, "STR_CONST")) string_values <- character(length(arguments)) string_values[is_string] <- get_r_string(arguments[is_string]) not_start_slash <- which(!startsWith(string_values, "/")) not_end_slash <- which(!endsWith(string_values, "/")) if (allow_file_path == "double_slash") { check_double_slash <- function(str) any(grepl("//", str, fixed = TRUE)) } else { # always skip on strings starting/ending with //, since switching to # file.path() would require file.path("", ...) or file.path(..., "") check_double_slash <- function(str) any(grepl("^//|//$", str)) } # First input is '/', meaning file.path() would need to start with '' string_values[1L] == "/" || # Last input is '/', meaning file.path() would need to end with '' string_values[length(string_values)] == "/" || check_double_slash(string_values) || # A string not ending with /, followed by non-string, # or a string not starting with /, preceded by a non-string !all(is_string[c(not_end_slash + 1L, not_start_slash - 1L)], na.rm = TRUE) || # A string not starting with / preceded by a string not ending with / any(not_start_slash %in% (not_end_slash + 1L)) } lintr/R/exclude.R0000644000176200001440000003421314752731051013367 0ustar liggesusers#' Exclude lines or files from linting #' #' @param lints that need to be filtered. #' @param exclusions manually specified exclusions #' @param linter_names character vector of names of the active linters, used for parsing inline exclusions. #' @param ... additional arguments passed to [parse_exclusions()] #' @eval c( #' # we use @eval for the details section to avoid a literal nolint exclusion tag with non-existing linter names #' # those produce a warning from [parse_exclusions()] otherwise. See #1219 for details. #' "@details", #' "Exclusions can be specified in three different ways.", #' "", #' "1. Single line in the source file. default: `# nolint`, possibly followed by a listing of linters to exclude.", #' " If the listing is missing, all linters are excluded on that line. The default listing format is", #' paste( #' " `#", #' "nolint: linter_name, linter2_name.`. There may not be anything between the colon and the line exclusion tag" #' ), #' " and the listing must be terminated with a full stop (`.`) for the linter list to be respected.", #' "2. Line range in the source file. default: `# nolint start`, `# nolint end`. `# nolint start` accepts linter", #' " lists in the same form as `# nolint`.", #' "3. Exclusions parameter, a list with named and/or unnamed entries. ", #' " Outer elements have the following characteristics:", #' " 1. Unnamed elements specify filenames or directories.", #' " 2. Named elements are a vector or list of line numbers, with `Inf` indicating 'all lines'.", #' " The name gives a path relative to the config.", #' " 1. Unnamed elements denote exclusion of all linters in the given path or directory.", #' " 2. Named elements, where the name specifies a linter, denote exclusion for that linter.", #' " For convenience, a vector can be used in place of a list whenever it would not introduce ambiguity, e.g.", #' " a character vector of files to exclude or a vector of lines to exclude.", #' NULL #' ) #' #' @keywords internal exclude <- function(lints, exclusions = settings$exclusions, linter_names = NULL, ...) { if (length(lints) <= 0L) { return(lints) } lint_df <- as.data.frame(lints) filenames <- unique(lint_df$filename) source_exclusions <- lapply(filenames, parse_exclusions, linter_names = linter_names, ...) names(source_exclusions) <- filenames exclusions <- normalize_exclusions(c(source_exclusions, exclusions)) to_exclude <- vapply( seq_len(nrow(lint_df)), function(i) { filename <- lint_df$filename[i] filename %in% names(exclusions) && is_excluded(lint_df$line_number[i], lint_df$linter[i], exclusions[[filename]]) }, logical(1L) ) if (any(to_exclude)) { lints <- lints[!to_exclude] } lints } is_excluded <- function(line_number, linter, file_exclusion) { excluded_lines <- unlist(file_exclusion[names2(file_exclusion) %in% c("", linter)]) Inf %in% excluded_lines || line_number %in% excluded_lines } is_excluded_file <- function(file_exclusion) { any(vapply( file_exclusion[!nzchar(names2(file_exclusion))], function(full_exclusion) Inf %in% full_exclusion, logical(1L) )) } line_info <- function(line_numbers, type = c("start", "end")) { type <- match.arg(type) range_word <- paste0("range ", type, if (length(line_numbers) != 1L) "s") n <- length(line_numbers) if (n == 0L) { paste("0", range_word) } else if (n == 1L) { paste0("1 ", range_word, " (line ", line_numbers, ")") } else { paste0(n, " ", range_word, " (lines ", toString(line_numbers), ")") } } #' read a source file and parse all the excluded lines from it #' #' @param file R source file #' @param exclude Regular expression used to mark lines to exclude. #' @param exclude_next Regular expression used to mark lines immediately preceding excluded lines. #' @param exclude_start Regular expression used to mark the start of an excluded range. #' @param exclude_end Regular expression used to mark the end of an excluded range. #' @param exclude_linter Regular expression used to capture a list of to-be-excluded linters immediately following a #' `exclude` or `exclude_start` marker. #' @param exclude_linter_sep Regular expression used to split a linter list into individual linter names for exclusion. #' @param lines A character vector of the content lines of `file`. #' @param linter_names Names of active linters. #' #' @return A possibly named list of excluded lines, possibly for specific linters. #' @keywords internal parse_exclusions <- function(file, exclude = settings$exclude, exclude_next = settings$exclude_next, exclude_start = settings$exclude_start, exclude_end = settings$exclude_end, exclude_linter = settings$exclude_linter, exclude_linter_sep = settings$exclude_linter_sep, lines = NULL, linter_names = NULL) { if (is.null(lines)) { lines <- read_lines(file) } exclusions <- list() if (is_tainted(lines)) { # Invalid encoding. Don't parse exclusions. return(list()) } start_locations <- re_matches(lines, exclude_start, locations = TRUE)[, "end"] + 1L end_locations <- re_matches(lines, exclude_end, locations = TRUE)[, "start"] starts <- which(!is.na(start_locations)) ends <- which(!is.na(end_locations)) if (length(starts) > 0L) { if (length(starts) != length(ends)) { starts_msg <- line_info(starts, type = "start") # nolint: object_usage_linter. TODO(#2252). ends_msg <- line_info(ends, type = "end") # nolint: object_usage_linter. TODO(#2252). cli_abort(c( i = "Equal number of line starts and ends expected for exclusion from linting.", x = "{.file {file}} has {.strong {starts_msg}} and {.strong {ends_msg}}." )) } for (i in seq_along(starts)) { excluded_lines <- seq(starts[i], ends[i]) linters_string <- substring(lines[starts[i]], start_locations[starts[i]]) linters_string <- re_matches(linters_string, exclude_linter)[, 1L] exclusions <- add_exclusions(exclusions, excluded_lines, linters_string, exclude_linter_sep, linter_names) } } next_locations <- re_matches(lines, exclude_next, locations = TRUE)[, "end"] + 1L nexts <- which(!is.na(next_locations)) nolint_locations <- re_matches(lines, exclude, locations = TRUE)[, "end"] + 1L nolints <- which(!is.na(nolint_locations)) # Disregard nolint tags if they also match nolint next / start / end nolints <- setdiff(nolints, c(nexts, starts, ends)) for (nolint in nolints) { linters_string <- get_linters_string(lines[nolint], nolint_locations[nolint], exclude_linter) exclusions <- add_exclusions(exclusions, nolint, linters_string, exclude_linter_sep, linter_names) } for (nextt in nexts) { linters_string <- get_linters_string(lines[nextt], next_locations[nextt], exclude_linter) exclusions <- add_exclusions(exclusions, nextt + 1L, linters_string, exclude_linter_sep, linter_names) } exclusions[] <- lapply(exclusions, function(lines) sort(unique(lines))) exclusions } get_linters_string <- function(line, loc, exclude_linter) { linters_string <- substring(line, loc) re_matches(linters_string, exclude_linter)[, 1L] } add_excluded_lines <- function(exclusions, excluded_lines, excluded_linters) { for (linter in excluded_linters) { if (linter %in% names2(exclusions)) { i <- which(names2(exclusions) %in% linter) exclusions[[i]] <- c(exclusions[[i]], excluded_lines) } else { exclusions <- c(exclusions, list(excluded_lines)) if (nzchar(linter)) { if (is.null(names(exclusions))) { # Repair names if linter == "" is the first exclusion added. names(exclusions) <- "" } names(exclusions)[length(exclusions)] <- linter } } } exclusions } add_exclusions <- function(exclusions, lines, linters_string, exclude_linter_sep, linter_names) { # No match for linter list: Add to global excludes if (is.na(linters_string)) { exclusions <- add_excluded_lines(exclusions, lines, "") } else { # Matched a linter list: only add excluded lines for the listed linters. excluded_linters <- strsplit(linters_string, exclude_linter_sep)[[1L]] if (!is.null(linter_names)) { idxs <- pmatch(excluded_linters, linter_names, duplicates.ok = TRUE) matched <- !is.na(idxs) if (!all(matched)) { bad <- excluded_linters[!matched] # nolint: object_usage_linter. TODO(#2252). cli_warn(c( x = "Could not find linter{?s} named {.field {bad}} in the list of active linters.", i = "Make sure the linter is uniquely identified by the given name or prefix." )) } excluded_linters[matched] <- linter_names[idxs[matched]] } exclusions <- add_excluded_lines(exclusions, lines, excluded_linters) } exclusions } #' Normalize lint exclusions #' #' @param x Exclusion specification #' - A character vector of filenames or directories relative to `root` #' - A named list of integers specifying lines to be excluded per file #' - A named list of named lists specifying linters and lines to be excluded for the linters per file. #' @param normalize_path Should the names of the returned exclusion list be normalized paths? #' If no, they will be relative to `root`. #' @param root Base directory for relative filename resolution. #' @param pattern If non-NULL, only exclude files in excluded directories if they match #' `pattern`. Passed to [list.files][base::list.files] if a directory is excluded. #' #' @return A named list of file exclusions. #' The names of the list specify the filenames to be excluded. #' #' Each file exclusion is a possibly named list containing line numbers to exclude, or the sentinel `Inf` for #' completely excluded files. If the an entry is named, the exclusions only take effect for the linter with the same #' name. #' #' If `normalize_path` is `TRUE`, file names will be normalized relative to `root`. #' Otherwise the paths are left as provided (relative to `root` or absolute). #' #' @keywords internal normalize_exclusions <- function(x, normalize_path = TRUE, root = getwd(), pattern = NULL) { if (is.null(x) || length(x) <= 0L) { return(list()) } x <- as.list(x) unnamed <- !nzchar(names2(x)) if (any(unnamed)) { bad <- vapply( seq_along(x), function(i) { unnamed[i] && (!is.character(x[[i]]) || length(x[[i]]) != 1L) }, logical(1L) ) if (any(bad)) { cli_abort(c( i = "Full file exclusions must be {.cls character} vectors of length 1.", x = "Items at the following indices are not: {.val {which(bad)}}." )) } # Normalize unnamed entries to list( = list(Inf), ...) names(x)[unnamed] <- x[unnamed] x[unnamed] <- rep_len(list(list(Inf)), sum(unnamed)) } full_line_exclusions <- !vapply(x, is.list, logical(1L)) if (any(full_line_exclusions)) { # must be integer or numeric vectors are_numeric <- vapply(x, is.numeric, logical(1L)) bad <- full_line_exclusions & !are_numeric if (any(bad)) { cli_abort(c( i = "Full line exclusions must be {.cls numeric} or {.cls integer} vectors.", x = "Items at the following indices are not: {.val {which(bad)}}." )) } # Normalize list( = c()) to # list( = list(c())) x[full_line_exclusions] <- lapply(x[full_line_exclusions], list) } paths <- names(x) rel_path <- !is_absolute_path(paths) paths[rel_path] <- file.path(root, paths[rel_path]) is_dir <- dir.exists(paths) if (any(is_dir)) { dirs <- names(x)[is_dir] x <- x[!is_dir] all_file_names <- unlist(lapply( dirs, function(dir) { dir_path <- if (is_absolute_path(dir)) dir else file.path(root, dir) files <- list.files( path = dir_path, pattern = pattern, recursive = TRUE ) file.path(dir, files) # non-normalized relative paths } )) # Only exclude file if there is no more specific exclusion already all_file_names <- setdiff(all_file_names, names(x)) dir_exclusions <- rep_len(list(Inf), length(all_file_names)) names(dir_exclusions) <- all_file_names x <- c(x, dir_exclusions) } if (normalize_path) { paths <- names(x) # specify relative paths w.r.t. root rel_path <- !is_absolute_path(paths) paths[rel_path] <- file.path(root, paths[rel_path]) names(x) <- paths x <- x[file.exists(paths)] # remove exclusions for non-existing files names(x) <- normalize_path(names(x)) # get full path for remaining files } remove_line_duplicates( remove_linter_duplicates( remove_file_duplicates( remove_empty(x) ) ) ) } # Combines file exclusions for identical files. remove_file_duplicates <- function(x) { unique_names <- unique(names(x)) ## check for duplicate files if (length(unique_names) < length(names(x))) { x <- lapply( unique_names, function(name) { vals <- unname(x[names(x) == name]) do.call(c, vals) } ) names(x) <- unique_names } x } # Removes duplicate line information for each linter within each file. remove_line_duplicates <- function(x) { x[] <- lapply(x, function(ex) { ex[] <- lapply(ex, unique) ex }) x } # Combines line exclusions for identical linters within each file. remove_linter_duplicates <- function(x) { x[] <- lapply(x, function(ex) { unique_linters <- unique(names2(ex)) if (length(unique_linters) < length(ex)) { ex <- lapply(unique_linters, function(linter) { excluded_lines <- unlist(ex[names2(ex) == linter]) if (Inf %in% excluded_lines) { Inf } else { excluded_lines } }) if (!identical(unique_linters, "")) { names(ex) <- unique_linters } } ex }) x } # Removes linter exclusions without lines and files without any linter exclusions. remove_empty <- function(x) { x[] <- lapply(x, function(ex) ex[lengths(ex) > 0L]) x[lengths(x) > 0L] } lintr/R/object_length_linter.R0000644000176200001440000000471514752731051016126 0ustar liggesusers#' Object length linter #' #' Check that object names are not too long. #' The length of an object name is defined as the length in characters, after removing extraneous parts: #' #' * generic prefixes for implementations of S3 generics, e.g. `as.data.frame.my_class` has length 8. #' * leading `.`, e.g. `.my_hidden_function` has length 18. #' * "%%" for infix operators, e.g. `%my_op%` has length 5. #' * trailing `<-` for assignment functions, e.g. `my_attr<-` has length 7. #' #' Note that this behavior relies in part on having packages in your Imports available; #' see the detailed note in [object_name_linter()] for more details. #' #' @param length maximum variable name length allowed. #' #' @examples #' # will produce lints #' lint( #' text = "very_very_long_variable_name <- 1L", #' linters = object_length_linter(length = 10L) #' ) #' #' # okay #' lint( #' text = "very_very_long_variable_name <- 1L", #' linters = object_length_linter(length = 30L) #' ) #' #' lint( #' text = "var <- 1L", #' linters = object_length_linter(length = 10L) #' ) #' #' @evalRd rd_tags("object_length_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export object_length_linter <- function(length = 30L) { lint_message <- paste("Variable and function names should not be longer than", length, "characters.") Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content assignments <- xml_find_all(xml, object_name_xpath) # Retrieve assigned name nms <- strip_names( xml_text(assignments) ) # run namespace_imports at run-time, not "compile" time to allow package structure to change pkg <- find_package(source_expression$filename) ns_imports <- namespace_imports(pkg) generics <- strip_names(c( declared_s3_generics(xml), imported_s3_generics(ns_imports)$fun, exported_s3_generics(pkg)$fun, .base_s3_generics )) generics <- unique(generics[nzchar(generics)]) # Remove generic function names from generic implementations # This only lints S3 implementations if the class names are too long, still lints generics if they are too long. nms_stripped <- re_substitutes(nms, rex(start, or(generics), "."), "") too_long <- nchar(nms_stripped) > length xml_nodes_to_lints( assignments[too_long], source_expression = source_expression, lint_message = lint_message, type = "style" ) }) } lintr/R/actions.R0000644000176200001440000000116514752731051013376 0ustar liggesusersin_github_actions <- function() { identical(Sys.getenv("GITHUB_ACTIONS"), "true") } in_pkgdown <- function() { identical(Sys.getenv("IN_PKGDOWN"), "true") } # Output logging commands for any lints found github_actions_log_lints <- function(lints, project_dir = "") { for (x in lints) { if (nzchar(project_dir)) { x$filename <- file.path(project_dir, x$filename) } file_line_col <- sprintf( "file=%s,line=%s,col=%s", x$filename, x$line_number, x$column_number ) cat(sprintf( "::warning %s::%s,[%s] %s\n", file_line_col, file_line_col, x$linter, x$message ), sep = "") } } lintr/R/shared_constants.R0000644000176200001440000002717414752731051015310 0ustar liggesusersrx_non_active_char <- rex(none_of("^${(.*+?|[\\")) rx_static_escape <- local({ rx_char_escape <- rex(or( group("\\", none_of(alnum)), group("\\x", between(xdigit, 1L, 2L)), group("\\", between("0":"7", 1L, 3L)), group("\\u{", between(xdigit, 1L, 4L), "}"), group("\\u", between(xdigit, 1L, 4L)), group("\\U{", between(xdigit, 1L, 8L), "}"), group("\\U", between(xdigit, 1L, 8L)) )) rx_trivial_char_group <- rex( "[", or( any, group("\\", none_of("dswDSW")), # character classes, e.g. \d are enabled in [] too if perl = TRUE rx_char_escape ), "]" ) rex(or( capture(rx_char_escape, name = "char_escape"), capture(rx_trivial_char_group, name = "trivial_char_group") )) }) rx_static_token <- local({ rex(or( rx_non_active_char, rx_static_escape )) }) rx_unescaped_regex <- paste0("(?s)", rex(start, zero_or_more(rx_non_active_char), end)) rx_static_regex <- paste0("(?s)", rex(start, zero_or_more(rx_static_token), end)) rx_first_static_token <- paste0("(?s)", rex(start, zero_or_more(rx_non_active_char), rx_static_escape)) rx_escapable_tokens <- "^${}().*+?|[]\\<>=:;/_-!@#%&,~" #' Determine whether a regex pattern actually uses regex patterns #' #' Note that is applies to the strings that are found on the XML parse tree, #' _not_ plain strings. This is important for backslash escaping, which #' happens at different layers of escaping than one might expect. So testing #' this function is best done through testing the expected results of a lint #' on a given file, rather than passing strings to this function, which can #' be confusing. #' #' @param str A character vector. #' @return A logical vector, `TRUE` wherever `str` could be replaced by a #' string with `fixed = TRUE`. #' @noRd is_not_regex <- function(str, allow_unescaped = FALSE) { # need to add single-line option to allow literal newlines if (allow_unescaped) { !grepl(rx_unescaped_regex, str, perl = TRUE) } else { grepl(rx_static_regex, str, perl = TRUE) } } #' Compute a fixed string equivalent to a static regular expression #' #' @param static_regex A regex for which `is_not_regex()` returns `TRUE` #' @return A string such that `grepl(static_regex, x)` is equivalent to #' `grepl(get_fixed_string(static_regex), x, fixed = TRUE)` #' #' @noRd get_fixed_string <- function(static_regex) { if (length(static_regex) == 0L) { return(character()) } else if (length(static_regex) > 1L) { return(vapply(static_regex, get_fixed_string, character(1L))) } fixed_string <- "" current_match <- regexpr(rx_first_static_token, static_regex, perl = TRUE) while (current_match != -1L) { token_type <- attr(current_match, "capture.names")[attr(current_match, "capture.start") > 0L] token_start <- max(attr(current_match, "capture.start")) if (token_start > 1L) { fixed_string <- paste0(fixed_string, substr(static_regex, 1L, token_start - 1L)) } consume_to <- attr(current_match, "match.length") token_content <- substr(static_regex, token_start, consume_to) fixed_string <- paste0(fixed_string, get_token_replacement(token_content, token_type)) static_regex <- substr(static_regex, start = consume_to + 1L, stop = nchar(static_regex)) current_match <- regexpr(rx_first_static_token, static_regex, perl = TRUE) } paste0(fixed_string, static_regex) } #' Get a fixed string equivalent to a regular expression token #' #' This handles two cases: converting a "trivial" character group like `[$]` to `$`, #' and converting an escaped character like `"\\$"` to `$`. Splitting a full expression #' into tokens is handled by [get_fixed_string()]. #' #' @noRd get_token_replacement <- function(token_content, token_type) { if (token_type == "trivial_char_group") { # otherwise, char_escape token_content <- substr(token_content, start = 2L, stop = nchar(token_content) - 1L) if (startsWith(token_content, "\\")) { # escape within trivial char group get_token_replacement(token_content, "char_escape") } else { token_content } } else if (re_matches(token_content, rex("\\", one_of(rx_escapable_tokens)))) { substr(token_content, start = 2L, stop = nchar(token_content)) } else { eval(parse(text = paste0('"', token_content, '"'))) } } # some metadata about infix operators on the R parse tree. # xml_tag gives the XML tag as returned by xmlparsedata::xml_parse_data(). # r_string gives the operator as you would write it in R code. # styler: off infix_metadata <- data.frame(matrix(byrow = TRUE, ncol = 2L, c( "OP-PLUS", "+", "OP-MINUS", "-", "OP-TILDE", "~", "GT", ">", "GE", ">=", "LT", "<", "LE", "<=", "EQ", "==", "NE", "!=", "AND", "&", "OR", "|", "AND2", "&&", "OR2", "||", "LEFT_ASSIGN", "<-", "LEFT_ASSIGN", ":=", "LEFT_ASSIGN", "<<-", "RIGHT_ASSIGN", "->", "RIGHT_ASSIGN", "->>", "EQ_ASSIGN", "=", "EQ_SUB", "=", # in calls: foo(x = 1) "EQ_FORMALS", "=", # in definitions: function(x = 1) "PIPE", "|>", "SPECIAL", "%%", "OP-SLASH", "/", "OP-STAR", "*", "OP-COMMA", ",", "OP-CARET", "^", "OP-CARET", "**", "OP-AT", "@", "OP-EXCLAMATION", "!", "OP-COLON", ":", "NS_GET", "::", "NS_GET_INT", ":::", "OP-LEFT-BRACE", "{", "OP-LEFT-BRACKET", "[", "LBB", "[[", "OP-LEFT-PAREN", "(", "OP-QUESTION", "?", "OP-DOLLAR", "$", NULL ))) # styler: on names(infix_metadata) <- c("xml_tag", "string_value") # utils::getParseData()'s designation for the tokens wouldn't be valid as XML tags infix_metadata$parse_tag <- ifelse( startsWith(infix_metadata$xml_tag, "OP-"), sQuote(infix_metadata$string_value, "'"), infix_metadata$xml_tag ) # treated separately because spacing rules are different for unary operators infix_metadata$unary <- infix_metadata$xml_tag %in% c("OP-PLUS", "OP-MINUS", "OP-TILDE") # high-precedence operators are ignored by this linter; see # https://style.tidyverse.org/syntax.html#infix-operators infix_metadata$low_precedence <- infix_metadata$string_value %in% c( "+", "-", "~", ">", ">=", "<", "<=", "==", "!=", "&", "&&", "|", "||", "<-", ":=", "<<-", "->", "->>", "=", "%%", "/", "*", "|>" ) # comparators come up in several lints infix_metadata$comparator <- infix_metadata$string_value %in% c("<", "<=", ">", ">=", "==", "!=") # these XML nodes require checking the text() to disambiguate multiple operators using the same tag infix_metadata$ambiguous_tag <- infix_metadata$xml_tag %in% infix_metadata$xml_tag[duplicated(infix_metadata$xml_tag)] infix_metadata$xml_tag_exact <- infix_metadata$xml_tag infix_metadata$xml_tag_exact[infix_metadata$ambiguous_tag] <- sprintf( "%s[text() = '%s']", infix_metadata$xml_tag_exact[infix_metadata$ambiguous_tag], infix_metadata$string_value[infix_metadata$ambiguous_tag] ) # functions equivalent to base::ifelse() for linting purposes ifelse_funs <- c("ifelse", "if_else", "fifelse") object_name_xpath <- local({ # search ancestor:: axis for assignments of symbols for # cases like a$b$c. We only try to lint 'a' since 'b' # and 'c' might be beyond the user's control to name. # the tree structure for 'a$b$c <- 1' has 'a' # at the 'bottom' of the list; it is distinguished # from 'b' and 'c' by not having '$' as a sibling. # search parent:: axis for assignments of strings because # the complicated nested assignment available for symbols # is not possible for strings, though we do still have to # be aware of cases like 'a$"b" <- 1'. xp_assignment_target_fmt <- paste0( "not(parent::expr[OP-DOLLAR or OP-AT])", "and %1$s::expr[", " following-sibling::LEFT_ASSIGN%2$s", " or preceding-sibling::RIGHT_ASSIGN", " or following-sibling::EQ_ASSIGN", "]", "and not(%1$s::expr[", " preceding-sibling::OP-LEFT-BRACKET", " or preceding-sibling::LBB", "])" ) # strings on LHS of := are only checked if they look like data.table usage DT[, "a" := ...] dt_walrus_cond <- "[ text() != ':=' or parent::expr/preceding-sibling::OP-LEFT-BRACKET ]" glue(" //SYMBOL[ {sprintf(xp_assignment_target_fmt, 'ancestor', '')} ] | //STR_CONST[ {sprintf(xp_assignment_target_fmt, 'parent', dt_walrus_cond)} ] | //SYMBOL_FORMALS ") }) # Remove quotes or other things from names strip_names <- function(x) { x <- re_substitutes(x, rex(start, some_of(quote, "`", "%")), "") x <- re_substitutes(x, rex(some_of(quote, "`", "<", "-", "%"), end), "") x } #' Pull out symbols used in glue strings under the current sub-tree #' #' Required by any linter (e.g. [object_usage_linter()] / [unused_imports_linter()]) #' that lints based on whether certain symbols are present, to ensure any #' symbols only used inside glue strings are also visible to the linter. #' #' @param expr An XML AST #' @param interpret_glue Logical, if `FALSE` return nothing. #' @return A character vector of symbols (variables, infix operators, and #' function calls) found in glue calls under `expr`. #' @noRd extract_glued_symbols <- function(expr, interpret_glue) { if (!isTRUE(interpret_glue)) { return(character()) } # TODO(#2448): support more glue functions # NB: position() > 1 because position=1 is glue_call_xpath <- " descendant::SYMBOL_FUNCTION_CALL[text() = 'glue'] /parent::expr /parent::expr[ not(SYMBOL_SUB[text() = '.envir' or text() = '.transform']) and not(expr[position() > 1 and not(STR_CONST)]) ] " glue_calls <- xml_find_all(expr, glue_call_xpath) glued_symbols <- new.env(parent = emptyenv()) for (glue_call in glue_calls) { # TODO(#2475): Drop tryCatch(). parsed_call <- tryCatch(xml2lang(glue_call), error = unexpected_glue_parse_error, warning = unexpected_glue_parse_error) parsed_call[[".envir"]] <- glued_symbols parsed_call[[".transformer"]] <- glue_symbol_extractor # #1459: syntax errors in glue'd code are ignored with warning, rather than crashing lint tryCatch(eval(parsed_call), error = glue_parse_failure_warning) } names(glued_symbols) } unexpected_glue_parse_error <- function(cond) { cli_abort(c( x = "Unexpected failure to parse glue call.", i = "Please report: {conditionMessage(cond)}" )) # nocov } glue_parse_failure_warning <- function(cond) { cli_warn(c( x = "Evaluating glue expression while testing for local variable usage failed: {conditionMessage(cond)}", i = "Please ensure correct glue syntax, e.g., matched delimiters." )) NULL } glue_symbol_extractor <- function(text, envir, data) { symbols <- tryCatch( all.vars(parse(text = text), functions = TRUE), error = function(...) NULL, warning = function(...) NULL ) for (sym in symbols) { assign(sym, NULL, envir = envir) } "" } magrittr_pipes <- c("%>%", "%!>%", "%T>%", "%$%", "%<>%") purrr_mappers <- c( "map", "walk", "map_raw", "map_lgl", "map_int", "map_dbl", "map_chr", "map_vec", "map_df", "map_dfr", "map_dfc" ) # see ?".onLoad", ?Startup, and ?quit. # All of .onLoad, .onAttach, and .onUnload are used in base packages, # and should be caught in is_base_function; they're included here for completeness / stability # (they don't strictly _have_ to be defined in base, so could in principle be removed). # .Last.sys and .First.sys are part of base itself, so aren't included here. special_funs <- c( ".onLoad", ".onAttach", ".onUnload", ".onDetach", ".Last.lib", ".First", ".Last" ) is_special_function <- function(x) { x %in% special_funs } lintr/R/expect_type_linter.R0000644000176200001440000000607114752731051015645 0ustar liggesusers#' Require usage of `expect_type(x, type)` over `expect_equal(typeof(x), type)` #' #' [testthat::expect_type()] exists specifically for testing the storage type #' of objects. [testthat::expect_equal()], [testthat::expect_identical()], and #' [testthat::expect_true()] can also be used for such tests, #' but it is better to use the tailored function instead. #' #' @examples #' # will produce lints #' lint( #' text = 'expect_equal(typeof(x), "double")', #' linters = expect_type_linter() #' ) #' #' lint( #' text = 'expect_identical(typeof(x), "double")', #' linters = expect_type_linter() #' ) #' #' # okay #' lint( #' text = 'expect_type(x, "double")', #' linters = expect_type_linter() #' ) #' #' @evalRd rd_tags("expect_type_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export expect_type_linter <- function() { # NB: the full list of values that can arise from `typeof(x)` is available # in ?typeof (or, slightly more robustly, in the R source: src/main/util.c. # Not all of them are available in is. form, e.g. 'any' or # 'special'. 'builtin' and 'closure' are special cases, corresponding to # is.primitive and is.function (essentially). base_types <- c( "raw", "logical", "integer", "double", "complex", "character", "list", "numeric", "function", "primitive", "environment", "pairlist", "promise", # Per ?is.language, it's the same as is.call || is.name || is.expression. # so by blocking it, we're forcing more precise tests of one of # those directly ("language", "symbol", and "expression", resp.) # NB: is.name and is.symbol are identical. "language", "call", "name", "symbol", "expression" ) base_type_tests <- xp_text_in_table(paste0("is.", base_types)) expect_equal_identical_xpath <- " following-sibling::expr[ expr[1][SYMBOL_FUNCTION_CALL[text() = 'typeof']] and (position() = 1 or preceding-sibling::expr[STR_CONST]) ] /parent::expr[not(SYMBOL_SUB[text() = 'info' or text() = 'label' or text() = 'expected.label'])] " expect_true_xpath <- glue(" following-sibling::expr[1][expr[1][SYMBOL_FUNCTION_CALL[ {base_type_tests} ]]] /parent::expr[not(SYMBOL_SUB[text() = 'info' or text() = 'label'])] ") Linter(linter_level = "expression", function(source_expression) { expect_equal_identical_calls <- source_expression$xml_find_function_calls(c("expect_equal", "expect_identical")) expect_true_calls <- source_expression$xml_find_function_calls("expect_true") bad_expr <- combine_nodesets( xml_find_all(expect_equal_identical_calls, expect_equal_identical_xpath), xml_find_all(expect_true_calls, expect_true_xpath) ) matched_function <- xp_call_name(bad_expr) msg <- ifelse( matched_function %in% c("expect_equal", "expect_identical"), sprintf("expect_type(x, t) is better than %s(typeof(x), t)", matched_function), "expect_type(x, t) is better than expect_true(is.(x))" ) xml_nodes_to_lints( bad_expr, source_expression, lint_message = msg, type = "warning" ) }) } lintr/R/zzz.R0000644000176200001440000002511014752731051012567 0ustar liggesusers#' Default linters #' #' @description List of default linters for [lint()]. Use #' [linters_with_defaults()] to customize it. Most of the default linters #' are based on [the tidyverse style guide](https://style.tidyverse.org/). #' #' The set of default linters is as follows (any parameterized linters, e.g., `line_length_linter` use their default #' argument(s), see `?` for details): #' #' @evalRd rd_linters("default") #' @seealso [linters] for a complete list of linters available in lintr. #' #' @export default_linters <- modify_defaults( defaults = list(), assignment_linter(), brace_linter(), commas_linter(), commented_code_linter(), equals_na_linter(), function_left_parentheses_linter(), indentation_linter(), infix_spaces_linter(), line_length_linter(), object_length_linter(), object_name_linter(), object_usage_linter(), paren_body_linter(), pipe_continuation_linter(), quotes_linter(), return_linter(), semicolon_linter(), seq_linter(), spaces_inside_linter(), spaces_left_parentheses_linter(), T_and_F_symbol_linter(), trailing_blank_lines_linter(), trailing_whitespace_linter(), vector_logic_linter(), whitespace_linter() ) #' Default undesirable functions and operators #' #' Lists of function names and operators for [undesirable_function_linter()] and [undesirable_operator_linter()]. #' There is a list for the default elements and another that contains all available elements. #' Use [modify_defaults()] to produce a custom list. #' #' @evalRd c( #' "\\details{", #' rd_undesirable_functions(), #' "", #' rd_undesirable_operators(), #' "}" #' ) #' #' @format A named list of character strings. #' @rdname default_undesirable_functions #' @export all_undesirable_functions <- modify_defaults( defaults = list(), attach = "use roxygen2's @importFrom statement in packages, or `::` in scripts. attach() modifies the global search path", browser = "remove this likely leftover from debugging. It pauses execution when run", debug = paste( "remove this likely leftover from debugging.", "It traps a function and causes execution to pause when that function is run" ), debugcall = paste( "remove this likely leftover from debugging.", "It traps a function and causes execution to pause when that function is run" ), debugonce = paste( "remove this likely leftover from debugging.", "It traps a function and causes execution to pause when that function is run" ), detach = paste( "avoid modifying the global search path.", "Detaching environments from the search path is rarely necessary in production code" ), ifelse = paste( "use an `if`/`else` block for scalar logic,", "or use dplyr::if_else()/data.table::fifelse() for type-stable vectorized logic" ), .libPaths = paste( "use withr::with_libpaths() for a temporary change", "instead of permanently modifying the library location" ), library = paste( "use roxygen2's @importFrom statement in packages and `::` in scripts,", "instead of modifying the global search path" ), loadNamespace = "use the return value of requireNamespace() instead to provide an easy way to signal failures", mapply = "use Map() to guarantee a list is returned and simplify accordingly", options = "use withr::with_options() for a temporary change instead of permanently modifying the session options", par = "use withr::with_par() for a temporary change instead of permanently modifying the graphics device parameters", require = paste( "use roxygen2's @importFrom statement in packages and library() or `::` in scripts,", "instead of modifying the global search path" ), sapply = "use vapply() with an appropriate `FUN.VALUE=` argument to obtain type-stable simplification", setwd = "use withr::with_dir() for a temporary change instead of modifying the global working directory", sink = "use withr::with_sink() for a temporary redirection instead of permanently redirecting output", source = paste( "manage dependencies through packages.", "source() loads code into the global environment unless `local = TRUE` is used,", "which can cause hard-to-predict behavior" ), structure = "Use `class<-`, `names<-`, and `attr<-` to set attributes", substring = "use substr() with appropriate `stop=` value.", Sys.setenv = "use withr::with_envvar() for a temporary change instead of permanently modifying global environment variables", Sys.setlocale = "use withr::with_locale() for a temporary change instead of permanently modifying the session locale", trace = paste( "remove this likely leftover from debugging.", "It traps a function and causes execution of arbitrary code when that function is run" ), undebug = paste( "remove this likely leftover from debugging.", "It is only useful for interactive debugging with debug()" ), untrace = paste( "remove this likely leftover from debugging.", "It is only useful for interactive debugging with trace()" ) ) #' @rdname default_undesirable_functions #' @format NULL #' @export default_undesirable_functions <- all_undesirable_functions[names(all_undesirable_functions) %in% c( "attach", "browser", "debug", "debugcall", "debugonce", "detach", ".libPaths", "library", "mapply", "options", "par", "require", "sapply", "setwd", "sink", "source", "structure", "Sys.setenv", "Sys.setlocale", "Sys.unsetenv", "trace", "undebug", "untrace", NULL )] rd_auto_link <- function(x) { x <- unlist(x) x <- gsub(R"{([a-zA-Z0-9.]+)::([a-zA-Z0-9._]+)\(\)}", R"(\\code{\\link[\1:\2]{\1::\2()}})", x) x <- gsub(R"{([^:a-zA-Z0-9._])([a-zA-Z0-9._]+)\(\)}", R"(\1\\code{\\link[=\2]{\2()}})", x) x <- gsub("`([^`]+)`", R"(\\code{\1})", x) x } rd_undesirable_functions <- function() { alternatives <- rd_auto_link(default_undesirable_functions) c( "The following functions are sometimes regarded as undesirable:", "\\itemize{", sprintf( R"(\item \code{\link[=%1$s]{%1$s()}} As an alternative, %2$s.)", names(default_undesirable_functions), alternatives ), "}" ) } #' @rdname default_undesirable_functions #' @format NULL #' @export all_undesirable_operators <- modify_defaults( defaults = list(), ":::" = paste( "It accesses non-exported functions inside packages. Code relying on these is likely to break in", "future versions of the package because the functions are not part of the public interface and may be", "changed or removed by the maintainers without notice. Use public functions via `::` instead." ), "<<-" = paste( "It assigns outside the current environment in a way that can be hard to reason about.", "Prefer fully-encapsulated functions wherever possible, or, if necessary, assign to a specific", "environment with assign(). Recall that you can create an environment at the desired scope with", "new.env()." ), "->>" = paste( "It assigns outside the current environment in a way that can be hard to reason about.", "Prefer fully-encapsulated functions wherever possible, or, if necessary, assign to a specific", "environment with assign(). Recall that you can create an environment at the desired scope with", "new.env()." ) ) #' @rdname default_undesirable_functions #' @format NULL #' @export default_undesirable_operators <- all_undesirable_operators[names(all_undesirable_operators) %in% c( ":::", "<<-", "->>", NULL )] rd_undesirable_operators <- function() { op_link_map <- c( `:::` = "\\link[base:ns-dblcolon]{:::}", `<<-` = "\\link[base:assignOps]{<<-}", `->>` = "\\link[base:assignOps]{<<-}" ) op <- names(default_undesirable_operators) alternatives <- rd_auto_link(default_undesirable_operators) c( "The following operators are sometimes regarded as undesirable:", "\\itemize{", sprintf( "\\item \\code{%1$s}. %2$s", op_link_map[op], alternatives ), "}" ) } #' Default lintr settings #' #' @description #' The default settings consist of #' #' - `linters`: a list of default linters (see [default_linters()]) #' - `encoding`: the character encoding assumed for the file #' - `exclude`: pattern used to exclude a line of code #' - `exclude_start`, `exclude_end`: patterns used to mark start and end of the code block to exclude #' - `exclude_linter`, `exclude_linter_sep`: patterns used to exclude linters #' - `exclusions`: a list of exclusions, see [exclude()] for a complete description of valid values. #' - `cache_directory`: location of cache directory #' - `comment_token`: a GitHub token character #' - `error_on_lint`: decides if error should be produced when any lints are found #' #' There are no settings without defaults, i.e., this list describes every valid setting. #' #' @examples #' # available settings #' names(default_settings) #' #' # linters included by default #' names(default_settings$linters) #' #' # default values for a few of the other settings #' default_settings[c( #' "encoding", #' "exclude", #' "exclude_start", #' "exclude_end", #' "exclude_linter", #' "exclude_linter_sep", #' "exclusions", #' "error_on_lint" #' )] #' #' @seealso [read_settings()], [default_linters] #' @aliases settings config lintr-config lintr-settings .lintr #' @export default_settings <- NULL settings <- new.env(parent = emptyenv()) # nocov start .onLoad <- function(libname, pkgname) { op <- options() op_lintr <- list( lintr.linter_file = Sys.getenv("R_LINTR_LINTER_FILE", ".lintr") ) toset <- !(names(op_lintr) %in% names(op)) if (any(toset)) options(op_lintr[toset]) # R>=4.1.0: ...names backports::import(pkgname, "...names") utils::assignInMyNamespace("default_settings", list( linters = default_linters, encoding = "UTF-8", exclude = rex("#", any_spaces, "nolint"), exclude_next = rex("#", any_spaces, "nolint next"), exclude_start = rex("#", any_spaces, "nolint start"), exclude_end = rex("#", any_spaces, "nolint end"), exclude_linter = rex( start, any_spaces, ":", any_spaces, capture( name = "linters", zero_or_more(one_or_more(none_of(",.")), any_spaces, ",", any_spaces), one_or_more(none_of(",.")) ), "." ), exclude_linter_sep = rex(any_spaces, ",", any_spaces), exclusions = list(), cache_directory = R_user_dir("lintr", "cache"), comment_token = Sys.getenv("GITHUB_TOKEN", unset = NA) %||% rot( paste0( "0n12nn72507", "r6273qnnp34", "43qno7q42n1", "n71nn28" ), 54L - 13L ), error_on_lint = logical_env("LINTR_ERROR_ON_LINT") %||% FALSE )) reset_settings() } # nocov end lintr/R/extract.R0000644000176200001440000001415114752731051013407 0ustar liggesusers# content is the file content from readLines extract_r_source <- function(filename, lines, error = identity) { pattern <- get_knitr_pattern(filename, lines) if (is.null(pattern$chunk.begin) || is.null(pattern$chunk.end)) { return(lines) } # mask non-source lines by NA, but keep total line count identical so the line number for EOF is correct, see #1400 output <- rep.int(NA_character_, length(lines)) chunks <- tryCatch(get_chunk_positions(pattern = pattern, lines = lines), error = error) if (is_error(chunks) || is_lint(chunks)) { assign("e", chunks, envir = parent.frame()) # error, so return empty code return(output) } # no chunks found, so just return the lines if (length(chunks[["starts"]]) == 0L || length(chunks[["ends"]]) == 0L) { return(output) } output_env <- environment() # nolint: object_usage_linter. False positive-ish -- used below. Map( function(start, end, indent) { line_seq <- seq(start + 1L, end - 1L) chunk_code <- lines[line_seq] output_env$output[line_seq] <- if (indent > 0L) substr(chunk_code, indent + 1L, nchar(chunk_code)) else chunk_code }, chunks[["starts"]], chunks[["ends"]], chunks[["indents"]] ) # drop <> references, too is.na(output) <- grep(pattern$ref.chunk, output) replace_prefix(output, pattern$chunk.code) } get_knitr_pattern <- function(filename, lines) { # Early return if the source code is parseable as plain R code. # Otherwise, R code containing a line which matches any knitr pattern will be treated as a knitr file. # See #1406 for details. if (parsable(lines)) { return(NULL) } # suppressWarnings for #1920. TODO(michaelchirico): this is a bit sloppy -- we ignore # warnings here because encoding issues are caught later and that code path handles them # correctly by converting to a lint. It would require some refactoring to get that # right here as well, but it would avoid the duplication. pattern <- withCallingHandlers( ("knitr" %:::% "detect_pattern")(lines, tolower(("knitr" %:::% "file_ext")(filename))), warning = function(cond) { if (!grepl("invalid UTF-8", conditionMessage(cond), fixed = TRUE)) { cli_warn(cond) } invokeRestart("muffleWarning") } ) if (!is.null(pattern)) { knitr::all_patterns[[pattern]] } else { NULL } } get_chunk_positions <- function(pattern, lines) { starts <- filter_chunk_start_positions( starts = grep(pattern$chunk.begin, lines, perl = TRUE), lines = lines ) ends <- filter_chunk_end_positions( starts = starts, ends = grep(pattern$chunk.end, lines, perl = TRUE) ) # only keep those blocks that contain at least one line of code keep <- which(ends - starts > 1L) starts <- starts[keep] ends <- ends[keep] # Check indent on all lines in the chunk to allow for staggered indentation within a chunk; # set the initial column to the leftmost one within each chunk (including the start+end gates). See tests. # use 'ws_re' to make clear that we're matching knitr's definition of initial whitespace. ws_re <- sub("```.*", "", pattern$chunk.begin) extract_min_chunk_indent <- function(start, end) { indents <- attr(regexpr(ws_re, lines[start:end], perl = TRUE), "match.length") min(indents) } # NB: min() guarantees length(indents) == length(starts) indents <- unlist(Map(extract_min_chunk_indent, starts, ends)) list(starts = starts, ends = ends, indents = indents) } filter_chunk_start_positions <- function(starts, lines) { # keep blocks that don't set a knitr engine (and so contain evaluated R code) drop_idx <- defines_knitr_engine(lines[starts]) starts[!drop_idx] } filter_chunk_end_positions <- function(starts, ends) { # In a valid file, possibly with plain-code-blocks, # - there should be at least as many ends as starts # In Rmarkdown and Quarto, unevaluated blocks may open & close with the same ``` pattern # that defines the end-pattern for an evaluated block # This returns the first end-position that succeeds each start-position # starts (1, 3, 5, 7, 11) --> (1, 3, 5, 7, 11) # ends (2, 4, 6, 8, 9, 10, 12) --> (2, 4, 6, 8, 12) # return this length_difference <- length(ends) - length(starts) if (length_difference == 0L && all(ends > starts)) { return(ends) } positions <- sort(c(starts = starts, ends = ends)) code_start_indexes <- grep("starts", names(positions), fixed = TRUE) code_ends <- positions[pmin(1L + code_start_indexes, length(positions))] bad_end_indexes <- grep("starts", names(code_ends), fixed = TRUE) if (length(bad_end_indexes) > 0L) { bad_start_positions <- positions[code_start_indexes[bad_end_indexes]] # This error message is formatted like a parse error; don't use {cli} stop(sprintf( # nolint: undesirable_function_linter ":%1$d:1: Missing chunk end for chunk (maybe starting at line %1$d).\n", bad_start_positions[1L] ), call. = FALSE) } code_ends } defines_knitr_engine <- function(start_lines) { # Other packages defining custom engines should have them loaded and thus visible # via knitr_engines$get() below. It seems the simplest way to accomplish this is # for those packages to set some code in their .onLoad() hook, but that's not # always done (nor quite recommended as a "best practice" by knitr). # See the discussion on #1552. # TODO(#1617): explore running loadNamespace() automatically. engines <- names(knitr::knit_engines$get()) # {some_engine}, {some_engine label, ...} or {some_engine, ...} bare_engine_pattern <- rex( "{", or(engines), one_of("}", " ", ",") ) # {... engine = "some_engine" ...} explicit_engine_pattern <- rex( boundary, "engine", any_spaces, "=" ) re_matches(start_lines, explicit_engine_pattern) | re_matches(start_lines, bare_engine_pattern) } replace_prefix <- function(lines, prefix_pattern) { if (is.null(prefix_pattern)) { return(lines) } m <- gregexpr(prefix_pattern, lines) non_na <- !is.na(m) prefix_lengths <- lapply(regmatches(lines[non_na], m[non_na]), nchar) regmatches(lines[non_na], m[non_na]) <- lapply(prefix_lengths, strrep, x = " ") lines } lintr/R/pipe_return_linter.R0000644000176200001440000000240414752731051015644 0ustar liggesusers#' Block usage of return() in magrittr pipelines #' #' [return()] inside a magrittr pipeline does not actually execute `return()` #' like you'd expect: `\(x) { x %>% return(); FALSE }` will return `FALSE`! #' It will technically work "as expected" if this is the final statement #' in the function body, but such usage is misleading. Instead, assign #' the pipe outcome to a variable and return that. #' #' @examples #' # will produce lints #' lint( #' text = "function(x) x %>% return()", #' linters = pipe_return_linter() #' ) #' #' # okay #' code <- "function(x) {\n y <- sum(x)\n return(y)\n}" #' writeLines(code) #' lint( #' text = code, #' linters = pipe_return_linter() #' ) #' #' @evalRd rd_tags("pipe_return_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export pipe_return_linter <- make_linter_from_xpath( # NB: Native pipe disallows this at the parser level, so there's no need # to lint in valid R code. xpath = " //SPECIAL[text() = '%>%'] /following-sibling::expr[expr/SYMBOL_FUNCTION_CALL[text() = 'return']] ", lint_message = paste( "Avoid return() as the final step of a magrittr pipeline. ", "Instead, assign the output of the pipeline to a well-named object and return that." ) ) lintr/R/xp_utils.R0000644000176200001440000001120614752731051013602 0ustar liggesusers# utils for working with xpaths # like `text() %in% table`, translated to XPath 1.0 xp_text_in_table <- function(table) { if (length(table) == 0L) { return("true") } # xpath doesn't seem to have a standard way of escaping quotes, so attempt # to use "" whenever the string has ' (not a perfect solution). info on # escaping from https://stackoverflow.com/questions/14822153 single_quoted <- grepl("'", table, fixed = TRUE) table[single_quoted] <- sQuote(table[single_quoted], '"') table[!single_quoted] <- sQuote(table[!single_quoted], "'") paste0("text() = ", table, collapse = " or ") } paren_wrap <- function(..., sep) { sep <- paste(")", sep, "(") dots <- list(...) if (length(dots) == 1L && length(dots[[1L]]) > 1L) { inner <- paste(dots[[1L]], collapse = sep) } else { inner <- paste(..., sep = sep) } paste0("(", inner, ")") } #' Safer wrapper for paste(..., sep = " and ") #' #' The intent is to use this for readability when combining XPath conditions so #' the `...` elements should be in that language, but this is not enforced. #' #' Inputs are also wrapped in `()` so as not to risk mixing operator precedence. #' #' @param ... Series of conditions #' @noRd xp_and <- function(...) paren_wrap(..., sep = "and") #' Safer wrapper for paste(..., sep = " or ") #' #' The intent is to use this for readability when combining XPath conditions so #' the `...` elements should be in that language, but this is not enforced. #' #' Inputs are also wrapped in `()` so as not to risk mixing operator precedence. #' #' @param ... Series of conditions #' @noRd xp_or <- function(...) paren_wrap(..., sep = "or") #' Get the name of the function matched by an XPath #' #' Often, it is more helpful to tailor the `message` of a lint to record #' which function was matched by the lint logic. This function encapsulates #' the logic to pull out the matched call in common situations. #' #' @param expr An `xml_node` or `xml_nodeset`, e.g. from [xml2::xml_find_all()]. #' @param depth Integer, default `1L`. How deep in the AST represented by `expr` #' should we look to find the call? By default, we assume `expr` is matched #' to an `` node under which the corresponding `` #' node is found directly. `depth = 0L` means `expr` is matched directly #' to the `SYMBOL_FUNCTION_CALL`; `depth > 1L` means `depth` total `` #' nodes must be traversed before finding the call. #' @param condition An additional (XPath condition on the `SYMBOL_FUNCTION_CALL` #' required for a match. The default (`NULL`) is no condition. See examples. #' #' @examples #' xml_from_code <- function(str) { #' xml2::read_xml(xmlparsedata::xml_parse_data(parse(text = str, keep.source = TRUE))) #' } #' xml <- xml_from_code("sum(1:10)") #' xp_call_name(xml, depth = 2L) #' #' xp_call_name(xml2::xml_find_first(xml, "expr")) #' #' xml <- xml_from_code(c("sum(1:10)", "sd(1:10)")) #' xp_call_name(xml, depth = 2L, condition = "text() = 'sum'") #' #' @export xp_call_name <- function(expr, depth = 1L, condition = NULL) { stopifnot( is.numeric(depth), depth >= 0L, is.null(condition) || is.character(condition) ) is_valid_expr <- is_node(expr) || is_nodeset(expr) if (!is_valid_expr) { cli_abort(c( i = "{.arg expr} must be an {.cls xml_nodeset} or an {.cls xml_node}.", x = "Instead, it is {.obj_type_friendly {expr}}." )) } if (is.null(condition)) { node <- "SYMBOL_FUNCTION_CALL" } else { node <- sprintf("SYMBOL_FUNCTION_CALL[%s]", condition) } xpath <- paste0("string(", strrep("expr/", depth), node, ")") xml_find_chr(expr, xpath) } xp_find_location <- function(xml, xpath) { if (identical(xpath, "number(./@col1)")) { as.integer(xml_attr(xml, "col1")) } else if (identical(xpath, "number(./@col2)")) { as.integer(xml_attr(xml, "col2")) } else { as.integer(xml_find_num(xml, xpath)) } } #' Strip XPath 2.0-style comments from an XPath #' #' `{xml2}` uses XPath 1.0, which has no support for comments. But comments are #' useful in a codebase with as many XPaths as we maintain, so we fudge our #' way to XPath 2.0-ish support by writing this simple function to remove comments. #' #' @noRd xpath_comment_re <- rex( "(:", zero_or_more(not(":)")), ":)" ) xp_strip_comments <- function(xpath) rex::re_substitutes(xpath, xpath_comment_re, "", global = TRUE) #' Combine two or more nodesets to a single nodeset #' #' Useful for calling `{xml2}` functions on a combined set of nodes obtained using different XPath searches. #' #' @noRd # TODO(r-lib/xml2#433): remove this and just use c() combine_nodesets <- function(...) { res <- c(...) class(res) <- "xml_nodeset" res } lintr/R/trailing_whitespace_linter.R0000644000176200001440000000451614752731051017343 0ustar liggesusers#' Trailing whitespace linter #' #' Check that there are no space characters at the end of source lines. #' #' @param allow_empty_lines Suppress lints for lines that contain only whitespace. #' @param allow_in_strings Suppress lints for trailing whitespace in string constants. #' #' @examples #' # will produce lints #' lint( #' text = "x <- 1.2 ", #' linters = trailing_whitespace_linter() #' ) #' #' code_lines <- "a <- TRUE\n \nb <- FALSE" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = trailing_whitespace_linter() #' ) #' #' # okay #' lint( #' text = "x <- 1.2", #' linters = trailing_whitespace_linter() #' ) #' #' lint( #' text = "x <- 1.2 # comment about this assignment", #' linters = trailing_whitespace_linter() #' ) #' #' code_lines <- "a <- TRUE\n \nb <- FALSE" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = trailing_whitespace_linter(allow_empty_lines = TRUE) #' ) #' #' @evalRd rd_tags("trailing_whitespace_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export trailing_whitespace_linter <- function(allow_empty_lines = FALSE, allow_in_strings = TRUE) { Linter(linter_level = "file", function(source_expression) { res <- re_matches( source_expression$file_lines, rex(blanks, end), locations = TRUE ) if (isTRUE(allow_empty_lines)) { bad_lines <- which(res$start > 1L) } else { bad_lines <- which(!is.na(res$start)) } if (isTRUE(allow_in_strings) && !is.null(source_expression$full_xml_parsed_content)) { all_str_consts <- xml_find_all(source_expression$full_xml_parsed_content, "//STR_CONST") start_lines <- as.integer(xml_attr(all_str_consts, "line1")) end_lines <- as.integer(xml_attr(all_str_consts, "line2")) is_in_str <- vapply(bad_lines, function(ln) any(start_lines <= ln & ln < end_lines), logical(1L)) bad_lines <- bad_lines[!is_in_str] } lapply( bad_lines, function(line) { Lint( filename = source_expression$filename, line_number = line, column_number = res$start[[line]], type = "style", message = "Remove trailing whitespace.", line = source_expression$file_lines[[line]], ranges = list(c(res$start[[line]], res$end[[line]])) ) } ) }) } lintr/R/tree_utils.R0000644000176200001440000000135514752731051014116 0ustar liggesusersgenerate_top_level_map <- function(pc) { if (is.null(pc)) { return(NULL) } tl_ids <- pc$id[pc$parent <= 0L] tl_parent <- pc$parent tl_parent[pc$parent <= 0L] <- tl_ids i_not_assigned <- which(!tl_parent %in% tl_ids) while ((prev_length <- length(i_not_assigned)) > 0L) { # nolint: implicit_assignment_linter. TODO(#2015): remove this. tl_parent[i_not_assigned] <- pc$parent[match(tl_parent[i_not_assigned], pc$id)] i_not_assigned <- which(!tl_parent %in% tl_ids) # nocov start if (length(i_not_assigned) >= prev_length) { cli_abort_internal("Logical error: unassigned set did not shrink. Check file syntax.") } # nocov end } tl_parent } lag <- function(x) { c(NA, x[seq_len(length(x) - 1L)]) } lintr/R/which_grepl_linter.R0000644000176200001440000000145014752731051015603 0ustar liggesusers#' Require usage of grep over which(grepl(.)) #' #' `which(grepl(pattern, x))` is the same as `grep(pattern, x)`, but harder #' to read and requires two passes over the vector. #' #' @examples #' # will produce lints #' lint( #' text = "which(grepl('^a', x))", #' linters = which_grepl_linter() #' ) #' #' # okay #' lint( #' text = "which(grepl('^a', x) | grepl('^b', x))", #' linters = which_grepl_linter() #' ) #' #' @evalRd rd_tags("which_grepl_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export which_grepl_linter <- make_linter_from_function_xpath( function_names = "grepl", xpath = " parent::expr /parent::expr[expr/SYMBOL_FUNCTION_CALL[text() = 'which']] ", lint_message = "grep(pattern, x) is better than which(grepl(pattern, x))." ) lintr/R/function_left_parentheses_linter.R0000644000176200001440000000745114752731051020557 0ustar liggesusers#' Function left parentheses linter #' #' Check that all left parentheses in a function call do not have spaces before them #' (e.g. `mean (1:3)`). Although this is syntactically valid, it makes the code #' difficult to read. #' #' Exceptions are made for control flow functions (`if`, `for`, etc.). #' #' @examples #' # will produce lints #' lint( #' text = "mean (x)", #' linters = function_left_parentheses_linter() #' ) #' #' lint( #' text = "stats::sd(c (x, y, z))", #' linters = function_left_parentheses_linter() #' ) #' #' # okay #' lint( #' text = "mean(x)", #' linters = function_left_parentheses_linter() #' ) #' #' lint( #' text = "stats::sd(c(x, y, z))", #' linters = function_left_parentheses_linter() #' ) #' #' lint( #' text = "foo <- function(x) (x + 1)", #' linters = function_left_parentheses_linter() #' ) #' #' @evalRd rd_tags("function_left_parentheses_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' - [spaces_left_parentheses_linter()] #' @export function_left_parentheses_linter <- function() { # nolint: object_length. # NB: attach to SYMBOL_FUNCTION_CALL instead of SYMBOL_FUNCTION_CALL/parent::expr because # the latter might be associated with a different line, e.g. in the case of a # complicated call to an "extracted" function (see #1963). This mistake was made earlier # because it allows the xpath to be the same for both FUNCTION and SYMBOL_FUNCTION_CALL. # Further, write 4 separate XPaths because the 'range_end_xpath' differs for these two nodes. bad_line_fun_xpath <- "(//FUNCTION | //OP-LAMBDA)[@line1 != following-sibling::OP-LEFT-PAREN/@line1]" bad_line_call_xpath <- "//SYMBOL_FUNCTION_CALL[@line1 != parent::expr/following-sibling::OP-LEFT-PAREN/@line1]" bad_col_fun_xpath <- "(//FUNCTION | //OP-LAMBDA)[ @line1 = following-sibling::OP-LEFT-PAREN/@line1 and @col2 != following-sibling::OP-LEFT-PAREN/@col1 - 1 ]" bad_col_call_xpath <- "//SYMBOL_FUNCTION_CALL[ @line1 = parent::expr/following-sibling::OP-LEFT-PAREN/@line1 and @col2 != parent::expr/following-sibling::OP-LEFT-PAREN/@col1 - 1 ]" Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_line_fun_exprs <- xml_find_all(xml, bad_line_fun_xpath) bad_line_fun_lints <- xml_nodes_to_lints( bad_line_fun_exprs, source_expression = source_expression, lint_message = "Left parenthesis should be on the same line as the 'function' symbol." ) bad_line_call_exprs <- xml_find_all(xml, bad_line_call_xpath) bad_line_call_lints <- xml_nodes_to_lints( bad_line_call_exprs, source_expression = source_expression, lint_message = "Left parenthesis should be on the same line as the function's symbol." ) bad_col_fun_exprs <- xml_find_all(xml, bad_col_fun_xpath) bad_col_fun_lints <- xml_nodes_to_lints( bad_col_fun_exprs, source_expression = source_expression, lint_message = "Remove spaces before the left parenthesis in a function definition.", range_start_xpath = "number(./@col2 + 1)", # start after function range_end_xpath = "number(./following-sibling::OP-LEFT-PAREN/@col1 - 1)" # end before ( ) bad_col_call_exprs <- xml_find_all(xml, bad_col_call_xpath) bad_col_call_lints <- xml_nodes_to_lints( bad_col_call_exprs, source_expression = source_expression, lint_message = "Remove spaces before the left parenthesis in a function call.", range_start_xpath = "number(./@col2 + 1)", # start after call name range_end_xpath = "number(./parent::expr/following-sibling::OP-LEFT-PAREN/@col1 - 1)" # end before ( ) c(bad_line_fun_lints, bad_line_call_lints, bad_col_fun_lints, bad_col_call_lints) }) } lintr/R/undesirable_function_linter.R0000644000176200001440000000666414752731051017526 0ustar liggesusers#' Undesirable function linter #' #' Report the use of undesirable functions and suggest an alternative. #' #' @param fun Named character vector. `names(fun)` correspond to undesirable functions, #' while the values give a description of why the function is undesirable. #' If `NA`, no additional information is given in the lint message. Defaults to #' [default_undesirable_functions]. To make small customizations to this list, #' use [modify_defaults()]. #' @param symbol_is_undesirable Whether to consider the use of an undesirable function #' name as a symbol undesirable or not. #' #' @examples #' # defaults for which functions are considered undesirable #' names(default_undesirable_functions) #' #' # will produce lints #' lint( #' text = "sapply(x, mean)", #' linters = undesirable_function_linter() #' ) #' #' lint( #' text = "log10(x)", #' linters = undesirable_function_linter(fun = c("log10" = NA)) #' ) #' #' lint( #' text = "log10(x)", #' linters = undesirable_function_linter(fun = c("log10" = "use log()")) #' ) #' #' lint( #' text = 'dir <- "path/to/a/directory"', #' linters = undesirable_function_linter(fun = c("dir" = NA)) #' ) #' #' # okay #' lint( #' text = "vapply(x, mean, FUN.VALUE = numeric(1))", #' linters = undesirable_function_linter() #' ) #' #' lint( #' text = "log(x, base = 10)", #' linters = undesirable_function_linter(fun = c("log10" = "use log()")) #' ) #' #' lint( #' text = 'dir <- "path/to/a/directory"', #' linters = undesirable_function_linter(fun = c("dir" = NA), symbol_is_undesirable = FALSE) #' ) #' #' @evalRd rd_tags("undesirable_function_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export undesirable_function_linter <- function(fun = default_undesirable_functions, symbol_is_undesirable = TRUE) { stopifnot(is.logical(symbol_is_undesirable)) if (is.null(names(fun)) || !all(nzchar(names(fun))) || length(fun) == 0L) { cli_abort(c( x = "{.arg fun} should be a non-empty named character vector.", i = "Use missing elements to indicate default messages." )) } xp_condition <- xp_and( paste0( "not(parent::expr/preceding-sibling::expr[last()][SYMBOL_FUNCTION_CALL[", xp_text_in_table(c("library", "require")), "]])" ), "not(parent::expr[OP-DOLLAR or OP-AT])" ) if (symbol_is_undesirable) { symbol_xpath <- glue("//SYMBOL[({xp_text_in_table(names(fun))}) and {xp_condition}]") } xpath <- glue("SYMBOL_FUNCTION_CALL[{xp_condition}]") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content xml_calls <- source_expression$xml_find_function_calls(names(fun)) matched_nodes <- xml_find_all(xml_calls, xpath) if (symbol_is_undesirable) { matched_nodes <- combine_nodesets(matched_nodes, xml_find_all(xml, symbol_xpath)) } fun_names <- get_r_string(matched_nodes) msgs <- vapply( stats::setNames(nm = unique(fun_names)), function(fun_name) { msg <- sprintf('Avoid undesirable function "%s".', fun_name) alternative <- fun[[fun_name]] if (!is.na(alternative)) { msg <- paste(msg, sprintf("As an alternative, %s.", alternative)) } msg }, character(1L) ) xml_nodes_to_lints( matched_nodes, source_expression = source_expression, lint_message = unname(msgs[fun_names]) ) }) } lintr/R/object_name_linter.R0000644000176200001440000001525214752731051015563 0ustar liggesusers#' Object name linter #' #' Check that object names conform to a naming style. #' The default naming styles are "snake_case" and "symbols". #' #' Quotes (`` `"' ``) and specials (`%` and trailing `<-`) are not considered part of the object name. #' #' Note when used in a package, in order to ignore objects imported #' from other namespaces, this linter will attempt [getNamespaceExports()] #' whenever an `import(PKG)` or `importFrom(PKG, ...)` statement is found #' in your NAMESPACE file. If [requireNamespace()] fails (e.g., the package #' is not yet installed), the linter won't be able to ignore some usages #' that would otherwise be allowed. #' #' Suppose, for example, you have `import(upstream)` in your NAMESPACE, #' which makes available its exported S3 generic function #' `a_really_quite_long_function_name` that you then extend in your package #' by defining a corresponding method for your class `my_class`. #' Then, if `upstream` is not installed when this linter runs, a lint #' will be thrown on this object (even though you don't "own" its full name). #' #' The best way to get lintr to work correctly is to install the package so #' that it's available in the session where this linter is running. #' #' @param styles A subset of #' \Sexpr[stage=render, results=rd]{lintr:::regexes_rd}. A name should #' match at least one of these styles. The `"symbols"` style refers to #' names containing *only* non-alphanumeric characters; e.g., defining `%+%` #' from ggplot2 or `%>%` from magrittr would not generate lint markers, #' whereas `%m+%` from lubridate (containing both alphanumeric *and* #' non-alphanumeric characters) would. #' #' @param regexes A (possibly named) character vector specifying a custom naming convention. #' If named, the names will be used in the lint message. Otherwise, the regexes enclosed by `/` will be used in the #' lint message. #' Note that specifying `regexes` overrides the default `styles`. So if you want to combine `regexes` and `styles`, #' both need to be explicitly specified. #' #' @examples #' # will produce lints #' lint( #' text = "my_var <- 1L", #' linters = object_name_linter(styles = "CamelCase") #' ) #' #' lint( #' text = "xYz <- 1L", #' linters = object_name_linter(styles = c("UPPERCASE", "lowercase")) #' ) #' #' lint( #' text = "MyVar <- 1L", #' linters = object_name_linter(styles = "dotted.case") #' ) #' #' lint( #' text = "asd <- 1L", #' linters = object_name_linter(regexes = c(my_style = "F$", "f$")) #' ) #' #' # okay #' lint( #' text = "my_var <- 1L", #' linters = object_name_linter(styles = "snake_case") #' ) #' #' lint( #' text = "xyz <- 1L", #' linters = object_name_linter(styles = "lowercase") #' ) #' #' lint( #' text = "my.var <- 1L; myvar <- 2L", #' linters = object_name_linter(styles = c("dotted.case", "lowercase")) #' ) #' #' lint( #' text = "asdf <- 1L; asdF <- 1L", #' linters = object_name_linter(regexes = c(my_style = "F$", "f$")) #' ) #' #' @evalRd rd_tags("object_name_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export object_name_linter <- function(styles = c("snake_case", "symbols"), regexes = character()) { if ((!missing(styles) || missing(regexes)) && length(styles) > 0L) { # Allow `object_name_linter(NULL, "my_regex")` styles <- match.arg(styles, names(style_regexes), several.ok = TRUE) style_list <- style_regexes[styles] } else { style_list <- list() } if (length(regexes) > 0L) { if (!is.character(regexes)) { cli_abort("{.arg regexes} must be a {.cls character} vector.") } rx_names <- names2(regexes) missing_name <- !nzchar(rx_names) rx_names[missing_name] <- paste0("/", regexes[missing_name], "/") # auto-name regex "asd" -> /asd/ names(regexes) <- rx_names style_list <- c(style_list, as.list(regexes)) } if (length(style_list) == 0L) { cli_abort("At least one style must be specified using {.arg styles} or {.arg regexes}.") } lint_message <- paste0( "Variable and function name style should match ", glue_collapse(unique(names(style_list)), sep = ", ", last = " or "), "." ) Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content assignments <- xml_find_all(xml, object_name_xpath) # Retrieve assigned name nms <- strip_names( xml_text(assignments) ) # run namespace_imports at run-time, not "compile" time to allow package structure to change pkg <- find_package(source_expression$filename) generics <- c( declared_s3_generics(xml), imported_s3_generics(namespace_imports(pkg))$fun, exported_s3_generics(pkg)$fun, .base_s3_generics ) generics <- unique(generics[nzchar(generics)]) style_matches <- lapply(style_list, function(style) { check_style(nms, style, generics) }) matches_a_style <- Reduce(`|`, style_matches) xml_nodes_to_lints( assignments[!matches_a_style], source_expression, lint_message = lint_message, type = "style" ) }) } check_style <- function(nms, style, generics = character()) { conforming <- re_matches_logical(nms, style) # mark empty or NA names as conforming conforming <- is.na(nms) | !nzchar(nms) | conforming if (!all(conforming)) { possible_s3 <- re_matches( nms[!conforming], rex(start, capture(name = "generic", or(generics)), ".", capture(name = "method", something), end) ) if (!all(is.na(possible_s3))) { has_generic <- possible_s3$generic %in% generics # If they are not conforming, but are S3 methods then ignore them conforming[!conforming][has_generic] <- TRUE } # exclude namespace hooks like .onLoad, .Last.lib, etc (#500) and ... is_special <- is_special_function(nms[!conforming]) | nms[!conforming] == "..." conforming[!conforming][is_special] <- TRUE } conforming } loweralnum <- rex(one_of(lower, digit)) upperalnum <- rex(one_of(upper, digit)) style_regexes <- list( symbols = rex(start, zero_or_more(none_of(alnum)), end), CamelCase = rex(start, maybe("."), upper, zero_or_more(alnum), end), camelCase = rex(start, maybe("."), lower, zero_or_more(alnum), end), snake_case = rex(start, maybe("."), some_of(lower, digit), any_of("_", lower, digit), end), SNAKE_CASE = rex(start, maybe("."), some_of(upper, digit), any_of("_", upper, digit), end), dotted.case = rex(start, maybe("."), one_or_more(loweralnum), zero_or_more(dot, one_or_more(loweralnum)), end), lowercase = rex(start, maybe("."), one_or_more(loweralnum), end), UPPERCASE = rex(start, maybe("."), one_or_more(upperalnum), end) ) regexes_rd <- toString(paste0("\\sQuote{", names(style_regexes), "}")) lintr/R/methods.R0000644000176200001440000001351214752731051013400 0ustar liggesusers#' @export format.lint <- function(x, ..., width = getOption("lintr.format_width")) { color <- switch(x$type, warning = cli::col_magenta, error = cli::col_red, style = cli::col_blue, cli::style_bold ) emph <- cli::style_bold line_ref <- build_line_ref(x) annotated_msg <- paste0( emph(line_ref, ": "), color(x$type, ": ", sep = ""), "[", x$linter, "] ", emph(x$message) ) if (!is.null(width)) { annotated_msg <- paste(strwrap(annotated_msg, exdent = 4L, width = width), collapse = "\n") } paste0( annotated_msg, "\n", # swap tabs for spaces for #528 (sorry Richard Hendricks) chartr("\t", " ", x$line), "\n", highlight_string(x$message, x$column_number, x$ranges), "\n" ) } build_line_ref <- function(x) { line_ref <- paste0( x$filename, ":", as.character(x$line_number), ":", as.character(x$column_number) ) if (!cli::ansi_has_hyperlink_support()) { return(line_ref) } cli::format_inline("{.path {line_ref}}") } #' @export print.lint <- function(x, ...) { cat(format(x, ...)) invisible(x) } markdown <- function(x, info, ...) { cat( sep = "", "[", x$filename, ":", as.character(x$line_number), ":", as.character(x$column_number), ":", "]", "(", file.path( "https://github.com", info$user, info$repo, "blob", info$commit, x$filename ), "#L", x$line_number, ")", " ", "*", x$type, ":", "* ", "[", x$linter, "] ", "**", x$message, "**\n", "```r\n\U200B", # we use a zero width unicode character here so that Github # does not strip the leading whitespace x$line, "\n", highlight_string(x$message, x$column_number, x$ranges), "\n```\n" ) invisible(x) } #' @export format.lints <- function(x, ..., width = getOption("lintr.format_width")) { paste(vapply(x, format, character(1L), width = width), collapse = "\n") } #' @export print.lints <- function(x, ...) { use_rstudio_source_markers <- lintr_option("rstudio_source_markers", TRUE) && requireNamespace("rstudioapi", quietly = TRUE) && rstudioapi::hasFun("sourceMarkers") github_annotation_project_dir <- lintr_option("github_annotation_project_dir", "") if (length(x) > 0L) { inline_data <- x[[1L]][["filename"]] == "" if (!inline_data && use_rstudio_source_markers) { rstudio_source_markers(x) } else if (in_github_actions() && !in_pkgdown()) { github_actions_log_lints(x, project_dir = github_annotation_project_dir) } else { lapply(x, print, ...) } if (isTRUE(settings$error_on_lint)) { quit("no", 31L, FALSE) # nocov } } else { # Empty lints cli_inform(c(i = "No lints found.")) if (use_rstudio_source_markers) { rstudio_source_markers(x) # clear RStudio source markers } } invisible(x) } trim_output <- function(x, max = 65535L) { # if x is less than the max, just return it if (length(x) <= 0L || nchar(x) <= max) { return(x) } # otherwise trim x to the max, then search for the lint starts x <- substr(x, 1L, max) re <- rex( "[", except_some_of(":"), ":", numbers, ":", numbers, ":", "]", "(", except_some_of(")"), ")", space, "*", or("style", "warning", "error"), ":", "*", except_some_of("\r\n"), newline, except_some_of("\r\n"), newline, except_some_of("\r\n"), newline, except_some_of("\r\n"), newline, except_some_of("\r\n"), newline ) lint_starts <- re_matches(x, re, global = TRUE, locations = TRUE)[[1L]] # if at least one lint ends before the cutoff, cutoff there, else just use # the cutoff last_end <- lint_starts[NROW(lint_starts), "end"] if (!is.na(last_end)) { substr(x, 1L, last_end) } else { x } } #' @export names.lints <- function(x, ...) { vapply(x, `[[`, character(1L), "filename") } #' @export split.lints <- function(x, f = NULL, ...) { if (is.null(f)) f <- names(x) splt <- split.default(x, f) for (i in names(splt)) class(splt[[i]]) <- "lints" return(splt) } #' @export as.data.frame.lints <- function(x, row.names = NULL, optional = FALSE, ...) { # nolint: object_name. (row.names, #764) data.frame( filename = vapply(x, `[[`, character(1L), "filename"), line_number = vapply(x, `[[`, integer(1L), "line_number"), column_number = vapply(x, `[[`, integer(1L), "column_number"), type = vapply(x, `[[`, character(1L), "type"), message = vapply(x, `[[`, character(1L), "message"), line = vapply(x, `[[`, character(1L), "line"), linter = vapply(x, `[[`, character(1L), "linter") ) } #' @exportS3Method tibble::as_tibble as_tibble.lints <- function(x, ..., # nolint: object_name_linter. .rows = NULL, .name_repair = c("check_unique", "unique", "universal", "minimal"), rownames = NULL) { stopifnot(requireNamespace("tibble", quietly = TRUE)) tibble::as_tibble(as.data.frame(x), ..., .rows = .rows, .name_repair = .name_repair, rownames = rownames) } #' @exportS3Method data.table::as.data.table as.data.table.lints <- function(x, keep.rownames = FALSE, ...) { # nolint: object_name_linter. stopifnot(requireNamespace("data.table", quietly = TRUE)) data.table::setDT(as.data.frame(x), keep.rownames = keep.rownames, ...) } #' @export `[.lints` <- function(x, ...) { attrs <- attributes(x) x <- unclass(x) x <- x[...] attributes(x) <- attrs x } #' @export summary.lints <- function(object, ...) { filenames <- vapply(object, `[[`, character(1L), "filename") types <- factor(vapply(object, `[[`, character(1L), "type"), levels = c("style", "warning", "error") ) tbl <- table(filenames, types) filenames <- rownames(tbl) res <- as.data.frame.matrix(tbl, row.names = NULL) res$filenames <- filenames %||% character() nms <- colnames(res) res[order(res$filenames), c("filenames", nms[nms != "filenames"])] } lintr/R/spaces_inside_linter.R0000644000176200001440000000522114752731051016121 0ustar liggesusers#' Spaces inside linter #' #' Check that parentheses and square brackets do not have spaces directly #' inside them, i.e., directly following an opening delimiter or directly #' preceding a closing delimiter. #' #' @examples #' # will produce lints #' lint( #' text = "c( TRUE, FALSE )", #' linters = spaces_inside_linter() #' ) #' #' lint( #' text = "x[ 1L ]", #' linters = spaces_inside_linter() #' ) #' #' # okay #' lint( #' text = "c(TRUE, FALSE)", #' linters = spaces_inside_linter() #' ) #' #' lint( #' text = "x[1L]", #' linters = spaces_inside_linter() #' ) #' #' @evalRd rd_tags("spaces_inside_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export spaces_inside_linter <- function() { left_xpath_condition <- " not(following-sibling::*[1][self::COMMENT]) and @end != following-sibling::*[1]/@start - 1 and @line1 = following-sibling::*[1]/@line1 " left_xpath <- glue(" //OP-LEFT-BRACKET[{left_xpath_condition}] | //LBB[{left_xpath_condition}] | //OP-LEFT-PAREN[{left_xpath_condition}]") right_xpath_condition <- " not(preceding-sibling::*[1][self::OP-COMMA]) and @start != preceding-sibling::*[1]/@end + 1 and @line1 = preceding-sibling::*[1]/@line2 " right_xpath <- glue(" //OP-RIGHT-BRACKET[{right_xpath_condition}] | //OP-RIGHT-PAREN[{right_xpath_condition} and not(preceding-sibling::*[1][self::EQ_SUB])]") Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content left_expr <- xml_find_all(xml, left_xpath) left_msg <- ifelse( xml_text(left_expr) %in% c("[", "[["), "Do not place spaces after square brackets.", "Do not place spaces after parentheses." ) left_lints <- xml_nodes_to_lints( left_expr, source_expression = source_expression, lint_message = left_msg, range_start_xpath = "number(./@col2 + 1)", # start after ( or [ range_end_xpath = "number(./following-sibling::*[1]/@col1 - 1)" # end before following expr ) right_expr <- xml_find_all(xml, right_xpath) right_msg <- ifelse( xml_text(right_expr) == "]", "Do not place spaces before square brackets.", "Do not place spaces before parentheses." ) right_lints <- xml_nodes_to_lints( right_expr, source_expression = source_expression, lint_message = right_msg, range_start_xpath = "number(./preceding-sibling::*[1]/@col2 + 1)", # start after preceding expression range_end_xpath = "number(./@col1 - 1)" # end before ) or ] ) c(left_lints, right_lints) }) } lintr/R/routine_registration_linter.R0000644000176200001440000000214514752731051017571 0ustar liggesusers#' Identify unregistered native routines #' #' It is preferable to register routines for efficiency and safety. #' #' @examples #' # will produce lints #' lint( #' text = '.Call("cpp_routine", PACKAGE = "mypkg")', #' linters = routine_registration_linter() #' ) #' #' lint( #' text = '.Fortran("f_routine", PACKAGE = "mypkg")', #' linters = routine_registration_linter() #' ) #' #' # okay #' lint( #' text = ".Call(cpp_routine)", #' linters = routine_registration_linter() #' ) #' #' lint( #' text = ".Fortran(f_routine)", #' linters = routine_registration_linter() #' ) #' #' @evalRd rd_tags("routine_registration_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' #' @export routine_registration_linter <- make_linter_from_function_xpath( function_names = c(".C", ".Call", ".Fortran", ".External"), xpath = " following-sibling::expr[1]/STR_CONST /parent::expr ", lint_message = "Register your native code routines with useDynLib and R_registerRoutines()." ) lintr/R/literal_coercion_linter.R0000644000176200001440000001024014752731051016622 0ustar liggesusers#' Require usage of correctly-typed literals over literal coercions #' #' `as.integer(1)` (or `rlang::int(1)`) is the same as `1L` but the latter is #' more concise and gets typed correctly at compilation. #' #' The same applies to missing sentinels like `NA` -- typically, it is not #' necessary to specify the storage type of `NA`, but when it is, prefer #' using the typed version (e.g. `NA_real_`) instead of a coercion #' (like `as.numeric(NA)`). #' #' @examples #' # will produce lints #' lint( #' text = "int(1)", #' linters = literal_coercion_linter() #' ) #' #' lint( #' text = "as.character(NA)", #' linters = literal_coercion_linter() #' ) #' #' lint( #' text = "rlang::lgl(1L)", #' linters = literal_coercion_linter() #' ) #' #' # okay #' lint( #' text = "1L", #' linters = literal_coercion_linter() #' ) #' #' lint( #' text = "NA_character_", #' linters = literal_coercion_linter() #' ) #' #' lint( #' text = "TRUE", #' linters = literal_coercion_linter() #' ) #' #' @evalRd rd_tags("literal_coercion_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export literal_coercion_linter <- function() { rlang_coercers <- c("lgl", "int", "dbl", "chr") coercers <- c( # base coercers paste0("as.", c("logical", "integer", "numeric", "double", "character")), rlang_coercers ) # notes for clarification: # - as.integer(1e6) is arguably easier to read than 1000000L # - in x$"abc", the "abc" STR_CONST is at the top level, so exclude OP-DOLLAR (ditto OP-AT) # - need condition against STR_CONST w/ EQ_SUB to skip quoted keyword arguments (see tests) # - for {rlang} coercers, both `int(1)` and `int(1, )` need to be linted not_extraction_or_scientific <- " not(OP-DOLLAR or OP-AT) and ( NUM_CONST[not(contains(translate(text(), 'E', 'e'), 'e'))] or STR_CONST[not(following-sibling::*[1][self::EQ_SUB])] ) " xpath <- glue(" parent::expr[ count(expr) = 2 and expr[2][ {not_extraction_or_scientific} ] ]") Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(coercers) bad_expr <- xml_find_all(xml_calls, xpath) coercer <- xp_call_name(bad_expr) # tiptoe around the fact that we don't require {rlang} is_rlang_coercer <- coercer %in% rlang_coercers if (any(is_rlang_coercer) && !requireNamespace("rlang", quietly = TRUE)) { # nocov start: test suite will have 'rlang' available # NB: we _could_ do some extreme customization where each lint # gets a message according to whether the coercer is from rlang, # but this seems like overkill. Just use a generic message and move on. lint_message <- paste( "Use literals directly where possible, instead of coercion.", "c.f. 1L instead of as.integer(1) or rlang::int(1), or NA_real_ instead of as.numeric(NA).", "NB: this message can be improved to show a specific replacement if 'rlang' is installed." ) # nocov end } else { # duplicate, unless we add 'rlang::' and it wasn't there originally coercion_str <- report_str <- xml_text(bad_expr) if (any(is_rlang_coercer) && !("package:rlang" %in% search())) { needs_prefix <- is_rlang_coercer & !startsWith(coercion_str, "rlang::") coercion_str[needs_prefix] <- paste0("rlang::", coercion_str[needs_prefix]) } # the linter logic & rlang requirement should ensure that it's safe to run eval() here; # suppressWarnings() is for cases like 'as.integer("a")' which have an NA result, #2566. # TODO(#2473): Avoid a recommendation like '1' that clashes with implicit_integer_linter(). literal_equivalent_str <- vapply( str2expression(coercion_str), function(expr) deparse1(suppressWarnings(eval(expr))), character(1L) ) lint_message <- sprintf( "Use %s instead of %s, i.e., use literals directly where possible, instead of coercion.", literal_equivalent_str, report_str ) } xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = lint_message, type = "warning" ) }) } lintr/R/pipe_call_linter.R0000644000176200001440000000265614752731051015251 0ustar liggesusers#' Pipe call linter #' #' Force explicit calls in magrittr pipes, e.g., `1:3 %>% sum()` instead of `1:3 %>% sum`. #' Note that native pipe always requires a function call, i.e. `1:3 |> sum` will produce an error. #' #' @examples #' # will produce lints #' lint( #' text = "1:3 %>% mean %>% as.character", #' linters = pipe_call_linter() #' ) #' #' # okay #' lint( #' text = "1:3 %>% mean() %>% as.character()", #' linters = pipe_call_linter() #' ) #' #' @evalRd rd_tags("pipe_call_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export pipe_call_linter <- function() { # NB: the text() here shows up as %>% but that's not matched, %>% is # NB: use *[1][self::SYMBOL] to ensure the first element is SYMBOL, otherwise # we include expressions like x %>% .$col pipes <- setdiff(magrittr_pipes, "%$%") xpath <- glue("//SPECIAL[{ xp_text_in_table(pipes) }]/following-sibling::expr[*[1][self::SYMBOL]]") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) pipe <- xml_text(xml_find_first(bad_expr, "preceding-sibling::SPECIAL[1]")) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = sprintf("Use explicit calls in magrittr pipes, i.e., `a %1$s foo` should be `a %1$s foo()`.", pipe), type = "warning" ) }) } lintr/R/nzchar_linter.R0000644000176200001440000001230114752731051014572 0ustar liggesusers#' Require usage of nzchar where appropriate #' #' [nzchar()] efficiently determines which of a vector of strings are empty #' (i.e., are `""`). It should in most cases be used instead of #' constructions like `string == ""` or `nchar(string) == 0`. #' #' One crucial difference is in the default handling of `NA_character_`, i.e., #' missing strings. `nzchar(NA_character_)` is `TRUE`, while `NA_character_ == ""` #' and `nchar(NA_character_) == 0` are both `NA`. Therefore, for strict #' compatibility, use `nzchar(x, keepNA = TRUE)`. If the input is known to be #' complete (no missing entries), this argument can be dropped for conciseness. #' #' @examples #' # will produce lints #' lint( #' text = "x[x == '']", #' linters = nzchar_linter() #' ) #' #' lint( #' text = "x[nchar(x) > 0]", #' linters = nzchar_linter() #' ) #' #' # okay #' lint( #' text = "x[!nzchar(x, keepNA = TRUE)]", #' linters = nzchar_linter() #' ) #' #' lint( #' text = "x[nzchar(x, keepNA = TRUE)]", #' linters = nzchar_linter() #' ) #' #' @evalRd rd_tags("nzchar_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export nzchar_linter <- function() { comparator_nodes <- infix_metadata$xml_tag[infix_metadata$comparator] # use string-length to capture both "" and '' # if (any(x == "")) is not treated like it's part of if(), but # any(if (x == "") y else z) _is_ treated so. this condition looks for the # expr to be inside a call that's _not_ above an IF/WHILE. comparison_xpath <- glue(" //STR_CONST[string-length(text()) = 2] /parent::expr /parent::expr[ ({ xp_or(comparator_nodes) }) and ( not(ancestor-or-self::expr[ preceding-sibling::IF or preceding-sibling::WHILE ]) or ancestor-or-self::expr[ ( preceding-sibling::expr/SYMBOL_FUNCTION_CALL or preceding-sibling::OP-LEFT-BRACKET ) and not( descendant-or-self::expr[IF or WHILE] ) ] ) ] ") comparison_msg_map <- c( GT = 'Use nzchar(x) instead of x > "". ', NE = 'Use nzchar(x) instead of x != "". ', LE = 'Use !nzchar(x) instead of x <= "". ', EQ = 'Use !nzchar(x) instead of x == "". ', GE = 'x >= "" is always true, maybe you want nzchar(x)? ', LT = 'x < "" is always false, maybe you want !nzchar(x)? ' ) # nchar(., type="width") not strictly compatible with nzchar # unsure allowNA compatible, so allow it just in case (see TODO in tests) nchar_xpath <- glue(" parent::expr /parent::expr[ ({ xp_or(comparator_nodes) }) and not(expr/SYMBOL_SUB[ ( text() = 'type' and following-sibling::expr[1]/STR_CONST[contains(text(), 'width')] ) or ( text() = 'allowNA' and following-sibling::expr[1]/NUM_CONST[text() = 'TRUE'] ) ]) and expr/NUM_CONST[text() = '0' or text() = '0L' or text() = '0.0'] ] ") nchar_msg_map <- c( GT = "Use nzchar(x) instead of nchar(x) > 0. ", NE = "Use nzchar(x) instead of nchar(x) != 0. ", LE = "Use !nzchar(x) instead of nchar(x) <= 0. ", EQ = "Use !nzchar(x) instead of nchar(x) == 0. ", GE = "nchar(x) >= 0 is always true, maybe you want nzchar(x)? ", LT = "nchar(x) < 0 is always false, maybe you want !nzchar(x)? " ) keepna_note <- paste( "Whenever missing data is possible,", "please take care to use nzchar(., keepNA = TRUE);", "nzchar(NA) is TRUE by default." ) # For ordered operators like '>', we need to give the message for # its "opposite" (not inverse) if the bad usage is on the RHS, # e.g. 0 < nchar(x) has to be treated as nchar(x) > 0. op_for_msg <- function(expr, const) { op <- xml_name(xml_find_first(expr, "*[2]")) maybe_needs_flip <- !is.na(xml_find_first(expr, sprintf("*[1][%s]", const))) ordered_ops <- c("GT", "GE", "LE", "LT") ordered_idx <- match(op, ordered_ops) needs_flip <- maybe_needs_flip & !is.na(ordered_idx) # un-benchmarked, but should be faster (though less readable) as # > ordered_ops[5L - ordered_idx[needs_flip]] op[needs_flip] <- rev(ordered_ops)[ordered_idx[needs_flip]] op } Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content comparison_expr <- xml_find_all(xml, comparison_xpath) comparison_op <- op_for_msg(comparison_expr, const = "STR_CONST") comparison_lints <- xml_nodes_to_lints( comparison_expr, source_expression = source_expression, lint_message = paste0( comparison_msg_map[comparison_op], "Note that unlike nzchar(), ", comparison_op, " coerces to character, ", "so you'll have to use as.character() if x is a factor. ", keepna_note ), type = "warning" ) xml_calls <- source_expression$xml_find_function_calls("nchar") nchar_expr <- xml_find_all(xml_calls, nchar_xpath) nchar_op <- op_for_msg(nchar_expr, const = "NUM_CONST") nchar_lints <- xml_nodes_to_lints( nchar_expr, source_expression = source_expression, lint_message = paste0(nchar_msg_map[nchar_op], keepna_note), type = "warning" ) c(comparison_lints, nchar_lints) }) } lintr/R/one_call_pipe_linter.R0000644000176200001440000000472214752731051016106 0ustar liggesusers#' Block single-call magrittr pipes #' #' Prefer using a plain call instead of a pipe with only one call, #' i.e. `1:10 %>% sum()` should instead be `sum(1:10)`. Note that #' calls in the first `%>%` argument count. `rowSums(x) %>% max()` is OK #' because there are two total calls (`rowSums()` and `max()`). #' #' Note also that un-"called" steps are *not* counted, since they should #' be calls (see [pipe_call_linter()]). #' #' @examples #' # will produce lints #' lint( #' text = "(1:10) %>% sum()", #' linters = one_call_pipe_linter() #' ) #' #' lint( #' text = "DT %>% .[grp == 'a', sum(v)]", #' linters = one_call_pipe_linter() #' ) #' #' # okay #' lint( #' text = "rowSums(x) %>% mean()", #' linters = one_call_pipe_linter() #' ) #' #' lint( #' text = "DT[src == 'a', .N, by = grp] %>% .[N > 10]", #' linters = one_call_pipe_linter() #' ) #' #' # assignment pipe is exempted #' lint( #' text = "DF %<>% mutate(a = 2)", #' linters = one_call_pipe_linter() #' ) #' #' @evalRd rd_tags("one_call_pipe_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export one_call_pipe_linter <- function() { # exception for assignment pipe per #2330 pipes_cond <- xp_text_in_table(setdiff(magrittr_pipes, "%<>%")) # preceding-sibling::SPECIAL: if there are ever two pipes, don't lint # OP-LEFT-BRACKET/LBB: accept DT[...] %>% .[...] as a two-call pipe, # (but not DT %>% .[...]) # parent::expr/SPECIAL: make sure we are at the top of a pipeline # count(): any call anywhere else in the AST within the pipe expression xpath <- glue(" (//SPECIAL[{pipes_cond}] | //PIPE)[ not(preceding-sibling::expr[1]/*[self::SPECIAL[{pipes_cond}] or self::PIPE]) and ( not(following-sibling::expr[OP-LEFT-BRACKET or LBB]) or not(preceding-sibling::expr[OP-LEFT-BRACKET or LBB]) ) ] /parent::expr[ not(parent::expr/*[self::SPECIAL[{ pipes_cond }] or self::PIPE]) and count(.//SYMBOL_FUNCTION_CALL) <= 1 ] ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) pipe <- xml_find_chr(bad_expr, "string(SPECIAL | PIPE)") xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = paste0("Avoid pipe ", pipe, " for expressions with only a single call."), type = "warning" ) }) } lintr/R/expect_s3_class_linter.R0000644000176200001440000000660014752731051016374 0ustar liggesusers#' Require usage of `expect_s3_class()` #' #' [testthat::expect_s3_class()] exists specifically for testing the class #' of S3 objects. [testthat::expect_equal()], [testthat::expect_identical()], #' and [testthat::expect_true()] can also be used for such tests, #' but it is better to use the tailored function instead. #' #' @examples #' # will produce lints #' lint( #' text = 'expect_equal(class(x), "data.frame")', #' linters = expect_s3_class_linter() #' ) #' #' lint( #' text = 'expect_equal(class(x), "numeric")', #' linters = expect_s3_class_linter() #' ) #' #' # okay #' lint( #' text = 'expect_s3_class(x, "data.frame")', #' linters = expect_s3_class_linter() #' ) #' #' lint( #' text = 'expect_type(x, "double")', #' linters = expect_s3_class_linter() #' ) #' #' @evalRd rd_tags("expect_s3_class_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - [expect_s4_class_linter()] #' @export expect_s3_class_linter <- function() { # (1) expect_{equal,identical}(class(x), C) # (2) expect_true(is.(x)) and expect_true(inherits(x, C)) expect_equal_identical_xpath <- " following-sibling::expr[ expr[1][SYMBOL_FUNCTION_CALL[text() = 'class']] and (position() = 1 or preceding-sibling::expr[STR_CONST]) ] /parent::expr[not(SYMBOL_SUB[text() = 'info' or text() = 'label' or text() = 'expected.label'])] " # NB: there is no easy way to make an exhaustive list of places where an # is. call can be replaced by expect_s3_class(); this list was manually # populated from the default R packages by inspection. For example, # is.matrix(x) cannot be replaced by expect_s3_class(x, "matrix") because # it is not actually an S3 class (is.object(x) is not TRUE). # Further, there are functions named is. that have nothing to do with # object type, e.g. is.finite(), is.nan(), or is.R(). is_s3_class_calls <- paste0("is.", c( # base "data.frame", "factor", "numeric_version", "ordered", "package_version", "qr", "table", # utils grDevices tcltk tcltk grid grid "relistable", "raster", "tclObj", "tkwin", "grob", "unit", # stats "mts", "stepfun", "ts", "tskernel" )) is_class_call <- xp_text_in_table(c(is_s3_class_calls, "inherits")) expect_true_xpath <- glue(" following-sibling::expr[1][expr[1][SYMBOL_FUNCTION_CALL[ {is_class_call} ]]] /parent::expr[not(SYMBOL_SUB[text() = 'info' or text() = 'label'])] ") Linter(linter_level = "expression", function(source_expression) { expect_equal_identical_calls <- source_expression$xml_find_function_calls(c("expect_equal", "expect_identical")) expect_true_calls <- source_expression$xml_find_function_calls("expect_true") bad_expr <- combine_nodesets( xml_find_all(expect_equal_identical_calls, expect_equal_identical_xpath), xml_find_all(expect_true_calls, expect_true_xpath) ) matched_function <- xp_call_name(bad_expr) msg <- ifelse( matched_function %in% c("expect_equal", "expect_identical"), sprintf("expect_s3_class(x, k) is better than %s(class(x), k).", matched_function), "expect_s3_class(x, k) is better than expect_true(is.(x)) or expect_true(inherits(x, k))." ) xml_nodes_to_lints( bad_expr, source_expression, lint_message = paste(msg, "Note also expect_s4_class() available for testing S4 objects."), type = "warning" ) }) } lintr/R/equals_na_linter.R0000644000176200001440000000267014752731051015265 0ustar liggesusers#' Equality check with NA linter #' #' Check for `x == NA`, `x != NA` and `x %in% NA`. Such usage is almost surely incorrect -- #' checks for missing values should be done with [is.na()]. #' #' @examples #' # will produce lints #' lint( #' text = "x == NA", #' linters = equals_na_linter() #' ) #' #' lint( #' text = "x != NA", #' linters = equals_na_linter() #' ) #' #' lint( #' text = "x %in% NA", #' linters = equals_na_linter() #' ) #' #' # okay #' lint( #' text = "is.na(x)", #' linters = equals_na_linter() #' ) #' #' lint( #' text = "!is.na(x)", #' linters = equals_na_linter() #' ) #' #' @evalRd rd_tags("equals_na_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export equals_na_linter <- function() { na_table <- xp_text_in_table(c("NA", "NA_integer_", "NA_real_", "NA_complex_", "NA_character_")) xpath <- glue(" //NUM_CONST[ {na_table} ] /parent::expr /parent::expr[EQ or NE] | //SPECIAL[text() = '%in%' and following-sibling::expr/NUM_CONST[ {na_table} ]] /parent::expr ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) op <- xml_find_first(bad_expr, "EQ | NE | SPECIAL") xml_nodes_to_lints( bad_expr, source_expression, lint_message = sprintf("Use is.na() instead of x %s NA", xml_text(op)), type = "warning" ) }) } lintr/R/implicit_integer_linter.R0000644000176200001440000000531014752731051016636 0ustar liggesusers#' Implicit integer linter #' #' Check that integers are explicitly typed using the form `1L` instead of `1`. #' #' @param allow_colon Logical, default `FALSE`. If `TRUE`, expressions involving `:` #' won't throw a lint regardless of whether the inputs are implicitly integers. #' @examples #' # will produce lints #' lint( #' text = "x <- 1", #' linters = implicit_integer_linter() #' ) #' #' lint( #' text = "x[2]", #' linters = implicit_integer_linter() #' ) #' #' lint( #' text = "1:10", #' linters = implicit_integer_linter() #' ) #' #' # okay #' lint( #' text = "x <- 1.0", #' linters = implicit_integer_linter() #' ) #' #' lint( #' text = "x <- 1L", #' linters = implicit_integer_linter() #' ) #' #' lint( #' text = "x[2L]", #' linters = implicit_integer_linter() #' ) #' #' lint( #' text = "1:10", #' linters = implicit_integer_linter(allow_colon = TRUE) #' ) #' #' @evalRd rd_tags("implicit_integer_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export implicit_integer_linter <- function(allow_colon = FALSE) { if (allow_colon) { xpath <- "//NUM_CONST[not(parent::expr/parent::expr/OP-COLON)]" } else { xpath <- "//NUM_CONST" } Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content number_expr <- xml_find_all(xml, xpath) number <- xml_text(number_expr) lint_idx <- is_implicit_integer(number) number_expr <- number_expr[lint_idx] number <- number[lint_idx] is_negative <- !is.na(xml_find_first(number_expr, "parent::expr/preceding-sibling::OP-MINUS")) lint_message <- sprintf("Use %1$dL or %1$d.0 to avoid implicit integers.", ((-1L)^is_negative) * as.integer(number)) xml_nodes_to_lints( number_expr, source_expression = source_expression, lint_message = lint_message, type = "style", column_number_xpath = "number(./@col2 + 1)", # mark at end range_end_xpath = "number(./@col2 + 1)" # end after number for easy fixing (enter "L" or ".0") ) }) } is_implicit_integer <- function(s) { # styler: off is_implicit <- !re_matches(s, rex(or( group(start, upper), # Inf, NaN and logicals (TRUE, FALSE, NA, NA_*) group(start, "0x"), # hexadecimals, e.g. 0x0f, 0x1p+0 or 0x1.ec6666666p+6 dot, # doubles with a decimal point, e.g. 1.0 or 0.945 group("i", end), # complex type, e.g. 1+3i group("L", end) # integer type, e.g. 62L or 1e3L ))) # styler: on # only keep numbers that are within the range representable by R, and that are whole n <- as.double(s[is_implicit]) is_implicit[is_implicit] <- abs(n) <= .Machine[["integer.max"]] & floor(n) == n is_implicit } lintr/R/matrix_apply_linter.R0000644000176200001440000001073114752731051016023 0ustar liggesusers#' Require usage of `colSums(x)` or `rowSums(x)` over `apply(x, ., sum)` #' #' [colSums()] and [rowSums()] are clearer and more performant alternatives to #' `apply(x, 2, sum)` and `apply(x, 1, sum)` respectively in the case of 2D #' arrays, or matrices #' #' @examples #' # will produce lints #' lint( #' text = "apply(x, 1, sum)", #' linters = matrix_apply_linter() #' ) #' #' lint( #' text = "apply(x, 2, sum)", #' linters = matrix_apply_linter() #' ) #' #' lint( #' text = "apply(x, 2, sum, na.rm = TRUE)", #' linters = matrix_apply_linter() #' ) #' #' lint( #' text = "apply(x, 2:4, sum)", #' linters = matrix_apply_linter() #' ) #' #' @evalRd rd_tags("matrix_apply_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export matrix_apply_linter <- function() { # mean() and sum() have very different signatures so we treat them separately. # sum() takes values to sum over via ..., has just one extra argument and is not a generic # mean() is a generic, takes values to average via a single argument, and can have extra arguments # # Currently supported values for MARGIN: scalar numeric and vector of contiguous values created by : (OP-COLON) sums_xpath <- " following-sibling::expr[ NUM_CONST or OP-COLON/preceding-sibling::expr[NUM_CONST]/following-sibling::expr[NUM_CONST] and (position() = 2) ] /following-sibling::expr[ SYMBOL[text() = 'sum'] and (position() = 1) ] /parent::expr " # Since mean() is a generic, we make sure that we only lint cases with arguments # supported by colMeans() and rowMeans(), i.e., na.rm means_xpath <- " following-sibling::expr[ NUM_CONST or OP-COLON/preceding-sibling::expr[NUM_CONST]/following-sibling::expr[NUM_CONST] and (position() = 2) ] /following-sibling::expr[ SYMBOL[text() = 'mean'] and (position() = 1) ] /parent::expr[ count(expr) = 4 or (count(expr) = 5 and SYMBOL_SUB[text() = 'na.rm']) ] " xpath <- glue("{sums_xpath} | {means_xpath}") # This doesn't handle the case when MARGIN and FUN are named and in a different position # but this should be relatively rate variable_xpath <- "expr[position() = 2]" margin_xpath <- "expr[position() = 3]" fun_xpath <- "expr[position() = 4]" Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls("apply") bad_expr <- xml_find_all(xml_calls, xpath) variable <- xml_text(xml_find_all(bad_expr, variable_xpath)) fun <- xml_text(xml_find_all(bad_expr, fun_xpath)) fun <- tools::toTitleCase(fun) margin <- xml_find_all(bad_expr, margin_xpath) narm_val <- xml_text( xml_find_first(bad_expr, "SYMBOL_SUB[text() = 'na.rm']/following-sibling::expr") ) recos <- Map(craft_colsums_rowsums_msg, variable, margin, fun, narm_val) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = sprintf("Use %1$s rather than %2$s", recos, get_r_string(bad_expr)), type = "warning" ) }) } craft_colsums_rowsums_msg <- function(variable, margin, fun, narm_val) { if (is.na(xml_find_first(margin, "OP-COLON"))) { l1 <- xml_text(margin) l2 <- NULL } else { l1 <- xml_text(xml_find_first(margin, "expr[1]")) l2 <- xml_text(xml_find_first(margin, "expr[2]")) } # See #1764 for details about various cases. In short: # - If apply(., 1:l2, sum) -> rowSums(., dims = l2) # - If apply(., l1:l2, sum) -> rowSums(colSums(., dims = l1 - 1), dims = l2 - l1 + 1) # - This last case can be simplified to a simple colSums() call if l2 = length(dim(.)) # - dims argument can be dropped if equals to 1. This notably is the case for matrices if (is.null(l2)) { l2 <- l1 } # We don't want warnings when converted as NAs l1 <- suppressWarnings(as.integer(re_substitutes(l1, "L$", ""))) l2 <- suppressWarnings(as.integer(re_substitutes(l2, "L$", ""))) if (!is.na(narm_val)) { narm <- glue(", na.rm = {narm_val}") } else { narm <- "" } if (identical(l1, 1L)) { reco <- glue("row{fun}s({variable}{narm}, dims = {l2})") } else { reco <- glue( "row{fun}s(col{fun}s({variable}{narm}, dims = {l1 - 1}), dims = {l2 - l1 + 1})", " or ", "col{fun}s({variable}{narm}, dims = {l1 - 1}) if {variable} has {l2} dimensions" ) } # It's easier to remove this after the fact, rather than having never ending if/elses reco <- gsub(", dims = 1", "", reco, fixed = TRUE) reco } lintr/R/stopifnot_all_linter.R0000644000176200001440000000214714752731051016171 0ustar liggesusers#' Block usage of all() within stopifnot() #' #' `stopifnot(A)` actually checks `all(A)` "under the hood" if `A` is a vector, #' and produces a better error message than `stopifnot(all(A))` does. #' #' @examples #' # will produce lints #' lint( #' text = "stopifnot(all(x > 0))", #' linters = stopifnot_all_linter() #' ) #' #' lint( #' text = "stopifnot(y > 3, all(x < 0))", #' linters = stopifnot_all_linter() #' ) #' #' # okay #' lint( #' text = "stopifnot(is.null(x) || all(x > 0))", #' linters = stopifnot_all_linter() #' ) #' #' lint( #' text = "assert_that(all(x > 0))", #' linters = stopifnot_all_linter() #' ) #' #' @evalRd rd_tags("stopifnot_all_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export stopifnot_all_linter <- make_linter_from_function_xpath( function_names = "stopifnot", xpath = " parent::expr /expr[expr/SYMBOL_FUNCTION_CALL[text() = 'all']] ", lint_message = paste( "Use stopifnot(x) instead of stopifnot(all(x)).", "stopifnot(x) runs all() 'under the hood' and provides a better error message in case of failure." ) ) lintr/R/numeric_leading_zero_linter.R0000644000176200001440000000207614752731051017501 0ustar liggesusers#' Require usage of a leading zero in all fractional numerics #' #' While .1 and 0.1 mean the same thing, the latter is easier to read due #' to the small size of the '.' glyph. #' #' @examples #' # will produce lints #' lint( #' text = "x <- .1", #' linters = numeric_leading_zero_linter() #' ) #' #' lint( #' text = "x <- -.1", #' linters = numeric_leading_zero_linter() #' ) #' #' # okay #' lint( #' text = "x <- 0.1", #' linters = numeric_leading_zero_linter() #' ) #' #' lint( #' text = "x <- -0.1", #' linters = numeric_leading_zero_linter() #' ) #' #' @evalRd rd_tags("numeric_leading_zero_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export numeric_leading_zero_linter <- make_linter_from_xpath( # NB: # 1. negative constants are split to two components: # OP-MINUS, NUM_CONST # 2. complex constants are split to three components: # NUM_CONST, OP-PLUS/OP-MINUS, NUM_CONST xpath = "//NUM_CONST[starts-with(text(), '.')]", lint_message = "Include the leading zero for fractional numeric constants." ) lintr/R/pipe_continuation_linter.R0000644000176200001440000000457214752731051017047 0ustar liggesusers#' Pipe continuation linter #' #' Check that each step in a pipeline is on a new line, or the entire pipe fits on one line. #' #' @evalRd rd_tags("pipe_continuation_linter") #' #' @examples #' # will produce lints #' code_lines <- "1:3 %>%\n mean() %>% as.character()" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = pipe_continuation_linter() #' ) #' #' code_lines <- "1:3 |> mean() |>\n as.character()" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = pipe_continuation_linter() #' ) #' #' # okay #' lint( #' text = "1:3 %>% mean() %>% as.character()", #' linters = pipe_continuation_linter() #' ) #' #' code_lines <- "1:3 %>%\n mean() %>%\n as.character()" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = pipe_continuation_linter() #' ) #' #' lint( #' text = "1:3 |> mean() |> as.character()", #' linters = pipe_continuation_linter() #' ) #' #' code_lines <- "1:3 |>\n mean() |>\n as.character()" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = pipe_continuation_linter() #' ) #' #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export pipe_continuation_linter <- function() { # Where a single-line pipeline is nested inside a larger expression # e.g. inside a function definition), the outer expression can span multiple lines # without throwing a lint. pipe_node <- glue("SPECIAL[{ xp_text_in_table(magrittr_pipes) }]") preceding_pipe <- glue("preceding-sibling::expr[1]/descendant::*[self::{pipe_node} or self::PIPE]") xpath <- glue(" (//PIPE | //{pipe_node})[ parent::expr[@line1 < @line2] and {preceding_pipe} and ( preceding-sibling::expr[1]/descendant-or-self::expr/@line2 = following-sibling::expr[1]/descendant-or-self::expr/@line1 or @line1 = {preceding_pipe}/@line1 ) ] ") Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content pipe_exprs <- xml_find_all(xml, xpath) pipe_text <- xml_text(pipe_exprs) xml_nodes_to_lints( pipe_exprs, source_expression = source_expression, lint_message = sprintf( "Put a space before `%s` and a new line after it, unless the full pipeline fits on one line.", pipe_text ), type = "style" ) }) } lintr/R/is_lint_level.R0000644000176200001440000000352114752731051014564 0ustar liggesusers#' Is this an expression- or a file-level source object? #' #' Helper for determining whether the current `source_expression` contains #' all expressions in the current file, or just a single expression. #' #' @param source_expression A parsed expression object, i.e., an element #' of the object returned by [get_source_expressions()]. #' @param level Which level of expression is being tested? `"expression"` #' means an individual expression, while `"file"` means all expressions #' in the current file are available. #' #' @examples #' tmp <- tempfile() #' writeLines(c("x <- 1", "y <- x + 1"), tmp) #' source_exprs <- get_source_expressions(tmp) #' is_lint_level(source_exprs$expressions[[1L]], level = "expression") #' is_lint_level(source_exprs$expressions[[1L]], level = "file") #' is_lint_level(source_exprs$expressions[[3L]], level = "expression") #' is_lint_level(source_exprs$expressions[[3L]], level = "file") #' unlink(tmp) #' #' @export is_lint_level <- function(source_expression, level = c("expression", "file")) { level <- match.arg(level) required_key <- switch(level, file = "full_parsed_content", expression = "parsed_content") required_key %in% names(source_expression) } #' Determine whether a linter needs to run for a given source_expression level #' #' Used by [lint()] to avoid unneccessary calls to linters. #' #' @param linter A linter. #' @param level Which level of expression is being tested? `"expression"` #' means an individual expression, while `"file"` means all expressions #' in the current file are available. #' #' @keywords internal #' @noRd is_linter_level <- function(linter, level = c("expression", "file")) { linter_level <- attr(linter, "linter_level", exact = TRUE) if (is.null(linter_level) || is.na(linter_level)) { return(TRUE) } level <- match.arg(level) identical(linter_level, level) } lintr/R/cyclocomp_linter.R0000644000176200001440000000336314752731051015305 0ustar liggesusers#' Cyclomatic complexity linter #' #' Check for overly complicated expressions. See `cyclocomp()` function from `{cyclocomp}`. #' #' @param complexity_limit Maximum cyclomatic complexity, default `15`. Expressions more complex #' than this are linted. #' #' @examplesIf requireNamespace("cyclocomp", quietly = TRUE) #' # will produce lints #' lint( #' text = "if (TRUE) 1 else 2", #' linters = cyclocomp_linter(complexity_limit = 1L) #' ) #' #' # okay #' lint( #' text = "if (TRUE) 1 else 2", #' linters = cyclocomp_linter(complexity_limit = 2L) #' ) #' #' @evalRd rd_tags("cyclocomp_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export cyclocomp_linter <- function(complexity_limit = 15L) { Linter(linter_level = "expression", function(source_expression) { # nocov start if (!requireNamespace("cyclocomp", quietly = TRUE)) { cli::cli_abort(c( "Cyclocomp complexity is computed using {.fn cyclocomp::cyclocomp}.", i = "Please install the needed {.pkg cyclocomp} package." )) } # nocov end complexity <- try_silently( cyclocomp::cyclocomp(parse(text = source_expression$content)) ) if (inherits(complexity, "try-error") || complexity <= complexity_limit) { return(list()) } col1 <- source_expression[["column"]][1L] Lint( filename = source_expression[["filename"]], line_number = source_expression[["line"]][1L], column_number = source_expression[["column"]][1L], type = "style", message = sprintf( "Reduce the cyclomatic complexity of this function from %d to at most %d.", complexity, complexity_limit ), ranges = list(rep(col1, 2L)), line = source_expression$lines[1L] ) }) } lintr/R/any_is_na_linter.R0000644000176200001440000000356214752731051015256 0ustar liggesusers#' Require usage of `anyNA(x)` over `any(is.na(x))` #' #' [anyNA()] exists as a replacement for `any(is.na(x))` which is more efficient #' for simple objects, and is at worst equally efficient. #' Therefore, it should be used in all situations instead of the latter. #' #' @examples #' # will produce lints #' lint( #' text = "any(is.na(x), na.rm = TRUE)", #' linters = any_is_na_linter() #' ) #' #' lint( #' text = "any(is.na(foo(x)))", #' linters = any_is_na_linter() #' ) #' #' # okay #' lint( #' text = "anyNA(x)", #' linters = any_is_na_linter() #' ) #' #' lint( #' text = "anyNA(foo(x))", #' linters = any_is_na_linter() #' ) #' #' lint( #' text = "any(!is.na(x), na.rm = TRUE)", #' linters = any_is_na_linter() #' ) #' #' @evalRd rd_tags("any_is_na_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export any_is_na_linter <- function() { any_xpath <- " following-sibling::expr[1][expr[1][SYMBOL_FUNCTION_CALL[text() = 'is.na']]] /parent::expr[ count(expr) = 2 or (count(expr) = 3 and SYMBOL_SUB[text() = 'na.rm']) ] " in_xpath <- "//SPECIAL[text() = '%in%']/preceding-sibling::expr[NUM_CONST[starts-with(text(), 'NA')]]" Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content xml_calls <- source_expression$xml_find_function_calls("any") any_expr <- xml_find_all(xml_calls, any_xpath) any_lints <- xml_nodes_to_lints( any_expr, source_expression = source_expression, lint_message = "anyNA(x) is better than any(is.na(x)).", type = "warning" ) in_expr <- xml_find_all(xml, in_xpath) in_lints <- xml_nodes_to_lints( in_expr, source_expression = source_expression, lint_message = "anyNA(x) is better than NA %in% x.", type = "warning" ) c(any_lints, in_lints) }) } lintr/R/unnecessary_placeholder_linter.R0000644000176200001440000000354214752731051020215 0ustar liggesusers#' Block usage of pipeline placeholders if unnecessary #' #' The argument placeholder `.` in magrittr pipelines is unnecessary if #' passed as the first positional argument; using it can cause confusion #' and impacts readability. #' #' This is true for forward (`%>%`), assignment (`%<>%`), and tee (`%T>%`) operators. #' #' @examples #' # will produce lints #' lint( #' text = "x %>% sum(., na.rm = TRUE)", #' linters = unnecessary_placeholder_linter() #' ) #' #' # okay #' lint( #' text = "x %>% sum(na.rm = TRUE)", #' linters = unnecessary_placeholder_linter() #' ) #' #' lint( #' text = "x %>% lm(data = ., y ~ z)", #' linters = unnecessary_placeholder_linter() #' ) #' #' lint( #' text = "x %>% outer(., .)", #' linters = unnecessary_placeholder_linter() #' ) #' #' @evalRd rd_tags("unnecessary_placeholder_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export unnecessary_placeholder_linter <- function() { # NB: Native placeholder '_' must be used with a named argument, so it's not relevant here. xpath <- glue(" //SPECIAL[{ xp_text_in_table(magrittr_pipes) }] /following-sibling::expr[ expr/SYMBOL_FUNCTION_CALL and not(expr[ position() > 2 and descendant-or-self::expr/SYMBOL[text() = '.'] ]) ] /expr[2][ SYMBOL[text() = '.'] and not(preceding-sibling::*[1][self::EQ_SUB]) ] ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = paste( "Don't use the placeholder (`.`) when it's not needed,", "i.e., when it's only used as the first positional argument in a pipeline step." ), type = "warning" ) }) } lintr/R/consecutive_mutate_linter.R0000644000176200001440000000623014752731051017217 0ustar liggesusers#' Require consecutive calls to mutate() to be combined when possible #' #' `dplyr::mutate()` accepts any number of columns, so sequences like #' `DF %>% dplyr::mutate(..1) %>% dplyr::mutate(..2)` are redundant -- #' they can always be expressed with a single call to `dplyr::mutate()`. #' #' An exception is for some SQL back-ends, where the translation logic may not be #' as sophisticated as that in the default `dplyr`, for example in #' `DF %>% mutate(a = a + 1) %>% mutate(b = a - 2)`. #' #' @param invalid_backends Character vector of packages providing dplyr backends #' which may not be compatible with combining `mutate()` calls in all cases. #' Defaults to `"dbplyr"` since not all SQL backends can handle re-using #' a variable defined in the same `mutate()` expression. #' #' @examples #' # will produce lints #' lint( #' text = "x %>% mutate(a = 1) %>% mutate(b = 2)", #' linters = consecutive_mutate_linter() #' ) #' #' # okay #' lint( #' text = "x %>% mutate(a = 1, b = 2)", #' linters = consecutive_mutate_linter() #' ) #' #' code <- "library(dbplyr)\nx %>% mutate(a = 1) %>% mutate(a = a + 1)" #' writeLines(code) #' lint( #' text = code, #' linters = consecutive_mutate_linter() #' ) #' #' @evalRd rd_tags("consecutive_mutate_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export consecutive_mutate_linter <- function(invalid_backends = "dbplyr") { attach_pkg_xpath <- " following-sibling::expr /*[self::SYMBOL or self::STR_CONST] " namespace_xpath <- glue(" //SYMBOL_PACKAGE[{ xp_text_in_table(invalid_backends) }] | //COMMENT[ contains(text(), '@import') and ( {xp_or(sprintf(\"contains(text(), '%s')\", invalid_backends))} ) ] ") # match on the expr, not the SYMBOL_FUNCTION_CALL, to ensure # namespace-qualified calls only match if the namespaces do. # expr[2] needed in expr[1][expr[2]] to skip matches on pipelines # starting like mutate(DF, ...) %>% foo() %>% mutate(). # similarly, expr[1][expr[call='mutate']] covers pipelines # starting like mutate(DF, ...) %>% mutate(...) mutate_cond <- xp_and( "expr/SYMBOL_FUNCTION_CALL[text() = 'mutate']", "not(SYMBOL_SUB[text() = '.keep' or text() = '.by'])" ) xpath <- glue(" (//PIPE | //SPECIAL[{ xp_text_in_table(magrittr_pipes) }]) /preceding-sibling::expr[expr[2][{ mutate_cond }] or ({ mutate_cond })] /following-sibling::expr[{ mutate_cond }] ") Linter(linter_level = "file", function(source_expression) { # need the full file to also catch usages at the top level xml <- source_expression$full_xml_parsed_content attach_str <- get_r_string(xml_find_all( source_expression$xml_find_function_calls(c("library", "require")), attach_pkg_xpath )) if (any(invalid_backends %in% attach_str)) { return(list()) } namespace_expr <- xml_find_first(xml, namespace_xpath) if (!is.na(namespace_expr)) { return(list()) } bad_expr <- xml_find_all(xml, xpath) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = "Unify consecutive calls to mutate().", type = "warning" ) }) } lintr/R/lint.R0000644000176200001440000005433014752731051012706 0ustar liggesusers#' Lint a file, directory, or package #' #' * `lint()` lints a single file. #' * `lint_dir()` lints all files in a directory. #' * `lint_package()` lints all likely locations for R files in a package, i.e. #' `R/`, `tests/`, `inst/`, `vignettes/`, `data-raw/`, `demo/`, and `exec/`. #' #' Read `vignette("lintr")` to learn how to configure which linters are run #' by default. #' Note that if files contain unparseable encoding problems, only the encoding problem will be linted to avoid #' unintelligible error messages from other linters. #' #' @param filename Either the filename for a file to lint, or a character string of inline R code for linting. #' The latter (inline data) applies whenever `filename` has a newline character (\\n). #' @param linters A named list of linter functions to apply. See [linters] for a full list of default and available #' linters. #' @param ... Provide additional arguments to be passed to: #' - [exclude()] (in case of `lint()`; e.g. `lints` or `exclusions`) #' - [lint()] (in case of `lint_dir()` and `lint_package()`; e.g. `linters` or `cache`) #' @param cache When logical, toggle caching of lint results. If passed a character string, store the cache in this #' directory. #' @param parse_settings Logical, default `TRUE`. Whether to try and parse the [settings][read_settings]. Otherwise, #' the [default_settings()] are used. #' @param text Optional argument for supplying a string or lines directly, e.g. if the file is already in memory or #' linting is being done ad hoc. #' #' @return An object of class `c("lints", "list")`, each element of which is a `"list"` object. #' #' @examples #' # linting inline-code #' lint("a = 123\n") #' lint(text = "a = 123") #' #' # linting a file #' f <- tempfile() #' writeLines("a=1", f) #' lint(f) #' unlink(f) #' #' @export lint <- function(filename, linters = NULL, ..., cache = FALSE, parse_settings = TRUE, text = NULL) { # TODO(#2502): Remove this workaround. dot_names <- if (getRversion() %in% c("4.1.1", "4.1.2")) names(list(...)) else ...names() check_dots(dot_names, c("exclude", "parse_exclusions")) needs_tempfile <- missing(filename) || re_matches(filename, rex(newline)) inline_data <- !is.null(text) || needs_tempfile lines <- get_lines(filename, text) if (needs_tempfile) { filename <- tempfile() con <- file(filename, open = "w", encoding = settings$encoding) on.exit(unlink(filename), add = TRUE) writeLines(text = lines, con = con, sep = "\n") close(con) } filename <- normalize_path(filename, mustWork = !inline_data) # to ensure a unique file in cache source_expressions <- get_source_expressions(filename, lines) if (isTRUE(parse_settings)) { read_settings(filename) on.exit(reset_settings(), add = TRUE) } linters <- define_linters(linters) linters <- Map(validate_linter_object, linters, names(linters)) cache_path <- define_cache_path(cache) lint_cache <- load_cache(filename, cache_path) lint_obj <- define_cache_key(filename, inline_data, lines) lints <- retrieve_file(lint_cache, lint_obj, linters) if (!is.null(lints)) { return(exclude(lints, lines = lines, linter_names = names(linters), ...)) } file_linter_names <- names(linters)[vapply(linters, is_linter_level, logical(1L), "file")] expression_linter_names <- names(linters)[vapply(linters, is_linter_level, logical(1L), "expression")] lints <- list() if (!is_tainted(source_expressions$lines)) { for (expr in source_expressions$expressions) { if (is_lint_level(expr, "expression")) { necessary_linters <- expression_linter_names } else { necessary_linters <- file_linter_names } for (linter in necessary_linters) { # use withCallingHandlers for friendlier failures on unexpected linter errors lints[[length(lints) + 1L]] <- withCallingHandlers( get_lints(expr, linter, linters[[linter]], lint_cache, source_expressions$lines), error = function(cond) { cli_abort( "Linter {.fn linter} failed in {.file {filename}}:", parent = cond ) } ) } } } lints <- maybe_append_error_lint(lints, source_expressions$error, lint_cache, filename) lints <- reorder_lints(flatten_lints(lints)) class(lints) <- c("lints", "list") cache_file(lint_cache, filename, linters, lints) save_cache(lint_cache, filename, cache_path) res <- exclude(lints, lines = lines, linter_names = names(linters), ...) # simplify filename if inline zap_temp_filename(res, needs_tempfile) } #' @param path For the base directory of the project (for `lint_dir()`) or #' package (for `lint_package()`). #' @param relative_path if `TRUE`, file paths are printed using their path relative to the base directory. #' If `FALSE`, use the full absolute path. #' @param exclusions exclusions for [exclude()], relative to the package path. #' @param pattern pattern for files, by default it will take files with any of the extensions #' .R, .Rmd, .qmd, .Rnw, .Rhtml, .Rrst, .Rtex, .Rtxt allowing for lowercase r (.r, ...). #' @param show_progress Logical controlling whether to show linting progress with a simple text #' progress bar _via_ [utils::txtProgressBar()]. The default behavior is to show progress in #' [interactive()] sessions not running a testthat suite. #' #' @examples #' if (FALSE) { #' lint_dir() #' #' lint_dir( #' linters = list(semicolon_linter()), #' exclusions = list( #' "inst/doc/creating_linters.R" = 1, #' "inst/example/bad.R", #' "renv" #' ) #' ) #' } #' @export #' @rdname lint lint_dir <- function(path = ".", ..., relative_path = TRUE, exclusions = list("renv", "packrat"), # TODO(r-lib/rex#85): Re-write in case-sensitive rex() pattern = "(?i)[.](r|rmd|qmd|rnw|rhtml|rrst|rtex|rtxt)$", parse_settings = TRUE, show_progress = NULL) { # TODO(#2502): Remove this workaround. dot_names <- if (getRversion() %in% c("4.1.1", "4.1.2")) names(list(...)) else ...names() check_dots(dot_names, c("lint", "exclude", "parse_exclusions")) if (isTRUE(parse_settings)) { read_settings(path) on.exit(reset_settings(), add = TRUE) exclusions <- c(exclusions, settings$exclusions) } if (is.null(show_progress)) show_progress <- interactive() && !identical(Sys.getenv("TESTTHAT"), "true") exclusions <- normalize_exclusions( exclusions, root = path, pattern = pattern ) # normalize_path ensures names(exclusions) and files have the same names for the same files. # It also ensures all paths have forward slash # Otherwise on windows, files might incorrectly not be excluded in to_exclude files <- normalize_path(dir( path, pattern = pattern, recursive = TRUE, full.names = TRUE )) # Remove fully ignored files to avoid reading & parsing files <- drop_excluded(files, exclusions) if (length(files) == 0L) { lints <- list() class(lints) <- "lints" return(lints) } if (isTRUE(show_progress)) { lints <- lapply( # NB: This cli API is experimental (https://github.com/r-lib/cli/issues/709) cli::cli_progress_along(files, name = "Running linters"), function(idx) { lint(files[idx], ..., parse_settings = FALSE, exclusions = exclusions) } ) } else { lints <- lapply( files, function(file) { # nolint: unnecessary_lambda_linter. lint(file, ..., parse_settings = FALSE, exclusions = exclusions) } ) } lints <- flatten_lints(lints) lints <- reorder_lints(lints) if (relative_path) { path <- normalize_path(path, mustWork = FALSE) lints[] <- lapply( lints, function(x) { x$filename <- re_substitutes(x$filename, rex(path, one_of("/", "\\")), "") x } ) attr(lints, "path") <- path } class(lints) <- "lints" lints } drop_excluded <- function(files, exclusions) { to_exclude <- vapply( files, function(file) file %in% names(exclusions) && is_excluded_file(exclusions[[file]]), logical(1L) ) files[!to_exclude] } #' @examples #' if (FALSE) { #' lint_package() #' #' lint_package( #' linters = linters_with_defaults(semicolon_linter = semicolon_linter()), #' exclusions = list("inst/doc/creating_linters.R" = 1, "inst/example/bad.R") #' ) #' } #' @export #' @rdname lint lint_package <- function(path = ".", ..., relative_path = TRUE, exclusions = list("R/RcppExports.R"), parse_settings = TRUE, show_progress = NULL) { if (length(path) > 1L) { cli_abort(c( x = "Only linting one package at a time is supported.", i = "Instead, {.val {length(path)}} package paths were provided." )) } pkg_path <- find_package(path) if (is.null(pkg_path)) { cli_warn(c( i = "Didn't find any R package searching upwards from {.file {normalize_path(path)}}" )) return(NULL) } if (parse_settings) { read_settings(pkg_path) on.exit(reset_settings(), add = TRUE) } exclusions <- normalize_exclusions( c(exclusions, settings$exclusions), root = pkg_path ) r_directories <- file.path(pkg_path, c("R", "tests", "inst", "vignettes", "data-raw", "demo", "exec")) lints <- lint_dir(r_directories, relative_path = FALSE, exclusions = exclusions, parse_settings = FALSE, show_progress = show_progress, ... ) if (isTRUE(relative_path)) { path <- normalize_path(pkg_path, mustWork = FALSE) lints[] <- lapply( lints, function(x) { x$filename <- re_substitutes(x$filename, rex(path, one_of("/", "\\")), "") x } ) attr(lints, "path") <- path } lints } #' Run a linter on a source expression, optionally using a cache #' #' @param expr A source expression. #' @param linter Name of the linter. #' @param linter_fun Closure of the linter. #' @param lint_cache Cache environment, or `NULL` if caching is disabled. #' #' @return A list of lints generated by the linter on `expr`. #' #' @noRd get_lints <- function(expr, linter, linter_fun, lint_cache, lines) { expr_lints <- NULL if (has_lint(lint_cache, expr, linter)) { # retrieve_lint() might return NULL if missing line number is encountered. # It could be caused by nolint comments. expr_lints <- retrieve_lint(lint_cache, expr, linter, lines) } if (is.null(expr_lints)) { expr_lints <- flatten_lints(linter_fun(expr)) for (i in seq_along(expr_lints)) { expr_lints[[i]]$linter <- linter } cache_lint(lint_cache, expr, linter, expr_lints) } expr_lints } define_linters <- function(linters = NULL) { if (is.null(linters)) { linters <- settings$linters names(linters) <- auto_names(linters) } else if (is_linter(linters)) { linters <- list(linters) names(linters) <- attr(linters[[1L]], "name", exact = TRUE) } else if (is.list(linters)) { names(linters) <- auto_names(linters) } else { name <- deparse(substitute(linters)) linters <- list(linters) names(linters) <- name } linters } validate_linter_object <- function(linter, name) { if (is_linter(linter)) { return(linter) } if (!is.function(linter)) { cli_abort(c( i = "Expected {.fn {name}} to be a function of class {.cls linter}.", x = "Instead, it is {.obj_type_friendly {linter}}." )) } if (is_linter_factory(linter)) { what <- "Passing linters as variables" alternative <- "a call to the linters (see ?linters)" } else { what <- "The use of linters of class 'function'" alternative <- "linters classed as 'linter' (see ?Linter)" } lintr_deprecated( what = what, alternative = alternative, version = "3.0.0", type = "", signal = "stop" ) } is_linter_factory <- function(fun) { # A linter factory is a function whose last call is to Linter() bdexpr <- body(fun) # covr internally transforms each call into if (TRUE) { covr::count(...); call } while (is.call(bdexpr) && (bdexpr[[1L]] == "{" || (bdexpr[[1L]] == "if" && bdexpr[[2L]] == "TRUE"))) { bdexpr <- bdexpr[[length(bdexpr)]] } is.call(bdexpr) && identical(bdexpr[[1L]], as.name("Linter")) } reorder_lints <- function(lints) { files <- vapply(lints, `[[`, character(1L), "filename") lines <- vapply(lints, `[[`, integer(1L), "line_number") columns <- vapply(lints, `[[`, integer(1L), "column_number") lints[order( files, lines, columns )] } #' Create a `lint` object #' @param filename path to the source file that was linted. #' @param line_number line number where the lint occurred. #' @param column_number column number where the lint occurred. #' @param type type of lint. #' @param message message used to describe the lint error #' @param line code source where the lint occurred #' @param ranges a list of ranges on the line that should be emphasized. #' @param linter deprecated. No longer used. #' @return an object of class `c("lint", "list")`. #' @name lint-s3 #' @export Lint <- function(filename, line_number = 1L, column_number = 1L, # nolint: object_name. type = c("style", "warning", "error"), message = "", line = "", ranges = NULL, linter = "") { if (!missing(linter)) { lintr_deprecated( what = "Using the `linter` argument of `Lint()`", version = "3.0.0", type = "", signal = "stop" ) } if (length(line) != 1L || !is.character(line)) { cli_abort("{.arg line} must be a string.", call. = FALSE) } max_col <- max(nchar(line) + 1L, 1L, na.rm = TRUE) if (!is_number(column_number) || column_number < 0L || column_number > max_col) { cli_abort(" {.arg column_number} must be an integer between {.val {0}} and {.val {max_col}} ({.code nchar(line) + 1}), not {.obj_type_friendly {column_number}}. ") } if (!is_number(line_number) || line_number < 1L) { cli_abort("{.arg line_number} must be a positive integer, not {.obj_type_friendly {line_number}}.") } check_ranges(ranges, max_col) type <- match.arg(type) obj <- list( filename = filename, line_number = as.integer(line_number), column_number = as.integer(column_number), type = type, message = message, # nolint: undesirable_function_linter line = line, ranges = ranges, linter = NA_character_ ) class(obj) <- c("lint", "list") obj } is_number <- function(number, n = 1L) { length(number) == n && is.numeric(number) && !anyNA(number) } is_valid_range <- function(range, max_col) { 0L <= range[[1L]] && range[[1L]] <= range[[2L]] && range[[2L]] <= max_col } check_ranges <- function(ranges, max_col, call = parent.frame()) { if (is.null(ranges)) { return() } if (!is.list(ranges)) { cli_abort( "{.arg ranges} must be {.code NULL} or a list, not {.obj_type_friendly {ranges}}.", call = call ) } for (range in ranges) { if (!is_number(range, 2L)) { cli_abort( "{.arg ranges} must only contain integer vectors of length 2 without {.code NA}s.", call = call ) } else if (!is_valid_range(range, max_col)) { cli_abort( "{.arg ranges} must satisfy {.val {0}} <= range[1L] <= range[2L] <= {.val {max_col}} (nchar(line) + 1).", call = call ) } } } rstudio_source_markers <- function(lints) { if (!requireNamespace("rstudioapi", quietly = TRUE)) { cli_abort("{.pkg rstudioapi} is required for {.fn rstudio_source_markers}.") # nocov } # package path will be NULL unless it is a relative path package_path <- attr(lints, "path") # generate the markers markers <- lapply(lints, function(x) { filename <- if (!is.null(package_path)) { file.path(package_path, x$filename) } else { x$filename } marker <- list() marker$type <- x$type marker$file <- filename marker$line <- x$line_number marker$column <- x$column_number marker$message <- paste0("[", x$linter, "] ", x$message) marker }) # request source markers out <- rstudioapi::callFun( "sourceMarkers", name = "lintr", markers = markers, basePath = package_path, autoSelect = "first" ) # workaround to avoid focusing an empty Markers pane # when possible, better solution is to delete the "lintr" source marker list # https://github.com/rstudio/rstudioapi/issues/209 if (length(lints) == 0L) { Sys.sleep(0.1) rstudioapi::executeCommand("activateConsole") } out } #' Checkstyle Report for lint results #' #' Generate a report of the linting results using the [Checkstyle](https://checkstyle.sourceforge.io) XML format. #' #' @param lints the linting results. #' @param filename the name of the output report #' @export checkstyle_output <- function(lints, filename = "lintr_results.xml") { # package path will be NULL unless it is a relative path package_path <- attr(lints, "path") # setup file d <- xml2::xml_new_document() n <- xml2::xml_add_child(d, "checkstyle", version = paste0("lintr-", utils::packageVersion("lintr"))) # output the style markers to the file lapply(split(lints, names(lints)), function(lints_per_file) { filename <- if (!is.null(package_path)) { file.path(package_path, lints_per_file[[1L]]$filename) } else { lints_per_file[[1L]]$filename } f <- xml2::xml_add_child(n, "file", name = filename) lapply(lints_per_file, function(x) { xml2::xml_add_child( f, "error", line = as.character(x$line_number), column = as.character(x$column_number), severity = switch(x$type, style = "info", x$type ), message = x$message ) }) }) xml2::write_xml(d, filename) } #' SARIF Report for lint results #' #' Generate a report of the linting results using the [SARIF](https://sarifweb.azurewebsites.net/) format. #' #' @param lints the linting results. #' @param filename the name of the output report #' @export sarif_output <- function(lints, filename = "lintr_results.sarif") { if (!requireNamespace("jsonlite", quietly = TRUE)) { cli_abort("{.pkg jsonlite} is required to produce SARIF reports. Please install to continue.") # nocov } # package path will be `NULL` unless it is a relative path package_path <- attr(lints, "path") if (is.null(package_path)) { cli_abort("Package path needs to be a relative path.") } # setup template sarif <- jsonlite::fromJSON( system.file("extdata", "sarif-template.json", package = "lintr"), simplifyVector = TRUE, simplifyDataFrame = FALSE, simplifyMatrix = FALSE ) # assign values sarif$runs[[1L]]$results <- NULL sarif$runs[[1L]]$tool$driver$rules <- NULL sarif$runs[[1L]]$tool$driver$version <- as.character(utils::packageVersion("lintr")) sarif$runs[[1L]]$originalUriBaseIds$ROOTPATH$uri <- "" rule_index_exists <- FALSE root_path_uri <- gsub("\\", "/", package_path, fixed = TRUE) if (startsWith(root_path_uri, "/")) { root_path_uri <- paste0("file://", root_path_uri) } else { root_path_uri <- paste0("file:///", root_path_uri) # nocov } if (!endsWith(root_path_uri, "/")) { root_path_uri <- paste0(root_path_uri, "/") } sarif$runs[[1L]]$originalUriBaseIds$ROOTPATH$uri <- root_path_uri # loop and assign result values for (lint in lints) { one_result <- list() if (is.null(sarif$runs[[1L]]$tool$driver$rules)) { rule_index_exists <- 0L } else { rule_index_exists <- which(vapply( sarif$runs[[1L]]$tool$driver$rules, function(x) x$id == lint$linter, logical(1L) )) if (length(rule_index_exists) == 0L || is.na(rule_index_exists[1L])) { rule_index_exists <- 0L } } if (rule_index_exists == 0L) { new_rule <- list( id = lint$linter, fullDescription = list(text = lint$message), defaultConfiguration = list( level = switch(lint$type, style = "note", lint$type) ) ) sarif$runs[[1L]]$tool$driver$rules <- append(sarif$runs[[1L]]$tool$driver$rules, list(new_rule)) rule_index <- length(sarif$runs[[1L]]$tool$driver$rules) - 1L } else { rule_index <- rule_index_exists - 1L } one_result <- append(one_result, c(ruleId = lint$linter)) one_result <- append(one_result, c(ruleIndex = rule_index)) one_result <- append(one_result, list(message = list(text = lint$message))) one_location <- list(physicalLocation = list( artifactLocation = list( uri = gsub("\\", "/", lint$filename, fixed = TRUE), uriBaseId = "ROOTPATH" ), region = list( startLine = lint$line_number, startColumn = lint$column_number, snippet = list(text = lint$line) ) )) one_result <- append(one_result, c(locations = list(list(one_location)))) sarif$runs[[1L]]$results <- append(sarif$runs[[1L]]$results, list(one_result)) } # if lints is empty, add empty results list if (length(lints) == 0L) { sarif$runs[[1L]]$results <- list() } write(jsonlite::toJSON(sarif, pretty = TRUE, auto_unbox = TRUE), filename) } highlight_string <- function(message, column_number = NULL, ranges = NULL) { maximum <- max(column_number, unlist(ranges)) line <- fill_with(" ", maximum) for (range in ranges) { substr(line, range[1L], range[2L]) <- fill_with("~", range[2L] - range[1L] + 1L) } substr(line, column_number, column_number + 1L) <- "^" line } fill_with <- function(character = " ", length = 1L) { paste(collapse = "", rep.int(character, length)) } has_positional_logical <- function(dots) { length(dots) > 0L && is.logical(dots[[1L]]) && !nzchar(names2(dots)[1L]) } maybe_append_error_lint <- function(lints, error, lint_cache, filename) { if (is_lint(error)) { error$linter <- "error" lints[[length(lints) + 1L]] <- error if (!is.null(lint_cache)) { cache_lint(lint_cache, list(filename = filename, content = ""), "error", error) } } lints } get_lines <- function(filename, text) { if (!is.null(text)) { strsplit(paste(text, collapse = "\n"), "\n", fixed = TRUE)[[1L]] } else if (re_matches(filename, rex(newline))) { strsplit(gsub("\n$", "", filename), "\n", fixed = TRUE)[[1L]] } else { read_lines(filename) } } zap_temp_filename <- function(res, needs_tempfile) { if (needs_tempfile) { for (i in seq_along(res)) { res[[i]][["filename"]] <- "" } } res } lintr/R/package_hooks_linter.R0000644000176200001440000001732614752731051016117 0ustar liggesusers#' Package hooks linter #' #' Check various common "gotchas" in [.onLoad()], [.onAttach()], [.Last.lib()], and [.onDetach()] #' namespace hooks that will cause `R CMD check` issues. See Writing R Extensions for details. #' #' 1. `.onLoad()` shouldn't call [cat()], [message()], [print()], [writeLines()], [packageStartupMessage()], #' [require()], [library()], or [installed.packages()]. #' 2. `.onAttach()` shouldn't call `cat()`, `message()`, `print()`, `writeLines()`, [library.dynam()], #' `require()`, `library()`, or `installed.packages()`. #' 3. `.Last.lib()` and `.onDetach()` shouldn't call [library.dynam.unload()]. #' 4. `.onLoad()` and `.onAttach()` should take two arguments, with names matching `^lib` and `^pkg`; #' `.Last.lib()` and `.onDetach()` should take one argument with name matching `^lib`. #' #' @examples #' # will produce lints #' lint( #' text = ".onLoad <- function(lib, ...) { }", #' linters = package_hooks_linter() #' ) #' #' lint( #' text = ".onAttach <- function(lib, pkg) { require(foo) }", #' linters = package_hooks_linter() #' ) #' #' lint( #' text = ".onDetach <- function(pkg) { }", #' linters = package_hooks_linter() #' ) #' #' # okay #' lint( #' text = ".onLoad <- function(lib, pkg) { }", #' linters = package_hooks_linter() #' ) #' #' lint( #' text = '.onAttach <- function(lib, pkg) { loadNamespace("foo") }', #' linters = package_hooks_linter() #' ) #' #' lint( #' text = ".onDetach <- function(lib) { }", #' linters = package_hooks_linter() #' ) #' #' @evalRd rd_tags("package_hooks_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export package_hooks_linter <- function() { bad_msg_calls <- c("cat", "message", "print", "writeLines") bad_calls <- list( .onLoad = c(bad_msg_calls, "packageStartupMessage"), .onAttach = c(bad_msg_calls, "library.dynam") ) bad_msg_call_xpath_fmt <- " (//FUNCTION | //OP-LAMBDA) /parent::expr[preceding-sibling::expr/SYMBOL[text() = '%s']] //SYMBOL_FUNCTION_CALL[%s] " bad_call_xpaths <- vapply( seq_along(bad_calls), function(ii) sprintf(bad_msg_call_xpath_fmt, names(bad_calls)[ii], xp_text_in_table(bad_calls[[ii]])), character(1L) ) names(bad_call_xpaths) <- names(bad_calls) make_bad_call_lint_message <- function(expr, hook) { call_name <- xml_text(expr) lint_message <- sprintf("Don't use %s() in %s().", call_name, hook) lint_message[call_name == "packageStartupMessage"] <- "Put packageStartupMessage() calls in .onAttach(), not .onLoad()." lint_message[call_name == "library.dynam"] <- "Put library.dynam() calls in .onLoad, not .onAttach()." lint_message } # lints here will hit the function , # this path returns to the corresponding namespace hook's name ns_calls <- xp_text_in_table(c(".onLoad", ".onAttach", ".onDetach", ".Last.lib")) # usually any given package will have one or maybe two files defining namespace hooks. # given the number of checks, then, it's prudent to check first if any such hook is defined, # exiting early if not. any_hook_xpath <- glue("(//FUNCTION | //OP-LAMBDA)/parent::expr/preceding-sibling::expr/SYMBOL[{ns_calls}]") hook_xpath <- sprintf("string(./ancestor::expr/expr/SYMBOL[%s])", ns_calls) load_arg_name_xpath <- " (//FUNCTION | //OP-LAMBDA) /parent::expr[ preceding-sibling::expr/SYMBOL[text() = '.onAttach' or text() = '.onLoad'] and ( count(SYMBOL_FORMALS) != 2 or SYMBOL_FORMALS[ (position() = 1 and not(starts-with(text(), 'lib'))) or (position() = 2 and not(starts-with(text(), 'pkg'))) ] ) ] " library_require_xpath <- " (//FUNCTION | //OP-LAMBDA) /parent::expr[preceding-sibling::expr/SYMBOL[text() = '.onAttach' or text() = '.onLoad']] //*[1][ (self::SYMBOL or self::SYMBOL_FUNCTION_CALL) and (text() = 'require' or text() = 'library' or text() = 'installed.packages') ] " bad_unload_call_xpath <- " (//FUNCTION | //OP-LAMBDA) /parent::expr[preceding-sibling::expr/SYMBOL[text() = '.Last.lib' or text() = '.onDetach']] //SYMBOL_FUNCTION_CALL[text() = 'library.dynam.unload'] " unload_arg_name_xpath <- " (//FUNCTION | //OP-LAMBDA) /parent::expr[ preceding-sibling::expr/SYMBOL[text() = '.onDetach' or text() = '.Last.lib'] and ( count(SYMBOL_FORMALS) != 1 or SYMBOL_FORMALS[not(starts-with(text(), 'lib'))] ) ] " Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content any_hook <- xml_find_first(xml, any_hook_xpath) if (is.na(any_hook)) { return(list()) } # inherits: source_expression, bad_call_xpaths bad_msg_call_lints <- function(xml, hook) { bad_expr <- xml_find_all(xml, bad_call_xpaths[[hook]]) lint_message <- make_bad_call_lint_message(bad_expr, hook) xml_nodes_to_lints(bad_expr, source_expression, lint_message, type = "warning") } # (1) improper messaging calls shouldn't be used inside .onLoad()/.onAttach() onload_bad_msg_call_lints <- bad_msg_call_lints(xml, ".onLoad") onattach_bad_msg_call_lints <- bad_msg_call_lints(xml, ".onAttach") # (2) .onLoad() and .onAttach() should take two arguments, with names matching ^lib and ^pkg load_arg_name_expr <- xml_find_all(xml, load_arg_name_xpath) load_arg_name_message <- sprintf( "%s() should take two arguments, with the first starting with 'lib' and the second starting with 'pkg'.", xml_find_chr(load_arg_name_expr, hook_xpath) ) load_arg_name_lints <- xml_nodes_to_lints(load_arg_name_expr, source_expression, load_arg_name_message, type = "warning") # (3) .onLoad() and .onAttach() shouldn't call require(), library(), or installed.packages() # NB: base only checks the SYMBOL_FUNCTION_CALL version, not SYMBOL. library_require_expr <- xml_find_all(xml, library_require_xpath) library_require_bad_call <- xml_text(library_require_expr) library_require_hook <- xml_find_chr(library_require_expr, hook_xpath) library_require_message <- character(length(library_require_bad_call)) is_installed_packages <- library_require_bad_call == "installed.packages" library_require_message[is_installed_packages] <- sprintf("Don't slow down package load by running installed.packages() in %s().", library_require_hook) library_require_message[!is_installed_packages] <- sprintf("Don't alter the search() path in %s() by calling %s().", library_require_hook, library_require_bad_call) library_require_lints <- xml_nodes_to_lints(library_require_expr, source_expression, library_require_message, type = "warning") # (4) .Last.lib() and .onDetach() shouldn't call library.dynam.unload() bad_unload_call_expr <- xml_find_all(xml, bad_unload_call_xpath) bad_unload_call_message <- sprintf( "Use library.dynam.unload() calls in .onUnload(), not %s().", xml_find_chr(bad_unload_call_expr, hook_xpath) ) bad_unload_call_lints <- xml_nodes_to_lints(bad_unload_call_expr, source_expression, bad_unload_call_message, type = "warning") # (5) .Last.lib() and .onDetach() should take one arguments with name matching ^lib unload_arg_name_expr <- xml_find_all(xml, unload_arg_name_xpath) unload_arg_name_message <- sprintf( "%s() should take one argument starting with 'lib'.", xml_find_chr(unload_arg_name_expr, hook_xpath) ) unload_arg_name_lints <- xml_nodes_to_lints(unload_arg_name_expr, source_expression, unload_arg_name_message, type = "warning") c( onload_bad_msg_call_lints, onattach_bad_msg_call_lints, load_arg_name_lints, library_require_lints, bad_unload_call_lints, unload_arg_name_lints ) }) } lintr/R/lintr-deprecated.R0000644000176200001440000001215314752731051015163 0ustar liggesusers#' @name lintr-deprecated #' @title Deprecated functions in lintr #' #' @description #' #' These functions have been deprecated from lintr. #' #' - `open_curly_linter()` (use [brace_linter()]) #' - `closed_curly_linter()` (use `brace_linter()`) #' - `paren_brace_linter()` (use `brace_linter()`) #' - `semicolon_terminator_linter()` (use [semicolon_linter()]) #' #' @param allow_single_line,semicolon Irrelevant parameters to defunct linters. #' #' @seealso [linters] for a complete list of linters available in lintr. #' @evalRd rd_tags("single_quotes_linter") #' @keywords internal NULL #' Closed curly linter #' @rdname lintr-deprecated #' @export closed_curly_linter <- function(allow_single_line = FALSE) { lintr_deprecated( what = "closed_curly_linter", alternative = "brace_linter", version = "3.0.0", type = "Linter", signal = "stop" ) } #' Open curly linter #' @rdname lintr-deprecated #' @export open_curly_linter <- function(allow_single_line = FALSE) { lintr_deprecated( what = "open_curly_linter", alternative = "brace_linter", version = "3.0.0", type = "Linter", signal = "stop" ) } #' Parentheses before brace linter #' @rdname lintr-deprecated #' @export paren_brace_linter <- function() { lintr_deprecated( what = "paren_brace_linter", alternative = "brace_linter", version = "3.0.0", type = "Linter", signal = "stop" ) } #' Semicolon linter #' @rdname lintr-deprecated #' @export semicolon_terminator_linter <- function(semicolon = c("compound", "trailing")) { lintr_deprecated( what = "semicolon_terminator_linter", alternative = "semicolon_linter", version = "3.0.0", type = "Linter", signal = "stop" ) } #' Unnecessary concatenation linter #' @rdname lintr-deprecated #' @export unneeded_concatenation_linter <- function(allow_single_expression = TRUE) { lintr_deprecated( what = "unneeded_concatenation_linter", alternative = "unnecessary_concatenation_linter", version = "3.1.0", type = "Linter" ) stopifnot( is.logical(allow_single_expression), length(allow_single_expression) == 1L ) unnecessary_concatenation_linter(allow_single_expression = allow_single_expression) } #' Single quotes linter #' @rdname lintr-deprecated #' @export single_quotes_linter <- function() { lintr_deprecated( what = "single_quotes_linter", alternative = "quotes_linter", version = "3.1.0", type = "Linter" ) quotes_linter() } #' Consecutive stopifnot linter #' @rdname lintr-deprecated #' @export consecutive_stopifnot_linter <- function() { lintr_deprecated( what = "consecutive_stopifnot_linter", alternative = "consecutive_assertion_linter", version = "3.1.0", type = "Linter" ) consecutive_assertion_linter() } #' No tabs linter #' @rdname lintr-deprecated #' @export no_tab_linter <- function() { lintr_deprecated( what = "no_tab_linter", alternative = "whitespace_linter", version = "3.1.0", type = "Linter" ) whitespace_linter() } #' Extraction operator linter #' @rdname lintr-deprecated #' @export extraction_operator_linter <- function() { lintr_deprecated( what = "extraction_operator_linter", version = "3.2.0", type = "Linter", signal = "warning" ) constant_nodes_in_brackets <- paste0("self::", c("expr", "OP-PLUS", "NUM_CONST", "STR_CONST")) xpath <- glue(" //OP-DOLLAR[not(preceding-sibling::expr[1]/SYMBOL[text() = 'self' or text() = '.self'])] | //OP-LEFT-BRACKET[ not(following-sibling::expr[1]/descendant::*[not({xp_or(constant_nodes_in_brackets)})]) and not(following-sibling::OP-COMMA) ] ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_exprs <- xml_find_all(xml, xpath) msgs <- sprintf("Use `[[` instead of `%s` to extract an element.", xml_text(bad_exprs)) xml_nodes_to_lints( bad_exprs, source_expression = source_expression, lint_message = msgs, type = "warning" ) }) } #' Unnecessary nested if linter #' @rdname lintr-deprecated #' @export unnecessary_nested_if_linter <- function() { lintr_deprecated( what = "unnecessary_nested_if_linter", alternative = "unnecessary_nesting_linter", version = "3.2.0", type = "Linter", signal = "warning" ) xpath <- paste0( "//IF/parent::expr[not(ELSE)]/OP-RIGHT-PAREN/", c( "following-sibling::expr[IF and not(ELSE)]", # catch if (cond) if (other_cond) { ... } "following-sibling::expr[OP-LEFT-BRACE and count(expr) = 1] /expr[IF and not(ELSE)]" # catch if (cond) { if (other_cond) { ... } } ), collapse = " | " ) Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_exprs <- xml_find_all(xml, xpath) xml_nodes_to_lints( bad_exprs, source_expression = source_expression, lint_message = paste( "Don't use nested `if` statements,", "where a single `if` with the combined conditional expression will do.", "For example, instead of `if (x) { if (y) { ... }}`, use `if (x && y) { ... }`." ) ) }) } lintr/R/path_utils.R0000644000176200001440000001311414752731051014107 0ustar liggesuserscontrol_char_regex <- rex(one_of(intToUtf8(seq.int(0L, 31L), multiple = TRUE))) # control chars (non-printing) win32_bad_punct_regex <- rex(one_of( "*", "?", "\"", "<", ">", "|", ":", "/", "\\" )) win32_good_punct_regex <- rex(one_of( "!", "#", "$", "%", "&", "'", "(", ")", "+", ",", "-", ".", ";", "=", "@", "[", "]", "^", "_", "`", "{", "}", "~" )) # win32BadPunct + win32AllowedPunct = [:punct:] unsafe_char_regex <- rex(or(control_char_regex, win32_bad_punct_regex)) safe_char_regex <- rex(or(alnum, " ", win32_good_punct_regex)) # alphanumeric chars (including UTF-8), spaces, and win32-allowed punctuation portable_char_regex <- rex(character_class("A-Za-z0-9_\\-.")) # ASCII letters, digits, dot, hyphen and underscore protocol_regex <- rex(one_or_more(letter), "://") root_regex <- list( unix = rex(start, "/"), tilde = rex(start, "~", zero_or_more(portable_char_regex), zero_or_more("/")), win32 = rex(start, letter, ":", maybe(one_of("/", "\\"))), unc = rex(start, "\\\\", maybe(one_or_more(portable_char_regex), maybe("\\"))) ) root_path_regex <- rex(start, or(root_regex), end) # styler: off absolute_path_regex <- rex(or( root_regex[["unix"]] %if_next_isnt% one_of(space, "/"), root_regex[["tilde"]] %if_next_isnt% one_of(space, quote), root_regex[["win32"]] %if_next_isnt% one_of(space, "/", "\\"), root_regex[["unc"]] %if_next_isnt% one_of(space, "\\", quote) )) relative_path_regex <- rex( start %if_next_isnt% or(quote, absolute_path_regex, protocol_regex), or( # not an absolute path or protocol, and then group(one_or_more(safe_char_regex), or("/", "\\")), # (back)slash-separated paths group(dot, maybe(dot), end) # or single or double dot ) # (paths without slash or dots left out) %if_next_isnt% quote ) # styler: on path_regex <- rex(or(absolute_path_regex, relative_path_regex)) is_absolute_path <- function(path) { re_matches(path, absolute_path_regex) } is_root_path <- function(path) { re_matches(path, root_path_regex) } is_relative_path <- function(path) { re_matches(path, relative_path_regex) } is_path <- function(path) { re_matches(path, path_regex) } is_valid_path <- function(paths, lax = FALSE) { # Given a character vector of paths, return FALSE for directory or file having valid characters. # On Windows, invalid chars are all control chars and: * ? " < > | : # On Unix, all characters are valid, except when lax=TRUE (use same invalid chars as Windows). as.logical( Map( function(dirs, is_win32) { if (!is_win32 && !lax) { return(TRUE) } if (length(dirs) > 0L && is_root_path(dirs[[1L]])) { dirs <- tail(dirs, -1L) # remove root element ("/", "C:", or "\\") } !any(re_matches(dirs, unsafe_char_regex)) }, split_paths(paths), re_matches(paths, rex(or(list(root_regex[["win32"]], root_regex[["unc"]], "\\")))) ) ) } is_long_path <- function(path) { # Take a character vector of paths and determine if they are "long enough" # TRUE , e.g.: "./foo", "C:\\foo", "foo/bar" # FALSE, e.g.: "/", "\\", "n/a", "/foo", "foo/" re_matches( re_substitutes(path, ":", ""), rex(at_least(safe_char_regex, 1L), one_of("/", "\\"), at_least(safe_char_regex, 2L)) ) } is_valid_long_path <- function(path, lax = FALSE) { # Convenience function to avoid linting short paths and those unlikely to be valid paths ret <- is_valid_path(path, lax) if (lax) { ret <- ret & is_long_path(path) } ret } split_paths <- function(path, sep = "/|\\\\") { if (!is.character(path)) { cli_abort("Argument {.arg path} should be a {.cls character} vector.") } if (!is.character(sep) || length(sep) != 1L || !nzchar(sep)) { cli_abort("Argument {.arg sep} should be a non-empty regular expression character string.") } Map(split_path, strsplit(path, sep), substr(path, 1L, 1L)) } split_path <- function(dirs, prefix) { # add root dir if needed nonempty_dirs <- nzchar(dirs) i <- match(TRUE, nonempty_dirs, nomatch = length(dirs) + 1L) - 1L if (i > 0L) { dirs <- c(strrep(prefix, i), tail(dirs, -i)) } # add // to protocols (like http, smb, ...) if (length(dirs) > 0L && grepl("..:$", dirs[[1L]])) { dirs[[1L]] <- paste0(dirs[[1L]], "//") } # remove empty dirs dirs[nzchar(dirs)] } #' Simple wrapper around normalizePath to ensure forward slash on Windows #' https://github.com/r-lib/lintr/pull/2613 #' @noRd # nolint next: undesirable_function_linter, object_name_linter. normalize_path <- function(path, mustWork = NA) normalizePath(path = path, winslash = "/", mustWork = mustWork) #' @include utils.R path_linter_factory <- function(path_function, message, linter, name = linter_auto_name()) { force(name) Linter(name = name, linter_level = "expression", function(source_expression) { lapply( ids_with_token(source_expression, "STR_CONST"), function(id) { token <- with_id(source_expression, id) path <- get_r_string(token$text) if (path_function(path)) { path_start <- token[["col1"]] + 1L path_end <- token[["col2"]] - 1L Lint( filename = source_expression[["filename"]], line_number = token[["line1"]], column_number = path_start, type = "warning", message = message, # nolint: undesirable_function_linter line = source_expression[["lines"]][[as.character(token[["line1"]])]], ranges = list(c(path_start, path_end)) ) } } ) }) } lintr/R/keyword_quote_linter.R0000644000176200001440000001246214752731051016216 0ustar liggesusers#' Block unnecessary quoting in calls #' #' Any valid symbol can be used as a keyword argument to an R function call. #' Sometimes, it is necessary to quote (or backtick) an argument that is #' not an otherwise valid symbol (e.g. creating a vector whose names have #' spaces); besides this edge case, quoting should not be done. #' #' The most common source of violation for this is creating named vectors, #' lists, or data.frame-alikes, but it can be observed in other calls as well. #' #' Similar reasoning applies to extractions with `$` or `@`. #' #' @examples #' # will produce lints #' lint( #' text = 'data.frame("a" = 1)', #' linters = keyword_quote_linter() #' ) #' #' lint( #' text = "data.frame(`a` = 1)", #' linters = keyword_quote_linter() #' ) #' #' lint( #' text = 'my_list$"key"', #' linters = keyword_quote_linter() #' ) #' #' lint( #' text = 's4obj@"key"', #' linters = keyword_quote_linter() #' ) #' #' # okay #' lint( #' text = "data.frame(`a b` = 1)", #' linters = keyword_quote_linter() #' ) #' #' lint( #' text = "my_list$`a b`", #' linters = keyword_quote_linter() #' ) #' #' @evalRd rd_tags("keyword_quote_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export keyword_quote_linter <- function() { # Check if a string could be assigned as an R variable. # # See [make.names()] for the description of syntactically valid names in R. is_valid_r_name <- function(x) make.names(x) == x # NB: xml2 uses xpath 1.0 which doesn't support matches() for regex, so we # have to jump out of xpath to complete this lint. # It's also a bit tough to get the escaping through R and then xpath to # work as intended, hence the rather verbose declaration here. quote_cond <- xp_or( "starts-with(text(), '\"')", "starts-with(text(), '`')", 'starts-with(text(), "\'")' ) # SYMBOL_SUB for backticks, STR_CONST for quoted names call_arg_xpath <- glue(" parent::expr /*[(self::SYMBOL_SUB or self::STR_CONST) and {quote_cond}] ") # also exclude $ or @, which are handled below assignment_candidate_cond <- " not(OP-DOLLAR or OP-AT) and (STR_CONST or SYMBOL[starts-with(text(), '`')]) " assignment_xpath <- glue(" (//EQ_ASSIGN | //LEFT_ASSIGN[text() != ':=']) /preceding-sibling::expr[{ assignment_candidate_cond }] | //RIGHT_ASSIGN/following-sibling::expr[{ assignment_candidate_cond }] ") extraction_xpath <- " (//OP-DOLLAR | //OP-AT)/following-sibling::STR_CONST | //OP-DOLLAR/following-sibling::SYMBOL[starts-with(text(), '`')] | //OP-AT/following-sibling::SLOT[starts-with(text(), '`')] " no_quote_msg <- "Use backticks to create non-syntactic names, not quotes." clarification <- "i.e., if the name is not a valid R symbol (see ?make.names)." Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content xml_calls <- source_expression$xml_find_function_calls(NULL) call_arg_expr <- xml_find_all(xml_calls, call_arg_xpath) invalid_call_quoting <- is_valid_r_name(get_r_string(call_arg_expr)) call_arg_lints <- xml_nodes_to_lints( call_arg_expr[invalid_call_quoting], source_expression = source_expression, lint_message = paste("Only quote named arguments to functions if necessary,", clarification), type = "warning" ) assignment_expr <- xml_find_all(xml, assignment_xpath) invalid_assignment_quoting <- is_valid_r_name(get_r_string(assignment_expr)) # NB: XPath is such that there is exactly 1 node per match, making xml_children() ideal. # xml_child() gets it wrong for 0 (an error) and >1 match. assignment_to_string <- xml_name(xml_children(assignment_expr)) == "STR_CONST" string_assignment_lints <- xml_nodes_to_lints( assignment_expr[assignment_to_string & !invalid_assignment_quoting], source_expression = source_expression, lint_message = no_quote_msg, type = "warning" ) assignment_lints <- xml_nodes_to_lints( assignment_expr[invalid_assignment_quoting], source_expression = source_expression, lint_message = paste("Only quote targets of assignment if necessary,", clarification), type = "warning" ) extraction_expr <- xml_find_all(xml, extraction_xpath) invalid_extraction_quoting <- is_valid_r_name(get_r_string(extraction_expr)) extraction_of_string <- xml_name(extraction_expr) == "STR_CONST" string_extraction_lints <- xml_nodes_to_lints( extraction_expr[extraction_of_string & !invalid_extraction_quoting], source_expression = source_expression, lint_message = no_quote_msg, type = "warning" ) extraction_expr <- extraction_expr[invalid_extraction_quoting] extractor <- xml_find_chr(extraction_expr, "string(preceding-sibling::*[1])") gen_extractor <- ifelse(extractor == "$", "[[", "slot()") extraction_lints <- xml_nodes_to_lints( extraction_expr, source_expression = source_expression, lint_message = paste( "Only quote targets of extraction with", extractor, "if necessary,", clarification, "Use backticks to create non-syntactic names, or use", gen_extractor, "to extract by string." ), type = "warning" ) c(call_arg_lints, string_assignment_lints, assignment_lints, string_extraction_lints, extraction_lints) }) } lintr/R/expect_s4_class_linter.R0000644000176200001440000000330314752731051016372 0ustar liggesusers#' Require usage of `expect_s4_class(x, k)` over `expect_true(is(x, k))` #' #' [testthat::expect_s4_class()] exists specifically for testing the class #' of S4 objects. [testthat::expect_true()] can also be used for such tests, #' but it is better to use the tailored function instead. #' #' @examples #' # will produce lints #' lint( #' text = 'expect_true(is(x, "Matrix"))', #' linters = expect_s4_class_linter() #' ) #' #' # okay #' lint( #' text = 'expect_s4_class(x, "Matrix")', #' linters = expect_s4_class_linter() #' ) #' #' @evalRd rd_tags("expect_s4_class_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - [expect_s3_class_linter()] #' @export expect_s4_class_linter <- function() { # require 2 expressions because methods::is(x) alone is a valid call, even # though the character output wouldn't make any sense for expect_true(). xpath <- " following-sibling::expr[1][count(expr) = 3 and expr[1][SYMBOL_FUNCTION_CALL[text() = 'is']]] /parent::expr[not(SYMBOL_SUB[text() = 'info' or text() = 'label'])] " Linter(linter_level = "expression", function(source_expression) { # TODO(#2423): also catch expect_{equal,identical}(methods::is(x), k). # this seems empirically rare, but didn't check many S4-heavy packages. xml_calls <- source_expression$xml_find_function_calls("expect_true") bad_expr <- xml_find_all(xml_calls, xpath) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = paste( "expect_s4_class(x, k) is better than expect_true(is(x, k)).", "Note also expect_s3_class() available for testing S3 objects." ), type = "warning" ) }) } lintr/R/brace_linter.R0000644000176200001440000001530314752731051014366 0ustar liggesusers#' Brace linter #' #' Perform various style checks related to placement and spacing of curly braces: #' #' - Opening curly braces are never on their own line and are always followed by a newline. #' - Opening curly braces have a space before them. #' - Closing curly braces are on their own line unless they are followed by an `else`. #' - Closing curly braces in `if` conditions are on the same line as the corresponding `else`. #' - Either both or neither branch in `if`/`else` use curly braces, i.e., either both branches use `{...}` or neither #' does. #' - Functions spanning multiple lines use curly braces. #' #' @param allow_single_line if `TRUE`, allow an open and closed curly pair on the same line. #' #' @examples #' # will produce lints #' lint( #' text = "f <- function() { 1 }", #' linters = brace_linter() #' ) #' #' writeLines("if (TRUE) {\n return(1) }") #' lint( #' text = "if (TRUE) {\n return(1) }", #' linters = brace_linter() #' ) #' #' # okay #' writeLines("f <- function() {\n 1\n}") #' lint( #' text = "f <- function() {\n 1\n}", #' linters = brace_linter() #' ) #' #' writeLines("if (TRUE) { \n return(1) \n}") #' lint( #' text = "if (TRUE) { \n return(1) \n}", #' linters = brace_linter() #' ) #' #' # customizing using arguments #' writeLines("if (TRUE) { return(1) }") #' lint( #' text = "if (TRUE) { return(1) }", #' linters = brace_linter(allow_single_line = TRUE) #' ) #' @evalRd rd_tags("brace_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' - #' @export brace_linter <- function(allow_single_line = FALSE) { xp_cond_open <- xp_and(c( # matching } is on same line if (isTRUE(allow_single_line)) { "(@line1 != following-sibling::OP-LEFT-BRACE/@line1)" }, # double curly "not( (@line1 = parent::expr/preceding-sibling::OP-LEFT-BRACE/@line1) or (@line1 = following-sibling::expr/OP-LEFT-BRACE/@line1) )", # allow `(`, `,` and `%>%` on preceding line # # note that '{' is not supported in RHS call of base-R's native pipe (`|>`), # so no exception needs to be made for this operator glue("not( @line1 > parent::expr/preceding-sibling::*[not(self::COMMENT)][1][ self::OP-LEFT-PAREN or self::OP-COMMA or (self::SPECIAL and ({xp_text_in_table(magrittr_pipes)}) ) ]/@line2 )") )) # TODO(#1103): if c_style_braces is TRUE, invert the preceding-sibling condition xp_open_curly <- glue("//OP-LEFT-BRACE[ { xp_cond_open } and ( not(@line1 = parent::expr/preceding-sibling::*/@line2) or @line1 = following-sibling::*[1][not(self::COMMENT or self::OP-RIGHT-BRACE)]/@line1 ) ]") xp_open_preceding <- "parent::expr/preceding-sibling::*[1][self::OP-RIGHT-PAREN or self::ELSE or self::REPEAT]" xp_paren_brace <- glue("//OP-LEFT-BRACE[ @line1 = { xp_open_preceding }/@line1 and @col1 = { xp_open_preceding }/@col2 + 1 ]") xp_cond_closed <- xp_and(c( # matching { is on same line if (isTRUE(allow_single_line)) { "(@line1 != preceding-sibling::OP-LEFT-BRACE/@line1)" }, # immediately followed by ",", "]" or ")" "not( @line1 = ancestor::expr/following-sibling::*[1][ self::OP-COMMA or self::OP-RIGHT-BRACKET or self::OP-RIGHT-PAREN ] /@line1 )", # double curly "not( (@line1 = parent::expr/following-sibling::OP-RIGHT-BRACE/@line1) or (@line1 = preceding-sibling::expr/OP-RIGHT-BRACE/@line1) )" )) # TODO(#1103): if c_style_braces is TRUE, skip the not(ELSE) condition xp_closed_curly <- glue("//OP-RIGHT-BRACE[ { xp_cond_closed } and ( (@line1 = preceding-sibling::*[1][not(self::OP-LEFT-BRACE)]/@line2) or (@line1 = parent::expr/following-sibling::*[1][not(self::ELSE)]/@line1) ) ]") xp_else_closed_curly <- "preceding-sibling::IF/following-sibling::expr[2]/OP-RIGHT-BRACE" # need to (?) repeat previous_curly_path since != will return true if there is # no such node. ditto for approach with not(@line1 = ...). # TODO(#1103): if c_style_braces is TRUE, this needs to be @line2 + 1 xp_else_same_line <- glue("//ELSE[{xp_else_closed_curly} and @line1 != {xp_else_closed_curly}/@line2]") xp_function_brace <- "(//FUNCTION | //OP-LAMBDA)/parent::expr[@line1 != @line2 and not(expr[OP-LEFT-BRACE])]" # if (x) { ... } else if (y) { ... } else { ... } is OK; fully exact pairing # of if/else would require this to be # if (x) { ... } else { if (y) { ... } else { ... } } since there's no # elif operator/token in R, which is pretty unseemly xp_if_else_match_brace <- " //IF[ following-sibling::expr[2][OP-LEFT-BRACE] and following-sibling::ELSE /following-sibling::expr[1][not(OP-LEFT-BRACE or IF/following-sibling::expr[2][OP-LEFT-BRACE])] ] | //ELSE[ following-sibling::expr[1][OP-LEFT-BRACE] and preceding-sibling::IF/following-sibling::expr[2][not(OP-LEFT-BRACE)] ] " Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content lints <- list() lints <- c( lints, xml_nodes_to_lints( xml_find_all(xml, xp_open_curly), source_expression = source_expression, lint_message = "Opening curly braces should never go on their own line and should always be followed by a new line." ) ) lints <- c( lints, xml_nodes_to_lints( xml_find_all(xml, xp_paren_brace), source_expression = source_expression, lint_message = "There should be a space before an opening curly brace." ) ) lints <- c( lints, xml_nodes_to_lints( xml_find_all(xml, xp_closed_curly), source_expression = source_expression, lint_message = "Closing curly-braces should always be on their own line, unless they are followed by an else." ) ) lints <- c( lints, xml_nodes_to_lints( xml_find_all(xml, xp_else_same_line), source_expression = source_expression, lint_message = "`else` should come on the same line as the previous `}`." ) ) lints <- c( lints, xml_nodes_to_lints( xml_find_all(xml, xp_function_brace), source_expression = source_expression, lint_message = "Use curly braces for any function spanning multiple lines." ) ) lints <- c( lints, xml_nodes_to_lints( xml_find_all(xml, xp_if_else_match_brace), source_expression = source_expression, lint_message = "Either both or neither branch in `if`/`else` should use curly braces." ) ) lints }) } lintr/R/return_linter.R0000644000176200001440000002150514752731051014632 0ustar liggesusers#' Return linter #' #' This linter checks functions' [return()] expressions. #' #' @param return_style Character string naming the return style. `"implicit"`, #' the default, enforces the Tidyverse guide recommendation to leave terminal #' returns implicit. `"explicit"` style requires that `return()` always be #' explicitly supplied. #' @param allow_implicit_else Logical, default `TRUE`. If `FALSE`, functions with a terminal #' `if` clause must always have an `else` clause, making the `NULL` alternative explicit #' if necessary. Similarly, functions with terminal [switch()] statements must have an #' explicit default case. #' @param return_functions Character vector of functions that are accepted as terminal calls #' when `return_style = "explicit"`. These are in addition to exit functions #' from base that are always allowed: [stop()], [q()], [quit()], [invokeRestart()], #' `tryInvokeRestart()`, [UseMethod()], [NextMethod()], [standardGeneric()], #' [callNextMethod()], [.C()], [.Call()], [.External()], and [.Fortran()]. #' @param except,except_regex Character vector of functions that are not checked when #' `return_style = "explicit"`. These are in addition to namespace hook functions #' that are never checked: `.onLoad()`, `.onUnload()`, `.onAttach()`, `.onDetach()`, #' `.Last.lib()`, `.First()` and `.Last()`. `except` matches function names exactly, #' while `except_regex` does exclusion by pattern matching with [rex::re_matches()]. #' #' @examples #' # will produce lints #' code <- "function(x) {\n return(x + 1)\n}" #' writeLines(code) #' lint( #' text = code, #' linters = return_linter() #' ) #' #' code <- "function(x) {\n x + 1\n}" #' writeLines(code) #' lint( #' text = code, #' linters = return_linter(return_style = "explicit") #' ) #' #' code <- "function(x) {\n if (x > 0) 2\n}" #' writeLines(code) #' lint( #' text = code, #' linters = return_linter(allow_implicit_else = FALSE) #' ) #' #' # okay #' code <- "function(x) {\n x + 1\n}" #' writeLines(code) #' lint( #' text = code, #' linters = return_linter() #' ) #' #' code <- "function(x) {\n return(x + 1)\n}" #' writeLines(code) #' lint( #' text = code, #' linters = return_linter(return_style = "explicit") #' ) #' #' code <- "function(x) {\n if (x > 0) 2 else NULL\n}" #' writeLines(code) #' lint( #' text = code, #' linters = return_linter(allow_implicit_else = FALSE) #' ) #' #' @evalRd rd_tags("return_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export return_linter <- function( return_style = c("implicit", "explicit"), allow_implicit_else = TRUE, return_functions = NULL, except = NULL, except_regex = NULL ) { return_style <- match.arg(return_style) check_except <- !allow_implicit_else || return_style == "explicit" # We defer building the XPath strings in this case since we can't build the # pattern-based "except" logic directly into the XPath (because of v1.0) defer_except <- check_except && !is.null(except_regex) if (check_except) { except_xpath_fmt <- "parent::expr[not( preceding-sibling::expr/SYMBOL[{ xp_text_in_table(except) }] )]" except <- union(special_funs, except) if (!defer_except) except_xpath <- glue(except_xpath_fmt, except = except) } if (return_style == "implicit") { # nolint next: object_usage. False positive. body_xpath <- "(//FUNCTION | //OP-LAMBDA)/following-sibling::expr[1]" params <- list( implicit = TRUE, type = "style", lint_xpath = "SYMBOL_FUNCTION_CALL[text() = 'return']", lint_message = "Use implicit return behavior; explicit return() is not needed." ) } else { base_return_functions <- c( # Normal calls "return", "stop", "q", "quit", "invokeRestart", "tryInvokeRestart", # Functions related to S3 methods "UseMethod", "NextMethod", # Functions related to S4 methods "standardGeneric", "callNextMethod", # Functions related to C interfaces ".C", ".Call", ".External", ".Fortran" ) return_functions <- union(base_return_functions, return_functions) body_xpath_fmt <- " (//FUNCTION | //OP-LAMBDA)[{ except_xpath }] /following-sibling::expr[OP-LEFT-BRACE and expr[last()]/@line1 != @line1] /expr[last()] " if (defer_except) { function_name_xpath <- "(//FUNCTION | //OP-LAMBDA)/parent::expr/preceding-sibling::expr/SYMBOL" } else { body_xpath <- glue(body_xpath_fmt, except_xpath = except_xpath) } params <- list( implicit = FALSE, type = "warning", lint_xpath = glue("self::*[not( (self::expr | following-sibling::SPECIAL[text() = '%>%']/following-sibling::expr/expr[1]) /SYMBOL_FUNCTION_CALL[{ xp_text_in_table(return_functions) }] )]"), lint_message = "All functions must have an explicit return()." ) } params$allow_implicit_else <- allow_implicit_else Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content if (defer_except) { assigned_functions <- xml_text(xml_find_all(xml, function_name_xpath)) except <- union(except, assigned_functions[re_matches_logical(assigned_functions, except_regex)]) except_xpath <- glue(except_xpath_fmt, except = except) body_xpath <- glue(body_xpath_fmt, except_xpath = except_xpath) } body_expr <- xml_find_all(xml, body_xpath) params$source_expression <- source_expression if (params$implicit && !params$allow_implicit_else) { # can't incorporate this into the body_xpath for implicit return style, # since we still lint explicit returns for except= functions. allow_implicit_else <- is.na(xml_find_first(body_expr, except_xpath)) } else { allow_implicit_else <- rep(params$allow_implicit_else, length(body_expr)) } # nested_return_lints not "vectorized" due to xml_children() Map( function(expr, allow_implicit_else) { params$allow_implicit_else <- allow_implicit_else nested_return_lints(expr, params) }, body_expr, allow_implicit_else ) }) } nested_return_lints <- function(expr, params) { child_expr <- xml_children(expr) if (length(child_expr) == 0L) { return(list()) } names(child_expr) <- xml_name(child_expr) if (names(child_expr)[1L] == "OP-LEFT-BRACE") { brace_return_lints(child_expr, expr, params) } else if (names(child_expr)[1L] == "IF") { if_return_lints(child_expr, expr, params) } else if (!is.na(xml_find_first(expr, "expr/SYMBOL_FUNCTION_CALL[text() = 'switch']"))) { switch_return_lints(child_expr, expr, params) } else { xml_nodes_to_lints( xml_find_first(child_expr[[1L]], params$lint_xpath), source_expression = params$source_expression, lint_message = params$lint_message, type = params$type ) } } brace_return_lints <- function(child_expr, expr, params) { expr_idx <- which(names(child_expr) %in% c("expr", "equal_assign", "expr_or_assign_or_help")) if (length(expr_idx) == 0L) { # empty brace expression {} if (params$implicit) { return(list()) } else { return(list(xml_nodes_to_lints( expr, source_expression = params$source_expression, lint_message = params$lint_message, type = params$type ))) } } nested_return_lints(child_expr[[tail(expr_idx, 1L)]], params) } if_return_lints <- function(child_expr, expr, params) { expr_idx <- which(names(child_expr) %in% c("expr", "equal_assign", "expr_or_assign_or_help")) return_lints <- lapply(child_expr[expr_idx[-1L]], nested_return_lints, params) if (params$allow_implicit_else || length(expr_idx) == 3L) { return(return_lints) } implicit_else_lints <- list(xml_nodes_to_lints( expr, source_expression = params$source_expression, lint_message = "All functions with terminal if statements must have a corresponding terminal else clause.", type = "warning" )) c(return_lints, implicit_else_lints) } switch_return_lints <- function(child_expr, expr, params) { # equal_assign/expr_or_assign_or_help not possible here expr_idx <- which(names(child_expr) == "expr") # switch(x, ...) | expr[1]: switch; expr[2]: x. Drop the first two, check usage in ... return_lints <- lapply(child_expr[tail(expr_idx, -2L)], nested_return_lints, params) # in addition to the two dropped above, a third unmatched would be the default case. if (params$allow_implicit_else || length(expr_idx) - sum(names(child_expr) == "EQ_SUB") == 3L) { return(return_lints) } implicit_else_lints <- list(xml_nodes_to_lints( expr, source_expression = params$source_expression, lint_message = "All functions with terminal switch statements must have a terminal default clause.", type = "warning" )) c(return_lints, implicit_else_lints) } lintr/R/utils.R0000644000176200001440000002127514752731051013102 0ustar liggesusers`%||%` <- function(x, y) { if (is.null(x) || length(x) == 0L || (is.atomic(x[[1L]]) && is.na(x[[1L]]))) { y } else { x } } `%==%` <- function(x, y) { identical(x, y) } `%:::%` <- function(p, f) { get(f, envir = asNamespace(p)) } flatten_lints <- function(x) { x <- flatten_list(x, class = "lint") class(x) <- "lints" x } # any function using unlist or c was dropping the classnames, # so need to brute force copy the objects flatten_list <- function(x, class) { res <- list() itr <- 1L assign_item <- function(x) { if (inherits(x, class)) { res[[itr]] <<- x itr <<- itr + 1L } else if (is.list(x)) { lapply(x, assign_item) } } assign_item(x) res } fix_names <- function(x, default) { nms <- names(x) if (is.null(nms)) { nms <- default } else { nms[!nzchar(nms)] <- default } names(x) <- nms x } linter_auto_name <- function(which = -3L) { sys_call <- sys.call(which = which) nm <- paste(deparse(sys_call, 500L), collapse = " ") regex <- rex(start, one_or_more(alnum %or% "." %or% "_" %or% ":")) if (re_matches(nm, regex)) { match_data <- re_matches(nm, regex, locations = TRUE) nm <- substr(nm, start = 1L, stop = match_data[1L, "end"]) nm <- re_substitutes(nm, rex(start, alnums, "::"), "") } nm } auto_names <- function(x) { nms <- names2(x) empty <- !nzchar(nms, keepNA = TRUE) if (!any(empty)) { return(nms) } default_name <- function(x) { if (is_linter(x)) { attr(x, "name", exact = TRUE) } else { deparse1(x) } } defaults <- vapply(x[empty], default_name, character(1L), USE.NAMES = FALSE) nms[empty] <- defaults nms } # The following functions is from dplyr names2 <- function(x) { names(x) %||% rep("", length(x)) } get_content <- function(lines, info) { lines[is.na(lines)] <- "" if (!missing(info)) { if (is_node(info)) { info <- lapply(stats::setNames(nm = c("col1", "col2", "line1", "line2")), function(attr) { as.integer(xml_attr(info, attr)) }) } lines <- lines[seq(info$line1, info$line2)] lines[length(lines)] <- substr(lines[length(lines)], 1L, info$col2) lines[1L] <- substr(lines[1L], info$col1, nchar(lines[1L])) } paste(lines, collapse = "\n") } logical_env <- function(x) { res <- as.logical(Sys.getenv(x)) if (is.na(res)) { return(NULL) } res } # from ?chartr rot <- function(ch, k = 13L) { p0 <- function(...) paste(c(...), collapse = "") alphabet <- c(letters, LETTERS, " '") idx <- seq_len(k) chartr(p0(alphabet), p0(c(alphabet[-idx], alphabet[idx])), ch) } try_silently <- function(expr) { suppressWarnings( suppressMessages( try(expr, silent = TRUE) ) ) } # interface to work like options() or setwd() -- returns the old value for convenience set_lang <- function(new_lang) { old_lang <- Sys.getenv("LANGUAGE", unset = NA) Sys.setenv(LANGUAGE = new_lang) # nolint: undesirable_function. Avoiding {withr} dep in pkg. old_lang } # handle the logic of either unsetting if it was previously unset, or resetting reset_lang <- function(old_lang) { if (is.na(old_lang)) { Sys.unsetenv("LANGUAGE") } else { Sys.setenv(LANGUAGE = old_lang) # nolint: undesirable_function. Avoiding {withr} dep in pkg. } } #' Create a `linter` closure #' #' @param fun A function that takes a source file and returns `lint` objects. #' @param name Default name of the Linter. #' Lints produced by the linter will be labelled with `name` by default. #' @param linter_level Which level of expression is the linter working with? #' `"expression"` means an individual expression in `xml_parsed_content`, while `"file"` means all expressions #' in the current file are available in `full_xml_parsed_content`. #' `NA` means the linter will be run with both, expression-level and file-level source expressions. #' #' @return The same function with its class set to 'linter'. #' @export Linter <- function(fun, name = linter_auto_name(), linter_level = c(NA_character_, "file", "expression")) { # nolint: object_name, line_length. if (!is.function(fun) || length(formals(args(fun))) != 1L) { cli_abort("{.arg fun} must be a function taking exactly one argument.") } linter_level <- match.arg(linter_level) force(name) class(fun) <- c("linter", "function") attr(fun, "name") <- name attr(fun, "linter_level") <- linter_level fun } read_lines <- function(file, encoding = settings$encoding, ...) { terminal_newline <- TRUE lines <- withCallingHandlers( readLines(file, warn = TRUE, ...), warning = function(w) { if (grepl("incomplete final line found on", w$message, fixed = TRUE)) { terminal_newline <<- FALSE invokeRestart("muffleWarning") } } ) lines_conv <- iconv(lines, from = encoding, to = "UTF-8") lines[!is.na(lines_conv)] <- lines_conv[!is.na(lines_conv)] Encoding(lines) <- "UTF-8" attr(lines, "terminal_newline") <- terminal_newline lines } # nocov start # support for usethis::use_release_issue(). Make sure to use devtools::load_all() beforehand! release_bullets <- function() {} # nocov end # see issue #923, PR #2455 -- some locales ignore _ when running sort(), others don't. # We want to consistently treat "_" < "n" = "N"; C locale does this, which 'radix' uses. platform_independent_order <- function(x) order(tolower(x), method = "radix") platform_independent_sort <- function(x) x[platform_independent_order(x)] #' re_matches with type-stable logical output #' TODO(r-lib/rex#94): Use re_matches() option directly & deprecate this. #' @noRd re_matches_logical <- function(x, regex, ...) { res <- re_matches(x, regex, ...) if (is.data.frame(res)) { res <- complete.cases(res) } res } #' Extract text from `STR_CONST` nodes #' #' Convert `STR_CONST` `text()` values into R strings. This is useful to account for arbitrary #' character literals, e.g. `R"------[hello]------"`, which is parsed in R as `"hello"`. #' It is quite cumbersome to write XPaths allowing for strings like this, so whenever your #' linter logic requires testing a `STR_CONST` node's value, use this function. #' NB: this is also properly vectorized on `s`, and accepts a variety of inputs. Empty inputs #' will become `NA` outputs, which helps ensure that `length(get_r_string(s)) == length(s)`. #' #' @param s An input string or strings. If `s` is an `xml_node` or `xml_nodeset` and `xpath` is `NULL`, #' extract its string value with [xml2::xml_text()]. If `s` is an `xml_node` or `xml_nodeset` #' and `xpath` is specified, it is extracted with [xml2::xml_find_chr()]. #' @param xpath An XPath, passed on to [xml2::xml_find_chr()] after wrapping with `string()`. #' #' @examples #' tmp <- tempfile() #' writeLines("c('a', 'b')", tmp) #' expr_as_xml <- get_source_expressions(tmp)$expressions[[1L]]$xml_parsed_content #' writeLines(as.character(expr_as_xml)) #' get_r_string(expr_as_xml, "expr[2]") #' get_r_string(expr_as_xml, "expr[3]") #' unlink(tmp) #' #' # more importantly, extract raw strings correctly #' tmp_raw <- tempfile() #' writeLines("c(R'(a\\b)', R'--[a\\\"\'\"\\b]--')", tmp_raw) #' expr_as_xml_raw <- get_source_expressions(tmp_raw)$expressions[[1L]]$xml_parsed_content #' writeLines(as.character(expr_as_xml_raw)) #' get_r_string(expr_as_xml_raw, "expr[2]") #' get_r_string(expr_as_xml_raw, "expr[3]") #' unlink(tmp_raw) #' #' @export get_r_string <- function(s, xpath = NULL) { if (is_node(s) || is_nodeset(s)) { if (is.null(xpath)) { s <- xml_text(s) } else { s <- xml_find_chr(s, sprintf("string(%s)", xpath)) } } # parse() skips "" elements --> offsets the length of the output, # but NA in --> NA out is.na(s) <- !nzchar(s) out <- as.character(parse(text = s, keep.source = FALSE)) is.na(out) <- is.na(s) out } is_linter <- function(x) inherits(x, "linter") is_lint <- function(x) inherits(x, "lint") is_error <- function(x) inherits(x, "error") is_tainted <- function(lines) { is_error(tryCatch(nchar(lines), error = identity)) } #' Check that the entries in ... are valid #' #' @param dot_names Supplied names, from [...names()]. #' @param ref_calls Functions consuming these `...` (character). #' @param ref_help Help page to refer users hitting an error to. #' @noRd check_dots <- function(dot_names, ref_calls, ref_help = as.character(sys.call(-1L)[[1L]])) { valid_args <- unlist(lapply(ref_calls, function(f) names(formals(f)))) is_valid <- dot_names %in% valid_args if (all(is_valid)) { return(invisible()) } invalid_args <- dot_names[!is_valid] # nolint: object_usage_linter. TODO(#2252). cli_abort(c( x = "Found unknown arguments in `...`: {.arg {invalid_args}}.", i = "Check for typos and see ?{ref_help} for valid arguments." )) } cli_abort_internal <- function(...) { cli_abort(..., .internal = TRUE) } lintr/R/inner_combine_linter.R0000644000176200001440000001142214752731051016117 0ustar liggesusers#' Require `c()` to be applied before relatively expensive vectorized functions #' #' `as.Date(c(a, b))` is logically equivalent to `c(as.Date(a), as.Date(b))`. #' The same equivalence holds for several other vectorized functions like #' [as.POSIXct()] and math functions like [sin()]. The former is to be #' preferred so that the most expensive part of the operation ([as.Date()]) #' is applied only once. #' #' Note that [strptime()] has one idiosyncrasy to be aware of, namely that #' auto-detected `format=` is set by the first matching input, which means #' that a case like `c(as.POSIXct("2024-01-01"), as.POSIXct("2024-01-01 01:02:03"))` #' gives different results to `as.POSIXct(c("2024-01-01", "2024-01-01 01:02:03"))`. #' This false positive is rare; a workaround where possible is to use #' consistent formatting, i.e., `"2024-01-01 00:00:00"` in the example. #' #' @examples #' # will produce lints #' lint( #' text = "c(log10(x), log10(y), log10(z))", #' linters = inner_combine_linter() #' ) #' #' # okay #' lint( #' text = "log10(c(x, y, z))", #' linters = inner_combine_linter() #' ) #' #' lint( #' text = "c(log(x, base = 10), log10(x, base = 2))", #' linters = inner_combine_linter() #' ) #' #' @evalRd rd_tags("inner_combine_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export inner_combine_linter <- function() { # these don't take any other arguments (except maybe by non-default # methods), so don't need to check equality of other arguments no_arg_vectorized_funs <- c( "sin", "cos", "tan", "sinpi", "cospi", "tanpi", "asin", "acos", "atan", "log2", "log10", "log1p", "exp", "expm1", "sqrt", "abs" ) # TODO(#2468): Try and make this XPath less brittle/more extensible. # See ?as.Date, ?as.POSIXct. tryFormats is not explicitly in any default # POSIXct method, but it is in as.Date.character and as.POSIXlt.character -- # the latter is what actually gets invoked when running as.POSIXct # on a character. So it is indeed an argument by pass-through. date_args <- c("format", "origin", "tz", "tryFormats") date_funs <- c("as.Date", "as.POSIXct", "as.POSIXlt") # See ?log. Only these two take a 'base' argument. log_funs <- c("log", "logb") log_args <- "base" # See ?lubridate::ymd and ?lubridate::ymd_hms lubridate_args <- c("quiet", "tz", "locale", "truncated") lubridate_funs <- c( "ymd", "ydm", "mdy", "myd", "dmy", "dym", "yq", "ym", "my", "ymd_hms", "ymd_hm", "ymd_h", "dmy_hms", "dmy_hm", "dmy_h", "mdy_hms", "mdy_hm", "mdy_h", "ydm_hms", "ydm_hm", "ydm_h" ) date_args_cond <- build_arg_condition(date_funs, date_args) log_args_cond <- build_arg_condition(log_funs, log_args) lubridate_args_cond <- build_arg_condition(lubridate_funs, lubridate_args) c_expr_cond <- xp_and( sprintf( "expr[1][SYMBOL_FUNCTION_CALL[%s]]", xp_text_in_table(c(no_arg_vectorized_funs, date_funs, log_funs, lubridate_funs)) ), "not(following-sibling::expr[not(expr[1][SYMBOL_FUNCTION_CALL])])", "not(expr[1]/SYMBOL_FUNCTION_CALL != following-sibling::expr/expr[1]/SYMBOL_FUNCTION_CALL)", date_args_cond, log_args_cond, lubridate_args_cond ) xpath <- glue(" self::*[count(following-sibling::expr) > 1] /following-sibling::expr[1][ {c_expr_cond} ] /parent::expr ") Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls("c") bad_expr <- xml_find_all(xml_calls, xpath) matched_call <- xp_call_name(bad_expr, depth = 2L) lint_message <- paste( "Combine inputs to vectorized functions first to take full advantage of vectorization, e.g.,", sprintf( "%1$s(c(x, y)) only runs the more expensive %1$s() once as compared to c(%1$s(x), %1$s(y)).", matched_call ) ) xml_nodes_to_lints(bad_expr, source_expression = source_expression, lint_message, type = "warning") }) } #' Make the XPath condition ensuring an argument matches across calls #' #' @param arg Character scalar naming an argument #' @noRd arg_match_condition <- function(arg) { this_symbol <- sprintf("SYMBOL_SUB[text() = '%s']", arg) following_symbol <- sprintf("following-sibling::expr/%s", this_symbol) next_expr <- "following-sibling::expr[1]" xp_or( sprintf("not(%s) and not(%s)", this_symbol, following_symbol), xp_and( this_symbol, following_symbol, sprintf( "not(%1$s/%3$s != %2$s/%3$s)", this_symbol, following_symbol, next_expr ) ) ) } build_arg_condition <- function(calls, arguments) { xp_or( sprintf("not(expr[1][SYMBOL_FUNCTION_CALL[%s]])", xp_text_in_table(calls)), "not(EQ_SUB) and not(following-sibling::expr/EQ_SUB)", xp_and(vapply(arguments, arg_match_condition, character(1L))) ) } lintr/R/nonportable_path_linter.R0000644000176200001440000000160714752731051016653 0ustar liggesusers#' Non-portable path linter #' #' Check that [file.path()] is used to construct safe and portable paths. #' #' @examples #' # will produce lints #' lint( #' text = "'abcdefg/hijklmnop/qrst/uv/wxyz'", #' linters = nonportable_path_linter() #' ) #' #' # okay #' lint( #' text = "file.path('abcdefg', 'hijklmnop', 'qrst', 'uv', 'wxyz')", #' linters = nonportable_path_linter() #' ) #' #' @inheritParams absolute_path_linter #' @evalRd rd_tags("nonportable_path_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - [absolute_path_linter()] #' @export nonportable_path_linter <- function(lax = TRUE) { path_linter_factory( path_function = function(path) { is_path(path) && is_valid_long_path(path, lax) && path != "/" && re_matches(path, rex(one_of("/", "\\"))) }, message = "Use file.path() to construct portable file paths." ) } lintr/R/indentation_linter.R0000644000176200001440000003257314752731051015636 0ustar liggesusers#' Check that indentation is consistent #' #' @param indent Number of spaces, that a code block should be indented by relative to its parent code block. #' Used for multi-line code blocks (`{ ... }`), function calls (`( ... )`) and extractions (`[ ... ]`, `[[ ... ]]`). #' Defaults to 2. #' @param hanging_indent_style Indentation style for multi-line function calls with arguments in their first line. #' Defaults to tidyverse style, i.e. a block indent is used if the function call terminates with `)` on a separate #' line and a hanging indent if not. #' Note that function multi-line function calls without arguments on their first line will always be expected to have #' block-indented arguments. #' If `hanging_indent_style` is `"tidy"`, multi-line function definitions are expected to be double-indented if the #' first line of the function definition contains no arguments and the closing parenthesis is not on its own line. #' #' ```r #' # complies to any style #' map( #' x, #' f, #' additional_arg = 42 #' ) #' #' # complies to "tidy" and "never" #' map(x, f, #' additional_arg = 42 #' ) #' #' # complies to "always" #' map(x, f, #' additional_arg = 42 #' ) #' #' # complies to "tidy" and "always" #' map(x, f, #' additional_arg = 42) #' #' # complies to "never" #' map(x, f, #' additional_arg = 42) #' #' # complies to "tidy" #' function( #' a, #' b) { #' # body #' } #' ``` #' @param assignment_as_infix Treat `<-` as a regular (i.e. left-associative) infix operator? #' This means, that infix operators on the right hand side of an assignment do not trigger a second level of #' indentation: #' ```r #' # complies to any style #' variable <- a %+% #' b %+% #' c #' #' # complies to assignment_as_infix = TRUE #' variable <- #' a %+% #' b %+% #' c #' #' # complies to assignment_as_infix = FALSE #' variable <- #' a %+% #' b %+% #' c #' ``` #' #' @examples #' # will produce lints #' code_lines <- "if (TRUE) {\n1 + 1\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = indentation_linter() #' ) #' #' code_lines <- "if (TRUE) {\n 1 + 1\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = indentation_linter() #' ) #' #' code_lines <- "map(x, f,\n additional_arg = 42\n)" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = indentation_linter(hanging_indent_style = "always") #' ) #' #' code_lines <- "map(x, f,\n additional_arg = 42)" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = indentation_linter(hanging_indent_style = "never") #' ) #' #' # okay #' code_lines <- "map(x, f,\n additional_arg = 42\n)" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = indentation_linter() #' ) #' #' code_lines <- "if (TRUE) {\n 1 + 1\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = indentation_linter(indent = 4) #' ) #' #' @evalRd rd_tags("indentation_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' - #' #' @export indentation_linter <- function(indent = 2L, hanging_indent_style = c("tidy", "always", "never"), assignment_as_infix = TRUE) { paren_tokens_left <- c("OP-LEFT-BRACE", "OP-LEFT-PAREN", "OP-LEFT-BRACKET", "LBB") paren_tokens_right <- c("OP-RIGHT-BRACE", "OP-RIGHT-PAREN", "OP-RIGHT-BRACKET", "OP-RIGHT-BRACKET") infix_tokens <- setdiff(infix_metadata$xml_tag, c("OP-LEFT-BRACE", "OP-COMMA", paren_tokens_left)) no_paren_keywords <- c("ELSE", "REPEAT") keyword_tokens <- c("FUNCTION", "OP-LAMBDA", "IF", "FOR", "WHILE") xp_last_on_line <- "@line1 != following-sibling::*[not(self::COMMENT)][1]/@line1" hanging_indent_style <- match.arg(hanging_indent_style) find_indent_type <- switch(hanging_indent_style, tidy = build_indentation_style_tidy(), always = build_indentation_style_always(), never = function(change) "block" ) if (isTRUE(assignment_as_infix)) { suppressing_tokens <- c("LEFT_ASSIGN", "EQ_ASSIGN", "EQ_SUB", "EQ_FORMALS") xp_suppress <- glue("preceding-sibling::{suppressing_tokens}[{xp_last_on_line}]") restoring_tokens <- c("expr[SYMBOL_FUNCTION_CALL]", "OP-LEFT-BRACE") xp_restore <- glue("preceding-sibling::{restoring_tokens}") # match the first ancestor expr that is either # * a suppressing token (<- or =) or # * a restoring token (braces or a function call) # suppress the indent if the matched ancestor is a suppressing token infix_condition <- glue(" and not(ancestor::expr[{xp_or(c(xp_suppress, xp_restore))}][1][{xp_or(xp_suppress)}]) ") } else { infix_condition <- "" } xp_block_ends <- paste0( "number(", paste( c( glue("self::{paren_tokens_left}/following-sibling::{paren_tokens_right}/preceding-sibling::*[1]/@line2"), glue(" self::*[{xp_and(paste0('not(self::', paren_tokens_left, ')'))}] /following-sibling::SYMBOL_FUNCTION_CALL /parent::expr /following-sibling::expr[1] /@line2 "), glue(" self::*[ {xp_and(paste0('not(self::', paren_tokens_left, ')'))} and not(following-sibling::SYMBOL_FUNCTION_CALL) ] /following-sibling::*[not(self::COMMENT)][1] /@line2 ") ), collapse = " | " ), ")" ) global_nodes <- function(nodes) paste0("//", nodes, collapse = "|") xp_indent_changes <- paste( c( glue("//{paren_tokens_left}[not( @line1 = following-sibling::expr[ @line2 > @line1 and ({xp_or(paste0('descendant::', paren_tokens_left, '[', xp_last_on_line, ']'))}) ]/@line1 )]"), glue("({ global_nodes(infix_tokens) })[{xp_last_on_line}{infix_condition}]"), glue("({ global_nodes(no_paren_keywords) })[{xp_last_on_line}]"), glue(" ({ global_nodes(keyword_tokens) }) /following-sibling::OP-RIGHT-PAREN[ {xp_last_on_line} and not(following-sibling::expr[1][OP-LEFT-BRACE]) ] ") ), collapse = " | " ) xp_multiline_string <- "//STR_CONST[@line1 < @line2]" Linter(linter_level = "file", function(source_expression) { # must run on file level because a line can contain multiple expressions, losing indentation information, e.g. # #> fun( # a) # comment # # will have "# comment" as a separate expression xml <- source_expression$full_xml_parsed_content # Indentation increases by 1 for: # - { } blocks that span multiple lines # - ( ), [ ], or [[ ]] calls that span multiple lines # + if a token follows (, a hanging indent is required until ) # + if there is no token following ( on the same line, a block indent is required until ) # - binary operators where the second arguments starts on a new line indent_levels <- re_matches( source_expression$file_lines, rex(start, any_spaces), locations = TRUE )[, "end"] expected_indent_levels <- integer(length(indent_levels)) is_hanging <- logical(length(indent_levels)) indent_changes <- xml_find_all(xml, xp_indent_changes) for (change in indent_changes) { change_type <- find_indent_type(change) change_begin <- as.integer(xml_attr(change, "line1")) + 1L change_end <- xml_find_num(change, xp_block_ends) if (isTRUE(change_begin <= change_end)) { to_indent <- seq(from = change_begin, to = change_end) expected_indent_levels[to_indent] <- find_new_indent( current_indent = expected_indent_levels[to_indent], change_type = change_type, indent = indent, hanging_indent = as.integer(xml_attr(change, "col2")) ) is_hanging[to_indent] <- change_type == "hanging" } } in_str_const <- logical(length(indent_levels)) multiline_strings <- xml_find_all(xml, xp_multiline_string) for (string in multiline_strings) { is_in_str <- seq( from = as.integer(xml_attr(string, "line1")) + 1L, to = as.integer(xml_attr(string, "line2")) ) in_str_const[is_in_str] <- TRUE } # Only lint non-empty lines if the indentation level doesn't match. # TODO: remove styler ignore directives once tidyverse/style/issues/197 is resolved # styler: off bad_lines <- which(indent_levels != expected_indent_levels & nzchar(trimws(source_expression$file_lines)) & !in_str_const) # styler: on if (length(bad_lines) > 0L) { # Suppress consecutive lints with the same indentation difference, to not generate an excessive number of lints is_consecutive_lint <- c(FALSE, diff(bad_lines) == 1L) indent_diff <- expected_indent_levels[bad_lines] - indent_levels[bad_lines] is_same_diff <- c(FALSE, diff(indent_diff) == 0L) bad_lines <- bad_lines[!(is_consecutive_lint & is_same_diff)] lint_messages <- sprintf( "%s should be %d spaces but is %d spaces.", ifelse(is_hanging[bad_lines], "Hanging indent", "Indentation"), expected_indent_levels[bad_lines], indent_levels[bad_lines] ) lint_lines <- unname(as.integer(names(source_expression$file_lines)[bad_lines])) lint_ranges <- cbind( # when indent_levels==0, need to start ranges at column 1. pmax( pmin(expected_indent_levels[bad_lines] + 1L, indent_levels[bad_lines]), 1L ), # If the expected indent is larger than the current line width, the lint range would become invalid. # Therefore, limit range end to end of line. pmin( pmax(expected_indent_levels[bad_lines], indent_levels[bad_lines]), nchar(source_expression$file_lines[bad_lines]) + 1L ) ) Map( Lint, filename = source_expression$filename, line_number = lint_lines, column_number = indent_levels[bad_lines], type = "style", message = lint_messages, line = unname(source_expression$file_lines[bad_lines]), # TODO(#2467): Use ranges = apply(lint_ranges, 1L, list, simplify = FALSE). ranges = lapply( seq_along(bad_lines), function(i) { list(lint_ranges[i, ]) } ) ) } else { list() } }) } find_new_indent <- function(current_indent, change_type, indent, hanging_indent) { switch(change_type, suppress = current_indent, hanging = hanging_indent, double = current_indent + 2L * indent, block = current_indent + indent ) } build_indentation_style_tidy <- function() { paren_tokens_left <- c("OP-LEFT-BRACE", "OP-LEFT-PAREN", "OP-LEFT-BRACKET", "LBB") paren_tokens_right <- c("OP-RIGHT-BRACE", "OP-RIGHT-PAREN", "OP-RIGHT-BRACKET", "OP-RIGHT-BRACKET") xp_last_on_line <- "@line1 != following-sibling::*[not(self::COMMENT)][1]/@line1" xp_inner_expr <- "preceding-sibling::*[1][self::expr and expr[SYMBOL_FUNCTION_CALL]]/*[not(self::COMMENT)]" # double indent is tidyverse style for function definitions # triggered only if the closing parenthesis of the function definition is not on its own line and the opening # parenthesis has no arguments behind it. # this allows both of these styles: # #> function( #> a, #> b) { #> body #> } # #> function( #> a, #> b #> ) { #> body #> } xp_is_double_indent <- " parent::expr[(FUNCTION or OP-LAMBDA) and not(@line1 = SYMBOL_FORMALS/@line1)] /OP-RIGHT-PAREN[@line1 = preceding-sibling::*[not(self::COMMENT)][1]/@line2] " xp_suppress <- paste( glue(" self::{paren_tokens_left}[ @line1 = following-sibling::{paren_tokens_right}/{xp_inner_expr}[position() = 1]/@line1 ]/following-sibling::{paren_tokens_right}[ @line1 > {xp_inner_expr}[position() = last() - 1]/@line2 ]"), collapse = " | " ) xp_is_not_hanging <- paste( c( glue( "self::{paren_tokens_left}/following-sibling::{paren_tokens_right}[@line1 > preceding-sibling::*[1]/@line2]" ), glue("self::*[{xp_and(paste0('not(self::', paren_tokens_left, ')'))} and {xp_last_on_line}]") ), collapse = " | " ) function(change) { if (length(xml_find_first(change, xp_is_double_indent)) > 0L) { "double" } else if (length(xml_find_first(change, xp_suppress)) > 0L) { "suppress" } else if (length(xml_find_first(change, xp_is_not_hanging)) == 0L) { "hanging" } else { "block" } } } build_indentation_style_always <- function() { paren_tokens_left <- c("OP-LEFT-BRACE", "OP-LEFT-PAREN", "OP-LEFT-BRACKET", "LBB") paren_tokens_right <- c("OP-RIGHT-BRACE", "OP-RIGHT-PAREN", "OP-RIGHT-BRACKET", "OP-RIGHT-BRACKET") xp_last_on_line <- "@line1 != following-sibling::*[not(self::COMMENT)][1]/@line1" xp_is_not_hanging <- paste( c( glue(" self::{paren_tokens_left}[{xp_last_on_line}]/ following-sibling::{paren_tokens_right}[@line1 > preceding-sibling::*[1]/@line2] "), glue("self::*[{xp_and(paste0('not(self::', paren_tokens_left, ')'))} and {xp_last_on_line}]") ), collapse = " | " ) function(change) { if (length(xml_find_first(change, xp_is_not_hanging)) == 0L) { "hanging" } else { "block" } } } lintr/R/redundant_ifelse_linter.R0000644000176200001440000000702114752731051016623 0ustar liggesusers#' Prevent `ifelse()` from being used to produce `TRUE`/`FALSE` or `1`/`0` #' #' Expressions like `ifelse(x, TRUE, FALSE)` and `ifelse(x, FALSE, TRUE)` are #' redundant; just `x` or `!x` suffice in R code where logical vectors are a #' core data structure. `ifelse(x, 1, 0)` is also `as.numeric(x)`, but even #' this should be needed only rarely. #' #' @evalRd rd_tags("redundant_ifelse_linter") #' @param allow10 Logical, default `FALSE`. If `TRUE`, usage like #' `ifelse(x, 1, 0)` is allowed, i.e., only usage like #' `ifelse(x, TRUE, FALSE)` is linted. #' #' @examples #' # will produce lints #' lint( #' text = "ifelse(x >= 2.5, TRUE, FALSE)", #' linters = redundant_ifelse_linter() #' ) #' #' lint( #' text = "ifelse(x < 2.5, 1L, 0L)", #' linters = redundant_ifelse_linter() #' ) #' #' # okay #' lint( #' text = "x >= 2.5", #' linters = redundant_ifelse_linter() #' ) #' #' # Note that this is just to show the strict equivalent of the example above; #' # converting to integer is often unnecessary and the logical vector itself #' # should suffice. #' lint( #' text = "as.integer(x < 2.5)", #' linters = redundant_ifelse_linter() #' ) #' #' lint( #' text = "ifelse(x < 2.5, 1L, 0L)", #' linters = redundant_ifelse_linter(allow10 = TRUE) #' ) #' #' @seealso [linters] for a complete list of linters available in lintr. #' @export redundant_ifelse_linter <- function(allow10 = FALSE) { tf_xpath <- glue(" parent::expr[ expr[position() <= 4 and NUM_CONST[text() = 'TRUE']] and expr[position() <= 4 and NUM_CONST[text() = 'FALSE']] and ( count(expr) = 4 or expr[5]/NUM_CONST[text() = 'NA'] ) ]") num_xpath <- glue(" parent::expr[ expr[position() <= 4 and NUM_CONST[text() = '1' or text() = '1L']] and expr[position() <= 4 and NUM_CONST[text() = '0' or text() = '0L']] and ( count(expr) = 4 or expr[5]/NUM_CONST[text() = 'NA' or text() = 'NA_integer_' or text() = 'NA_real_'] ) ]") Linter(linter_level = "expression", function(source_expression) { xml_targets <- source_expression$xml_find_function_calls(ifelse_funs) lints <- list() tf_expr <- xml_find_all(xml_targets, tf_xpath) matched_call <- xp_call_name(tf_expr) # [1] call; [2] logical condition first_arg <- xml_find_chr(tf_expr, "string(expr[3]/NUM_CONST)") second_arg <- xml_find_chr(tf_expr, "string(expr[4]/NUM_CONST)") tf_message <- sprintf( "Just use the logical condition (or its negation) directly instead of calling %s(x, %s, %s)", matched_call, first_arg, second_arg ) lints <- c(lints, xml_nodes_to_lints(tf_expr, source_expression, tf_message, type = "warning")) if (!allow10) { num_expr <- xml_find_all(xml_targets, num_xpath) matched_call <- xp_call_name(num_expr) # [1] call; [2] logical condition first_arg <- xml_find_chr(num_expr, "string(expr[3]/NUM_CONST)") second_arg <- xml_find_chr(num_expr, "string(expr[4]/NUM_CONST)") is_numeric_01 <- first_arg %in% c("0", "1") | second_arg %in% c("0", "1") coercion_function <- ifelse(is_numeric_01, "as.numeric", "as.integer") is_negated <- first_arg %in% c("0", "0L") replacement_argument <- ifelse(is_negated, "!x", "x") lint_message <- paste( sprintf( "Prefer %s(%s) to %s(x, %s, %s) if really needed.", coercion_function, replacement_argument, matched_call, first_arg, second_arg ) ) lints <- c(lints, xml_nodes_to_lints(num_expr, source_expression, lint_message, type = "warning")) } lints }) } lintr/R/length_test_linter.R0000644000176200001440000000265414752731051015637 0ustar liggesusers#' Check for a common mistake where length is applied in the wrong place #' #' Usage like `length(x == 0)` is a mistake. If you intended to check `x` is empty, #' use `length(x) == 0`. Other mistakes are possible, but running `length()` on the #' outcome of a logical comparison is never the best choice. #' #' @examples #' # will produce lints #' lint( #' text = "length(x == 0)", #' linters = length_test_linter() #' ) #' #' # okay #' lint( #' text = "length(x) > 0", #' linters = length_test_linter() #' ) #' @evalRd rd_tags("class_equals_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export length_test_linter <- function() { xpath <- glue::glue(" following-sibling::expr[{ xp_or(infix_metadata$xml_tag[infix_metadata$comparator]) }] /parent::expr ") Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls("length") bad_expr <- xml_find_all(xml_calls, xpath) expr_parts <- vapply(lapply(bad_expr, xml_find_all, "expr[2]/*"), xml_text, character(3L)) lint_message <- sprintf( "Checking the length of a logical vector is likely a mistake. Did you mean `length(%s) %s %s`?", expr_parts[1L, ], expr_parts[2L, ], expr_parts[3L, ] ) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = lint_message, type = "warning" ) }) } lintr/R/consecutive_assertion_linter.R0000644000176200001440000000407414752731051017733 0ustar liggesusers#' Force consecutive calls to assertions into just one when possible #' #' [stopifnot()] accepts any number of tests, so sequences like #' `stopifnot(x); stopifnot(y)` are redundant. Ditto for tests using #' `assertthat::assert_that()` without specifying `msg=`. #' #' @examples #' # will produce lints #' lint( #' text = "stopifnot(x); stopifnot(y)", #' linters = consecutive_assertion_linter() #' ) #' #' lint( #' text = "assert_that(x); assert_that(y)", #' linters = consecutive_assertion_linter() #' ) #' #' # okay #' lint( #' text = "stopifnot(x, y)", #' linters = consecutive_assertion_linter() #' ) #' #' lint( #' text = 'assert_that(x, msg = "Bad x!"); assert_that(y)', #' linters = consecutive_assertion_linter() #' ) #' #' @evalRd rd_tags("consecutive_assertion_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export consecutive_assertion_linter <- function() { # annoying expr-but-not-really nodes next_expr <- "following-sibling::*[self::expr or self::expr_or_assign_or_help or self::equal_assign][1]" stopifnot_xpath <- glue(" parent::expr[ expr[1]/SYMBOL_FUNCTION_CALL = {next_expr}/expr[1]/SYMBOL_FUNCTION_CALL ]") assert_that_xpath <- glue(" parent::expr[ not(SYMBOL_SUB[text() = 'msg']) and not(following-sibling::expr[1]/SYMBOL_SUB[text() = 'msg']) and expr[1]/SYMBOL_FUNCTION_CALL = {next_expr}/expr[1]/SYMBOL_FUNCTION_CALL ]") Linter(linter_level = "file", function(source_expression) { # need the full file to also catch usages at the top level stopifnot_calls <- source_expression$xml_find_function_calls("stopifnot") assert_that_calls <- source_expression$xml_find_function_calls("assert_that") bad_expr <- combine_nodesets( xml_find_all(stopifnot_calls, stopifnot_xpath), xml_find_all(assert_that_calls, assert_that_xpath) ) matched_function <- xp_call_name(bad_expr) xml_nodes_to_lints( bad_expr, source_expression, lint_message = sprintf("Unify consecutive calls to %s().", matched_function), type = "warning" ) }) } lintr/R/paren_body_linter.R0000644000176200001440000000300114752731051015424 0ustar liggesusers#' Parenthesis before body linter #' #' Check that there is a space between right parenthesis and a body expression. #' #' @evalRd rd_tags("paren_body_linter") #' #' @examples #' # will produce lints #' lint( #' text = "function(x)x + 1", #' linters = paren_body_linter() #' ) #' #' # okay #' lint( #' text = "function(x) x + 1", #' linters = paren_body_linter() #' ) #' #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export paren_body_linter <- make_linter_from_xpath( # careful to do recursive search to the less common OP-RIGHT-PAREN # and forcond nodes (vs. //expr) for performance -- there can # be O(100K) nodes but in all but pathological examples, # these other nodes will only be a small fraction of this amount. # note also that only has one following-sibling::expr. xpath = " //OP-RIGHT-PAREN[ @end = following-sibling::expr[1]/@start - 1 and @line1 = following-sibling::expr[1]/@line1 and ( preceding-sibling::FUNCTION or preceding-sibling::OP-LAMBDA or preceding-sibling::IF or preceding-sibling::WHILE or preceding-sibling::OP-LAMBDA ) ] /following-sibling::expr[1] | //forcond[ @line1 = following-sibling::expr/@line2 and OP-RIGHT-PAREN/@col1 = following-sibling::expr/@col1 - 1 ] /following-sibling::expr ", lint_message = "Put a space between a right parenthesis and a body expression.", type = "style" ) lintr/R/redundant_equals_linter.R0000644000176200001440000000413214752731051016646 0ustar liggesusers#' Block usage of `==`, `!=` on logical vectors #' #' Testing `x == TRUE` is redundant if `x` is a logical vector. Wherever this is #' used to improve readability, the solution should instead be to improve the #' naming of the object to better indicate that its contents are logical. This #' can be done using prefixes (is, has, can, etc.). For example, `is_child`, #' `has_parent_supervision`, `can_watch_horror_movie` clarify their logical #' nature, while `child`, `parent_supervision`, `watch_horror_movie` don't. #' #' @examples #' # will produce lints #' lint( #' text = "if (any(x == TRUE)) 1", #' linters = redundant_equals_linter() #' ) #' #' lint( #' text = "if (any(x != FALSE)) 0", #' linters = redundant_equals_linter() #' ) #' #' lint( #' text = "dt[is_tall == FALSE, y]", #' linters = redundant_equals_linter() #' ) #' #' # okay #' lint( #' text = "if (any(x)) 1", #' linters = redundant_equals_linter() #' ) #' #' lint( #' text = "if (!all(x)) 0", #' linters = redundant_equals_linter() #' ) #' #' # in `{data.table}` semantics, `dt[x]` is a join, `dt[(x)]` is a subset #' lint( #' text = "dt[(!is_tall), y]", #' linters = redundant_equals_linter() #' ) #' #' @evalRd rd_tags("redundant_equals_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - [outer_negation_linter()] #' @export redundant_equals_linter <- function() { xpath <- " (//EQ | //NE) /parent::expr /expr[NUM_CONST[text() = 'TRUE' or text() = 'FALSE']] /parent::expr " Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) op <- xml_text(xml_find_first(bad_expr, "*[2]")) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = paste( "Using", op, "on a logical vector is redundant.", "Well-named logical vectors can be used directly in filtering.", "For data.table's `i` argument, wrap the column name in (), like `DT[(is_treatment)]`." ), type = "warning" ) }) } lintr/R/outer_negation_linter.R0000644000176200001440000000406614752731051016340 0ustar liggesusers#' Require usage of `!any(x)` over `all(!x)`, `!all(x)` over `any(!x)` #' #' `any(!x)` is logically equivalent to `!all(x)`; ditto for the equivalence of #' `all(!x)` and `!any(x)`. Negating after aggregation only requires inverting #' one logical value, and is typically more readable. #' #' @examples #' # will produce lints #' lint( #' text = "all(!x)", #' linters = outer_negation_linter() #' ) #' #' lint( #' text = "any(!x)", #' linters = outer_negation_linter() #' ) #' #' # okay #' lint( #' text = "!any(x)", #' linters = outer_negation_linter() #' ) #' #' lint( #' text = "!all(x)", #' linters = outer_negation_linter() #' ) #' #' @evalRd rd_tags("outer_negation_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export outer_negation_linter <- function() { # NB: the double negation is a bit hairy, but it's what we need to check if # _all_ of the inputs to any(..., na.rm=na.rm) are negated, i.e., there are # _not_ any entries that are _not_ negated. IINM that's what we're stuck # with in xpath if we want to guarantee a condition on _all_ # coming after any( and before na.rm= . # NB: requirement that count(expr)>1 is to prevent any() from linting # e.g. in magrittr pipelines. xpath <- " self::*[following-sibling::expr] /parent::expr[ not(expr[ position() > 1 and not(OP-EXCLAMATION) and not(preceding-sibling::*[1][self::EQ_SUB]) ]) ] " Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(c("any", "all")) bad_expr <- xml_find_all(xml_calls, xpath) matched_call <- xp_call_name(bad_expr) inverse_call <- ifelse(matched_call == "any", "all", "any") lint_message <- paste( sprintf("!%s(x) is better than %s(!x).", inverse_call, matched_call), "The former applies negation only once after aggregation instead of many times for each element of x." ) xml_nodes_to_lints(bad_expr, source_expression, lint_message, type = "warning") }) } lintr/R/quotes_linter.R0000644000176200001440000000331514752731051014632 0ustar liggesusers#' Character string quote linter #' #' Check that the desired quote delimiter is used for string constants. #' #' @param delimiter Which quote delimiter to accept. Defaults to the tidyverse #' default of `"` (double-quoted strings). #' #' @examples #' # will produce lints #' lint( #' text = "c('a', 'b')", #' linters = quotes_linter() #' ) #' #' # okay #' lint( #' text = 'c("a", "b")', #' linters = quotes_linter() #' ) #' #' code_lines <- "paste0(x, '\"this is fine\"')" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = quotes_linter() #' ) #' #' # okay #' lint( #' text = "c('a', 'b')", #' linters = quotes_linter(delimiter = "'") #' ) #' #' @evalRd rd_tags("quotes_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export quotes_linter <- function(delimiter = c('"', "'")) { delimiter <- match.arg(delimiter) if (delimiter == '"') { quote_regex <- rex( start, zero_or_one(character_class("rR")), single_quote, any_non_double_quotes, single_quote, end ) lint_message <- "Only use double-quotes." } else { quote_regex <- rex( start, zero_or_one(character_class("rR")), double_quote, any_non_single_quotes, double_quote, end ) lint_message <- "Only use single-quotes." } Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content string_exprs <- xml_find_all(xml, "//STR_CONST") is_bad <- re_matches(xml_text(string_exprs), quote_regex) xml_nodes_to_lints(string_exprs[is_bad], source_expression, lint_message) }) } lintr/R/expect_identical_linter.R0000644000176200001440000000755214752731051016625 0ustar liggesusers#' Require usage of `expect_identical(x, y)` where appropriate #' #' This linter enforces the usage of [testthat::expect_identical()] as the #' default expectation for comparisons in a testthat suite. `expect_true(identical(x, y))` #' is an equivalent but unadvised method of the same test. Further, #' [testthat::expect_equal()] should only be used when `expect_identical()` #' is inappropriate, i.e., when `x` and `y` need only be *numerically #' equivalent* instead of fully identical (in which case, provide the #' `tolerance=` argument to `expect_equal()` explicitly). This also applies #' when it's inconvenient to check full equality (e.g., names can be ignored, #' in which case `ignore_attr = "names"` should be supplied to #' `expect_equal()` (or, for 2nd edition, `check.attributes = FALSE`). #' #' @section Exceptions: #' #' The linter allows `expect_equal()` in three circumstances: #' 1. A named argument is set (e.g. `ignore_attr` or `tolerance`) #' 2. Comparison is made to an explicit decimal, e.g. #' `expect_equal(x, 1.0)` (implicitly setting `tolerance`) #' 3. `...` is passed (wrapper functions which might set #' arguments such as `ignore_attr` or `tolerance`) #' #' @examples #' # will produce lints #' lint( #' text = "expect_equal(x, y)", #' linters = expect_identical_linter() #' ) #' #' lint( #' text = "expect_true(identical(x, y))", #' linters = expect_identical_linter() #' ) #' #' # okay #' lint( #' text = "expect_identical(x, y)", #' linters = expect_identical_linter() #' ) #' #' lint( #' text = "expect_equal(x, y, check.attributes = FALSE)", #' linters = expect_identical_linter() #' ) #' #' lint( #' text = "expect_equal(x, y, tolerance = 1e-6)", #' linters = expect_identical_linter() #' ) #' #' @evalRd rd_tags("expect_identical_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export expect_identical_linter <- function() { # outline: # - skip when any named argument is set. most commonly this # is check.attributes (for 2e tests) or one of the ignore_* # arguments (for 3e tests). This will generate some false # negatives, but will be much easier to maintain. # - skip cases like expect_equal(x, 1.02) or the constant vector version # where a numeric constant indicates inexact testing is preferable # - skip calls using dots (`...`); see tests non_integer <- glue::glue(" NUM_CONST[contains(text(), '.')] or ( OP-MINUS and count(expr) = 1 and expr[NUM_CONST[contains(text(), '.')]] ) ") expect_equal_xpath <- glue::glue(" self::*[not( following-sibling::EQ_SUB or following-sibling::expr[ ( expr[1][SYMBOL_FUNCTION_CALL[text() = 'c']] and expr[{non_integer}] ) or ( {non_integer} ) or ( OP-MINUS and count(expr) = 1 and expr[ expr[1][SYMBOL_FUNCTION_CALL[text() = 'c']] and expr[{non_integer}] ] ) or ( SYMBOL[text() = '...'] ) ] )] /parent::expr ") expect_true_xpath <- " following-sibling::expr[1][expr[1]/SYMBOL_FUNCTION_CALL[text() = 'identical']] /parent::expr " Linter(linter_level = "expression", function(source_expression) { expect_equal_calls <- source_expression$xml_find_function_calls("expect_equal") expect_true_calls <- source_expression$xml_find_function_calls("expect_true") bad_expr <- c( xml_find_all(expect_equal_calls, expect_equal_xpath), xml_find_all(expect_true_calls, expect_true_xpath) ) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = paste( "Use expect_identical(x, y) by default; resort to expect_equal() only when needed,", "e.g. when setting ignore_attr= or tolerance=." ), type = "warning" ) }) } lintr/R/trailing_blank_lines_linter.R0000644000176200001440000000354614752731051017472 0ustar liggesusers#' Trailing blank lines linter #' #' Check that there are no trailing blank lines in source code. #' #' @examples #' # will produce lints #' f <- tempfile() #' cat("x <- 1\n\n", file = f) #' writeLines(readChar(f, file.size(f))) #' lint( #' filename = f, #' linters = trailing_blank_lines_linter() #' ) #' unlink(f) #' #' # okay #' cat("x <- 1\n", file = f) #' writeLines(readChar(f, file.size(f))) #' lint( #' filename = f, #' linters = trailing_blank_lines_linter() #' ) #' unlink(f) #' #' @evalRd rd_tags("trailing_blank_lines_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export trailing_blank_lines_linter <- function() { Linter(function(source_expression) { blanks <- re_matches( source_expression$file_lines, rex(start, any_spaces, end) ) line_number <- length(source_expression$file_lines) lints <- list() while (line_number > 0L && (is.na(blanks[[line_number]]) || isTRUE(blanks[[line_number]]))) { if (!is.na(blanks[[line_number]])) { lints[[length(lints) + 1L]] <- Lint( filename = source_expression$filename, line_number = line_number, column_number = 1L, type = "style", message = "Remove trailing blank lines.", line = source_expression$file_lines[[line_number]] ) } line_number <- line_number - 1L } if (identical(source_expression$terminal_newline, FALSE)) { # could use isFALSE, but needs backports last_line <- tail(source_expression$file_lines, 1L) lints[[length(lints) + 1L]] <- Lint( filename = source_expression$filename, line_number = length(source_expression$file_lines), column_number = (nchar(last_line) %||% 0L) + 1L, type = "style", message = "Add a terminal newline.", line = last_line ) } lints }) } lintr/R/semicolon_linter.R0000644000176200001440000000563714752731051015313 0ustar liggesusers#' Semicolon linter #' #' Check that no semicolons terminate expressions. #' #' @param allow_compound Logical, default `FALSE`. If `TRUE`, "compound" #' semicolons (e.g. as in `x; y`, i.e., on the same line of code) are allowed. #' @param allow_trailing Logical, default `FALSE`. If `TRUE`, "trailing" #' semicolons (i.e., those that terminate lines of code) are allowed. #' #' @examples #' # will produce lints #' lint( #' text = "a <- 1;", #' linters = semicolon_linter() #' ) #' #' lint( #' text = "a <- 1; b <- 1", #' linters = semicolon_linter() #' ) #' #' lint( #' text = "function() { a <- 1; b <- 1 }", #' linters = semicolon_linter() #' ) #' #' # okay #' lint( #' text = "a <- 1", #' linters = semicolon_linter() #' ) #' #' lint( #' text = "a <- 1;", #' linters = semicolon_linter(allow_trailing = TRUE) #' ) #' #' code_lines <- "a <- 1\nb <- 1" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = semicolon_linter() #' ) #' #' lint( #' text = "a <- 1; b <- 1", #' linters = semicolon_linter(allow_compound = TRUE) #' ) #' #' code_lines <- "function() { \n a <- 1\n b <- 1\n}" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = semicolon_linter() #' ) #' #' @evalRd rd_tags("semicolon_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export semicolon_linter <- function(allow_compound = FALSE, allow_trailing = FALSE) { msg_trailing <- "Remove trailing semicolons." msg_compound <- "Replace compound semicolons by a newline." if (allow_compound && allow_trailing) { cli_abort(c( x = "At least one of {.arg allow_compound} or {.arg allow_trailing} must be `FALSE`.", i = "No lints can be generated otherwise." )) } else if (allow_compound && !allow_trailing) { # lint only trailing xpath <- "//OP-SEMICOLON[not(@line1 = following-sibling::*[1]/@line1)]" msg <- msg_trailing # nolint: object_usage. (usage in linter, since need_detection == FALSE) need_detection <- FALSE } else if (!allow_compound && allow_trailing) { # lint only compound xpath <- "//OP-SEMICOLON[@line1 = following-sibling::*[1]/@line1]" msg <- msg_compound # nolint: object_usage. (usage in linter, since need_detection == FALSE) need_detection <- FALSE } else { # lint all xpath <- "//OP-SEMICOLON" need_detection <- TRUE } compound_xpath <- "self::*[@line1 = following-sibling::*[1]/@line1]" Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content bad_exprs <- xml_find_all(xml, xpath) if (need_detection) { is_trailing <- is.na(xml_find_first(bad_exprs, compound_xpath)) msg <- ifelse(is_trailing, msg_trailing, msg_compound) } xml_nodes_to_lints( bad_exprs, source_expression = source_expression, lint_message = msg ) }) } lintr/R/unnecessary_nesting_linter.R0000644000176200001440000002344414752731051017405 0ustar liggesusers#' Block instances of unnecessary nesting #' #' Excessive nesting harms readability. Use helper functions or early returns #' to reduce nesting wherever possible. #' #' @param allow_assignment Logical, default `TRUE`, in which case #' braced expressions consisting only of a single assignment are skipped. #' if `FALSE`, all braced expressions with only one child expression are linted. #' The `TRUE` case facilitates interaction with [implicit_assignment_linter()] #' for certain cases where an implicit assignment is necessary, so a braced #' assignment is used to further distinguish the assignment. See examples. #' @param allow_functions Character vector of functions which always allow #' one-child braced expressions. `testthat::test_that()` is always allowed because #' testthat requires a braced expression in its `code` argument. The other defaults #' similarly compute on expressions in a way which is worth highlighting by #' em-bracing them, even if there is only one expression, while [switch()] is allowed #' for its use as a control flow analogous to `if`/`else`.] #' @param branch_exit_calls Character vector of functions which are considered #' as "exiting" a branch for the purpose of recommending removing nesting in a branch #' _lacking_ an exit call when the other branch terminates with one. Calls which #' always interrupt or quit the current call or R session, #' e.g. [stop()] and [q()], are always included. #' @examples #' # will produce lints #' code <- "if (A) {\n stop('A is bad!')\n} else {\n do_good()\n}" #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter() #' ) #' #' code <- "tryCatch(\n {\n foo()\n },\n error = identity\n)" #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter() #' ) #' #' code <- "expect_warning(\n {\n x <- foo()\n },\n 'warned'\n)" #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter(allow_assignment = FALSE) #' ) #' #' code <- "if (x) { \n if (y) { \n return(1L) \n } \n}" #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter() #' ) #' #' lint( #' text = "my_quote({x})", #' linters = unnecessary_nesting_linter() #' ) #' #' code <- paste( #' "if (A) {", #' " stop('A is bad because a.')", #' "} else {", #' " warning('!A requires caution.')", #' "}", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter() #' ) #' #' # okay #' code <- "if (A) {\n stop('A is bad because a.')\n} else {\n stop('!A is bad too.')\n}" #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter() #' ) #' #' code <- "capture.output({\n foo()\n})" #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter() #' ) #' #' code <- "expect_warning(\n {\n x <- foo()\n },\n 'warned'\n)" #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter() #' ) #' #' code <- "if (x && y) { \n return(1L) \n}" #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter() #' ) #' #' code <- "if (x) { \n y <- x + 1L\n if (y) { \n return(1L) \n } \n}" #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter() #' ) #' #' lint( #' text = "my_quote({x})", #' linters = unnecessary_nesting_linter(allow_functions = "my_quote") #' ) #' #' code <- paste( #' "if (A) {", #' " stop('A is bad because a.')", #' "} else {", #' " warning('!A requires caution.')", #' "}", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = unnecessary_nesting_linter(branch_exit_calls = c("stop", "warning")) #' ) #' #' @evalRd rd_tags("unnecessary_nesting_linter") #' @seealso #' - [cyclocomp_linter()] for another linter that penalizes overly complex code. #' - [linters] for a complete list of linters available in lintr. #' @export unnecessary_nesting_linter <- function( allow_assignment = TRUE, allow_functions = c( "switch", "try", "tryCatch", "withCallingHandlers", "quote", "expression", "bquote", "substitute", "with_parameters_test_that", "reactive", "observe", "observeEvent", "renderCachedPlot", "renderDataTable", "renderImage", "renderPlot", "renderPrint", "renderTable", "renderText", "renderUI" ), branch_exit_calls = character() ) { default_branch_exit_calls <- c("stop", "return", "abort", "quit", "q") branch_exit_calls <- union(default_branch_exit_calls, branch_exit_calls) exit_call_expr <- glue(" expr[SYMBOL_FUNCTION_CALL[{xp_text_in_table(branch_exit_calls)}]] ") # block IF here for cases where a nested if/else is entirely within # one of the branches. no_exit_call_expr <- glue(" expr[ OP-LEFT-BRACE and expr[ position() = last() and not(IF) and not(expr[SYMBOL_FUNCTION_CALL[{xp_text_in_table(branch_exit_calls)}]]) ] ] ") # condition for ELSE should be redundant, but include for robustness # condition on parent::expr[IF] ensures we're at the first `if` of a sequence of if/else statements # condition on expr uses following-sibling or preceding-sibling to ensure # that the other expr falls on a different branch (earlier used separate # conditions on two expr[], but seems to allow any branch with >1 statement # to lead to a lint. # use position() = last() to ignore any expr but the last one in any branch. if_else_exit_xpath <- glue(" //expr[ IF and ELSE and not(parent::expr[IF]) and expr[ OP-LEFT-BRACE and expr[position() = last() and {exit_call_expr}] and ( following-sibling::{no_exit_call_expr} or preceding-sibling::{no_exit_call_expr} ) ] ] ") assignment_cond <- if (allow_assignment) "expr[LEFT_ASSIGN or RIGHT_ASSIGN]" else "false" # several carve-outs of common cases where single-expression braces are OK # - control flow statements: if, for, while, repeat # + include foreach() as a common package-based for loop extension # - function definitions # + includes purrr-like anonymous functions as ~ {...} # - rlang's double-brace expressions like {{ var }} # + NB: both braces would trigger here, so we must exclude both of them # - any expression starting like `({` or `[{` or ending like `})` or `}]` # + note that nesting is not improved by "fixing" such cases, and could also be worsened # + motivated by the most common cases: # * test_that("test", { expr }) # * with(x, { expr }) / within(x, { expr }) # * suppressWarnings({ expr }) # * DataTable[, { expr }] # * DataTable[, col := { expr }] <- requires carve-out for `:=` unnecessary_brace_xpath <- glue(" //OP-LEFT-BRACE /parent::expr[ count(expr) = 1 and not(preceding-sibling::*[ self::FUNCTION or self::FOR or self::IF or self::WHILE or self::REPEAT or self::expr/SYMBOL_FUNCTION_CALL[{ xp_text_in_table(c('test_that', allow_functions)) }] or self::expr/expr/SYMBOL_FUNCTION_CALL[text() = 'foreach'] or self::OP-TILDE or self::LEFT_ASSIGN[text() = ':='] ]) and not(expr/OP-LEFT-BRACE) and not(preceding-sibling::OP-LEFT-BRACE) and not( OP-LEFT-BRACE/@end - 1 = preceding-sibling::*[1][self::OP-LEFT-PAREN or self::OP-LEFT-BRACKET]/@end or OP-RIGHT-BRACE/@end + 1 = following-sibling::*[1][self::OP-RIGHT-PAREN or self::OP-RIGHT-BRACKET]/@end ) and not({assignment_cond}) ] ") unnecessary_nested_if_xpath <- paste0( "//IF/parent::expr[not(ELSE)]/OP-RIGHT-PAREN/", c( # catch if (cond) if (other_cond) { ... } "following-sibling::expr[IF and not(ELSE)]", # catch if (cond) { if (other_cond) { ... } } "following-sibling::expr[OP-LEFT-BRACE and count(expr) = 1]/expr[IF and not(ELSE)]" ), collapse = " | " ) unnecessary_else_brace_xpath <- "//IF/parent::expr[parent::expr[preceding-sibling::ELSE and count(expr) = 1]]" Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content if_else_exit_expr <- xml_find_all(xml, if_else_exit_xpath) if_else_exit_lints <- xml_nodes_to_lints( if_else_exit_expr, source_expression = source_expression, lint_message = paste0( "Reduce the nesting of this if/else statement by unnesting the ", "portion without an exit clause (i.e., ", paste0(branch_exit_calls, "()", collapse = ", "), ")." ), type = "warning" ) unnecessary_brace_expr <- xml_find_all(xml, unnecessary_brace_xpath) unnecessary_brace_lints <- xml_nodes_to_lints( unnecessary_brace_expr, source_expression = source_expression, lint_message = "Reduce the nesting of this statement by removing the braces {}.", type = "warning" ) unnecessary_nested_if_expr <- xml_find_all(xml, unnecessary_nested_if_xpath) unnecessary_nested_if_lints <- xml_nodes_to_lints( unnecessary_nested_if_expr, source_expression = source_expression, lint_message = paste( "Don't use nested `if` statements, where a single `if` with the combined conditional expression will do.", "For example, instead of `if (x) { if (y) { ... }}`, use `if (x && y) { ... }`." ), type = "warning" ) unnecessary_else_brace_expr <- xml_find_all(xml, unnecessary_else_brace_xpath) unnecessary_else_brace_lints <- xml_nodes_to_lints( unnecessary_else_brace_expr, source_expression = source_expression, lint_message = "Simplify this condition by using 'else if' instead of 'else { if.", type = "warning" ) c(if_else_exit_lints, unnecessary_brace_lints, unnecessary_nested_if_lints, unnecessary_else_brace_lints) }) } lintr/R/with_id.R0000644000176200001440000000145514752731051013367 0ustar liggesusers#' Extract row by ID #' #' @describeIn ids_with_token #' Return the row of the `parsed_content` entry of the `[get_source_expressions]()` object. Typically used in #' conjunction with `ids_with_token` to iterate over rows containing desired tokens. #' #' @param id Integer. The index corresponding to the desired row #' of `parsed_content`. #' @return `with_id`: A data frame corresponding to the row(s) specified in `id`. #' @export with_id <- function(source_expression, id, source_file) { if (!missing(source_file)) { lintr_deprecated( what = "source_file", alternative = "source_expression", version = "3.0.0", type = "Argument", signal = "stop" ) } if (!is_lint_level(source_expression, "expression")) { return(data.frame()) } source_expression$parsed_content[id, ] } lintr/R/assignment_linter.R0000644000176200001440000001504514752731051015465 0ustar liggesusers#' Assignment linter #' #' Check that the specified operator is used for assignment. #' #' @param operator Character vector of valid assignment operators. Defaults to allowing `<-` and `<<-`; other valid #' options are `=`, `->`, `->>`, `%<>%`; use `"any"` to denote "allow all operators", in which case this linter only #' considers `allow_trailing` for generating lints. #' @param allow_cascading_assign (Deprecated) Logical, default `TRUE`. #' If `FALSE`, [`<<-`][base::assignOps] and `->>` are not allowed. #' @param allow_right_assign (Deprecated) Logical, default `FALSE`. If `TRUE`, `->` and `->>` are allowed. #' @param allow_trailing Logical, default `TRUE`. If `FALSE` then assignments aren't allowed at end of lines. #' @param allow_pipe_assign (Deprecated) Logical, default `FALSE`. If `TRUE`, magrittr's `%<>%` assignment is allowed. #' #' @examples #' # will produce lints #' lint( #' text = "x = mean(x)", #' linters = assignment_linter() #' ) #' #' code_lines <- "1 -> x\n2 ->> y" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = assignment_linter() #' ) #' #' lint( #' text = "x %<>% as.character()", #' linters = assignment_linter() #' ) #' #' lint( #' text = "x <- 1", #' linters = assignment_linter(operator = "=") #' ) #' #' # okay #' lint( #' text = "x <- mean(x)", #' linters = assignment_linter() #' ) #' #' code_lines <- "x <- 1\ny <<- 2" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = assignment_linter() #' ) #' #' # customizing using arguments #' code_lines <- "1 -> x\n2 ->> y" #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = assignment_linter(allow_right_assign = TRUE) #' ) #' #' lint( #' text = "x <<- 1", #' linters = assignment_linter(allow_cascading_assign = FALSE) #' ) #' #' writeLines("foo(bar = \n 1)") #' lint( #' text = "foo(bar = \n 1)", #' linters = assignment_linter(allow_trailing = FALSE) #' ) #' #' lint( #' text = "x %<>% as.character()", #' linters = assignment_linter(allow_pipe_assign = TRUE) #' ) #' #' lint( #' text = "x = 1", #' linters = assignment_linter(operator = "=") #' ) #' #' @evalRd rd_tags("assignment_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' - #' @export assignment_linter <- function(operator = c("<-", "<<-"), allow_cascading_assign = TRUE, allow_right_assign = FALSE, allow_trailing = TRUE, allow_pipe_assign = FALSE) { if (is.logical(operator)) { cli_abort(c( "'operator' should be a character vector but was logical.", i = "If you intended positional usage of allow_cascading_assign=, that is hard-deprecated." )) } if (!missing(allow_cascading_assign)) { lintr_deprecated("allow_cascading_assign", '"<<-" and/or "->>" in operator', version = "3.2.0", type = "Argument") operator <- drop_or_add(operator, "<<-", allow_cascading_assign) } if (!missing(allow_right_assign)) { lintr_deprecated("allow_right_assign", '"->" in operator', version = "3.2.0", type = "Argument") operator <- drop_or_add(operator, c("->", if (allow_cascading_assign) "->>"), allow_right_assign) } if (!missing(allow_pipe_assign)) { lintr_deprecated("allow_pipe_assign", '"%<>%" in operator', version = "3.2.0", type = "Argument") operator <- drop_or_add(operator, "%<>%", allow_pipe_assign) } all_operators <- c("<-", "=", "->", "<<-", "->>", "%<>%") if ("any" %in% operator) { operator <- all_operators } else { operator <- match.arg(operator, all_operators, several.ok = TRUE) } no_cascading <- !any(c("<<-", "->>") %in% operator) trailing_assign_xpath <- paste0( collapse = " | ", c( "//LEFT_ASSIGN", "//RIGHT_ASSIGN", "//EQ_ASSIGN", "//EQ_SUB", "//EQ_FORMALS", "//SPECIAL[text() = '%<>%']" ), "[@line1 < following-sibling::expr[1]/@line1]" ) op_xpath_parts <- c( if (!"=" %in% operator) "//EQ_ASSIGN", # -> and ->> are both 'RIGHT_ASSIGN' glue("//RIGHT_ASSIGN[{ xp_text_in_table(setdiff(c('->', '->>'), operator)) }]"), # <-, :=, and <<- are all 'LEFT_ASSIGN'; check the text if blocking <<-. # NB: := is not linted because of (1) its common usage in rlang/data.table and # (2) it's extremely uncommon as a normal assignment operator glue("//LEFT_ASSIGN[{ xp_text_in_table(setdiff(c('<-', '<<-'), operator)) }]"), if (!"%<>%" %in% operator) "//SPECIAL[text() = '%<>%']" ) if (!is.null(op_xpath_parts)) { # NB: Also used, essentially, in implicit_assignment_linter. Keep in sync. implicit_assignment_xpath <- " [not(parent::expr[ preceding-sibling::*[2][self::IF or self::WHILE] or parent::forcond or parent::expr/*[1][self::OP-LEFT-PAREN] ])] " op_xpath <- paste0(op_xpath_parts, implicit_assignment_xpath, collapse = " | ") } else { op_xpath <- NULL } Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content lints <- NULL if (!is.null(op_xpath)) { op_expr <- xml_find_all(xml, op_xpath) op_text <- xml_text(op_expr) op_lint_message_fmt <- rep( sprintf( "Use %s for assignment, not %%s.", if (length(operator) > 1L) paste("one of", toString(operator)) else operator ), length(op_text) ) if (no_cascading) { op_lint_message_fmt[op_text %in% c("<<-", "->>")] <- "Replace %s by assigning to a specific environment (with assign() or <-) to avoid hard-to-predict behavior." } op_lint_message_fmt[op_text == "%<>%"] <- "Avoid the assignment pipe %s; prefer pipes and assignment in separate steps." op_lint_message <- sprintf(op_lint_message_fmt, op_text) lints <- xml_nodes_to_lints(op_expr, source_expression, op_lint_message, type = "style") } if (!allow_trailing) { trailing_assign_expr <- xml_find_all(xml, trailing_assign_xpath) trailing_assign_text <- xml_text(trailing_assign_expr) trailing_assign_msg_fmt <- "Assignment %s should not be trailing at the end of a line." trailing_assign_msg <- sprintf(trailing_assign_msg_fmt, trailing_assign_text) lints <- c(lints, xml_nodes_to_lints(trailing_assign_expr, source_expression, trailing_assign_msg, type = "style") ) } lints }) } drop_or_add <- function(x, y, add) (if (add) union else setdiff)(x, y) lintr/R/with.R0000644000176200001440000002255014752731051012712 0ustar liggesusers#' Modify lintr defaults #' #' Modify a list of defaults by name, allowing for replacement, deletion and addition of new elements. #' #' @param ... arguments of elements to change. If unnamed, the argument is automatically named. #' If the named argument already exists in `defaults`, it is replaced by the new element. #' If it does not exist, it is added. If the value is `NULL`, the element is removed. #' @param defaults named list of elements to modify. #' @return A modified list of elements, sorted by name. To achieve this sort in a platform-independent way, two #' transformations are applied to the names: (1) replace `_` with `0` and (2) convert [tolower()]. #' #' @seealso #' - [linters_with_defaults] for basing off lintr's set of default linters. #' - [all_linters] for basing off all available linters in lintr. #' - [linters_with_tags] for basing off tags attached to linters, possibly across multiple packages. #' - [available_linters] to get a data frame of available linters. #' - [linters] for a complete list of linters available in lintr. #' #' @examples #' # custom list of undesirable functions: #' # remove `sapply` (using `NULL`) #' # add `cat` (with an accompanying message), #' # add `print` (unnamed, i.e. with no accompanying message) #' # add `source` (as taken from `all_undesirable_functions`) #' my_undesirable_functions <- modify_defaults( #' defaults = default_undesirable_functions, #' sapply = NULL, "cat" = "No cat allowed", "print", all_undesirable_functions[["source"]] #' ) #' #' # list names of functions specified as undesirable #' names(my_undesirable_functions) #' @export modify_defaults <- function(defaults, ...) { if (missing(defaults)) { cli_abort("{.arg defaults} is a required argument, but is missing.") } if (!is.list(defaults) || !all(nzchar(names2(defaults)))) { cli_abort("{.arg defaults} must be a named list, not {.obj_type_friendly {defaults}}.") } vals <- list(...) nms <- names2(vals) missing_index <- !nzchar(nms, keepNA = TRUE) if (any(missing_index)) { nms[missing_index] <- guess_names(..., missing_index = missing_index) } to_null <- vapply(vals, is.null, logical(1L)) if (!all(nms[to_null] %in% names(defaults))) { bad_nms <- setdiff(nms[to_null], names(defaults)) # nolint: object_usage_linter. TODO(#2252). cli_warn(c( i = "Trying to remove {.field {bad_nms}}, which {?is/are} not in {.arg defaults}." )) } is.na(vals) <- nms == vals defaults[nms] <- vals res <- defaults[!vapply(defaults, is.null, logical(1L))] res <- res[platform_independent_order(names(res))] res } #' Create a tag-based linter configuration #' #' Make a new list based on all linters provided by `packages` and tagged with `tags`. #' The result of this function is meant to be passed to the `linters` argument of `lint()`, #' or to be put in your configuration file. #' #' @param ... Arguments of elements to change. If unnamed, the argument is automatically named. #' If the named argument already exists in the list of linters, it is replaced by the new element. #' If it does not exist, it is added. If the value is `NULL`, the linter is removed. #' @inheritParams available_linters #' #' @return A modified list of linters. #' @seealso #' - [linters_with_defaults] for basing off lintr's set of default linters. #' - [all_linters] for basing off all available linters in lintr. #' - [available_linters] to get a data frame of available linters. #' - [linters] for a complete list of linters available in lintr. #' #' @examples #' # `linters_with_defaults()` and `linters_with_tags("default")` are the same: #' all.equal(linters_with_defaults(), linters_with_tags("default")) #' #' # Get all linters useful for package development #' linters <- linters_with_tags(tags = c("package_development", "style")) #' names(linters) #' #' # Get all linters tagged as "default" from lintr and mypkg #' if (FALSE) { #' linters_with_tags("default", packages = c("lintr", "mypkg")) #' } #' @export linters_with_tags <- function(tags, ..., packages = "lintr", exclude_tags = "deprecated") { if (!is.character(tags) && !is.null(tags)) { cli_abort("{.arg tags} must be a character vector, or {.code NULL}, not {.obj_type_friendly {tags}}.") } tagged_linters <- list() for (package in packages) { pkg_ns <- loadNamespace(package) ns_exports <- getNamespaceExports(pkg_ns) available <- available_linters(packages = package, tags = tags, exclude_tags = exclude_tags) if (nrow(available) > 0L) { if (!all(available$linter %in% ns_exports)) { missing_linters <- setdiff(available$linter, ns_exports) # nolint: object_usage_linter. TODO(#2252). cli_abort(c( x = "Can't find linters {.fn {missing_linters}}.", i = "These are advertised by {.fn available_linters}, but are not exported by package {.pkg {package}}." )) } linter_factories <- mget(available$linter, envir = pkg_ns) linters <- Map( call_linter_factory, linter_factory = linter_factories, linter_name = names(linter_factories), MoreArgs = list(package = package) ) tagged_linters <- c(tagged_linters, linters) } } modify_defaults(..., defaults = tagged_linters) } #' Create a linter configuration based on all available linters #' #' @inheritParams linters_with_tags #' #' @examples #' names(all_linters()) #' #' @seealso #' - [linters_with_defaults] for basing off lintr's set of default linters. #' - [linters_with_tags] for basing off tags attached to linters, possibly across multiple packages. #' - [available_linters] to get a data frame of available linters. #' - [linters] for a complete list of linters available in lintr. #' @export all_linters <- function(..., packages = "lintr") { linters_with_tags(tags = NULL, packages = packages, ...) } #' Create a linter configuration based on defaults #' #' Make a new list based on \pkg{lintr}'s default linters. #' The result of this function is meant to be passed to the `linters` argument of `lint()`, #' or to be put in your configuration file. #' #' @param defaults Default list of linters to modify. Must be named. #' @inheritParams linters_with_tags #' @examples #' # When using interactively you will usually pass the result onto `lint` or `lint_package()` #' f <- tempfile() #' writeLines("my_slightly_long_variable_name <- 2.3", f) #' lint(f, linters = linters_with_defaults(line_length_linter = line_length_linter(120L))) #' unlink(f) #' #' # the default linter list with a different line length cutoff #' my_linters <- linters_with_defaults(line_length_linter = line_length_linter(120L)) #' #' # omit the argument name if you are just using different arguments #' my_linters <- linters_with_defaults(defaults = my_linters, object_name_linter("camelCase")) #' #' # remove assignment checks (with NULL), add absolute path checks #' my_linters <- linters_with_defaults( #' defaults = my_linters, #' assignment_linter = NULL, #' absolute_path_linter() #' ) #' #' # checking the included linters #' names(my_linters) #' #' @seealso #' - [linters_with_tags] for basing off tags attached to linters, possibly across multiple packages. #' - [all_linters] for basing off all available linters in lintr. #' - [available_linters] to get a data frame of available linters. #' - [linters] for a complete list of linters available in lintr. #' @export linters_with_defaults <- function(..., defaults = default_linters) { dots <- list(...) if (missing(defaults) && "default" %in% names(dots)) { cli_warn(c( x = " {.arg default} is not an argument to {.help [{.fn linters_with_defaults}](lintr::linters_with_defaults)}. ", i = "Did you mean {.arg defaults}?", # make message more subtle cli::col_silver("This warning will be removed when {.fun with_defaults} is fully deprecated.") )) defaults <- dots$default nms <- names2(dots) missing_index <- !nzchar(nms, keepNA = TRUE) if (any(missing_index)) { names(dots)[missing_index] <- guess_names(..., missing_index = missing_index) } dots$default <- NULL dots <- c(dots, list(defaults = defaults)) return(do.call(modify_defaults, dots)) } modify_defaults(..., defaults = defaults) } #' @rdname lintr-deprecated #' @export with_defaults <- function(..., default = default_linters) { lintr_deprecated("with_defaults", "linters_with_defaults or modify_defaults", "3.0.0", signal = "stop") } #' @keywords internal #' @noRd call_linter_factory <- function(linter_factory, linter_name, package) { linter <- tryCatch( linter_factory(), error = function(e) { cli_abort( "Could not create linter with {.fun {package}::{linter_name}}.", parent = e ) } ) # Otherwise, all linters would be called "linter_factory". attr(linter, "name") <- linter_name linter } #' @keywords internal #' @noRd guess_names <- function(..., missing_index) { arguments <- as.character(eval(substitute(alist(...)[missing_index]))) # foo_linter(x=1) => "foo" # var[["foo"]] => "foo" # strip call: foo_linter(x=1) --> foo_linter # NB: Very long input might have newlines which are not caught # by . in a perl regex; see #774 arguments <- re_substitutes(arguments, rex("(", anything), "", options = "s") # strip extractors: pkg::foo_linter, var[["foo_linter"]] --> foo_linter arguments <- re_substitutes(arguments, rex(start, anything, '["' %or% "::"), "") re_substitutes(arguments, rex('"]', anything, end), "") } lintr/R/spaces_left_parentheses_linter.R0000644000176200001440000000575714752731051020217 0ustar liggesusers#' Spaces before parentheses linter #' #' Check that all left parentheses have a space before them unless they are in a function call. #' #' @examples #' # will produce lints #' lint( #' text = "if(TRUE) x else y", #' linters = spaces_left_parentheses_linter() #' ) #' #' # okay #' lint( #' text = "if (TRUE) x else y", #' linters = spaces_left_parentheses_linter() #' ) #' #' @evalRd rd_tags("spaces_left_parentheses_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' - [function_left_parentheses_linter()] #' @export spaces_left_parentheses_linter <- function() { file_level_xpath <- "//OP-LEFT-PAREN[@start - 1 = ancestor::expr/preceding-sibling::OP-SEMICOLON/@end]" # apply the lint by requiring a gap in three cases: # (1) if/while loop conditions, e.g. 'if(x>2) { }', including 'else(' # (2) for loop conditions, e.g. 'for(i in 1:5) { }' [very similar to (1) in code but different in XML] # (3) non-unary infix operators, e.g. 'x&(y | z)', and including commas, braces, e.g. 'c(a,(a+b))' # -1 on LHS because, when RHS matches nothing, +1 tricks the condition into returning true... # while @start will always be there, the @end may not be. if_while_cond <- "@start - 1 = preceding-sibling::*[self::IF or self::WHILE]/@end" for_cond <- "@start - 1 = parent::forcond/preceding-sibling::FOR/@end" # see infix_spaces_linter.R; preceding-sibling::* is needed for unary operators where '-(a)' is ok unary_nodes <- infix_metadata[infix_metadata$unary, "xml_tag"] unary_selves <- paste0("self::", unary_nodes, "[preceding-sibling::*]", collapse = " or ") binary_nodes <- c( infix_metadata[infix_metadata$low_precedence & !infix_metadata$unary, "xml_tag"], "OP-COMMA", "OP-LEFT-BRACE", "ELSE", "IN" ) binary_selves <- paste0("self::", binary_nodes, collapse = " or ") # preceding-symbol::* catches (1) function definitions and (2) function calls # ancestor::expr needed for nested RHS expressions, e.g. 'y1<-(abs(yn)>90)*1' infix_cond <- sprintf( "not(preceding-sibling::*) and (@start - 1 = ancestor::expr/preceding-sibling::*[%s]/@end)", paste(unary_selves, "or", binary_selves) ) expression_level_xpath <- sprintf( "//OP-LEFT-PAREN[(%s) or (%s) or (%s)]", if_while_cond, for_cond, infix_cond ) Linter(function(source_expression) { # else/if structure for trees that are missing XML content (both global & local) if (is_lint_level(source_expression, "file")) { # 'x = 1;(x + 2)' can't be detected from the expression-level tree xml <- source_expression$full_xml_parsed_content xpath <- file_level_xpath } else { xml <- source_expression$xml_parsed_content xpath <- expression_level_xpath } bad_paren <- xml_find_all(xml, xpath) xml_nodes_to_lints( bad_paren, source_expression, lint_message = "Place a space before left parenthesis, except in a function call.", type = "style" ) }) } lintr/R/expect_true_false_linter.R0000644000176200001440000000343514752731051017016 0ustar liggesusers#' Require usage of `expect_true(x)` over `expect_equal(x, TRUE)` #' #' [testthat::expect_true()] and [testthat::expect_false()] exist specifically #' for testing the `TRUE`/`FALSE` value of an object. #' [testthat::expect_equal()] and [testthat::expect_identical()] can also be #' used for such tests, but it is better to use the tailored function instead. #' #' @examples #' # will produce lints #' lint( #' text = "expect_equal(x, TRUE)", #' linters = expect_true_false_linter() #' ) #' #' lint( #' text = "expect_equal(x, FALSE)", #' linters = expect_true_false_linter() #' ) #' #' # okay #' lint( #' text = "expect_true(x)", #' linters = expect_true_false_linter() #' ) #' #' lint( #' text = "expect_false(x)", #' linters = expect_true_false_linter() #' ) #' #' @evalRd rd_tags("expect_true_false_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export expect_true_false_linter <- function() { xpath <- " following-sibling::expr[position() <= 2 and NUM_CONST[text() = 'TRUE' or text() = 'FALSE']] /parent::expr " Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(c("expect_equal", "expect_identical")) bad_expr <- xml_find_all(xml_calls, xpath) # NB: use expr/$node, not expr[$node], to exclude other things (especially ns:: parts of the call) call_name <- xp_call_name(bad_expr, condition = "starts-with(text(), 'expect_')") truth_value <- xml_find_chr(bad_expr, "string(expr/NUM_CONST[text() = 'TRUE' or text() = 'FALSE'])") lint_message <- sprintf( "expect_%s(x) is better than %s(x, %s)", tolower(truth_value), call_name, truth_value ) xml_nodes_to_lints(bad_expr, source_expression, lint_message, type = "warning") }) } lintr/R/regex_subset_linter.R0000644000176200001440000000644014752731051016013 0ustar liggesusers#' Require usage of direct methods for subsetting strings via regex #' #' Using `value = TRUE` in [grep()] returns the subset of the input that matches #' the pattern, e.g. `grep("[a-m]", letters, value = TRUE)` will return the #' first 13 elements (`a` through `m`). #' #' `letters[grep("[a-m]", letters)]` and `letters[grepl("[a-m]", letters)]` #' both return the same thing, but more circuitously and more verbosely. #' #' The `stringr` package also provides an even more readable alternative, #' namely `str_subset()`, which should be preferred to versions using #' `str_detect()` and `str_which()`. #' #' @section Exceptions: #' Note that `x[grep(pattern, x)]` and `grep(pattern, x, value = TRUE)` #' are not _completely_ interchangeable when `x` is not character #' (most commonly, when `x` is a factor), because the output of the #' latter will be a character vector while the former remains a factor. #' It still may be preferable to refactor such code, as it may be faster #' to match the pattern on `levels(x)` and use that to subset instead. #' #' @evalRd rd_tags("regex_subset_linter") #' #' @examples #' # will produce lints #' lint( #' text = "x[grep(pattern, x)]", #' linters = regex_subset_linter() #' ) #' #' lint( #' text = "x[stringr::str_which(x, pattern)]", #' linters = regex_subset_linter() #' ) #' #' # okay #' lint( #' text = "grep(pattern, x, value = TRUE)", #' linters = regex_subset_linter() #' ) #' #' lint( #' text = "stringr::str_subset(x, pattern)", #' linters = regex_subset_linter() #' ) #' #' @seealso [linters] for a complete list of linters available in lintr. #' @export regex_subset_linter <- function() { # parent::expr for LEFT_ASSIGN and RIGHT_ASSIGN, but, strangely, # parent::equal_assign for EQ_ASSIGN. So just use * as a catchall. # See https://www.w3.org/TR/1999/REC-xpath-19991116/#booleans; # equality of nodes is based on the string value of the nodes, which # is basically what we need, i.e., whatever expression comes in # [grepl(pattern, )] matches exactly, e.g. names(x)[grepl(ptn, names(x))]. xpath_fmt <- " parent::expr[ parent::expr[ OP-LEFT-BRACKET and not(parent::*[LEFT_ASSIGN or EQ_ASSIGN or RIGHT_ASSIGN]) ] and expr[position() = {arg_pos} ] = parent::expr/expr[1] ]" grep_xpath <- glue(xpath_fmt, arg_pos = 3L) stringr_xpath <- glue(xpath_fmt, arg_pos = 2L) Linter(linter_level = "expression", function(source_expression) { grep_calls <- source_expression$xml_find_function_calls(c("grepl", "grep")) grep_expr <- xml_find_all(grep_calls, grep_xpath) grep_lints <- xml_nodes_to_lints( grep_expr, source_expression = source_expression, lint_message = "Prefer grep(pattern, x, ..., value = TRUE) over x[grep(pattern, x, ...)] and x[grepl(pattern, x, ...)].", type = "warning" ) stringr_calls <- source_expression$xml_find_function_calls(c("str_detect", "str_which")) stringr_expr <- xml_find_all(stringr_calls, stringr_xpath) stringr_lints <- xml_nodes_to_lints( stringr_expr, source_expression = source_expression, lint_message = "Prefer stringr::str_subset(x, pattern) over x[str_detect(x, pattern)] and x[str_which(x, pattern)].", type = "warning" ) c(grep_lints, stringr_lints) }) } lintr/R/line_length_linter.R0000644000176200001440000000261514752731051015604 0ustar liggesusers#' Line length linter #' #' Check that the line length of both comments and code is less than `length`. #' #' @param length maximum line length allowed. Default is 80L (Hollerith limit). #' #' @examples #' # will produce lints #' lint( #' text = strrep("x", 23L), #' linters = line_length_linter(length = 20L) #' ) #' #' # okay #' lint( #' text = strrep("x", 21L), #' linters = line_length_linter(length = 40L) #' ) #' #' @evalRd rd_tags("line_length_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export line_length_linter <- function(length = 80L) { general_msg <- paste("Lines should not be more than", length, "characters.") Linter(linter_level = "file", function(source_expression) { # Only go over complete file line_lengths <- nchar(source_expression$file_lines) long_lines <- which(line_lengths > length) Map( function(long_line, line_length) { Lint( filename = source_expression$filename, line_number = long_line, column_number = length + 1L, type = "style", message = paste(general_msg, "This line is", line_length, "characters."), line = source_expression$file_lines[long_line], ranges = list(c(1L, line_length)) ) }, long_lines, line_lengths[long_lines] ) }) } lintr/R/list_comparison_linter.R0000644000176200001440000000364614752731051016526 0ustar liggesusers#' Block usage of comparison operators with known-list() functions like lapply #' #' Usage like `lapply(x, sum) > 10` is awkward because the list must first #' be coerced to a vector for comparison. A function like [vapply()] #' should be preferred. #' #' @examples #' # will produce lints #' lint( #' text = "lapply(x, sum) > 10", #' linters = list_comparison_linter() #' ) #' #' # okay #' lint( #' text = "unlist(lapply(x, sum)) > 10", #' linters = list_comparison_linter() #' ) #' #' @evalRd rd_tags("list_comparison_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export list_comparison_linter <- function() { list_mapper_alternatives <- c( lapply = "vapply(x, FUN, character(1L))", map = "map_chr(x, FUN)", Map = "mapply()", .mapply = "mapply()" ) # NB: anchor to the comparison expr so that we can easily include the comparator # in the lint message. xpath <- glue(" parent::expr /parent::expr[{ xp_or(infix_metadata$xml_tag[infix_metadata$comparator]) }] ") Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(names(list_mapper_alternatives)) bad_expr <- xml_find_all(xml_calls, xpath) list_mapper <- xp_call_name(bad_expr, depth = 2L) vector_mapper <- list_mapper_alternatives[list_mapper] # we are at `x ? y` in which the comparator ? comes 2nd comparator <- xml_find_chr(bad_expr, "string(*[2])") lint_message <- as.character(glue( "The output of {list_mapper}(), a list(), is being ", "coerced for comparison by `{comparator}`. ", "Instead, use a mapper that generates a vector with the correct type ", "directly, for example {vector_mapper} if the output is a string." )) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = lint_message, type = "warning" ) }) } lintr/R/settings.R0000644000176200001440000002372214752731051013601 0ustar liggesusers#' Read lintr settings #' #' Lintr searches for settings for a given source file in the following order: #' 1. options defined as `linter.setting`. #' 2. `linter_file` in the same directory #' 3. `linter_file` in the project directory #' 4. `linter_file` in the user home directory #' 5. [default_settings()] #' #' The default linter_file name is `.lintr` but it can be changed with option `lintr.linter_file` #' or the environment variable `R_LINTR_LINTER_FILE` #' This file is a DCF file, see [base::read.dcf()] for details. #' Here is an example of a `.lintr` file: #' #' ``` #' linters: linters_with_defaults( #' any_duplicated_linter(), #' any_is_na_linter(), #' backport_linter("oldrel-4", except = c("R_user_dir", "str2lang")), #' line_length_linter(120L), #' missing_argument_linter(), #' unnecessary_concatenation_linter(allow_single_expression = FALSE), #' yoda_test_linter() #' ) #' exclusions: list( #' "inst/doc/creating_linters.R" = 1, #' "inst/example/bad.R", #' "tests/testthat/default_linter_testcode.R", #' "tests/testthat/dummy_packages" #' ) #' ``` #' #' Experimentally, we also support keeping the config in a plain R file. By default we look for #' a file named `.lintr.R` (in the same directories where we search for `.lintr`). #' We are still deciding the future of config support in lintr, so user feedback is welcome. #' The advantage of R is that it maps more closely to how the configs are actually stored, #' whereas the DCF approach requires somewhat awkward formatting of parseable R code within #' valid DCF key-value pairs. The main disadvantage of the R file is it might be _too_ flexible, #' with users tempted to write configs with side effects causing hard-to-detect bugs or # " otherwise "abusing" the ability to evaluate generic R code. Other recursive key-value stores #' like YAML could work, but require new dependencies and are harder to parse #' both programmatically and visually. #' Here is an example of a `.lintr.R` file: #' #' ```r #' linters <- linters_with_defaults( #' any_duplicated_linter(), #' any_is_na_linter(), #' backport_linter("oldrel-4", except = c("R_user_dir", "str2lang")), #' line_length_linter(120L), #' missing_argument_linter(), #' unnecessary_concatenation_linter(allow_single_expression = FALSE), #' yoda_test_linter() #' ) #' exclusions <- list( #' "inst/doc/creating_linters.R" = 1, #' "inst/example/bad.R", #' "tests/testthat/default_linter_testcode.R", #' "tests/testthat/dummy_packages" #' ) #' ``` #' #' @param filename Source file to be linted. #' @param call Passed to malformed to ensure linear trace. read_settings <- function(filename, call = parent.frame()) { reset_settings() config_file <- find_config(filename) default_encoding <- find_default_encoding(filename) if (!is.null(default_encoding)) { # Locally override the default for encoding if we found a smart default default_settings[["encoding"]] <- default_encoding } config <- read_config_file(config_file, call = call) validate_config_file(config, config_file, default_settings) for (setting in names(default_settings)) { value <- get_setting(setting, config, default_settings) if (setting == "exclusions") { if (!is.null(config_file)) { root <- dirname(config_file) } else { root <- getwd() } value <- normalize_exclusions(value, root = root) } settings[[setting]] <- value } } #' @param call Passed to malformed to ensure linear trace. #' @noRd read_config_file <- function(config_file, call = parent.frame()) { if (is.null(config_file)) { return(NULL) } # clickable link for eventual error messages. malformed_file <- link_config_file(config_file) # nolint: object_usage_linter. TODO(#2252). config <- new.env() if (endsWith(config_file, ".R")) { load_config <- function(file) sys.source(file, config, keep.source = FALSE, keep.parse.data = FALSE) malformed <- function(e) { cli_abort( "Malformed config file ({malformed_file}), ensure it is valid R syntax.", parent = e, call = call ) } } else { load_config <- function(file) { dcf_values <- read.dcf(file, all = TRUE) for (setting in names(dcf_values)) { parsed_setting <- withCallingHandlers( str2lang(dcf_values[[setting]]), error = function(e) { cli_abort( "Malformed config setting {.field {setting}}:", parent = e ) } ) setting_value <- withCallingHandlers( tryCatch( eval(parsed_setting), error = function(e) { cli_abort( "Error from config setting {.code {setting}}.", parent = e ) } ), warning = function(w) { cli_warn( "Warning from config setting {.code {setting}}.", parent = w ) invokeRestart("muffleWarning") } ) assign(setting, setting_value, envir = config) } } malformed <- function(e) { cli_abort( "Malformed config file ({malformed_file}):", parent = e, call = call ) } } withCallingHandlers( tryCatch( load_config(config_file), error = malformed ), warning = function(w) { cli::cli_warn( "Warning encountered while loading config:", parent = w ) invokeRestart("muffleWarning") } ) config } validate_config_file <- function(config, config_file, defaults) { matched <- names(config) %in% names(defaults) if (!all(matched)) { unused_settings <- names(config)[!matched] # nolint: object_usage_linter. TODO(#2252). config_link <- link_config_file(config_file) # nolint: object_usage_linter. TODO(#2252). cli_warn("Found unused settings in config file ({config_link}): {.field unused_settings}") } validate_regex(config, c("exclude", "exclude_next", "exclude_start", "exclude_end", "exclude_linter", "exclude_linter_sep") ) validate_character_string(config, c("encoding", "cache_directory", "comment_token")) validate_true_false(config, c("comment_bot", "error_on_lint")) validate_linters(config$linters) validate_exclusions(config$exclusions) } is_character_string <- function(x) is.character(x) && length(x) == 1L && !is.na(x) # perl=TRUE matches rex::re_matches() is_valid_regex <- function(str) !inherits(tryCatch(grepl(str, "", perl = TRUE), condition = identity), "condition") is_single_regex <- function(x) is_character_string(x) && is_valid_regex(x) is_true_false <- function(x) is.logical(x) && length(x) == 1L && !is.na(x) validate_keys <- function(config, keys, test, what) { for (key in keys) { val <- config[[key]] if (is.null(val)) { next } if (!test(val)) { cli_abort(c( i = "Setting {.code {key}} should be {.strong {what}}.", x = "Instead, it is {.field {val}}." )) } } } validate_regex <- function(config, keys) { validate_keys(config, keys, is_single_regex, "a single regular expression") } validate_character_string <- function(config, keys) { validate_keys(config, keys, is_character_string, "a character string") } validate_true_false <- function(config, keys) { validate_keys(config, keys, is_true_false, "TRUE or FALSE") } validate_linters <- function(linters) { if (is.null(linters)) { return(invisible()) } is_linters <- vapply(linters, is_linter, logical(1L)) if (!all(is_linters)) { non_linters <- which(!is_linters) # nolint: object_usage_linter. TODO(#2252). cli_abort(c( i = "Setting {.arg linters} should be a list of linters.", x = "Found non-linters at elements: {.str {non_linters}}." )) } } validate_exclusions <- function(exclusions) { if (is.null(exclusions)) { return(invisible()) } exclusion_names <- names2(exclusions) has_names <- nzchar(exclusion_names) unnamed_is_string <- vapply(exclusions[!has_names], function(x) is.character(x) && length(x) == 1L && !is.na(x), logical(1L)) if (!all(unnamed_is_string)) { problematic_entries <- which(!has_names)[!unnamed_is_string] # nolint: object_usage_linter. TODO(#2252). cli_abort(c( i = "Unnamed entries of setting {.arg exclusions} should be strings naming files or directories.", x = "Check exclusions: {.str {problematic_entries}}." )) } for (ii in which(has_names)) validate_named_exclusion(exclusions, ii) } validate_named_exclusion <- function(exclusions, idx) { entry <- exclusions[[idx]] if (is.list(entry)) { valid_entry <- vapply(entry, function(x) is.numeric(x) && !anyNA(x), logical(1L)) } else { valid_entry <- is.numeric(entry) && !anyNA(entry) } if (!all(valid_entry)) { cli_abort(c( i = "Named entries of setting {.arg exclusions} should designate line numbers for exclusion.", x = "Check exclusions: {idx}." )) } } lintr_option <- function(setting, default = NULL) getOption(paste0("lintr.", setting), default) get_setting <- function(setting, config, defaults) { lintr_option(setting) %||% config[[setting]] %||% defaults[[setting]] } reset_settings <- function() list2env(default_settings, envir = settings) find_default_encoding <- function(filename) { if (is.null(filename)) { return(NULL) } root_path <- find_package(filename, allow_rproj = TRUE) rproj_enc <- get_encoding_from_dcf(find_rproj_at(root_path)) if (!is.null(rproj_enc)) { return(rproj_enc) } rproj_enc } get_encoding_from_dcf <- function(file) { if (is.null(file)) { return(NULL) } encodings <- tryCatch( unname(drop(read.dcf(file, "Encoding"))), error = function(e) NULL, warning = function(e) NULL ) encodings <- encodings[!is.na(encodings)] if (length(encodings) > 0L) { return(encodings[1L]) } NULL } link_config_file <- function(path) { cli::style_hyperlink( cli::col_blue(basename(path)), paste0("file://", path) ) } lintr/R/empty_assignment_linter.R0000644000176200001440000000231414752731051016676 0ustar liggesusers#' Block assignment of `{}` #' #' Assignment of `{}` is the same as assignment of `NULL`; use the latter #' for clarity. Closely related: [unnecessary_concatenation_linter()]. #' #' @examples #' # will produce lints #' lint( #' text = "x <- {}", #' linters = empty_assignment_linter() #' ) #' #' writeLines("x = {\n}") #' lint( #' text = "x = {\n}", #' linters = empty_assignment_linter() #' ) #' #' # okay #' lint( #' text = "x <- { 3 + 4 }", #' linters = empty_assignment_linter() #' ) #' #' lint( #' text = "x <- NULL", #' linters = empty_assignment_linter() #' ) #' #' @evalRd rd_tags("empty_assignment_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export empty_assignment_linter <- make_linter_from_xpath( # for some reason, the parent in the `=` case is , not , hence parent::expr xpath = " //OP-LEFT-BRACE[following-sibling::*[1][self::OP-RIGHT-BRACE]] /parent::expr[ preceding-sibling::LEFT_ASSIGN or preceding-sibling::EQ_ASSIGN or following-sibling::RIGHT_ASSIGN ] /parent::* ", lint_message = "Assign NULL explicitly or, whenever possible, allocate the empty object with the right type and size." ) lintr/R/namespace_linter.R0000644000176200001440000001247714752731051015257 0ustar liggesusers#' Namespace linter #' #' Check for missing packages and symbols in namespace calls. #' Note that using `check_exports=TRUE` or `check_nonexports=TRUE` will load packages used in user code so it could #' potentially change the global state. #' #' @param check_exports Check if `symbol` is exported from `namespace` in `namespace::symbol` calls. #' @param check_nonexports Check if `symbol` exists in `namespace` in `namespace:::symbol` calls. #' #' @examples #' # will produce lints #' lint( #' text = "xyzxyz::sd(c(1, 2, 3))", #' linters = namespace_linter() #' ) #' #' lint( #' text = "stats::ssd(c(1, 2, 3))", #' linters = namespace_linter() #' ) #' #' # okay #' lint( #' text = "stats::sd(c(1, 2, 3))", #' linters = namespace_linter() #' ) #' #' lint( #' text = "stats::ssd(c(1, 2, 3))", #' linters = namespace_linter(check_exports = FALSE) #' ) #' #' lint( #' text = "stats:::ssd(c(1, 2, 3))", #' linters = namespace_linter(check_nonexports = FALSE) #' ) #' #' @evalRd rd_tags("namespace_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export namespace_linter <- function(check_exports = TRUE, check_nonexports = TRUE) { Linter(linter_level = "file", function(source_expression) { xml <- source_expression$full_xml_parsed_content ns_nodes <- xml_find_all(xml, "//NS_GET | //NS_GET_INT") if (length(ns_nodes) == 0L) { return(list()) } ## Case 1: pkg is uninstalled in pkg::foo package_nodes <- xml_find_all(ns_nodes, "preceding-sibling::*[1]") packages <- get_r_string(package_nodes) lints <- list() # run here, not in the factory, to allow for run- vs. "compile"-time differences in available packages installed_packages <- .packages(all.available = TRUE) installed <- packages %in% installed_packages if (!all(installed)) { lints <- c(lints, xml_nodes_to_lints( package_nodes[!installed], source_expression = source_expression, lint_message = sprintf("Package '%s' is not installed.", packages[!installed]), type = "warning" )) ns_nodes <- ns_nodes[installed] packages <- packages[installed] package_nodes <- package_nodes[installed] } if (!check_exports && !check_nonexports) { return(lints) } ## Case 2/3/4: problems with foo in pkg::foo / pkg:::foo # run here, not in the factory, to allow for run- vs. "compile"-time differences in package structure namespaces <- lapply(packages, function(package) tryCatch(getNamespace(package), error = identity)) failed_namespace <- vapply(namespaces, inherits, "condition", FUN.VALUE = logical(1L)) # nocov start if (any(failed_namespace)) { cli_abort_internal("Failed to retrieve namespaces for one or more of the packages used with `::` or `:::`. ") } # nocov end ns_get <- xml_text(ns_nodes) == "::" symbol_nodes <- xml_find_all(ns_nodes, "following-sibling::*[1]") symbols <- get_r_string(symbol_nodes) if (check_nonexports) { lints <- c(lints, build_ns_get_int_lints( packages[!ns_get], symbols[!ns_get], symbol_nodes[!ns_get], namespaces[!ns_get], source_expression )) } if (check_exports) { lints <- c(lints, build_ns_get_lints( packages[ns_get], symbols[ns_get], symbol_nodes[ns_get], namespaces[ns_get], source_expression )) } lints }) } namespace_symbols <- function(ns, exported = TRUE) { if (exported) { c(getNamespaceExports(ns), names(.getNamespaceInfo(ns, "lazydata"))) } else { ls(ns, all.names = TRUE) } } is_in_pkg <- function(symbols, namespaces, exported = TRUE) { vapply( seq_along(symbols), function(ii) symbols[[ii]] %in% namespace_symbols(namespaces[[ii]], exported = exported), logical(1L) ) } build_ns_get_int_lints <- function(packages, symbols, symbol_nodes, namespaces, source_expression) { ## Case 2: foo does not exist in pkg:::foo non_symbols <- !is_in_pkg(symbols, namespaces, exported = FALSE) non_symbols_lints <- xml_nodes_to_lints( symbol_nodes[non_symbols], source_expression = source_expression, lint_message = sprintf("'%s' does not exist in {%s}.", symbols[non_symbols], packages[non_symbols]), type = "warning" ) packages <- packages[!non_symbols] symbols <- symbols[!non_symbols] symbol_nodes <- symbol_nodes[!non_symbols] namespaces <- namespaces[!non_symbols] ## Case 3: foo is already exported pkg:::foo exported <- is_in_pkg(symbols, namespaces) exported_lints <- xml_nodes_to_lints( symbol_nodes[exported], source_expression = source_expression, lint_message = sprintf("Don't use `:::` to access %s, which is exported from %s.", symbols[exported], packages[exported]), type = "warning" ) c(non_symbols_lints, exported_lints) } build_ns_get_lints <- function(packages, symbols, symbol_nodes, namespaces, source_expression) { # strip backticked symbols; `%>%` is the same as %>% (#1752). symbols <- gsub("^`(.*)`$", "\\1", symbols) ## Case 4: foo is not an export in pkg::foo unexported <- !is_in_pkg(symbols, namespaces) xml_nodes_to_lints( symbol_nodes[unexported], source_expression = source_expression, lint_message = sprintf("'%s' is not exported from {%s}.", symbols[unexported], packages[unexported]), type = "warning" ) } lintr/R/source_utils.R0000644000176200001440000000216014752731051014452 0ustar liggesusers#' Build the `xml_find_function_calls()` helper for a source expression #' #' @param xml The XML parse tree as an XML object (`xml_parsed_content` or `full_xml_parsed_content`) #' #' @return A fast function to query the common XPath expression #' `xml_find_all(xml, glue::glue("//SYMBOL_FUNCTION_CALL[text() = '{function_names[1]}' or ...]/parent::expr"))`, #' or, using the internal function `xp_text_in_table()`, #' `xml_find_all(xml, glue::glue("//SYMBOL_FUNCTION_CALL[{ xp_text_in_table(function_names) }]/parent::expr"))`, #' i.e., the `parent::expr` of the `SYMBOL_FUNCTION_CALL` node corresponding to given function names. #' #' @noRd build_xml_find_function_calls <- function(xml) { function_call_cache <- xml_find_all(xml, "//SYMBOL_FUNCTION_CALL/parent::expr") names(function_call_cache) <- get_r_string(function_call_cache, "SYMBOL_FUNCTION_CALL") function(function_names, keep_names = FALSE) { if (is.null(function_names)) { res <- function_call_cache } else { res <- function_call_cache[names(function_call_cache) %in% function_names] } if (keep_names) res else unname(res) } } lintr/R/condition_message_linter.R0000644000176200001440000000506414752731051017007 0ustar liggesusers#' Block usage of `paste()` and `paste0()` with messaging functions using `...` #' #' @description #' This linter discourages combining condition functions like [stop()] with string concatenation #' functions [paste()] and [paste0()]. This is because #' #' - `stop(paste0(...))` is redundant as it is exactly equivalent to `stop(...)` #' - `stop(paste(...))` is similarly equivalent to `stop(...)` with separators (see examples) #' #' The same applies to the other default condition functions as well, i.e., [warning()], [message()], #' and [packageStartupMessage()]. #' #' @examples #' # will produce lints #' lint( #' text = 'stop(paste("a string", "another"))', #' linters = condition_message_linter() #' ) #' #' lint( #' text = 'warning(paste0("a string", " another"))', #' linters = condition_message_linter() #' ) #' #' # okay #' lint( #' text = 'stop("a string", " another")', #' linters = condition_message_linter() #' ) #' #' lint( #' text = 'warning("a string", " another")', #' linters = condition_message_linter() #' ) #' #' lint( #' text = 'warning(paste("a string", "another", sep = "-"))', #' linters = condition_message_linter() #' ) #' #' @evalRd rd_tags("condition_message_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export condition_message_linter <- function() { translators <- c("packageStartupMessage", "message", "warning", "stop") xpath <- glue(" self::*[SYMBOL_FUNCTION_CALL[ not(preceding-sibling::OP-DOLLAR or preceding-sibling::OP-AT) ]] /following-sibling::expr[ expr[1][SYMBOL_FUNCTION_CALL[text() = 'paste' or text() = 'paste0']] and not(SYMBOL_SUB[text() = 'collapse']) ] /parent::expr ") Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(translators) bad_expr <- xml_find_all(xml_calls, xpath) sep_value <- get_r_string(bad_expr, xpath = "./expr/SYMBOL_SUB[text() = 'sep']/following-sibling::expr/STR_CONST") bad_expr <- bad_expr[is.na(sep_value) | sep_value %in% c("", " ")] outer_call <- xp_call_name(bad_expr) inner_call <- xp_call_name(bad_expr, depth = 2L) lint_message <- paste( "Don't use", inner_call, "to build", outer_call, "strings.", "Instead use the fact that these functions build condition message strings from their input", '(using "" as a separator). For translatable strings, prefer using gettextf().' ) xml_nodes_to_lints(bad_expr, source_expression = source_expression, lint_message = lint_message, type = "warning") }) } lintr/R/object_usage_linter.R0000644000176200001440000002077414752731051015754 0ustar liggesusers#' Object usage linter #' #' Check that closures have the proper usage using [codetools::checkUsage()]. #' Note that this runs [base::eval()] on the code, so **do not use with untrusted code**. #' #' @param interpret_glue If `TRUE`, interpret [glue::glue()] calls to avoid false positives caused by local variables #' which are only used in a glue expression. #' @param skip_with A logical. If `TRUE` (default), code in `with()` expressions #' will be skipped. This argument will be passed to `skipWith` argument of #' `codetools::checkUsage()`. #' #' @examples #' # will produce lints #' lint( #' text = "foo <- function() { x <- 1 }", #' linters = object_usage_linter() #' ) #' #' # okay #' lint( #' text = "foo <- function(x) { x <- 1 }", #' linters = object_usage_linter() #' ) #' #' lint( #' text = "foo <- function() { x <- 1; return(x) }", #' linters = object_usage_linter() #' ) #' @evalRd rd_linters("package_development") #' @seealso [linters] for a complete list of linters available in lintr. #' @export object_usage_linter <- function(interpret_glue = TRUE, skip_with = TRUE) { # NB: difference across R versions in how EQ_ASSIGN is represented in the AST # (under or ) # NB: the repeated expr[2][FUNCTION] XPath has no performance impact, so the different direct assignment XPaths are # split for better readability, see PR#1197 # TODO(#1106): use //[...] to capture assignments in more scopes xpath_function_assignment <- " expr[LEFT_ASSIGN or EQ_ASSIGN]/expr[2][FUNCTION or OP-LAMBDA] | expr_or_assign_or_help[EQ_ASSIGN]/expr[2][FUNCTION or OP-LAMBDA] | equal_assign[EQ_ASSIGN]/expr[2][FUNCTION or OP-LAMBDA] | //SYMBOL_FUNCTION_CALL[text() = 'assign']/parent::expr/following-sibling::expr[2][FUNCTION or OP-LAMBDA] | //SYMBOL_FUNCTION_CALL[text() = 'setMethod']/parent::expr/following-sibling::expr[3][FUNCTION or OP-LAMBDA] " # not all instances of linted symbols are potential sources for the observed violations -- see #1914 symbol_exclude_cond <- "preceding-sibling::OP-DOLLAR or preceding-sibling::OP-AT or ancestor::expr[OP-TILDE]" xpath_culprit_symbol <- glue(" descendant::SYMBOL[not( {symbol_exclude_cond} )] | descendant::SYMBOL_FUNCTION_CALL[not( {symbol_exclude_cond} )] | descendant::SPECIAL | descendant::LEFT_ASSIGN[text() = ':='] ") Linter(linter_level = "file", function(source_expression) { pkg_name <- pkg_name(find_package(dirname(source_expression$filename))) declared_globals <- try_silently(globalVariables(package = pkg_name %||% globalenv())) xml <- source_expression$full_xml_parsed_content # run the following at run-time, not "compile" time to allow package structure to change env <- make_check_env(pkg_name, xml) fun_assignments <- xml_find_all(xml, xpath_function_assignment) lapply(fun_assignments, function(fun_assignment) { code <- get_content(lines = source_expression$content, fun_assignment) fun <- try_silently(eval( envir = env, parse( text = code, keep.source = TRUE ) )) if (inherits(fun, "try-error")) { return() } known_used_symbols <- extract_glued_symbols(fun_assignment, interpret_glue = interpret_glue) res <- parse_check_usage( fun, known_used_symbols = known_used_symbols, declared_globals = declared_globals, start_line = as.integer(xml_attr(fun_assignment, "line1")), end_line = as.integer(xml_attr(fun_assignment, "line2")), skip_with = skip_with ) res$name <- re_substitutes(res$name, rex("<-"), "") lintable_symbols <- xml_find_all(fun_assignment, xpath_culprit_symbol) lintable_symbol_names <- gsub("^`|`$", "", xml_text(lintable_symbols)) lintable_symbol_lines <- as.integer(xml_attr(lintable_symbols, "line1")) matched_symbol <- vapply( seq_len(nrow(res)), function(i) { match( TRUE, lintable_symbol_names == res$name[i] & lintable_symbol_lines >= res$line1[i] & lintable_symbol_lines <= res$line2[i] ) }, integer(1L) ) nodes <- unclass(lintable_symbols)[matched_symbol] # fallback to line based matching if no symbol is found missing_symbol <- is.na(matched_symbol) nodes[missing_symbol] <- lapply(which(missing_symbol), function(i) { line_based_match <- xml_find_first( fun_assignment, glue::glue_data(res[i, ], "descendant::expr[@line1 = {line1} and @line2 = {line2}]") ) if (is.na(line_based_match)) fun_assignment else line_based_match }) xml_nodes_to_lints(nodes, source_expression = source_expression, lint_message = res$message, type = "warning") }) }) } make_check_env <- function(pkg_name, xml) { if (!is.null(pkg_name)) { parent_env <- try_silently(getNamespace(pkg_name)) } if (is.null(pkg_name) || inherits(parent_env, "try-error")) { parent_env <- globalenv() } env <- new.env(parent = parent_env) symbols <- c( get_assignment_symbols(xml), get_imported_symbols(xml) ) # Just assign them an empty function for (symbol in symbols) { assign(symbol, function(...) invisible(), envir = env) } env } get_assignment_symbols <- function(xml) { get_r_string(xml_find_all( xml, " expr[LEFT_ASSIGN or EQ_ASSIGN]/expr[1]/SYMBOL[1] | expr[RIGHT_ASSIGN]/expr[2]/SYMBOL[1] | equal_assign/expr[1]/SYMBOL[1] | expr_or_assign_or_help/expr[1]/SYMBOL[1] | expr[expr[1][SYMBOL_FUNCTION_CALL/text()='assign']]/expr[2]/* | expr[expr[1][SYMBOL_FUNCTION_CALL/text()='setMethod']]/expr[2]/* " )) } get_check_usage_results <- function(expression, known_used_symbols, declared_globals, skip_with) { report_env <- new.env(parent = emptyenv()) report_env$vals <- character() report <- function(x) report_env$vals <- c(report_env$vals, x) old <- options(useFancyQuotes = FALSE) on.exit(options(old)) try( codetools::checkUsage( expression, report = report, suppressLocalUnused = known_used_symbols, suppressUndefined = declared_globals, skipWith = skip_with ) ) report_env$vals } parse_check_usage <- function(expression, known_used_symbols = character(), declared_globals = character(), start_line = 1L, end_line = 1L, skip_with = TRUE) { vals <- get_check_usage_results(expression, known_used_symbols, declared_globals, skip_with) function_name <- rex(anything, ": ") line_info <- rex( " ", "(", capture(name = "path", non_spaces), ":", capture(name = "line1", digits), maybe("-", capture(name = "line2", digits)), ")" ) res <- re_matches( vals, rex( function_name, capture( name = "message", zero_or_more(any, type = "lazy"), maybe( "'", capture(name = "name", anything), "'", zero_or_more(any, type = "lazy") ) ), or(line_info, end) ) ) # nocov start is_missing <- is.na(res$message) if (any(is_missing)) { # TODO(#2474): Remove this. missing_msg <- vals[is_missing][[1L]] # nolint: object_usage_linter. TODO(#2252). cli_warn(c( x = "Couldn't parse usage message {.str {missing_msg}}. Ignoring {.val {sum(is_missing)}} usage warnings.", i = "Please report a possible bug at {.url https://github.com/r-lib/lintr/issues}." )) } # nocov end res <- res[!is_missing, ] res$line1 <- ifelse( nzchar(res$line1), as.integer(res$line1) + start_line - 1L, NA_integer_ ) res$line2 <- ifelse( nzchar(res$line2), as.integer(res$line2) + start_line - 1L, res$line1 ) res$line1[is.na(res$line1)] <- start_line res$line2[is.na(res$line2)] <- end_line res } get_imported_symbols <- function(xml) { import_exprs_xpath <- " //SYMBOL_FUNCTION_CALL[text() = 'library' or text() = 'require'] /parent::expr /parent::expr[ not(SYMBOL_SUB[ text() = 'character.only' and following-sibling::expr[1][NUM_CONST[text() = 'TRUE'] or SYMBOL[text() = 'T']] ]) or expr[2][STR_CONST] ] /expr[STR_CONST or SYMBOL][1] " import_exprs <- xml_find_all(xml, import_exprs_xpath) imported_pkgs <- get_r_string(import_exprs) unlist(lapply(imported_pkgs, function(pkg) { tryCatch( getNamespaceExports(pkg), error = function(e) character() ) })) } lintr/R/expect_not_linter.R0000644000176200001440000000174714752731051015471 0ustar liggesusers#' Require usage of `expect_false(x)` over `expect_true(!x)` #' #' [testthat::expect_false()] exists specifically for testing that an output is #' `FALSE`. [testthat::expect_true()] can also be used for such tests by #' negating the output, but it is better to use the tailored function instead. #' The reverse is also true -- use `expect_false(A)` instead of #' `expect_true(!A)`. #' #' @examples #' # will produce lints #' lint( #' text = "expect_true(!x)", #' linters = expect_not_linter() #' ) #' #' # okay #' lint( #' text = "expect_false(x)", #' linters = expect_not_linter() #' ) #' #' @evalRd rd_tags("expect_not_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export expect_not_linter <- make_linter_from_function_xpath( function_names = c("expect_true", "expect_false"), xpath = " following-sibling::expr[OP-EXCLAMATION] /parent::expr ", lint_message = "expect_false(x) is better than expect_true(!x), and vice versa." ) lintr/R/yoda_test_linter.R0000644000176200001440000000473014752731051015307 0ustar liggesusers#' Block obvious "yoda tests" #' #' Yoda tests use `(expected, actual)` instead of the more common `(actual, expected)`. #' This is not always possible to detect statically; this linter focuses on #' the simple case of testing an expression against a literal value, e.g. #' `(1L, foo(x))` should be `(foo(x), 1L)`. #' #' @examples #' # will produce lints #' lint( #' text = "expect_equal(2, x)", #' linters = yoda_test_linter() #' ) #' #' lint( #' text = 'expect_identical("a", x)', #' linters = yoda_test_linter() #' ) #' #' # okay #' lint( #' text = "expect_equal(x, 2)", #' linters = yoda_test_linter() #' ) #' #' lint( #' text = 'expect_identical(x, "a")', #' linters = yoda_test_linter() #' ) #' #' @evalRd rd_tags("yoda_test_linter") #' @seealso #' [linters] for a complete list of linters available in lintr. #' #' @export yoda_test_linter <- function() { # catch the following types of literal in the first argument: # (1) numeric literal (e.g. TRUE, 1L, 1.0, NA) [NUM_CONST] # (2) string literal (e.g. 'str' or "str") [STR_CONST] # (but _not_ x$"key", #1067) # (3) arithmetic literal (e.g. 1+1 or 0+1i) [OP-PLUS or OP-MINUS...] # TODO(#963): fully generalize this & re-use elsewhere const_condition <- " NUM_CONST or (STR_CONST and not(OP-DOLLAR or OP-AT)) or ((OP-PLUS or OP-MINUS) and count(expr[NUM_CONST]) = 2) " pipes <- setdiff(magrittr_pipes, c("%$%", "%<>%")) xpath <- glue(" following-sibling::expr[1][ {const_condition} ] /parent::expr[not(preceding-sibling::*[self::PIPE or self::SPECIAL[{ xp_text_in_table(pipes) }]])] ") second_const_xpath <- glue("expr[position() = 3 and ({const_condition})]") Linter(linter_level = "expression", function(source_expression) { bad_expr <- xml_find_all( source_expression$xml_find_function_calls(c("expect_equal", "expect_identical", "expect_setequal")), xpath ) matched_call <- xp_call_name(bad_expr) second_const <- xml_find_first(bad_expr, second_const_xpath) lint_message <- ifelse( is.na(second_const), paste( "Compare objects in tests in the order 'actual', 'expected', not the reverse.", sprintf("For example, do %1$s(foo(x), 2L) instead of %1$s(2L, foo(x)).", matched_call) ), sprintf("Avoid storing placeholder tests like %s(1, 1)", matched_call) ) xml_nodes_to_lints(bad_expr, source_expression, lint_message, type = "warning") }) } lintr/R/conjunct_test_linter.R0000644000176200001440000001306314752731051016175 0ustar liggesusers#' Force `&&` conditions to be written separately where appropriate #' #' For readability of test outputs, testing only one thing per call to #' [testthat::expect_true()] is preferable, i.e., #' `expect_true(A); expect_true(B)` is better than `expect_true(A && B)`, and #' `expect_false(A); expect_false(B)` is better than `expect_false(A || B)`. #' #' Similar reasoning applies to `&&` usage inside [stopifnot()] and `assertthat::assert_that()` calls. #' #' Relatedly, `dplyr::filter(DF, A & B)` is the same as `dplyr::filter(DF, A, B)`, but the latter will be more readable #' / easier to format for long conditions. Note that this linter assumes usages of `filter()` are `dplyr::filter()`; #' if you're using another function named `filter()`, e.g. [stats::filter()], please namespace-qualify it to avoid #' false positives. You can omit linting `filter()` expressions altogether via `allow_filter = TRUE`. #' #' @param allow_named_stopifnot Logical, `TRUE` by default. If `FALSE`, "named" calls to `stopifnot()`, #' available since R 4.0.0 to provide helpful messages for test failures, are also linted. #' @param allow_filter Character naming the method for linting calls to `filter()`. The default, `"never"`, means #' `filter()` and `dplyr::filter()` calls are linted; `"not_dplyr"` means only `dplyr::filter()` calls are linted; #' and `"always"` means no calls to `filter()` are linted. Calls like `stats::filter()` are never linted. #' #' @examples #' # will produce lints #' lint( #' text = "expect_true(x && y)", #' linters = conjunct_test_linter() #' ) #' #' lint( #' text = "expect_false(x || (y && z))", #' linters = conjunct_test_linter() #' ) #' #' lint( #' text = "stopifnot('x must be a logical scalar' = length(x) == 1 && is.logical(x) && !is.na(x))", #' linters = conjunct_test_linter(allow_named_stopifnot = FALSE) #' ) #' #' lint( #' text = "dplyr::filter(mtcars, mpg > 20 & vs == 0)", #' linters = conjunct_test_linter() #' ) #' #' lint( #' text = "filter(mtcars, mpg > 20 & vs == 0)", #' linters = conjunct_test_linter() #' ) #' #' # okay #' lint( #' text = "expect_true(x || (y && z))", #' linters = conjunct_test_linter() #' ) #' #' lint( #' text = 'stopifnot("x must be a logical scalar" = length(x) == 1 && is.logical(x) && !is.na(x))', #' linters = conjunct_test_linter(allow_named_stopifnot = TRUE) #' ) #' #' lint( #' text = "dplyr::filter(mtcars, mpg > 20 & vs == 0)", #' linters = conjunct_test_linter(allow_filter = "always") #' ) #' #' lint( #' text = "filter(mtcars, mpg > 20 & vs == 0)", #' linters = conjunct_test_linter(allow_filter = "not_dplyr") #' ) #' #' lint( #' text = "stats::filter(mtcars$cyl, mtcars$mpg > 20 & mtcars$vs == 0)", #' linters = conjunct_test_linter() #' ) #' #' @evalRd rd_tags("conjunct_test_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export conjunct_test_linter <- function(allow_named_stopifnot = TRUE, allow_filter = c("never", "not_dplyr", "always")) { allow_filter <- match.arg(allow_filter) expect_true_assert_that_xpath <- " following-sibling::expr[1][AND2] /parent::expr " named_stopifnot_condition <- if (allow_named_stopifnot) "and not(preceding-sibling::*[1][self::EQ_SUB])" else "" stopifnot_xpath <- glue(" following-sibling::expr[1][AND2 {named_stopifnot_condition}] /parent::expr ") expect_false_xpath <- " following-sibling::expr[1][OR2] /parent::expr " filter_ns_cond <- switch(allow_filter, never = "not(SYMBOL_PACKAGE[text() != 'dplyr'])", not_dplyr = "SYMBOL_PACKAGE[text() = 'dplyr']", always = "true" ) filter_xpath <- glue(" self::*[{ filter_ns_cond }] /parent::expr /expr[AND] ") Linter(linter_level = "file", function(source_expression) { # need the full file to also catch usages at the top level expect_true_assert_that_calls <- source_expression$xml_find_function_calls(c("expect_true", "assert_that")) stopifnot_calls <- source_expression$xml_find_function_calls("stopifnot") expect_false_calls <- source_expression$xml_find_function_calls("expect_false") test_expr <- combine_nodesets( xml_find_all(expect_true_assert_that_calls, expect_true_assert_that_xpath), xml_find_all(stopifnot_calls, stopifnot_xpath), xml_find_all(expect_false_calls, expect_false_xpath) ) matched_fun <- xp_call_name(test_expr) operator <- xml_find_chr(test_expr, "string(expr/*[self::AND2 or self::OR2])") replacement_fmt <- ifelse( matched_fun %in% c("expect_true", "expect_false"), "Write multiple expectations like %1$s(A) and %1$s(B)", "Write multiple conditions like %s(A, B)" ) lint_message <- paste( # as.character() needed for 0-lint case where ifelse(logical(0)) returns logical(0) sprintf(as.character(replacement_fmt), matched_fun), sprintf("instead of %s(A %s B).", matched_fun, operator), "The latter will produce better error messages in the case of failure." ) lints <- xml_nodes_to_lints( test_expr, source_expression = source_expression, lint_message = lint_message, type = "warning" ) if (allow_filter != "always") { xml_calls <- source_expression$xml_find_function_calls("filter") filter_expr <- xml_find_all(xml_calls, filter_xpath) filter_lints <- xml_nodes_to_lints( filter_expr, source_expression = source_expression, lint_message = "Use dplyr::filter(DF, A, B) instead of dplyr::filter(DF, A & B).", type = "warning" ) lints <- c(lints, filter_lints) } lints }) } lintr/R/is_numeric_linter.R0000644000176200001440000000633114752731051015450 0ustar liggesusers#' Redirect `is.numeric(x) || is.integer(x)` to just use `is.numeric(x)` #' #' [is.numeric()] returns `TRUE` when `typeof(x)` is `double` or `integer` -- #' testing `is.numeric(x) || is.integer(x)` is thus redundant. #' #' NB: This linter plays well with [class_equals_linter()], which can help #' avoid further `is.numeric()` equivalents like #' `any(class(x) == c("numeric", "integer"))`. #' #' @examples #' # will produce lints #' lint( #' text = "is.numeric(y) || is.integer(y)", #' linters = is_numeric_linter() #' ) #' #' lint( #' text = 'class(z) %in% c("numeric", "integer")', #' linters = is_numeric_linter() #' ) #' #' # okay #' lint( #' text = "is.numeric(y) || is.factor(y)", #' linters = is_numeric_linter() #' ) #' #' lint( #' text = 'class(z) %in% c("numeric", "integer", "factor")', #' linters = is_numeric_linter() #' ) #' #' @evalRd rd_tags("is_numeric_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export is_numeric_linter <- function() { # TODO(#2469): This should also cover is.double(x) || is.integer(x). # TODO(#1636): is.numeric(x) || is.integer(x) || is.factor(x) is also redundant. # TODO(#2470): Consider usages with class(), typeof(), or inherits(). is_numeric_expr <- "expr[1][SYMBOL_FUNCTION_CALL[text() = 'is.numeric']]" is_integer_expr <- "expr[1][SYMBOL_FUNCTION_CALL[text() = 'is.integer']]" # testing things like is.numeric(x) || is.integer(x) or_xpath <- glue(" //OR2 /parent::expr[ expr/{is_numeric_expr} and expr/{is_integer_expr} and expr/{is_numeric_expr}/following-sibling::expr[1] = expr/{is_integer_expr}/following-sibling::expr[1] ] ") # testing class(x) %in% c("numeric", "integer") class_xpath <- " //SPECIAL[ text() = '%in%' and following-sibling::expr[ expr/SYMBOL_FUNCTION_CALL[text() = 'c'] and count(expr/STR_CONST) = 2 and count(expr) = 3 ] and preceding-sibling::expr/expr/SYMBOL_FUNCTION_CALL[text() = 'class'] ] /parent::expr " Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content or_expr <- xml_find_all(xml, or_xpath) or_lints <- xml_nodes_to_lints( or_expr, source_expression = source_expression, lint_message = paste( "Use `is.numeric(x)` instead of the equivalent `is.numeric(x) || is.integer(x)`.", "Use is.double(x) to test for objects stored as 64-bit floating point." ), type = "warning" ) class_expr <- xml_find_all(xml, class_xpath) if (length(class_expr) > 0L) { class_strings <- c( get_r_string(class_expr, "expr[2]/expr[2]/STR_CONST"), get_r_string(class_expr, "expr[2]/expr[3]/STR_CONST") ) is_lintable <- "integer" %in% class_strings && "numeric" %in% class_strings class_expr <- class_expr[is_lintable] } class_lints <- xml_nodes_to_lints( class_expr, source_expression = source_expression, lint_message = paste( 'Use is.numeric(x) instead of class(x) %in% c("integer", "numeric").', "Use is.double(x) to test for objects stored as 64-bit floating point." ), type = "warning" ) c(or_lints, class_lints) }) } lintr/R/nested_ifelse_linter.R0000644000176200001440000000542414752731051016126 0ustar liggesusers#' Block usage of nested `ifelse()` calls #' #' Calling [ifelse()] in nested calls is problematic for two main reasons: #' 1. It can be hard to read -- mapping the code to the expected output #' for such code can be a messy task/require a lot of mental bandwidth, #' especially for code that nests more than once #' 2. It is inefficient -- `ifelse()` can evaluate _all_ of its arguments at #' both yes and no (see ); this issue #' is exacerbated for nested calls #' #' Users can instead rely on a more readable alternative modeled after SQL #' CASE WHEN statements. #' #' Let's say this is our original code: #' #' ```r #' ifelse( #' x == "a", #' 2L, #' ifelse(x == "b", 3L, 1L) #' ) #' ``` #' #' Here are a few ways to avoid nesting and make the code more readable: #' #' - Use `data.table::fcase()` #' #' ```r #' data.table::fcase( #' x == "a", 2L, #' x == "b", 3L, #' default = 1L #' ) #' ``` #' #' - Use `dplyr::case_match()` #' #' ```r #' dplyr::case_match( #' x, #' "a" ~ 2L, #' "b" ~ 3L, #' .default = 1L #' ) #' ``` #' #' - Use a look-up-and-merge approach (build a mapping table between values #' and outputs and merge this to the input) #' #' ```r #' default <- 1L #' values <- data.frame( #' a = 2L, #' b = 3L #' ) #' found_value <- values[[x]] #' ifelse(is.null(found_value), default, found_value) #' ``` #' #' @examples #' # will produce lints #' lint( #' text = 'ifelse(x == "a", 1L, ifelse(x == "b", 2L, 3L))', #' linters = nested_ifelse_linter() #' ) #' #' # okay #' lint( #' text = 'dplyr::case_when(x == "a" ~ 1L, x == "b" ~ 2L, TRUE ~ 3L)', #' linters = nested_ifelse_linter() #' ) #' #' lint( #' text = 'data.table::fcase(x == "a", 1L, x == "b", 2L, default = 3L)', #' linters = nested_ifelse_linter() #' ) #' #' @evalRd rd_tags("nested_ifelse_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export nested_ifelse_linter <- function() { # NB: land on the nested (inner) call, not the outer call, and throw a lint with the inner call's name xpath <- glue(" following-sibling::expr[ expr[1]/SYMBOL_FUNCTION_CALL[ {xp_text_in_table(ifelse_funs)} ] ]") Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(ifelse_funs) bad_expr <- xml_find_all(xml_calls, xpath) matched_call <- xp_call_name(bad_expr) lint_message <- paste( sprintf("Don't use nested %s() calls;", matched_call), "instead, try (1) data.table::fcase; (2) dplyr::case_when; or (3) using a lookup table." ) xml_nodes_to_lints(bad_expr, source_expression, lint_message, type = "warning") }) } lintr/R/xml_utils.R0000644000176200001440000000207714752731051013761 0ustar liggesusers# utils for working with XML #' str2lang, but for xml children. #' #' [xml2::xml_text()] is deceptively close to obviating this helper, but it collapses #' text across lines. R is _mostly_ whitespace-agnostic, so this only matters in some edge cases, #' in particular when there are comments within an expression (`` node). See #1919. #' #' @noRd xml2lang <- function(x) { x_strip_comments <- xml_find_all(x, ".//*[not(self::COMMENT or self::expr)]") str2lang(paste(xml_text(x_strip_comments), collapse = " ")) } safe_parse_to_xml <- function(parsed_content) { if (is.null(parsed_content)) { return(xml2::xml_missing()) } tryCatch( xml2::read_xml(xmlparsedata::xml_parse_data(parsed_content)), # use xml_missing so that code doesn't always need to condition on XML existing error = function(e) xml2::xml_missing() ) } is_node <- function(xml) inherits(xml, "xml_node") is_nodeset <- function(xml) inherits(xml, "xml_nodeset") is_nodeset_like <- function(xml) { is_nodeset(xml) || (is.list(xml) && all(vapply(xml, is_node, logical(1L)))) } lintr/R/linter_tag_docs.R0000644000176200001440000001101414752731051015070 0ustar liggesusers# This file contains all documentation for linter tags in lintr except for default_linters. #' Style linters #' @name style_linters #' @description #' Linters highlighting code style issues. #' @evalRd rd_linters("style") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Robustness linters #' @name robustness_linters #' @description #' Linters highlighting code robustness issues, such as possibly wrong edge case behavior. #' @evalRd rd_linters("robustness") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Best practices linters #' @name best_practices_linters #' @description #' Linters checking the use of coding best practices, such as explicit typing of numeric constants. #' @evalRd rd_linters("best_practices") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Consistency linters #' @name consistency_linters #' @description #' Linters checking enforcing a consistent alternative if there are multiple syntactically valid ways to write #' something. #' @evalRd rd_linters("consistency") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Readability linters #' @name readability_linters #' @description #' Linters highlighting readability issues, such as missing whitespace. #' @evalRd rd_linters("readability") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Correctness linters #' @name correctness_linters #' @description #' Linters highlighting possible programming mistakes, such as unused variables. #' @evalRd rd_linters("correctness") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Common mistake linters #' @name common_mistakes_linters #' @description #' Linters highlighting common mistakes, such as duplicate arguments. #' @evalRd rd_linters("common_mistakes") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Efficiency linters #' @name efficiency_linters #' @description #' Linters highlighting code efficiency problems, such as unnecessary function calls. #' @evalRd rd_linters("efficiency") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Configurable linters #' @name configurable_linters #' @description #' Generic linters which support custom configuration to your needs. #' @evalRd rd_linters("configurable") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Package development linters #' @name package_development_linters #' @description #' Linters useful to package developers, for example for writing consistent tests. #' @evalRd rd_linters("package_development") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Deprecated linters #' @name deprecated_linters #' @description #' Linters that are deprecated and provided for backwards compatibility only. #' These linters will be excluded from [linters_with_tags()] by default. #' @evalRd rd_linters("deprecated") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Code executing linters #' @name executing_linters #' @description #' Linters that evaluate parts of the linted code, such as loading referenced packages. #' These linters should not be used with untrusted code, and may need dependencies of the linted package or project to #' be available in order to function correctly. For package authors, note that this includes loading the package itself, #' e.g. with `pkgload::load_all()` or installing and attaching the package. #' @evalRd rd_linters("executing") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Testthat linters #' @name pkg_testthat_linters #' @description #' Linters encouraging best practices within testthat suites. #' @evalRd rd_linters("pkg_testthat") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' - NULL #' Regular expression linters #' @name regex_linters #' @description #' Linters that examine the usage of regular expressions and functions executing them in user code. #' @evalRd rd_linters("regex") #' @seealso [linters] for a complete list of linters available in lintr. NULL #' Tidyverse design linters #' @name tidy_design_linters #' @description #' Linters based on guidelines described in the 'Tidy design principles' book. #' @evalRd rd_linters("tidy_design") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - NULL lintr/R/system_file_linter.R0000644000176200001440000000372514752731051015642 0ustar liggesusers#' Block usage of `file.path()` with `system.file()` #' #' [system.file()] has a `...` argument which, internally, is passed to #' [file.path()], so including it in user code is repetitive. #' #' @examples #' # will produce lints #' lint( #' text = 'system.file(file.path("path", "to", "data"), package = "foo")', #' linters = system_file_linter() #' ) #' #' lint( #' text = 'file.path(system.file(package = "foo"), "path", "to", "data")', #' linters = system_file_linter() #' ) #' #' # okay #' lint( #' text = 'system.file("path", "to", "data", package = "foo")', #' linters = system_file_linter() #' ) #' #' @evalRd rd_tags("system_file_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export system_file_linter <- function() { # either system.file(file.path(...)) or file.path(system.file(...)) file_path_xpath <- " self::*[following-sibling::expr/expr/SYMBOL_FUNCTION_CALL[text() = 'system.file']] /parent::expr " system_file_xpath <- " self::*[following-sibling::expr/expr/SYMBOL_FUNCTION_CALL[text() = 'file.path']] /parent::expr " Linter(linter_level = "expression", function(source_expression) { file_path_calls <- source_expression$xml_find_function_calls("file.path") system_file_calls <- source_expression$xml_find_function_calls("system.file") bad_expr <- combine_nodesets( xml_find_all(file_path_calls, file_path_xpath), xml_find_all(system_file_calls, system_file_xpath) ) outer_call <- xp_call_name(bad_expr) lint_message <- paste( "Use the `...` argument of system.file() to expand paths,", 'e.g. system.file("data", "model.csv", package = "myrf") instead of', ifelse( outer_call == "system.file", 'system.file(file.path("data", "model.csv"), package = "myrf")', 'file.path(system.file(package = "myrf"), "data", "model.csv")' ) ) xml_nodes_to_lints(bad_expr, source_expression, lint_message, type = "warning") }) } lintr/R/strings_as_factors_linter.R0000644000176200001440000000601614752731051017210 0ustar liggesusers#' Identify cases where `stringsAsFactors` should be supplied explicitly #' #' Designed for code bases written for versions of R before 4.0 seeking to upgrade to R >= 4.0, where #' one of the biggest pain points will surely be the flipping of the #' default value of `stringsAsFactors` from `TRUE` to `FALSE`. #' #' It's not always possible to tell statically whether the change will break #' existing code because R is dynamically typed -- e.g. in `data.frame(x)` #' if `x` is a string, this code will be affected, but if `x` is a number, #' this code will be unaffected. However, in `data.frame(x = "a")`, the #' output will unambiguously be affected. We can instead supply #' `stringsAsFactors = TRUE`, which will make this code backwards-compatible. #' #' See . #' #' @examples #' # will produce lints #' lint( #' text = 'data.frame(x = "a")', #' linters = strings_as_factors_linter() #' ) #' #' # okay #' lint( #' text = 'data.frame(x = "a", stringsAsFactors = TRUE)', #' linters = strings_as_factors_linter() #' ) #' #' lint( #' text = 'data.frame(x = "a", stringsAsFactors = FALSE)', #' linters = strings_as_factors_linter() #' ) #' #' lint( #' text = "data.frame(x = 1.2)", #' linters = strings_as_factors_linter() #' ) #' #' @evalRd rd_tags("strings_as_factors_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export strings_as_factors_linter <- local({ # a call to c() with only literal string inputs, # e.g. c("a") or c("a", "b"), but not c("a", b) c_combine_strings <- " expr[1][SYMBOL_FUNCTION_CALL[text() = 'c']] and expr[STR_CONST] and not(expr[SYMBOL or expr]) " # like data.frame(character()) or data.frame(as.character(1)) known_character_funs <- c( "character", "as.character", "paste", "sprintf", "format", "formatC", "prettyNum", "toString", "encodeString" ) # four inclusions of arguments to data.frame(): # (1) "a" (but exclude argument names, e.g. in c("a b" = 1), #1036) # (2) c("a", "b") # (3) rep("a", 2) # (4) rep(c("a", "b"), 2) # two exclusions # (1) above argument is to row.names= # (2) stringsAsFactors is manually supplied (with any value) xpath <- glue(" parent::expr[ expr[ ( STR_CONST[not(following-sibling::*[1][self::EQ_SUB])] or ( {c_combine_strings} ) or expr[1][ SYMBOL_FUNCTION_CALL[text() = 'rep'] and following-sibling::expr[1][STR_CONST or ({c_combine_strings})] ] or expr[1][SYMBOL_FUNCTION_CALL[ {xp_text_in_table(known_character_funs)} ]] ) and not(preceding-sibling::*[2][self::SYMBOL_SUB and text() = 'row.names']) ] and not(SYMBOL_SUB[text() = 'stringsAsFactors']) ]") make_linter_from_function_xpath( function_names = "data.frame", xpath = xpath, lint_message = "Supply an explicit value for stringsAsFactors for this code to work before and after R version 4.0.", type = "warning" ) }) lintr/R/object_overwrite_linter.R0000644000176200001440000000771314752731051016674 0ustar liggesusers#' Block assigning any variables whose name clashes with a `base` R function #' #' Re-using existing names creates a risk of subtle error best avoided. #' Avoiding this practice also encourages using better, more descriptive names. #' #' @param packages Character vector of packages to search for names that should #' be avoided. Defaults to the most common default packages: base, stats, #' utils, tools, methods, graphics, and grDevices. #' @param allow_names Character vector of object names to ignore, i.e., which #' are allowed to collide with exports from `packages`. #' #' @examples #' # will produce lints #' code <- "function(x) {\n data <- x\n data\n}" #' writeLines(code) #' lint( #' text = code, #' linters = object_overwrite_linter() #' ) #' #' code <- "function(x) {\n lint <- 'fun'\n lint\n}" #' writeLines(code) #' lint( #' text = code, #' linters = object_overwrite_linter(packages = "lintr") #' ) #' #' # okay #' code <- "function(x) {\n data('mtcars')\n}" #' writeLines(code) #' lint( #' text = code, #' linters = object_overwrite_linter() #' ) #' #' code <- "function(x) {\n data <- x\n data\n}" #' writeLines(code) #' lint( #' text = code, #' linters = object_overwrite_linter(packages = "base") #' ) #' #' # names in function signatures are ignored #' lint( #' text = "function(data) data <- subset(data, x > 0)", #' linters = object_overwrite_linter() #' ) #' #' @evalRd rd_tags("object_overwrite_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export object_overwrite_linter <- function( packages = c("base", "stats", "utils", "tools", "methods", "graphics", "grDevices"), allow_names = character() ) { for (package in packages) { if (!requireNamespace(package, quietly = TRUE)) { cli_abort("Package {.pkg {package}} is required, but not available.") } } pkg_exports <- lapply( packages, # .__C__ etc.: drop 150+ "virtual" names since they are very unlikely to appear anyway function(pkg) setdiff(grep("^[.]__[A-Z]__", getNamespaceExports(pkg), value = TRUE, invert = TRUE), allow_names) ) pkg_exports <- data.frame( package = rep(packages, lengths(pkg_exports)), name = unlist(pkg_exports) ) # Take the first among duplicate names, e.g. 'plot' resolves to base::plot, not graphics::plot pkg_exports <- pkg_exports[!duplicated(pkg_exports$name), ] # test that the symbol doesn't match an argument name in the function # NB: data.table := has parse token LEFT_ASSIGN as well xpath_assignments <- glue(" (//SYMBOL | //STR_CONST)[ not(text() = ancestor::expr/preceding-sibling::SYMBOL_FORMALS/text()) ]/ parent::expr[ count(*) = 1 and ( following-sibling::LEFT_ASSIGN[text() != ':='] or following-sibling::EQ_ASSIGN or preceding-sibling::RIGHT_ASSIGN ) and ancestor::*[ (self::expr or self::expr_or_assign_or_help or self::equal_assign) and (preceding-sibling::FUNCTION or preceding-sibling::OP-LAMBDA) ] ] ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content assigned_exprs <- xml_find_all(xml, xpath_assignments) assigned_symbols <- get_r_string(assigned_exprs, "SYMBOL|STR_CONST") is_quoted <- startsWith(assigned_symbols, "`") assigned_symbols[is_quoted] <- substr(assigned_symbols[is_quoted], 2L, nchar(assigned_symbols[is_quoted]) - 1L) is_bad <- assigned_symbols %in% pkg_exports$name source_pkg <- pkg_exports$package[match(assigned_symbols[is_bad], pkg_exports$name)] lint_message <- sprintf( "'%s' is an exported object from package '%s'. Avoid re-using such symbols.", assigned_symbols[is_bad], source_pkg ) xml_nodes_to_lints( assigned_exprs[is_bad], source_expression = source_expression, lint_message = lint_message, type = "warning" ) }) } lintr/R/condition_call_linter.R0000644000176200001440000000547714752731051016306 0ustar liggesusers#' Recommend usage of `call. = FALSE` in conditions #' #' This linter, with the default `display_call = FALSE`, enforces the #' recommendation of the tidyverse design guide regarding displaying error #' calls. #' #' @param display_call Logical specifying expected behavior regarding `call.` #' argument in conditions. #' - `NA` forces providing `call. =` but ignores its value (this can be used in #' cases where you expect a mix of `call. = FALSE` and `call. = TRUE`) #' - `TRUE` lints `call. = FALSE` #' - `FALSE` forces `call. = FALSE` (lints `call. = TRUE` or missing `call. =` value) #' #' #' @examples #' # will produce lints #' lint( #' text = "stop('test')", #' linters = condition_call_linter() #' ) #' #' lint( #' text = "stop('test', call. = TRUE)", #' linters = condition_call_linter() #' ) #' #' lint( #' text = "stop('test', call. = FALSE)", #' linters = condition_call_linter(display_call = TRUE) #' ) #' #' lint( #' text = "stop('this is a', 'test', call. = FALSE)", #' linters = condition_call_linter(display_call = TRUE) #' ) #' #' # okay #' lint( #' text = "stop('test', call. = FALSE)", #' linters = condition_call_linter() #' ) #' #' lint( #' text = "stop('this is a', 'test', call. = FALSE)", #' linters = condition_call_linter() #' ) #' #' lint( #' text = "stop('test', call. = TRUE)", #' linters = condition_call_linter(display_call = TRUE) #' ) #' #' @evalRd rd_tags("condition_call_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - > #' @export condition_call_linter <- function(display_call = FALSE) { call_xpath <- glue::glue(" following-sibling::SYMBOL_SUB[text() = 'call.'] /following-sibling::expr[1] /NUM_CONST[text() = '{!display_call}'] ") no_call_xpath <- "parent::expr[not(SYMBOL_SUB[text() = 'call.'])]" if (is.na(display_call)) { call_cond <- no_call_xpath msg_fmt <- "Provide an explicit value for `call.` in %s()." } else if (display_call) { call_cond <- call_xpath msg_fmt <- "Use %s(.) to display the call in an error message." } else { # call. = TRUE can be expressed in two way: # - either explicitly with call. = TRUE # - or by implicitly relying on the default call_cond <- xp_or(call_xpath, no_call_xpath) msg_fmt <- "Use %s(., call. = FALSE) not to display the call in an error message." } xpath <- glue::glue("./self::*[{call_cond}]/parent::expr") Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls(c("stop", "warning")) bad_expr <- xml_find_all(xml_calls, xpath) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = sprintf(msg_fmt, xp_call_name(bad_expr)), type = "warning" ) }) } lintr/R/any_duplicated_linter.R0000644000176200001440000000736714752731051016312 0ustar liggesusers#' Require usage of `anyDuplicated(x) > 0` over `any(duplicated(x))` #' #' [anyDuplicated()] exists as a replacement for `any(duplicated(.))`, which is #' more efficient for simple objects, and is at worst equally efficient. #' Therefore, it should be used in all situations instead of the latter. #' #' Also match usage like `length(unique(x$col)) == nrow(x)`, which can #' be replaced by `anyDuplicated(x$col) == 0L`. #' #' @examples #' # will produce lints #' lint( #' text = "any(duplicated(x), na.rm = TRUE)", #' linters = any_duplicated_linter() #' ) #' #' lint( #' text = "length(unique(x)) == length(x)", #' linters = any_duplicated_linter() #' ) #' #' # okay #' lint( #' text = "anyDuplicated(x)", #' linters = any_duplicated_linter() #' ) #' #' lint( #' text = "anyDuplicated(x) == 0L", #' linters = any_duplicated_linter() #' ) #' #' @evalRd rd_tags("any_duplicated_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export any_duplicated_linter <- function() { any_duplicated_xpath <- " following-sibling::expr[1][expr[1][SYMBOL_FUNCTION_CALL[text() = 'duplicated']]] /parent::expr[ count(expr) = 2 or (count(expr) = 3 and SYMBOL_SUB[text() = 'na.rm']) ] " # outline: # EQ/NE/GT/LT: ensure we're in a comparison clause # check for length(unique()) matching: # - length(unique( _ )) == length( _ ) # - length(unique( << _$col or _[["col"]] >> )) == nrow( _ ) # NB: parent::expr/.../following-sibling::expr is the path from # the expr of the unique() call to the call that needs to match. # the final parent::expr/expr gets us to the expr on the other side of EQ; # this lets us match on either side of EQ, where following-sibling # assumes we are before EQ, preceding-sibling assumes we are after EQ. length_unique_xpath_parts <- glue(" //{ c('EQ', 'NE', 'GT', 'LT') } /parent::expr /expr[ expr[1][SYMBOL_FUNCTION_CALL[text() = 'length']] and expr[expr[1][ SYMBOL_FUNCTION_CALL[text() = 'unique'] and ( following-sibling::expr = parent::expr /parent::expr /parent::expr /expr /expr[1][SYMBOL_FUNCTION_CALL[text()= 'length']] /following-sibling::expr or following-sibling::expr[OP-DOLLAR or LBB]/expr[1] = parent::expr /parent::expr /parent::expr /expr /expr[1][SYMBOL_FUNCTION_CALL[text()= 'nrow']] /following-sibling::expr ) ]] ] ") length_unique_xpath <- paste(length_unique_xpath_parts, collapse = " | ") uses_nrow_xpath <- "./parent::expr/expr/expr[1]/SYMBOL_FUNCTION_CALL[text() = 'nrow']" Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content xml_calls <- source_expression$xml_find_function_calls("any") any_duplicated_expr <- xml_find_all(xml_calls, any_duplicated_xpath) any_duplicated_lints <- xml_nodes_to_lints( any_duplicated_expr, source_expression = source_expression, lint_message = "anyDuplicated(x, ...) > 0 is better than any(duplicated(x), ...).", type = "warning" ) length_unique_expr <- xml_find_all(xml, length_unique_xpath) lint_message <- ifelse( is.na(xml_find_first(length_unique_expr, uses_nrow_xpath)), "anyDuplicated(x) == 0L is better than length(unique(x)) == length(x).", "anyDuplicated(DF$col) == 0L is better than length(unique(DF$col)) == nrow(DF)" ) length_unique_lints <- xml_nodes_to_lints( length_unique_expr, source_expression = source_expression, lint_message = lint_message, type = "warning" ) c(any_duplicated_lints, length_unique_lints) }) } lintr/R/seq_linter.R0000644000176200001440000000711114752731051014100 0ustar liggesusers#' Sequence linter #' #' This linter checks for `1:length(...)`, `1:nrow(...)`, `1:ncol(...)`, #' `1:NROW(...)` and `1:NCOL(...)` expressions in base-R, or their usage in #' conjunction with `seq()` (e.g., `seq(length(...))`, `seq(nrow(...))`, etc.). #' #' Additionally, it checks for `1:n()` (from `{dplyr}`) and `1:.N` (from `{data.table}`). #' #' These often cause bugs when the right-hand side is zero. #' Instead, it is safer to use [base::seq_len()] (to create a sequence of a specified *length*) or #' [base::seq_along()] (to create a sequence *along* an object). #' #' @examples #' # will produce lints #' lint( #' text = "seq(length(x))", #' linters = seq_linter() #' ) #' #' lint( #' text = "1:nrow(x)", #' linters = seq_linter() #' ) #' #' lint( #' text = "dplyr::mutate(x, .id = 1:n())", #' linters = seq_linter() #' ) #' #' # okay #' lint( #' text = "seq_along(x)", #' linters = seq_linter() #' ) #' #' lint( #' text = "seq_len(nrow(x))", #' linters = seq_linter() #' ) #' #' lint( #' text = "dplyr::mutate(x, .id = seq_len(n()))", #' linters = seq_linter() #' ) #' #' @evalRd rd_tags("seq_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export seq_linter <- function() { bad_funcs <- xp_text_in_table(c("length", "n", "nrow", "ncol", "NROW", "NCOL", "dim")) # Exact `xpath` depends on whether bad function was used in conjunction with `seq()` seq_xpath <- glue(" following-sibling::expr[1][expr/SYMBOL_FUNCTION_CALL[ {bad_funcs} ]] /parent::expr[count(expr) = 2] ") # `.N` from {data.table} is special since it's not a function but a symbol colon_xpath <- glue(" //OP-COLON /parent::expr[ expr[NUM_CONST[text() = '1' or text() = '1L']] and ( expr[expr[(expr|self::*)[SYMBOL_FUNCTION_CALL[ {bad_funcs} ]]]] or expr[SYMBOL = '.N'] ) ] ") ## The actual order of the nodes is document order ## In practice we need to handle length(x):1 get_fun <- function(expr, n) { funcall <- xml_find_chr(expr, sprintf("string(./expr[%d])", n)) # `dplyr::n()` is special because it has no arguments, so the lint message # should mention `n()`, and not `n(...)` if (identical(funcall, "n()")) { return(funcall) } fun <- gsub("\\(.*\\)", "(...)", trimws(funcall)) bad_fun <- fun %in% bad_funcs fun[bad_fun] <- paste0(fun[bad_fun], "(...)") fun } Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content seq_calls <- source_expression$xml_find_function_calls("seq") badx <- combine_nodesets( xml_find_all(seq_calls, seq_xpath), xml_find_all(xml, colon_xpath) ) dot_expr1 <- get_fun(badx, 1L) dot_expr2 <- get_fun(badx, 2L) seq_along_idx <- grepl("length(", dot_expr1, fixed = TRUE) | grepl("length(", dot_expr2, fixed = TRUE) rev_idx <- startsWith(dot_expr2, "1") replacement <- rep("seq_along(...)", length(badx)) replacement[!seq_along_idx] <- paste0("seq_len(", ifelse(rev_idx, dot_expr1, dot_expr2)[!seq_along_idx], ")") replacement[rev_idx] <- paste0("rev(", replacement[rev_idx], ")") lint_message <- ifelse( grepl("seq", dot_expr1, fixed = TRUE), sprintf( "Use %s instead of %s(%s), which is likely to be wrong in the empty edge case.", replacement, dot_expr1, dot_expr2 ), sprintf( "Use %s instead of %s:%s, which is likely to be wrong in the empty edge case.", replacement, dot_expr1, dot_expr2 ) ) xml_nodes_to_lints(badx, source_expression, lint_message, type = "warning") }) } lintr/R/linter_tags.R0000644000176200001440000002003114752731051014242 0ustar liggesusers#' Get Linter metadata from a package #' #' `available_linters()` obtains a tagged list of all Linters available in a package. #' #' @param packages A character vector of packages to search for linters. #' @param tags Optional character vector of tags to search. Only linters with at least one matching tag will be #' returned. If `tags` is `NULL`, all linters will be returned. See `available_tags("lintr")` to find out what #' tags are already used by lintr. #' @param exclude_tags Tags to exclude from the results. Linters with at least one matching tag will not be returned. #' If `exclude_tags` is `NULL`, no linters will be excluded. Note that `tags` takes priority, meaning that any #' tag found in both `tags` and `exclude_tags` will be included, not excluded. Note that linters with tag `"defunct"` #' (which do not work and can no longer be run) cannot be queried directly. See [lintr-deprecated] instead. #' #' @section Package Authors: #' #' To implement `available_linters()` for your package, include a file `inst/lintr/linters.csv` in your #' package. #' The CSV file must contain the columns 'linter' and 'tags', and be UTF-8 encoded. #' Additional columns will be silently ignored if present and the columns are identified by name. #' Each row describes a linter by #' #' 1. its function name (e.g. `"assignment_linter"`) in the column 'linter'. #' 2. space-separated tags associated with the linter (e.g. `"style consistency default"`) in the column 'tags'. #' #' Tags should be snake_case. #' #' See `available_tags("lintr")` to find out what tags are already used by lintr. #' #' @return #' `available_linters` returns a data frame with columns 'linter', 'package' and 'tags': #' #' \describe{ #' \item{linter}{A character column naming the function associated with the linter.} #' \item{package}{A character column containing the name of the package providing the linter.} #' \item{tags}{A list column containing tags associated with the linter.} #' } #' #' @examples #' lintr_linters <- available_linters() #' #' # If the package doesn't exist or isn't installed, an empty data frame will be returned #' available_linters("does-not-exist") #' #' lintr_linters2 <- available_linters(c("lintr", "does-not-exist")) #' identical(lintr_linters, lintr_linters2) #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - [available_tags()] to retrieve the set of valid tags. #' @export available_linters <- function(packages = "lintr", tags = NULL, exclude_tags = "deprecated") { if (!is.character(packages)) { cli_abort("{.arg packages} must be a {.cls character} vector.") } if (!is.null(tags) && !is.character(tags)) { cli_abort("{.arg tags} must be a {.cls character} vector.") } if (!is.null(exclude_tags) && !is.character(exclude_tags)) { cli_abort("{.arg exclude_tags} must be a {.cls character} vector.") } # any tags specified explicitly will not be excluded (#1959) # never include defunct linters, which don't work / error on instantiation (#2284). exclude_tags <- unique(c(setdiff(exclude_tags, tags), "defunct")) # Handle multiple packages if (length(packages) > 1L) { return(do.call(rbind, lapply(packages, available_linters, tags = tags, exclude_tags = exclude_tags))) } csv_file <- system.file("lintr", "linters.csv", package = packages) if (!file.exists(csv_file)) { return(empty_linters()) } available <- utils::read.csv(csv_file, encoding = "UTF-8", as.is = TRUE) if (!validate_linter_db(available, packages)) { return(empty_linters()) } build_available_linters(available, packages, tags, exclude_tags) } build_available_linters <- function(available, package, tags, exclude_tags) { available_df <- data.frame(linter = available[["linter"]], package) available_df$tags <- strsplit(available[["tags"]], split = " ", fixed = TRUE) if (!is.null(tags)) { matches_tags <- vapply(available_df$tags, function(linter_tags) any(linter_tags %in% tags), logical(1L)) available_df <- available_df[matches_tags, ] } if (!is.null(exclude_tags)) { matches_exclude <- vapply(available_df$tags, function(linter_tags) any(linter_tags %in% exclude_tags), logical(1L)) available_df <- available_df[!matches_exclude, ] } # Due to removal of deprecated linters in the returned data frame, there can be gaps in row numbers. # To avoid this inconsistency, regenerate row names. rownames(available_df) <- NULL available_df } #' Make sure we always return a valid data frame #' #' `data.frame` constructors don't handle zero-row list-columns properly, so supply `tags` afterwards. #' @noRd empty_linters <- function() { empty_df <- data.frame(linter = character(), package = character()) empty_df$tags <- list() empty_df } validate_linter_db <- function(available, package) { # Check that the csv file contains two character columns, named 'linter' and 'tags'. # Otherwise, fallback to an empty data frame. if (!all(c("linter", "tags") %in% colnames(available))) { cli_warn(c( i = "{.file linters.csv} must contain the columns {.val {c('linter', 'tags')}}.", x = "Package {.pkg package} is missing {.str {setdiff(c('linter', 'tags'), names(available))}}." )) return(FALSE) } nrow(available) > 0L } #' @rdname available_linters #' #' @description #' `available_tags()` searches for available tags. #' #' @return `available_tags` returns a character vector of linter tags used by the packages. #' @export #' @examples #' available_tags() available_tags <- function(packages = "lintr") { platform_independent_sort(unique(unlist(available_linters(packages = packages, exclude_tags = NULL)[["tags"]]))) } # nocov start #' Generate Rd fragment for the Tags section of a linter #' #' @param linter_name Name of the linter to generate Rd code for. #' #' @noRd rd_tags <- function(linter_name) { linters <- available_linters(exclude_tags = NULL) tags <- platform_independent_sort(linters[["tags"]][[match(linter_name, linters[["linter"]])]]) if (length(tags) == 0L) { cli_abort("Tags are required, but found none for {.fn linter_name}.") } c( "\\section{Tags}{", paste0("\\link[=", tags, "_linters]{", tags, "}", collapse = ", "), "}" ) } #' Generate Rd fragment for the Linters section of a tag #' #' @param tag_name Name of the tag to generate Rd code for. #' #' @noRd rd_linters <- function(tag_name) { linters <- available_linters(tags = tag_name) tagged <- platform_independent_sort(linters[["linter"]]) if (length(tagged) == 0L) { cli_abort("No linters found associated with tag {.emph tag_name}.") } c( "\\section{Linters}{", paste0("The following linters are tagged with '", tag_name, "':"), "\\itemize{", paste0("\\item{\\code{\\link{", tagged, "}}}"), "}", # itemize "}" # section ) } #' Generate Rd fragment for the main help page, listing all tags #' #' @noRd rd_taglist <- function() { linters <- available_linters(exclude_tags = NULL) # don't count tags on deprecated linters to the counts of other tags linters$tags <- lapply(linters$tags, function(x) if ("deprecated" %in% x) "deprecated" else x) tag_table <- table(unlist(linters[["tags"]])) tags <- platform_independent_sort(names(tag_table)) # re-order tag_table <- tag_table[tags] c( "\\section{Tags}{", "The following tags exist:", "\\itemize{", vapply(tags, function(tag) { paste0("\\item{\\link[=", tag, "_linters]{", tag, "} (", tag_table[[tag]], " linters)}") }, character(1L)), "}", # itemize "}" # section ) } #' Generate Rd fragment for the main help page, listing all linters #' #' @noRd rd_linterlist <- function() { linters <- available_linters() linter_names <- platform_independent_sort(linters[["linter"]]) c( "\\section{Linters}{", "The following linters exist:", "\\itemize{", vapply(linter_names, function(linter_name) { tags <- platform_independent_sort(linters[["tags"]][[match(linter_name, linters[["linter"]])]]) paste0("\\item{\\code{\\link{", linter_name, "}} (tags: ", toString(tags), ")}") }, character(1L)), "}", # itemize "}" # section ) } # nocov end lintr/R/class_equals_linter.R0000644000176200001440000000335314752731051015773 0ustar liggesusers#' Block comparison of class with `==` #' #' Usage like `class(x) == "character"` is prone to error since class in R #' is in general a vector. The correct version for S3 classes is [inherits()]: #' `inherits(x, "character")`. Often, class `k` will have an `is.` equivalent, #' for example [is.character()] or [is.data.frame()]. #' #' Similar reasoning applies for `class(x) %in% "character"`. #' #' @examples #' # will produce lints #' lint( #' text = 'is_lm <- class(x) == "lm"', #' linters = class_equals_linter() #' ) #' #' lint( #' text = 'if ("lm" %in% class(x)) is_lm <- TRUE', #' linters = class_equals_linter() #' ) #' #' # okay #' lint( #' text = 'is_lm <- inherits(x, "lm")', #' linters = class_equals_linter() #' ) #' #' lint( #' text = 'if (inherits(x, "lm")) is_lm <- TRUE', #' linters = class_equals_linter() #' ) #' #' @evalRd rd_tags("class_equals_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export class_equals_linter <- function() { xpath <- " parent::expr /parent::expr[ not(preceding-sibling::OP-LEFT-BRACKET) and (EQ or NE or SPECIAL[text() = '%in%']) ] " Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls("class") bad_expr <- xml_find_all(xml_calls, xpath) operator <- xml_find_chr(bad_expr, "string(*[2])") lint_message <- paste0( "Use inherits(x, 'class-name'), is. for S3 classes, ", "or is(x, 'S4Class') for S4 classes, ", "instead of comparing class(x) with ", operator, "." ) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = lint_message, type = "warning" ) }) } lintr/R/scalar_in_linter.R0000644000176200001440000000347014752731051015247 0ustar liggesusers#' Block usage like x %in% "a" #' #' `vector %in% set` is appropriate for matching a vector to a set, but if #' that set has size 1, `==` is more appropriate. #' #' `scalar %in% vector` is OK, because the alternative (`any(vector == scalar)`) #' is more circuitous & potentially less clear. #' #' @param in_operators Character vector of additional infix operators that behave like the `%in%` operator, #' e.g. `{data.table}`'s `%chin%` operator. #' #' @examples #' # will produce lints #' lint( #' text = "x %in% 1L", #' linters = scalar_in_linter() #' ) #' #' lint( #' text = "x %chin% 'a'", #' linters = scalar_in_linter(in_operators = "%chin%") #' ) #' #' # okay #' lint( #' text = "x %in% 1:10", #' linters = scalar_in_linter() #' ) #' #' @evalRd rd_tags("scalar_in_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export scalar_in_linter <- function(in_operators = NULL) { # TODO(#2085): Extend to include other cases where the RHS is clearly a scalar # NB: all of logical, integer, double, hex, complex are parsed as NUM_CONST xpath <- glue(" //SPECIAL[{xp_text_in_table(c('%in%', {in_operators}))}] /following-sibling::expr[NUM_CONST[not(starts-with(text(), 'NA'))] or STR_CONST] /parent::expr ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) in_op <- xml_find_chr(bad_expr, "string(SPECIAL)") lint_msg <- glue( "Use comparison operators (e.g. ==, !=, etc.) to match length-1 scalars instead of {in_op}. ", "Note that comparison operators preserve NA where {in_op} does not." ) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = lint_msg, type = "warning" ) }) } lintr/R/backport_linter.R0000644000176200001440000001505314752735352015131 0ustar liggesusers#' Backport linter #' #' Check for usage of unavailable functions. Not reliable for testing r-devel dependencies. #' #' @param r_version Minimum R version to test for compatibility #' @param except Character vector of functions to be excluded from linting. #' Use this to list explicitly defined backports, e.g. those imported from the `{backports}` package or manually #' defined in your package. #' #' @examples #' # will produce lints #' lint( #' text = "trimws(x)", #' linters = backport_linter("3.0.0") #' ) #' #' lint( #' text = "str2lang(x)", #' linters = backport_linter("3.2.0") #' ) #' #' # okay #' lint( #' text = "trimws(x)", #' linters = backport_linter("3.6.0") #' ) #' #' lint( #' text = "str2lang(x)", #' linters = backport_linter("4.0.0") #' ) #' #' lint( #' text = "str2lang(x)", #' linters = backport_linter("3.2.0", except = "str2lang") #' ) #' #' @evalRd rd_tags("backport_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export backport_linter <- function(r_version = getRversion(), except = character()) { r_version <- normalize_r_version(r_version) if (all(r_version >= R_system_version(names(backports)))) { return(Linter(function(source_expression) list(), linter_level = "file")) } backport_blacklist <- backports[r_version < R_system_version(names(backports))] backport_blacklist <- lapply(backport_blacklist, setdiff, except) backport_index <- rep(names(backport_blacklist), times = lengths(backport_blacklist)) names(backport_index) <- unlist(backport_blacklist) Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content used_symbols <- xml_find_all(xml, "//SYMBOL") used_symbols <- used_symbols[xml_text(used_symbols) %in% names(backport_index)] used_calls <- source_expression$xml_find_function_calls(names(backport_index)) all_names_nodes <- combine_nodesets( xml_find_first(used_calls, "SYMBOL_FUNCTION_CALL"), used_symbols ) all_names <- xml_text(all_names_nodes) bad_versions <- unname(backport_index[all_names]) lint_message <- sprintf( "%s (R %s) is not available for dependency R >= %s.", all_names, bad_versions, r_version ) xml_nodes_to_lints( all_names_nodes, source_expression = source_expression, lint_message = lint_message, type = "warning" ) }) } normalize_r_version <- function(r_version) { rx_release_spec <- rex( start, "release" %or% list("oldrel", maybe("-", digits)) %or% "devel", end ) if (is.character(r_version) && re_matches(r_version, rx_release_spec)) { # Support devel, release, oldrel, oldrel-1, ... if (r_version == "oldrel") { r_version <- "oldrel-1" } all_versions <- names(backports) minor_versions <- unique(re_substitutes(all_versions, rex(".", digits, end), "")) version_names <- c("devel", "release", paste0("oldrel-", seq_len(length(minor_versions) - 2L))) if (!r_version %in% version_names) { # This can only trip if e.g. oldrel-99 is requested cli_abort(c( "{.arg r_version} is not valid:", i = "It must be a version number or one of {.str {version_names}}.", x = "You entered {.str {r_version}} instead." )) } requested_version <- minor_versions[match(r_version, table = version_names)] available_patches <- all_versions[startsWith(all_versions, requested_version)] selected_patch <- which.max(as.integer( substr(available_patches, start = nchar(requested_version) + 2L, stop = nchar(available_patches)) )) r_version <- R_system_version(available_patches[selected_patch]) } else if (is.character(r_version)) { r_version <- R_system_version(r_version, strict = TRUE) } else if (!inherits(r_version, "R_system_version")) { cli_abort("{.arg r_version} must be an R version number, returned by {.fun R_system_version}, or a string.") } if (r_version < "3.0.0") { cli_warn(c( x = "Depending on an R version older than {.val 3.0.0} is not recommended.", i = "Resetting {.arg r_version} to {.val 3.0.0}." )) r_version <- R_system_version("3.0.0") } r_version } # Sources: # devel NEWS https://cran.rstudio.com/doc/manuals/r-devel/NEWS.html # release NEWS https://cran.r-project.org/doc/manuals/r-release/NEWS.html backports <- list( `4.4.0` = character(), # need character() entries for oldrel specifications `4.3.3` = character(), `4.3.0` = c("R_compiled_by", "array2DF"), `4.2.3` = character(), `4.2.1` = "findCRANmirror", `4.2.0` = c(".pretty", ".LC.categories", "Sys.setLanguage()"), `4.1.3` = character(), `4.1.0` = c("numToBits", "numToInts", "gregexec", "charClass", "checkRdContents", "...names"), `4.0.5` = character(), `4.0.0` = c( ".class2", ".S3method", "activeBindingFunction", "deparse1", "globalCallingHandlers", "infoRDS", "list2DF", "marginSums", "proportions", "R_user_dir", "socketTimeout", "tryInvokeRestart" ), `3.6.3` = character(), `3.6.0` = c( "asplit", "hcl.colors", "hcl.pals", "mem.maxNsize", "mem.maxVsize", "nullfile", "str2lang", "str2expression", "update_PACKAGES" ), `3.5.3` = character(), `3.5.0` = c("...elt", "...length", "askYesNo", "getDefaultCluster", "isFALSE", "packageDate", "warnErrList"), `3.4.4` = character(), `3.4.0` = c( "check_packages_in_dir_details", "CRAN_package_db", "debugcall", "hasName", "isS3stdgeneric", "strcapture", "Sys.setFileTime", "undebugcall" ), `3.3.3` = character(), `3.3.0` = c( ".traceback", "chkDots", "curlGetHeaders", "endsWith", "grouping", "isS3method", "makevars_site", "makevars_user", "Rcmd", "sigma", "startsWith", "strrep", "validEnc", "validUTF8" ), `3.2.5` = character(), `3.2.0` = c( ".getNamespaceInfo", "check_packages_in_dir_changes", "debuggingState", "dir.exists", "dynGet", "extSoftVersion", "get0", "grSoftVersion", "hsearch_db", "isNamespaceLoaded", "lengths", "libcurlVersion", "returnValue", "tclVersion", "toTitleCase", "trimws" ), `3.1.3` = "pcre_config", `3.1.2` = "icuGetCollate", `3.1.1` = c(".nknots.smspl", "promptImport"), `3.1.0` = c("agrepl", "anyNA", "changedFiles", "cospi", "fileSnapshot", "find_gs_cmd", "sinpi", "tanpi"), `3.0.3` = "La_version", `3.0.2` = c("assertCondition", "assertError", "assertWarning", "getVignetteInfo"), `3.0.0` = c( ".onDetach", "bitwAnd", "bitwNot", "bitwOr", "bitwShiftL", "bitwShiftR", "bitwXor", "check_packages_in_dir", "cite", "citeNatbib", "clearPushBack", "packageName", "process.events", "provideDimnames", "quartz.save", "rep_len" ) ) lintr/R/addins.R0000644000176200001440000000142114752731051013173 0ustar liggesusers# nocov start addin_lint <- function() { if (!requireNamespace("rstudioapi", quietly = TRUE)) { cli_abort("{.pkg rstudioapi} is required for add-ins.") } filename <- rstudioapi::getSourceEditorContext() if (filename$path == "") { cli_warn("Current source has no path. Please save before continuing.") return(flatten_lints(list())) } lint(filename$path) } addin_lint_package <- function() { if (!requireNamespace("rstudioapi", quietly = TRUE)) { cli_abort("{.pkg rstudioapi} is required for add-ins.") } project <- rstudioapi::getActiveProject() if (is.null(project)) { cli_inform("No project found, passing current directory.") project_path <- getwd() } else { project_path <- project } lint_package(project_path) } # nocov end lintr/R/infix_spaces_linter.R0000644000176200001440000000755714752731051016001 0ustar liggesusers#' Infix spaces linter #' #' Check that infix operators are surrounded by spaces. Enforces the corresponding Tidyverse style guide rule; #' see . #' #' @param exclude_operators Character vector of operators to exclude from consideration for linting. #' Default is to include the following "low-precedence" operators: #' `+`, `-`, `~`, `>`, `>=`, `<`, `<=`, `==`, `!=`, `&`, `&&`, `|`, `||`, `<-`, `:=`, `<<-`, `->`, `->>`, #' `=`, `/`, `*`, and any infix operator (exclude infixes by passing `"%%"`). Note that `"="` here includes #' three different operators, from the parser's point of view. To lint only some of these, pass the #' corresponding parse tags (i.e., some of `"EQ_ASSIGN"`, `"EQ_SUB"`, and `"EQ_FORMALS"`; see #' [utils::getParseData()]). #' @param allow_multiple_spaces Logical, default `TRUE`. If `FALSE`, usage like `x = 2` will also be linted; #' excluded by default because such usage can sometimes be used for better code alignment, as is allowed #' by the style guide. #' #' @examples #' # will produce lints #' lint( #' text = "x<-1L", #' linters = infix_spaces_linter() #' ) #' #' lint( #' text = "1:4 %>%sum()", #' linters = infix_spaces_linter() #' ) #' #' # okay #' lint( #' text = "x <- 1L", #' linters = infix_spaces_linter() #' ) #' #' lint( #' text = "1:4 %>% sum()", #' linters = infix_spaces_linter() #' ) #' #' code_lines <- " #' ab <- 1L #' abcdef <- 2L #' " #' writeLines(code_lines) #' lint( #' text = code_lines, #' linters = infix_spaces_linter(allow_multiple_spaces = TRUE) #' ) #' #' lint( #' text = "a||b", #' linters = infix_spaces_linter(exclude_operators = "||") #' ) #' #' lint( #' text = "sum(1:10, na.rm=TRUE)", #' linters = infix_spaces_linter(exclude_operators = "EQ_SUB") #' ) #' #' @evalRd rd_tags("infix_spaces_linter") #' @seealso #' - [linters] for a complete list of linters available in lintr. #' - #' @export infix_spaces_linter <- function(exclude_operators = NULL, allow_multiple_spaces = TRUE) { if (allow_multiple_spaces) { op <- "<" lint_message <- "Put spaces around all infix operators." } else { op <- "!=" lint_message <- "Put exactly one space on each side of infix operators." } infix_tokens <- infix_metadata$xml_tag_exact[ infix_metadata$low_precedence & !infix_metadata$string_value %in% exclude_operators & # parse_tag, not xml_tag, since the former is easier for the user to discover with getParseData() !infix_metadata$parse_tag %in% exclude_operators ] # NB: preceding-sibling::* and not preceding-sibling::expr because # of the foo(a=1) case, where the tree is # NB: parent::*[count(expr | SYMBOL_SUB)) > 1] for the unary case, e.g. x[-1] # SYMBOL_SUB for case with missing argument like alist(a =) # NB: the last not() disables lints inside box::use() declarations global_xpath <- paste0("//", infix_tokens, collapse = "|") xpath <- glue("({global_xpath})[ parent::*[count(expr | SYMBOL_SUB) > 1] and ( ( @line1 = preceding-sibling::*[1]/@line2 and @start {op} preceding-sibling::*[1]/@end + 2 ) or ( @line1 = following-sibling::*[1]/@line1 and following-sibling::*[1]/@start {op} @end + 2 ) ) and not( self::OP-SLASH[ ancestor::expr/preceding-sibling::OP-LEFT-PAREN/preceding-sibling::expr[ ./SYMBOL_PACKAGE[text() = 'box'] and ./SYMBOL_FUNCTION_CALL[text() = 'use'] ] ] ) ]") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = lint_message, type = "style" ) }) } lintr/R/terminal_close_linter.R0000644000176200001440000000252514752731051016314 0ustar liggesusers#' Prohibit close() from terminating a function definition #' #' Functions that end in `close(x)` are almost always better written by using #' `on.exit(close(x))` close to where `x` is defined and/or opened. #' #' @examples #' # will produce lints #' code <- paste( #' "f <- function(fl) {", #' " conn <- file(fl, open = 'r')", #' " readLines(conn)", #' " close(conn)", #' "}", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = terminal_close_linter() #' ) #' #' # okay #' code <- paste( #' "f <- function(fl) {", #' " conn <- file(fl, open = 'r')", #' " on.exit(close(conn))", #' " readLines(conn)", #' "}", #' sep = "\n" #' ) #' writeLines(code) #' lint( #' text = code, #' linters = terminal_close_linter() #' ) #' #' @evalRd rd_tags("terminal_close_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export terminal_close_linter <- make_linter_from_xpath( xpath = " //FUNCTION /following-sibling::expr /expr[last()][ expr/SYMBOL_FUNCTION_CALL[text() = 'close'] or expr[ SYMBOL_FUNCTION_CALL[text() = 'return'] and following-sibling::expr/expr/SYMBOL_FUNCTION_CALL[text() = 'close'] ] ] ", lint_message = "Use on.exit(close(x)) to close connections instead of running it as the last call in a function." ) lintr/R/length_levels_linter.R0000644000176200001440000000134514752731051016146 0ustar liggesusers#' Require usage of nlevels over length(levels(.)) #' #' `length(levels(x))` is the same as `nlevels(x)`, but harder to read. #' #' @examples #' # will produce lints #' lint( #' text = "length(levels(x))", #' linters = length_levels_linter() #' ) #' #' # okay #' lint( #' text = "length(c(levels(x), levels(y)))", #' linters = length_levels_linter() #' ) #' #' @evalRd rd_tags("length_levels_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export length_levels_linter <- make_linter_from_function_xpath( function_names = "levels", xpath = " parent::expr /parent::expr[expr/SYMBOL_FUNCTION_CALL[text() = 'length']] ", lint_message = "nlevels(x) is better than length(levels(x))." ) lintr/R/lintr-package.R0000644000176200001440000000167214752731051014462 0ustar liggesusers#' Lintr #' #' Checks adherence to a given style, syntax errors, and possible semantic issues. #' Supports on the fly checking of R code edited with Emacs, Vim, and Sublime Text. #' #' @seealso [lint()], [lint_package()], [lint_dir()], [linters] #' @keywords internal "_PACKAGE" ## lintr namespace: start #' @importFrom cli cli_inform cli_abort cli_warn #' @importFrom glue glue glue_collapse #' @importFrom rex rex regex re_matches re_substitutes character_class #' @importFrom stats complete.cases na.omit #' @importFrom tools R_user_dir #' @importFrom utils capture.output getParseData globalVariables head relist tail #' @importFrom xml2 as_list #' xml_attr xml_children xml_find_all xml_find_chr xml_find_lgl xml_find_num xml_find_first xml_name xml_text ## lintr namespace: end NULL # make binding available for mock testing # ref: https://testthat.r-lib.org/dev/reference/local_mocked_bindings.html#base-functions unlink <- NULL quit <- NULL lintr/R/sample_int_linter.R0000644000176200001440000000456014752731051015450 0ustar liggesusers#' Require usage of sample.int(n, m, ...) over sample(1:n, m, ...) #' #' [sample.int()] is preferable to `sample()` for the case of sampling numbers #' between 1 and `n`. `sample` calls `sample.int()` "under the hood". #' #' @examples #' # will produce lints #' lint( #' text = "sample(1:10, 2)", #' linters = sample_int_linter() #' ) #' #' lint( #' text = "sample(seq(4), 2)", #' linters = sample_int_linter() #' ) #' #' lint( #' text = "sample(seq_len(8), 2)", #' linters = sample_int_linter() #' ) #' #' # okay #' lint( #' text = "sample(seq(1, 5, by = 2), 2)", #' linters = sample_int_linter() #' ) #' #' lint( #' text = "sample(letters, 2)", #' linters = sample_int_linter() #' ) #' #' @evalRd rd_tags("sample_int_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export sample_int_linter <- function() { # looking for anything like sample(1: that doesn't come after a $ extraction # exclude TRUE/FALSE for sample(replace = TRUE, ...) usage. better # would be match.arg() but this also works. xpath <- glue(" self::*[not(OP-DOLLAR or OP-AT)] /following-sibling::expr[1][ ( expr[1]/NUM_CONST[text() = '1' or text() = '1L'] and OP-COLON ) or expr/SYMBOL_FUNCTION_CALL[text() = 'seq_len'] or ( expr/SYMBOL_FUNCTION_CALL[text() = 'seq'] and ( count(expr) = 2 or ( expr[2]/NUM_CONST[text() = '1' or text() = '1L'] and not(SYMBOL_SUB[ text() = 'by' and not(following-sibling::expr[1]/NUM_CONST[text() = '1' or text() = '1L']) ]) ) ) ) or NUM_CONST[not(text() = 'TRUE' or text() = 'FALSE')] ] /parent::expr ") Linter(linter_level = "expression", function(source_expression) { xml_calls <- source_expression$xml_find_function_calls("sample") bad_expr <- xml_find_all(xml_calls, xpath) first_call <- xp_call_name(bad_expr, depth = 2L) original <- sprintf("%s(n)", first_call) original[!is.na(xml_find_first(bad_expr, "expr[2]/OP-COLON"))] <- "1:n" original[!is.na(xml_find_first(bad_expr, "expr[2]/NUM_CONST"))] <- "n" xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = glue("sample.int(n, m, ...) is preferable to sample({original}, m, ...)."), type = "warning" ) }) } lintr/R/string_boundary_linter.R0000644000176200001440000001441314752731051016524 0ustar liggesusers#' Require usage of `startsWith()` and `endsWith()` over `grepl()`/`substr()` versions #' #' [startsWith()] is used to detect fixed initial substrings; it is more #' readable and more efficient than equivalents using [grepl()] or [substr()]. #' c.f. `startsWith(x, "abc")`, `grepl("^abc", x)`, #' `substr(x, 1L, 3L) == "abc"`. #' #' Ditto for using [endsWith()] to detect fixed terminal substrings. #' #' Note that there is a difference in behavior between how `grepl()` and `startsWith()` #' (and `endsWith()`) handle missing values. In particular, for `grepl()`, `NA` inputs #' are considered `FALSE`, while for `startsWith()`, `NA` inputs have `NA` outputs. #' That means the strict equivalent of `grepl("^abc", x)` is #' `!is.na(x) & startsWith(x, "abc")`. #' #' We lint `grepl()` usages by default because the `!is.na()` version is more explicit #' with respect to `NA` handling -- though documented, the way `grepl()` handles #' missing inputs may be surprising to some users. #' #' @param allow_grepl Logical, default `FALSE`. If `TRUE`, usages with `grepl()` #' are ignored. Some authors may prefer the conciseness offered by `grepl()` whereby #' `NA` input maps to `FALSE` output, which doesn't have a direct equivalent #' with `startsWith()` or `endsWith()`. #' #' @examples #' # will produce lints #' lint( #' text = 'grepl("^a", x)', #' linters = string_boundary_linter() #' ) #' #' lint( #' text = 'grepl("z$", x)', #' linters = string_boundary_linter() #' ) #' #' # okay #' lint( #' text = 'startsWith(x, "a")', #' linters = string_boundary_linter() #' ) #' #' lint( #' text = 'endsWith(x, "z")', #' linters = string_boundary_linter() #' ) #' #' # If missing values are present, the suggested alternative wouldn't be strictly #' # equivalent, so this linter can also be turned off in such cases. #' lint( #' text = 'grepl("z$", x)', #' linters = string_boundary_linter(allow_grepl = TRUE) #' ) #' #' @evalRd rd_tags("string_boundary_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export string_boundary_linter <- function(allow_grepl = FALSE) { str_cond <- xp_and( "string-length(text()) > 3", "contains(text(), '^') or contains(text(), '$')" ) str_detect_xpath <- glue(" following-sibling::expr[2] /STR_CONST[ {str_cond} ] ") str_detect_message_map <- c( both = "Use == to check for an exact string match.", initial = "Use startsWith() to detect a fixed initial substring.", terminal = "Use endsWith() to detect a fixed terminal substring." ) if (!allow_grepl) { grepl_xpath <- glue(" parent::expr[ not(SYMBOL_SUB[ text() = 'ignore.case' and not(following-sibling::expr[1][NUM_CONST[text() = 'FALSE'] or SYMBOL[text() = 'F']]) ]) and not(SYMBOL_SUB[ text() = 'fixed' and not(following-sibling::expr[1][NUM_CONST[text() = 'FALSE'] or SYMBOL[text() = 'F']]) ]) ] /expr[2] /STR_CONST[ {str_cond} ] ") grepl_lint_fmt <- paste( "Use !is.na(x) & %1$s(x, string) to detect a fixed %2$s substring, or,", "if missingness is not a concern, just %1$s()." ) grepl_message_map <- c( both = "Use == to check for an exact string match.", initial = sprintf(grepl_lint_fmt, "startsWith", "initial"), terminal = sprintf(grepl_lint_fmt, "endsWith", "terminal") ) } get_regex_lint_data <- function(xml, xpath) { expr <- xml_find_all(xml, xpath) patterns <- get_r_string(expr) initial_anchor <- startsWith(patterns, "^") terminal_anchor <- endsWith(patterns, "$") search_start <- 1L + initial_anchor search_end <- nchar(patterns) - terminal_anchor can_replace <- is_not_regex(substr(patterns, search_start, search_end)) initial_anchor <- initial_anchor[can_replace] terminal_anchor <- terminal_anchor[can_replace] lint_type <- character(length(initial_anchor)) lint_type[initial_anchor & terminal_anchor] <- "both" lint_type[initial_anchor & !terminal_anchor] <- "initial" lint_type[!initial_anchor & terminal_anchor] <- "terminal" list(lint_expr = expr[can_replace], lint_type = lint_type) } substr_xpath <- glue(" (//EQ | //NE) /parent::expr[ expr[STR_CONST] and expr[ expr[1][SYMBOL_FUNCTION_CALL[text() = 'substr' or text() = 'substring']] and expr[ ( position() = 3 and NUM_CONST[text() = '1' or text() = '1L'] ) or ( position() = 4 and expr[1][SYMBOL_FUNCTION_CALL[text() = 'nchar']] and expr[position() = 2] = preceding-sibling::expr[2] ) ] ] ] ") substr_arg2_xpath <- "string(./expr[expr[1][SYMBOL_FUNCTION_CALL]]/expr[3])" Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content lints <- list() str_detect_lint_data <- get_regex_lint_data( source_expression$xml_find_function_calls("str_detect"), str_detect_xpath ) str_detect_lint_message <- str_detect_message_map[str_detect_lint_data$lint_type] lints <- c(lints, xml_nodes_to_lints( str_detect_lint_data$lint_expr, source_expression = source_expression, lint_message = paste(str_detect_lint_message, "Doing so is more readable and more efficient."), type = "warning" )) if (!allow_grepl) { grepl_lint_data <- get_regex_lint_data(source_expression$xml_find_function_calls("grepl"), grepl_xpath) grepl_lint_message <- grepl_message_map[grepl_lint_data$lint_type] lints <- c(lints, xml_nodes_to_lints( grepl_lint_data$lint_expr, source_expression = source_expression, lint_message = paste(grepl_lint_message, "Doing so is more readable and more efficient."), type = "warning" )) } substr_expr <- xml_find_all(xml, substr_xpath) substr_one <- xml_find_chr(substr_expr, substr_arg2_xpath) %in% c("1", "1L") substr_lint_message <- paste( ifelse( substr_one, "Use startsWith() to detect an initial substring.", "Use endsWith() to detect a terminal substring." ), "Doing so is more readable and more efficient." ) lints <- c(lints, xml_nodes_to_lints(substr_expr, source_expression, substr_lint_message, type = "warning")) lints }) } lintr/R/nested_pipe_linter.R0000644000176200001440000000504514752731051015613 0ustar liggesusers#' Block usage of pipes nested inside other calls #' #' Nesting pipes harms readability; extract sub-steps to separate variables, #' append further pipeline steps, or otherwise refactor such usage away. #' #' @param allow_inline Logical, default `TRUE`, in which case only "inner" #' pipelines which span more than one line are linted. If `FALSE`, even #' "inner" pipelines that fit in one line are linted. #' @param allow_outer_calls Character vector dictating which "outer" #' calls to exempt from the requirement to unnest (see examples). Defaults #' to [try()], [tryCatch()], and [withCallingHandlers()]. #' #' @examples #' # will produce lints #' code <- "df1 %>%\n inner_join(df2 %>%\n select(a, b)\n )" #' writeLines(code) #' lint( #' text = code, #' linters = nested_pipe_linter() #' ) #' #' lint( #' text = "df1 %>% inner_join(df2 %>% select(a, b))", #' linters = nested_pipe_linter(allow_inline = FALSE) #' ) #' #' lint( #' text = "tryCatch(x %>% filter(grp == 'a'), error = identity)", #' linters = nested_pipe_linter(allow_outer_calls = character()) #' ) #' #' # okay #' lint( #' text = "df1 %>% inner_join(df2 %>% select(a, b))", #' linters = nested_pipe_linter() #' ) #' #' code <- "df1 %>%\n inner_join(df2 %>%\n select(a, b)\n )" #' writeLines(code) #' lint( #' text = code, #' linters = nested_pipe_linter(allow_outer_calls = "inner_join") #' ) #' #' lint( #' text = "tryCatch(x %>% filter(grp == 'a'), error = identity)", #' linters = nested_pipe_linter() #' ) #' #' @evalRd rd_tags("nested_pipe_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export nested_pipe_linter <- function( allow_inline = TRUE, allow_outer_calls = c("try", "tryCatch", "withCallingHandlers") ) { multiline_and <- if (allow_inline) "@line1 != @line2 and" else "" xpath <- glue(" (//PIPE | //SPECIAL[{ xp_text_in_table(magrittr_pipes) }]) /parent::expr[{multiline_and} preceding-sibling::expr/SYMBOL_FUNCTION_CALL[ not({ xp_text_in_table(allow_outer_calls) }) and ( text() != 'switch' or parent::expr /following-sibling::expr[1] /*[self::PIPE or self::SPECIAL[{ xp_text_in_table(magrittr_pipes) }]] ) ]] ") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content bad_expr <- xml_find_all(xml, xpath) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = "Don't nest pipes inside other calls.", type = "warning" ) }) } lintr/R/if_not_else_linter.R0000644000176200001440000000604414752731051015602 0ustar liggesusers#' Block statements like if (!A) x else y #' #' `if (!A) x else y` is the same as `if (A) y else x`, but the latter is #' easier to reason about in the `else` case. The former requires #' double negation that can be avoided by switching the statement order. #' #' This only applies in the simple `if/else` case. Statements like #' `if (!A) x else if (B) y else z` don't always have a simpler or #' more readable form. #' #' It also applies to [ifelse()] and the package equivalents #' `dplyr::if_else()` and `data.table::fifelse()`. #' #' @param exceptions Character vector of calls to exclude from linting. #' By default, [is.null()], [is.na()], and [missing()] are excluded #' given the common idiom `!is.na(x)` as "x is present". #' #' @examples #' # will produce lints #' lint( #' text = "if (!A) x else y", #' linters = if_not_else_linter() #' ) #' #' lint( #' text = "if (!A) x else if (!B) y else z", #' linters = if_not_else_linter() #' ) #' #' lint( #' text = "ifelse(!is_treatment, x, y)", #' linters = if_not_else_linter() #' ) #' #' lint( #' text = "if (!is.null(x)) x else 2", #' linters = if_not_else_linter(exceptions = character()) #' ) #' #' # okay #' lint( #' text = "if (A) x else y", #' linters = if_not_else_linter() #' ) #' #' lint( #' text = "if (!A) x else if (B) z else y", #' linters = if_not_else_linter() #' ) #' #' lint( #' text = "ifelse(is_treatment, y, x)", #' linters = if_not_else_linter() #' ) #' #' lint( #' text = "if (!is.null(x)) x else 2", #' linters = if_not_else_linter() #' ) #' #' @evalRd rd_tags("if_not_else_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export if_not_else_linter <- function(exceptions = c("is.null", "is.na", "missing")) { if_xpath <- glue(" //IF[following-sibling::ELSE[not(following-sibling::expr[IF])]] /following-sibling::expr[1][ OP-EXCLAMATION and not(expr[expr[SYMBOL_FUNCTION_CALL[{ xp_text_in_table(exceptions) }]]]) ] ") ifelse_xpath <- glue(" parent::expr[expr[ position() = 2 and OP-EXCLAMATION and not(expr[ OP-EXCLAMATION or expr/SYMBOL_FUNCTION_CALL[{ xp_text_in_table(exceptions) }] ]) ]]") Linter(linter_level = "expression", function(source_expression) { xml <- source_expression$xml_parsed_content ifelse_calls <- source_expression$xml_find_function_calls(ifelse_funs) if_expr <- xml_find_all(xml, if_xpath) if_lints <- xml_nodes_to_lints( if_expr, source_expression = source_expression, lint_message = "Prefer `if (A) x else y` to the less-readable `if (!A) y else x` in a simple if/else statement.", type = "warning" ) ifelse_expr <- xml_find_all(ifelse_calls, ifelse_xpath) ifelse_call <- xp_call_name(ifelse_expr) ifelse_lints <- xml_nodes_to_lints( ifelse_expr, source_expression = source_expression, lint_message = sprintf( "Prefer `%1$s(A, x, y)` to the less-readable `%1$s(!A, y, x)`.", ifelse_call ), type = "warning" ) c(if_lints, ifelse_lints) }) } lintr/vignettes/0000755000176200001440000000000014752763366013435 5ustar liggesuserslintr/vignettes/creating_linters.Rmd0000644000176200001440000003455214752731051017430 0ustar liggesusers--- title: "Creating new linters" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Creating new linters} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- This vignette describes the steps necessary to create a new linter. See the last section for some details specific to writing new linters for `{lintr}`. A good example of a simple linter is the `pipe_call_linter`. ```r #' Pipe call linter #' #' Force explicit calls in magrittr pipes, e.g., #' `1:3 %>% sum()` instead of `1:3 %>% sum`. #' #' @evalRd rd_tags("pipe_call_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export pipe_call_linter <- function() { xpath <- "//expr[preceding-sibling::SPECIAL[text() = '%>%'] and *[1][self::SYMBOL]]" Linter(linter_level = "expression", function(source_expression) { if (!is_lint_level(source_expression, "expression")) { return(list()) } xml <- source_expression$xml_parsed_content if (is.null(xml)) return(list()) bad_expr <- xml2::xml_find_all(xml, xpath) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = "Use explicit calls in magrittr pipes, i.e., `a %>% foo` should be `a %>% foo()`.", type = "warning" ) }) } ``` Let's walk through the parts of the linter individually. ## Writing the linter ## ```r #' Pipe call linter #' #' Force explicit calls in magrittr pipes, e.g., #' `1:3 %>% sum()` instead of `1:3 %>% sum`. ``` Describe the linter, giving it a title and briefly covering the usages that are discouraged when the linter is active. ```r #' @evalRd rd_tags("pipe_call_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export ``` These lines (1) generate a Tags section in the documentation for the linter^[NB: this is a helper function for generating custom Rd styling. See R/linter_tags.R.]; (2) link to the full table of available linters; and (3) mark the function for export. The most unfamiliar here is probably (1), which can be skipped outside of `lintr` itself. ```r pipe_call_linter <- function() { ``` Next, we define the name of the new linter. The convention is to suffix all linter names with `_linter`. All `_linter` functions are function factories that return a closure that will do the actual linting function. We could define additional parameters that are useful for the linter in this function declaration (see, e.g. `assignment_linter`), but `pipe_call_linter` requires no additional arguments. ```r xpath <- "//expr[preceding-sibling::SPECIAL[text() = '%>%'] and *[1][self::SYMBOL]]" ``` Here is the core linter logic. `xpath` is an XPath expression for expressions matching the discouraged usage. `xpath` is saved inside the factory code (as opposed to inside the linter itself) for efficiency. Often, the `xpath` will be somewhat complicated / involve some assembly code using `paste()` or `glue::glue()`[^See `infix_spaces_linter()` for an example of this], in which case it is preferable to execute this code only once when creating the linter; the cached XPath is then re-used on each expression in each file where the linter is run. Let's examine the XPath a bit more closely: ```xpath //expr # global search (//) for 'expr' nodes (R expressions), at any nesting level [ # node[...] looks for any 'node' satisfying conditions in ... preceding-sibling:: # "siblings" are at the same nesting level in XML SPECIAL[ # 'SPECIAL' is the parse token for infix operators like %% or %+% text() = '%>%' # text() returns the string associated with this node ] # and # combine conditions with 'and' * # match any node [1] # match the first such node [self::SYMBOL] # match if the current node is a 'SYMBOL' (i.e., a 'name' in R) ] # ``` Taken together, that means we want to match `expr` nodes preceded by the `%>%` infix operator whose first child node is a `name`. That maps pretty closely to the description of what the `pipe_call_linter` is looking for, but there is subtlety in mapping between the R code you're used to and how they show up in the XML representation. `expr` nodes in particular take some practice to get accustomed to -- use the plentiful XPath-based linters in `lintr` as a guide to get extra practice^[The W3schools tutorials are also quite helpful; see https://www.w3schools.com/xml/xpath_intro.asp]. Note: `xml2` implements XPath 1.0, which lacks some helpful features available in XPath 2.0. ```r Linter(function(source_expression) { ``` This is the closure. It will be called on the `source_expression` variable that contains the top level expressions in the file to be linted. The call to `Linter()` gives this closure the class 'linter' (it also guesses the name of the linter; see `?Linter` for more details). The raw text of the expression is available from `source_file$content`. However, it is not generally possible to implement linters from the raw text -- consider `equals_na_linter`. If we just look for `== NA` in the text of the file, we'll generate many false positives, e.g. in comments (such as `# note: is.na() is the proper way to check == NA`) or inside character literals (such as `warning("don't use == NA to check missingness")`). We're also likely to generate false negatives, for example when `==` and `NA` appear on different lines! Working around these issues using only the un-parsed text in every situation amounts to re-implementing the parser. Therefore it is recommended to work with the tokens from `source_file$parsed_content` or `source_file$xml_parsed_content`, as they are tokenized from the `R` parser. These tokens are obtained from `parse()` and `utils::getParseData()` calls done prior to calling the new linter. `getParseData()` returns a `data.frame` with information from the source parse tree of the file being linted. A list of tokens is available from [r-source/src/main/gram.y](https://github.com/r-devel/r-svn/blob/master/src/main/gram.y#L395-L412). `source_file$xml_parsed_content` uses `xmlparsedata::xml_parse_data()` to convert the `getParseData()` output into an XML tree, which enables writing linter logic in [XPath](https://www.w3schools.com/xml/xpath_intro.asp), a powerful language for expressing paths within the nested XML data structure. Most linters in `lintr` are built using XPath because it is a powerful language for computation on the abstract syntax tree / parse tree. ```r if (!is_lint_level(source_expression, "expression")) { return(list()) } ``` Here, we return early if `source_expression` is not the expression-level object. `get_source_expression()` returns an object that parses the input file in two ways -- once is done expression-by-expression, the other contains all of the expressions in the file. This is done to facilitate caching. Suppose your package has a long source file (e.g., 100s of expressions) -- rather than run linters on every expression every time the file is updated, when caching is activated `lintr` will only run the linter again on expressions that have changed. Note that this check is unnecessary because we provided `linter_level = "expression"` which guarantees that `source_expression` will be at the expression level and not at the file level. Therefore, it is preferable to write expression-level linters whenever possible. Two types of exceptions observed in `lintr` are (1) when several or all expressions are _required_ to ensure the linter logic applies (e.g., `conjunct_test_linter` looks for consecutive calls to `stopifnot()`, which will typically appear on consecutive expressions) or (2) when the linter logic is very simple & fast to compute, so that the overhead of re-running the linter is low (e.g., `single_quotes_linter`). In those cases, use `is_lint_level(source_expression, "file")`. ```r xml <- source_expression$xml_parsed_content bad_expr <- xml2::xml_find_all(xml, xpath) ``` `source_expression$xml_parsed_content` is copied to a local variable (this is not strictly necessary but facilitates debugging). Then `xml2::xml_find_all()` is used to execute the XPath on this particular expression. Keep in mind that it is typically possible for a single expression to generate more than one lint -- for example, `x %>% na.omit %>% sum` will trigger the `pipe_call_linter()` twice^[This is particularly important if you want the `message` field in the resulting `Lint()` to vary depending on the exact violation that's found. For `pipe_call_linter()`, the message is always the same. See `assignment_linter()` for an example where the `message` can vary.]. ```r xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = "Use explicit calls in magrittr pipes, i.e., `a %>% foo` should be `a %>% foo()`.", type = "warning" ) ``` Finally, we pass the matching XML node(s) to `xml_nodes_to_lints()`, which returns `Lint` objects corresponding to any "bad" usages found in `source_expression`. See `?Lint` and `?xml_nodes_to_lints` for details about the arguments. Note that here, the `message` for the lint is always the same, but for many linters, the message is customized to more closely match the observed usage. In such cases, `xml_nodes_to_lint()` can conveniently accept a function in `lint_message` which takes a node as input and converts it to a customized message. See, for example, `seq_linter`. ```r linter_level = "expression" ``` This is a more efficient way to implement the condition `if (!is_lint_level(source_expression, "expression"))`. ## Writing linter tests (NB: this section uses the `assignment_linter()` which has simpler examples than `pipe_continuation_linter()`.) `{lintr}` works best inside the `{testthat}` unit testing framework, in particular, `{lintr}` exports `lintr::expect_lint()` which is designed as a companion to other testthat expectations. You can define tests inside separate `test_that` calls. Most of the linters use the same default form. ```r test_that("returns the correct linting", { ``` You then test a series of expectations for the linter using `expect_lint`. Please see `?expect_lint` for a full description of the parameters. The main three aspects to test are: 1. Linter returns no lints when there is nothing to lint, e.g. ```r expect_no_lint("blah", assignment_linter()) ``` 2. Linter returns a lint when there is something to lint, e.g. ```r expect_lint("blah=1", rex("Use <-, not =, for assignment."), assignment_linter() ) ``` 3. As many edge cases as you can think of that might break it, e.g. ```r expect_lint("fun((blah = fun(1)))", rex("Use <-, not =, for assignment."), assignment_linter() ) ``` You may want to test that additional `lint` attributes are correct, such as the type, line number, column number, e.g. ```r expect_lint("blah=1", list(message = "assignment", line_number = 1, column_number = 5, type = "style"), assignment_linter() ) ``` Finally, it is a good idea to test that your linter reports multiple lints if needed, e.g. ```r expect_lint("blah=1; blah=2", list( list(line_number = 1, column_number = 5), list(line_number = 1, column_number = 13), ), assignment_linter() ) ``` It is always better to write too many tests rather than too few. ## Other utilities for writing custom linters Besides `is_lint_level()`, `{lintr}` also exports some other helpers generally useful for writing custom linters; these are used a lot in the internals of our own helpers, and so they've been tested and demonstrated their utility already. * `get_r_string()`: Whenever your linter needs to examine the value of a character literal (e.g., whether an argument value is set to some string), use this to extract the string exactly as R will see it. This is especially important to make your logic robust to R-4-style raw strings like `R"-(hello)-"`, which is otherwise difficult to express, for example as an XPath. * `xml_find_function_calls()`: Whenever your linter needs to query R function calls, e.g. via the XPath `//SYMBOL_FUNCTION_CALL[text() = 'myfun']`, use this member of `source_expression` to obtain the function call nodes more efficiently. Instead of ```r xml <- source_expression$xml_parsed_content xpath <- "//SYMBOL_FUNCTION_CALL[text() = 'myfun']/parent::expr/some/cond" xml_find_all(xml, xpath) ``` use ```r xml_calls <- source_expression$xml_find_function_calls("myfun") call_xpath <- "some/cond" xml_find_all(xml_calls, call_xpath) ``` * `make_linter_from_xpath()` and `make_linter_from_function_xpath()`: Whenever your linter can be expressed by a static XPath and a static message, use `make_linter_from_xpath()` or, if the XPath starts with `//SYMBOL_FUNCTION_CALL`, use `make_linter_from_function_xpath()`. Instead of `make_linter_from_xpath(xpath = "//SYMBOL_FUNCTION_CALL[text() = 'foo' or text() = 'bar']")`, use `make_linter_from_function_xpath(function_names = c("foo", "bar"), xpath = "SYMBOL_FUNCTION_CALL/cond")`. Very often, such XPaths look like `//SYMBOL_FUNCTION_CALL/parent::expr/cond2`, in which case the `xpath=` is simpler: `xpath = "cond2"`. Another common case is `//SYMBOL_FUNCTION_CALL/parent::expr[exprCond]/furtherCond`, which becomes `xpath = "self::*[exprCond]/furtherCond"`. ## Contributing to `{lintr}` ### More details about writing tests for new `{lintr}` linters The `{lintr}` package uses [testthat](https://github.com/r-lib/testthat) for testing. You can run all of the currently available tests using `devtools::test()`. If you want to run only the tests in a given file use the `filter` argument to `devtools::test()`. Linter tests should be put in the [tests/testthat/](https://github.com/r-lib/lintr/tree/main/tests/testthat) folder. The test filename should be the linter name prefixed by `test-`, e.g. `test-pipe_continuation_linter.R`. ### Adding your linter to the default_linters ## If your linter implements part of the tidyverse style guide you can add it to `default_linters`. This object is created in the file `zzz.R` (this name ensures that it will always run after all the linters are defined). Add your linter name to the `default_linters` list before the `NULL` at the end, and add a corresponding test case to the test script `./tests/testthat/default_linter_testcode.R`. ### Submit pull request ## Push your changes to a branch of your fork of the [lintr](https://github.com/r-lib/lintr) repository, and submit a pull request to get your linter merged into lintr! lintr/vignettes/lintr.Rmd0000644000176200001440000003624514752731051015225 0ustar liggesusers--- title: "Using lintr" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Using lintr} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` This vignette describes how to set up and configure `lintr` for use with projects or packages. ## Running `lintr` on a project Checking an R project for lints can be done with three different functions: - Lint a single file using `lint()`: ``` r lint(filename = "R/bad.R") ``` - Lint a directory using `lint_dir()`: ``` r lint_dir(path = "R") ``` This will apply `lint()` to all R source files matching the `pattern` argument. By default, this means all `.R` files as well as `knitr` formats (e.g. `.Rmd`, `.Rnw`). `lint_dir` is vectorized over `path`, so multiple directories can be linted at the same time. - Lint all relevant directories of an R package using `lint_package()`: ``` r lint_package(path = ".") ``` This will apply `lint_dir()` to all subdirectories usually containing R code in packages: - `R` containing the package implementation. - `tests` containing test code. - `inst` containing sample code or vignettes that will be installed along with the package. - `vignettes` containing package vignettes. - `data-raw` containing code to produce `data` files. For more information about the assumed package structure, see [R Packages](https://r-pkgs.org/structure.html). Note that some linters (e.g. `object_usage_linter()`) require the package to be installed to function properly. `pkgload::load_all()` will also suffice. See `?executing_linters` for more details. ## Configuring linters ### The `.lintr` file The canonical way to configure R projects and packages for linting is to create a `.lintr` file in the project root. This is a file in debian control format (`?read.dcf`), each value of which is evaluated as R code by `lintr` when reading the settings. A minimal `.lintr` file can be generated by running `use_lintr()` in the project directory. Lintr supports per-project configuration of the following fields. - `linters` - see `?linters_with_defaults` for example of specifying only a few non-default linters and `?linters_with_tags` for more fine-grained control. - `exclusions` - a list of filenames to exclude from linting. You can use a named item to exclude only certain lines from a file. - `exclude` - a regex pattern for lines to exclude from linting. Default is "\# nolint" - `exclude_start` - a regex pattern to start exclusion range. Default is "\# nolint start" - `exclude_end` - a regex pattern to end exclusion range. Default is "\# nolint end" - `encoding` - the encoding used for source files. Default inferred from .Rproj or DESCRIPTION files, fallback to UTF-8 ### .lintr File Example Below is an example .lintr file that uses 120 character line lengths, disables `commented_code_linter`, excludes a couple of files. ``` yaml linters: linters_with_defaults( line_length_linter(120), commented_code_linter = NULL ) exclusions: list( "inst/doc/creating_linters.R" = 1, "inst/example/bad.R", "tests/testthat/exclusions-test" ) ``` ### Other configuration options More generally, `lintr` searches for a settings file according to following prioritized list. The first one found, if any, will be used: 1. If `options("lintr.linter_file")` is an absolute path, this file will be used. The default for this option is `".lintr"` or the value of the environment variable `R_LINTR_LINTER_FILE`, if set. 2. A project-local linter file; that is, either 1. a linter file (that is, a file named like `lintr.linter_file`) in the currently-searched directory, i.e. the directory of the file passed to `lint()`; or 2. a linter file in the `.github/linters` child directory of the currently-searched directory. 3. A project-local linter file in the closest parent directory of the currently-searched directory, starting from the deepest path, moving upwards one level at a time. When run from `lint_package()`, this directory can differ for each linted file. 4. A linter file in the user's `HOME` directory. 5. A linter file called `config` in the user's configuration path (given by `tools::R_user_dir("lintr", which = "config")`). If no linter file is found, only default settings take effect (see [defaults](#defaults)). ### Using `options()` Values in `options()`, if they are not `NULL`, take precedence over those in the linter file (e.g. `.lintr`). Note that the key `option_name` in the linter file translates to an R option `lintr.option_name`. For example, `options(lintr.exclude = "# skip lint")` will take precedence over `exclude: # nolint` in the linter file. ### Using arguments to `lint()` The settings can also be passed as arguments to linting functions directly. In case of `exclusions`, these will be combined with the globally parsed settings. Other settings will be overridden. If only the specified settings should be changed, and the remaining settings should be taken directly from the defaults, the argument `parse_settings = FALSE` can be added to the function calls. This will suppress reading of the `.lintr` configuration. This is particularly useful for tests which should not exclude example files containing lints while the package-level `.lintr` excludes those files because the lints are intentional. ### Defaults {#defaults} The default settings of `lintr` are intended to conform to the [tidyverse style guide](https://style.tidyverse.org/). However, the behavior can be customized using different methods. Apart from `lintr.linter_file`, which defaults to `".lintr"`, there are the following settings: ```{r show_default_settings, echo = FALSE} default_settings <- lintr::default_settings default_settings$linters <- "`lintr::default_linters`" default_settings$comment_token <- "(lintr-bot comment token for automatic GitHub comments)" default_settings$exclusions <- "(empty)" make_string <- function(x) { if (inherits(x, "regex")) { paste0("regex: `", x, "`") } else { as.character(x) } } defaults_table <- data.frame(default = vapply(default_settings, make_string, character(1L))) # avoid conflict when loading lintr in echo=TRUE cell below rm(default_settings) knitr::kable(defaults_table) ``` Note that the default `encoding` setting depends on the file to be linted. If an Encoding is found in a `.Rproj` file or a `DESCRIPTION` file, that encoding overrides the default of UTF-8. #### Customizing active linters If you only want to customize some linters, you can use the helper function `linters_with_defaults()`, which will keep all unnamed linters with the default settings. Disable a linter by passing `NULL`. For example, to set the line length limit to 120 characters and globally disable the `whitespace_linter()`, you can put this into your `.lintr`: ``` r linters: linters_with_defaults( line_length_linter = line_length_linter(120L), whitespace_linter = NULL ) ``` By default, the following linters are enabled. Where applicable, the default settings are also shown. ```{r show_linter_defaults, echo = FALSE} library(lintr) # needed here for formalArgs default_linters <- lintr::default_linters linters_with_args <- lapply( setNames(nm = intersect(names(default_linters), lintr::available_linters(tags = "configurable")$linter)), formalArgs ) make_setting_string <- function(linter_name) { linter_args <- linters_with_args[[linter_name]] if (is.null(linter_args)) { return("") } arglist <- vapply(linter_args, function(arg) { env <- environment(default_linters[[linter_name]]) deparse(env[[arg]]) }, character(1L)) paste0(linter_args, " = ", arglist, collapse = ", ") } defaults_table <- data.frame( row.names = names(default_linters), settings = vapply(names(default_linters), make_setting_string, character(1L)) ) knitr::kable(defaults_table) ``` Another way to customize linters is by specifying tags in `linters_with_tags()`. The available tags are listed below: ```{r show_tags} lintr::available_tags(packages = "lintr") ``` You can select tags of interest to see which linters are included: ```{r show_tag_linters} linters <- lintr::linters_with_tags(tags = c("package_development", "readability")) names(linters) ``` You can include tag-based linters in the configuration file, and customize them further: ```yaml linters: linters_with_tags( tags = c("package_development", "readability"), yoda_test_linter = NULL ) ``` #### Using all available linters The default lintr configuration includes only linters relevant to the tidyverse style guide, but there are many other linters available in `{lintr}`. You can see a list of all available linters using ```{r show_all_linter_names} names(lintr::all_linters()) ``` If you want to use all available linters, you can include this in your `.lintr` file: ```yaml linters: all_linters() ``` If you want to use all available linters *except* a few, you can exclude them using `NULL`: ```yaml linters: all_linters( commented_code_linter = NULL, implicit_integer_linter = NULL ) ``` #### Advanced: programmatic retrieval of linters For some use cases, it may be useful to specify linters by string instead of by name, i.e. `"assignment_linter"` instead of writing out `assignment_linter()`. Beware that in such cases, a simple `get()` is not enough: ```{r programmatic_lintr} library(lintr) linter_name <- "assignment_linter" show_lint <- function(l) { lint_df <- as.data.frame(l) print(lint_df[, c("line_number", "message", "linter")]) } hline <- function() cat(strrep("-", getOption("width") - 5L), "\n", sep = "") withr::with_tempfile("tmp", { writeLines("a = 1", tmp) # linter column is just 'get' show_lint(lint(tmp, linters = get(linter_name)())) hline() this_linter <- get(linter_name)() attr(this_linter, "name") <- linter_name # linter column is 'assignment_linter' show_lint(lint(tmp, linters = this_linter)) hline() # more concise alternative for this case: use eval(call(.)) show_lint(lint(tmp, linters = eval(call(linter_name)))) }) ``` ## Exclusions Sometimes, linters should not be globally disabled. Instead, one might want to exclude some code from linting altogether or selectively disable some linters on some part of the code. > Note that the preferred way of excluding lints from source code is to use the narrowest possible scope and specify exactly which linters should not throw a lint on a marked line. > This prevents accidental suppression of justified lints that happen to be on the same line as a lint that needs to be suppressed. ### Excluding lines of code Within source files, special comments can be used to exclude single lines of code from linting. All lints produced on the marked line are excluded from the results. By default, this special comment is `# nolint`: **file.R** ``` r X = 42L # -------------- this comment overflows the default 80 chars line length. ``` `> lint("file.R")` ```{r show_long_line_lint, echo = FALSE} lint("X = 42L # -------------- this comment overflows the default 80 chars line length.\n", parse_settings = FALSE ) ``` **file2.R** ``` r X = 42L # nolint ------ this comment overflows the default 80 chars line length. ``` `> lint("file2.R")` ```{r show_nolint, echo = FALSE} lint("X = 42L # nolint ------ this comment overflows the default 80 chars line length.\n", parse_settings = FALSE ) ``` Observe how all lints were suppressed and no output is shown. Sometimes, only a specific linter needs to be excluded. In this case, the *name* of the linter can be appended to the `# nolint` comment preceded by a colon and terminated by a dot. ### Excluding only some linters **file3.R** ``` r X = 42L # nolint: object_name_linter. this comment overflows the default 80 chars line length. ``` `> lint("file3.R")` ```{r show_long_line_lint_not_skipped, echo = FALSE} lint("X = 42L # nolint: object_name_linter. this comment overflows the default 80 chars line length.\n", parse_settings = FALSE ) ``` Observe how only the `object_name_linter` was suppressed. This is preferable to blanket `# nolint` statements because blanket exclusions may accidentally silence a linter that was not intentionally suppressed. Multiple linters can be specified by listing them with a comma as a separator: **file4.R** ``` r X = 42L # nolint: object_name_linter, line_length_linter. this comment overflows the default 80 chars line length. ``` `> lint("file4.R")` ```{r show_nolint_multiple, echo = FALSE} lint( paste( "X = 42L", "# nolint: object_name_linter, line_length_linter. this comment overflows the default 80 chars line length.\n" ), parse_settings = FALSE ) ``` You can also specify the linter names by a unique prefix instead of their full name: **file5.R** ``` r X = 42L # nolint: object_name, line_len. this comment still overflows the default 80 chars line length. ``` `> lint("file5.R")` ```{r show_nolint_abbrev, echo = FALSE} lint( paste( "X = 42L", "# nolint: object_name, line_len. this comment still overflows the default 80 chars line length.\n" ), parse_settings = FALSE ) ``` ### Excluding multiple lines of codes If any or all linters should be disabled for a contiguous block of code, the `exclude_start` and `exclude_end` patterns can be used. They default to `# nolint start` and `# nolint end` respectively. `# nolint start` accepts the same syntax as `# nolint` to disable specific linters in the following lines until a `# nolint end` is encountered. ``` r # x <- 42L # print(x) ``` ```{r show_comment_code_lint, echo = FALSE} lint("# x <- 42L\n# print(x)\n", parse_settings = FALSE) ``` ``` r # nolint start: commented_code_linter. # x <- 42L # print(x) # nolint end ``` ```{r show_comment_code_nolint, echo = FALSE} lint("# nolint start: commented_code_linter.\n# x <- 42L\n# print(x)\n# nolint end\n", parse_settings = FALSE ) ``` (No lints) ### Excluding lines via the config file Individual lines can also be excluded via the config file by setting the key `exclusions` to a list with elements corresponding to different files. To exclude all lints for line 1 of file `R/bad.R` and `line_length_linter` for lines 4 to 6 of the same file, one can set ``` r exclusions: list( "R/bad.R" = list( 1, # global exclusions are unnamed line_length_linter = 4:6 ) ) ``` All paths are interpreted relative to the location of the `.lintr` file. ### Excluding files completely The linter configuration can also be used to exclude a file entirely, or a linter for a file entirely. Use the sentinel line number `Inf` to mark all lines as excluded within a file. If a file is only given as a character vector, full exclusion is implied. ``` r exclusions: list( # excluded from all lints: "R/excluded1.R", "R/excluded2.R" = Inf, "R/excluded3.R" = list(Inf), # excluded from line_length_linter: "R/no-line-length.R" = list( line_length_linter = Inf ) ) ``` ### Excluding directories completely Entire directories are also recognized when supplied as strings in the `exclusions` key. For example, to exclude the `renv` folder from linting in a R project using `renv`, set ``` r exclusions: list( "renv" ) ``` This is particularly useful for projects which include external code in subdirectories. lintr/vignettes/atom.png0000644000176200001440000007451614752731051015102 0ustar liggesusers‰PNG  IHDRž­¹Fž¢PLTEôôôDDDÞÞÞæææðððÝÝÝçççÿÿÿÿÿÖÿHÛÛÛáááÚÚÚèè蟟Ÿüúýùùøààà÷÷÷âââäääÌ{{{¹¹¹õõßùùùõõöõà®õ÷ùÊõôàõõù÷õ÷õô®ßõôÉŒl®á===õõÊÊõFDGõöí®kŒ"""ôôÀá­hÀÀ‰bKÿÿéÈŒjjÊšK}EIfÿå÷ÒÒÒ‹k­¹{^WVVÂòøbID÷ß¡F‰ÆƒÁôõÙ¨¨nKšÓõß®Œÿë¼³Þ×éõõ÷亹äö¿ëöޝßéÿÿÙö÷ÿÌŒÊÊM[€ÏÏÏk¨ÙX}ºÐ•UW‘ËÊGã¯nøÍPIDÑëöFk¬ûöØw¸éîííöîÕúÖš•••S×¢ÞõúìÊÝ£OƒƒÀ|J™ÿÒêØ©lØ¥€„¼çÊùøîõõ´éÿ຃ŽKŒ¼}ITp®Çëÿ¤ŠÂ‰SšZVNj–ÞDøùçÿ{ÖÖÖ]MŒÆÆÆÝݲÓÿÿ©©©‚£Þoj¬ÿÿ÷ì·sn]\áYPÿá‡êìêõÿÿDIRÿâîçÈ“ÿŠs”H@ÿ¿Þ|R|¦Úøëùúk˜µéÞÞj|»Ž‰þäÞšššÿÿЭŒ®ÿWVoþè¯óäÅ¡„ak™Ñßy‚¢g9ÿ^rK=É“zW‰ÁüLT_£ÌÝʪd]’M!‹AjËÞÓœgÿõǃºÞ蛜@IŒÿô‡Îþø¿¨mnnÝÝÍÿHfˆ¤°°±J[%ýg-É–gßæîüY‚ÇÿOhÉ‚^«ãê¹´–°•j\”20.³ÝëVSœ„b›×!ÿ¨ „…… %Y žÅöÐË­£náöÓ$\§ÛŽÐÿ£ÃiS{°g$ÿ÷â²¶ƒ¨~£âÊ¥Ôu±Éy´¨æUüu»ÿ¡fêP¢à­åäÌü~‚AwÿH9¼ž e—ÿÔLšŸ¶kFlÖ¯žÿÁ/ÛŽëÕ¶ LžÊóÓçéÿßkRPMËÝêÿ^K] X¤Å®,S÷Û IDATxÚìLçÇ‹±}`LY¶Ì™"e™@² äšIŒC](cJR缆eÀL”-*«¨ aò<gGñÄIú#°Ô-BJ–X©ºi‘Õ¥¨¤ L£ Q˜æ-íªLZ”nRº÷}ï‡ïû° `ßñ|ßÄØwçó{ÜÇÏóþxÞ œ P–ªà…R!(YV*8< A l&”àIhå¶À#ÚC<-OL§iA1ø+r‘ÙãOpP4]LˆPb=1ª èôyŒR…Ïb€¢«bÂî[OL£IYüFMÉ¿ð  h»`>9_äù©¿¹gô8²MïxüŒo€§ÃY”aÑ÷j|oš$„£7UMU꺦~†¼ÎšÅ¾',ÀSA[l9œûj£*žùg¤xü!UÝÞM?¸ô‡Þö)kX3âùÈë©6êúH¥J§¾=纲ízã>°T8 A0²}ç\í{ÐÁo¾ìšú>o<ûÊ™ºWB”wï\Áµ _d˜77‘]õÌã)±šü3~ tÈ94Ôb~ŒGF‘5mI³kT žùøùƒÖÏ¿`<#Æ÷v'Ó]ˆ'Ùp“?2žeÜBá(þùy·È^ÙÑÝÔ¡ò&ÊË´oîÜAÑGÝ4ïÖÚÁ»ëÏ)ã¹Ðzn¡¨Ú^µ®Rgãx^© GgÜ“S'Îï¦èÙ©ÔðSmáèT1zÑF±Gš¸þÑÜ Ýëö~Æ![{øuôÙ'Èg“m  ã™À©‹Cô7ð óº¥ ,U§íÜóDëÙ$ÇSéܱýTày˜œqà90‰ æ-ŒçMî]teS¼êt xz¬º8ž§Éú§”LZ϶Ž-Ë:î™~׈XÏRÁS´ž×g]q<‡%Ö³)±õäñä;}‘XÏó!Ïð§¯Ç?Dtî§ϵ…çÈÉÀËáI?øÉ†'½ ð\8èÃãù ¾Í)àɾ*4-KùÆ©KÚýa(ŽgC„xîj{î,/¦<éÊí"Š—Å®Ñ[€gF{l™‡åÙù~¤Ç©lóKOz#oû{SÀS°žÈtN};Ç“¢?Žrx6¾cæ!¨ž PjxJÜ{,+;7»$L1ÖžNgLÒ;jIß~‚õž 5Ús‰Þýä² Ï¡ØÚÌ5ž Ðs:÷,ÀÓ„ØJPýme25õ¯¿òœõð»5p'@«†';~º+ùÇÊ35ÇÁv‚VÑzn@ÿú:’¬<Ò&@ Ê]¹¿¢†§<™ÃùbJjKfòÍ×È °T²:xïí¢v¢:g°”Ÿ|`‰®Dí¾7Hžá`·•ã”cºrKˆn%ÉÇžµ'N²ûŽúcŒgÞÅ:¼j‘Ú’™ª]#± u·O½áI?êï¿~@å=$ÏôÜßg˜? D<aÈÁb_>ÌãÉpýïñ¼MÛÊ0ƒ¯ŒïðTY2s‘%¡Ô\9 XÏpÖCÀR+Î=U¥=îÉ/Æž ÀðéOðž‰ðÌ‚ÔM¡ > x¯x‚OÀx‚@€'ðÔ/žôÕªÌ|°wæþÕñ¼ÿH%žn1»FI‚—<ÿÏÞùÆ6qÞq|™ªû¦do²Ñ"1/22zÀ‹ØQˆŒ(uT!È Å"cHÓJE*LxƒWÎödi/¬$Î0T“¨bFëxÂcE‘P› š˜PnŶÉUÑ1ö¢{žçîüç|÷ølŸSÇþ~ÅÇñùœ»O~¿çw÷|ŸßUÕšôÅÓ=ŠŸDóís¶/~!¥6†„ëï®þ:@ŽC«'ÜÊ~ŠÖ!.žrrWœ‚ÁlùíBxæZáÔè™ç³ºIÆÊNüF>KVÐø¡ø,E{'a3¼©MpßöŽÊù¥/pÈ»­ÎrÙT¢1;õײðÜžî(ïÎM÷•Æ“|J?}¬à)¬»øÁ56€ö¼èéžkyþ‰Õ‰ž_²6øžÈ‘ôˆè];òèR¸u(ÜÊz¸•ÑŠ#c<7ÇBåã™ç³Ô˜)Œ}–*žiŸewGß)ó†Oˆ{;Y‡Ä}gå­Í³†x^ O_¢x®x_ÙWÏþÌkd¼¦ÿãË$¬ÍàrrüÇ A >щž$öþâ)ÿÚ„é×”×TǶù5ÎL\èéVwÅöר.žtª·Ë*r|–̈©ÅÓ8¹gGOú&žý[%ÉÙ–MOÑüÔ%GOíÍ0¹+xƧ¯…4ÑSƒ§ô³×¾ÒKî¹Ñ3Nã\\)j¢ç%%zÊxÚÑãp}cèúš…­oÝè2Æ32øDa1“ÜÀSïéÞÒ/,) \õY¦˜yx–F žªÏÒ=1êÚŠnݲƒ^r {w ½ôëU¥‘‚gäJ‡pæЧûî.žë.ˆ³ìîVÙæ=žd”ø_qr†~úžœ…w´Ñ“$ùíÂ:=ù¦ka~Êø¨:ƒ3êÁÈü`À³x<³eˆ§ê³T˜:xê_XJã©ú,#ºMÆë)l&ïüõi]¨žbM Éô»P©Dtú[AõŠgoêwT¾S³åÝÜ[“¶ f›JQ<ãÀxªjLXš?Y;ãCǹiÐ3ĺ¬ét [Þ¼Z²xŠ©.þ6<§¦_±ÂIãç}‚¸eÊæUšge©ýÊÝN^ŠŸ‰>ÿ§<XOmn¿w95r¯« ž/r£'m0NæEÏ–+ÿÞÎ’TîŸs!jBºx¦b!á«ÂV8§¦šÜã§~£+?¹KÝÍr/uñass³Nßj–Ü#¬áðž:ÑÓ%÷}5—Üð$y¾Cgì)–Œ'šLO6öÜ-³©Ýe–FÎã?asÝ‹Oî¼è™žuާŒ…¤¯Þ0Æ€ïÔ¤mØi özÿá.¥C«PLižŠSÓ<§Í->ËëÊ Õ"žÒÇ­ÉoZ¨pYž=cz³8—î¾ú©/ë+^WN¨ñÜ7_¢Nuj<ß 8v†Û¦[;V‘·Áá8¹Rž:‘3_<¨ø;rá °·ò8·ÑרײNÜò–¹xò:#Aµˆg2&”†g&z:6º"!ÁæýèׂÀ%zÏ%޹„ñ].É> ¯Ù‡Í;u§ÀËÑÓ¶‰ý{ºßæ]÷³-g]ã¹gt·i< ¬p„Hò<O@û¾:y€g£ÊlÿQä}ÅÚán&º”‡§hï$Û„7µõQ2É–ëš™²]tÀ³®ðLÆBeã¹KÅS†OmU¬älóx Ý}§<Î>öÆ¢½ÃOX9ëÏÞ·)œéÒ(ÏÈìÿp^9ÞËOî‚ß³ë£ä.—[ŽžCüä¯\Íã¹ù nÕ=ü"ïÂ’âÔÔâ9kßÈÜuR÷€¶êÒ/(ŠŠš{bÔµÿÔ^=Ç\À³¾ñœM½Îݦ1뱑S3Oa–Tîú$ù¾ã¶ÏÄ…%aózR¹ ‘€‡ ÈÖyV®ýµxfºrBõQ¹›njBÀžÀžuñP—&gÂÀ³VÇžRrd„×äº8<Óä(ÑÓèdö8mô4çóO¤è ›@¯ÅSùPÔþôð¬Yuf¼šÜÝ7ÎN…ŠJîY)^3ÏìâˆvFž5=öÜÆY‡¡LžÌCÜ;ê3܆Û×xBų7µ]H$M{4ú‚ =ÿ(OÇD"ÈúÒh_jdþO£%[á„#Ñ962èµ;?!«ñL@M%÷|<…²“‚EÏåÌ-¹G²O‰×1›[Qõ1<³ÆžË'dž‰ä=Ž¿1å\X¢‘7È–òÈÂsxBá)-ŒÌß2[Ôäá > ¡r‡*˜Ü…RñÌxB•*,À³75¡jÅSB ªŽžŒO Kqà UìÂRÀA4@Êö šßMí•;´Xѳ„}O¨ªñÄMM¨jñT§„ÜÄÙ€ª2¹35ÜÁ逪Oð Už?&O>~Ü>¡Šài‰ã“àÙp ÆW¨º|îÙx‚O¨šñŸPUâÙ(ãÙpç[KC¯¼Üˆs_7x6¾Ð°Ätç;/ãä× žß}i©áÙð½?—ž{Rò’œ‰N_=½òí%‡çÿ^Bø\RxJÉØÃsÛÿÙ9 ¦ò;Ž¿P ‚¤B^^!1$ B\.Q® "dD‘]¡¸°Ë¡Ãr¸*1;¬rT:õÀ©Žº]uë"MÝCwt±]¥¥ÎhwG·£YíÚ©Óv†:Óÿ‘„‚. )¿/øxïÏÿxÇÇïï½Çÿ—?Ý{N</§Ã“ç+‚«ïLxߨFðœ»ü—É“OÀÓÉ‚;ʼn›xz1põÏvÏ™ŽD«)/Ïp ›€'h¬ñœ9s”|Îp(Àx‚&ѽ'à ÷´¯úX‹ ¥ÁC`Z×ëx<ƒg‹À´x:#žù߇¤ýù¶âŸÿXòÂxöÎîE‹©& ñ–]<;»»»;ÇÏå–ž¼àéÜîù²rO‚'†²-{§¢Í^ºm…g?N—ïìêºO]]M÷;›ºš,ñÔõð†X}AA=Ï_ÇLÙ׫çõ¸zbý\õá®®á<ÁƳȓaW-pe ñ$¶*ˆ\<'=žSñ?l¤xk6Z³Å³£«kSWwW^\C?ú;;ú;û7Ùà©óëC様_ïeØë+p+âõÔïõ+,7ô¹õù՘ܓ–ùíõw 5×}nþpï xšÂùlågšðìµÜ ž×f4‘òÒûˆÍ¦ûvÜ/½öbô4ðz¦…Suõzâ˜õºsp§%zËàN5__ <O#ŒS㉃;"“.šú75a<‡Þ{b0ÝžE^E¤(ÀS?€YÐ ôá”K ?†ÑÜzƒþ= ÓRÏk\îÊ´ô¡Qô :ÖiIc¬kl,à x¾Â÷žÊáß"ÙüÚÎüÎÀð|U¯åmñY¦×ò€'à ÔMD܉¤õƒ±™4xº³®Ó\<¼œG.Ó\Á<'žîÞ¬ˆq"Á(N.S k<]<<Üì~ùÒZðG«OᔂÆOâ0¢µø£œRИã9Œyºž pOÈ{z¼÷ö‡gy ëž;êøwRùü¶[–4–Þ²gXÃO?Ï®Ì ±-ÛŸ8R“Ü“ë÷›üþÍ•Ixú#K´iü¯oZ%Ö2µZ´Œ§{¾÷ö[vË<ñ‘÷¼“É/ýfÿÕoê,iÜQ7fx†Ùâ©úí:Ÿ‘šˆ}FѯL>d³Ä„§mã’“šaðœ“IJA@˸¹'”¸çÙCGrÊÔêïÎF$Zß{¶7?în»õ øjŒû¹ý¥çJûÝS÷—f¶/öίCe vð,<¤ŒI­¹“Yš_Ûö¤=µ¶4Õž Ù¬*.…ýÙHïùß°4!ÙùùGÓ“·,*˯ Áv&Ôàñ0©pÖº ªl¶ø@0w7ÝGŠ€Ù\ùâ­KØ Ü³”Óž®aeÕ´#înFq„\µ!„)Ôd³²q®·Ä^˲²¯Å%I>f<ϬeUq5ln5Ý¿*‚§P#g}òwV°É[$Ô=KÔGV¯ZÆÙ=£E-ú]Ô¢¡…‡µ{^ínOxp®íéÕ6o÷̘'ü˜'(Þ#<ö—6·=½ÐnOî®6M±“g4°BM¶OÐи+- ^)—2Šy4¸#Ys Î’(ÞYLjÂB¸H‚˜ðDc^¢ðô®U î™á´ÜÖ4Ü–v„*! Y¢G‡ö IDATò6ZW, îÂ×xÇ® wìž ˜Ð=Š›èÆòßÄ`EÏäߣ­ä_2âª7)žbvóŠD eÜÝ“àùÙÇO7ë'÷¶î§W»;êÚ‹±{fòÉ7³™ðl~låžkG3ÄÂò¯þóÎ:–%&Ú\þÕ dãMa“³08 -CMxZ¹'ÂS‚aç"IAÙá@.Rt¯±÷Œ‚;·Çˆ'îUB-0ždH¼n‰ç9Ÿ'$ÚàùVè÷¦ý3¹g"“.Lx¢}O<'ˆ{VûÎŽ{òÛçÖ]hKåßñžÛmçïm–xŠr³2˜íÕŒHw£*Û4šhúær-²>–x&oÉP•åHÃèý•{2¨õÁéFv%C#—׆šSnÙñ”(ë&ösœ(ü£–µ<=Æ o[îÖ>é=ãZžÿ¿4™¹–°ú©Áw^D^'¬ÐèÃŽøX“šÜ °ï™7R“ä)¤<˹Zûdÿ.ðA qx YÊSšå˜ù Íh ϧúž¡™\\§[~vtpr2† ¸&ŒˆMñ©äɧÐ@(2vÙ†t};B[Ôºœã¸0#çg¦qr‡“޼'-(ã@yöï•o*yP®÷”®þ³U ©~[ûï= ®ÆíW×=`¥e Õ¨’§¶¸~ã)XÎr3xNöéýíhr?Ž O6…®Oú9m ø-¥;Òi¨:t»ýv®ñäŽe¥WÅ1¡‘ƒS-kyzŒÁûŒÚ?â“*jI0Ä©=úSÄ—Æ‘tHòLO>³0¹caìBCYžî9BË“3¦}SZ¶;#rÉ3¦ ÕÈ×ׯ±<Ý~ÉÕù¹7ÄëQ]m2[-XHÛ&y®c¤äÉÍÐ9Û§dôNÐDöëR9aë}"FMîÒ„öíÝ‘Ý3üJOl¤6å–µû|†NFXL Ð/O2ÆhüæäÒ¨m.‡<“s¼]8§ƒÑ‡íøOz¬ÉÙ®÷Ì+©]ÙµgfרwZíHí®=òLß?ÚõWTÀ˜‰¶Z…\J#ؽ8ñrq(ø1~Œ9ÃD\, ĦŸøÄœ- †8…ý¢SsŸ CÞË5þ§ÿ,åÂÜBCIžm+MtB£påIEu“SõëDny*H5ý¤¢çËÓíW¯Ü1NÊuݯ¸ø,¤mc÷•W`NÍÐ9ÚG.rpÛ®|q´ë™#·;H“ÊŽð`hktÿ¨´Œ…/¤xär‡ µè²¢í/¨-2rÐb<@¿<É(Ït߃Í'ìê2~yÚÙ•ºÇ0 ŽÕñÔ¢ãËK_Á?ò§´]ï™WR–ôàØËʙ”³Ün‰ÆE‰£Í0®„­ÀÈ}—sÚ<Õ‚À'´³tTN+n3c¤ˆM/ñ‰9Df®B£p ™w’ùgå|«¡% ¥ ¶âj¸Dð&<µÕC phsWÉ!ËájÜ~yqRªKf ÁA‰*…6u3pŽöQ°C!+úõQ>vd=X¯G¡3ê›jqËÎöLðˆrZ [êÛóƒî áà€™Í•…µ@f(Áo‹ju¶pŸñ»&57¸q‘þõA<÷=¹«Ýïî/½|Géû“òlŸä\WG1ÿÕè»#57 2£Öº/%Œ¾Ë·~YÏ<ÛÇ.Z˜Ç‘M*ú¿¹›d’‘§I&yšdäi’IFž&yRÓ¤b–§!5M*byÖȤb–§!5M2ÞÓ$“vè=óJjf{ZEp+xk‰\޼ŒñCjë#Žäg×g¼3ë?ºöih¨7³CSåÀƸ;¡Êü!DsÕÀ§Ázà¨gdõ¹ J¼èûd¤2yw]¤²¯n©)V(yæ›Ô¸ªmå¹Ó7“§r@PdÁõGýàÕå™lìŒçüh³×†¿+yVïPžÕ9åéšpsy®TÚ–5ú07RiYCwSóžy&5m ÎþÑKž+%Rcb~H€aZ±ƒÉCɹ]{@6NH0Á‘öLˆšr ¢‰häáRâëß®\ín…çlM$˜1@ABô®©ÏbðM3 Œç ¡–C™t](,‘kÿýþÁOj¯N B¥±CŸÃ^¦žT®O@/üУÛ+&¡H«2¬Ù,ë—c¢b“L,Ó@•â8ƒà(õ˜-¦­HU*n†TÊÖøÉÏ R)Í)¬÷ÌcLÍšã¢þÙ£öì"“‚[~˜dÀP±ƒÉC¶üé;D6Jy"¹(åI×·cMD#—G(3Ž\€gÖšH0c€‚„:Ã$OªÏh äéºPX"×Þmw“ ¦3ø¬öÙÇTjy¡GÕ+,ÂD(⦠kt:PèÆØ¤Ö¹x,„ã ‚£lÔcB¬][ÑŸ6E*ÇêþE€á¤òÀòã)§ÀÞ315xyµ±³:seX“‚Ž`üCÅB`,š™¤œÀ{ž¡9ÓOU5¶bMœœ—GXŸpìêr`¼šˆðb‚tå© 4ž5ÑI- …%ªÚEÙSG^g˜³ëúìc*µ<ƒÐ£îáJ71¬éP`P˜¤7Æ&ýò|êÐ8ƒà(uMHaG•}is¤2 LuN¤Ò¶FæR÷žùŠ©¾õö¦3pGÎàD Âr‰ñC ;¸Fž¥lØ 5ƒh²<‰#„ãêa¡‰3)HçËN”òü{çûUvÆñ“?að…ÌÜÉL& G&ƒ!ë‚’5c”51ˆYbâ¦þ â¯à/\•lŠP™Â"‹¬)öE¡[ƒAK1v)‹¥ –-E»mm—Rº ]ØRßÙ÷¾+=Ïó}Î;™‘˜L6cöý™QÃãùLJ¼g–Äp–N—U×ý—/2¹ñŸ¼ŽÂ¢©[®“/)†À’âé¹9ù-#ñt7§™%t©È*‰ú´ÿ@tš£uc¤û2`'}¨äíݾcSñ%Í×."'úŠI“ RŽQù˜<’þ7¹.÷ñ?hõ\ÃٚЩÞö4«Žô¯ÑÕ³¤&HHð“úÇJ§Ú~+7’af’Ä™ 5¦‡ [w¤ŽÜTw>æØä=uŽ>BG^úŠIÓõ‚c'm}ö2NŽgÔ17ûÛ}¹5»z6ŠÔt"Küâ{ßþf‘DÄLBý¦¦)žï œh·8s¥‰'#‘†r¤Ga@%ž7½x*ƒ|ŠÀ’=›Sâé<äæ´S pç+VVYÏÂô;5Úöà/zоc’ôlG}IÓÅ“^„ -&/›|”¹<†“Þ¦—ßÊQµ¶WÏšFdIü$ïÒþ>š#Ž˜IÚƒ3Ô¨wîFÍ ¹lÁßMèIOK9ÒÏà#%"bÑÔo®ÓXãtĸ9%ž`.›ÓNwîÔÙÉ*ãñœì=˜µSã¹<»•‹96ýx¢¯3iv¸»ž >&F¢ªÐ‹£å1œHõàý¡5yìÙPRÓ‰,ÙѨŠ÷oðMˆ™¤ 2Ô¨ãs|`õ3ÊbŽÖ© zÒÆÓRެ4>“ ŽˆX4ÓÑp¾À’ãéÜœOñt7§™­aÜÙÉ*9R•²|±ôæ­™œþièå;6ýx¢¯3išxÂ1Љ‘8´£˜ê’N‰çc}®”[“«g£IMˆ,ì‰R¬ÅÜR FÏæh·8h1‘ g¥E"‰¯TF.)ŠKþ¢(Õvþo9´" 1á ,1¶usò[Ö siÝœ‘GYº4e$|;%Œ’75^l¯îQ1Ç&¾‹ÀUZ<3•³½ÌªšÍ”g—ÁpÚ_MÛšûZ¾éIÍú|er`¾³Y©Jþ´›™x§=pqßF<›žÔ¬ÏWFÔ¾"­«×ÝØ{C­pµô{w¯RŸ{¤§06÷/©üg3Çsr çѱãúaTâ%¶õ {⹤fúj–(ø2¿ ¡ÿÀÂ,Š¶ÒŠ/-7 ²drãÙ6‰'“šƒ ¥—õFæ?œ>“^ÊÌ#ä™U˜äàÕ=|ó¡bÑ'iâé<—7«fåâ)£V¶^ÌVÊgî¿5Óæœ¡<Š5jr‹ô¾ÖŽ£¼jr<÷Ï9˜­ŒÏ>r1‰xî?:“(|}45xÿ˜ìÜÕ6>¶ ñ\!R³°uhb<'¾Ì'9Z,³ÈÚJ+¾4ܤعӣÄÓ’š¼‘é9§ÏD’‰þ€<3ŽI~yïÇ8]ćM!s’&žŽ¸Y5+O;jqïÝ¡»»!ÎÔ-»œ3”G±FME õÜ‹¬Ý¹ÓêyL%¿É>îéÑ‹¥ÞƒÔ‡xv=ï£=À‰rˆçKWÏF‘šÑ»ŸíPž/sØ1‹EЧ_Znd§‹'œ”N^iãéé3ek×^È3«0ɨíß?"ÖŒùPOæ$áãô P€›U³òãÉ£&7ž/—~½2ÎÇ33wZ£¦^³þ¾8U+ž¿ÁKNè˜öйQñyFB<³z6€ÔTƒëõA¤ø29žÂ,B[é¹3ÁM Ùi H œ”V^Iûhöõ™6žgVa’:˜Îñ¡Ö¢™œ>,>NŸ¸Y5+ïØ£Fw×ïN¯ÿaâLŠ´ç ¥Q`é¤ãƒèDtþ«ñìþ 7AÒG—7÷éœêýú9z È2ijÞêÙPRSŸ•ê}»ø29žÂ,B[é¹3…›äðX’B6è‰7éÕãÑ»ò¸ïÕgÚxBžY…I¦ïÐ-i”b>T,šÌIÂÇ#@nVÍÊ?5t:q0›|?¯ Τx:g(ÂO|À‡¯ÅùGϦ²]óÞ©ÇóòØÜ¬ÜöAŽ=é$ªý8Ý&âYoõl(©)_%Y`²µ­ž;S¸ICv‚Œ¬Ú2fÔLµ9ÒÀÂ2BžÇ$#7D"fÑDozŠç’ÁÍ³Š˜‹tHi+M²Íµôœ¡èlŸq(|›ú3xéMAÉÜ•ôâsyFÆ ñ|­œš¡¾{ñ|œš¡¾{ñ *Ä3T¨ÏP!ž¡B…x† ñ ª™ãHÍPMÏ@j†jâxÖ(T3Ç3š¡Âê*ÔWÏÆ:5wÖ ËjñoceüW\ƒÞK|û «Ò¸~(N9md-„­†ŠÓï{K)¿Ø_¢uç+_Mص…çrúX-RóÐ|¹zӾĮ°“œ0à5C<ïÔ\l<Í%c‹gqJ¿¢ô$÷ÒxFõîæ]#žÝ‹Ž§„îãYœ’xÖšTå{µã™¼÷L¿ ¼fˆç 85u<á§t$#g¯k3!_¾¯72Á©_'4§\¦lYÉÖ6a0ºÄ®§ IDAT,uªÁ©Œþ»åébôIn@¤$_Z‰õ€ gZñ¥àœl®¬†2 îÎwÃÊæOšê°eZ ”)Íä($™)z‚1îÎó° 4-mʤfñ æŠt<‹'Uéáülÿ9u~nvœëÁ«²ó857û¤ðÉÉ„±z¦(Õà5CÝ·Edzˆ'ul™fLi( ñÄ‘Z&ïÚ¥ihS&5ù]_x&Óœ¨Âôœ6ä¼Ì~œÖp™ì5= Òl<ñáúµªÁ"™V|Iñ$seÊTw`P}7;ýñ$â“l™vDi(Š—F0Rφ‰»Á¶„oZÚ”HÍÆaߥÆ3®/„^ð¥=ÜKpiTÂ+&‰ç³gÔNMë§d’Q‘^-N k|fY‚S½“ ådø³ÎPqóV >t­e’ž´¸ÔË8§µ[† ÌjÇø+=Ä“†Š¶ÌШ³‘vZËe5ì†å–hË´´)ŽQ/Dò3àµ;«ÒÄñÁPjR¾÷Æ^þÏöT<÷©Yj Äý¥Jl™•ϽGj¾šiSl™O))‰§””ÄSJâ)%%ñ”’xJIUr<…Ô”ªàx ©)UÁñÖHª’ã)¤¦”ÌžRR/9{FKj6WU]}«¸U×YŽš‹¤ÊBkLNBÅ:vØYwÜ+Í·©Ð@+Àצi•é {E3|_³¿P¢Ðô ä4‰½0{FJj6眺Åï·úó7WD<ÝøoiþÉãég=MM™xn¾Í._0„A(žÊqœ…'©_z<#'5›ñò!Æ5•bi&)-ì"¿fOš@KuHKã¤ì@É÷Øoyº¥a5|$Ê+•ÏÆ™{¿¥áÀôÈ´¥™Î´\&¢¢ÔnR^»’DôVIÌœ¦Ulß×ÒØ‰VÃpá&ä!VnêncÉ€´“†‚Œ‘^ˆýÙ>‡ *îÕ`¨„{¢7¼c×ñ<6·3Ïÿ ¨Plƒ¿ÌÚg­ýS­­(u/‡ìœ©¼™:OßÑs¥ßÎ©Ôø~¹“箑š8?Ö¶3®©”ò+- I~Íž4q—#·F íÀñY§.Ö]ïûKý–±Ž{Nõ8ò‘(¯TÖÆ©Ÿqû‚Óõe‚ã‰t¦Çe"*J}'õv™ù$¢ŸsOÏÌékÕ=áP'Z Ã%µ'a¤¥‚S”vòa9Š ©?ÇéOØ«ÅP ÷„E5Þ±gêϵ_§Æ@…Bš÷ôó3OãS…jÏsªuyl”ŽÂ Û9ó'Sj̞ёšÏ®!Â5að+--†~Íž4–zòœ”ˆ]î;«Üáú-ñ“?ˆ¹Dy¥òÙ8k¯ôªx[šã‰t¦å2IzI}a»,@UU8/IÌœ¦Ê©­Æ“;ª=#Í ~¢‚ÒN>L‚KÚ¤þO¤?a¯C%Üs]/ò{æKInŒd‰nçú¶ª•GÞÉfÏ€Xìa<Á'‘휱ÛiµwfϨHM àÝ Â5ýñD®Çâ‘à×ìIh ë”uRv‰¯À.æÐo ÑRÄG¢¼Rùlœ¸Ndz@ñ¾Èr™ˆY*ê[»ÔKl3ß«|$pË™VOìÄ«ùµ'Ч€pÄ'?›_H;ù0)ž¸ú“»“èOØ«ÅP ÷„E¾cϬ}9ÊQ]¯ÛÐɽ4ôùÁÎrñüÔ <]Ä’ÂGß휵ó½jÍžšú/;óÇãš6ž¤´4x$ù5õ¤„ eÎO$«„ª91ë¾§ôIý–±Û:ÌG‚¼RùmœzÞnäho×÷OËTTQßìCêÜ|’}›Áxú[élP'ÏÇ“1RW¿ž H;ù0 š§Rrwý {µ*áž8¡zÇž©ÏÌPc¤Bu›ÿì‡'<®oœÒ³çD8žÆÎ O8îÎØµY²s6ŸÜ#ï{FJjÂKK£)Æ5mé—FÀgÐÎézdUØÎéþ²µœ?'© sÓ¶UîÝ¿]ªÝhñ{¥¯ïÿý<¤æRÜnõOöžÈn´zí}ÂQÅSJJâ)%%ñ”’xJII<¥$žRR•O!5¥*8žBjJUp<…5’ªäx ©)%³§”ÔKΞђš©½ÝpµÝPgÙÃ?4Žð-›%†ekK#æ6X#è×ÂO;x¿½ß]€;ðZ7ú%•6{FJjf‹NìâÐÜ.ÇsK#æ6XãÂØÀ&¬‘â™»¨ŸVšp¦ÍI4*iöŒ˜Ôl<(¥ÜñE¸ïö¯sÙÃ#GçTæ©*ã TÊh( wÔ‰%—qlÚ×´ÞC>iƒm°ÆØþ¯W6Ò1nŸ»m´ˆ5öÁ½»ÏxµNõäwÄCHUØì©I„;œ#Â1{8öaBµ½£Ê8(!˨¡dÜ‘ãi›f#Ä!¾¤õòIlƒ5Æîœt:;.8#ózRlú¸¥õì±Æñk³Ð›Oî0é‚Qhrÿo%•7{FFjR<•Ž'ŽÙÃîLŽˆÍ°ƒ2M0¥>¹3îÈñ4ŽM‹n2üÈñôOÚ`¬1¦³Ö´”…ÏËx¤Ø³YVÅXc×­¤ŠŸ?ŠgLâY™³gD¤fc*woô££_{vµLÀôvP¦(Ë:žŒ;þ ŒÚIëØ¤†u¾¤õòIlƒ5b<§›¾e>3û-¤U1Öˆ_ñ”“{¥Ïžš™Á¯T¬c(eãÛ÷ž¢ÃJe5”Œ;–fÕÌXÒ:6i#}ÆN1|Ië=ä“÷²5ÖHñ~‘»M¨À,k„/Á“»;<«ÐŽ(UQ³g¤¤f|ñfÕËו§»Àïð„”YÔP2îØG¾MãØ´)†û ÚÈÈ'm° ÖHñ„ ¡øv@ÓeJ4búËF:å‹§Þpùù¨$£ÒfÏHIMB5k$ÝÕx±@+ÂJ¥Œ†Ò“pV‡›f—?ú6&äÚk Š1 º e%œ ‚ïî+ 夢çž_±~|ã¹û¤f<šIàÇ×1žRRO))‰§”ÄSJJâ)%ñ”’ªäx ©)UÁñRSª‚ã)¬‘T%ÇSHM)™=¥¤^röŒ–Ô,g",ǵ• ô}3ú¦—äs[|Àw[™½£ø¨\Ñ®OÉïØÀrËÜŠâÃòØŒxæTìÍS¡­ÀE´ ½7çgï´>˜•Dn5{FJjî4žæ²ñlþ1ñÜòã·ËijyÇñd‚ôGÆ€Œçfmgã4]é-O×qN¬Ê]úegϨš:ž^¢Ò¥’˜½ì~`1ÖQ$™y·¥Sow÷xC½²d¦2ÚÉxp˜`µœOz>Jâ2ñN&ND4ûÌVŸü zÌÁ¢B)¦§ÖlûßMýt"ØéY»Ö}õ ž0¾?w¼£bÝùôŸëÝlq£áÑ>¸)—:CŸá•å“MÏHÖvæ”^~íÎrçœ:·²l°êR3;³²üD{¸¼ÚOñÔ]<*óÖ³g„NÍž4ƒ—¨´D©$ÆÓ-åT~‚$š™·F«u<ãÎ¥} KfZí¤è±\5Y-=¥n*Ú šÈ}êxæÇÆ»õÆ¿w2C“è¦ôÔšÃ]Ÿ|óåÊ8=¿é?ÝRßx1GÒË|½ªEÕ¦_ÿ rKe˜´OÀMyXØíüŸ½ó *»ãøèÛ> yXæÞ™ÉÜ™a2³$iBl iœdÆeó`B4ÉØD’&KŒÁÄ %P”ø²HX[ìSÐ,Wvµ >‰²EV´¶.[X –ZÚ· 4ÐÒöüþœsïL±îÌîÎ1×sgÎýÍÌ7¿sÎx>÷»´Þ&«§£åù¼gl5:qªz){€K+îÕmüÄŠLlôDòí,Ï|ã+³KÿuÕ³tžšïG ¼|‚––h*I#wf_ª©›Œ$c÷¨²/þÕÕd¦¶¤á’\-]?JÜd7J@4‘û”ò|³®ì1É›R[kÊÁ]ž‹“®´i"8'¯æWÛRMí^ûO=¸CzbŸ¢7å´ðÊîŽÒðû;Q=¸ƒ<'{f*ߨ-×ëÈÀúËù#/åƒIž!@š$_W=Kå© þ“^>¢˜L%IžõÏÍ‘‘$qH²ZÏ5E5™©m'•<Ë“NhÏMÁn”ˆh÷‰òDÕÈKy¢7¥¶ÖĹgÝQâD]OO´V­áün="-zí?=sÏàEêSà¦*-ž{v½xÔyzªPžp¿¯^Vàz7­‘@¬ùû•§<·m%eä)ÊAjÂàŽà%XZ’©$ÉÓžùuI’<ƒû.­F5™©m'AžyÒ ×s“;AƒKà>¥<—U7°<ɛҵÖ^ë¼´ÚÍœ({z*yr~¹¬9®<‰EsKåÉ–ž¸)¥EW†Ááᮕ)¿=òÌmtó .øú†ax»‰îT¾ÝQòü›©ž»VÏ’’šä?y¨š,-ÑT’—år:ÈF’$ÏÔÉC—£šÌÔ¶“ ‚«í®<é„ nr'€h"÷ °rk’Í+ÉÓµÖ„õάCœ¨òôTò$ÓK‘X½ \y² çH’–Fõ qqSJ‹® 3ŽáwF³S©aÏÒå’ ¡WøúëïQñO–K#h–¿p(ÏØ•Æç ƒ·[õ,­§¦¼tÐT°K8£$µO%:azÉLþÀËiO¥ nr'ÊÚ`Ì5½ÞS@fjkM¸@™'4ÄôcSFÈôRdÎö©Üm gD(L—ö,ÂM›ztht¨£*ÇëÆI‰¨·HYˆ:ôÎÀaÄ(ry~?žš%ÜYÜÞ¶þ²QS»*Ržß§fÉ#䮪Þ"LíªTyš0aäi„‘§ #O&Œ³}_2n·¿_ÔxœõruJö"çY.Rs§PØbÈ¿«<½˜²iú27h9ßFžšÜIžÅΞy¶T[ã­Cs”à·‘§NY€À™qaT¶ûJŸÙNx†,kl>¼£<óײSòµ†‚{Ï©\¤&ÑŽã—“Í7¸p]ãëáþ°lØ{¦lžùŒg“èt©Z˜³$›M)2åÔÄep¿o#Œ (Ò›]gnŸ­–]]jHÊBÄL%âŸ(Opó¬w5øzð)ýa¯¨ÀËÍN˜ŠXç¸bRáEÀÖÕ˜Ï7:#EºpÑß®ç±zá¸A–Ÿuªõ€5x¤n!Î’m6AžhÊ©‰ËP.î'èM8¦E+vJÊ2ò‰ø'Ê31N5uÛ–•‹ãSúÃxÌèfâ NA~ÐKïHl†sçÀ`Qç®å)ì¦(]'töLˆ 8‚ííÄyü`ƒ½0¥ó•°n!Î’m6AžhÊé—rld”'g;AÁ^85)äñO”§TQmKgàÓsGÚqìîã1£›òR*žO4Eÿw_p-¡swåù'_Pt*;)pÅüy S&T”qR|z|·cçfæñx>A„§ÜAžíQß‘¹ÒHæÊò‰hUgç']“åi£xÖ$QàøCÜå‰Ó ÏyvºÔ-D ±Í&ʱOM\ÂÍCˆey^ôÈS(ä“ðOš{¦÷Õw83kÕŒ]ö‡ñ˜ÑMüMÐø< þïÏž<;Y“ps×òìú™Ì/ˆÞjé,p¥üଔ'b^&Õç~<«:çé5ž…ò”õ°#ýYµ¢W†)€;á驞©/â{Ð,¬\¤&ád ƒâÒ*jõ_:0Ú©Ö(Œà7Et*qµ ç’'ÛljyºÄ%¬}‘岓X= 놔gàú"ô@L%áŸ$ÏÀ{_·‰áÙÔŒªžxÌè&\j°`åÜõîAûÓwÛ„›»’爸œ˜ðAY#?u œ@½ò$¬Óˤ²<åŒõóÍ0ã¢)ºçžÛå™XQËñÚyšYNóÉ„§§zæ†"{û{Ï’’š$OÀ4 þ©ýÍPÆHò£µ9Ðà7GÉÏZLg“Í¢0¸…äÉ6›Zž.q)ÿM (ËÓ>¿€Í`¯ +žn‡˜JÂ?Ižvœ“¯6?PÕÝ”WP) à’5l¨%ÄrOÝê¡/–’r–(¯CÄ’÷´M8zåIX§—Ie¡7ŒþöhÕòcÆEYžDxÚuïtÊÓÎ\m¼ƒphz”U€;ï1á驞žû<ìÍêYjRÓFÃJ†lXÆT9ä±ý~ {BÍ>ê—³ô#}©AÇzpÓ¿ޤ±ÌY‘“ê ÀI?ó“€Òµ«üì´‰OÁ$d¡›^³M\ Dlà'=TfâX'æO%b@ˆân‰äu¥üóä ˜T~'€ )\Tµ+Â3B}È,É‘Tg§¿s«bQºŠú² 8++²7åYñ¤fðª¯ùæŽo~ ›„êU¾Èôîr"±2Ðcþ_ç»gÅ“š»3˜v¨Ì»ÚxÚÆ¸ø;’§ Fž&Lyš0ò4aÂÈÓ„‘§ •,OCjš¨`yRÓDËÓ°F&*Yž†Ô4aª§ oY=KKjÖù|Íj§âø³RmÙðrnýÄjhWN`8ÿzíp†×'4‚Ö±b8" [×ÿ\ôÜ4‘——²òi±½¸©­BªgIIͺ«ëcÞÌûÖ\ãÉSoÙÈ Z~ÿuóú„òJž¡âÞ`s[¾ØŽ“äY?zºögîÁMm•P=KMjÖÕ8†Γòq;¿?G ó¦ Vrº!¹&žN!„ËS2vYƒ|F!¬)”C'Éóý(ÁÀp~Ø;½ tF eðW­€a"Œ ý~àd¢ó`뉮œ˜tð«Æç=yb{¤<Óg?úæÊó¨˜¾ÑøœպȮU¶ü1Üu£ñO‹,Ï?ò4Š*_õ,!©)å™yÚF€˜üãw{Š0IÜdëMË?†<#œTžˆ§cì’äYk åЩå‰p' Á^{9^‡=îZÖxòP'˜Ðo€“¶LˆÏƒ­'¸rª-ÁVìq(ßá×ò¼1i-·§Z­Ü)èóGœGÄeê+³@“òàŽE7߸ɍ±Å,[õ,©YçK&I¬$«0‘"Ò¢L§dì2j€KvoŠS "±tîŒ èÕWY‘„ªhô\˜Q#óĉr3ÁnK~îö…ÌÑs*ó PÒuVrš›{Ú¢ñÜ4RsõWÀ·*í!þåÇsÓHÍè&O.±=Ä¿üxÚ²eãiË–§-O[¶l®æâ“Á} ·Oœ„‡Ã:ž—¶ÊgÏ"š’[ö}v4’h¹Ÿ!‰;-Êm$„¥$úæÛHÈlÆvLVS†·I{ùä@(óç…cWR<Íjh’ìrŒ‚RsˆfrkÌzÎ@#B}ÒRB4³I‰Âù˜·ýîý]q_W¸¢À„x².Ô7fD)žÄŒ‚ZŽýét2ýí3ÓU¼œ>K^¹¹¨)5TÑ«$·Ìà— —‹OvZÒuÉl³”L_¶àf3¶c2ʉÇWØËFüƘv}iä­®<Ìш‚¾ æp)·¦ãÙ$ÏdÑcï:0Á &ªw '÷Kq_W¸¢ÀôÇÓŒmƒqÖK< A¥þÐÉ^lâ ƒ÷£¦¤,Œ7G'ç‰gÝc'2¡øÝNp^ÇÕv〉çÄÍö­0{ÔÌ&Yn™† ¤´O~†ï$;-ño¸ä`–’éKÜ¢ÇlÆvLVSâñö^™¾{¤†ˆHm®¤Ã_Ï—Fˆ‚rs¸”[ãP¢1“ŸñRD4áóa¢³>ZììnuùºÂý¦?žz”ù/jd©FP±?piôÅhÝ‹'"顦lÔ¬½~ûÇSñÔuߥÅs¦{ie&T.¢’'ñËs\ŽgåÒâ̓îV˜=‹@jÆ\㊌$ ÇÈ@¤pÂR2}ót‘JÛ1ý”%é.å•Ò¾o5‹· 1gÉ­Ö3ažEè ¶dÏç§4êsºRY%ýЧ«¢9ãH3ñ A]ìO9ïIÉr%ª5 UZÎ/Pèüôö¡Ç©4êÁ­ÒÞΆ¾v§fÀ,å+¢ á?îߨØz ñ|NÍ€YÊWDA£å…_¶á_ÜÛ*R„5 夙ÖÀåÉúšsÏ”nž;ªØ$'˜f§c6R"ÕäõL@">Él\Œ™ž@Sc*õÎîV›ŒÒ›=ƒ#5Yîí­f22Õ¾â¨íó&žijàý–-ç–óM‰ÑOÂ#‘†ÐT¦©&¯gñIÞà%ĘßixŒwwcÖ~³xßÚ_Jqö ŒÔ÷d¯0’©Žèh5» iDHS—ˆ/ÂÉáHØFâÉxd§c¨L%RM^Ï$žÜyƒ‹1ÏÎG†ë)$ÆT‘ô¤=¹—æì©™¦ÓãàåƒÌöÀgÏ–Æ>’ù2ÒH¦.1ËO„#kwÅÙÃ)x$¢Ž¸Q/$P¤š¼ž HŠ'm°q1æ^H%þYKŒ™ùÊ&£tgÏHÍÊCTxwkâÞö:E3ÒH¦.Ó“Qsxr?˜íqÙÃ)x$¡Ž|ÆvEªÉ뙀D|RZÙ°³öF«þÊ][ŒigÏ’›=%5csWËv~° L<£³òB Ò4Àe[}ÍGÏä"»ââá<.ôFJ¤š¼ž HÄ'yƒ—cVÞY|L=ò‹1ÃO­³gÏ@IMœï2d22Z®ÒÓoñŠ!‚g2ˆhÔ›Bf‚i–ûhE„!á³§ocEø¤f*7*ÆôàÆ¼b̨c–Z<‹OjVÖ2#Yjr+Ƴø¤f,˜ÉR“[1ž¶lÙxÚ²eãiËÆÓ–-O[6ž¶l•r<-©i«„ãiIM[%OËÙ*åxZRÓ–=mÙzÅÙ3XRáÒ¢ùö•×G™S~ÉáïþÈóåßìcñÃukÊ×ÙÑà³8ÚL­+áÌ&×viš®(h8Síïñˆ¦:ò¿ByãÜÈw â Yæ™—jý¤ ÌS©½ÿlÚ¬xNjVÂS—çåd,³ûÖèˆk'ge5zcÛ“:žÂ~â‘É^8‚Úaøiù»Ên«¥÷#.M¿»S1 ¹–œÜáÞyVw7|$ m¦Ä“ºeü ÞìI-A/šþG8 ™Âëø[%ôðŒG”â)Cì«jù¦j&XcÆ)jRÍÃ’îÓ3yÒÎàB€†ì±¯Bµš“;Ξ92ÏhÅÅs_·ç‘y~òû¦ðk˜="5g®µšxâ{Gd&Å.“xb@<6ŽPf`¢U!˜É¬&¾ù>/'a™‰Ø¿ëñìgœœO8ôÜÆÓ‘Öéú|ý|¤väSq|¹x×~íÒô»;•RŒæ‹'1¡O›l( {â7‰'vËøA! ÏÚsâù.‚£4 ™šxÊð<¨‰'¼¼väôüéÿv¸Ôoœ¬&u4KºOŸÉó _БTS­yâ)2Oœ…‡àÃj™ç0¸¡ø×FÅ"5ç=Pƒ‹k©$‘™&ž³]ñÁz:¹“}RØLŽgj×3‡ÀLf5ñ-öy9Ë,êá“ÓlçÂ3µ„'wb?qŠ{C¯«êûõØÌò­vn+úöoÇ\íÒô»;éäNÀ¨/ží*Þ¹‰§l( ç§ñƒÒ 6=Ýlâ ?ôHí)ñäß ðð<(ÅS†˜^þÖù{çâ¶yÆqùN·ŒôΚ¢³¥Óçâ»pç°dÎ-Œz»¦iJ~Àª&”„tj¼$li ! l FC„œ0!:nŽÿÈF#B×B.l¦U¡û£õ(ƒáaÒ²¿¼•ea°ý =Øö¼ï+É’¥û‘^îz»½Žs’eýxߟçyå÷ëgTvªë¤¥I³ž–”ûôOÉ=Ä|Éô$ç ªÖ(ž^1Oœt^Ã)æ =tñ;OdWÐ{>R¥¦tõõÄs²^QI¢ÌôñúVkr4…g“«Í¤x¢ÃîOtP­&nâ@]N"˼{-A2~Z““p€ËXÂáèž`AµŸdì…×`ìo S»³t_Üþ??Á‘Zš\¸v'G kîTÎäÃЈ,PM¨§»¡»ãX»ò ¹RÚ“¾Ôís/¯SG”àé^"·}wvÛí·®¨´4©¯‡%å>;§DgE.™¼³Lð¤ªVZÌ3ˆ§WÌœäû[ˆ÷ó\™JÈË©Ô (-i-HÉnfÔ“49÷jDŠ~ÝË—ÞzÕÝÑjºu1Cu9Q§6'–tR}ePå¹Ù“szå*IíÍ,¹qB÷u"–_˜3P»³sæ~åLXÎK\f²1x‰îŽ;e33ø²ÝÓ"›üÚ¿TÑÝ-=CW°šñŽëÖíô.¯SG”6œ»Ku‹…v®Ó½OKäªS:Cv#Ñò¡ÞepUkÖUµvóDÞ¹E‹y~é|_Ï®©yä(8ªøkÛ~åùåÿ.bìÚsWî›ùêu>b{DzØÕö­Ñ ×ÔÌø†˜—6/ÿE£²ÏW¯ó[f­)ôÙtdf Of̞̞̘1<™1cx2[ýx.¤Ô¬µÓsY»Æ‘Ùòâ¹€RÍM'ðÉ‘Ùòâ¹Ö(=Ÿ!ÖŠÌ–Ï”šóâÉ‘Ù*öž¬™-¿÷œO©I0ütݺ¯·—Ž'V>úFçvný馠ތ®æ^>±ñqçÐi<§ý4ÃÍèE_g¶Ö¼çRåàþ¹÷ˆØˆJhÉ D<íõÕm$JÀûÖ{oßÜ}†;{ë&) ‹Ä'¿;{³™Ÿâ\áÖ;·n›¢xÒ×™­Aï9§RÓ îÏ<ÈŒÞËŒZ÷÷Ø?½¿ÿÍ(žT‰H•œ?=ŽEŽ/ýd/Ub±¥„뵒ׇÞ:¯Žº¥Ü|y7RÕ‡xϬç?¾xcäø‡/>MõK¿s'ÜYXA˜½üÉÔÅsù?Àð\£Þs.¥¦Ü­ß…GZ7}ï—÷ÿ•ŽñžX¬p—*Çv:+²hûª$bKÀ“*vi_'ÒÝ ¡}ëË»n}>ìwŒç²èô "½z*‚'Qrþ&‹öìfx®}ï¯Ôôƒûƒ‹mx¤õ¿µÿþäýgCx”ˆw©2plÇûHF¹ýûneÌqšnRåàÆ_ðÄj^l—ýØ ã‰ÿ8õ‘?…™w€rÜr8Ì3<ÿo¼gD©é÷oÛÏO¿±îÅ7Ãx†”ˆTøÁùãÜ ¯íûÕTäHÄ–cߢÊÁ±{¹³^p§ZÚÎ~xNuáyäÞ)cüFß>ŽŠDAÈAp:·…Ṧ½çÜæHAK3ŽáÉlÙðä–Š'bx2[½Þ“áÉŒyO†'óž ÏŽŠáåTE‡§éD®™ ®î©—læêxÎ]JÎMj Á¨™nÑÙDBþ ½'_ÃÏ-wQ¯ÙðE©’NU0Ðz%Í*ÛkV¥Zuèv’ªô!ÞŒ îYòÛCf¼c%æH~Â,ÔHøÞK—÷ôðäe!¯álLvxGˆæž”=ýf?wøÒà9¯ñäÓŒn<‘y'äŸíFÀ{Jµv»AGîxÔjµÓÖu®–¶ìFp¶’°}-š{òÕ£ôÞOhh$“99Õu‡(U ‚äÀ Æé‰IÍÉt’{:äöT(÷ì†,Šç€J>Ó¸³D>"ÂÄ¡ð½œ>àŸS€Á¤$â÷05Ü0Ð<±ÞõOO|Ó âÙ?ù˜¬GsOÊøÆªPÈШª¡ °˜Ü 8<ñ+Ä©†½§nè(k7¼"ç#º&Jø—, t:>i$º7º¾-]‡{_”:÷qBã(D"÷ÓûÉf˜•ÿ¶w+‚0=uÙ­Ÿè_úÿ)'1ƒ ”!ïFo{ çŒBÚ{JeMC²»ž4à]8rRÐÿ¨Ù{Û«½gЃ¢MbsS|éªc0=mI£s&ÔPêô?0Ô¬ç[ÚS£eÍÕÑýPSzΪçÃ̽¨–\ oÕ“+!à¸z¢'ôÑó#;ß¡' 'z”z¸å‹ü‚zÞ·IEND®B`‚lintr/vignettes/rstudio.png0000644000176200001440000015452714752731051015634 0ustar liggesusers‰PNG  IHDRNV×À9ÆPLTEÿÿÿáâåþýýö÷øûñÓòôõóõöýöãçèêÌÌÌöøùôôöüüýúûûÞßâôö÷üýþïñòñòôÏÐÓØÙÜëîïèéìðòóøøùëìî»ÁÅøùúÏÔ×åçêíïñíîðÑÒÕÿÿüîðòùúûÚÜßýÿÿÍÔØ¶»ºÄÅǶ·¹º»¾ºººõö÷ÿþòþ÷Üûÿÿæçêðýÿÿÿ÷ÿ÷ÔÃÊywyâäæúá¦÷ÿÿáãçàáäûæ°iåûÿÑöÿ“›úÝ™sŽØø¾e|ÐöÂïýÛùÿe¿ùõãŒ5ëüÿ®äûûèº<”Úþô͹éüQ©äÕÖØ]´êÿýíS›Üù%9YS«.O!þ÷àì¸`>6ææå÷ÙŽÿûåFè±XÅÍÔä«QÂÈÍÓ„)nÂð+ƒx†Ëôÿx ]ˆ±àžIðÂk—CL'äãÔÁ—tuÎHŸß¤ÄÏ(qÇld s£ÌÔÓɰZ^´¥âú«ÖêñׯT½ÉÌÂþðÂ>§~tª¨¨´‰L—¸ËÑɸöðßïôãÌÝê‡tw†aAXmvù鯄«ÄwRöÓƒMœ¢O—ÞãìÍ¢.…Ñ‘ÆëíëÙÉtÍîúÙ³‹Õ”@‚´ß\s޶ÌÐÄ®ÐìãòÉvDe‹í¿>ÏÕ̸œ5OxpL.4@i??-ešTtž¹®ÓĦw¥mi{þòÑóêÑÉ \o½½áÞ²ŒrÖ9ˆ˜vt¯†Å},Ôäñêõù­puy𥴼#NíàÃÓžv*O—§²9X2'ùôîâÈŠ•ŠˆZžÅÄÁ©#Hné§569z½Ð—¿à|—·šb8gchY9,@záñã˜a†f??#Áf˜avšŒpþî-™熪£™ÆW7 óvýßu¬€f9Ë®¿› Nþì/f˜}Xá†áÆ74'©í£ÚÕÐUUf¨ªnôÛÖøDbù}ظœ`r‚ÃéDþˆ'©¢„v5¸½€œ¬G¸åÙT2K øJ٠ٳK&S‰|ŸGÖÉÖÑááá–ª ¬RÃqèÚ’‡mvU÷~ç±'æÔh•[NÅ!ØHŸcÉ04V8ÕFHLµðy„ T'Eãþ¹Ï8Ìz°aƒsÿ0¦’~æŽ}Òétv!Û7¢u4›JöÆJ=ehýu¥–Â+<ÏÇã-Ûów¥uêÞo<öòc²·¯[ÀÙÊ,µ‰G©r¼SRvÿ¿ 3ÌF2Ð }kÿpŸðɽP‹E¦- $ò°sþRîÈÆþ>™ÐüZ÷a©áÝò商©ëi†Sø†íM,^‰¼wn6øÚÒ²·Û‚ûãÖ©ÐÕœ­ç‚‡+·ÁzU æÖõÕ^a¡™o5Ö»×ýÖúí|¨Ú¯Ó_’PÕÿ§Þ0`ɰ¦Ò4&L'‡zªX$®N BcU:\ÆnÆÝþú¢ªê_öABá:šI $Ø×nø7}ãL~žáƒÎ4lž÷ºM÷t5rÝùºÙl~ ßͯk¿({ûzZ«'’þ•œ™[^rêª÷x½ÛZ%OåžBžš—{W=UÄìËž(ÖŸ‡çÃu…Ù̉t9˜a6š™×@oR¤¿¥÷÷'Ç‹ÅL&ëÏû݉Ÿí®@•,OQ•ìÓ „êhæw'0àê„-iÜîį³œBQè8t'ZÐhÖbüÁâö¼·¯Ûh=Ä–Ç,§íÔãîÃó¢k‡®0ÿ˜õ#St kA ϧ¬WnwrÜÍ‹ÉJw¦;%>î^$ç«MÓ„¶fýy>ßÚ™š7§»× ;y¡µzl¥-óâÝIø`†ÙHfDƒæD“èR‡0T®N4še‰—2 ÈG®LXwªhwâØÁb”>è„s=Ó° èNÜ©,ñâ¨3^ܽ{÷ÉÝw÷DÓ ŽÍŽàë$&Íg—§½íØ öx§Á“ÂíVq§qÙëNÎ5^nX´#Yé^,0P£€A΃,/W<´V7ÄËPK’t¾Ï‹×»Çùë°Sñí:Ñ¢ç3ÌF3#:E3¸÷N« ˆïP4H²n™Þ øñ_G[?JûÔ&ÑÒ ˆ,vô®NÜÅN£Ìõvu¦k!d'ZàëD¶Ûmg»í´-6p®±Zh ¥ðÁ [Ól˜— OÀ/a –e‰—Á!Ðù'Þb¾ÏµŠä\‹.‡höVè‚è:\Ÿð[ŸÛòurT›¬R€lîüþMüËz¸º:/r}Š˜Ž4Ã-íÕÒ:€>ôÆ•Æ (Ó M•_ÓMÒr®N´>Ì•hc²Mƒc³Ÿë]ìlˆ=< ëd=Ð [誧O'MÔ ‚œF'pJ°za™ê\¯;ŸèáŽCÛÛ½råÊ¥K—®Þ¼ùÛïÊÝïMB¥Ñîdp°ØyS'¯^¿®˜•׃»“\¶í8KKD{®w+öغ,v`ýB;ÇÑÅÎJ÷ X‡Î…êd½ûQ¡éëdÇ]ì|Zì Nä݉äŽè#sr9 6y™•$˜”46ë]Æ´n÷ïT&WoÞ¿¿³×ñf]ŸøY–c` ¶¢áB:au¡ Û€ï²ìíêÅ›TZi¶UZO'ZT'ó΢ *üRÛ±ùXø…âÕ®PzÌî¦Ü‚[±½î„w…|k$:!×,Ñôu²þ&Š;‚ÈnÅ ôVì t2àl`†ÙeDrQ×LËIßP™M2ɬ!ë—½è\™Ü¼yÿáÃOv;Ò ‚ZI¢Ö â`: ׄ&˜ND³oW§ÑjI<¡˜NôØžNêYKƒd ¤{ã½#ƒ.ûžŠ0Ï6‘êbo?ZòuâX]BD’‚ XN í‰å9j“T&ÕÒ¡"u!ÆþÔåòî&•Éý‡›››NVHËýôk%UÎ5@gPÈjðW…'l ]–£»Nfk–r‘cçeú¾µ9[ä™Uléݾ+ÖÈãóAÂ:©Ôk—d*UÛ^ WM]ð‹þÒuÎÇ›?lþði§¶½d¾qD¿V3Ý&Ä04ª3çWø€Îd­WÉ´òÙj¥RM§ÓÕjÅòb¤ *,Cç¯2›QÇﱪøoY¢™&—±ê¤<“L¹\8uLÎÈøª‚ŒÚ Åô½l°ö©¦Õñ¹é¹ÙÙÙééÙSG8Ò¸Š'AFP'U°‰©ŒŸ-êž]-TÓU mЉ™å™™™DbbYK€m[z|y‚œ0‘ñ1<»2Z:I»˜Vœó< ñx)•¤\Èfe…ÅOY0ñì"Ȉé¤Êt"æ© ØÇ“+|)ébÍ/Nl„?YT@+ñ<ž]ù` rM_wbŠýr0ÄÒ³[·î5’ÉŒU¶Ë:Œœô „ÂqSxÆäe-úIX¾NLfÓž£Ý…•žµ¹õ¬‘‰Y™bÝY£~PøEŽ¥,à9GQhNjµ¡îÄLƒN8Žö'†b|õˆ<»GÝ‹eæ?û¬Ö6ƒûò§!*œáGýó/4È›¿þó?þöG­7D8êA>ÜîÄ—%èNÒ¦ÛLq8Ú åÖ#òÕŸÈ£[±L&S,Ö,Ì“Ÿ>fªáýÈ}þHCiþûW܃ÿüÁ߆¸íÖÀ‘ u‚ nw2è,vè&ZSlB7Ð !\Ä’µÿ²wm±Mdgx6‡sã„$`'VCZr‘ƒæaû Ø/”Hì…&A‹TUªŠ´ÁM‘0Ýݸj%TÕÀÚ­¹ÁŠÇtÉJIÕ¤Ú•Y!;BP¨ZYÝmÒÆ+må—*/n\)¼ô?g.žñ%K®Í&çKfòûŸóÿ>cÎùæ;ç ã6ðõ¦¦ÒO‡ö?êN§ÏÍ•†ûã=ýžýà:mÅù|>¶©Y¬\pplbu’—N”±¨+¦k2—ÒÁŽðÁø MvMÑäÞ_´Z/¥Õs¸k¾cwðòÜ£×g_2úz2ÐÜç,l2†-€¬£ôä«Ü9½SQQ¹Èûr‹[«g;<Á #›oÅã#Þ‚±F:éìJÌ)t2¡•S l:Rކû!û ^^•çä¨`“ G%Åm¤éE©Õ¤OÌêD¹±V–³Ô‰‘N¨:9=ÒLÝ]ïÍÄÇôQ‘V·Çê¾úè·éôpËîÛ°g Äú¯Ñø°_¹6ÝÃ>¾ÞÔQæœNx­gNDñ£T‹ÿ~:}.PX„¼I@ ÅÊϨÓSÀ&‹+P'¾Ãº:©ä—MŽÿ‡:™˜`WÜ›#ëÛ7/ N:)VN6©B°þO¡'rw,Ðue`wð$ÆîV«ûF@š ê}“ãI29›„‚¯¤¼øË±äõç r~6 Ù¬÷þÜóä*!{¢Ç“—RòöÀ¾{Ï¢±{œ©=TLµ€N@'ÆZéÖôTú"²;ç¨CЬ,u’' ·¸µú–KH(øÎ„ zôUè&Ÿ7¿ Í¿7ÕÜ›šjLáL,múÌr »:;OtkÑJfZÀ²«ÒG»¾×ŠéQ*R.Dýó§H×üÑ®ùPã¹ÒËv’]¼#…êœyÈ Ic>Õ×dÃìësèÖ¤”‚fIõ•L©W} Œê„þüîºÿ‘¶éôp2x’`÷ Œ©GÂÁ§ÓÓéá<ÿYT §Þ¸>–”N'i>rë/ïÿnßìN§4wÍwøçù?ü+”¿ÕkÏÞW©ó9ûZZš[-}NS­T‹² XnIv3ßE å¨vr²T^lR'¹Y¸Å­5°\Âà`‚þ !L`I:8ˆÝKH½©@ïL¹4ÈÄB³U,6wR÷ïΓÄ-éí:—N† ‡}üÎÈ'w /^ކ ’€NŽÿj Šƒp‰¯°Þ»À.ÞÆšê]F’3·±)Ϧ6Ù?{ªª³Êf;µŠh–\É ^Ž5ýkR'ªÏÿE‡L餕J'BéD–IÐCÔX ™ÒÉlR~u<©æÃÁpÊ d³|~öæpÀ¿pÌønªÅ*¦øÚC2IxC£yÊQ6¡–[y ÛÅ_^Tª'V–:ÉÉÂ-n­…•«N,ÐA¾ÿé‘„ t"S:Iµ@'iÉÄ:ÕºØõ݈§Ó»Ë-Ë¢Öis鄽o×oþøý2-DÎ tÍŸ’Ì“ý Gi¿Õ.ÞÆšª]¬ÌMö(ƒ†Š=*œª¯Êp+]­^r‡ ›&:AF˜æNàu¸=Š…ÁNìÊ ü£¨ÿ 9ã‘ vP,:9’@±Z ¾’JÈ0Ø9=›D”N:îš"ò0*9ÒŒzSýIÖDþ2ÃP1t Ôçõö…F}£(”M²}ssd©ÄÁ±ÈÌn9 |£^P'ǃ³Q Äè¤mKµäiú=è9ÑÙ:'„´h„BvvÁ…°‰¨¥¸{ã# ™Ñ RèÀ¸xç©§Þee&¶V§ö¤×NªŠUÕX,lùÃb©UË!$Óª‹:Ø(¥½bô¨q°ã×›0,{ šé1ŠEáþž³ý­ŒNb·gÒÃͰ§/üñh|8NÏFE…Nü÷Ùsìñtã|˜±Ÿüà×à|NEëï–C'¢XOoc»Ö3zeÔP«6³-È¡ZfuâÛ[(‚[ÜZMËÜá'&”É ^Ü–zMɦQÖš¾˜­efÄ\:¡>þoÅ‚ŸíQ;±èÍF'pÙžCÕØ|ñήsf°c* ›Í{Ê'§ÓésT«>²òÎÞIÚi(·CÐ,¥“H¤¦F¤t¢ú”r¦ûNÀ'Š6{M üµ3بÃfЍ±‹ì•²§†h§‡ †•³+óÂZ„½D=šÉ³›ÎH´¿? |bô¡gÀ&4 MEŸ¼mŽPNŽY~\žQ'âTC›ÍünÜâÖX{ â‡/Ù'Ô£@'6Ûù±ädºÑ™ |?Õl:ÉÄ*ÍÖf3GÛ&”žd§}ƒ•Ë:þ?öÎ/¤­,ãØîíŸD:m‡Æº…–M™Öm¹Äêà Ë<܇ðýSvÜBŸô¡k3š`oœ…@gc[J )qì>L©80Ö¸…гmÇî`„€Ð¥3ȲçÏÍýóçú'­3ý~Ôxnî¹çcÎ7ßó;çžû7¾—~È“ÏðýŽÏh(ÖÝuUýúêÖ_|àv‡¦ÒÿmýÌ>¼÷©³ÑÙñ0jùc-ÑÉãâ›ü9ºQ[ã:WmÊçi>ÈS\NH±,vâöèåÕž4ÏŠ5Ž­hŠTÌxnÕ¡wpOߺõÙM#_íÃÿ—:¿;TUk-¥ù`.µOz|T—“f©®¹ÂµG )ÂéÔ[ú›.XµçèžßT‘½nÒé/·‡}¦Ò´Ëe«½õk kµJ?D÷¯Ò¢\´±»xy.9Ùp¹]òÁMNî2ŸÍš2Ü ËÄò±TÝ IKϹ<5®jËsçãÁr,i“¼­jG«¦£Y¾½N–/¯ôj¶¿D­\úyùF¡|†;qYpzê$×Fjª­Ûç´[—zÜ{Þ}ïÈ{ô›>ì©ò˜Šr9N-õÊÈUÌEziGö;[G8ûû«Ó¸õ,‡®Ü¾ gµïº3)ƒVüžÕUòš½Â?¼áô¸Vic]]uZÚ“åwÑ·¾“M窳`†ÕB¥—ÇY¢!¿Å"±Ô8ó9ø¶³,.Ë:Î׎«ð-é>QÝ|ü$ý:yüxsó©ó{<%Êà—kÛ¶ŽqÀ·`;ð[žÓâc°Œc8¶‚ÆJöÀöäD¿G1ä°mwb«³ã¿öùbz¡ˆœ(ê:´•ó×_ÊfWFËåjœk)ßZ{‰|Žñ‘²gÇÛeüߨˆœäFvÊÈIÏ u¥¨œôL?ÌÂ[8½r1{úA ló~–S¥çn)Áèš]*Nßì(þïTÊØŒ\\,&'M C[<ÿ³•ÑË%8âí6rÁžP±Ø‰=wR\N”1•1$ø§dAl»í÷ÔX¹f[ÿ]–B´âb6EœÇZ»¬<[ùv-»’b"u—쑵\ÙËÔËd³\1ü²}‚9¿î;"÷ê­Yl~N ;Åå½>Ãv<  b±“îÄíjx†-r2‘J^‹¥Lg i˜$Fv$Ÿ­d’Q™É‰Àå$+|kiðMk+ÝÏ¿‡ž+I:SõÉF;©ÿqåôó?fGS~AÑt"Ò;1ò|Šœœ]ë©ÈTë’ ^Sû:Ç ìä>‰ÖKÎ7;æNlì”íì˜åd4Û§LGQÖÅ8TdöMðnŒâ¥îÄÇÝIJh¡âd—"+F.&\N¼Ô¤ø×¤°‘Ÿž¢ÆoZÆb—éÉ;d…¥¼DXšHÍ”'\n‚äY!ÓÍéÄ›€r'¹Y±;,'C4@ËÜ@ ;C#àÐÒ±&&w²²Ä7{Ö^Êc'=\N˜~ÁY2òÓÐI=‚«F=©‘r\câ²0ÆŒ’—Û¥É8íõ„¢ŒNÈ ;ØÙ9U!9ñ›åÄÒÙÉ—‹;Y¢1’"r¢ørrBž yGüDA49™!½Aœi%r2Áäd(ÞQ/³ÎYÜÔÉ@NØE±Ò³(åN8–ÎŽÙøl¸_ wB:;ôÑäN49¡îD·FÂdÐT‡@ov,v²Ý‘ÃLövÈ‚¿7Ïh˜;;ùr¢4ÒqoÖìNXì„ì"?ëùî¤Å;Ñ݉²<È 7ÅNrrbÉöSøÇð:ÝI×üõÅÖùîd 9gèxN¢ ;Ñ‘ ¹“ž5)êû"kv'B#Ù R…ðf_’aAI&×^&“!¡þ;}dÇp'B(î1Fvrr"^‹Ýïìó‘Ÿ. P1wbkdçÓ4åv Ô4¶È=5Ö×VØF““ïZveÞ;mÞ Š|Éæø×ø ”” ›æèîDð³!󼓜œ°y'ê3—û08 @EÜIn­X›ýM–»PÙZEd¡¥Ew.-ëìQ!e)l¤X`)E+[–é·B2Xò Êp_¸dmØV}*×ÙÙ¥WoÞCØQ e¹/Œÿ;¯5vò‹X  ùQÙ,bj@c'§°Þ à•ÇN '€MÆNúãœ~È À*'›\+¶>)†ÈWr¾rÈs'›‘1žE¢&ä'.âX݉ÎN×ÔÍtúN†Ê ù1ä$2/aª)o¼œØ Å~|CŠ·-ÞÈP9 å»eyöHSM€;±u àz±Î¥ôs'‘EOt9Ñ®å¼ÑrÂg±•u'“Ú5ÅÜÐÞŽÉ8 '¶Q¼ à×ìNl†b?L·3wÂ;;Ü V_µÃÜoçð"€_±;±9ï¤éçÛÑ\(–ZðõÍäNmùU|ú–t'sx}ÜIÏ?n¤øÈÎcŠáN”[€¯¾…œ”Ö“­^t À®—Û«±E¾øçù¢î$‘HȺ;ñIR»é²:¹rÀ›êN¨?)/'þ»ß´óil´§óX6b'J²_2/ ÐÅë À›;±yEñÇé>ö›¹E¶ÄN&ã¸O'»îäRzbžÐišÆ†y'«;©¶åNþÌ–ŠM_á:Íy'€­¸Ó%€l[î°ANìÞgÇ¡ÇN8†; -ã@ 'ÕÕ›v'IÍž$K#A\Q À/'›^+V¤Ë'Q’óýÆz'JWw²YwÒw aù$€Õl*vâa]&_늈Å&w²ùûì„r±X,= Ø–;Á1E݉¥§½Ÿ/¦Ó_g*#'ʘªªC»ü¥r,ÿôÕW?à-@q9±¹Vì_¤øõ›72‘ÙNìv9‰|õ¿Ÿ '”q'ö:;“Ç—‹ •êì4íz9Q„–1È %ä„Ï;±нh[N"÷ê” ˆ3­ã êQò”¸< Æ,W;ÚZã õÑ’IN”± ’·‘nL’c,“ãX}aAðO^O¨ƒt•=ÓèÆ<8;Z²f‚Ð5§Æ—,…™óSŽ…œPÞØ’“H× º›9‰ôNŒ<ŸŠ¥ˆœ¨ƒ®é‡² ^Sû:Ç &=ÛÔŽ¥½Ã…äDykÏôG­!–ARD‡L ÖNúGÿ"j2ÐúÉó©‰<épô¥ûK%k& 'uöO““…™ñ•,‰ @±Ø‰Ýµb?M§óÕ$''r ·bR4"-c±Ë´¥wÈâ iéÊ“‰%¡©( K™Ü Ý9LÛöF9©o»’ç„É^ò‘™Q¢D&§òòÉ™èþ¯†ø`^šý$_Lòkæg…Ñ“ë…YþÝÈÑ€¦ëLN°$.Å݉Í{wõ_ý{áPl¨»SKuvÓæÈUƒ ‚8C-Õˆ1¦ÞXÊìN¨b45 ’ñIì~'dd IDATÆ*(\5¼d§šh=ÜOPϵ С¢—NŸÊY‡¡pÍšž’íž§FaÆ_¢„BDNø±rwwÈâN°$.Åc'6;;“ï͇öäd¦u‰ÅM 9acÁ”ËfwB›°oàiÁ؉c¼AUÍ&ƒ+@£YNzx©¬Ã¤ËÉýfMN|AIš ¬Yc‚¹PHN†%[w!_N4Ó‚%q(;±Šõýü}ÒNìD,ìN”°Ù´w'tÃ1®.”s'¬Tóò´ íì»À»?ÀrÁš5%Úµú˜åD#<ŽŠä”KâïNlÅN&™ŒxÿÏÞùô‘åq¼i”f›»êÄ•ÑjuÅ4¹paÊ),K×ÏJ ew+ßI¶DEd°àb#ÖpE,Y"2Aç$‹ñÉRÅ"Ò¯ [ N …ÑmÎ""èæ½7ÿ<à™˜eL¾ŸbÃúÏxB˜¿÷{ï}g’¯kéè:aÖÐÊ’Ô#™V'ùeõIÖ;Ñž.¨‰}M›j òBéä›Y[ïD3€D« ÂI1´½,ºÜ‚ÂÒ;—õqèDtÙ¹ÀÌ×U'ƒÈ³ÌLssåÝŸN’æÌŽ®i1¿5‘*ÒX”à)KÈÌNtjmî=SEtâô€\é ¹Ä†ª“ÁâÖƒ“çÌ+‘i"™Ž™ÝÁ¹Ò÷©M碕jjùÊ3S²å…‰‰f¨æ¡ÇÌŽÔnŸ¯·Û Wèä!GÞIµ@Ùç ]¯;ÑuBdJtቦ!>ùrH[w¢$vè:{éx(Sj’Vì±úÀ¶NEÓ‰u݉aòIùíe±î„~â›­H1ÛÄRdò ?4|^uÒqçónVÅj cÔ¡X$ãÅâ(ù?Ùí8äu½ZðÑíqFÙ¹_à§€+z'ÞÉŽbÁ¹´ð¥T'½Õ‰p¯tBgŠ‘wèEurgƒÀ=ì :ô`°Óe’=tðÒ ²b=ìpöN"ÿhMòë$¼“ÉŒßz&Hn)¤ ï{‹´öÈù˜ÛLT‚®ó?¿\¿Lw°ï »Âs$©Rözƹ2ít¡°¸àx¬R\¢ÂXÿd׉™-«>Ù>_ÿ½×&½üÔ>Ö>4û3îÀ'Õ ß`'ù¡´Â¯·Ëñ¨ÔYÆÁ®üèDtYIËŠQ¥s›NŒlYúÌ ýéϦ*«Q`–rK¢àªOuòíN>òêD Q¯H·m6Á¡1 ëØ ìï(mj)³Z¼kmFÕ?i ò$6‡Ø'‰‘éñ5õSWX5åvÑ)èNþÉff|Vœ/’xÚeãüÉneã`ÉL†v$r0N·2K/Ÿh†1uRÐÿfL'ºÏ§c7²RÈ7w2«ät¤FôDý[íÉún"}oµu ¶'Áõ¶ØqÜmu·î$øñI['RîíôûXnÖu°z¡äNß6;uâï(¯Öª‹ÖxWíJS£,¸mõ@TŽ·¦N׿HM™Î—¾Ž­uºC"™n:‘ù¥xfa­\ÛßL¤êª'´óω–ƒ)¹*-…DE=-VAŒÌèqP†N”ãP­C'aõ’O‹YëhGý¶DÎ×Y”SþÍRìdIÖSl#Ó¬Ô±ôƒ”´†cÄ£5K‹$¤Ø‚»ìpéäÙjÎS'ö¬Xs°àQBt¢þ—í¤ãˆwUu²Ë2ÛŒxWrÅÍ?˜¬ËIõ°ZÎ+½LWiAaDQkg¦TS3ÛùÊv±W“³#ùZrã©n¯ÇÖÁŽå`z+VˆGO´áUØP‡‹N´|µ‚È®·:!±+4éRiäk¥KbI«ç#LW߃°–G¥‘6âÔ‡žÆE‚ì©FŠ-ðEïäzŒüoIðÔ‰=ÜѼ]ÔôF G¼+Ëf#Ú0â]¥Æûô¡jU1$!<·'²id2äWzdú½ÜqfÒqh믳–ãË–W&ç—#G,ÝТã`ÆÌNxƒ¥I’Öɲ]'µÃo´ÛN8u²¬‰Kj°4n3ÅVUâpyWˆÓÏeß!¦aFâR¯_j#(¦5¤Ø‚»Õ g[òC´Z ¬LV»Ô‰K¼kGW€#ޕ鄼݌w-¬Æâ;»u|Bú(Yrm ñüR,¶Èt2Þ©µ`Øz¤éD(†Bš؇+†N”Å̓ӻ¡E'ãHÌžx½N.ÌÁŽhì–JƒÍJYSlk‹¥_ç7ŽÌïAÇ`ÇЉdޕЬ’b |_?¶(¶86ï_]Ø›ŒWÅ»Zª#Þ5Ÿ*­ýú3ù}®¬Á"g÷ôßúç¬L•tfþ,ÓqOg`­¥:aç¸^'ÙòŽ6 n×®­Nh+V±µb HšNÌÛ䯨æÒNªliô­ƒãÄ ¦¡¬:AŠ-ðyu9I¥Rkû«©\w:1{'ôÚýp›³¸*ÞÕ¨NÌ+;9Ÿß©“G¥>N{—ô ƒuhí÷™]'ô}Ê!ìÔ½u¢:²:;4gh½gv¬ÅÒKZθT'fŠí`¼T:ˆ‡,w$ºèìØÛ°Uþï•J…fÇЉ9³#5ÈüLÙC'Z ázMÕ‰ï:Ïì©#Ž]Ús`7Û¨LG„ÅŒ§NDYRî3;ºNÈ)JÙ!ªõë¥XN¶L 3;d¶ªBæˆC´;Xdñ“B»}~Ùn§-­X3[Ö²Œ­Bo@èVXRl3ãrAïÎx’UÚÖ²k¥c¬c~ÐI[o s݉8¿©~¿J'î\Õ‰ïJë¶À^I±ßãa²&eÑ['^˜Õ‰Xy^Δšìì›ƺYÔ´ÅÖÒÐ9k67CfhYÁ‚d·èÄÌ–U—ú"ûÈ=Y·êÄL±V…ºfežrnÉ®Šñ³ ü “.ny~Ó-€F¼«Ò»3—õãW"*J:j9¾ûßF{ž~ZçzÔŽ7šg£èÑ·ãVÈŠÇ»xÕu+ksðÃ`;ŠoLWÛe”Bô6®{éå–®¿T'È;ùŒK9v÷] !†Î ðƒN"+Ыêäî’ì÷®:AïГêä˜Ù|Õ ¢§½©N8'Ї÷É–Ÿr½ÍŠUŽC¡Îà3aÕíåYõå˜ÄÀǃžVìð~©ÙlNU{›«oǼVÝHç°š_W'<½“áýÝ®;|Y±ŠÃFÂ*ïþ©N¾â¬Nv«ü:áÍŠuµtÀÐ;ÉŸö8+ö¦:A(*>íðÌìwškñýW§½ÍŠ5u"çô, §NÌ'ÙŠ €o{'¼ËØþÙÚímV¬E'SSiÏêÄ|R{BQðiï„{[Ð~ß®kurMV¬e°s•ND»N4Ë ŸU'üËØ:q/+ö3[±EÀoÕ ÷@¯ÁŽ·N®ÉŠuÓ‰Ù;É:o•‰™ü¬®VläY~¦Yßÿ)ÖÛ¬X§Ì„U§xÐg½ŽêäðÇVë]é´ÇY±N;˜ «äv›¨N¸Õ‰f?Øã¬X;˜ «É g˜;t@ÿW'·³£Ø¹ÐB°ì(N°ŸW'w˜Æ–ÎåÒÞÏ^t÷rÀ\ è࢓~NcÀ¿!þÑI_ßg:ƒè€û§ÞÅ‘Å[­7Ü«bÃsÜ=3Ò\îîägô á3óé‘Бl}:ÀgÕ ÏŽâïZùbqç”W'…¼ÃæbØÏÐÉö‘Ðß½“ÀÊûj7ƒ[Ò‰ýIè€þë|ûK¿w"5hTlæ©8¿1Nó5¥Ñãcm'Kòu:™9;#ƒœàû: uRyöêùJëÕguRÍýœ¯år³êU_ÞC»²(äCGô!+ÊÛfhÛK'Â׳L'gc§Å³ -é:aO 5€~ÓÉkÕ%kÿjñfÅêƒi1:Ͷò™ƒýõBj&´õw› ̃Él7`øì…,ΗhÓÄlŲí„Zj,|€t³Œ-òš$'?þ·Êî8¢÷N*õÌê²­wÂ^¯$BÛôj%­"Û¦A{'æ‹ND¦ƒNèŸÞɳw5A˜mËOòÖ‰ÙŠ-èý»NDU'ßkÓÉB1Ú^¾B'‘Z¢ˆ²S'¬(‚Nè|Gt’ôЉ Fuž+峯3;ÒI1´E{ J5‹yDhÕÉ ÷ê„éd: ot2²Å`lj’Õ’Ô*õèAƒvÂsÎ _¹zE+ÖYxéÐG:I~øe{íß­X‚C ¤ÜU­$Y/62=9³ç¥Ðê${[zÑ1;Ð:‚õýVfŒ{›tÚ{>>ñR•Ë)ë)qŠgâûíêß«¾­†A_ʼjhÛvÕã­&½ºk…‘è|µÖÐ @;¦“{•cú]±†Xæ†g{×U¡“‰Ÿ&õ½I50újoA”$R¯Â×—Ö+òKæzÔ?à–i”äêȺžL:ELÚNh»¿7táúRÈ´O°¦NTeÚJ'Á•éœÔ`W¬"ºN”ÇÆ¯»öÔªQ2Ÿ’c[rpÄ ÙÍ(jRW­`2ãòe…Lœw:ƒàÈ–¿p£gaPÓ©Ûeé¤ðzùÈÔ‰¶eu~âm1Øé{øm…âÚ]±æÜ‰6%bhÄÊK"«ô,¬«ý½¢N:2&þT‡‡…ˆѵÉKŽD õ±ö; :Qž®Çv&æ”ÄÅ"c[ª‹:1>¤ôõN:IZ €6ÑÉŸ+Ë“8"t\T~‹Qµäõås'j´Å`'ò®¢(ÖKWlY:±tbüî낤ܟ0•mqã«Ú¥>ÖYÙ雞›}õÏÇÛé1ó"Ò‰ñê½è¤®_r›;qd—ä'ÐéärvÐû®X§+Ö%Z±—m‚n˾ª*î¾3ê¾¼œ^°>"2æŒ?7T¢¸Î9be ýt’þúÙ|›ì®Øêt"÷Í}¾¾|[hàûpxÃ_%eõÛ®W5ì1©'U¹çÚøKå©%õõ†.ÌŽÕXÙQòùÃÅ|¡´—Núßÿ’l@'vW¬K:‘Õørj|BÜUÇÜ4òÓ“mÏ_®XûNdmÇKM‹™•’}'JåØ(¸hrÌÏ ½;§9XËhåÿyzÔ²ZÙ嫹b½ãˆ4@ u‰bhëtèƒ@'€Nlø˜;€æ¥“º:IÜÜlä–çÚë7öî´ž«oß¾¹k>ŒGÍ·ÚÐçU{èÚnì+Ú7¯•°Þ˜ý¿ZÛR´Ùß­Ož©n@‘•C6¶|Jô=œ¾8{³òLqí +÷–-?h—ß^\µ»LvG­ÍgÎþØìÈêD-ÓÉÚ¯ö'wt"'\ÿô³Oà“êÄl'¨j<ñò)^¿q~á#zJótR–NŠÑ¨ —SÒá1:ø”:¹ÚN¤‘NzŒoÁNbM<\2KN }Ä—Åž‰ùb·ì)Òɰ_8£ßìÓ‰ò`´bgÿÑÔ‡8:ø”:éÿ8ÿÇ‹Ié$“ù5w"e^¿Ée’jñW[Ëdž†rIñÔPê¥Ü×»¥Ê’Ó-[$f#jÖìGåÆúà +ìO†ý¿o›M²s¶NäÕyçÅ–ÂJˆ/…NTúcÎB'>S±}ßmnVÚä„®XÅ™ŠU ƒttÀ‹8ƒ凉܈Õ<]ìXSØíjÁ¨õ`MDXá3©æé>#Ü–µ!3ž§bK²ÈÐÚݲ¯L9¿»øÁ|\¼7E¡HÖ~=u­çJ'^ neCúлÍG^Ë5YN,æÅÃôŒS9R(’uú©k8_ƒŸ§]±ÁìææÜ;¯]±‚ˆU+¢­FýÖÍn*ubC]+ÀyìxÙßÓïרÆf—žI3£¹ÏõR× p^ÒIgv®z¿G±Á”µ¼ge cÒ‰—•)²YȆ’žt¢çó‡öT, Ť“2ײ›ÓkI›ìÄB±itP:ñ5ÿD±XÙ¹b=dW,@‡èÄs“ý©O'Êïtç8œe}’–ðûiètâ3OvVéDM";Ô'@CƒoGÑ ÔO'g;Ø€NJ'Ý>Ò 4A''¯ìô-|·9m6:²µ»bã~*:~°ã3ãI-ÜûoïCS'ñ•gk5»bµÝµÏXÁ`°Sg*6¸bêärvÐK®XåÁ(2@'õ6Ù§-üETO÷¿ÿ%㦠€XÙ18aeÇJ'Á;Ó¹t&òνÍN'T¿t¸NŒÑޝn:1þ̽3þy¤»¦“±‘^ Ûݯ:ßW€Õ‰ïDØéDèä¾£“ŸEh«þoÄ[«ú5‰N:wþÜIÚìH’3؉¥R©XA'¿ ¤½Q £€ÎÔI½3;A·©ØØÏ±â`GË\÷—Vš„“|_:u°Ó]î¤r¡8V6w’ž¡„Ô9³ŸÝø÷‹èFNŠœ´}'`-Ÿ “/²›‚­“7Ù³ïÌú$_ýÅiûßGI'P7x;QÛå :iŠN´x”ÅèĤûcë“´'ŠЉ™Ohc€fè¤ÀÇëäŒî¨“&LÅ8ûNjv ]±Ánf7·\u¢êf-AŒï&:9¡>©Ðy7þ¦†Nr¢âDE'è¤ÎB±}¢Ø<誓Ø0:/åŽit-J'*:;t\:‘utMI'²œÌ¡¨·²ã%äÐ :iF:A'дtF'è¤N:)tÅJC?fCÃÒ œ*ºbƒ5¸ßt^ë“Ò.H'ÐH:ñx¢8™TuÚØÐ‰66h›t@:Ò N€t‚N€t¤øÒIéš “.;ÐÌÁ:€¦è¤ éÚL'¬ìƒ`°è@m0w¤ht¡ :€ó§ó`:Ò ´S:é"@3Ò +;ЬÁmlÐ$N€Á @'èÐ  @'€NÐ  @'€NþÇÞÝÇD‘ÞqßeÝ©Ìî8îÂeWw¢!,ÙZ]¯ÚĹx Ö ¾Ø‘’4\ljÕ²¹Ú‹šÔä"Ðà [«‡Ðm¡z\ƒ‡u#ƨ èÄÔ#žÐ(äš‹ÿ\oÿ2iÏ3˾€o™ËõûñaöÙÇÙ¸y¾ù=3³ˆ8Ä $cœàÅ€ê’)Nð»b@»ÅªЪ:ÁïŠ-ª=΀F‹Ä h´ØÑë±ØMªœŠÍâD8 â§b@«êD¯Guĉ>[ûN@›8Áml ÕbçN@£ê÷€6q¢×ãÅ Éb÷€6q¢Gœ€6‹=®ì€Fq‚€6q‚O€6qÂï±Ç¹Ð Nð™@œ@Ò-v'€ê’'Nôz|f4‹|f´‰Ü šÄ nc­ªÄ N‹@u‚8€—Å .€&q‚ÛØ‹Hª8Á©X@uI'ø au‚+; Mœà#€€8€$[ì NqI'¸ïP@RÅ î;T'€8Ä â'€8Ä ü¿Æ‰ `:¢q¢KˆKßZÌåHœ qéøÐ`.k'_ŽÃ›€8I“'¨; vSG¨«µX§¿–?ÆréØöË(>*<jÙ·ŸûJÏÄ—ª>.ïï 92Ìu.Ëu'CCõ÷ù¬4> =‹î"ŒÕža´Bˆ G&n4N wlëï«s¯X?¯p4 Ž{à2=ÆïæÒ±-’ qŒ¶|<¯z}ün÷H³ìžðZÞê®ç÷srrÜ/Ü íÞÔ¹L3²È}$¸…õßËýYÝÑY,ÔuÉjß=R Œ³‰«öcãDŒmþàÞ± ¢¸•bD4ø{~Ïâ$n7—Žmyœèø–=íï Õ?¨ê¼Ý¹-w÷´ ³Ô0¸††:†ÅðHÿ'ôŒû<²z¨Fœp|44´ï¦©sÙ0çúaš®ëY?·…Ïw÷‘õÁ¢+Áœ=ÍTŒtÜ=á ôžl[Õ¬Î\>qÕƒDãDŒw$xc¨å¾Ø_»Käq"Šy׊üì1ý„§‰Žç Í«.ß¡8É­êÎmÍ7P²¼Ñ3F 5lè 4xÇ 7|?N—’¢Ó‰0#Ô¹,ÖQœ4óù<¾ÖvùlâVˆýÝs¾n T“Œ<s Ò²G'MÜhœØŽØ¶:Ô,SÉcòŒžRŒ8ìåÝô8a7—ŽmYŽ¨Õ ^]äx§j³ƒÅ‰·Û¾Ú˪êvÌ9‘él[µjUǘcuÇØ„c¢¡¡}÷MËö×O†B¡F‘÷íM÷ª[7²‰ë°Ï ntØ)DF D;Uô0ù Ñ8qÆóóy§Ö;zBÕ‰³¿“¾K¨5?~7—ŽmYŽü]>Jqâ¤8qªqâ\í]›ë]ë¤ŸÊ©Æ t÷yD¾/ûŽ×LN˜ê\v¾~ý°} #Àû4ùóNý”M\§s…ʼn8²OtR @=礉)ŽóùµFÇÖàéß]ôlkðM’Ìþàoâw“\:¶e9òa>>Jq"Q€-ï{ÌâD¢8ñ÷¼)ÑbGú¸ã­ðHCëF©( ®T•B?”N€¡Îe‰;R§ÇAÝ+ÇEÉÿu‘ÿD…D‹=4ùYœ|èïÛÇREš4q§ŠIòWÕßw,¯ÝåüA5•%U›ÙØÔq¢û° 6Nè'êk¹|£js®w3 ç׊$‰ŸŠ•Â#ËŸ Õ7‹Ëßk?–i0ÓqBÕ + òy„BõÍ+%~*6'ÞëCÞ1ɽ¾Ù9qâFãÄ<+Gæ‡{ÒWæ)¸tü!rÛIäÕæùæ:DäyCùJsŠYJ‰Ÿ5*xzÞŠ éÌ0CÂs™2b|dþüÏçÓ”˜ÙòÄœ’"x¾RSÁ q”JããdBu’ž‰“£Å¬2YSúÉåbÇq Ž–vßããOÞÛ«”tð‡ÛºxœŒžÜí‹©bR)1,TŸXlþ²’½ïqèöî#*•Ïš7ÙqwïUŠ“¦o|ƒ_œkWn—?£±í½ú—vÅ×6L… QMM¾X(Ñ‘2-ˆ€$­NÌ1ÿEÏÔq²èWÊÏ»X§áíâ;§”÷ÏßTÝù­ÏÓðö饗îœï¬|TóPdqÒ»©ø—n?]ì°u ûã/[W»#ç¨÷à@ï­÷6W4¡£ì·òê7¾ò×~Yùxa­ÏÃÇnmZ·YͰú:k 3~ª€d“=yAuŽ“ÒNåì¢Þ²âŠ›JAé_•m£e%õ—÷ÿîoÕ/§)d<G²£1'FvMÆh´Rœ|P¦ø€ÅÉ©ÏÅ·«îÌŽõFëG•Н`ñ± ìuÊUªNu‡|m=ûŸ±ëÃìâ0¥‰5Ü·'³;Nþ£.vJõÑ8ñP´l[4zãÄÞ÷ãâdûßÒÒÒÖDâDà9`4±89ÿke[ïÁçÿì,Ü Pœ6Qœ\¬<8¶ÁWž^˜ÞÅÆŒ¦¦KwÛ‘^e4yuÂû좳€8HŽô˜x¢äU«“'áS±´ØÉQ;#½J–)KØë›Yv#N’-MÔë8¯'‹žœ» ”´V°S±%üT¬''?W.z»&œŠU>óvEâDdvs¼Àâ$ ˜Š“À‘v¥õ¡'ÅÉYK§òéùsíìð±¼kì o€‘à–khû_öÎ?&Š3ã¹si«ñ8x5í–l ˆ€DDÐ")"Bê*t[s¸wXPP„ÛbÕ®¬+zÒÁâù Vi‘TŒ«Fˆ9ã -ˆ9¥ÄØ\Ê?äc0—óþ¸÷™Y`a¡Ë?ü~pgŸyßwß\ÞÏûÎd)ác¾/è€iÀò×q–G ©]'?_ºt)mñëåâÎb¡t±¸Y¼˜Ú;æÜŠ‚mæYÿxЭ››°«ÊB›±¶|?Ð Ó";qg¼ÙÉOf®B©T(èƒáì–u0-²“áòXþЉ(^+ÎnY?Ð ÓtídÌ»b'C'²INoù® ¦óÝé¿a_|‰uW*™t2ç*Îmù® f“<ÙQ°UV%Ý*œÞÒgLvxmu®íRÜØ²9»eÝà66f¦N–8ϤëÄo `Æ ë„sžI× ˜AH:™Πt€N`$õƒÿ†N“c“Ï¡€Ó¼%Ù:8ÁîݲMìèÄíú‹DúEôqÔ¯_ŒÄZDˆ!yû^DôÖÁRk™ì„ºäÍEwä!¡†CùGg[jgg½´/ëÄÃ1ÏMÌNþø¢+ìåù7-†—5k²ûÅZ7©"Dˆ^çhÎçmÏ:Ûž=»*•ÙèÄ#ÀƒGÔÉ÷n‡.¡‘DZýÕw< Ö@l‡¢×8Úýã†Ô6Kg›¥[*“u"|h4Åš$ŠQÀƒ1üGJôéÃ¥!BôúFßÝ‹ˆˆè¤2±´-je(¬Xu²NáÊ[EAu"Ô@‰>Ñy¨“Ò6Ø*ŽÐ‰R±ñE¢«¤×ñ²NøOpE„Ñë)•×;yÌÓÛr­¬oOOOöðä%’¸ñÅ:}gù[Ý…Áo©"Dˆ<•Çž 6)µ©•uâÃãíîííîîíîãííãÃþDÏ|woOw±ÖÇ"DˆèÓ1³Ål±ì™gS&넪Ç÷ÿ‡¾ƒXËÜ¥È"DˆÜï.]h2YL]íw½.X<¯¢Ê_,]äUaêŠâuò˾PÖÉ|˜ª  7l÷e¸€3È:ñg˜Ô?ŒÀÆ€NÐ :@'¡Y)ñ|‰*T‡;jø>É`õ„¼i?ÉÀÛ ÀtÔÉáצBšêþ>q„œ;°Þ¾N¾îÝ70¬lÛ~}ŒÍî‰5g˜N,½kÕv[оÿ4¦N"4ô¼ï÷Dâ½`zèDu±àL:iz™KÈÞ`¡$hü:ù¤*iHkÕcœÁP„¤ß˜3<3±i1ŸõêH'_6’„7€i¡“Àôgê›/TÑd‚$¹Vd’ûّܲœ­“á@§¶ -¢‹“[sóÂù¾ÅG7d’Ž}Á\ÈÙܦž*I')ñ§I^8Þ\¦R'ªö;Ý%ˆ Ëa:¡Ã›$ѱMêvÜl#}a’4FôÙ·2W%†f‘ûa¹$a`«AÖHn¬ÍÑýkKÊAµjke,­ì‹Š£•i„< ;emÂt²R£k© "WjH]WoâÙBRõÅNÒ\Òu9–[ù*ÞF'ärIîZDÓÃíú澫®½U£ÏPGëYB"ëdY²¦T'ªC¤¯|ÁÕ–H.úU¢ “Mï“:¶«ƒ¹ …tбË›F¬§Å†ficÔ'2 h~‘¡fƒ˜‹ÖÐ,b€¾&!œV®åR‹ V§‘äX:C›P¸Ó~ß½§ÛœNns*5?• 9G²ûO5§J«Œ´ÑÉG‘‡ S…ÉNtqÊAÎÚ7àÕ.jÏ´Çs$/xcœíÚ )ÂÚ S©“ÀÁß[ÅD{>\µóÀú!ÙI†šç5«ùMHÐÊW¶„¡Yus 5G(ÛPɬYÇq³b„…Z¹ŽµjÙ†ê$ð36܉>æ3!ƒd±!‡–5ÇnÚ¿7ÈF'yá—oÕ õÒо¿j`=å)YOÛäµý—$ù Þ[¦2;y‹¦ÿYD“„mUIA¼N-ÂÚ Õ‰MvòQ$¼Bv’j“¨.f’Ì],ø”“2þÒð°ìäéÂwÞYØo›p.ª£?æèc¼–³ÑIõH}³çè,1‘¼s´!õ^†êºïøÃЬ0¥k'V"^mæBØ•'„ì t²I^;!uedU¼¸„Q=°• #‡·¤äçhO…¤SMH•¼NTÖ&l/Z£k)¹}éSaíd]àiò0*ñ75Q­…Úµ VԉЂ×ɾRtgÑ&µX×SAè+èÌ'œÛ.K“S®ÕV~äZï;ï)ûDº²sÔÙa½²óT¸²Ó”ÝO}“4Z\p3޶¶VŠ7®‰M¤+;ú‡=‘üsójîP#ù|Ý` {´U‡Ô‰Ð‚×ɲ!}ÕHêLlêu6W›c£6GÛ;€w€©×Iài»÷®ºðAü!jÕðjFô«ÄÑnJáÇ»ÔP,³é!4nô{aå¾¥Ó­Z=²ÀôÑɦúÄÑGµÃå7䢓Àú-ú1}áê×?öéÞËÆ{ÀŒZ; ‡:qaÙ‡],ËÑ:¸€ëâàà..x˘=:á'øLŽN`tÌg€NÐ `ºëäÑó+ž?’˜{Hqýµ#;4¶ï½–o·ª4®r;íDóô÷í\éªØ êyºÝ©c^-,úi/ìî:‚@0›uRKeÂx^kO';ò‘ã;nON,º‰PcU_»Ÿ—sÇìnxðÓ^h.~€@0›uÂlòü¶e×÷NôW¨Ñ„ÉŽ¹tDiŠä33>îkÔ¶”é›kåoÓX•üû\r‰va"ÒÁ˜•:aɉò䊓,=á Ê:1z™EôÖÜõ½Åœaîmñ»r|¸Oö8Ô‰qP×RÒzœöÖw¿¥¤L7Ì'¥tDw”;Ð ¹t·;§¯–ŽZÚY™žJÄ×ߤ+÷Ïöt|EìZ£ÿ•¬æ_ù{±yÇ¥öÖ\ÚÕISG_«­ËnÕD•´æÒq/Ÿv½¦¹½¤+{;߇†×I}aí‚©ÅzfÆÇ)Qõ—oý¹\þ6UúËï]Ém¦ù›‹‹üý½ð3f«NزÉIî~ùÄÎÚ‰U'ål¤|ném6 ÌÃhg'¥9•âø6i÷ÑŠœfÛá~¥"³©æ®£37iËÙ䦜ª ˆu‘\kg²S'ä¤hÌÉŽññzÊ–o÷1hízÌD[ȧmþVn$.Śء-†"ùÌŒ+·ÓºZø@þ6UìHƒùX;¯…NV|Á}#ëÄfíÄ(é„>]=Þ#x…‹-¾æqd'Ú¿ÜÆqËÿËÞµÇD•^ñ Ù¦ÝÿÚšl"¹›íNãØâf ÌH1AÞ¨A^FÞXÐÑáUVÞ "‚¤ +O× ¸XÀåWKtÝ€.>Á´ *µ»´”l²Ù´iÒ&í9÷Îýw.ƒËc—’{þ™¹s^ß9¿ïœó]îÐÛœÐ?›Á‹6;XÜÀ쵉¿:ÎNFj$Zf$8‘4Å6ÌV^ <šiÊ@þDm0â©ÿ6ùmNl­XÛôUWRÍD8¹{~Ô:MÍ´µ¶tÊÊj³6|³ÎeÚì¨V'ø£N„‰f—1;ÉŠz ±r¤â!0Ÿ…“§c®t¸Qйœˆ"Žpâ´Ù!ÕIË£ÑlhÊãër¦ÆÜÜjÎSµqPb¦™ê*„“NNòG­•ÔL€“ ûZu¢Ñ‡“?mßþ™NœÄÚG±Ìì„V'øcFªN¶!½âìÄF3ó¯ÉR‰{ú¤ÇbæVnRÏ}1ͱ®ÈXAu²T³£V(áD,"l"œÈj‹ÖŒ H è¤:!pBÌdáD«N4ÚØp’ñÍöÞ¯Ú¾aŠU'uê§/‹U'PòcžYìI4j}‰‰¥v²k»}M˜*å“ZY8q6;±±ÍÎLýD§óÙÉ´œt˜Fþ²¢¢ÚTµÙ‰œP398‰‘á¤Îÿ¾vÀ£Ñ†ƒ×Iù6¶IW¹:™­‘j„_»v=otueª<Ù™t«y¢‡Í­füùýšm*²Êò,ýþOSê&î×4áxr&ôÁXý°C6Í( êFEb†:œÐ“ì†'ݘë¸?è‹ ÌW¯N¸“‡f'®%jªvÞûx؃ÅÖ;ïŒÄ¼üTWâÉÎ ANˆ™,œÌX¡fq•ÄÇwj±¨ÑFƒ“mn“Óx“ýô¤|¯h—4ù°sFúT¤:ï;yîåÏæyÝ-µq -:’zàöñâ­"ÒœsðýÆ%­Uö+NÈ}'(a5·í÷X w}º $­³”òwU¿gR]má@ÍwOçÐpJfë>§¹×Z„D_IJÍœº0+~7kS ßDë}zßÚÁ‰o¯t“}¯¯ œ\ðßµ;Óçc®›ú¼®ªFCxa‹kWÌÍ¥ÓûyØŠŒÒo>¼àĸù^Üú‚ÓQ)àÕóÒÜple >zãñ¡ U`¶8á„/'NCc%p¢OOÈßò_5I Í~p8a} ÿrx÷šÁÉB¯ü¬ØÞG8yM5}9qY-–;¢túƒ©AkŸ6zSñ:€ÁÐÿ'8Yò>°«»,8Q_Nœ†ÆJàDv­ª¤Wv‹éû€“åûà;ÂI}Vl›NôyyIÍNøñÎÛ^gÀ·ú{·½ŽŸwPLQµ+JiE|bNzDV6UL•b"ºç ýÀËX|ª+·hè²T¦b³£?8sMxzr0úóܤÌÚxGW® ƒÃ—¥“0Â=4âÊ€ðâÈî/}úN,¨0;¥1øTpÞ‹\áÜ a0SÄÀ MÏŠú¿ØA5ABR‡ªzhÛŠú/‰j_Õ†ZŠzþb@µ!ÄýˆÀÉÙáé$'æ¸éñgÒ7Àã'‡wtÍbW…]‘øU8ÆëíÌP³©Ò½JÍDK¨C‘⨃ð<»p" [3©?1µ'Ž6TL]õ`-J’sÒÕQÉhÂLÅL&"òð½’Ïdf×›,S­œ j3fÂÂÛÓNnúh ¨§‹ƒ"‰„FöN©Ô†Ÿdõ†pÑ"v ²Âεfët­…ZׂwˆfD£™ü&#œ2ûOž2ÈÁ®‘1¨Íh³@ƒV¦€Cÿ‚ÄÂÞ@%íæ$1¨e×,:XÄf‡Í5ðöƒ«ž«'½ôY±½ÊêÄø³³v8©{ïÑ•‰]àœúÆ-=Wª Õ‰ZiÅ Á# “®þèb ¦Mkàù²ÚÔXƒ±8©òë³ÖvˆµáÇœCw>™ÿš²’JËj-œÀk³[ëÎñpò ç‡û¨¿ÂK@ˆ©ƒíÁÂPZ_ ö\äú€1×7ëæZ€¸u>ÿí¾ _ª™®ùaé›e·ƒØ<¨*|™V6Ëf,î싵¯çÌç×ÍF©Á‰K•u¨³o@àádðê[«ç| [:ëæâý0Ztúì„0F¸Î;æ™ïýn„1 ÊÚÒ9ŠÌô‹¦7uU³!—¿Lµ&îÖ1%.ûÅáö–;ol^áS™¯ß¨áT´f…2œ öç®û‚æ ‘”xBÚ"Èê¨Á a¦b&¥ëO&·–Õî c–:¥<Ü(ppB€ªÍ˜é'†æêÊM]ÏRO«I"¡á#]lêHô%«ŸÒz¢¨ûn,¨1ßù÷™Y_NŠ€­eŸ»: ×þÒƒj¦'ò›ÞT8afÊJm,«­àáD€ Ê)8ÁhÆ` ZúRõü™ß߀Òw[PÒMOF’ œ¸<úI‡Nä0v$•¾ÝU½ÌÁ'ì³bņ×_2è®ßŠ5¤Œ#’xWNTà5eªJ0¶Í¡{<# !LGãwcëcÀÚÖÓX f™:$g&Ûá‹”nØe"ãà“î9\èú”œDþ)'àyÖ_Ævp#êÆ`j}6F½^\ j:ˆÖ¸¨fú,Ça•¤  nŽ_¢%Ù¨lUaÄ‚ œ@_ 0“]Áà H lÃÆOA ¬I È6ŒS{©pŒ@ۉ2sϦ,vß1Ee›†è8‡:6;àžß‚pV™žšÚ¹TÁíX–ä}(Vï½…ª’º:êýF¤ 'f:t0û=(³ä‡ˆ<1,œÐ j³f:ÀIt0¤˜ñhêiŠ$æÐ}¯ex¦”ÛW_pg”2ví]88ןÆûq>Sº–j¦'äM*|0‹´:¹>=)½;‡¬™‚¸S‹„ª’cs(F 4|J3y8!£XºÞ1N|ϵ"8‘Ÿ»8œ‡—ÜÏ]2„×cÔ™o)bïµñRÕÆŒ…̲ì„(c;ªó'#(÷Š2œìæÁ¸(>1¸5Ë×G_¹V!I!°œöW¨fºnKfÚg¼‰á%C_{ˆ³»ÚR¤D—8‰±¸EÉà ¼ j›CÑ-â¸íÆ #–W1Ò4'Ú™…‹ÝSóà ¶¡Ä Gÿru„»pV'Ê`"’ #£Ëãý’ï†ÑÕYNÍdºâ†gž~fú#€•t$" @˜±f:À‰7¼$Æöw=³ROG3ÕMÑÖ”Öùów³¨!hÃ8Ÿ)]K5Sò&N™T;¹Ô«‹Þ šQ¢j3ÍN4ä‘¢€…1Ó9œÈ p0!Lœ<…­N³#?+¶wI8ñð©÷éï?ΛõU?Ÿ›³ØìàT«;õ4önH~lX8‘ó23†ßiÁì(8‰XPøË='ÂØÎͤKÅ.H¾ëÌ-‡h™ãì… Õ ‡47„ÀØ"ÌC§IÔ6µcÕ‰©®'Ñâ ½J1;±«ÇvHÀõɆmˆ‘»‘2“bF CZFˆ VpUÅ¢pV'Ê]HŠþàÂ·ßÆ¦C9ƘéNÍdNÒ3·þæ^SÑé³0¬£X“¼„™º™váR.ó£X"‰ŽÕŽÄÿùÿÜðï0ºúPÓ´øëÓ çr…Aî€RÅv§Ær>Sº–j¦'äÍ"œ2S rÑ®”Ö=;Íh·OÔv„“dé+¤„ýÔLs8! }05våpbh£ÏŠý{çÅ™Æñɦ‰Þ%5ééÑó²mî¦q›Ë]– Û ^³T¡¢êÒB VVA%”U„ƒ¸ ÄŠÅÒÂAOÛÓœÅ匭Ö_GM¼jzç]c5iˆÿ›æ4éÍûμïóÎ̳˲¬4ÚyÿA™—÷}Þóç}Þw>óÖør’º«v6I:§Ï[1àd‰Š]梂àìîüÓ%}?TNÆ÷N¼äD鮚j2ë¼5¿:ÌytÞ ³Œ6êëê͆‘û&ñKAN ÞIžÞ;!U¦âr¢<¶ç’šn;Èdú7iˆX¹INtÞ ¡òNB‘]3Ë ¯I^Ûyéúðòne™4A9š Ö NˆÊS2‰¶Â°³£/lj¿è@M05òîõþíÒõ‚Ìd}2óÞÚ«. dùã&ƒ#x'âÔË;qñÊ¡0d’3ï„ÚÇ-Ó=9T³ÍÞɪ+¤Ô5§ ™!ÊÉê¬Zò‡OÇDÀ;û3cÅbÅF9É?þTNœ#pózr¿#Ú'Vn’“ñb'Åtuî 'jäŽW®kf`9šò>í(Êø‹²šGå$Ž[k”±™ÌZÏŸo¢2ÜPmÚ(¦À ƒfÒ»ØÙM›©UNÝ7wNNxM05ÒJ¾ézìÎÕÍ10ú’”³÷ò‡¼E]׳ØI²aj˜b'šeâ$Ô,ƒ‹¼r(,­D‘ |?;1X¦Ÿ´ˆœ@¸×d˜ ¸œùÆg©³å— “‘“Ÿ·2Vl믘œ4¯PÒœùò“OÔ­¯}âg.¹n}óœM-oýÒØJ’³BæÇØÒ¶UÕÿ¤ÂGwvþÕ<³åøë‚ÓêžuéÃýQ³…9¦½¯wv6’eŒþ³xا—ycvû¬ß“ÿx»í:QW¦cÕ‘^¶³£æw®Ûšî¼TNF†ììÔ¨;;šeî³C½¿îkÜ"F—óÞ«|j°d{‚ ‚GSÈÎÙ;ˆË=U—BåDQ§ÊYÊ󸡤þÔî2;*'Š0é­ùüÅè²**g¼rDNÈÎNáàêÎN½agÇ6/ãHá`I§~ËCÀW¯Ì}z¾P9¯I¾ufÛ–éÄÕ4Ë ÔÔ°-kés)Štâr]ÖY8+A‚ÂÐf²R7~ºÿñº»('ùþ΋Gt;;0Po¦"ãûŸ¼TN›©U.íÉ}÷§ûªE9š`jäû«ŠœÝö•.aôÉ܆]Ÿ<ÛrU·¸ ;;êΓœÀˆ“YÆ/òÊ…yVšX{ñ¿>|g,ƒy,˜m’¹ÿ†š¿îJjÇS³Ì5½'±5ê €³'«}fËIº7Ÿ4)9™1ë+ŠýjÖó\NhJH;AÿqzÈ =w;T¹D\ê¨ùñ‰ì}ڶѶ…_Qnÿì½ZÁiM­¦‹·ø$aÂzM[ò’ƒ;‘Žvìü¬Ý¯—É;ÜhWx£áÜœþ܉š?ºÉ—ýÑçþŸ IDATôÆ%çN.Ós'še4Ч?‚ ¥ô«áØ;w¢HjyÕ@ŸzŸ)¶Q5«k³Ÿ?‡/vh•öóÔ©SV®Çèc„UŽÉ‰vî¤?w²9)§éšzîâMZM9êžÉì4Ë Ô”ï%ÁÙ­<Ñp9‘ê>°Û‹$( m&/õ,ù^sŠn7ìh‡ïðÐ^SÀ–Æ›Iúð†aµ™jåä܉ýÐI}üÕSƒ8Ëê¡Jaô•g=¬–süKvN;wÂGǼŽËÄI¨YÆ/BåPØýŠòªœ;ËéÌ6Ê ©ÉWu¨]l¦n¡ZÖo׎ˈ÷¹¯þ9QîRÝ”„÷9B¯ÈÙàªÍèOj$4‡Í!›ÿX V²B¡L‡#¤¿±üyÁŽmÛ&0S}P×TŸŒä Í(ÚL›ýsR¬Ä -?Ý hº#Ô>³k°-ظ:Ü2¬™!OGà_Ër$ޱMQšðëaqŸ<»©/wÑħ¾sS_cÑ}´=ÂÉ{°wÆÍ«¯$HVŠp’o –tÅX–…Ÿ9ióÙé d¢©¡:{tÉ#6égM‡«­‘”ﯺ¾À²ìa“+M*Ù&¸ž±ÒúÖfYfɉ•¬d%KN¬d%+Yrb%+YÉJ–œXÉJVš9™$+Vª;¹+öt%¶™¢¾RÊ^øD“Â{Ñn‰qOÃ'_zŒ6O®öTxtQ# Ì–Ú¶Ó¾l¼½)çAv6* πÉäü y=-¾8Àè<(R˜ýfÒ¸Sc¼ÊsÊt‡˜Ir¯ eÙxB¤1²ü!ãí¶졔“ɲbå¯Ï½6óà®×‘-r¯_½aèëdáË ƒ[b ÂðɗΦúù¸œ„G5ʉwafáœÛã€ÑÞñ‘"Îð KNä‹Ó×N½œÄ™Oœ°UNX~KN09™4+–$‡üþébó¯ÙëgóÐé¢f™µåsO¹œ„GÖ4Ê Ehr2U)ø}#¯äÄýCʉے“‡ON"ÄŠ}ÿt¾JIÍØ¾„Y¦U”kÇÒ8®H™äâá ÌLùÉá–÷”_D8© ±’ï?#×u”kïàðÊÉ‚†úNîwÚ®Ù)*Ö“û]›ý2ÅÊq91c4¡0Àt"¨RO#µVÄsUöö‘–KQIÞ@ ù¹GÅ›ÉÍŽ[Ûxä`yâ§…J÷úØ“ÛÜá£fó×r„×l¸œã˜btQà벋riâÉòªt‡„ ãžÊv­§¤ð!ª!Þ´‰ ¬X>Ð-€¸5#t!?LB^2 lrV¬üø/μ-v¤þøô=¾­ V'{G²škš²é;´®H™îž¬æ-ÿHêôÇ'É n‰qOùE„“ª‚ñâV9äw¾xmÅAz‘³båÙo«K1oʚ>ô4V "ä= Eš1šn^ÇtJªÔ9ûLJ×ô¨SQND•Soµ\ϸ %€…ü‚œ°fr³ã2ê32{÷nŽá´PŒ{ }ìi<ßþ‡«„.ÊÁ³ˆœå˜btQŽwååR{ç?Žd.°àÜÓ‹Qû2Š¢”ž’‡¨ÍßMëÊ3­cF9Ѹ¼rÞ-â֌Ѕü0 ¡0ó$ Õ²GEN"ÀŠÍ?ÛŽªí¼Ü—Ö¹³£´39.c¥‹¾›ªáZIÀ““2YŒE”‚cîÿæ–»‡¼ÌÇc”&î)01Nj¿â©Ü: HF+†bé=ï!wVtáD09 „Ѥ…qL'Ž*Õ¼bQN4ˆ*Pou±µ%€…ü‚œèšIÊŽ[õBÎÞ®±µ œŠqO¡=äÅÿÔŒ"ž‚ÈIPŽ)Ò-€wååRòVk*CY™@bÜSÍ•'QE¢TÆS¥z$®Z9_ì°n·f„®¸ØI¨†ÂzC³ìQ’“I²bå3O \ý†êE#Ëï­{1¦Ÿ †ï·ð®@Êt÷¼ÚÞªwx 2“÷øVz¥Gäd £±œ˜9©i%Ë]*.8ºâK @Ù²¬Ûnŧ;9ž ŽÅp€F“äUŠÊ 3[Èj’àw‰Í„ÅÎNGPÍŽ»·#߿̵:3™ÓB÷ú˜› àYDN‚qLǰnaxWè3ÛHbÈÜSMN&Q 5øÆ¸BåºØ‰Ê!âˆ[3BW”6:¼0Öû¨§È³b•T·~)¶ýßK=õþecäÛ’ÊñcÈ”9­BYw낞{KK¿½þñËäAä„Ï~3ëƒÐÀ(iŠ|záù5Ãbå 'ä so,¤«gj)É ‚Ñ„ÂøÄP¥¨œp £Þ"rèQ±™¢E ãfS9ÙBä„ÓB]÷úØ+&·."'Á8¦c]”á]¡ÏT‡…¸WȈÜSÎT ¢ºœh *7ɉ€¸E00úP,åÄñÂpàÌIN"ÁŠ¥~ȉýÈÓ»pàPqÿ¡”•w¢N(=)sñY1­äÊÝÊ;ƒ÷vHáˉMyB®%Ž+¥Äj7“œP¡óR9Á¼F ¼ª4¨œ„ì‘n6È ÐBî)ô±è¸TÝà»Ü; Â1 @¥xWè3™B(ÉÑ{ʽ“p!ª•±rÌ;á$ßPä ³ädò¬X÷Åîp`;»UŠ7^ý‚ –b±uBH™Ï‰÷U–ú·î~³5Y/'îip9‘Ò^¥ÓŽnTçûQ9¡üWÅ&r"ÄN4²¦ˆÑdñ ^Ÿ€ªæ MEê¡F½%@Ð.SìD£‹“0äİÙá1o¿Ò>æfCìD€ï’— £cˆ¬ÂA4ïÊ/Ê¥$?ñ¹§Zx%|ˆê„åDÇŠíÒˉ€¸Åä„å9á…#'òÍß0þn÷ïZ’œLš;í$=Ɔ~C.°/›¢ZµR"µR‘%’ÉËTl^ªaK5ª ±1%1qí Và“˜„·|—¼J1ÔB…¬âÅB‘ƒ[©ˆC\¹ð”À§*JZâZ}°úоô!{gî9gvÎÎ~Ø‹ç@Ìì™{ÏÝûßs¿~³p‰È1e‚xW¸h·¡¸ý6®(÷´¬fèäre'Oˆj®rB®[·œœ¨û‘° Î2ÈIi|¥o—ù¸·XN¦ËŠŒŒÙ÷¼Å“Â]­aû—y›áÝw2¥v68¤ÌÈÙÁ˜³õƒ®;®tni0ÜS¸È·¤X¥–ÙUùÁïÐ}«»ÛaÊ:sÉüäT¿œ;}'Àü$Meà ¿€ ª³b@›yê­ýûÔÓ%*‡Õºh œ@±QNÊpO1ÆXlÏ"|×®K»ˆq0ÇÔÂ×U­{Åýõa®(÷Ô:3èî;É¢š£œx «n`XqËɉºŸ°¼•3-'ÆÌ°b­Ì+_ü ’”bH¡¡ðcZK ‘Ê3ìØ¬0šéP¥nMò-U¶ÅÎæ£¡@+õ„S[‡¯qPX܋ܻYSn ‚õæ QÍÕ2@WsëaËøšš>Q¬í±Xf9ÉÏíQÕr¢M[ÑËÉ“QÕr¢MÛ“`é ªÖ™±Ÿ:Ò¾˜R›–mÚ²³°c:ZN´iÓ¦åD›6mZN”í¾¢Ã¢M›¶™“‘Êä^Ÿ9Vl*z455Mb&ÃGÞ÷â.p·W&g›úòÙ•eM2YmçúUÓ©fZóž?D®1žÈš§ùœEª_žÎâ­<À«mNÈÉÄdò:/'ÓcŦ¢GÓYdÁu9ÊIùg¯¦ù6gpf]Èë¸G–5ÉdÑÓ/N§šÓ‘“ŠôˆÍ<*’êLˉ–•œLN’ôdæX±F z4½•Õä('>E"ßæ@gM}Uù©B–5 ¶ ]k¤Qµœh+9™h8>9à—“i³bi'Ä3;ÖážX㻇 êW€„Ìò(gÓîAuþ¤|ÿv·Ç‡–[[k.Fª ¼è—gÀüôær¸ÁYU V×q¤·ë¦Ì¼TMÈÁŒ4DÖ{.xÖÉ"ÁU <¼°H À™(Yü=q> ªiî1ï}Ô¹&Lh¤€kå@µêô‘ÕR%é°+(‘UY[UoüÈ•˜í À³uëÄ ‘~šC‘š¸1㜑ðƒdÙ˜AëŒöÆnžêÓr27äd¤<Ñn&0=™AV,vBdÅZ‰£Î¸¶ŠDýrR&NŠYêQ7öÑ Ž/e*~ºãäφ—·Kî8“ £êb¤ÚÚ|±SÐ Á2?‰Žr±>"+ J©œ4þî›g¢"¥ðË CdÅjH ®âÞ!¯¸!xuw<Ø|`Xt_¨f÷öÓçF.™BNq­ ¨¨· '„ÈŠrÒø·+]Nl_ð¬£wµž™ bÆ8Ã`@²\Ì u[éÄ}SËÉÜ“‰DbðÓÊÉëÜ`gš¬Xì„ÈŠmê;(: »¯ÑˆúåD²sÖÂÛnÊÖ‰ogyôêjfŽR\ŒT/û¡`üæ§ß"+¢J©œœ€äøøå„!²b5$‹WûÖyó˜ÂȸΠjÎÆOçßÖ–†z»r]BNˆ¬¨È-('Ìø¤­j[mgëÚj7ɰšGœ¹5Á˜±ƒÕ HÖ3Ú:Íû]Õr2'äDÌœÿ,‘L^ “‘¼þË•¸èÌ:YºëŒ0?™nì'²"ª”ʉXU–ØFnîÄGd%ÕT\¹Hˆ8sKæ?œQ‘SM'Kë–s'ŠÆDVT ÔÛ`9Y/ä¤tßÏ—"/ײcnßæäc–v*ÖnޝËÄ [GªõT윓ðC;/I&w&“ãã3ËIެØÀì„D9±3úJp™:Öu°r‚ùìD1?ƒ³EÕT)•“-6R4#'~"+—‚«„Ä€8+}侟ÜQYPmjvÒÌʉ…r‚¼\ÿð¢ÎrÏN| Y&fÐ:ÎÐj“žŠÙÉÆäx2Ùn¶Œ÷g–“Y± G‘ëÎ|‹\¹WkV¾þ?1@p€X‰/'p‘Î(æóõ×Òïñ`ˆ¬ˆ*5€áY×!A¯²o»5Aö«SL§LMßÛ¼ÔSMB2àmÑïê `¹¹Õ/ÈÊj‘zÛ&²±q…A^xãËN¦—k{ú¤Ý»Ïj‚1cœ‘¹?H–‰¶Ž»îN-'O¾œ„†'mIþçšøküš+'3ÆŠ5=ЬXgeg÷þ¥ jߪöÌ÷¦‹vÅìÔjûËÛß>\cR9)]Prçý·KLáÅHu|蜻²£œ!óÓo!†È ¨R„îÕuÄ<½;&*nMýJ‰¬åQÙ;°šHd‚+;æR1@gÍ¿ßóüÈv[s¡šbegóÈ Iåq­ ¨©·Ñ»®‘r¢ˆ¬Lv‚¼\ñÙ†zƒ•¤ØúØ H–‹´Î¦_œ~ç•ëzegÈIIÿ8±ê8r2s¬XD⾓»ï„D%¬Ôô¾ëÀƒ;‹«·›ïí©¡rRÛ)‡Ýö'á"Ýw΀ùÉÂ"+ J‰œÜí9ûN &À~¥DVWNè¾Õ àÊÄÕö¶;¯¼ÅjºûNZ‰œ ®•Õ"õ¶ôl{üÝór°DVÿÜ òr…½¼:œ@Ìgž}'>¾.3hÑÞØ—õ`gÈÉâ…ÃÇŽ½4&ì¥cÃóóö™ž ?`¡ ò¿lÿGü"dd¸—oñj0û5”ãÿ…,e`ôú ßm×Ê‚j­,#@ Vã¯Ö¼*Hžäɦ™"kDÉÜXÙ‘`+sþZ•“Y´µÏ=óèþk/þI¿ytý*ÝîÚò–mE/'‘?7ÝQFa­tÀ¼÷…N´i9™ËÊm¸4-Ój¢Mˉ6mÚ´œhÓ¦Mˉ6mÚ´œhV¬6mÚ $'cÅfo Õ]U²X ®Õc «îQakKV¯¦ûãê³,feITƒë`£á-RžÚp‚½§6©ô‹V×À“–PS^jYÑ+ÌÈ ß=òžy7‹¿KgGšdˆjIæÆZ²ãD³Ø¦Ô˜q¢ÛØx¾\l¥uƒhÜ×·;mç––õû¶#ñ¬Þ‚ᛣ<4ô®p$¼«#"¹ovÔSÜ›W®ØñÃo|û'/pÝeÙ/SjÛŽ ?ø; ÔÃe jS±¡ðj†feµ²Ê`b¬œ¨ƒ%ß'Q½§¬20¸Rœì!8AÛã‡kåÑ3éæ¹“™LÄ Q!´ÄÁ Çb ®Xž/[iÝàW*Š>{üņ¬'k‘xÖâiânm¦Ûл‘𮎈äʼnWåÈ„DgbmS±’+Wì:0\ªÛC¨B¸À'Phd'½8;1좬RVËNJ›¤"ï©N˜Á•á[låRûëæýWÿXµ™ÅXK´gë÷™²r2,wZ(;±ùr±•Öev¢7^þdà·7ïU½‚ij€ÈN˜ÞŽ„wuD$qv23´lhªç¡Ãƒb®Xßfµ¶“/þå¿ÜÙýPø`z¿ ýl¶íãℚæN¶ughùM¾-åÊXkÉŸÍ×gÂI qÏŒ>w²Þ±À™;‰‚0¸2œX,¶YöGÐäö‰á„µD»J'D@yH#!ñ,àDòëN@ï G‚¯ŽÀ‰À‰öÎùÍS=ÑšˆRèå8}ÞQ뙿ƒSìv2²z¼^wáñ¾ãÕ’ýÃq†ó—¨Þ‰¸½8;ŠEˆ!p"B„"Dœˆ!B„À‰"NDˆñ¬â¤î²8-"DˆHNƲ"c¬®"[eH‡7›[‹N$éþtä*'stÅòT¥¼ŸêÅïoŠ'Ë?]뀓•)ƒoÇ4Òõ¡mNÕ¤ÔçÇÓY«w.8I©IàÒS[e'"抓±¬éi”ž$ÐËßÐÊp¹qâÄF$´>je¥áì˜ZGå¶ŽÜQÚ¯Ì.èYlj_àDàä~yût¿'swÅ"œ»èmºËÃPbµ©]ôf¦M½K#+Ù2;UW[!“¼ÛA}@!ÚÌÂ*ï)Š@!Ñ P]ë°¦kÕ¥«tÛ±D·ÿ²iõÉODHqk4N²—ëïO¢ ®XPâJ t÷+j\9y¬u´šôèÀ1ùö5 N>j¯ºAôwÈel+b¢Z8¡šB©Xr(d½%§…œ3NehÓë²­FW¬]Ö+"q2¶¼«VîbéI]± 'W‹ìo'úP*HmjÃÉR²OP!b0²’ýûWw¼þN&y·ƒ6w2n2‰*«ŒyOM™T'uFVÈÞ»tGýééê.-m …ófˆ1;Þ†·Ð¸:ÐŽXŽD•¹bA‰«¹_[ NŒÆ•Áª{[Çv¨ÉQB‘Í8!;~«Ôp¢Ö•ÛûµEßMÅ|4Dµì„RÞ…Â8‡bÖÛñš»j7²ó%NelK7ë'W,OÖ+" qr¿«køã¬é«¼›¹ºb' ©Úä¦Y=ª«Mm8¡&¤xÕ1²’}ÅÈ‹ðT,)d"¨ yO9ýª é v ]]þÚFåýŽ™¶Æ¯f62&<4Å-jÜó Þ¡š$ª¦éWýÏY†û•5¾4—TÚu½E©,ÎWûßjÆ ÙÜ|µÈ´ÚvÂDµì„ª0N'²\™a½ÕÞ¥Ö¶lëæÜìÂè'W,_Ö+"ÙpBfNÚ?íŠDÎGÁÉl]±€“Aò3Lß“ÁÔ£HmjŸî ¼ S `d5l„'Pš2/T†¼§<œ~©CƒIWU*4e–__Kk$ÿά´¸q[Ø%ª&W¬n‰¢î×Ò‚½q½Ò¶Æí¾†î ¬eÕpB†<ÉТâDµì„úwþ,Óbºë­xAÕöÚqbÈz¡g^nvbsÅòe½"’ '÷§#Ó•g§#ðp'‘®XÀ õ1R]!¨G±ÚÔŽbE¡–Y0²êº1N $ª©Pòžòp¢ &]-XÕ{üÑ£•䨯y‚N¥ Åírç—{q$ª&W¬Žp¿²qY^¥µ¾AKÄxS±Ä1qBe+è„JrÆÍ§Ì-þ>2yäk êþT,‘õBÏRùs'VW,_Ö+"¹pâ} æ%‘ÈÎHdròAlœÄ튒`µ©'êOægÌÈÊÁ +äg'†÷4N@ºªTvß¼wùG}$›Ù•ýnM^ªIq'‰ª„]±Fv²²PO—ü™4¾yBÞë£d'šH6 NÐ -Xuå¦Irpâ&;éM‡žYÏY¹þFR‹+–/ë‘dÙIYd2©•+&''ûbã$nW¬¡*¥o+Æs'ϙԦœÇŸY¯ý‡dÚÌÈÊà â¹½2ä=ý{çerÇñ'ûª½4“£$Ú5=Ÿä¶í›]âb+w .¢^𨬇¸'ІÝS8\ù#…“ØzDCï@Q‡(zh(öOâÙZõjﮩ我FÛ䈉mÚ\b_ôùÍó<3¿gŸÙ]pUæû”çÙßüá™/3óÌ|&‚ èjþå_~ï´èÌußž#n#Ù‰¢ª•AýŒyîDOœLrhÝ‚-PÞÜÉ ’e§™ìWhÏå×Ó¹v‚çNLÁð܉ù…4œ(çéç¥Y±|X¯ÐŒ²Ëàßùç¿.À·¯.hv2…¬XUêù,÷`U“×§¿ÙÙV™„ѦÎÂÔ²8c7ÂQÒ*#²²íœÿÅ©ãg³‹ ¢Ê‚1îi$;Ax×¹‰nòzÃî¯ÉÊX„¸`'<ˆ*eÅʉ ƒ‘ª›~l'rϵ¢MUƒïg)êú‘%æ7;ÛàÍÉÚ;Êkq?g'¸B‡ÜAãTÃT¹áÍyUf †ßìè9ÿË#{ÜŠpX±|X¯ÐŒ²“øŽ¯Ò^Síd*Y±:ª”­;¡èQŒ6j©³ÿRÊ+yKI‰¬¬EgV»òIz¯;¡Á(÷4’0è*tž”–‚GˆÛvƒ¨RV,CâjgFvsÉþ`ÿÁd²îäêŸÂ¬;Á ÙÍuÆu' T‹*Ô©nàÙ ]w †ÖXhÎØïòHi°·,˜ÃŠåÂz…f”$¼2¸wï’?ƒ–쌛†Ôhó°D¼mæ©üHe~"e1ÞuRÔ(!Õ0‚<ùÉp¸°ôò£V;o¬ò8²pk++ÖfÍkfÏ–D“,ªfz%ß-{åÝ&Ó±AÓ ÿ}Û”[#*\(v"ô¤ìäã“uAãYÓ¤Öº+]â\>!a'BBBÂN„„„„ ;v"$$ô\ÚIR{ß‚}íôMÀ²b%É~÷dÝéO²¦âm†ºø+Œ`¿_5[\nñf«Õ»tÊ¢‚•{dã‚cïrñ0 =ev’¬˜ ¨/™c'Q²ba#KÑœ¿´ø¦ÝNäÙëÓ&¶à.½ýŒÛ‰ëZeÜ‹°RvQ„eºBB1±“qp“ð¥oÜl'“SxV¬kõ¥Y[~$M·H²s×$ìÖÊ?ãvR¼Xsxa'BO´+F2Ö)(†Òb'ѳbG)®Tß³ã(960úÓ’]ãÅ©-Áúaÿ™NDd•÷4×û?LÀAtè*V›UÂ*Ý„@ ÔN†4"+òD¥UíÄQ²’˜§ò&Ž«ö#Voo†ÑN´Äi° IF²*-BÜRé„U9z¡4Ø›eÃ9ÓºƒÙw‘ @¹Yr Y™„î—óoñ{ë狇\(6vý’Ú€«ô…öN¢fÅnØÝ¦m £¬XGIÛ¯ÝËšÖ¬(öþu¸îö¾­Ù6FdmØy{SÕ`W’!†]• ‚ýegÝ}¤àYލDV+¶'¢ÒªvâìPoÎ\·Œ%Ϋ­×*çV]XjÃv¢'N‰¬¥²N8TÚ!†¸eæªV倵­ó7@mdxWŠÐìz|Anmüìqå‡VûâãGlè~9Ïû߃¯Þû<]<äB±±˜6i—ÆÈô‰y°%+ÖQ¢@(+ÖQò+€å?Ì*NÝ’Yáó¤i{Õ‘UŘXðN2 ]• `G|ÏÆžåØI¾N1 WÈ^aÕNä¼ò罋¶ÖËY,qJX•å)¦O뉳`„&Kᨴ*âV#¬à  £%Á(Bw¢`¡ƒt¿œgèH2!¡é¶“µ¤“ÁN“ûµJcs”d赃 f—¯h¨Xfú%²fVœ9~ߨ"(tU%¬ Œ¡ÝÌv¢YvŠmQiµ¹×Ú†Ûç”ÞMœV{üE›FlF;ÑgÁyîçQiâ–õN4ªŠy$ýŒBê& j'è~{+$ÃÁŽ2Ðéäv¢fŲÁeÅ;©N;Yvâܵ=‰YaÁ:Zk¥CW%gÍvB‰¬8ŒJ«ÙIbޝµ¿¿3í0JœV퀒>ÓišŠ…äX0`µòJ‹·hîD%¬ª½Àʳ`¡;Q°P;A÷«ð8!¡XÙ‰Mñ‘‰ÌÄš¦b¥¨Y±l*ÖØ; ±DdU>s/ôt ºÊZtHïD…¨ÒÞ 4© †©XL¥ÕìÄ“vøhåÊÜÙ6”8&¬zîVlçž1ƒ‚5TøH…C¥Åˆ[,BXU,o¹Ú­`Ápï$b0NïD¿_؉PŒ{'ã} úÆÚ„yQ-+ÖÕ/Šå+–c'ãˆÈ*IÜFÐUÜ¢uð,‚¨*mŽ|ž4ð† l'¢ª5B90úck0Ö@XµïZ›Î³ÌÓQMÆF*-F܆̀ìH0 GO°`¡;Q0j'ÚÜ ºÕœ}ßœdñ¨ =i;ùáþê2¶û_ÖídêX±Î£°Œ­Ùg£¬X^ï„Yó•Í=»µ·„ºÊN¢àYQ•‹½ã^‡Vç/?3¼ÙÁUGIÛ¦8Ò8ÛV¸•AÂÁê„UçÏŸ×݈ç=Xâ8XqÐOn2Si1â–Ž¹tª DÖ5[P0ŠÐ(µ“D÷™ýëG0Ù‰Ã-:*B1°“ãÆCy0÷µ“)dÅÚÄ ‹ìÙº³0"kfK©vØ/›ÎÕ¡«!GäªàYQõ 7Z¡ƒ2Ôâ?}Î0Ø1Pi•OX}ÐY™”è† †ƒÕ «dæS[§b²¬a§zT2‡J‹·¨.Tª("+l=`Áðº“HÁ¨È‡NêëN´û…ÅØN(ís!aú%ÂuÛ£ä‚ %Rê…±=Zælúü¨«¦D¹£„U΋èG6ñýBB1°!MOŒ°:);vò ë‰V… ;v"$$$ìDHHH؉°!!!¡Çµ“(Y±6YìÖ•À¹æp[­§á<ìIËr¨,üÇ“fµ.Þò TpxœA­—k–ôõ)# éJŽ<*¥îàœP‹VûÌ…Ëü\±þtÙIÔ¬X×;ÇW­Zu߯µ“µ?löú&ÿ ; ׆Ûk"_ÿÞæ™a'ö¦ú¤©ÊŒ^¡Ï¥°%ÂBO‡DÍŠåºmœ»(ÓáV–§#uùTØ YD>#ìd*õ¼Ø‰,ìäY°“èY±®K?³Â›Ø‰Ôê÷ÙÐ6ú7xWuwiPEô‹‰9 Ý–jÉIë—«Û c˲.ò¡æºÓE†®/ÏzÒÖ~zË[ôÁUÝM¤¤î92`½Ú#J‹#KiằmJvSHö ÜEa+’=©RlÍ Z(Ý7Ö«Ào uàüx ØÛ vÂÉ6LÈ`'1熒íúdÃ0H/ /g4˜ëíïZê®tá U‚mÓ‚9>-µöÃ/“!qi„õj'µÓ” Õ:³ß)õ~2¬ü‚ˆqÙa¼và½o´XŒbKGvr£É…ðBî•JF¾¬Ápß-·‚PN°çkÊ Z/¦ε.ãg[(v5+v̼S–ÞN2+VŽ3¼+²oýý=ÀI¥å—×w´]*²jíõáËo";axWJX•{ü·7ÝzÏ9Pð¬'ÍZÿnåâºê xÿö“}ï-•ìG½•󺳕5_š’´põ×EûßL‘ó‚7^ên$³뙋¿»¹fT«ü,÷àܳï/GˆÛÖÆú—ºoÃ…“mçìvkvrºëÇ_4âSEXIx9£Á\£µ¿ÎÍX…&æ\)úþpìÂþ UÉÆÆ7m ‰Ëê€ë*UÊ” ‚ž.œNòÍóVV û vâ:7gî¾›Àj¡[–8²“ R~è¢8ÜW{¿þDCèJ™[GËæ¸” vâ¼s Ü„SçΗxÙŠ…DÏŠÍœ³êÛ?ïšÖNÞØ œ l Q‚ì¤4RU‰ÊU¢MÔNÅòÐvmyÕÄ21—R#°K]ƒãKL°sDÆ¡¸¶©Á ‘!ÜŒˆ[ Ť\‹i’êÐX*Ê[¥>DJÏý|3sf½Ën1%ßÿ!"žÝ3ç|;ç?çú;¿«âg€˜I;10†Q£ÔÙIŒ+>h<Pwv4ÞÕùÒgv.섾xx”v¢ñ®Š°ZZÅûÑóÒc'<Ë«$}àt•<ß|€Æªá_¤U]RiAIƒd3Ä)Yüi¦7†c'†bÕFÖÈ©bæÕSè}¿š² ìÄñš×WhI 9Ó‰íD$FçÛ©Vg)$.ˆÖkwÐÞ /E†÷¤03æ«êNvMy˸’ë ¦i ¸¹k(–ymªàÃh„î„ù‘YP¾‹u’`̤˜è‡o'‰³bå—~u(ÖØ:‘v2Bëd}«µ;ÑxWÝ:Yð¦–\pÍk0ð,'Á’@WAëdýâs 1Ï©´`æ@ƒdeU"u9·™¨VÛ‰TklÐZCOÙ0g;šˆ’„ 9Ó‰E³Ê?ÒO}Ã*.Câ:bà†õ:Z'†ƒEÌ\­Z†ê翟´çÍ ­n'¡ ['óÊÖÓŒ˜Ùñ2†Q¿u’0+6ð}6rqŸŸä÷Mð®;y…wŽ÷?ý;YLJ•Öùm’•UI(P­Fµ@µbìÄ ëb².‹ÝÉÆNLÙŽf'¢$¦œéÄvª³Š§Îq ýf–+NX¯cìÄ|Ž)™;ap ºcæ`×4;qÝÜ1v2CÛ‰Fè:ÆNȶ7ݳÃ`PÜÃúçO÷a%-;I˜›þRE㡉ÆQuºŒí[Ʀñ®;­âò&=7Ùa''Zä\@fÁÖgÇ¥¼«"¬Z‡¯VW4ž~Ã1Å,Á³ù9 'v­ýÓ,]µkŠª+øÌNaËØæóg¶I*-èÃi¬¬JV1ˆ 3; T OÍð€jÙÌÎÅÌŽ(fë˾»g-›ÙñfûZÊÖoø&åBØh'¢$¦œUbÀNd@ub©íŸíÛÜ»n²Fâê`½gséÌ;ÏÐk'šä[\´îÉ&:³Cš3Ÿ¿ØSEÚA•«çD®×B;Ñ7wÍìÔ‰™yÖ«âñÒ™F1³CyÀ‹Ã0f[¿W2+³mw4àÙÍ£g'‰²b#÷n¿œlž(V‹ìMëN¤À‹ ›þæ^wòŸ]bÝIÀ~»–^xW¸î¤ªáh ¬ N×TZðjÖwRUI­;Q Z’5€jYé<ëNBGÏ‹u'®lÛ•âôáûF;‘%1å,(v" K%Ù¸B~€ÄU10ÀzëNÜ5UÇŒ„¶­;!1Ø|¥…Îu§6UºÇNôÍ¡Àu'¼ñ x¼tÝÉ€XwB[ºs`Ì"wkÙºm´“Ñ´“„Y±Á0žÎ|À‹|БǠo~é„å®/…Ù€¾|‹æCoõE|"lÅC7(Ž˜òçó7ƒÄF3Ù—c¾6lÅpó˜o4ý3@Rî£c'¸ < ’¹¥ntõˆ—„Ϙ£ÐNÐNÐNÐNP» P(´ …v‚B¡Ph'( í…B=v’ +6øºûÜÄ‹›Y[(éæKðkQ(TôBŠáÇ;I˜kmYòyØg)¦ÝI—Ä—;í#cÁC±“Dزh'(ÔØI¬X»ÐweUY;§ý¬LƒÜSa'ÙWé6VÇžZ°ùEsL½tQ@d•ûIô °DÙ‰ $»çXèÈir'°™E&–½íš¡ûa¢BTQ(´“ä²bóët¿1qpŸi×DÞ2Fc#ÿ…ÜSa'eí‘zø/`Ñ+°Å15ÐE5‘UqL¡(ô¨¢·ˆ¬w*ÕA;щ=}9wï)?I‹QE¡PIfÅ–õNÜù¯Þ3_nµm-Å”Pöäž ;!•Ô܈@Ñv¢8¦–.ªˆ¬šÅíD¡G¥ˆ¬v%ù€Uí‚=dg'D…B%›;¦÷b–0œ¨v¢¹§rìd[ý¼4N^5´N$ÇÔ@ÕDVM ƒv¢à^ÒN]ÔúÎSOý<ÓÒ9ñU³vLØITˆ* …J6+¶¬wֿפùuv&°ÎŽfwH;‰T¶=ÿŠƒVä;áS]TY5ÇÚ‰BJ;tQzð Ã2ð`6;PTi'Ñ ª(*Ù¬ØH¿¿À¡X¯Ä›ìÀ —”ЉdÆ15ÐE5‘5ÖÖ‰¦‹Ú¯Î;n–§u’ïÛ:ñ‡¨¢P¨d³b­·)&–÷‚ܲ;§ˆ‰bh'™’éµ°}àçœñr†B•ËÜ(ÇÔDUDV=ÜÁË‘0vB+>gËšˆ¬zìD¡MáØÉBasfˆêîŸíÄV 嵓„Y±äïƒã{ϘÞÛ–ZÆí$uE[ÅžgÍŒ 4Ypó–\RÉ5ÇÔ@ÕDVÅ1%^ðÖ¯×Ê™Ž•lY‘5œ-gvÚBQ#«7MúÊ¢j‡pU e²“DY±À»äOï'ŠÙj ¶ÈÞÁ=Ýr,ZÌÝÃuÚµ½¿¶áÈ!:³£9¦^º( ²*Ži~ÏöÕ=Îu'’-kÉÒu'GOs¼«@›(j`÷®Íb݉¢Šv‚B™í$aVl_fSÅ#&æ“¶ 0 ®¸>âþ?~Z^ôÉß$ATQ¨o‡Œ–¬/º—í]TavRv¡Ph'£m'eëîdnÐNP¨ÇÃN¸È…B;A¡P(´ …v‚B¡þ?줮ÂB¡’a'ÝÙÃÝúzœ¬Ø²^Ï®@¥q­¥ÛC¡•iqÂ}6 >|¤ÄÊÚùÒ¹àΣd ìb‘]ZÏâkÑêØ&®Û¥Å!ð._º”¼ÝBÞÄÁîA´Í±-õ-·“»CÃ}f;‰kA—äºhú`Œ¸ÖÈÓ—çÇi'ŸÌö±“³‹mBl—O|vÒŸÜ=5#YvÂ63%MžÄÐNPI³“îì¡!Ð<‰“K——#ýëÌ ÒbĵNÈ]™–P¡"àðÞ¨‰-lŸºôÁ줬ý×ÿ›e26Ú êñ±“»¥MC^;‰Ë¨so…£ÛɘºÚÐ;=ƒ’CŠŽl [[~_+¶åx •uf(`©¬îØæ"¾“&cÁ?êjNfÑÃ5ÊYgG]Œäl¨«-âGp¨ÄèœSÓË,`»)÷„¨pù×Í:A±MÍýåþã¡€-«X±$kç9ó¨s¦A²´˜'ª³x?wvòûIÆšˆc^®ÊÙ×uâ"´“ÓÇÙÖ!µÏ)²†cW¦Á¦RÛíò–7lØýú§|7‘¾{ëXh€bZä`H îsòÆŒ­õc†£‹©Ã²eWhàÚ Ú‰´“îŒÖÚP«nžÄÉŠåÆsÑçÅ-í$¿¯pGcSyÞ­Öíw6ž_wßÚ?øÛ¹]Ë Àc'¤RÜX”Z’wãÒøÆ&¶Ï7£àÃꯞ΢‡k𱓳òb$'t²¢k-;‚C&–Yßv°ù¶«IqöF ýŒý£’޶÷Rž¾O*í•ê'{6Ó~Ljî_ü¹¤k¶¥Ø²šK‚ð¾«ï¢n®A²vgᎹÍ7ÈË?xí‰Nf'vMѺƦ*f'’—«rf×”·46mvÚIè³UÍ+V/Û&¯¥¼R¸)RfìÊ)«únîgc ûÌ3Ï6ß&&i„ï†N¾÷îm’¾þ¼‰¾®!fÚNT1BwÙɃ]ÇCh'h'²qÒÚzìÃì¡>Sg'V,{O;ø&;É, Ï^ÙzÒ¿XØÎvùåóÎêœÇNìJZr6ˆvЄù´Fgè{àP,½É¡¤”ååub‘>R%i'ì3";¶ì±¤ IDAT;ä& ÙöäÔÜÕ.¶¬fÅú-áe9 Y _Ò}.1›7Ÿfê f'‚—«s–·L^vBë<‰WîÂv÷OìÊ™é‡ çä-Œl’#|—¶â“’èÀØÙ|]SÌ´¨bª°X‹èÉ'Ë7£ è‘“¦OZ‡‡»¢ØIV,ûÊ’áèvÂa‹5S—²ŠÂ¯¥Ö}JÝìÑöwÐG—õɪ€OÖpæ+´u1’C+J&û€HlB.møøÇìDQlSs_ÀiÁ–¬XSÙTÎHÖî,oٙl ‹bî¨î¤s–½]^vB#BI¸ÑíäµÉ­S¦OÈ]ΧÌPÑ43|—†Ÿ‚þŒv"v¦˜i;‘ÅÔa‰¬icaG;A;“¡á¡E‡††ÕäNœ¬Xúl÷Ÿñ›ÃvÂa‹”ÊÈjkÒ¬Ÿºê%=>v’Jz;Ë)¿ t{õøI—çÓç=cÁ´€ÓNÔE^ëøð†H,¯žÌLÁNT¥¥÷d©J¶,`Ťs¦A²cꎇÄqBÂNJ¯¾@m†Ù‰¸“Ι¾èŠ-kŸ£ÐþÒ¸’ë44Ñà»úðŠ%ŽcŠ™cì„S‡…·q(íD°bï‘vÉðpÍððÜÙN ¬Xú4ž;ˆ»ušü]l°RÇþNk’]I‡Nóêv¢/š['“(èõ«p¼v¢Ø²NV¬'3’}±¿Š•ÐÐ:wÒ9Ó=­“½“Å6ªpˆvéÕiÿeïücªºî~CLf›Í,ѹ¾ìÛôõ¿÷WSØ ÂhëcŠ*`/"Býùü€ &Ú""þȳXþÀᯎéšIH´eþª’VÝœ±K[³‘%[Ó¦‰&Ûýž{~Ý{Ï»<ç{«çûGµÞǹçœwχóós•òÝ1õNlu†p’·ÑXûAÅdÕbˆºs%N$NŒÞIÉ£áGj]åÃÃÃÁÑq"pÅB§ßa³Öµ"ï?wò}¥uèѼÄ3mé·ð& ÍtøÅ8¡ù¹œ˜g€ŸEA!NØâˆÙkI€Ë™ÂD²xø$œ;!+54gyUë ZÄs'Ôb 8.Ì…È´V€ª±ÉwNØ`OŒùuEu†Ô¾IÄ›‡ŠI«EïJ­„:8‘8iµs×9òè?—àáK'csÅ*¾5w憼Öµú Û·¶U’•5[’½5¿|rÁ¡V‘¾~š¹á­ @¿]]}åжg»xœhÓãoüîPüôvÑ“8ÓWvHb)úPë­?e†ZÂ.û䵟$‹pGݲÌ+H€åŒŠdK}g…^Ì9nÅ?¹+}wüË ÆâÍ=',gZuzÃõ‡~ñʳØBsnš²l®'žŠ ùžµ'6ù.à ûì‰q~]Ayk¶}ù‡¯]0KŠÉª¥¹ªipO\Ù‘8œÄ‡¹Èø™“1ºbůì"Ï=Öµ²}'qx߉’Ûæ:½Ê˜;a«ËÔM‡wÜ ·€z>ªuõ®Ïæq’» ÝõŸ¤ù}'4±={ï¹®¾8DΊ[ïûNl8Qâ¨[–ºbÁrFE²žwOù]½PÌyϱo Ýw½ çìÉšÚÀÙûN8‹­âyXkÙwB§b½­þ¢³·Œª±Êw¹±/À–˜y߉­Î¶ŸrݾŒ¦b©/—UËö6×Õ?ËÁŽÄ à$á•s;v¼~âõç¦Eànô9s6%©Êø/«Îÿ0î'=Žü´ªŽvsr8·ønž hB˜XzCUuiÚ²~Ý*‰ä;'Tb–|»ÅÕé6ýT‹[²Dâ„î;ÑŸ ô`¨²j")—_}ûèÒÌÈ·¹ïÊxîq"#Â8ió“QFd#ä»2$Nd|gBÊweHœÈ!CâD† ''2dȈN¤+V† ƒ“ˆ¹bëûUc" ؃…¯8Šgy›(1ªP Óà [Ô óÃ̼(g4Û\£©ÄGqgaõ^RË5ô¾ñ"{S·áDÊ|ZÀ»Ãæ¡óœlÀ%×* ……çó6ÑÙòqÇN"æŠ ?¬îW=f´¡á´]:ŠgM8$ÆpžÁ5íÚ–iSÂÝÃ!Ê™'QUâŠÃ[Š™IM¿:ׇ¬Uæ:{Ö8IY’iÏ59SEp’û×;?>ZàxFKÆ3ÂI$]±O\»tÏšp"ÆžÉÈ:ZŒÑÍjÏ™'QU⊳ݼùbb(œ,p+yÙÛl§±žNrÇ„Ï ü¾»;)#‚8‰œ+V *åžKªƒeîWf#…Î<ì|Ûæº ÿÄ-gp¥íŒœÙ¡‰q7§FVjpå.NÚëjïä…AX§j>jDDµÜM™'ծĥَ %.Á#ü Ÿ7z´e^²'EŸ\h|°«jÛÛ™®WPÙ/ÜLq˺|ôÏ‘­;ê8‰ +V¬*%£^Kìj†4ŽŸŠ…GÔ[³6‘5ZÞàJqÂ|'8vsÞÈŠ§ÙÅ´kà‚.°( ños.Ûœ¨Žó¤Ú•¸\¶•PâÎÈžŸ0é—‰¥uGVCÉ› ëSÜGœtø¡•ã:óeèßSa Rä-Ét{kôa“V­gOØ;Y™»¹Ò—1o¤~/”ÖájAŠ[ªÐ 5‰‚;Ë—X´Ò<ØaÕž–åy¥èã$’®X±ªTáÚ ñâvC¥«N®Qan´"ƒ+oc£8!7ç¬'ø¢Zcšâ1N¸ls¢Z2$ZL=©véËvL(q=Áµ‰Õeõy+µ ¨_ݶ¹Î“ÀvœÌ”²Ú„­zÃl$§4Œl׿q²!«ys¦ž‡—‚è{„ßTqËÉzp§U»ÊŒçN Û‚j4‰œDÒ+V•Ò5¢ƒåÚ •®r ÅH§ 4Á‰ÀàÊ»b)NÈÍy#+Å ¾¨VCš¶ÖˆqÂe;É:%È{RJ\’íØPâªå‹þöõ7 ÒçhA˜„0X8*Nz +öÊm„Z¦bõÖÞ1àádàDÛ´æa tQÅ­àóÂÞ‰~ œgNR *¥'!ê8‰¬+V¬*¥O:ÖÁš{õTºêÔ;±\…½rsÞÈjà L#†Õ;±â$ÌÞIŒ(q—?îþý勲ÆÒ;AS±\ïr×cêèP½xº‰â–“Þ‰©·¡Rœ¼Ü÷[ÈìG˜â6\œwÞ.0fGD8ÉýjŽÄIô{'uÅŠU¥4°Ö2I@¤«ö¹"ž\…s'äæ¼‘ÕŠ“ÑæNh¶m81½cƦĥَ%n^Õ?NúêîÚD•Ÿ;á&Óo6¸m8Á ÅtîDÿ?­ËŒ¥çJßs!7dî„WÜZ{'#%éù¬[f(nGÁI.~D´®ôüÕW3ŠÍ~m\Ù²£Ž“»bŪRÖÓ7t°ÌýÊl¤êõø7®›¬wƒð 5cñ¬ÀàÊ\±L$KoÎŒ¬ÔàÊ.Â`dë]¿'\¶m8•çOžT›—f;F”¸¥uJOÖÞû³aegVŽ¥—dñ½ÛØ ë9ë­Ò±ôÈ‹6[pÒŸÞ¯–À‹¡¼âÖÚ;IövÞß9u×[’™âvœÌÈ>³{Ù [íбï3æb=Á ¯ý+ÁÒ›’ƒ¨ã$®X±ª”]Æ:Xæ~¥6ÒâNôOúÓÆí;¡âY»Á•mÈ ‰q7§FVjpå.ö£}'…81í;±m§2ö ÇئÄeÙŽ %®Ö5+_G ,sûNXý ë-ÍÓåZ›ì™õV;Þçê½dÙª¢ÓÃX½'ûNxÅ­µw¢wØô z¯!A¡ŠÛQp¢8ûNš‘h.½ŸQÙÓÖè²ôÉ’ä«Ã¢“È»b늞s7ÃÙ¯Žfp¥ì”XG_¶“–Î1å,α÷‹J\£ŠFTséA ëVmUgÀ9:œLÙtu„"‰ë+;Ï»+Vý|ý+o·¦çý'}'»§|q÷»qP$íqθ~îÉ?[ ëe›’8‘¾2 yªÑÖ÷+<ámâÏqt4‘{Q%N$N&fü&å¬2$N$NdÈ!q"C† ‰2dHœÈ!CFX8IÞbæÌûéüüºb‘ý&ÐkÞ½—{9+Fª"„Y NÕao‚ÐÈŠ·ÿ›Jz¼¿E\(ªg<©2dÄ2NRu˜@œHàä)]±jyYû ·îÌûŸÇ(N|ö8Q§/à ±‘[lM„YøàÕ)ƒ¨úþ’3aùˆ eȈaœŒMþ ÿ91bÇI8áàŠUËáDjÞBóV¯˜Ç‰¢j›¨Ñ(<½kJA$¾Ä‰Œÿ/œì×AòÙaePÊ~ N& 8ñe,Ê¢3°‡Õej'pÒåôªÙp´ÿRmàX¾›7¬‚¥èœw¥RTòyîNìóZpñù¶Æ¡# žEÛÌ<›ÞHTÔ·ÒgÃIš½ú¥d‘÷Tát­N8á-¶FbÄhšÉDµÚ[¤f§9ÐÊ b$=0øófÏ{·Ïu»žJT™'•;f£–ÌêÞë/jJÔ ÑÆ ôK^Ü?¨rÂÚ;™W,4*o;TvÎ {Xù´®Âoîºùs8·ïð;‹t°PêÚÑò {ë¥-#LŠJ?Ï%ÁŒ¬Zðtïúe»>MH*x°â|Õâ,'-÷~s2%ðžö3]«N8‹-IÌ0šB™¨ÞÕ—±8Ë7`2¸R‘,WÌ?äz³¯û㲓9L¢Ê<©L殺}ÓþÓ/.ÏÔ ÑÆ L›ìW>CÓ'öÁÎÓ»bëôÎ׺þبm°ã#ÇOÕj8òJ †aµ¸s[*R1)ª¯N|üÔ0²jAÃf`x‚:®ešp¢ƒ YO_ä=5ðt­ÎƒjbÁ‰™†%d*¶¹jÝÃ+& &ɲbÎ@'dј˛­î±MC©àT9E‰Zâ2+†ª2¢Œ“™ ¨“–q»b‘e )UqĉÖUÖ¾;á¤fHÔE «)ää9“¢ÒÏsÁŒ¬Zа¹•v‚r Œ„ü`GoÇ3ªæ'ˆ¼§œ®5<œÄ„8‰ëh ˜ÕêTÕÆŠiX:’¼ÙX¹B%ª4UN †=¹\ÉSƒ} sX8Ø™WlÙ§o¢Gœ(ß[ó?öÎ6&ªìŒã7Ó6ÝfÓDjÓfÜ®·qúe; .¶.-ÈJªEè:¬¸ˆ JƒDä¥ì² ‚o Ú¨E_VŠ]e‘hã®!¾ÅÚº¢uMvÕ,ÙhÚÝ%&~hÒoÛûÜsïyž;÷Ì003:ÚçÿÁàÜ;çžçÜ{þs^wÈ oZÑ«¡ÞÕ «&7ZTb EµÏ'í#$² v™åJ@$œ«°÷”àZc`'Æ7-®- ’Å0K+ELFz&ž SBTÑNïj£ê4E°XOØN|†ÕFb]C±Z X±ö+p)@T9³ó›¿W.ñé4›!HX¥­E5ϧ Idµíd‚Ö‰‹{Jq­1°ÿ‘kCç2CµN¬03– !­º¬I;AˆªºuB /¨ X¬'Ý:ÿçï?xçQˆ‰â¨Y±¶P€è€òåð~½Þx=$¬Zc'ß †¢¦;„"«m'Ö5úªÏÄ/ûû¨(¸§×jXK&ÉøìDïZy0£ÙÑÛ‘ Y “°‡¤HˆªErŒP/¶Ê ä¥ò¹ü\³ÀN¾¿û‘XÆöh÷‹¶ÄkÛ ˆf¶M[E¿Q¶ãNyKGñ|˜òkØU[´NCª˜Ù©ß8¡¨ò|2t‚DVÛN<…ÃågªŒ&‡Qþàfµ÷”âZõšâΤ_Œk ¼«)¶n;Aêm^ÕâT}…c,V‚d1L}`t}yËé=h'Q•œT‚w•vBË ƒ_öÍJ;™–ôÀ0”G’~)í$†¬XÛN(@ԿιîÄx°Ò{Ò\ñöé!±  «t݉€¢Êói&äù¶Xk:Àùm7:ìDÁ=%¸Vø†W4P‚ñ®”b벉w-kí†þI_Ñ:Ç‘½îD†ééÝ[Ùt²3í!ª’“ê\w²ÀYfl'¬Ä±Éߌs'< J/çñYÿc”ȇçGr]qw*>5ªTÎc4ÌËà|zB„éb0M QL°XÍNHÙÉÓ¯ÿ“0Yl'\Ï8LëY°‹ÅvÂb±ØNX,‹í„Åb±°X¬gÕN¢dÅji_þcΜ©ñI6+V ]}LR¿Oñ®(ãõ¾².øSOÞÞ­æ23OoC´»{m„®x{h)@µ1ŠJ;Ù+Á2Àe†i–é” ’ä ¬ªâù\¡ÊN¢eÅj‚¨¤ÜSŒ¬X5tõ‰Ú â]#~ã¹ß»í$ST>Và›»‚¢”µ3r";Q€jc Fr²WÊݘ4-5Â0á¶t´Me«’|o̸¹’í$¡ì$jVlÚý+¹ð¥ÍJ;AVl„ÐÕÇg'“Ä»ê+Üv"÷>F;‰bA¥Œ=)˜|3–³$”DÍŠÕïÿŨIóÂØ °bÑN‘õÛõŸ{¯ßÉbÐ÷úQZå û•|¶wkÓɃ)Fs·mÿÖkÀ…‹,1Φúºâõ_ŒÔyO ÞUî¤!¸V$¸*ìDÌÚn±\Ó—š8ú¥üzÐ{v9)(¶’zëß°©¿®iø†]ÃN>Ùë½ {”0ã|‘†Õ†gÅÚa.t!kùÚsÇ“xG‰<˜óÆÈ=(J¥Å\H\òrxï½ MSVFH´ D2("±ï!CŸE¸¼¼Š+a¶m„®Fñl' f'Q³b=ûÎvùõw2CÚ °bÑNÈZÖº¬sæ™= 4ÿ‘â³ú·Óž:a¿Jµ7~QÞrÚxÚò‹~«·Ð8??¢Äü9ÞáòÍçiÉ=Ù;[:þ(ñ®’àŠ¸VBpuÛ‰G4:p <7ã²OqU_÷%ØGLjceö–]}Po‘b+©·þ Åm·ÁA‰ÐÕ×4l8³Ðp`Œ¤¬uìØ¿?"– Ú°¬X ³}éâ¹gk€W5Ö0ëÄ•L<Èñ¶=üÛÂs©„JK ÍÄÅN^ýÇå-ý£k­ÍÆ©x‡/}x~KäÝAR°þÃwÅŽP¼Š+a¶%B—í$í$¬Ø¼ósæÜùJSX¬Ø ÎŽIdÛëü[|«‹r]_w,F$ü°ÏaZ…}þ„‰ùstP³z³¾bµqVY+p•ìö½$¸Z¸VH ®n;¡ÃtvJ+l”ôX~è¤Ø"õÖ¿ám i›™•ˆÀN µþÇŠ¥a–®¼Š+ÉlS„.’|“k»Ë“25—‰b'Q³bÃ.²'³~t•YKêëì¥"ƒÞSÇ?£#‹È~Åö׉•ù·öWšëN"KŒ®;1κö¬ ‘¿lŽu'ã–EÚWçŸÅr"澤ã^ðº“ÿî5ר(¶H½%vb!tI%”‘”Œ|.–× ¨–²b³¶p½ÄL„Ù^GòÍÉ(XÀaÆi ÅrO Rie/C‰Äµïkï÷zgŸÚN$˜Db²ywì0Ó*¬µ.ãt݉ÛNd¶ B—|·Ù^Ëv’0v=+Ö£ëšö=Ï„çé!þ¶/®OÈGõ9[áSILe¨¬{Â}u¢xåÛ»"ˆ'äGa"!¬Xô7O˜Œâ¿SÜ3còñx&¹'² !t™•›vòô)>»àb«Hì$Fò÷˜’-LÝNX,¶“gÔN¦*¶Û ‹Åb;a±Xl',‹ÅvÂb±ØNX,ÖSh'qdÅjÚ6@ QxAÌŸ°!Wõ¹\¥Æ»F&ÿ‰-)ü¤°X“µ“x²bµ¼Æîõž£‹hcøœÐNÔx×È„Ë]Y,VÄvWVlÚ`’¬Xí´ØlÐNÔxW¶+nvWVlYô¼•’¾ôÖÈ= ÏaÙIÖ(l˜uìÞ%»<ü‡‡¼ÅÇ!'6Ú”èìþÊk=`']…Í,¸ù%½êV‡ØÐ£À»’l÷zŸ6®$ñ˜˜}ƒ‚g%¨–Åb…²“¸²bó« ÊÿéKOýñÍíæ.xËNÊzÆ:p•¬%vÒ5ºqfË…ù>Â=% “ì†]w½FÚgkÇŒ¿² vÒÔ6½Њ ¼+i"~QÞ_WLíØŸ¤\«Õ²X¬PvWVl{30o€}‘¾Ô¨ÌefƒÂ¶£²5×±-íD¯¶0±¼«¥R€Ï+|s®^èöF ±¡ åbѯÔxW»Vaœ WS;Áݳƒ¸V Tëáç‡Å k'qcÅR;y+ÅÞ$b´7.IhAEëd r}9ð7xWû,@^,­L'кiµðA tã]õo<ÿüÏR iþÔ5Jì“vBp­TËb±ÂtvâÇŠt³³#G(¤ø+º3×d;h°tìdp«wø“{jU .C±i}A)µ’}]‰w…W∗u°h'21´ĵJP-‹Å a'ñeÅÒ¡X·ˆwzoÒvRjM$þÕüfªïjŸœè9EÚ:A¼kÚ^{mö"Wë$²uBÀ³TËb±BµNâÊŠM;òŠ5QLíD>Kznàœ3®1é¥ö27£¥°ÈwµÇNÀoÚ›éØ‰É~ö÷‘±óÕ5n¼«kìѦdìÄ~AŽ×*©FSì¥ÝÜJa±Üv_V¬\ÆFíD>õ5Þ bó¼Âÿ±wþ1U^g¿!M–جY2ãB÷î¾I_ã²]/QYw­h‹ ´^D¤NA`Àª ¢ RÑ£nJhÔ¢8Imü8MÕý1kê¯Úùƒl­nÆféj²™þcl–hÒsÞ÷œóœû>÷^¨=Ï?÷xÞóœçœï=??ïõs›2H'·/<ðR_ÛÚDïʬ©{ïkgÙÎNÝŒ™‘IÁÒ{~tµšïìÔ° ïÊW||gG MeftŦnã´¯®U€j©ªúTŠ6m˜œŒ%+–Ö`‡ì¡œHÀ'ƒ˜+ƒ†}ÕõûèÎ}—óf_€wåöagű“ʹŠ=¶ò´zîÃ»Š’í:b¦çNÚdFþÙÑâž;qq­T«åD›¶pròݱb±¡[Å^³"þ*þµO"!Iãè…ÊIäÍ_kÕÓmÚ†–“'eæ—'Vì~²tÁÀRýÖ'mÚž9)jª¿3óÉAˉ6mO‡œøô!Seþ0lÊIDATmÚ´œhÓ¦M›–mÚ´i9ѦM›–mÚ´=;r-+6nÓµ©׆ÙñõÿûH˱ã9Va›a¬M ŸI´/ÍË^gæ…ùÐ?š¯»c·ƒÂº¡ºÙªÜ—öøÛhÅ6OøU)\NF5cÍ05Ó¾9Eqs9Éλ3ù…sà‚a<’茺œD8Ž9‰šë§WÍÐ;;¾@îZRÝq?öÑ{x‘ä$j3íõ1 '!n†‘“ǧ؎œŒi¾Ë̆)'©¹éEå7݇Q—“hDZ 'Q³b—04Aêö…HÇa7ŠCû™¸#p°t IoóR@Á#Æ ¥Š/U¬lW~zæø^x(!c>Ée°™<Ëi€f)»õx³ÜaÞPCr£À8‘~Ç–ò;8;:oÕþ,Pi%¨VF™³býë7ìë¯Ø <˜鿦cð¼"'ö¾Ž[{o3¼é“ŸE5GZ hfÙyôB¿§;Í÷½zOh¦"'ÂA±…õÓo\¦÷œKÿ×ÙrÍb‡ÜBò,}§³‚}(º"´Oý«¦º~>Ôu3aÕ|ö…C~Bò¯tÏU,š¬W °ˆ&(¶Ö‹D‡ÎŽhsnJ9ñ¦çÉÒAarB0øY »®Î2\œ&=‘ÀbOt‚³é0‹á}ot`4ÅÃ#Ò’cUN¢fÅ:r’µ5ÉüŸ "«ÄÁÒæQ§ºIDÄ®,x»±½B‘ò·Ï'oÝòŠ*'WþyÙ¡LÙ³$¸%’Ô(9Ô@ "}àä‹?Ùz“/kÅíÚ—}œ¨´²dr ÁY±þõÇŽ8”»€j9‰k]1pàP¿å$XóIIcSò6“°Ê©“÷gÌɾv~rcûŒLRtÊ¥¤^ؽùï¼±õÚ扤؂ïµúë?ìk£ŠÑv{ãNçg*cù]¹å“&£`í+;{“|hJ„.%×ýmå¶ÕµÇÝ´{Ü ~3’=r‚DÓD`½˜œÈbóÌ0X/;þ=v‰¸Iìâ6¦Hz'Y|¨3DN‚góIƒ(H·ªf±ß‹ÞOx"ÅHtÞ§ Q†ì>M!'‘hÉ1+'Q³bƒ5ôO»¦îGä$a•nºýLREV.Þ™ÅôC‹ì<Ò_T\Qj9™?På¤î-çnŸh€”>«Nü³)F¥jy3LÏÆýä©vÂÅY’J«”L)`ì¶e—-š <ñʉYJ_ RÕâ™ì8s%·Íø{^Mz4å®ÝÛæö,Ò (c…¢‚Mž±³ôDRlAm“ækW’ÖÿÔî.&;û•[n)ÝB!'gÔ‚tóWu3í¯>²º.ä@ò¯WN¼ÑD`½¸œˆbóÌ<°^Ÿ‹XŠ•“÷Ò'žÞM&ë ‘“Ô\Rž¢¦ÅiÓ—.4‰6µ6¤'O°‹k–#£DD“?<"-9¦å$*V,™mœpj *'K¼r˜g  ­JÚ/4ڴӂܘ¨ ȧhÍ]$+öíà3þüó謊=S)1V¤Rx¤QΘ³N¨%•–Ì5ÁŠõÓçPî›ô‘ÿúnöH('q;:« gËÂm3fñ¢¹] ‚³w§0"Û*j:“Ä`qvïòÛ’BäÄõPlAéÓ(a޼pÈ»vB?]('ª€6·®[“TÙ=’#É ¦ò¤H“Ql>uÅ`½HtÂȉchz7™¬3DNBh嬷ˆÌ›Í,¼)<‘Àb$:–M´€ 3aë•Ñ÷FFSŒN"Ð’cz²+–tÌ©SS»cÅ"“@då8XØy¿,¤VBê<‘“ù÷BZ3™Ûûq9}_ÍÁIÊfA<½]¹|çËË®’6•œçd•–L®8¬X‘”ž rd;êR,ÿLûÒ™V»m&ð0³ò›;§òʭ¶•“§]Ì#¥3«fä¼,:u'³ge…Bx(¶à+Ž6õ@[ú0å tœ„öFéfr^y×áÃ{‰ö)ôšr"¢ Ÿ4"9Á`½Ht"ʉ¥w“É:CäÄ!„’"Ñû÷ï/,]4Wx"ÅHtiöª{2úˆœ€h‚µ“°´ä˜•“èY±t&ŸÔºÛB–b!‘ÕÅÁb pèÑI0œœ˜¥uÎ÷ࣉo¼ñBJÈ脯'Rzcá§ÊèRiEÉ€7Œ+å$dtR¨ŽNè#UN?kAEN²WüýAíý›í2Úi³Y2{Åë½\†_»T³€£@±£“DâaŽN$B7’œ7I§ê}ûAmÆk¤r¢< •“`ØÑ ëõF'‚œ éåèÄ­³H£³´ûêÓ¯÷¬IžH`16:!Å9sõ‚Ò%dôÑщpîì„£%ÇôFqt¬XWIñw“y:]î˜à“4g@duºÝ<¬†Y;¹ÇÖNÞU‘“2w‚4‘oêä^›²vâÊ ýiW֧õ…JËK¦îáÍ‘r<ˆ[îf)]½ë‚Zàf[×±]—bl:xðîƒÿÔ͵Ùû†º*héìÞ+Õ¢­%+ÇuÀÚ‰wbÖN09ÉrçâCe)¬œÀÅ®Û÷3‹ÿø°Ù‡Ë‰€'šðIÁ¾“{CŠÍ£ åÄÍ ‡õ"Ñr’…N©<鑵)Dnt,®ø /t–ì'B*<ÀbtŽL·û_Úvœè#ÑnVåç(ÅVÚå’Ÿ•¤Ä²œDÍŠõ=÷Ó’Æ¿LÅ_a÷Òcllq­lVíį-Id•8X;~ÒÕ£{&Ń5M:il¿º³³²„îìH¼+³ª`çÄ_Ð_‚=†ÂÇ'a®8Àwvœôþ²ºÿÕj"'lg§ÑÙÙq©´²d`)–³b%3_²eâVºÙºb󹫔’jÞsZ˜œpŠm¥±û^±q&ɬº°çû›2 Vº@kQE[>/il/xÅÂ<‘[¸³³ÙÝÙÁä$9c`Û2º³Ã?”]DN€›]Ýsmd°‚Ê Më-zwysèðÇ&(6Ï õbÑùë¤÷š6|Ë6t¸›2$½ÐYg€aÌ£<›Oai½­ëò3“3è”Kx"ÅX;#µV².¢DFÓ}8NKžž»8-¦å$jVlýËavÅ£"9Û§oaÝ\œÖ8ج69œ1,Bk<çN,~îà]¥œPZ¬á|¥U…¼c]=wâ¤Oh¯(8~ƒµ)zîd;q©´T+¿Û9+VʉRi þòˆ1H9”Y±`8Á‘"ÿoïÜb£*â8|²ÁXöAM­f½t7ÝFÀT”"6È -ÖZ 춨]R@¢@ ±RlZ/%¶±¥¤% MI% TiEÈ%\åò ” Ä|PBšh©…ÏœËÌÿìNw—ÒÕ%þ~ tNçÌy˜™93ߪR½~ãT9]QÓ¼ê¨á¾ä•éèèhÕdd-£‚É rÒ%Ò‹ I“„ºb8éÚºtnýO^.EesœŠ0œ¨¶óS[^Tsùƒò¶ JmyKG·Cºšez)|_›È½§¢2a ͪhé¨ïcæU®Ý „²«{wÒÕ+Â%ªBUʬú¹ãÓg&:pRÔ~Kë¬>¹NW¬âRÔV'¾#=9J>SÇÞ8Éš5B¥,p‚ Rœ¸úûWö\б2†“ø\±ìB'Ŷ_bjÑù…»#³àÔ»Ã–¨úsÛ2_iáJjXåzWåÖw陨-7ñL¡…;šCG›Ö:p¢¶6®êZ£;ù6o«üb“'ÂÈ*ªå³¶,Ù‰Õò–‰'™Tǯœœ¸zõÉ_ÊàcÎsGØè$.W,–˜8ñÿ°Îó¨‡n(NºÚ:QWæ!ÕÀœ2Ïø×ó¼Ä°*ô®ÁªÂ¦º^TzÓJ «ÓØQa^¬Ê^Zßç¦8qu†ÎÏë.ß•Aî´¦®æîMgK(N¸‘ÕRÊ:Ä-®Þ”NlQ-o™xí¾Ã¹m)†ñA€::Ym®Â²AJoÄd'W¬Lo˜üAú¬†W¤8Ñ{zPP‰ªoaö÷oêл*æÁ|˜ìˆÂÀqY³(N2sYElfÃï”ÿBKŽ¢½EqB¬"ÒïgXK±\TKܯ‘†É‚ ?:Lwma8I'Q\±btRÛ09k~õp8Yâ5ÔHÔȬr¿Ê¤dܰ*ô®¬ ‡­ðÂK¥ìh?·¨™6ôÓµ+Ê<üN™ìúE'Ây'–¨V´ 8A˜£E§È}éC•‹ú_”X8‘ºbùè„Mvœ¿Nq2ëhz'§FVu¶¡%†U¡w5ŽœˆÂ…ÌŒè\Š „ÌÂW¬vaæ¦ùKg^öH¶±qï)ïäB¢ê[øì4e[‹†U®wÕYSØô{³ÃÖEjRçêŒâ…Áª– /í {³s|Á¼÷¶7¼Lî´fNûí­+œov¸‘5'.--ecö§ic½'¼eö“0åý²êqaßÜAàÄ•~WÊöF(W¯~tOZº…“ësÅw—µ³Â“Opl²çÞSÑɹDuÍñ2/3Áçy‰aÕÖ»šè=v†G´_ÛûN¬ÂÍ¡®ç¾Wkc¨rkÓDr'ßæmî­{äûNd£“N·µ£„âÄnVIã*ì;Aˆµ³+zGi_¼*U¾z¢üÓÃá0óD«ÄvÛÊÚì8ÈÈ®ð¨7ô@a-ƒ»Abáä¿Nò*!kDà8Aÿ'NNN€A€A€A€AàAàAàAàA8A8Aä¦Î?ÎG…ôúghwIEND®B`‚lintr/vignettes/sublime-still.gif0000644000176200001440000027320014752731051016677 0ustar liggesusersGIF89aÖ÷üóÜûó×õóçýôãôíÏlrwLLLQNQPPPMLQLPMIGHìãÌèâÉhluØØØgv‡sleèéêØÊ²RMKCCCááÞWgxéÚÉzyx¬¬¬ÒÒÍøæÉçÑ´FJKC<:KQWxˆ˜½ÁÃSJEgxι¯„|s†vXj„»µ©VQLztkKJFXKF’{h§©¨¯¯°§­µ669‡{·¸¸µ¬¦ÂÁ½ðîíüì×õöö±z‰yh¸š|Ľ´{ƒŠv|„¬{µÄاŽv966‰ƒw::C¾Á½HB;™¢ªV[f­ÃµÂÁÂ39CÊÁ¶ÄÅÈÅÀ³>B=:9:¼¼¼486.7==4-:9669;859áááB52¿Âa^c;DO—¦¶¶§—C5+ðãǹ©¤¤¤©³ºZWWEKX®¢hb[Vdq¬žŠŸ¢Ÿ•†xµ½Æihh‡“›¬£—VMVe[V¼¾Â:5,’§¶qqr²ÃÓveWRNdYH9ˆnUIVh¨™‡ËÀ«´ÂÌ………vŒœÕéúhTE˜¥çõû/+.qYJȽ¹¶ÃÆ™˜š...E=CCLg(&)G<7R<5º³•ĵ£–„m¥œ•‡˜§ª·ÆºÁË;GZ‚“£46C18R‰š±·¢ŠSnŠ~’£˜°Ç¿ØÌÛìxfN̾«'#"59J:QhÇ®”z”«Ó»¦Úöþ&&&Ò¼ª¹…:KeHYxT]z®ºÐµÑìcK7BNt.7C­•Œ+:L)8JH7'hR=)9V$7]:PsT<'¯ÅÎOb‰Ïêö®ÃÔžÅZF-§½ÔJ4(ªÃÚþöꤤbôýþ/VqÓÀj( /Jüï¬Ýž¡˜z.¼p‹‹Ü=w°Ê˜ÿúÝÙBKo„gyw'þ²Ïþüôœi"ÿüäÿûëëþÿ!ÿ NETSCAPE2.0!ùÿ,ÖÿMxbÅ@<*\Ȱ¡Ã‡#Jœè0!E'2jÜÈcÇ CŠI²¤É"Oª\É2eË—0cÊœ‰’¦K›8sêÜy“gÏ‹ š°x°¨ ¡C*Uzâ`Ó¥‹>…:U¨7‚P£º4Á1#ÁŽ\7†íZDãØŒ5Í~{6㊷‘& 7.\ŒqÕ‹·¯B¡rëN”Ûp^¿ H4ëÁÆŽ"…\4­Ø®hÍr,’¶³çÏ i–½Œyô‰ÐEf ^ͺµë×°cËžMÛgmÛ¸sÿ Ë»iY¬Y§Nåê”3i¯Ç»h­eµÈoÖ¼ñ¹ÀÑmÛj,[·»w»ßËÿ¿Û]2xóãߢ¿^2ú÷‚Á“?šî{÷éóçÍP¿üµfÝ–šj 8`¨à‚ 2è`ƒBá„R(¡…f¨á†ºavÖ‡É5%qÊ"ˆš™ð\uÔmw‡‰\3ÖhãŒÞÐx£:îè]áÝØ£Dòø–‘E‰d99¤9©ßS)Gf©å–\véå—`†)æ˜d–iæ™h¦©æšlv ã›n—gªqf§rWVYusuöy矧á¹ç ‚6ggXw:h£Ž>:ÚŒJ)\i˜¡Â¦têé§ €*꜖:j¨§~Jª©-°šêª­Žÿ««ŸÒjë­¸æŠ@®°ª:«©fÌ‘†z*Î`ì ¶Ñæ²Ì6ëì³ÐF+í´Ô†‰!œ‹:§ç §uÛg¤r*é£yʧ¥Í*;é •nË®¶’ºµBiX’ÂôÛï,ðÀ üoÀ|pÂ/Ìðà GܰÄ;<1ÁþB qÅ #üD 8àÁBÕ&[òÉ&‹‰Ê,·ìòË`^‹-¥ôFúîºîr[ó¡ßBª.9ýî¸ôÒ nÎE/z¤ dêO„Œð觯þúìË,<¥ÙjŽüÑ’/_¼ãÇoN¿òŠRÏ®ŠñkÒNó–aio|L ÈÀïI`WjŸ'¨, N0eÏrßû•9ãôŒqÍËßãÊÕ-þË9œëœÿÆ@£ °GJÁè¶6€Úð†8¤aUG€Dà ç³ ÿ‡HÄ":èKŒž¤¤—BCÕozÌÙ…FBž©yÐ[bâ–x”4à`†®«¡ǸC2š±ŒhL# 2#ñpŒã“ˆ’ÿm‹O<áÏð7ÅãUQrMÚ=wÇz­{ÇÉÈF:ò‘Œ¤$'IÉJ À’˜\dùrçF9zÒˆü¤ïèØBrŠ…ú£ }V¹>®rY$¤ü`8‡Ø`†™¼d.wÉË^úò—¿ô!'Eé²Áó˜žÔ )±èÄU‚PŠ®DšÎlÆÄVïvz "­Ìnzó›à §$7Àˆ9™è “1ÓÉNeº“Ž“K—óÈÊF3g¥”å _Iÿ®‚DÀ ×ÄIÐ1  Mè#-às ¥¨DßIÑ ªQ“»ŸóîI®ÿ¢@¨O}P“²$zôr’.pPƒŽ‘mЀ!*™”¡¥bÌvЧ±§@uiP:T…•¦F$N0¬‘ši(ƒêD§Jª’i™“Þ=©Ê xµ¤\ñ*Š¢£­r­@¤&¨ê‚DêT­à <ÃJ…ŠSDâ3¥«^0MÌuXÁ¦Ì/H ¨ˆ=j$›T½:©eìO}0¬‡Zõ²¼àG3Q¬fõ”ÌÓ=ŸiæF4b—Pl~! `ÿÆ ªœ<ç:ÓÙÎx¾sžõÜÒüaA`˜Àˆ#ë ´a˜¼+oMcÍ‚7ƒçý“‰—¼öBQ£Ç;íW×KdKJÉ@XÍYóûÕ–h3‡Ý3‡‘‹l@aP)0Pƒ `` ¹ÐÀ& ‰7<¡¾„v €5»z{ÐĬjb7{ÐÏvv´¡=í:OÀ&cqª= ÄÁ¡|t£ÇMnjÙXhÆrÞFýèÇšišµdýÍø+êú¨Vµ›•Í!Wðj5»½Àa90Hàá x›Ä)^ƒ5èâ¦à€…OLÜ+/¢ ýæ¶Æ7®ØmK›ãvœ VÕ€áãÍÿ¦eËÍò"2zŽÊ7<9 Ew6••þà f‹Ò£‰uÓ=ß§õ´™=g<Û®p˜iÐà ésßxqÕyKû¨’¦V¿¡5—§; ÃúlÉ-´­Í[)€a7{Ê8˜)Ö`ðI,â"FΫ³”¯~*†½}Šä¶ì¨O½ê:©âàäG1Ú˜2½\”·§;îK3:Ö4Ë£bÎ3 ¨"¬vÈ‚ÿ çJôxöóš\AªŸ=e¶<ð€x°ˆ€‡ ÃÿÒu‘<ͯ®°æ s€(¿ÈWOÿ«ã~6™ÀÎíÜźGU2€Ácww7Kó£cƒGZ|´(Av,õÔiëÖ.ü4<ìâ$¢Óqx¶[‹)Ðöf—‡a  `]’@ŒèW ìg p Uqów9X:¨z´†m3ðzNÀg/PYoG€s7DC€AMÈ{Již5€«QB Èc|Gs„M‹C,ä.Ú”ü×l&ð 8°~}fÀ IÐCƒUsP~—n %K‡=Óǃ‚xb;XˆP– /@„ ·iÿDÞeU¹GU“8•˜Lx€ù#³?W¸w ¨8ÖTð/ÿ`þ†rÃÆŒèq§qºÄŠŠƒX‹¶ølã ]yæ l´rt‰Qh{PŒK¸;™¨‰ÎÇ-Èg…z‡iZ(|×ô…x/3°\·xبŠÙX‹ÎPLå‹ÄŽâxŒÈ8BÓ¤€ÍX|¡ØGêÕ…ý#wr$Ø£`ÛXˆ=Xø¨„¨÷˜gä„„16ŽE…”hn‘f€êU/ˆŽÄ·GxO8æ?üñCPÖö˜‰‘ü¨‘åCf˜’Qxä¨"”By×YØG‰ù“é•cì5”­„JBKH©Doµ¨8•lÙ–RɃ ÐvÄ2'}’nvy—x™—z¹—|y—RUÒ—I €)˜{y ~Y—†¹˜Œ¹˜™˜‚© 3P˜i—ˆ™˜vR™š¹™éö˜–i˜’ ˜]é•ó2@B©’öD–ÉxEfÉBчƒPù–n9›³i•¥“[Ù™ŠÉ™¼é˜Æ"š ©›”¹™—‰—øÓ›È™¿ ™})™£ùŒ5·a‰š=†O ÅšG©4µFG›Téà rÿ0·…›¹ù™™™œê™—ž©›Êy,“¹žÅÉž»¹žö˜Ày˜-Ùšüi=ÐiŽé5|ö£Ž©E ^Ñ$¡”)ðŠQžM ¡ßé”Îðm‡h$ùœÇ³ŸÙÙŸøŸÍ|:¢ ¢*Bú„ñ¨K‘ _aÞ¡òÑ$ñ!ë‘ÂbàxKZªHjªÀõoN€;ÃrqQ*9¢©õqøñ©Ÿª¶Š+°«íq¾Ê©öñª€ÑJ,ÿÇßÁ©ýÁ«Ç v1ä‘©BÑ£ÕªÄB«|#qØŠü±­ßzÓJyA¬æ‘®ÍÚ«ûñ^Åú¶ÊÈzšª°jºØÊ¬éA«ì1%ß1#Ôª;üê$Ïê©u!¯Ë:°šº+à ±y±÷²yðC¸±›$à±E²±™2EÐJ›IŠª,¡HÚo ,²4[³6ÿ{³8›³:»³<Û³>û³@´B;´D ´3»#yà±G[#K;²7{±;±åY±TK±V{µX{µ›µT›Z{[V»µËH@¶f[¶,¶f»¶e‹¶kû¶p ·#¶Næê²x«²µ²§Ú²}›Î€b!“¶nË#0·@¸jk¸s+·sÛ¸Žk¸Š«¶…[¸‡+¹“›¶— ¹‘˹r›¹Œ‹¹‹k¹»¸j˹¤+º¦›ºž;º‹»¹”»º¯[º¦ëº§K»µ{º ;…»»¸+»‹›¸»‹[¼Ã«¹º»·«º¹Û¹, ¼ à»gkºÐ¶Æ ½Ø+½#½Úû¼ ‹¶½ÿ[»H¾Í¾q+¾çûºÊk¶Pàîû¾ï›c¿ô[¿ð+¿ö›¿>`k)›·ýë·›ãÀ ¿|ÀœÀð; ,¿ìÀ4ðÀ<ÁLÁF\Áì`ò«Á,Á ÁÁ|ÁÂüÁLÂ(¬Á!ÜÂ"¬Â2ìÁLÂ<Â'ìÂ2 Â1üÂ>|Â7Ä; Â><Â5|ÄCœÄ8\ÂÌÄ)üÄCLÃlÂTüÄ(œÂRœ&ÌÄ9\Â$lÀZ¼ÅS Æ\Æaœ‹Wã jL5‹Û3>zÀrì–ª£jt:º”Çz¼Ç|ÜÇ—5¾È~<È„,‚|È…œÈŠÿlȈ¼ÈŽÜÈÉŒ,É”\É–<É—œÉ˜ìȰÉüÉ ÜÉk<ÊkʦLÊV£Æ ¦ÜÉ?5,5 s|˸œËÉlÌÅËËl%¦ÀüËÃÇ’Õ˨ŠÅÌgzL•ˬgÌEÌæËÏì¿@UÌÕü·-@¶\ËÜ ÷¸m´LÎèœÎêLTá¼mìÎ €ñÌŠòÌŠ ‹øœÏú¼ÏÀÏþ¼Ï¬ø·lT´]Ð}ÐÐ ½Ð ÝÐýÐÑУÚb  Ðbp]Õ ~Z Z°è ˶¼Í°ÌÍ'ÒìœÒáÌÒ´,Î?%ÐóÿÌŠ6}ÓýlÓ9 Ðÿ¬Ó7Ó@ýÓæ ËæÜÒâÎf@2°ÔJÍÔYðÔMÕR=ÕT]ÕV ÕWÕZ½Õ\Õ^ýÕNÖ]-Ö`=Öf}ÖhMd½ÖjÝÖiýÖp-nÍÖWP×qm×t×w­×s×{ý×€ÝׂÍׄ؆í×U­O€“0 Ïð Ÿ0 Ò ÙÏv° ž`K`#Ë*mÔ23ÍÍ%=Ú¢-Ó%íÍ#­Îè\Ó?íÓ²-Ô±=Û °Ó·mÛ¸}Ó(Íé|TI=؇=ÜÄ]ÜemÜÈÜÇ-Ü…-×νÜÊÝÜÑ-ÝÓÕØÏ}ÝØMÝÛÍÝÞÿ½Õ ]0 Ð`Þ-µP £°CÝÍ%ÝÎ(}P¢-ÎÛ6ßÜßÌßí<Ó?EΧíÚÛ pÏ÷ÜÓ±½Û´]Û9à .‹aGÀ%P¤Üß­ÝÎÜÎáþážá"â$>âJ]%nâ)âÕmÚLßõ-΢=Ó!r2 ΰ\ãû½·GÎ7~Ô3}à±}Ï;ÅÓðಸP6ÀÓ ÎIå'†Ö  Ú€ 2 Îâ^ÞÝ*¾â`þåd.æfæhžægްæn^æjçÙ=ç{íâßéΣMÚìLÎçüÎ-Íç¨Mãù½Íé,ÓûmËþÿ]àõlÓÐèÕpÏJåN 5 ¦àéš.‹(  Ö°S>ÕfVê¦~ꨞꪾê¬Þê®þê°ë²>ë´^ë¶~븞뺾ë¼Þë¾þëÀìÂ>ìÄësMW§ë‡É7p70¬` ð]γˆÎˆ.Ë/½ãÿ­ç§mè,ý߈Nã¬Ü5ÝÐ;Ï  Ø¥à¬è`S åQ^Û· äÀWŽ:ÅåS½»,ðŸð ¿ð ßðÿðñ?ñ_ññŸñ¿ñßñÿñ ò"?ò$_ò °b8ð1`˜ eÿð™ð2bîþ•p ßà~Öã}P¶,Ó‰NËÞíø}I®äæœçüß°Í ;0õTÿ  éJÞ϶&aSPïÿéTqWŽåY® Ç Ú`]ÞŒˆd÷r?÷t_÷v÷xŸ÷z¿÷|ß÷~ÿ÷€ø‚?ø„_ø†øˆŸøŠ¿øŒßøŽÿøùv‡àuQ Í Í  ¢ ù›¯ Ê Þ@ž+@èÎà0G ÎØ¾ß±ÌR6¾ôø½·|Îí!Gä C°î¾?õŸéöžÓ)@ïð.ÔS¾Ï¬7ö¯ÐüDØïkߌ|S@ÖŸýÚ¿ýÜÿÏÞßýàþâ?þä_þæþèŸþêýß¿þîÏþïïþîÿô_ÿöÿíoø¿ÿüG¦!x„KA„éYˆð Á…|˜P!ÄN$XÑ"DŒ 6ähðãņG²IÓˆˆ D@Ò¢¥A ,UâibÈ?n6èÐAÌÑ£œtÀЇ1CxVÂÀ€ƒ0€+‡^0ÖìØ²gÕÈYUZqåîR œWàÍÉ7gŠ% rôÍYØ0὇ ãå:€€5mrˆ…lÁL–,Dˆ4z£É.6lxPúiÓ©O›F]z´êÔ­[»žÍzöÿkتkãvm;6ëØ·y¯î»¶îà§/޼9ìã¾iCWþû¹s⹉ãfœvwÒ²{‡~ûzöéç³£æÎ~¹vöÉÉc-^þùừ#oþ½îþÜSϾýzëºðî«Aô¬kPAà¢[Ž=:`xÃ%˜dð@øc­fàƒRòÈãU:˜„•&yæÅI\DƒkTaÅlžðƒkJácŒ (a Æ Ä" ±¯Â2+­µšd *ÞšK® ÄÀ)1Å k€’2®ÄK½üúò0Ƹ 2 Œ„l3ˆ B*¹ƒ†'6 a‘jÒsO>ûôóO@-tPB 5ôPDUÿtQFuôQH#TÒI)­ÔRL3½tSM;õTÑ2¡áB˜ˆÈ„Z,hŠ›jÀKbõà ¼®Cš ŠÊJ×ÈÕ‰üèÁK6 €€²"À+±¬f™lò¬'s’rJºÄ¸Ê/¼øÒëIJ¦@,K0 ó¶°»(+U´á ±Ç´±ÌM8ådb ˜ÀP-.å·_ &õ×Ï ¸¦‚ûL˜àƒûýWÏ…n8b>)Þ3`¾Xc„'æâ1Føc9Ùa’G6Ùã”UÖød‹?må—YžÙå‡a¾yã•3Þ¹äš3õ aJ@VxƒW–­³Y²ÐâJj²¢5ÿËjÈ’v­­£V׫®Çª6J¸°}Æ.¾Äó¯. [[1nÉ…·Ý­´^³Í7㼃‰<õåTæŸcîØçŸÎÙæÂqþWçÄyZñƘðÆ _ñÊ!7˜òÌ5ÿ“ñÎ?œóÐiÝóκh¼°ƒ>œ`€­žè^ªÈZ÷°Ò Kݲ‚G êi‹¿ZÉ®qªªÊžK«sÇü2…Wz¸³4+4™=32¼ëÝû|÷åWrÐKýrÒÕ7}ÔKGs÷-?Ÿþúã¯ÿüß¿¿ýþùosú«ßü@~nb«Ë›LHa¥1`k˜@êV¯©jIKðÀFÿ5ã…P„Þà ^0ÐæÁ.ÒØ–Û²Ô?@ Vu¥·‘É……‹º sÁdu’ f6³7|ùm} ÿ˜@†ð‰$`©Å'VqpZ´b¥˜E.¦ŒŸó"§ø/– OÀ%(qBo<£ I‹ÓÒ•©!I-Ä Û´ˆ'©­-F¤Ñ/åÐ0Ð@ ^ðÈlJݺ^–Ö¦Ap2hV°¡ "f&öJâ"vEÉe•c4Y±ÈÊ%ð•°´Ÿ,SÉÊUÒ²•=3#-sɱ4¾BÀÊ †lL¢ OX–ïšÄdz lx¤fÿÍâÿ RK×Sd–n²CraOLW{×Yr0 ¨ÀˆG¼Wù"öK]¾Ì•·Ô%<ã)O^Îòž›ç>SfO欟ÝS0¯p\£ˆ,Ì ¦’4Åk~T‹´¤éGf1ËškÁæXLxœx©’Ù#éH£÷¤´ñ°+˜œ“ÚT*{¹Æ|ç(Awù8}Ú´– ü¢Nù™OzÚ >]\M‰zÓÓåTO½‚Já„ <ƒE8шre rpI€äjW‰§MŽ©›à$—Úò2Ò«9æ, ŸÞøf;ý¦@=ê?ZW|â4¨G*^‹JW¿Ú°f&ˆö&"ÔŒH¬G(TÂÿp°DŽdšÐÚjW=k<¨µ0"Å^XK*Ö”†óH+]kÔÆÒ¦—È ¦îaóšÔ½¶¯¶ý«^y;³Ýþv®¾Õ)SA !`âøƒVz€Q4ÃPÍV6ZM=¶6š^õl[ÂYZ²š¶¬ßgæ„ ÜŽµm­‡‹[á÷®ñE*ü”JßXò´—ø £ùû^ûæ¶OÆ¥…(ì°PâèÁÊpà 0Óu£¦F³{µŠr·«è/y¿ ÞÅ|8' ¨Fr¥« ôàviaïøÊ—'ö¿ËïO‰;c“QÆ8®±RÅÈcý÷¿£Ø˜@´R _“ÿ*˲©*pàœÈr–…ñ¸Ç sõ!ô.¹¾u—{XÄcÅ '/¦©â+lG‰DÚÖÈ12Wgü¢o¾s&žé{Ë$íFÐŒ ̰AkZ8ËÛ-ž’ÌôÁFsÍxŽmxOÛ–å…Yµ¶¼(ဠüà=`q’gW9ó˜ž~ŽoPY-ܽ¾ú·¹•µm ª‚Ét–£®ýl¯w]¼¯E­*P²ÊhI b4ò0°ÁrG*Þ,©¢iÀ ~°®À¢™-~«{µXkÛ Ü„°ý;äÄ[·‘ÛsÓÞ~êa»Ç«òüm½®”O5Ž9ßy-°wl¿îF±Ìh@ÒØk›š‡­ü[ð‡a¤¾iÉ‹‰ð˜€’ÿN–OlûéíÔŒ­nùÏ4ù•·%Ö?~3ÍóŒÑ'êò;þ'Ѿ‡nwùgñÇÏ2ilxŸ’•fÒx&ðëÏ Ã}Pƒ\€ Ÿ¸-þâëë÷òäÆe»=Kêó)닱©;¹Œ±Ò82ÖÁ5ík)Ïb’–K¼µÈšíû5n8‹ ¤(y=lI¯cS¤ô³Kƒ¶…«†Xƒ@p;ÐÈšÅ{©˜ ¥8 #ÿ›±$@É3À{ @ºÁãk>ç »4;˜H;±X» ”¹ S½H󵚳ç9/ma¿÷;‚ÛÃ=…k¿iË K¸€ˆ¸úS§Ë›Sƒ<;°ó'ª€ZCÿå{C•SµÂlÀ¹£»·Û£°¡@ðÓ® ‹?|¦±1/lÙgÀ€0ù.x)À¡Ü±œ˜„iC§‡CŠk:8©—ΨðÐŽ‘êìEÅR4Åù€RôÄOdÅS|OüWLEXdEYœEZŒŽY¼E\ÌÅ^DEõøE^üE_$F`¬EcFc,ÆemT"XT>ÕR%VEÕM…ReUZ}ÕN•UP­UQuTB…Ô]%UJíÕUmÕ:USSmÓ7‰8M,>Õ¥T<ÕÓ˜àSÖ©ieÓ+`³ãS)ÈJ…“—ðÖ>íÓ6µÔ8×sUTu5QSÖ9…S9ÍÖA-nÖRýTÍpU[-XdUS]Ö;uÖ_…VsØd5ÔY5Øÿc%Õ‰ÕUIeÖT½Ô‡ Ö<ýU{½Ô=ÕÖ‰%XZ=ØFÅX…ÕX^µT8YÉÄCBmä¾ÍŠ»šåF.íPH<¿T1À €ç*Ño5Y…EY‹½Õ„-T—åX‡ÍTuÓ5­Zj¥—ZíW:Ö7mÖnÝS:W@%‚*øÚo Û?=I²…YXMÚ|EXceZ–uÚS…Z˜}Ö©=Ú¶õÔ·MÙ‹ÍÕºmØ»ýXWmט¨×ZUW+@Üt%ÙlEZ¾=T¸UY\ÍØÀõZU%ÜhÓ_…\bÜ¿µ\†Å\•ÚÂÍÓÃ-ÐC%×jÍZlÝZ; X¶…ÕÈ­ØP•[ÀÝŽõUÓÝÜÔÍÿ|e]¬½VFÕV€Å\MW_m]âõW®½ÓTÅ””‚̈Óé­ÞZ•Ù;R+ŽÊ¨<º2íÊCÐêµ.ÃÂMëYŸ½+'ͤ`…Cå½Z~}Ýw]ä]T‘M\Ç-XvÍS°…×´WWåÔíÛ¥EعUÖÜÌíÝBã\Uý_wõW±UÛ²µÓÕ]ÞáÕÚûÝÖü¥Úàåàú-ÞíÚèµU³}×7൥S>Y¾]ÎÝ&]XÜëÍZý}ׯÕáùÝWkõ`ãEáF•^7Ýa¥Øb¥Ü¦eà—¥W‰u[Éõ[ÜÝÞ]¼=] ¾ÔÄJÉ?ÕÓ8 cKýâWMÛÃ]ÿ4¦SqÕ M]c@%U8VÛ9¶>}ãÙUÛ;&‚ä%ÛE=´ vÞW.à­å£åS\Ž­YÝåXvâEeXæÔQf[&æSþäTþåÂõedÞÚVfa7žå­=IŒufÛuecÎåbíÓN®ætfSfáÆgç=ÉK½Öo&çK]çlm\ÄÂænÖ[Yçwng36cQ^ægöfAæ{ÎDûèBƒçÃýgjfgay†[6´A6ämäÿE–h ,äe‹ó}dކDÞÃKÞ>Øjhåe}~çaÎæ‡ŽU’>]“ÎŒ–ŽÖ—æxTgJµiĪçs6hl}Sœe”>f•ææÌÈi‚T|ᛎÇx.`sç¤>Þ“.蔞ç™~“E­Ó˜†á$£—1Þf“vh¢öjRN耎g©þÓv-`F=jt^è´v炎ê®}Ý­^é¢ÖcµF]¹Fj¸®ë9MÞ¾~k´ì˜Àce®j±¾j½NI¦d‰nA.žD!EÖ2ãéhÍÞltÒ•’ä©1Ç&‚ XÓ>mÔNmÕ^mÖnm×~mØŽmÙžmÚ®mÛ¾mÜÎmÝÞmÞîmÿßþmànánâ.nã¦í¬6Ðð= –ªìIû5®š&.ÛlênäÐîC³€­Ä*mønðoñoò.oó>oôNoõ^oöno÷~oøŽoùžoú®oû¾oüÎoýÞoþîoÿþïõ–Ò?…ìˆÆÃÓ‹n [=ð«n :ƒð­Èníf¼‚õnÏp ßpïpÿpqq/qü–Ò¬&ðWpGdŒÖÒå6 / ¨ñGš‚àè¡k2&Ù2î¦ 7q!r"/r#?r$Or%_rõFñÄd dÂË­;r’Ãà€£1¨†o±€‚ A ÐqíAÿi!ž¯&os7s8s9Ÿs:ÿo'‡èîCð¤*¶´ÈrUxq‚kP±wä€Èq37Œë¦pííkeó:¯tú6 6(°tOÿtPuQ¿sqŠ6çžh‹VõÃ`…(Œ ­@tØPÍ©eô>\sñ6ƒ;` hƒö†6Xð6Fˆƒ4u7˜gG3(r5`Fèe¿vlÏöJ'õU߾Юð‹æ>_ñi1 1(Äè1€d'H6Ÿtd[ωGïv]ofg°?`o9(vðVLðb×öñžJHÿþ&@ö7¸ƒN'òÿÀ„ˆ€9ö8ƒßxŽó;.õå–@ïSBw}+ ò£’u‡Ä ¨—_Fïh[4ßšf©÷„‚2`Eß÷õ6xÓz‚ïøï¾€ˆ øoç@ò.xk‡s3ð„0£Ïz­7rnïv?wÐo/ù0 œ’ôŠÐïs 8‚FGŒy÷׺ã ÿn=H‚Dðyõî÷_úïx((ø3;„€øðV{„Ò„×øõ–L|…‡ï7Hv5È °ø]ü x¾7%ø¨ø˜þžx:˜4Hö¾Ï€ÂWý€ƒ©d}Œg|ðü@ȯïàõÿÛ7|º/€h}ðV×WøÁ?40ƒÉç{%à|Á·üÙ7€.à|ÞÇ} Å}ñ~ƒõý£Oþç‡Rønðwè‚âßzõ_ÿWk7uïësËDÃHù¸¨’GN¿˜,X°Á@(lèP¡"W¨©°ÀFŒ’$ò“ñ#ÈŒrÊøhƒñ¢’+0*IBcÊ”& ,Póæ”BòÄ(H)Lô,Œ8?Hº©abDF_˜ÀL£ ›01!t†Ñ°E `¢#ÂFŠ8@õá&'X¨Za0bô2OVŒ 8Š“Œ Ðð2f„¬-ÿÓÀÑÁ0; (sÆ‹21&©1Ã%LKs0šétÚ.d[R±VN ¦S³üâu×jÊÐA›V…Øà‡/nü8òäÊ—3oîüy"RˆÈ0£0ÀÃ…Ù·ÀÎýûÃÞÁ“o` V;Ö³_ߣƒò ¦Ðð`>~€@*ÄÐCMTQHz$aÃfÁÉII'’+p‰)°AFE ÀnG¼ÀˆO¤Ø`FõR‡®)÷ƒ0Ñ o)¸Á[5ÔEƒ jðÃMSÁ†…gìEšI*©¤`¥†KZâXŠp1b´±à‰•hÅ‘FHK YÿHo ò¦%lÄ1#M¥IÆLdQ2†SÄQ gùhÆTSQC ½ÍD!Lhù’ôvFUÚYÈK3…胙-JAK\%¥åszú)¨¡Š:*© F7]u× Èå©êêwâÁšAÀÒ{¬Ä—Ÿ@÷ „Ùð:ß~õ µZ ÍRQAFGnÄàpÎDIx  ´¡x€e5€Ù—D©è—S£1cN&Ì %ŒÖGâ6ÚÛd8Úè"H}aö/À_—`!) æö‘§h,˜‡")$f—>øÑÅ·)ñŠùØG¤P©kÀj›}K–Ä\ h`oxìÿ}^Ü’›)!ÊY3¤qA LøpU1”„iÈ „˜8—4ÏL á$Íq•:5ÕU[}5ÖVŸJuÝ);+ܼúÝx_ÏZ6x©D;ÑÃà äD ‡¥pS±r”÷±,k6fÈÐ,Ђ4mƒÁAx-eNÆ‘€ÉR qdDBs lôö‚¹Â˜Ä wœ0¹Qìj« ¦ B $™”IŒd¥¯“<ùûðÁß°X˜Ø`! 0i›À¶Ìe„ˆ%‡mZÂÂè52J0™K,çNUŽñ-vÂüE0ÃAmãPx¨Év A¤—‹?ZÒÝ’FÿæÓ”Éïᑲ&À°€¤ÚÖRå5Àeço \ÕwĶ@²=0mé€42(½1`5Ø7ê‡ ÉÊw‰PÄpAÜp…™\ä`P˜ YÌ 72:ÌæöG‡Þ\…`™Ô§ºrŽ5@Fúð–ÑÐ<‹¦r½3ð®(]àØ0f†0Î!cEÑW,£°N Σ€'ØW t4àÂY`.´+#}á£UÃLH,›`Â=€ µfBIš:4R 1-9†™èA~TJboÆG’ð{Óâ¤( yÀU²²•®|åGØ5´ýMÿ… ‘ Ú²“K[r'—´"á°FLš („àvÇB‹€DA6Xƒ†óFlù/)`’>êˆ uaDzò»ÀoXËGÌðÍu2b2*R h€>ôf4@pC¹>¢E¨t‘'•Á# Ѐ2bfì W®h€õ¥`v,yc’=’l%ä– ©J/I„Àg´?it}»8Ÿ ø“ºæf ‘·õ),ƒ*Ô¡U9²+È˰!u;»Ûx†É+¾Iu |r€Lf ®"ùˆÈMiÚ@wQB=û¹†Lt؉Hïw$ë¡´a©ÿòi€Íÿ;ý*Ä“¤©6‹6@eäÆÄ¢ò¶·¾-êQ'èZ’‡@KÅ%yžJžªâ‡ªÌ%æ@5Üdvµp!9C6#kŽh`yâsÑ9±§|t(ºKQ#ºÚµ'føÂ&¼jä.‘¼I<}JXs >x+ç2PºÒ XÀî„ïö@rÞXÈ>0«îyØ A»‰…Èô±.èN—<Íð–•€Ïèÿ%ÞpÏŽ•Oæ$jmh.žÑ¡®šé 0#& “áHÿ¢vÞß¹ÈF.`p}©¤>¹àQ.¬”¬‚ôç¹Ð5–•¡ûŸçof ÈD\h€¸ÚÅ”¨ËÈŒ’<´"ëÖ°·¡øi4ÍCd|qð‚@ ™'qET‘v{Dœ]ö#0šD^é°WŒÜ“ –ƒC\tâe€u‚6 ÍÈ =äxrÙ„•,‘6¥o‘5+ʤk ç·P‚(zÀL b#"é͹st ÁìJ Ô£P)â²RJ¶ô / Ô°wc8é(Ž5‰ð‡S–¹6ˆL]4¬íms[TIŽUq·ÿš'S0<`ËòAŠ™åýüÇ–Šˆ³\˜vÙ +> ´QBÐë®\Œ4«éÒ‹™×§#ø¬§p%Ñ{¢®XÂóÍï@惑á€+g±“¥£¤ÊâÜŒ ›å )±‡‘7ó‘~ ß,<:8¡Þ•âÍ^A𒋤d\È5™>@:š$ì˜2ÆÆÎd ZûÚ½,Å刼é‹iã|Ñݾ:Ö³nœoƒ»ÉMÕe£ 6¬¢{oêβ߲*ܯ}y™é,À"÷;¬à EyC êߌuá±>Á9A€Ù Ä:u7Ǧ—¼Bcî¹Ãäià½ðf9i¿ºÿäÐ/z¾‹|F€€ĺÍÀ9ë,Í ~ô¦7ÀXßf ¦ ¤uàãNà‹fص£Á zŒØžuˆÀ·TlüÔ?>8hóäy|Aò…ù~l½Ö³¯ýíc„ëåYê’ûõ‡@™;ù©²Tû\&kºÌ¢Ât˜Éýž„àg-Èö+“§rÁûs—ÿQŒTBŸÍ ’Š÷Mr™ÇpIÙB`ø—Cœ_ú]–‰[vÀ$DJdsD$E‡Eb\A³t øAU# W>*ËH6Aô@?¶Güc.ÖÀX$sq¢ûÈà„ÙE.GFædqì$O‡Oþäpår,£*6ãx<#>6ã>¦¤5^6æÇÔ @¤ <Á7ú"vˆ#xh ê…PbäXVdYšåY2Q†„QeH*e¬”$Ù1@zT£{´!¯ŒÀ"T ø‡W~GDt•C¦%O¬¥aŠb&fX,&cQ¶¥*‚+Š$4šd,öcÛàx:Rˆ¬aü 09 ˆæhgi æàäaaRèÀ Àþa &ôç ä—§È„‡ˆm@œ5Ç%l¾çGt'„rç„òDT—G†dy"% ˆ bGÙõà_†h»‘XÊ›¡ÔƒžÄO-gXX€ ‡‚TÂ%GàÀdÈ‚L€ÃÇ8C"5GHÀÌè„Jÿh…Fh“¢" A†–'e⦇.¥ù…h (º“'Údræ'¨KÆœ)¦8@šõ„B88Æ ˜)¿ ©d@ ÆÆ¼A îšPŠÀÁMßÀ`ìù© &C™b–ò b’P†šêÖ5aHÀX-é“*“ftÈ£†ºeeÂåæ’–^ð`–yé—Þar.a¿<4ÀBÀÄAœÁˆZ, 0ÂXÀ$˜{ Á›À†ÄÊðç®ÌÇÁ‹¼Z·<°¶Öúë´A¸)8ôÁä¼<€ä*Tø*°V+F”LX€°ÚÌK¤ë(ÿv‘k¶ò’®)§vª§V¨dŠßÚUéqöRy¤ªª²êsm™€09š#H@€¼iL†@8)Å@’Þ­ €L,ôÎ^èE­S¦k#@™Î€IžÊ<À›Z€À `Àìi¨¸òç €,˜Œ©3«øÁ‘Rl̶€ƒk^,À¬Ç‚,ô)€CÀ 4íô§GÜ‚ðìÄvÀºB¹Þ€X)ä@ŽVè§ú«“n§xÚfÚá-Ñ&f¦ªúYÃÒÒæa³äç%© pÑÅÆ™'h¬ D­`À \€!ÎG„€!¼©å^n8@8Ó ¨€>ÿª¡BÎrQÍÞlÍ.n&„CAÃì„›N€¶`Ï@Ã@Å,”C’ŠB8tÀ/€ m)È‚›:®D® ¯äž-®kéÀ ñ’ƒƒB€!@ò†-Q¨Õ9ÐÛÂ-ZÊm”ÎãGŠ]©Öæ©.—–îíHúߗM‚ðÄà&)€ózBÒr¬ ÕJnF‚`.æ"«dÆ^΀èÞÍF¯àl €«<&ÁëöÁÄN'F )%à.áj°€‚ü¯ÿðÚ&¯èŽl-8m˜°ðØÎðjiöZ/׆íí2o8$køŠïøŽe`Arª€ÝRÿéml+êæB l–ÝÖ$DP1Ú/ážÅb,ÿn,)0DÒÀ[לñwì›:΂†!ÊÉqΓ®ÍNðéÞB&ü/Thp(ïîm„íŠp™®m#E­TBÔ‚±“ññb/¦¬íLÈ»€$?@)Ü0öZ¬3`Àt²Z€À~öO¿ ñ«æÜ²J3ÕÀ.q*ÿRˆ~ægÎçªfŸ¦à.lñ0¯3l,¹†qŒñŒ& Æt109üÁhÔèÇ6óÇ‚nF8ðèÒl'A㢮Ÿƒ€›‚oòÈ“ƒ¸â0 ÿr(0+`mV¼p#Q3Hÿ2\ò³¯À¥¢È(@Û1)·#¨Ê¦q¨‡=¾jC§ˆ’&ʺ'qÒ§’½˜…åDá2(4nÄ@åz±³0E¸i8H0£ÉÞ ^ XçÌ1 Ü€æ&ÕZ° `Ç&¨®AýÀNXs’žÒ&©¨.^4ïHï‹4T0 èÀMŸAQo[ígôV²=ãpò¬)€ ìD›2€ut@ ôYVÀFvdÁ6\4oDjÐ-rP p‹äõV‚#EÛí`^qF5t.Ï‚4S+éG¨ƒ‡4ß7‹í&csTostlúÁü€ë øÿ(ÆŽÏò'QplH/²kÀ’¶”±vaã^Vc²kl+Ï %jrY?ÇÛ&ctÈ<*ô€´µ[—!*{ÚÌâÛ°Â^D ÔLú%–ÄS±àfOFƒÐ[Ô€G(ˆçíZœÞÝ¢bÿ‡%ùˆ€ŒdN#Y”¶À½€ÌÑÁ ½mØD½YQVl`|p~é òý…зb ɼ¨ÉØM8À¤-nç¶n?&ZwÕo;U\Fãp‡ÝB[UàÊzt&¯|ÐÈçD „t-‹—Y1F¿ ¸,i `ŒÇܳ‚¦“ËIyƒDSL6O8…WxZž2\sÿ¸«´eNÙ@ð£JÞ%CÄ¿Ï,7% üú’0Z±&& 0Þ‹‘9‘ÿdZKé[—GRª/\ ·*6哯G{ ¥L@@¾€ X¹ÞüG-ßg—7én“¹b ú¨ú‘‰çšçæ†wøwœ¤S®ÇJJô°¼! èù°¸*pÿuýB¨¡zcz:©tzo¡5G¢yšß¦©¶9’'œ‹øl0‰HANô–y!9^A~²¦¨ƒ:dòz©ìú+Ifù©yyº9AL€]^ã0%Š¥_ºß¾ßæºj»¯µW{O\ûqa+j•¦:[søÞ°BJÖ"¬óJÈ!Ýd³7ô,O÷«FÿE< Œvª¶cûwâûÔÜ{§9ÞŽ ¸‡‡›gé@t@$ŠÛÀÞ¼|f‰Ï'Ÿûu¬Jû´ë;Õð»ÅS¨où{­º·£ú=¦[5¬§ÔµÜt€Ô øŠÏdWr«(N>)Æg|ÜÚü¯Ç¬†7ñ¢Ã »»ÂS—Ùg˜Ú;Î_|Ò+½+í<±§¯¢¯¯>ý–FwUõ­`ÆãÌùÒƒJÍw}F|}xô,1:+;›‡{ÞR½û’«Ú’¦C‹Eì!M¼¨Ýß=Þçý‹Î½Þ÷½ßÛ}ØÕò=áÿ½á÷}à+Òà>ãß}â7>äûÔãc~åG>äO>æ7ÿ¾æo>ãw¾ç>臾á>éÿ½éŸ¾ß§¾ê#¾xÀ°@ë÷}`èZ+±’ü=2¶}Uu%øÍoà~DAñKÁÜíò7ÿ ¿(ÿ0¿ô;?õG¿õW?ö_¿öwõg?øSø‹?¿ùÿö§ÿùsÿú£¿û·ÿø¿?üÏ?ýË¿ýß?þç¿þï?ÿD” Q>T¨`DàÀ( .Xð @‰´(ÉEƒ ¬¨°aÃŽ5ô˜0dÊ‘%Nµ#Oºî üN2g«mÄK4°¯Ó-<ÇsqºÓK‘ÿ¾|Š«±¸’È"¿Âj+!ãz+.¸Ú2‹É&¥dr@È®ª2ã³ùlÌÁ ÛPBÿTŒ©÷^s;Œ.ÇQì«G[„ÓD9w¤S°½è»Ð¾Ñ4Œ0µ)Ûd‘R½Û“ÆÊô3ÌMÜ<ÕS>E ÌÂÐ}Ð4¼8ì/ÒÚ“޽ødûS¼7OÕ3ÕP3­ÕEï# Âý ¥•B+üüÃF“•µÌZ±¸ÕKEÁdÙX5[vÂÅ$m Ȭ²,Ýt£:òª$«œ^¶ÜŠwJ`×*.'õõÅQÅa+vÛcUÿÒCm}-8^ÔQ„ wa Ë•M½:s,DNùóR€ë oÓMí÷Ó`Ô¸}OYÆG­B‡ †xÚo¦øZ†/¾¢´Dës°¡ SZog 7µqñËT_Î3d™5¥ù¸¨MÞeTE¾z0–{ÚÒ˜3]k:1–¯¯+ª` èÒ@,«sÏUwÝ»ñ¦Jo¨è…w'œØƒ¿—´ß-›ÖÚ/ 0`ãq…Ͻ,_ÀhW‘î6̥ͬ˜5¨ Ž–s2Áý¼gŒpÀ3Ä]¯Np½Q—¹†yNaÅ ¶µwÍK‰"ÈüaX;'L Ò¢h5e@%ƒX"ÿnRAÔ‹ú ±Ø^0¨Ç¾j³U¸e:{§œm«pž gK¾óWXÁÛIÄÔ•GMÑüö»~@Ä»™üV@’î`Ô:µ°õ4¿Àns ÔÙÄ—ºÐÝÆ }«KÝö¦ îí\jÁ@á Çh€ ОT´Ø+1´KX”F$áq`„!(ÀáA|Á *@„m}ï~áËt À†á±/cŽYß_%¦œy®0°ƒŠ=¹mÏN Øâ Ф+$âH‰ù›YØôÿ1î9!P¨Áˆ)pLðƒ­× 8eL Ó'ÅÂôÐ`sŸ T*ð•m‰kÿ,Ÿn¨P‡ÈUæ|¯QC(±¼:"ÆŒÈÀ%)IÅEÚÆ~h„dz”€ JDàm@ÀAøX0’²=À© ÔRY)Uíläã%ý@^âÒ7´¡ÛU>•fé™é @Z0 i\³à¼þ `  œ Õb¯uaÅuÄjJÜ0…x“ 5È2›BT@ >xAè`ƒxRÒ (Ê­*âç"Ø#!§¾Ë gJ«–}`cÇ:Í£xÀPÞÐÇm—ñhÀBš¡^þêRrDÃHA:E 0¡~ ¤þHˆ“ví_VCûÇÒ¶¹t1 3¨¯X-…y ~Ùdÿ'“…› B¡>u¨IKQã™NK}â»øÉDæì”Ø«ž-ms…‹öçYÚBà'È,žÝj™Vé[–Î5€fÀ®LZ: Šü5=˜8§¤Âó,-dÀ[@­(Žax©B’0;3d€Ÿq+c؇Ï)ø`fèÂDàÎ@Þ*k ذ©:†žÀ¨bf›ÛUà \<+ÇD„òµiT-Ø&Ùžb~R¥ÌqdW™ªUÁ™ÓDM3×¼à6÷k;-®«ZQ¢ T˜ñC2Â3KMƒWAÓÄ\÷—âÓÝþxçÆiµ5?°Ä^[Ò—æmRè/P™ÿC„*ìÖ:Wˆ-m ªÖƒr.®UÑ`âÌ¥×¼¡ë,€Å_û× Li58ÂHLXĶМç¼J:ýòž*±1y¬AjëT,x!t¨"‰‚2ØÀ| Œp€.Ü! ‘óÂîð6¥f0'Ìp‡`Ag²gÌ@&$€ÉP2“ÓàÐŽ4ÿ©€˜üÚ 9 2PÌT@!›¡ `rAr[,ÀYM^Ørg@[ð €Zà|†7Ì“6 h³Ælå;´€)œ0B àd¡Ê€ÓoHƒj¹=,€ùH¾‚%“k†7taB“_ܼ…, QƲY:„ÿ콘Ìg n‰\7ˆZь̋±­l@êÚ3º^Ê’›½ (O¯ oÁ¤f†<ãy6ȶª©èjZ#ÁÚû6¹–€MpÁRþ€z»]é7°@3Yôƒ%PÀ’žƒ^pS»ºÉ,0+`~g!×ï$Ž ‰ƒù s0kjxc5¸2u ‚–‘°½†ó;©VÁÆû-i¤á,7xj¼ „cÃ\æýÖùέÀrTüûÔL^9š˜Ø@Ü0VØ9z¾½¦ó܈'z¿UЕ±LÅ+*¦JÖ³, Ioæ ßÊ‚VÃiïA5¤4,A…€ÁûBºÿ‰]w±NlxÛ”,„€ )CßÑJš ˆ <È9‘‚A I°Db@Ô`‘ˆ  Q†)ÐÀ+OÌ40Ò_>wýSsXÂ/ j°‚§GÞò0°„ Oxp•ÿ| ö`„$ÔÀ©ié3O„(l󗘂ã=Ðg¨0ùýp°–Ú3è<íýPò‘"'H À€ßò—ylp?|K”Ü … @óÔÀÿòÚ ç¨Àß’Àó.çï€@øâÀÿš öùbÎ1‚o”Ï4 üCúöˆàêôèÀ ljïò‚óâ Ö/)Pÿš`üúO1ŽÏö6ŽôºÏ^0ôšŽý Ê fP1ZNÿ,o÷jÀÿ8,/pÀü–®“púÖ@ô| ýÞ@S@yN¤ï ¦@çàã^é ‹Àûà A Ù@õd€»/«$ïô†€uîô¢p஀ù(ôâ€ß¤@ 4°\Ï@Áw. çú²¯bÀ  òR Òàé¬0÷ÜÐ÷Q÷Èé .7JPV°@ Q ±Oqæ éˆ@é fQ©Í@@Hðe*ÂN]¢iHòŠH̤íÒŽÃÄ`›âbTÈ'^À¢¤î¦IK<¨+ÖÐ åÌ·ÿ¾@,Áø®¯Нïo ò€lÀh`Ÿ>«ÌÊ <¯Ø D ý80ÐqÝ€ â`ð² SŸhàóö‰ /1”@S€^@KÀ¦¯ÐD È€ È€ø¼à/P:ñ8·D€ ¢Pp‹‹*À²qhÎóL1"Á °ä@@ø¼ðþ” j@‡àQR!Ñ‘"_ üÎrÇ %ð²†È + +Ò·ð>/÷±ñ© RÛ “Ȥ pè±éþQ z2’ FÐ •@¸@k (ù æ"2-¯äN’ vräD´dÒÿî’ø2!$q’ƒàúÀó|`÷21mRÒR'›ÒÓ^02“öŠÒG.øÒ(Áð‡¯10Áà1k€0§` ÃCr³·<à$]SE€ÈŸ R(×’QñŸ|€–±2—.Íê2³ðÁ8Õñk`‰@ ÜÀthöh³ïàôrs =/ +?‹ ’<È÷ ï3ÚæÎÚ±Jk Nç´ˆ`,S| Ìà9£² ÎQEmÀ`‰àFST *ÀG} 8q`2CÎ~õ3q¡°³ùPt%Ó*Á þ0T}ÿ¤H¯T¹H.`ö\ cæ@uºãC#W•sö˜0 ¤5(Ï‘³UÏ@öè2FMÀ~õ!ûÎ-_© ¡$‰à9 rP¥”ßPÁ+˯XÝàUÛòp0¹ÓB%/á^ F7u=£)£cõBehë¤É™¶î®xq?«â,€Q‹›ÄíèÀ´tJœ±œî?¥ÂuV±ËÓ v4û6V¼24O1e€¦Eý¯7 á7×àØ,Q#C!jà!à8ûFfpº|@S3hÓÄ6çzQ¯´3Ò18RÀò#7Ð /Ó[5aÐNåpç@À/ÿÉÐ1–Vñüv 0±oµÖlé¶ßuj–t A‹muî ôÑЕå’ò!ÒP¹ÕˆÕßÓŒ8>V?jxƒp8óÓëÿž Z¨Í¢Xáv  ©“.œ ’p}à@£ú‰±$¨¿B óbùŽsh;»{òƒ× /À•Äúj¡v Wç[WÙúEÛøÂ9¡Pò<¯uõ2•%wÑm5¡¯ÏÙDŽ$‹€ïp븓mà¹!9}ÍC× ÛzMôô˜dÁóøV1U•¡9¨ð¢ j#2àù °™À3%Q`ö9b}Wµq!~S7Èú ¿œºgOÃ'®)úÕ€½R·›÷šr—’£®àIêÕQ1~%”¸ió2œa`Zû|ºqá$Ñ`s¹·´{þ¸h$Ü0ä¹ ÿÃûmG¹N¿@r55rŒ–Z/·w î"’ÙÀŸ½@úÈÀ û0˃¯Áú¿y—· û`ö*Øòê·7•·0‘eº4,œaûð€cÚÈËŠ„1Ägk:: #ƒz˜H¸N‡{ºÂ|Ú‡Ó¢-Ä`Ä`Ƨ¤6 :¡šÇÓb.F\Å‚\<ÂÝÓ4¤¯B9&¡™É[Þø&ÓûZßÿO¡ÞÖÊã­1œºì4îA˜y«JÇ@#© M'Û•‹T“ív{–O Úp³paSÀK¿ åWutÓôœ¹^“¾È7îO€’·šc<ÀébÕB;çC–Om ýWÿøæya¿ý‰[Ò€ñØ2çTýmù¸óX©þ0mÔæÒ¼E3 ¥W}ϙە ¥ îé •XÀÐÏ’˜Í ·Û ž³i1Z¼½R<#?µ]½Mž¾šºõ`ÇW7=Ô0}ó›æL}Ãâ<—ï3Àƒ°ÀSRš%bSÕ¦v½ ]§>æ¸ @û×ýcÚqXÐMÅßbnêŒDˆVÄI~ƒò³Ä¹âÄy˜â³¢îp–ãC¾,¦šª}ÚäŽ"&qØ1ˆc‹ DfÁÒËÂ,hØHѦËNj"B“mÒÀqãÃ…Œ,]0©aâ Fÿ¤¹$ÂÏJTèP’D…Ê¥)~¨Hh œ4‰DDE74¦À¨* ¡…2°Pi¨$†~2à“&‹‘8ÈÐaBT – _|TºB¢‡ºE²4ì#rJÂ… ‚5ÅG™eˆ"!rxÌ +W²xù""E 81l$2D†7LRàÈÀÈ’ ˜kÌxƒz•N©Ol¸u¡WÈ1E¸Ó˜$!˜|º‚…“7”ö$/.¸ËÆ5"QÉ*“éB4¸Ðc…§¡EQÁáâÄR[:\L!’ÂШ)JDQŠÒK•¶\ÑSÆHm¼q# G…ù0˜ ae›Y5QœÿDØôPD 9˜4¸…yÈЇ6,v‡Xc´Dy9(V +t±Ÿ< g†}øÉÐI!>´‘áaaÓ*™ÔPÄR¨ %sÈp…&dLq#ºMÈ…@xqèä|r}Q˜¥0c(Í€ cÁ°Õ"a™SMR¸8UÂGDÈ &LR’ kµ±ÐŠ€M<’ÙTt¬‘Á0Ò|W0Ô4ø`I 5¢¡^Y\¡F~lõ)µrBgGx7FXˆ*GÁC|@]>Ñhx{ETMÀaC˜¿xvD"ªQ{†(cD …_"cÂDÖ5ˆEó –֥ʚ‰Lq Ñ–õ¥e|>’¸å`˜ñgqÇ%ׇcìRpÐð°ÿb©þUF"pÕÐ5xâ µrÔO}•a^ ÞÇP'ûõ7_Ô6L ñ× ™ÇÅJ­„ÆLØpò ”‰Ž'¹^¬4ÀàZ >ŒøiAÌÅÔa„‹Q}ÚEË\¤€9HõÝ÷§ñ6™9§‰FØKAU()tâ6àAæú€™ÖÅŒ3ÓÉ84 „ýiƒO“­è–ü%¬ š Ö¨*ì'*ÈÜTÀP¦h"1ž‹ÔP†K-> Ü…p¢t8C²0“MÁ>àÛ|vã…Bdm )`Ã[R€, ’2Ö„>Œêu?“!&‚ETˆ„Ê’Âÿ%øÃ\°­geË‹MÒ´¯$lfp—¸ æ-?ªË‚€ ãeÈw)R\»W©/~ý ’“¼9€L~+^Ëã»PŠ2So«Càs-È &58èB £B„ `"wNóO] fÁA Vð:%d ¹¤/3Ke`zg(ßZt‡;dñ+XHÀæ€ÒîOžd /}ùËijê4%1¯@5ómêT7e°Š#XÂ? “HÓ à–&0@‹*à€uÊ–9•ˆ@LjHè/whÌ^þRƒÂtèXð)Ozq=•9‡i"”ÊbH ÿPrJ Òñ¥F@J(õa˜jBlIN|NóEŸòB@)`A&Ó«B5%º3ГÂ\A2w)Ñ|ꦔ±VšækfsT#jQAo™r)]1Ãnˆs~% ?Qa ªµ´Ÿ>]2'“ס ßô¥TéCÕfF`x žDV¢Ê޾¡2 O- Ê÷ÅO•’…È@ƒGÍÕdœP§yéD)Œ™óó A:X¼¼ ¶ ÄEm‰Ì*ó ¢‚`“é…h†æ pf.½¢[<:௰¢*S@=þi ©c¶¶E®C*Rºâ"dt™Iê*’¬¤¿¸ëÝÿz…—[9Øä½%Ök|»X*¿G±ö¢²0… ‰“2+Àå.·¹ÉÝ a¸ò"¿¸w½ª‚y&ëd!> k‹ê”?øm‡0\#¢ ¬`aÝÔ/€%’£òˆpˆKL˜_ØÁ©Ã;óû_€xÁŽ1C[ˆÒä¦+Ð2ìDÂä!Öiu$’~¥e“jq°”òÅ} L„!Ï·ÈW=²‡e¼’%ÃWÌæ©m¬ä6ÍÔ²}…Üæ÷.l¹5fn ÉtB«YÑ^35á\a0¿ÿˆÏ-¤y êó†zÔê /wÅ+ÉS3ÀÔ«¾—À &jÐ!Úbs~ó~ä Z–)X(~• h]C:öJ”eàâÒÕ€ /(œP…`AÄ&N[‘üá< š‘ŽðŸ~ˆÏm°Ò}–ÈžåìæÂ0÷Úw¾±ž¹ÎÒÂØÑÂt¼1ýe2§’Üš6w}ÙKët/š+¿ö/½µ=loS8ßT( ^@†Î0HÁ Æu¶qœpXž;ÑE6¸‰]”i}¿ÙâxƸ½ÎíݤÙÐEžõ)îqŒ¹œÈtÞ¯›g^kuÛ<•Ï* ®ðäÿÊØ79¼ƒÒNkËÓŸ&µÓÍȧÏKÕÿùb5«ûeõz½š`œ,8¶KþînkœÛÇv±ƒ’p·0‡üÒofw°~òê]e › c½‚ ·=ì÷.LßeàΰIå…^ó¡þrEÇœçeŸ²=ÿ¼÷m‹=•ñfsÀ¿nÆ/ÜÒ›V·×Ûý蓽ò=ЂB”¬Ã $ÍòŽãæ™/Œ¨ùc3&£Ï5Ü>ú \ö†§/ñ?è2ß‘!Ÿ*}´Â£wß}ò~¾ r†w~a)F<ÍmMpÍC„ßJ‡.×»5°óK}ýìŸ:Õ-ɯ4àÔY¯Wy€$r\HïÂ8ÑÑwq|‡rñf Ð+·'aRæÿcŸ÷vÓ×wƒF opQ!Cm)fm×€øÆy‘,°SöDx“ÖqÉgy‰×qµ×XÔôbD'}|_q}{¶vÛ—d)ø}:~¶ç‚>6$ËÇm€"€`'yÈm`xQÇw‚)w!O-?W„îv„h}ª¥ƒ97pçƒy1e[H{;÷…Öâ"äÇvž§^$g…GyY¨nlzÀ÷†4¨…@d»(}Ôt°æ‡íˆN0W÷]ô2°‡xˆà•jö²uê‡^ £^xXrXotX}v¨nãç}\¸xe†/hp1x…38|›¸q—·‚dØ‚`Ø Ã"s8†=ØÿŠf‹U8‡Ô'šXO%…>×4hˆƒ6nÙ÷ïeŒu6o1t ÎG…¢øum(zuxŠ¿8-³‡y¬x!?è"9&†Ýh‹ßèŠáKNx‚Èq1–ø{¼Hv¾Šw䎈…òøŠÓÒiç‚.ÚˆþèGQ·Hï‡/“4 0€ ùŒXuö’éׇ›$kÈXnʈ1{T2ˆ5¨w‹‡õoñ¥Š5WŽ·w޹8„YŠy‡.’㸊' Ž*9ŒÙo©^AF‹äè…·Šâ˜G ˆlŽçfÒØ4x‘m·“³H’*h’?iޏX[Ì!y”›·”jØ…FÖŒØÿ’™˜óX[6¨}þÆ}M¹“Ü8“R‰’T)”W©‹—¤Ç‡uˆ{é-ô2À À Ò@˜ÀÀ] ˆˆ"ª–u˜¤IiXÉsÔB”f'‹—fèæ“Æ8•A™Žri™¶'@,é†bé‘d¹msùŽHHz/ÙXeÉM%{EÆŽðQš³©GxD(“Q šo)šVI-Q¡vg©“]ÉAĈ–9ˆdkÆ–Ây”5Y•Cxœ‚æšöhŠ«™1ùN¨yª)›ÓÒš7Ùd[™–ÌÉsÁhz:æœËipû¨~ࢗü÷.þ/íw/ÐA ;°¬ð˜ªÖN Pÿ É/˜D]Ü2²†b¿‰œ˜¹A,V”hš½¹Iž¨hžd@Z™“LÉž>˜™FÉ™²`Á ~niq™Ê5/:œ1:š3Úœ8)rI·pÏX•r‘{BØ|y©Ù‹cù´9¢–Iê@šcrá¤HJ “LÚ4ŒÖ{`‰¤F¥Ž—›µ›Ó¡Ôzt ›pø‘Zª^€âžåÇtÉ—£ïb/ ð ʧJ Éä³Ùjùå…—Ý:ešf, )ª¡¼é¨µÅ¨Ô¢dê¢<£)yyT¡ûÖ“my£œ*£¦\#gGâWœØiªÅŸ&:Šk†ÿ’±Ê•³z->Z¥ã©«$*r·š·«˜¥å žMêdì(t€bn¶ºž¸ú…p晢Z¤š£¯ªhaŠ›¡›É™Œ²¬Ñ*§üH§åZ§€X/ AЧ|ú b˜à5/@° ƒØˆø'‘x‰0FJŠV› z¬[ºª« ŠùXªŸŠ›•z¦˜š©]8ªpy­ k|ÞW ¸™:©±Ÿ” [±ÚÙ°©ª6Z­kœØZ²hú€Z¬ë¦Ü‡! Àé­ê úE«§ê¬;›‘âê²G:ž1Û¦çù¦¢­ÆÇ­˜:¬W@Ÿ~xŸì7µh/ëÚ®|j˜ˆÉ]>ðÿƒJIùª/󒨊ú´kŠYŠ´4 Ø—ž% ¬<+¬ ã›7[¡_á°+|¨:­²è¸²+–☱º±’ºÐ-Cû¯E{¥Þ©¶"J°€Ò¶)Gƒ…‡|PØ­Çø”;(±)ÛªžJ²«GÕ2¤gF„J ·Ï®­¨^~ñ³Ë(·B‹Xy›¸”ÚvâI¬k¬3»\J»’]j„õŸ¦—wz®P‡§õòŸY+ bÀµÜ•/p¯ô'I”‰H•y¶÷ˆ¥³¹¶¿[¹º¤»uɦ¬)¹I;¾xd›ÅçwM+|̃^ê¸{´é˶¯2„™S¾hû½!ê•⫿䋇ºg•ó…ÿ”ÅvºzˆÀʇº œÀôx_9¼õ{¾N¦¾š†¬;»®K·NS£š:±¡KšÅWyEeAøÀ„!ž"¼Ö¸»ö‹¾\°ë›9D§f°䚼悼Owµìê¼ðzjÉÕk½†šŠ.²v¶%¢VMà¯ôù4L¹œYDÒ½ÝÙ»á[ÃZ|ûA´Ì¢Nsa;6t£HÅæ›¶à‹¿ŒÌÅQ8&ÂXlS\ÁUÇübt¼¿ŸrÇÛ¹žÈ‚¡)²;ºƒkº|-‡ÕÅ.)³`œÅu¼Å´–ŠP‰²¬ºÈ®*¸IŠÂDâÀzX¼éRµ= jwZ/0ÍÛ®°Pÿ §ÖÓ ¶iuØ HéÒ¯ýÛ˜ S°T8Éz¿X ¼v¬ÉŒûÆþ ¹rŒÌ6LÈË,­'+ ûÉ¢{ªŽÜ(r¡ÁÅhÆ;‰Æµ‹™ýë½Ï ÈȚ̙|J‹öÍÏ)»glޝ«ÆÕ\’œ°€ Ê,Ê kllªû«,Ï(IÏx{Jq:‘,¥ÑhnÅl´¡xÊçgŸª¬Êý) ºÏÐñ IP4€ÄI|/÷W¶Ó}oû«ÐÓÄ ( m]»‹Ïk“%œ­ñëÏÔ²´ï{1ñ˹©zÏ×ìÉú¬Í&ÌÓÝüϼGÁ0 Çÿ;°ê+ÆÓÜÎôÓ(¸¹ðiÿÓFÏ9­£;]ºLíÓpšÇï)ÁgÎ^\ÉsƘ<ÆW}-WÉMƾ—k‚ë¿À†ª7ÏáìÎóüÁ}!¥|À,ÌÅu-f™•Gý‡èŽÔî}Hõ¸ ™ð·ûžá€ 5C…uëíxöb/ód?ãìlóí ùç÷‘Œ±¢Ñ™îÝ…ïøh¯ö‹†±{Õc‡k¦z»¸7âßñ)¯ÔcMÊ.oÖ»Ö‘¬ÖÝö€Íìýì™ß”O“ÖêñAD‚¯P¡"ÿ ,R°¡rE†*2°d!‚qbƇD°È¢ÇA–’`I"®Ä˜°bˇ¢|yKB)kJDgK_Ê0# @M p ÕéTªU­^eŠõêV§ ¼~VlXc”‹Ö¬Y´ €•ª™—Y:~ I¤Š3}û~Ñ.܆4ú”ã‹#A+D‰²4yódA—5;(bÅ„…-ÊÐ!D‰-bÔØs1ɼ#?|'A—(cB8ڦʣBehî|S2É,YŠ<8Ó Q)WLvìy\ æ›=³8—øÛ¢”Ü+ r—ae¦òµL™~àÇÿâÒ¯$gy¥‘÷Õ¹?*;vË„–WÎ޳—€JN!ÑŠh¢Š.ÊH Õês ¼üÔã?º Àòô¬ÀÐB°´QsÐ$àdŽ=ã ¾‚ lî9ÚZ‰:¬Ã$‰ênÀ+À¯<œÌ;/8•&SÑ=—ãɹ• £q:”R*«¦¤zŠ+-·äÒʪ¼œj-1Ù"3­1Ù€ªÓŒ””‹@š©¤Zc€1Ä_X„ð> ƒ¢¥Ê0ü/³ ë´…@$MÁÓÜ(Ñ—š © ñ¢ =ãT8ØNL/ÅVDμ™sÑ–¢<¯ºŒrÔŽÇW}r¼ÿ!+Ò±<‘)µÞ%ª7½ð% s öo‹ #ØÊXÀ3jQ…\\#ÝXº"š!KkÚJöÀ„=0…ì{\“ÌÄIJüA A h`ƒ”Iò+2c)J§¸©7¼kœÛ"§’>H@”Ð O|¢®=„; ¡e× (1ØPŒl̼̓Ab}H`"š”ÁB(%lo=­^|nx¼©ÕHy;ì•­Tó<ݱw‹ÃŒÝV÷Láéx°Ãaòʸ¼lj›ˆóæ¢NÂ+†LI"TËW-„–²¥åNÉÿ&Êm"¯‰MÄéÌ ëœÓtÕ߬¹Nl: wBÉU<û5OÑžÕ›ˆJÂ}ŠzÉ‚€dÒù-œ4|:©)Q"|ÌK";ÙVFùÈ-‰¥Æ3¤Ñ ¤Œe—Dßjƒ¨Ì“^QKšéȦÀnxüÚ¹ @K á:©óÕÝ‚SFm¦9¼æÕx¨Mhe”Zß¼=?CS•³†5kDÑJQµ¶ó¢‡›y6ʸU.T†M‹¦ûvVuʪ¯õ!F‘ÄÌùÕ•¬x]¬^»¬Ç6o›? ì®âÚQ¼ÀqaãÒLIð1ÓÊ1µbd­a-ëPiæõX4­;!ûYÉÂÿó­ò$,CnTO#‚4Ÿ$5jFÈ33ÜÔfSáFɹ=¹Põ‘`i@†îaª(ê™:ðXÀe4xASZ&©:rd¦tXyLʵ”g¥£+Þh«Xãipi\y ØÝ7œÂ=hÄÕË{ýÒ? &‡þÅ1H lD”zPQþ–ÊǽÍPq•çêvÇFstðÅ.8̬cN&²áüŽu¿Äêïm÷êØ³uk@œˆÂ\ë°ÕÆŠ;Ä¥žJ¬W:ä E#5~æáá'§% “"‰Å˜UÏñQ]~L#ÚZx¾±!B.ˆ â¾«D—dÓ ö®Ò=-­¬ÿÒàîô¬gV¼lL€ú6‚ø9’âc@(¹÷\º´T¬/½qñb‡¼ÿòµÇîm{àÒ"ˆÃ2€‚;E9¹]Î3¼ágOü)Aƒ—™¯JŠ£ÒÍP¬NDp¨=~gh7Ú Ùu‰–½&@=Zyl”ÝÙèE2’&Üù]–ï8ueAÊ6µ®Tèì7s ÎN‘3Wè^°Â»{Þó382'À P¸$\–>õy¥½Õ}ß­=¢*GóÙ‰Åÿñ¤«ÉLŸÓ½]ƒT¾“:µœ¡à¾«¸¥Mé‰Ö|­7'°F{'×áBàau9Ðc QrS›³—þ«[»tÒ6a>?,4ÃÍ_™ãV‡p[»ùÛM3=Á_ûl¡-ô²ïøê6ÏúÚ·N*H9[ND(oD¸ez_ÑË¿d MçhϺVYxS¾¥‡7%âuþ ž1Žñ¤L©/(èÑGòO†%jzn)e«ß¹“=V7÷ÑóîÛ½³Áî>‰°QJkÐÌsðDØå‚íu/|ÓR#&ߌÙA‚‘¨R3†°‚O\¨â?c‹J¾‹+ŒÌ>_ÃÑGò=—üïJû&ß{Ðÿ]ÏXØëÖ³j§½h9ÚnAO¹„·b—O˜Å|¯0_¤&‹;Öƒ9I{½¢»;Ù‹¬ÃÉ9i“ ê ã‹>äk1 ;&r¾ CðC6Ô"²{¡Ž#@k½˜;@šKÀô»&:((ê‰0ôe+²2œ“3„´44@ö»A÷K»S7¸š¿Û«? ô6¨û¹ô£Áq³A647„«. t¸ ÿ”.ꊳI ¼¸Í ‚Γ Ѐ#0¯ð½3yª³øŠöb3À™Ä5UµÉaBrB'4¿ ª¢Ú£ýë£þS¼1ë ©Tİ›Á²rD¢ƒD@D·LS:¾ëº·³¿ŒÐ×;5ôÃg¬¨÷DMã:úûÁ2œÅ+,^óŸ&,£s²‰ª,ÜÆ>ô¯?üÆíxCƒª²Ø˜Ãð3.‘Ò§ä’ ¼,º[ÃÜÊÇhĹ r‰®‘DÇ‹<žÒĪ @‰Ë@¯È®È3Œ“†Kâ$¯8ÅTTEöB½ÔƒE°j&e<Èõ»GoD;†L:¶GC,Ǽ8Ç)ŠBA™>_ÿª>‹0Q¬å‹”æÃ°ƒÙ0#Z=4,@™ŠI…œI¤;©š¨ ƒ´‚¦Ü示G”J¬¾T›%V W3’nËF©cÆ¡›¹¯Ä;Ô;ä4¯»Æ¤,—ÒFõãÆ¨<;°ì‰ˆœª‰ôž‰¼ÈDÂĦ‹ гŽ|†ÎA³ø<—ù<“$½¨JÉÔsƒŒ4¨¬:|œÊÙkÀÚÐʼlD¶4;{ËÛÁu+D„;¤“óKF¹ãÊtF·TÀƒ7@MµŒ¶º+7h¤ÊÉR›H% ),)üšMzÔK{ìL™ôKøDs;Ü3ÇØDÆ–¤ÍzäL¯ìËÔ„¿Lœ¢È9³D ÿÌİh€ àÈèð2*Ð{K²õZ¯±( š 6q¼ª,h„5ÐEÐUÐeÐuЅЕР¥Ð µÐ ÅÐ ÕÐ åÐõÐÑÑ%Ñ•Ð[+ÏŠ<Ï LOH è€uL˜!pʬL°89‰¬ª–k:ü#Ë…Ò"R;$C0Ò%=Î`Ò#}“'m-)eˆ&ˆ%*ÅR#Õ‰ 8R#08‚£I1mŽ2 ÓæøÒ3+Ó+øÒ1ES0ý6Ó5mS8}Ó9¥SuÔ3…ÔHÿ=TJeÔBµÔJÍÔGEÔMmÔMåTPÅÓOUIíT=5$¦PUË«™ZQ…®K —I´Õ1@¨È ©` 3`©(Ö` Ö Öb5Ö8VdÖd=Öf]Vg}VeVhÖjV)(Vl¥VkåÖmµVoíÖmåÒ„qpWsE×t•Vhe×vu×w…×x•×y¥×zýV{Å×|Õ×}å×~õ×v½CÊUˆ P“!ÌKÌÄ„}Š[eX’X‚Í_¥ œ ªØ#‰·‹ÅØ"¤XôØØ‰ +éS“!Ž ªa(Þ\YýKÙº9Y˜å›Xœ™%¬%¬‘U‰PYÿå•_|Y#Yže¨ýÙ‘õY±ÓŠMZ”ÈŽ7a©£ÕIÕY_ÚPᜠ'k:)£UÚÒˆ–½Úª7ºa­•Z빎„±Ø1Ú· SÕ*`Ú¨ýZ¸Ûîà[‚؇…ØGrUW]цE\•ÙDÁ…8‰½[šÍÛ°#†ÁZ”uÛ¾]BÊ-Û•Ã ´Ü«±\«5Û¹í\¨…\§ÛÉýÛwô—#¼ Íí¹˜Å\×­Üô\ÔÕÛÉ­Ý[[Ý¿{#ܨ¯ÛåZÉ·ˆ`[ ½\“ÈJá•’Ü-Þ§µÙ­m^âe‘![¢•›—h„Ý/±Ýß­ˆúº^¹߈ÝèÿMÛÔ}Þõ€ÓÍÙé]ÎÑ x‘ÝïíŽð]÷ÅŒ¬”ÔÀe\ï)ÜWuÑÄ%`³X\^ PÇ}Ü÷Zê•ßdÞŽßH© –^ ÖÝùu¹ µß~2ßG+Yò½ß®žãE^Ñe]ÒÅßR^¯Å]¦à)³àôuÞêÕ`ŒíÝ&*_ñEÎñ]àí9~™áÏÍ`†ïMáâÔZZ—MÞ$a–—ßðá¦]†!¤ÅÛ°Û*†b–b!v޶Eaßaþõbáðßÿ`«àë*à8 ¦P“]µ ÖÙlMcŽâ%Îâ)©ß•0ƒ;˜ƒ&vâ2æc0öc5X¸ÎÞ>ÿÆâé8bý¥aN3(€4 ZÐdNÞãHVäI¦âx9ƒ;ˆ€ Û.ÀVåNe‘d¢ä²ä¯ÝÞ!~á ¶^6!þâ+©.¸G6dÊØÓC.[#`dcÖek"æWŽåÖb äg†ß"®`uaæ lÆàõÝfxƒk¸Û5fã6fg…•ãw69;vãFc¨`„B`KÀ¨bV6(¸ ÀXZ%„;8fÚçN€ƒ#UžfþàÀiŽ/H„6ØÝ‹gµÕf_&#ðä@ è!†7€¾[ PéˆVbRãâ5 J„Úu€2ÿ°ž^$ÈZ˜že%‚Šþhõµa#f ’æÞJF_"g‘&¦®Ú ÀèêQø‚XX>aˆH&Xiº-Õ1 :ƒ¬æþ (ƒ1øê£®á®`\Àh4êÉøUçÿÁlç’çw¦]-X<¾ / )Hp.ˆƒB_—ÊF…B°…›„)`ˆ> X•#>†vhÑÖ·i"HÐh ÖÛ°ØÞÝÚ.‚¦ž¶âHéI`”Vi–Y˦kL¾a‡™êv!\¸€›ÞEŒŽƒ@eÕæmümÁíì&a·žé£ÖFj»ÿ–jªÝ͵jÛönñQk³6T\Ðl½êˆÖ“Hk4hï Þn"àêø>n^Nn\k?ˆ„á t^ç-Ù)ÁlÄ,`'ðÆÆQ†u‹¬gÕÃY8È38ÀöÖ7@yƒOå,ЄØlˆõ6ìFí‡îï6˜ëGHKØ‚›èîǽñðΖ‚@ï‘PƒB ññýmì¾ ãò¨.ò‘fîšvìèfZ/ñ¹®qáè|í ò¤ç‚Ðíwìrð†ï(ÀèJHó÷p¦T­A è…†^ƒ0HhÇø[/KèýVë4— `èqp.gÒÿIoìUˆ\N˜Kà”&¸·’ UÃ¥ÄÃ5 CS™Ç†ÐT$`5É,ñtøq_âöÜæsî=Q°6àóçîi7H`è‚bçR@ñÖb_Z3(ö3hè%—(v3øæ,§Ñ68v*¨np3àR/xî`Ïv,èngïâftq? pWc¯jp— zç‹b7€sæçè‚s·ö¥åwyrEP…oÇ÷2EXkÁuÏ÷¸ øu×w,@¯÷jwè>f=@q X,øvm§w*ð·ø“X€bïw$ ÷L0w€>wGy‡YxOƒ~Gã‘ÿMe§ö~—T¨ö½~qpW÷½.úáð‚ Ž(Pyg¦ÚŠÇw8J÷.ù‹?yŠ?÷¡7ú®vôµ½ øzv8rpgö§ù”P\7—‚ý–b÷ùŠ…z38ÓdGÖ´GvPl‡ëøvvÅŽøŸ îžÏw¤õ‚†ÖõLï¿nðOWÏóô)Uè† ¨Õ1¯@cQ\R·UÈp6Vì<¾êZ¿^K>÷{&ŸÆ ëEòrlA_ìKˆƒ („2,  _ò$ol@§‰Bˆƒ<8 |Îí†8~„ˆqˆÍ~êÿF÷\ÿä§L—(Ø„˜kx(ò¢ÉÖYxØN5 €À1âS`ĉ€…ˆ 5IüyA£Í‡ lüTâ%4hÄyÃPE`"–ùæŠ)ÜL¢B„.8˜ ú™se¦Œž Àyc H32e@xѦ€Ä)9wÁâ 5Ñ¡´ggODÔÄÁ[‚ž¸"WR?‘¨ÈƒGÄ~X‘!…ÈTƒ04¬ Ö††„X‚®"ƒ“’Ki¼0ñaf–¤mú鵫šB~¦¦¬‘Ø«™ ~ýPø°P.1ª¢®KÃÒ†X”2˜ÂìÈÆ)ihÿ@„E±×¨X2H´;‚H…/>LÈniKW"®?¦°¤s&ˆ/†‰t"8ºû˜Ã}׬^&Û‰[4{eªjm I‹~¯ä ±qü`h`fIš½Ap3‘^„Ç —€T› ÃI!H6LñBB ˆRžM4À@‘ƒ^’ hDðA28ð‚áÔâ‹ê‘@DÈ4SšTçf@‘0’K.i$“N&ɤ”SRYe•PZÉ€–ZvÐÃ_±ƒ4lY¦™ üñ 0Ð 0lp¦œsšI@ Ù$’J`ÔH3ñ8SøÆêU×c$ˆ0Fm«L‡ÿ`˜Ê%\´óM‘ÂGOÝÑAYH`±I4eÓ)ªP†ê£>¸EE´ØÆR ²¡p·a] L$ò¦ DÜšBV0¸aC,IñE"38( ³À¹ÁEš•¶VàÉñ§Á}tÔÐ\tkjT¼4 2xC 0|J˜$p½dƒ >@kÃÂÑ TTÐl¿`üÛÕfo`²/ÝÆñ^\tÄm¯;P»¬v«•mRÈ–Xû¸!€ ýð1Cæv\ð«3ÅÌ„Å)¸à×°#± ÅÊ…§gJ…!dR3ÆÔù$$ ˜ø ›n„ôT&o¾ ÿ~h|iÕûv«â>ÌKÄ®GÔ@Õ×ó7ŧ)ˆ*ƒƒ2Q2ÁŸ®A ͉@ó"ØPXÁiÛNQw¬c,K„&…ˆ0¯ –§XTY¨u =Áå• Ü‹¨Š˜Ú.³ÀõK7±º4€ÖŒ `lá`Èì&g¢qwªÅU`áoFãO1ðŽC–1É·ç~EÀ¦F-µÄÒF PÁL¡oö¹ C^¹'•Pòi¥ûïO‰¥ûevæ—÷«‚[¦g›ÀùMû –òÔ¾)ù =<¢à°.×ÝGçCbÇ/Ü*[ÁB$*=PÍ÷ê‚ްÿ$00nYŽb‡T%ÅUà„è‚4ì…“iƒˆ -Tý i”À¡lø/sY®ˆ>`"Á,ÔÅ! ÝÁœh„¡mÌ)0ÆE­â¬íyËC€ ,l;Z3Ú ˜H„zÝËf£Å€‰ÆkœRF ¸!+¸BÑF³9µ àFIÜ(¡1¦Ñ h@9B ZГ®ÅAYÀM#-4œ£œaC-rDbàƒ!ô„Bq ‘ ÂD€”Cª¼@‚EàB €Ôд&:ÑP˜*(wCæÀ’ÛÄ+·˜€˜i%‚p¡ÂÔ´8@À uä¬KÅÿ!/R¸T¯Þpþ8!I`Ø,eBM±:ñ‚íl¤+jAÌä* É+®WiЃµÐàÄ]áŠX‹ ú–BN&““ÖRQîyÏÜÛ(G¹×£™` žxåÌ@@à;¹€([RÈ&uyô¢Öé‡{ÙÄWRH€ °œ/ÎD@ör„ À8m2‘㤰¨³Y€°¦ [ð$j>ùhVr")}Q‚YÉ*¿²ªd€4ìw¿/=£L“ØÔO€4 •̤Ïuç1>¢¶ (#˜ p%ä°¡h šÔ–»dЄxÎóVÿ~ˆØÆR°ð$óf ƒ p`†  §:j¸I&z¶"0’7ë´Ü®R°Ã,¤ kú¤†g-lùcŽËÊg«SÓ¯¡J¨Nì‘”¸€ÙÈ+p´[ <0ZÏÞ•ìITõ¬Ö‹ ¸(„@ÍÐ…$ Vcž“I<…¡¢´ËKZÍ뎆EÄî…PÆP- ËËz±JÅ\f:Ù--ÑÈ( œ“ Æ Þ¡1Ôp Qž´à2ß+ b¿{økÞDV'jâN¨›ƒþv†˜a#ƒ…(§:R1}(aº`½%†žL`Ñm³P…âÈà±»¦ê ÀÅA·1;ÿ!.¼H„ËvJ'{ÞD-‡¹Hs‚›ÑªÂõ§ ®“ žô¯ ÀÐñ„Ì=ù0*úÕ…äf0â‡CžâгafÔ·d"Ð& À ÜÍÒÌâÎoœêhAS`Ä# OÔ¢ÎÕ}NâûÐjêõºLm}ë[É4À¼@˜„’W½îïNNµ”üªi´· 6I/|Êw¬"lXq:K1WªC|e¢·4X¡ƒcxžL¦­±N„ÖEˆÂF3‘æƒbÉ€éÉTûáVëƒ?SË”kC^¾üëó¥ÖÓvÛI¨ fž!_,ÀÆ–‰ÆùF!ÁÜbg;¢Àj‚ýsꑬUBkÌò =ÂXR?|`Q„öZÿŒ”cQæã´èõ²ù°Z‰×O’R©Om}$ªv+«ÅÀN@¬Žš´´V\Ë)x"uZ‘ä×0µ+b«¶Àñ&f"ˆœ >È€hW8Ù:!\Õ¤tG"p[œÎÄ—€ï¹HÅ paàìC¼¬£àÀuEÖ?!QOàÛHÜJÚèSCù–¾iÝëYˆVÁMÖ¤€QpëœMœfL i¸…’ö0þ•əľmˆ§…P0È‹D SìMÌ=R&¬Aop]’eB dZŒ–VpÅG ‹™RMÌÌ$ /a4 ÜðJÿCH8 ÍK@sÜJÖQQWØ×œGqHE„D•PÝ@¨°Á±àç°üQçÈݰT¾ÀžŠ0μ)B é„¿™@O„‡SDB/˜Ë^"=NätKÇ^óÕœóZ`Ñ`Áqí‹ÜÒé]Ní+-†y– 0 Ô@¬IèÄ9mÑåáCh›œuVÜ z :yñmhÂ¥}¡Û‰SVÛ¦õ‘_]ßXéÉôµ_⩊%Ù±øÀÙdN9j²Ñ°˜fdò-;÷z/ÌÞF×pÁ-›+CÈá‘ ÂEwC¨A ŒîM”†Õ HáMŽÒâ#CœË!²Ì]ûœ*QAÍöl„qŽÄlëʬ€xngW2˜Hÿ"w #oÁUbÁ¾º' … ƒeW <6¬•Ä0“°pY¹ð’È t@l,úÑš $›É ¤ô9h™Ÿ%0B 3üaWhÂuoÂõå#à@àÒa@€ž! Èoô¾A lT54µ¦¹1Dd@œ±T-JÿU;oÂv BéáÀ Pbã€óªÁS3ט€dÇnbîÈ6Ëq S/GW€mw^ßÁÑ5ÿ‹õõpƒ”ÄmUï5 @ ÀAkOö[·DÀ&vQÿ“^ôu.õD"Íö'6®uei\jSÀo–í^HÁWç×k#wTàõhãZA¼œb§££I7u ”Ž€VÛ3hGE"Ùö0«Ä-vu–¿X AŒfuvßusµò…Ñr•e_öTu|@ÁËîm8Šœ&. /bSµy³Ä¸këËõ˜\øy¨wPÁ‘ý¶ƒW5fþ@„åö-Ê‘†§&}žZK/ÉK“ULç§“÷'O(Xù–Àç€J»ŸÄ,dH6C õ˜9q?wÕýí\Ôª™^ÿÍaRsBODpzœ9WÙW­9ÛºùfpO$u¥âyÔè¹µùŸ¼ùŸË9 6uÚe<Ȇ›ÙG5Á†kTGaºG…ËÊ:zW5H£—ÏŸ|ú›¡3„F-DV¸˜ºWìù¡ûD¢ÇùfÌù…›DöˆnË:Þ¢OPhcÁB¨£fì·ó'„Á˜S—ª?qnF¡³¹£{…¬#CÔúÊ ªc%z»³/$æ!™®7©³ú³á«K;|Þ¯ƒú¬dzîL0ùJW •”Ôcß™œ_–o –û»–—,B†,¹;»W»¡§;µúb0ºÂ“0Ë>ú¨s… —ºÿ¹»:Ã÷¹èͺµGüù´{Åûò.'ç%'ŸÙa Þ”ù™;¸Ëç§©<|^ª‡:¾+sP蜑MiŒÿ#ƒø,ÖŽ>Ä+QVRµJñxm•¨8Ÿæ¿&bT¯näëçîºFô0Ê‹ê;ûÔé3ëÍí’ÙË$N.³6N^Ö“0Õ¬™8û§›‰´rb©e)ö¶1¢&<¤mlÛÊÍZRµ¤l­BtÚ˜ê ]ÖhÜ‘|êœÑ{©ÂZ‚Ápn¨ÕURVtƒ»Ýí†0“©#2<Á)xA ¼Jƒ<3šÒ k5‰RÖoió}5in$a6[†¡–·£ü¬!5¢É×Þ6¦­EÉ1Èüö‘£$ÃÇžÝ&Ø 0p?ã`—BX¿ãK­ßÉ`oÓ¤­,,¦XGQ¨Åõ¢s%sÿCÕO “ö¹“”0‚Û‰É_ø‘Ñ©Ÿ¤6ŠÒäMtœmq}W6cÜfv®Òµ..‹zT]Öè)¯Ð†w»k È*ÊÝ^Ò’ìµ@Y Pƒ¨Á„BM$÷ùÄ›Q¿£‹Ü8*¼Ç§æD€€Ö`ƹÛïÈ¡;…öî,H„ñ€J¼KÙ÷ †-‹ÿ1̨á qm]0£yŒÿ:)ôOºËáïËÇFò ¢íêA$3²D V¨ý§l/…Æ×Ý£¬g-ìŸ*Ò3v"¹;ê!ü¼gž¶$=ñ%üÞõ$‘àâE?×ÐUûÙ—óõüËO_õâ÷=¨#}ÖÎæöº?=á“Oþk^'f';OìïtëFG àÀÔ©î»0*6 ¾¬)¶4€¼Ànç« \Ì®X`Р…Ppâ"ðÈ$a{ãù´ü:fAP!  |¡¼ŒPóªo¸¸¯òÌ/öÐoþb°ùÆâ&TONÖBýˆ€$ Âa"¡­ï+÷6äüN ¸¨ÿ¯ôlðCž «Àû¶ )D§0tPC¢ý$âýz 7F »°û˜ð 7€Ëø&ˆùšðUÈ0 §…$öp ûð"Üð · óð=æâkLðûœðÿcøZ¢ ½0õä iëC‘Ù@îÿô¯é°+Ú„bÛ¶‹ê‚`  èÀ) À™j`½ÎÜÐm+¶¢1Àf)©T`÷H° CBt@ü ¢¶° ÌP@ñhoi0ôVP>›Ñuƒ3¢ 8a· ­ÑùÎçbö`ãoýŽ#çì $Ñûxá ( û à DÀ&€ÍqüБIBV ÿ‘ñPÏ$¥ÉHV¼1ã3ÖbIþQQ ‘gP"cÃðàOwÐû! âÙï = £P CòG’$¿PùN²#+Rì³p"+"QÉA2² [RSrù‚Ãoòo'‚rڔ⇪+ž‚r¨ÎPñ)6àÈ+ª4€½Ü-«fñqfÉYì€ß(út Û` ³@ ’` Ð €` 04âž` `f¯ °~ !«žà"Á/à ˆ R@/ej€-9!.7à ,¡w-ïÒŠ€QÈ h/W€Q$3N`/#ÿ-%` 2ö~@.7 Z $  &s ”Ô²2’#P@jÀ2{‘BÀ³5Y2Eò%q0'MÒ9Q:ËC7>„,;?¤,>2›“yÒ:ë$©Ó%“Lg°Ñ ´ñ/ Ó#)2"¡„&#Ï 1ïó"õñ+Å1 ûÓnb$±>/ð“K"uB‚b(;Ñ(‚ÿÌE»°Mš».–`& )&làZq ¢j't'äËìЪã‚ º F» Ž0`3½€‚ñ€² |4GaŒA€t65¢0I‘ÿPGWÀBà0à“EAR@ ú@ ÂAn–$€QJ  ˆ@6@J‘ ~€à€ΔQ<àÄ”† ½0KaLƒñvQ ŠÔ "“I ×TôPÀK÷PÁ6àRÔ-’@Ÿ#8@ÒST8tðó±TùSAýóü.Ã<Å“ûÈó²:µU1 T[â2ܳÁ³Å=aN/®ñSÎжÔ+â@™XÕ!‡µÖÖÓ.dU>i5=ׇ¸èoE=‘BE1} *– ºAp1*¼n*Õõš"`À™h`CÑíì&”ÍjéEaTdÁ¦ÿ´_§”VÀ†A ì@6Àˆt`ï@ A"!@NÀ ¢1¢”ŠÀ ÄR Y1v› K'áŒpÊQé¢ ´”ôÔnÀv¨T–PáMqÀ’X 9H=¯Yû`bÑ` úÀGýÀ¢´8À:À~ Sà0Á¾´AÁR 29•°Y÷ÑZ¡Õe´Ul72XÇ[mõSD ²Ó;1>õ9Ù–XÝö`ªUm¯5Z—K‚VfoŸµ'uælWF!1íWÇ–oËÖT W7m·Vñp1 mùÐnýöqÕ&!ü¦+$ô' Î[‘Jƒ¦ÿ‚I^B-1@-ÍÛ&À T÷«j©ï͸_Í‘øÕ_ûuÆ@Æae`8- ˆTÊò´ "áv BSþ 5V†` P ¨¶³tKKÖR+Už`ÌòIiAk»q&Ö$öš–&vp6¤÷ t lC ÀG7€Ž@¼·jU död[ö 2A„טàTaµlÓ7_—äVgòUSõòRYMÕUuÕ7þ3Yï°†sUCuü”Y]Øaø‡Y'évq'÷nk­>:—…IÿNp5×ló¶ PóÁ2Aç øòZlÒÕèBPrö¼ïs¹ÕƒD—t¿u'®bv¯Òq¸õgé^¡ø6Àð8Ç2NÀNÛ !â~ÙÚôœzÃ!µ 83–ÀÌÈÊÔB6|I6k=¸rt œ”#P8ãw‚A´€²€FZ øU‘)a9ÀfÉa1‰C2A‘-QƒÍ’ ¡<€ód[WÁkCÔ-Oñxè2bTs ²:™øoØZ¶n»óà†øS}xW8¸Y;‹”‡R#yÕ#¾S:›SŒ{ÀÊYn¡c»8ftÿX&‰ø†‰@žçYÑöy?_ØŸÛÙY¨y'û–Š-÷‰ûè‹)ÅŒÏ]ŠR3ˆŸÂêÞø!gEj º\t < 9!jô hô ö¸òÀc i±@´€JAb€%–ž÷aWà€Zw¯’9¡º—’Áwd‰1k·   n`Rûw}‹VÞ×MOYèwZ øÕ€úæÀA ƒ¯ööšÀ Þ ­Ûz¬{Ù{"¨×|Ô~ºÒ ]° 8ÏT ÚšÀÞšSX9¡˜AW"µxauœWæ›Ou!bøˆfnK2>—p³µŠ/÷/ò3‹ÕÿyAų'[%)Q‰§ØqAÛ¡CŠ­ys_[›û¨õô³"+›%{1\X¢'úÉF·p¼u£;*èuEŠÂH0 wÚGVO›à`UÖDaHsš vúìØÀ`kÔ/a  pY(΀©­|µ”Ìà öd•7=”³¦rVƒ ™¥-€‚áŽQY•¹º€1ÆZ Xóàµ6;ìÔ@Qái¯š¥$]¼Æ‹Ü\µÏQÉg›¡³Ùɇ‰7Ûs¯K(m¸¿Å¢«ítû«Èü'Œ,x±·£tÀþ˜%–¶Î'Vy·@»uÚ È4SÜ œ`½ÃAðƒ«Äàa›y,OGóxG± nà‘½à¬óØ*« |•góÄ”Ð9 Êú¬c9ÝRÝ0x¬ÕÀÓÀ6©ûzÄ·Ö M±½n}ÑM´ú<×–¶Ú¶¿œé$F qMO¶…•Ë3›Ù·£kb’ ûùÅ}ÈÈ)ã%«ñŠõ£ÇMÆÁ=sVFU·]·§œ·c<Ü×.êÙ›=‚Ú“ÿÝÚW!€û[òÏÌÑœÚÀ£Õ|Í'+Ïø+¬!ΩQS `ó x€½@½  ÌÒîR-Û 3)SžÖu œãÙÔÕÒÁ f@ . ã7`â3ý€ ¹ló6  B¼¾ÀbÀ r³ úæ³×qàèc° BÀu§ÀØuÓ \·8 ç»q‰7bú î\óæÑu på<§ÌÈÑÝÊåÀ<ÌY{Ë£„Ü )ÈiW}ÜÆÑ^ÝÕ>£ü±ÏýÛï>m€0 Úùb5r3×í™|Ù½<ÛÑ™U ÚÛÚ‰ñ>ðUCÚµ½þ’BB>à…ªÿ¤â¥ ôáÿ8tÀ*pèØg5(`NÅÖ ‡z䨡ð @!€†^óTŸÅQœ¬W¿ì àõG¥÷õÉÖ³ÛVñkãɃ°ñ…œîû>ò3{òY0ÊÉð«¹Ú]ÛùE›ñ£FÇí™!Zø!¿·Óžòaý©üìûĤîÿýý>þ?û+ d(£ $BE†”ƒX°$”AÅ .^ ‡F?~ )²¤É“(OfÉ ¥Ë—^ÊœIó%š8iz¼¸ó¤† ©P9X"B)CyH‘J¥±\šèà # ææ† +œ†5zéÔ¥ ‹ÿ¦=ËÐ!D‰:”!¡T…W .”qÅ A"}ùˆEJU¢•VmÈ4âD¹†ëêÅ;ù``¢çíK¤ðá¦O?ßhx¯[¬t¥žØ÷¡¦ ¤rEòÁ¤ƒ…†^8™tÕ‚WÛj]M°õRØÀ Ò¶Mqa`ÝP{S5<«jµ–ݾÎ>wvmŸWC=µ4ÁÓ¯ÿå«yw†ß;;ž7Ýò¿Ñ[¼Þøvöï-Þ|ô9Ý} ™gÕBû—kîfF#ñtI%a˜Ò†ª@N1å$¢L7(bG`Fsô•TBL1„Y½8PŒbù¥¨AÆœ©•TŒÿ½õXr’!(P^r‡›¦ Qõí5ÚtçU—¬µÇlð1ÞXé8ƒn¥vä\I^Éä]Nþ¥Ù`Mé—™l©f\H¦åfe>9'gžÙ7žD¦éŸlú9Õ›{]&gAQÖùŒV¼–…Z9"TeTøQ‡æpرá—ÊÅ¥"º˜¢pÝÖ§]*iBƒJy鈭•hc±%Ä+m¤QO&iXa‡Ì6û!N!š(b‰ÒâdaJ? ÕT¯C¾ ìš‘9JY“N*¡vÂ(c‹eÙˆÖlç%v&jß2.­ãÂY.®”ÒY¨i¼e y æ§%©ýy ˜Ê—™XÿÍØP»gá8Oñön¿}*‚Àª^—§.œª˜¬þÕ©¯Þiï}ø.i럫«¡w<°}W‚¬ß–šzªÞ¡\3v/ºŠf½²63`3—Ys¥…VBµaQG\;ïEì²×¦¤¬Fc;kö³5Q[-Nj¯ýŠ®Ú=,2—Å)ÛÉ­2×»Yj–wí_„|;ÌåßTv jÁ¢¢†0ÉC›\tß‹'”ôÜûyzx?XùÞ—+¾ãB*M¯ËMß+¤yK ¥¿éæ¬sà{N¸ä#ç]2éab~ºæñÞæøÇvóºÐÿßðª~Ï­™J±©rÜrÎóà ÿ*o¸—_“-R±Ì– ÒÙf»­~Km¯Ï@Ø>i/8仃þýïÉ•}æO/îXêžýJu8¢Ït“‘ÿ¸µ£Õí©u0{]ÔÕ/tí -r)“¼ò+pEPIP#×­¦F» >$ƒÆÃò>× ê-Üßðú'¤Òüo…õkaÂð UÝ&eÒ«a™<BŸ¬w¢k Ÿ÷ÃèÑÐ/6Ô Ë–Æ:a…+|ÆBŸ/„ó¡&ÑrŸMÄè¸a (Ûºa“7ÀŽn‰>lŽ(Ä' ©maš?ø'ÒlvÄ…Ô)™E)ë ç•Ç*B†µò£ìre)Ažj¬ÿ æB2,ŽcË";«ÑkZÉ$÷Bæ½N¾±‡Fã¡XÊErPlS$õ5B@Þ `ƒô‹\ˆ¨ÉrÒJ„%°x¾-:ó™ !£´Ú·>øùÄ–¿rä¬$(I Ú¬’À¼¤0ï´Ál>pºÌW¤þHÉÇvžZêyÎ\ŠKfÝ4ÕjÌx>æxkÜää|÷ÊOÆr†³$哬Vȉըb IŠT0¦± †œStࢠ˜N|ò’i„)‹×-*Ö39V  Iñ¨§¢óž!üè$+øËwö³iQÉo˜Â1O´˜Ìô"4Ÿi>ŽHsšG}Ÿã§Jú P‡”K¦Aÿ…—ÀÍ•¥–B‘˜‹ /EJ„˜«üÙ@“ˆ8ý5Q–VËB‚Í–ÔiÜ”©7÷i¶Œs"_ýiX¸¼Z.†gEhZ£8†%/RˆHah3¤©Ü‘‘- –=Ÿ»8ñë›î|’8ý)–T£’Ý&+»/2œvåìÕRH·°u¨*ª“j"j®#Ⱥf[MêÒÉÆu3Å,?7‹ÓÕÞ®µNee£ZVÀÊ­$%, ˜Me!(tzì-µ ×ÑNPŸ%´dj‹{JÄ€5¹bE"óšËÄç 6ºX=ìuµJ1DFôbqHõ®¯ÔQTc<½èõŠ^¾Þ¯ ‰“aUá»ÿÖ¬^áºÿÝ)b˜T&êiŠSÙ«Ë<#ëÁº¼vC²…íÙ@ÛÚ’Y¹ýH¶‚Òˆ»øÅ0ޱŒgLãÛøÆ8αŽwÌãûøÇ@²o\‡!׸ÈFN²’—Ìä%#¹ÉP޲’Aóa—¯‹Í*±‰ÅhÍ’È­¡[µoW'š¦ wðe)pç^Ô¢PXEÌkö‹aÿvF§ 0…­baëÕùN} b‹” Ùj‰H¡;.3ãR´}”+xOkSâÂÙ¸ÀtSu÷Ôc2×€í %Òü—>ów]€®S„óUh"‘b^f$nQ€|Œ]@¬Õ90g`b¨ÖUkØ…kƒ‡{!wJY`]TsX`˜&€†±„¨^~E:i؇¶|êÔ|Cç]Ð,€ˆóI‹h¾´€˜§ðˆp:Báœø†Eˆ37U57jÈ–Ôåxw!vò£‡sP‡q‡’(y”èQi÷0fðHÀs3Hw/eƒ ÈÛ…Òã÷w#…"ñ\x@€Œ00Fñ_àEÀ µ¨|ÿ÷² GàFW#¸W…ã@`dèYJ¡0@ i8¡˜sð†– Bñ\5uï7€òØ9I Ã·X†¶Çרw‹€nÀ<òg‹I¢?+óYׇuOc5ð5`ØU9 ‘Èù[Œhyø§.úv™Öy(EJ ” ‘gNÞèZR|¡ 0`yðŒIƒu'Œ’Æ/¡…bŒÐ”Œ.q…kx(±" å˜04@GÀqÀqYUºv`¢8ˆ€ŽâøU)Ç~nÑî˜+°“2@)CHðˆ‡·æ9Br v9ÛS`ÿ…‡z¨r–m5*Yƒ,i‰š‘©‚¸©T‘‹òS­!{ýE{‰u=`ˆ @”°AŽ'™’™”‘YZ—˜ƒ0¹ƒ2 w4YuDq“9ùšÁ›[WA NP”™±tÄ—µò"‚X‚×±}mèS6260ÀR9-Ué”*¦1EÑ—i`8àÚüñ)f‰–¾iOlùž¢—°@âS¸ã—|Ù/‰¥Ÿ€yX‚©+ ò©ˆ¸ÈˆŒÉliéœ2çI©ÙX[àxd©HÚE$–É‚DP/Ж×H`Eh`ØÑð` šH' ®é‚zFÿšÀ šxÖ=Åg„–‘™Çe†¦:^ðŒ “¬åŽ9™4Í r&Xˆp$B™ÆBšÙiö“²ɲß•)±#B•oãáŒ{Q–ˆåº»… *Qp¸ §f  ЉQˆµVkñÙ)^(¨²h§x ˜Û&|ºŽ  †µ††ú¢úɧf`‘þi]p§t f*qÐÖE© ‹D@‹ê•ú…½²rp¨¶)ià§›BojÀª±«­Ú§zZ O¡ªx¬{Z†¬Ü’œ >0¥Lò‰}Ú©9²¨¥Z¡¶V­ÿ‚戎š…¨¨H ­Tà«q:®½b¨ÆZШg’“ ¢ÁÒš®*Özèúî&h³cÐù P‡ï*Ыsú««Úk‡Y «¼J‰*ÌjQ E €šk}À˜,€…Ä›@ªÌ–`½X†D`^°²ÇE|ú‡`<@«ð¢»Y©Q*­C¤pؤ¥hÅ8qÜ—E"qÑ¥%¦a*-Oˆ~b¹‘2PkŠ—U«J0à•–°ƺµ1à•5à7dе0€ëHš#m` ¡ÓHdàµ&@œp hpIPÿk€ôi ÷Y\Ûµq°V ~·0q`š™jð^»Ÿf_ ¡º)jp jûµšæ#'àIà•~@’áº^ùš¶&ðc ±Koê#yœÐd` z¡0¶4éyá#dë÷Ip _Ë»4m¬¨ð]{–q˜p¸)À0 4@¬oPÛë»$©\»½q€¡d0¼œàz»½ÒÈÆi¼CСPï{æê¼¶ë( lP»çI 0+x’ëû¹±¾sÛ p¼ 1ð6p¼·».ð¿ÿ(ðºk»‹ Š; ðiKÀdè…ÀF*Âk®2€‚ûÚ 3€ˆ!½Ü8üº6`ÃC0±2À›&€ºÛ‹¹ˆÑ¸4ð»hÁ`ìÒ¸ŸÚ¾Ð)iNo€g¿1€4P>[ªH-Ȳó3¢‰9ÅX[ZL…âç´3!¦ïC¦a¦ŽeQpœù—þø¦îx>¾4PxÉS ìHà |/‘Ãë¶áÈV&‰žÕKn0’—0) É|éÉ\¹Hª“R¬˜p5À—ôèdûË>ð¼™Ê™´ÌÀ0º›A]psЉùˆš¾,›¬­ÿ— )à•4‘8 ­PËÌ•-œ4ž ÞìtŽ$ù¦Œà`p&Êc žW Ì]›Í ¤ÌµL+|Ÿg GÀÀÝŒÉÏK!À•];ÅPL ð¹õ1˵\"ÌrG0 *€¨ÐË•kœœÇèY0‘ÇŒ1æKË2Í5@ qÙøÏ6 ÊC­Ó¨ù ‘ÄÌ•m2 žG  uزÐν¿ÌÍ»ñ™PÔ^ÉlEím9̵‘~ 0ºqÀTà}íº½Ñ4ð¼F°Ð6 Ó/`Ó .m¹¦z‡7iÿëLuý^à ålž9ÐS@É©Å9ùHÌ5ðÅÖx×SÉÌ\ÉßÌ>P ªk¸K³Fšª]}«©j¤Y´G›´`3…\È‚ÈO{"Œ ެ̾Ä?ºíÙHA¿¸y ŨP"€– `Ófð] ¨OÐØRð¶·á” À£Û˜t:Ì_Á ƒ­*`$;@_è^‰Ì8°‹?m þ ^¹ÄJOÊÐÛœ ÚÍÍܽÍyÞŒ “À¨0¶8 Úq`ÅCaØLácp»ð|óœÔ' êé¢Ý–ÿ ‹jzðË–@†jÂ<Ó"À ~ÉU\ôH f€Ñë-ÑqÞuxÙÏ Ù‘·[½'½RÙ>ΠÌ<X@Êí¼ßà•|¼À™5ðÆwËEÝýóK.ÊD ' aÎØÐ çUðÔ>’Ã<å:|Vð€À5`×ËGê­)€ ?a—@ÓºÐ)@›‘5`Ã'¡ÓiPã6ÐãÃÌt:ÎSÐãz@Ù0o„ÞÞûmêŒËÛèiÜn=”y Ý{ˆ pŸ}PÚèr0ÞaæANŸ^yÇìÿ+'zéPœÇHÛâîI«Û"q¼ÝÛ8Á ÌX¦êqžëÍKŒ—À¿EQÆ{V}ÉXž]€“¾ñÈ\}û·”iÓô¨ iÐ#‘]© `æ¯-pßÖ¥S0oÑkžëŽ(ÐÎyð‡¹~ë™Î3.‡Ì^a€«> ÜT°Í'^Ï5À¦ð4‹éKšþ­f$–ˆ@æÐÚãp€š&ßõÈ;­zñ/ðÒMÀäEð­X •‰@½;ålŽ|(± ‰°ñGpá2p”=‘šÐâï=àÿnó,@Ëô:ž¾Ÿ]¯ªÙõIïç+Û›¹ð±t†NüK$Àè%+ÀÍ €éDpÉ•@^@¿<­i¢^º¼Ðõm¹Ð(IÛ=ª †8 óýNƒïDàê<œ0Ë¡Š²³lð" ‘’MìRpö¨¹²«Ð´<rºç€K;-²Rг ʤ¤¡úîâÞLãÎ!ä~6çŽî4±îe ž{áð¨ÜûCQTà¦Eú4Sò!XÁŽ[ Ð8’G*YˆÈ â#Fž€™HeÓ?D Nœ¨¤Ì˜Ž>Z’$£ÂŒ’аQ„%¢(E˜(Cÿ†<± ‚Yˆ CÕèLCPF@ ‰¨ÁD)M–S¦À€¡a-W²Pñù–‰ }ÌyH„¨#'®¹4Å)¨ Ð#‰ 7>¸z=2¦EOŠ=ÙhCd.*;\ü„‘aÇG)T.‰ˆÓó‚a³f’"N*NËrº¤¬Œ±ÊÐhzæËD8u‚sdH”*uk lI4YŸ©Ñúäå æÌ#I‰˜ùÂä˜Hf¹” 4Ž9W(þàKDSŒ'C¶ì¤Á‰tªVǶwÂ'Ëô)`¼€A3áÂ#“A/:(Ù1’ƒ‚ˆ¬†48 3$°hB:|ÐN† ÿ#+¨¸¢ ´ÎúaŠ8¶‹@[C@RÈL†3.ʈ °tcÄ 0"ІšK†·R0!5Tàðaˆ¼êŠ# ÇdŒî»Í„¹VÄ )¬Èi§‘Pqƒ‰òÓà ¦°Á¸!{šò**RÁ‡7R†#¦ # áà‡¸¢ ,üëIq¨K¼²(K$}B‹K,¥HŠHIÒT$0•aKŠ:òIŠO§ RUuUV[uõÕ`]5ÖVàÕUozõõW`ƒvX†5VXTOÅ5U3’©-‰(ò“)RðëYŸH¢( Ë0[(… ‰¨à ü0ˆ)|ÿ@M5d£ƒ®p\“Bzv"/¾°!3N2a #.ùê‹Lᡤ ÎÂëKÔ¼`ä«ãÁÂø®+–1ó¸¢bî¼Óo6ÓÄ#ZMIp#B¢¥Î‡"Ö«ë.":q@‘¾X´Áýà%ŽA‚Ðrt±Æ;ˆÍn3ÛŒ#š¸ 4(Åû!þ š ˆšH‚‹8Dæj#·å˜q á·*ÈŹ+†ÉrK.EL,I­R(CMé¨P:1C¤3Ä>B„Ø"âÄM$hN¼xÁéd“ M’€"©>Êð†œi¨!"LF™,UÙCÒP¥tcB¼‚LR@dð)j¨ðÂ?Gÿ—A AÌôΈȋ&Æ£":ü‹7 ¦ALDx- è¾"!B"¥x+.ñxQ’É&ìIuÝ Ò<ËL°žˆFª ‰aˆ¨À˜ ûÊçàM!¡HlJ†Xh ë"Bò"™a1gC®P9ÆaÏp‹Zñ‘h5h"%ºT¨z‚)ª} -âÉÖDDæ;O¹Ï ©º•ªh%+W½2ta —eC.‹UÇâa}(¬b KY:Ü›=˜š²OxQJL¶C„¢]Àrö™ˆbàs]€SX(’šBÅ! M€ÀF:R/‘ q"U8ÑæÜPƒÈ 4)Âÿ¼@†šÜ„ag‘üãTQ\ôâRG¨áS©ÊUB€#ëaï žr¢¦¤D„ 1`™xÐHTDu¦;É<¸A õd\6à_Ñ4#0 ©Œ=ºßžBÅQc¡ž"I„ÌÍk¸X'pà›4¡;`ø ËbJ#α&HˆÜä°·°‡ª'Jð[ZÂm!r’i¦ ×8L¤ xAÅâxp…Èi“djÉå€ð„I\+5n: ,è9[Œ ÂB.°‘ MÅCÈ” ¹¢6n¨C¡AÁÄX¼ aœMn8q I”o|œKìËËùùªtÿ†ô§,vK—Î.”B WóÃvI–ÔˆÇw2@—UAÊÀwHŽ›¬¤ œe©Ã&/ã˜ÄY.\C’û>•˜+l 1ÎÊ`ƒJER™µS "‹XIÎpˆ:t! SEûæðUzÕë«xE¬ö0ˆV²æÚª½=ꉚB…pšæD ’ÄEƒàÔ¨â ÒrqX@‰€Ô‰´ôyŸTcWcÁ¨-+/¨P¡l‚“ ìSJH'j&Ô)ô ÑyH|2€Ä¨2”*ê”ÂÌg!hš•ƒ•ÍRÌ×E¼ Sê "iP‚©¥Ñ%JHC•d°˜„T`c\;]y4²ÿ(!?¢é,8чŒ]¡]èÈè¼pQ /µÌÄšdƒ!$]êZÛ–2#ÔS6!\¨_úàΰ¢¢œãœ ¼¥6.2œšèe*`†Kdˆ>q@Uæp–NÄÀ`2pØuNì“õ`A‹[ÑBL‰8Ê` 06] Tp#$á:‘0‚~+€%T'H,b¤I!æ42 @ã‹:À(4g(o½˜%O$It PÆã³T„\#.)õŒ‹)n"(„ó¤ Ëœ`=–Ú1lQ²"#L™{(²óê¤ãP-ÈÎU§ <âL’( Q8Ë„܆+8%i•&ª³Uÿˆ¢{¶)Nk0Õª6µ½jWSáÕ¦¢«ñz×YŰ¯­Úõ®ÀÂ[Ø<¬5š…èa¡o`B€ .X" ²~T«'˲… >8 çÅ‘EŠHDVp‡@Á$G0÷ ¸m‚ ~@³jBü§4|JÛ—)@mà‡\aŽÏÀ÷m‚ ™1â¹À»M`†Ð ÞÚ$ò/&À`ôM·P[Ý $)ÂHf¸ãÀd,„˜ÞD@E‰'!îÓôÍŽœ“#H[™9}«Y¦â!Ïgp—Æ yÁ"`†}âvÐÆtL%„@â˜ÿ&Òšep“RÜÒt€ÁÃßp=×»#¤ÄŸfp¸åŒÈ€·Á‡bI=eŽT¡Ä a ˜ ‚)°¹á”8±²¸‚Q%çXC îp/€;GrØjÀìkPÏä±ú6„‚k~s¨|„ÊiÉûÏ$Ë3 ~%|Ûzûæ9ι1ç-Œ€¶òPµ3‹#ˆA6§@"숵+‹>;@Ä‚¸*6[³ÿ+¹ª_Ë\±¡6ìÀ^)¶f¡¶‡ ¨˜8A냵™‘k;Yó€ÎCÁˆ‰Àà?Њ)@ ˆ›wC·•S;ç*7”«œ#ÈAxa½5ˆ„=Z“Ø $ƒ¶¸)žë)ÉCÁ#ð58 Ë; ¾Ó ‰ <$@ø‚ÀÁ|C "ô‰Np®|ª4“ÁÃÀ9ó„Ö1C3£A‚º¹Ð+ÔŠ:Ã=–cƒ2CAã¼6˜6H:´qƒAÆùºå“55D‰³„ ‚¥SA=è²ÔÀè) @Á3<1M0C4½ÚË ù3Dpc³Md¼JS1ÓcRÔÿÁ9bˆ<Ѳ#4”µÐSÅ1è)ñè=&d„.¬,ȼ IéKµXÄ‚ "Ó²-hB3û¿Q2r\µ"É åë“Å.ãBF7mt. 482Ã9pƒI”º³È€;HƒóX1"I7q[JÊÄ‚(èxLµLÊ.xKFÐ;8(ÌUS8àMÍœ=$ÓLÀιÍäôƒÈìnb³ÙºÌÔèÁ_4Ψô6Œx1\10ð…Y5QM°+€­¬”ÙrNºûD+2Ç亱lKçŒKNã&6xÌâÌ2¹üÎ@P̆Tÿ‚ØìIÚ¨ØôLHN6@Ê@ÀÃXM“ä£Oq,èÈÔKUcÁ“\ޏŠÉbcIº5[I˜ü+š¼Qb«µÄr"'ª€0|õ ?íÕ‘éSW×reÕ‘Q¬M-ÉN%@nMÀpU×jVwÕVxu”l¥RLÑW!eS^¥×l!¸v-ÒÁd³Wƒ@… Ñmõ×€%Àu­%E;Qˆƒ£„FðDoÉJŠv‰Xz”kJ5ÝWcí×/A“Õ Sõ ÀÃV‘Å ’åyMW‰­Y YsÙ™XìaØŒtWdL¦a~&æ5ƒè}âêÍÿe\¦ÞT¹b,ÖÑG^åümeæå"&ÛwM^%ŽdG¦åB&]XeO®Wú% ½õ^íreC¾diä Öfhææ&åogâ•áqžfUa=Õ4KåÚ]æ;nfgþßJn`NîcMV¬¯2gKFçNöf~.Ñ"žäñ}eqè}^çn…geaf&æ¯+cÅbg´°`4e'Þe lIŽžbUñej5,"*Ü–Ec áMFäLžåîÖ1ÎaV6b)½æ/ߘNãan¢g>g6Ög—fhÐclÆé`–gVFÀ² ¡žþçŸNä n"‚†”•Žer~é¡þäy g€jjªÖj¤uÿê|†ê¯–j˜.妯g––å³î‰©Vj±`¶¶juNŒþèe‰b]®!˜é‘nV™eZ.ÎÝ$†èy–hãb›cÓ­ên^h´ÎjZ.æS¦:.a;ži’pèÃNã¤.åóólía–ë‰ÖáƒÞæ®6ë&Zç>jÄmZþÒµÞãÈŽj¸Nëʶèc}c-êÇ–mÓaÔÆRÔmŒN«VSî±õ×…l¸‚V½®5¾vÉ)vQÀžV›,èOÉ锎ÚH-lßeäˆ>î26é3®c™ÞiMyna­ædþl–äÚNïеçPŽæth°FíïÎlÖi•~o¢¾éá&îú¦ç¥Æÿo3î[ö&pñ•’]oÍnï§p›½mQîoÉÞmÊ~&,ÈoJÞï„öêמì°q²Xî×þ\cÞS· ÙÄqß!àFÀ¼®î äeöëWÙnµI_m®~ê–~kÒ ñ²ñµ"móNlôVd%æpþVhÝ^òoò7hPFèÖNòñ-—”.Ÿë{ÆmÏò¯br3_«ÔíVxUðFVl·f(‡äyŽm:?oѾsžÖo0Gr·s-p'§¤,pqİòwí±"s*Øq«åñ¾Öefu!¿Q"ðÃýá2žðí°Y®ëÜVò6/óï†sؘX!ŽqªAeƆcá^ðÿõÁ Z47ñ0/ôH?ôR^uE_WGïõ«þï`Oô¶]×RWs,Gõ¸Nv>ïs)ÿs*ÿà "Q¼=Võî[ç¦vÚ~&äfß bôg*vB?vGt² tçñëþñ¼²âM÷ÀNWŽYn·ué~vCOuvgõE§f¶fZß÷TÅó|_[Çæ÷L!Üˉ=Íq/nø„¢<fã¶v&÷Oqu!u‰OXù6ìÒ^p;¿vkþø]ô²ó_ød?óVp?mŽÏçIÑö“!|/ùòÖópop•¯ñ‘9UtÏgwïèêŽ÷Lïåz·w`¾‚[OìÅÒõ–gm~ ìëwÿùhïmšø”^ú¶VwIŸyŸØÎ&oû%zœ¿ï£/wÒ{³þv¼‡ùo{ZVöÔuûõˆ—]øŠ—ã_yd6ù(/zŸwlgù~Þ{_ï{Þþû²ü_ùËŽ«[¦¡[~b¨ÇÚ©§zºÚã¥øÔExMa|/ßê¤EЂÉ(ò/çú—¿|¬VuÀ¯y î ï¶ñ·xœ(¼ù§ûŽŸ|ž¯|ËW{`'û¶·ù&’u¡{·oqt»‡~sïù~N3 ý±6õ5‡öÌgñêþÈoü¡ß~|ï§üS•âWü‡hzhð „ &d(СÁ ÿ&R¬hñ"ÆŒ7fTˆÐ *2¨!"ã¤É’WBÊÀrE Ž"WHf‘±²¤”’'·È(i’äÈ”D¤H9Ù3 K’:Q…€Æ–šXPbZ(•¢#súœš…ŠÈž&GŠ4ìÉš7­š¼"Ö(Ê–Tªf=™Õ'¯`QŽEk–¥Ñ¯Zïú„ E€Ž [ˆd©ZVìJ‘.¯®ËÓgÐÌ8µMŠ³Ø±cã¶´r´Q,"s¦å¬sìÍ¡3Ý\ölÐ×:g÷„;vjdÔ'UË`-#‹ë”'cçŠWŠH#=«Z­™”o_»ÂÝî¾n‹Ö©Fsrþ}îiÇxqFŸŽ“qO‘aA‡ÿ ·´¡†BDP‡q4"‰%Žø¡GfŒ„Tnø)xŒ´Q^s¡ùÝ[ö±x×^µ±dR/M=¥Ú`\•¤×|ÙÅUnU$^HòuÒ‘HW×VQ·×[d-É`iU£O¼¤Á™ëA°Á:L°Xc£]¦“€bˆnJ9‡i¤wZƒraQV°h½©ÄÒd!UÖ“¡&!ª“Ž•S]£U¥Þz8J×\uñyIŸv ºè]KáùG„[ÒùÓ€®åùYw >Vƒ g\„S¦§ÏµÿjNÖéÇ[}Ûu‰*¥Ç*UÎÝ(Ò«2DZœžÅ¹ «fCÉj`Jbxa†„bˆ¢ â@™ø.¼&®{H3¥)ì[BèŽ'ð$ƒŒñD äe8Ü5Ìa.@Ð@pHùÄ ldÄ4¬ S:€A„dTLD–|ŒE1Ø0—©wŠP¼*?0t8|p û°ò¦Ò¡PòØ¢’ÝÔòË8´pdÉOøp‚•J’Gø0ÃâÍi Äqí¤’&‚!onK[¬ÊG+‚¢)ˆ+ º>Øš„½™æ\°ÓÊð)uÅŠš¤’öuª~ß©ÿúl«CY:h¦©Y6[¶á .o ¡ö›iЧ¶÷qÉùÍN“cZ”¦rbέæÍ} Ÿ~ûºp‚òjú¯ÎAeW[&iÓ`¢%¼ä’RÎzjâ–›ÐóæJŸ.õëBÄP¼ÙkQº ÍîžX˜1þø¡HN8 𠃣Äx>yT‹7h>9d‚1ü¦¿‡¨P“N`BçCV20T áøDŒ€ g¤À} 4n  X)(X0ö¥A¸€ Áx‚,€¿ D E8à7µæpÊ —À üà·Ëˆüº§¦òk}M±bÒ6ñ, I‚eÿ#ü mpr øÖ3jqë8?ÁÔÜÄB­·ÜKp„{±Fµ›d™jYKU ‡’œŽ=ƒsO¨®ƒ¬RÝÇdq\OòŸž¬Î.FÊ‹ð¦ä%E._!‰Ôr#´jlp³Ó·f·§ÎÝíO¢sРøæ«åG2°dæ¼%·ÜlÒsÄ] vE¨¾õ.4Rp¹.ô¡yQ¯! ¹Þö‚©½îH,ŽQ‚ Leî  HƒÒ73p¶ˆ 耑ˆÅn€ƒ.¸AdWF9 €5",’¢ A#ˆ‚‚R€À 6†ñ­è'¡Ø`Ìð…Ä\s\§!0Tÿd"–0C œrűô!i:Pš>@+DIZx€ÈÌPúáƒ.Ñ6GüÎpÂaÏ·¡à‰å‹cØæ¶2ÚñŒy<©2ÓÇî¼±YLTä0g5‡+Xy[*ï$;VvÎV·Ë\d)J2’ÒwhA%ìT¹9MVÕn·òdî´Z:ZvÕ–ó©ãïH,øè1¨ŸdÜáè,AB‹!Ûëº%ÕFfËsVõZcIº^õ—‰ž/§×Kuýr ¼컈ù½®†ÀhAK !Ãa (´`<ÐOFDx„¼©†„€a:Ã9'8#aƒŽ€§',Ô3ÿR@ABmp²‹q‚ô…fQ?h"œ:ä)ЂN|–0›&jC ÀË%‚Aƒõ¡ k`ZfKR!š¦ð mÀ0C0€¥nšš'$|Q…ð.ià]0Ì:9µ"OãêSÃÕu|\œÇhÔU%õ¯hËgÀ*ØLRÕ°f½jÞ²ºXÞµUpÓ‘J´¤ðaÌh%žÂ#…ja¡b˜¨yݰý:£ˆØGƒí8yVXê-”3¦J\d­C8Ê6æ¢PwÆn‘*€2'{.‰¹]cž,fÓ<"bÚ«xWèÃê'ç"pÙÝ­0H!ꪶTÿgQàR ÈÙ¸ÍAç JØ„´¢¿À.q1‰-4!çðZR†` y§†  !X€D@Å(´‹Ïª–И(0ŽÈ/>RÐD&Ýê nñ”¼Àý°R*°ABAãyÜO=nÀ;™Ó–RpJ8Q ÜÔ[@À×ÐÀÀÞ„AŸðyÉ]ßüåb_Ù/FÅ“)ÊqÜú„|âºýEb¼MbS]…%jÆaÑMíŒFÿ4B$ (%‹¬DǤûÑâIÞ"ñU‡-_w‰]ÔÁRe_UT"Y°NT>ßTÚÕÈÝÞ!ßJî¢/"ÍÁå…põDO0VB£À1*¾¥IœA˜Á`Étd;Îtáà ®¹MÎÄY;ÁA>€£$BœmÀØ=À|*|µ1l€­ µ=ÀnU×ÈØ@j2‚$A'ÄÀP.”Á²åÅD[;zZ„UXpº£ H¦à`^(búã¬ÉgÊ ˜¦F.ôf3JjÖãØÀl§ÓP^øMPŠÕTýaQ¾Ò êÎ,=êÿÄUúuÅLæHM†ÛM’Û(ÆÛWƘOŽå‹1UXþçjL‡x¶ÄMPÁ£¤Ä"f™Mö›(þv"#>hmTÁT€…‹¼¤¶Ä$ñä€J"RA œÕ§TÎ"ZÊ…Àÿ #»˜Œú’^b`\„”â!II*dÔ6Šø˜*¢¹@i“–… @dèd(h^锎D•B%jˆÏ´!…:(~ŽD,°Ü¥À“i‚.(óý%ûÉ^…IŸíåÇZZŸ.òÞ²¨OaèHXiYŸŠîXUªeÉái[êéVÚÇyç˜X .HŠ_!Âg)½•‘@UXÿ9*YAªí„ߤâ{rÕ!¢_"&J£Q*ÙU½åAXÈ‹zˆÍͨˆÔ¨Îõå€Fªú᪺R’rh­ ¡¨Y*ö˜¡Výå©VŠŸÇߤa«Î!—ì#áa+Z‡¦Ž¯&™+-Y{ªUù)G©Êç©î†”ÅE¼†úÁi,ÊiÈ _¡Úé¡.k¢6+Ur`"óhâî­D·Ü·¶Òa b¨ºçV™ß¹šRºÂFµþè—hë# ·–(…*«ÄøŒÞ%­£­¦Y`¹« Î)½¦åIäL PH«Ëš$ÌÎ^JrØîéëtð+P÷¥g¯ÿ¬¤~’Â:©Æ§Ã‚hÌDÄžâÄbë_Ïź¢I«•½ë) mvŸz²*¨"-¹²XÃbêÓ>‰¿jÜ&²Š¤¬íËY…À¾«ïÅëOEßËN_²îl±äžíÀȦª*¸-Þ-|ì@dˆÈ #ÉÎèɪYÊvH½øHͶì¼â¬ÞÚ«²ªdVÞß¾šcu­àz+ØmÂ!,â’ŸÙ2-Úªë“D-‰^«’d++^mƆ)º©è§„Î1Rd (y~†1([<Y–ÜZÌI U Ážná¦îѦՊ¢ëJ\ÚfE±¬,Þlí!+çò­Özh ìÐeõFêÉÿa ).^Êh¬#™ c䦮6ß+âKŠŠ/üÙâÞâ"Ïb_Knf‰ÄÒîðÙ®ÕŽ ÖzÑå†oæŽoü ðUÖß.þ­èrFXì*õ¬õ.ö²®ö^*÷®÷F/·L/Ѷ離n WêÒ¢ð|ª0¢@ëZ¼á´þH R0Þjnê,÷í/jµü°¼± °½Ê︜YýzÄã–YþbÖþþ¥yz­P"™»ob5 3ìöÞ0Ä®°5èîòH~Bâ"/¿pÇðõ*– [ªW¥pç0‹®ô®/—•3Ùùº-×Np—äãÕ½znÏ‚îÏ&1ñäòÿŠåˆzÝÂbìÝ­#0$wnû-+íëî}º1„æd«†Çeãö߬¢Y ÓkQoÈ®RíÞ.ç. _Ò?ê÷á1 ëq›ë?ìrÄ®è2(ø6òûÕâ(ó-VNò[òaQ³ïã_2“ñ¨šßQ¾†Ÿjè‘L3(Ws½q³$²°nœú~­22'–S¶Å:Ãë'瘋2Jq60£2øô'%þg,ã\W–dQÏ- ]R.«X.#·3Uæ,³°åçn3B×HÑøóÿV°@[¥GkóA3V*/£¢/¯âëaoXLà²=ƒ3>‹ó3kX<ËdŸÿ|s!{*O/¥–33WÁŒ¥³•ÎÛ¥¸œóÊ-ôö¯Ù¬I[ó@dzB÷¤ˆjK^õ"G&(XsrÆ)°Ô‚ECËjŒc-wÈDS.¯Ç.«rZXè¸Á±cÑKOmíV­#sM¯ð¬õð,’`; MG³’µ1b>#µ¨.,3Û°3Û4ƒ[?×í?“¤;s4î!êG¯´‹uú‚Ž ·0!GözŠk–í ÷1?³³}’4V´V£4i«ô)³tB‡‰P ¯×ï,ÃuD_È\—ÈZD]—g /£´©t3¯ò–õ._O¨vdw^óî^G¨No_ sTn8³glÿg/G\mkömodwê1‹3G1±F¯èwôotp{ðp‡Å>G«~t(÷6§4€;+wów°b}{Ÿdõ¸ºw Óv"¶uº$w™]±B4÷0õœg4‚‰Ÿ8Ч¸Š¯8‹·¸‹¿8ŒÇ¸ŒÏ8׸ß8Žç¸ŽßxSòøŽ£xÿ89‘¹‘9’'¹’¯xïxÌå¨ãÞï‡ÇõAˆ8‰<7E¨¬ éò°mÀVuZ›âì&vÇâa¯Eµž¹O|¯nc.o¿³ãkVªù®61£§N{* —WÀÒžE'ã‹'Š÷#’÷+›w©ü5+ö/Ï4Ævv¬ë~ $ÿuözT£“yñX,a;6ñpé_jú¦×a§scKp¨‡yÂt`?ú`§ºM“Ed”:Å:°#‰ËCOÖ®ó:‡Xù»Ü(®–©”bA™^A™{(û²/²/{²/@´3;´;;´Wû³_;µKû¶Oi³O{³g»¶K;¹S»¶À´s{¹s{º_»µkû²£»´GAHA»W»»ƒû·¯{¾ßû·ï{²ã;¾—»À|Àÿ{¾<Â'üÁ7<ó»Ã?|¿Ã;ÀC<ÄS<¿<ÅWüÄo<Çk¼Çû{Ä{|Æ/|ȼɟ¼È_¼Ê¯|ËÃ{É|ËÇ<Ë¿ü±Ç‡Où[뼌V9°g‰ÿo–]O7u§£\w?ÛyzìN³÷ê.óé`¶Óâ0¿î ^ƒ+s7¢÷õy{É„‡m¸¢ØÓ+uÔkøÔÿqÕÏTwyÜrb(wþýS›_?÷¹Tÿ9U¿}K{vI¿¹hß©œ·ƒssKÓEY€7Öo÷x»2×/º‚4 ñ½ñÖ½@¯ë¼…@9ŒþüF`ùDhùsÔs1Ûw…;ý “}-!âÙÛ6 [}Ж® çù}›¾2£þù¡ëêËwë«=Y²3‚‡öæÂ3ƒ›òà‡´c>i|=êò…ïq†ÃwfCíîëŒáÕ7âo½wjÓó^)? [x{;ÎGù΋Ér¾‰ÿD·ñÚ‡­Çt#1v¤ƒ:­«Ûû¿ºLÇúü«zý2‘A„È"Td`Q¸ð!ƒ‰`1(e¡‚T0"¬(#Ë@Š ND˜eaI‰HÉ2¥A  dÈqcG„XV29³¤Á“)K†¤Òò¥Á˜$k¤R…'•:#‰T©(Ô#B) %%ˆr&F§X¹RM˜ ,7ôy•bÖ­#½‚t+ö&Y+elõØ· BŒl'6,È6«V†FZlI$éÍ‚ΔYòÊÏ”e±h”aÅ"âÄs_}¹òßÊu1k–l°3Až%1f>(vvÕ¨TÆ*—«[™`9.ÌK±¬Dÿ„WЪ%않L·~:víÛ¹Oà½{øëßÇ`p}zõëÙ·wÿ¾½xëf6+O<±®@ÏÅ=ò4:™¤‚(Bɧ¯Xr &Êh2î¦*^Ѝ#*€+±*`A&œÂÊÊ¿ @# G β¯î2β @àA:’Á¶£‚ 8º†ó¢€;î¡!¶ZÔJ¢Sêï7¹2ÃMJ(%*‚-Ä ±$ˆðBŠTÌF7 ¹%)b.­µ úÊ‹úÊÈIßâ2R†Ò“¢‚¨‚®¯`t1ȶ‚ÛɈ @âŠÐÚ"®½Òʳƒ´Ì>"‘"á”HÔÞRÿ°-•`t (Ø<› Ú  ÀƼʢQ®ØÂBEE¬±«áN!# @ Èú)¨†ÔZè1"¤Ë®»êä[¶<Ècv»g§ƒÚj­­–YúòÂ*ƒ@p`Øë¢£$òŒI7 ËmV8kõ’ rì¥+4,N‰æ07&¡Ý~'¡7!ýrâP50¡dßаÂñŽ$+p¹”îDEüøà #Þˆ7k‰ÄºˆÃË20±aŠDü(쮃ûë)Õ±B)„LÐh—K" ðWƒ8 ¶b†î\è:üà™ä.íúò8„â-`GˆfÒh•¾*;´ÞW\˜ž ¡ 4°ÿDØ^ÊÍ¢Ž ì#V‰¥Qá#ü£À%’w… îÈÀoJs}c… U :(ÙÃ*XrMœ.³²¶‹„*KDÿ‚+)õuÛß&“é²u÷d­J†0*DJîZÊŒ kˆôÊ×<¨,…)i£oq—G3í²¡c•åîxh•wvùð®}úk³­O(/0ábŠ)˜Á´ÔòÍž…ƒåE‡4‹L*TžÄð¡ïÅhÚxI`‰}âHà^‰oº+5D# ´{ N6‰4\+5iÈCxCŒiìTHÀR°(YÄfc²#"Šô" G¨·L»ÈQI6µcÒíΧ¡ÿˆ cãJÖ¾‰%pƒDHÚÒL8¥ÙQn…|iah‘,«/æZØê€À `bf˜ q–“ÊÄ —¨ Kw$úå\yŒ•dã?&Üí-–ª |=hi“Á(XBUáO¨ã÷9 ƒYYR”æ¶¥¦aê4¸K §J¤.ä5 UIà@‡IHâP‰âE<”G™ë7ºkC DÀpd`bépd5–ÑO,Á=[Þ’HÏô¶u/$]è#Žàƒ"|àŠ­\ Ô:8H˱F™G£‚b°„d?:!B4ІÌülök‹À¶à¸Lnnÿ|DÐ]!3E(á h¢ã„“ÛèÍ8˜ÂÆ®àKÄaWS 4›‰BZÏyØÂ#', K†]ÊÞ‡°¬OÍ!žtHoÆ…¡ÁJËA ˜ƒžh[3²DºT£€”Úì°ÅëS–ùBö9á —°[ÆV·°Œ€)ã4Vð‚DA…lຖœó]æëdA>ùÕ|µ¡†©I…u;|΃{úÍ\£‚àâ6ˆIÿ‚.ÁäI&ì VÊà€ë JÀ a‰›¾HHÆ Ou¤EËî§±ÍÃådoÉKHQ¤N3ñ€Œùý‘æ Qÿˆ‚[U²€ ˆ–´!B­ ,Á #ˆ‚†TtZœT ¶XÈBýè”Yµ\!€z’oïÔ@,¬³·Ž ÐlèÔª&´Q¨@SÀO#€À ¸-”EÜš\¡Oz-t…¢‰ë"Œ1—Š®ðN¢6¼vúnE¤+ß…„€; ŠhOë+{aTìu¯V¤»€öJÄG²6<—2$Hx½» gVW†kŒžD°+<Ñ€D°D¾¬Ó²”#øÖ Ç΄×(qç¢ÞËÀGhC°:¾ºE &j`¸p7"`W»]SÑT«ÊGV5´b¨Pò lÍeµsRàoÿJbZÝæ Tn‰t+l\éa¶Ù$B/H`·-@Æ"^(3x¹^–Îø/°if¼À:0Tlˆt­È:V;¥%eí]ª'[S¬g{â ÎîÊXkH,±h€5˜A¡Ò„4€Á TpÑ€~X)\;­„B´!IJ€CªkÐ=ü±!/§”JK°3¸DhÂb@à !MØÂî°ëTF ½2ÐC¬[@#pÚÓ/Põ ²}”S«:©Jã˜!ëŠ@€ <¸èh+äµB†A ,F|Ô#Ì™·¸FœQú7ØÄnf[µQÑuªÑÿpFøAŽuµ˜íìŠÊ"ë+@(Rm #H `ÐMW$im Ú©N„>€«ÀA J7gaÛ~xÃ%ʰ$ôm0œvÍòcÿü‰”ˆ€µÉ€m(ÁÔçÎï* ’™3ˆÂh“*ºÐt 0‚/yª·nEXËš›©´àZ@0Ì߆”‚Â|¸ â G !* Kä¡ /„ªÉ€E@ü0œ¶#A„Œƒ :Õd`µWÌp wË@?`âYp:•'ÀQ³Wí Ït>ó3ø9FÎr›vHfÓ;={Ò9`Ÿx“ֻ齊øîÍ~ª”ÿf§úÞWb H¿3h kPÎg]ùÊí$yˆ¢%ÛhóÃÇ²æŠ TdH=-jžYìPoÂfϯ0’Êp–MA„AD@ìp@sjÈV̶ v¨%~&îO¦ !3H@À@ÂBÁ¸àÀ fEa¸ Šé¡ê¸& è¤þjÀû.# àþœíìfÝêæD@a DÀ0Mžh³†@.núÅLÉÖà  ÿþ/e"ñ/x|¤î¡ˆŒÆÀø4îJ’•p0Ž Bel`©|€| ŠˆÍ |ÀÈ%Ád.X€À Àÿ\HÀR`Bˆh€àj@§íhà-áË8« ÿÂS {‚0ò@ذ/~€àâ`+‚‹*à 2à ÒK H)¦0æJ² -q j *B úo ±ˆä…ërÊ$~ì‘P€ y€Žòï rÑ”¦€lÌ3’f*Â6áŒX¿X†ˆŒ l¡"´fîb!„&/Xbp?ÑˆÉ i Π D€§€ŽoÅRm  W.° SÀø£%*ÀÌ€Á<1?ñÁøÌì@ 31ñ¶‰l€} @®Þ€‚"0ùdCÚ&âX¾üÄoÿYͱÎO%ÑãÑÎczì¥HÎÀß^àW`*”Ã**ªþþp”‘ŸêN®‚& ­ .B Þöà%~ s޵æ , >Ðn8‚Wíô0â vË_"ègÆ ®@ ƒ¥n|Ì bàK¹*Àk |2‚àza8®ÿ~’©ÀEè@ÀÏH)ö…š`( •ôÀ l X Œ ÿóú ^Ç2á^`TàͶB š€uh ¤ÀÖD` ö %Œ’¢¨@m  èÄ(ýª%ÒðÙÌÀýäê²@ àÀ è$ ˜€["Áxˆ+¤¡Š Pšà  €ÿ9&SelsïV-ÍÀ{ˆ¨PB ¨s"oQ Ò0;m7ÇsQ³ ¦ !§€99)9¹ð|0 ’q=3sìb ! XgiÞ ìä* `"]@4ù'.Èæ ÆV€ÔP®ÿÚ ¡à„Óƒó È u š`+°às±€¯RÀº`e,a¤`7g À±Pú`8K4D)b3m@ÞÀ jà Ì€?ô¡©ŒD@?¿-zÓ}àE;-av3JT+Þ X F'rÁ² ÀΪ®:aTeh Pó1!´m賄0Mß„AäXh %M2üîTÿ;V’OwiY‚óM(â=§ÀlÀ¸L°”6Ó‰ ~@IKðIçà PRfIˆàÂsìXgÁh(Šš@kx`2›¦H´_L“ÔŠ´l+FŠ43Ãël @ß„ïd¯"ôÐA†RáÒá x!Iw!pAÏ 0Fv¡7Aà9O@ 63!Þtö  6Õ lTI0)þBÓWeŠ)HmYOS •XÙ!ÔF9A è`5[SÖ€ ~‰ РT½àl5ä0ÁØ”’~,5R_âTdu2gPÏ•d?KTaΨXGÇÿø J"WI­6v}‚Rk ÂË(ç*PcS´P8áMÇBÓÕæ ¼ú…&S À.XSX§Hí6’c9rcDyÖ šÊ p@Å,” ”à@I&j=ôF“ÖV'3\)À(]ç :!Ià Þ`a,ˆ b¡`KÕWO„Ò`jŒl®¯HµtçJIÆd£´:ý °@ø“nÔq»ó¢¨Pœu( ŠöâÀ{:¡ìu+¬uV+ Vý€'ª‚ÔTÔFMQE ÑôTüÈO<ú”v³%DæTÄ*’`"uw… ¢€³T×Ré@`@ˆóÍx"jÝ•ÿ¾€{Ôi‰U`@SZ…°Šl'– ´•K¢_¸º†ó4@Ó–·i£î>âánqÀë |`iÇ®’¶ fvjŒ ª`‚´6 6ÁnHÍ@k@ª€ôÕ{B[KõMÊ5ÎuYCvkדM/ J8á%âbSûÎsl‚ù•¢ÜQ6›&ykàÍZÖkÝ ˆU@p V\eàÓ„l´æ4ku}Ô[¦Ï\ %tÇy‹ÐIæ üuÆÀp¡ˆR "_i ¬ e+¶PÑW&2zsu¯à÷UâDáA ˜ ¼¸^Ç€hE,H 8×s™¶ÿg@j&øn‰kxeŠ S÷ |¶ŠF_Y3P_Ö “ fSˆÿ—„v;&BnmâÒH zý`yW!7µ½¸˜Ü5[ýÍ|£4j«xqIX-úâ ×bCXhƒ³hç8g§F‡sLIyˆe¹È|!„k¶!@”dê”YëYJOÍyh—O³…%¦9P5a8S€}‹d"°`“RÎX'Œ1â:)á€tY[À‰£¶ÀD“€På P¹·~x¸ÁÇw>  ø³ •Pq “•Ä“ âw~ ú€à²³ÆÎ(‘µ Y ÔÖ`kø~çñ 8@³Õ’øl#˜£w¸ÿ‚Wæ\×Vƒ1·ƒY›#™2ñ*úà Âùj ”d’÷zSeT4-ä—X©©˜h`EW5ôzÛ@HÇ DØ û <¶‰¯Bp‰I'’¨ U•§ú¸1‹—¨|—1ž§€ ²ytdZq¼g+Ð.4y S Eoy¦a…ÇØ2ÈF‰³9_ý*™Ó3P(F´U)–¦‹ˆ9aH!YkTÀ”˜!ZÙFãâ‡P!HóŒþ”—† ÿ¯PSà °ª·Seêµq‰ùCÏ¢P{ è:g•¶Xý™Æú—)ú ÙµùG`wyŒÛ±dwO¡Yÿ%sÀv3Õƒ,¹À4xŒ»yÙúu2Á5ˆ±4±;V úeIÇnC q#Pcf‚¼y¤%ø°†Ÿ‡ ̺i'¢ª¦§ ¨›. ˜¢!Áo¨@mŸ•Á¤Õ€5šd~ZXóIϵxEzš ƒ‹©“aÝuxâ¾­x"W †Íø…ÖôøsÁH†a{ ¨ÕŽâ§ t˜R¿äî˜Ï6Ü 3}F5Û“²5<µ…ü>—õ*ÀOVSË@r“X~}u‹WüC;âw3ã)–Ucß³v‹P#˜èÚ"ìFó8à å:I˜/bõ¡Q &õ ª _ÑKk5ÿð:½é[ƒ%Y)!Î`nZ°;  àVAy}E¹ÇnY¿“c•†³  vp)Vœ÷\†Aó–K<õC%z¸«€ç*dê@Ð -™Éƒ™›yј[%Ÿ[(~7¢[Ǻ]»Ã½Y»9Ah ùR ¹i:]vû°‡O©‚/ý èÙ_0d+,X¾{aßw¸%»!€€3YsDì¢+bŽÎö\õ€¾Ë‰­K”ÁÍÛ’Æ[)´´ÔٓàèÀ ¬½][»Õd÷àI5¹Äÿu8ý `ý•Gö ¬•iúUI—Çö»w·  f¶]ÿª‡œ‰1õX¬pBk¬½6xDCuYIýqC!dPÙTgUBi>èW)ÙsP¯ó©à{¹HSWf‰™à§• ¼•Ó?:qáMé€PKtf%¯Ã‰Þàýè¸6+»i}lѯàß¹lÊ•íúõÍN~ø˜¼Š'Í5»k@Â×–¬Ì±@Ì¥@YÿØ] ºàÖCÝ"\7¹gÉN±¹±ÖcýO©+RŽGàVTø•vª@xUÚRí&á= ÿ^d ÕR¼f!;q daX°2À Ô “˜Ù™ÀäÀôKTµþcIß ºÀoÚA³W  ^S¼ÛºÿZ¢{?˜­˜Ò[Zm 6¡_ Þ Ô0IØSÉ|37Ö¤ÿzk`€†Æ žsÌ{ÆYutú¨žÄ³?’W&-•Àηš ÂR3$茩tE &&kÞ)s$Å"R<ñs…È•,2:RL„ƑD¨„rCƒ‡ƒB"l´!BD!¥40¥P¹€iRš&—D¤¸³’Δ[ˆ\pc#Î @h¸”‚ÅAÎ9¸@|Ä™.î\±"fX›aeຠci‘!â)Ó‘fÌÜ äˆHQ”VPD• °W°x´“©†­,©„UhG×@Œ‚1#ÅÃEd ÿb™ÂD–6(‹…HX˜V[jØ£ZI™)`Ò€AÇ›JDa´NKÝm–rÅŽ6›$±áGµŒUGâýѲM»ðô¹âé"WdHIÑ‹†D|¤x„©Z5Ù´m‡pJËÞ¾ª?‹h}5,ÅÕ …ÕäØ%ŒGï‘LW˜€\ˆa†n˜azÈaˆ‚ˆ!‰"fÈ@Š*®Èb‹.¾cŒ/ž˜¡«‰J0h R i”'CaïŇEÊ‘çvk QÑ ÁI©ÐXYðy!Š >D …D Â$,˜GÃ58UÃE]j 5”Sø`ÿÉ‘àQÈ€˜t@ C"–l!ƒ{áäÃSÀàT Ê M|Å TdÑ tì‰jlŠP¦Ped•na­BB*UèGFK6LÁˆ `Dâ c0iâF"á[rúà£)7CFa9¸ÚIÀI#4Œ› !ˆ°FG¨ÀA‡ 0JCn})ÂŸÃÆA¥ ÙP& :’dQtݨZA !A‘B‰ÒÀ/»âF Ÿ‘Ê€»S¤àT¸[5+ ŒÒIRMbY8P¦™eÆñ—UFHDjÄ £S”Ìá‘/ȵ# ”°0_+`E'…$ q…^!bŠ} ÿ)&ZJ9k ¦§qWHµ¯0ˆ`X ŸµBÍPeSìFéC£òiœ0<̓ÔTÛä‰ÉhlA…ÔYRžì2šÂR8m¢q¶aÅÄfd¤I >˜ÈñÉ µÃ4tM¥ ȬšÍ‰ ñj­ñƒŠZHå!5Ž^JѽeQh!®—øáë'ší"ʈ{îºç.»@á,/Äy#j‡ÀéX4á#.x–ŒBF3ÀäXºšU#&®Ä%mx€80"<#?vpTP¡F!3Œ&¼¸õ!¾ÎJ`ÿFà€KÔ›6ƒ•ÏÿÕÚ`#TÁ}a©‚xÊ65Tü }]‘žM*¼/~DÅÿÆè™à BžÆå=ÏÀ“àðáï ó#Âä÷»6áÈ€”àj©f%&X .€À†( ,0)_ @H¢ 09É`¼Z‚APDœé£¾æUIlXJÅuÃ6¨à-6‰£ ž‡E2çd@ˆÌÇÆRÁmÙÔ×¾)ê 9îé¡c ðE0oRÀ…(Ó>¢O ‹-á<Ó7ŠñYnȈë]O„E1 )H…(Ò âƒ!‚¤€ŽôÂ"y‚Ó9F8ÿÐ!~˜Pò{\Á ŸÈD¡^Àieâ—I’!{|ã”ðÀ;z†2¿b ‰“ë‘ÁÁ„‰<? Œqч/ZB‘‹œa9«Pø,.5¯bìª!Û!Ôu Ñî ÑÝõÎJUS dÁ‘1YyyK*s X€˜…£Šò‰¯R|*PEòL™ó‹Âž`jRŽ´,Ið” Ô,:YZ’Aê*s6‰‚ Ê3*g¦óK,›,±E˜8ȶ‚Ejqƒ “¸évgIUÞJ„Ì>ö¸ loK‡Úèþ ®Ul•º«ãQ#Ê´êxËcÐ…24vêíPBiÑøÊ·E Ýf¬ô\ž†Ô° µ˜âô«ÖÕd—¼ýeL~ÃÛ’„%s.MëXSŠV¦R´°ð©ªp¥Ó` GHÀß«py/<¯°„  8Äb`Dàœ¨Épr]à” Œ0q¬lÿÐNv³¦Uðy?ìß•ÁÖÕUjЬ<ªáâÇÆpylá Ï ¤P²§ aèÆxÃ7ÚDhšºT±NX,–•, Rm¨L6¯ÏHQ»Ëªr“ß¼a°:xÌÒùoX·¼”YÎNo{iÔÐCÃν!š¯£å;Ñ>‡ÐdŽ›‡¬äìøµ\ÔÕ¥aü`.[úÓm1]j)w¤¨õ˜q#*3å8#vžóªe¼V+1MQü$ER}å[ç9ÎZu ­ÔÃZ›ZحεHï|j´.NÏFuŸÃÒCWçy‰^¶“Y-m+ ¸ ? º$½äÔtDÝ|B2våÿ`¸ÙÈ–íjtÕÐ U˜qŽ÷·qß’¸ûÈ„ÙtX(¤hõÖ7áî}´Ãw—ƒÞª,Þó¶`xŸÏô¶4¿Ÿmëy‡Ûã~¶¸µ1žíýzÚÌ9¶©Ç6®˜8H`±Ô*^m×ddáNPZwØÌ,ù´‘ óî:¶ÓØÖöÉwÞØI»ÒØdòN‘‚Kgj©ƒ·9îrÇ' Rç3Ê­ÎšíØœ±X7Ô”­j£üåc_ì¼ËtÃ]Þà>:É Ó=j¿¸È†f¸ìnx<|ñ¸‹ô¼Oékg¼jg-¶Ù¡Ny½ïs;àù©K>åb™xè/?jÿNÒóÅ1_zŠ;]ç©¿ºìg/ꪫ~â!>ýëkŸy'ãÜõO~ì…?üÈŸ}÷·ï}˜,…µwäãü 9çý·º ÷Ç6~¦›ÿø½ÿ{ØÓÎþçÃ?tBÇó…Oü†l7€Ã¿ÎCb¼ýgôºŠ‰ì~§ûù1^v¿§{¶‡|ØzÊ{ßW€ç{Å7€Áb½7}ËÅH„õn:¦cw·t>–~–'€“w|øxÓ×vZGv­}ƲÑÖžG^ÛçlÕ·lr‡}I×=¸‚-ׂæ÷‚#ˆ »Õ\x  €‚ (‚‚V(•`¢·|˜„×%šg}W~68!â~ ÿ…xŠv_¸"ì%"÷µ8ëÖû¦rDW…ä‡tÚ烿–ƒ4p&Š™È‹òè‹}Èö˜:øˆúH’ ™ŒÌ¸h]¸^ŒÖŒÎhÐè:Š‘ð‘8i‘¶X‡žØ ‰AWr9—{‚È{éøñv’ùȇ·XØèEù¦Š‰o:©OÞ¸„ë’ɆG•%i•DY4s†É%‘‰ƒ’?é‚Ay x•m f§ˆz爄biˆ6q 8âØt’æ“g ””¨–xÉ–4C…3˜’S™…­ã’!’h G;õG“÷qšB†²·—h„¤÷—L9–N™8BG‘´ÿv“h‡51”¨•M••b¥[©•º5ŠCXŠ‘¹~t)›Bɶ©—¨ñ›©Áˆöš’IœÖX•މœi6ËI^2`ЉY‹uɘ ¹–Õ‰›]Òˆêր樔ৄIƒ©,ç™”¨©ŠªÉžîƒ³Šé³Ù’—“ ×™÷G"2  2šfi;éŽUŽñÉ©êÈšRgPi–ÝYœw™Rs›ÊyR¹ù*¾ù•©¸”Ú”‚Ùš<‡¡°¹ƒÒÙ˜J3" ŠS#œz¨Ÿ:2ú¡×™SC¼edYGŠÚy#ØÙœS¢Þ7Ÿ(ºš*j¡ô± £àIšœ>ÿÊuqhŒBDý™!ñçŸï Êx$‚¦r órAÚH]š\e9gF™|¨È¤'*OÚž+êRÚ}~Ù¤yZŸ| VSú¢ I›Ç‰¥Ö95!ê1†:+™¨á¹¨ãé¨Ó¢ù©¡U:©WJ3YÚ¨?*‘s™£œúkŠú©ŒJžð˜eú•‚Ró–˜èX÷©†šêN9}q*§¶z¨’zª” ¦"¦cºhíe¦Œçxhšè)Ÿx:‚2pQR^Žßu˜ï±¤€ê¬ëÙŠ{¥`Eª›Š¨¿ê©=ª¬J«y8~â꫟ȣ ºª£JlMØ—é¹€ ¥ágGI|Ì¡ú¬ƒú­ÿZ§õÚ¬ê)…ÝjŸ}:ˆx]ŠœFª¤å™®š(’ Ù®µY©2€p5¬ÄZ;‡v¬‹—¬â–©ÃYª¿h3Ðç§x°÷š¢Þª¯ {Œ:’ii¥ï ™f8p‚Ë ¡Ì'³zº°àš«Ùj¯„8³GK°Çx£ëJ¥ãê®y©ª—ªRá:µ‹ªæ¯z¶«(Ë®:Û©A<Ò¤šU(ðó‡;¥ åÀš+Wàš Ç«®ËÂeÛ¼Z:»« …€©°§«s©ËEËä¸R8‹±ܵðеÒf1¢8¹§ù¯Ûš°déÀÆ;©,ÊaIŸ¥<°Dð¶ K¦p›x:ìh%›zŽQñ+Õœsô7ðZ`Ç0>—PÍ ·’+±°ÍÜlÇN€â˼ò·V€ ñÛD@€Î70 Q`Y0 v,ÎNœ  Zÿ`—{€T`p0üœÁe1¥ …ð7ÀqÌ‘ªcUHdÇ0H ?@ÍÖLj°álڌΠ€$@ƒ   ä¼jù˜KÉÔšL™ßÉɱ ¢h›µµì|«í8«ÎÕn½i£¿k§Ú*¼MkÊ\†ÊäE£$¸ºµ°L©Ô‰K»¶Ì'ÁŒŽNÚÀÅ{ÊÇkÕ=ÌX¶‹ TpÌb(†7|™]èÌó²"kºnLj €pÇwñ['©`Ç€epÇ‘P¹Z ¤`qlÎ!ÀÍ~Ð Šíš€ïŒ ûÜD_piróD½€ ûÿ\’p âü8 Ú°0–ëþkäËCQ>çÜÅ.¦`à<ÐÃ]Ï@1™pc°"-Dá ]‹½Ò°àP_UQM ÓÙsM`Ù´ÍÓ„ëÓäj¶_ýÉÂ%ÖMåÊ¼ÉæÝÉçšÞDÝ×m«Âš\Þ°+žèýÁëmm(èÑ7‘˜,¶[ýÞú½±žÜßE f0LîͱíE½‡–™ u×–x«iw× uÌ ¨ ‹ýÚ À ¡ êüÜ <BD`Î@:™}”P8ë΃!Ïœâu2é+Ï[ÞZ°* Ù[@@Û!n\<Ñò²nš'Ýäïÿ$}ÐÇ å5PU¢  æ`Î80Z°¨ Ú5`Bp€"à? Í bØÍ½ªñE©ýÃc 5Ä]Œ“<Þ‹9›ð Ô >Ô¡<Ö<¹L:äÈ—Hº¤ÌËhMÕj]xÙÞ=]èîÕ>jŒk—À~±Þéìµ³ã™mãÈ ¸ Í &]ÍðÒñZ@ï3âsPäN ™ Î7ÐìZð9†bÜl<¾R2ÐØñ> Öôñÿ.ÐâÜÑ>ä Ð)¨äà#=Ðp.ç`U`â)°ÌbTŽÎÝfTg! 胾ŸÆÙÕ©.Ô´¬è n6ü°¼»"œu$̯¯zd*Ÿ»&È»/ŸiªáÖò:ʼ‡.ß ^ßD"‹µZà+œß¨.Ë%¿ê'¯‘0÷²Û!±®hNáË\½¶QÐürºu† gÜ ?ìɽ upìêœÚÜPb`ÔRðâÔŽ 1pÇ^ðÙþÎ /ˆã,óÔ UÐ9@@Åðæ„ ˜»îB¾›Àö&¦­c@€Üwüì Ø“‘]ð10wlžÎHà†`ÿâ°ñ«3`b+ A7ð `âÞíUà° 'Þ+à¾5áñ™[ÂGzÂÔcŠÐ%óÁ I=à2xôø}ê±|µLOQN¿YŸº´”^¡½œÖ¿¼Ööï|àJ_ý` Êþý¶ý0›ËQm´®^:q·›‰!³ÎŒ¶£õÁ@à@‚aB† ÍH¡‚E†”+RdP¡"ƒ/R7*!9SæFHÂ$¼ò•…„…?‘i±Àƒ3HŒÂ1'Öƒm¤ô¡#aH§2øÄÊtcˆ‘LÈ0c¦‚R"Hу£ˆ!7Ö I ÒLjXœìÁráÁ_+-øÄ¢dÄÿL‹«TâFË 3¶™YåŠ W¬`ÁB„0)€«ü0vC€DWúttáHI×5Fh$DÄ‹T?n€ CeÓÈ-„5B” ”–%*Ö˜XŠ8†&D’’Å5àÜŠC$Q"E‹‹[$r%ñ`Â'¯®¸qõ×LåzÜ„ÅטÞ8•íÑ טœ8ñƒgb©ƒØJüÜ„9o¦ã"š¨¢‹¼ÓM#éÜãî:‹È›H1ëâ#N±Äª¸?âÔÃè;íÒs-Dܤ€¢£ó½_«Â=úôŽÂðÆ+ï¢ SO#öŒŒ:õä³°¾ÜðCL£ý*”(B¯K ÿ»ëp¼0à [O< 'ѵ:®(/Åô¢ü‘¿F@4B3ÍÐ\ˆ¡6×L3N9猳M Â3O=÷ä³O:2#Ëõ ¢¢8$°` •É$”T²À $4‰A h aƒ4yà?vºÁl¸á€A‚JŒ ƒ'$à¢(c¦`ƒ9J ÕŒ´0‹ Dý*ˉdˆ€@ ñâD1Ýé¨Dòn@&ÆâsnÚ+g‚ £ I΋/B¥áÕ®º`¯ F¥á¦ÆHm RØ" o›­6å l®è¸A‹)^؃G ¡,#)¬P ÄpcÌ1ú¶5ÿ‹&þÛ°&3öÒB"0 sÃ*=IJFÂŽÌØ¿†™ˆ#5¨MÊ(] M5a¢§ØÀ–ø˜$6^‰ÞEµaƒ«†÷}þúa­_¼¡öf¤ŠT6HáX5èð!"@øÂÿúþrä(€€B[èÌȾ§-¬Òh 0 ©Ý†<,Àñ ©úÁX€ÀÐ`Íäu~(n¼½ ðn€h!İ–8­-ŽkSÂÑ æ£ï”íEöA[‘èÒ´šáH0„áÒ¿˜s çüA‚Ãá$¤ž}ÝldÒQEv¸¹'@=3¿64±ýÈ„g#ÒÒÖÖ¶.n2“›Õúó¤ôñaSáüd62)©èdW‚NˆDäŸQáD\B߆ÚÓ˜ ‚§ƒHÔÐB6÷lGsOÒðs…2Ir äò¦C6²N á\$%Ù§6]Î!DÔY=€€‡lI1Q£ÿ¨¼Á ˜DÅöÆe†.8"1‹ùº@5Á$…*• ÈoT`àøÒðÅ­=bzL¦#+=M gPB+C )t¡ ‘¨›Ð`v³×ø²9rÒ‚¨ƒÃig‡ ã¢ÈH¦LܜљYRãˆÚøÆg-Ì‹näµdj¨ÌDYÕ8¶‰Ì³IpL§=Yä¢&IókR‹¼#þ|¬ŽF¤QˆºB1ÑF R S(E¦3>Q›Z»t›‹* ZèFX4 ™M¤QT[IÅø¶”"I‹s$"Ù4T¡Õ¨˜dR•:3MΩqzH6;f3uSªwƒ¨qvÿ‚RX¡CÞââþ“$ò´ôŽTæg:6Ú…8]!ÛZµ+RMm]ò$|¼IC¿Ep œ9¶\rðˆhÕcG×êD@¾5mq¥"]{Zµ•’ qv<¬F•¸GÒô‰7},ÓäjRžÆÍ§•…Q]ŠX·)6l­é ‡Ú)Îõ;(5-eéF¡½ö-A~½!o³³"ÃÙ'Žc\§?ÙÚ!4ÂsPiªQH…uºÒuäRµ+ÉJÎé”fͬÏ6ëÚ>6+{ø*·4"5.dÈ-#8ÔLât òì=ã¨ÐäàӦđ?ÉX²Â/ Î…OAó{ÐzºLcjga1›Qÿñ¦•³‹-acg«BÑFö¶uUéntÜ~Ni¾ΠÜ\¶$Ålb°´XDÒ8˜Ë¥ï‡T–`åÂÔê-8¡#ÎÀ W‡ƒ äÂVöÒx¸ÆèÖ4«L–õGIj’EÂ(àäšØD0Ã,ÙHê>U‘×Åîã¶»fÍ5!g:S%‰‰#cj‡š¿¬!pÇid"¤n&³Û6«š‰AyµSN¬_ëY ’¤£Ý©'{WÇÌÐgEtkÝGF‡Ô±ÎëØÞ'`/BL7Ez¥Ìþƒ!«G"/,Ìa¦¹·oæ™È€Í¡`‹›°’Úa¦Nªk\j0JÄØ[õÅfÌÒËFÿÙƒ™æè¦‰ÆÖØB‘¶:u›¤sKi*QÍI5î²ÚܴLJÓoBÜ_†>Í>-jš‹zæêÎ[Þqbs¾÷dfïöšaá–ï—uÇÆ»û¢—rÌKOùÓ[^¶Ž^}Î[oWžg\ ¯ ²­ÿÚõ#ïZ1{]ìx;ŽrŒd»÷ÿDwò3€žÑ“dôc§H¹s­ûÊu>Ë Ôé±Èý?´¥¤ƒì‡¢1¬ó­pš¾úû:tºQ:€ë8³«/+¸ÜC‘Åã=«S¹ß›=¦¸”¹=‹:Ý›þªº|r< LµŠ5Ã@ BY2ïh2²Ê@Ó¦ö4‘ 2ÿÚ³«>°»>°‚Á±r¯ÜH¯†Y/#|2,P¿Ã2[¿è›¿ ¡œ¦ ô²q³½§Ã½¬@.Z»ð{$2L“…Xˆò#¿7Ë»4ù¥#¶S3¶1ú»g¾h3=ˆË0‰C>ÈR>ms=nÛ"Ÿ£”Ãí“Ã'¼²£“™)>;”Ed?›A:6r¹LŠ<ÒÃCâÓC´6«-ÒDæ›Ø#Dèƒ?´µÀ³´:|©ñ’¶&ÚÃËëÃûCÎ#E-¢±Øû9,¡£f;´;Œ)N”EO-ýÐBqó¸.¼¯/L¼0Ã?)³ïc·3ÃEÂ5œ;ô¡Á>“*1e„ÀóBÿ|F„A“뽫k+ z¹L„©hã£NlÇOÄ9QÄÅ3ECÅÿpEÖÚÄy,Æz<Æ{Œ´|ô¼AäÇùò?‰ ¢@'i@²+<§kFst#©KGÆÃÀ÷hÇ?£AËBû­Š$¼Ú‹@´C¼A»@ô½Ä‡,Žÿ‹Hj™Èºx’î»FlüIE’;mÌ·ókˆ6tˆL¶Vk™ÃQÅ* .Ô5 \@ŸIÆ€ã•ü@‘sÉ0ìȘü¯ ¤ÉF˜“¼áHز9ÌóC|¬+–á2‹TIrÌH®L·¯¼§|<‘©ÉKÌx„Å<Èj+ÈäsË+E…|>†´#p\ºÿ-\F­,G»äH˜ÌK™dÇØš .ñKýxT«ÊûŽh|¸“œi´.k4*¢Ô·î’“@‰\˜‰1iÚ´Í©ÍôÊÍÛäÍݼÍ:ðÍÞÄÍÝÄâ4ÎãÎâTNåäMŒpÎÚ„Nç\Îè$N*€ÎF°NëÄÎåÌNíÌÎF<ìOøÙNêÔNñ4NøéÎòÌÍõOê,ÏâOùÜÎó”Ïï Oü¼ÏñôNþ´ÏñdÏútÏôDOüOú´NÀ›ÎùDNûÜÏEÏmOOíè|Nù¼Ð ÅP }ÎàüÐ Ðþ¬Oø¤Ï -P=O %OÏUÏÿ,Q ÑeQ ½ÑÿóTPýOýNäDQ Î^S§²œzã·ðSÍ„0ÍÇ™FÖÌ73»»„ˆ338‘ëàÎîQéÐ-•N-ýR0 S.S2-S/=Ó.=Ó/UÓ4]Ó0mÓ5S9}S8íÒ9-Ó ÓÅÓ=EÓ:Ð>…S6­SB5ÔBÍÒ?}Ó8ÔCTDMTG…ÔF5ÓI…ÔH}TKÔKSD•‚2iC Õk³ðƒR6;Ò7s3§²Ò׈‚ €ÕX•ÕY¥ÕZµÕ[ÅÕ\ÕÕ]åÕ^õÕ_Ö`Öa%Öb5ÖcEÖdUÖeeÖfuÖg…V_ÅÒÆU$ýÉR•·S]3$5¤¦:“Vý¡i‘ÿ@ 4)ˆ‚,;×,S×1%”/EŽr]WsmÁ*WƈW,¥#ÆHW‰y{=¹B ¶!‘}]‚Um’˜¦9ú #¡×šdŒ‡½é Æx·‰ ؆-’‰ ØXÆ x Ž' Ù’í/‰™Ø­I 6­W~m í1šEº…ØšÅX‰ÉY¤û˜“Ù…Y›mÄÄ`×fêØÂHXƒY¢E £Ù¾›W•5ÃÀY-Z¡aÙ•Ä­­ÚmA©µX‹U¤­ˆ¶Ú˜éסm¡´Åމ`Úû`ޏmÁŠøXü£[‹­Ø«%4ŸÕZ| 6”­‹ša ªÖU“&uÔJÿ4 *mÝ.)…œøÖ|Ü„ Ú#ÙÌU’µUZ§qÚ‰a¶ÍWÁ}°°2Û„µA·Ü}bÝ+Û"9Û±JÙ–µ+ À= ÏÝsXª½ÝÜå]Õ€åY¬}Ú¿5ÙÒåܲñ×íÜJ]Ð5ÉÐ…Úš¹[›^ÚÅÁ­ƒá¥Þî…XŠÀ?<Þ¾ÍÚÑMœËYµuÞÚ^ß•‚ïe_Ó^!BØö}Û÷m'ëUÞ0Œßâ}Ú‹e[ùà‰Ø¯ÝÿU_ÅË^,ùYæu_0kÜn]ˆ%Å•FëBR –ÈÕ®#•\*×Ù"¶_îíØšcM«æcØ%‚^¾b|}ƒ;x`Y=cÌ…e:“å‹ `LžbÞdª“]âýeJÎæcrbÿ1Žå?öê¸äÞ¨9Ö3®^VgZŽç{çcöåjI6fc^ÛW5[îãqvægÖ߀–fý06ú½gñMc¸i…FãJæä* çhn ržåQra;Æhjî¾Ã3l½74l$TV*¤Œ®¦jågN€7Hƒ]bŨXæìõ—þˆFŒp€—¶åÀ0 {Ö ¡¦e݈QçDŽ€sgñíH=àaH:˜@ƒÐioæ‡ÆÙU‚8€®Ææ¯Ž¶Íµèþešrf«§ŽèoÞDO˜‚€iá=c€& °ƒàáU©æjÏu€2@ê].d¦ëÿ6p0`W;ð"ÐëûeëËhøÝæðk´Fµ¾åqnëÌŽ°Šíƒmj&(JdXôMÞ®@άº|¶eŸ<\4Á`QžRî`É1éI:?ž.½³Ü& S88jd%…Xì%äîêÂ>lvìêîW+¸n¨l(ÖâØ-àâÕƒ)˜êáÝHÀ6Xg³nè‰þl"¸„ºvo‰N¸ aížM_ŽíãHjù`DŽXàUd‘!ÉfìÿnŒ©ra¾žì{ lJ jÀ½nå®ïoVè&Apé€ìËÝðîæèÔv£Õveh>í‹&qsî¶°ïn>k‡ÞÄ]„kÿ`–ñÏ~¨÷êOkŸüäRé ¬F4aM@UÄ€•W‰ép&P…Ðm/°&hµý‚#°k'5ˆ8°pjUlÏÝnvÞ ÷lňê1˜ð~Ž&HðœærÑÆlð‚ ìëØ˜s5çqüN’,Îð»^ä jãùÑñ‡ïtø&7öð7ÇÒ1óÄîïþJŒïð\G¯sÔ¾s*øn ±««ÙìLÞqHtè9~å¿l@.ñ‹¾¾0mê47to +PpmúXÿä8Éí¸ã`3Ã`(5òÈMòOþV!ör&€òÐd`‚1°vÿ^§Ã_7‚¨(n»¹bÇ&sö=óG¿ï*J’&¦‚6·ô×ðQ° Ùh\.uË 7ß]èîuïwÂ`ƒÐ6hƒ·uÏ›ø!Ûét`ì*dI™ø•tJw ç]L/øZ·¿/ qPPÇWQ™Oî`w°þ‘w÷+ò¥xoŒjFgïvŸyB†'f‡wk\_@xfˆáR'öb7v:Ñm9ámeÿ`¢löÈýñáþœí¥r­6ìmOa/((HpÀ…°’5Ð È èÐ8hƒ7€‚˜û6àî(p€»‡?×ë~xûœØÿ‹X÷&(2üjöý{·×È¿% û>0|¸Ïth{`„/o|F˜&`ƒõ– `„ç–%`„-—h}5`„ÇG‚ëàøʃ<¸€«>FÀ ÀÿŒÇ×KøŸ×€ý"P‚ÍÇLïW…60ƒÞ¯Føö½¦ý·" øÙ¯ýÛðØÇýëHï/ÿH Xhþ··„ð×÷O|€xQd„ v|´QÃŒd‘K  jÌ @$ pÌÙ"¥J8+®\ñpБ–Jp0dDDŠ=W"F„p^À`4GJA"g~ÿ¼¨ñ‚eK"T¤‘‚%B-1…x°ÍMŠÀ4}ËÖ›2@ µè' Ô pp¨€x£<IÔU p›RlóŒ6"½`dQà )F|e"–Äãð(ˆ«I204aªT)YZ•'Ä¢X°HI-ƒÊ•¢®#R‘avlÇ+¥[b‰*õum¨YˆBmÍxÁ›Îa׎H48T±µ!7`;÷ßþ=<ùòæ¹¾;ƒöîßÃ/>ôïÇ ^z¾›ÜXbÅ‚ 5¼Q„`÷šn¿Ü%SÄ¡BK^t‚|q„S0aÉpÿ&>ÀÀ~|`â$f\B6Ø@Ç–XÀ‰0ÐÈ…ˆ„D`°Û Ú¢%’Œ•e@Ñ£hˆ$À¤ð‚>úD^Ä¢ \Ð1%{•]&O¨ˆ¢²x3ÉTLXCŠm¶á%O!e!Òf"\y2EÁ¡’GØhC dQKOÉø( ’Â(C‡zöHG°D8PF›’aªPÞJ*pЧJ>0B˜6è*©M¬Í¦# {®Yê……”KCÿ¶W4â” Y È´>œtSYDÐÙ`oRt˜íŽB) ÈÀ‰L™hÃ`!n vA@ïéŠ4¢ñ¼™Ò4‚¸F'jØ8È#IB¤6L¹§2xÚ’rÃ=˜3uÃaqÅÍ9/7,i°UA«)çl²Ñfe¸é†“Ñc™†ÚÒ:£«Ýyêm7Àzc“-^Ùáá—¶Úö©¶ÙÛñgö“EXonYÌ”BONbjQW—– 4ðK:Ö0”[@PÁ‘>Ø%C´LÐR\Ѿ(ƒ&±P¯CÉ ¤¤ ])¢TI$ѦÑ„3,° f\rÇn11†Ÿ311%ÿíGŒ±‡M¸šÂ 8fMØ è tîèzÆCD¸JGëJ,Ë$*Z¶Þys Vf* AD¢‹r‚Ç&T £ Á?“)àð;ýMÞ?¨>Zâ ë—ñ†ø9ªU‚¦‚ ˜¡C4™÷Ž*áJ48à‘À0T` x‰fÓ¿|ψœì¢œ@ Z¢*¥ÄU`rÞ*Cë$ÒxM ßb ñèƒ4 /,an¢"ºÊuáq,ª¡Rp@8¸!qM’Â.Ñ$ L*û×L>³ ùFYG(‚á\ů p/w-ˆÂ„âÄÀ)€WÈ—õÿ—.`«%¢ƒå°P:KÌ!~øBa;/‚ ÁÓŠpT9€În Dh^…ÈmiZS ×ZC™§d6×ÉI„¨¶ÙùÆgÂyMÐHyR6Íj©ÚsPƒÅg¯qŠ×ÌóŸ³uGlæáÆÙ”ÙïpGlm›æ|ØFMùè‡;qËæ1“QAØÚßü¶3ÅRœ‰˜X'¸†ô ,0€œá"ƪ‡`Žnê Æ:Ðb ðIžæ($U° ˆÖ“Ðü ')DG58‹Š,rg'*xÅE@Bø¼,ô!Mf¡½s™’ ^… Vp3鵤©»h(2!¯ÿ‡”+#®',%´„ëÃBHMG…ŠŽU¼«Gûp©lÑD>xM4¡D<ëŒ Õ É1,²ˆ)Ä‚jðX8ŠUòc‰&ÄPJ!o¨RS\x1"ࢃEMXø8¶\K£X¨B'€(§oe¦¨.àˆähP“WÎFH“ÚB ¬u$™…kxa KH! dAHW¾‚Á¦´„e)*¯”@¸JÕˆ{P§$Ù2¡Æ©6¡¢ÀP!”Wˆ…òô)LÔðÓñ¼ò蛈àÂðLÔ[a ¡ŸÑ²8AÎr”¡æW¸rÊѲ¦4Rv÷”Á,HÔLÙÊÙTÿ­5gD Q¬›ˆ`¡˜å[z¢‰Ìÿ‚ld»&ÛcÍ»ç;àÏ~ÐãÍVeFh0ƒЕ³Uœm ¥„¼0b ô<&(:ˆäóBo¸BìS¥®„’ERÇ\8êžaƒ@»ET8Ĺ CK:øÐ3lÒ&  =º‡,ô¯+m©—pL‡éÉi«qx¨«T¦I0Œ ;‰7BTEL²%—8 ˆ †0eµC>¦ÓCšÐÖýE™  š[ˆÐ‰=Ëx3w^HºB«ÞŠ 2@ZÄ!„$u‚ƒPSêWKìp(9¡B¯Uxœ/°ªÂJÿ°•Aa%v–ž  ƒóAŸ9ª3¥r,VHÝD‡GïXÄY î@è«N¯Ó¤%£¡#ß²,ù®U †|À¢SçaÉža‚ Âhâ*ÜÒd°Ñ D¢#UX(8¬oƒÜb‘ˆwP¬R ¥XĨã%(ÏË4tE•ì]åmàûÊØˆ6Êk Ñ 9'<‹åj°K[r7—Âêˆ~ÉãLd~<<Ì,[Ȭe"˜ÀFp6Ÿ €mbº%šäº`©0žœ%Bhq„J˜(Lš6Râ9ð¤Ì.ŠËæh0ªÚrÄÆ¹¹ÂŒ÷ø•„Ž‹ÓòñCk“n5Ðcc(ÿ5®tÁ– y’“6'œ eÆ^ˆ¥+ ÷’Ý„­.Üuõ—õø8ãžy B $ç† Ò5QsþJKpÑV(Ø–J(qŸÕ,3ð˜Fn M÷.‘HæÑš~º`« ?i±ë­™ ¦ÐS)Xá_œ ³X›w¢“¤ màH«ƒø­XW]"Ñf¢°øš9ØÿCF³Æ ¡ÑT¡ ¢ÂÄæß;Ø  È?{SZÉ‚’C>x}‡*I¸óC óÈšeÔs§ÛÍnÀ>…Í+"ÛÚ<©ˆ˜u&øˆ0Bh5ÜœÃÉÉM`°WTXÁÎù[)±RÃA ÁMÁ±F0ñÿFÏTÜ,]œq…ÝÜËì¬GÈ5ÓyŒÙ”\€ùWÊMÓÊ¥ÜÛ¼\ÌMžΛYÄ ¼€´ÜÏëY—Ï4—£à@@„ý Uì`ŽÒñD\å0ŽGÍDœFè¸ ‰á„Ä#DAA¨tÁÁ¥d€¨Á90´ö@UÌSìtT’ýX˜pL]A^1Á–ÉI—.|™$܈ÕZS8•à5ÅP½ð@S¨VÍXAÀDE,œTTaŸéŸHesÑÄ¡Ð!¢QAté£=B˜LÚCaL5AŒŒnY—ü€” «Èž¨% ”0ŒÃøÿÀªõÞ…Ø ‘„"ÐÚ ² %Ÿpé¨ÀC͘b…áúj…Œ Z½‘|‚u}îeÁ’|Ë1|A ÌÁ’Ñ@ˆ±Š«ÄÁdc|€ ­lTÁºI¢X¥á"ŽL[h¬ˆ@3Jé£>Íj àô[jü›{Q`*µ×ºRb¤:Íz!~ÅFH}É€}IAÇ…‡ "“€Øzôw¸à æd{¼Üw0˜6ùdÌ9Åí,@ãÐÉèÜBE^m^™ðASl¬—ÈÓˆ±N™!õ ád’L‚F>Ú^‚$™“t¨$XŽqÿ§,b•0Úa• T]À<=ËVáYIÁ”í¡QŒ ä](x'h’*¤I9Á=i†lÒàq…@ÖP‡ÍeîeQÜZå]UfäxÉV)QÀAa¾£\ÒA„&<¤RfÐhaƒ<`Xôœ•Ú.‰!ê¥ßä `uØ,PŸïD`Á¬õ‹âÚß´á‰n¬b" Aä»Õמ•‚ Âgy_öDÀ¤‰ƒ¬–ªÙ‰LÚ‚h#ñàDN/‚R×ñÚ‘9Šs%‡•†¤ '8&<å; åSdk¶RldÆáRw1/‰B:hkdAJu4àu¨ÅÕÿ&¨rÀ$xÈ$È¡à BÓˆîdÛÀ ) vG€š†°Éñ](€K‰ÈAA/0‚¼ÁÈð.a”Mãô¼è(¼$B¿ˆŽ!À˜e‹ÔÊ ¼(A¼A†a­HäÎ?ÑÂÙUÁ#à!(òËØJå„JÉÝ)ÂÂÁ¸ fÝ%ä—‘H¢¸ÞøÜÁà'-È ô\ÁPq‚¯OTQÝrÂã¡){f:AbÈZÐ!©$ aÚ>šæB‰ŽåtÁ $ D€4R& LE©„ÉŽWÀá¸x´Áù舵}@JÈ™E pN˜”É ÜAˆåÿ΢¦ 3Pèe¶”§ÞAÌÑ#é„Êdü £ÁÒ¿d§Ê"©œKªq vÚiÞL êT)À_+Rõ]Øt[®€ Ù€]„ZЪ¾ØªÄÁù˜AžR$¿™×H¦×V Ô¼×Ô$6`àŒRFN À©ÁÊWHŠ×K–àˆ’MÖäÆ~\‰šhNþ¤ËÅ àíT¤œ$Ψ/H¥ñÊ!BJ dJ5j” 5^Aé`J»°ÄÕœïlŸhD¼Y €~B˜`È,zJ ÃT&”ŒDäË–¤Êòlà€É‘ú‰ÏŠ.*PAâH€c=h¦XBˆÿÍa„ ꈊE|ȤÉ@ebb +˜ˆqÄÖ~b¥±‹ ¼ÀPXªþfèõV$„ÖÒÖÜMyá0D™ø`ƒä ÝZÑHØ&ÀH CHî‰eÂp« Ö•Ê›ØÈqNM¹ P.BÇÈ™> ôÐ|Émì" …<Ä8r_KÜDüËÉÔ\.Þ ™ö‹¯¼¬ºd‰Í•ê4áM$Úæ­‹cͯÐÀ̈+(ê‰äÂÑÎ×mÑJètDE…¦ÒùNTu@……úÆZ²¤Kâ—p$í/‘F0ÑyQ¤YPïH Ó€ä¯ÅžÇÇiìÆ؇nG zìǦ\ŠÂ € œVÂöÿ›,¶A4FÇÄ•F%˜^଀,2Æ`^K¢‚RÔP)¾±DáEàÀÜŒBTW}†XÂXixAE±–âÛI\@ðŠj®-vì¨cžÊ4I¡¥Aòn©Eä)ôDÄšKxñHYEŒp°1fäì pÚ„Pà[ŸµÄ,81JÈ€&°AC„6’ #näG$À¬hÀZ Ŭâ ä%ðJ·ÁñÅ ÅH²EœÀE $EhÀûM'_¼¬Œä \ -^E‰ña…BÅÔ$¿H°üâ  {h$elég|p"ÿ"(†_˜Á¬pL÷ $§äJúF¸òHq''q†+ ÿ # ÜÉè0 ± È ût¢W/à°E82  ²ÐŸÄã '˜ðU”«HnMÀnäÀAìGN¬°P¯ÿë=7z ¬Fò³tPl‡&Sx0ƒè2@;p¹œË±è€š™°äšE4z ´$@t³¯%€H˜žtÄJ_(Hï2lˆ¥æœ´T°ì  €hX @' ÀÒ´8S$P/,ÚÝŽœp„¶ø)\Áô6FEÂI)5œo$`Ä!¬¿z€OÛ´H`GLdSx±5Žì;lGœÁö³ðþ´G ޝ—w{$x«ÅîbÓbGcxÕDÅ€/Üt×ur wØ÷~· ˜r/÷4…¬Ù¨G@÷v±¶û ×kcôЇm»8.QvEÚ³Gs÷ÓÄùX£ì@ ,GZ`ÁÆWxû8e ÂQ5t<œZMŒ¶8‚n¸wÅxƒÓxV“†ù²&.Ì9ÖdA9 zxº >ÅʶDÁ…§’i'j_w”33ì1ú;º‚›¸Œ£ø¤£–Q9Ÿw·Ž_ÿ §¹x‡z¦“$Aûù>¹‚z„œNž³õóúÓ\¹ŒÍ b¬g9NzùÚXsoÓwtÓ™«os´¨¸»6¹(J@ø„¶6T$$kDh¬g8zÓú}Ûº{ãÌu úÒ˜ûûª¹n`÷³ïz¹¯úÁ!9NÀÆiÉ;qXAÃÏ÷‹Ûw¤÷vÊ>Í/Ù`³kôÒ´®T,¹;ù  ¸ƒ¼7[r ›¨¬Ç»Chtp´vÓ¹FæøŸG,°+{’7{€¯;ú¢9ü–ûnHElî·Çëôþ†<¨üÂ1 žo·Ì¼¾ÛK…«F{ówl0ù‹Âjs®Y8¶y£kx½S¼è×é/~´?=²Û|Â{€OÛËC;Á7þ¯?þÍ+|ÎëFîëþÀ;}ïüÁFþÂë 埼à§>á“8Œ‡þ­~SL;¶g;µC4rŸ=·Sˆsg™wþ¬~ë[ÿë£VÒÿžóþ±wí »ä7î/½ÀÃÿñË?@‘!ƒTd\(PŠ‚DÄ"… WªX|h‘ÿŠ"R&f±èP†Ç…œHR•+)Sl™ðdÇ RÔˆQ£EŸ?†9Ð$JWlù¥Äƒ4QÚ´ˆsbÅFDfQ*å ‚ ½^iÒ`C,g_zÌâУQ£*”k°ŠC,L}™èؽ$‹žDjs K˜Ngâ,épêª;3.ì 6áX‹eÁÞ-©×Š×‰>ßþ¤2š´Î‡[rôèwèæ“GU^z¸àSÅR!:Öy1òÆÍ€¸â ~œùæÈ™/Oþœzuë×`°{wïßÁ‡g@@|ùïà.=@3/ Ä*E«^®]¹F•Qv>D¥ÿbµº""ù@ê˦³ êȤÜhú¨Š³JB ¡ ¬ÐÈ+)êºK¬ý£L¬Ïj3 ­ÍÖÚÌ-ɼ¢i.ˆ&z‰¡ý>ê©Êð§Õ„úˆ¨žšŠ%Ãz” ¡Ûc0§Šxëi² tÈŠ†ÂŒ+ŒP¬‘°0Ю³æ[0"…„±™n оÖ 2©ÂðŠÉ¶šŠ¤j·„zí#)¢8 ¤Íô«+…*: ?#ä¨LÈÆ¯ ü¬;LK¯«²Úª«ßpxé~v žþv鱯}{ë­>zôÇ·¾tó×gß{øÛ—ÿýãëg¿xõóG_zþ“§?÷ P{ñ`ûÀç=Ù].}ô  ÿÀêA°~äë_ñʇ¿0y\^ÿ8ؼ҅ÏväÞÓÀ7¿!G9…s¡à^hÆÍp;Œ£¡ ×ÂÇõ ‡Ó¡äÄ¿õ…ëâ ‡óÃ!òЇF,ß ³ÃöZKüU›(ÿ¿Q1‹‘ƒ–zúF!F±‡ À—“F,2ŠÌAã¥èÅ6‡Èñ¢ùæEiÁqŽO”§Å'1‰NdcàªøF2q…„ ¤‹Æ>2ñ94ä “IG*ñy„d%»ØÈMÒpÏJ³É0®r‰€ä$&G)ÈæÄQ” ,¢,cH,DæR†4l– }é¬IfR‘Ë)æ©(9ö¨’‡{lftøøÌêàq™”$5yLèøm—”¤slYH\G9´ô#4ÙCmë”;t%)ÉÙžXFnƒœ§(ËÙJKŽpìY£8™™OR‡›÷|Ž@úN~"4¡û ¨<©ÎGâÿ¢W\¦( :Ë]ºÓ¡Ýè#õʃVšx„F'ÉËbu³pÁL0gR6J3Xhäâ-úÑ|^´:Ú£ÿVO6ú4’¬”)@=ÚSJô‡*,™ Ï~ö”£“¤æ*O‰ÎNr²”:m9 šÑ®V§òŒêBIjIˆž5§dí§?í‰Ô‘z•¤lMjDßzŸNt®n-'"íÚW¼þ•:&«JÛR—" ¦7œ'XŸ£ÌT¢T²Ó4æ5ÚÅF¶o?Åâ³xŠ×;Z¨¨ ¬FýúÕÂB¨ ,Y…úE£VÑ™jÔëV¥ÊPµ"Ò° më`U;Ò£òµÀMk ‡ËÕxÒ•·ÿÎÄ-Z™»ÚÛúö®W$¬p§ÛQÁZ7¸³të^•‹ÜĺðpÔáF/»¬ô2ào¡M$f‹“MTžT©è¢m? ÞÜ·ˆò´©LÙÎDÞ7šxÕ/tå[UœnqÀ V¸¿ƒiÅÕ«õxkѹoÁ½\Ù §)©­ƒn„â·1KÿKž+Ó†2´}®Ë”ò;ã×µ¹´SŒça³øÚw1ÅAŒô§3\éF¯vÏ·nõ¨œ¼ØáÊ—Þ|KÖÝ1×uD'N_¿Xî7µê§ë͵‹ÙÀÔ™»œ™sÕc‚:Ôö†¹Ìç\x0ïšîw¯i­æW'=êWŸö¬%_ó{é Ç<'öŸ£ÚëWtÄGu³®ÛZ-y±Ðî•¿4ïo†w$÷¾jK½âÆ-héy~zÊïÞòÐtsÞµÊYÀ_>Í ×|«Î0oÒ8ës@‘³9™££Ó<¦²Ü–i/·Òß`Ѿ¤o39s™hÅB;ó:»k -Sñ19¹s2#°§3)C2»3 %Óð.ó5/ð;ãóÇ..Û³ÿ³.”8ç“?óFùñÓ kýq óÁQñJ™n¯5ô3GTJ7’%‘Т֨–JrEM2èè)£iBwòÏS8;lJ±³*i´GÕóGÉ),-ïMý1N HsÔ3‘­!Á5m”óø4IŸ2˜,`½fïåÎÄÔšblGGPŸñ©°H"0ß"ÇMCÏÿ˜é"‡=ÿÃÓHÇsNûCUMóÓóÔTƒtÊRõ%õ/åt:NõF•LÕ’"w²óÂò@…QA™T%­Ê©0ÕEƒªšþ ßöRûqø†ÑYê ôIÕJ¿Q¯Ñ3‘Ý3ù’0gU@q•@UGß“Gï”T÷ÓU÷”Ocõ's2^ñ3ú|õ\©õ@Wuäbðì–ÔȦSçÀÕ4Åu_¥oPÍõZE+J q76¹•$!´œÊrbÓÊ#‘ƒM?K·°ÓvÕN¡õRO«]@×5ZGÖ]K8ÓTV ö^“N4IS퀒.«Mïó4cVZ¯#_ÖdƒR]C– +Ñ™˜•Mÿ½Õ>gÒgíh÷ðVû^¡¶WÖV_U•HGUe{“dϵeû°ï‚UX2-ôX5µYÕŠÔS%D!°²\lßzÍX{hè¥2•Ít;ÃtsÍ´Lôo‘ qc[ÒMõc×2eókE6lYvl¿µh#õg³Vhe4suöYSp¼ÔÑÖ¥4c%)UaÿŽQ ·Éd”Ëš¶•²#^w9#×OkÔ&£Ncµ1+Óus£¶si.­¶`×rµö]ý³xEw7ÙµV 2ê®wä0à_QWŸØiu#vxs×ByUpwÕR­Õ‹Ê³½¢ßβnùnú wwöpÿ‘õa­ÓÀÚ4&aTv{Q#;6ù 74vtÁ¶TŸ—l–-™k×sed ¸r« ²9o6mÝöv·tW!¶“@ zx9(p·„{7\'w\}T—Þ×oñn[‡J¶²læ<8]’qVs§·H¸]sXrÿ”s8yi3DOôná6v—x쎳èx©_YÏ9µ#ƒÇMQ/2ö%‹ªEÛ–:¿¸|OØp-ìB?Xo˜AØDí6Åømï … ˜®ÆR‚©÷‡­‰ÅS‰ßX~]¶gø.‚±}¸)©ø;ítƒ)u]+„Ï~Ãø;yöiY>[5ˆ‡61y…ÿ½E_uyA¹yØ#-Ø™r‘6•ùXH»VTYX=3h­¸fÇË‘} ’Ç÷J; |=TxíÎ#˾xˆÐ÷Š$§ÂâHaGn6}…w±4ψޤԘU• 9–«v–»Ùa™jáUœaÖ›÷Øœ«tUŠ—iÈ—A²WØïô–›Y‹S´í¯åª4M8Ð85ç,µ†pƒÝv1г• —Ù"ÅkÑ•¹ôˆÙ™hC×kk¹z7Y••W¢ë•œ¿ùssÉcžgHž53Žc1Á€5šç8waZZ*˜³-ðÐØÓÚŠzæþ™ñ›7+‘¹³„N˜ÕX|ÿ‡ã¼Zy£õ¸£ÁaaÌ|é¸OU¸ˆÕª/Ú“ø”«˜1™“P¥¥3­~©ª¾W†õ×î´ÙšÎ"•©sX©-ÖŽ›XEéY-:K»Ó¶zú ¹9Ez·V–¥W£Cy¤;œ›–Û°st_}AÉzåÌ:oÉX ûš4O¶é.¹«Á“mñk”§võY5Ó çš­ëZ’ãp°'Ú©)˜±¡£¯R±³º\éSˆïº‡)z’ßðÛ8 1]õl¡rXu‘´y2_ ¿”ž«:W¥[¦å"͸5«Ò²vÙ8©CµÛŽjº»›õ±Ç™%[[· [«ûœÑ›°ÿÕ¾o{ŠW‘“ï²i¯I7;}q¡S˜`½úúέ˜O+#Ðoï×SU-w: ©TÐÚwŠúú÷š:²í›½ÿÛc«Ú”±ú½y[l;ts²w›Ûrù¸‘ûýtY¼·CÁ[ ë+礳ê,£›ª³[‰—ýΦM<8é[“GürK|ˆ}N9úÈ9™¤ÛÅE¼lÊe;¤ëÛÉK–²ß™{٬ǛBÝÚ/ÜAASɯúwiuÃ}ûʯV ÚCíÚÍ39P¥šÄ­<ÃSüΑ<Ïe¶¢Ë9¾9¿#¿åÏ¿õ|Êù\kËüQç[^Ïû³3u}G²®¼qɜԢ¶ÿ<ñDµ³Œç™Çw8£¥<Ë©¼·“|Á=pÿ¼€ó¸¶×»ÍÚl`‘#mŵV±’`ýÕñQ›¡Ñ‘wõZp]ZŒ•¹£H¾rú²HJ"56¶¥]˜ai¥UB¸iû•m›ÃkÝÃ!ÒÛ­ÃøÃAúÍ<ÕI6¶i¥•ãºÒè½Þí½Þã€ÞóÝò}ßùýßÿÝßûýÞþÞÞà-¡À@áã`á¾ ^á!žâ!þá/>(^â7^ã'Þâþá9^â~ã;¾áIÞä?¾ä+þâ#^å]>å+~ä3žámžäq~âž 0~ækþåo^ç;~æCÞæk¾èÿi~ç{Þè“^ä1žãU>å5þæ_^葞êE>ã¡~ë³~åsÞéižèq>â¯ä«þë{ê#~F~ìŸ~éÍ^æ“þèÛ^êcþâÙísë¾ê7~b>ìç¾ìí^è‰>è¿Þì?ä¹^ñÁžñÝ^ç!_ï%ßâa~ï ¿î;Þéûñ%þó?âaàê'ô]¾åA?õCä*àõa? `öi¿ömÿökn_÷mŸ÷{÷+À÷wø__øqßøŸøgù‹?ùÿùsßù£_úiŸù—ø‰ßú­¿ú±_ùµ_ùaÿûÁ¿ù¡üÅüÉúÑ?ý¹ýÿûÝ?øÿá?þÏ_ùe¿ü¯üï_ýÛü"J… .(Xð Â…2¨pać+Z\èð¢F‚w:züèÀã›#?šI2eÇ’L–t™ò¥Ê“+iÊ,É’&J2yîüi³&LŸ@u5jóMÏ™'qvlé3$S¡FGJÍygiÑ¡\³REJS*R±aÁ’Õy-Xi¶u»ö«Z­qï¼[×ä]³yOî•Û×n`½q¡Â]k¸lß´LÉÈ1Ù²f9•9w®ü´Ïž+O.„ Í¢%Ë}4eÖ¦A£Îº¶ìÛ²sÏî͸iÎÁ{Óþm¼¸ñã¸mví»ùÿråË™WÞúúnÙÒµ—~;»öí AX¿>úøäܵ‡×½ž<ü噩»/m?~þá¿9?·Ý^|’ý x8_gY‡jê¡W™j ÒáqæMx «Y—™ “àÚd°½'ÛÝeš #œ"e¢¸jbxà†û­·!æ¨c|<öˆ#{føãƒ(jXÝ㉠rDzà‘LÊçdë)©Ý”Ø%h¥~QÂx ŒTžèc†b"pcY™–I~ù$Šg69är *PÛ‹Õ© GŒÇifžt®É¦›×ay¡‡ÂÙ%›ˆîÉf“d©‘`Vjiœ˜¹ä¦’Fªh˜Œÿîè)¡R–jꥠ¥Éi–¨¦ªé«ëµ(› î ˆ ÙZ>º\¨ŽŽZ¦¬TÎØ$²Ÿjì–©½Y'©ÍÂÚè´™V;­šÔJkí²§v{ì¢Ñ®Çj«‰‚ë줲©ë³åÉ‘@|´VèxÄ‹@ öªÀ °yÅ)Tp€„¬-`Àq !l.¤Ó& qÄB Ú \<±vgLq…ö"`@¾YÜ$x°±oÊ.—ðœÆ1ŒqÌ_'2jÏÜk“7ì° žù{r2ãÌr¸ƒ–2BëêruHÈ@ðÐR·Û4ËRTQp»S7,º²%oÕÆ‰\Y¹3ƒ 2È £ŒöXÿœ±ôÖ Ë7ÑcM7m T€Eþ¯­ó"Ð.ÙËñÚ®ÒP2 ¯TDogý‚FÁ2”ìñ×jË–*8ÐZ_L®Hqz|ÛhЧ  躾!Zä Ìþ{ʰ¾ôðÀ‡||ÈyÓkÀé3¼{ï hòÕ;?tdˆCØ/Ÿvô•ùŽüï@,EìjŸÏûøÓ—ß|Ä烿»øJ¿¯|üá?]2Ït¿ƒ<Œ€~ò£]í*s;äi û ·>Ú¡M 8XA/Ö2Ù¬ìnH»˜€€ZÏ|»àïT¶ÃÑN„&$[Õêg8ò™m„ñ{ÿÉQ2ÊNbÀÁèæº\äâQ@ñ²FCö•0d0žÝ*CÁ `ø€{!à Òb*SE" X€g(ÅÄËŒÈø$²>0"#ØÐ‚²SØ@oTx1%  Ђ|p:%ü x7`Hx/‰K¤dø €Ä9€!L˜`` KFì¢T)) µR†ì”P iJ°°n-üZü0è9‚fP%&‘7KZJŒ F8ÞAƒX0“„ƒ>Ñ_²’C[Ö¤ ÌÚ|X…R°!륒™I{Ä(@l†Œš´C€íÿpW¹ÝéêóTgó~§Í¢ 7í|§ã™°7Ð` hAßpH¬Sˆ% I l`xC ÈÌ$€ŒçìB dYDÙïÔ¸Eä)/pÏÂ"à‚4´r!KÀ’ !Ô¥Pƒ&` ‘áDúê)npDl˜H!¢2û‚!n €1h ÆÀ,p'¤Ó„‘˜XPVˆ!fM}žÖÖ„¦¬¡ëvŸb,®ºBBZ÷´Rò¯r%lÑ… “ž€À 0`&Œ¯p5+ ÐJXPV ‚"Ю¹™•³£fëvÿZ™‰?¸ƒbÑö¬ Àt‹EÛœ †=dÖ¯‚,[M«ÖƒTQ‘“\Zf}Ü X–«Õl1v‰o†ÖÀ5nÔÌ€ØaV×¹š8çíÉN|Ððc=-i0Æn3Ì'èð¨;R¶7($L`[ˆ=‚=.~ …@Ò®@ Å–ZÙˆU€´µDšjqƒ' b„›ÀT@š–´z—U^<;j"Àoœ V " |a xD!n€†TÀ ’Å €Z/wâi…IÀÁU¬à-`¡ }[”PHÝš5… EXÛõOÜ „ …&A·)Å ¦u„ºÐKÿd! an‘[4…Ì#¨ÀŒô=7f‚°«ÐòÚÛÂ} pŒ,·&*A²IH<Øb&¬o[n‚f“pJø7‰^B¤·@°( 9ÑKs[Þ &·™á ’0²–;Y+¹—ž\& ÜœX'äËfu©@ä+ÌWk”€PU§z͵^€;HÌyj…À)fKNÍžŒÍgˆ®ˆk”–Ì×Ä,±_è9Á B3B#Fm†|ákàì¼°e¶šÈÖ ÷k#Æ:„š– £¢¥L‰hV@Ù.·™÷,åHaßsªÍ†&<›@àÅg½Ö)Á¯yàÿ‰žëàí`øÞêåO‰¦Ì¦ÚÛO–—yDVúdž.xoÚ]xw+ùËD€f»çÐ…–èÊú~ÈAPdë.× ˜Àê°<;XL€†Iy†Drî´X®€ë.x ˆ¸‚¤ ‡.¨  w¨ÌÀåf*êÅCøÀæ €ÀÆNø…;‰<ó`Q ƒ¸÷ ¯>à mø€|.`xti¢x2Ä^< +˜á «o]ù€øà‡ }A2`†'¼  ¢oø+Q°…ÁÀ™„ „  Áâ0Ý3Ôy wMž/–ûП^`¤Dgçå.@MÿÈý ðûÀ3Äà £ =E…(Þ Dl-ð?Œöj쿹Á‡g7À í.ÀøOà$ž €x€##¶ O {5@´zZ ° X½ôO€jp0€LÀ} Ü'€°|´z0zÊÇpÎ7QH —À} µêGžuH¼<ÏF[¨U10+]qL·W€"0€h P} z 5 à 8Vw ‚èLÆx#`¡7‘ +4СwzNpx¨U¡ã¡‡} §+¯zà„0J€ ¨p~é·h(zÑ×m¸xæyLUqÕ³cí£4ÊÅÿ‡ ×;‚Hˆî#r×SI¬„rîUˆ*¥_R6 Å÷IãGz"`5êN±àYqÀeKóx“ ÷§xŠ5àoZ¸‚ƒ¿×…^àL ÖWLµ¡`a¤„1…ðŒ0(ÃLÀpð°€*`È0&ð€i0@Àº÷ŒÐ i` Ê„ 0 7` -à/¤@“0 ЃÀ]è`ðU9€çtPð=•Ç`9`Êwx Uº÷d² õµcàS éùU|!`Z°5ƒ€~@Š À‡txÃW|y5 0‹ƒ–ÿ‡€}ÃÔ ’cµ|èY7 Q€åK›Vʼnc@ ”JyÅeY—p~`°ŒÖW…‘¡1xx~ˆ B@•Ë ð)€àtB@Õ„¸ÀgXµ“ׇ•9`…4`Ä’_%& „¤“t_pNTù‘|ølT•2M‡‘Ò˜Ñ5˜¦~v°x¯ä’gðT™>e”iy€` ™±—[gTy@‹§8‡çP‹À… @HyØ> NzpðdF5˜@3•–àÀé—jés‰U“ׇøô9ÛdˆÈÿˆ{‰‡x?‰HB—4M·cõÓˆÚ‰Ù)‰%9 ö˜š,p "€U¡·ŒyyX5+ÀsfI ±…iW)`8p$`7LPHe‹÷fY S¼ÈU/¶½äZ€ˆ€ Ëø`y`xP_àwà ÊøJ'†/vÊ(PPŽN` }€/ÿ²Ž»£ƒ Ñô9ð1V?$eæð( ãÆt²u` 'e‰ ^ðm©2ZG?TyNGZ úL* …`¬¶NiÕfg¡©WsI ¹À8pœÇ® eФ`šÿ•†‰ hD DC ‡°]¢PÉ Yfð‰ÑD ‘6떘Ã°Щ†F˧Äg„Ešëv’Y)E1~ffV†j@ Àƒ2Y9¾p§k)opÏ–[lH‘ 0—p• Ê‚f`UÐBxCðT‡ic˜:   $pc-  I#ƒÕÄU°|£áLJ•Ê{ju€ ´K 0 q¹!ÐDÞÄ{˜`=¹>¢`À7¤ìf(Ÿi œ¨§¹¿f¾Å°¶4UÖïZy¼çMà4¥aÀ VRYK§)` ðrV ¡ÇÿéP ƒ˜×YH³Ù©R7‹³ÖI;›³=;žäY³pžsHÐÞú ­}ÐtdJPy:‰³—Ÿ†ëÖ€9«<Ð$  oŸ— «š§OP²ƒˆh¡ NÐ.Y”²'–—p`Р À`¡¥@ Š€°–7ðÐyÐÔ  7à ðb Ðp Ðs`c0¢p!*u=*Åg¶95@oÀ©y¤ñ(ªM*47õ¢+z›ŒÊ±õY·@•X¦Àj º| I.  ð]giµ·hYÂg©ž$y`4É|9™YeÿVMHq@q˜`H´‰‘3hV¼f*][_‹FuÕ°/WM]€Œ€íë¾ùˆ=¯UW–à ãXWËû½ ˜ØyfÐtaµS`Ç»žøY} à=p*—7 ŠÏ­#À°½Ô¿¼— MW jpU¡`¦µ9M˜Wé­±©P:kãjVý‹ßÕb›@ÁÑ$‰,P‹„‰0šùS¿°hwÀÉt“°_ì¦`V%°çdH±Õ“F寡 œZP¨1jp~/0•F—´H½ WªT VŸås¬Yg@§%ëdd\H. e,Ü]³2ë³v|Ç.|ÇB»Ç6 ÿ´¬†Ç;[´š¥EüJ'ÉPýåLpWAú…H5 טµ %‹ñÉðl[\(ªMÇŒBI€lë àMPGXÄi5  `¦ãü7Àyà jÑt™&2@Àt[.p¦Ñª+=*i`cç8 „ÓŽ˜”6JóÀ]( P•¿GUª {(1®ÛJ_ I Àªc<€¸»cåÀ,¬“Úb¯äË`èt$ªb+§y&Œ`»5@u5–Ë´„U¬Š‡B“¨xŠSZáú¦ž%@íL«†¶|—O‡©–Ue`P•W)ª#»O…¿(“ÿ§Z®ÂêU<9aú¨“´ ¶K¼æôYõ ÁºR¹q@¬7°|ë6  ,ì­ìÁpU {¿—­:¥Æ€z°ÂJƒÐ¦`pÊÂ÷ò6ì§•«Š’¹³z• i£çCNxÄ)kÂã {‰`ˆ°Ð„ QX5ý9y-øµ«{prМçüž…ÆoºÆ àYs­{6êk± PÇÑyq<CC»ÇzÜÇ|2A+Ú!eG\’™ü€Èü%Kfù­!ƒ0 àðzýº›š¶|Æ;Ë'®²uUСlC³` @u¦L6à­ÿàs "À¡>À“n$–|ð;»ÜËi^õ³Et×c å8iÐÌ @+cQp>ºp åÑú ýJ«»¤ ¾ã²`:cM—©¥JöL0é̼r| éW)ë’:»®Òk:MtDãXà ý}|W§M› è_J@ÏV\­þó`©ÐGˆU[ÌÜñ C£<°`qŃ'„Œš\@R‚ÉÀH$aL  PFðE f<ÿx’°aji*к±¢ÅGBDP"À n´ÑTèÆ„¸¾Üp‚`Ö-• ´Ï Õ%hqA¥Jª´jBƒA 8ÿ<übôh‰Ì 9™&+|ÑrCËè²$LpÌ€>þSÈ0±Ž¢ €@‹ ´;#‰ƒFs‚‚ ae X©¤ã&´* b¨N|@Ä|[o0 „í3ޝx `F’ëã‰Æx¥3lQ!à! H‘`=Õ< Á‚&]„±¾‹¬¤G惒*XàŒPn ä)%žX/ÄB¸A•“«Éën R@lÃ8ÒÿÄ`Ž32¹(ªºnâÁŽCµ;n¢Ü€36»|¤J(bšüQ$¢…30 O%j©nÿk, 8ƒIöÈS&0C`Q ŠØŒhª <¬ûŠÖY$¨‹¾/ 9È‚€D€ÑŒ(¢j,òо9Ðç`D9 ¼àlHÁ À†àÑ@&àÌØ0åè @°€(àU´èrV2‘µ$j'»RCY’% a+9¨KúçP€€™m HYòª²D;H€hÅ$ ™Ž–Î$tä(’;„Àt¢.5øÀôR[iÌK Õ˜I¶@Ÿì4§¤<ÊÃ:©ÉS¾àƒ$BNº1£N5¥)s‰éJy7XÀ‘©I*SŸÂ¤¤,ÁQI»žòÔ¬É *ZzV¶5«-õ’MYZ‚Ú´$Åè›LY×¶ÿÕ&dukLg*Õ›<”¥‚])[ÓšWÆÚD¡$³+G‹ZVË*à¢`Z([ezÓÂZ5«žM€rTÄ& ]@ÂJD±Pvù©gDeƒ&Æ$œa‰g&³âò6ôYê[âÚvÛŽJ"“±Ô:Ž%Ði­iŠZ8–°•}-w)Ѹ~·´ïy;û\óÝ´CUEol»ËRÄ¥¼YMhh•—Ø—ÀöI@ƒN9^ùjl¿†Õ$ï{Ú\‚hø„ ôÊÖŽö±,µðwÙ»ÖÈ<"¸”í]3×çN82†ïzek`õ:Ô»$F H_ìÐϤÙïŠkbEfÿÆ­ñ‚·[àÛX£)&°ŽëÊ’"¹¿ ø$J~ ™ y¢é]òXÌ`%û4£8Vñ|³LZ–b | ð€gÀä µ›ˆBg>…æ*`%v–3¢fì¹ÍV£Ll•+ÊWÁ.’î1íN|T6þ¬Bië‘9¤6m´Ñ77'O7Á›\n€yà>-¸½Ùo¿4ÖÛ†L·u^sqÇçýù«¹j]öÝ0¿öÑ!sp±æ5é·f:ÕÉbõ«/ý§3g¶ÃõkÜO·Ì§ÞôPç{ÜR§–i.v›¿ý¥G3Uç~vžC}ßx‡õ—ÈÜi +:ëØ¼«±Î‚"þ„WzÐ_ö÷=ípÏ;•S½×U÷§Çžïh¯¦àVÉâÍ=¨ú™¥(dL¡…ÿÉ£ ÜÈÀŽ ±åm–\ŸÓ•çD¬d‰«Ò_5Ý熽»'®Æ†ÿèÈZõl¾aƒZܵC½%f«ç) ü¾*úc2øsZÜäÿ>ù‘ÿ}j½V¶~þ®u8±üç »¯ÊXQDæl°¦|û¬¿¸£¬‰ ¥’ 1s?™ ¨Gc‘`H5ñ£¿©r¾~Ãh¿ £¾¸ë9×Ê) d8ö )î)’j¿â?䣾åC³ƒª¸ ù¿â4À¼¿žûº¸2 )+ï;Áð;>ò[AEkÁßK¿çc¿éÒÀéÃ?k»>ðý(ÜÁW9À4[?þóA$"û#?ú3’ÿ (ì+ák¿¢˜ ®3BóK.²ÂT¿œ.q±žx•ð’ûã3èÛÀ ¬+)ˉéC³5Ë;ë‹@ A,ăÚ?+ó¿À< â@ìQB"bBÂÚÀE̵CÌAöâA?\Bé㶉zÂO¼;DÔ>$¢8,ÅT4Tì@«š¿DÔ $>!TÃòÓDæCB8ÌÄïkBZ4ÄU Åõû#l¾¢Æß³FŒ-$¬x$"ƒ¢G"J4­{ì>Úú'}dÇ~tÇa¾†ôA7ÌG_?~dCÓrÆôŒh«ÃðÂglD–"œ’¼D<¾W[H~ÄÈsÔÈï“ÈŽ\Ã`444@GMY’vÏmmm+*+&&& |¸TTTMMMDCDƒ\…†…0--ppqyyy‚‚%%$aaa666???HHH’““~}}»»»PPQÇÈÈ% ///WWW45:¤¥¥ )4¾¿¿ $ŠŠŠ\]`ªªªZZ[0*%+% #(71µÀÅ6HaVdt-ÇDC,₵ÎÂÃ¥M„M¦ÓoÓk@ànCöÂ× [´wZ‡Ì7f=-g6Xk{¯–ýÝÐ,pˆ¦Ú~wÇR¨®ÊXžv"¤¶ÄôOù¤VQìucµÅÅvÇä· þzSk'ôƒØ;‚Õz:‚# ÁS#ûCGؘÍäUÔ|íASꙟ’‹ÜÎ9wov!ƒ(¶:n.O“Š_ < ¡…¢(}:¡Têû›Z:a#ÇÞ,˜jœ#,ù"œkÖœ0Gصý31éÉÌõ×Ð6‹[&Ǽù|ÞP?»è¨”äcõ³®²áV˜!• ;:†gñ’s.oŽAˆ‡#˜åSgЪ‘¿Ï£óæ}†ð ̶°#‚ÐJƒp«E\ah¹1+¬®™ÎXž 5³ÎuJg\æ[–ò.GGõXN~ÍO`žÔe·|CÞ1vd¹¤Æžoé¥k"`j9öŽ`À˜ï˜õÓÍ@K/0ë§íé6\=Ý„fÅP{–˜ä¢íud¦œ”V!XiA¹f¢.ÒØNs‘2…Ú³FÚó±Z߈àE8‘Œ J™Š ™Û)õM—w$ª&œ°‘cíÒ`H A èÂ&<ß´>*ð‘° 9ˆH‚0è»1®ño¹‚z/SBÄÁ]ÍW cGûй´¾¾¾:à CóóÁÉ (ùtkkë)É…—X@G0èn6Þ,xF¸ÊPÒ»AAGT]} õf:‚-ô2l(¨7Ól¯›# &Ø];Ù¤ðå¤98qø&Žꊃ¤WÒ>ç¥dµ€Vª\N„‘Þ½ß_mç¾Ô;«å~28’8À>~öwκì¯ÿ1ê¼åîLö¥9Æ~)§(ªîݽ ‘y¢Ø¿¦Aâ¿ÊL¤æw•gqŽ… ãJ„‘DbŒJ‚(?+‰ÇKRÛ<÷ y AÈR ŒžÁˆ+¥ú0Â@ÙìVZ:¿ç'ÜVwVë]2ŸM\¬;õ¢eĄۦÆÇ§Ú~wÔ£U×âèÕd6;lÖt‚uÂó•ühnuõÒ\íŸw'! £À‹‡Q)lB¼eìûê«•}B% …EÑ‹ ¨ ƒ¦,«A,£ b^4@ @HLÜ7V[dèÎÏÇ•¹ÙzB°›#hèά9•ðºó´–š+L×JŽ\8— š.Lˆ)ißõ ôMMLLžÆ€põÓÆ3o-\PõŸIºýlÆ™‚~–¡:ÅN~´:¯1Ïýxb÷™GG%$ó°r’ !þŽpù¯+++nE)*ƒ¡KÅ !Õ‚YÄY†ì$© â§p졈U\°3•Y„\*Ü„„\L`¤Lèæ„«ÍJgµR©Vß$Kt:ªÿ¢’R_“Åö§}_´MM}Áf@x4úþ°Û}iu¦ypnÎÝ=æ~¶z-€°tòä¿/ÝßV2_GqÉ0Gˆ¿ŽI .óD¢“ÉR¬ Á”jà–¬DNNÁ>á˜Çgè…©LYDòX¥E¡ H4 íÈc@Ð+•J¹žËß„‚ÒÒb6d´ ÜV»Jë´uÝæóç†Vüi$û³˜:ÂѶñ³oŒ÷ Lµe@øÏêÕ{sÓy÷æ®_~ÖÚø³æz½Ž°ÄÝÙ‹#Ð$†rAˆ›D’‰¯" ÓZ\Z‚Êí̲¯Zp~Î>A¤ 8¼D›ŽËã•F˜^yA ‚$ÏóÿÉõ>8ž9 r7Ž}ß8ðC¡‡r5¼· ûÃo:*®œúcÅGïÊb›#o˜J{{¼ï»‰©ÏY! ¸²íÒ{vÿä¯~h=ãÍ܃î¹Ñ÷÷’-³“ôŒ Ax5ž 1K1­Ä¼ptxn^:?÷¿ì[oÛÈ€- ) )«²$C" Aâ¡•J”x‰•«‹ãL²fa-… -Ší¦.°Å&-¶m‚$[,úàÞT4ÍÂ.(š1Чû /‚6?¡@€}ίèºZ–ÉÇâ/àÌp8²ÎÇs‡3ָʑ-S®F+™<)ƒ;mJ‘Rív;>ÁîX^ÓíÙbFÁ²kÂûO<7òÛʵ[ܽv‹zÍO0d 6¯?Üz°õpgÛÂ_WøÉ—7¿ýóò•§ÿ¸lÝäÿýø³Þ'Ïÿsƒ€âäŽR¨1ÎãÓ"ÊKÑ(ò¢ëÍA3zÉHG·DÑÇ¢hÄëG±y!‚ ù¨qŒ0L{™knZR¯+•i‹Ðá®mná¯ûñéÒõÝ·¶s4ö€ðí„ó˜Ûm¹Fßÿâñ——ÇhÅ Œ,ŸŒx,l™eÂY5(ªU¡Ž#Ø/^Œ7‡!çà í†Â÷SO¦,‡__8ssskkswk36 „ëO?»·,ÂÆß¿¹hË7Ÿ>¿÷r×ÈݶâDB8 œ –I˜aÊ‘’.Šz]WŽnñÔèu€ÐwÌüÐõ¹{íoùQ p{‚çÇåÂWÇBa}ggucwg›Âê?ûá÷ÿ}öOÂââÇÿ:ÿò~„tÐîP£4„S` œñ¼Ámo?K¿À"–%Ê)´onÏw4î=¾D'¿K'¿Cã•(×ÝÒmE+A>Q9––bîþ¦¯¯¿|´‚–«wÎcëÍ'‹„ÐÏ~õõÒúý;ç?z´‚aWêwÎú ̉N„Y!!tëÅfW ÍU×È=k[Ž‚öz@pMõ{Ïp±Ôå0Ì+w+åEÌ^¿ƒ¡u[\\XBë²õž:v^º;}âÊõÊ}©–“Ó~OO¶Ü k5¶é™¿¨h’zÝÚ*~âÍY„9x Û™àë…*uSQŠìT¦ý@¿/Íèìó9–£GÐ^(çÆ³MF|ŽÌêÕA`\ÌÀ5Šz<Ó™H¹cƒy\®Ù‹@Ëü‚€ùø#/Ÿï Ä(ƒùCs ‚wÏ(@Gö uF@(ÌAÌæm‘${'$ñy!È:ü åLƒ€HÐì.²œdm¹î€àÈY›Âpì~*žœ1€ßÁ‘ya ©xq®g±p@˜g(iòIeæ:7)R39OàM ›;öõ”‚~ç©Õ™º7}_78à¥ã× B„|ë%*rS à8ÝK[›ep[˜™ÁÒ¿I¥'òʨh¥©¤’ (ˆ‚ MvÂV‚þ=çqBgY_ò¨‡áíÿ™Ï÷ƒ0õ¯$g‚°0 J …šÞ±zP æ$@HÈù½6)PÐÕª‡q]5|ãæ°yC›Ð]&!l1ÁÆ~4`©„g~@X˜Â!d.AHëP† Úžd­dÊ OÐwX&Ü0vc@ß” ÊŒ-Ìd*y2`\b¼>¡Ÿê-5D1Q–Ç ¶  `TÉë-žNƒ°Ü+bØæ½õŒšFm%Á¨‚¶™ 'BN~¿3 Bv@8  Ì»°Àð"öEÅJ|t䉤9%ˆ†®DRá”"JeJö[™‰@¿Œ8šÒÐ.ˆ@$Íq ? .v3€J¸¬zheò\Ž@°kCõD;d&@ˆ†…¬ˆŽpšãÙòµU)Á3x:%0H–*€ óC×  K£3+¨º :ò'¸´ Œˆä8jd„ð‹*ñŒÕfââQfDÑ)%欂>^^O`ØÂ2ö€1N¸‘¾F>RU·u½ék"(–‘'Ò©”Lõ ºè¨Ê“bYG{ÜׂPβŖ]f » m• “Jí×*bB³R=™:mBf\¬¬Âí! Œj7B‚˜åézQ䩦Fdà6ÔM>ŽšX@“ó~ÎÈû‡ÞVÂRºUë‘о†³Y5$tÔ(áûëù"-û’•šŒ¾XÓo5xà¸F‚°_‘‡)ç˜}YKØòdy÷]Ψk$‘¯ ¶þÅï.[þ}7_Æ–1ì{v ¶ßC¶þùwnºG |ùîo>¾¸ˆYŸå_´þ°¸dÏÚ»»Q­e ÕO/žzå…‘hÜGQ~Òh¥Œ,Šºå’`vØ!¿Ðà Sþ€Àíl#ÐÒê€S;Õ뫯îφ{¯zþô}¥?öLjÍ0¥t~ÔÜg.êÚ‰ÌHfƇÆ3ÙD5ÃréÕØ©dì\S"ô =Û8ê…<±ƒœu‚@‚3î=_©T¡¨Ûì(¸ ±›" f º”õL ³ëõ"ž“ˆÌf¾z¥›)SÞ!†e`;\SÐcÒŒÃ@#T’¸ ]‹¾_ïP•×íq¥£‡—4ªôBT‹o&ËÛ¿°ßÈu<ø)÷ÖAò¸¨/na`\R ý$W0`V¡Ö f³]& ùFÝu´uà°Ë0¢Þ̇‰n7ú¥2\©' „KÅ‹ýØåÓg@ès:mƒûûC±±3;Ê U‹M\šOÄÇ3£é ”ì˜SÂY9¢A"8Z„±?ýþî[ëcÕ¨|S[ñ ¦Uo2¥¿`¦‹{NŒÙÛ­º§˜WþZN-fTWÁ*š­•-”j>(¨nH`tõè«:‹UÿLAG,ÚŸâ©þŽÑ´:>šÖ2 üíð֣é#ËÁ‰±ÁÝý±o;ÏHOÜ=Ö¹ëð6NäƒØeéFá—ù`;G(Ëv¾ÁÈI‘ä¦: Å•õ\9GŒR &‰ºÄÏ è@ è³¢ªÙ¤åqµn6ƒc`·/pË€—p4›zQÓ?ã=~,¬Ex!ä½ðžÞf:eÚ˜°M‰Å™$€aƒ€ðº       ÂZ…Ï‚ðKÄY©-"ûÆüÛÖ•D[gdŸY^7+µEµ!A\RXO‹ðƒ\.÷Q€ãbŸY® •šBØ7&|½¹ ÊÜ… îû8J„W ®W2€ #YXX8 ýÏ‚TZØ++<áùbûf€yмØùj5TW«ëâyiÄs“_ „ ÿ/j«6À?|ˆbø™=€#ßûÕž5ë´Zz‚JËoçšKµ€º†îÓÕ¶gw¡S„·g=z,/ù`éXÉÊjV3wU%¥ëÖh€og"\œ[VA~)yuáªÜ庸»2`AXÅ5ZéÔGãÚ0ˆ·×z”@*üçòüM¨¥ÝüÕœÈ7ó§Ö|sض4Kƒ ž™Œ$'ž=:†ó«Ñ½½¥jÝ_ü(Ìug¾»÷m)•y2ûà w¸V€š™™I§ªõ7½`”7 s‡â•yÉ…$ÊKÍͬ áh¬‡…ÚmøJ%t!’n…Ð;MLs¸ÎÓâ Õ¯‘>¢Á£hp6ym(‚»t\„"ó àv½)àër¨ð—Að¦®õϵÆxíæÓ4RßòM9a°‰~%¸TŠnVôÿÅo…héí÷³KÈ4!ôtÔyÓøÔ&ª+u÷ßöÒ÷ø¡Ôî[ÿÞÜ$åÔmOÞ AtQùæBs5A ùüõ|~.U¸Ñ NÌ䓌{²¿~=¿˜(Ø:/Bñøõ¢4âÅhµh,^œà¹üª ÃB0B{5VYøf 0×hè Ù\RC|¤â…5åÚ<¢œG4ûAŸ†Ž“”K¾'äæ½’%{­, ®‘ÁuÑbi6¼‘Ó.««&é^‚Øtvø ÂÃá›[AýàððÙÁˆ~øøÙS½@ròØððç’OÿÒ D‹Í³?@cnOçAÒÙÜÑ7´Û'.Læ¦oîžÈåKJV";õãôô =ËôvßúG.wZÌQߦAïNç¦Ý°¡Î¥ÙÒU,B"?OÌåÓDb( G~wr(¢AH$‘™XXLÄg 'ÉÄP‚óâ„™4ŒÇ!¨0/ó’©äPÒý,—‚ŠBŸÂQÈú|dƒPØŒüf8&á<¥Í¦$L=‘IHðìÖ µÞlªox3É5+|B8Ô tmw³" 2À<ÙŒ“6›žkè‚6b&ÈpK;,È÷ô¹¹X‚°ÂÃû†.—Õç ëõ]«OõaËk¤ ‡ô°0#[w·Í///‰./Ï/Ÿ’>†©Ëñ¿þçò ÍE¤ßÏ>‘B~795y/ªž»qcrª¹ûÖ佩©ûîÛßÁ¯ÿbø¦‰¿ß›¼1õ´X™úu/ AÉ[“7&ïC¤f—Àª ÌD*7´ ‹IÞ\>Ÿ_HA’‹ è/,¤ˆÔâBÚ…9:/‘Fäz‚À›A ˜°?3ϱá}zâì_hÛÚÇcì›´ŠKä?ج;lãY®â?’“x®ü'‰§+ÄÃßËe˜PöŠñóvóV˜ ¡d,{èC)ÔЗÑKÈmáÂ(Ü—b u©ñƒ“µ¦8%i_ú²Ÿ$;qZ7ÖÞ5äú!éèwäôÑï÷=çwލ˜ÇchÚ5!Ä@!†KÓ&WÚ¬÷¥£ÄÒP0MÓ\ÔÆ¨GKvrc4E,‘éQÔJ“ja™Ÿ†§9Ú áÎAs Or.\éçI±¡‘S“`ǽØÑV €âh†wà}>0Ž` ºSQ$(GÔï~^öxAõ›cyƒìâ+ „{¨³þhns÷ÚÏ•ÓȰҒª¿U}]¿'SN…ÝõGñÍÝN ¼|‡H­´U¸a.›½]Ú2̬ܵ †ð|¶øàMGxÇ‹O*–Â0"Úl\~ðÆ[\{£”¡”u¬àXj!ì¥* úq#jg;4: ½súɲO±½t$¤GnÒþ)ò»WõÝ®¥€±YìùÎë.›½Û´ï#-³ ¬•*±N×ÓÞ5Õë×òÓ˜t‡{“ü¸isø1SëÞãöc“ñβGP©n±Lvõ!}Ž4ìsÿú}wÚ¼Ùgnüò“Ý}»zå”fŸz&§¾œi,$eÜï>u)Ïç€t}Y ™Éë +‹‹9ù'òKöÁîsƒ€+ú |VP¯Éäí ¨ Z)zz&æèò‹×WVæ¯/β•¿°Ó BbÎçÕP¢N“Ï"¤XXÌ.wÐrŠf¨açoÿõ֌Λùñ—Àëƒpfç,Ó#ø‚ R6Ÿ/¡(›åTMÕÄäç ÿ§e û˹c9íÙTaö’åv» µÃòÓ³|ÁÛ«ŒôKWQžYP¯ ´2j1Æ úÓ¼?¾Ü«Ä ý²_ägtÈJöçjþ¨«X6ä†p>{LA÷î|þö8Âq~ò¸ `'ÿo½3äÑ/§!í:hùøÉûÇYÏÝ0¯w=£K|~¸{ìàˆçM>S‹»lVqÐèê2€…;ŸihÛõ|bÿËÞù†¶‘\\A“s,oÈÆ^´†øƒ”%ÇÛ¤Wår{Û´Ö¦ÒQU\í†Û(ªöLŒ}Þæ8Äe}8FEÍ÷Alªí©“béY`HÛ5þC\}8I‘‰,qª>}3+ËNˆåÒøhÒhŒw¥ÕÛ™‘ý~ûÞÛ™y[ʪ¶a»¯þ½6zÓ8!©Îø:ygí­(áKrרùc§= ½q—¡i›+'rO§-:ÞÉ>ëCJšÊ–2P<[FؽqS• $ñÂ|§§7¡ûß<²ÐBh¥^SK§˜Ü4Yôw³èî*Œ¥±®®=Ì`¡€—T×T±¸Ò–ƒmˆ <6Ž×U´ð¥°‡Þ:¶¿ÙðÜ ðßo<Ñ]þ‰˜ˆ‰.$-”o®þÙ‰ãQâLÑ® ß\3ƒJW×¢„Óßo[–ÂS¬A†µ Å3{ñ´$Ä=˜ÅTÑ 7•YéWm¥4œNô"äJ«jj}…Û ”úQÚ!Tš]…¸ÂÚc½ŽrÆ]Ù¡:Ø;úÖ xYÝý{÷îW¼£—„7O´Wž;¯-üúû&Ž•ûŸ#Áè]Hî‚Êçný&Šh“Óèx»ÝÈ"=È´‚ŒÞi·.UÉF§æLΑa„Sx¶ ÐÈi¯ý¶K°ž Íìµ ö ‚VŒqPy®~W¯§ÍòQ7(>ÙhÅír¹Ü[[e²€Z³¦6¼Óí5Uµ±5¦¶&xsŽ»k¡ IUAެz%«¦¬H߇Òôý{Ï^ W)/†ÖG÷v"Á×–±Ÿý­LW$1Q’ö@döÁøŠ¡¨5{qÙÃûÆ#‘Ù8³ø ù°Š „±LUΘk(J2‹ÓJx|<ËÈ Ó_ÅMÏF"àÿК—Ç#«Y½c$øª `^¼h2S»‡4Â&ÞÕ@¾öÐ:!Ȩ“”;“²:“ Í–ÑNÿ\·<ž%¸ÜÜè_r¹ÜßíG¿„m/r~–Ë¥º¡=‘ËåGöçr‰\~Œ‰®@ÕñDR¡ ª^>­N"l'&ÁwÓoµö¡RþÇ <±fÙP·ÿ†ÉtGÓº¡#[_û˜ètxET’ÆÐƒÙ¹•þ*Mñø³?Á媴°D–{ff`ç 73ãWV‹þ#­(K++ˆÈ´+%yX³x•Î̃ðAê_Xí/HL0ˆgWV”Ì©poÌV¹2Íýçxó¦Ú8€Ð©^ÍvÇÕ÷ŠýYVæ| «ƒw?…3>}w8K\:wˈ¥±oÙx,.–ïu«¹Ô¥Ôä‘X"–Ï}eñ¬=/L_[›ì™Tö‹ ðBGõ­ÝAÚª¢ŠExAøÕé§b„Kù8ØØm-Q.*qŽÌ¡ðes1*¦ù Çÿøøñî ’5ƒ£wKòBÚRLÞ…œ^ÏôÆÂ|-yeÈzd“·hA g½!%n~H– ó²2Ê0’’´@Œàú%idŒaÜbø—τϱ”È[v©ùfœe¦1vÇ­æmrÉOän¥ó½}k$g¢4®$Õv $²~óÈRQÄ„·ßønrŸ¢ÎÆ/ÊÅÊ̲2a&ÁrP©+ù h¸Js­?üš‚e> ‡gÉzäà@‡•¥Û¨˜æ@°à„¦Dƒ@…”V â(aßJ· ,*̂ɀ9dÑAp8xÒ¸cÝ"\#¦€àšMÚ¹\\\M²‘»4¸;Z5iaHéõAhúKÞ‘µ›Ž~ôÇ.´ÅÈ2®ªX¾&UR”¶¡ù>|ñ×þ4©ìTaí±…8Fz+áUá9úX𝰕ÑtÓÃÒìz½ZPM¢ÀXEŸÞôSø9'ÿÕ\#‡ÐG¢z£>丈9Сû+T@ؾ°,Bȉ×t3;AÚMkÀ› ù=ÕÈ~Ÿé}~YØ7lhÔÞ¹9ÎãF9Nòû½ÇoÓ&££OUË8Z­º ¶-Ì€\ãC Ó+ý÷Î* #{Á@HôÔ„Ä(³>؆„2« h¯ì–§ƒbÐíƒÿ€$úý¢×ëÚ¦_zäxÆ,ŠöU@ø»çý¢¬wb¨Æ¾Ó$0²è è`+JŒ¶>ä…#e’0ðù´ÌI"ô‡óB¯‚Ѩ_ ø˜Š&U@ønc„ÙÃÒÈ%ûÀg±ûvZðÉ.D³Ù õJ²¤×!Ü^9WM’=‚À{eŸ“çÿÍÞùÆ6qŸqÜü¬ÕÃñّϱU[²u•‚#Ûºú~1g÷tMnT©u©™ÊRdhEÆ…ŒjÂĈ4²­«²-LbB¢bBM‡'&7“ÐX‘&íßð‚uLl¯’À*‘-J•—»»8ñŸÄ69â?ßÈ!Á$¹Ÿßó»çy~Úw54004=;„W÷¦Á äùqCа¶+äck>DùLXmãÌïC­}¥êQ$ÿäÉf½   Eƒ’°Ê·?ùð“q×€ B\(@%"€ö\R¢ª²³"°>3Ên¬ž=YÖH)æ‰@ÈÖ£KÈð쾦š}FÈ üë·4–æ®*ü ר²ŸXüOžV<÷€-ÂÀ¯„Œpµú±š¾p¾C-©wŸ=yø¨¯Ð¯ïÌ:›Õ+MÎuÒs¹ùܼQQ§?ÇñÊBN/këë{@Í"ð&UŸ¾Ôï˜ÎWd70óþçÿX虹’=vꇽ¤øò%cg_"Ö™“~Ëà+³êåpE%|¾ñy½¾Ù5‘{üêRîÏ>vàîÑ–Ë}¤?Å@í"„m&åÿ„Teœ ;pãf6{oaò³ì½ìÍ/¹’Ë×7›]òÝýâ~9õÁOo‘Á”¬Í77É9忚K¹ú¿¥·˜=¸s½‡%®ÍÁB ¨]„••¨I=Ëéj•¦e£Cm6»Ð{îrög'¿ÞQrùºf´5ÓÙìKÞÿø{Ç]ç~óºÆÑü¹šì[á¡U<óg´5Òƒ;—ZjþtU„ƒÔ.BhŤˆ0žŽK?ª\϶޳œŸbQ";8õOï¬ì#Ãéó}d8dìö®kÅæEXÊýDaxf\O.|Ÿ""€ús„°i÷†¾ùóÊCÝÂ…)7õ)ë¯ã« ÿÊ›úÒFôö-céÖ8qº\„‹ö¯hK£|™ëBDõ‹ðšÃ$ˆoðg*‹°>×Èu#p^ÇÉXüDŸ…ÜýÓm}˜/{÷Ä×¹_¾­ñÞŵËÛ§‰Ðç:œû{ødî,ûƃ="è"¸@#‰À^8KÓK•GY¹Æ>Ëþïzv¡O3âþõ¿ÚÖ’eßç=N,¯ß»'k ¦Ù=îrØ8ü'#ƒKs¹ù3·†r×ôñ¢î\y™Ñ¹ÿä_Ò̃ a–FìàwâÁøïªMø2fŸ~1×GÞ¸rûö}ÑA¿ypêM¢+Ú¯úãïõ!Ò¤¨s“ ÏÍk\tM,äæ/iQcæÊ^‹ïä^íƒ÷‚íSP‡©M’åMÏÉ©qiäÿêžkõ©ðƒ£ã/ûõÔÑñN«ö:¾ü耶úîë9@ÆN^ϧ#X¿öêFˇÃo!No?«ªÓ›ˆYý£«õô#ˆjae£œ»Ë¾ ÉòÖåŧ h"<|¸ìòMìûÆ!¢Ï&úC§QƒTµ_`-J°ë–¾Eíó@P«a¦\oZ Á÷b˰Yöôòò²¶ ²öègÇž›>ìÕSà±ñšÎ’eý–õÈ@m"¼Y^b!zhFW;FÍ”~–-šƒä “Ù©©i-G˜šš­ÅVÿ<¨=5‹P^tǤ¤„ÈØ»…Êç…l‹´®ÿÕÐå³³Sg§§¦µß3S³[žbYÀŠŸ1Ø)ÄØ˜ 1ùfMÁÙßa­„_ gYë´Ø™©ib`;±ØB±u6A¦QíâOSýä.¤¨Ñ„}rogœ{ÆGõ7££NíÍèd'ÛJw«VMÆ ’iDÔOØ”(¥¯)"Ð÷”Þ*ßhOÑ#~n`»E°oٳ̤‚’$u'=]èNÅT5I+ÐK£X…æ}·‡W(ºÆzM»ý ’åJ"h™òêÑš#†Á@{Š`lÙT)`c’B·XŸV?D- “ i%¨ÙPìÀ…kÕÆª@Ð,Áëæi_cN'""€fÁ›‘‘ª<÷Xxrм"02U9FyþÆ2Úo Ir¥L£AÓ!ôÜj¤jÏ$D$–w¨Q™a8½ðÔÜVMˆI„#é2ºA©’Çìæ}ˆD„®Ío¨J©Þ˜c¶¿€AL… T¸³Ü¥¤e;cö\#þm¥Ç ÀÎ`†ãe™íù¸%J0éè`G("p1Õ“ˆzˆÚYQ•¨Diw "€6AœJƒr, q7Dm)g_=5'¦¥\šWµ÷¼^ˆÚM9°1^Ñ“â"cñBÐn"P!À¨4Õ¯ïqqÁná3´ÝÒ(" ‰8ïQ šè¦;–F í’eNåyZ,?z"€ÖáȆ]£MD£QÙø¥½‚^ì–Á³!"xhŒ)`óÐ"hylÉb#v‹Ï–ÕD"€–a%\,BRMq!E,^)E© @Ë‹Ð%‰À$xIõr%)CŠ¦Ëªï h=ÂÖb<¼ÄgºJDи¢D¼´´®Þhd„ ²XŒLyž—’ D­,B$Q*BHT$š(Ü:`Ò4DDÐÒ"å"0¶PœÖo\Ø]Ö¢@ë‰ l±'¨ÔŬåÊ#n¨–ae¥ªâ2´Ñ*K#-UŽ‹hÌ­/‚RĈ‘,ý¶”À !DÐú"¼*AöèÛ§n5åå8·"I#tƒ ´ž™DÙ 5š‰ÙlZTˆ{2Z8Eeƒ ´žÁô† í²A’‚é¤ÍÆ)B´º¥9Iu-Kݱ¤×i!&9ˆÚKÆÆº+ð@;‰€Ù§"@ €@ˆ D¡N:-VšK§£p×+‚è ¹íÅï¸eŲ/]³»œ´ý±ˆåHí9 •èЖF¼Œd´9Ø5 /›ˆ"D,{!€X™Jg?¨•=;$‘4D0 ÒïµÂYwFm8Œ­–a—{7¨‘á·¶4ò;û9Žqú!Dx¡!ÒP"øw%Sh4êê÷Cˆ°Ž+là"f‰°·¡–F»fÁ*{Dhiì%Õ?öj"Ît¼[#žv“DØ×HɲÃ-"éhì:»µ?Û+]Æ긔ÖôG{…Ï]úD³®êݵ~ wF(&m¯"Âÿ™3ÿŸ4ò4ŽÛ1é†é—iFDçJb1@X¤Ò‹îdz‚T9—±ìHJYì˜Z´.Ýö„bK*kk 1]-¹ÖKÍþp×úK¹ì%×ûÁ„lb÷‡K&ñgÿŠ{f´í mïλýÌ ŸÏó™Ïx^Ïûyì"g’Ó„ý»?Æ[ǃ||Š`b«AÔÒ ¶^ÛPg©Ñ=“ô »‘††·>Xí™’8 %]@*UÓ µêšòMù¶Òy¿÷W¡›ÍÌ¡ºŸF%bwyÂÞ{”ÐÀ4àBDh7ÄÑwÆKÍæÀK6¨Æã¸kþ—kŒ¬ô[m(/_eëß³öÔ'P+ØòŸ@ÙÕegw_}ö* `:gHJŒtõÖŠ U~läpý1q´Vo8`«ÍKqõ585åÎd„ñÎö^07šëû‘¡•n°¹2766õgùnð×ÉÐlÝÕcïØ½Ç)›ˆÁHêì¥XB"âðþŸj2ª_ìF¾´Á}:7¿vˆmqÒàpú‘Iè­ë!ú=Ro¼ãÿB˜c¦àJM%™¥yÝ‹œrq†å÷ ªsæNt ±ìl$Õ4æÎ;ÒΕÜ¢À»M¼G“Òø[úâ —©UOPþ*ŽjS3»â![¡ž{÷ãïÌQìí±lƒ>c2²ÁxaÏZ2L²<å_¢Ês/~¼"˜h‡ •[k—¹"H3ÕJÛ[[[G«€€œ¡*§MÈq§õ uÓä`AP?.÷å–g‡…å¾vaýÂÏÂ2Ýž[ïÜúÎ «£»<ŠÔ¨oÁ`ßw³s;/°ìçíÉ5¡ë[áMoù&¨èýɵWíÂΦ¤ Š}óÅ«þ`c‹•ïrö#uçü™l‹ÅniáïX--Nï߇‚7Dìm“z» ¬èõ£> $™%Äo„¥’0H¡M3¼CVÜfP*•{Þ’LMÉö¸‘ç¤9^ŽÇÚ̱̿Q…"àmd8&F*ÒÅ ©P4eaø:ðÒæ›€°® IDAT…lŠã‚ ô;­$aQˆ 6ÑÊf îyã å9°’Ʀ ¥QR#íÞŒ0f‘F@@aRÚ-ì ëíç¥9®0ÿñš`tÒ”lêjÁ+ÖHg—íª ¦b/µU!áH‚›¦:5R?ÍýãøëÏr/NL;kåžHl`¦l~ØPþÊ ¥©Ë-‘ÐôÈŒWyjĺtâ_KºFKE0Ó¦d-ÕI¨¯ÀÁ„»ºžµçÙܬ®gîÁO‚ô…é­qÏëå+eިГ'æv–¯è†…;ÂjâóßזåKr~ê/Ë-¯·7¤kÍ©_~0äËÈz¯xäµ2uØUç] 2ýY×ˆÈ Ôaß@o…¯¥Ùx ÀS~QSÓ€vÀ üæxŠrhSSfÉÅÄ#LÌígãtlÅXR„â¿QL’Šcn?= ãPBŽ0cú,ܼãý…D˜‹Ê¾¦m3Y-+>н%HNæÃp%¾bÔ)¸Ãv9‘AÒ[ƒmyOdÊ–bùPò´àJ€›É2^w€öÚ"…•0•¶ó¬lÐc®Á—?·”Ny éÄeÆ_ÆÑØ8°$Y'™å÷ÆR|Öb5µéÛœVË'(Ô7–.èŠùQSÕǧv—N¬÷ª€zÐv;ÃVÑìý»VìÂC‡_Øþi* ›?-_)9þÖN{nçùùrj”koÿîæ\ßõÍ ¯/»Ñ|/'\¿-—¥ù¯^½ÚyXº>¼“‘iuM]O`f5¸<‚ 9Ь5£ ö—@@ÄÞ _Šþ·!SžmiÀN^²žFXh(¼^ËD¦ÂÅ™ñ`\γÓEÖn‡´Â7ˆ‡6%‚ ÐPp„”þ!êã–¨P1ê‰plF•åv]Ì.Åq|À¼ˆCr²ˆæ<)Öóx„åõåž"àZsÇÉ4$UöŒ6EɈ7ÌM«<¯M¨´ƒÞ,ø´;ŒK 0ÕmfZ.¸Á s­©)z@Ê ¸‹`=x¥ÅH!“çIœt-)?é1J¶uQª¦®‹Š€€ŠõÞÉŠ €À ¤¦: nš“ꄃA÷Tr¹Ç£ÃÂå'ÛÏÏÿ)ÁXý‡ÜúÖ*"<,+Â}·;qxîùëšëck½žtQxܼ¥šðö²%µý QQ„º¤Ç ÜAx!ƒðû”ÓiZ:?TáEoÜ©AÏLÐ×VßpðŠ ×´eÚn·Zù€WNö!5ÊCåéWóü0FîÖ»‚do·òª4-:"÷~ÌÅq19)?¨Ð,TÞrMöÆ÷& · ‹b¹LÞóú  ,þ  Ų×Ud­v{¬;ÞfhºÐÊðpGn‰™‘Šå]\"¹öäx»D¼ñw¢~ tã» ­ B­ÝÕÄAs›Y›Å²ÈIÖrBJs„f¤úCÎ $ì±ýÚG)‚<¢ÎMŸ[»1zKØTc?äîn­vèþz}@i»•{¡ÓAæôx8÷hÙ¸¶1ìÕõ|cT¡Yzhtog“X2"¶}øFzSÝ618 5¦¾™FÊŠ0{æX&öbß Îª«€_®ò(Šj÷7jܶqAi,×â  ñM2c¤Q© ¼(Â¼Ñæ†¬†ãøïù ɉÔE" ƒÆ.FåAƒþ­ ûÇH„07¿«)P„¨‘ $SU PEYÂ\&©Q¸¤’5á°é#œ~ðáð÷ ´©>¤H4ì_ìýOÙÇÇi´ÒŠ}mÒÞ6)hº¡ítJyÑ…²p‹Rµ°EX¨ ꢸ,KÄ늄”E [‚!Y³Þ_4æfÐÍÍ&æfïÞnÒÄŸù+î9Ó7мѪ竴v<Ó™2ç3Ïóœóœ§†œjSÊ:—§ áŽ"¬{Íå0NøÛ5’Rë(e›10?o¹ü½âA°Õ¶|‘öŸÙÃk`‚^ƒa¢3øTkxxõÞŒ—¿üÇ‹KÁ¥L×äRØ"`r ‚ðï ³DÛvÆ"èÖRë1utŸikmùÒíœ*«®‚ì¼ý œF(w·Î”Õ8Ÿà›‚ðG~u݇wg >mÔܬny±»r€Pæ†7SàyµZmo¿ „ÓsDñVK›Wâ2A_éüÍÚl_SpUÜsSc¯½½"ßšçz™n^oêý x- µàzi8cPö‰q!`@hsÚnÖŠ™¡Öèfb±§Ò›BªN¡Ãsò£õÕÓž›K½—çLëæ“ÓmsFzbSuÛ¡2#èår|³é2ð¼þ} çÓ¡ˆÙ¸=‹ Ö·¥´lù=˂ί@T€ÉzîöÉ*^-µ\™ÏÌ}ÚRô·ã……u­¥ÿ-zÑó3x<5òêÆ‰K§Fó¿§]þnròq¬·òaç·½ ®¬Ìv01‚z½³õ“výôK;[£×[§@ä|]ù¸FÊ'Ì;]#ôvë Ã/*Ï%)CN8£q+ìa=ݪ2Ѧ‡”Ë+ ƒÐl‚¾Ï(Aج·+o®´'a{„ÀÂ~û°®†Ajc|× ;'„27ÝÑÜ@ÓÓÝÍÕ0^.«1Å@àŒ¯GC6r¨ši ¶êèÑ´žœ¦úÛhºuJÕ¯ïå4Û§8ÍΛ¦á¨‘›6Yí·4m•&Ò9UßÚj]VN;â“]Yõ– ˜”3~š•U¬­ÊÜxô‹UafsÁn8WmN \Î ÿ «·&yÿÂY‰E_‡~Rà6 Î û­ ðRàöð^ÑöB‡Âíjh.~RÓöƒ˜·”Ë¢ôÓAWÏJ¤¸`8L…Þ(E¢ÒÁCèT³ØgŒIcGbN•r(•Š™GMÁÐ~ŠPk8 ³H¨6ïn23ªõ™Õ[€€[NcDs¿±EFdðí‚`T¯[µ v6ã½Q#fj¸G¡!#˾ wÃ7ý\ɲša㤻 | ަ¡š>ÉŒmÒžnÉñ k÷€/]Þ·ò&„õÛŽê(ÄP½;J1*SŽîÂ3âØ¿¹{ÊÀÙ"û4#5üIÍÞË4ì·AX;HÄO „„”o‰åÜYø,ìãVÙ§ªbѲe£5-„ÔzDZ¬“¼Dm~Bá|‡±ÚUŠ­Îb±H¶LÃÆ÷v±Vò€¥Sáu„.& í1Û –Ø l*ófuð}ÚP©¤*Z2w,øÆ;QX죡K®ßI;ÖÁwÖÍ 9Û¾•É:s~9räŸ?ß•@-w |-Ç«¿ÈÃð46?»¨§¶»Æ (._˜}ý&Ø¡²ÐuDÚcÂiØ›WºËVÚ! ªÒ5 ².Ÿï„a||qµƒ…¿¹&$ÿ˜®ÔNÎ,O~S;¡ë‚¨¨™¦½_÷vûhÞBoïдÑvE4”fj€e)–Wnë^­ +6®t„ô.AØFÉG<›$Äqü~ŸßÁ[ô úü QÄ" æüæ:þ‹¬ëÑ Çüý¼ÓËí}rtžj ¯gÿ YŽ‹5Þî³mÔ©ïg÷rê[ÓDÔý —GU¸Þ´Ó“ÁS"2ùFHÉBˆÈA¬GŠÊýÀ",úü~ßâXŒAh"ûòÞÓƒ a;BÝ©ïrBõîD§ëoç}K7f5›0Tæ¼.û¹¨AÀ„†M‡þõlåYûÄFåQ‘>€eeÆêò/ø}ã>ÿ ##0 \Tü¡€kô'߉•EE„1ÚJDïõ!½É{€ƒ ̾·â4Î_¸,R2€áU%ñE)E¬òÁEŸoÑïd­±a·@Nkzó:sžiº÷c¨»òzL#×m/Ë^¦Ÿo½¶ „pŒÐÿ}pBUÿf‰©Œb¤dN¯Ù"É*Ç»šüþ¦ˆE8ÎËuO y˹s3Ë/-P××Yø\€_ʽ5: ¢£ng Æ>S_¨7\iðJñ5£FóÏÚ+'Wh")©@XW¢ò&VÞ俼¦?wž<×O~;jO\k£G†¦ÿêp9[ºÈ>/w{K™îŽ_ôK°t],ûT—Š."Òg –Á —̶HшÒ‡aÍÈý{þ:œ•Ɔ_tÁOÃÐÒ»èQ ‚Î×ÁÃÜ÷®ƒ¹HHïH‡% pôP¼(ÛþCHH¯([AB ìW™í/û‘>Z*{ àЯ)©A°î„_7áС³===g"’Ü"üŸš«yMdÙâ+Y–Ä»ƦánŒ ÷>"êØ‚uiÒ㢟ñ«¿‚„ QÐLÌ fx 1#™8ÑÁ ¸ˆ«½ÉæÂp‘7‹ü5ïT«ùšdfò˜<˜¬JÕ©ß9§êüêœr‘ßž2# þóñÖÇ­ãüÿ‘ _d ¯¦¤/'oŽ<:›¡oê@ßo‰ìq† »àèÑ–>^éÿ{¿±(&~x‘Aˆ°ú„Ž·>Ä ±Ï[DZkÓ1ùy:bP¼â¶‚^#>xÐw¥ÉzÍuŸÖ‹ß¿é (¨t÷XDßÐ!к‡ìÖëæõâ7OS%ò*ê¦ãš¯R÷ORüõ° Qˆè‘$xê;OI.hä_§œ„fA†nÄ ’ 93bágz# èñ›(y”cþýVaîï$ÿ />„Šÿvthìl>pYîâ\~gýðH7³Uð:.‹7xñ Å*9ê½Üû2ÃôFçW¡vþ^שÄıwØñ1wáûó1‰—'ð{%…h·!+>…¨\ÉÞ7•ó6æk§!©àu¸Wyª>W}wP!uØ3Dæ¢÷Ó‡wkWŠ˜.Ï£y~}ñ{!êÖjÕ?ô&ý1Dx0#ˆï£Àߨ—Ó›7Âl0:6Öì7’! šóMG¦·5ºNW’ÒÈ×Yn2oŒàô`QDSüi3D@1ÚÈ1–Ý€ÉuwSE(ÖÞɪ.ΦKç·¬¾îãÄËCœ`_aŠMl╃‰ý¬ˆ®=»ê Í@òdêùGñÚå;¡tYœoÒÜ«ýšz„Kb)pƒö†Zœo弜 Ц"¸œjÍk éÄ9RIq&³Ûú¼;‹®ë‘kˆéŸ·Pè:êèñyÙ­5×5 ŠU"½•>š­¬>× ÛÀ]Ã+‹úZøÿæœaûó°½ÅÇŸÙûèçɨ°• »~L>c{3Ó£ã#¥>ÞÞy‡èê¢RFy”å šòû:0¨4먲v>èjpIœÊÕ 2z‰æ–U3åಞTÕE2/ÁÎ"”ˆ \\& z²f•2>4ËÁ_=Ç-C`©ØøÌìi˜à²øZr b¢DI†w¦_15RHNò–¹:F¤Ù@ úÍñŠMYaC«gÏZ¶fo(†:še„˜ý01•&ÉKïuµÊnW1ñÉ¿¼t•DjA¸"‚°Ö)bH {?WF@âû7„…Ÿ¡ùeNx#X÷áNËo˜Î9"¥{¶)\dŠÁƒ3Žœ…Øm¡¹\,Ã1CŠÖL~ ÃðÃLƒh½l±„ÆgzãÚïδóÛA¦¡fÈW+¹Éî †/Á¯œ:õB…Ñ`úcíËeÎmú‹äŽæÞ;›8‘N–Nóø;Dˆ_™’i»·þƒy#`gú5FNÓm±pκ»ïpÉkv9HqP ÿù™ý7AÂÐÿµ}F”ä»§y3£,Œ^Åá¡Â0 Ù”éÿàÜÁ9^‚v ïàÜÁÑ/ " a;bë~¯i£ê³ÍRæ_x˜1Ï6qt|Æ­ÿ…© ˆxÄ7ÁSÞ»H›-\é4r§4ÂNí;|E„,BÞŽ¹’”c>È*-\¨ì9]$®\æ’M‡ãöÃ9bö¼®÷Þ«Žsáš}å…’BQI3L-œ¤+ 1ŒQâö>Î¥ür¯Vñ_öÎÿ5- àlÁ}¤oýáúLË[A§B–e&„¼bŸßY§È›v4ˆXã3Ž!0˜˜l¾¤ ÄXƒÞnè4Ò¦mjš!?$¿\Øþ²P–Ðüпæ{ï8š~ ¥äµ¤x:_î=÷Îä~î9çžQù è\œ W"ó,ß­—R!‹ <3«Ž§„ˆ'à²8Ûƒ€›h†[ÐÍÉR8PlàCzŒ€÷ŒI9Àzl\4‹pr_ÖA0l=m¯â¸o>8løƒ^p)æ; Ü:‚Yrq¯ìÛl(µb%'Áy逨“¤—Ä&ŒSôŸ±‰æˆ7èo$¥W8|ÌûI1˜üýÞ×u#ô`¤Ìc¯„©Zûõ|pöJE ‚ ‚e'ÅáæèT^! dˆÎi VÁ»ˆWrw¢ÿözýÂz¿LêË•:Ÿ_‘`†²uá ndZ9–‚¯7q&(¤\šEbä= “m9‚¸y¯5¥ijÎnóàAÎÁìÉX³ÿBÍÙP 야WN/ÜABâfã6.P9öso€¤ƒ° Ž •æÉ…B2÷3s¬N›ð Ýa?sƒ3  Éñ‡í…d ‰LŒºÝî—KvP%ŽÂvdI€‚0\–a;œy‰uìV+¥ˆÛÃÍÂ^$ÅEc‘ÃýÝc›¢»¶e( …泚iÒ,B7¹2»á‰\0‹€ä)¤ 9HZŒpeù¨¼÷‡Y˜Ê]á&n¯ƒsÞRðn6w€ó.¼æmW£ÇO&ðD #üzn7¤hÁ.drE\Ì&'„™Ü3‹ÇëxÀ).ýýÄ"ÜkÁdÚ  4¶¾ µ„éæ“y6 „œ8F‹p4­t[é/áÚº#°G@`Vi<|Ñi†±U°˜ì¡x­¬2b!]òÿ¯u÷ÁÌ61 ¡V¼ÂÏu@x2Á£DȤY„ƒÆ±!qtW*«êã±vN9 Â#~’‚Àä„¥’Y[˜ãQ&V „‡çcû BÇ"Øx&¹ žŒ¯€-€ÐL±Wp):·y „ ¸U Ã)ÛÕdd <(ç3‰5>:ñ2áÑdé:Çq¬­B—EÐÖ“‹e0©~‹pÊÇåä­-iÁòÓ5±mp°<ç/NÕž 3£lp©úÀé¾¼_ó7nà ©'â¯aR”ã7'ì3þæƒC6³ð,éŸæ’¹†Z[¯«{³éƒõzbfÔü2Å©GëØµ9öOû¢¹{ûXÿøèvTª.îÍûVýÓYA|<;Á%o’°úq¹n×@Èç}àë:IŒ8&eîR‹P®;IŒðºîüðBÃW9 ð¸Ž9TÛ Ha—‚$ænî¼Øe g•ƒbþïó¶h®øÏXeS·ËGëuØmƒ ³ ` À ®ÎrôîÕ6y_éÂîf¹ª>nƒ D´Õy W~2/©EÈï®ÄcW&6±\ò¸à>»ZJ¹ÞÁ>žòÙ3×·ñø^Oq}íá¡ÜþÌèŽ-!AŽÆ&lÊЄB¬.j Ja.‘ô°3;ƒ…Ò8J®B|^ª‹@È;@íàHÙ+CÕwZQðÑátxð“[„ka*æS?/û¡y4µö«Ì#!æä¹fpŒ LnÎVÿ¿Ŷ×hƒPÚô{ý¯ÁZî=€v¦&yý`Úq*8"5\Mp¦r0 T0×pF¤ †7Psèzáñâä€ ½þr•IæàøŸz+ ª±A@Yº ̪ͪ°øÂý4’GxÖŸÇM7«FÑ\0|2-B9p‡V ZlJ¸NÛ"Løy/¡š­IÐcË\Î;"…Å©MéÇx>ip IDATÜzõM×HnbmºE€‘„Ý»xbäUhsìN+¿ gf·µ»³¯ƒ€/ý^i½:lƒ0÷ Ø¯¼»c‘¶EØÆ»‘°MŒ¦”Ò†˜„½Ýú"Á=Až®¥sGšÈøNŽB€ŠOü3 þMd·jn JÌ€‚Ô¶‚I‰Äv4œð¯b;öxä†Û]Ç ÅvëÐú (ŽÕñ§AØ/Eæ ´o§-¢ $"d•Ì>C:Œ>¹Ex4¾»u壞5Ê®me'ÅÉý­ç';!°ðZ0ÛduØêp2j Å'J8úQâ–õøBL瘜'%Þ2ÊͲyx˜ÅùE«€k‘úˆªAbÅ: +òÅ:¼ )ÃVÁ„ìX(NÛФÅ4edZ+iD#õY’^(„ú´2"8f¤!8Ÿ±:LHL[ͪàTC}ÚfKV OB?SH×í±øJ¨Y°BdÁ‡ëY ‹]DŒj‘XÓ¬ÐOºÍ¶ðî-Uè/&®$+V+´#«é¹CäîàN`—$Ó •Ôb¶„à„?»Ã¢;k‚;)8|>‹X°á}'² æ\»=°@•jvX rƒ[ÀX–#• ¬ˆ3b@0“¾d JXZ;ÖÈÉ8åAÔÙ  êøZr!d¡r° Uà‚T‡€“ªY°à¤‰9äR‰ºkÙAZ“ƒâðÙ@?Q¦[„%[ьÚOHCiQùÄaÀú=õŒB×»2çß>EË[Ï×Ö֞ߟꢑ–…©ÇYQ¼G ég úž¶%¿(?¢™\ž&^á…7tÞÍãhæeñ»¦‹á;éëŽZ}³«i½3zyÚVTºË·Ï€ZÒ¤ÖÑúDòÀm-‰»Ð­žá‘VH»<í6£u÷]»ýš=ÔÕ)Äw÷_¯EþP÷#sZî¶°×ÒÃ¨Ý -= Í#凡¡¡<·yý0½ÄÅ$9a†`™×U ª§›¼ÖšÖO½¥N:Zßãå(Q·ÓjÿÿÛ5Ûùi¾ó È8IbÀÑ 7rˆìMÆÝ£¿¿E0úwÁXit`<„³>€˜åìIv™9n3ÑðíÏö87RÜ+_ô³ä #cyÇÃI}øxŸ\0OC¤y4O.!ò ª t÷KVµã¿£E0^¤â¼öÁ ´Îü`:¿GMåÏùA8¦Ïð¥K«Õzß üœc;ôÈeK‹aÞSç:)½Ã"\N_§âñ];‹Ð“ž\y cÈb‰¤=ýÆ÷‚Àœƒ@`zÒ“‹*ïÁüÝ!üÍ7äz/øö´\ãþømOzrqÅhcßî}C6Åâ4½tZþbùó¥žôäâÊצ³Apx"¡aëeãû: @è}[ZO¾¤¯||„Ëf«í¬ßP;„KW¯^½ôMï^÷äƒðÕ÷&*—¿úH®þé§_~ýå§ô¾¤´' cÆîôÚG€ðÍÏO×¶¶¶îoýü{çþ“Æ–ðÙC¶Û¬Ø¹]ÜN–&z¯‰±©7¨è˜Ž8T½‚-( "‚Š ‚„‡‚¯ú‚ë|ÄWºŠ¢õÑhLlZ2Ý›ýÁúC³¦izè_³çÌ€Õ»v{cj“›xÃy}gÂ÷3ßï÷ ™ïÕ¿Èõ²W]< |U™àR³0ÿòÕ”[|¦çº\9»ƒJÎ}Áݶöåô²Ÿ¡sð¹•ËãÚ77OÓÞpnÆ¡7ëë*ßíâ~î—'Û‹ÀWSsà»+»Äj½q aq¬ýB!À÷àÁ‘ûâ³Ýü8.f…=œkÕ½r™lÉUó~¸,Ääà8F†åƒÑo”§Vb˜ºòUó¥8°æ_¤|„÷==ÿe­äµÐHøï“¤¹ÿhÔ[Uð»WKŠžž¤Å¯7hÙ¼›Ié,¡ž£¤Mâ¡Tºú©›W2!œÅljY|­ºW‚°š-‰‚ ¶’‘{7þr ð¸ Ï1€•Œ[6ŸjØo¨†.î6Àç(…ŸƒÿŸ13Œ=ào1N]àWàãŠP:\…ÏCI×psBÆGØVF ð&ú¡»ÁlÚ6>‡@þ‡ŸIæ†D „›ž¬…ˆ³§Á®b#9XkaÍ [Ю†þN[؉x7fÏ[ÝU–žÜŸO6VS€À¢˜‘¬,‡¡÷»nSO^=<ÕzÐ7RTjâõ=× |׈} ÆÄLù»0ÿ’ `Oªg“èÿ`'a þy´YãJ·å@5!ö‹OµÞ—¯=KHNpHýbà› ³,#ö˜õ•ñSwXÞ( ³YÉ™äòa¯¬ë‘CÝz²'¬äX2ɶv4JQÕ›ñ=¹š·*Ȇ-a¥·~Î% —ꤳr q‹r‰ãq#ÙsdÕ¹wV?Î÷Å)ÛZž¤4»º_|sÕÙGJ_ž ºdÕKÉKqÉKÕÙí  ïAýv{CBB¯¨ÐnZÒ\ʶÌ×Hµ± Au/e%‡ª·µª j¹_®©©†JÒÌ%°×Ž; ͸Íp„—èòS·N—+ *ä„o¿k+—Ø\àò0¬deZÏžó΂€,‚Gñ±iö§WTNÏÞòq-*?½¡?NG†Óô#F7¬è§I9œèt6o­‰ ‹FÍ–ºú]Ä“c­hÌß·_WëÞù랢vÚør²èÐ;)¬P´š¦+ ÝcþqwQa‡±âÑ~äPâ¡MGBª Ô³›BW¬·Ÿæúì62IgºÅ$̤ÚêÉDÁl!Í^™)¥œé•” “rÊl”4—’JsM¤Y£‡=¿ÆE s©¶d]•pUáO]Ît=šÐó#<¬j©\9õ“Ž’.³¡EЂäp†Ašu©º a]P‰]ƒð‡áù3D€ý_ãÈl>㟷»ÿ^Õªô¡-÷[™we·Ž•”ê*µÛrŒKt•TO$gs;à0ëF«¹Å€]<‰§•WQ5Q·5­Sq[î¡äŽWí·ÐŽ•4ÀÝ*úÐEÏò·Êö_˼®ÙIQð]$xÏrA0Îr[èãî··ºèW²Éµ!KÇ«tëÆX/\§Ä£8†®Ñ™ð»´¾?@ù» fÉ@SéH“ØZßk!ý]d˜[j‚ Ì\å·Q›Žª&h¸°×à =t9µšFC;tøØYÊŽ¸-ë½^S@i!gå>³@çl¿Ç^6Ž@€>¢ÄAx1£gjÒ\ƒpU ¤]-œSØç,‚v/RÛWÒëÁŒÑŒc «#RÎÂñ¾òÚÚÚhŠ{Z_à0®ðÀx‹"0¾gò öFu†Çöý!1(YÙÉë8d’;s“3„#ŠÍ=Z¶¨U­×W{•(W{ £Í¸wmxKtœÚÙJýå`¨…®ÞGf7^ËSmE‡çcnéã„D¤é¹Ù½r»ËÒ¯åYȰnYÔ•eé•Ãbü Ùo3hq åG®#µšPï*Ëq5)ñ>ÒÜMúñs ´‰ñn* âj9!Áe(ÕcÛ¥ŒE€´Û¨`V,ØÖ;e%ºk×èŠ@øÏU‚Љä(ü…Ís1‚äÍh³]_(R„ôôÇòòrä„  ¢o¤ªjý8ÂafÈÓÚð-úe,X.x€Ê‘ò“E°¯Á…¹»ù$h«£®ö„IæÊëèmƒëQtDÁ7Ðø¨ßAv›që~„a‚áQymùz˜!ÚôgØHaf.åç$ ¨6ùíj!Yff@cêFà•É12WÿAB˜ø- d„\4ò{]0öž±P&Õ RÔ5U=ùÅ&a¿ü„?ÀŽd ZèÐa|BD·OWF_à¸÷`§ùÇö8Ę̈^q¨ä—.¡;_I²kM±¾(Çø°p0.ÿ •Š—„Úñ³¹F"‘ºFœ8~Ô"¨fvšS½û¯kx’½V?f+ Y“îù<ôa’öæÀÚ|Ÿ(è‰ûÊE ØÜ!%¿!Íw Â0âï0¨µjA åÏáú×ÃwnÝ죚’I¥¡·ºœ€à ÍÿÏGªÔÔg@HµQS¿àHõ Ö"ô™Úd8ÀøÈA¡P@‘=Úk¾ wâ¿oó©À8PŸ ͳØþ¯ôÇÕê÷ôû z£á|éÁX›~}€sôûÑ`xMH1X×hf¨tlYçž—ÙèùEñ©EhçYCAýŽ^O9‰ZX‹©qfÌü3ôNQV¼a¬ßßÍÖ»ßöN®µ’'4ë!Š nûŠq9c÷he^Ntvþ²?ÚT°1jF'Æ“T’Û]U0&ØNÓ•Ý7-ß P¿-#eÕB,ë£ Z¼žÔï“óþ„)x# ‚×Ô³„žŽs LùLÎþÛ®²ÅǦaßo,B·i=%;{Q^³Šâ'î7¬®6ç„oÂýÜêz¦$ 2ØJÊ¥Ÿ#@¿vaÁËüèκðÔ~ºÿ¢A/‹« ÉÕ¶“ººõ0†óþh7Y‹_0u¢Ïý=>èªjš7ÃbÛIEݺ™PíÕ1rtûTýkYÜVëÇUúéŠé¼ûä˜q¼#uÿeïjšXÖø:›@¯Ý¶Ü,— k+‘dÛÒÓj¹¼®T‘–7ûB{ -J_RÚòR@+B)Z"ÁÓÊë!9DøDŒ9'Á/&ÆýÀ_r?ÞÙí …k %Ws÷ù2íÎÌ3³³Ïog¦ó{ž*þ¹ë´šÍeã)=efó¶÷^ýˆ¶i¸Ìân³é¶Ëw—?Òï½ß%® ?Ž[fs}P?ðN/½Rê&Ö37×#½7Qyb‰Í)¦¨ü0çYEÙU½’-4;#ßnr‰ÆÆ1ðFΖˆ½ù6Âg ¢uù5gЋgpÐ+ñªÇ¨P FËJ§p¥³¼âÃ)¹¯lÎ µôJ(*äÕ‹§f„rAã*2èjÊ#?,uãTÜ‘°@8s $ËoJŽËŸ?Y†6¿6¸Ôý´{ið¹óðl ¾«™"®¿S²’¥t"§“õø²ŸÙ^b9h„–¡/IæÂÒ˜0%b `~oBÈd’ê¥?2Š8É<.O.Dš.çat^65"*YÝ¢9(£K“9Óàdeå„nŒÌ)BH>ŸäJ£î9!É%–T,…·À/擀䢎Ô=¾ÓاÂàú®Òà–B˜§XH„‹ÑÜ'¥Ž Zæ ŠqÑh„”JQÀ)>‡EJÆfÙêùàkÆñøðÒ‹7 „³BrVÚqÉú ®Àº—f!ŽÒOcı(©ìsÜ2zi³~”3+vä¢zy¨*ñúh; áj4püÖP?Qéÿ¼1/P&âÚZ«%ƒ’à'МŒlÁç˜ ÇÚu5é!q×L<ànÊ£æX œ=N"§ñG H½^OÂ!AÛûë hAÊ\Û)uk+Äyù«ªoDá$ïÜL]½2ËŒ¬æNB’E°”n´’:ór`Ž”µÜÿõ–>¹€™ÌéIÉ ‘oGeÅÏ€0hÇú Xö VXaÀ +,Xa…+¬üP@¨¿ÁHÙÙÎÁÔ رfå{BêG;Öfgמ’ìo~¬üÿ¨×—w?^\Ó"H𱙘LJãÃǬÌ:/„ â;'<’-ï|Ĭʃ‡ÏILž&P\F¥˜ãWÑ äY¾˜ĵåé@ɯEœuš¼é˜\7H³÷¸°*’’ÂØ½:¢,K–$ª;%‡ŸVô° пµaM†Åäɸ:-›@žM¿"ŤX±ˆDªÛûDd‰—Kß7ærÉáC–ƒ¦3TÚâbš‹&ñr" ý<Ç‹±q[kZ|{$ƒµÄçîL#U”ƒñyEQ Èî ŠqQ…»/nõ I¡€ß”,NÕèž­†OAÝ}Z26›àªI”oGgn ÐhÛ)ÔlCëÖ®¼×˜]åOkó÷5õ#¸ÓmÖŒTéuš²q•ZW¦9°ÑSULhøÉN¶ÖÖjüÃÍbP«R7ûŽ[Ö Í¢pZ5fÙo4€ƒ.VÇ€ íÙ6|R kÌ}Yö4L t>{¿Kt ûãej{ÝfË– Ãj†_•¦Å÷š]Ú!²gôÌ—}ôÍtGúo k¶¯ÂÛ¶¸¹Š C“ø"EÙ“u Y~¸Ùž-y€ßÛ³E³%×óì*GFjòNX.dú±¼ë’p•¾™Npßu=¥B 4Í ›/f\Ïñ™2ÉV‰˜¢æZÔcó)[”+³ bƒ@©«‰M>Àé™X œÿ>C àLàŠÈŒpÔyŸÂOž)B;0za Ò2#àÍNà'wån·§ÁeZx?Tºnï¶>Nß~?ÿªÕ“†‘Öšû¸RºÊšÔý6Û‡ÉÍ— }¦® ïæF9ñfÁßïi =¯9›…ñÎ \ý¶-¤ëšNáC›÷·—ç?Ž-l¤fN•¼½?Ð0B;XG”Ú_欅Céoút ë¼Í¡‚ÉÀœÑãz´ßÖyu ÐòËdCp¥°-ou¹aÎÔ5t±N¶×ZÛW`RŒÔ¹]—å:?ÏdñöÈÏ#às»reÁº[–ÕÃ~a£lõ™ÕÏïQÌ]6ZlÍ0q×x›«b/w„ž‘®¶ó2ýoÃÖ¾¿-3cŠñtcm(òÜ•Nw|³£l´ì5²@8ŠÏrFH çB$„s™Î-0z¶ëJ ´tÿãÕ%˜¯kÚË+ðv{Þi{*?Þy çµ·å¾Ü0:(ûòh˜×Ôåú0?.ºCóùÁ9OWüÐОƂžJ{OõòFæÂkÌ¢ ”̾À+Y0êý£íá%G׻ꗯ«èD÷ÂD) Rð¸ðI•öSåT;T A7º†¼Éíó3›£[un¸¸brºj ÐÒA+ïïz·âÙ×öá¤ìp|@ÌÛj±]rZwÕ¦'EJ_ÕaÍ“ME\Ÿ;¬¢ô+¢:Åж.Þÿë•$_cÍïîN• ãöUcŸAøH1Ó( óK®`H\å‚~YPm'úSç|:Ë^»_ß#@ Ðãj’=<¼4…²@ø^ö‘_Q €¥µØÎa’þ·ùé­þC ÐÏQ¿éi¨ŸSu—¾@Pø+¬eæÒ¶Ÿéð8ꛜ7›Í…ÛÙ“•fK^õºaö|¾Û­óA ·ËB×+Ù \îúHß mÓð„Ù³‚’Bà?ìëOKÀë4ÇËkËzleã’ÀiôÄ’BK[i_Z…Ó‚´ …eiUhÅ’JË¥€@[¥^¸_"— /‰ FüdŒ9Ô'91F>¼‰ß™Ý-´Š¼EÞ×Bfw;ûÌìv~yæò<±O&BiÓ-f£X…àCæ–¦^”®V%û«Îž¿ƒ dÿÉ‘SÆ¡£u‡Ïñ¼ßü–™‹þÓ¹f µX}1{Å;Š<8ÉiÌ8uNŸ7Ê„iTr‡;2ÔJ}IaõMÔmôú´Je^ù3¹O¯–± \Û‹7çõ@@myžªÅYMƒk¶uNÛ5i?SBSe é¶áR¤.jÎPS}xL‹¶ úcA€)º3ÞÛÌÏãC­ ÷g4 ÏM@xìWØ+Ñh4ÓÅÞ|ß|ïy5ÖªNÏÌЃaCþXY±óƒ Wn„`]ŽHGÍËðîÛKñ-B<ä£[½hì ¬"amæ»Pþä&þO$»¶õ¡Tº<΂p ÇìOŸ×C$¹ëºqÅ:¬ƒ`i/¯älÁÞ‚ Øi‚u*¸“%ÇÉ €8ÔìëD¦šB±Â¥åȉ‚ ^äõP°E¨Õ{’ŠiÙ ²];IpCIXÍu­Á ÕwJy¶Ã¨5qªÉT_3à}‘0ˆÑ0€×´^µºßB̃™hD_=, ¶>¯õÓá+EsËãÖºWUÓ¯‡jGZ5‹: “ý² VUP7ú¶?*b@¶®Ðö+wz®4ïk7FAè]:°ÌAÀƒþ¿2Ý£ÿØ"´›+;X›ÿjzøQUO“q ¡ctI±¶'¼š.¢£zÀY>`µ—UfW{2Ã%ºŠ’Àn§2ÇEniW÷ä>øóþøcÈŠ[Çumw÷‚øÈz½gǡ⠽Ko>¤×Wé¡y¶Å<>i€1 ?é‹ö_9kØÀ~Û˜;bì½pi¹êªàÍO«ÊGªž´ù‹FNÇÅÈÒ©¿êrp¾*·µE§ç{V7ÊÍK„¼bÛh€Ø¡0µ´©×¡Vsö±[èÒ1O&°8 Ê9éd±ýœªGÔm€ÁÝ0/€†@=VªßcãF.[Ý! »»DÎYÂ"Ÿþ¥ €SÝÇ_êtºDÙoù.MW±S{\#…‰¼ù®É¤l›¥PãZ ÁDª[*=²K—“'†l…¡ßåÓ° oÁMu»à¤s¶x„.¢¹…#H­ŽV|ù´‰ y¶áÐTdâîÝH¤O»Öˆ»O@0þž¸ýì°›,Aýó'ç4±u¡XÀE\Hp3ÌLbÀÎõbÌU &âÜ%(®KFGxÔew Ù ÞÄL³fÅ0äF¡)ËÈiƒ„•Í܇ ¨XLÀxI`³Gw¬O/ŒÝm1ÓÎð0… "#EÊ™ °àuŸ€q³ dòÅq0b.¢i®`¬g„!9¦Œ¨u…Ÿ‚˜ÌPé6xl¬]ÆJðÚk5ÉüÌòöA ¤Úï.¶Ù·êW:=Œýð÷RZZ6nýƈ:†ÂN‚­»*zñ¢(ù޽› á|Mˆk¨äË1r%n&Ä›~Ù ﲇq|ë•J´C´Þ uè[/ä\[sO™@l-ý–$¯¯å&˜>ñ ~0Ÿ_a¶Å›ùÞ6SÀÿ˜\~«&~ >±UsÿÊ<|øÿdo‚xWbZ–")e¿L̃À‡Ÿ„÷‰ –¥h’YSØŽìD1~Þ+>A|T£Ê(ÈJ;z åˆC•ñfá™OñÏ4â~ØG d%'gsޖŲ4©¡@÷å `¿4tÉήåÃv!ë}|×Hœ¥rì‹uidl7éˆJ£ûbÿu÷§"‘ÈÔbݱl7ŒØ©Þx3Û¾ñX{¬t€¯û `ó‘\ ·|ª<üdÂV@H>‚ø@² ª‰µ¡€ë)ÖŽ>ÛœKóÔD[iš˜ŠÙÕ‹[Y¾×ó9éë3ÚB™ŒÈ¡ÑÕ¥º˜nОTB´G$NŠo¶º1§ùVfý,ƒºÈк‹ß3kž.éü2ó¦¨a-€&OØ“dc®iþªI Ù¥NZ¡Ê=–‚‘7]DbròÑ…œ¬®i¢Ð5×eîY “vÅžüTx(t»l¤aO;tNNÀ±<²Od"pÂ÷ Çqûl=%ÕœŸI’$a?@¼»’¤ÄûLꂸ9#ÕŒ†8ørG–¢îÄ„79¡ðâ“ FžÚÙƒ©d IĦЭ$üi}Š ðx< ÿÅx¯œœ¥o¯Ýêlj=g’Äñƒ³ZÄX¢ miD©/ß&Å*W“%`0¹(;—¼úL„ùÞZ5• 6Å´º¨ƒ£ù‹ÎnÅP8™ÞJ¡Û'vj4i_Œ×ö øÜ:f¶i°¦sv.¡Pˆ§¬”&䩟µ¶¡õW@øß@(»YE.ýî—ÜyÂ~Zùà&›b…ª{’K¹XP£_)‹7‹‰~p!ZG‹÷CÝÄçk|o0ùÞâ}x0Ð]ÕoÚç>}™SùÃãq‰‰ˆìq–ÍðùÓ†;€#·S‘qûا•‰"krgübõÌÅb;ìMnsþEGжsI½ ;NvÄ_i–å“Å&ùgÇÂûkaâþ¸ýebÄEÛ“Ûëí ÿX`eâp+¹»cÇ©Éü¡GM!orOyólúsÆå[½Ë«ŽD´mhÓ—)h­Xhë±[¼$}ižäšM“ÚNlÔæ³ÐRMWŸ¶ýç9ëãµ£¹)4³òØ|JH¡f°uSëzĉ­?ÃÂgßWv.¯F•NéÜoÜáZ³8z†¹ÖÑâg@€©Óˆô´`æ©AiBïÙhò ¬ºÓ/¹ó ¡¢Î"pËî°¹‚4þy1‘h^>ûµ‹/¸í[•( Ÿy‚ÞYsуª#Ù²­—Õ$b/«L½{NùÞëj1ŒcÖ?¨rAñ~› [þN 0ô¹XŒGQaÿqLR5B¤¦îÇ“ šåØ[A0y¦Yö$äö)ð”èïPt򿧢ÆùŸ@ñ~jã5d¦JXûäT¼‚{v':‰‚úMûð(;;ÓMk–#=gšå¿‚W9]@#®¦²C1ߊµñÐéú­›5B[“Þån@Íå “ k¥‹3Ò—5¬l&ã†uè ], x_(´µ†³Š v.C._Fä`¤€ a\áŒPõ$·¨T …°‰tJ>5J …üi Ø>|×Q@œ¹X¨;OâKT¨!ƒÉa'IžÚ¹ ‚FÊÎ…œ`5“5WÆî]¼ÿÏv.ã´ U,ç™›qò¼Ëw\,PÓ µ©ó©ËZÚÎ¥¢7n¡€ÐqÂÐv.í´Ë2´sAÚáDt‘‰œc„ â}ÔûèÔŒQ]ò3†­… B ’Žvj4"Œ¶sAÐÎE¤yqjκjgv.i ÚÎETYþK°§)ã)à"Æ.ÃßA$»4èb™JxžsÅò^ié]é¯ît±€_ ŽRé0õN fy‚éÞáýp$à—-lëPs­0±s¨d…ns¹ÖM0î‘ÆDtýš‰¶sÙ’Ó†—©¨V0xfç² ^Ú‚Aè@Çû{ÿ^ˆ{Îàë;.ÁXVÀÞçÆ¢@ÐmpÕÇýOûÅÊë5„nù$˱@1BÄ„å_Sª:ww´7îÍç€ÐØŒnIÎ)-e-IÝVéõbu®>Ëm'B\6ê{ÖÄ¥¶øVi–¾¹Õò};—éhviqAãñ>â‰l^åe¡ á —a„Ús©‹ÅþI$º“ϽdjÄ€=S„Áï03þ?εOa±Ìà õoÎô ôî… tdÞW=Ó<Ð{½”ð¿ØßíÜ·¯6†…Í S1 ™æãè¢>•‹¥š‚ûÑ×K' ­ßè­œ!´iË6Wh ,×8ûÿ#ÜMÙ_'b`ÐðwaàX[`eyÔÙ¿œ“ˆ-Ö¸¾„i ר #Øãl\x´ñºX|H,¯[÷· ŽZµß0íb¡}†­ÚèÉd°Ò-±bnëãáõ’_‘«/÷èØ‹j§t݉½¸Ù)Zu‡slßB}³/ ꃰ޶ƺÀͯÜ5…E:GÚ2Bš®€p ”UÜ<nn]U9],\fB­ã÷7f\ug~s6¡†4žø¨J ä;]›†m ‚4¦’JZpÂ>Ë189këøÍ€öº:~#pb94rB 5‚>¾IŸ'çþˆ‚t`k— ü í'.ÍŽ$? |éY0àKÃÔhÄjÙ¶½oÜœ8íít¡'Çà„¢1q¼”œlð&aÁËìÁÈEu`£7DÇPï>ã“7RÛZÔ³ â“{ o’˜…÷"|º-ò#ª6á8Þ2ܧ¬ò`CKÚò Ø̦¸Bíì+%À=&¡¶X¥" Ö:W?ƒÜȧõÀ9F·`ó¨¤G£ÑLQc×"u‹} äƒhÎØ‰iÚFz0L4Gïô‚ƒM–giAYaœ¡áªX¾ ÊOÛ§¹pì§µ9÷ª.¹ÄâùïÓÁˆgúù¯™%|•’þ²¾\f(‘êC#zY ÜzÙ¡áè…a.û>Ï\$+¿… ærY‘A"…²jhÁžÇwÈŠ¸º¬¸XB%†¶<ÂÂâñ ¶Žžý -Ô äF¹ì%ád–Xpàj•œ€ë0²rAq]ç˜T0P»ZÀ#Bð4F®„\# ©Xàú| ø, ßGÌà^yê¿È ‹ø*IúŸpƒË¹­T0øÊRæ51“™%ÎféuÄZUWWW[&Vå³³AúfW‹™GUýoöÎý'¬ãä p|uâ4¡iÖ¦ûFŠ´qEq¹ˆâ‚$‚7(ŠV´VëïmÐmºZoµj4M4]2Í›lbûƒyMcìþ5ï9Ãp±º»m·6í»s~™Ãœ3Ï :Ÿ™s8Ïó}.²ò ?—”)Ô†Ù“••ד_»íæ)y+É(à&NLf1jMW3{‹Ì„{Üø˜˜‹/rõÕ!ITì-ÃZÊwF„ž#d ÉßKá H”˜ñÃ;Ïý$§;¼Œtº{°æŒr3-›†Ö€ÃB*ÈÍȱ.ùé´•eÊÙ (y–`¦ÒŽ’X } YÆIQ”°Ó]´à F ®„ƒ`€‡ä\Âk¾X(7•ò*²¦<=µ7<[¦üä¨-ƒìÈáAP§$u»àð‰\Jæ…Z©ô!á æ¬!ûoaÑöxÁ¾8ˆv;ÂíEkHÎ¥%€‡¯"ØG»¢Ò. 7÷4‹JAò'»aë=w=î† <|ÛWà+©uÌn= ^”,¸^ô—H®b›™täéóÛN’’œœNgRûXb’‚8ÊéNrº»’}žûÅs¾ŽÐÞ7¤bíg þ¼™. œ%$frc’E¢Â̧ѧºaÓ….ß*è¾O<Çå&_» ÌÉ&fÒ1Ëtù§sžŸñC&ª“t5»0™Þ§Ëÿ=Šr.ܤaFþ…¬ï²’r…ü¿¼Oº| ŠN‘s¹–Hɹòãh]#ºü3‡F$ qÎçþp>+ó3ˆÓz.tùVAøl’¸¾}í—µöž•…§ ]¾2>‡0yòäÙÚÚ“c‰BþÞOÛø©" Ê|ÊÎ?+g¥¡Á;‹_ïøƒ¯âo{|1.*Àköô­ÿ>’+gñüÁˆž‰3ôí‘ÔQ°?q=77Yþ‰÷IU]ñ)ÿýúJrI”V¦G—<•[¹~û}>©p¦„~õgfY:#®ºþú§Z׋Šfä7é\B¤9%+)¸¸L°Xrý•¢+Jz¬úÿeHóÏ.™`ûƒ ðpð»ád‚  ¯^¼u+ǧ<¦í®¿W=¶È kÌÞ¡ÆcÍÁ*ŠçAOË uÅGrÞ`ÇŸ§QOìà¬Éò'›I½_§|b?¬¸rÆY•OñHÇã‹Õ'Ž ‡œì*Í\£†Ì\ sQ6¹÷ÒöIÓê.7(’ÙP¼è4J$i3HšÀž¦ÙròÓ$6„ œ}zÙçw£ÓË2´ïd뫅˲=9±ñLÀ F±—y€I€X1ÀØ p7FÄ#GSÀ‰çogŒ¬APO`&\äÁðAG‚Û°ÊÆ ø D]Œ€'@OV‚²…@ÈyÉ'Bæˆ`3c£}$ÌD<%œ ä ¨?ê‚….*lAböº'ÙÞquкDNBÄãb4V¤6ƒ3S Í¢*¼J6yØqÄdæd6›"‚ ,í’£>z¬5<›˜²´ììrº¥­I Ò±Pl¬Q3s©Eƒ\ݳÁî£Aø¢ ð&PÂñ ‘„ãø¶‡¶0̹¼ÑXV[nòíbU>~ùÒ½ÑrS¼3[Pnô šf•Úî–K«rfŸõ†yù”TÁÚ=fïϳå¦11ðTï›Z•µujP/"#ÑÐ:Dm}ƒA«„æA“¯Ü6š ­yµ³Å Dך25hÒt¡g-³Ó¸oCxÀIž°^XØÛpý¨ô†æ)¼(?Á ¯Ìš‹ ͧnª–feGÍ·ûKâ²ju)2»]#<•£MÆŒ¼d*¿F¸7*œocô­Ž ëv§„]ê’¾ abÐOñ…«T´ ¡êqìÔØu·¬V*ªSö" ú†üÊV*Âa®ÀV4X‰ÑDa‘ÇK]XAƒ$Ãlx·‚áK‚€?GñúÁ„ã ðlÚëp ™ªë]ñ½2Ó k½Q÷ëOÒEÕO’í¿Cf‘nªr–dãžM·â`Áo_JÛ$ƒÇ&PÍmëýõ|é\^XÚ—õ³æ¦åX·+Aðl[àq¬Û‹ºÞÉ ,¯Ox‡·œÛ¿Ý‘™¬®é×8^²v×Ûßá:²z‘ªpXû ‡j¤…¡2Êì^ÕÑ k£vQx‡*ºÝŠM ¼ÊaŦ{c€›AC!|׿,’ƒ…ϦìGMch¬âi1W—&ë[Ì£ÔŸb4ùRI¶@: Ô²3¤‘Àª©X‘ÎVZ}ÊQikåG@ÐùXFC¶@Ò|p®Z‚,”µDó@ì÷î Ëz,1ŠÚlÃ:­cÈ^EƒpWÏ „µg ¬bžS*ØŠk‡ŒHµ{SèT;µª—:Ù¸Úá:t¨Æå#®þ⻋ý×3&9Ý‹{M²q޹fã¨VÊoë]x ìÞ=xGËõ/,3$· þ· ;Dýtò»8+ª84zëÞê-¼éöîLͧë{ÝOMCã{²:hµ ÷ÌmÄÕ<×L; 'ï,¹ [l‡ëZêÉð‹;·_ÉQ„éF…¾æ±Ý;ݯö°JÐÆÑÝzóÚ=ɳï¼°øÙ Í»Y #›184Â;TcâÎG륛ÓœÈX_rŸQϯ•Üg–›/}J½QÓVС©Ði*Jt°uJb³?V–4™ãªážª{D4Í̉Íi ੟Ýcôý«e@Iý H`ÑëÂÊ“h’RYÒWk»Í4BZîÙ¾B ¬­±ø ºÃà6uDÀpwOçÞJmR½Líô:,þÔ x3–m÷súD†²=û¦ÅÔjS£øX›íBs¬ìÑ+#¼ãS¡©0«/†1í[ýT<О³óâèáÞ;·ÍY+)_toÝqÛ:,“Ý‹9¦Ö]5YÖþ>\Q*”š\Ó=së¬×ÿÞt ðuƒ#Õ £aßõ ©#õª~Ô<.¶{qܳ¸Çµ–?´ønê÷ðõd*ßw­#}KBé¾+ ‚¾õÊ˽ù›{=ð’j_1 )ºf¸i0wÇÔ%ÕÍJmÁ'׎š±*ÅVJŸ€ßbnk¦ÍÏ3¢Acb’ûeÖ€¶ ¾KøVsRKX`ŒJ:¤¨h;|µÀÙƒŸ×AÀhNÁtõìæOÊBr.gO.íØG´$p ‘CÌ ôa½´µ=ZZާ-í€PA)¯BI È«´–òª‚€A0 ÈKÀ`L0â'bnrðƒIc~ ¹ÿËÝ{fZ¢Þ¯èÍ™•ÀtvwמÇþí½öZk¯Õ¨L›Ó½oZ8 ¨Î–•Z.¯_·íi¬Q¹võÓ XÑZ Ê,œ?[æPMMó3ÂQkhÈÐ CHÂïörZÇÌ'ÃæÝz~ÉßcλiÝv„œ–‹nùße/›,´ƒDÁ?M–€v›‚Óºm³t•Ã57hšfC$ýÁ¸y·Rt“‚ñ…µ±sÉ`íõν1[^4¾´?-6ÜU«S»NE€ÐïhئܯÇt-s#ôƒ•Z‘ûüDñ‡ÙQƒ…¸4-ùåÁósþ7&즵VÉk²BѨ“rW4o6VŠìLÛ0Qrõ¾ŽÌ½Ô{ë+ÊxçvÁ˜Ü†s#;—içr@YIByÅw(CVÜÈÞÀi»¼8—Í£¦ŒÙÓî@0.©\ \‚ E\’Ôù0œvÊd²4•ü6„#Ò™z)V¥_=ñ,Z}Éߘ£™½o1;Ö¤ù¥l¸:+B/E¯æ´EòÕI(ͯ$l•†DHš_I—¾å€ð·­Ò’¾†7¦.-ä19zËúª®[ÃÌbkÒÎ×ÏMnß3¼&Ÿ›¼«³oá Ö§…ýõÃ$ú§ƒ\;EœhÔt·Æß/ßš\ÑY6ÿ5fÎûа¢Þ‚_ sÀŽüõ$Z#T?(m­oèIöÏ^«ð÷·mΖT4̾õ ßÍ®£CB£ÚFPPs¿nl½ñº1­¯¡'8÷Ž Î=¯ŒÐ9§ªdªQ1šv€@ð(Û%§¤ªµ¿;”®Š)’ûν@°–¸Ê KNU ‚¨½o^&Mp™k¦LhJ.Ì•K¥ÒJB¡ Ëœ2¡] _^}zä@Àpb±{bñÞâx÷3ûÞ0‚¤ Ȱ8Æn…æoîo÷#²_1Ø«ä>qU."»šDœJr%„8kÔF YB‹"…€‚ùe‡JDˆçýİÃIdn‹¶¾û5có‹Á„q¤¨Ê¿Nˆ Ô.¼Y½RX³_ kw‹2bøH$¨"²ÿíß>/’¤2¿‚‡wGG”¬’X s/± ЂR¨eû½AuVìã<ª™Ç:xG8èúQv¢@g\ˆòKÞ vÄ@€ïÔ»8>1þ¬E²ÿÉïu­ø$ƒnä¡LÀa. ‡ºá eËSíš `‡ìÎ?ÈüräóVµúŠÚßî®òõÁg¾û˜èÓ¿A:mþ4£èi¶L¶Ìê‹€[Þù1P-•I x -ØqK¨åŽÉÓ¿¦ûéïá°Æ†€úœFáãŽÌ–3‡!“Hø}Tß?Q_éJþ?ÅFáÇ}<ñÄ'žx ðÄžxúQ¿fã鯒"èjZBñA,xú+Xn-tww/ܳ|ŸYa_«ddƒ/¹/À¯däé[Ð Ýφ¼C‹ îÝîFq 7¾=á©‚=g± œÍø'F]Û†Pñ?mT’ºëð@Ä‚¯âN(pBñ…ì’ØX´ßëÅ‚K8‰=jAª‚_Å}G z|ÜÍ„º«^˜ˆæÌ±<,++;¿±ûã¾U>`¯ˆ¦ÜÃHKaÝÕ ÏM;_î?îù¯’‚R?ß1=òwÒëßvN}…)xšÓZ£â°:å2õŒ™¾Sv~zw\öù²sÈ„NZ2.š2¥j5ï]ô=°8ASn'P@‹…È^BúV£ÑÞ Ql>$j(— ºÂ¦\Ì­H„,*’þ DÆ7,:Ò1I–@4¦'é*€ɳÌrdf4½l×N%J%‚’Ûfië9×%ŽMhµ·ø1ŸqVbŠÉ=ÍïP’'ÒèTºNæ³@ˆj ØœäT `ß]îênæ °É­,ÎGZvEp «T3còUê,e(âŒíQ¦©Uͨaj¾Órñºª“â»ûç ÿf;Ô@5Ê­ §…[(o+ʹÌaíÌ™ÿJmäósìMÃ6“ôwÇ·)€%)õ—Œ$åŒ÷ÁQ¿¡ÀX½…)dDšlT þ9&ÃÄé$øéŽI’L–$av|š»À©¸<­£OÄd$šñàƒ•¸lŸð‚à¿3£4Ã,&Ý~:9ó‹á)Ö‘~òìˆO4a›w;… öt¼ÏìI1‰m¶˜Œ Ó®2ˆO ì)ÂcǸ»°5Iàö¥þGjq$ù_ÌÉ ˆýIt•Ä?–‚|W/ŸLÇÙº·3'S¢@¨í8. á¯t¸»¾9öcÇS#ì8f怠¬üµ]5ç.¬c§6Y_W ˜ïÀ]¯T‹¨`„/Îßnóþ½ ä|M´Ð°›HÆ£@è¡Dy›w—¯„¨¼üçœV3V 0c`D£Y+Ò«Š5Åë¶àS¡x[G×k WëL™…W W{ÍM1Ú¼}°¼™\¹bxwcKcØ56™DÿoW] _5ôSÁ°AS4ÇÁ+ô‡,Ñ<Ë•‚÷z½Æ°–øDkíwmö.Ü·UmÕ±u †PÞû\f¥RT†¼CƦ+#¥ƒèW¦»´Wï—Ãæ‹›už½aíá–F³3¼»/²Jíó¨eYÊæ3•Rþ80˜,µ¹ ]ìnË;iYYͦdµ4+KÝ‚°ž|šìf)Óéh'<ܶ¹°pØÂÒTz@&Wf¹Üˆ_eva–rê¥%ÿßì]ÝOZ[çÓ;xÏ h‰šŒWKCbå”b x‹|VA \PŒŠÊÖã IDAT‡ˆ¢€ŠXEm­ÑÖ´ˆ¢åj£1±QžL§ÉMð>4™˜Æ>Ü¿fö>|ˆÌdjî „# aj–æ9§ Ê‚hôs ‡·¯½`„Ù÷èÇ¡P ®ÅúÅ<êçB·+¬EZ¿˜ê¦–NÌ l#à 8(X>LJ!ˆóm‡ò–íÉl€B ¨úÑGºsMèΓôO–ÚÄP ´A1ö’þXÌVÉ:W@,…öÙÙbpzbÖ±ÅëѼ\ ÌüÏit‹Ho&cÆrWvöOQŒÑì È¢öbs«=WëÇæ~¼Â÷F/ºõ}Œà€(§G.‚å‚‚ŠR¨OG½ˆI«OyŸF„'Têˆpp#¼ËšrÒ–_òÁTÌ\Þ”•q}ü –%a1 ¸,,ȼ#ÐÃá7+Õ»õ, ®gF™çšµ²øþeF¸ eœuê jÅ0&_t…ߣ­.'Ýb7.¶ÑÇq€›bÀ% ´/ñÁ@läê ¤’× U·3µbÄF–…½¢÷.pâÛÇ£j«•6˜íë$©X›w“¹jOËâe€P|Ä@ée¯˜Ì Ýe Jµ1’Ùšœ@níÅëQ«M\#nìŠk \ ø! qé»6 !K_½ËCÒç}ü%5]µœŠ`Ñ£çxXŸ@p|ªUÐî¶“;½žP¯cÏg>Y÷†Ç6LÑÓJÅ(Ç=eZ¹|jUoO–¸bs(”KþO1B·ç%èaZš2ÍU¸x $7ÂK.#PüžÐCýáe„3ùzbÜzÐXs½l}Ê{]…–m £¼ó‡6(Ýåü½¯0ðÎw„¿Sú:Çk‡>ïk îæÿĽخn0õ#ê=rw¬sQßæÖ6Œ÷:%f»*ß`ôý°ŠEÀ¡¤òïQÛfm‰Å¨ýw HuãÚ±NwíÄÂfþWŒ ±°­€Áùx9g©'UTÜ‘q¹ÜöfòWÂmé‰Dkgà ¯žGðNÏ—R`F0?=‚dó!\-WyÊîM¸ÿã2ïe?‚ôlÄ~æ8çFBN /tg øOBç¤wYÞáØïû,!œðp~–ƒÆd‘ ^6á@©œù'~¯ÇÔ!Ì¡ÀcQ ±ÄyÇWŒÎ‚ÞsÜ<Ê›Q—Âåàpä3DOì!£N‡ü¸º]Þ„¼ºFÓ³-S 5‚ô€÷¢ÃôÌì §JësÁ…¡¸ÓÍ÷³­ A(JûXÕ¥g‡½¢Q³k€k$é¶c5l·dÌŽÝgkWÙ5÷15ÀìÁ% ˆ,ìŸ øOØJÉWŒàokÃ0L¥µá:w}và@aØ.È#\ëèŒ:zQ2BEñí+˹G¦ßz5D÷Ý?æ³Ñ¤”‹ëLƒ¯k¾[Æ­'ÈšÖêÁ·×ÓDßô!#BwSÕšQ®Ví²hä'üéF½(‰”V¶ÓwaÂѬÒಙ֌¥úªª@3"ÒWµGhÉ ¸d¾¨²½=ôÁ¸‡A_+ Ü­ŒHõÑR¨p¸;:Hƒ]D}TA ú̵ÍjÒ 4Öê Ú7£|DTYE_“´VFˆPº*À*4AF´Tö }W‹ö$JU„/ FRw&:Qþ×è).5'yæd>K‹He\V9x0óËÜa²‹pi ‘òž€UPÌ'ôp@\A™!ÊhßÃâr¼½¯¹ÑG4'KÉšj-RÂ*“HeÐXÏ»B´~‚eåwÔ㸦L5~ª%ãé án%v „oðŠšjê~¹_×~¸F……Ì:FÃÕÝ ½š~ýúõô«ç9Ë2E芠P‘’ÉáÂõù5•®EðIðˆ2Mç^ɩ˩3xLÒ/A‹ð)Íy£Ôž¬ÆŸÀòãÔûS2icŸõ¥çÄè?Fô¨.RSµ ïâ¾aøâ'çSáßhÎÕx£[ùµ/<óãï[±Ã?Ö:8•’âTÆõÜý¬št.UÎ¥¤äÆIø ïÞžY>›ŀǾ–ÆkÈ‘Œ䱆ÄL°°2 r‰‹ —„×ÜÃÍ€…Qƒ V¸ÚŠ l´Ìv*«f¸*gT¼ÕyO5~³JeÕ¤ž!s * à ;ÌÑö]裮°õ¶À9ô@‹îÖj˜*u,ŽgF ‚EBhb òwp•Ýõ˜`J/;0S©£²Í dp”nß¾þ °ü— 7Æ„³‘|9« /#c^w*½!‡A(ºz„¨‡“yú¤jŽhžåƒjsöGй¾Ú,©æáË¥ |y@ÔæL牞*ÍÒ+¼Y“1ŸIæ1|¶›~ªÏ™wR§Ù\…ÖÜÃ3°&h§qQo¾d —úøT„§¹¿«ƒðSUNÛáå´_)ŸîUÒfòá‡Ý--ç7ÐÉÎ5æạ̊泊Ç5ør¸€Ìe ̲$3‰Æ<ünd¬5†ó(kø"Qo¡JšR'‚ïqËSqdá&Ü©-Ìuø¼“E^Þõ4¿z×0›­'—î–Âç³ÝJ­´ o6Ö•Õ{FG ØËN:#=e€ï¿PÍž)¥•û«ù½—ÓùË:–Ä(e?ENÙ|¾??‚±›q©UÕN fŸ–iaÕ-¥<=ez9¢`AeÕÌéÆ$õµ‘ÏC±AÝq>v³üÍä\hTÌ2ñP¨˜åH»~Ÿ ¡ êå¤zR=¡xU¦!ÄdzÂeï·â‰buMÍâÂTãœB&¶÷;&ÅEÅ«H¸Â±k(r­:Ý„Xæ²?Ò®5j…W;ç+ÄzЧ ω u1Ó¹n‘æQñÔœ¯¬cq¸ùÖä«z²f‚lWlpäÛ#7ÖÅE$’f%‹'Ô Þ„5…L­_ƒ#+GpÓËH’5RmÃ× €ôñ² ÅÞ=—X=A¼*µ¸Ô¨JǤ~R?Ü7¹j‚ͳ2Œë]„¬¶ˆ/ù·Ñaì8‚ ñJt¬õB¼¤Ö¤¢üÚ;œ^‚ Û²4Â’!Zí*íA"]ãeŽ ÃÙ1£ Ç9°ªQ/,™ÝªGúU6aIDJ8žpKëÓ·Dî~äú®lvv.¤5Âwá°ŠÅ›ˆŠ'@îQŠv˜cqe«Ï½ð²žðžjýmðr¹g!sÛ Ÿ®ÇÕRþ¯©|‹Ëk%¼Œ€)­4^n@Øí&¼I2 uÆçv Ïb(·gz„žD«bcTìiÑY‰…G÷\{šZ§vmäéúf¡#8ØNl0¬K&ñJgœ\ýÃ6[êX÷™VÅøó‘GZb"en/»‡ÄZPth³ÙÖ–îZ5Ážjt'´¹6’Á!8:kE€ƒÆ†¶ÒÎu_–{ÄĸçòZC—{‚¾òàª?7ú-¡ ú¬NÛÝ€p&ËhCã~§ÙVÛ}AS¡ÓÀ«Z¿äI˜,ó:y{íy}…N;EŠ€P±•T/0™¦PàÛY‡m覭e+¢çJÀ=y¶¥ˆÖK{çWDV3'Â÷!“’2Ú—s Ÿ),@n„A°ÀÖ™ÓáÒØM™(¿Óµg1x2’^Žj}PiäóÈ…îêE¡V˜Å5Ü•­£¹G^`“›zC?†Á‹=”›Š·§†F’ò:^ag´Øã–©½VC¿v O´k7¹í/¬ …|ÛÕ›KÝ#À1•Ä=¢3KSñEŸyr3amøZpXÄk ZànÓÏISm®M‚ö¹bi¾»"ÅátºB ÕU¼×ÏÜJ$ŸD<ܵ‚¤*nR†Pˆ?ÖéòV¶µŸH;B›ëô«¦0«p^*µU¤Ø6¢ ß4p/'h ÷,m^›3! |á{õ÷QÀ~îãß#C# 9„ä]N¶*¦0àX Q (Ž€ÐÒ‡'2"Ähz­VPƒ µæDWØ­¹Í;v€¦öb ,¯”ŒºYEu‘Œ@ ü'X±;´æÛ^Õ¹E‹ö–âñµÕfù´ås¢ÞPW¶Ž¤ÏËŠH_aëHo0tnÑPK›²&ÅðõMÄi´MÆï¹ ½æÅAMqMQÁ3郌dÞš[@´ÀûX2¤ØÁMÈà;¯ªƒ!Vì·}¹~¨ °8•š–2Ø.üÆ{ ˜šàÐÈVëTá%‚©C=‚—:(*­¿â"¯­Ü¶¡¤‘OçÊ­Kþð]— y»e>~³|é[ÀŠhŸ>·ÉGLû´q}؉a·¶W¤ä³Þúã@¨h]ðp{\!fr’¹•‡Í|_rRŸžØ‹€ TjP“œP irÉ×’m{?×Bõòm±xÇ*.97K`w Ú}«)û(«œ(Ãқ߸ë+ìÿS¼£Z_ifü ýö Þ,Üet¬#äɧ“ª×W³]!e¦…lù/{WöÓF’Æ;ÕŠ1¸} &i¹W"ËJ”D˜±a²†ØL68`Øl2À î+ÁˆK'Ë%"¤ $Oyˆ´ä)B(ûÀ_²[Õ¶“ÉD³Ê0Dšþ¤¨šrÕWUþuWÕ÷Õï›zé%,9#kûIËæœYÿ¹‡£©Ö…{ŠBœ>Ü»]!ðYhÇ´ú¾Å ç.\Ó½_Âs8YÓ×;½|¯Üšq9o”‹i~0ñg@hlX¼ëjx4ÓØê> a²µ«ØîôVÇÙÐúÝR²ÚËNþƒÚ Ü:7ç&Cñ˜H!¸ÞbÊÉ15<@ »™º×…¾c¯°Æÿ!©åèu»nRØ¡› kƒ·†2M÷uOÜ.“Éщ6pÜ;&“©3¯yö¸½ Þ8ÊÌÜî%«`1ÿÈS݈ÆâÈÔ)QèÐñeN·gO&=õ7¨õûÇ»fŸÃäÿx¼›ô´m;¸‡ ÖÁ|dPËîš·cì&Óq¶S |¦O… v‡þjêqeÂüDYï7™¶{«ÛŽ™Ž*ªÆŸéøE×k-jÈ£#ú„#EFõ!즾Ùt\‰ªÍV¾ÿøé1“¢Õ.åij#°ÍZ2]¨©hÍÙø’ÔuÂ[“±[ܨ•ÇwÚªíÚ”Œ.Ú4LÔ·æùZ%–*„ŒJs]JÆn·\« ìJFNA_§E<¡TPþcºV;­²Û§_Âå賎˜Óñt«®åÄžp÷µk^5|j¬cebÀ•RÁ!0Jª@ ÁQ`¸DD11I2àýEÑ[úú[±65I ÑÏ&‰Ž”ü$’ò`E@ñ£e<)=D_F™R5T {+€¹8?6+YJqë >‘4óz­•Â/WŠ·¢¥ü›Ã 6Å6ʽ óEh¢‡s`ƒ$\,CE8À.DG%KÕ°ÑØÐ ®Rąݤð ±—“FIáI#.MŽ#!‹86ÉMÆ1B„saoy"tIá’()ODa‚¨(EKQ"”2¯ ‹S" PhX‚¾à"æˆ5¨IŸß+Ôô\º!#îU:Ï}CFágX |mp¶1ÔÆæúûûçÆ¬§¼Âî_ dÊ=ùÇ\ÒÆÓÙ8€&lfŒÅô% @¸"¡Í“PÝ“¢¡‚¤uǃŒ`´Ãu0U‚V\1cª‡óƒ%H´XŽl÷³L…Pü ÝKDWÓrDDº á¾DÜ‹`|7¤Î}IÈfÆ RCØÅB›2¡FÝÀ`=øH…X_‘¢dðÛ»FBTMâ{9‘¬ñ]ßò0C®÷Æ‚DE¿§(!åÂo¡S¾N¸€ÃQ°Ïü9!ø†ü~ÞCâ¤oôßý)£ˆ¸Ö§Çʼ>W °Â VXaÀ +,Xa…+¬°@ø|§pÀr’³ò—‚s¯Ï=›[oÁÙ;Vþº@ÄzÿÜúØú\ÿz„iù$ˆÅ9 ˆü`aghäø37îÉH38÷{Ì!ò{ ßêo'H’¤:žý‹A‚æÆ•+W.E¨œÙÿ@îlLg4VËnÖ¶¸·=ýçÆ'ê?òé®Nô2áâr»êªò¿a€Õ›y}K_'œî²¢Í|êâÍ›'L/Ö$’¾¢¢ç…ìc~î@ ÇÐé}ôÊ%kŸm…KŽTÛ•!o²CÞ¢‰ ƒn3a?áo'Ì8ñ%3îJá²$ ˜É¼øo‡‚ ŠõûM½A ±fgy6îÕl~„'8¬Œñ0¢§x¨sbºƒu|ð…æ©§ã•!ífŸ2°È2RïפÌh³wCmhrÅ¿.ª•›ùu(ü2C‘Ó­„’þ¼/^YÅáÜ ÏÆÂ,äÓ~7^vûêÕÏ›üdX‹HÆÇrÞÑG„Ü(™Pɘ„¯€Õð¬¨dÄí"I ʘÀLŒ% †EÃ8(ŸP|) ø|`<†áÉ%¢8Q(8¡†/ë ˆR“a `Xù¢‚à|Y!¨}±mãïpD€G{p’>_ óð,䞊ºtó¸°7ú¨¬B ßÞ…?\ˆJ&1*™Ê’‰ ~ÐS5<êK Š 8Rš;eÔ{QÛáÙ"GGÉÃDRä‹K9(‚ <4I£€I.„92ëÜ7Ô…ja†Æ hÕAq9Dé] e¨õr¹Ý¦Øp>ºtýºÖ`pþ@ ÛŸй17 ôˆ@Â)ÔïÎ+'I0n¬;R9Ð,sÍCÈëHÿè_µvãÞH¡¾â£ãþ´ZïC eµd;î#×{`(Ñ9îÏãéZÇ`y£ßáìEA­kú¡RžípV kí~»ÇÀC,P©gÂËÖ;e>­Ë¯kýaßSzÞ>Ñwošlqµž”5ûŒv®Á&tÛÑŸ‹sÈñ®v°Á[ÒVý®§õNÜ­Lñ\wùýÆÝ~½òD[wb™\>U¡tžoL_Ÿ*6é·5~7>%c>ÿnbn†|É&ì)“#ŠëLFJÏÀ¤Kl—§´zÅa /IëâRS2 Jm`×]$—WåéÇËâåÁxitxYwœ7IX—Š föuæI$â>bð{}vg–×q°n!âS°µ…GA³?šæ™&ÍGoî¼Óhð~j4ѵü®Ý³ì´·½ô8SW†m>ÏqüÑòȆg;õ¨t²^õ¦èí0âvñ¼I};ê=\5¦­-Q  ùýÊ`·§4Ã¥à>V­þø Çôû¥ vϬä$Îr“÷ß HoUÅÊpêߦþ>5¼÷‘¶ÀOD©ÑîÙ¶5/Œ†T¢¤{[¶³0œñóÑhÀ¥:˜™*í\lV­Æ¿jêÝP•:ãöKvÏs@qú^ý=ù’ÕG}.ãfŒe0Án´Õ¥OYWÿÇÞÙÿ4•¥q¼sš,¶^×¢ w’ºÔ1ÌäÚV.r í ¶H_€–ÒRX(” XúfQ € ÓVE À6 ŒäÅ`H$ÂO†Löô‡I1úƒÍžsû"¸ÙÜvY9_H¸ôž{n¹½žç¹çœçifƬ5´ÃÆŒ\j¦7í#—;˜9MWÃíƯé‚mÇ”}D·¿àx Úß7ewEÓëVmÌ£LKMïªù#ò?»«W›ÌdÔyëWb>ªð¿’Î…³œHçA˜þ>¿Þ==¤bAèì.xù-ÊØ6ó5-Ýn—²ê}ù«Ö¨ù^ÏwOBDݱ¼ä ¸öbŽ3ehV>(ÓdeV«ÆöàÝëtÀ#bŽ8£A÷h…éÉó例`Å@Põ_X ¥ Ž«QÁqÏà·Á@²à¸Ò(V¡ehŠъª½òIo,,4,E4ûæocÿz¤…c*š½Ô41]q/ÔÙöbZKÀÃWÜïÈoC}™C³©+@ ‚ãÐ"ùì¯Ð”]«Ç.·Ç²hw´™ùf+®PßYìkºx&³Ùø·.xÛ7If-½æ3V¦¿™î;Õt‘ÇÙ‚±-AÖ[ [™É3ÕÆo¯6yùY@°„©I®SÓ×Cr,‹cB ÂáA¨»ytá/d ðôYÒ‡žP¨ÖZ‚A@) ¯Ë\tèPÊ:”ã¥ÉR<^à)ÚÚ†$o`"6^:®Ø´¾(/5²5Ä-»ã±1ø¿¸#ˆžÀHÒ"^ 9로À¨´o!ª‚öâq÷sóG‹A€€ý²•AíaSª‚÷c„ð±Êï˜AÕ^£Èí)-]`!꩟Ð{@«‘{P熉í‡W._^IDATª7Buµª Îÿqâ?ª¡ o_ÂÐõΔ¡ª£ÒÏ:LÕL‰xV ÛäŽýÉ&—ÑÆ2û$ÊóÑÖEËdTÍ+«–¯š9ûAQ }%apÖP2™}1ß›zÔÅ‚C~¡¥!á©­ý:Â×5ªÄ ‹áñð@2 0í‹ÖŠ4³Zaн6¥â¸b´[5 ïÄ€k©Ñ(~@P€òúDD"‹û+šjíH ÐÛ1Šíªax„ÛŸ´„{¡Bx¯ílj.ßVD*~ûü E8‚~}&Ò’¡›€.”Ƚ‰ÖH^ƒ}C ðA$‰g,B „Õ¨­¢]Ŧ.¹l†H€pÃ’Aý°2DMÙ¹2&Œ Ž­LÔÒ°š#eAäe_—+j‡ûÇ" “ðr’ \¿”„M&¶)¼þ †¯•q—‰ÆWK¨Ë gzïáx<52ýuËË>€ž¤¶ƒ}1=þªk{AP"ÃÑ$$ƒm§{óŠÉ[î‡Î‡a½qvÉ3x:Xìíäú$ýSóf=tZÐ>±Öyê^9 BÐ}_kòÆ¢÷<ƒ¼[î$}[k§î( ¸_•moÿ¥E¸¥Z\Ø„^9át»´™÷baoìÝUß“Pá¶–š»€@¸£xÅmE DZÚ¶žoœ¾åYÁÐåµ= ™§¢Êa­´Äî?¢mÓìp{쬌Cgjnȱ¿Rêy—™×*Ÿ…?¸°µÿª©™ÞøGô¿ºFJ^v”ÿ Î’1’t2áS?À—7,½Ztš ÂñGè~Œ Ãï»ÃË©Q¦­ûèÃqi¬®Té¼»ÐèÒaÏ ý¶ËvÓY¯cuÅŠÆAgÀS¹às.x˜á=Ň’…ç@ _WÔíºco¦uŇÝòmí-÷Ÿ+ f`°Ì‚й§íªP° ÃðÆšñ#¬%- –#q&XÊ^¬]ñ*Þ »°³bÅæïLcÝxlTíU|¨q¯±x0à©ùqfZù^šlv‡*ݡ¥Øbe¹«i!÷~,'@ð"zÓa»Â„ÑR=¢­«¡ÖB£`Y*g Xh‘Œ1j %²»ÌAÆ(±wî0szNÇ®}N€Ð A Ãêjfn§š‘JQ ˜ƒ @·j^L»Ì+2·ƒ‘×ÚZpŒp<@àËÃL\À5=~¦$‡››ý­]Lo­_§î æÐãÓ`Ó0©ìVáË·…MFf›3s‡(†š­àZáþ ÓCš‘£5Ç ­ž¡lÒ <šifÎ àQz^4æ“Bgůƒméy :UU6O4é¡Ãt 9U9ç´N¿ªÃ&ø^LÍQ«|PØ^FÁ@5MûÍUÞˆˆ¦:Ô)|7êŽGWz¥„öKíÕÔK}G ãöH7hªgèy­¡z>ž…\¿y¥'ªú©Ÿy0††îú¹Ü¡ijõ6ꇲ IíÏ0FÐØÄQ-ðeˆssŠtêìZIîm™]+ÎØ˜¦ÄâU3ŸUvT—=kí'A³®çf˜ poT«J £qÇg“J·ÕÕìð@?$’Î÷Up1ŸÂÑeÃæ¸ÝÃÃOŸ=^Ö§¢I298,äðȳ&aâW.Á:à±éxT}‰@`.ÜÉÉK¦@Ù¢p›ä±x$z ¹ÉB¶-™˜nðDè;1<Í–,@Å[é$ª4°ûx<@Ì\’í”=#»nBŸ.ž v‰Ÿ…ì˜/ÿÀ†—lpA¥ šj¨ «»iwCƒ2Ñpàv00J†å‚ƒÍnYR—Æ3ÃER}ž±Ü­®ßï{ß{ÕrûúnptÒp=Þß^õv‡Ý‹áp8::Ùë¾ FÃÛ^÷åëÁ°?,GGŽÛN„×ýûÓ?ôözýÛƒ7ƒäÍ—û×7ƒá•#‚ÃNáôo˜\®ºÝ×Cü°Qo(8"8ì.®÷!Cè] o.¯ŽPzW§G#G‡ÊúŸâ¦éð|пèu. Wè»Áa—ˆ°·x{¯wz‡ÇƒÁ»—z×èøâû·n×Èa—ˆÐívŽû·øA샫}|yu>4ˆçM³Ü—¡±´y/ŒSº <à°4û*ŽVW‘®,¡ëgàœ˜¯WÄ<œX¬!HÛ„ –ü– a½õÎRfºµªÒžk©à³´ÄµØú>h€Bƒ¤z:Lµz3±4aAtÈ2!Rbk?Ti©•‘l0.„•·„F¿~:Û@! t$aaÆBÃÄóªfY$S,º <@=Õ2$PŽR,ÞË’xˆà,xñb5¦9i\šq‘ͪé#–õ™ÚëáY(CŸ è—™ͪ¶ù•ëŽ:¤l±$‰—Tií˜yV2´,X‰VMt+›ÈÕ¾.¿¬:tª»EM¦ð^P@mž—§Y‚³a†d`’¶ Vz‡—Î׫$žÎ#ESnä‚û6‡ÞbÏç,å¼(6Ah,‰§Œ¯lf#ŽYè7z˳KRèk `ñLÓ¦ƒ^Eõ4¦;¯»Z·?"$ŠsáM8W^ 5N§•"³'–. 'dùÒeý,rÎÃdnsùi¨5ÌNbÂÆÏ+Âã§ggÞ?žÙ¬¼@ð(- W¤žçB).›Y×s0Ccg ¸Î=‘î!§t¶ DÐÓÀ‚dè‰a¡Ñq–¡«‡.2L’ =©9šÁQN{¢#2ïWòi‚Àü¦Ld^•yÌaÇN0ø¬qš0˱×,I˜@_@Ö¹i¬&B¬¼ØâÊK ©à>VUv”iÚ”Ó½š›G Ç1‚1f=šI>ºÁ8Œ»Ñ bÌ©¥KWA¢–IKtúÂÉE#¬]‘$Ï*ÂãÃûgÿýô¸!4‚1“ØO!Ì¢2DU…eÕ2mšõC^`|ÖÈ0 ™áëüB1Ý ¦•4/J²ýŠ0NR4B˜s02MæHbQ¥8RP‚›§ ­Zà ËTxeH5K&P@A±üÈÑ­C ÑYÅ™A‚ÓN :hˆ@ýz¥8V5ahòÐ&8Þ$Ç,nš”Ðû‰È±¯Ð;('E+è#ü ò¹0í€ù–]#´,ëÀŸ"KréµB#ºP¼t}ˆŸQ„L‹ø©Šˆ-GË£‹ËÚDøñd5G°1á÷'q `•r Ös§‰šé…–8Ï©%-!Ĺi 1/Iv#GÈ­t…In‘c\ÇT0öæb–ÌgI)bÆeâ®VÚŠ ÿ‰ò}ðÝÕ¯í³’&Ç\˲,±äLùIÅ"–Ö]£†,*lDøáõjŽÐh‚5G@…)PxbmÛ8B Œ¿,Êk$Ax?3Z+BŒãÓDP:Dá%ÆGn¿"ÈMĨ¼!‚Dè Ì{æ¡k€¦× Ã dYž”ã íV'ËìÖËó\†hP³gˆÖD‰™½S‚Ž>ŠŠ†6EèPʈòAŒrÌöÊЫr/Ç%í0:M Yù&Þuô‚BÅ>££^EQ'(ŠB™$T´|û“"”‘ŠÚzQTbjµPÎXe¡õó©_ç®g_°kôøþÞG°‡F~]?¦ÆïƒCêWè~³Tê  ^è†` è"V‡e†:JÒåô·ÝÈpµ‰¢µS®‰0óÉ„•&,ÑY}ׄ•d9("l†ˆ: ƒá{áØØ3Ú?dœiF`ƒã$ö“RÿbÑ¡ÌFKó Ô5óÒP„ #……zs³*ª‰¤ãÄ÷ ?•ÏU(á& "à2€ÃÂs¯Š‹Dh"$Iƒ¸äQáÅãdS²œ@`0O"tHáv µLãÛ!Dýð M—&GÀ¢¶"(Ï‹CX¡1¤ ð2Å6s(WB9ˆíÃÏAt#©Ðx“ £f鶨kÔŠP7Åô~V,ŠV²Luïü¹mWL›œÄ]ûö{+§*…>l¸Ñ!E}ç9[Døç:l( ©k½ Ì–Ù–94I,Ò6qð£^cÂú’‹Â?`Š˜ àÆ%Å74!—E~„¡S#g¤}Ãä–þ/çú¾0"6—vØ@3ê—¡´p}ú}²ªÖ,¾Ù1ŒvÏœ&‘ªÚ:2ÒŒì\ë¼ÃqS¯oݱ,¼{,•¬ÜBŒpœÂZ¶ŒVe ‡ìÛu–ôLl““š ÚHú™–P³GrîW'§ã øfžsVZÉ5Â'D8°hâó&ӑ݇*1iKª];£aeúæ‚à†[oãVw’\U˲¹š‡Kè¶Û=ðn­v[¥)?}:ñ¬>µYïk é™Ä·óÓá-¼Ãlt`žÖw…ÿ‘àq†ö'ÙnÆnnpÕ šN²a‰ûu^É5k7  Íf.—N+ŠR¬$“ÉD"“E1¿b„-ıX˜|¶Õ*¿„êÓ™ç!rÊVáé¹ÌSñêÙbóV ŽŒì2<€f7Â{@Ø‘ä,1L>ôâÉK‰÷qp¤À^,Ç Ï Ö¢˜Éd‰d²R,*J:Ë"ü}›@(3ø¹yIEND®B`‚lintr/vignettes/continuous-integration.Rmd0000644000176200001440000000667314752731051020626 0ustar liggesusers--- title: "Continuous integration" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Continuous integration} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` You can configure `lintr` to run as part of continuous integration (either for a package or a general project containing R files) in order to automatically check that commits and pull requests do not deteriorate code style. ## For packages First, take special note of the proviso in `?executing_linters` about the need to have your package and its dependencies installed or loaded (e.g. with `pkgload::load_all()`) in order for certain linters (e.g. `object_usage_linter()`) to function as intended. ### GitHub Actions If your package is on GitHub, the easiest way to do this is with GitHub Actions. The workflow configuration files use YAML syntax. The `usethis` package has some great functionality that can help you with workflow files. The most straightforward way to add a `lintr` workflow to your package is to use the [r-lib/actions](https://github.com/r-lib/actions/)'s [`lint` example](https://github.com/r-lib/actions/tree/v2-branch/examples#lint-workflow). To do this with `usethis`, you need to call ```r usethis::use_github_action("lint") ``` This will create a workflow file called `lint.yaml` and place it in the correct location, namely in the `.github/workflows` directory of your repository. This file configures all the steps required to run `lintr::lint_package()` on your package. Alternatively you can use the eponymous [`lint-changed-files.yaml`](https://github.com/r-lib/actions/blob/v2-branch/examples/lint-changed-files.yaml) to only lint any changed files: ```r usethis::use_github_action("lint-changed-files") ``` Comments to the commit or pull request will be printed as [annotations](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/about-status-checks#types-of-status-checks-on-github) along side the status check on GitHub. If you want the builds to produce an error instead of just a warning, you can set the environment variable `LINTR_ERROR_ON_LINT=true`. This is set by default for both [r-lib/actions](https://github.com/r-lib/actions/)'s `lint.yaml` and `lint-changed-files.yaml`. Note that this will kill the R process in case of a lint. If your project is in a subdirectory and you would like to use GitHub Actions annotations, you can set `options(lintr.github_annotation_project_dir = "path/to/project")` which will make sure that the annotations point to the correct paths. ## For projects You are not limited to using `lintr` for packages -- you can use it in combination with continuous integration for any other project. ### GitHub Actions If your project is on GitHub, you could take advantage of GitHub Actions and the `usethis` functionality. [r-lib/actions](https://github.com/r-lib/actions/) includes a [`lint-project` example](https://github.com/r-lib/actions/tree/v2-branch/examples#lint-project-workflow), which you can use by calling: ``` r usethis::use_github_action("lint-project") ``` ### Super-Linter `lintr` powers R lints for [Super-Linter](https://github.com/github/super-linter) and [MegaLinter](https://megalinter.io/latest/), which provide a unified linting experience across many languages. Specifically, they execute `lintr::lint()` on the R and R Markdown files included in a given project. lintr/vignettes/editors.Rmd0000644000176200001440000001324114752731051015535 0ustar liggesusers--- title: "Editor setup" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Editor setup} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) in_pkgdown <- identical(Sys.getenv("IN_PKGDOWN"), "true") maybe_still <- function(url) { if (in_pkgdown) { url } else { gsub("\\.gif$", "-still.gif", url) } } ``` ```{r, echo = FALSE, results = 'asis'} if (!in_pkgdown) { cat( "Note: This vignette is best viewed [online](https://lintr.r-lib.org/articles/editors.html),", "where we can render full animations of editor flows.\n" ) } ``` ## RStudio lintr lints are automatically displayed in the RStudio Markers pane (RStudio versions \> v0.99.206). ![RStudio Example](rstudio.png "Rstudio Example") In order to show the "Markers" pane in RStudio: Menu "Tools" -\> "Global Options...", a window with title "Options" will pop up. In that window: click "Code" on the left; click "Diagnostics" tab; check "Show diagnostics for R". To lint a source file `test.R` type in the Console `lintr::lint("test.R")` and look at the result in the "Markers" pane. This package also includes two addins for linting the current source and package. To bind the addin to a keyboard shortcut navigate to Tools \> addins \> Browse Addins \> Keyboard Shortcuts. It's recommended to use Alt+Shift+L for linting the current source lint and Ctrl+Shift+Alt+L to code the package. These are easy to remember as you are Alt+Shift+L(int) ;) ## Emacs lintr has [built-in integration](http://www.flycheck.org/en/latest/languages.html#r) with [flycheck](https://github.com/flycheck/flycheck) versions greater than `0.23`. ![Emacs Example](`r maybe_still("emacs.gif")` "Emacs Example") ### Installation lintr is fully integrated into flycheck when using [ESS](http://ess.r-project.org/). See the installation documentation for those packages for more information. ### Configuration You can also configure what linters are used. e.g. using a different line length cutoff. - `M-x customize-option` -\> `flycheck-lintr-linters` -\> `linters_with_defaults(line_length_linter(120))` ## Vim - syntastic lintr can be integrated with [syntastic](https://github.com/vim-syntastic/syntastic) for on-the-fly linting. ![Vim Example](`r maybe_still("vim-syntastic.gif")` "Vim Example") ### Installation Put the file [syntastic/lintr.vim](https://raw.githubusercontent.com/r-lib/lintr/v2.0.1/inst/syntastic/lintr.vim) in `syntastic/syntax_checkers/r`. If you are using [pathogen](https://github.com/tpope/vim-pathogen) this directory is `~/.vim/bundles/syntastic/syntax_checkers/r`. You will also need to add the following lines to your `.vimrc`. ``` vim let g:syntastic_enable_r_lintr_checker = 1 let g:syntastic_r_checkers = ['lintr'] ``` ### Configuration You can also configure what linters are used. e.g. using a different line length cutoff. ``` vim let g:syntastic_r_lintr_linters = "linters_with_defaults(line_length_linter(120))" ``` ## Vim - ALE lintr can be integrated with [ALE](https://github.com/dense-analysis/ale) for on the fly linting. ### Installation lintr is integrated with ALE and requires no additional installation. ### Configuration You can configure what linters are used, e.g. using a different line length cutoff. ``` vim let g:ale_r_lintr_options = "linters_with_defaults(line_length_linter(120))" ``` You can also configure whether `lint` or `lint_package` is used. Set to 1 for `lint_package` and 0 (default) for `lint`. ``` vim let g:ale_r_lintr_lint_package = 1 ``` See `:h ale_r_lintr` for more information. Note that configuration through `.lintr` files are not supported. There is a work around that can be used to read the contents of a `.lintr` file in the root of the working directory. This would allow the use of configuration through `.lintr` files. ``` vim if filereadable(".lintr") let g:ale_r_lintr_options = join(readfile('.lintr')) endif ``` ## Sublime Text 3 lintr can be integrated with [Sublime Linter](https://github.com/SublimeLinter/SublimeLinter) for on-the-fly linting. ![Sublime Example](`r maybe_still("sublime.gif")` "Sublime Example") ### Installation Simply install `sublimeLinter-contrib-lintr` using [Package Control](https://packagecontrol.io/). For more information see [Sublime Linter Docs](http://sublimelinter.readthedocs.io/en/latest/installation.html#installing-via-pc) ### Configuration You can also configure what linters are used. e.g. disabling the assignment linter and using a different line length cutoff. In the SublimeLinter User Settings ```json { "linters": { "lintr": { "linters": "linters_with_defaults(assignment_linter = NULL, line_length_linter(120))" } } } ``` ## Atom lintr can be integrated with [Linter](https://github.com/steelbrain/linter) for on the fly linting. ![Atom Example](atom.png "Atom Example") ### Installation Simply install `linter-lintr` from within Atom or on the command line with: ``` bash apm install linter-lintr ``` For more information and bug reports see [Atom linter-lintr](https://github.com/AtomLinter/linter-lintr). ## Visual Studio Code In Visual Studio Code, [vscode-R](https://github.com/REditorSupport/vscode-R#r-extension-for-visual-studio-code) presents the lintr diagnostics from [languageserver](https://github.com/REditorSupport/languageserver). ![VS Code Example](vscode.png "VS Code Example") ### Installation Installing `languageserver` package in R and `vscode-R` extension in VS Code will enable lintr in VS Code by default or run the following command lines: ``` bash Rscript -e 'install.packages("languageserver")' code --install-extension reditorsupport.r ``` lintr/vignettes/vim-syntastic-still.gif0000644000176200001440000020060714752731051020052 0ustar liggesusersGIF89aÎ ÷ýóáýóßôìÚõôÜþîÜþîâר´ØÖªÙ×´ÛÙ¹æÕªÚصwcLËÖ¹ÊÖÇŠue××ÅçÚÅþíÔÕÖ³ÛÖº§ÒâýóÔçäÉÔÕÊé÷ê÷òõ÷î÷ÓÙ»«´©slt¹¹·ŒoSööØ’‘’ÿòÌeijš¤§ôÓµ®Ä·ëõý¹¸¨ÚÖ®˜‰yu\F[dkWdhã̤¦‹v—¦Ž’‹k–Œ‡éçט˜˜ÔñöëôÛ¶¨—‰“šÈÈ·ºÆ©ºÇƪ¸¹Ç·¦˜•‡“‰†††ª¥‰÷èÈÉȨc^cüìËÿòÆ…kYö䨋rjifjZ^es]Ut]6ºœ{¥™‡ÚåéåÕ¸jtwôôëÎæÔÉÈÇÕÌÅÆºµYbZëòÍ[cdæìôͶª›¤•Ž‘’†Œ•Öã°§ª¦çêçg^Yrtj°µ’Êù¸˜x…vöé·ˆ|wØÉšúö祆k×ØÖæÌ¨–œ¤y„ŠË×ÕææåØæ×¨¦˜ôôãQgl÷ëæËËÒlv„[iuíöäygWeieç÷ø˜¬²Š–¨¥­µiie´ÍΉ‡zµ«¥ôëÕÖÖ¹’’‰†ŠçÛØjfd‰‰‰æå释†‰††·Åš††‰vhgÖʶËÒ¬™“xeekóÖÌZŸ¦iijÛãÉwwxv{…gkthcZ¹Ç¸ÛäÔ¨•sV^mÈ³Ž¥œ•Ƶ›{‹“¬ôüÖʨµ¤‹r]J†r\}‘˜ÉÙë­³Æbx§–Ž—lª¬“wfŒ}…l]HÕÝ寕‡eed\^ZmgNUbRêΖ¯§y“èúm]4íÙè7ˆ°pôþ¤¤o\eMÅÍ«oYعϑ£Ï®Oc×ñ*™çͰr·ýþלdœ˜XJµ)Œèm±ù`£áKÎ’ÍþN}ËP•è Žð&#"tŒQxÿÿ!6B‘ý`S6ìÖnî§™ýð“­e**¡¤±Œ1Ñe.’’ÚkY›$ +Jf/#Ýjž±Ïf‹‹,iˆÕ$´‹ÒjÜfáhÝhæp!ÿ NETSCAPE2.0!ùÿ,Î ÿH€A‚8Ȱà¨ÐaE‹*¼˜ðaF n\8’ãÈ„ 9>TI#Ê–']Š ¹2cC™cR¤©QçN–7mò„ù$PŸMjiÏšB•²ù³éRžHƒvdúrêÒ¬Ni¦, öªIœO½ž;Ó§Á’(Ùæ\kU-βv«¢%úñlß¡ZÉK7j]Áz wEl´(Ô¶Œÿ•9lâœf÷*†ü÷²c¼•¯nÆœ·±c®œ…z>-9mh¯Ÿg^ͺ5_Õ¦k£&ýZ÷äÃsûÞx'm‚‰L0`‚Ð'8‡¾àóçÕ¥D´PêI„·­ÁËÿí©tpÛÃm§*<ýêõbE7½ïñ$K©ÿÜ•…¥¶U{éÈÛy–Õ¦}Ú§P²•æ ‚¿-† |¬™äyµ`Já'LºvaˆÄÈDqàÜuØ-0Ý%—Èp ×ÉH@—¬# "‚Øq„ivŸCïy܃m˜_‡ífb} fxW„½¹g\{ "Ià|Äay!lÒÖå–ZyÜ™ì¥yZ‰DÎöå‘Kª§äœµ=±N;É“„ž|n‰P°9*‡À?4Ý LwhC ƒÅ}¨ßÆåEpÂ'˜uÚ)§›±•jª„U¾i¤”·5ÿØjªxÂ*ê«eÖÚ)Ÿ¢¹j–ZÆG¦°ÀQ‰¡«¥.(¦±Ã"«+„”%‘L;º°#ŽÁ´ã ;h$@Á·ÎM@Ì©Àh —t›#  †¥ydêiˆœVä¦Qz4¢¦½R•ï¯cÛf•S±I¬À£zië¨Ù§Îêðy£M)ë±´¦9¬Á 3™,YNîK¯¿ÊR0¸^µAí¬SËÁä!Î:¸d"Òa‡h"¨òC >\²ƒ ð¬Ê#ˆ£Îwöb%d¾öFÞÓ >u°€ K|rÆY/{q³ü0Ç);«ñÃ3+ðÕh·™dÄO\ŸÂq²÷Öm‹F¶ªacÿ(áfI˜ÂÎ:é³à„÷y³t ¢ ,0 Ø¡.χjqŽ:IhÐ4¿ôBmuÉÅ~½vÇnûZq¬]ƒ-wƒtWˆ5šZ«mvì²h{°¨ŸêªÉ»kÙûß¿—Þúé)_¼…Á»7üÃÈì3nH_ÀãÞcÑ*,@Ä%H!t8¾€˜@ž×ý:Ïæð¦£ü1ÅLÒ¼ýñãÿYÈT3N” e<ÚÝ­ysSÝÿˆ¯ª ©`^Ûï’'?«¼Ín®Ã›ÿîö/õd"†Ó@LBÏaORˆju H¬ å£Î @€q@ ñºàû<Ö¿þou·âÛÿSGDñt$`Órg1 ‚ì‹ D]™MlQ´ ”œÖ@%1mõ›àý|hD£Ü«_úZ¢`ôgÀ Ú…HD÷^äœ Ž”²” BŰڅ1oÝ[ˆF©ù-‚mDÞa÷¦ªG‡,É(ÅŸtpoVìÛÆ*ø3ytÞ$ùCO2‘u‰äßÙ²ØÉìÕñqÍ!×ã ½GA€RâØV% †AEö”e]Ø8°†’ŒtdÝIRýwÁ eÈBÄd›( ÍJšò˜UlX3¡™LKBˆ™tæÙ,ÇÅÕQgq¤Î¡L ŽzÚ3è<¦:±HÿI-J3˜g:É9ež“—CTÓ3Í'3 ~tâËùÍnBÔ˜EfAÍ PB†Îšj\ÞìŠéÆ$ g°”ãrÀE.ì¬{&HŸ 2a5 !ŸÝç!Y9“ŠªŽp+iN zƒ¡ãäá*ûÙIa©U*?éM§2TM"ɾ¸«ÿ|Ô‹òj/U9Õnú3W¤ÈUÇX¢{Ô9e8â;è  bMèwÊÔžZ5vSãP¥ÊWªžõ‘€õÕE…šJ®1´ªÿ¼êOIR_.Õ°Mlb‰¸XË–õ±‡]æ9/0‘ƒ¤ˆ j¥£sXŠ!a]P@ €ÓÆÿ¤—^¡ªOø]Ö¬€j[Y²¸~Õìd‹ØYãn’§˜ñiêËÛÁæê· Í¬C7VÊjS’ÜÌnr·»ÜC éØS2òð'õn ­ˆœ¢ Z¤%˜¯sÏøÀ|耆°†` 7À1Ñ‹a k˜B ú0 ¼ €ðË °‚:PáHp…S²`1 ؆8p¼NÁ4#pG4N`ä ÿB ò_>ô`À>°ù5 °É4qŒY<ƒ¸ßÕésûÝ¿–·YÍãB¹ª]Ä^9,®–±Ëåñzyºâ¥b1jÛ‰nTÿº€ÙI@Øv€ãZÙb‡7ÐPß;º•—ø@~…³X!`@làU¡ Xˆ&.À V |¨„ 2c`ÓD¨ð rá!l‚ hEnÀФmH¢]½…<úÓ˜,ÍLT"%¢1Ž>$9´Af…LC€™àB T0?|ºL+‰Âqh!Á @*RáäšPsdiä*é@i]…’™ƒF•l™!Õë~vÞV³2šñ­æ zö¸iηr÷mÌ,?qŒ33Ì 0³ZC¿…Žå~KØ¡\å:NF Š=h`nHA<à9%œt 5ÿ(zaˆ˜úã´ø@ŽpaH`SX- ÐPbcH‰^Ð ›‡|ä%¿ŠPS¬¼åÇ2¸† D h' 2ŽOytÑtP¤€$€êpllp‡G ŽÝD89"Ɇrïö:eÌšY´¸ªÁ·¹exsTÞlÐD¡åW?µÜ@ãÔüæ$¿='n°l" IhÇc?ü ;W>ÀýW?ã‡ÿ;x!K$ ¾ˆ‚×¼ ö€A  X| u A'J^… °(j°mîàám w÷Š'eî†\U6pWpYUM`E&Ÿ4RQæ[÷fxpvP%•WIeoÇo‚xò‘'fZ=í €^ÖRqÌ!.   D@bD°VÓ±q ÐQ   HW&7[À o@#P qPj-0F€…aÇgj3§h žƒHR¨….`Dh„`sÙ·„Mèa»…îð^`j1AÈiÈ.°  :WæzøÅ'w—‚HX}ÿç€G^‡‚Œ¸wšÔ€W/’”X‰es‰·“‰%xP[Ò‰ž(D!è;AB°2ðA1Ói%#«7_Ýó8 v@…ò"­7#0%à,7 Lˆ{¸¶ðA7O@jÖ$À­sàN@ .0 #Ð YÀ ` °dà´ÐA· @Pj5@ŒÆ(ˆI@ ¤5ŒÍ¨Žqágàzÿ·ÁXLPŒ7pÉ­pŒ¶G p(}j€``#š  8àHaÖˆ"øˆ¢oÜeŠ]Å!_µUÝDkÆX*èfEuxIx)‰J/É€¡H‚ùe“‡Þÿe‰Ðg¯t(¡7zóµx·EqSã1dû1FPtÑç§M cQyB‡”NRLnsÒ0”QZÇÃ7`ˆôÖ[Žˆ‰4É’6©Nq–M:™ŠÊÓPgƉ.ù9ù‰ —µ‰X—Ô‘oYoW1(´4±$.†y‹ÒA_Ρw‘Wg{`’O2’éV’ùÖkqMœâ+` n‰—pÉIGŠì’°±€8‚èx}y“x—¨(˜zZ¦¨i%¡9›fÉ\;Y˜<œC™ ÀEPœd°Ypœ¹ÐœÉùË/ÿQT€œÊiœÏyËIÜYyPM`u^ÿ¥U—™šù!žËDW)“ŽUfè©/\x~‰M€)š´IšÈ—ò ›`Æn’Çž€ôf®¹Ÿlé:ªy–3éÚc.Gƒ Ê_!Iž#¡Z¡Z¡Ž™z¡(`¡Zÿ¨;½)Lï ySyúy‚ó¹Fˆn†›“µ›™”—ø‰sùšênº‘hÙšˆ£¾u\;ª£¢_73z/r‹º•.‡` yF–ù¢{õ˜æ w0¥u’=ÊH# /Ж§€OTJžVÚ7é>å1¥¡3:šÐe£&è%¹ŠCÊw=Š¢7J AÊ‘‚õŸ« ¨>êP@BS¹“Kú"fÿ`#¯¥¤…"Â?Ѐj§§ªá‰0h›æ![:R#:ä1>pc¡h@–áì•ãÑZ‘6jp*P–@#ö‚ÜÒ«%¨ ŧuZŠ+Úž“ƒº§ú£~ªT¬Ù¬I¤„Š¢€Ò'°­‚’= šq>>?S>«×@Øœ° Hb$PZ`µ`s0p}°>às‡*}16c…ÈFd` Öbƒ`õJa‹ `°C0 ¨8 SðcP §àsu x,b1ö‰ˆjP æ° ÐÐΣÀ#`ò (ÎÿÀæ`ZÐ`f€ 0\6t©j <C0 MödHû8°2Kv šð å U0 PA ÔÐ Ô$×p Í0 v Õ Ô€ÊPA—Ê`‡¡’P ’ naš Yx&À{”©5¢µÙeÉzšËZAy ŠÌЬ·I]×U­ý6Vc¶®#-Úb-gàÀglÅ.¡ŽV—` æÚ¿(Gð„à¶P,°hör·ça3ÀV €©q«Ð Äfl•u…‘† °k—æk­ p3H ¤ÀC€p H¯à›ÿ†  t`€l´p¼cÐ.¡Îð¾Ðà 8pË0j° G`áj0 á ËÐ ãuáp ”¢<Àª4Â;n‹Ë0 üdjp ¿P’PrÛÙp ©0 [§ ±0 ¿Ðu` ¯ð Ùð ÊÐcˆÒÐÁ€‡¾pþ€d ©ð Ûù»ëu¦H’0ÊìK¬læ¬Ç­)j§ËSK£sª‰}ª¢ü9“&éoE±2 ׊ÁÐpŸ÷Á™B 5P_ `u†¨”`çqÕ§ÉG ý‡?€ãà ð·¡§€à#u¬t¤Nÿ÷P€ëj@ ð™Ð †[A u¦ "~Ü .gf°uá¾áà ¥0Ù )kIppà h…lïër ð±Üã`Þ(½€ ñmÜ4#`³`‡:0   ÃÌ)á 6À¶shkÀÒð  0¶Ê` ¿PÌTz ÇÐ aäp-D좣s¥ÄJŒ’ך¸¥ùT‡Y*›šŠ¸5jÅ‹‹›QLe— ,—Çyɰy„“ ŒÀ ‹JP¢K.ˆ"%IðÆ”ò~ô*r éa¦ðz<f2@C€~1ЄlŸ s'÷§ Œp(ÿµP(@Ó²° ØÃ§ dÀvv9D~î+Щ êçîÛ ª¬óÀ½`4RMΟévã0Ö½ìG â Ì‘´lZå}› ÌP4ìÒ l[0¶ØLÛ °p P †] q[> ŒýhÐ#p Ç T‰VÈÀÎóüoÙêÄW ÅY̬kTŸ¼ÙnöœŸ­¬ŸýÏŠzªÅÁ‚†3|{b¦ãâÐ*.Ìq?àp )À)ÄÑxèLÈ¡@˜öàÑ)`Nè9‡³plÛl+sÀ-À„Bÿ •àÐNÀ(0 àU0}Àb6Ô›1‡1`¸9Qý¾ à ½° æ •½° ž*úír½a©,àÀÀ{+‹xÐ@ …w7åp³PU FÛ>É̶0„}"$ ©`‚°½Úp ×€ Ìi7³ÝßæÇÀ Ò§âÐΚø@ð,Ï™í\к’8­•K¨"%¢íÖÚ‘ËÙM¹ ˆä‡qn=‹Þ $3ž3.‡3µˆ.—äc>Îᕠѥ¡žjËèÆØsL€¾Û^°ª¾uãÐ,â±Ý Ý!` ©.ð ‰V€ÿ +0¦Ü(~߉çæûÐjà {\ &à j€bñ`v€Ë`#)Rà‘Ѱ nàh` õ{¿w• ëTÉ+ ùØG° +à½ÌPiÐmÀÀà93¼×}ðÍ¥¥Ô Ò  €ÀÍ0 !ܲk¾ áå°7" ™Àã¦Ê™¡±¦rå¥BîÚN>¹™è6RNòž¹¬)¹ø|§ -Ú㜙=]ÎVÌÁºÌ1ƒûeæ| I0àª+ñB1Ä…ˆ0®'OI™"Cð!¢³µ“‰Vr1ä pÒ ù »#ÀàÿO î“Ú»01ïrаaìRêæ%@n¸ÅÊľIäŠÅ9ªÅ¹3ÅrJÐmN_1˜[Öñµø(ä2*Ôº3dô`có.ðá9y÷ðþ9W¸kò8€ì0=“™Wé`”uSÙmÌϽP÷äü¾ÙJ/­Lÿ§_ªA_?žäMd¬´ø¡H%š,™’bLJ1+šŒÉ$É“'#²|™1@—6KVT©1(ÆD9òì§Í§>}2]º2%Õ–;e¾dy)×£EZ@`Á‚ʪ=;Á ÐH`6U–™zCìÊŠCžàWSé…^on÷ÄT°»m7™[ñ´é–›06Ãnü'¬øC¨¥è£H±‘2âQ:Ÿ€ü ;L$ñµM‹.H%üÆžÚY§+Ú—-“É#‰J¤ €òÊSA• @à’8Pဴ;È £“M¬ÈÀ?0È!jÙ €êèÿ†S< ¤*2Q‡T|hMŽ™å (ëLF3Î+ËŒÃRE)%¤ÒÒE‹ñ²{ÓÉÆi"rÂÌŽL±)%UR °™ŠÌu'$Cëµ:T­[2YâDµð2hW…ªÕ© ÜmYÚjŒj[MuöUä¼öÙ‚I¦pÀ'˜`ÐeJÎD  êD‹ÞxãMK8Xo½ä¢JaF<@!Š1Þ°%@¶`cˆ%P(@‰:n˜Á–d‚é#Rv´Óñ¡TRÙôI…^'TÕ‚ÃVÜl™T•\ÏXµrÜ]i~5êšD™Ôpi.V¨¡™ÛŒCj›³ÖèkMómÛÛVsRæS‰ÎÿçÉlnº)p¡‹Õ)m“âiTogË 6ÈCËÇæJ×SË,UDcñÀ7‘¸óW„(¹!€^è Ü8¡ŽN4(€Eíø$$ed1‰F˜Å†–ë3bÈ(XÈ‚ÅuºÜ‚þQº… È£Ó!§f–8رe)¤oN=f¬…Ö,µØ}u¹Tß_ÖÙö£«ÜúÊ {ß9ìà…W–ø®gƒYöµ6šy—’ Æ–uÖIfSØY'd2™Í¶ÞZO T¹DŒ}ÑÒÛ¾ŸLBpÂ_@EƒŒâð€€1*Øá ±œé²©¿u*™`G0~V6”Uíz,ºJî–×ÿ»ç|-[O놴êÁæxSÂò¶¦‰Ði³‚Ú §‡ÂfUH†0ôÙ´tW¢ýN‡È–ЯöÖª&+jÍjU“òŒV<aÅsL¶°/àyËÜBÐ[«™0‚ \¬d¶Íèlû食˜·ÿ…oc1#áÒÖ÷´÷M­ŒV[Ü ›°CóÿM1I™_ç ¸¯׎¼_ã.C%ÄÑ­àª«Úæ8­;æ1„G eOÖkïAÞ ‹.Î ‰x³Y¸R°´V!ží_"P@Á¡ÈðŒˆd€!œôÂëÕ3ûxÂR†®…«zÕ"¿ZF·Þkæ'K:Ȥ±/•3ß+3hÓrª•»Ûf9ʤ²©/Œißi§&ëUH{)¿¸EŠuBÃ%†ÍT¦sXp,…Î%d7#ìˆE‡ btÈG’k÷a´i­ZJrᘮ`!s™—ëæª’Â6"ò­%*+IÑ£ž~ô€#=ßIÓzÊ­ºôÿ½C©V­"ÇýVñ¿39³„<Á‰H\˜6LöÝ+-$>€"$×a9«¥'¿Q%ÈàZH@‡ ->@“OÁÜÜ(š!8‘4‘ ùdªÇ ö,ŒÎ9„ø< w2¼ÑŒ½Öšàf¨ W­ä…3¬Nõ¬7$õã<ÁE¸kœu­Ëšwõ×vªïPçb‡ºæŽ.p˜M,Õ"œÍ´i»z+&cK9,Ì€ \(€<‡R´âwÀ‚!Ï• ¬ÑGt~ Ò\`©è›&˜ñ ¢ß ¿Ø\D.ð‹¥§=ÞB|8†ýi`KÇ=Õ¹zZùÿ-½Bšv³ç`òÞ#݇É“Ü7ÚÝ-|××R­p½Å¾BÈhÉPiÓ’,2!…Á–‡T¤:>WI>´b-ĺéc2H‚ò9Ÿñ Bô †Äª.K‹6Q¬ ³0è ¤ÁåÓ7…ëA¤Cìº;¸JÓó=±‚ž„ó¯ C¨Œ¾ªË°R›ºDÄ4$r¢< €&j‡_ʃ_+&ô»9¼ÁC(lŠJ#xˆ501P‚ʸVwx‡@:…Ø1ãØœ>hCEã„rà”ç­P³C¨3¾CDÁ=Ô$,K2ßs¾< >c¬Cé£D°C¾K48Jê½æëAô2º±¹Ò1‚DèÛFdü`—´I]J›ÈÀÁº:C"H§ø!8E¸$ð[x"(* ÀÈŒ€† ¹èÂ:ø<¿‰„@ÿDÀ*H'M(‡v*Æ}²ÆIÌ´±:AK¬š‘ÔAhüFšÃHTÇk$ÉJ„;uLÉ>\«³G„´cŒI±šImDÉù5í⸹1·0ʲ@JÆ"›$0¿•!=›ˆÂ­¢ÆÄuäÃÛ«>f¬I佌FÜIëÉ”œ7£I¡Ü½ß)K–L­±AÇjäJŸdˤášflya)˜"&µ1¾˜^£pÌÀqL·r³è€ÁtÔ µÄC°æ³ égvd¨õicVØ¥%jJö`fžæ›ÝéaNk±^ë²Û¼åi»î[¼nk½f_´.N×BPŸ+;0ô9gd¨^{¯ˆXg*›Ð¸U0?ÀçÑ‹Rèh;H"h1(íP¨…v‡Ù5„+Iˆ†hàbm^€Øç Ã2xÿ%è„fê„9Hð5Ð?w‡ `m0Ý.êU‹€ið¸mµ•ä`-êJþà®G·Vf©îe›ekšìølíöäiþj¾vÛ»ï¼æÖ³6êhF6¹~ßøÎî¸Nê`¦kh.[µvoÀ†oþ6ïü._žµi¦îjž½î·Ú©Žäï †à¥áöjˆŽNü¥$HM5 Hñ’h“ˆu¾ê³+h„ Øl ‚{n€K°ƒ H ^p¸"H_/ã—6&wp‚ÚÕßbêÒ…÷9p!°Ì(f€>VƒH´R&5‹Y¨Vpùöïö¶Vÿ ‡oêæf˜Ep W` _óñ¶Ö®ëùaî>U9_Õòepï¾e¤6p=¯óþ.ð<,·Øs“%oûÍîë4÷TØ%süîäú–ô6Ûjk†ó4™t?j^.fŸsDïnPÇ_òø‹hGÈP_:*qj‹'¯‰žÜ –å#HPPƒJ( €€Ïn€°qW È`€öP^°?^M•Ýp8àUòñN€JØ[6`8J`ÓMv[È5Pƒ1P4ý]U@rHõ`sõ¶óó¾ôA— B7ïGÿkRW, ¾o¸¶týÆt~ï÷2ÿ÷Qß` ¾÷B7xÿA/õ„×tS½ðN7u°>jú>ø}f‚çd\>tÏtXUt›]pimðRu4oLWù°ýóò8Цãˆu>ÛË•žCˆDHc鎋Û.zAg®ìË-‹¸`ácU…­¶Ê…¨h€YKƒí ù–ÿï—ðAðOßxööë†WsÆút’oŸŠ?eJ/ø‘'T„·ä¾5{@§o…Åæöx—ø´'±µø¶y´‡û}æ`íÕé¯_ï|÷xŠ—{™ßk|7tBýÏK:qñ9ˆT³èÆvþet4¡-ÏW¬®Qð饵w:g ¨¦îÒ.UÒÁÂÒòU÷U çUUpÿSÖû2§üôV{È|Áþ}¾'üÇ?ù _üÉ?þà÷ûá÷ú•§yŽÇsä/ù¿Ÿp7ß}ŒÿÚÛÏóðe‹O`îóšF|~jºGu¶ø~ä_ÿêßîë~å¹̇¼u{€@P¼ÈlA&PP¸ÀÀT(tˆ`AÅŠ P0HÅFŽ<4pŠ p¨hÀ$Æ” ÙÀ«is\‰ *"Ñ!Æ..8pBC1"€&#T…/OÊ\ÙR*C‡%ª´ÈTcÑ£I—J½ø4jE)P‡ »pìɦfѦ] hÇ!Rx¸1ã× L¿–ý ªÐ…ƒÿ¢ÌÑ#È|ýLÔbF˜ _:a1[Ä`óFÙbe—ãº\íÚ¡gÐ?Ö+%eÀª sÖ|pl‹¡uÓ&½wäC¼“4™õâÖ‰º9‡4úVi\§tªÍúïs¿\§#vlü6…ê`¿~=€öíßÃ/Ÿ>þTŠñï¡kwh  TpPBŒuži¹©æÕb™¹f˜FÁ!Ná„3†î4ÆT1xUSŸ¹…vLi·]w}‡‘‰Ö¡H–\ œµj2Â¥â\Û5UX)v#]¨)wj'î8¤?nÆàdF>xoPùvpŠ 7[yPæQBBMÀÿ–d É[m¥Q"L(èÒgÊÙÖ ”˜QakR›–' 7eqˡ砂ÙYØfˆY#—Q•y&Œ A‘t»•G”ŽBÖH$Zu.h¦‘„èfE,Á̧^{#Ðwß{˜IãKAdÒéÕ·*|ìpÄ †¾prƒz«dâ^~°Úçì«ö1ûÞ°“{Iü€²{I@Q²Æ¯ŠÜ.«:ÄAÖ@2"=ìÝw¯Çþ"ìCá9÷ ²ÐZﱪխÖt>²¼">å©Íàųt­êXÁšE³ž5­nÿ bYÇÉÕ¬²u®n­ë]ñŠÖµ¶U=4°;Ö‘éV°ÉÆ_küEÀ¨•6º;5ôâ£!åN `‚t¨Ê¦+í)LÒ+°´a>!dð4œ6µi0CKyÊž¥@ ³ êP¯5„rØrépê«T¡‰@ÌB–¸:÷ÊWªÞs¹ÍµëÎâúηN·¯ÛŒ®s§+Ýê&÷º…nu·Ë]æv—»â/2  HÀ ÐË„,@†$(1†1É0ÐXP¤aíRÃ8ÒP”ªa¤) @DáhÓ+øá=k°ƒ< Ògö=CHÀ … h! œÈðN+,- 51 êÿ8QŽTć¶õÊÚ:€›Sh¡…`ÆmAJÞ¼†7»ã¥î}ìÝköôÅ;Vn»ëÄï*9Èl=o Þ$ëuÈLf•‹±fÝ%› ëe¯¼Ü  / *ŒIˆ áB€‰ød €ò­* A¸„A7˜O0ÔGU ¶ØÅ|@*äA °M‚¡w1ÕhÉ9kÈâ,lT¡ `ÓD9W „@˘¦SqŒ>èøÈV~îÄ üã°*wɰ樬ÇKk ;ys˵y l*×ZÈÄÞæ°µëêbÛKÃqùÈÆ$Q1: )ß[Ó¥ràb…´ô¾hÿPd-o™>—Ž"Ô Z¬pÜ&¬4¶Ü-Ö*[bvµ­±‹Î{3»×±¶¿ûíÊù¶á¾çmÝz>YÆv¹Î1{ûÚØÊŽâi଑DH Wû¥¼C®J“z>f#ð-qõœ{yèE 5 ò•ïz=ü–ÏÃé#â™K¼æê¹9Á§|ñ±Ý›ô:Z‹nð•=?J_:Íwüt,{•Üë‘,¯îóL½é OBÂþ~djà/E‚b€ÿ«_CPÜãnž¿ó .Ç y+ì.FYê5ú‘~Ä®·ÝâïÜ:á^uˆëY÷7âÿþo¡ÞïÓà—-xÿŠ_Þ|ï¹åogÏrŸF+Ö6 ê«mmò}~™0 2‘ ×Ëû=Ž|R‘Ša ƒÌxFoÑ™M]‡>r˜§kà+ŸðΞêô²ºzn{'Gžù“Ÿ~ß—/ú×þêÈ×¼ò‰.ù‰{ýèáOúø ŽóÅ뼫ÏgüíWÕ¶dTR A{\’ÃxZ«2&4Ý9™ „˜ÊÜZqÞö‘ŸÌ$Ûù ^ú…‘î0 ‘´4_ÁåM öŸçÑŒ”}_ö‰Ÿõ) UžŠ`ªŸ ÛÐÇ ­œYY(…P€\Â%¼®˜ÀÛ«àà¨AD]BÀaßtñÔ¶XÀFíÿœ}]¢ßªàâäœíQ•^™N!O“EÝV ÷yá‚^² f^ÞÚ¦`fžZ¡.”õ$.@O2P’ZÈ ê¥€üÀôQœ5Žªe5T謡¾¡ Z`Üì˜#"$ŠaöU%ÊÕ%¢!~Îzâ.Ü&þS'ÞL&jÞ)`ù!ÌÀ¡uÝ8ˆƒ—Íáô…Ä„Ú!€(`@%\ JA_lÄþчhÂ,ØA" À ¨A)0¢,"Ùæ½b$Žá5`¯U,ÞP7z#õ¢*~"ø!!ñá9–b:ªc°±ãиcyA¦ÿâ<Æ"~DT-¬‚­.ƒ‘\ pˆ€8Ö˜(dËIËÌÂ/üB9‚ Œ€ @OËu_ô1×y±â½_û¡› j!nã*Ö£=j9æ£8&_JBÞJ~SK¾#(¤<ʤºd(bc–$&¢ãæ$)€Ã:¬ƒô¬B` #ÄI^H ´„*\ ¼BN@d0ÞÃß3Ì dÀÈ2¼ 9Faš$Pòx *Ja8æ$Mîä«="[š%=¢¥©¥+ÆKâ¤]Þ%Ó#]êã[¦åÊ%A:ÄXÊ@zµƒ Àü™D_œ]®|„"ˆ2*Öµé ©­˜ ÌEA/(ÿA»½ä7ÆäñÍ$JÊ¥ùà\þd]ò$ê$ú$) fjÆæ`rbkÖ&jö¥jʦjÒf;Ú¦oþ&se‚?j g0P’cšž\(ü!€ 4Dr°ÞGÀ‹ÍB9¤A <ƒ €f;LOªäMž¦[Þ&k®&Ij£k'l pZângoÎ'}ææZ–e|æg\6`}ê¦òæz§€‚]/ EF™„AþEG¬ÄÕœ8CyÖdi¦gÌ8f(Š¢†J"êç:~h‰Þ'K(‰™zŸðäl§rè€Æh¾§^> |"ÌcâÆÙí ‘àSà›°;ÀAsŽ%ˆâÿ#NÒ(þf+j•p¦¨“²§òidãíÝÚ¨Óé(€â%µû]áð`iüÅL‹nd™nÝŠè”6éÖ¨¾5¢³™ê5EJ˜ÈÙñ×EÀÛÍ,•Äܱƒ´K”ÒÕ›ªg•"ès­KšféšÎÖ˜ºèÏÔŽÀÙ$“*jœ>i˜. Œ§Œâ§ŠèwYê¥z(ŠÂé$Z©2Ž™b¡î(@AžÞ¨¨€‰`„¾‡¸ñN& ˆÃë ˜Ñ§ÚgŠê¢¶i£zŽ’žè±R馲j©2k³Æc¦nh´2êœRkµ2\Žrᎂ©\¹*\Šë¼%j\æ`4hEØ*fj§8@C̰xÿ`|\Úa ‰æ«uk6~k[&+©.kÅ쫹bÀæ—2ÝÌ«Áþ¥ibëªjk§,aÊaªjêÄ*ë¶Zì«p˜® |-€ºj„øÜ  è „ fRù˽†$AÑ¡žk¨BëÆlÇ”Ü<ê™RÓÃb쳪êˆêlÅò,7j9†(7ÊéÑâÚú$™Vêú,¬†ŒÕFªÇ°é©›:¤ƒ€º V%ÀÑ|e†o¨‚8£ì—¨2trv ¾ªVþk—‚ëÂ2ì¼8,О'¦f¬ÄíÁ¶àbL7n:ímÀf+Ç>-阪Ғ%ºŠhúíßr«â–ëxÿ¦ƒ‘BCèéu’,d>Di£øÀ 4ÀG@‡€ÜÒmæÚÞ9ÔùkOÞ,ÑÞ®ßæ+Ô–à–‚jÂþç¨2îä$®îí=.æ’!à ïä_>ïÐj¬ájîêxìzl€@ƒ:t[l€øÖB&TBɶGa 0%êi8¨Ã¼2ñ,ãm-i.íµFo‡®#ó"²«›ú®öïô 0Ò6¯_ íå6-§Ž+ç2pcïóeäJ°P²ƒ:œCâÀ6tp2d‚,¨É$v¾A \§éYÀ9ZÝþܤªi–²“þî¯åpá"0ÄNõYÍ"¬ã*lòr/õ¶õòÿn{^ðYfð?°gLÖRmÈ8/zöïÄl›:ˆÃ¼ªÁ §#€c …öÀ[œÁ8ü@ hOdÐ.9`AÝþNUÙå¥ËÝF˜ÿê¤ôI0< ßåñ Cê¾0!¹Z ¾Âl½†"»<ò"Ûì#CòõAà$Srƒ X2²Ñ×zë#¯À2nîÂ,6E×â2ãzˆ±Í&w“º4²á-äz¯ÀPÖ©¥[ìÁ{<æKè® ÀüÀ%@¨1¨9Èq#6®µ^~Ü>½æóVÚ°âÆìíà‡±o) pûÝ[¿á-òá®J°¼ìЄ¨4Ei$‚RT`GÜŠƒUBXýï³46ÃåãÐ4õžôË^Ì7[•ý ¶ýšZ¦(ç´ææ+Ívrå’U 5WOœªHo&OðN÷ŽqJkµmÞñÀÀÈüs,€¨4uPHHETMtš€ Â]&Œ]MhÈĵV‰ñ{°ÿ²­eÎ|쥾pkó˜ŒGç&󳱓òÏvnÒn§‘M-™*s-A:ïZ÷ôH·‡ã9‘L£Žþ.p_ës©\ö3á¹3ɇg[é’E÷Xõ3uîn»GØáªT7EŠ H@¼Àž wÂL¥®4gׇh—â+¿c3y³O#?O¿÷“Årc1- ³Nq›_O·c+[M¸7Ç÷¼HÖ[ Ú´G{7‹t½êýZ¸YÅ“o‡-%P(”!”¸‰ƒÂ¤ø&œx#˜¸Š¯x‹¿¸‰71À¸Ãx8‚ÔÀŽ‹€"ôøóø,üx›}ÿA›¹|’3y“‹€$¹‘¹Ž+¹ B\,˜Âÿ“ ù’C9¼‰bŠ©"ÑLe}iüõ#:t’ÜiÀºþ¸°Ñœ GTŠä!68L)A .?AÈ„Ê 1ÀÙ[P` …ć¡·¡±:5„ÈVõD €eÐêÕ\Ô·§Å}êG}Ü«‡ß^~ý÷ñSÓ£ÿ>õòû¯¾Áëo 1ø’E²ú›A–Á/EâxCGÞ ¦†1LŽ79Ä/¿+Á*ña†Èˆ©%Ž8®PiCbôЃ=šòlÿF0îúዬ Œ#ЖÊ)ÑÖ $£¢„"J¨F‚ò “2JˆÂ“Z’ d(pð(˜.• „BÌ̉‘%1‰2¨?ùƒ„?‚ò ÎMHÀd G‚hl?ø€e&'‡ÊLB–àÕ[îòã9{ò ¨'bÀ‚æ™!z¢ î±çqJÇhÆ gžt 1a5Ô@s ÁWç¹'“$Æé…SçAÆ„xæ9§T3-è UQ½gž!F@õœt\5B„T‰­—ƒÈ)vØY‡… ¢GÓt,ˆ§Yegž^Á%çÜ{¢Ç„Î9‡^që!× ‚`;€C¨C7áƒÿAèF/1`Ib >nÑb9Xº+ öTñ£‚Wº¸â“=ÁBP({"DÊ=I’)¥J€å¹`¹Â”AxÀº–úàE ›¹f+zþ—ªle уEҾȡ*+rˆÂhEjȇ7®ÐzÃ[â°ƒSjࢄ®à°³@#æ‘8 HbÍÎC‘œEh‹©À@l*¸£õ ²¨Â‚, e @dÓ%ˆ˜0#&N„”!fˆæž@¢éÞˆ  Tn"Ò5`„ïŒ'ûá•(9eöôÛ?éÈúf‡/ÝwWÏw߯5ÿr¯Ox:´Òó(ŠW/…¶ÀZ ÿ©8RôZ–´%ÌA :bÄÅǢ1(€ä\ KB–©9¤ã$ï¦!C0 €é–~€¬È´˜rJj‚TP%JiˆB ö@ ,À¨‡ÙtT2 å|ØĘ䓂¥IlJà›HÀ‡Œt‚ < „Ÿx €¢PKÈ…PÌ$Ã=ðÁ`£e@:9*(HhA>Õ/…¸ ¸"DoHÐç!1©§_è¾£‡+”!)Ä-já$¡”˜(¡òÍ(k¬qž°p+8@™™Pi²Ö<ðÀ ¶´B%ì ÁBbnt#n: j/‰Œ4W0³3b˜QgÞпGÜ¢FJÁ#–GÜh >€A6›Ò2µtS5‘p&‚œØ(` æáD¤óÂ È ´²2\@Lˆ‚ láÒ-®¹(‚üFºÒQä;îéˆXè ¹'y·ë€n7;Ú Èvª)Š÷Õà<==Ðÿó’úˆAÂyB¥ ò0¢¨ez´nšAÌÈnù[`âÀƒd˜"²ðL¨f¡[BQ‰×ˆ‘¢9˜Âb¡z‹¸L3 FªZ1ö‰„r Ê¡q?ÁBhðœAxðO\( Fbxº NŠ¥0:&Ãv„¡Ó2¸‡H eˆUí&@quшéTëñ„Lá]48/r C èr† rz”bR°B:•/5nÒˆü’•±@e*r¤#ìBÆÒŽ#˜¨dvéqŽð†ëºyn&ÄeÜ.¯ê"³¤h/ieYœTˆ9^ÿÅÒs ‚ˆjðF(a,©òÞð†M|@´„…ÞFØàEÐÁ1û“H jšOK«z5 mgÛ막â1¼ø 8«ÐÝ R˜C¸2Lã«_Ä’OÉ´S4®(²)O¨~àyàîÒ¿AÌ¡.= ù>+¤À›@ÐYÝüR½[Duªm(é0„ÙHô¤•pál„4¡,©H/PÒÑmdzéÁ:ч͹:§«Ï‡d7< µ§Rmt é£:z©ª1ªRW“ÓùÔGÒöQÏWXÿQ¯-yWûre$¹åN»òâ–6 ¼!ùL‹¶ ÿº2â`èÔè—A¸N°DBòh>›ØÕÖ‰¤è’@±‘9`zÀAµE¶ÎÞQXC<1L6û{ð±}'tÇiµhb7ºAáÛäR†Ü­¦îQ[n„A÷G8L`‚%¶K ŸG¶  ˆ‘ŸrCÀ߃h2TÜUÕ8äaÜsA]¥PE)p{~m¾†‡"¯ð¦ ChE4Â.ÎC ΰ—©Rù&Ä ÿ2pDÅAP ?tbôüVôХ͠Ä&ž’"ºò”ö¹ÑÓk^Ï¢¾1')¡Ö«Á:颼!ÿ%%ld0÷v½Ð %" Öf©1èá«–ñš ðƒ©á é1R ú§Sü@hd_Ù‘(ä3d^©>tFP‰Ul!¸Cr£-XÔ–°EbÀ‹B¬€ ð N° œà9¹Q²…R8áÙŽ%SÕ$Á*ƒYbbbÓ¡OÓ‘öéO3m¼KoŸÒÒþì=;R#õ;};Y“ —ÏÈbmeJèðö¥PØ`ˆB`°NS¨#tí}¸ ®\A‚¯(1h $*DðÁæ­‡…µØDbÖÀö l¸ Oð <á :«Š &°€hAÍíQÿ‚b%L‡ð íVÝrÂÂB¨ÝÖDPÈSì¡5Ež>…L@¼éWÚ€^–è¸Î"N^|¥àSÔ ^Àì¥X,îâ¶«îÆè¸Œ¼+zAX2SÂpŒ~p ¢$€\èA^Ä0œ\ÁâÏá‘b^ÌÁçÑ_Ô p­"þ Ñ袮¢@ 6£@6¡Ò$Âê *þ à ¬Žx já V#t€tÐÄ~¾CC-Ââf r ‚ ô`zñWFà t X¢Ëìw,,S l‘)À "#Ž14ÿÚG> É,/ ’àná jà h òg"#‚!á òàžLa„fÕ ¬12–*Í`Í Çêl! \`@Gq^öÀü€0x¡Oüঠ€v@qZ 2 êÀÀžƒÍ @@Èqú¢à ¦‘)¬`ª!îC¨„Êú$MªPÓ ‡ÓPÃwTCxj2&Ч„(‡R§ð±rQÁ$§/!•QÀ`£€ X$Ч˜"СcA"€l +³A¡,¹à¬‡+Mª¦* Þàê`)ì²}d!°f@-Ecÿ;Aì–`(rAìñ':5¨ 2(á> r‘Vq/³&Vc ,ó0;ó0KüÛF‘=1b D€ ؃¬À'ÌDN³'dSæ\nåâ.ÚÀ¹ÜehåR€\ÂP¼ŒÀ¹Ü@WÆaã~3ŠåÈÈ0]¸es3\eNå:±SÞ ®ˆXÆÁUb[Œå:ðTÖˆ8Éž`º"L@ ²³ðå7ŽÔ`ÈŽè… ‘ÀM"H©Á4u0‡:±@—Û†b±ÌÄ”<È@IÀLLAu#:a*gÀ)d1­34¶2g¤r¿’B>t)ÊÌóÿL4B‚10Úg,0`¯ HTB¼"Û0rt+;O7Ô)"$ïpR§A$ER"Ú`$»#"”T"!I-J‘ƒ"¦4JÑp–"´tœÔ$›’HŸGL…ò(sg&É”©v2&C (‹?Ð4ÔÂtMõÃùà*+ÄD`ejH;/E!ÕDcGW¦GeaßÏBö´PÁ 4øOgÑP§‘ì`QT:3C3µó5{B0/1­€ª˜¶MËtv¤*y¢–iAM@< NÉ‘| I´FõO´Eÿâa­.+Õ/,ÕhRmF[‡ÒRaUE;á4!…UÂ`3Â@ÿ –o_Õ@ùõ'rà Á00oYË0Q36!TõV¥DU}¢q÷ÖU1¡_á¤_{õ[«Õ=n.Å\ãÔ [3…Y0e!Øu!ñZ©õ]§µZÙÈ]âR˜Õäq_ŽåWÝ…¡5w‘Õ‘„å äÓ?y·váuè’´$wsIe&Ô^1t`7sc•q‹¢5tGg±eA4l4lÿôd›ba‹æ/¶CÁ,d+£’Ød1l•Ñh”âIÔdÓ‚hDàätú”ôf_jgµƒùT}‡î€ÍjãÔ=nR'¥ªü&xû¤6fçÔ§,øyrJMÝtjWCÇ|æaÿ=l¡•âyôhHdg˜F鑆Ù™æÑSiÕ@ ÖƒbÕNž¤^e76±·oµ×`yØU/ÂV?5U ó_1⇥äT!´]l·î%v{W‹by±u=Õˆ[ûEy}·]Áiwåë Æ˜ˆºØ‹î ˜YÓ…Xßø‹ë¡!˜ôÀ¨—ˆ·'"—A‡8Šx ‘ߤqé,ávFÃ7C>6bEöF)€ã~E#…Û'znµÕ—|+¤}Sö}A ¹Qs@‚CM8š´yåõg]jôW–X;´høv~Y€…˜C¸‚×ôÓèà•CM„G˜ƒõ£&áÔ=ÿ6™ìxÌ+f”eSy•g”’“šâîPùHT9P‰—¸`Ë_Q朅)¹[1×o›8e•!×r Ùˆ!ňy÷ëYËX!úçÎø w7Ç¥š¡ZÀþó¡7©t7Sf×â[ïåVR÷ â6V¯f_j—z`¥[TÀ&¦ç  (@¦'À`ú¥wúT Ì€^zŠÚ¨:§‰©‰:Ð †Z©£z©¥šª«§yÚ¨U @ ¬:© ¨ ©c«½Ú¬§­É©»ú¬ÓÚ­Ïú bàvÀ¦ßZ­Ëº­ú „€«ÿÍZà¨ÙڮÇ:¯ ›¨ÿz°›±Û±»°#û±'›²!»ªñ*°û°»²-´?{³¯®€´¯:NÛªq6 Ç.AJZg ¬ä`¥Yz€¤zj€®£šd@¸/Á§Ý  z$¸C§}Àb@²/ᄳE[¦‰€¯ûŽ›ª%AXZ„š³™û²={±¿»°Û²š !~»º­;§Ïà[¾ÉÚЛ¼ï›¿Ç»¿%û¿\À)[³÷;³ ü³ã{À)»¯qz´óšE2¿XhA$\¶Ù̲¦¡†úª¡¨¥ÿ©¡²¡B¡®_Zk„á^A4¡`»« ³@ ~웩kQ Š:j±È:®!³UÇü¨¡À§U€ÇáS¦í ¶Ò¯fÀdÚL!ú¯!ÈÀ  /|úÆ¥¬ÓÇýÀ ª@` r ¦qÀkµ {üæà§Õڼ˚ Ö` HÀbzÎIÀ € *”¦@Ð_ú~ „ Рūú @A³`Ñ¿à¦eÀ~‚|Êý¤ŠZ9ød DÓÎÃàÁÄz.Á]@ Ñ¥Àþ` ÖŠÏsAÏà ÿä ËMLÒU}Á Û¯]¾]Û³À»ÜÃ}ÁY`Ô`Ô` 0œf3|ù:œ†¡4®¬¡t`Þ?¾g „ál@fá@Ò`º0\©‰à*Á ATa þR] ˆ Ì«º/ ¬# R`§‰àt ®À¡ÊW€ÉÁf€Éa§s¬¾‹ZæÞL¾°@,É ^×±ºÍ¼Àlæ ˆ€v¡æ >¸e¾» †þÛீ ì ‰`l¡ a >þÖ`ô€°¥À á ÁºÜ­à\3›`ìÿuÀ@áã aÁ aÓàéË> vZéç œžº€ékxA¬Oì%“®¿¾Ùà:Á: ¸áÈÞ¶@ä@ìsá  íoĘܿÅÝÛeöךöcëo_÷wŸ²±T¤cC hAÝ’Ü86 ¤¡c”!*à”!´œü=ªá´¬à¶ÿnZrcH{ÉU}üà –\žZ Né©:æ?`È÷]¤`†ü>é»hÞÂŽ)*(øñæÊ%K øø‚A¥8@±D„¢”‹ŒJ3gÈô*2‚/<¬äp ”.H?ÿÈØq0a‚  Üðê`À€NK—~I‚U*""h6Í‘"„kŠ\ª”B ìl:²äÒ¦‚‚²Ô@š)Wiiýaˆ‚N–Ž,%# ¨ (QúÑ ÌK´ú=“åªÌ9‰üÀ]"•ˆ !1 íð¼Å‘21,ý‘ªW¯ ò-™V)X¿ r@0á¶ìÖ»“Ê.Èûµ_ß³EÖÎ[·Òà~ÕþþêZïpç®ÛN.¬ëæÙ•Ÿ-=öòå TH_Þ;ô°°ER'ü6òݳ¹w×YR¹k;ëËÖ«_Kq0AmM@àl¥SyBéw`A;Í–ÿP*äG_[^Ø–R º¶àmßE×qÕ-vô5dVPH‘@mcŒp‡jÐB@3ÖÀwãohrÍ+RH,Ê03M!°HóË+³F *¼¡Ç7P6ÃA\…”H"*h„@‹ÀAD tF ”­ÒR°á…Ž'~Úa¹éÁ)?Tƒ¡¬àƒŠXb€)°FQBÀ¥À?¼Yü CF@Àc–‰Ô¥àဠ+9Àˆ)KðÂÆ)[ˆ!i(”%Rž px‘NpF`)p €.ÀHfE…ÀTf€´€ Z¡‘k³ùÌ.Þ^Ò¬ÿ…RX‰:)PJ'vÚUvLÐЈHbË*4²ÃXÄ”Á‹**@ +/DtTJdè’P~HÒ@#¸JÄ%fü†$† ¡ ®‡FFfÒ•¼Â‰WŠ×Q¨]oÎɯxL9uÛm õ5žÌÚ’8]†Ö!‡2sîu‡[¼ëüsÖ§]€ê^Ñ%§Øs}N³ âÐM›ßÉÊ¥LÞÊJÁ«”Pˆ;!„6X6}Šû¡wmÉì2[Au8³Ú`)Û³B3]â{KYä5 †€Nãà8oHÃŒ•ÊTPNÌXSH!Âüò‹0'8P,³ˆ›_#L¾ŒÉÿ¸L‘­ bŸîN—œ`€mB°”š ÔŽÀ%Ç&;tàà >Ôž‚QHêוrtÀ—à4E¤bëÐÑG…ŒE¶L8 K„!v¢oðB µM P›ˆ¶~ ‹–{Pa –H =@XHAú³¥¨Â’PÅ)&…û%¦:H[À.,d> Ø¢N‡›¶à DH__„õôÏ ˆI.Þ€®,â¶àÿÀ†K áiHAvÐ>*  „ñ(a ¯øÀO‡ ÄŸ–íeo£›€jv·›±'gF3϶æ3âP-l©ZŽÜb–E¥XBfÑ"ÿѰF­e'Œ^ Ýx5¿íL>`”š¿¶Ÿªñ‹O“ãŠT4²E)\ŠÒ†ã*ÎÍf4K#Ó3‘åQg^äãá€rÙ ÀA‘g£Å¡RF°†4bWT@ÂÈF6r ‡jÞkÀ+z0‹ pIø5Ò@ 7¤!aš‘AQ„ªóØAE Ó4/Í\ @04ÅužÌ›  R¤P‰/¢+àÞ3c`4¤`$±ƒ@.±KA¾ˆ]D.¢‚Aíìˆ2«PF( ÁjE9Ë V ¡œ@–e&¸'J¡»J hØìõ8Q‘ÂTÎÿ,$‚•8x±Æ„JÒ¶H üT® ŒEµ… Rs(7ª€ YàÅvát‚ ð Ê€Vð`À†.˜àžfá¨ù*Cftˆ—¨´§¥ÄÃü@˜–ÚÂD  è÷šå­YKOß8 µ>ngj€¼ãsI²åuŽ~¬£"(Ó3Z±’NÉ¢!¤!°iò®]ì!»–È@Î1±0[¬Ýê&ÅH*–’Ÿd­FÙB~‘°{ý£ۂؽÍ&(7¤Y q‚³Ñ@’¼M@/1 “%*Ü)¸šS…Çf(Š‚´+!kHô ò>šíB™ ÿ‚˜Á^ø¨¥¦›V‘)hC®S8[E™‰¾“ æ»à ÝÄ#e‹K>¡Jl¹›CÒ‚Ñ¥”¤ @€×.°¤%-Ù¬; 0…œ’þL8;–./´É^7k«½¬}²sØÍÖg%1Y»]w—<µn‹ãXbíb–»~¥qYì4ìæ˜k'#lU, ›-ÃáEíˆq,ŸK>²º,^®HäᥜHBb\'# ®·Aúm˜T( 2ÕïCê›{ÊÃñù÷É{T‘Ž‹Ü×#{7ÉÚJ°oFƒ\â] á¡HoC +§gÁN&™¢±W|ôEcݰÚ™íÿ¥/@ t¥=‹i=7|ù´Ì.Á p¨ÔÏjQ²Ú˜¼â-Þ¸ÎQk­agì—ìèFijÌ××.ÒÇa Úôê (-Ëûqo¦(7)ghν¶ìƒâ=¶që,iCݰCö }dÿšŽ™ [l$%@ån}´ÊYàÒø†¿ÿ ð€ƒJùíËw`ê4Vȱš¦vºq\pw¸ ¦€«kk´Yf˜¸p-žðK/<ÓÂq8i­×yعæ3l÷«7cKÙWö×L®G_×ZåyfùW\Þƒ£ûä:OùŽeÜã–o;èT‹$-}Å‘dÃÿ yÔKré4ÝŒÞV8ÖMÛpGR])öxÅ›Âì°9»@¼~8Êa|ô•ÇV×dÌÎ9ùî-ãÌò®·À$übÌáOøÂ+~×ø…îKa¡0Ú]ù×ÃöòX]Âþ!»äe d¢[Ø®Í6±ŸÈôÖt;¾^÷¬¸^´Gv¯?–µÛË3àc_ø@6'5¤`öà¢ýî•Í.éoôŸ/]¿)k»èÏnëùôºI=X"žÈsøó—r6¾–_µ/61¶q­|Ô3Ÿ7ÀùyœŸóÑGéÓWºúí΢Hϵ!z÷mšµz¹“XÀ€ÐÀ[8Bo4‚ÿz@3÷†o5‚0GWÒv>`ÃcNã'dåwm   hœ—@ž#•`TÐñ6$ö¶J2’o8b&.HoAâwóö‚]¶J8>° :à‚\68~' Èe4òe¸w¨´€¨”ƒ?¨J5B„F¸e>ð€fd$bX†Hx†i¨†kxmˆ„>D’o`…>(og8ƒºÅ†>â¦à…1b‡M(…©ƒŠãwrø†8ƒA˜‰¸‡2Ø…:X$`Ø[m [Xˆ„88Bh#xö‡yø„i8`opNø‡:Ð >`VŸôÿ‰xX#žx 4‰5’œXˆmXƒñƇex#1|Ã5|"! —pæ\p rÅHf€q ”(ˆ+ Þ„@£.¸fp ›ÁãGœÁ; Ð~#²CÚ'e3º·dAAàÇ ‹æx„>8` »`JÆŠsRPy0# I‡{hŒiÈ[b]°Š<ˆ‡‡£ àE‚‘U¨ˆð¦…¹…†ˆ ’/H[ð1i’HÀ é„S¨8f¨†Ù‡=©“½•P0-i…@b&ð‰HŒ¤ˆ†tè“äJI‰&ð#YŠÇ(†˜ø“«Ô 5IÿŒiX”õv#˜H‘42•02ùI_i’N$:°‘«8oT$)#P $µfc o˜‹ ð;Ð$ 8•0—¨–—(©—Ù¸8ni’àd ¯XŒz¹†3(”8?hf ±3MoÂÙ@ Í@ s Õ` ­¯Ù ͵xJŒ ©°Êp 6`O€0þ4;¬æP0b ÍóÌÙ~g 'hã;b°)ÙQÛc!y’œ¦` ‡Pb ¦` "` :aP` h†ž3ð.*pŠ0M¡°ŠÂy[6l@ o ¡P†`Ÿ «HS-Ðÿ€k0K I0+€` #`Š `p€HP ê‚›Ÿä­@q`CP+P}0§À/:/0œ° ƒP‹¥P,Z…Cp#0Ð3Úú >€SôÖ € ƒ#§Ð¤O ‹¹¥€|PZP”3॰è~ऺ¢àIGð®€1ò¡k@/Ú‹C ¡:4Ń0OPÄÉ£(À§J:X`€•«Ð !:P¦$À„|)‡Vz¦:ðyG’@J|  J à¥Y¦I#† Š€›1j¤†™‘ 0bÿ+ð€º4§6É85 qZ«JŠ©K §e:¥ý—Hº xú `p€Z Eð¢oi©‚ ªbŒ°¤WŠ¡µ°à¢Tà«ÀŠ~0­ªÈŸÌª[o§´@£G`Gª˜ F¨ÄÉÃy­zwjp¥ QŠªU8    °¡D`¦´pp£P®AÒ¯ãjòªÈJ¥8:ª P­ 8ûŸP° j]ðû‰J8P¯JJ… +p+ˆo¸PP€f}Q?RÙp ÏÐ :Õ xÓ@IK¿  ##p Âð ½9 Ï`ÿ«§ s€ ³q!.¡ g1,øgº£&3  oà"`šêhp%4iPp: ;?ðW ‡Šb€דŠk"*Žb w0¸¶ü©Ÿ€ iР€\€ :¬p¨«@zº-p°ˆ¹P‹E» A¥C­¸Y$ÀR|  C@,ú5 ¬`tÐäê®[Ц @‹U(¸ëº0~ ŒPu Ip .€«ÃK«;Е€¬«¨oIò‹ C€»Ã{ Àé믻 qÚ ê½«›ÿ z°Vk±Eé€  À®;½Ä)UoÀ™ï˽M`Áð¼[Ö?¼[ À™èk[¿M»gزµÀ\À d»À F€º•ˆ€Y€›¸À¼"|€$ ¼)ìTu`R 4à1ü– IP»ÄŠÃ¨Û¿ ÀÃl’™€ð .€¡ ðÀ˜ Bÿ«À \Å,P € ú‹ÃQàýk ÐÂÅ»áª4zÀ¬kdÀÆCÀÅå;Ž5¶~ u  Ë”@¾|`lHÀQЀr0»†i0Œº–€À\À‰`’úð¢c Á&0¼¦,½{ÿ±ÜÂpÐ ‹,/Ä \Êè»Æ#iÆpºŸ”Œ»JZÆc<Žeè(²`—о{†Ÿ&=öÔ^ 6€°p6p ÊP›Q@Z ÊPÔLIàoÚð Gºdq`¸Á!xbššb'Pt ‰uŽ!Œ”8Ó$‹V@„q¹‡@hJ1=–@ § Ô9Ñ¢²=º§ºO u€ ïº\¦ PS 4¯œ;½€¡ð®ýËÒ€ \£{Àº¤È«ŠÄð†½ÐØнCPïzàŠÀ‡XÓjÓûé¦LpÒ Ðÿ`,Û‹1ÂÓl±€¼ÀÅÓ€ pf] °ÎPÏÄù{ÔGìÓnM ºK[ýÔ$ð™Ð~ ÕRÝ;Í¢J–ÖÈP0k±uÝÓȰ+½I@ 5ù–W`C9z}– Õ(ÝÕÒÛáÓÔ#WX#;§È€‡ú„`@f}œð榨¬nÚ(0¡Í@ P ¥ÍÕqŠJi¹†œ °È}S§}Ü124bJàb0Ú@J}žFà'PÖÞ¢À¹/ÜÅ©ÝÈ]½M[‰S 0 ½[£9ðÿX ›`Àýßþ7@ zÀd Õ­ä½J°h˜pÜ´: [Ý^†y@ 0nºÄýÞÄ­ ¿$GÐ ¿ºÓ×íPá†pE°Õ)` ùoÀßßCÀááÝÕ >ájä5Òະß5bä‡p` dØß}#4A!›í§ÝŒÊp© § 6ð Òð ( ëLåÀß0 ÍÀ }ÐÝžKÜ  — od_q ^€hqŠ.«°ÈÒè@MÁFb®_ž¢†RP(‹Ò(Â=æ ÍR )ÀF§Nø´ÿ)ˆi )¶Àjä`¥Üø Q ßnË >€û=T ß½-Ÿ ÓjpìÈ•ð Û=å´5#Ð ÖØ#G¾0ß` àÝ4bß( f ‰{ëîÝÙkÖà‘])€‘•À ] E ªÜ1â¦Eð¾ß€e0ÝuI‡? pH¾ÝëÞ£ßòM Ð2§ŠM­Pí|yé–ÐOë,` œ°Ü¿ÈPMïãN$G í×ÍØ–Ä-ñ$îïånOK€ÞðZä5r3poç-­ Ü¹ðX€QPàp@ ×9.óòfÿån£ðkök@Þßñ5â¦àÜnZõ)Š 6$ÿ>`ëL…‰ÐrÏð@ñë§CÞÝA’bFð¯Æ í•°ë@ÿìðzñ\¯ìì«”,€÷û]£Àm¥ö‘° ”ßãôÝ‹¸!`Pð?îÅýìïÝNŸžŸƒ“'žâü®ó»õ˜nJà[ù0 övâ= ð ù? ÌÒîýÔè^úì^#p÷ùNß©4PÀùŠvIå]ž~°¥%  þð‚šÖð €L¯ µ×€ ·µ© ÂÀ }°zaC#iÏRI«“ÿaÄW(F P$FÅ \\ @.í ò£ãÇ Îx0ÑâE T¨øAÅ„( ¢ÊQ‡?Ðñ‚!Å K̤0ô@LP,%eÃQEH.Y¢ªƒè€#«;@€#/Z¼bk‡–,s !’È—«8јB¥€N}ʶp8ă Jh¥ƒ„aÉšEñvGL\2ÙJèÅÇX°FØ| `„“(, ÖÂ>n‘dÇØ/ä:Åê‚¥tAÄ%EwU„ "4hŰcMÔЋD^*hA˜à"C:êÐp9am0_ðáñÿ;ÍG ™¢Áú…0[–¯z“!­‹9µ³ÏŠN k¬±n15 M`ã,4éb ”:<ÐK‰*2àL¬®ð#µ÷+,Ą뫬"P;«@²&t¸@róÎ.PB”íb¤í3ø …Õ<Ø€ZH`®pȯÀÚPAÁÝ.LÉ!T˜K½ÆPK èÞÒA  >J«P‹\ÆHk/3 ÆÚn˿愃”@º`"øÄÌ/H¹Å‚ç¢ )‡ÀÄ­î Ì(¾Ì³Å(2 THȱ,P…J:·ØŽKtÀãF[€N ÓK4Âÿ÷Zã.RF«BFF`Q-Ø‹q€! C2ÚP¡¢ .B ¥—ˆá’~[m±ÆšXbÄa„¡¦š4¨Fk„Ùpƒdfˆaž±šÛjh„éV¥°EÀ ¼M$…W÷„K¼5$\q8£[ €°[€à¡’*©dc( ¸„ž*º(&)œâV†ÃuÙ)Äàø‡¸bˆE0[|¯l¡:øø„…Vn@h[–¦n>œp‚&FŒ0¾Bˆƒ ZÖ“ñˆ®é4²ðƒú0e³±*¡Új(Æ‚b  –RX e @jø¬#ÔpÁÿ%(ÛiZ˜.a‹§i Ph%I› `Éùî/ºh‰€ë,X)ºÉÓÖaêªIyÂOHa€…/ÇÁ$‘K€ë¡+ïú=P8b§y—-B  ë¯/° kŠ>޳ ‡.:jZ8m. Pl±E!öH’– n¾Õ·Øbn(OÖÀ„gâù´Àã/o ä¸ëì4‘¸™€ܪ¶_¨a (@+. ;„H/a‘€ G $p# ùCóä0ºD5gXØœnp!*R@ ¨×ÓmuçsAë6» ÷Âõ 3j¾œT±¶Ë½òƒzPón8Fÿ\¦³†œæ8KØx8–ð{¥ g,kõÏ™Üï[3jaiµù¢‹®í µ õ X¿jO4ç<_4ÿs¤w†t´øÌœM÷ÑÒú3ªÏ[WK ø’7Õ§›WýêÂ%NWf/;Ù_<£¿v°…Ýg<º˜3Poùã'Å"ÍnI¶L©l #¹ÈK-Š“ldÌz–³¸HˆAWyŽ:Ö[-u´$:èóBøÌÒsóìe9'ÕÝd–©®MnBŽºÞ‡6§Œ·\ûÊ“¶@Ê€!lÒõN×ß~F0K¼ÑLÃ:¾†·ªù ŒÔ¤ø]u¦MßèžÖ.í.…ÁÒžJ¿ùàèFÿ.mïÀ™6º¿Ž0§íKæ3¿<¿ ŸVµLÌ’ SàÛ €rÄ»=ø)àÀT  Hv¯¸4€¬Îb¾À/Â5Ñ'pt(“–Ç(–e×µ® 4@À%™åÖ`šJX!¶ÁU8¢àƒ«Ú¤HA>Ók„ÀK)…o-ÌÓÝ~¢×4€¿;j$€øaù`:¤•×l¼S0í’#8¼) ÐIÛó͈8üÝ ^ædmÁJù˜Q}*-œ€Cí6}NñÌ_˜ïù4 âóÎ_W5ª®OÏo ?ø÷Â>ëÓ[‰PdÞ¨pèýx;%Ûz úï¶tIG°ã{´ôa©Döÿ©€ê›úÂv=x¹w._úwHÊV»ÌЭŽa+ˆð@(uÒ¨hÚ€8è‹‘*¸0€‚dÂf©ºý»„þÃ?¬[¥• !ˆV² 0ƒ‰YjC¤ÈÚµnû+ ˜6 ØÀL2°CP½$`€¢B?(ªk…:(!ž3½G‹ ‚SP 8ÓPƒ¸ƒó»ÿ‚:ˆ+î)“¼ñƒØÂ(˜ê¸´G‹«–³.°P ¸¤Qù½{#¹S¡„ 0…)|8Ù#¾œ7Bû7 I Õó)‘Y„»C‚7èvzPðC'Ô¼=¼8:̤˜›Ù2üÁvÿºD„5< €Që3D(ˆ„È{?ÔH¸qB„H\ Lô)h9*Ú"BÚË…òËCé™@/ô¯ÅV³4ZóªÆ«5þ »la¤éŸx¤‹€€ÈjhjHk¨lpF€Æl˜†[1}ù P†Y0¶MÚˆbTCVò¨‰X€žøH 8‰”à¬pô¤7–°™Šˆ8.dÇ„ñP°SPÔ2; H ­0…ˆ ‰ž0…ÐÞY­ºB‚µyL @‚)(°X cH@‚Z(‚:èƒSP‚MˆcZZ \$$²IðdòƒÀƒÿp¯ð€/8 X¡~b¸a .°€RÈ@ÀJð€Iø„%HˆÊ2É)œÊ—|Œò‹`KyBª´Êe™‚Ô0I”¤ë“2 É)“Z8ŽQ¸8J>HÊè?˜‚3!>ØÉX%p„èáH|@ÊÔø™Ú9Ê%÷úJX0‚RÀOJ»ãH>XK–IJ¼¤Sð—ÌðI²¬Ì\–¿IªË\ø ùChM°È µ„&ØôHãdÕ<¦5Xƒ)¦Y…–„ÄJ’¼ƒ¯|Ë‘ü„=HÃä1 “”PÀžÿPJK#X…@#8/8.éÙ¤÷‹û¬«É’´Î#i‚%ð„ÀŸ$†ðL˵œ.ðJˆïPÁ˜âP‚ª|Î,Ì3ÔOo˜Ë¹8]$ÑU£? i¼H€ œ€Ä‘ÑD€d̆kx†l°„ȆTHl € À†[†fÈ÷ €`ØnôF#Ø$šp¸ŠcLа3 R=P„3Ⱥ“À€2 С¨Ò‹¬ˆ €‚+° ˜…Á‚_š€4ÔÒ¸¸‚rt;P„¨ÓH¿ÈQ ¨H¥R‚Pð¨„O¸݈>P…€V°‚†ÿˆ=(Q¸&ˆ@ƒc1?Ð ÊË1°€.hº°€˜.x Ð2À.pæI,° 0?˜ULˆ€2‹ø|(ð€UmÕGP¹%…§W>@€À…eíZ[Œ"Åå§œZ>€€¯mØÕàU£•XÙR1&¿Å¹hñÅMó9d 0‹‹J`Ѭ3Ut—Hi°€X°WPkŒ‚(Ø@P†*°;ÛFˆ1mЧÛ$j‚/¨<¦»À€—‘„ŽP… ˆ¥]j1!ÿÀ^V’‚UHˆÄ‚ °¼ˆŒ „¬¥p;§à)Ø=ñ pŠíý\@õ †h^o’€'˜Ê&HC¸‚´€B 6ø¸ü¡„¦–…À‚N =ø‡P…Ê ­‹!ø„ È%PI ”ÀHáVI)LÐõ`@,‚¾P˜X®ÚhË©ˆ„\ÀØÊ°Zè ЂTA:)†…¨ÏÙE0b7Ñ€6P‚P¼($À8’P‰º¬)3ùj ÀL+˜)•ð‡pƒJ@ d°ùœ:Upƒ ƒX…0g™x•â%nP1ƒ‰ÿ:R1èÛÑŸ0P:%Hî ”NàWì9#À‡ …Ð\häy}d§ ”€P}5%XbAŽËÌP²âHÐ?™Sy(6P » ã5ÐY â%Ðô¼Eä00l‘.@Î €HÁ`‘.6Râˆà}Ó¢D0„¡Êš$P‚üP…Kˆ„6“$i…‡šE-ÑåEBjÝSÑ)c™{>„7Ы Me(„Tˆ… m8Þ‚„@Ø“€ †o†o`†>&(X¬šxƒ0˜‹ñÒŠ˜ ‘0äqô|Ä?’Yi4È¥ÿ(/0GS8ŠH,P„¢à‰¤@y¼G¶•š1”þu äqÐ’S CÊC¸U…øö96hãVè‹À‚2È‚ ‹R€Î5ˆ„p8 a¨„xv¯L¸ëé8àÂäXö (8™>Ð[8… ½/`Ÿ¡FVXì?ÌO@ pØèÙø|\ø,ØËñhÀTŒ ÀNKð„ ©2† 3‘ðá3Ñ6FãdqaLÐÏøpƒ¨ƒ%ýqŒTÎë:p€ÁÅÔ!€PˆLù€¡®@Ð,˜‚,à„±·Þ5ÿÀëè0M6’®¦æîƒ=„²kNÀ¦a*°€;n€,ÈnˆI‘žŒú€MÈ5HæHª%!Í>B`ˆW•|‘¡Z °ôÌU˜âðQum$kþ±ïbeð ø€ °TÌ8*°ÀO©Vè‚xõP„hÎkNP…F€WþïH‹–q6ÂÛéççî=…À< òÁÁ æ¬b4{ÃÏQL·í›µù Fp;=ƒ±£€ŠhG) kø.˜… 8ˆg¸kx„[¥—>`:eÈ—}yk8-ؤ¨‰~ôª €3e ’‚3°éÛÞbÿÔéë è€rü‰p2=HzLj9ô2=ƒKàßï…‚§v­Ø™=¯@ +¡•·ˆÞœ`‚ð°… à„1¹HS… V?`°;5`cPUñ“#Á½bI±sŽr !õàb‘ ” iyU…$” pKáàfƒò¨ ô!ìa¡c8„+Ál  …-y5?t Õ .H‹ËÎ[q?°½0c‰âà–‚LéŽ ÑŸàì $Ù‹°„NÌ$xê‚*``t· Ðu+¨OÕuK°jÉÕ ¡ ˸uüÞˆà~à`2NûæîxuüðÂSÿ‚j…›‡ YÉÐÛ8L?™ðÇðö{_Œc§‘¼•8>J – ‰OÈ‚W(¸F;?5{0!xìv·’„€€|§i…Í…ûÈ?°8 c!€4™xܰ-À °`•ı§¤Ïä[¾(…ÀÜ€nµ–_‹M;¬˜KHW‰Ÿ/—s±a¨†l@ˆ—r©=À—çÝ—~‘…¨Þ‡Á…¢°•‹P€PýU™ 䀸7X ”ˆ€˜H€\Úˆ™J‰K0(ø@4àtU°ß˜nK™_ÐÓïõôDþ–T×Ï{)(Hçÿ™gµœØ ´ažÓA.ˆ­P4b(p 8ôƒí‰€²FZU 8qBŠÉ¨!P U'C€Š#îÑ`Ä„ k”¤¹EGÅ Á4J V™r âŽÞ24x…¤U†>]X  (?Húzø â‚/lùöé¤ ++ PþñeÄ[[(^ÿ4Âç+Z7èmuƒJ‹H³P‚(@&5!Ú2…-0‘¢…$¤©pt!>Mqɨ’|È9lÔ¹3Àˆ?$¢g@.S@tQE`e  ¨ )47‚x„R{ïÅ·TD„‡ ‘D¦`‘Õ Z@ ØÂK†)qA‰'ƒ_g] T‚X1XÑ«ˆ‚Ið„+™¤’ öhb’ú•Á P%•,0 0%•V"€eI4‡•WBŠhòØ`EF U"Ð¥ *tI%SÒye–pÀA— $0Ÿ`b©%—S`ÀUNPg£ÿTvÙè£DÚh—u.°%¦‡"°@ ˜¡—XrG‘GZÔd«XYpƒg&8‚Ÿ…fàmî8"Àt)ð«)à$›Y¹Ú«Ç,ƒ®­EÃ^4m¿ºz"³°f5@ßÙäq îj"y,›`ºmÒ @·Ì’Û£whl´yXÐFۋȸÀÎ,°Ì&m²ZD«EZˆ–­¾Â2ˆÈ´­f%Å €ÆhÐq°—5xñDk ÛêÆÙ*«nH„"ä’H°$;ÏI(¿JïŽ/P€ÁF-ÀÊK¢K´Ñ<.@ŠGMµÕKËãÔ'9¯›ÿJz=Ôž öIé¤fw™À®X… ´Ðe¾­n‘³¹gŸwãÍg£vk™ö¤ ä))çiöàzp8âŠ/^øßv\²‚ÜaÄ*®Ø\rØN^ € Z µÜ´±´Û·çR+Û&½%W´õéàî(:Ÿ/]»í“nÁÕßî¾úʨ«Ž»ï¨Oìz°ÇgÕ×2ÓëûìÜQýôÒwn<ÁÄm̲ò°öØ>çì­.V °àF€7㌠7äAGÀ€hëƒ^‚f°ëŒ|ß–ìÖ¼Ñ Tô.’,&=ƒ7›×Øç¸Æy©K!ˆì¢74ÿ×Åívy[! [ˆ'¿1 †r!µ€Ô°S7œ$F<AÒ+áò´ö>ÔyË}¯; Ì.æ¾ÚIMkÞ‹ Ÿè-ìñuû ^çðÇ5&¬‰  -R:@)‰(›V¿†ÄªoUãw”."Â4àë•Ð|X5*ð‹sÓ+BBT)9ÉžV¡ã+gRÐ9¯¬ «Èê}‡‘••Óbž:±Ú½ð¥U‚­²€ì@«jÔ@j+\;w Yi |Å«4û)¿¸Î1 hÔ¸R€¾;v®ütà_!‹X€f4ÿפ`D'ûFDâ«•¼ûg;õ¨Ó]¶´¾;-a»)ZáÉSµh<¾Öœ®Ð —ŠI99ØŒ‰Û@ ª‚º ¼ý\„‰¨"@·¼-æ M*©nJDB €š73Èཥ®(­ L\ s†]Ò’*ìà]>) qB$¢úÃJüÀoe«?‡_ ìwœºã"> ( öZ `Xþkßׯ hmíCD[¶³EÌha™Å­\â1¥p“¤à…k8ÌkÅö;PD4@pjÙ¨@Ò2( 4¶Ú‹‰ÑtjÒ„­E€É ÏÑÆv­³=ç'É ‹q²N†ÿ(·n,ÏÏuɆ§Z³ÌÚLB‘•,­èH5E¥R†jªP(…¼”Ë5šAŠ\£Ö¸3òÜŒiT¡Ãe„0RÁeÌÂxBP`5;€—HA›'…Ãü@bhT .!‚ð‰ 5¨ôÝ IGšO€B8ß@Ó"HA£p kKX¦{` (x¡Ò5Øõ¦p`×À@.0ç6 ¼ ŽÀ)ð‰T¤ ֎îp`mX hÑž¶ËVQG—BT¨özð¹øÀKhñ („¶á@ Ÿp·ù" l@ÜÒFü€‰´€„ÍÿØ=ˆa 3ÀŒVp hZXÛ>¢j&BÄÁs¦ÕHSPNÇ‘æ`î'¤@%üç•&‰QYë™D©žçÍã%™#6I¨ƒÂ^…F(ì±^·€T˜Y(‡Nh‚´Ÿ—HJ%TÂÔÀR©šdBV@ÄÂ5 DÚ€4š2TnÀ|Ã0h3XÏÀž$‚в(Ÿ¤¤’›KÂäJÒ$Þt ’"N% °›„ ¤€ARj©Ð ¬!¥ (.@þµ«A)@F`U6ÑÀÿ´‰›`ÂÀèpYİB€#YЈ,à‚% øiÐÀ<ˆ¾ æaTBŸêÁm^À'p]´àœfª |@XA EÖiê) t€vÆÈA§bAX¦@fc&Æ$ÁÑÜdA‹Íå¨î FS\€%䤀Däô ¢þi|À&dÁÉhàj‹§p~&- ã¯*A›]¢8cx‚(AT§«šœ8æ¤"uÒgÒ<ˆ'ÌAøÀŸ~À"àÀŽ™&*∠0ÜÀ€|âW}|¤ª`A´ª¶ÙHë(À.~€·^@žöe82h;bhÿ¹hèë5¨‡vÍDzãèuìȂ膆¬Ç>RÊ‚¬E”¨‰žÁ—J.˜Aªá åXÃ/p TÀ+XÃ3\ƒ5Dd¡¥‚4Úè2Ø@ô Ã3_ Qe£€*@B¤]¨½P—Ü_¤ý@ý$ª©€¨‘ZR!àªimŸ¬døÀ  ŒšÜ ÐÚ˜®iRªßÕâ ›¹i×bÁ ¼)Õ^¥Èµ ° à\Ô¥0p ÐÀur¦Û`  ÌA¢Àäî) –¸µÀŒgznlÁæ¾ Ü›(´à*8aö¼n ¾àc¶æ„#À*PgܘæJͰnÿ£]&  c Ä”ñï¦>â šªîòbønÂùˆé¢¯•„ )/Â]/8¢¸ñADª^Nc€à¸ÀÏÁrnø`8^æÀíbÂ#,oU\W¸+¼"à ! ¤+T…ã2Á+Dcal ¶.:®JA%ÀEÒÝðê/ð.€ªÁ.o\€ó*nRÆ/öÒ¯òÚ‚Æn¬ÉŠ,ÓlÃ3P{„$ „€‰Eÿ«Å™(@\ŠWRšOÎìÖˆWÞ@NO±à—àW%ä@°qÀƒÐÉ鄸§/4eKÊ_/r ÀÔ¢ SƒB0ÁNÔ€ °‚ìÊZ°‚ @ðA…¤ä)à‚ÛЂºŽ@z(A+°‡ø@°P@N0„IJxp ´ 8@NðÁN¬ ´‚wÎ*ÃÀ øjT9r¸@M|ä ï¸À'0sð (DøÂx°ñupÇýøB9Ÿrýps‚ŠÂ ¸+T3” ztÄK<ÓeA(ÁGÖ3wŒŒ2”òÔ@xd`õ†Àÿ4?ÀÉÈÁ°þšó&0-dÀijÜง-ì‚®^ .ÄÀþ1ŒGÉ‚!d:Ek„³ýd@P‚-Ø#¤OŒ45_Fu¤3ìW',´-AH5w|$GÐG‡´5‹£iácÁܰéu(ËŽlé¡ãcÐW¯VX3‰•u%ˆ¿¤HÌfÉ/µÊc1RU¥˜ §ô våIy!ÀIzU‰w¡W ˆRí¡Ù-Ý’¥Pú• RVœFÙò8Œ9É T:õ—=ŽcËÊË0Xì5Ù•Õ8_ v0#¡á¨OVtOLXg „Ž$…VÐÀ!A“Ó ÿRëÜkÛÁeà‡U(LLwÎɷˬÜkûÈÍÕLuŒ­6k· ÄL÷³¡L¤ÀḚ̂×0ʦw¯·ÇØ‘Áiƒukëõ°{›5|?¨ AvNÑ’•„À­6§‘Õz™YvU×a× R)v•öz=øIýµ„«×Ÿ€]O@ ONåi{ÇÞ~¯5…ò0ø}ów†¦¬@°ˆ—µŠ—ø‡BèËV„€‚-¬Àÿ°µ–åãfÃc‚PØO(÷UŠmS~§¸C­8KŠÇ8“Ï8{?9Yè_Œ_yËfyŒQ(Ì.±¡4ñ(E •l­ü‚4läš³y›oäÿÓj€ÉŸ”¹.-Îaÿ7y“¤HJI9øyÕÞÄê9hk¹ZkÒzëãgú{W„t/:‰ú~룒—uhKç)zkžiï£Ëx¤Ëø¤Cù–³7£ã÷¨úGAú©[yªMpø(•Ô/"<¿Á¤`”‰Øª˜€ ûXã׋°B Âì8’[„œ¾@½Ó[dÚÏ[½‰˜Ú[% †a :e@\E#@A"‘‚•P,ìT€ÐðÃFêÀi$ c„.¾Ð Æm ‚‹`¨v§RHèd†Ft ¢ øèA Vie X€rZ*ç²€#ž5€?)!\Áðˆà3!`,(Å@Œ@‚Ù¼âÒk(¢ìZ‹c²<ÖKä‘Ǫê*Í"Ù-‘;.Y,Dø®¯ ˆ[`ÿ&PeâPŒ1 ¸#›kRÉf‚²yå—ihH›T–®b¢Diæ™ `©Æ‡sÄ‚h ì8øË/".Ñ¡ R¨d…J‚âN‰Áâ3·€ŠéDÀ ($i@±¾ ØÁ"ˆøA‡¿×öNˆKB¹‚K~ÀB ,1f ï‡¬P„ñ*Ña†þ,pÆмj¸ ,¸háXÈ$Š-‰ |d  2Áb‹ ‡` ‚ ÀЂ€$ºpaD#@¡"V` ˆ€!jçÈ¢!Œ ÃzŽðY †˜}÷D8Q^"ª•À‡-¸ø±úÚoo"“+˜`®„ ÿBŒ8ÿ‚‰°À la…`Ü¡&‹ Œ`úQE`@ "ÀL¨bÆ ].*? à¤@ÈØ @ÄI4 8ÞœPˆ(0 ·p"q‰&Xဌ§\€‡>ÔBù¬Ç:¸4‚Å·<á ñ^¢Ð@+r¡F`À •d„Sh€KH¹V%Z€lÉÐ#Áq…\¸ N¦ú@Pˆ7°Œ[ ḇs)«¨EjqH Òïã„zè-${ÉàPˆF  `ä´À 4â.€hA"p'Q’Žb€(³Â2­T….ÿ'™N~™±¤_;ÑKË€i²‰¥˜ÂÌeYº’¨˜1ff5»Ù¤£;p „é    @…°Á+”‘iD! VCÍl°’ ãßІ6ø¸Š×RÀ…,jМ›õEgˆC $@¤[jn‡0 @€t(Œ®0ÀͰ xá¡°Fê…/¬'vPÌ0úƒõ4p*P…t·¸¼ap:ˆ¥/\s”„üh T €.@„=h€n8AG`\èá‚7èÃ~1(Á8É¿‹éaâ ¡îG½ ïÅ P`”!`bB´€ÿë~·\€€Ô ÔºÚéteŸPpÔ˜M{­¨BЖ‚PÂTªXjS e‡,Ó/˜ @‹Ç¦uD/ØCb:†(Ñ®€è "A¿>°hŸZM.æPÕ;¸ Ex¬fW‚8|ÂSª€m.Ð'£*¡[Ó±ÚjŠ·š0‚k7ì@¹pëÆ€XЂ´­0 ¶n@ s.) l J…yY²=0¢ G8ÀqÔÔ¡zEj¨ò4hÖ˜Ÿ)¤ûTÞ4ðÀrk24ÝÅ´uï|*Á­=˜a¢²— ɤ ÇÜeuÿ_L2`ê2d+¦/]¶–džÇi¦Çž‰2•@ÄfÛŽ_` höhàÀðvXcœ°èAbñŠa4ƒV„2¤¶6~c˘¹¶ö9J@à 5@Ã4 PœšúÅ8`há@„ˆâæ/PVŽ)€^À" §  v3ÚR Óà< h ý–(T½L‡¿µ‹k(X~ôÙÐrb3Â(LœÑ ŠÀ<‚UlMÀBx¡)¼îÚFè„ÝGUk­^¤£p⤠b €S3`"¯¯™'êZ‡>«ˆ‘jÿYîÑB€(‘À Cp]:;Äy>m‹—Ý|î æ ƒÐ`ÜÛn!šàƒùÕáF`C³ãò¯| P@%XÑ…+lÐXxVAXÔ¿R ãó“‚úJ܇ºS >"Ôº'C“¼ ¾dá>ÐAlà0ûë! éÉ5‚Q¸fRÀÄk^P`´¢Ý Å"Üc(9Ž¢A'¶ÔD¬bB€DÜôøü|,èÂü.pO¸êe9‚*è8¤€àu½€%rsD» §¶ Uã¾—+sñHN]²¢«Œ"‘Ðä)¿—ÆÏxdS!‹'+¯ÜÿÄ9fÄiÌ͈‚ˆGÓÔL@¬ñ‹`T£©Æ3®a(ÜB©x†0¤¦=(Ãó´Ú/¤1Z B¬ 1í€rò¶"(b•øÁ ç€\bœP@Ýî†7ÆìmUE 8`ý™Š_£+yDy³žJ£PÐô.ïZ ØÉ>V ?JÍòB¹ŽêÂÀ¸ ni†ºâ‚\à jB×|$j  @`LXd}Ô€æ X€YÒj­\4Vá àä!,`¶`$ >€bÂJ‹î Æà‚ªåàh¬êJÄ\ 0®¼&&(«a^ }%2 6<¯(îd×0n_ÿÀå^ Àbê $ˆ@äÀ[Xጠ6‚e+ ¢’‡ -@&ÆXÁMj Vº NP`U8A \Àa`¨kðj fèï  ZL-®K%@x €`@ <@ê‹áÚ %@€¨«"B*ÁÀG êZ€ ¼‡q%Ú ñàCr †€n%$à |€ n%ïòân@K PY1gÑb,Œµ@\ ® Q,Ú`T žÐ,‚l%¾‘,¦"ô$ÏñDfd‡L‰ šB %Z ó†,9ˆ£Óòq; ÿ@›& ö‘`ObÁlÀ¤Aª!ŽA¬!ù2`ô`ŠnϨ|ä ^G¤ ~à.¡£¾ãgì~ ÌV@8`Üà€àdòȤïdà&%‘$W :j +x (+ÁXÒ ýÌ rnJp `qL’%}¦0€p¡s: Àqb $p$¶ñÜ”H ¤ j€ l2à$̲ ha N"œÀ ¶ FÁ:XA ¸Àœ€H¡FaH€X 2€0à0Ÿ`JÀ-³):B߆€0á0a`ö´h!Bÿ@²€  @S4Ñ2´P3˜@t¿VB r2]€à2ì`œ± Œ€7i¡5_“ &³-}³n` 6t3ø€Ö Ò 9¡`8ÿê´F@ Z h;û@R`$( /EÓ]`<Óà8 @ ’ÓŒ 2má2ƒlF€6Y¬ª2Y“(ÑE«B €°!Xä0mÁ¨ > ¶Àlañ ì’?ió-ã².”F‘Ÿ€pÀn„?[A$]Àd Ê-Ç+̾q­k˜ón *ñ¯.@ XÔª†Ó°g.õ},cx ò6/‰)%ÖÿQÇB¦w J}LJãQ™t$<©, *, ò;ðúI¡‰îàã "Ï+_'Æ´NÉôNñÔL@OõM?J ' 9øtPí´LiÆOQ‰Ã :ê$+ˆ,íâ*|ÉMåMÔT!”;1µ!‘ R‚MÅT 4µ&ˆ¥ ì€M[S./U?®c¦âæFÀPTÑL•"h TO €Rá´TÂM}‰"$@²Ò‹+H•vU"u%žÅ>ÕW[.Ž‚)5X¹t$¼ñ'â‡'U 0YÑ1JG‚€¬µ'ejâY•Ißbu[…©™šdî5¬‡ÿVã”»šêBóΑóÒQK—”JVÇ,õ±P oz¢S'–"Vq[BŸfb#0ãšj¦N€cóFoÀ;Œ dÅ/Oõ†8<êaÕVRìàh†@c›5g·u^/_u‚YIJeíUu`…,4~‚[M laœóT©Â—†Nk07‘Ö!¸e†U_W/Àu+è1š¶6+úµhAµe,•hËV-Ú@DUS›‰R³V!¶œÀ âc­BßÖ,âbwöoy)+ ïA6 K3s˜V%Œ¶,ü¶g½¶`WIáBañUñäñI‡, cý‚PKvp–Iÿ¢aY–Hö£@w1`öuW7Q; 75t½ivY0 €0D×7è¶nýU-À¶ Ì5rÙ–gÿ6¾4_ß”l•WÈ,ÏMËñ™tö˜d-—îÂ`϶¢)¢{£·IבzÕv,º— Ôw/³t¡˜~sA~÷´~\qL|¡)xKWSrsâZ¿Ö`¹—l96Fq7—rßa/×qCæq‡Ì/ï\ÕÂríri%Äv{—8Rp¯wrg dàÔa[ww 1>gB6wcWüÆïds#ÎR7e]xeÅb5ôÜÇ,/|¡—p)Öó2˜,„ø'Öv„4/RõyÝÿƒãâeíSGb‰G8!Ìw„×vTEF3!Ú 4 ŒÍøŒ5̘ ì·(,ǪøtIе6zßƺ6šÒ‚tS‚·8K÷ï8Œûcª”sUFŠ1÷ZÆ(8š,xq Âa€vñÆuWX7pw€u4ô@Cs6u,…õ4…y7p@^6†û"7Z8Q£vkx†Qv1@TQQ9–¤`LÐwƒ¿Ö_" ÚØ,GÀ˜!Ï `Lx€¹˜N!nY±˜MáÚ8ZG‚RíB : ›ù½ âÃy-R@Ž_"+Nt@‰VbšEØ”Y‚ãøŠõõV¡·ÿâLAŸÛÂZ  š9Ú±x‰6â|VXˆnߨñúµ]º‰‰‚X 6sÙz…¹s1š™d‚—·‘KW‚÷µoWâL7ù’yÒ$çf(€9 PaJ@)B A Á"/,ï2 … 'Mùƒ'€ìýD,–íެœºÈ˜Z‡_9t[©! v b œÑ¤ *´¼§bIU j žÙ‡ ò !в«‘i˜¹"ž¥$ì—" R ZR" ¶òGp-b(æ6Jg¬¡u‹™˜c¼úTÑÆ­s›B š*Äv¢Å‚ @²ÛÚUy±­»Çvÿ‚óº÷€Ó  »ÔéØníø_ë±µWâK… NO&pãš%øú‘Ý1‘øˆéYsi ¢ý…`+Ø`§¢¨ëô¶2 ‡’1#2"Ã#6èá *C¤¦!4€Lƒ `álà?^ˆ ¾@ •7½ €7j¾€”ºLUa¾€Õò;:²ºN«òeÿ à  RðºD@& V²fÁìã¿Ma%áûì£|jœa¦÷f¦‡€,¥tdMŒAjf€<È%$%^ø“VPXd¦B४•Kœ} „Å×úJ,T¯Â¤ ÀÄ,‚ÀWÿ H d À „CâÀ(±>ÁNÍ”@ìwU>¡B@W¤œÊyq¢ *¨Ä%:6A2Àr!N< »&åÊ/`áí\F ôÊ ŽEº¦ e44)JÄ@AaÀaÇ!¯ÄAOüˆŠ<¦ƒâj``FàÉ}D§©àÐMf`M<€á„b H8ÄÄÆÊ1½Uôxe‚죙‘;ÆŒ=+|ûJ8š–Ez£w{“»r…v$V÷¦JR(_ö›ú`hR¡TA ²Á~Á€ž&j@û»­fRãÌB Œ‹#–ÑÿFâæ ò½tXY— "Ö{d1œ›uvñšqˆtÀ¹K§Ó€ ¬€1~àÞ ææ |à$U@)ózÁ'>€sÆò¼)âL€pq£ $à\àÔ`$ȼ°àé@ ü`æñ`´À|¸`°'­^ä‹2€ºš´…øsvDèviáäÞ èlÑ‘ Â¤¹ €¸ TÁ° ¸€¦   ²à$"À tg *aö.à‡Þz àdžæ{QJ ’äà lA Ȩh ”2¨¹T•G aìÞz¨¾@1õŠ®k|cå‡~®ž?MÿˆŒtÀ{®ˆé›¢!ü~æ[`­Gð F0žÛ óà‹v§`L –Àð3!ñ`@‚Ó¤`w,aõX@ P hÀôÿ™Ûµ¤]û`™}‘3z‚/Ú«¿£;/¸›Ø‹ÚÅYeæogpæ¦: f`Z™" ¤aœÊ霔´ l¼öŒ‹²9} @£oß´}»ÓÆÈ*W6,ø¡Ã’ 0’M R¨8#C!88ãÕ(˜pÁ xøÁH(HY•âÇ“>ìÄ¡ŠÃ!;-PU#Q(– HQõsÁK.ÿ€%B}F`-K°+`áÀJf¨{Y„ݲ¾œq#Õ`1C`.¢`6Њذð´Ç À/ðÙ)lqäbðC(P§ 9ÌF.ˆÎ*ƒ½©‘ Á4,pá/œ¸Ã^z“J\ñpÆÈ"9!ÁE`-àÿ"xˆ+8òЏÇfÃK,­JxƒÈʃ8%ˆj´ÅÀ’˜p­‘YE.P!“¾ÉËjÀ$(ÍR 2‚„Ü` cÈs/rÁB¤à‚4_ÆÁÑt°Š7|¨7#ð" NÑ„ÌÙˆ yIç$"3¦6¤sc¢$ˆP <â, ¶P—U$axt1¡rÐ/pSøÒàCjp€¾• \êø¦ðP0KŸŸÚÄÒîí«KØ;ébxS½ÕÄ”z”MEú=˜™ôNä)Jkº˜öÙp'=‰€p‰$ℜ‚"ÿ¬aXXëF5²Qºjà ÌÀ¬0‹P1‚ 6 úv‘ºT :ÀŠV€U¬Ä4U+‰Y8°ƒK4Ufh€H&EÈ?€.!ƒKa¯9_%€PˆÉTˆ—0N‚rDP( XvàÇ^B …Ö¬‚XŽç‚u)“è°ÜA -p-†>Ô TX œàRb&à)Ö „4|ç¬hEà`‚ ¾8B ˜`‹VŒa•æÉ­ Z!ƒ ìL !ƒ XÀŠ—…‰JÓ: $°À7£',°][Ѐ Al±‹Kà [(Â(FPÿ‚õ ‚ÌhA!ÕXn®B\àæÒYkÀîP‚,0 ÀŠÀ %d „Ú }Y@‹ܬ@/qƒ>tb `€ @\RlaCð‚ìÞòÀ º­ŽÖ‹„ï>mVouPä-@¡]†Âó†[Ü-¶üº× µUá·÷bšqßìe/¾7I[ßó»Û´$¸Î gs¿#E–ö=€oû¼¨žz‹äÊ··s³ËTï—®5y*þ&ŒÓßlšyóçäzŒï }H~Öw_sì‰@ËoyN¿¿ÓîmZ÷y2ûPG-i­«½íÁ75ØÙŸi8½ß{¦ã·vjçhφÑyŠGyœ×¿ 8AÚÇ{Œé’x“§l7‡€GEw#Anƒ5wIERn Ø•Çl ˆy"hmÿP|Ú·>ÿæwpÒ:(qG7|8õwp|ا~‹B{áWO ·oñ—wH˜ë“g"„D¨(m"êWo dqmiTè… çzÒQA5†˜„‚‚zž†<;ÕwÔ·S^7'lÂb÷‰_7€;˜vt؇lWjùW(ë³Ú#qí§<¹€z؆|(&a@ƒØö((ø Ïð Ý‰šØ ˜¸‰™ø Ï~˜†{ñv¬&w(8)*¸å–ŠuÇŠƒu€ (‰ ¨-¸yâæx!hƒ¸WˆÒ'€‰Ø\˜içGuŠ‚„ù6(g'ðÆÔLlSX~ê#&TȄΓˆ(·/Ãqÿ½‘oyA7{ËènÞS}·„ŽWH~Ø·†I˜â8pˆŒŒþ·ˆy˜Ž¸uø‡Xm·‡5U&ö(‡w¨eGb7ýز8%¨mÑvl6… 9Ä'q î•o´• ©‘ÞæBׂÕF‰(ž…€·È€¹èy3“hy ¨ f@,-”¶Hx€/R`0s>€:ð=ÇsjØ%>VÐ…E·8Ò<…¨2o#À…&]:`âxà'§V‰„X(€9‚=C`c€(çgkX…€ÐÁÕhÜ“&§ {·_)†Â—tÿ…rë˜wÒx&LŒ¿V˜¤}Tù#·'§ðtd€Á×|~hˆsŒC%'v<¥œyuXji†nw@ixF±X2Y HAA ‘Ô3[%À ·H`X†  @!p¾€›:a“/HBà Z“hp ”’n”ø>âV‚+XlÎF‹Àr¥³‰‡‡Àn†°J–Ëy—IÆ7YËIbòŒŒ$PpN]²C {W ÊÙ—F† Q }·&Tè•\àæ8RÁ4 „pNœvjþ¹S `ú'u~ƒc! m‰qC° ¼8q–qÿhÈ”>Cp ¶ç °¢e¢”××{ð(Š'ê‹¡Y€ùuÙ¥™é& iŒŒžéþ(v”&ˆÕ¨&™.$a¶ :@h a) Q  Ô ¦xq [E mš Ù*6+gõ (  ³ð ì&xP 9PG’𔊠 Ô?^ÊBîyl!ÓB0CÕI¤*` pP°¨2a;D `‰!ešv@,Ú²+î⩦PI9§gjCp¨Op H0b°]ЫÄ8 ŸÐ«FŸƒ6«PžñQ€€½Š¬´å”°Œp+€ÿ"@OÅz¬#`~0Ÿ€/2¢¥€|ÐLiS›‘«áº3À`€k]À$0ã1æ3F0 ¡ñ­Ôº]°ã!dò™#«Ð eÀ¯»Ú«q§ ˜ ãÕ­{± ~P UôêŽ (>À®+­?ÖdáŠ"[ñV P+›@Sà 87¥ ”€k«0€ ]Py8% (ëŸÐÒŸà \ç1” ³ÐV+±Ö1A@"nÀ7ßj®F$Ð ÁN/ò GÚ†IJšY×SëG&©ˆPÊRŠuT šôGu+…ÿ8…·y+&ƒ×mì)),á+€î“ cÙp ¿ @Ùp‰Â ˆ€ ©ð ©R”¾ aee´¸2—P^0‚‹¥g°X•4’À €-Py)ð °MÔ‚ )ðDd3p¡–°£ WÀF”µ{ pXPCCñµûDN.–Ãæ‹ÕDgQÀ•ðR`$ àð[ðH/ ôä%fdÍ @·à!`? V }ÐI@6$rH ¯ÐFP XÀ›€¦~w¿˜0¡|7[€ s âÚÁ˜@QÿN \ ¿Hà+ƒ™ NâZœ·@ {1B–­r `cbÁÜMw5(€ ‚ÉR€A 0ÁRÀ™`¯!` óÂH<¿ ÃM1ÆÐÁ›@C@²7‚1\YûiPkp†PúûÃð} ÂôÆÁQ°0ưȕ`X`ǰwzÑÂl À CPÆ\9”àK»AÆ“›œ€ÐfŒÆC8¾h¸|‚¸ÕÓ¤{«iª¥ ¸®itˆYZS²<˨é~a?Éž0?0&Âéâ) ²°P¡ sj@©+ÿ¯Â±ÍÐcpAaŠ qµžRÀ¿«ÎÈ»ªðC#ØeñB>B!KñŸª'A‰ñP`?©M´Z ð¼fq.–°?aoÑ0l«±‘ @8Ñá; t³±CYàN¨À;u$à&` xQ „±;T $5w%¢!-° šA ùA:¨<Ú ù1}'LËÑ   "5$}áà°ưÒ5ýÒ3 ¸=“1E}p­bB"³±x´hÄ ¨”3SàJ @¤q$)pj­Ê9E0ÇÇ4ÇopÔ±¢6Ñ)PKÿÃÒ\íÕ ›L8 ±G€Lзó×€Ýq|1ß‚"¦qȹ¶Á;SSB  /Ð÷a"u­Æ„‹¥¹¤­¹z‹†rË~›Ë± ›TÚËX:ˆÌõGËŒaÌŦyª o@8°»ÙÖ(Ÿò yz¯ §2 \ð šÝÊÀG]²1 ßP+[`—`Pp f €é|)±^À'ä¨#¨–zô3›R€? YÚ ê .aj) -€ azÔ\? )kÑX#ç›v1 ‘>3I£¹š#RP2i|¤RŒ4bðŸz#1ÿE€k¦@F¾a!˜0N00^|K€:Â5RX6!S|ö ƶá8ÇР† kà¬ý‚ «ÀâM€˜óÒ2þ<â'–3â€e °¾sŠD40ª Ö´‚¤ j °óp Ð2‚Ã7á—#Ä ÑQ0H|sŠ€~IHðD€ sÀ >àÅ|ó‹€#v¹6Ä!çJ0xÕ¯4ìØz ¡mݯ)wþQ‹n ( 8ÂÙ;c®/à8`£ç-C­#<¨ÛU j]WtJz·SŠRÂ=ìc‚‡ ÙSºËy½-&ÿ´6x®æj*¡©*¡€n÷Ãí0üÃÕ ¯` 4 Øœ ©V ô@ ô ÖÀ7à ¡óâ‡ðDО!¡©@à?ÐC—``?–л?ÔBÜþ(íqG*Áj °.ƒ>°50)0–ÀžFAoŠEK—`¾ Ð-  Hí¶â¨ó N %NÐß\@H0/r­M@ Q ço¢ójÀL0FIPLo´Ãó£¡éD…æ-`õ P0X • Eúî}DíJ°[Àm€œ`þt À°%#` ÿ.p í+QM€æ¦àÉCˆ6šFëÄ 5bÀ®oPáÑ <ö½@ôWŸ t /HEêp÷ä´2[ ™` q/LCoô¡ ¹«Ï7•àp(oòQqðÑ›ÏôFÀ.P]õŸŽ a |Pô 0G¹O8Ëè°ô÷cúpïRïùC° 9cùÀ>ôoo•M·ßÆ.šÈn·‡»ìtØìOº™¸Ì𿇼,®ìï$H@‚ &,PaÁC† R̸¥„¤HÀšµX³¸Ø&¬Z50(Ž ³&­J† zfÙØÀHØ3Ôä2²Êÿ  @ÐaãCíYa‘ÃÒBì¸Tµ¢‡ œ‘!ãGE®^aèa¥<*Ͱd SPbpÀ‘"QRŠ0P€B„HUH?|©‚±ï„cÙÞñägZPɉY|ˆÃ„.Jx¦…(‚ ´¤ÑÌj(‘'OnÕIÃ5[¶ÈX=ÆÎ‡”9\Ö=ÊŸÔ~d\ÈE‚E« sˆ»ÅÙs+}dH™€ кpg4%!8áy¥†A VLAqäx‹5~Ò܈±c;eÉ `ˆûxkE‹N@aE í\°¦Û¬3ZX¹A.P¢¼Zÿ°; äðÌ–:;ŽøÃ¹ÒîHÐVÈ Jl±¥¼ÿV!‡˜Ôò3d ž ï?†OÃŽFc† ADÁ]’à?Y¼á†ÎXÁŽ P/pQA¹ÌÂËð¤á(À‚ê¤2<%ÓÓ > º3€+ëtÐ9¢óÄ>çÜsOA5” 6íÔóÏAMt€>é¼SSB”R<;}t2„B*"¬J"x¨£àòØŽ†ÿh%€€í ýÇ€ªNm5+¼2B@´J0–]•Uc[m()a£] ,j«u¨ÕŒ²ZUp2\ÐЂK,ÿé£1WlhC6ï -¬DuõÞ„ì¿!ÈÄÙüµ5´àlÝî]ð}wRy ½U2ïAÅç ²óý—S%³÷ÊÈd½W鵃Ö÷2 ²‡!s8²!RŽlâÒÂclà;ŠûÕõg?B¤€…N‚‹•Æôã™VúĨƒ™æ˜æÎSQC}tQ¯Ã¦ôOK»î”Ó"Ý7ç®ËÐL •;ì®A¥ûí³ù{ÓDçh€RÂÖUœ}H¤`Mzê~qýx¶Éz @Ûc¯%ÕÊ·!oß܀ϟŜ[‡š–ðqà /Õ ·£"²`¨ ýÿèf×:Ññ<‘´ýf jèÉdÍ=W}F¾`bžò~`@›ßºú9¯,¾zD--[{Sx±Ê F%™zë»úãç¡Ïóc:ãý—‚'¡m޹žmÝ¡M{üó]¿ÐF¿èɆ_þ‚›Üè5»}J‚v2ßöÖ·±Ämfãš Ø·œÍSL[£ Ö¶] äi£’Ìê"rº‡ŒëTxÈ/¤ñ æP‡;üÆMœ'0Ê‘N+A´Ü‰¨9±tIT¢cعcM+˜ÊØú¶×¾GÙïvß#ˆ‰G) (¯wsTÔv‡ÝEÐRT ƒ.ŠÐœ62¡ºq#ÿå˜ Pð"oÜ£ûH†& M3ÉrgÊôoÐý2Gb2–À Áˆ'ûyÍÒëç vì{ò¢½ø3.R°ƒ~Z%¡,8?¾ù oÙã`Þâæ5DÉRóá*Õ& ¶‰jƒtZa¨øÀº¹°UÚrUhøÌ_<£Ó¤f5­Ùg<#…jâBR8ÃE+PTÇ©*Ï“#Ýdâ8ÉiN@[‘Òâצ74ö°PÔ×ãäw;M­ï”¼‹¤>í9§wi€ ](CêÐ…&t¡\hÃC-ÊIMµÁy©¡¢8½LæÉЧìÞvfL+~Úë_.ýdÿÅ¡iʤ_Ki07µÍ}NðP¬¦)h·2þÒ£¹êÔ0UxK±ÉRT@må¿K ªR…ä 0¸"N‰,Ê8 èAkΫ„Ò÷Lv~sœ)¨K²D7¬Ì-Q­X!×p9¸ Ñ›H1€T†£QvR0+Ny¹8fLO• é&ï¤ ”œp ì]écµ™VÙâÓ} œÔ€:&ùD£>㥾J Á{B¦…œ©J#€S¼µÁŒTl+IÔ~zÇm¿•Œ%kÚ;ÅÊ”yÈÜ¥?©ê· Ær–tÛ`-A˜Ü¾ U_À­T ÿ†Té>—§Ríè*£Uƒÿ(ÓUäú‹UJQ-D œìެ6@Œ*0l Z0„ ¦Y`@¸ƒž)²`µpZU°<;)|3"f¸„ l\¥Á N+_‰`‡»@k[E”Ý*†4ÓàøÀF2hZ¬XZÀQs£j„Épªƒa·’QB¤·]ɬðÙ¦V»Í!4QÌ[Ay'©OÑw´Çãè”À(¤@·Zˆaõô=4G¹¢ €”Ýgå-Ú­žMî1•jKò¾™¼ç…nœ«kÝYb×—& fQ½Û@Öyºpæ©U¯ÃC>`‹%°ÅÕlP£Ô¸Ò5ªéêYº͈P ¥`#ÿPÆ,´)¹¤”b £EÀj á?èÀCü(X?0L ˆÐ#\bnEŠSÀ â«ÆÊ*RP¦X ¬íP£»Ú8ÀD Ùør¶#¸¡€8>! ”b ˜A°pŠЛ˜Å»{™v¢Õ£˜òž 3àÃÀàƒ&|¢ ױܠÛr§¤xí®Eê¦@EJø,¼÷‚`Ù€tÜï’K`bÄN‘ øÀÝ5ˆÔÄF0J(¢áøùa™ß¦9@Ä?1àZæÿX»÷‡Ÿ¯a ÿÈÔS _ÉéPwdÑÿ-P¡Àl#Ôî ±»ê0D<` ø¼ ×¢ˆ[öóoâ­OCæJHñ™»‚2êw=¸H9;u¼å3T¥{7²~©†_üäµÂç^Ñ2¤Ö²Îdã©È†ºªñŠ_Lc4Àì§ñ’±À—XÂ/?дp aXÐBñY‚ÀÂ%ŽòƒèAùÈ×òe'¹­‘ gðø9¨ˆ€(h8x9ð‚5è‚0ÿ9ˆƒ58Hx$€W …[a)@TØ0“ Ô9‚# ,X@¸|„P-È(€Và„ ‚и°FЃ"`¹{atÐȸšC‚P¨@;FØÀ”8pP TÀ9PhÁˆL‚)¬Â+ä7H@.À„+H4CR0 `B :èƒ>À‚à‚G€d.àƒ °\°+퀜Ìã³+2¨Öb¡Î3¼š*º ^ê ;ù¼Ä2›Æ4ƒ¼ACÿ¼¦ºó²<ô¡;Ã3ïp^ëG¿ÀȈÇ@ûñ¦»’#x= 7ØS`«‰œbH¥˜ùª„X»»£9¢*@šû9JØ …ë˜Ô²%Ð É»¬9˜ñ 9Œ‡©ðIªÔ¸'À‚µ³‚”àÿÉH(‚òh+H‚&  ¤„A $1¸AZÐ-´$N€˜ƒh‚`ƒ"À6PØý¤ñÊzË;˜!JJ8J#À„ ÐÈ€½¼U˜Ú)·-0Ì¢òJŸÄJ0$+PAzÏ´PÍ¥$d\›ú"T¦?+¦Œ‘3ÍëEP!¼Wò©¤špB§(’‚K耽ø®’†TÇ@x…X¸†Ø{…*°†pÇô!¸ È„oè†o`íw4ƒ°(X48ø5`//Ø‹™s«lÓ–|œƒ8¤xƒèOg9ÿ…°ýìóþ“¿¶BŠØ‹¾ PHøHèP¾¿ŒÜÈÿ{Œ‚±€R˜wѨJ‹ƒHÏB¶ ü0dC…9`°£‚ K]ðB"5%‘J¦T…0èð.%ËšcOÊ+mϽ« [8…+ øhIùrQ%к5(9`….Søø€à‘HÁ‚2È‚«¡™%¹R`€S.¸UÀ„Hè´#­?…Ó>@$$Ý„"]Rpƒ(SÍ܉“³7D­‚ÜFí!Ì»Ó$˜J€¤18ÈXÀPøðàHĈ9›{RN[í3BÉÿEÝ|›ð².¦Š3èFA#ÆÞôEjE` ¼‚2eªñêUfõÕZ2´nÁÎr2€’¶jyCkø.P† x…›¸kˆ‚[¸‰TøØ€dPJuµ†:hÇ•$Ø1ø"ð> èû£€Kð5dÓÎaS å)¨«‚3°?$X€<=…|U‚A°> ‚{T6ùK»À‹ÂÉdyÆx IæP3“"aQ1‘<(  …{t*eK苜ÌOmHÐ8VH¨0A‚ÂB50Z`Â:° ‰°s Ø:À.(S6¯–ÄÚtLÉLôÿÈŽÁôZUÀƒ@8ð‹ µ4b&xPYJ¤õÒ6H8PÊ›€¸-÷È‚WðÌ Á7HL €ƒÁ-ÅɈS8Z -˜ƒ@¸e7 Ù Ñ\ h*]Ý¢#ÐR8…&¸íðƒÐˆŒ+p]Ù1·ÑÍ/!¬ )…u“<гFYäÅŽ:VÞEÎ\żÄsÖéÌMðJ”c VâÖàNc5N;A+¼2žt¾Á᪉(°r†l@ ¨– ×>ˆ‰™hFÏg †ý˜ÊŠ¢p¡ÃO ƒ !G«€„—“Ȧ¸ˆ` (Œp+)Q+ ÿò³„K€„¸˜ ;Hº ɾ  7x _p öĀ‚Å0,˜#è!•Zjˆ13\eî %ÊF¥çRéÞ~¥}jÎ礭_öhZ<äDFPÚ˜VV%¹†nëâÕÓ¦ÖŸVí zÎÖÿ^ "ÞVÂ.kMrº«©Ž+®¨*ÂŽ ©¾p½ç¯fn8æÒã€pÊV¬'äF ¿2qWIf›­?+ï|б‡NeOÆo³>(]í¢i<¸..ÀÓpñ*lèÊëðȦ ’ª“ÿï*[,e ð‚©cŒ™T|2òª§{VE‘êmÑæÍ_|i¨*V]†ðã$³ãMíì ë$gà €ëÁ[-±¢Õ”A€Âº‹u hñSñ,Mî«6î'ôdUÙ2‹J–â!¬>žCÉàò–REFYï䔌S¸¬Lg-W./“±¿{ÅG¡Ã&O1ÞµùÒñÿ‹N£8­Ê•wN?9²<Ü óÿQå¿Ëë¹~,yAõ˜ªU¡vŸb?oÅ¢ È­Mïfïè|eâé@^8ÇìÕ~ªWª×6› תàÆ0 ;ùZ-2”ûÚJCI‚þ²°H00™«`¾®þ°v"Ȱ Kô‡'ï¦yœæpΈâ0hj°…2¨„T/-]‚Kh®´¤‚Û xwßJù¶Ö Ä;!Eš¬gוÀ—".Éh…zUšQI/(u‚ó“)Ù4¬ îH²é;± æaF†îu_öPzmo²J`—òš$èÿ2SÏ©ÇF5ˆ3ºäBþb800‘€;:#ð2ø¸ƒk#к)@8Ù¡Q¤« ª#?º‡c€?ƒå €¢¸!Pþ ³ûº†~˜ª ¸88iX’£ºð»ƒà7‚!¨8xPþß¿ˆ&µŠÔÉ €6ø`0%N€>ÿšL)aA¢Ÿ53œbÀg DX¸‚’" #†™Q , `dÍšO5®òS¦ÃÈX¦|ºp§K oÎà&Ä?¬>yZIÉ%D‰M>õ@xªU§!&r鄇 -äA`bÅ ><3Jsá§|Š3$ž: B¥-}p(™k@ˆ§èÖéC¶ÇÚ¶ŽDmjqÀš.”ó}<–b‰!:1J‚ÄJ¤˜–R"ÓÉÓ_|k ¹ð.ðšwjþ&áñäw+g^œøòåª#GîÜø_ãË{× þü»ôëЯ‡ÿ¾p  @`@E{ö?:ø€ÿA„‚ŠDíZ*ÓXBC5Ï8ÀؼòË4m€œŒó ÊTcþä€B•ü`Ç%h, žzíqI%V(B?èàÀ –´§J ŒXâ~¨0Á4A{ëAE °¨ˆP@`•¨€ÃXèÑÀD¾!\Å È÷ÁŠXBÄ )®x‡O¸ˆr0‚[p¨ÔÁŠðAÄHšqæQ´ xêY \rñÈÃED“€r±çH/€ˆ ‘Ä--- A¡Cp‰Ž’„h ÇC4h DhÊ)ŸÚ¢€ –ˆÂʧêÿ‚-¼ª…vP’Ä+žZ0CV0’Á†ò¡Ê §„(7*h F GŠI'n$ØZì©–\ÀJ&äÖñ ¦¶ Šo%÷(X-§&ÑÛ_oFE«»~ðFÜ‹-zD@©§&bcÂÉŠ>Æ´^PhÂ&Ñ„¯ÒPñ½à‰*Óäº$à C´tô‘Aqy½ŒŠ…frh‘˃ pR‡Âo¸ €¸°"ñ¿‹jùZ0¬í€KÎ0-Á+.P3Ÿk0‚.Ô²RrË@ p†]Þ9¬v37G]r€7øBY3W]yÎeG8wÏEÿGxââEžxâ$°Àˆð‰ÞˆÖ •”ØŸ46  ,€¼¢L6ÓDq‹4*SÏÉi@Ç7ßhÓLL¬âŠ¿DÔ —œÀ9*@ãA¶Pt€€§ÔXb|ùpÆp€èíE°Ê1ü°ƒø`‡+r`†A"ðCZ’l᥇ÐC1æ ®ˆ4à#P›ˆ#UàÁ_O‚ö ¸á6Pˆo†à F –è¦*h+Â:"Y‹0±Т€€Ó¥¦ Z,¢ ‚Pà&#À!5°(zP»„ü«èÀþÕ @ .¬ j˜ÿ‰JÈ }X2¸.bCâºE‚PÁ@(ÀHØà HÀ )xÃ8H‹nm1ø [Á‰ Xg/ߤ Rp‰˜  „ ¨¢50B7N[X¡™H‹7PÁ„CØà†Äæ†0Fn` (ìð[ø!(v… 6± WXrÔ°&*!x%…èÅ1ᘀ¥0)!†!*d3/@¤"%iF4š°&”PfЉÈèQ åûÅrÒ3XÈØÀd^°&J ¥NUÀM§ U±FðS‘~ƒ¿ààd¢°g†é›Àÿ1T<„ãÛáÚñøÍo½èC%Ñ64pná¨u"Gžˆ\.=ëiÏ{Ú³¾+¼¡h Tp…$X#€D^ Ãuu°†ìh×'l€ßèÆ7˜Ñ¨ 0À(" /GPE÷œWHuÈcƒ¼$¿ì]¢b pŠý fÅ R ÷Ù!ùIO÷*1Õ Há @À@Lÿj¿9 ?°DFð»vV˜P‰€pOh@£§'= CZHA¨`" N 0åë7!I¡ÝàÂtÔ`ˆv*êd®ìÁ|`ºÒ  sáEŒà.Aÿµ°…¬`CÚÒdÆü€\ëˆ6 % `XÐåVÆXXˆ^€ 6^–SØ@”vó*2úL$*³œðŽ!ÎÍ¡`+¬±B%–]DM‹ €s1ÁÆOæ´“Žp¹ :@»h î…4÷¹Ñ­Ã£Nôá ç´‰p59Û- ¸ ‰š/ÔðÜ| 2ÀÂ&¬;QçÖ‚¼D 8|¸XàÆÐ…Ô¨Ã^®½´¨Ãq“K†î~×&&0 –³öªÈBî+¤´Ü~T HhAœ[,›˜’#0²."ðÑ}}ÇQ5ms&×Ñ;﹡†ÿë7zàï4Σw~GÍ“ÑâXŽ=ìYÏ~ô#"(âG—Hr¤X〨F!^»_XãuÂHÅ3¬>l ʰè0¡T¨:ܺp Do¿¢SÏT^ÿÀ”æõ¥! ‚3xÁ1ÍÏæªD„„/¦˜Ó_RðƒPzhˆÑp€éõ`ѳÄp†]Ç”~˜*¥-¡ƒÃÞဗjƒtF>  ¬˜€%Z@\ð`ˆÛ„Š'@Šb W „". a s $i6Œ÷jÄ)€U‰-L Ó–“pð†>tÇj0z‘ Xã:ÐAÿ},0¸&ç€ æ´ D LÌxíŽSÌñêüº¦HA‡å$‚Ó<h'´@KZ¬˜ j°ÅÊ—`ŸŸ|N B%‚~áËñ‰CÏ tôÝv !ŽêoþÕ‚7H@æ–`:°4 õ79¾‹ Ê IÚ]Á7ˆ¸†+¥-€|\E.Pƒ6Ø[p{Š~ô‚kYY0»4}Àù–lóG»Úm-(x;Ï9+º;ø±àí-BÍ dÕ~!ïºkB‘NÐ k¯ÔW±òÆKüåG—äJá…énÎ i¢ÍPà„Ñ…£ÎÌDJœA3´Ðz“ŽùAÿ:Ò\ÒR°?( …ü`¸HD¦Ù§YC,h‚ D4C6dCh@5ƒ5ƒYÁ,Àš„<Ã3Pƒ!ØÚlH]`µ ˆ p@*É\‚\µ9€]ºzìˆTBð@%¬@Pšþ@ @¶©€ÀÐϹµ /Pš²M• ¡%ÔÛÜ[tX)hW„@¸À@ ÑBÁpù'ˆ!°€2‘ìB±@Ç¿l °‚ƒ¸)ø‚ â A+X@ d ÐÂã•¶Â$]su,âãµèá@ÿ¸-´Â!Ž¡È@#¾á!‚F%Ò妆 2Á'¦AÔ: A ! <^'lÁHÌ g…€¼!ØÁÝ,:¢%À²Â-@02€ì!¢)²œtT‚üáŒBÝi€"UFw¬D äa+Ѐ(tâ'vÂx:€1†c6À“ÝA04-ìÂd£ô4Ú hÁ1&c8öc¨âtÝÅŒ@2®€ÄâwÁ_s­A*Þ32Ëjèâ.T‚â+€ÙJ$" @¢4‚—ðÁ0€œ¡)„Bs©A'®€ÈÀˆâ Dâd˜”‚¬ã †3îBpAä"fÀÿ=A}mTxŸúu‡ÞÈDyTùETMüt¤G±ßvtß¡ñv‰¤åþ¥UŽÔ_µ±ž›dXw¨%륟tt ¤•eµM ࣹGN@^@_:_‰åÔå$¡þÑåX&_Éb¦¨€PŠ`á†4NH@ÌtÐ[ÂßU?NœsPÜy%CÖÄã…!xufh¢eIh?®D' ×r´fMÐ@%Ù¦m¢%²äfêËBÄDM ÂiÞæþæBìæn^qgq>§h~“iÖs"˜¤<Bئu@ZÖfwçrЀxÖýÆn:$xÚ¦i¾#Lç]ÿì&žæ-å<§r¦gwäç y§¢±_øeS‚ÔS*%UJ%ùIqX¥SšDieM¸Ÿå$æ`æý‘åb"!Itg !ÄX¦‡†”/ü¥{ ¨_ª(æ8&´¡{¬è¯é_>榋ި…n¨YN€œ`dÖ.sœçqXrÚa’î‹‡š–‡ŠDŠ£ofæá )•Vé’"ب›<§SŽ(åPΗ6T“2iž)B̘šVo,eyÌ™[ŒèJpiw^æ•béâ)pRÇ Ý%™é¾é‘féù¹pÚiI´‚|A§eZéžò)¡z%£’)ùµiËiç™z¦¤ÿbGSBåEyŸC_ø½é§Nå÷5èhö(þ•¥¢è/HCîάÎjîLHqXÔGÑç©*‹ÞŽî({¨@«Ž +± k´e¨b«±*¯`‡~æ¾X*¨š÷…Ä©~ª´‚hŸÚ”>ªvVjŸm¥¶j‡£2è·¢kT Î|rëß8©´vÔ •Ÿ¥šk¤ºer`Р^©©*qœgt¤éE¬™NêrNb¥ -%„~(Ô+xÌg¨Îߺªk¦’颅‡€¨¢¨Rh¶Öijªh«Îà/¬TÂëÄÖé¹R쾂kûݪãÀßÖ~ßSÒ+Æ>(¼êª[Gœ6­wœPÁŒß˜º©L()5!‡Ò­Ä"*ºlÚö–W2©ÁR”[zíú1ìB¸_ÄbT§.šøuëºVÔ»žmFm,dž„±ê_ÞlDy ©XAgÞÅaL£Ư¢Û¯Þ¬à€$Ü¥Ð:+aÖ. æÐÔ.˜² íIÁ¨HHAªÐ­ÃúÍëï¶R n¡y„´fÀúÍàÕ¬‚Ì-à*¨‚‡Ó¶mTzl™†êØfMÞ"ŽRZ©£ÄiDp¥EÿyoÝR*áú¾Z+›R.߯,¦îø¶­‘æ/DßàJmyPS‚Šoã²ëtŽÂF(â¶o¹âï€êY‚Nlâ ±šÁ%ÈÔ®ä“NmàP)Tç]\€)É€HÜ(@XΉ\‚/à®ëÚÜ °MÀæjpø Á›Í«Ï.+Ðö,cÆhïâeëÒ%‚9¡e Ì# åüà „èÒb숎íûÊ€ »æ€B—Š„\Â%cKnE±mË]À £å›‚/Úr+â^«·Šª¨¶«Õš_ÞJl¨j­¡™â4åûBèâä1C.àªwί¾Lo¾ܽïqæiâJÒÿ&Z/?®Å..œ&°Å:(žq2§F¥û-±Ð›^aÚ~@"\Ad545ÐÄ5TC60ƒ›ärëÜœ˜®„xš2ÌÂ3ØÛé•PàpÎúÀ(‚°‡¶IsްA üî*ÿÐþ¨+ÏÀ Ôå»á0ý‚)ˆÀˆŽ¤ÿ¡›)˜‘ˆÎ;ÛÁï¾s L3¼sªH€3éı Ìí¥@¬À `*„¡ŒuÜt€J”‚ëÕÄJh]cèçù€€¸f`@deDñ'X„ÔzÍây `‚E€s] Mè\IŸ&c †ÑX4¬@ep´G[EGãFÿ|ÄBdt Û™ãFw¨1åî™ÆŠTorãö+‚†/Öšò)Ó™VOè+®Ü2îV+pàV°SkªøE5ÇšµÇ’­'s-(#D…欲N€œ"˜[ˆX‚Yzî[øÈréœN!ØÀê´NTAì‚ àÝBl@0äŽ6hƒZÂåPZœH8ãŸBZš¯3LZ³‘ìšÛ*Ô•tÜ¥¬;o[6û€´µ™3¤ ©Paõðv»ÝTíÀV3eÆeC© ÁAÿiwÓ†ˆ„Å%(”.i:Y·\“W€ÁöÅg/@¸×åWÜÀ'8YО& ЗJ¼¼s#”‚ðÝ3qg5ƹº&IÒ”mmÁ*Q(Á'Ø4ʱçx«uäôçR‹éUƒmƒmÃÊ+‘Ëõ[G.ÈZ0ädõ¹‡ûÚW_²¶;Ž9W,צõþ¹DÕµ] ¦èÀ=ÏÀP[øx®&<Ã(,¼B,\3LÃ-¼PUˆ–—kÃ04/×[q[4ÏAÀnh¯ÇfsŽ€vž¼›k3ð.=c@]á¹öE³)¼Uˆ`ÁŠ4€¸ÿÍ%–Ô`o+ú˜(B¡_¡dwœ6ýŒ‚+ŒÁ&$Ò;Æt®@@‚lcñoÈæÑ‘˜‘mŒaBnac|]€ À@-­#{—¥ÓxèÀBt‚¬oß|eݨÜ}—µY$˜Þ뀃àXœÁq¹_G}~í¶·û¨ö¸‰ï8ŠïxÅZnY—jüÝñç“uó¾»§ÆûgλF1ŽŽKðåÇxækñ™ 9ŸÍkîzëÀ]^ÁtZ…(ƒ¨=©E œZ*`Cü¤¼Z„Ìš5È—˜Oq@²&o‰\ z€¶í®ý¨‚î_‚Ëç%¶Aóÿ›¶A!¹1á%¸¿º…œK‹ ›Ï7ËÄ“(áYÞ aêÆ' hUÉ0B@Œ`°åBƒ:Á4&‹ *DP±€„HL(¬zÓÇ`€#^¸àÁV„ ¤@ªÎ’<ŒšpºÐâÍËP,¼@…‚'&.pYÙF¡O ´hÍÄ ‚ ðÈpÅ€<]Œ €+B„m€°â²”" æˆð`aņ'Îið0äÅ“)ONìøNaLjv~Üø³fÑ‹7‡ Ýy3å©yù5cÄ•A“¶M;´gݲg¹7nÖœS[†¼7ïÿË‘##§`,à°@ ì\’‚ƒt\`ÍZ¬Y6lHV-ÛÕ„YÃfq–õè{öŒ Æ0bWP°@€˜ 8&XÀ .iƒ /äàܰ %\€døa…UTèàp0€ê HJ )¤’,!âE ø1RÐnU~À€(v¼Ä€ðå€#)À…ˆ:€äGKîá ãh„!JÈ–Kn¨Ã  å€qÂ…- @—)6p ’Fð„ ?v©$C²`A‰(ÁZ#C “Ol¹€†\`†>úèÿd X°D >¦`„ Üt‚ &žaLEu-€0å`‚8 S?>µ &lYÑ$ØÅ5Œ(A[@d€NÈh‚– 2 ÀÁšs¹ÃJ;M2Ü€ã Ö/c74á,»¶ÍvóŒÜ8Kî·â°…÷Ëk)cÛâð$îÝy³=!ÓC-¸oÉ `uÉ NÞrg£ º ¤@â ˆNK&8€<"'˜ð5’ €†Ù¸A€ FÈÝnˆ  µ“.º‹‚é´K€¼è¢Óîbšo6 çwˆe^àgš…Æy:™ŽNcŽg¦ž«3C)”ܲKkC 2ƒÿÌ‚Ú@ÄPáZæ(hˆ$æîÌlÎÒ‰‚Gp!-Ô-1‘ @ˆ¡  ¥Ž;`6§ÉçŒÙÄ’Á´ƒÉ<6vé-weé]®aÍfXmÔû5=Ý}?;{aÉv3Œ£Ãî^ÂV½[ÚJoM6Ù“K]ßx«Láu—×·°ÒMç#äCN`f°ÖÚgb”ŽF_»£Ž$×ö3usGŒ@ˆx⊃Vûì“^àcŸ™ž9h›¡Î_D’‚ 1¥éÏg£˜öæW¿ìý Ò 0—jím$d;œqªç. 8Á Òb jHÈ*”ol#ë]ðºÅ‘‚ÿ4Ot¢3 ”àÜÉÐ^¯YŸA$××±0z°{Ýê~‡; Nfx¿)ÞŒǺäÕî\¡«\úš=ÂHÏ_ÔË!·ƼÖñëˆBÞñ|Ç­-*&‰AÉe½€%â:9#ψˆ–´© íÒøÆùØG?~Ã?)Üàb~&)€•P£ƒ½¦õiÿ›PÏòWýò‘ àžå‡1άiø‹=i¿ Ž«sÕ#[ú 'š}á©•SÔ!g^ȘòP¹%h—AF±Š±¼M sƒAÅ´Œ9€3Œ0k·XÞa—½ôå ›)7Èx¦ ¤aæhð5KÈÔ26´Ë“WØÍi–sÿuãüå0Wç0uR“›°i_Ü©Ìâp9àœMfÔGËÜ€Ÿ¹&/7s¶êm—e'ûåÂÜliÑáÀ"÷çHŠ.àÏøE7º±QŽvô£!ýª§P„<2:šDÚýG´¨ÝL{G»Ÿ÷ÉȬU§RP$üh±RÚ¯i<í$Ť`1íPǤñ<^?¿é°á%l›ÅK,É9Ð¥.³ªì4hI’ÍçåóŸM*U×Y›´‘t|-;§É®™¯z³¡sû§¢ÌœU]äÃjY•JEÍDu\æÌ!/‘iĦ„R¯IlR¥ºÔ{²Pnà´d虦:TabÍ%^+§JwáÓŸ™ÿMŸa1K˜‰à©‡†Pí"XËZ,è ˜DkƒPÛH@â¶¶ÕmnQÛÝÖ9ˆí$rû[ãÚ­]m>àÛãê¶°Uns , 7Å Bt­ Ú>¼á­xÞZˆ÷¼æUozËËÞõ¾¾çuïxk;ßø²×¾õÍï}ù»ÛýÚ÷¿à p|û+`ûwÀ†/yÛkÛ5¤—Vhîwk! ã b¿UDt±úRøÃ 1p»ZíÚV?€„Üàï:âÄå…qŒE„€žê2qkE@+‚µo¨ÁŒ\ÞX¡¶i*JP 'ըŵ½Âu$÷ÈÐÅÿ, ‰/DA@ñ ¬@S@ù»^ò‹ÕŒf7¸Èq–óœéüf8×ÙÎxÖsž÷Üg?óùÏt‚ó¼Z'q!Ìîõp~‰¡ƒâ>¹3,è@åA‹÷ tx Žü+€áWn³,8]ÞÓX»°xÛOÛÔÈPÎñW @…V "¸˜ÁyÑåÚÂâŒînÁG›NA-q‹:ÔaÕµÐÃ-lcXØ@صõ4#®0ƒV른s¸Å ñëb_ ²¸hßæ PXƒ!4…]‹ Œ83ª£,è;ûûß¿tÀ^pƒ|àWøÂÎð†üÁKpÿQ‹t“;z„´õÐîH¿aÜ‘™W‰[ˆ Áøk#¾ßV¿œÞ‚x½ƒ:8â5¸¤yŒ°8½pso=3ⶨ@E®e Çáz¨C¿uÛDÄ8>·x-ôÛp!3H‚L…°3B PÿB ’îèáÉ` h°k¨ ¢Œ„#èЃÜ<ÆŒX9raôš!€@âI®àæ IßyÉÙì 0$Á×üo›îpÏô¡ï¼èNúÒ›þô¨Oýè Îb\W<‚<*nAŒZ `ï°= ?9 â X ´!î-xVËYö ÿ€º­ éÿ½k×Ã¥½á— =ÈØ¸@Ã^þÛ6¸î 'fö-*ÎÚ®/ƒˆ€ P[1`Ü·ƒ˜Ã¦e±1\µé§!<¡jzëá~Àør.½zk¶zMûPAöoÉÖm¸ A VmÖ b/ÞjK¸À".`Aj µrÀøXê8¯cWOW[Ð_ lµb œ„Ù.rNoçhÁ¡î"a š.Á¶nÍá :à!í¬OÓ| å€‹n! lPótË€KöJn׺Ä8ÔhNÄVkÖcÌp¼šM×,NÈX+ý(€ÿ^áÔÿpK ¢ ÿöPf Ô´0èý`ÁÝ&¡ gÀøæ ò~ë o¶–û ð!ï/·Ž0¡Á`çî-æà Ä “0OU/W‘M0_‘k·¬èrÍîpðdÔX‹õ/îlàiNúü è‚+·š ® õíÞ€ËMQ·\1É‚ è¸O«e r`êB¬ÕÊ'¡ƒ|°. dÁñÌÀ ýT®¢ˆaá"À(mÈJ ´ &ÎñNnM®j!Òè+W ýðáØ¢à 0 ”Ëp­ËRÎÂxo°c‘#;Ò#Oð#CR$mµ Áÿ iÙö×LA /  €aØq À Ba*¬gêæL]2߀n âpÇ š¯ØÁv·Ö€÷B¡ÈÒmæzÒÒð1Z-÷ €¡ï&¡’®o® ¢`Õò. Äís0*¸€ ’€ô® ¸ œdö°ð+£àö ¾/7- n!·ª,©Lö¸²ïMÉL¬è q$3S37$93¥ñ+sü*.‘¢ éhoV=PS^Íäàì2!qs "€¸ '_ËxÀ7±)Ár#I¬ßö5ÉÚÏ,Åkÿƒh€˜òİ’#4€g  gŒÅL<NAÕŽPûØ0óR®áO­ Srß¶P=“å“>ëó>óÓ>ñsàÒ Ù¸ÓëÜ+kë=ôÏk12ÎÈQ w+¢@|Î:Wó€®¼Ú€$®É„È1èñ¶"Î*Åë<%ÒÏ,“íëó¬0ºÍ~ë¤ó8õÓFƒ p´¶v4&~”GY+¡¶ˆt&¾´G‘”HyÔI'ÁIƒ Üœ´Ü„4GuôJyÔGtG…´I”IkKI‘”¾¢TL£tJy´J‰ôJs4KwtKÓtH´H‡4L—tIËÔÿL¡”JÑtNqt?oÔMƒ`â¤3ÊòÅÞÓW+¹&ôübêæRA­’ÐŽAw ;ÀÖ a"¡S•L‰‘êÄ!0 Í·Õ‹•ÄÅ›J«¤êV®šGŠr¬D O®–oCË–Òp/+oO WŸrB³ S7¬ÒçqIëpc£p)wq¢q!×o᪅*wŸü owrñ6sJru‡_ºJu —tU—3.×tCCJ7®^è„¢)S+°¦J•V)†Ë‡Š]I>Ã˜Þ ®ª1ôÊÿ R`YÔe.  ën‚³(ladà W¸÷87t<Ël ëu>÷tuÂ|Ø—x17r~;7}#+réÊ­Zw~×sí—~!«où·~8œD÷vã·Á ^üW€ ÂvÕXp X~g÷ã†`tÃkµ}Þ Œ6ˆ)1«¤¢©y‘©‡,‹|)oÑ„˜¬Êv\0ˆ«pL-xpéʤ  j MÜeJ!P@†€fJÀ´`á š˜Oê ´e*a ¢`d` 6´nM` P@XÜ&ˆÃl])Š Hª~WB£ˆf錢‡w`F«ò%ÿ—g…ØêvXmÔÈÌe¦Òå‹Ú*ŒÄ®0ܤ‰5œÇ6vGyª‰é˜nQWÑG†F(»¨w+¹–¶e`YŽ}£Ž­N÷x’G'yœÇ…Ý©”•'m6åž^¦‹‚Ø>A¨^Á %.@Š r.#+¸ÀZ)a7`âF4à,êàmž@#„gŽO™‰R¹“Õ8õ¶çJ±h^´è› Ù‹|ã‡âX‘«H$ÎÇÍ(ÓÈ’k›YY•õŸ•Ç•Ÿçé8 y…óÙŽï–ÅÈuÉœàß%¡Ù”—È÷ù‰¸Ù—†` 4àZ,@ ø€ ÿ4ÀÉ‚  @¦`#j¾Ï™_` È äeTF¡†`”ø]Ô ›'Úž+Ú“»™•¿™“Ãù•é…œñx cÇ¢ÿù ­I‘ƒ\à^Úvæ9›)ZœŸå…¨¥È¨õ95’Ú9Ì™›z•e¡¹ºœ‡ª«Zž &«z«•º™œY < ¤ai>ˆG!ºš 0 .Àµí]Ö×zÅ ‹Â•§ß æ¿^Ý›H5>æßý•­ä×ü×GÞÐ%âaGâUžâÑÝå×èg¾Ã™ýÝýٞͽ×a9:ƒÕÓö®r ÄÑÕÑ ”/yÛ]ýß=Ö>ã 鯞´s=ä›^ª–>ß³h߾ؿþ`.^ìçýÐg¾ÙÅyÑ™>ç§äÞäO~ˆZ|âç¾åÁ`dàÒïüêO½ÑS]ÕÛ¸¿Ãë^Ì1ïA[ï“ÞÙKÛï^瞟ð~yV¾ç->óïÞèó^  œïm^Í#^äçýíÛzªë3ÿÌ#ù´£d ê bê1yQÏo#_ë÷;ù»>Ðó‘}ÌÇþèÝÝìÓ¼¶Óþïžím~¡áS>õƒ‰Òèa>öÉ^ûƒÿóÑçE÷Iÿ©UüäQaT_Їþ ;lintr/vignettes/emacs-still.gif0000644000176200001440000010730514752731051016331 0ustar liggesusersGIF89aþp÷ýôäýõêüøë÷õÛóøæþóÜõôåüîãÄ­šíéÕìùìÝéÜœŠ}åúôèÚÆŠ’‹íêÛûìÓñæÕíöóüíÜúõòìë㌄{óùìËÄ»v‚j}†q‘’ëõû„}täõý|~u”ІèäÉÊÓÈÚøúwˆ“ƒ‹’¶¬ùè¸êì¶ÿôį‘8²«sýè˜îæÖíæÚäåÜñæÚòéÚ{‚|óùóÓÑÄÓÎÃm‚Šz~{u~{u|{‚‚fƒ‰zv¸»¶íõììùót…wóõóíäÌèÞÕ×ÎÅäêÜäéÕœŒƒ¡„èæäóäÌ׿çäÛÌåÔ»ÜåÜtƒ„œ¥¤Üêìëúû¦®´Zv‚ÈרË˽òì㙣œÅÍÓzŠŒ¥ª¥—š–ØÆ«‰•—³š„s„‹gtwøèÉ©³ª¤¤œäôôçôæ×ÖÊääÔ„~z¨··¶­¤÷îòó÷ùØäׇˆ‡ºÆ¹“†zÛÚÌ»ÌÄÍâ甌ƒ‚‚¸©™¥”‰›£·ÈÈ‹ƒvÚÓ»ËÌÃÄÌÊ~t˜”й´ª©¥™’Ž’ãêäãìëÇÈÆÅ½´z„‹„uäåâíîìÆÃ·ÚÚØ“§”¶¶¶Æ¸©‘~rÜìóÜÛÓØëôÝêãùæÖãÞâÄ˼|‹“èÖ¹þóÕſįø_tw­½Ã†|mÓÜãäÝÓØÊ·š°²˜¦§Í¹¦´Ìσ‚|ºº»úúúuzvµÇ”ž£ãîó¢§óÜÅÓÛÓùùôãζˆŒ”ÌÈ®ÉÛ㡟 ÔåÔéóÛusj¥—‰Óñí”ÒàǶ”ºûûÿôÌÇþùóéÕ«•p”P˜¥V´òðX˜“ÿô¼ÿô³§FÊ´qª’P’•2Øç©­ž+ÕÉüù·•=ýö©øùÇ‘m·”FêõÈÓÊsøëŽ¢Æ¤éרý覸–X}’O´©UîÒ“`¡¨b½ËþõšÎ®P”—íÌt¤lUâ·JÏŽnéäpħ>ïÖ¯ò³™döíéÒla_§Ñi»îi¡h¼òrºêhœþxl¤.' !ÿ NETSCAPE2.0!ùú,þpÿx A8Ȱ¡Á‡0X @ć3J¼h‘£Ç1‚ÜHr¤É“%Sª\‰²äB–0cÊœI³¦Í›8[æÜ9p¢Ä—<†ÙqåP:…õ´iФPŸJ:µ*Õ«V³bµŠAe½y_ÃÎkEâÀ]}îÌȉ5µ‰tš¬Û3l åžJñc…¿Jµ LxkáÈ cB›‰BþÎZE™2¸@ÅŠ%;`É50çädËX±9¢™upÙ 2ÅžÉ-*²L虣(ÞÍ;)Pýƒ œ¨#È‘++ba–İô¢ß«G6SzV@˜¶ƒâLµAÿ3–-Â]¤I€Mš Ò\«_L›¹» ¥i³…ž€ú÷œpR |ñ äÀ ei×ÀP‘S8h¨t0Ü…f¨!prx#µ1ÙˆËa±CöhöY!ÂA¡uñ¡!È®hgT,ИcŒ1}lD.)ã@ŘÆ¤àM’›ØbŽÅô¡Ëè€.ÑcÍ/œ,E¾89…õ†¿Y¥u¡[* #ŒtPDÀh 2‡nìŠ`q†À»Á‘ôÄ&pJ÷A§BÿG¬6DÎ2d( M7Ó¬lN4¶|´9¶ôáL6$4s&ýélͳÙà<3 Ï8.ô¶o,xtYIàÍiql±"PÂ$¸¯„mûí¸çŽSc ¢-°*ˆh¢D”VZÖÜSt†(2±ÝHÌ'Æo8òûrá*èÊ´¡+þÌ0ÎÄf ˆ÷ˆ•؄Â1ÛpÓ% Ù,®òèHÐ}`ÓF@/1%P˜W S'„O©ÑØð¥»¯)ÐÂDr滀±mxoKÑ=6HzŒ£,‚˜XWòˆÌ º€ÃDð!Ä;!B‹HT@ AteÅp4bƒk1,Á©]¶}Ù#ÿNŽÙ‘íDó¡Å›– PAj¥Xä fÆO·jç«S€ j¡  Ñ€w+Ó"v?Ø\p C!yCÞAÅ Ñ Ž éO‹ZJ±´3¶;-‰Tu6|§!_¹Ü•ìV®úr¶auHʱ­ã‘Äù»ê¶å´sÁD"™ƒ8!{T‚¨ÐÃÁj4¤EìužGDà?to z¨6udM$Bà |㉛=w¯Ñ=(Ïö¥RA+e½[˜îûCa./É¢ö²`s`/Ø0@ë@ÿÀ£·xÇÏ  àCÚ€ÈÀÛ k(šz ÆFž…OÐþ"T¢ê@ÞA•œ %Pr`£@[2ðEù|R|¨'µ³lÄ·U|îU…†6Œ5mŠf{—c}Q†¡0] (p0ÍpÀ -ˆÜ0 € ` »p › Ö€M,ƒ¶0Kj NTÉð e`ÁpD¡ İQ(¶ …ÅàÓ$ʲm'Ђ/ [ßpºÀ<ȶðràÙòWIp&T‡zæÖ5|¨/$‡wü×'XaV|ñ€,ÿ€…À,°cDð øhLpAœX)„†PØ`CÀ›@ ) DpsPºðˆ'€Ðy€Š§cÀÈ xQ‚AO©Ø ‘XмˆCpcŒƒÀˆ‡fLˆ–•d ‚4a3–r†eHCÑÐ ç°Ñà çø æ¸ìxŽÑp ëØŽÎÐŽÌР̰÷8ç˜ êèŽíxíø òˆŽíèðx ù˜ Í ºX3D ™ ÙøˆŽÞ^ TaS!7\)ˆR!_†fGßaŒàŽ;¦Á€ÔÐ ìÐ(Ð å  ÊÐ5ÿy“9Ù ×Ð:é“(°“Bé“8i“0i”59“Cù“7é D¹“Ì Ø’LI“@9”I`Z9ˆ!yÇ’™Õ`w‡6ˆ†AÝå]öÀG%&LøSÝtZid^ (‚¨P dût’\‰ôâbÝR„–jÉpà~à`#|‡;½÷}.‘FÅ~ 4ÀxÕyÐѶ ‘‘à™“])6—YƒyPgH?ˆ—†Õd|)OæU à!a[ƒ¹‘€ó´[xr'qQ6B`g}a–Aœnæ–lð‘‡]yÖ(M“1HCÇÉá Èá-Á uÿà‚„1 o˜³s@AB%°~1^ts€PKzÖ pH¥›)æp€[Ô1âg{©E’¾sh¡Å–!R Gr %°‡©j:0iœ€j™B0vÐ.Ø* ¡LÀ®°ehy]”i€ %Ò4 f@k×kãr#lJ€ ˜@ØBá¢Ð7r¡@¬Ð[ƒo *#¼ åטLB å·™ïy_}`ƒl”©IC¦sñj1.Uú‘Ƥr`taR12„OÀ$8›¨¹—…awQLè…–+R€q s3/ ÿw .@.×—¦ 0 ‹ ¦{VäupÇg:—F°<§µ …0p@‰à…02 IúªVp”àp©qApÈ ~ÐqF€ …@]ðSÅ¥¯J p«¨º™j`©d¤0¤Ðƒ°ð,T*qG>è s¾§{P à‡ ¢²§h€ÒÚ¨±@.pð¬DÀž|ƒ*¨8hd9ë)g² ¨~ºµYrmcŒyÄA{õ©ëÅ0ÉóubÑó.h ƒ©AuV‡u€ :öV},Ts¥uT°k`¢5PV¦°5°­à6¢ë§ ÿ¤±WZÇu  Y@ °0`Ÿžp–àð®ð± CëGs5! LfÐz|r ‹ Z¾—¾ ®@~õ V#y@p±™ÇžI°\à\6PVs‘1ƒ=2ôPC Z0àW _I°‹R~IS k¨»)Ès¦ix¯7©6Ë{m*PzhªšÐuD1µ x®;G¢ šÀ¢0/[ “v4Žp·*Ï WzuP ©·¹å³²´]}­Û02À²ðE=!µ|Rµ!¥3®®wfêJ®a:œ@W±‘5m›¦#@º¦;Hjÿâ˯ÖùŸ2„x]Y¸Ÿiœ P’ö¥h[â €Ò¸±£oLê7”z^í€qÀö–7Öç€$ dÀ O0¨D´°'Z!·ºmðNU'!ˆª»AËÙ÷0àï²-yxÙ×Ñ›k0 ÷E½¸tq 6„1^P£ª¿¹° W #ñ†½Ž°—Áµp =м!¢P=OjsÁ¢ )sÊÆY"I¸Z)–u%Nu5‡Øº‰¨ I*m¨1cÊÂmy†Ð« š²‘,Ø‚¤´^à|ðàg „LÈ ·ÿJÈmi£Ð>;¬Yšƒ*WÐl°ÿŠs,¢‚¢l ¶°)8X”®VBPp˜Ð›oŠð¤\ê%äixyc s± ¥p7qçf7à‘+!$&tBEƒ\`ê;¸aƒ À| š¸O…Ʊ·Xµñ `Þ —ÀÑ(Ÿèš¯˜Ÿ¥¨Î1£Î}pÅœ¸%¹(›wÉf̱fy!Ctg̉œh1œ©$H{6O2`ŸIlɰ ¸i XGÑWQP»R` ã) Q ¸Ê|(Cì6 ¼E"ÙÅ æÒº@‚а/ÿ¿`¨·å'Á` å˜ÉüX‘yŽÌð@­Þ ʰϼäk1{*ȰLâµL­ VÕX]T *ܼN=ÍËOÜX_m˜ »NcÝ–§)c¡Ïr”U9”Ý ×ܰ”Vy“âX]í$ ÿÇ_ÂO•ðÀàV×_ÿÕ_¦ÅŸÁçÅŽ­»dÍ©œ JZ‡òŒÝãüzÉÖž rð¿Á éÓ¦]Ú)!–%Y–Ú\);žKF™}ÂöIFd>É*±£"ZÒbýØÀ^`¹Dð´c)P¤mºùÚqgô ½`2gñ‰¢p¦Ÿ=ÜÔüÛ­ÿ—ÛM® mbüQ”­"õÕWë"­,qŠ¡¢Æ rü¡!Š½Èˆ¦v©ÅÁ½ß¨ÍÝêYÈåyÓ‹‹FfD±.iÀ¨ú¹Ûb±Ñª«‘ëaŒ¯Ä1ZLÙÔÖÊßÞm;30f]5uùµAj]à ¦ã¶q` >E Bh'=ôd¦t¶úá;’ûb$ÞÚEl´Ñƒtc@µx¹OpIÃ^gá‡çuÏ«Ï0íá[ÌãÆ7’…8ÙŠÆ$òë{¯µ#Z tè·¿EœPoËͤà€Ûa ::ŽYWŽåwÞÝbÍá˜ç<ÖeMAg=}¶å ê-Bÿ€²»ÕlÀ 7 Ûa `B¨@EŒœNl²lBd(ÉüWú­å±éß=ŽY?.0¬íéí=%*m€ ½%® Ñu å–H©=PÀ.~Q†’€´r±|1§MêýçФìj¤Ú4âÉ «¾Èä±]MÕ`ÕʤÕ]]éwømFaÜ»ççÇlÌžì‡)Çm’‡gLí¤ÁW÷וPñ„Øõ~ØÂÀÁbîÇžå£.ð>§~Íæ]¨å°N6ü¼œ÷Å!Ó˜ÇoÜ-µìz¾Ö¢^êRÖcäÄcÙ)Ñ%¬í2·1Y·¹ÿÖ´/¿•³íñêþñ8Þ?—’ŒEòh­NPõçg0î$Ý?ÐíÖü‚Ýyq â°pS¯pÕ»g[¶0õÈ®óÿõVqð& Óþ™úÊ  ¥P›:”Ê Q °¾- BšÆõÀãâ°dÀÛÀ'RÏÜ Ÿóçžîîň«ê&ÏM\f­k°‘ŸdG„À* Ü,ÔS½0žÐ\oô‡†ÿ^ßú„HÞ‰_[`‘Ö ´¥‚а§q UWïà±â ¾}·âÀ_¼›P ‚Oøgµú¬ßóÁ ð‚åì†æYÿ¼ðvµöK½ñ¨/U€¹zœª•àïYàíàïÒïúOÿý^®øÛ¬  ÄT",ð‘¥@€Bˆ¸5Oœ&S¦ QAâLjDà CT$¤'¬Èc†8ÓæM˜7kæÄÙÓçO AyÝ)T§Q¤I•.¥ÉÔéS¨>µ™ ÒUUª@!Rµª–66ë½W–^½V*}FšÃ…-8B$ဠ ýH‰_…$jùh2qr! "Y&ÁQ%OVX”òeÌ-gæ ¸ógПQµ ‰kÖ¬„$:Öµë´@W+T=xÿíÙžu¿ð“ ìbP @˜0&†f®»yÓçÑ¥;Ÿ^:ç©T±¢Îê5¬Øy¯Ç¶ryýrÎ%|‰óÅ!e€—2›·½>ýûùõWß¼ÿröÒ²e+P¼ã+¼z̺­Žð㌄Jä9†"X:ŠÏ?þúsC5„3=ópīä*«¨@ ‘­ÜøŠ¯tÒa'Fcb̆š…ŠL3Bôé; K´Ã ‹$‘H#‡DrIÿNÔn»¬qÑ‚ #Š‘wÌyçtn¼Ð¾QXÃ"¿’ä‰è6›ÇˆˆD•2™”sÎúޤóN¥¦R JÓ Ì­©·ôf¤ñ©&±ÿ‹$Õn+Ó#"  ¶ù…&Ò8´)¦x48¹4ÇPI- >vè€ÈšìÄÓÌWc…ÈUYÁ$Ϭ¨b¦@%T™YyjB‡ ¶€b’º€¢ ÅBÔ`Öf0E!jw¸v>˜*q¥Â£è¡Ž…C—¿a‘Fª]#¾H\ù3Xq)­UH¢î…UI~õÅPÏ¹ëª Þ†º²×r¼ü’Ç4±¢† cyâJÔX/b¹Áй2yâc,äÐÂS˜|‘‡q Ó9ùfmX–EH‚f]Ž€bd+f¶KpG‰' øÀ_¤“Vzé¥Äu`Àb,'-Ùaÿ'C6õ‚€&‚0#ä3и Ý+xXCÊøã†µ‘0å‘GB`ŠC¥qäÎE²C` 2¹¢ +Œyjo¸¡®¦6Qœé`÷¥ürË3äq(Z…"EHTT¥¬\¬²Y‰b Ôœ Ý-p†yàè$èø ãðŽ=iÄSJ轿4Ež ä©§—Pù–VþæúNHùB8ºð h§Ã’%Nø¢’‚gIòU1ÏñòÎ7ì¯}õ1w+¡&À²T·zêt =Òd¯1*d·SCî$w˜4¸`XR0€ `°>‰TâùBF>À‘Í)äh°Ë6ÿè@"€%1¯ýBGãIõ–ÁÌÅO†1d•HúECÿˆB.;ÍÀ”ðõ @uTãRÿ²Ĉ¨à Á&Æ`Œ~ À&¬A|M€øF(¨ø‹bë œÌš~FE¸`!^ B(’ 6ô`y舀¾âmLgˆÃ?RCØv¶Òepˆ[jݵ€K°x‚$+@I“›I&]p4›(„N@F#¹€c(Ãìx‚X8k”Á °Q9?¢‡¹Ñ 9H$þ†ÀLš“x%¯üB¢ê\w#Æ8Ç ¢ÑŒjÿž£ÙX3°iÍoþâ›×<Ç5¼€J¥¨€åô&7µYMqV3ÞˆF2„IL_Ö ~÷ħ>“¢Ã' ̇Á@3 ,Æi*H2ZPm8¢ÒèÆDª T´¨FG ÀÕ(G©qQŠf2füÌ'Kû)Ã}jîNóïšÁ±ØAãQ .?DQ[ÜRà„4pô‘YÌ"M½`‘ø™ gVÂá–CéÒ?Æ´¥/Ý*W=ǹàÊO»BtºSÆÆ§x‰4˜aTÆ Å(F êØ<Äøâ^š“"Ø>Yøf6Q ©6A°Î"“’la éhUÿ}’õje©ç­bU`k]£ 5õCœ(j8¶Q Ò’ÃÒÌÅýHÈÂ3Ì@Q¸ùqpЩ))¶h iÅÁ¼ò4 ¶“É)ZR¼Ç&àß,ûÜÈB÷34Ø”*Øô”­ €1Œñlp"ÐX­1Z«®5xÊP`…±ÒЇs…,c8pon—Â[— CŽ)Ea°éî¸ð!FÒÄô7ºÒÍ*V¬V%³n Ò#±ËSÎ}(×°Fk# gXcjP¨'x@è @±†Z4kf…hÊ)r—”/8 €¸ <´ÈðÅ8ð»ôaÀLÿU*|<ÈÂÊQamQè*¾ü Sg¹ÊLÂ,wi]Ñ~–c­’ÈÁ c„·äXÁ XLIª˜^`.ˆW(pkJ Á”Ò¥´D¡KµVdäí¶ãDJa’2)ÔƒL–ÑÖ@åARöÁk•©–·|ÏBâÊt×½°Z#lã!4È®¹Xa8p6Â.›u‡ BÏswðë‡Ø#([›…8¨Ä KÎÉàˆ pp±3½iOcû2Ÿ ¨M¹’Ì`àÂeR4Xðhà‘×Hï‡j‡²0$2`ÃAP'‡†Ð¤Ño´#íï' ÙE€áDÿI€l•¤àѺ­ úxd&Dá ×ö 5ýW+gÜ>í€ ú4 Dž"b. ¹¡#‚o|ƒ®T ÖÐÓHT°26žAàr$°A.;~àS.جâÌ1tÐE¹ñ˜9ÏêÅR $èXñlC=ê÷*¤  rÍ*s3ã6u0±aŒgPã°È…4R *dÒ¤rm'*¬´«ˆ¥]ðˆâhŠg8Ãq’#4ˆ$ ¸æ§>=uÄO6ñxºøágbÌz;©2øñNК]ûVj íY/x°žVˆC¹ ±ƒÓÓ ¬íK 3©ÇþÚ2 uä¡Vùû€ägé:.ëÿ¼E¨É Zu> àƒ*°a󬡯o:ú²_üd¨Ë"Dj=&\ïéQ–?0W_üÔ'ÿø9š°ŠšÂ¤Ænïñçq $„èy±ËÏiÇ›ÿ^Ó¿s®ÌDÚœÝ3¹‚S¸Š„ˆ0h…ôé?ýs@ÅË?}qѹŠNð“ïh‘à>‚›:P(û{@Äþ+Á&Ôè„Ó7œ*5hC¢˜=z5Î Á˜‹c=DAìA%Ḡ#+‘8+Ðr?†‚Äá³MàX¨°;A „:),¼*üAø¡®C’’õë,¼°ƒ=˜ T¸BüÃ8,ÜÁÖë´ÿ)¬në8õƒÂÜÛ@Ä¿ s†¸ @,¹£B4”ÀØ Ä5tÿû¶.@²3Þ‹Á˜˜à(@¬ŸÁ6D5”=ø!ÄBŒ=!\A­€„ð³ ®+¾pyø½: ¬&„1¼ª+ëÄ(ÄDNLÃZdÃ4¼,.‹¼<$‰ô@öhÄP…#àÁXüA‘Egl©Úó27°—œ0B³ ·Í8>‘¿0¼7\ÆÙûÆ[|Æ‹ë²ADíë,‰Àup|xÇwŒæ0(p|¬ %˜GÌrÜ¿¬q¤ÅÚÅê @‚G|ȇ|xGuÀ"Ð#)Ð|tjüÆÿ$H÷ùGŒÇ^êªÿË>ÎÒ…dÈxd¾ˈ¨HVPF@ÔÈŒH|F—bƒ¬)D¢’lH|ÇÀAXÉ  HÐÁŽŒIšäÈË1ǃ¤ÑÚI‡¼„»x„JÇɦCJæ˜I¥ÔJdJîE˜€J|ƒKà>Ø•dIGI·<Ê®„Ë\|KºtÃʉưü¾Ñ ²Œ‡Kp ÄˆÄ ¸¢ü4®¬Ë¸dFŤn«€! 7²4ˈÕ`–tÉÅÔ¸ÍäÈPãÅœ¤ ²|ÈKpy©5`K*ôÊÎLL¹¬O˜±BH¾THx|Htp‡ HM|œ£lÍÿY¬,×ìG.»•9ÌÀõ!K|ÈMtˆ‡xÀ\+Lè[ι|Mì¤>-ü²¶“LÛ„ÇXøËxˆ%9 NÃlˤìLÖÌN$‚¿€LÙ¼)¢Jèë¿âNüǼÄC¤O[Ô@,[Ï­œºülÏoĬ ­#XƒEulÌ—ôÇí”ЮŒ0ùÍD|ÐK$Pí¬PýÏ)Á½¹`ÞbD¦Þ6促+ø'ÖÜ>Ø…"v^RLƒF`dÐM•7ˆ[Cxš!ªP6áÁ%!K²Õ£xam¡‚H .C°àWæ?p0ˆZ˜ƒ90À=èåÐ… (òY/^žƒ4À[(!ï•cVàf¾âî‚쑲€€RÖ…%Há5€‚-PbÕ%@Æe#(e HÜ$à$N]Vf»EƒPh0@‘e;ˆYî`Nîç¿]dØíP¨åÞ^Zø„*¨M88Ø1Xè#ø‚Laÿçõ1¨ƒ  ä:`Ü?€ ˜“;.SÆÞ­%¡:¨`Zȵ%(J 5`^]0pá%PéA{/pæ.°+†ìM®&… ¨CHgªméW°\$PãZø‚e9‚#€„0€2H ©‚, =:è±@ZÆÛœÞVâ@X1²Öòá}V…¼ °jB(áRÒÛ¸%êQŽ>…,0Xc«%H è¶6ìG0…3†‚‡ÉëjîhËö]€Ö\0ø‚Ndí…ƒÞ=ƒ¯~€5(1ð81 j®Ûƒ.….ØOêñõlÛ¶\.HŒ/[ °ƒÿ’ömK(Ýœ[à[£6„XØÞ d£Üé­é³•µ!Ѐ/ˆâ+`.MJøKp&ƒ\€Ú|¾bÉ1î.\¦®m$ð„•&¡5H_N-H[H(ð+à4 ¡ï}ƒã^]¹î.èãÞ6ãô^ï\ЀùÖ€ Xâ.`’áº%ð.“@šyéØh9P?¬ÅΦZwë°]¯â¶oÃtlÒƒi~¾lÎl±A +H^z¦Zo÷¸Qn‚ڃ…`…1¸1û„c …Ö–[ƒ Ph«>d-w^²u%\›q„5Öð_’jÿ­ ð¢¡$èùõ_IÈ…B÷öóF<€â&=â gï¸íó_âoê®]ï^8kxf€LÈ·>ËíÙ™Kpô8€2€.¨åô6q¹%¡<ïJ'r¦®t·Á3Iȶܨ9ïÏk"–…8t¬ue6ñÛAˆð"pð™4,ˆqc¿mdw]Aî:Û"ˆb-ˆ`$¸afk?[&Ž]ø. mO m&¯ƒ"mx¦òƒÞ›*Øñd¯ß"À1øƒRÒðÎ&s³&!"—Û²jF HXéd—z\´\Câà–€„§è§®ìXÿ"a&ŸDŸmÖ5Z¶t Hê$(â-˜„J÷Kßóƒ9ßuù-¡¾Vj2çð<ûðϳ$ðUÿä|·f€ÛZ|wÎí%ØuËíô6Šl´ýpð!‚Â~÷c—ñ7—ÛeÿÚ>¤mßp…^r+Àz"&m‰Æøó¬„ ÿ„:ð‚]ˆæ-_ø‚•´{"´¯t*4¥Niȸ‹‰H…º†‚PõlÆáße7÷ T`¾Ÿ5fÿV|)`|˜s9ps'PãPV…”Gqæenð©—‘§u1ßú†ƒ+FUHœÄåž¶x½u¶ž8¹§øúæÀŠe&Ø‘ÑôE…ÿ‡iýÈñ£§è–„˜vk¦k4èýSˆûfæ{#€1¸}˜ü¶¥¾Ö§é§gzíÏ~åÍìò%[¨;ènŽ®ò*°rÞÇä]Ø…,™Lvó°ûâ¾€‹®m§} hþKH›ˆ9ibxÙeŽ . ¸X2$‘8²0IèF˜FFÖÌÐaª †/F’,iR¤ÉS_^9„¢ãÎD4.qÔJScfM ö,ZÒÇ LznÒPi!Ò¤HöÔqXËÐ%$qŒ˜ré*Mš-–¢N¥2óÏŸFcIÚ(—ž¤4„qp% \- †DéxÕfÇt@’U˜ ,“à ¼4¨‡²vÿ€˜‘ÁÈQ¤(´%ã¨röÉKeä^¥(Ÿ,mö´i¿©W³NзuÒ×±a·àömÕ´w—iÚV%$)%”a¼‰k”Ê,Î{ùóè³™Kï=’Ò“FŒsïý{„43F§.rÔ(ç0ˆ3´BƒŸ’D oòªo“ïÉ7/Czê-—CMð¡&º%—oÚý·ƒÞAà_$!±ÆVçMáI‘|Qˆ æGÉUw"Š)ª¨`R¸áC1öaC 4Úx£5⸣Ž9Ž#A ÙãDydI*‰$“MY¤“hD¹d}h1‚”T)¤V yå—?jÿc–F. æŒS’9¦šk %•1æHŠ—nò(¦Že¶¹'›|öùçŽi *£‹¹É†Út+*º(£ˆ6ú¨£,J:›C“Bz©¥‘fš¨¦‡2§Šº¨”†:ꦨ*Xj¢… !§Ê©:+­µbšê©¶&‡«¤òšÚ¹Þú«°µ²:,¬º*»,±È2»P©® -µÕÚf-¶Ùj{-·Ûvë-¸Ô.¹åš«mߪ{.»íºû.¼ëÆ;/½õÚ{¯¼ðŽ‹/ºüöëïµéæ 0Á|ðÀ+ìb¸H@T»¯µA­n°¹d¼±¾LC·³ì;Ë·ÓÊÛ†È-»¼ÿ0Ì1ËüòÌþ âG¡è°À¹‘’–«ìÇ »*# M4w¼ $ÓFâGÃí:LnEà†ÈÏ ˆÑÙ~]tË£ØátÍ4§½6Ûh³­¶«2ðÐ nâÉxLƒS¨,€ÅÔF±Eƒüñƒm@l[0„]·Q®~ÛŠܰâ¸!±âpSŒ@uXà~9n|S<ùƬnzâ•«+t·¹¢‰eØrD- î°êûNÈ"”/NÀ _|ñR°·ì¶çoK?=õC °Ô-!àìð…ÔŠ@Á…´@aHì4¶ÆÕ?žÛúÜqÁ èÛÂÿÅŧðo p€¾ÛlÑà 8°†F\  Glc‹ua\œØd5à~„"ÂW4PZ`€DíÆ°W,/!p§EÂ}1à%s!Š'‡  ¡ØÁÀ€.¨¡‚ð‚&>pÀê1±‰N¬Y²G±S$u@Q8PÔh¥ˆC•¨²ïmAŒœpÀ ná>Œ@bòûV0†q&àf i €x%Þ¡CØÀ- T(±€K >O¤%tm¸À^¶` a\‰p*)ƒCÀ;@ƒ¬x?¬Üñ“–Ú¢ÔŽ~<ÄŽPʈÕÂÿˆ£ * ÀŽ·¨@öð b<ì埨ÌCþ‹™Ët¦»"ÀƒRêsÄbÔØƒ?‚š¨‹)Äx›3&ó6N(A!… pN`.Š¢ÆYRBüÓ„ˆ †ØbkðüfÈ%F‚Y€ƒ#ºpˆüQøÁj¡Š¤ @&˜ÊmAˆ÷I$xdú Šz†3n¡°„ÈÙJdN¢ H°E&n@O8¡õ£!"R»‚44 ‹aäèøÌ¶AÏzE½ÚPŸH¹u+€Ä"PEdB<€¡Î€±rœh,d°Îv ™B¥Qˆ È‚>ÿèÂl™Öµ¶u¬b_¸–&8!{¨(a Jl _˜ÁưÀµ D@&VpO&âð…†`ýÜ]‘ê"vú­«¹é3ÐMìÁˆ(‚Ü*ᢟÁaü$mfIô·W%‚…ÐL*nñš[ÜZ`zðÁÍ,à„l`N@£/„Ù ´ÂXÃïé !±Ã$\xJ@ŽQT#"pÝ– '‹ÀŸX€(¡arÀÛ! N\e$ ÀIfðüš·6I¢>3!)Œ–â!ï P†¶æõR ¸^Y’€$°õ-ý8ð`¿|H&C@#‚3¹Ï1nBÂp»-ÿŠw«â÷ )ÃM$’ƒ AZ0P& À†âiAó€Dp¶c DáæÄ_PÉÁdÁ­@þ$óàÐ9v„jpBG 0Ûréucô"ž\]ÀáÅãºþ\Á ¸X/²~@åñàU%b,p•!@ˆ!js® Ä ˜Ecƒ”ÿ,â1`üK1‹# éIµ“û¦eg–¢sÔZâH¦C¬Ôrš®Ûò,jRWÍÔ”ÃÂ\—<Íš‹dã:#׺ÊýÀ¶—¯u݆3쀬†PÀÇâ:zZF3àm: mH»uƳͱwý°“ÎZÒÞþöPcÿÕ¬q‹<º9ºÍmªuïêYív÷»Ë],Y% 4´9IÒý|ŠßõvÀ9åïvÜÞêfMÁ >)}W'áì6I(]·-£mG•8ÀŒ£®‹¿K·7ÈC.ò‰ÝÖ#?ñÇïer¢r¼ã$GùóRîD™Ó|ã+nanTŽÑúä1sÚʃŽr½ù[=ϹÚÒ¥ô–ïüÛB/:ÔEÆtÞªÚÒ«¸:Ö¯Nq™M]âGíz3¿®sµëDÙÙO^ö¨ÅŽ`YƲ.w ´ý_àDvd7à®`'Ú~ëSÇœoºð¸Ú¦²S/oæR§@ÌÁuë'»îÓWàņÿ ïÙE®ã.w¬Õ`œÀÆ ¶h¤AmqxÄ#r‘vq‘‹}„‘—(4(áqˆÇMQv åxõ¡ ŠG*Ø€‘ö’«0ëÍà‰ep­ßgËÆoŒp|N@¿Z•´<Íš€qUðã¼>ÙOÀ ±m¢Þ¿m‚Á ܧ 7˜€»èGÏ|™|Åp†9˜ÃP_Y‘A´2H[ÀdÞ¸à2(ƒ ¨€ÞD 4(ÃÝQ`0è tƒàF0Pà¸<àzË@Å·4ž ÐèVåíšÄOß\ ¨’À(ÎÝ‚ïh̸”ö¹²Q $ˆÂzY˜ ÊòdÌÙõ͵ïÿš"ÔUؤšò\ìÌ bަýÎé\áéÏ ÖQ︎ê@|áÊгý LÞâµ`ðL0óLä .ÎΦŽót€º‹4´/ì Z ´(Ãû9Ì(C7Ü;åA ÀÛáßèÅ`Í9 5°ƒ9¬ ÍœÁ2äœÌà xC3C4ØF;84à D1°@30ÃÝ•ƒ7ØBü© Ã/Ü34C-JßÑ1Ì ÍüÌBTtBBcæô ­yÁ¸ÇûŒ  € \@w}MG¬ÁÝ…å^2^"°B$º`9€ùp€~iÿ5Y/ÙÁí™;æÏÆÔ@@¡áÀ$Bëu˨c‘ÀýDзhÐÅäATÀÙÒUd± ÉIƒ7œðÁ¢,b"Þ†7ì¢fu@\߀žÅ¸A%Â%ÝŒÉE`1CÇ8ˆÃáq 5¬@;Œ2¼"pìà A„à œÂæ2„ƒ6$&(C8èd57´À  À&0À0ÿ&úaËÙQ>B[íBðM9Bí$ã~Uh@ ›fL1)”NF!ÎAèBì›Ò„í2ý œR¡äÁ äó©A&<Á=((ÁcÉÐFåæB¯]‹”ÔjZ¤›*8]Ùž?T+¥Œ4Å~]€–ÁAzy–ûÁÔB)øA7Q“¸\ˆOŽYFU”D‚WÁ'?geç$À\A?Ñ“°LÖ~æ¨rvq`ˆ„ùÕŒY™œ^1’DÁd¦Ò(4ªy¢Ó¼T  +¶b Èáãàº"üÿÁ§†@@M‹Ææ‹^#DÀ<Õh5ÛБà  Ÿš†WüyÁîÜF2”ee^&·@b˜‚) LbþA©Â4$çÔŸ”ÁP“|Æ@ Ó8Û«lpfmDZ¼rj㈕5aV'–¼Œj´Ô‚k“e@DÆÁÚrh±Uµˆí)yˆ"ô ×Ä•””’¿ÆÁ¨­Ø™ M-—â…!LµFŒ îæÌÈÿBPBÈB½@Ô¾ÒêF¿ÊD:Á樈jÀ}IÆ_©ß: ëN˜:Ö ,l!B®ÔÚÚå¤Î´±á·ü¥ã؆ͺ œÀ t`íµôl$@Õ¬åZf¬y…žÕy¬ÊÉË:˜Cª €(€.Ê^/  C:¤Cgr1DÀ9 iÍÞl)FgÞP2øìä,†ý^B8ðéÖ}Ë…ˆÕx Òá„Á†ÝÂ@ÔNØœÎÅ ô@-- ˜.!QbÕ -.€ñÁ ¢‚ !gtWD«‰¨&`mA^-hJE›©â—!4*Û܇Â^ˆŸÄÙ(ôWVÿê@ULÕ@”Ñ: ˜#ýˆéÓ¶ÒOz屉‚Ön—AºÈÔ A€îœpÄ<Ò‰ª ´nåÊ(|q=Õ‰ŠÂ ­W󾓯€ÿÏÀ‡ÝñHT±4›6ÊŽÿ ² ¯fíèTÙó®hÞÝF7x"\o4 @’¦ÆbÜu@\Vü! ƒô]©¸¸22ˆ£]K3pýFÀ ¬@34à ¦àÝ &1€Ò2Ôò ôôò/3¬À5$ì12 =n%pðR Ú'AÀ’ZÞ`™~]HY:.ÕDªòÉØ@@™½óSì²6;ΟwhÿÐ â øxÚ)¸Ødå íóѱ8€‹©Ù%ÀÄO†Ç’ñ§ŽáOKêBòõ™“1 m‘D¸dÀt-LË <ÙáÀ)ôÀ -4”At#œ³›Q@±Å…ËØŸ¥Ù¾D‚èÀÑVL?Ó™«Pôx`Á93¤˜P7o$<ÚmDB“]‹dÀs¨À/ä©mlX 'pÃ-C s0—§åD[rløêß%@2¨WЍ0´µ0àUàC < "ŽÁÄ-¢4è 5< !† @ tÞž2ÇX"¶™AÀ(`“bÑehŽÇ(â¨NéíÍ¥YÀ¶N¶)ÿ¢¢`ňáà¡ÚRc×ß÷âZè™¶Æ`öòŒŸìÌN¢a'…*ˆöcKAÎ6²%ïôL²­Ú:A—Åí òÛö§…êœ6Ãôžjÿc#7p_¡qÛÆÅE bwĉèõª ðu_SCÅ>Ôµ¸eY›5ÛÕ^Q-s3€e3£]|'Ìß¹š«ðÜZ?¾Ð$5¢ò85äÀA}Ï÷3AÏ|„Ý¿8iÆe”F]}ç^#·Àà5÷Ëß=8ÿxäMa¬­Ø…šO‚yøË(fÇê_~c8ÿÙÙœŠ#øÈ½¸†ox~Ïøz› zŸ8Ö5xÍÙx^Ûƒ‡x…û8õxCÿØm‹‰/8ƒß8„9Í­Ý2%0•ƒßì ¹“ùmäx4y–ø–g8˜‹9‘cy½ù—9Å„MQÝË€²—ËÜݨ4d ác÷•“KOå@ÏîÍ(#öo‹èu+*W6Í¡3ÌP ך§a âAõ}K]òºލe¿ po²Œ¯Õ,y—ǹÁ Á/üÂ6üÂQb‹DVJ €A•‚(ÚË!é•ß:¿XŸÇéú –^ðåq¾Ü ›ëúÀüi¥¢¹m¸@™áL»4AEëVùeðÝíž5’¯+w'Ÿ9ÍÀÞ ÑxÛr³r ±O^T{™SËŒÄ7P"©Óe üÿ_ Ñ= 0€hX+º )›öõØy!vZß5´@." €wB`Ÿk˦o¡¤³¡ t4Ö‘\Œ Ù¡‘• à(€¡Ã4(s·•¹ößøá$Æ»`ÆSm8ýÀ¬¸§Cµò¼7ë–üªàö]Ûš¡¶Yá JÌ%ÔB\š@+ðˆü}!m‘ªº„üÅlN •hI"Ïz!ªñ侚}ƒx«ý|eÓ6ÕoÚl£ŒÐ#Õ/À‚85ÚRbø†ò(Löµ&Ž,Éå‚8Cº@[‡¢Óç†)Ž*zÃ5¼÷mÐo9Œ% C3㜥Ä Øb0ÿÀ0£¶$A¬£2šOÔ¸ 6nLRÿDJäm\O¯>Ç+%;BkSÆcnÈþÀ>mPS‡Y- èþ%tïO ‰’qÀ ´ÑÑŸå#á}$ò§k¥¼þ>ú˜cÍ>^Ý$"é${#÷€Øø»PHbe¢ÊùÌ}¡À$”€~ÙA \KeÙ‚DÐ_„,4HÁ†Bvü!ç$!}„‚£Æ† ðR†€S\*ØR£ƒÌ€]B‚©!€#A[ph^pXCÑŽ(°¡a Á@>³ØX &'°Hì…KÈDÚT²pUV­nÜ`y0ÿ©A°aÉŽ B™1cf¶u€ ˜J•¾Aª²›7n(P´c@!ŠsШž[qJ·1͵XaE88©hÍq_‘`K”=D¥I³ái-Ä.òÁ€Mc¼˜b=@Ó­6hÒv5@„0{.I¢;É œPÜÐ-gOƒƒÂQGe&BmØÔIšã§ò´~«î‚ÏYà=(o’ž5g(\B­%d`\» µ"JS $˜¢> Rãc]J%ãÌ8ÄKv°BºäTé¨Ƹa$ F,˜Á !æØo³‹89 uÑ : <ÿ“o9À& ÂòÄ °Â®R,ä 5ô+â4+(ðï=±‚9‰^.¡:ЄǤ [\¸ÁBL`-‰ëz2Èøâ,ž¸!à¸Î,j”åÆÑÚÛ°5ÄÒ*©j!¬¶ÊÊ«*­üŒR¶Tˆfšg&Ýtqâê _Œê°f¢aæÉ<"†(iãœkzƒ›C€d¸aã€`ƒœk¸‰æ„ºé¬,Ð8á D$®˜£„Úà%:+5½&–Û4©Å r¢<áBd£äÄóbP‘ƒŠ „J@`8Ù¤[5hÊÙ ¾€í‚àÿ8s{ʤMÔÕ¨Jªu"Œ¦ºðÄŒ/ÏøaR/ô`-ƒ „†ñ¢-0 ê=@| !„FÒ@â` +F EkZmEm"/FáÐ!“íE Ý‘·e×];Èз,…Xc 6ñ£ +.0ê‹=6ËÈ—“>ú¥eàà½/ ! ‚" ”×4ÛÍàÌ Ž(déú†RÞµíå˜ÿp°Ù™+-  ¨$'`F®âêQ­¨àñÎ='š.zN–2ÐR€Ë(aÄنЂTà¦vdfb6Yg…"hÁÐÆƒj\=+A(ûrVK¨¹F†˜6ÿ6ã@# àÚ”î.<Éc S<Û×¶‚"ñ©gòõ†Y˜~Ø£PA$Jº7¶÷à÷¶Z¬Ï¤m!;Ø&`Ô#ÿ¡ €Ò ¤$F‚}e¯@ÑÑϨªDŠ@ÚßÉ’´»E‚ ”pÎ ‚„·7pÏJ>ÈB)¨°ÁÔ@g ²øZLøŠ-( ‘ûš¦ÁShbô³_éªd®Ø µÐ,Ö 1‚dá\XÊ‚ãìëcùØŽPˆ”Ô^â+[‡²¦t™EЀ‹Nhôs@Bd½Y¯‹l‰\äL1ˆ©LÀ*Ì\W$å¹±UjÎðÁý I> gâÿh}¦£Œ¤#ïh7ˆ1†Á4!áèÝYP@ŒKwɇñ|eJåqƒ“KôHáXoã[845À(P#ƒ©¯G¢¡ ´†‰Äb‡/¨Ütä¤+’‹5Ô[H¿3 Òˆ‡ýÃÞœ• íLd‹N2C$  ©‚~ˆ¾Ä„$mд—M -ˆè#ØBHxE8³ ø¥#68Òg‚£Úßà?…¦¬RÒ>¤Ï©ŒˆaÉÙF|ÉBç4)¸ÖWdÂ+Kˆx[ ±„N!…TDGŠ€Gå°8ÔÄ@ WôâÒØÆ\¸‚ ÿšŠÿú°¦‚ª •âˆõÇËa.sâ:¤!·*=fã´Ò#8€ d¨1f ‚C8bÀ²“c¸Æ ®± Ýqò(ÈSíD°¿®À—Þ^ûf,c®a­åìpÏ>±9pÅæ&•„êq‚4‘½C‰ŽWÈÀG›Á 2›“˜À(èÃîÖwý 9È.…ZÈ ³£Í¡”"ØÁ F1ZÝZ ±fsˆ < \F¬DF¬\º"¯x1)Ì=šxCM·(PDs¿PŸ œluÂhk¥$r,j@¯Cæ ‡Ôæ6½08ïfZ Ô"µ«.˜ÿËßplR!)ð"ðÛˆâ¿á5È ªG¶ÑÂA ùeC0P†œÌƒ ¼Àk”àêàÀÙ­‹R`™A@´:0Sr;(Û®þ€ !U…ÕGEª«b ²•¤! FŽ­ †0B '3b¡¼´ Ê€I081>¸ V.5”Q涆™ Yv ic Äf$K5 Èë*cÄ+²I?Ë–s†`Mé°±B¼ùȘDŸ10g˜D>BÀŸ"•©ŠË° ’ EêMÒ³@^…ŒÀmn4¡Í!»àÕn®3|€@:Z¢És£ã£ÿ¬º#€u åœèK»ù*p3°  mŠÒ^Ôµ¡%Ý!© ƒ®õÆî¢­jÏš@ª4倀ëK?.Ç1E}¼6 ™«ñr[ rdx‡ZÞiU1NÏ|KÏðø>ð­v¡¹5¸ç †0…à øôþíoNWœJ]ÅwÁ7õßwÓ¹âÇ©X1Á(Afµ*ÿ²ÈCÎq— » ß*½»‘e+Ë|ä,WùÆ'ÞsÊÜþ9Î b>ûéC¦wÒ™¾ô—ÑéIŸkºí¦?}çë Ý=ô–_èKûÈ£v¦{½Îf·ø×׎ö—]íUWûÜ•Žu»çÿ|R+§;Ó1¡vòãl?»<­=xž×Òí‰?»âQmqÀ}ñŠ—üä÷Ny"ê½ç‡¯¼å ¢õË\+Z|çª\å·#š @ØØ_ÚePÇdæ9ä®ë‰{ó§½ÕoŒlsóžãˆžbëF?ïâ›®?$—Ñ’åWì¾Ë½àKžçv‡~ò§x4¶ñ‹_¤Ôåò|êEOlc b›L7½Mü¹;ÓÁ†Ž ”?Gµæ#Ÿø$ªð’BÃp¿Âé@Ç8åhü` ÒÚ.óvvÏî´¯éN`î-š¡€l_XIî( bN,6¦/ñåïPàÿ(0é6¡œÁÌ!ãnæ(ÊÀ<ÅoaDPŽI>B$8H¡iØ` PËJ>DgF„ˆÃ8î$E`hEÁJd·,$ÃL=ÀÙ2Æè3pF`2Oà„‡˜ŒB®1ŠD.¾,F )@‘,{ä2ÖÌ-—a Â0"©ê£”Æ ‡®ú>ðÜŽÿ÷O0ES.*ãŽ.Òà ~ °ÁR@xf†²!‡‚¬”‡­FO8 €¶z†œŽƒ!Åbh"\ZÓ ¿  Æç 6€ Álƒ&AôÄ"q@ ŠdHhú‚œÆðˆÎe2ànäAÃ@qª3:ùÔÞ¢\^#4—Êo¢b¤ î ^Á¬GiîÅ2á²l£¾P'½Ôq0"$(;à8ÐPO‰TaM%OCa"Vq#Æà®` G2@q2|¥€åì§h‰ ÂÎŒVP ÿ6¯@Q4E÷’ðŽtaEÿ @ )$záP¡ð ̸!1Ç€Zƒef¤âu¬á”ØÁq3ój "HõD5¡"ÁKuÚØÀ üÉ71 <ã'ˆW.âÐJPAVóá¾l8`QÆžT`@¦O(5ö$CdT;ׯ†´i—܇Q±)õjËžþcN–¨¸ †CˆT$U;¢K †c"VR·‡j– °¾@ÓhÍ*‹.Zí-XÚK” NàRÀoò¢½T`•Žx”‡7º¡¢i]€D+ÿê®r…ëZuíªµsÉ•î‘>ÅP CîGÀUT` Ô• ¡\ÿÏ5o»A]É!3ÙîËÞõx4€ V^9”jD ˜ŒC >à¡bS'—€Æ„rRêqAÌÒTb,Ê êaE7KªŸ—è bA¦~*Ʀ‚m,·tim`â à‰Æ€Ø¤Zbal¸AV¥L—zŠüI¹Dh*@š ¢ = ô7&!šB>A¢ˆ)Ó@*Ú N| Zè(l!G7åyt§X)ô,¸Ìõž'º ŠÇ–:IkÝ2XSëkAƒ“ž¯D%îD¯/+´ óȶtÎòä.ïÈʬ®Òª&EbЊ¡t`¯†ðR ´±¾²lÿ#°` âÄt¦kÓ’ ¢ –€%÷‹›`†A€] 9÷k'Šè""«‡–Äš‹›k:8KN,†;m¿dF#Š€½lv‹Å‚Dk³xKŠÝ‡­üS³2'ÛÀlØ`ÜŠ®ÄpÀ @ˆ1 ¢¸7bŒ ö¼˜ h¸º€–z~b²6|’ ˆ yŠ8a$\.¢ƶÚç88p<–Á¯–Á b`°ˆW‚á8P\jg娡Ȳ€!0i Âóò² ò† )š÷°œ¬ÉŽaÉ@.ùÈŒÈ!BÑâ Iñ ñ‚R ¢°åoå”õÎÎÿ¾ðè´©èðâlëdëšQ¯ÕÂÙòð5§nÛBª™ÜnJRÎf´9šëÍr8f$ í÷¤ùÑd-õ¨™ ó9ÁZ g&àS+œÅšñLºžÃpŸU Ÿ­­¡Ii3òÐRbO~™²l˜“¡*J/$š ^•ïíé<mƒqYôßZyæR¸!ϧG‰OšR\Z¦îbÚ¦_lßd "€ôöNZúìxl›ÓVW™北o©‘ºî^:©ƒÏ¸¦«šm¥úÛrZã´:ßvªzè^yJz¬ßíªuŽ~Ï:õÞ )Cù^:öÈaž›Úçf!ù"QíÔš« iØÿ xÞ6q®A£œ£zîé«×õ •®ÃbQð°[ú€¹Ž ÷zR¸N`7·ú(< |0Y6a!;„†à/³¸þŒ$Ú‹J[IEñ°%`¯ñhýzNb©”ì ½fÁš€™)ë»CUBÎ YEi:BA¸qj¨Pñ† !ó¸çv‘2Я‡ìR¼îª‹l¦a™°¶©”·! “¯±—™ÈXÀ¼É ̛ «¥fê0ך_+Œ¢Í(ví+þ[Øèp:B Qœ¢Ïì6†ï÷œ¯¿ýÛqr #[Öpÿl -gñ;½" ô3a©É=ü„:ç“ Â^çç<¥¸ÿ¬`R³;àé9V7¿L;Í£@K›S€)ê?€pá<Ñħ6%€åU7ï½Þeí|c ’©;5Ó53-å[Cëo8pI4ÐÃ`jaé¡ävF 7´K¤AáóõЦ¤½{Ô¢u±YnfÐ>Þâo†fô ân9~ z”\ HS¦ŠôH¡ám‡JÿV> hâÓ4HF’h­*µ|3õ]â…7óˆQhåM îÏ1!:p’h=‰L‚J ˆæ"B\Îø°¢ о16¢˜´¡i*¸…˜w"`W)×ÚgIÂÙI ˜¤Nž]ÇRÕè „x’rBËY˜ÂFǵd9“m\à–Çn¾7œpµ1_«òýXsÎl“3•ÁÊ\›¹ø7Óq±†ó]x`CÎ5çIÃ̱)X#9ÐȲ®ÒÖGr FAFˆlkPàÂÿDH¦Ä ¿å·i.(R(º'‚ƒD)é#l±­Ô%ÊAK8@®©pBVÔëÈQ• £g;ŠQŽà¸`,†½ÀcH¬žÅYÅ€IÃ'´?ˆ5h²íƒLŒ¢ÅQ…+Ë’îq@+hi™<ÁSðî W9‘&Mmtu^t¡”N2 Í!ƒx’ˆu[ôÿä†K/¡ŽîŒ“?"MÑ‘2¨_,¿àAÛÆ-ŠWʲ×ëlE´hºf #XÚÍf¤Fnà#§º‘ªp9ºJùuiãÌ7ãUwÒ´ˆ2ÈlcÀ[)8SŒ3ÎôMÿº`cÌóK(2SL1'´YyçÊqbô†â€C¸pÔ9ƒ4ÁñÊ ¢È 3 bA2\@|òfËw¼®”ˆP˜0@ØãpòÌ;/ô9hPDõø_‹ ¸ŸCü e€"@³Qù1þ¨ç;ôAz.0àÿv ?6ÄGGP¨ü²ƒ Ö/eÒÓA „à‘‚à€H(S%â-!„` ñç]tï{ÜÊàf,pâ°,'À—r`Ø8,( \pÃú´GÂðíà ù‰„,¨"tP{BÔÊ,¬ã–îi/ä\¢×ƒ @.¬Ì•7!ÎA‹üóßÿ²ð™!ÂMQ(ƒqBÖ› D.8ÅÁçz÷;Nƒ)À¶÷ÇœãÂ"ÝBHJ]ÒP ÀcIIƒØ0äyK¾rXT©¶·ˆSbÁe¥)AòHëTånÐK£hIpé\áа ÊWÑ@ 8)%H„Kdd•}¤3© ´ÒŽ“ç2…ZBÓ8j›+“y†“UÉùæ8…Í d¼äå™鸪8ç‚!Â9?+4óUÄ,Ë› J¡)Fýc¾‰ŸlÆR–—¥2ýéÊßlS˜–±¤Y:r–Eç<éI“Ž. ­cõÿ׆=grX¤K_ê«–ÂôU2éKAiSD~F£Æ¡iFKwÓœ Õrdô)NÔIÈv@õcMê*µh4¦T}êP¯ŠÕ²ˆâqÛ#K±jÕ¬&°UT=ªM}«GNˬ¿›*ZÙ Wi…ª`ÜZÅŠÔ¡>µ€{kOçŠ×ÀÞ”yÔ£JÛBÖ»*v*P`˺ h‰SœtÕK0ÄלCÔx,V1JS7”í“J%mRMëԇʵ¬¬XÓ2N#(PPa×Ûºö´¹*&âiX¯æ5°)`Á°¹€>Pç8qàÂ#ráÓ`lB¦å„ŒQŒøu¸•Bºð†ÿ Š XboZ^¡µ2€fÀÀ»zVM˜¯kO°‰Øn¢Þ°k"Á" ²›Coy[Y+øÀ½kW…»ÛÎ5vÎ0‡9Œà·¾r!tÀ XâÐ dè¢W“†6>hi¨!G9X‚­¸ ÆÏqd« *ø*ñ§<%¤œlSµy(=›©Ð° !¢ÁhPÑ$%Qû¨´Ú›"û8—=èg:י̺Dá@‚fU  eÀJýÕd –FÆ&Ccí: ¡ K`¶i³7–VãíF8ЀUìûàÈ}•»‚&ë&œ±é ø:g2Y€œÿAV*8Œ±Ü`°ÀºK‹…;D£ÖˆdÏJ£Òx¢Hè‚÷¦¤ØÂŽ8EßÒ…²ð"~ˆQDo‡Öܱfžð[üï[pï°kFf'áOÊÖSÊ›œbÃásв0ldÀØß’"+…4 Û\°ÎºgÀD¼RÃ^(7ÔáeàaÀšm3A¼áS$,PG3~©w@Ãİ ˆ@Ù(Õ ?Nh¿¥è€J:RFëV¶Ð0G…›*L;àÒeéÅ6Ä!˜ç„̦èØ7žÑg¨$=cQÁ²€î “éµ"‘:A&Ñ!nA[*ÿWqAÐBp«F pñÔ-潓¯cıX® ˆ44!lƒãº'…=Ä@lT'Æp±êwßÀ-ŠÀ‡»ù h·àVßÒÐ4b'Ðu6é¬Rã€@8V`‹ØN¶æe¬Á@f6`¶Íˆ†6V´õþ=Ç N'È™c9È mûÊm5&‡ðíÇ`aÕe¬Ñc 9ΰqˆØš@°0Y b%]ÊÈÆ±Ú󞬫¼ÑøÂ@ðˆĬ2¾Ù6ç¾ ÷¤üxá\7ÊZa¥4…ì,ñþüÔé²íwÿ/Žñ¡ÐaUˆçÀ66^yÁf©'‚á zwG ÊД«q× ucÐ µ—{7ˆƒ€DX‰–*¸}A寀tt)`|‘õ¨À=% Ï,@,×`Ê à}äÀÚ'T ¸1…°62ÂOðd ” ¥P Oµu ‚d2 ` šp =rAO9! v7±ñýw€˜kqÒrHߥ ±f6C+“‡¨€r2r&«¥eàfe vå!`eÞ`('€_"È{ÃXíp‚cPÚÕ ¨gŸg wq/øÿƒºu‹9xƒ»§N*µ ‹¦s vÎ1 Ù æ ;­2sÐÖ pè$òÑ„Á"@Æ2ÈRÎa Ò§tUfGrÐvjx-£…=uÀ$aÀs'1P90C 0€1Wd( s#O <1ŽЇÐ-ºw†#Øò33||'3ë2<Á-?ã 2d3#þè©·48Ôc§@]ò‘á‘Õ3’ÊÑ Þ ? ‹6¶YXÔ ×À?c ©XqÔ`0y'b6튱 §‹çޝõjÂE<؃ÆÑyC™‹9a ¨c >èW¥:Èð3È:9ç;":¨ÓæÆÿXÆ-*P;œƒ;ÅÀ­õRîc aBVtNÀ@¥ƒ6ó#ƒð@•q>Áv?Æ?Ì—~‰anÄ—xyûU"K¡™³9SSœêô²_ºeVv±òñf2iˆ³1ÛG.pÿûD² „¨U³Ž+F+4ûQÁ³?H³ŸžÙKÀu£IªI• Ì0 Ú r«×ñâ0¢TðiP 7j«9-g ß@=ÙÀj®¶…¨¸YF{oßÅ6>¥˜ØÂB¶æ^Ðó£ƒÊw?ÁÖéÖvÐ À—>»k‹S’,™ÞFrà:e’žH€=s@€÷F!mãCŸ Ûw›ºžË—y <“1|â–BKU@<ž+€r pðâ;¼p ë:’÷–o:±uµpkd8 yÍKm„À 3À—ò:=p¬[7»;¤l‰Ðÿ–0ºÊ4 ¾«°~eq½X`¾ÊDPk9ð¿¾c´ù‘íÕ¿pÄË&_Ù«<:GÛ3\P®x„*8¸X% Ñi’ö±QÕ ­à Z90) Á¢ß` ä t @ê¡ Ê°,h  Ó—UÚòH>»y'|-šðu¶êQ6a~wx Ha²6V gXhí×”À „A±æ·"8Uöýb Jˆ @¶0Ð2”Åh¼ Uüu©Åm`«:[5;±ià'o%ÜRé€2"ÇíÀŽ~`)”úÇÇ·&ã³Sq €x¯p<=…!t²/³ÿÈù1;°K ~4ã2êw–L w¡àKÑù=` aœ9vàz0†{ Çn…w…'8 ;;¨7ÅÜ9F Í^,[Â,uGrUÝ4“r<Æ£ÕŠ#PH)9ä$¬CEŒÓ`a¯ÚÏ.piÉ;ç„°“ä° Dtg`tÝè,ZxZ±§(ÁKá(òƒRm|ÑÒuWX-¥2§ÿR‚§aˆ§HÖßnp@å}Ó⻪øw+Âa²>bà(Flœ@ļ³>$à"@ 0Ò°`¶aZ±F ‡PÒµ0½>à…OÆ6ôGIÐ8¬áâ=“Ë /r‰É¡6ý3">¨ùéb¥ ª£ ÒÐr¹v¦Çà ã =Óˆ§âAÍ ;éq*Ð ÌR߸…Á5:™ØÒä¨ E"ÚP ‘Ÿü9&4C ÐŽ.3@0·1}”ŽP%œxmìùa¬êÒ- °í6#0xæ'Q4i #¹@|xᎡP±DF  Áÿ-šÌ1€¦ = ù7ÝÌPÀéÄ lG ¢ð5 ÿ˜ãRሠd‘Q~ÙÉ›™òâI1¨u¶n4ÿ *ešè@ž6Ô]ìb=‰PÓ´ö‘ànf#£b6»ÇœÍÙÏ„ OY ¶Wþé À|›:F `©©F;“†;Ö–R;S£—–Á˜à@$× ìç³!^/¤ÇjÇpFóþ@„Ú«0p$vy¸€Ð™5ªÖ“Cì#ñÒÓFÍ?8$=ß#¤ó£C¶í€$ ‘É ™P1Äc­>./!¿½ÆZ<ñ¬_ÿ>Z´±°Q1Ý{Õ=µP:Ù9„iUDL_ÛOëU$ò¬?”pw¡=+_ªGm¯õRå3ÙŽ=¨Lõ%TF?ð˜uÁÔ* :Ïp³.Œ"îz·Ã±Oy S@×°gZ^!UIäÐY²„f €IÕ³Iô§;šJs‚N)wQvîÅ´òQ©÷ €¬'‘ø¨û¨¯©3K2óùÖãeôaOo"¡¿ÄŸË?MÃ"U¡“0M"û@u +ûµ?š![Nø´aD+ )*ZÉÿLºLý¤´ÈÍÂ,f»DÁ¡³Ö”V z‰TM1kÀ!~Ðÿ†@†`)4a>V€ lX ¡! *Ì Š« E1Ò¡‚–«\¾Ä €Æ‰lÞÄRgM}æä 4¨P¢wÊ”ùsèÒ¢D›æ¤ õ)Ï@jf¬™ÚÓ)TNpàpÌ*u«ÆÅ*ݪÓlØŒ4Ñ` U†×˜ÒÅ{7/[½Hùò}»0°Ý>Zãö먠ʗYÖ¼÷,âÉ}ïºõ+6hdË{Jþ{Æ N¸D9—¾)Q-æÎ¤§¶^ý×îXÙÌ®Œú4ìݼ{ûN4RL(S¶tlP8Á fàÐýÂ". HHð"»õÚÇ`ËaIŠ!åµ[?ÏýúÿíG,`ž¼®#ÝÓs M›‘ë÷ñÇ@ã“”h/ûTϼ% ±`»êìÏ? /´Bþ&´¯Bï†ØÐCëÌ£CKDQDICÅø.yÐ@#Än@k$‘CkLñÆm„aG‡LpŒ1”@ÐG‰0Æ—ˆQÈ%Tÿœ*®’fIî1úb‰$šÁJ »ëã6ZL`“N¨¡?)]Œ`O|€/ǽ8!DEØÄg2˜ñ…94qŽ<ºðãÀ*׋€”, ‘°PD ÝJkØa†9Ìd’½@}”½C§t!ê”” àøô¾<РóT;œP@ÿ©¬®»9!ªWãDOÕP¹#%$s­5E[«âŠN) ñ eYE5T^¨õK-‘ë,æh 3#dQCô6.”’‘D‘M”í@äWEO¼¯>vP-°g,NÖÝ…Nç4n¦t»•Y–àeY–^$§ôX桱ó˜Â¤•x…ˆM^qk$)” ¡f²+@N¤’¬Í4$ã›Èàl°kðn!,SÿìX»Â=¤Â>ÿ”'DÒª qc« !„ÖL_¸© \2ÊrKp]ê@Ü̚¡§s§\§cžƒ›i²YÇœ/0—\ÙWOŒ)&úÒ œoN(o]Üã̦k€·Û I ƒp;y‚8fàÂÊLÁ!‹¿D‡G´ËCŽê­ ¤û.´ă-jqÙC$ž#ôü’h4äø¢cçø”I_ˆDþä8äO{/¨ì ¿4;_Þ…8Ù8Ÿ°÷… !bƒPJDfÐñxð*å‘þÀŸLÍlAp 9 u§|9Ÿ³ç‚"kÒ!.°S;toTþIŸW>ÿeÂñQ‰‰ä3ß&'i±b $ ­¤CS(|\Q.Ð=c±Çƒp¨ÞF‘$XÝP~=‚Ⱦh !¸ñ:ØE¢  îA…Ý;`5‹'Q®!\(ÃM2·¹Æ@Æ/kÉ r€Ð CÔ`AžAŽg¬®Î C!•žwÑN@܈FõDkDcÎ…ÈÁ H¬’Ö°Å+G@Ÿl± [Â%xñˆ^Ü` DDæT`#ƒÂ1ñ´Xø¯PÚ(æÔ`¨ÈÀ4ó„£ZÀ" °Eà±çYbDCý”€„XFÀ9¸E ä  KŠ'›È™ .P†ÿ'ÔÏ:›Á.5±Ç ¢7@… .028h¯‹O"ÖÖ(„A›@ƒ,6 …û­pì„Çèù„%8á·§ qdL4L #u¦'FÐ6,"EEä08?x€ ”@„hÁ+Ä´ß,‚"´0Îmb¤”ð©H=±M™Ö¨¦# „?Aá€P„ k*Æp =NQ=*žJ4†M쀤>}&½jú†hrUoåˆØ:‰õÕ¦/}AZE„'&ØõÌÄ*8ÕTZ- YÈH²H%Pâ‡P ç™”­L`”ì§Šž‘oðAÔ™äÁ‰7½å‘ïü¬œ^œØjÝaòvÖ)9t8BÂ.­“;À¢.ØQ{s!<˜B ~ØAÊC DtŸ|}ï"Á5DÂ’ãîH}û "¨…ºý9³O<µÃ¬›„µE Ô¶6{L$@ÂØ{Èî.!*˜b à(]%DµI%nÿá34 âfg*ÌIèð¶»Ý •µöŒ6Kš:ã…óC$Þ†Ð`0r!ßKÙ²Öa€L‘n3&@èÆVù¿¿Lo{ç\áqà.ÏO\È Úr¦D˜ð­"x<숅K<Ç¡˜Ö\[³Py²a ÂGCu²5G.ÀCèl]A·JA*u‚MBÚ0†qYÀÜÜÚ®s§T×|ª´Dç6$¬€`J\çF–”u xvoZÁ lÍâ|î&8`:°=¼]¦'“ae€à@D‡¥ä/aç7ÝÓ·Ùá€"dE ý FA-Ä@o.³XþýOÝLè7õ34ÿïÚla[¢¥/õëz@h "£ŸEÔ’EFJ× dŒŽp4z ¾9X¦Ò£ëª!«2/æ&,P³û°™š¿ª‹ƒí£gK:ìþË'9È„Ž‚2H(J0?#û›R'/ ¯“6ôÓÀ]3éó¤?[–:ˆ¿\I Ь ã€4•CHë„UèÒ Iú»™¢9p†),<8‚lp†ßB^‘Gàd@Ü'(*AËKbÐ8ŒbãaÛꥡ ˆ›Ñ€0+IŸ€‚F˜8ðšó{èHª 5»±éA±HÁžˆŸ€ŸB'ÿùµ2”A&± (8"-¸ ‰/è˜B¹‚P˜Ä>ÔB¹€z£!iÅ8Ÿ£Q‡3K9€m1‚tË–$ –Ñ›žºQ‘>èRûˆSf‰Ò/àMRh†fGøòA°‘" Ô ÿ¡0`Ó@­PLR*% Ö¬U…NÀR€ -•‹…gð4ºr†xIH†g0‡Pè9Ì4˜Õqt@K¥€p@‡x@‡yu‡fPYI¸„”Ew—UÙ$ÿ8€ˆ-ðù;º¨uÌ‚!#z1Æê¢à¢í˜ ?x§Øɧ 5`DÀÄZ¢M¨F½Ñ hÂ:@àÙïœ#(’Eí#„Ú£Bú¹=èànÚô†S¨n oX+l™|ÝÀ(‡½ýNo †f`ñ‚hÜql‡¿]†A‚8‡ky؉åܼU§PŒ pÍ+eÏ%lŸÄ¤Ö¢†hø†hÈs¨-窆S«ApˆwpYRˆwÈèØ"<Ø ?唓ø…œM‡ß½„sˆ‡¹Ñs@‡Ÿm‡”ÜÞðÏ=[L3[¸²{±H(X7)»®ìª±,;°[øL$ñR£3(s›æ”ß_Ã2[9k_[À¸ø=X`"32<'Ï­cÀ&óãA5éÿí°E˜!X•F·y;… ÆW}݈†^¥f(Òkè¾pX†FMv³X@bÖ–aZnSÐ]×Ì®í´ ç"ÒN{jð‚ix†Ö©ýœCÚµ-`†ÜEw L°b(v‡'F·h@"¸fD€‡”•¢ŽÒXX§`{8”‚~ 9™+ðÞ`j·I{,w.Êʲ¸D;R¸8Â’¨”7+º8)ÆiÛ°ŒË—š¯K@ä^˜?„1 ‚ü®h7¾R8‰¬¤¹QMLÀ+nT P¾>ƒMÀŽ0áê¸Ýfá—Œà`Xqvo°Ývƒ[ÿõ\[öéÅå­aÕ Ñè¼i`hè$c`s¨øx×!ñ#F/@Zˆ`=€k&ž®æ1HÙvè†wà]p6Iqv.rg5Pàn«=jù.à^ï-;Ü×8¦&ˆ¬ÓFî½ìÁ1d2¤EË„ælíp© ¼€fCdÄ-Fº­j¾n{Ê&Pò­¶E7XÁ m누ю–æÓ%aPXM醆ÕàQ–^ÝimXºaiIÅŽ’nh †%èéà®åÍ•X¾RŒ½Œèt*¥7€-k`Å/C1ì˜Ít +6¯ŽuPYlönÏåÅVÿÄ‚>Føá®°¶ ëöy¡Ú݉*?$v{Ž5rÆU4‚2PŸ !!ÈtòF¿æEaä±ërE(ƹ²­ú†ŸÃ–ƒtbGö±€ò.ÅëǹhÁúëÀƒGiô@b0pa/ †K¯eh†Mè_eðà^%IEb_#_`Hnâþi[Æ’1±ØQ­4͸‰´’Ô†‘Ô†™Ô¥[aPI–¤\ÉjýN™e ©ÕXøÙ`}ÓGQL­‘·²´L Àšh³ä&P¯Ü™­)ͺ¼ËJé¬'€š“©s½ónMÌÈ\–&ø±B»TL©½á±Ïœÿlq¯iR…n (é—~)b5VîU…åUé)òá6u  j+µX/ù ØäR‡uŸžŽ)òZ'uÞìâ ïÍ‘>uÑíX·u`W¦X"®QÿÿžxjⱋˆUHÏ·bÁ{ ùqãÖ¯WÇ®]"läœé:‡^úvòÙË#G¯žôa‚ŠŸWøj>ýü”×ãOß=?ÿ‰ÁsÕcõ™´}çØŸ‚ÛH ƒ,—˜s=ɇ`ƒ.x`†nˆaIßI`hÓyX"‚&vh¡p²èà8׉(¦¨¢-Ö˜#p ÆÈØ€ÝG£ŽCâx"ƒ,FÈh?6xaRD:I$ZEÞ(e•bÍ¢mŸé&¤•^~&˜êµ§%"€fš.ˆÙ¦›W¾9¦IIz†ˆxqâ™§ž,FYØ‹ÎÙ9 ãɹ'œ}š¨‘ÇñhÐm¹ÝY(ÿˆJº¥Šb*%@ui¥Ÿv)•™‚:*ae*Ùe¢jj«¯’Zj¦Ž $„,?ÝÖ ­?N«¯²ºú«r?PÈ%š‡(ÁX… ± ì¢Â»*´°V¦W²¢kOÊ:í´Ý‚KmŠ0dÅÜ,Bm;â·áz»®»+Íöbç*T¯3ð®¾û²‹¹éÚË·ÉCÁŒ°Â 3ÜpÂCüpÄS\±Äc|±Æs¼qǃ²ÇÀÈ"£œòÉ*³Ì² &C̯Ì3Ó¼â“Á¾Öl¢:O™¯¸J´>× g¿=ù¬iŸ}´DÄódKø!5¼µD:ô„šÿH{t$ äK†Ù\ü!ˆbìaIÒU´ Û`s·I¨Øg©k€" ÖIÀsüí'Àt kDAø1ŽFâU9PÅ-D5± h Ÿ[AƒÕ Epæ!OLÑ­ à‡ÊÙ …¼Tv: Ò¾¦Š#‘A¶sŒ"8©#½ñ"ù$ ¹¥ l4s“±pa55@$ldCCˆpŸXQwäl…-Fì²¶YXÊmWe7ÞäÿL8qwâ¬ãëf郠 S¨‚x^ _ô6‰êeÄ ž‚t$(¯ÑÑM"vóE%’¹ÍipmíAö6âÿ´©¢ £HÉ †w’”áuÄ Ê0üeëƒ+¡IˆApÁ‡@D¦½ãMé‡Òé˜×A±Áq•J^H¨' 6…õ!D¼ ‹\|bR¢ h‚GƒìÆC€hŽl`¸A% 4€’XjP… ˆ¡xDÄ ž`|œÃ'Pa…dáðÄÚô /D¨á b¨žø IN® Ä„">9*¬-ÈBû8pÁ¨±¡†»šàþÐç‘! ˆÓÄüO{”øA,£0ËbîP‚K ñ‰ bP$v«+L¯´ïxÑdû&¸*¹‘ÿ q¬"±ø4àm^„74ˆpâgØŸ‘Gp,øÃ  ˆ±Á{WÛe|` 3 ¢.ó% <”!x!€/‡ÉC´ Øã¥2#j5"°qÿÄeþ9‚ZB !-ƒIË2 o¢¼Ž@]‚§€ÄxúPÒÄéôCmââ…µU¡ >€ÀáìE`œýC…va<Xµðc ôð‰ Ô@ ¥XCØÐ5°b Z «W­©¢ñï}kؤذ‹0˜â¦‚ØE^:1|Á«åÂ]Ma )Ò QˆÀİ‹¤”"¾›ç ·ˆ<¬0 ÿeøƒ!(A(äÁÐ œ Ê™EDÈnPX@DÕÔ¨Â6˜3xÈãC8a· ¸b“º„æêƒF¼O‘ ¼m?±†<Œ$Ô a„Á-bp*ƒ×^X KH„zãsˆ ‘“(ÞΟ?qa@gC §lˆƒ(1‡…Z \€v¸ÃÚ0B" æØ€ˆJ {Ä” 6[.6!t(„ë »ÃàíáÀ&€,TgŠ,¨žû¤àã”WCP|Op{NüÀ á](„8±Øá©H@rqK… Ä¢ UhÅtâꋪf‚ Ÿà@n¿@‰竸I­#/0d3~¡9»pÿaöª‹7:Y Ø…>`å$ïb¦°‚H"€‡/")9Eè aR"Ÿ gºá¢ÍCóB—Û uúð‰ýã`(Ðl ÇÊU ½'ýˆ+·OT¡ŸýÈ Ñ`‹< á ¦%[ “Ì”¢s?|ÜyiRÚP¤»¼ñŒà3U48¥.s©0tfË¿£E/òhøCœp:ônðˆè[ºÂzp„R¸ÀÑÚó¢Þ4°ç°8U°¡hP@Q="D¨‹ x=¶5æ­ÃH.* 9ƒøq¥ê.!dMÂ@Câ]ÜT¡'ùÅ“³Ð6Rú ¶˜(ÿ>1 ÚËŠ°§,ºÀGˆ‚Õá3çê b"+5)Ø[Î6Ÿ¢µI9çh184È‚\Ç^Šý°‹.ÙHt%ªÚèA·%¨Â²W)lb¥ø[`E/.ÕEýãá­¤ÎÔ}ÍPÀ ½ÂP0žh8¼|,PCÔ4µøÉÀ]Ot…ššPÔ!x›|[§}VÉ„_²ÌÜ:á³Î áLߌx#tÏÐÔ“ÞPe(¢DIw”ŽKíR”ùS¤ÖPÚpÎ``*üà @Öíð¢9„´O½õÁü¤Þ:–U¶X/ÐØ¸F°’céDwÁ¡þ˜Qÿ É ¨AK\‚¬Md­ÜÓ@pAIáE &Q;ÁÔø€1•Á±œÖpœHèKí"ÚSå|ÂÚ<#ˆë•¢µ 0Ø_('Ðß$„„ù’š¢!âE¸/ù’!F‚,³!‘Q‘M`DPO¸"üb×TT}Eþ@%>"`‚à ‚äÂ"€1F¹Ôkµ` ¦PS úRdùÓˆePSH HLÜO/…;ʀܜßàŲ¬£uMÓôbÁŒÅ,?@c0‰ 6ĤÅ;ñÊDüM|TDjâ½CEºÁ >ªQA¶£;®c;J¤EäÿÛ4äF‚$Db$âI›FV?…äD}V=v$Øeä=dIŽ$K6„KºÔJŠäLÖd?Æ…¶A‰ eQöÆQòFR¥QöQ €QB%S"åTúR eU&¥XUr¥R^¶a¥SRåXŠeWšåÛ5¥QžåZ²eX’e[šeT¾e[¦åQÞ]âe^êå^Öå\ú¥Zn%_þå`–˜Û &aöŽZ*æa2&b&&YîLÑ8M»äÍ9N&¿è«¤ãOR¦¤Òt¦dâ ÐXæeVfó„Ég†¦i¦&yðÐí‹jöJiŠæ·læÒMm®&m²&©ÜæÏŒ&pöæpçn¢¤¸ü&oêfq.gsgr‚¦s2§tF§ çt'ujçvÚ&t"'iNK:z'v'w–§sš§u¾y¦gv²ç{Âg{ÊçuÎçxÎçy¾§}ÆçiÞ'}èç~hþçy°‰{Æf¨•üÓeÚç€Bè‚*è„@L¨„â'†rˆ„€Òá¦rFh†fJˆ.(‰†D@;lintr/NAMESPACE0000644000176200001440000001270314752731051012631 0ustar liggesusers# Generated by roxygen2: do not edit by hand S3method("[",lints) S3method(as.data.frame,lints) S3method(data.table::as.data.table,lints) S3method(format,lint) S3method(format,lints) S3method(names,lints) S3method(print,lint) S3method(print,lints) S3method(split,lints) S3method(summary,lints) S3method(tibble::as_tibble,lints) export(Lint) export(Linter) export(T_and_F_symbol_linter) export(absolute_path_linter) export(all_linters) export(all_undesirable_functions) export(all_undesirable_operators) export(any_duplicated_linter) export(any_is_na_linter) export(assignment_linter) export(available_linters) export(available_tags) export(backport_linter) export(boolean_arithmetic_linter) export(brace_linter) export(checkstyle_output) export(class_equals_linter) export(clear_cache) export(closed_curly_linter) export(commas_linter) export(commented_code_linter) export(comparison_negation_linter) export(condition_call_linter) export(condition_message_linter) export(conjunct_test_linter) export(consecutive_assertion_linter) export(consecutive_mutate_linter) export(consecutive_stopifnot_linter) export(cyclocomp_linter) export(default_linters) export(default_settings) export(default_undesirable_functions) export(default_undesirable_operators) export(duplicate_argument_linter) export(empty_assignment_linter) export(equals_na_linter) export(expect_comparison_linter) export(expect_identical_linter) export(expect_length_linter) export(expect_lint) export(expect_lint_free) export(expect_named_linter) export(expect_no_lint) export(expect_not_linter) export(expect_null_linter) export(expect_s3_class_linter) export(expect_s4_class_linter) export(expect_true_false_linter) export(expect_type_linter) export(extraction_operator_linter) export(fixed_regex_linter) export(for_loop_index_linter) export(function_argument_linter) export(function_left_parentheses_linter) export(function_return_linter) export(get_r_string) export(get_source_expressions) export(ids_with_token) export(if_not_else_linter) export(if_switch_linter) export(ifelse_censor_linter) export(implicit_assignment_linter) export(implicit_integer_linter) export(indentation_linter) export(infix_spaces_linter) export(inner_combine_linter) export(is_lint_level) export(is_numeric_linter) export(keyword_quote_linter) export(length_levels_linter) export(length_test_linter) export(lengths_linter) export(library_call_linter) export(line_length_linter) export(lint) export(lint_dir) export(lint_package) export(linters_with_defaults) export(linters_with_tags) export(list_comparison_linter) export(literal_coercion_linter) export(make_linter_from_function_xpath) export(make_linter_from_xpath) export(matrix_apply_linter) export(missing_argument_linter) export(missing_package_linter) export(modify_defaults) export(namespace_linter) export(nested_ifelse_linter) export(nested_pipe_linter) export(no_tab_linter) export(nonportable_path_linter) export(nrow_subset_linter) export(numeric_leading_zero_linter) export(nzchar_linter) export(object_length_linter) export(object_name_linter) export(object_overwrite_linter) export(object_usage_linter) export(one_call_pipe_linter) export(open_curly_linter) export(outer_negation_linter) export(package_hooks_linter) export(paren_body_linter) export(paren_brace_linter) export(paste_linter) export(pipe_call_linter) export(pipe_consistency_linter) export(pipe_continuation_linter) export(pipe_return_linter) export(print_linter) export(quotes_linter) export(redundant_equals_linter) export(redundant_ifelse_linter) export(regex_subset_linter) export(rep_len_linter) export(repeat_linter) export(return_linter) export(routine_registration_linter) export(sample_int_linter) export(sarif_output) export(scalar_in_linter) export(semicolon_linter) export(semicolon_terminator_linter) export(seq_linter) export(single_quotes_linter) export(sort_linter) export(spaces_inside_linter) export(spaces_left_parentheses_linter) export(sprintf_linter) export(stopifnot_all_linter) export(string_boundary_linter) export(strings_as_factors_linter) export(system_file_linter) export(terminal_close_linter) export(todo_comment_linter) export(trailing_blank_lines_linter) export(trailing_whitespace_linter) export(undesirable_function_linter) export(undesirable_operator_linter) export(unnecessary_concatenation_linter) export(unnecessary_lambda_linter) export(unnecessary_nested_if_linter) export(unnecessary_nesting_linter) export(unnecessary_placeholder_linter) export(unneeded_concatenation_linter) export(unreachable_code_linter) export(unused_import_linter) export(use_lintr) export(vector_logic_linter) export(which_grepl_linter) export(whitespace_linter) export(with_defaults) export(with_id) export(xml_nodes_to_lints) export(xp_call_name) export(yoda_test_linter) importFrom(cli,cli_abort) importFrom(cli,cli_inform) importFrom(cli,cli_warn) importFrom(glue,glue) importFrom(glue,glue_collapse) importFrom(rex,character_class) importFrom(rex,re_matches) importFrom(rex,re_substitutes) importFrom(rex,regex) importFrom(rex,rex) importFrom(stats,complete.cases) importFrom(stats,na.omit) importFrom(tools,R_user_dir) importFrom(utils,capture.output) importFrom(utils,getParseData) importFrom(utils,globalVariables) importFrom(utils,head) importFrom(utils,relist) importFrom(utils,tail) importFrom(xml2,as_list) importFrom(xml2,xml_attr) importFrom(xml2,xml_children) importFrom(xml2,xml_find_all) importFrom(xml2,xml_find_chr) importFrom(xml2,xml_find_first) importFrom(xml2,xml_find_lgl) importFrom(xml2,xml_find_num) importFrom(xml2,xml_name) importFrom(xml2,xml_text) lintr/LICENSE0000644000176200001440000000006014752731051012410 0ustar liggesusersYEAR: 2014-2025 COPYRIGHT HOLDER: lintr authors lintr/NEWS.md0000644000176200001440000024432014752734540012520 0ustar liggesusers# lintr (development version) ## Deprecations & breaking changes * Various things marked deprecated since {lintr} 3.0.0 have been fully deprecated. They will be completely removed in the subsequent release. See previous NEWS for advice on how to replace them. + `source_file=` argument to `ids_with_token()` and `with_id()`. + Passing linters by name or as non-`"linter"`-classed functions. + `linter=` argument of `Lint()`. + `with_defaults()`. + Linters `closed_curly_linter()`, `open_curly_linter()`, `paren_brace_linter()`, and `semicolon_terminator_linter()`. + Helper `with_defaults()`. * `all_linters()` has signature `all_linters(..., packages)` rather than `all_linters(packages, ...)` (#2332, @MichaelChirico). This forces `packages=` to be supplied by name and will break users who rely on supplying `packages=` positionally, of which we found none searching GitHub. * Adjusted various lint messages for consistency and readability (#1330, @MichaelChirico). In general, we favor lint messages to be phrased like "Action, reason" to put the "what" piece of the message front-and-center. This may be a breaking change for code that tests the specific phrasing of lints. * `extraction_operator_linter()` is deprecated. Although switching from `$` to `[[` has some robustness benefits for package code, it can lead to non-idiomatic code in many contexts (e.g. R6 classes, Shiny applications, etc.) (#2409, @IndrajeetPatil). One reason to avoid `$` is that it allows partial matching where `[[` does not. Use `options(warnPartialMatchDollar = TRUE)` to disable this feature and restore some parity to using `$` vs. `[[`. * `unnecessary_nested_if_linter()` is deprecated and subsumed into the new/more general `unnecessary_nesting_linter()`. * Dropped support for posting GitHub comments from inside GitHub comment bot, Travis, Wercker, and Jenkins CI tools (spurred by #2148, @MichaelChirico). We rely on GitHub Actions for linting in CI, and don't see any active users relying on these alternatives. We welcome and encourage community contributions to get support for different CI systems going again. * `cyclocomp_linter()` is no longer part of the default linters (#2555, @IndrajeetPatil) because the tidyverse style guide doesn't contain any guidelines on meeting certain complexity requirements. With this, we also downgrade {cyclocomp} from `Imports:` to `Suggests:`. Note that users with `cyclocomp_linter()` in their configs may now need to install {cyclocomp} intentionally, in particular in CI/CD pipelines. * `scalar_in_linter()` is now configurable to allow other `%in%`-like operators to be linted. The data.table operator `%chin%` is no longer linted by default; use `in_operators = "%chin%"` to continue linting it. (@F-Noelle) * `lint()` and friends now normalize paths to forward slashes on Windows (@olivroy, #2613). * `undesirable_function_linter()`, `undesirable_operator_linter()`, and `list_comparison_linter()` were removed from the tag `efficiency` (@IndrajeetPatil, #2655). If you use `linters_with_tags("efficiency")` to include these linters, you'll need to adjust your config to keep linting your code against them. We did not find any such users on GitHub. * Arguments `allow_cascading_assign=`, `allow_right_assign=`, and `allow_pipe_assign=` to `assignment_linter()` are all deprecated in favor of the new `operator=` argument. Usage of a positional first argument like `assignment_linter(TRUE)`, of which we found zero cases on GitHub, is totally deprecated to allow `operator=` to be positionally first. See below about the new argument. ## Bug fixes * `expect_identical_linter()` also skips `expect_equal()` comparison to _negative_ non-integers like `-1.034` (#2411, @Bisaloo). This is a parity fix since _positive_ reals have always been skipped because "high-precision" comparisons are typically done to get tests within `tolerance`, so `expect_identical()` is not a great substitution. * `object_name_linter()` no longer errors when user-supplied `regexes=` have capture groups (#2188, @MichaelChirico). * `.lintr` config validation correctly accepts regular expressions which only compile under `perl = TRUE` (#2375, @MichaelChirico). These have always been valid (since `rex::re_matches()`, which powers the lint exclusion logic, also uses this setting), but the new up-front validation in v3.1.1 incorrectly used `perl = FALSE`. * `.lintr` configs set by option `lintr.linter_file` or environment variable `R_LINTR_LINTER_FILE` can point to subdirectories (#2512, @MichaelChirico). * `indentation_linter()` returns lints with `ranges[1L]==1L` when the offending line has 0 spaces (#2550, @MichaelChirico). * `literal_coercion_linter()` doesn't surface a warning about `NA`s during coercion for code like `as.integer("a")` (#2566, @MichaelChirico). ## Changes to default linters * New default linter `return_linter()` for the style guide rule that terminal returns should be left implicit (#1100, #2343, #2354, and #2356, @MEO265 and @MichaelChirico). ## New and improved features * New function node caching for big efficiency gains to most linters (e.g. overall `lint_package()` improvement of 14-27% and core linting improvement up to 30%; #2357, @AshesITR). Most linters are written around function usage, and XPath performance searching for many functions is poor. The new `xml_find_function_calls()` entry in the `get_source_expressions()` output caches all function call nodes instead. See the vignette on creating linters for more details on how to use it. * `Linter()` has a new argument `linter_level=` (default `NA`). This is used by `lint()` to more efficiently check for expression levels than the idiom `if (!is_lint_level(...)) { return(list()) }` (#2351, @AshesITR). * New `return_linter()` also has arguments for fine-tuning which functions get linted: + `return_style=` (`"implicit"` by default) which checks that all functions confirm to the specified return style of `"implicit"` or `"explicit"` (#2271 and part of #884, @MichaelChirico, @AshesITR and @MEO265). + `allow_implicit_else=` (default `TRUE`) which, when `FALSE`, checks that all terminal `if` statements are paired with a corresponding `else` statement (part of #884, @MichaelChirico). + `return_functions=` to customize which functions are equivalent to `return()` as "exit" clauses, e.g. `rlang::abort()` can be considered in addition to the default functions like `stop()` and `q()` from base (#2271 and part of #884, @MichaelChirico and @MEO265). + `except=` to customize which functions are ignored entirely (i.e., whether they have a return of the specified style is not checked; #2271 and part of #884, @MichaelChirico and @MEO265). Namespace hooks like `.onAttach()` and `.onLoad()` are always ignored. + `except_regex=`, the same purpose as `except=`, but filters functions by pattern. This is motivated by {RUnit}, where test suites are based on unit test functions matched by pattern, e.g. `^Test`, and where explicit return may be awkward (#2335, @MichaelChirico). * `assignment_linter()` can be fully customized with the new `operator=` argument to specify an exact vector of assignment operators to allow (#2441, @MichaelChirico and @J-Moravec). The default is `<-` and `<<-`; authors wishing to use `=` (only) for assignment in their codebase can use `operator = "="`. This supersedes several old arguments: to accomplish `allow_cascading_assign=TRUE`, add `"<<-"` (and/or `"->>"`) to `operator=`; for `allow_right_assign=TRUE`, add `"->"` (and/or `"->>"`) to `operator=`; for `allow_pipe_assign=TRUE`, add `"%<>%"` to `operator=`. Use `operator = "any"` to denote "ignore all assignment operators"; in this case, only the value of `allow_trailing=` matters. Implicit assignments with `<-` are always ignored by `assignment_linter()`; use `implicit_assignment_linter()` to handle linting these. * More helpful errors for invalid configs (#2253, @MichaelChirico). * `library_call_linter()` is extended + to encourage all packages to be attached with `library(symbol)`, not `library("symbol", character.only = TRUE)` or "vectorized" approaches looping over package names (part of #884, @MichaelChirico). + to discourage many consecutive calls to `suppressMessages()` or `suppressPackageStartupMessages()` (part of #884, @MichaelChirico). * `unnecessary_lambda_linter()` is extended to encourage vectorized comparisons where possible, e.g. `sapply(x, sum) > 0` instead of `sapply(x, function(x) sum(x) > 0)` (part of #884, @MichaelChirico). Toggle this behavior with argument `allow_comparison=`. * `backport_linter()` is slightly faster by moving expensive computations outside the linting function (#2339, #2348, @AshesITR and @MichaelChirico). * `string_boundary_linter()` recognizes regular expression calls like `grepl("^abc$", x)` that can be replaced by using `==` instead (#1613, @MichaelChirico). * `unreachable_code_linter()` has an argument `allow_comment_regex=` for customizing which "terminal" comments to exclude (#2327, @MichaelChirico). Exclusion comments from {lintr} and {covr} (e.g. `# nocov end`) are always excluded. * `format()` and `print()` methods for `lint` and `lints` classes get a new option `width=` to control the printing width of lint messages (#1884, @MichaelChirico). The default is controlled by a new option `lintr.format_width`; if unset, no wrapping occurs (matching earlier behavior). * `implicit_assignment_linter()` gets a custom message for the case of using `(` to induce printing like `(x <- foo())`; use an explicit call to `print()` for clarity (#2257, @MichaelChirico). * `todo_comment_linter()` has a new argument `except_regex=` for setting _valid_ TODO comments, e.g. for forcing TODO comments to be linked to GitHub issues like `TODO(#154)` (#2047, @MichaelChirico). * `vector_logic_linter()` is extended to recognize incorrect usage of scalar operators `&&` and `||` inside subsetting expressions like `dplyr::filter(x, A && B)` (#2166, @MichaelChirico). * `any_is_na_linter()` is extended to catch the unusual usage `NA %in% x` (#2113, @MichaelChirico). * `make_linter_from_xpath()` errors up front when `lint_message=` is missing (instead of delaying this error until the linter is used, #2541, @MichaelChirico). * `paste_linter()` is extended to recommend using `paste()` instead of `paste0()` for simply aggregating a character vector with `collapse=`, i.e., when `sep=` is irrelevant (#1108, @MichaelChirico). * `expect_no_lint()` was added as new function to cover the typical use case of expecting no lint message, akin to the recent {testthat} functions like `expect_no_warning()` (#2580, @F-Noelle). * `lint()` and friends emit a message if no lints are found (#2643, @IndrajeetPatil). * `commented_code_linter()` can detect commented code that ends with a pipe (#2671, @jcken95) ### New linters * `condition_call_linter()` for ensuring consistent use of `call.` in `warning()` and `stop()`. The default `call. = FALSE` follows the tidyverse guidance of not displaying the call (#2226, @Bisaloo) * `sample_int_linter()` for encouraging `sample.int(n, ...)` over equivalents like `sample(1:n, ...)` (part of #884, @MichaelChirico). * `stopifnot_all_linter()` discourages tests with `all()` like `stopifnot(all(x > 0))`; `stopifnot()` runs `all()` itself, and signals a better error message (part of #884, @MichaelChirico). * `comparison_negation_linter()` for discouraging negated comparisons when a direct negation is preferable, e.g. `!(x == y)` could be `x != y` (part of #884, @MichaelChirico). * `nzchar_linter()` for encouraging `nzchar()` to test for empty strings, e.g. `nchar(x) > 0` can be `nzchar(x)` (part of #884, @MichaelChirico). * `terminal_close_linter()` for discouraging using `close()` to end functions (part of #884, @MichaelChirico). Such usages are not robust to errors, where `close()` will not be run as intended. Put `close()` in an `on.exit()` hook, or use {withr} to manage connections with proper cleanup. * `rep_len_linter()` for encouraging use of `rep_len()` directly instead of `rep(x, length.out = n)` (part of #884, @MichaelChirico). Note that in older versions of R (e.g. pre-4.0), `rep_len()` may not copy attributes as expected. * `which_grepl_linter()` for discouraging `which(grepl(ptn, x))` in favor of directly using `grep(ptn, x)` (part of #884, @MichaelChirico). * `list_comparison_linter()` for discouraging comparisons on the output of `lapply()`, e.g. `lapply(x, sum) > 10` (part of #884, @MichaelChirico). * `print_linter()` for discouraging usage of `print()` on string literals like `print("Reached here")` or `print(paste("Found", nrow(DF), "rows."))` (#1894, @MichaelChirico). * `unnecessary_nesting_linter()` for discouraging overly-nested code where an early return or eliminated sub-expression (inside `{`) is preferable (#2317, #2334 and part of #884, @MichaelChirico). * `consecutive_mutate_linter()` for encouraging consecutive calls to `dplyr::mutate()` to be combined (part of #884, @MichaelChirico). * `if_switch_linter()` for encouraging `switch()` over repeated `if`/`else` tests (#2322 and part of #884, @MichaelChirico). * `nested_pipe_linter()` for discouraging pipes within pipes, e.g. `df1 %>% inner_join(df2 %>% select(a, b))` (part of #884, @MichaelChirico). * `nrow_subset_linter()` for discouraging usage like `nrow(subset(x, conditions))` in favor of something like `with(x, sum(conditions))` which doesn't require a full subset of `x` (#2313, #2314 and part of #884, @MichaelChirico). * `pipe_return_linter()` for discouraging usage of `return()` inside a {magrittr} pipeline (part of #884, @MichaelChirico). * `one_call_pipe_linter()` for discouraging one-step pipelines like `x |> as.character()` (#2330 and part of #884, @MichaelChirico). * `object_overwrite_linter()` for discouraging re-use of upstream package exports as local variables (#2344, #2346 and part of #884, @MichaelChirico and @AshesITR). ### Lint accuracy fixes: removing false positives * `object_name_linter()` and `object_length_linter()` ignore {rlang} name injection like `x |> mutate("{new_name}" := foo(col))` (#1926, @MichaelChirico). No checking is applied in such cases. {data.table} in-place assignments like `DT[, "sPoNGeBob" := "friend"]` are still eligible for lints. * `object_usage_linter()` finds global variables assigned with `=` or `->`, which avoids some issues around "undefined global variables" in scripts (#2654, @MichaelChirico). ## Notes * `{lintr}` now has a hex sticker (https://github.com/rstudio/hex-stickers/pull/110). Thank you, @gregswinehart! * All user-facing messages (including progress bars) are now prepared using the `{cli}` package (#2418 and #2641, @IndrajeetPatil). As noted above, all messages have been reviewed and updated to be more informative and consistent. * File locations in lints and error messages contain clickable hyperlinks to improve code navigation (#2645, #2588, @olivroy). * {lintr} now depends on R version 4.0.0. It already does so implicitly due to recursive upstream dependencies requiring this version; we've simply made that dependency explicit and up-front (#2569, @MichaelChirico). * Some code with parameters accepting regular expressions is less strict about whether there are capture groups (#2678, @MichaelChirico). In particular, this affects `unreachable_code_linter(allow_comment_regex=)` and `expect_lint(checks=)`. # lintr 3.1.2 ## New and improved features ### Lint accuracy fixes: removing false positives * `unreachable_code_linter()` ignores reachable code in inline functions like `function(x) if (x > 2) stop() else x` (#2259, @MEO265). * `unnecessary_lambda_linter()` + ignores extractions with explicit returns like `lapply(l, function(x) foo(x)$bar)` (#2258, @MichaelChirico). + ignores calls on the RHS of operators like `lapply(l, function(x) "a" %in% names(x))` (#2310, @MichaelChirico). * `vector_logic_linter()` recognizes some cases where bitwise `&`/`|` are used correctly (#1453, @MichaelChirico). * `expect_comparison_linter()` ignores faulty usage like `expect_true(x, y > z)` (#2083, @MichaelChirico). Note that `y > z` is being passed to the `info=` argument, so this is likely a mistake. * `consecutive_assertion_linter()` ignores cases where a second assertion follows an intervening assignment with `=` (#2444, @MichaelChirico). ### Lint accuracy fixes: removing false negatives * `missing_argument_linter()` catches all missing arguments in calls with several, e.g. `foo(,,)` gives 3 lints instead of 2 (#2399, @MichaelChirico). * `duplicate_argument_linter()` no longer misses cases with duplicate arguments where a comment comes between the argument name and `=` (#2402, @MichaelChirico). ## Notes * Fixed a test assuming a specific parser error message that recently changed in r-devel (#2527, @IndrajeetPatil). * @MichaelChirico has taken over CRAN maintainer duties for the package. Many thanks to @jimhester for more than 10 years and 15 releases wearing that hat!! # lintr 3.1.1 ## Breaking changes * `infix_spaces_linter()` distinguishes `<-`, `:=`, `<<-` and `->`, `->>`, i.e. `infix_spaces_linter(exclude_operators = "->")` will no longer exclude `->>` (#2115, @MichaelChirico). This change is breaking for users relying on manually-supplied `exclude_operators` containing `"<-"` to also exclude `:=` and `<<-`. The fix is to manually supply `":="` and `"<<-"` as well. We don't expect this change to affect many users, the fix is simple, and the new behavior is much more transparent, so we are including this breakage in a minor release. * Removed `find_line()` and `find_column()` entries from `get_source_expressions()` expression-level objects. These have been marked deprecated since version 3.0.0. No users were found on GitHub. * There is experimental support for writing config in plain R scripts (as opposed to DCF files; #1210, @MichaelChirico). The script is run in a new environment and variables matching settings (`?default_settings`) are copied over. In particular, this removes the need to write R code in a DCF-friendly way, and allows normal R syntax highlighting in the saved file. We may eventually deprecate the DCF approach in favor of this one; user feedback is welcome on strong preferences for either approach, or for a different approach like YAML. Generally you should be able to convert your existing `.lintr` file to an equivalent R config by replacing the `:` key-value separators with assignments (`<-`). By default, such a config is searched for in a file named `.lintr.R`. This is a mildly breaking change if you happened to be keeping a file `.lintr.R` around since that file is given precedence over `.lintr`. + We also validate config files up-front make it clearer when invalid configs are present (#2195, @MichaelChirico). There is a warning for "invalid" settings, i.e., settings not part of `?default_settings`. We think this is more likely to affect users declaring settings in R, since any variable defined in the config that's not a setting must be removed to make it clearer which variables are settings vs. ancillary. ## Bug fixes * `sprintf_linter()` doesn't error in cases where whitespace in `...` arguments is significant, e.g. `sprintf("%s", if (A) "" else y)`, which won't parse if whitespace is removed (#2131, @MichaelChirico). ## Changes to default linters * `assignment_linter()` lints the {magrittr} assignment pipe `%<>%` (#2008, @MichaelChirico). This can be deactivated by setting the new argument `allow_pipe_assign` to `TRUE`. * `object_usage_linter()`: + assumes `glue()` is `glue::glue()` when `interpret_glue=TRUE` (#2032, @MichaelChirico). + finds function usages, including infix usage, inside `glue()` calls to avoid false positives for "unused objects" (#2029 and #2069, @MichaelChirico). * `object_name_linter()` no longer attempts to lint strings in function calls on the LHS of assignments (#1466, @MichaelChirico). * `infix_spaces_linter()` allows finer control for linting `=` in different scenarios using parse tags `EQ_ASSIGN`, `EQ_SUB`, and `EQ_FORMALS` (#1977, @MichaelChirico). * `equals_na_linter()` checks for `x %in% NA`, which is a more convoluted form of `is.na(x)` (#2088, @MichaelChirico). ## New and improved features * New exclusion sentinel `# nolint next` to signify the next line should skip linting (#1791, @MichaelChirico). The usual rules apply for excluding specific linters, e.g. `# nolint next: assignment_linter.`. The exact string used to match a subsequent-line exclusion is controlled by the `exclude_next` config entry or R option `"lintr.exclude_next"`. * New `xp_call_name()` helper to facilitate writing custom linters (#2023, @MichaelChirico). This helper converts a matched XPath to the R function to which it corresponds. This is useful for including the "offending" function in the lint's message. * New `make_linter_from_xpath()` to facilitate making simple linters directly from a single XPath (#2064, @MichaelChirico). This is especially helpful for making on-the-fly/exploratory linters, but also extends to any case where the linter can be fully defined from a static lint message and single XPath. * Toggle lint progress indicators with argument `show_progress` to `lint_dir()` and `lint_package()` (#972, @MichaelChirico). The default is still to show progress in `interactive()` sessions. Progress is also now shown with a "proper" progress bar (`utils::txtProgressBar()`), which in particular solves the issue of progress `.` spilling well past the width of the screen in large directories. * `lint()`, `lint_dir()`, and `lint_package()` fail more gracefully when the user mis-spells an argument name (#2134, @MichaelChirico). * Quarto files (.qmd) are included by `lint_dir()` by default (#2150, @dave-lovell). ### New linters * `library_call_linter()` can detect if all library/require calls are not at the top of your script (#2027, #2043, #2163, and #2170, @nicholas-masel and @MichaelChirico). * `keyword_quote_linter()` for finding unnecessary or discouraged quoting of symbols in assignment, function arguments, or extraction (part of #884, @MichaelChirico). Quoting is unnecessary when the target is a valid R name, e.g. `c("a" = 1)` can be `c(a = 1)`. The same goes to assignment (`"a" <- 1`) and extraction (`x$"a"`). Where quoting is necessary, the linter encourages doing so with backticks (e.g. `` x$`a b` `` instead of `x$"a b"`). * `length_levels_linter()` for using the specific function `nlevels()` instead of checking `length(levels(x))` (part of #884, @MichaelChirico). * `scalar_in_linter()` for discouraging `%in%` when the right-hand side is a scalar, e.g. `x %in% 1` (part of #884, @MichaelChirico). * `if_not_else_linter()` for encouraging `if` statements to be structured as `if (A) x else y` instead of `if (!A) y else x` (part of #884, @MichaelChirico). * `repeat_linter()` for encouraging `repeat` for infinite loops instead of `while (TRUE)` (#2106, @MEO265). * `length_test_linter()` detects the common mistake `length(x == 0)` which is meant to be `length(x) == 0` (#1991, @MichaelChirico). ### Extensions to existing linters * `fixed_regex_linter()` gains an option `allow_unescaped` (default `FALSE`) to toggle linting regexes not requiring any escapes or character classes (#1689, @MichaelChirico). Thus `fixed_regex_linter(allow_unescaped = TRUE)` would lint on `grepl("[$]", x)` but not on `grepl("a", x)` since the latter does not use any regex special characters. * `line_length_linter()` helpfully includes the line length in the lint message (#2057, @MichaelChirico). * `conjunct_test_linter()` also lints usage like `dplyr::filter(x, A & B)` in favor of using `dplyr::filter(x, A, B)` (part of #884; #2110 and #2078, @salim-b and @MichaelChirico). Option `allow_filter` toggles when this applies. `allow_filter = "always"` drops such lints entirely, while `"not_dplyr"` only lints calls explicitly qualified as `dplyr::filter()`. The default, `"never"`, assumes all unqualified calls to `filter()` are `dplyr::filter()`. * `sort_linter()` checks for code like `x == sort(x)` which is better served by using the function `is.unsorted()` (part of #884, @MichaelChirico). * `paste_linter()` gains detection for file paths that are better constructed with `file.path()`, e.g. `paste0(dir, "/", file)` would be better as `file.path(dir, file)` (part of #884, #2082, @MichaelChirico). What exactly gets linted here can be fine-tuned with the `allow_file_path` option (`"double_slash"` by default, with alternatives `"never"` and `"always"`). When `"always"`, these rules are ignored. When `"double_slash"`, paths appearing to construct a URL that have consecutive forward slashes (`/`) are skipped. When `"never"`, even URLs should be constructed with `file.path()`. * `seq_linter()` recommends `rev()` in the lint message for lints like `nrow(x):1` (#1542, @MichaelChirico). * `function_argument_linter()` detects usage of `missing()` for the linted argument (#1546, @MichaelChirico). The simplest fix for `function_argument_linter()` lints is typically to set that argument to `NULL` by default, in which case it's usually preferable to update function logic checking `missing()` to check `is.null()` instead. * `commas_linter()` gains an option `allow_trailing` (default `FALSE`) to allow trailing commas while indexing. (#2104, @MEO265) * `unreachable_code_linter()` + checks for code inside `if (FALSE)` and other conditional loops with deterministically false conditions (#1428, @ME0265). + checks for unreachable code inside `if`, `else`, `for`, `while`, and `repeat` blocks, including combinations with `break` and `next` statements. (#2105, @ME0265). * `implicit_assignment_linter()` gains an argument `allow_lazy` (default `FALSE`) that allows optionally skipping lazy assignments like `A && (B <- foo(A))` (#2016, @MichaelChirico). * `unused_import_linter()` gains an argument `interpret_glue` (default `TRUE`) paralleling that in `object_usage_linter()` to toggle whether `glue::glue()` expressions should be inspected for exported object usage (#2042, @MichaelChirico). * `default_undesirable_functions` is updated to also include `Sys.unsetenv()` and `structure()` (#2192 and #2228, @IndrajeetPatil and @MichaelChirico). * Linters with logic around the magrittr pipe `%>%` consistently apply it to the other pipes `%!>%`, `%T>%`, `%<>%` (and possibly `%$%`) where appropriate (#2008, @MichaelChirico). + `brace_linter()` + `pipe_call_linter()` + `pipe_continuation_linter()` + `unnecessary_concatenation_linter()` + `unnecessary_placeholder_linter()` * Linters with logic around function declarations consistently include the R 4.0.0 shorthand `\()` (#2190, @MichaelChirico). + `brace_linter()` + `function_left_parentheses_linter()` + `indentation_linter()` + `object_length_linter()` + `object_name_linter()` + `package_hooks_linter()` + `paren_body_linter()` + `unnecessary_lambda_linter()` + `unreachable_code_linter()` ### Lint accuracy fixes: removing false positives * `fixed_regex_linter()` + Is pipe-aware, in particular removing false positives around piping into {stringr} functions like `x |> str_replace(fixed("a"), "b")` (#1811, @MichaelChirico). + Ignores non-string inputs to `pattern=` as a keyword argument (#2159, @MichaelChirico). * Several linters avoiding false positives in `$` extractions get the same exceptions for `@` extractions, e.g. `S4@T` will no longer throw a `T_and_F_symbol_linter()` hit (#2039, @MichaelChirico). + `T_and_F_symbol_linter()` + `for_loop_index_linter()` + `literal_coercion_linter()` + `object_name_linter()` + `undesirable_function_linter()` + `unreachable_code_linter()` + `yoda_test_linter()` * `sprintf_linter()` is pipe-aware, so that `x %>% sprintf(fmt = "%s")` no longer lints (#1943, @MichaelChirico). * `condition_message_linter()` ignores usages of extracted calls like `env$stop(paste(a, b))` (#1455, @MichaelChirico). * `inner_combine_linter()` no longer throws on length-1 calls to `c()` like `c(exp(2))` or `c(log(3))` (#2017, @MichaelChirico). Such usage is discouraged by `unnecessary_concatenation_linter()`, but `inner_combine_linter()` _per se_ does not apply. * `sort_linter()` only lints on `order()` of a single vector, excluding e.g. `x[order(x, y)]` and `x[order(y, x)]` (#2156, @MichaelChirico). * `redundant_ifelse_linter()` is aware of `dplyr::if_else()`'s `missing=` argument, so that `if_else(A, TRUE, FALSE, missing = FALSE)` doesn't lint, but `if_else(A, TRUE, FALSE, NA)` does (#1941, @MichaelChirico). Note that `dplyr::coalesce()` or `tidyr::replace_na()` may still be preferable. ### Lint accuracy fixes: removing false negatives * `unreachable_code_linter()` finds unreachable code even in the presence of a comment or semicolon after `return()` or `stop()` (#2127, @MEO265). * `implicit_assignment_linter()` + finds assignments in call arguments besides the first one (#2136, @MichaelChirico). + finds assignments in parenthetical expressions like `if (A && (B <- foo(A))) { }` (#2138, @MichaelChirico). * `unnecessary_lambda_linter()` checks for cases using explicit returns, e.g. `lapply(x, \(xi) return(sum(xi)))` (#1567, @MichaelChirico). + thanks to @Bisaloo and @strengejacke for detecting a regression in the original fix (#2231, #2247). # lintr 3.1.0 ## Deprecations & Breaking Changes * `.lintr` files can now be kept in the directory `.github/linters` for better compatibility with Super-Linter. Note that this may be a breaking change if you already have a config in `.github/linters` inside a subdirectory as well as in your R project's root, since the former will now be discovered first where it was ignored before. Please see `vignette("lintr")` for details on how configs are discovered (#1746, @tonyk7440 and @klmr). * `single_quotes_linter()` is deprecated in favor of the more generalizable `quotes_linter()` (#1729, @MichaelChirico). * `unneeded_concatentation_linter()` is deprecated in favor of `unnecessary_concatenation_linter()` for naming consistency (#1707, @IndrajeetPatil). * `consecutive_stopifnot_linter()` is deprecated in favor of the more general (see below) `consecutive_assertion_linter()` (#1604, @MichaelChirico). * `no_tab_linter()` is deprecated in favor of `whitespace_linter()` for naming consistency and future generalization (#1954, @MichaelChirico). * `available_linters()` prioritizes `tags` over `exclude_tags` in the case of overlap, i.e., tags listed in both arguments are included, not excluded. We don't expect many people to be affected by this, and the old behavior was not made explicit in the documentation, but make note of it here since it required changing a test in lintr's own suite where `linters_with_tags()` implicitly assumed this behavior. * `lint()`, `lint_dir()`, and `lint_package()` no longer accept certain arguments (`cache=` for `lint()`, `relative_path=` for the latter two) positionally. The `warning()` since 3.0.0 has been upgraded to an error. ## Bug fixes * `linters_with_tags()` now includes the previously missing spaces around "and" when listing missing linters advertised by `available_linters()`. This error message may appear e.g. when you update lintr to a version with new linters but don't restart your R session (#1946, @Bisaloo) * `fixed_regex_linter()` is more robust to errors stemming from unrecognized escapes (#1545, #1845, @IndrajeetPatil). * `get_source_expressions()` can handle Sweave/Rmarkdown documents with reference chunks like `<>` (#779, @MichaelChirico). Note that these are simply skipped, rather than attempting to retrieve the reference and also lint it. * `assignment_linter()` no longer lints assignments in braces that include comments when `allow_trailing = FALSE` (#1701, @ashbaldry) * `object_usage_linter()` + No longer silently ignores usage warnings that don't contain a quoted name (#1714, @AshesITR) + No longer fails on code with comments inside a multi-line call to `glue::glue()` (#1919, @MichaelChirico) * `namespace_linter()` correctly recognizes backticked operators to be exported from respective namespaces (like `` rlang::`%||%` ``) (#1752, @IndrajeetPatil) * `lint_package()` correctly finds a package from within a subdir if the `path` points to anywhere within the package (#1759, @AshesITR) * Improved error behavior in `Lint()`, `lint()` and `xml_nodes_to_lints()` (#1427, #763, @AshesITR) + `Lint()` validates its inputs more thoroughly, preventing errors during `print.Lints` like "Error in rep.int(character, length) : invalid 'times' value:". + `lint()` no longer tries to create an expression tree with unexpected end of input errors, because they can be broken. + `xml_nodes_to_lints()` warns if it can't find lint locations and uses dummy locations as a fallback. * `linters_with_defaults()` no longer erroneously marks linter factories as linters (#1725, @AshesITR). * Row names for `available_linters()` data frame are now contiguous (#1781, @IndrajeetPatil). * `object_name_linter()` allows all S3 group Generics (see `?base::groupGeneric`) and S3 generics defined in a different file in the same package (#1808, #1841, @AshesITR) * `object_usage_linter()` improves identification of the exact source of a lint + for undefined variables in expressions with where the variable is used as a symbol in a usual way, for example in a formula or in an extraction with `$` (#1914, @MichaelChirico). + for general usage warnings without location info (#1986 and #1917, @AshesITR) * `function_left_parentheses_linter()` produces a more specific lint (and no longer fails) when the opening parenthesis is on a different line than `function` or the call name (#1953, @MichaelChirico). Thanks also to @IndrajeetPatil and @lorenzwalthert for identifying a regression in the initial fix, #1963. ## Changes to defaults * Set the default for the `except` argument in `duplicate_argument_linter()` to `c("mutate", "transmute")`. This allows sequential updates like `x |> mutate(a = b + 1, a = log(a))` (#1345, @IndrajeetPatil). * `object_usage_linter()` + gains `skip_with` argument to skip code in `with()` expressions. To be consistent with `R CMD check`, it defaults to `TRUE` (#941, #1458, @IndrajeetPatil). + Handles backticked symbols inside {glue} expressions correctly, e.g. ``glue("{`x`}")`` correctly determines `x` was used (#1619, @MichaelChirico) + Detects problems inside R4.1.0+ lambda functions (`\(...)`) (#1933, @MichaelChirico) * `spaces_inside_linter()` allows terminal missing keyword arguments (e.g. `alist(arg = )`; #540, @MichaelChirico) * `brace_linter()` allows empty braced expression on the same line (e.g. `while (updating_condition()) { }`) regardless of `allow_single_line` to match the corresponding behavior in {styler}. This is an expedient while the style guide on handling this case awaits clarification: https://github.com/tidyverse/style/issues/191. (#1346, @MichaelChirico) * `undesirable_function_linter()` and `undesirable_operator_linter()` now produce an error if empty vector of undesirable functions or operators is provided (#1867, @IndrajeetPatil). * New linters which are also included as defaults (see "New linters" for more details): + `indentation_linter()` + `quotes_linter()` + `unnecessary_concatenation_linter()` + `whitespace_linter()` * `lint_package()` also looks for files in `exec/` (#1950, @jmaspons). ## New and improved features * New `get_r_string()` helper to get the R-equivalent value of a string, especially useful for R-4-style raw strings. Previously an internal `lintr` helper, now exported to facilitate writing custom linters (#1493, @MichaelChirico). * `object_usage_linter()` improves lint metadata when detecting undefined infix operators, e.g. `%>%` or `:=` (#1497, @MichaelChirico) * `unused_import_linter()` can detect datasets from imported packages and no longer warns when a package is imported only for its datasets (#1545, @IndrajeetPatil). * When a linter triggers an error, `lint()` will provide a more actionable summary of where the error occurred, particularly useful for cases like `lint_package()` where both the responsible file and the responsible linter would be unknown (@MichaelChirico). Typically, linters should not themselves cause R to stop -- syntax errors lead to error lints, for example. Please report such failures as they are likely bugs. * `pipe_continuation_linter()` recognizes violations involving the native R pipe `|>` (#1609, @MichaelChirico) * `paste_linter()` also catches usages like `paste(rep("*", 10L), collapse = "")` that can be written more concisely as `strrep("*", 10L)` (#1108, @MichaelChirico) * `spaces_inside_linter()` produces lints for spaces inside `[[` (#1673, @IndrajeetPatil). * `sprintf_linter()` also applies to `gettextf()` (#1677, @MichaelChirico) * Documentation for all linters contains examples of code that does and does not produce lints (#1492, @IndrajeetPatil). * `implicit_integer_linter()` gains parameter `allow_colon` to skip lints on expressions like `1:10` (#1155, @MichaelChirico) * `infix_spaces_linter()` supports the native R pipe `|>` (#1793, @AshesITR) * `unnecessary_concatenation_linter()` (f.k.a. `unneeded_concatenation_linter()`) no longer lints on `c(...)` (i.e., passing `...` in a function call) when `allow_single_expression = FALSE` (#1696, @MichaelChirico) * `object_name_linter()` gains parameter `regexes` to allow custom naming conventions (#822, #1421, @AshesITR) * `literal_coercion_linter()` reports a replacement in the lint message, e.g. code like `as.integer(1)` will suggest using `1L` instead, and code like `as.numeric(NA)` will suggest using `NA_real_` instead (#1439, @MichaelChirico) * Added `format()` functions for `lint` and `lints` (#1784, @AshesITR) * `all_linters()` function provides an easy way to access all available linters (#1843, @IndrajeetPatil) * `missing_argument_linter()` allows missing arguments in `quote()` calls (#1889, @IndrajeetPatil). * `get_source_expressions()` correctly extracts indented code chunks from R Markdown documents, which helps avoid spurious lints related to whitespace (#1945, @MichaelChirico). The convention taken is that, within each chunk, all code is anchored relative to the leftmost non-whitespace column. * `available_linters()` gives priority to `tags` over `exclude_tags` in the case of overlap. In particular, this means that `available_linters(tags = "deprecated")` will work to return deprecated linters without needing to specify `exclude_tags` (#1959, @MichaelChirico). * The {lintr} configuration file is now searched in the system's user configuration path; the lintr config filename can also be configured explicitly by setting the environment variable `R_LINTR_LINTER_FILE` (#460, @klmr) * Errors in the {lintr} configuration file now produce more informative error messages (#886, @AshesITR) ### New linters * `matrix_apply_linter()` recommends use of dedicated `rowSums()`, `colSums()`, `colMeans()`, `rowMeans()` over `apply(., MARGIN, sum)` or `apply(., MARGIN, mean)`. The recommended alternative is much more efficient and more readable (#1869, @Bisaloo). * `unnecessary_lambda_linter()`: detect unnecessary lambdas (anonymous functions), e.g. `lapply(x, function(xi) sum(xi))` can be `lapply(x, sum)` and `purrr::map(x, ~quantile(.x, 0.75, na.rm = TRUE))` can be `purrr::map(x, quantile, 0.75, na.rm = TRUE)`. Naming `probs = 0.75` can further improve readability (#1531, #1866, @MichaelChirico, @Bisaloo). * `redundant_equals_linter()` for redundant comparisons to `TRUE` or `FALSE` like `is_treatment == TRUE` (#1500, @MichaelChirico) * `lengths_linter()` for encouraging usage of `lengths(x)` instead of `sapply(x, length)` (and similar) * `function_return_linter()` for handling issues in function `return()` statements. Currently handles assignments within the `return()` clause, e.g. `return(x <- foo())` (@MichaelChirico) * `boolean_arithmetic_linter()` for identifying places where logical aggregations are more appropriate, e.g. `length(which(x == y)) == 0` is the same as `!any(x == y)` or even `all(x != y)` (@MichaelChirico) * `for_loop_index_linter()` to prevent overwriting local variables in a `for` loop declared like `for (x in x) { ... }` (@MichaelChirico) * `is_numeric_linter()` for redundant checks equivalent to `is.numeric(x)` such as `is.numeric(x) || is.integer(x)` or `class(x) %in% c("numeric", "integer")` (@MichaelChirico) * `empty_assignment_linter()` for identifying empty assignments like `x = {}` that are more clearly written as `x = NULL` (@MichaelChirico) * `unnecessary_placeholder_linter()` for identifying where usage of the {magrittr} placeholder `.` could be omitted (@MichaelChirico) * `routine_registration_linter()` for identifying native routines that don't use registration (`useDynLib` in the `NAMESPACE`; @MichaelChirico) * `indentation_linter()` for checking that the indentation conforms to 2-space Tidyverse-style (@AshesITR and @dgkf, #1411, #1792, #1898). * `unnecessary_nested_if_linter()` for checking unnecessary nested `if` statements where a single `if` statement with appropriate conditional expression would suffice (@IndrajeetPatil and @AshesITR, #1778). * `implicit_assignment_linter()` for checking implicit assignments in function calls (@IndrajeetPatil and @AshesITR, #1777). * `quotes_linter()` is a generalized version of (now deprecated) `single_quotes_linter()`. It accepts an argument `delimiter` to specify whether `"` or `'` should be the accepted method for delimiting character literals. The default, `"`, reflects the Tidyverse style guide recommendation and matches the behavior of `single_quotes_linter()`. * `unnecessary_concatenation_linter()` is simply `unneeded_concatenation_linter()`, renamed. * `consecutive_assertion_linter()` (f.k.a. `consecutive_stopifnot_linter()`) now lints for consecutive calls to `assertthat::assert_that()` (as long as the `msg=` argument is not used; #1604, @MichaelChirico). * `whitespace_linter()` is simply `no_tab_linter()`, renamed. In the future, we plan to extend it to work for different whitespace preferences. ## Notes * {lintr} now depends on R version 3.5.0, in line with the tidyverse policy for R version compatibility. * `lint()` continues to support Rmarkdown documents. For users of custom .Rmd engines, e.g. `marginformat` from {tufte} or `theorem` from {bookdown}, note that those engines must be registered in {knitr} prior to running `lint()` in order for {lintr} to behave as expected, i.e., they should be shown as part of `knitr::knit_engines$get()`. For {tufte} and {bookdown} in particular, one only needs to load the package namespace to accomplish this (i.e., minimally `loadNamespace("tufte")` or `loadNamespace("bookdown")`, respectively, will register those packages' custom engines; since `library()` also runs `loadNamespace()`, running `library()` will also work). Note further that {tufte} only added this code to their `.onLoad()` recently after our request to do so (see https://github.com/rstudio/tufte/issues/117). Therefore, ensure you're using a more recent version to get the behavior described here for {tufte}. More generally, there is no requirement that `loadNamespace()` will register a package's custom {knitr} engines, so you may need to work with other package authors to figure out a solution for other engines. Thanks to Yihui and other developers for their helpful discussions around this issue (#797, @IndrajeetPatil). * The output of `lint()` and `Lint()` gain S3 class `"list"` to assist with S3 dispatch (#1494, @MichaelChirico) + As a corollary, we now register an `as_tibble` method for class `lints`, conditional on {tibble} availability, to avoid dispatching to the `list` method which does not work with `lint()` output (#1997, @MichaelChirico) * `object_usage_linter()` gives a more helpful warning when a `glue()` expression fails to evaluate (#1985, @MichaelChirico) * The documentation of `object_name_linter()` now describes how `"symbols"` works when passed to the `styles` parameter (#1924, @hedsnz). # lintr 3.0.2 * Fix test to avoid leaving behind cache files in the global cache directory. # lintr 3.0.1 * Skip multi-byte tests in non UTF-8 locales (#1504) * `modify_defaults()` no longer uses the mistaken `"lintr_function"` S3 class, instead applying the `"linter"` class also common to `Linter()`. `Linter()` also includes `"function"` in the S3 class of its output to facilitate S3 dispatch to `function` methods where appropriate (#1392, @MichaelChirico). ## Changes to defaults * `brace_linter()` allows opening curly braces on a new line when there is a comment ending the preceding line (#1433 and #1434, @IndrajeetPatil). * `seq_linter()` produces lint for `seq(...)`, since it also cannot properly handle empty edge cases (#1468, @IndrajeetPatil). * `seq_linter()` additionally lints on `1:n()` (from {dplyr}) and `1:.N` (from {data.table}) (#1396, @IndrajeetPatil). * `literal_coercion_linter()` lints {rlang}'s atomic vector constructors (i.e., `int()`, `chr()`, `lgl()`, and `dbl()`) if the argument is a scalar (#1437, @IndrajeetPatil). * `redundant_ifelse_linter()`'s lint message correctly suggests negation when the `yes` condition is `0` (#1432, @IndrajeetPatil). * `seq_linter()` provides more specific replacement code in lint message (#1475, @IndrajeetPatil). ## New and improved features * New `sort_linter()` to detect `x[order(x)]` and recommend the faster and clearer alternative: `sort(x)` (#1528, @Bisaloo) * `unreachable_code_linter()` ignores trailing comments if they match a closing nolint block (#1347, @AshesITR). * New `function_argument_linter()` to enforce that arguments with defaults appear last in function declarations, see the [Tidyverse design guide](https://design.tidyverse.org/required-no-defaults.html) (#450, @AshesITR). * New `allow_trailing` argument added to `assignment_linter()` to check when assignment operators are at the end of a line, and the value is on the following line (#1491, @ashbaldry) * New `sarif_output()` function to output lints to SARIF output (#1424, @shaopeng-gh) * `commented_code_linter()` now lints commented argument code, containing a trailing comma, as well (#386, @AshesITR). For example a comment containing `# na.rm = TRUE,` now triggers a lint. ## Bug fixes * `object_length_linter()` does not fail in case there are dependencies with no exports (e.g. data-only packages) (#1424, #1509, @IndrajeetPatil). * `get_source_expressions()` no longer fails on R files that match a knitr pattern (#743, #879, #1406, @AshesITR). * Parse error lints now appear with the linter name `"error"` instead of `NA` (#1405, @AshesITR). Also, linting no longer runs if the `source_expressions` contain invalid string data that would cause error messages in other linters. in other linters. * Prevent `lint()` from hanging on Rmd files with some syntax errors (#1443, @MichaelChirico). * `get_source_expressions()` no longer omits trailing non-code lines from knitr files (#1400, #1415, @AshesITR). This fixes the location information for `trailing_blank_lines_linter()` in RMarkdown documents without terminal newlines. * The `vignette("lintr")` incorrectly cited `exclude` as the key for setting file exclusions in `.lintr` when it is actually `exclusions`. (#1401, @AshesITR) * Fixed file exclusion detection in `lint_dir()` so it no longer errors if there are multiple exclusions or no global exclusions configured for a single file (#1413, #1442, @AshesITR). ## Other changes * The minimum needed version for soft dependency `{withr}` has been bumped to `2.5.0` (#1404, @IndrajeetPatil). * Changed the deprecation warning for `with_defaults()` to also mention `modify_defaults()` (#1438, @AshesITR). * Quarto files (`.qmd`) were supported out of the box. The documentation and the testing infrastructure are updated to reflect this (#1486, @IndrajeetPatil). # lintr 3.0.0 ## Breaking changes * All linters are now function factories (i.e., functions that return functions) for consistency. Previously, only linters with customizable parameters were factories (#245, @fangly, @AshesITR, and @MichaelChirico). This means that usage such as `lint("file.R", seq_linter)` should be updated to `lint("file.R", seq_linter())`, and the following update for custom linters: ```r my_custom_linter <- function(source_expression) { ... } # becomes my_custom_linter <- function() Linter(function(source_expression) { ... }) ``` * Exclusions specified in the `.lintr` file are now relative to the location of that file and support excluding entire directories (#158, #438, @AshesITR). * Removed long-deprecated linters (they've been marked as deprecated since v1.0.1 in 2017): + `absolute_paths_linter()` + `camel_case_linter()` + `multiple_dots_linter()` + `snake_case_linter()` + `trailing_semicolons_linter()` * Removed `return()` from `all_undesirable_functions` because early returns (which often improve readability and reduce code complexity) require explicit use of `return()`. Follow #1100 for an upcoming `return_linter()` to lint unnecessary `return()` statements (#1146, @AshesITR). Note that you can replicate old behavior by supplying `return` as a custom undesirable function: `undesirable_function_linter(c(all_undesirable_functions, list(return = NA)))` ## Deprecations * Lints are now marked with the name of the `linter` that caused them instead of the name of their implementation function. Deprecated the obsolete `linter` argument of `Lint()` (#664, #673, #746, @AshesITR). Downstream custom linters should follow suit. * Renamed `semicolon_terminator_linter()` to `semicolon_linter()` for better consistency. `semicolon_terminator_linter()` survives but is marked for deprecation. The new linter also has a new signature, taking arguments `allow_compound` and `allow_trailing` to replace the old single argument `semicolon`, again for signature consistency with other linters. * The following linters were subsumed into `brace_linter()` and are now deprecated; see the item on `brace_linter()` below: + `closed_curly_linter()` + `open_curly_linter()` + `paren_brace_linter()` * The `...` argument for `lint()`, `lint_dir()`, and `lint_package()` has been promoted to an earlier position to better match the [Tidyverse design principle](https://design.tidyverse.org/required-no-defaults.html) of data->descriptor->details. This change enables passing objects to `...` without needing to specify non-required arguments, e.g. `lint_dir("/path/to/dir", linter())` now works without the need to specify `relative_path`. This affects some code that uses positional arguments (#935, @MichaelChirico). + For `lint()`, `...` is now the 3rd argument, where earlier this was `cache`. + For `lint_dir()` and `lint_package()`, `...` is now the 2nd argument, where earlier this was `relative_path`. * Deprecated argument `source_file` to exported functions `with_id()` and `ids_with_token()`. It has been renamed to `source_expression` to better reflect that this argument is typically the output of `get_source_expressions()`. For now, the old argument `source_file` can still be used (with warning). The now-private functional versions of many linters also underwent the same renaming (`source_file` -> `source_expression`). This has no direct effect on packages importing lintr, but is mentioned in case custom linters imitating `lintr` style had also adopted the `source_file` naming and want to adapt to keep in sync. * Deprecated `with_defaults()` in favor of `linters_with_defaults()`, and add `modify_defaults()` which is intended to be used more generally to modify (i.e., extend, trim, and/or update) a list of defaults. Note that the argument corresponding to `with_defaults()`'s `default=` is called `defaults=` (i.e., pluralized) in both of these, and that usage like `with_defaults(default = NULL, ...)` should be converted to `linters_with_defaults(defaults = list(), ...)` (#1029, #1336, #1361, @AshesITR and @michaelchirico). * Deprecated the `find_line()` and `find_column()` helpers from the item-level `expressions` returned with `get_source_expressions()`. These helpers were typically associated with regex-based logic for building linters, which is rarely needed and prone to false positives; now that lintr almost exclusively uses XPath-based logic for linters, these are no longer necessary (#1373, @MichaelChirico). ## Other changes to defaults ### Updates to `default_linters` * New `brace_linter()` which combines several curly brace related linters, deprecating the following predecessors (#1041, @AshesITR): + `closed_curly_linter()`; both now also allow `}]` in addition to `})` and `},` as exceptions, i.e., `}` doesn't need to be on its own line if paired with a closing square bracket, a closing parenthesis, or a comma. Also improved lint metadata so that source markers land at the closing brace instead of the closing parenthesis to improve the experience of fixing the lint (#583, @AshesITR). + `open_curly_linter()`; both also no longer lint unnecessary trailing whitespace (use `trailing_whitespace_linter()` for this) and also allow `(`, `,`, and `%>%` on preceding lines as exceptions, i.e., `{` can be alone on a line if the previous line is terminated with an opening parenthesis, a comma, or a pipe (`%>%`) (#487, #1028, @AshesITR). + `paren_brace_linter()`; `brace_linter()` also lints `if`/`else` and `repeat` with missing whitespace. + `brace_linter()` also newly enforces the following rules surrounding curly braces (originally Google linters, see below): - Require `else` to come on the same line as the preceding `}`, if present (#884, @MichaelChirico). - Require functions spanning multiple lines to use curly braces (#987, @MichaelChirico). - Require balanced usage of `{}` in `if`/`else` conditions, i.e., if the `if` branch uses braces, then so must the `else` branch, and _vice versa_ (#983, @MichaelChirico). * New `paren_body_linter()` checks that there is a space between a right parenthesis and a body expression (#809, @kpagacz). * Added `semicolon_linter()` as a default because it enforces a tidyverse style guide rule (#683, @AshesITR). * `assignment_linter()` (#915, @MichaelChirico): + Right assignments are now linted by default (`->` and `->>`). + New argument `allow_cascading_assign` (`TRUE` by default) toggles whether to lint `<<-` and `->>`. + New argument `allow_right_assign` (`FALSE` by default) toggles whether to lint `->` and `->>`. * `commented_code_linter()`: use the parse tree to find comments, eliminating some false positives (#451, @AshesITR). * `equals_na_linter()` (#545, @MichaelChirico): + Extended to lint `x != NA` (before, only `==` was caught) and `NA == x` (before, only `NA` on RHS was caught). + Extended to skip usages in comments like `is.na(x) # use is.na(x), not x == NA`. * `function_left_parentheses_linter()`: improved location information (#1266, #1267, @AshesITR). * `infix_spaces_linter()`: + Added argument `allow_multiple_spaces` (`TRUE` by default) which toggles whether to generate a lint for operators used with multiple spaces, e.g. `x + 2`. The default setting allows extra spacing to be used to increase line-to-line alignment (#940, @f-ritter and @MichaelChirico). + Extended so that usages like `a~b` and `function(a=1) { ... }` are linted (#930, #michaelchirico). + Added argument `exclude_operators` to disable lints on selected infix operators. By default, all "low-precedence" operators throw lints; see `?infix_spaces_linter` for an enumeration of these. (#914, @MichaelChirico). + Add an exception for `/` usage in `box::use()` declarations (#1087, @klmr). * `line_length_linter()`: place the source marker at the margin of the affected line to improve user experience during de-linting -- just press Return (#735, @AshesITR).* * `no_tab_linter()`: use more reliable matching (e.g., excluding matches found in comments; #441, @russHyde). * `object_length_linter()`: correctly detect generics and only count the implementation class towards the length. This prevents false positive lints in the case of long generic names, e.g. `very_very_very_long_generic_name.short_class` no longer produces a lint (#871, @AshesITR). * `object_name_linter()`: + Improved generic detection -- in user-defined method `my_method.upstream.class`, `upstream.class` no longer throws a lint because the generic (`my_method`) properly uses `snake_case` (#737, @AshesITR). + Exclude special R namespace hook functions such as `.onLoad()` (#500, #614, @AshesITR and @MichaelChirico). + Correctly detect imported functions when linting packages (#642, @AshesITR). + Correctly detect assignment generics like `names<-.class_name` (#843, @jonkeane). + Added new styles `"symbols"` and `"SNAKE_CASE"` (#494, #495, #615, #670, @MichaelChirico and @AshesITR). - `"symbols"` is a new default style which won't lint all-symbol object names. In particular, that means operator names like `%+%` are allowed. + No longer lints names used in `$` extractions (#582, @AshesITR). * `object_usage_linter()`: + Detect global variables if there are top-level dollar-assignments (#666, @AshesITR). + Report usage warnings spanning multiple lines (#507, @AshesITR). + Detect usages inside `glue::glue()` constructs (#942, @AshesITR). + Extended to include functions assigned with `=` instead of `<-` (#1081, @MichaelChirico). + Detect functions exported by packages that are explicitly attached using `library()` or `require()` calls (#1127, @AshesITR). + Improved location information in some cases where the previous regex-based approach didn't work, e.g. unicode characters in variable names (#1285, @AshesITR). + Correctly detect functions declared within `assign()` and `setMethod()` (#1322, @AshesITR). * `spaces_inside_linter()`: ignore spaces preceding trailing comments (#636, @MichaelChirico). * `T_and_F_symbol_linter()`: + Added as a default because it enforces a tidyverse style guide rule (#517, @AshesITR). + No longer lint occurrences of `T` and `F` when used for subsetting, and give a better message when used as variable names (#657, @AshesITR). * `trailing_blank_lines_linter()`: + Extended to lint files without a terminal newline (#675, @AshesITR). + Also, running `lint()` on a file without a terminal newline no longer throws a `warning()`. * `trailing_whitespace_linter()`: + Extended to also lint completely blank lines by default (#1044, @AshesITR). + Added argument `allow_empty_lines` (`FALSE` by default) to toggle this behavior. + Improved so that trailing whitespace inside string literals does not trigger a lint (#1045, @AshesITR). + Added argument `allow_in_strings` (`TRUE` by default) to toggle this behavior. * `undesirable_function_linter()`: + Added new functions to `default_undesirable_functions` related to debugging (#876, @MichaelChirico): - `browser()` - `debug()` - `debugcall()` - `debugonce()` - `trace()` - `untrace()` + No longer lints `library()` and `require()` calls attaching a package with an undesired name, e.g. `library(foo)` (#814, @kpagacz and @MichaelChirico). + No longer lints undesirable symbols if they are used as names in `$` extractions (#1050, @AshesITR). + Added more explanation why certain functions might be undesirable and what alternatives to use; ditto for `undesirable_operator_linter()` (#1133, #1146, #1159, @AshesITR). ### Other noteworthy changes * `cyclocomp_linter()`: set the default `complexity_limit` to 15. This brings the default into sync with what is enforced via `default_linters` (#693, @AshesITR). * `lint_package()` now lints files in the `demo` directory by default (#703, @dmurdoch). * Moved the default lintr cache directory from `~/.R/lintr_cache` (which was a violation of CRAN policy) to `R_user_dir("lintr", "cache")`. Note that 3.0.0 is a major version update and invalidates the old cache anyway, so it can be safely deleted (#1062, @AshesITR). ## New and improved features ### New linters * `backport_linter()` for detecting mismatched R version dependencies (#506, #1316, #1318, #1319, @MichaelChirico and @AshesITR). * `duplicate_argument_linter()` similarly checks that there are no duplicate arguments supplied to function calls (#850, @renkun-ken). * `missing_argument_linter()` to check for empty (missing) arguments in function calls (#563, #1152, @renkun-ken and @AshesITR). * `missing_package_linter()` to check if packages in calls to `library()` and friends are missing (#536, #1037, @renkun-ken and @MichaelChirico). * `namespace_linter()` to check for common mistakes in `pkg::symbol` usages (#548, @renkun-ken). * `package_hooks_linter()` to run a series of checks also done by `R CMD check` on the `.onLoad()`, `.onAttach()`, `.Last.lib()` and `.onDetach()` hooks (#882, @MichaelChirico). * `pipe_call_linter()` to enforce that all steps of `magrittr` pipelines use explicit calls instead of symbols, e.g. `x %>% mean()` instead of `x %>% mean` (#801, @MichaelChirico). * `sprintf_linter()` to check for common mistakes in `sprintf()` usage (#544, #624, @renkun-ken and @AshesITR). * `unused_import_linter()` to detect unnecessary `library()` calls in R scripts (#239, @jimhester, @AshesITR). #### Google linters Google is a heavy user of lintr internally, and has developed a large set of linters improving code consistency and correcting common R usage mistakes. This release includes many of these linters that are of general interest to the broader R community. More will be included in future releases. See, e.g. #884, #979, #998, #1011, #1016, #1036, #1051, #1066, and #1067; special thanks to @MichaelChirico and @michaelquinn32. * `any_duplicated_linter()` Require usage of `anyDuplicated(x) > 0L` over `any(duplicated(x))` and similar. * `any_is_na_linter()` Require usage of `anyNA(x)` over `any(is.na(x))`. * `class_equals_linter()` Prevent comparing `class(x)` with `==`, `!=`, or `%in%`, where `inherits()` is typically preferred. * `condition_message_linter()` Prevent condition messages from being constructed like `stop(paste(...))` (where just `stop(...)` is preferable). * `conjunct_test_linter()` Require usage of `expect_true(x); expect_true(y)` over `expect_true(x && y)` and similar. * `consecutive_stopifnot_linter()` Require consecutive calls to `stopifnot()` to be unified into one. * `expect_comparison_linter()` Require usage of `expect_gt(x, y)` over `expect_true(x > y)` and similar. * `expect_identical_linter()` Require usage of `expect_identical()` by default, and `expect_equal()` only by exception. * `expect_length_linter()` Require usage of `expect_length(x, n)` over `expect_equal(length(x), n)` and similar. * `expect_named_linter()` Require usage of `expect_named(x, n)` over `expect_equal(names(x), n)` and similar. * `expect_not_linter()` Require usage of `expect_false(x)` over `expect_true(!x)`, and _vice versa_. * `expect_null_linter()` Require usage of `expect_null(x)` over `expect_equal(x, NULL)` and similar. * `expect_s3_class_linter()` Require usage of `expect_s3_class(x, k)` over `expect_equal(class(x), k)` and similar. * `expect_s4_class_linter()` Require usage of `expect_s4_class(x, k)` over `expect_true(methods::is(x, k))`. * `expect_true_false_linter()` Require usage of `expect_true(x)` over `expect_equal(x, TRUE)` and similar. * `expect_type_linter()` Require usage of `expect_type(x, t)` over `expect_equal(typeof(x), t)` and similar. * `fixed_regex_linter()` Require `fixed = TRUE` or `stringr::fixed()` for regular expressions that can be expressed statically, e.g. `strsplit(x, "[.]")` can be `strsplit(x, ".", fixed = TRUE)`. + Added parameter `allow_grepl` (default `FALSE`) to toggle whether `grepl()` usages should be linted. These might be treated separately because `grepl("^x", NA)` is `FALSE`; the `startsWith()` equivalent to get `FALSE` for missing input is clunkier, but more explicit: `!is.na(x) & startsWith(x, string)` (#1376, @MichaelChirico). * `ifelse_censor_linter()` Require usage of `pmax()` / `pmin()` where appropriate, e.g. `ifelse(x > y, x, y)` is `pmax(x, y)`. * `inner_combine_linter()` Require inputs to known-vectorized functions to be combined first rather than later, e.g. `as.Date(c(x, y))` over `c(as.Date(x), as.Date(y))`. * `literal_coercion_linter()` Require using correctly-typed literals instead of direct coercion, e.g. `1L` instead of `as.numeric(1)`. * `nested_ifelse_linter()` Prevent nested calls to `ifelse()` like `ifelse(A, x, ifelse(B, y, z))`, and similar. * `numeric_leading_zero_linter()` Require a leading `0` in fractional numeric constants, e.g. `0.1` instead of `.1`. * `outer_negation_linter()` Require usage of `!any(x)` over `all(!x)` and `!all(x)` over `any(!x)`. * `paste_linter()` lint for common mis-use of `paste()` and `paste0()`: + `paste0()` encouraged instead of `paste(sep = "")`. + `toString()` or `glue::glue_collapse()` encouraged instead of `paste(x, collapse = ", ")`. + Lint `sep=` passed to `paste0()` -- typically a mistake. * `redundant_ifelse_linter()` Prevent usage like `ifelse(A & B, TRUE, FALSE)` or `ifelse(C, 0, 1)` (the latter is `as.numeric(!C)`). * `regex_subset_linter()` Require usage of `grep(ptn, x, value = TRUE)` over `x[grep(ptn, x)]` and similar. * `string_boundary_linter()` Require usage of `startsWith(x, ptn)` over `grepl("^ptn", x)` or `substr(x, 1, 3) == ptn` and similar. * `strings_as_factors_linter()` Check for code designed to work before and after the `stringsAsFactors = FALSE` default change in R 4.0 by examining code for `data.frame()` usages susceptible to assumptions about the default value of `stringsAsFactors=`. * `system_file_linter()` Prevent usage like `file.path(system.file("A", package = "pkg"), "B")` where simply `system.file("A", "B", package = "pkg")` is more concise and readable. * `unreachable_code_linter()` Prevent code after `return()` and `stop()` statements that will never be reached (extended for #1051 thanks to early user testing, thanks @bersbersbers!). * `vector_logic_linter()` Require use of scalar logical operators (`&&` and `||`) inside `if()` conditions and similar. * `yoda_test_linter()` Require usage of `expect_identical(x, 1L)` over `expect_equal(1L, x)` and similar. ### Other features and improvements * **Documentation**: Reorganize linter documentation into new tag-based Rd pages (#888, #1015, @AshesITR). + Each linter has its own help page. + `?linters` also links to tag help pages, collecting linters with a similar goal. + Each linter can have multiple tags. + `available_linters()`: new function to list available linters and their tags. This feature is extensible by package authors providing add-on linters for {lintr}. + `available_tags()`: new function to list available tags. + `linters_with_tags()`: new function to help build a list of linters using tags. * **Encodings**: lintr now supports non-system character Encodings. The correct encoding is auto-detected from .Rproj or DESCRIPTION files in your project. Override the default in the `encoding` setting of lintr (#752, #782, @AshesITR). * **Jenkins CI**: Support for writing comments to GitHub repo when running in Jenkins CI (#488, @fdlk). * **Performance**: Optimized performance-critical functions in lintr, such as `get_source_expressions()` resulting in about 2x speedup in our test suite and even more for complex files (#1169, #1197, #1200, #1201, #1214, @MichaelChirico and @AshesITR). Average `lint_package()` execution time is down about 30% and the median package sees about 40% improvement. * **Raw strings**: Several linters tightened internal logic to allow for raw strings like `R"( a\string )"` (#1034, #1285, @MichaelChirico and @AshesITR). * **Selective exclusion syntax**: New syntax to exclude only selected linters from certain lines or passages. Use `# nolint: linter_name, linter2_name.` or `# nolint start: linter_name, linter2_name.` in source files or named lists of line numbers in `.lintr`. Note the terminal `.` is required. Also allows for partial matching as long as the supplied prefix is unique, e.g. `# nolint: infix_spaces.` works to exclude `infix_spaces_linter` (#605, #872, @AshesITR). + Added the linter name to lintrs output to facilitate discovery of the correct name (#1357, @AshesITR). * Improved S3 generic detection for non-standard S3 generics where `UseMethod()` is called after several preceding expressions (#846, @jonkeane). * `extraction_operator_linter()`: no longer lint `x[NULL]` (#1273, @AshesITR). * `is_lint_level()`: new exported helper for readably explaining which type of expression is required for a custom linter. Some linters are written to require the full file's parse tree (for example, `single_quotes_linter()`). Others only need single expressions, which is more cache-friendly (most linters are written this way to leverage caching) (#921, @MichaelChirico). * `lint_dir()` excludes the `renv` and `packrat` directories by default (#697, @AshesITR). * `lint()`: new optional argument `text` for supplying a line or lines directly, e.g. if the file is already in memory or linting is being done _ad hoc_ (#503, @renkun-ken). * `seq_linter()`: improve lint message to be clearer about the reason for linting (#522, @MichaelChirico). * `unneeded_concatenation_linter()`: + Correctly considers arguments in pipelines (`%>%` or `|>`; #573, #1270, @michaelquinn32 and @AshesITR). + New argument `allow_single_expression`, default `TRUE`, toggling whether `c(x)` should be linted, i.e., a call to `c()` with only one entry which is not a constant. In some such cases, `c()` can simply be dropped, e.g. `c(a:b)`; in others, the parentheses are still needed, e.g. `-c(a:b)` should be `-(a:b)`; and in still others, `c()` is used for the side-effect of stripping attributes, e.g. `c(factor(letters))` or `c(matrix(1:10, 5, 2))`. In this last case, `c()` can (and should) in most cases be replaced by `as.vector()` or `as.integer()` for readability. In fact, we suspect it is _always_ preferable to do so, and may change the default to `allow_single_expression = FALSE` in the future. Please report your use case if `as.vector()` does not suit your needs (#1344, @MichaelChirico). * `use_lintr()`: new exported helper for creating a minimal `.lintr` configuration (#902, @AshesITR). * `xml_nodes_to_lints()`: new exported helper for converting `xml_node` objects obtained using linter logic expressed in XPath into `Lint` objects (#1124, #1216, #1234, @MichaelChirico and @AshesITR). ## Bug fixes * **RStudio**: Source markers are cleared when there are no lints (#520, @AshesITR). * Error message for mismatched starts and ends of exclusion ranges is now more helpful. (#571, #860, @AshesITR and @danielinteractive). * Improved location information for R parse errors (#894, #892, @renkun-ken and @AshesITR). * `get_source_expressions()`: + Fix possible error on invalid XML produced by `xmlparsedata::xml_parse_data()` (#559, @renkun-ken). + Fix handling zero-length variable name error (#566, @renkun-ken). + Malformed Rmd files now cause a lint instead of an error (#571, @AshesITR). + No longer fails if `getParseData()` returns a truncated (invalid) Unicode character as parsed text (#815, @leogama). + Fixes the `text` value for `STR_CONST` nodes involving 1- or 2-width octal escapes (e.g. `"\1"`) to account for an R parser bug (https://bugs.r-project.org/show_bug.cgi?id=18323; #1056, @MichaelChirico). + Handle Rmd inputs containing unevaluated code blocks with named format specifiers (#472, @russHyde). * `line_length_linter()`: fix a bug causing duplicate lints for lines containing multiple expressions (#681, @AshesITR). * `lint_package()`: + Warns and returns `NULL` if no package is found (instead of giving a peculiar error message; #776, @MichaelChirico). + Stricter about what is considered to be a package -- folders named `DESCRIPTION` are ignored (#702, @MichaelChirico). * `linters_with_defaults()` (formerly `with_defaults()`): + No longer duplicates the `lintr_function` class when it is already present (#511, @AshesITR). + Warns if a named argument is `NULL` but its name is not in `defaults` (#1049, @AshesITR). * `linters_with_defaults()` handles automatic naming of very long arguments correctly (#774, @MichaelChirico). * `save_cache()` will now recursively create the cache directory; this avoids errors that could arise if any parent directories do not exist (#60, @dankessler). * `spaces_left_parentheses_linter()`: fix a bug causing warnings like "In `parent == parent[before_operator_idx]` longer object length is not a multiple of shorter object length" in nested expressions (#654, @AshesITR). ## Internals * Added a new, more restrictive test workflow - `test-package` - that fails on warnings emitted by tests (#1263, #1272, @AshesITR). * Added a secondary, more restrictive lint workflow - `lint-changed-files` - for newly written / modified code (#641, @dragosmg). * Several optional `Imported` packages have become `Suggested` dependencies: `httr`, `testthat`, and `rstudioapi`. This should allow snappier CI builds for usages not relying on some more "peripheral" features of the package. * Special thanks to @bersbersbers for early testing on the 3.0.0 changes. * Switched CI from Travis to GitHub Actions, using the full tidyverse recommended `R CMD check`. Code coverage and linting are implemented using separate GitHub Actions workflows (#572, @dragosmg). * Updated R CMD GitHub Actions workflow to check for R 3.6 on Ubuntu, instead of R 3.3, and for R 4.0 on Windows, instead of R 3.6 (#803, @ dragosmg). * `lintr` now uses the 3rd edition of `testthat` (@MichaelChirico, @AshesITR, #910, #967). # lintr 2.0.1 ## New features * lintr now supports GitHub Actions and will print the lints as warning messages if lints are printed during an action. * `lint_package()` will now lint vignettes and data-raw by default (#447, @AshesITR). * `lint_dir()` will now include Rmd and Rnw files by default (@AshesITR). ## Minor fixes and features * `single_quote_linter()` no longer causes a print issue when open quote appears at a column > than close quote (#457, @jamieRowen) * `absolute_path_linter()` and `nonportable_path_linter()` now handle file-paths that are wrapped with double-quotes (#433, #437, @russHyde). * `get_source_expressions()` has been changed to handle `expr_or_assign_or_help` tokens arising when parsing code containing equals-assignments in R-devel (#403, #456, @russHyde). * `object_usage_linter` has been changed to ensure lint-position is indicated relative to the start of the file, rather than the start of a defining function (#432, @russHyde). * `commas_linter` now allows spaces to come before a comma when used to denote a fall-through in a switch statement (#499, @MrMallIronmaker) # lintr 2.0.0 lintr 2.0.0 is a major release, and incorporates development changes since the last major release (1.0.0) in 2016-04-16. ## Deprecated functions * Deprecated `camel_case_linter()`, `snake_case_linter()` and `multiple_dots_linter()` in favor of `object_name_linter()` which enforce the given style: snake_case, dotted.case, lowerCamelCalse, UpperCamelCase, alllowercase or ALLUPPERCASE (#59, @fangly). * Deprecated absolute_paths_linter() in favor of the new `absolute_path_linter()`, with a lax mode for fewer false positive lints (#199, @fangly). ## New linters * New `cyclocomp_linter()` identifies overly complex functions (#361, @fabian-s) * New `equals_na_linter()` (#143, #326, @jabranham) * New `extraction_operator_linter()` checks that the `[[` operator is used when extracting a single element from an object, not `[` (subsetting) nor `$` (interactive use) (@fangly). * New `function_left_parentheses_linter()` to check that there is no space between a function name and its left parentheses (#204, @jrnold). * New `implicit_integer_linter()` detects round numbers not declared as integers, i.e. 1 instead of 1L (@fangly). * New `nonportable_path_linter()` identifies paths constructed without file.path() (@fangly). * New `paren_brace_linter()` checks that there is a space between right parenthesis and an opening curly brace (@bfgray3, #242). * New `pipe_continuation_linter()` to ensure there is a space before %>% and newline afterwards (#216). * New `semicolon_terminator_linter()` reports semicolons at the end of a line (#147, @gaborcsardi) and between expressions (#181, @fangly). * New `seq_linter()`, finds `1:length(...)` (and similar) expressions (#155, @gaborcsardi) * New `todo_comment_linter()` lints TODOs (@fangly). * New `T_and_F_symbol_linter()` warns when using T and F instead of TRUE and FALSE (@fangly). * New `undesirable_operator_linter()` and `undesirable_function_linter()` lint uses of user-specified functions and operators (#48, #149, @fangly). * New `unneeded_concatenation_linter()` lints uses of c() with a constant or no arguments (@fangly). ## New functions for writing linters * Export `expect_lint()` (#178, #210) * Export `ids_with_token()` and `with_id()` (#297 @stufield) * linters can use the XML parse tree as well now, via the https://github.com/MangoTheCat/xmlparsedata package (#154, @gaborcsardi) ## New functions for users * New `lint_dir()` function to lint files under a given directory (@arekbee, #360) * New `summary.lints()` function to summarize the linter results (#260, #262, @wlandau). * New `checkstyle_output()` function to output lints to checkstyle XML output (#156, @joshkgold) ## Linter fixes * `closed_curly_linter()` now allows closing parenthesis or comma after closing curly brace (#167, @Enchufa2) * `commas_linter()` now handles missing arguments calls properly (#145) * `commented_code_linter()` now relaxed, it no longer lints comments within roxygen blocks and does not consider "-" an R operator to avoid too many false positives. * `function_left_parentheses_linter()` now allows spaces if a function starts with a left parenthesis (#311) * `no_tab_linter()` now reports proper line in all cases (#134, @fangly) * `object_length_linter()` argument `length` now defaults to 30 for consistency (#325 @DragosMG) * `object_name_linter()` now works when passed multiple styles (#341, @infotroph) * `object_usage_linter()` has been changed to better detect lexical scoping of global variables (#27, #336, #91, #382) * `object_usage_linter()` now respects `utils::globalVariables()`, so it can be used to avoid false positive warnings due to non-standard evaluation (#352) * `object_usage_linter()` now ignores top level calls that contain function definitions (#26). * `object_linter*()`s now only lint objects declared in the current file (#76, #108, #136, #191, #194, #201, @fangly). * `open_curly_linter()` and `closed_curly_linter()` now do not lint double curly syntax (#388) * `open_curly_linter()` now allows comments after the curly braces (#188) * `pipe_continuation_linter()` now behaves better in nested expressions, functions etc. (#366 @russHyde) * `space_inside_linter()` now reports proper line and column numbers (#203, @fangly) ## General improvements and fixes * `expect_lint()` now no longer shows Rstudio markers and error messages are correctly preserved (#180, #211, @fangly) * `Lint()` / `as.data.frame()` error now fixed (#179, @fangly). * `lint()` no longer errors with inline `\\Sexpr` (#127). * `lint()` no longer errors with '<% %>' constructs (#185). * `lint_package()` now works with the cache, as intended (#146, @schloerke) * `lint_package()` now excludes `R/RcppExports.R` by default (#282) * `lint_package()` now removes fully excluded files as soon as possible * lintr now looks up its configuration in any parent directories as well as the package directory (#238, #345) * `seq_linter` is now one of the default linters (#316). * Fix issue in lintr's compatibility with R-devel, due to to a new version of the PCRE library (#411.) * `read_settings()` now has a better error message when the config file does not end with a newline (#160, #189) * `expect_lint_free()` is now automatically skipped when run on covr (#287) * Now lintr only tries to generate comments if running in wercker or travis CI (#166) * Add support for overriding GitHub API Token via `GITHUB_TOKEN` environment variable (#63, @mattyb) * Config files are now also searched for in the users' home directory (#266, @randy3k) * Fixed crash caused by ambiguous cache file paths (#212, @fangly). * RStudio addins to lint current source and project (fixes #264, @JhossePaul) * Added proper handling of tab characters (fixes #44, @fangly) * lintr does not need the igraph package any more (#152, @gaborcsardi) * Fixed cache not saved in a directory other than requested (#213, @fangly) avoid reading and pre-processing of ignored files (@mwaldstein) * Allow for any number of `#` to start a comment. Useful in ESS (#299, @prosoitos) * R Markdown files that do not contain chunks are no longer treated as code (#370). * Fixed plain-code-block bug in Rmarkdown (#252, @russHyde) * Fixed bug where non-R chunks using {lang} `engine format` were parsed from R-markdown (#322, @russHyde) * Ensured `lintr` runs / installs / tests on R-3.6: pinned to github `xmlparsedata`; ensure vectors are length-1 when compared using `&&` and `||` (#363 #377 #384 #391, @russHyde). # lintr 1.0.3 * Fix tests to work with changes in the parser in R 3.6 # lintr 1.0.2 * Fix tests to work with upcoming testthat release. # lintr 1.0.1 * bugfix to work with knitr 1.16.7 * `expect_lint_free()` now is always skipped on CRAN. This is necessary because the non-binary R source may not be available when running tests on CRAN, and those tests may not be run in the package directory. # lintr 1.0.0 * bugfix to work with testthat 1.0.0 # lintr 0.3.3 * infix_spaces_linter now properly checks `=` in named arguments. (#130, @saurfang). * commas_linter now properly recognizes lints when preceded by a blank line and points to the missing space rather than the comma (#111, #129, @saurfang). * Make spaces_left_parentheses_linter more robust when determining `(` type (#128, @saurfang) * commented_code_linter (#83, @jackwasey) * Now trims long comments (#55, reported by @paulstaab) * Automatic commenting of Github commits and pull requests when linting on Travis-CI * expect_lint_free expectation can be added to testthat unit tests. * Robust configuration system and exclusion logic * Emacs and Sublime Text 3 plugins now available from their respective package repositories. * add `names.lints`, `split.lints` (#49, @ttriche) * Fixed bug that caused vim syntastic plugin not to work properly in windows (#46, @abossenbroek) * allow lintr customization per project using `.lintr` config files. * use `globalenv()` instead of `baseenv()` for default parent environment so that `methods` will be included. * do not check object usage if eval fails. Fixes (#24, reported by @fabian-s) * `trailing_whitespace_linter` was reporting the incorrect line number * Use RStudio source marker API to display lints (#37, @jjallaire) * Permit single quotes if they quote literal double quotes (#28, @jackwasey) * `# nolint` comments are respected with caching (#68, @krlmlr) * Properly handle all knitr document formats * Allow for (( when linting (#259, @nathaneastwood) * Remove ^ from infix spaces to conform with tidyverse. (#302, @nathaneastwood) # lintr 0.2.0 * Initial release lintr/inst/0000755000176200001440000000000014752763366012402 5ustar liggesuserslintr/inst/syntastic/0000755000176200001440000000000014752731051014405 5ustar liggesuserslintr/inst/syntastic/lintr.vim0000644000176200001440000000610314752731051016252 0ustar liggesusers"============================================================================ "File: lintr.vim "Description: Syntax checking plugin for syntastic.vim "Maintainer: Michael Chirico "License: This program is free software. It comes without any warranty, " to the extent permitted by applicable law. You can redistribute " it and/or modify it under the terms of the Do What The Fuck You " Want To Public License, Version 2, as published by Sam Hocevar. " See http://sam.zoy.org/wtfpl/COPYING for more details. " "============================================================================ " " Security: " " This checker runs the code in your file. This is probably fine if you " wrote the file yourself, but it can be a problem if you're trying to " check third party files. If you are 100% willing to let Vim run the " code in your file, set g:syntastic_enable_r_lintr_checker to 1 in " your vimrc to enable this checker: " let g:syntastic_enable_r_lintr_checker = 1 if exists("g:loaded_syntastic_r_lintr_checker") finish endif let g:loaded_syntastic_r_lintr_checker = 1 if !exists('g:syntastic_r_lintr_linters') let g:syntastic_r_lintr_linters = 'default_linters' endif if !exists('g:syntastic_r_lintr_cache') let g:syntastic_r_lintr_cache = 'FALSE' endif let s:save_cpo = &cpo set cpo&vim function! SyntaxCheckers_r_lintr_GetHighlightRegex(item) let term = matchstr(a:item['text'], "\\m'\\zs[^']\\+\\ze'") return term != '' ? '\V' . escape(term, '\') : '' endfunction function! SyntaxCheckers_r_lintr_IsAvailable() dict if !executable(self.getExec()) return 0 endif call system(self.getExecEscaped() . ' --slave --no-restore --no-save -e ' . syntastic#util#shescape('library(lintr)')) return v:shell_error == 0 endfunction function! SyntaxCheckers_r_lintr_GetLocList() dict if !exists('g:syntastic_enable_r_lintr_checker') || !g:syntastic_enable_r_lintr_checker call syntastic#log#error('checker r/lintr: checks disabled for security reasons; set g:syntastic_enable_r_lintr_checker to 1 to override') return [] endif let setwd = syntastic#util#isRunningWindows() ? 'setwd(''' . escape(getcwd(), '"\') . '''); ' : '' let makeprg = self.getExecEscaped() . ' --slave --no-restore --no-save' . \ ' -e ' . syntastic#util#shescape(setwd . 'suppressPackageStartupMessages(library(lintr)); ' . \ 'lint(cache = ' . g:syntastic_r_lintr_cache . ', commandArgs(TRUE), ' . g:syntastic_r_lintr_linters . ')') . \ ' --args ' . syntastic#util#shexpand('%') let errorformat = \ '%W%f:%l:%c: style: %m,' . \ '%W%f:%l:%c: warning: %m,' . \ '%E%f:%l:%c: error: %m,' call self.setWantSort(1) return SyntasticMake({ \ 'makeprg': makeprg, \ 'errorformat': errorformat, \ 'returns': [0] }) endfunction call g:SyntasticRegistry.CreateAndRegisterChecker({ \ 'filetype': 'r', \ 'name': 'lintr', \ 'exec': 'R' }) let &cpo = s:save_cpo unlet s:save_cpo " vim: set et sts=4 sw=4: lintr/inst/example/0000755000176200001440000000000014752731051014017 5ustar liggesuserslintr/inst/example/bad.R0000644000176200001440000000024414752731051014670 0ustar liggesusersfun = function(one) { one.plus.one <- oen + 1 four <- newVar <- matrix(1:10,nrow = 2) four[ 1, ] txt <- 'hi' three <- two+ 1 if(txt == 'hi') 4 5} { lintr/inst/lintr/0000755000176200001440000000000014752731051013514 5ustar liggesuserslintr/inst/lintr/linters.csv0000644000176200001440000001621714752731051015720 0ustar liggesuserslinter,tags absolute_path_linter,robustness best_practices configurable any_duplicated_linter,efficiency best_practices any_is_na_linter,efficiency best_practices assignment_linter,style consistency default configurable backport_linter,robustness configurable package_development boolean_arithmetic_linter,efficiency best_practices readability brace_linter,style readability default configurable class_equals_linter,best_practices robustness consistency closed_curly_linter,defunct commas_linter,style readability default configurable commented_code_linter,style readability best_practices default comparison_negation_linter,readability consistency condition_call_linter,style tidy_design best_practices configurable condition_message_linter,best_practices consistency conjunct_test_linter,package_development best_practices readability configurable pkg_testthat consecutive_assertion_linter,style readability consistency consecutive_mutate_linter,consistency readability configurable efficiency consecutive_stopifnot_linter,style readability consistency deprecated cyclocomp_linter,style readability best_practices configurable duplicate_argument_linter,correctness common_mistakes configurable empty_assignment_linter,readability best_practices equals_na_linter,robustness correctness common_mistakes default expect_comparison_linter,package_development best_practices pkg_testthat expect_identical_linter,package_development pkg_testthat expect_length_linter,package_development best_practices readability pkg_testthat expect_named_linter,package_development best_practices readability pkg_testthat expect_not_linter,package_development best_practices readability pkg_testthat expect_null_linter,package_development best_practices pkg_testthat expect_s3_class_linter,package_development best_practices pkg_testthat expect_s4_class_linter,package_development best_practices pkg_testthat expect_true_false_linter,package_development best_practices readability pkg_testthat expect_type_linter,package_development best_practices pkg_testthat extraction_operator_linter,style best_practices deprecated fixed_regex_linter,best_practices readability efficiency configurable regex for_loop_index_linter,best_practices readability robustness function_argument_linter,style consistency best_practices function_left_parentheses_linter,style readability default function_return_linter,readability best_practices if_not_else_linter,readability consistency configurable if_switch_linter,best_practices readability consistency efficiency configurable ifelse_censor_linter,best_practices efficiency implicit_assignment_linter,style best_practices readability configurable implicit_integer_linter,style consistency best_practices configurable indentation_linter,style readability default configurable infix_spaces_linter,style readability default configurable inner_combine_linter,efficiency consistency readability is_numeric_linter,readability best_practices consistency keyword_quote_linter,readability consistency style length_levels_linter,readability best_practices consistency length_test_linter,common_mistakes efficiency lengths_linter,efficiency readability best_practices library_call_linter,style best_practices readability configurable line_length_linter,style readability default configurable list_comparison_linter,best_practices common_mistakes literal_coercion_linter,best_practices consistency efficiency matrix_apply_linter,readability efficiency missing_argument_linter,correctness common_mistakes configurable missing_package_linter,robustness common_mistakes namespace_linter,correctness robustness configurable executing nested_ifelse_linter,efficiency readability nested_pipe_linter,readability consistency configurable no_tab_linter,style consistency deprecated nonportable_path_linter,robustness best_practices configurable nrow_subset_linter,efficiency consistency best_practices numeric_leading_zero_linter,style consistency readability nzchar_linter,efficiency best_practices consistency object_length_linter,style readability default configurable executing object_name_linter,style consistency default configurable executing object_overwrite_linter,best_practices robustness readability configurable executing object_usage_linter,style readability correctness default executing configurable one_call_pipe_linter,style readability open_curly_linter,defunct outer_negation_linter,readability efficiency best_practices package_hooks_linter,style correctness package_development paren_body_linter,style readability default paren_brace_linter,defunct paste_linter,best_practices consistency configurable pipe_call_linter,style readability pipe_consistency_linter,style readability configurable pipe_continuation_linter,style readability default pipe_return_linter,best_practices common_mistakes print_linter,best_practices consistency quotes_linter,style consistency readability default configurable redundant_equals_linter,best_practices readability efficiency common_mistakes redundant_ifelse_linter,best_practices efficiency consistency configurable regex_subset_linter,best_practices efficiency regex rep_len_linter,readability consistency best_practices repeat_linter,style readability return_linter,style configurable default routine_registration_linter,best_practices efficiency robustness sample_int_linter,efficiency readability robustness scalar_in_linter,readability consistency best_practices efficiency configurable semicolon_linter,style readability default configurable semicolon_terminator_linter,defunct seq_linter,robustness efficiency consistency best_practices default single_quotes_linter,style consistency readability deprecated sort_linter,readability best_practices efficiency spaces_inside_linter,style readability default spaces_left_parentheses_linter,style readability default sprintf_linter,correctness common_mistakes stopifnot_all_linter,readability best_practices string_boundary_linter,readability efficiency configurable regex strings_as_factors_linter,robustness system_file_linter,consistency readability best_practices T_and_F_symbol_linter,style readability robustness consistency best_practices default terminal_close_linter,best_practices robustness todo_comment_linter,style configurable trailing_blank_lines_linter,style default trailing_whitespace_linter,style default configurable undesirable_function_linter,style configurable robustness best_practices undesirable_operator_linter,style configurable robustness best_practices unnecessary_concatenation_linter,style readability efficiency configurable unnecessary_lambda_linter,best_practices efficiency readability configurable unnecessary_nested_if_linter,readability best_practices deprecated unnecessary_nesting_linter,readability consistency configurable best_practices unnecessary_placeholder_linter,readability best_practices unneeded_concatenation_linter,style readability efficiency configurable deprecated unreachable_code_linter,best_practices readability configurable unused_import_linter,best_practices common_mistakes configurable executing vector_logic_linter,default efficiency best_practices common_mistakes which_grepl_linter,readability efficiency consistency regex whitespace_linter,style consistency default yoda_test_linter,package_development best_practices readability pkg_testthat lintr/inst/doc/0000755000176200001440000000000014752763366013147 5ustar liggesuserslintr/inst/doc/creating_linters.Rmd0000644000176200001440000003455214752731051017142 0ustar liggesusers--- title: "Creating new linters" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Creating new linters} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- This vignette describes the steps necessary to create a new linter. See the last section for some details specific to writing new linters for `{lintr}`. A good example of a simple linter is the `pipe_call_linter`. ```r #' Pipe call linter #' #' Force explicit calls in magrittr pipes, e.g., #' `1:3 %>% sum()` instead of `1:3 %>% sum`. #' #' @evalRd rd_tags("pipe_call_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export pipe_call_linter <- function() { xpath <- "//expr[preceding-sibling::SPECIAL[text() = '%>%'] and *[1][self::SYMBOL]]" Linter(linter_level = "expression", function(source_expression) { if (!is_lint_level(source_expression, "expression")) { return(list()) } xml <- source_expression$xml_parsed_content if (is.null(xml)) return(list()) bad_expr <- xml2::xml_find_all(xml, xpath) xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = "Use explicit calls in magrittr pipes, i.e., `a %>% foo` should be `a %>% foo()`.", type = "warning" ) }) } ``` Let's walk through the parts of the linter individually. ## Writing the linter ## ```r #' Pipe call linter #' #' Force explicit calls in magrittr pipes, e.g., #' `1:3 %>% sum()` instead of `1:3 %>% sum`. ``` Describe the linter, giving it a title and briefly covering the usages that are discouraged when the linter is active. ```r #' @evalRd rd_tags("pipe_call_linter") #' @seealso [linters] for a complete list of linters available in lintr. #' @export ``` These lines (1) generate a Tags section in the documentation for the linter^[NB: this is a helper function for generating custom Rd styling. See R/linter_tags.R.]; (2) link to the full table of available linters; and (3) mark the function for export. The most unfamiliar here is probably (1), which can be skipped outside of `lintr` itself. ```r pipe_call_linter <- function() { ``` Next, we define the name of the new linter. The convention is to suffix all linter names with `_linter`. All `_linter` functions are function factories that return a closure that will do the actual linting function. We could define additional parameters that are useful for the linter in this function declaration (see, e.g. `assignment_linter`), but `pipe_call_linter` requires no additional arguments. ```r xpath <- "//expr[preceding-sibling::SPECIAL[text() = '%>%'] and *[1][self::SYMBOL]]" ``` Here is the core linter logic. `xpath` is an XPath expression for expressions matching the discouraged usage. `xpath` is saved inside the factory code (as opposed to inside the linter itself) for efficiency. Often, the `xpath` will be somewhat complicated / involve some assembly code using `paste()` or `glue::glue()`[^See `infix_spaces_linter()` for an example of this], in which case it is preferable to execute this code only once when creating the linter; the cached XPath is then re-used on each expression in each file where the linter is run. Let's examine the XPath a bit more closely: ```xpath //expr # global search (//) for 'expr' nodes (R expressions), at any nesting level [ # node[...] looks for any 'node' satisfying conditions in ... preceding-sibling:: # "siblings" are at the same nesting level in XML SPECIAL[ # 'SPECIAL' is the parse token for infix operators like %% or %+% text() = '%>%' # text() returns the string associated with this node ] # and # combine conditions with 'and' * # match any node [1] # match the first such node [self::SYMBOL] # match if the current node is a 'SYMBOL' (i.e., a 'name' in R) ] # ``` Taken together, that means we want to match `expr` nodes preceded by the `%>%` infix operator whose first child node is a `name`. That maps pretty closely to the description of what the `pipe_call_linter` is looking for, but there is subtlety in mapping between the R code you're used to and how they show up in the XML representation. `expr` nodes in particular take some practice to get accustomed to -- use the plentiful XPath-based linters in `lintr` as a guide to get extra practice^[The W3schools tutorials are also quite helpful; see https://www.w3schools.com/xml/xpath_intro.asp]. Note: `xml2` implements XPath 1.0, which lacks some helpful features available in XPath 2.0. ```r Linter(function(source_expression) { ``` This is the closure. It will be called on the `source_expression` variable that contains the top level expressions in the file to be linted. The call to `Linter()` gives this closure the class 'linter' (it also guesses the name of the linter; see `?Linter` for more details). The raw text of the expression is available from `source_file$content`. However, it is not generally possible to implement linters from the raw text -- consider `equals_na_linter`. If we just look for `== NA` in the text of the file, we'll generate many false positives, e.g. in comments (such as `# note: is.na() is the proper way to check == NA`) or inside character literals (such as `warning("don't use == NA to check missingness")`). We're also likely to generate false negatives, for example when `==` and `NA` appear on different lines! Working around these issues using only the un-parsed text in every situation amounts to re-implementing the parser. Therefore it is recommended to work with the tokens from `source_file$parsed_content` or `source_file$xml_parsed_content`, as they are tokenized from the `R` parser. These tokens are obtained from `parse()` and `utils::getParseData()` calls done prior to calling the new linter. `getParseData()` returns a `data.frame` with information from the source parse tree of the file being linted. A list of tokens is available from [r-source/src/main/gram.y](https://github.com/r-devel/r-svn/blob/master/src/main/gram.y#L395-L412). `source_file$xml_parsed_content` uses `xmlparsedata::xml_parse_data()` to convert the `getParseData()` output into an XML tree, which enables writing linter logic in [XPath](https://www.w3schools.com/xml/xpath_intro.asp), a powerful language for expressing paths within the nested XML data structure. Most linters in `lintr` are built using XPath because it is a powerful language for computation on the abstract syntax tree / parse tree. ```r if (!is_lint_level(source_expression, "expression")) { return(list()) } ``` Here, we return early if `source_expression` is not the expression-level object. `get_source_expression()` returns an object that parses the input file in two ways -- once is done expression-by-expression, the other contains all of the expressions in the file. This is done to facilitate caching. Suppose your package has a long source file (e.g., 100s of expressions) -- rather than run linters on every expression every time the file is updated, when caching is activated `lintr` will only run the linter again on expressions that have changed. Note that this check is unnecessary because we provided `linter_level = "expression"` which guarantees that `source_expression` will be at the expression level and not at the file level. Therefore, it is preferable to write expression-level linters whenever possible. Two types of exceptions observed in `lintr` are (1) when several or all expressions are _required_ to ensure the linter logic applies (e.g., `conjunct_test_linter` looks for consecutive calls to `stopifnot()`, which will typically appear on consecutive expressions) or (2) when the linter logic is very simple & fast to compute, so that the overhead of re-running the linter is low (e.g., `single_quotes_linter`). In those cases, use `is_lint_level(source_expression, "file")`. ```r xml <- source_expression$xml_parsed_content bad_expr <- xml2::xml_find_all(xml, xpath) ``` `source_expression$xml_parsed_content` is copied to a local variable (this is not strictly necessary but facilitates debugging). Then `xml2::xml_find_all()` is used to execute the XPath on this particular expression. Keep in mind that it is typically possible for a single expression to generate more than one lint -- for example, `x %>% na.omit %>% sum` will trigger the `pipe_call_linter()` twice^[This is particularly important if you want the `message` field in the resulting `Lint()` to vary depending on the exact violation that's found. For `pipe_call_linter()`, the message is always the same. See `assignment_linter()` for an example where the `message` can vary.]. ```r xml_nodes_to_lints( bad_expr, source_expression = source_expression, lint_message = "Use explicit calls in magrittr pipes, i.e., `a %>% foo` should be `a %>% foo()`.", type = "warning" ) ``` Finally, we pass the matching XML node(s) to `xml_nodes_to_lints()`, which returns `Lint` objects corresponding to any "bad" usages found in `source_expression`. See `?Lint` and `?xml_nodes_to_lints` for details about the arguments. Note that here, the `message` for the lint is always the same, but for many linters, the message is customized to more closely match the observed usage. In such cases, `xml_nodes_to_lint()` can conveniently accept a function in `lint_message` which takes a node as input and converts it to a customized message. See, for example, `seq_linter`. ```r linter_level = "expression" ``` This is a more efficient way to implement the condition `if (!is_lint_level(source_expression, "expression"))`. ## Writing linter tests (NB: this section uses the `assignment_linter()` which has simpler examples than `pipe_continuation_linter()`.) `{lintr}` works best inside the `{testthat}` unit testing framework, in particular, `{lintr}` exports `lintr::expect_lint()` which is designed as a companion to other testthat expectations. You can define tests inside separate `test_that` calls. Most of the linters use the same default form. ```r test_that("returns the correct linting", { ``` You then test a series of expectations for the linter using `expect_lint`. Please see `?expect_lint` for a full description of the parameters. The main three aspects to test are: 1. Linter returns no lints when there is nothing to lint, e.g. ```r expect_no_lint("blah", assignment_linter()) ``` 2. Linter returns a lint when there is something to lint, e.g. ```r expect_lint("blah=1", rex("Use <-, not =, for assignment."), assignment_linter() ) ``` 3. As many edge cases as you can think of that might break it, e.g. ```r expect_lint("fun((blah = fun(1)))", rex("Use <-, not =, for assignment."), assignment_linter() ) ``` You may want to test that additional `lint` attributes are correct, such as the type, line number, column number, e.g. ```r expect_lint("blah=1", list(message = "assignment", line_number = 1, column_number = 5, type = "style"), assignment_linter() ) ``` Finally, it is a good idea to test that your linter reports multiple lints if needed, e.g. ```r expect_lint("blah=1; blah=2", list( list(line_number = 1, column_number = 5), list(line_number = 1, column_number = 13), ), assignment_linter() ) ``` It is always better to write too many tests rather than too few. ## Other utilities for writing custom linters Besides `is_lint_level()`, `{lintr}` also exports some other helpers generally useful for writing custom linters; these are used a lot in the internals of our own helpers, and so they've been tested and demonstrated their utility already. * `get_r_string()`: Whenever your linter needs to examine the value of a character literal (e.g., whether an argument value is set to some string), use this to extract the string exactly as R will see it. This is especially important to make your logic robust to R-4-style raw strings like `R"-(hello)-"`, which is otherwise difficult to express, for example as an XPath. * `xml_find_function_calls()`: Whenever your linter needs to query R function calls, e.g. via the XPath `//SYMBOL_FUNCTION_CALL[text() = 'myfun']`, use this member of `source_expression` to obtain the function call nodes more efficiently. Instead of ```r xml <- source_expression$xml_parsed_content xpath <- "//SYMBOL_FUNCTION_CALL[text() = 'myfun']/parent::expr/some/cond" xml_find_all(xml, xpath) ``` use ```r xml_calls <- source_expression$xml_find_function_calls("myfun") call_xpath <- "some/cond" xml_find_all(xml_calls, call_xpath) ``` * `make_linter_from_xpath()` and `make_linter_from_function_xpath()`: Whenever your linter can be expressed by a static XPath and a static message, use `make_linter_from_xpath()` or, if the XPath starts with `//SYMBOL_FUNCTION_CALL`, use `make_linter_from_function_xpath()`. Instead of `make_linter_from_xpath(xpath = "//SYMBOL_FUNCTION_CALL[text() = 'foo' or text() = 'bar']")`, use `make_linter_from_function_xpath(function_names = c("foo", "bar"), xpath = "SYMBOL_FUNCTION_CALL/cond")`. Very often, such XPaths look like `//SYMBOL_FUNCTION_CALL/parent::expr/cond2`, in which case the `xpath=` is simpler: `xpath = "cond2"`. Another common case is `//SYMBOL_FUNCTION_CALL/parent::expr[exprCond]/furtherCond`, which becomes `xpath = "self::*[exprCond]/furtherCond"`. ## Contributing to `{lintr}` ### More details about writing tests for new `{lintr}` linters The `{lintr}` package uses [testthat](https://github.com/r-lib/testthat) for testing. You can run all of the currently available tests using `devtools::test()`. If you want to run only the tests in a given file use the `filter` argument to `devtools::test()`. Linter tests should be put in the [tests/testthat/](https://github.com/r-lib/lintr/tree/main/tests/testthat) folder. The test filename should be the linter name prefixed by `test-`, e.g. `test-pipe_continuation_linter.R`. ### Adding your linter to the default_linters ## If your linter implements part of the tidyverse style guide you can add it to `default_linters`. This object is created in the file `zzz.R` (this name ensures that it will always run after all the linters are defined). Add your linter name to the `default_linters` list before the `NULL` at the end, and add a corresponding test case to the test script `./tests/testthat/default_linter_testcode.R`. ### Submit pull request ## Push your changes to a branch of your fork of the [lintr](https://github.com/r-lib/lintr) repository, and submit a pull request to get your linter merged into lintr! lintr/inst/doc/lintr.Rmd0000644000176200001440000003624514752731051014737 0ustar liggesusers--- title: "Using lintr" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Using lintr} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` This vignette describes how to set up and configure `lintr` for use with projects or packages. ## Running `lintr` on a project Checking an R project for lints can be done with three different functions: - Lint a single file using `lint()`: ``` r lint(filename = "R/bad.R") ``` - Lint a directory using `lint_dir()`: ``` r lint_dir(path = "R") ``` This will apply `lint()` to all R source files matching the `pattern` argument. By default, this means all `.R` files as well as `knitr` formats (e.g. `.Rmd`, `.Rnw`). `lint_dir` is vectorized over `path`, so multiple directories can be linted at the same time. - Lint all relevant directories of an R package using `lint_package()`: ``` r lint_package(path = ".") ``` This will apply `lint_dir()` to all subdirectories usually containing R code in packages: - `R` containing the package implementation. - `tests` containing test code. - `inst` containing sample code or vignettes that will be installed along with the package. - `vignettes` containing package vignettes. - `data-raw` containing code to produce `data` files. For more information about the assumed package structure, see [R Packages](https://r-pkgs.org/structure.html). Note that some linters (e.g. `object_usage_linter()`) require the package to be installed to function properly. `pkgload::load_all()` will also suffice. See `?executing_linters` for more details. ## Configuring linters ### The `.lintr` file The canonical way to configure R projects and packages for linting is to create a `.lintr` file in the project root. This is a file in debian control format (`?read.dcf`), each value of which is evaluated as R code by `lintr` when reading the settings. A minimal `.lintr` file can be generated by running `use_lintr()` in the project directory. Lintr supports per-project configuration of the following fields. - `linters` - see `?linters_with_defaults` for example of specifying only a few non-default linters and `?linters_with_tags` for more fine-grained control. - `exclusions` - a list of filenames to exclude from linting. You can use a named item to exclude only certain lines from a file. - `exclude` - a regex pattern for lines to exclude from linting. Default is "\# nolint" - `exclude_start` - a regex pattern to start exclusion range. Default is "\# nolint start" - `exclude_end` - a regex pattern to end exclusion range. Default is "\# nolint end" - `encoding` - the encoding used for source files. Default inferred from .Rproj or DESCRIPTION files, fallback to UTF-8 ### .lintr File Example Below is an example .lintr file that uses 120 character line lengths, disables `commented_code_linter`, excludes a couple of files. ``` yaml linters: linters_with_defaults( line_length_linter(120), commented_code_linter = NULL ) exclusions: list( "inst/doc/creating_linters.R" = 1, "inst/example/bad.R", "tests/testthat/exclusions-test" ) ``` ### Other configuration options More generally, `lintr` searches for a settings file according to following prioritized list. The first one found, if any, will be used: 1. If `options("lintr.linter_file")` is an absolute path, this file will be used. The default for this option is `".lintr"` or the value of the environment variable `R_LINTR_LINTER_FILE`, if set. 2. A project-local linter file; that is, either 1. a linter file (that is, a file named like `lintr.linter_file`) in the currently-searched directory, i.e. the directory of the file passed to `lint()`; or 2. a linter file in the `.github/linters` child directory of the currently-searched directory. 3. A project-local linter file in the closest parent directory of the currently-searched directory, starting from the deepest path, moving upwards one level at a time. When run from `lint_package()`, this directory can differ for each linted file. 4. A linter file in the user's `HOME` directory. 5. A linter file called `config` in the user's configuration path (given by `tools::R_user_dir("lintr", which = "config")`). If no linter file is found, only default settings take effect (see [defaults](#defaults)). ### Using `options()` Values in `options()`, if they are not `NULL`, take precedence over those in the linter file (e.g. `.lintr`). Note that the key `option_name` in the linter file translates to an R option `lintr.option_name`. For example, `options(lintr.exclude = "# skip lint")` will take precedence over `exclude: # nolint` in the linter file. ### Using arguments to `lint()` The settings can also be passed as arguments to linting functions directly. In case of `exclusions`, these will be combined with the globally parsed settings. Other settings will be overridden. If only the specified settings should be changed, and the remaining settings should be taken directly from the defaults, the argument `parse_settings = FALSE` can be added to the function calls. This will suppress reading of the `.lintr` configuration. This is particularly useful for tests which should not exclude example files containing lints while the package-level `.lintr` excludes those files because the lints are intentional. ### Defaults {#defaults} The default settings of `lintr` are intended to conform to the [tidyverse style guide](https://style.tidyverse.org/). However, the behavior can be customized using different methods. Apart from `lintr.linter_file`, which defaults to `".lintr"`, there are the following settings: ```{r show_default_settings, echo = FALSE} default_settings <- lintr::default_settings default_settings$linters <- "`lintr::default_linters`" default_settings$comment_token <- "(lintr-bot comment token for automatic GitHub comments)" default_settings$exclusions <- "(empty)" make_string <- function(x) { if (inherits(x, "regex")) { paste0("regex: `", x, "`") } else { as.character(x) } } defaults_table <- data.frame(default = vapply(default_settings, make_string, character(1L))) # avoid conflict when loading lintr in echo=TRUE cell below rm(default_settings) knitr::kable(defaults_table) ``` Note that the default `encoding` setting depends on the file to be linted. If an Encoding is found in a `.Rproj` file or a `DESCRIPTION` file, that encoding overrides the default of UTF-8. #### Customizing active linters If you only want to customize some linters, you can use the helper function `linters_with_defaults()`, which will keep all unnamed linters with the default settings. Disable a linter by passing `NULL`. For example, to set the line length limit to 120 characters and globally disable the `whitespace_linter()`, you can put this into your `.lintr`: ``` r linters: linters_with_defaults( line_length_linter = line_length_linter(120L), whitespace_linter = NULL ) ``` By default, the following linters are enabled. Where applicable, the default settings are also shown. ```{r show_linter_defaults, echo = FALSE} library(lintr) # needed here for formalArgs default_linters <- lintr::default_linters linters_with_args <- lapply( setNames(nm = intersect(names(default_linters), lintr::available_linters(tags = "configurable")$linter)), formalArgs ) make_setting_string <- function(linter_name) { linter_args <- linters_with_args[[linter_name]] if (is.null(linter_args)) { return("") } arglist <- vapply(linter_args, function(arg) { env <- environment(default_linters[[linter_name]]) deparse(env[[arg]]) }, character(1L)) paste0(linter_args, " = ", arglist, collapse = ", ") } defaults_table <- data.frame( row.names = names(default_linters), settings = vapply(names(default_linters), make_setting_string, character(1L)) ) knitr::kable(defaults_table) ``` Another way to customize linters is by specifying tags in `linters_with_tags()`. The available tags are listed below: ```{r show_tags} lintr::available_tags(packages = "lintr") ``` You can select tags of interest to see which linters are included: ```{r show_tag_linters} linters <- lintr::linters_with_tags(tags = c("package_development", "readability")) names(linters) ``` You can include tag-based linters in the configuration file, and customize them further: ```yaml linters: linters_with_tags( tags = c("package_development", "readability"), yoda_test_linter = NULL ) ``` #### Using all available linters The default lintr configuration includes only linters relevant to the tidyverse style guide, but there are many other linters available in `{lintr}`. You can see a list of all available linters using ```{r show_all_linter_names} names(lintr::all_linters()) ``` If you want to use all available linters, you can include this in your `.lintr` file: ```yaml linters: all_linters() ``` If you want to use all available linters *except* a few, you can exclude them using `NULL`: ```yaml linters: all_linters( commented_code_linter = NULL, implicit_integer_linter = NULL ) ``` #### Advanced: programmatic retrieval of linters For some use cases, it may be useful to specify linters by string instead of by name, i.e. `"assignment_linter"` instead of writing out `assignment_linter()`. Beware that in such cases, a simple `get()` is not enough: ```{r programmatic_lintr} library(lintr) linter_name <- "assignment_linter" show_lint <- function(l) { lint_df <- as.data.frame(l) print(lint_df[, c("line_number", "message", "linter")]) } hline <- function() cat(strrep("-", getOption("width") - 5L), "\n", sep = "") withr::with_tempfile("tmp", { writeLines("a = 1", tmp) # linter column is just 'get' show_lint(lint(tmp, linters = get(linter_name)())) hline() this_linter <- get(linter_name)() attr(this_linter, "name") <- linter_name # linter column is 'assignment_linter' show_lint(lint(tmp, linters = this_linter)) hline() # more concise alternative for this case: use eval(call(.)) show_lint(lint(tmp, linters = eval(call(linter_name)))) }) ``` ## Exclusions Sometimes, linters should not be globally disabled. Instead, one might want to exclude some code from linting altogether or selectively disable some linters on some part of the code. > Note that the preferred way of excluding lints from source code is to use the narrowest possible scope and specify exactly which linters should not throw a lint on a marked line. > This prevents accidental suppression of justified lints that happen to be on the same line as a lint that needs to be suppressed. ### Excluding lines of code Within source files, special comments can be used to exclude single lines of code from linting. All lints produced on the marked line are excluded from the results. By default, this special comment is `# nolint`: **file.R** ``` r X = 42L # -------------- this comment overflows the default 80 chars line length. ``` `> lint("file.R")` ```{r show_long_line_lint, echo = FALSE} lint("X = 42L # -------------- this comment overflows the default 80 chars line length.\n", parse_settings = FALSE ) ``` **file2.R** ``` r X = 42L # nolint ------ this comment overflows the default 80 chars line length. ``` `> lint("file2.R")` ```{r show_nolint, echo = FALSE} lint("X = 42L # nolint ------ this comment overflows the default 80 chars line length.\n", parse_settings = FALSE ) ``` Observe how all lints were suppressed and no output is shown. Sometimes, only a specific linter needs to be excluded. In this case, the *name* of the linter can be appended to the `# nolint` comment preceded by a colon and terminated by a dot. ### Excluding only some linters **file3.R** ``` r X = 42L # nolint: object_name_linter. this comment overflows the default 80 chars line length. ``` `> lint("file3.R")` ```{r show_long_line_lint_not_skipped, echo = FALSE} lint("X = 42L # nolint: object_name_linter. this comment overflows the default 80 chars line length.\n", parse_settings = FALSE ) ``` Observe how only the `object_name_linter` was suppressed. This is preferable to blanket `# nolint` statements because blanket exclusions may accidentally silence a linter that was not intentionally suppressed. Multiple linters can be specified by listing them with a comma as a separator: **file4.R** ``` r X = 42L # nolint: object_name_linter, line_length_linter. this comment overflows the default 80 chars line length. ``` `> lint("file4.R")` ```{r show_nolint_multiple, echo = FALSE} lint( paste( "X = 42L", "# nolint: object_name_linter, line_length_linter. this comment overflows the default 80 chars line length.\n" ), parse_settings = FALSE ) ``` You can also specify the linter names by a unique prefix instead of their full name: **file5.R** ``` r X = 42L # nolint: object_name, line_len. this comment still overflows the default 80 chars line length. ``` `> lint("file5.R")` ```{r show_nolint_abbrev, echo = FALSE} lint( paste( "X = 42L", "# nolint: object_name, line_len. this comment still overflows the default 80 chars line length.\n" ), parse_settings = FALSE ) ``` ### Excluding multiple lines of codes If any or all linters should be disabled for a contiguous block of code, the `exclude_start` and `exclude_end` patterns can be used. They default to `# nolint start` and `# nolint end` respectively. `# nolint start` accepts the same syntax as `# nolint` to disable specific linters in the following lines until a `# nolint end` is encountered. ``` r # x <- 42L # print(x) ``` ```{r show_comment_code_lint, echo = FALSE} lint("# x <- 42L\n# print(x)\n", parse_settings = FALSE) ``` ``` r # nolint start: commented_code_linter. # x <- 42L # print(x) # nolint end ``` ```{r show_comment_code_nolint, echo = FALSE} lint("# nolint start: commented_code_linter.\n# x <- 42L\n# print(x)\n# nolint end\n", parse_settings = FALSE ) ``` (No lints) ### Excluding lines via the config file Individual lines can also be excluded via the config file by setting the key `exclusions` to a list with elements corresponding to different files. To exclude all lints for line 1 of file `R/bad.R` and `line_length_linter` for lines 4 to 6 of the same file, one can set ``` r exclusions: list( "R/bad.R" = list( 1, # global exclusions are unnamed line_length_linter = 4:6 ) ) ``` All paths are interpreted relative to the location of the `.lintr` file. ### Excluding files completely The linter configuration can also be used to exclude a file entirely, or a linter for a file entirely. Use the sentinel line number `Inf` to mark all lines as excluded within a file. If a file is only given as a character vector, full exclusion is implied. ``` r exclusions: list( # excluded from all lints: "R/excluded1.R", "R/excluded2.R" = Inf, "R/excluded3.R" = list(Inf), # excluded from line_length_linter: "R/no-line-length.R" = list( line_length_linter = Inf ) ) ``` ### Excluding directories completely Entire directories are also recognized when supplied as strings in the `exclusions` key. For example, to exclude the `renv` folder from linting in a R project using `renv`, set ``` r exclusions: list( "renv" ) ``` This is particularly useful for projects which include external code in subdirectories. lintr/inst/doc/continuous-integration.html0000644000176200001440000003130114752763364020560 0ustar liggesusers Continuous integration

Continuous integration

You can configure lintr to run as part of continuous integration (either for a package or a general project containing R files) in order to automatically check that commits and pull requests do not deteriorate code style.

For projects

You are not limited to using lintr for packages – you can use it in combination with continuous integration for any other project.

GitHub Actions

If your project is on GitHub, you could take advantage of GitHub Actions and the usethis functionality. r-lib/actions includes a lint-project example, which you can use by calling:

usethis::use_github_action("lint-project")

Super-Linter

lintr powers R lints for Super-Linter and MegaLinter, which provide a unified linting experience across many languages. Specifically, they execute lintr::lint() on the R and R Markdown files included in a given project.

lintr/inst/doc/continuous-integration.R0000644000176200001440000000021714752763363020016 0ustar liggesusers## ----include = FALSE---------------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) lintr/inst/doc/editors.R0000644000176200001440000000112014752763364014733 0ustar liggesusers## ----include = FALSE---------------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) in_pkgdown <- identical(Sys.getenv("IN_PKGDOWN"), "true") maybe_still <- function(url) { if (in_pkgdown) { url } else { gsub("\\.gif$", "-still.gif", url) } } ## ----echo = FALSE, results = 'asis'------------------------------------------- if (!in_pkgdown) { cat( "Note: This vignette is best viewed [online](https://lintr.r-lib.org/articles/editors.html),", "where we can render full animations of editor flows.\n" ) } lintr/inst/doc/creating_linters.html0000644000176200001440000010552414752763364017376 0ustar liggesusers Creating new linters

Creating new linters

This vignette describes the steps necessary to create a new linter.

See the last section for some details specific to writing new linters for {lintr}.

A good example of a simple linter is the pipe_call_linter.

#' Pipe call linter
#'
#' Force explicit calls in magrittr pipes, e.g.,
#' `1:3 %>% sum()` instead of `1:3 %>% sum`.
#'
#' @evalRd rd_tags("pipe_call_linter")
#' @seealso [linters] for a complete list of linters available in lintr.
#' @export
pipe_call_linter <- function() {
  xpath <- "//expr[preceding-sibling::SPECIAL[text() = '%>%'] and *[1][self::SYMBOL]]"

  Linter(linter_level = "expression", function(source_expression) {
    if (!is_lint_level(source_expression, "expression")) {
      return(list())
    }

    xml <- source_expression$xml_parsed_content
    if (is.null(xml)) return(list())

    bad_expr <- xml2::xml_find_all(xml, xpath)

    xml_nodes_to_lints(
      bad_expr,
      source_expression = source_expression,
      lint_message = "Use explicit calls in magrittr pipes, i.e., `a %>% foo` should be `a %>% foo()`.",
      type = "warning"
    )
  })
}

Let’s walk through the parts of the linter individually.

Writing the linter

#' Pipe call linter
#'
#' Force explicit calls in magrittr pipes, e.g.,
#' `1:3 %>% sum()` instead of `1:3 %>% sum`.

Describe the linter, giving it a title and briefly covering the usages that are discouraged when the linter is active.

#' @evalRd rd_tags("pipe_call_linter")
#' @seealso [linters] for a complete list of linters available in lintr.
#' @export

These lines (1) generate a Tags section in the documentation for the linter1; (2) link to the full table of available linters; and (3) mark the function for export. The most unfamiliar here is probably (1), which can be skipped outside of lintr itself.

pipe_call_linter <- function() {

Next, we define the name of the new linter. The convention is to suffix all linter names with _linter. All _linter functions are function factories that return a closure that will do the actual linting function. We could define additional parameters that are useful for the linter in this function declaration (see, e.g. assignment_linter), but pipe_call_linter requires no additional arguments.

xpath <- "//expr[preceding-sibling::SPECIAL[text() = '%>%'] and *[1][self::SYMBOL]]"

Here is the core linter logic. xpath is an XPath expression for expressions matching the discouraged usage. xpath is saved inside the factory code (as opposed to inside the linter itself) for efficiency. Often, the xpath will be somewhat complicated / involve some assembly code using paste() or glue::glue()[^See infix_spaces_linter() for an example of this], in which case it is preferable to execute this code only once when creating the linter; the cached XPath is then re-used on each expression in each file where the linter is run.

Let’s examine the XPath a bit more closely:

//expr                  # global search (//) for 'expr' nodes (R expressions), at any nesting level
[                       # node[...] looks for any 'node' satisfying conditions in ...
  preceding-sibling::   # "siblings" are at the same nesting level in XML
    SPECIAL[            # 'SPECIAL' is the parse token for infix operators like %% or %+%
      text() = '%>%'    # text() returns the string associated with this node
    ]                   #
  and                   # combine conditions with 'and'
  *                     # match any node
  [1]                   # match the first such node
  [self::SYMBOL]        # match if the current node is a 'SYMBOL' (i.e., a 'name' in R)
]                       #

Taken together, that means we want to match expr nodes preceded by the %>% infix operator whose first child node is a name. That maps pretty closely to the description of what the pipe_call_linter is looking for, but there is subtlety in mapping between the R code you’re used to and how they show up in the XML representation. expr nodes in particular take some practice to get accustomed to – use the plentiful XPath-based linters in lintr as a guide to get extra practice2. Note: xml2 implements XPath 1.0, which lacks some helpful features available in XPath 2.0.

Linter(function(source_expression) {

This is the closure. It will be called on the source_expression variable that contains the top level expressions in the file to be linted. The call to Linter() gives this closure the class ‘linter’ (it also guesses the name of the linter; see ?Linter for more details).

The raw text of the expression is available from source_file$content. However, it is not generally possible to implement linters from the raw text – consider equals_na_linter. If we just look for == NA in the text of the file, we’ll generate many false positives, e.g. in comments (such as # note: is.na() is the proper way to check == NA) or inside character literals (such as warning("don't use == NA to check missingness")). We’re also likely to generate false negatives, for example when == and NA appear on different lines! Working around these issues using only the un-parsed text in every situation amounts to re-implementing the parser.

Therefore it is recommended to work with the tokens from source_file$parsed_content or source_file$xml_parsed_content, as they are tokenized from the R parser. These tokens are obtained from parse() and utils::getParseData() calls done prior to calling the new linter. getParseData() returns a data.frame with information from the source parse tree of the file being linted. A list of tokens is available from r-source/src/main/gram.y.

source_file$xml_parsed_content uses xmlparsedata::xml_parse_data() to convert the getParseData() output into an XML tree, which enables writing linter logic in XPath, a powerful language for expressing paths within the nested XML data structure. Most linters in lintr are built using XPath because it is a powerful language for computation on the abstract syntax tree / parse tree.

if (!is_lint_level(source_expression, "expression")) {
  return(list())
}

Here, we return early if source_expression is not the expression-level object. get_source_expression() returns an object that parses the input file in two ways – once is done expression-by-expression, the other contains all of the expressions in the file. This is done to facilitate caching. Suppose your package has a long source file (e.g., 100s of expressions) – rather than run linters on every expression every time the file is updated, when caching is activated lintr will only run the linter again on expressions that have changed.

Note that this check is unnecessary because we provided linter_level = "expression" which guarantees that source_expression will be at the expression level and not at the file level.

Therefore, it is preferable to write expression-level linters whenever possible. Two types of exceptions observed in lintr are (1) when several or all expressions are required to ensure the linter logic applies (e.g., conjunct_test_linter looks for consecutive calls to stopifnot(), which will typically appear on consecutive expressions) or (2) when the linter logic is very simple & fast to compute, so that the overhead of re-running the linter is low (e.g., single_quotes_linter). In those cases, use is_lint_level(source_expression, "file").

xml <- source_expression$xml_parsed_content

bad_expr <- xml2::xml_find_all(xml, xpath)

source_expression$xml_parsed_content is copied to a local variable (this is not strictly necessary but facilitates debugging). Then xml2::xml_find_all() is used to execute the XPath on this particular expression. Keep in mind that it is typically possible for a single expression to generate more than one lint – for example, x %>% na.omit %>% sum will trigger the pipe_call_linter() twice3.

xml_nodes_to_lints(
  bad_expr,
  source_expression = source_expression,
  lint_message = "Use explicit calls in magrittr pipes, i.e., `a %>% foo` should be `a %>% foo()`.",
  type = "warning"
)

Finally, we pass the matching XML node(s) to xml_nodes_to_lints(), which returns Lint objects corresponding to any “bad†usages found in source_expression. See ?Lint and ?xml_nodes_to_lints for details about the arguments. Note that here, the message for the lint is always the same, but for many linters, the message is customized to more closely match the observed usage. In such cases, xml_nodes_to_lint() can conveniently accept a function in lint_message which takes a node as input and converts it to a customized message. See, for example, seq_linter.

linter_level = "expression"

This is a more efficient way to implement the condition if (!is_lint_level(source_expression, "expression")).

Writing linter tests

(NB: this section uses the assignment_linter() which has simpler examples than pipe_continuation_linter().)

{lintr} works best inside the {testthat} unit testing framework, in particular, {lintr} exports lintr::expect_lint() which is designed as a companion to other testthat expectations.

You can define tests inside separate test_that calls. Most of the linters use the same default form.

test_that("returns the correct linting", {

You then test a series of expectations for the linter using expect_lint. Please see ?expect_lint for a full description of the parameters.

The main three aspects to test are:

  1. Linter returns no lints when there is nothing to lint, e.g.
expect_no_lint("blah", assignment_linter())
  1. Linter returns a lint when there is something to lint, e.g.
expect_lint("blah=1",
  rex("Use <-, not =, for assignment."),
  assignment_linter()
)
  1. As many edge cases as you can think of that might break it, e.g.
expect_lint("fun((blah = fun(1)))",
  rex("Use <-, not =, for assignment."),
  assignment_linter()
)

You may want to test that additional lint attributes are correct, such as the type, line number, column number, e.g.

expect_lint("blah=1",
  list(message = "assignment", line_number = 1, column_number = 5, type = "style"),
  assignment_linter()
)

Finally, it is a good idea to test that your linter reports multiple lints if needed, e.g.

expect_lint("blah=1; blah=2",
  list(
    list(line_number = 1, column_number = 5),
    list(line_number = 1, column_number = 13),
  ),
  assignment_linter()
)

It is always better to write too many tests rather than too few.

Other utilities for writing custom linters

Besides is_lint_level(), {lintr} also exports some other helpers generally useful for writing custom linters; these are used a lot in the internals of our own helpers, and so they’ve been tested and demonstrated their utility already.

  • get_r_string(): Whenever your linter needs to examine the value of a character literal (e.g., whether an argument value is set to some string), use this to extract the string exactly as R will see it. This is especially important to make your logic robust to R-4-style raw strings like R"-(hello)-", which is otherwise difficult to express, for example as an XPath.

  • xml_find_function_calls(): Whenever your linter needs to query R function calls, e.g. via the XPath //SYMBOL_FUNCTION_CALL[text() = 'myfun'], use this member of source_expression to obtain the function call nodes more efficiently. Instead of

    xml <- source_expression$xml_parsed_content
    xpath <- "//SYMBOL_FUNCTION_CALL[text() = 'myfun']/parent::expr/some/cond"
    xml_find_all(xml, xpath)

    use

    xml_calls <- source_expression$xml_find_function_calls("myfun")
    call_xpath <- "some/cond"
    xml_find_all(xml_calls, call_xpath)
  • make_linter_from_xpath() and make_linter_from_function_xpath(): Whenever your linter can be expressed by a static XPath and a static message, use make_linter_from_xpath() or, if the XPath starts with //SYMBOL_FUNCTION_CALL, use make_linter_from_function_xpath(). Instead of make_linter_from_xpath(xpath = "//SYMBOL_FUNCTION_CALL[text() = 'foo' or text() = 'bar']"), use make_linter_from_function_xpath(function_names = c("foo", "bar"), xpath = "SYMBOL_FUNCTION_CALL/cond"). Very often, such XPaths look like //SYMBOL_FUNCTION_CALL/parent::expr/cond2, in which case the xpath= is simpler: xpath = "cond2". Another common case is //SYMBOL_FUNCTION_CALL/parent::expr[exprCond]/furtherCond, which becomes xpath = "self::*[exprCond]/furtherCond".

Contributing to {lintr}

More details about writing tests for new {lintr} linters

The {lintr} package uses testthat for testing. You can run all of the currently available tests using devtools::test(). If you want to run only the tests in a given file use the filter argument to devtools::test().

Linter tests should be put in the tests/testthat/ folder. The test filename should be the linter name prefixed by test-, e.g. test-pipe_continuation_linter.R.

Adding your linter to the default_linters

If your linter implements part of the tidyverse style guide you can add it to default_linters. This object is created in the file zzz.R (this name ensures that it will always run after all the linters are defined). Add your linter name to the default_linters list before the NULL at the end, and add a corresponding test case to the test script ./tests/testthat/default_linter_testcode.R.

Submit pull request

Push your changes to a branch of your fork of the lintr repository, and submit a pull request to get your linter merged into lintr!


  1. NB: this is a helper function for generating custom Rd styling. See R/linter_tags.R.↩︎

  2. The W3schools tutorials are also quite helpful; see https://www.w3schools.com/xml/xpath_intro.asp↩︎

  3. This is particularly important if you want the message field in the resulting Lint() to vary depending on the exact violation that’s found. For pipe_call_linter(), the message is always the same. See assignment_linter() for an example where the message can vary.↩︎

lintr/inst/doc/continuous-integration.Rmd0000644000176200001440000000667314752731051020340 0ustar liggesusers--- title: "Continuous integration" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Continuous integration} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` You can configure `lintr` to run as part of continuous integration (either for a package or a general project containing R files) in order to automatically check that commits and pull requests do not deteriorate code style. ## For packages First, take special note of the proviso in `?executing_linters` about the need to have your package and its dependencies installed or loaded (e.g. with `pkgload::load_all()`) in order for certain linters (e.g. `object_usage_linter()`) to function as intended. ### GitHub Actions If your package is on GitHub, the easiest way to do this is with GitHub Actions. The workflow configuration files use YAML syntax. The `usethis` package has some great functionality that can help you with workflow files. The most straightforward way to add a `lintr` workflow to your package is to use the [r-lib/actions](https://github.com/r-lib/actions/)'s [`lint` example](https://github.com/r-lib/actions/tree/v2-branch/examples#lint-workflow). To do this with `usethis`, you need to call ```r usethis::use_github_action("lint") ``` This will create a workflow file called `lint.yaml` and place it in the correct location, namely in the `.github/workflows` directory of your repository. This file configures all the steps required to run `lintr::lint_package()` on your package. Alternatively you can use the eponymous [`lint-changed-files.yaml`](https://github.com/r-lib/actions/blob/v2-branch/examples/lint-changed-files.yaml) to only lint any changed files: ```r usethis::use_github_action("lint-changed-files") ``` Comments to the commit or pull request will be printed as [annotations](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/about-status-checks#types-of-status-checks-on-github) along side the status check on GitHub. If you want the builds to produce an error instead of just a warning, you can set the environment variable `LINTR_ERROR_ON_LINT=true`. This is set by default for both [r-lib/actions](https://github.com/r-lib/actions/)'s `lint.yaml` and `lint-changed-files.yaml`. Note that this will kill the R process in case of a lint. If your project is in a subdirectory and you would like to use GitHub Actions annotations, you can set `options(lintr.github_annotation_project_dir = "path/to/project")` which will make sure that the annotations point to the correct paths. ## For projects You are not limited to using `lintr` for packages -- you can use it in combination with continuous integration for any other project. ### GitHub Actions If your project is on GitHub, you could take advantage of GitHub Actions and the `usethis` functionality. [r-lib/actions](https://github.com/r-lib/actions/) includes a [`lint-project` example](https://github.com/r-lib/actions/tree/v2-branch/examples#lint-project-workflow), which you can use by calling: ``` r usethis::use_github_action("lint-project") ``` ### Super-Linter `lintr` powers R lints for [Super-Linter](https://github.com/github/super-linter) and [MegaLinter](https://megalinter.io/latest/), which provide a unified linting experience across many languages. Specifically, they execute `lintr::lint()` on the R and R Markdown files included in a given project. lintr/inst/doc/lintr.R0000644000176200001440000001031614752763365014422 0ustar liggesusers## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ## ----show_default_settings, echo = FALSE-------------------------------------- default_settings <- lintr::default_settings default_settings$linters <- "`lintr::default_linters`" default_settings$comment_token <- "(lintr-bot comment token for automatic GitHub comments)" default_settings$exclusions <- "(empty)" make_string <- function(x) { if (inherits(x, "regex")) { paste0("regex: `", x, "`") } else { as.character(x) } } defaults_table <- data.frame(default = vapply(default_settings, make_string, character(1L))) # avoid conflict when loading lintr in echo=TRUE cell below rm(default_settings) knitr::kable(defaults_table) ## ----show_linter_defaults, echo = FALSE--------------------------------------- library(lintr) # needed here for formalArgs default_linters <- lintr::default_linters linters_with_args <- lapply( setNames(nm = intersect(names(default_linters), lintr::available_linters(tags = "configurable")$linter)), formalArgs ) make_setting_string <- function(linter_name) { linter_args <- linters_with_args[[linter_name]] if (is.null(linter_args)) { return("") } arglist <- vapply(linter_args, function(arg) { env <- environment(default_linters[[linter_name]]) deparse(env[[arg]]) }, character(1L)) paste0(linter_args, " = ", arglist, collapse = ", ") } defaults_table <- data.frame( row.names = names(default_linters), settings = vapply(names(default_linters), make_setting_string, character(1L)) ) knitr::kable(defaults_table) ## ----show_tags---------------------------------------------------------------- lintr::available_tags(packages = "lintr") ## ----show_tag_linters--------------------------------------------------------- linters <- lintr::linters_with_tags(tags = c("package_development", "readability")) names(linters) ## ----show_all_linter_names---------------------------------------------------- names(lintr::all_linters()) ## ----programmatic_lintr------------------------------------------------------- library(lintr) linter_name <- "assignment_linter" show_lint <- function(l) { lint_df <- as.data.frame(l) print(lint_df[, c("line_number", "message", "linter")]) } hline <- function() cat(strrep("-", getOption("width") - 5L), "\n", sep = "") withr::with_tempfile("tmp", { writeLines("a = 1", tmp) # linter column is just 'get' show_lint(lint(tmp, linters = get(linter_name)())) hline() this_linter <- get(linter_name)() attr(this_linter, "name") <- linter_name # linter column is 'assignment_linter' show_lint(lint(tmp, linters = this_linter)) hline() # more concise alternative for this case: use eval(call(.)) show_lint(lint(tmp, linters = eval(call(linter_name)))) }) ## ----show_long_line_lint, echo = FALSE---------------------------------------- lint("X = 42L # -------------- this comment overflows the default 80 chars line length.\n", parse_settings = FALSE ) ## ----show_nolint, echo = FALSE------------------------------------------------ lint("X = 42L # nolint ------ this comment overflows the default 80 chars line length.\n", parse_settings = FALSE ) ## ----show_long_line_lint_not_skipped, echo = FALSE---------------------------- lint("X = 42L # nolint: object_name_linter. this comment overflows the default 80 chars line length.\n", parse_settings = FALSE ) ## ----show_nolint_multiple, echo = FALSE--------------------------------------- lint( paste( "X = 42L", "# nolint: object_name_linter, line_length_linter. this comment overflows the default 80 chars line length.\n" ), parse_settings = FALSE ) ## ----show_nolint_abbrev, echo = FALSE----------------------------------------- lint( paste( "X = 42L", "# nolint: object_name, line_len. this comment still overflows the default 80 chars line length.\n" ), parse_settings = FALSE ) ## ----show_comment_code_lint, echo = FALSE------------------------------------- lint("# x <- 42L\n# print(x)\n", parse_settings = FALSE) ## ----show_comment_code_nolint, echo = FALSE----------------------------------- lint("# nolint start: commented_code_linter.\n# x <- 42L\n# print(x)\n# nolint end\n", parse_settings = FALSE ) lintr/inst/doc/editors.Rmd0000644000176200001440000001324114752731051015247 0ustar liggesusers--- title: "Editor setup" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Editor setup} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) in_pkgdown <- identical(Sys.getenv("IN_PKGDOWN"), "true") maybe_still <- function(url) { if (in_pkgdown) { url } else { gsub("\\.gif$", "-still.gif", url) } } ``` ```{r, echo = FALSE, results = 'asis'} if (!in_pkgdown) { cat( "Note: This vignette is best viewed [online](https://lintr.r-lib.org/articles/editors.html),", "where we can render full animations of editor flows.\n" ) } ``` ## RStudio lintr lints are automatically displayed in the RStudio Markers pane (RStudio versions \> v0.99.206). ![RStudio Example](rstudio.png "Rstudio Example") In order to show the "Markers" pane in RStudio: Menu "Tools" -\> "Global Options...", a window with title "Options" will pop up. In that window: click "Code" on the left; click "Diagnostics" tab; check "Show diagnostics for R". To lint a source file `test.R` type in the Console `lintr::lint("test.R")` and look at the result in the "Markers" pane. This package also includes two addins for linting the current source and package. To bind the addin to a keyboard shortcut navigate to Tools \> addins \> Browse Addins \> Keyboard Shortcuts. It's recommended to use Alt+Shift+L for linting the current source lint and Ctrl+Shift+Alt+L to code the package. These are easy to remember as you are Alt+Shift+L(int) ;) ## Emacs lintr has [built-in integration](http://www.flycheck.org/en/latest/languages.html#r) with [flycheck](https://github.com/flycheck/flycheck) versions greater than `0.23`. ![Emacs Example](`r maybe_still("emacs.gif")` "Emacs Example") ### Installation lintr is fully integrated into flycheck when using [ESS](http://ess.r-project.org/). See the installation documentation for those packages for more information. ### Configuration You can also configure what linters are used. e.g. using a different line length cutoff. - `M-x customize-option` -\> `flycheck-lintr-linters` -\> `linters_with_defaults(line_length_linter(120))` ## Vim - syntastic lintr can be integrated with [syntastic](https://github.com/vim-syntastic/syntastic) for on-the-fly linting. ![Vim Example](`r maybe_still("vim-syntastic.gif")` "Vim Example") ### Installation Put the file [syntastic/lintr.vim](https://raw.githubusercontent.com/r-lib/lintr/v2.0.1/inst/syntastic/lintr.vim) in `syntastic/syntax_checkers/r`. If you are using [pathogen](https://github.com/tpope/vim-pathogen) this directory is `~/.vim/bundles/syntastic/syntax_checkers/r`. You will also need to add the following lines to your `.vimrc`. ``` vim let g:syntastic_enable_r_lintr_checker = 1 let g:syntastic_r_checkers = ['lintr'] ``` ### Configuration You can also configure what linters are used. e.g. using a different line length cutoff. ``` vim let g:syntastic_r_lintr_linters = "linters_with_defaults(line_length_linter(120))" ``` ## Vim - ALE lintr can be integrated with [ALE](https://github.com/dense-analysis/ale) for on the fly linting. ### Installation lintr is integrated with ALE and requires no additional installation. ### Configuration You can configure what linters are used, e.g. using a different line length cutoff. ``` vim let g:ale_r_lintr_options = "linters_with_defaults(line_length_linter(120))" ``` You can also configure whether `lint` or `lint_package` is used. Set to 1 for `lint_package` and 0 (default) for `lint`. ``` vim let g:ale_r_lintr_lint_package = 1 ``` See `:h ale_r_lintr` for more information. Note that configuration through `.lintr` files are not supported. There is a work around that can be used to read the contents of a `.lintr` file in the root of the working directory. This would allow the use of configuration through `.lintr` files. ``` vim if filereadable(".lintr") let g:ale_r_lintr_options = join(readfile('.lintr')) endif ``` ## Sublime Text 3 lintr can be integrated with [Sublime Linter](https://github.com/SublimeLinter/SublimeLinter) for on-the-fly linting. ![Sublime Example](`r maybe_still("sublime.gif")` "Sublime Example") ### Installation Simply install `sublimeLinter-contrib-lintr` using [Package Control](https://packagecontrol.io/). For more information see [Sublime Linter Docs](http://sublimelinter.readthedocs.io/en/latest/installation.html#installing-via-pc) ### Configuration You can also configure what linters are used. e.g. disabling the assignment linter and using a different line length cutoff. In the SublimeLinter User Settings ```json { "linters": { "lintr": { "linters": "linters_with_defaults(assignment_linter = NULL, line_length_linter(120))" } } } ``` ## Atom lintr can be integrated with [Linter](https://github.com/steelbrain/linter) for on the fly linting. ![Atom Example](atom.png "Atom Example") ### Installation Simply install `linter-lintr` from within Atom or on the command line with: ``` bash apm install linter-lintr ``` For more information and bug reports see [Atom linter-lintr](https://github.com/AtomLinter/linter-lintr). ## Visual Studio Code In Visual Studio Code, [vscode-R](https://github.com/REditorSupport/vscode-R#r-extension-for-visual-studio-code) presents the lintr diagnostics from [languageserver](https://github.com/REditorSupport/languageserver). ![VS Code Example](vscode.png "VS Code Example") ### Installation Installing `languageserver` package in R and `vscode-R` extension in VS Code will enable lintr in VS Code by default or run the following command lines: ``` bash Rscript -e 'install.packages("languageserver")' code --install-extension reditorsupport.r ``` lintr/inst/doc/lintr.html0000644000176200001440000017155314752763366015201 0ustar liggesusers Using lintr

Using lintr

This vignette describes how to set up and configure lintr for use with projects or packages.

Running lintr on a project

Checking an R project for lints can be done with three different functions:

  • Lint a single file using lint():

    lint(filename = "R/bad.R")
  • Lint a directory using lint_dir():

    lint_dir(path = "R")

    This will apply lint() to all R source files matching the pattern argument. By default, this means all .R files as well as knitr formats (e.g. .Rmd, .Rnw).

    lint_dir is vectorized over path, so multiple directories can be linted at the same time.

  • Lint all relevant directories of an R package using lint_package():

    lint_package(path = ".")

    This will apply lint_dir() to all subdirectories usually containing R code in packages:

    • R containing the package implementation.
    • tests containing test code.
    • inst containing sample code or vignettes that will be installed along with the package.
    • vignettes containing package vignettes.
    • data-raw containing code to produce data files.

For more information about the assumed package structure, see R Packages.

Note that some linters (e.g. object_usage_linter()) require the package to be installed to function properly. pkgload::load_all() will also suffice. See ?executing_linters for more details.

Configuring linters

The .lintr file

The canonical way to configure R projects and packages for linting is to create a .lintr file in the project root. This is a file in debian control format (?read.dcf), each value of which is evaluated as R code by lintr when reading the settings. A minimal .lintr file can be generated by running use_lintr() in the project directory. Lintr supports per-project configuration of the following fields.

  • linters - see ?linters_with_defaults for example of specifying only a few non-default linters and ?linters_with_tags for more fine-grained control.
  • exclusions - a list of filenames to exclude from linting. You can use a named item to exclude only certain lines from a file.
  • exclude - a regex pattern for lines to exclude from linting. Default is “# nolintâ€
  • exclude_start - a regex pattern to start exclusion range. Default is “# nolint startâ€
  • exclude_end - a regex pattern to end exclusion range. Default is “# nolint endâ€
  • encoding - the encoding used for source files. Default inferred from .Rproj or DESCRIPTION files, fallback to UTF-8

.lintr File Example

Below is an example .lintr file that uses 120 character line lengths, disables commented_code_linter, excludes a couple of files.

linters: linters_with_defaults(
    line_length_linter(120),
    commented_code_linter = NULL
  )
exclusions: list(
    "inst/doc/creating_linters.R" = 1,
    "inst/example/bad.R",
    "tests/testthat/exclusions-test"
  )

Other configuration options

More generally, lintr searches for a settings file according to following prioritized list. The first one found, if any, will be used:

  1. If options("lintr.linter_file") is an absolute path, this file will be used. The default for this option is ".lintr" or the value of the environment variable R_LINTR_LINTER_FILE, if set.
  2. A project-local linter file; that is, either
    1. a linter file (that is, a file named like lintr.linter_file) in the currently-searched directory, i.e. the directory of the file passed to lint(); or
    2. a linter file in the .github/linters child directory of the currently-searched directory.
  3. A project-local linter file in the closest parent directory of the currently-searched directory, starting from the deepest path, moving upwards one level at a time. When run from lint_package(), this directory can differ for each linted file.
  4. A linter file in the user’s HOME directory.
  5. A linter file called config in the user’s configuration path (given by tools::R_user_dir("lintr", which = "config")).

If no linter file is found, only default settings take effect (see defaults).

Using options()

Values in options(), if they are not NULL, take precedence over those in the linter file (e.g. .lintr). Note that the key option_name in the linter file translates to an R option lintr.option_name. For example, options(lintr.exclude = "# skip lint") will take precedence over exclude: # nolint in the linter file.

Using arguments to lint()

The settings can also be passed as arguments to linting functions directly. In case of exclusions, these will be combined with the globally parsed settings. Other settings will be overridden.

If only the specified settings should be changed, and the remaining settings should be taken directly from the defaults, the argument parse_settings = FALSE can be added to the function calls. This will suppress reading of the .lintr configuration. This is particularly useful for tests which should not exclude example files containing lints while the package-level .lintr excludes those files because the lints are intentional.

Defaults

The default settings of lintr are intended to conform to the tidyverse style guide. However, the behavior can be customized using different methods.

Apart from lintr.linter_file, which defaults to ".lintr", there are the following settings:

default
linters lintr::default_linters
encoding UTF-8
exclude regex: #[[:space:]]*nolint
exclude_next regex: #[[:space:]]*nolint next
exclude_start regex: #[[:space:]]*nolint start
exclude_end regex: #[[:space:]]*nolint end
exclude_linter regex: ^[[:space:]]*:[[:space:]]*(?<linters>(?:(?:[^,.])+[[:space:]]*,[[:space:]]*)*(?:[^,.])+)\.
exclude_linter_sep regex: [[:space:]]*,[[:space:]]*
exclusions (empty)
cache_directory /root/.cache/R/lintr
comment_token (lintr-bot comment token for automatic GitHub comments)
error_on_lint FALSE

Note that the default encoding setting depends on the file to be linted. If an Encoding is found in a .Rproj file or a DESCRIPTION file, that encoding overrides the default of UTF-8.

Customizing active linters

If you only want to customize some linters, you can use the helper function linters_with_defaults(), which will keep all unnamed linters with the default settings. Disable a linter by passing NULL.

For example, to set the line length limit to 120 characters and globally disable the whitespace_linter(), you can put this into your .lintr:

linters: linters_with_defaults(
    line_length_linter = line_length_linter(120L),
    whitespace_linter = NULL
  )

By default, the following linters are enabled. Where applicable, the default settings are also shown.

settings
assignment_linter operator = c(“<-â€, “<<-â€), allow_cascading_assign = TRUE, allow_right_assign = FALSE, allow_trailing = TRUE, allow_pipe_assign = FALSE
brace_linter allow_single_line = FALSE
commas_linter allow_trailing = FALSE
commented_code_linter
equals_na_linter
function_left_parentheses_linter
indentation_linter indent = 2L, hanging_indent_style = “tidyâ€, assignment_as_infix = TRUE
infix_spaces_linter exclude_operators = NULL, allow_multiple_spaces = TRUE
line_length_linter length = 80L
object_length_linter length = 30L
object_name_linter styles = c(“snake_caseâ€, “symbolsâ€), regexes = character(0)
object_usage_linter interpret_glue = TRUE, skip_with = TRUE
paren_body_linter
pipe_continuation_linter
quotes_linter delimiter = “"â€
return_linter return_style = “implicitâ€, allow_implicit_else = TRUE, return_functions = NULL, except = NULL, except_regex = NULL
semicolon_linter allow_compound = FALSE, allow_trailing = FALSE
seq_linter
spaces_inside_linter
spaces_left_parentheses_linter
T_and_F_symbol_linter
trailing_blank_lines_linter
trailing_whitespace_linter allow_empty_lines = FALSE, allow_in_strings = TRUE
vector_logic_linter
whitespace_linter

Another way to customize linters is by specifying tags in linters_with_tags(). The available tags are listed below:

lintr::available_tags(packages = "lintr")
#>  [1] "best_practices"      "common_mistakes"     "configurable"       
#>  [4] "consistency"         "correctness"         "default"            
#>  [7] "deprecated"          "efficiency"          "executing"          
#> [10] "package_development" "pkg_testthat"        "readability"        
#> [13] "regex"               "robustness"          "style"              
#> [16] "tidy_design"

You can select tags of interest to see which linters are included:

linters <- lintr::linters_with_tags(tags = c("package_development", "readability"))
names(linters)
#>  [1] "backport_linter"                  "boolean_arithmetic_linter"       
#>  [3] "brace_linter"                     "commas_linter"                   
#>  [5] "commented_code_linter"            "comparison_negation_linter"      
#>  [7] "conjunct_test_linter"             "consecutive_assertion_linter"    
#>  [9] "consecutive_mutate_linter"        "cyclocomp_linter"                
#> [11] "empty_assignment_linter"          "expect_comparison_linter"        
#> [13] "expect_identical_linter"          "expect_length_linter"            
#> [15] "expect_named_linter"              "expect_not_linter"               
#> [17] "expect_null_linter"               "expect_s3_class_linter"          
#> [19] "expect_s4_class_linter"           "expect_true_false_linter"        
#> [21] "expect_type_linter"               "fixed_regex_linter"              
#> [23] "for_loop_index_linter"            "function_left_parentheses_linter"
#> [25] "function_return_linter"           "if_not_else_linter"              
#> [27] "if_switch_linter"                 "implicit_assignment_linter"      
#> [29] "indentation_linter"               "infix_spaces_linter"             
#> [31] "inner_combine_linter"             "is_numeric_linter"               
#> [33] "keyword_quote_linter"             "length_levels_linter"            
#> [35] "lengths_linter"                   "library_call_linter"             
#> [37] "line_length_linter"               "matrix_apply_linter"             
#> [39] "nested_ifelse_linter"             "nested_pipe_linter"              
#> [41] "numeric_leading_zero_linter"      "object_length_linter"            
#> [43] "object_overwrite_linter"          "object_usage_linter"             
#> [45] "one_call_pipe_linter"             "outer_negation_linter"           
#> [47] "package_hooks_linter"             "paren_body_linter"               
#> [49] "pipe_call_linter"                 "pipe_consistency_linter"         
#> [51] "pipe_continuation_linter"         "quotes_linter"                   
#> [53] "redundant_equals_linter"          "rep_len_linter"                  
#> [55] "repeat_linter"                    "sample_int_linter"               
#> [57] "scalar_in_linter"                 "semicolon_linter"                
#> [59] "sort_linter"                      "spaces_inside_linter"            
#> [61] "spaces_left_parentheses_linter"   "stopifnot_all_linter"            
#> [63] "string_boundary_linter"           "system_file_linter"              
#> [65] "T_and_F_symbol_linter"            "unnecessary_concatenation_linter"
#> [67] "unnecessary_lambda_linter"        "unnecessary_nesting_linter"      
#> [69] "unnecessary_placeholder_linter"   "unreachable_code_linter"         
#> [71] "which_grepl_linter"               "yoda_test_linter"

You can include tag-based linters in the configuration file, and customize them further:

linters: linters_with_tags(
    tags = c("package_development", "readability"),
    yoda_test_linter = NULL
  )

Using all available linters

The default lintr configuration includes only linters relevant to the tidyverse style guide, but there are many other linters available in {lintr}. You can see a list of all available linters using

names(lintr::all_linters())
#>   [1] "absolute_path_linter"             "any_duplicated_linter"           
#>   [3] "any_is_na_linter"                 "assignment_linter"               
#>   [5] "backport_linter"                  "boolean_arithmetic_linter"       
#>   [7] "brace_linter"                     "class_equals_linter"             
#>   [9] "commas_linter"                    "commented_code_linter"           
#>  [11] "comparison_negation_linter"       "condition_call_linter"           
#>  [13] "condition_message_linter"         "conjunct_test_linter"            
#>  [15] "consecutive_assertion_linter"     "consecutive_mutate_linter"       
#>  [17] "cyclocomp_linter"                 "duplicate_argument_linter"       
#>  [19] "empty_assignment_linter"          "equals_na_linter"                
#>  [21] "expect_comparison_linter"         "expect_identical_linter"         
#>  [23] "expect_length_linter"             "expect_named_linter"             
#>  [25] "expect_not_linter"                "expect_null_linter"              
#>  [27] "expect_s3_class_linter"           "expect_s4_class_linter"          
#>  [29] "expect_true_false_linter"         "expect_type_linter"              
#>  [31] "fixed_regex_linter"               "for_loop_index_linter"           
#>  [33] "function_argument_linter"         "function_left_parentheses_linter"
#>  [35] "function_return_linter"           "if_not_else_linter"              
#>  [37] "if_switch_linter"                 "ifelse_censor_linter"            
#>  [39] "implicit_assignment_linter"       "implicit_integer_linter"         
#>  [41] "indentation_linter"               "infix_spaces_linter"             
#>  [43] "inner_combine_linter"             "is_numeric_linter"               
#>  [45] "keyword_quote_linter"             "length_levels_linter"            
#>  [47] "length_test_linter"               "lengths_linter"                  
#>  [49] "library_call_linter"              "line_length_linter"              
#>  [51] "list_comparison_linter"           "literal_coercion_linter"         
#>  [53] "matrix_apply_linter"              "missing_argument_linter"         
#>  [55] "missing_package_linter"           "namespace_linter"                
#>  [57] "nested_ifelse_linter"             "nested_pipe_linter"              
#>  [59] "nonportable_path_linter"          "nrow_subset_linter"              
#>  [61] "numeric_leading_zero_linter"      "nzchar_linter"                   
#>  [63] "object_length_linter"             "object_name_linter"              
#>  [65] "object_overwrite_linter"          "object_usage_linter"             
#>  [67] "one_call_pipe_linter"             "outer_negation_linter"           
#>  [69] "package_hooks_linter"             "paren_body_linter"               
#>  [71] "paste_linter"                     "pipe_call_linter"                
#>  [73] "pipe_consistency_linter"          "pipe_continuation_linter"        
#>  [75] "pipe_return_linter"               "print_linter"                    
#>  [77] "quotes_linter"                    "redundant_equals_linter"         
#>  [79] "redundant_ifelse_linter"          "regex_subset_linter"             
#>  [81] "rep_len_linter"                   "repeat_linter"                   
#>  [83] "return_linter"                    "routine_registration_linter"     
#>  [85] "sample_int_linter"                "scalar_in_linter"                
#>  [87] "semicolon_linter"                 "seq_linter"                      
#>  [89] "sort_linter"                      "spaces_inside_linter"            
#>  [91] "spaces_left_parentheses_linter"   "sprintf_linter"                  
#>  [93] "stopifnot_all_linter"             "string_boundary_linter"          
#>  [95] "strings_as_factors_linter"        "system_file_linter"              
#>  [97] "T_and_F_symbol_linter"            "terminal_close_linter"           
#>  [99] "todo_comment_linter"              "trailing_blank_lines_linter"     
#> [101] "trailing_whitespace_linter"       "undesirable_function_linter"     
#> [103] "undesirable_operator_linter"      "unnecessary_concatenation_linter"
#> [105] "unnecessary_lambda_linter"        "unnecessary_nesting_linter"      
#> [107] "unnecessary_placeholder_linter"   "unreachable_code_linter"         
#> [109] "unused_import_linter"             "vector_logic_linter"             
#> [111] "which_grepl_linter"               "whitespace_linter"               
#> [113] "yoda_test_linter"

If you want to use all available linters, you can include this in your .lintr file:

linters: all_linters()

If you want to use all available linters except a few, you can exclude them using NULL:

linters: all_linters(
    commented_code_linter = NULL,
    implicit_integer_linter = NULL
  )

Advanced: programmatic retrieval of linters

For some use cases, it may be useful to specify linters by string instead of by name, i.e. "assignment_linter" instead of writing out assignment_linter().

Beware that in such cases, a simple get() is not enough:

library(lintr)
linter_name <- "assignment_linter"

show_lint <- function(l) {
  lint_df <- as.data.frame(l)
  print(lint_df[, c("line_number", "message", "linter")])
}
hline <- function() cat(strrep("-", getOption("width") - 5L), "\n", sep = "")

withr::with_tempfile("tmp", {
  writeLines("a = 1", tmp)

  # linter column is just 'get'
  show_lint(lint(tmp, linters = get(linter_name)()))
  hline()

  this_linter <- get(linter_name)()
  attr(this_linter, "name") <- linter_name
  # linter column is 'assignment_linter'
  show_lint(lint(tmp, linters = this_linter))
  hline()

  # more concise alternative for this case: use eval(call(.))
  show_lint(lint(tmp, linters = eval(call(linter_name))))
})
#>   line_number                                   message linter
#> 1           1 Use one of <-, <<- for assignment, not =.    get
#> ---------------------------------------------------------------------------
#>   line_number                                   message            linter
#> 1           1 Use one of <-, <<- for assignment, not =. assignment_linter
#> ---------------------------------------------------------------------------
#>   line_number                                   message            linter
#> 1           1 Use one of <-, <<- for assignment, not =. assignment_linter

Exclusions

Sometimes, linters should not be globally disabled. Instead, one might want to exclude some code from linting altogether or selectively disable some linters on some part of the code.

Note that the preferred way of excluding lints from source code is to use the narrowest possible scope and specify exactly which linters should not throw a lint on a marked line. This prevents accidental suppression of justified lints that happen to be on the same line as a lint that needs to be suppressed.

Excluding lines of code

Within source files, special comments can be used to exclude single lines of code from linting. All lints produced on the marked line are excluded from the results.

By default, this special comment is # nolint:

file.R

X = 42L # -------------- this comment overflows the default 80 chars line length.

> lint("file.R")

#> <text>:1:1: style: [object_name_linter] Variable and function name style should match snake_case or symbols.
#> X = 42L # -------------- this comment overflows the default 80 chars line length.
#> ^
#> <text>:1:3: style: [assignment_linter] Use one of <-, <<- for assignment, not =.
#> X = 42L # -------------- this comment overflows the default 80 chars line length.
#>   ^
#> <text>:1:81: style: [line_length_linter] Lines should not be more than 80 characters. This line is 81 characters.
#> X = 42L # -------------- this comment overflows the default 80 chars line length.
#> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

file2.R

X = 42L # nolint ------ this comment overflows the default 80 chars line length.

> lint("file2.R")

#> ℹ No lints found.

Observe how all lints were suppressed and no output is shown. Sometimes, only a specific linter needs to be excluded. In this case, the name of the linter can be appended to the # nolint comment preceded by a colon and terminated by a dot.

Excluding only some linters

file3.R

X = 42L # nolint: object_name_linter. this comment overflows the default 80 chars line length.

> lint("file3.R")

#> <text>:1:3: style: [assignment_linter] Use one of <-, <<- for assignment, not =.
#> X = 42L # nolint: object_name_linter. this comment overflows the default 80 chars line length.
#>   ^
#> <text>:1:81: style: [line_length_linter] Lines should not be more than 80 characters. This line is 94 characters.
#> X = 42L # nolint: object_name_linter. this comment overflows the default 80 chars line length.
#> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~

Observe how only the object_name_linter was suppressed. This is preferable to blanket # nolint statements because blanket exclusions may accidentally silence a linter that was not intentionally suppressed.

Multiple linters can be specified by listing them with a comma as a separator:

file4.R

X = 42L # nolint: object_name_linter, line_length_linter. this comment overflows the default 80 chars line length.

> lint("file4.R")

#> <text>:1:3: style: [assignment_linter] Use one of <-, <<- for assignment, not =.
#> X = 42L # nolint: object_name_linter, line_length_linter. this comment overflows the default 80 chars line length.
#>   ^

You can also specify the linter names by a unique prefix instead of their full name:

file5.R

X = 42L # nolint: object_name, line_len. this comment still overflows the default 80 chars line length.

> lint("file5.R")

#> <text>:1:3: style: [assignment_linter] Use one of <-, <<- for assignment, not =.
#> X = 42L # nolint: object_name, line_len. this comment still overflows the default 80 chars line length.
#>   ^

Excluding multiple lines of codes

If any or all linters should be disabled for a contiguous block of code, the exclude_start and exclude_end patterns can be used. They default to # nolint start and # nolint end respectively.

# nolint start accepts the same syntax as # nolint to disable specific linters in the following lines until a # nolint end is encountered.

# x <- 42L
# print(x)
#> <text>:1:3: style: [commented_code_linter] Remove commented code.
#> # x <- 42L
#>   ^~~~~~~~
#> <text>:2:3: style: [commented_code_linter] Remove commented code.
#> # print(x)
#>   ^~~~~~~~
# nolint start: commented_code_linter.
# x <- 42L
# print(x)
# nolint end
#> ℹ No lints found.

(No lints)

Excluding lines via the config file

Individual lines can also be excluded via the config file by setting the key exclusions to a list with elements corresponding to different files. To exclude all lints for line 1 of file R/bad.R and line_length_linter for lines 4 to 6 of the same file, one can set

exclusions: list(
    "R/bad.R" = list(
      1, # global exclusions are unnamed
      line_length_linter = 4:6
    )
  )

All paths are interpreted relative to the location of the .lintr file.

Excluding files completely

The linter configuration can also be used to exclude a file entirely, or a linter for a file entirely. Use the sentinel line number Inf to mark all lines as excluded within a file. If a file is only given as a character vector, full exclusion is implied.

exclusions: list(
    # excluded from all lints:
    "R/excluded1.R",
    "R/excluded2.R" = Inf,
    "R/excluded3.R" = list(Inf),
    # excluded from line_length_linter:
    "R/no-line-length.R" = list(
      line_length_linter = Inf
    )
  )

Excluding directories completely

Entire directories are also recognized when supplied as strings in the exclusions key. For example, to exclude the renv folder from linting in a R project using renv, set

exclusions: list(
    "renv"
  )

This is particularly useful for projects which include external code in subdirectories.

lintr/inst/doc/editors.html0000644000176200001440000163057114752763365015522 0ustar liggesusers Editor setup

Editor setup

Note: This vignette is best viewed online, where we can render full animations of editor flows.

RStudio

lintr lints are automatically displayed in the RStudio Markers pane (RStudio versions > v0.99.206).

RStudio Example
RStudio Example

In order to show the “Markers†pane in RStudio: Menu “Tools†-> “Global Options…â€, a window with title “Options†will pop up. In that window: click “Code†on the left; click “Diagnostics†tab; check “Show diagnostics for Râ€.

To lint a source file test.R type in the Console lintr::lint("test.R") and look at the result in the “Markers†pane.

This package also includes two addins for linting the current source and package. To bind the addin to a keyboard shortcut navigate to Tools > addins > Browse Addins > Keyboard Shortcuts. It’s recommended to use Alt+Shift+L for linting the current source lint and Ctrl+Shift+Alt+L to code the package. These are easy to remember as you are Alt+Shift+L(int) ;)

Emacs

lintr has built-in integration with flycheck versions greater than 0.23. Emacs Example

Installation

lintr is fully integrated into flycheck when using ESS. See the installation documentation for those packages for more information.

Configuration

You can also configure what linters are used. e.g. using a different line length cutoff. - M-x customize-option -> flycheck-lintr-linters -> linters_with_defaults(line_length_linter(120))

Vim - syntastic

lintr can be integrated with syntastic for on-the-fly linting.

Vim Example
Vim Example

Installation

Put the file syntastic/lintr.vim in syntastic/syntax_checkers/r. If you are using pathogen this directory is ~/.vim/bundles/syntastic/syntax_checkers/r.

You will also need to add the following lines to your .vimrc.

let g:syntastic_enable_r_lintr_checker = 1
let g:syntastic_r_checkers = ['lintr']

Configuration

You can also configure what linters are used. e.g. using a different line length cutoff.

let g:syntastic_r_lintr_linters = "linters_with_defaults(line_length_linter(120))"

Vim - ALE

lintr can be integrated with ALE for on the fly linting.

Installation

lintr is integrated with ALE and requires no additional installation.

Configuration

You can configure what linters are used, e.g. using a different line length cutoff.

let g:ale_r_lintr_options = "linters_with_defaults(line_length_linter(120))"

You can also configure whether lint or lint_package is used. Set to 1 for lint_package and 0 (default) for lint.

let g:ale_r_lintr_lint_package = 1

See :h ale_r_lintr for more information.

Note that configuration through .lintr files are not supported.

There is a work around that can be used to read the contents of a .lintr file in the root of the working directory. This would allow the use of configuration through .lintr files.

if filereadable(".lintr")
  let g:ale_r_lintr_options = join(readfile('.lintr'))
endif

Sublime Text 3

lintr can be integrated with Sublime Linter for on-the-fly linting.

Sublime Example
Sublime Example

Installation

Simply install sublimeLinter-contrib-lintr using Package Control.

For more information see Sublime Linter Docs

Configuration

You can also configure what linters are used. e.g. disabling the assignment linter and using a different line length cutoff. In the SublimeLinter User Settings

    {
      "linters": {
        "lintr": {
          "linters": "linters_with_defaults(assignment_linter = NULL, line_length_linter(120))"
        }
      }
    }

Atom

lintr can be integrated with Linter for on the fly linting.

Atom Example
Atom Example

Installation

Simply install linter-lintr from within Atom or on the command line with:

apm install linter-lintr

For more information and bug reports see Atom linter-lintr.

Visual Studio Code

In Visual Studio Code, vscode-R presents the lintr diagnostics from languageserver.

VS Code Example
VS Code Example

Installation

Installing languageserver package in R and vscode-R extension in VS Code will enable lintr in VS Code by default or run the following command lines:

Rscript -e 'install.packages("languageserver")'
code --install-extension reditorsupport.r
lintr/inst/rstudio/0000755000176200001440000000000014752731051014055 5ustar liggesuserslintr/inst/rstudio/addins.dcf0000644000176200001440000000034014752731051015772 0ustar liggesusersName: Lint current file Description: Runs lintr::lint on the current file Binding: addin_lint Interative: false Name: Lint current package Description: Runs lintr::lint_package Binding: addin_lint_package Interative: false lintr/inst/extdata/0000755000176200001440000000000014752731051014016 5ustar liggesuserslintr/inst/extdata/sarif-template.json0000644000176200001440000000271714752731051017635 0ustar liggesusers{ "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", "version": "2.1.0", "runs": [ { "tool": { "driver": { "name": "lintr", "informationUri": "https://lintr.r-lib.org/", "version": "2.0.1", "rules": [ { "id": "trailing_whitespace_linter", "fullDescription": { "text": "Trailing whitespace is superfluous." }, "defaultConfiguration": { "level": "note" } } ] } }, "results": [ { "ruleId": "trailing_whitespace_linter", "ruleIndex": 0, "message": { "text": "Trailing blank lines are superfluous." }, "locations": [ { "physicalLocation": { "artifactLocation": { "uri": "TestFileFolder/hello.r", "uriBaseId": "ROOTPATH" }, "region": { "startLine": 2, "startColumn": 22, "snippet": { "text": "print(Hello World!) " } } } } ] } ], "columnKind": "utf16CodeUnits", "originalUriBaseIds": { "ROOTPATH": { "uri": "file:///C:/repos/repototest/" } } } ] } lintr/inst/WORDLIST0000644000176200001440000000221214752731051013553 0ustar liggesusersALLUPPERCASE AST Addins Backport CMD Checkstyle Config Ctrl Cyclomatic Deprecations EQ ESS Github Linter Linters MegaLinter ORCID RMarkdown RStudio RUnit Relatedly Rhtml Rmarkdown Rmd Rnw Rproj Rrst Rstudio Rtex Rtxt SARIF SublimeLinter Testthat Tidyverse UpperCamelCase Wercker XPath XPaths YAML Yihui addin addins alllowercase backports backtick backticked bookdown bugfix checkstyle codecov codinghorror coercions config configs covr customizable customizations cyclocomp cyclomatic de debian deterministically dplyr dragosmg envvar eval flycheck generalizable ggplot github grDevices grepl https igraph importFrom infixes io jwz knitr labelled lang languageserver lapply len lifecycle linter linters lintr's lowerCamelCalse lubridate magrittr magrittr's michaelchirico mis nd nlevels nodeset nolint nzchar parseable parser's patilindrajeets performant positionally pre programmatically qmd readably regexes repo rlang roxygen sandboxing se sortedness src stopifnot stringr styler subdir syntastic templated testthat th tibble tidyverse tokenized travis tufte un unevaluated unicode unnest unparseable untrusted vectorized vscode wercker withr www xpath yoda lintr/README.md0000644000176200001440000000471414752731051012674 0ustar liggesusers# lintr [![R build status](https://github.com/r-lib/lintr/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/lintr/actions) [![codecov.io](https://codecov.io/gh/r-lib/lintr/branch/main/graphs/badge.svg)](https://app.codecov.io/gh/r-lib/lintr?branch=main) [![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/lintr)](https://cran.r-project.org/package=lintr) [![lifecycle](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html) `{lintr}` provides [static code analysis for R](https://en.wikipedia.org/wiki/Static_program_analysis). It checks for adherence to a given style, identifying syntax errors and possible semantic issues, then reports them to you so you can take action. Watch lintr in action in the following animation: ![](man/figures/demo.gif "lintr demo") `{lintr}` is complementary to [the `{styler}` package](https://github.com/r-lib/styler) which automatically restyles code, eliminating some of the problems that `{lintr}` can detect. ## Installation Install the stable version from CRAN: ```R install.packages("lintr") ``` Or the development version from GitHub: ```R # install.packages("remotes") remotes::install_github("r-lib/lintr") ``` ## Usage And then you can create a configuration file and run selected linters: ```R lintr::use_lintr(type = "tidyverse") # in a project: lintr::lint_dir() # in a package: lintr::lint_package() ``` To see a list of linters included for each configuration: ```R # tidyverse (default) names(lintr::linters_with_defaults()) # full names(lintr::all_linters()) ``` ### Setting up GitHub Actions `{usethis}` provides helper functions to generate lint workflows for GitHub Actions: ```R # in a project: usethis::use_github_action("lint-project") # in a package: usethis::use_github_action("lint") ``` You can also run lintr during continuous integration or within your IDE or text editor. See `vignette("continuous-integration")` and `vignette("editors")` for more details. Without further configuration, this will run the [default linters](https://lintr.r-lib.org/reference/default_linters.html). See `vignette("lintr")` to learn how to modify these defaults. ## Code of Conduct Please note that the lintr project is released with a [Contributor Code of Conduct](https://www.contributor-covenant.org/version/2/1/code_of_conduct/). By contributing to this project, you agree to abide by its terms. lintr/build/0000755000176200001440000000000014752763366012524 5ustar liggesuserslintr/build/vignette.rds0000644000176200001440000000045114752763366015063 0ustar liggesusers‹’QKÃ0dzµÛl lŠèK¿€ý›{ñEDÁ7 í9m2’”â›\¬×ìRÚÉDJ.Éÿþí/wéK̳p‚1Àe°À0ÅqŽ#Ä'Âù:SÒ Y©ÊÜ ia«¹J¦eNŽe¦5¹}-Zƒ6½Ü)䪵.í„!érÕ‘’ÉSVDI$Ô ‘(7¿s”Ä€­vžülZ³ƒ€nŽ”ônË‚,¿jê%羨žï«rÊvu¬”g¾/]«H˜Q£p¹p®ýwÙó?}áÈ0ÉK0”œ’nDÞð$l· ÖZŽºƒ®a2÷·qrµÒ¸‚"­êÔÃÎÚ_ïCÓ4_‡'Ê nü‰¼çÜòôMãû¸ûþ^ñ’¼lintr/build/stage23.rdb0000644000176200001440000001330514752763363014464 0ustar liggesusers‹í][oÛH––ßswâÜ»›-çb'¶”«sé¸;Žc§Ä—ÈN&éf·›"KÛ©&)Ûš »‹™—`gvæiþÀû0½¿dþÁb±‹ù“­CJEŠTÌ‹¥›ÌwdY_Õ9§ªNU±ôj8•J¥S½}ôÿ} £ÿõ¤RûOÑÏG¬Ï½©!Š“¸ÇD%º`‰+Ô9]Û©—ˆzý'iœª™‘d¾( ª”Jõ¦™{ûóÒ†)”¨Ä>q`neii~yÝ›ØÐE)ƒðɦԸ&›èºk€ÞU”BÅÞ”ýïož$ûæUÑC¡ïÅúÂÔOºA¢Šš$«%O ø&îS… 1<œoÌo¡|+6ûЕÙO3ˆWØ"¹èŒ´ÖU¿—óù‡>ü ±@<…ò©(ü|síãm¿óͶñ4ʧ;¯Èþ ƒx}0Úö{ñ4Ê‘ªÉ7×~^PdÁÈ·ñ ÊÑê%–z û³ â•”zV,õp ®½zøõ¡JúöH=¦l*~ÞÓ‡*éë®zúP%ÆSOz·túòs+æ}øô£ Ä+fµ¬´zñ¸aÖbp3œ8ž1Ta“lˆ´GËLr£^)hŠ‘™˜ätR";vª²  "Ü81ºT¨`À”W4²š!”üŒÌ ¦\ÃÎNÙ m Ä+¢‘õÇ¥ß`¯è6Ÿòkšúm Ém­dy ÄâvÜÃéÀ,gÔ 19­¶Ö€ÑaÄ3(Gj°¬xìp@ƒ>€Î’Ü~4nÀ›(ßLÌÁxãyM3ý<,±Œ]µžäºU¾Z𣠧2GÛÇzù ô"~Ôˇ¨—áæ€â£b>(Ŭ-Ï>ߘ›]›ÿ¨˜I1û%Í4‰”ýè2šf†m›èõòÁéåÅêê|þÿeKæ_Üg‹këOHÃ,‹Fd¹Y{æÈ(k5E A9n!>BùQl;¯¦X擃)v©©„FkœY&%jÅ”Yn½LÂZã¬qÀq”Ç“³ÆÆ¬I­À¹à“C¼òíĬ¢5ÉÏ!» Ä;(߉­¼£¶†8š‚ègjam èÜE\Dy1>-kY5ÕdUVKaç  àQ”&f<½šªÔ#0:…xåH—fC*Õr@¶#ˆçP>[?Sœª©S‚R- j­BtYlÎ7_p$[ÊNr)FÖÝ'ˆ‹(G3)?Ýí»påB¡€ÀUÄu”×TÝÑ Ù>A|ò‹Øª =ûø’A¼bÒ8RÔµ W*UͼÎizX#9d«ÖÂ#(IÐH¾ k$@ä$âY”“ôï#ìŽ"žC9¾_å,õT„’.›¦ÎmÃpÃÚfRÂM(ÖâM oRŸ kSÀöÄg(?‹Ízp»Lt: kK‡Ñ~•‡hk8¾Å…Jèç0soâ^d3„8ŠòhlµdmcRj]–ÀtÆ™~½ ™tìÈv$”wqå¹ä‚ÆnªP„ž >C9’m‡ëè!»GˆK(/u¾·€ì—Ä+&±6à »uʆ$j§±q 屨jb¦…êtè*‹ еßÎ†Ž´Õ¨l’ŠÃa†áy”χe)¼k¥OËæƒxuÚØ˜‘}*Þrq»…Ñ\TI*z Õ}Øž\ÊYdS=寫šaÈ¥nÍ HMŸà¶ˆhÒ1•Q%¢\¬C;+pbÍ0i3 æI?Ó&x‹¨°.¶ÖG0à7([ù¯‹v9&aꀳÀmYQ¸áj‘`£|c<ˆ[²Ü ý“¾-ľÍÙÿ@TQÑ {«lÈâ¡ Xøå׉u(=¹ f h¾žòƒxíõ|Ã1Ô. €²[Ë£~* k€@©€¸…òVlj‡\†–Óq´@&6‰[]Ë/™eÁd}9$µQ¤3ê–2è÷´Žf LÎ!fPÎì½YCv'ÇPŽÔí»*á$§Ñ!5ÞÒ¦š!‰…šbFÑÔyÄ{(ßKLSí7ø´UÔ,âÊ QÔˆQ~[Qç²ÜšÆÉE®®Õ¸m:¼©Ñ¾°RÕÐÔÀìkDeñƒð««(W;£. ñ'”Š­®>ŽÆ_Qô¢#n¡­{HØ‹Þ"þ å_uF-Ûˆ¿Fù×±Õ’=áùÿ3âoPþMl¬Ù•Бuc:¨ ;UEe“މíþR&¡Ã¶Ò-¼€r¤Ø&\´7Âd{å‹© ûK â•Pé‡yA/YïÞø½0„Å>™ŠÎíMÀ ”Ò â±MÙ—,b¯˜Ærc®LÄM{¸©5ßS°Öኚ^'œÒjC“O£Ro |#6ñ{ë̘‹ågp‚N8v»¼Õ¡4Ö~CógÞ|°Fh=©ˆ#4ß\ðt)êrâòµCŽgã8H|g8‹à`CÌ œÜÀò¸­šÚ†ƒz&¹l6IGˆ÷Q¾ß!Π<[GÇi€/ÐžŠ¨&G{°¢VSC÷´ÀèKÄç(?Íì,ÔµšÎ-Ï.ͯ­ÎÎÍsp†N–[,†5ªŒm :1¼³(|ϤÐÉO5Y'n(t ü¾@|†r’[žš=êÁwòGg¼ì#pG¼ƒr¤}õ¾Ov®¥&A6¸˜jí¾:—JbÖ®Hã:pÛ{»!dÀApX¯^+ˆe”# *\üh#áMÐö@¥mƒ¢ib²±c†·šzÉ„U¡ fÀnhØŽ@‹b„- ³qÌZíIE\u•åskÖÞs«9û[,â ¼Û&…ИÝcì¢Ó*f5%Áí³µZµªÁ "í¶ÉŽP©*ô,𖅭ЫºÌÚ Š%Ô‘Á1V­j˜:*¡;ñ‹Ìu«‰{ݨ@6â4ÊÓ tâ-}eè•E`tñ ÊOb3»½]–Å2W6a a‹6}V£!Ó¸žìØq=·vÃÞ /‹\±¦ŠÝ…% ìïIE|—Ìר>6¨)J}ƒö&ÙP4µ´áPÝhž’¶{ëƒÎqñÊÉ­Zóú_ÌWÙo/Ú+]ÐP˜0½CvL¢J “ŒØ½¿ Äe”ãw¿× õæûT'jºNG;š §\rb–5Éjþ,æÖÉ•\HÞX¯€×Q¾ž˜)Vêx f8‹:w ü`ï-²»8‹rüI¸tèžòˆ8‡r´·Øo‡Ö©½OÂ6¨t.£a¡<”œ‘8½bX#¹Œ O¢|rï²F<…r¤s,=ï^áP¶1ŒµgŸÙ™Z½¦“´€aM ØžFüå¯c³~êìë5˺¶­rÆu…q²eA«•ÊV‹+Yƒñ Mš±zÕbÞ]ÒDh¹‚†øå§Ý2G#'8º]„­ bÐx@¨CÐR¢Žuv/|ØÖôM»3aÏ“lXam7lŒFcœ°Å™Â".¢¼»8³V—+›—\£*{c¿A äµÞâs™;•¨ÅCßÚ8²H0ÖjŠo®ƒ¼DLˆ‹}r>‡¹åµ‡Ðf Ù§Ä+b“}e·tÛê«)û ñŠY-£cöêUUפšh‡üÑ| ·k¨&Àx;å]ß™ñÐd˜A˜õ¹ÇƘdNsœIºÜ —¡C²-AçîOqמeã®@~Ìö­S¾Å¡ÓæíNAÍ4ŽøË„?ß”9Í%ÁƒºÓá‰0™³§‡ïU#Ècóv0™Æ*¢å3‘p‚–¢iù;¯Ùìï !À(ŸˆMn~·f/Žgç(Áٿî2Žù½‹üçQžï†0[)»ê_`ÞvÕ î#û‰ºÁ©¦,Õ_Æhÿg ³15~ôs{×í?s_„àKd oæ-¦é…™ÕeÓ€y;ØUÓgFê{Ó†Ùð"!Àäz€¹÷>s²û8¹ÙÇvÑ’,œ‡n x>Jû?‡ìçÜrçàfþ¨ËNÀt‚ :ÁÀ§m õÐl˜EöDþî¸äc$ð8Q—L.ù99SZÉ„#ӻwLÂÛ?3ÁÂÅ;ïˆO0ó']vDf¯û½Ñ3$ð,QÓgã‘zôxd &×í> gÐÜ—‘/`WÃðÌ|¥Ëf¿Šy;ØU³Žž'jöÙ?Ûhñ¿à*uüp=Šä‘ àE”/Æ&û8DXÎÆ#qó5, ÓñvÞ1Ö1óõ.;Æ ÌÛÁ®:ÆK$ð2QÇsE'EÇ-¨¼¹sø²ŒuÈY×C•WȰ«¡ÊkÌüu—=âÌÛÁÈá›íéüV¶®bvß&ꌡW¶¾E 8˜Ž¬‰DÞÉçSö£¿†ì{ z\HRߥìÐð`*Æ!tþÆÉìÌnɶñʇb[ÈMk‹ì~˴Π5¬Öȵ¤l-’‡^/Ƈ¢ü0± ä BÅÐìêéûîzÕ÷èIÆó*¸Û÷PÜu¡Ö–7Щ6Ж‡£Ú²ÅhÜŠÚÀtâ•¿€37äRMsÉ쇔ý6àÊ{âô-¯cŒÎ°¼7¢5ZÀ{ñ,Ê‘Ònyr"³—-î("ô/­@þW'QžLÌvö[ïx&QÅzb‹ˆk(¯uÆtŽÏ0´cXÎ Ä”³œ)Äu”#ý@–óñ%Ê/“eà!:Hiˆ5”k±š#3H9†Å|‡¨ ¬$f1¿@ÜBy«K³¸ƒòNb3D#=±fÊj)­CüÊ¿ëŒÍŒÌ4HǰšDü-Ê¿MÌjꈿGù÷]²šGüÊHÌjú¬9”þñ/(ÿ¥3shÆ"ÃZþ„øg”ÿœ˜µüñg”Žm-¡‡Âý2ˆW‚A“p"Ú†m\Ö Õ] š û4ƒ‘ƒ&ßTÖ¯Áµäéü+`±SQŠ)¼§%Âßš©+‚¨k”óðâßRÍ Jl>µYg¼)š9ôòI3ÄKšjšÄ0™„ƒ^*¼ È‚Á¤è÷}?j’Õ!5öz ÒüÄõz•¸Ó°Zhމx+ža“÷$ÙÇ‹º»„ÞÒYÇúØgõ$êãUëW½|<‰$ò“êfâKz?oýn:ºM#ù±frŸ[T²-j•Šõ“'[N¶¹e€wµi$?à˺lœ“hÔýÌàçÉEUrÝši©[°û÷ØXËiûÜ>Nd`nØï›¨ )Rk"ŸZ‹D1Øçha¹vÓ~KÏ_žç¦®¹ì78k¿§º’ S€ßL\ÆuÄçaƒ< ÀDRe}Ðë8ì¼p#Q_‹£n JÍîpK›@´ é^¾ºéS~w.cD•dÖ6ÆZž²%èïyŠór—×v<5Ó˜¶këžy9‘GoBêMO×t?oIà®f_#èçI3Y…ø5±L/ÚH7ðDÏ9¤iåɦùô5]I¹Z ŸöŸj“U§Ÿ&hØRT¯§Ýò4O}Ðn©¦¸ $È#]dzFíSP­fº Ø QØÇXºËÜâ([ï­8£¬m¿§âø¼´Ruñní——Ьæ÷ût ª©×Ô6ÜòUÚìkzŽ”“Ú$„†Çë1~¾:ÀKøS½ï5¸~Þ”Me7Ýû µ^yOæý´/jéŠÚèŽù–éÓæú¤Ý$õmM—vÁ6ÍçÛoÐÆÙßü¼ƒ ëíÿ¶#©æ/#ûU·ß8ÉÒuk)ÚÇ»zZoíü*Ý.:‚ÍB»¦`?íA‹„ö¢"y_UѦ1h(ÜörŽÿõ£wŒÇf±ý_ÚÉât@Xè:»É>µ;Rö¦GvÅ«£¦˜ÆŒ.M&Íz¦P“é»7¦¦)ƽ{÷òÒ’Ú`zåñÌØµÌÄ[Ÿ¸ðS›¬…E”‹Í¸Ûào}-!/Ö¦ð¬~ï—)ûïƒ!Œ2zfÿú_?þ'çï`3í8òêÊÚâ+ÑtŒÍúh6k~Ø›Áå\ÍÐsŠ& JN‘ ¹|Î( :É奜‰æŒºA¬ï÷>a"gVª¹<ýO)=_|žË[:-ŠÓ×o‹w¯îŠ9kqØm-ò ”1NJÒº´Øê8«ùH$µÔL‹½¸l¾ÛXÍ]óµ æuVöÅ"Ç*È®g(ºÛgÂ:yÅôTô‚^ÀxêBc–·o`HõæÃÛ·oߨ‚O¯b¹}çYÆA¾ ì‘VêL]ó) Ò<òé(EðtU]+)Ä”Ip÷ջ׌⛱k $ú¿Oñ¦±HÓî¢FÓP«vìhdï´Ã¾‘—œvÒüâ^’¾‹D™ß6ŒIzŸËÏ.[QzÔ§­)¢7eÓ¬÷r9xv6?E­6f5½”Ã>p†Ö˜°ì̧¸#XDÀ%”—11:(Å&“håÎøùÐ?PÏáüJż`éw¼vø¦ÍgîkxÝœ’Ðê—á‡8VØ<¸aNAew@Æ«‡]ÍEvêgQ•dktšD =_C²p±‡4}ò÷‰uƒÍ!òüÚ\~qu}qe9™ºˆ0 f8×{Ȟπ8bxÈ©‡YœÉK¢ ¾ _öDbpé?Ç:[ ùDÚÃ^^ÒädÊ=µ‹±-Í,¸”SX2À(?ˆ­ãGÇK‚lýb=IHÏsáõ\iP®öœW e)ñÖÑ@wúry C4Wõî:¤A¥šk}…¡]6Ç;UTi Õj¾_ýoÊù‡¤¼Õ:ðàÔßÿ«»Vuû¥lintr/man/0000755000176200001440000000000014752731051012162 5ustar liggesuserslintr/man/default_linters.Rd0000644000176200001440000000354314752731051015642 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/zzz.R \docType{data} \name{default_linters} \alias{default_linters} \title{Default linters} \format{ An object of class \code{list} of length 25. } \usage{ default_linters } \description{ List of default linters for \code{\link[=lint]{lint()}}. Use \code{\link[=linters_with_defaults]{linters_with_defaults()}} to customize it. Most of the default linters are based on \href{https://style.tidyverse.org/}{the tidyverse style guide}. The set of default linters is as follows (any parameterized linters, e.g., \code{line_length_linter} use their default argument(s), see \verb{?} for details): } \seealso{ \link{linters} for a complete list of linters available in lintr. } \keyword{datasets} \section{Linters}{ The following linters are tagged with 'default': \itemize{ \item{\code{\link{assignment_linter}}} \item{\code{\link{brace_linter}}} \item{\code{\link{commas_linter}}} \item{\code{\link{commented_code_linter}}} \item{\code{\link{equals_na_linter}}} \item{\code{\link{function_left_parentheses_linter}}} \item{\code{\link{indentation_linter}}} \item{\code{\link{infix_spaces_linter}}} \item{\code{\link{line_length_linter}}} \item{\code{\link{object_length_linter}}} \item{\code{\link{object_name_linter}}} \item{\code{\link{object_usage_linter}}} \item{\code{\link{paren_body_linter}}} \item{\code{\link{pipe_continuation_linter}}} \item{\code{\link{quotes_linter}}} \item{\code{\link{return_linter}}} \item{\code{\link{semicolon_linter}}} \item{\code{\link{seq_linter}}} \item{\code{\link{spaces_inside_linter}}} \item{\code{\link{spaces_left_parentheses_linter}}} \item{\code{\link{T_and_F_symbol_linter}}} \item{\code{\link{trailing_blank_lines_linter}}} \item{\code{\link{trailing_whitespace_linter}}} \item{\code{\link{vector_logic_linter}}} \item{\code{\link{whitespace_linter}}} } } lintr/man/executing_linters.Rd0000644000176200001440000000175114752731051016210 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{executing_linters} \alias{executing_linters} \title{Code executing linters} \description{ Linters that evaluate parts of the linted code, such as loading referenced packages. These linters should not be used with untrusted code, and may need dependencies of the linted package or project to be available in order to function correctly. For package authors, note that this includes loading the package itself, e.g. with \code{pkgload::load_all()} or installing and attaching the package. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'executing': \itemize{ \item{\code{\link{namespace_linter}}} \item{\code{\link{object_length_linter}}} \item{\code{\link{object_name_linter}}} \item{\code{\link{object_overwrite_linter}}} \item{\code{\link{object_usage_linter}}} \item{\code{\link{unused_import_linter}}} } } lintr/man/class_equals_linter.Rd0000644000176200001440000000244714752731051016514 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/class_equals_linter.R \name{class_equals_linter} \alias{class_equals_linter} \title{Block comparison of class with \code{==}} \usage{ class_equals_linter() } \description{ Usage like \code{class(x) == "character"} is prone to error since class in R is in general a vector. The correct version for S3 classes is \code{\link[=inherits]{inherits()}}: \code{inherits(x, "character")}. Often, class \code{k} will have an \code{is.} equivalent, for example \code{\link[=is.character]{is.character()}} or \code{\link[=is.data.frame]{is.data.frame()}}. } \details{ Similar reasoning applies for \code{class(x) \%in\% "character"}. } \examples{ # will produce lints lint( text = 'is_lm <- class(x) == "lm"', linters = class_equals_linter() ) lint( text = 'if ("lm" \%in\% class(x)) is_lm <- TRUE', linters = class_equals_linter() ) # okay lint( text = 'is_lm <- inherits(x, "lm")', linters = class_equals_linter() ) lint( text = 'if (inherits(x, "lm")) is_lm <- TRUE', linters = class_equals_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=robustness_linters]{robustness} } lintr/man/return_linter.Rd0000644000176200001440000000633714752731051015356 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/return_linter.R \name{return_linter} \alias{return_linter} \title{Return linter} \usage{ return_linter( return_style = c("implicit", "explicit"), allow_implicit_else = TRUE, return_functions = NULL, except = NULL, except_regex = NULL ) } \arguments{ \item{return_style}{Character string naming the return style. \code{"implicit"}, the default, enforces the Tidyverse guide recommendation to leave terminal returns implicit. \code{"explicit"} style requires that \code{return()} always be explicitly supplied.} \item{allow_implicit_else}{Logical, default \code{TRUE}. If \code{FALSE}, functions with a terminal \code{if} clause must always have an \verb{else} clause, making the \code{NULL} alternative explicit if necessary. Similarly, functions with terminal \code{\link[=switch]{switch()}} statements must have an explicit default case.} \item{return_functions}{Character vector of functions that are accepted as terminal calls when \code{return_style = "explicit"}. These are in addition to exit functions from base that are always allowed: \code{\link[=stop]{stop()}}, \code{\link[=q]{q()}}, \code{\link[=quit]{quit()}}, \code{\link[=invokeRestart]{invokeRestart()}}, \code{tryInvokeRestart()}, \code{\link[=UseMethod]{UseMethod()}}, \code{\link[=NextMethod]{NextMethod()}}, \code{\link[=standardGeneric]{standardGeneric()}}, \code{\link[=callNextMethod]{callNextMethod()}}, \code{\link[=.C]{.C()}}, \code{\link[=.Call]{.Call()}}, \code{\link[=.External]{.External()}}, and \code{\link[=.Fortran]{.Fortran()}}.} \item{except, except_regex}{Character vector of functions that are not checked when \code{return_style = "explicit"}. These are in addition to namespace hook functions that are never checked: \code{.onLoad()}, \code{.onUnload()}, \code{.onAttach()}, \code{.onDetach()}, \code{.Last.lib()}, \code{.First()} and \code{.Last()}. \code{except} matches function names exactly, while \code{except_regex} does exclusion by pattern matching with \code{\link[rex:re_matches]{rex::re_matches()}}.} } \description{ This linter checks functions' \code{\link[=return]{return()}} expressions. } \examples{ # will produce lints code <- "function(x) {\n return(x + 1)\n}" writeLines(code) lint( text = code, linters = return_linter() ) code <- "function(x) {\n x + 1\n}" writeLines(code) lint( text = code, linters = return_linter(return_style = "explicit") ) code <- "function(x) {\n if (x > 0) 2\n}" writeLines(code) lint( text = code, linters = return_linter(allow_implicit_else = FALSE) ) # okay code <- "function(x) {\n x + 1\n}" writeLines(code) lint( text = code, linters = return_linter() ) code <- "function(x) {\n return(x + 1)\n}" writeLines(code) lint( text = code, linters = return_linter(return_style = "explicit") ) code <- "function(x) {\n if (x > 0) 2 else NULL\n}" writeLines(code) lint( text = code, linters = return_linter(allow_implicit_else = FALSE) ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/functions.html?q=return#return} } } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=default_linters]{default}, \link[=style_linters]{style} } lintr/man/Linter.Rd0000644000176200001440000000167314752731051013715 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{Linter} \alias{Linter} \title{Create a \code{linter} closure} \usage{ Linter( fun, name = linter_auto_name(), linter_level = c(NA_character_, "file", "expression") ) } \arguments{ \item{fun}{A function that takes a source file and returns \code{lint} objects.} \item{name}{Default name of the Linter. Lints produced by the linter will be labelled with \code{name} by default.} \item{linter_level}{Which level of expression is the linter working with? \code{"expression"} means an individual expression in \code{xml_parsed_content}, while \code{"file"} means all expressions in the current file are available in \code{full_xml_parsed_content}. \code{NA} means the linter will be run with both, expression-level and file-level source expressions.} } \value{ The same function with its class set to 'linter'. } \description{ Create a \code{linter} closure } lintr/man/get_source_expressions.Rd0000644000176200001440000000705114752731051017255 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/get_source_expressions.R \name{get_source_expressions} \alias{get_source_expressions} \title{Parsed sourced file from a filename} \usage{ get_source_expressions(filename, lines = NULL) } \arguments{ \item{filename}{the file to be parsed.} \item{lines}{a character vector of lines. If \code{NULL}, then \code{filename} will be read.} } \value{ A \code{list} with three components: \describe{ \item{expressions}{a \code{list} of \code{n+1} objects. The first \code{n} elements correspond to each expression in \code{filename}, and consist of a list of 8 elements: \itemize{ \item{\code{filename} (\code{character}) the name of the file.} \item{\code{line} (\code{integer}) the line in the file where this expression begins.} \item{\code{column} (\code{integer}) the column in the file where this expression begins.} \item{\code{lines} (named \code{character}) vector of all lines spanned by this expression, named with the corresponding line numbers.} \item{\code{parsed_content} (\code{data.frame}) as given by \code{\link[utils:getParseData]{utils::getParseData()}} for this expression.} \item{\code{xml_parsed_content} (\code{xml_document}) the XML parse tree of this expression as given by \code{\link[xmlparsedata:xml_parse_data]{xmlparsedata::xml_parse_data()}}.} \item{\code{content} (\code{character}) the same as \code{lines} as a single string (not split across lines).} \item{\code{xml_find_function_calls(function_names)} (\code{function}) a function that returns all \code{SYMBOL_FUNCTION_CALL} XML nodes from \code{xml_parsed_content} with specified function names.} } The final element of \code{expressions} is a list corresponding to the full file consisting of 7 elements: \itemize{ \item{\code{filename} (\code{character}) the name of this file.} \item{\code{file_lines} (\code{character}) the \code{\link[=readLines]{readLines()}} output for this file.} \item{\code{content} (\code{character}) for .R files, the same as \code{file_lines}; for .Rmd or .qmd scripts, this is the extracted R source code (as text).} \item{\code{full_parsed_content} (\code{data.frame}) as given by \code{\link[utils:getParseData]{utils::getParseData()}} for the full content.} \item{\code{full_xml_parsed_content} (\code{xml_document}) the XML parse tree of all expressions as given by \code{\link[xmlparsedata:xml_parse_data]{xmlparsedata::xml_parse_data()}}.} \item{\code{terminal_newline} (\code{logical}) records whether \code{filename} has a terminal newline (as determined by \code{\link[=readLines]{readLines()}} producing a corresponding warning).} \item{\code{xml_find_function_calls(function_names)} (\code{function}) a function that returns all \code{SYMBOL_FUNCTION_CALL} XML nodes from \code{full_xml_parsed_content} with specified function names.} } } \item{error}{A \code{Lint} object describing any parsing error.} \item{lines}{The \code{\link[=readLines]{readLines()}} output for this file.} } } \description{ This object is given as input to each linter. } \details{ The file is read using the \code{encoding} setting. This setting is found by taking the first valid result from the following locations \enumerate{ \item The \code{encoding} key from the usual lintr configuration settings. \item The \code{Encoding} field from a Package \code{DESCRIPTION} file in a parent directory. \item The \code{Encoding} field from an R Project \code{.Rproj} file in a parent directory. \item \code{"UTF-8"} as a fallback. } } \examples{ tmp <- tempfile() writeLines(c("x <- 1", "y <- x + 1"), tmp) get_source_expressions(tmp) unlink(tmp) } lintr/man/length_levels_linter.Rd0000644000176200001440000000140414752731051016660 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/length_levels_linter.R \name{length_levels_linter} \alias{length_levels_linter} \title{Require usage of nlevels over length(levels(.))} \usage{ length_levels_linter() } \description{ \code{length(levels(x))} is the same as \code{nlevels(x)}, but harder to read. } \examples{ # will produce lints lint( text = "length(levels(x))", linters = length_levels_linter() ) # okay lint( text = "length(c(levels(x), levels(y)))", linters = length_levels_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability} } lintr/man/consecutive_assertion_linter.Rd0000644000176200001440000000221114752731051020440 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/consecutive_assertion_linter.R \name{consecutive_assertion_linter} \alias{consecutive_assertion_linter} \title{Force consecutive calls to assertions into just one when possible} \usage{ consecutive_assertion_linter() } \description{ \code{\link[=stopifnot]{stopifnot()}} accepts any number of tests, so sequences like \verb{stopifnot(x); stopifnot(y)} are redundant. Ditto for tests using \code{assertthat::assert_that()} without specifying \verb{msg=}. } \examples{ # will produce lints lint( text = "stopifnot(x); stopifnot(y)", linters = consecutive_assertion_linter() ) lint( text = "assert_that(x); assert_that(y)", linters = consecutive_assertion_linter() ) # okay lint( text = "stopifnot(x, y)", linters = consecutive_assertion_linter() ) lint( text = 'assert_that(x, msg = "Bad x!"); assert_that(y)', linters = consecutive_assertion_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/fixed_regex_linter.Rd0000644000176200001440000000445214752731051016324 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/fixed_regex_linter.R \name{fixed_regex_linter} \alias{fixed_regex_linter} \title{Require usage of \code{fixed=TRUE} in regular expressions where appropriate} \usage{ fixed_regex_linter(allow_unescaped = FALSE) } \arguments{ \item{allow_unescaped}{Logical, default \code{FALSE}. If \code{TRUE}, only patterns that require regex escapes (e.g. \code{"\\\\$"} or \code{"[$]"}) will be linted. See examples.} } \description{ Invoking a regular expression engine is overkill for cases when the search pattern only involves static patterns. } \details{ NB: for \code{stringr} functions, that means wrapping the pattern in \code{stringr::fixed()}. NB: this linter is likely not able to distinguish every possible case when a fixed regular expression is preferable, rather it seeks to identify likely cases. It should \emph{never} report false positives, however; please report false positives as an error. } \examples{ # will produce lints code_lines <- 'gsub("\\\\\\\\.", "", x)' writeLines(code_lines) lint( text = code_lines, linters = fixed_regex_linter() ) lint( text = 'grepl("a[*]b", x)', linters = fixed_regex_linter() ) lint( text = 'grepl("a[*]b", x)', linters = fixed_regex_linter(allow_unescaped = TRUE) ) code_lines <- 'stringr::str_subset(x, "\\\\\\\\$")' writeLines(code_lines) lint( text = code_lines, linters = fixed_regex_linter() ) lint( text = 'grepl("Munich", address)', linters = fixed_regex_linter() ) # okay code_lines <- 'gsub("\\\\\\\\.", "", x, fixed = TRUE)' writeLines(code_lines) lint( text = code_lines, linters = fixed_regex_linter() ) lint( text = 'grepl("a*b", x, fixed = TRUE)', linters = fixed_regex_linter() ) lint( text = 'stringr::str_subset(x, stringr::fixed("$"))', linters = fixed_regex_linter() ) lint( text = 'grepl("Munich", address, fixed = TRUE)', linters = fixed_regex_linter() ) lint( text = 'grepl("Munich", address)', linters = fixed_regex_linter(allow_unescaped = TRUE) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability}, \link[=regex_linters]{regex} } lintr/man/unnecessary_nesting_linter.Rd0000644000176200001440000001075514752731051020124 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/unnecessary_nesting_linter.R \name{unnecessary_nesting_linter} \alias{unnecessary_nesting_linter} \title{Block instances of unnecessary nesting} \usage{ unnecessary_nesting_linter( allow_assignment = TRUE, allow_functions = c("switch", "try", "tryCatch", "withCallingHandlers", "quote", "expression", "bquote", "substitute", "with_parameters_test_that", "reactive", "observe", "observeEvent", "renderCachedPlot", "renderDataTable", "renderImage", "renderPlot", "renderPrint", "renderTable", "renderText", "renderUI"), branch_exit_calls = character() ) } \arguments{ \item{allow_assignment}{Logical, default \code{TRUE}, in which case braced expressions consisting only of a single assignment are skipped. if \code{FALSE}, all braced expressions with only one child expression are linted. The \code{TRUE} case facilitates interaction with \code{\link[=implicit_assignment_linter]{implicit_assignment_linter()}} for certain cases where an implicit assignment is necessary, so a braced assignment is used to further distinguish the assignment. See examples.} \item{allow_functions}{Character vector of functions which always allow one-child braced expressions. \code{testthat::test_that()} is always allowed because testthat requires a braced expression in its \code{code} argument. The other defaults similarly compute on expressions in a way which is worth highlighting by em-bracing them, even if there is only one expression, while \code{\link[=switch]{switch()}} is allowed for its use as a control flow analogous to \code{if}/\verb{else}.]} \item{branch_exit_calls}{Character vector of functions which are considered as "exiting" a branch for the purpose of recommending removing nesting in a branch \emph{lacking} an exit call when the other branch terminates with one. Calls which always interrupt or quit the current call or R session, e.g. \code{\link[=stop]{stop()}} and \code{\link[=q]{q()}}, are always included.} } \description{ Excessive nesting harms readability. Use helper functions or early returns to reduce nesting wherever possible. } \examples{ # will produce lints code <- "if (A) {\n stop('A is bad!')\n} else {\n do_good()\n}" writeLines(code) lint( text = code, linters = unnecessary_nesting_linter() ) code <- "tryCatch(\n {\n foo()\n },\n error = identity\n)" writeLines(code) lint( text = code, linters = unnecessary_nesting_linter() ) code <- "expect_warning(\n {\n x <- foo()\n },\n 'warned'\n)" writeLines(code) lint( text = code, linters = unnecessary_nesting_linter(allow_assignment = FALSE) ) code <- "if (x) { \n if (y) { \n return(1L) \n } \n}" writeLines(code) lint( text = code, linters = unnecessary_nesting_linter() ) lint( text = "my_quote({x})", linters = unnecessary_nesting_linter() ) code <- paste( "if (A) {", " stop('A is bad because a.')", "} else {", " warning('!A requires caution.')", "}", sep = "\n" ) writeLines(code) lint( text = code, linters = unnecessary_nesting_linter() ) # okay code <- "if (A) {\n stop('A is bad because a.')\n} else {\n stop('!A is bad too.')\n}" writeLines(code) lint( text = code, linters = unnecessary_nesting_linter() ) code <- "capture.output({\n foo()\n})" writeLines(code) lint( text = code, linters = unnecessary_nesting_linter() ) code <- "expect_warning(\n {\n x <- foo()\n },\n 'warned'\n)" writeLines(code) lint( text = code, linters = unnecessary_nesting_linter() ) code <- "if (x && y) { \n return(1L) \n}" writeLines(code) lint( text = code, linters = unnecessary_nesting_linter() ) code <- "if (x) { \n y <- x + 1L\n if (y) { \n return(1L) \n } \n}" writeLines(code) lint( text = code, linters = unnecessary_nesting_linter() ) lint( text = "my_quote({x})", linters = unnecessary_nesting_linter(allow_functions = "my_quote") ) code <- paste( "if (A) {", " stop('A is bad because a.')", "} else {", " warning('!A requires caution.')", "}", sep = "\n" ) writeLines(code) lint( text = code, linters = unnecessary_nesting_linter(branch_exit_calls = c("stop", "warning")) ) } \seealso{ \itemize{ \item \code{\link[=cyclocomp_linter]{cyclocomp_linter()}} for another linter that penalizes overly complex code. \item \link{linters} for a complete list of linters available in lintr. } } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability} } lintr/man/conjunct_test_linter.Rd0000644000176200001440000000655714752731051016725 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/conjunct_test_linter.R \name{conjunct_test_linter} \alias{conjunct_test_linter} \title{Force \code{&&} conditions to be written separately where appropriate} \usage{ conjunct_test_linter( allow_named_stopifnot = TRUE, allow_filter = c("never", "not_dplyr", "always") ) } \arguments{ \item{allow_named_stopifnot}{Logical, \code{TRUE} by default. If \code{FALSE}, "named" calls to \code{stopifnot()}, available since R 4.0.0 to provide helpful messages for test failures, are also linted.} \item{allow_filter}{Character naming the method for linting calls to \code{filter()}. The default, \code{"never"}, means \code{filter()} and \code{dplyr::filter()} calls are linted; \code{"not_dplyr"} means only \code{dplyr::filter()} calls are linted; and \code{"always"} means no calls to \code{filter()} are linted. Calls like \code{stats::filter()} are never linted.} } \description{ For readability of test outputs, testing only one thing per call to \code{\link[testthat:logical-expectations]{testthat::expect_true()}} is preferable, i.e., \verb{expect_true(A); expect_true(B)} is better than \code{expect_true(A && B)}, and \verb{expect_false(A); expect_false(B)} is better than \code{expect_false(A || B)}. } \details{ Similar reasoning applies to \code{&&} usage inside \code{\link[=stopifnot]{stopifnot()}} and \code{assertthat::assert_that()} calls. Relatedly, \code{dplyr::filter(DF, A & B)} is the same as \code{dplyr::filter(DF, A, B)}, but the latter will be more readable / easier to format for long conditions. Note that this linter assumes usages of \code{filter()} are \code{dplyr::filter()}; if you're using another function named \code{filter()}, e.g. \code{\link[stats:filter]{stats::filter()}}, please namespace-qualify it to avoid false positives. You can omit linting \code{filter()} expressions altogether via \code{allow_filter = TRUE}. } \examples{ # will produce lints lint( text = "expect_true(x && y)", linters = conjunct_test_linter() ) lint( text = "expect_false(x || (y && z))", linters = conjunct_test_linter() ) lint( text = "stopifnot('x must be a logical scalar' = length(x) == 1 && is.logical(x) && !is.na(x))", linters = conjunct_test_linter(allow_named_stopifnot = FALSE) ) lint( text = "dplyr::filter(mtcars, mpg > 20 & vs == 0)", linters = conjunct_test_linter() ) lint( text = "filter(mtcars, mpg > 20 & vs == 0)", linters = conjunct_test_linter() ) # okay lint( text = "expect_true(x || (y && z))", linters = conjunct_test_linter() ) lint( text = 'stopifnot("x must be a logical scalar" = length(x) == 1 && is.logical(x) && !is.na(x))', linters = conjunct_test_linter(allow_named_stopifnot = TRUE) ) lint( text = "dplyr::filter(mtcars, mpg > 20 & vs == 0)", linters = conjunct_test_linter(allow_filter = "always") ) lint( text = "filter(mtcars, mpg > 20 & vs == 0)", linters = conjunct_test_linter(allow_filter = "not_dplyr") ) lint( text = "stats::filter(mtcars$cyl, mtcars$mpg > 20 & mtcars$vs == 0)", linters = conjunct_test_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat}, \link[=readability_linters]{readability} } lintr/man/linters_with_defaults.Rd0000644000176200001440000000371714752731051017063 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/with.R \name{linters_with_defaults} \alias{linters_with_defaults} \title{Create a linter configuration based on defaults} \usage{ linters_with_defaults(..., defaults = default_linters) } \arguments{ \item{...}{Arguments of elements to change. If unnamed, the argument is automatically named. If the named argument already exists in the list of linters, it is replaced by the new element. If it does not exist, it is added. If the value is \code{NULL}, the linter is removed.} \item{defaults}{Default list of linters to modify. Must be named.} } \description{ Make a new list based on \pkg{lintr}'s default linters. The result of this function is meant to be passed to the \code{linters} argument of \code{lint()}, or to be put in your configuration file. } \examples{ # When using interactively you will usually pass the result onto `lint` or `lint_package()` f <- tempfile() writeLines("my_slightly_long_variable_name <- 2.3", f) lint(f, linters = linters_with_defaults(line_length_linter = line_length_linter(120L))) unlink(f) # the default linter list with a different line length cutoff my_linters <- linters_with_defaults(line_length_linter = line_length_linter(120L)) # omit the argument name if you are just using different arguments my_linters <- linters_with_defaults(defaults = my_linters, object_name_linter("camelCase")) # remove assignment checks (with NULL), add absolute path checks my_linters <- linters_with_defaults( defaults = my_linters, assignment_linter = NULL, absolute_path_linter() ) # checking the included linters names(my_linters) } \seealso{ \itemize{ \item \link{linters_with_tags} for basing off tags attached to linters, possibly across multiple packages. \item \link{all_linters} for basing off all available linters in lintr. \item \link{available_linters} to get a data frame of available linters. \item \link{linters} for a complete list of linters available in lintr. } } lintr/man/unnecessary_lambda_linter.Rd0000644000176200001440000000437314752731051017674 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/unnecessary_lambda_linter.R \name{unnecessary_lambda_linter} \alias{unnecessary_lambda_linter} \title{Block usage of anonymous functions in iteration functions when unnecessary} \usage{ unnecessary_lambda_linter(allow_comparison = FALSE) } \arguments{ \item{allow_comparison}{Logical, default \code{FALSE}. If \code{TRUE}, lambdas like \code{function(x) foo(x) == 2}, where \code{foo} can be extracted to the "mapping" function and \code{==} vectorized instead of called repeatedly, are linted.} } \description{ Using an anonymous function in, e.g., \code{\link[=lapply]{lapply()}} is not always necessary, e.g. \code{lapply(DF, sum)} is the same as \code{lapply(DF, function(x) sum(x))} and the former is more readable. } \details{ Cases like \verb{lapply(x, \\(xi) grep("ptn", xi))} are excluded because, though the anonymous function \emph{can} be avoided, doing so is not always more readable. } \examples{ # will produce lints lint( text = "lapply(list(1:3, 2:4), function(xi) sum(xi))", linters = unnecessary_lambda_linter() ) lint( text = "sapply(x, function(xi) xi == 2)", linters = unnecessary_lambda_linter() ) lint( text = "sapply(x, function(xi) sum(xi) > 0)", linters = unnecessary_lambda_linter() ) # okay lint( text = "lapply(list(1:3, 2:4), sum)", linters = unnecessary_lambda_linter() ) lint( text = 'lapply(x, function(xi) grep("ptn", xi))', linters = unnecessary_lambda_linter() ) lint( text = "lapply(x, function(xi) data.frame(col = xi))", linters = unnecessary_lambda_linter() ) lint( text = "sapply(x, function(xi) xi == 2)", linters = unnecessary_lambda_linter(allow_comparison = TRUE) ) lint( text = "sapply(x, function(xi) sum(xi) > 0)", linters = unnecessary_lambda_linter(allow_comparison = TRUE) ) lint( text = "sapply(x, function(xi) sum(abs(xi)) > 10)", linters = unnecessary_lambda_linter() ) lint( text = "sapply(x, sum) > 0", linters = unnecessary_lambda_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/read_settings.Rd0000644000176200001440000000555414752731051015315 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/settings.R \name{read_settings} \alias{read_settings} \title{Read lintr settings} \usage{ read_settings(filename, call = parent.frame()) } \arguments{ \item{filename}{Source file to be linted.} \item{call}{Passed to malformed to ensure linear trace.} } \description{ Lintr searches for settings for a given source file in the following order: \enumerate{ \item options defined as \code{linter.setting}. \item \code{linter_file} in the same directory \item \code{linter_file} in the project directory \item \code{linter_file} in the user home directory \item \code{\link[=default_settings]{default_settings()}} } } \details{ The default linter_file name is \code{.lintr} but it can be changed with option \code{lintr.linter_file} or the environment variable \code{R_LINTR_LINTER_FILE} This file is a DCF file, see \code{\link[base:dcf]{base::read.dcf()}} for details. Here is an example of a \code{.lintr} file: \if{html}{\out{
}}\preformatted{linters: linters_with_defaults( any_duplicated_linter(), any_is_na_linter(), backport_linter("oldrel-4", except = c("R_user_dir", "str2lang")), line_length_linter(120L), missing_argument_linter(), unnecessary_concatenation_linter(allow_single_expression = FALSE), yoda_test_linter() ) exclusions: list( "inst/doc/creating_linters.R" = 1, "inst/example/bad.R", "tests/testthat/default_linter_testcode.R", "tests/testthat/dummy_packages" ) }\if{html}{\out{
}} Experimentally, we also support keeping the config in a plain R file. By default we look for a file named \code{.lintr.R} (in the same directories where we search for \code{.lintr}). We are still deciding the future of config support in lintr, so user feedback is welcome. The advantage of R is that it maps more closely to how the configs are actually stored, whereas the DCF approach requires somewhat awkward formatting of parseable R code within valid DCF key-value pairs. The main disadvantage of the R file is it might be \emph{too} flexible, with users tempted to write configs with side effects causing hard-to-detect bugs or like YAML could work, but require new dependencies and are harder to parse both programmatically and visually. Here is an example of a \code{.lintr.R} file: \if{html}{\out{
}}\preformatted{linters <- linters_with_defaults( any_duplicated_linter(), any_is_na_linter(), backport_linter("oldrel-4", except = c("R_user_dir", "str2lang")), line_length_linter(120L), missing_argument_linter(), unnecessary_concatenation_linter(allow_single_expression = FALSE), yoda_test_linter() ) exclusions <- list( "inst/doc/creating_linters.R" = 1, "inst/example/bad.R", "tests/testthat/default_linter_testcode.R", "tests/testthat/dummy_packages" ) }\if{html}{\out{
}} } lintr/man/robustness_linters.Rd0000644000176200001440000000221714752731051016422 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{robustness_linters} \alias{robustness_linters} \title{Robustness linters} \description{ Linters highlighting code robustness issues, such as possibly wrong edge case behavior. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'robustness': \itemize{ \item{\code{\link{absolute_path_linter}}} \item{\code{\link{backport_linter}}} \item{\code{\link{class_equals_linter}}} \item{\code{\link{equals_na_linter}}} \item{\code{\link{for_loop_index_linter}}} \item{\code{\link{missing_package_linter}}} \item{\code{\link{namespace_linter}}} \item{\code{\link{nonportable_path_linter}}} \item{\code{\link{object_overwrite_linter}}} \item{\code{\link{routine_registration_linter}}} \item{\code{\link{sample_int_linter}}} \item{\code{\link{seq_linter}}} \item{\code{\link{strings_as_factors_linter}}} \item{\code{\link{T_and_F_symbol_linter}}} \item{\code{\link{terminal_close_linter}}} \item{\code{\link{undesirable_function_linter}}} \item{\code{\link{undesirable_operator_linter}}} } } lintr/man/rep_len_linter.Rd0000644000176200001440000000155514752731051015460 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rep_len_linter.R \name{rep_len_linter} \alias{rep_len_linter} \title{Require usage of rep_len(x, n) over rep(x, length.out = n)} \usage{ rep_len_linter() } \description{ \code{rep(x, length.out = n)} calls \code{rep_len(x, n)} "under the hood". The latter is thus more direct and equally readable. } \examples{ # will produce lints lint( text = "rep(1:3, length.out = 10)", linters = rep_len_linter() ) # okay lint( text = "rep_len(1:3, 10)", linters = rep_len_linter() ) lint( text = "rep(1:3, each = 2L, length.out = 10L)", linters = rep_len_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability} } lintr/man/all_linters.Rd0000644000176200001440000000206114752731051014760 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/with.R \name{all_linters} \alias{all_linters} \title{Create a linter configuration based on all available linters} \usage{ all_linters(..., packages = "lintr") } \arguments{ \item{...}{Arguments of elements to change. If unnamed, the argument is automatically named. If the named argument already exists in the list of linters, it is replaced by the new element. If it does not exist, it is added. If the value is \code{NULL}, the linter is removed.} \item{packages}{A character vector of packages to search for linters.} } \description{ Create a linter configuration based on all available linters } \examples{ names(all_linters()) } \seealso{ \itemize{ \item \link{linters_with_defaults} for basing off lintr's set of default linters. \item \link{linters_with_tags} for basing off tags attached to linters, possibly across multiple packages. \item \link{available_linters} to get a data frame of available linters. \item \link{linters} for a complete list of linters available in lintr. } } lintr/man/ids_with_token.Rd0000644000176200001440000000362114752731051015465 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ids_with_token.R, R/with_id.R \name{ids_with_token} \alias{ids_with_token} \alias{with_id} \title{Get parsed IDs by token} \usage{ ids_with_token(source_expression, value, fun = `==`, source_file = NULL) with_id(source_expression, id, source_file) } \arguments{ \item{source_expression}{A list of source expressions, the result of a call to \code{\link[=get_source_expressions]{get_source_expressions()}}, for the desired filename.} \item{value}{Character. String corresponding to the token to search for. For example: \itemize{ \item "SYMBOL" \item "FUNCTION" \item "EQ_FORMALS" \item "$" \item "(" }} \item{fun}{For additional flexibility, a function to search for in the \code{token} column of \code{parsed_content}. Typically \code{==} or \code{\%in\%}.} \item{source_file}{(DEPRECATED) Same as \code{source_expression}. Will be removed.} \item{id}{Integer. The index corresponding to the desired row of \code{parsed_content}.} } \value{ \code{ids_with_token}: The indices of the \code{parsed_content} data frame entry of the list of source expressions. Indices correspond to the \emph{rows} where \code{fun} evaluates to \code{TRUE} for the \code{value} in the \emph{token} column. \code{with_id}: A data frame corresponding to the row(s) specified in \code{id}. } \description{ Gets the source IDs (row indices) corresponding to given token. } \section{Functions}{ \itemize{ \item \code{with_id()}: Return the row of the \code{parsed_content} entry of the \verb{[get_source_expressions]()} object. Typically used in conjunction with \code{ids_with_token} to iterate over rows containing desired tokens. }} \examples{ tmp <- tempfile() writeLines(c("x <- 1", "y <- x + 1"), tmp) source_exprs <- get_source_expressions(tmp) ids_with_token(source_exprs$expressions[[1L]], value = "SYMBOL") with_id(source_exprs$expressions[[1L]], 2L) unlink(tmp) } lintr/man/regex_linters.Rd0000644000176200001440000000114214752731051015321 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{regex_linters} \alias{regex_linters} \title{Regular expression linters} \description{ Linters that examine the usage of regular expressions and functions executing them in user code. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'regex': \itemize{ \item{\code{\link{fixed_regex_linter}}} \item{\code{\link{regex_subset_linter}}} \item{\code{\link{string_boundary_linter}}} \item{\code{\link{which_grepl_linter}}} } } lintr/man/object_name_linter.Rd0000644000176200001440000000664114752731051016303 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/object_name_linter.R \name{object_name_linter} \alias{object_name_linter} \title{Object name linter} \usage{ object_name_linter(styles = c("snake_case", "symbols"), regexes = character()) } \arguments{ \item{styles}{A subset of \Sexpr[stage=render, results=rd]{lintr:::regexes_rd}. A name should match at least one of these styles. The \code{"symbols"} style refers to names containing \emph{only} non-alphanumeric characters; e.g., defining \verb{\%+\%} from ggplot2 or \verb{\%>\%} from magrittr would not generate lint markers, whereas \verb{\%m+\%} from lubridate (containing both alphanumeric \emph{and} non-alphanumeric characters) would.} \item{regexes}{A (possibly named) character vector specifying a custom naming convention. If named, the names will be used in the lint message. Otherwise, the regexes enclosed by \code{/} will be used in the lint message. Note that specifying \code{regexes} overrides the default \code{styles}. So if you want to combine \code{regexes} and \code{styles}, both need to be explicitly specified.} } \description{ Check that object names conform to a naming style. The default naming styles are "snake_case" and "symbols". } \details{ Quotes (\verb{`"'}) and specials (\verb{\%} and trailing \verb{<-}) are not considered part of the object name. Note when used in a package, in order to ignore objects imported from other namespaces, this linter will attempt \code{\link[=getNamespaceExports]{getNamespaceExports()}} whenever an \code{import(PKG)} or \code{importFrom(PKG, ...)} statement is found in your NAMESPACE file. If \code{\link[=requireNamespace]{requireNamespace()}} fails (e.g., the package is not yet installed), the linter won't be able to ignore some usages that would otherwise be allowed. Suppose, for example, you have \code{import(upstream)} in your NAMESPACE, which makes available its exported S3 generic function \code{a_really_quite_long_function_name} that you then extend in your package by defining a corresponding method for your class \code{my_class}. Then, if \code{upstream} is not installed when this linter runs, a lint will be thrown on this object (even though you don't "own" its full name). The best way to get lintr to work correctly is to install the package so that it's available in the session where this linter is running. } \examples{ # will produce lints lint( text = "my_var <- 1L", linters = object_name_linter(styles = "CamelCase") ) lint( text = "xYz <- 1L", linters = object_name_linter(styles = c("UPPERCASE", "lowercase")) ) lint( text = "MyVar <- 1L", linters = object_name_linter(styles = "dotted.case") ) lint( text = "asd <- 1L", linters = object_name_linter(regexes = c(my_style = "F$", "f$")) ) # okay lint( text = "my_var <- 1L", linters = object_name_linter(styles = "snake_case") ) lint( text = "xyz <- 1L", linters = object_name_linter(styles = "lowercase") ) lint( text = "my.var <- 1L; myvar <- 2L", linters = object_name_linter(styles = c("dotted.case", "lowercase")) ) lint( text = "asdf <- 1L; asdF <- 1L", linters = object_name_linter(regexes = c(my_style = "F$", "f$")) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=default_linters]{default}, \link[=executing_linters]{executing}, \link[=style_linters]{style} } lintr/man/exclude.Rd0000644000176200001440000000373314752731051014110 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/exclude.R \name{exclude} \alias{exclude} \title{Exclude lines or files from linting} \usage{ exclude(lints, exclusions = settings$exclusions, linter_names = NULL, ...) } \arguments{ \item{lints}{that need to be filtered.} \item{exclusions}{manually specified exclusions} \item{linter_names}{character vector of names of the active linters, used for parsing inline exclusions.} \item{...}{additional arguments passed to \code{\link[=parse_exclusions]{parse_exclusions()}}} } \description{ Exclude lines or files from linting } \details{ Exclusions can be specified in three different ways. \enumerate{ \item Single line in the source file. default: \verb{# nolint}, possibly followed by a listing of linters to exclude. If the listing is missing, all linters are excluded on that line. The default listing format is \verb{# nolint: linter_name, linter2_name.}. There may not be anything between the colon and the line exclusion tag and the listing must be terminated with a full stop (\code{.}) for the linter list to be respected. \item Line range in the source file. default: \verb{# nolint start}, \verb{# nolint end}. \verb{# nolint start} accepts linter lists in the same form as \verb{# nolint}. \item Exclusions parameter, a list with named and/or unnamed entries. Outer elements have the following characteristics: \enumerate{ \item Unnamed elements specify filenames or directories. \item Named elements are a vector or list of line numbers, with \code{Inf} indicating 'all lines'. The name gives a path relative to the config. \enumerate{ \item Unnamed elements denote exclusion of all linters in the given path or directory. \item Named elements, where the name specifies a linter, denote exclusion for that linter. For convenience, a vector can be used in place of a list whenever it would not introduce ambiguity, e.g. a character vector of files to exclude or a vector of lines to exclude. } } } } \keyword{internal} lintr/man/best_practices_linters.Rd0000644000176200001440000000606514752731051017212 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{best_practices_linters} \alias{best_practices_linters} \title{Best practices linters} \description{ Linters checking the use of coding best practices, such as explicit typing of numeric constants. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'best_practices': \itemize{ \item{\code{\link{absolute_path_linter}}} \item{\code{\link{any_duplicated_linter}}} \item{\code{\link{any_is_na_linter}}} \item{\code{\link{boolean_arithmetic_linter}}} \item{\code{\link{class_equals_linter}}} \item{\code{\link{commented_code_linter}}} \item{\code{\link{condition_call_linter}}} \item{\code{\link{condition_message_linter}}} \item{\code{\link{conjunct_test_linter}}} \item{\code{\link{cyclocomp_linter}}} \item{\code{\link{empty_assignment_linter}}} \item{\code{\link{expect_comparison_linter}}} \item{\code{\link{expect_length_linter}}} \item{\code{\link{expect_named_linter}}} \item{\code{\link{expect_not_linter}}} \item{\code{\link{expect_null_linter}}} \item{\code{\link{expect_s3_class_linter}}} \item{\code{\link{expect_s4_class_linter}}} \item{\code{\link{expect_true_false_linter}}} \item{\code{\link{expect_type_linter}}} \item{\code{\link{fixed_regex_linter}}} \item{\code{\link{for_loop_index_linter}}} \item{\code{\link{function_argument_linter}}} \item{\code{\link{function_return_linter}}} \item{\code{\link{if_switch_linter}}} \item{\code{\link{ifelse_censor_linter}}} \item{\code{\link{implicit_assignment_linter}}} \item{\code{\link{implicit_integer_linter}}} \item{\code{\link{is_numeric_linter}}} \item{\code{\link{length_levels_linter}}} \item{\code{\link{lengths_linter}}} \item{\code{\link{library_call_linter}}} \item{\code{\link{list_comparison_linter}}} \item{\code{\link{literal_coercion_linter}}} \item{\code{\link{nonportable_path_linter}}} \item{\code{\link{nrow_subset_linter}}} \item{\code{\link{nzchar_linter}}} \item{\code{\link{object_overwrite_linter}}} \item{\code{\link{outer_negation_linter}}} \item{\code{\link{paste_linter}}} \item{\code{\link{pipe_return_linter}}} \item{\code{\link{print_linter}}} \item{\code{\link{redundant_equals_linter}}} \item{\code{\link{redundant_ifelse_linter}}} \item{\code{\link{regex_subset_linter}}} \item{\code{\link{rep_len_linter}}} \item{\code{\link{routine_registration_linter}}} \item{\code{\link{scalar_in_linter}}} \item{\code{\link{seq_linter}}} \item{\code{\link{sort_linter}}} \item{\code{\link{stopifnot_all_linter}}} \item{\code{\link{system_file_linter}}} \item{\code{\link{T_and_F_symbol_linter}}} \item{\code{\link{terminal_close_linter}}} \item{\code{\link{undesirable_function_linter}}} \item{\code{\link{undesirable_operator_linter}}} \item{\code{\link{unnecessary_lambda_linter}}} \item{\code{\link{unnecessary_nesting_linter}}} \item{\code{\link{unnecessary_placeholder_linter}}} \item{\code{\link{unreachable_code_linter}}} \item{\code{\link{unused_import_linter}}} \item{\code{\link{vector_logic_linter}}} \item{\code{\link{yoda_test_linter}}} } } lintr/man/implicit_integer_linter.Rd0000644000176200001440000000245214752731051017360 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/implicit_integer_linter.R \name{implicit_integer_linter} \alias{implicit_integer_linter} \title{Implicit integer linter} \usage{ implicit_integer_linter(allow_colon = FALSE) } \arguments{ \item{allow_colon}{Logical, default \code{FALSE}. If \code{TRUE}, expressions involving \code{:} won't throw a lint regardless of whether the inputs are implicitly integers.} } \description{ Check that integers are explicitly typed using the form \code{1L} instead of \code{1}. } \examples{ # will produce lints lint( text = "x <- 1", linters = implicit_integer_linter() ) lint( text = "x[2]", linters = implicit_integer_linter() ) lint( text = "1:10", linters = implicit_integer_linter() ) # okay lint( text = "x <- 1.0", linters = implicit_integer_linter() ) lint( text = "x <- 1L", linters = implicit_integer_linter() ) lint( text = "x[2L]", linters = implicit_integer_linter() ) lint( text = "1:10", linters = implicit_integer_linter(allow_colon = TRUE) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=style_linters]{style} } lintr/man/sarif_output.Rd0000644000176200001440000000070214752731051015174 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lint.R \name{sarif_output} \alias{sarif_output} \title{SARIF Report for lint results} \usage{ sarif_output(lints, filename = "lintr_results.sarif") } \arguments{ \item{lints}{the linting results.} \item{filename}{the name of the output report} } \description{ Generate a report of the linting results using the \href{https://sarifweb.azurewebsites.net/}{SARIF} format. } lintr/man/commas_linter.Rd0000644000176200001440000000267214752731051015314 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/commas_linter.R \name{commas_linter} \alias{commas_linter} \title{Commas linter} \usage{ commas_linter(allow_trailing = FALSE) } \arguments{ \item{allow_trailing}{If \code{TRUE}, the linter allows a comma to be followed directly by a closing bracket without a space.} } \description{ Check that all commas are followed by spaces, but do not have spaces before them. } \examples{ # will produce lints lint( text = "switch(op , x = foo, y = bar)", linters = commas_linter() ) lint( text = "mean(x,trim = 0.2,na.rm = TRUE)", linters = commas_linter() ) lint( text = "x[ ,, drop=TRUE]", linters = commas_linter() ) lint( text = "x[1,]", linters = commas_linter() ) # okay lint( text = "switch(op, x = foo, y = bar)", linters = commas_linter() ) lint( text = "switch(op, x = , y = bar)", linters = commas_linter() ) lint( text = "mean(x, trim = 0.2, na.rm = TRUE)", linters = commas_linter() ) lint( text = "a[1, , 2, , 3]", linters = commas_linter() ) lint( text = "x[1,]", linters = commas_linter(allow_trailing = TRUE) ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#commas} } } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/normalize_exclusions.Rd0000644000176200001440000000277414752731051016737 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/exclude.R \name{normalize_exclusions} \alias{normalize_exclusions} \title{Normalize lint exclusions} \usage{ normalize_exclusions(x, normalize_path = TRUE, root = getwd(), pattern = NULL) } \arguments{ \item{x}{Exclusion specification \itemize{ \item A character vector of filenames or directories relative to \code{root} \item A named list of integers specifying lines to be excluded per file \item A named list of named lists specifying linters and lines to be excluded for the linters per file. }} \item{normalize_path}{Should the names of the returned exclusion list be normalized paths? If no, they will be relative to \code{root}.} \item{root}{Base directory for relative filename resolution.} \item{pattern}{If non-NULL, only exclude files in excluded directories if they match \code{pattern}. Passed to \link[base:list.files]{list.files} if a directory is excluded.} } \value{ A named list of file exclusions. The names of the list specify the filenames to be excluded. Each file exclusion is a possibly named list containing line numbers to exclude, or the sentinel \code{Inf} for completely excluded files. If the an entry is named, the exclusions only take effect for the linter with the same name. If \code{normalize_path} is \code{TRUE}, file names will be normalized relative to \code{root}. Otherwise the paths are left as provided (relative to \code{root} or absolute). } \description{ Normalize lint exclusions } \keyword{internal} lintr/man/function_argument_linter.Rd0000644000176200001440000000263114752731051017557 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/function_argument_linter.R \name{function_argument_linter} \alias{function_argument_linter} \title{Function argument linter} \usage{ function_argument_linter() } \description{ Check that arguments with defaults come last in all function declarations, as per the tidyverse design guide. Changing the argument order can be a breaking change. An alternative to changing the argument order is to instead set the default for such arguments to \code{NULL}. } \examples{ # will produce lints lint( text = "function(y = 1, z = 2, x) {}", linters = function_argument_linter() ) lint( text = "function(x, y, z = 1, ..., w) {}", linters = function_argument_linter() ) # okay lint( text = "function(x, y = 1, z = 2) {}", linters = function_argument_linter() ) lint( text = "function(x, y, w, z = 1, ...) {}", linters = function_argument_linter() ) lint( text = "function(y = 1, z = 2, x = NULL) {}", linters = function_argument_linter() ) lint( text = "function(x, y, z = 1, ..., w = NULL) {}", linters = function_argument_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://design.tidyverse.org/required-no-defaults.html} } } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=style_linters]{style} } lintr/man/missing_package_linter.Rd0000644000176200001440000000135214752731051017153 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/missing_package_linter.R \name{missing_package_linter} \alias{missing_package_linter} \title{Missing package linter} \usage{ missing_package_linter() } \description{ Check for missing packages in \code{library()}, \code{require()}, \code{loadNamespace()}, and \code{requireNamespace()} calls. } \examples{ # will produce lints lint( text = "library(xyzxyz)", linters = missing_package_linter() ) # okay lint( text = "library(stats)", linters = missing_package_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=common_mistakes_linters]{common_mistakes}, \link[=robustness_linters]{robustness} } lintr/man/efficiency_linters.Rd0000644000176200001440000000315514752731051016321 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{efficiency_linters} \alias{efficiency_linters} \title{Efficiency linters} \description{ Linters highlighting code efficiency problems, such as unnecessary function calls. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'efficiency': \itemize{ \item{\code{\link{any_duplicated_linter}}} \item{\code{\link{any_is_na_linter}}} \item{\code{\link{boolean_arithmetic_linter}}} \item{\code{\link{consecutive_mutate_linter}}} \item{\code{\link{fixed_regex_linter}}} \item{\code{\link{if_switch_linter}}} \item{\code{\link{ifelse_censor_linter}}} \item{\code{\link{inner_combine_linter}}} \item{\code{\link{length_test_linter}}} \item{\code{\link{lengths_linter}}} \item{\code{\link{literal_coercion_linter}}} \item{\code{\link{matrix_apply_linter}}} \item{\code{\link{nested_ifelse_linter}}} \item{\code{\link{nrow_subset_linter}}} \item{\code{\link{nzchar_linter}}} \item{\code{\link{outer_negation_linter}}} \item{\code{\link{redundant_equals_linter}}} \item{\code{\link{redundant_ifelse_linter}}} \item{\code{\link{regex_subset_linter}}} \item{\code{\link{routine_registration_linter}}} \item{\code{\link{sample_int_linter}}} \item{\code{\link{scalar_in_linter}}} \item{\code{\link{seq_linter}}} \item{\code{\link{sort_linter}}} \item{\code{\link{string_boundary_linter}}} \item{\code{\link{unnecessary_concatenation_linter}}} \item{\code{\link{unnecessary_lambda_linter}}} \item{\code{\link{vector_logic_linter}}} \item{\code{\link{which_grepl_linter}}} } } lintr/man/linters_with_tags.Rd0000644000176200001440000000456514752731051016214 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/with.R \name{linters_with_tags} \alias{linters_with_tags} \title{Create a tag-based linter configuration} \usage{ linters_with_tags(tags, ..., packages = "lintr", exclude_tags = "deprecated") } \arguments{ \item{tags}{Optional character vector of tags to search. Only linters with at least one matching tag will be returned. If \code{tags} is \code{NULL}, all linters will be returned. See \code{available_tags("lintr")} to find out what tags are already used by lintr.} \item{...}{Arguments of elements to change. If unnamed, the argument is automatically named. If the named argument already exists in the list of linters, it is replaced by the new element. If it does not exist, it is added. If the value is \code{NULL}, the linter is removed.} \item{packages}{A character vector of packages to search for linters.} \item{exclude_tags}{Tags to exclude from the results. Linters with at least one matching tag will not be returned. If \code{exclude_tags} is \code{NULL}, no linters will be excluded. Note that \code{tags} takes priority, meaning that any tag found in both \code{tags} and \code{exclude_tags} will be included, not excluded. Note that linters with tag \code{"defunct"} (which do not work and can no longer be run) cannot be queried directly. See \link{lintr-deprecated} instead.} } \value{ A modified list of linters. } \description{ Make a new list based on all linters provided by \code{packages} and tagged with \code{tags}. The result of this function is meant to be passed to the \code{linters} argument of \code{lint()}, or to be put in your configuration file. } \examples{ # `linters_with_defaults()` and `linters_with_tags("default")` are the same: all.equal(linters_with_defaults(), linters_with_tags("default")) # Get all linters useful for package development linters <- linters_with_tags(tags = c("package_development", "style")) names(linters) # Get all linters tagged as "default" from lintr and mypkg if (FALSE) { linters_with_tags("default", packages = c("lintr", "mypkg")) } } \seealso{ \itemize{ \item \link{linters_with_defaults} for basing off lintr's set of default linters. \item \link{all_linters} for basing off all available linters in lintr. \item \link{available_linters} to get a data frame of available linters. \item \link{linters} for a complete list of linters available in lintr. } } lintr/man/repeat_linter.Rd0000644000176200001440000000112714752731051015307 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/repeat_linter.R \name{repeat_linter} \alias{repeat_linter} \title{Repeat linter} \usage{ repeat_linter() } \description{ Check that \verb{while (TRUE)} is not used for infinite loops. } \examples{ # will produce lints lint( text = "while (TRUE) { }", linters = repeat_linter() ) # okay lint( text = "repeat { }", linters = repeat_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/if_not_else_linter.Rd0000644000176200001440000000373514752731051016324 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/if_not_else_linter.R \name{if_not_else_linter} \alias{if_not_else_linter} \title{Block statements like if (!A) x else y} \usage{ if_not_else_linter(exceptions = c("is.null", "is.na", "missing")) } \arguments{ \item{exceptions}{Character vector of calls to exclude from linting. By default, \code{\link[=is.null]{is.null()}}, \code{\link[=is.na]{is.na()}}, and \code{\link[=missing]{missing()}} are excluded given the common idiom \code{!is.na(x)} as "x is present".} } \description{ \code{if (!A) x else y} is the same as \code{if (A) y else x}, but the latter is easier to reason about in the \verb{else} case. The former requires double negation that can be avoided by switching the statement order. } \details{ This only applies in the simple \verb{if/else} case. Statements like \code{if (!A) x else if (B) y else z} don't always have a simpler or more readable form. It also applies to \code{\link[=ifelse]{ifelse()}} and the package equivalents \code{dplyr::if_else()} and \code{data.table::fifelse()}. } \examples{ # will produce lints lint( text = "if (!A) x else y", linters = if_not_else_linter() ) lint( text = "if (!A) x else if (!B) y else z", linters = if_not_else_linter() ) lint( text = "ifelse(!is_treatment, x, y)", linters = if_not_else_linter() ) lint( text = "if (!is.null(x)) x else 2", linters = if_not_else_linter(exceptions = character()) ) # okay lint( text = "if (A) x else y", linters = if_not_else_linter() ) lint( text = "if (!A) x else if (B) z else y", linters = if_not_else_linter() ) lint( text = "ifelse(is_treatment, y, x)", linters = if_not_else_linter() ) lint( text = "if (!is.null(x)) x else 2", linters = if_not_else_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability} } lintr/man/sort_linter.Rd0000644000176200001440000000434314752731051015021 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/sort_linter.R \name{sort_linter} \alias{sort_linter} \title{Check for common mistakes around sorting vectors} \usage{ sort_linter() } \description{ This linter checks for some common mistakes when using \code{\link[=order]{order()}} or \code{\link[=sort]{sort()}}. } \details{ First, it requires usage of \code{sort()} over \code{.[order(.)]}. \code{\link[=sort]{sort()}} is the dedicated option to sort a list or vector. It is more legible and around twice as fast as \code{.[order(.)]}, with the gap in performance growing with the vector size. Second, it requires usage of \code{\link[=is.unsorted]{is.unsorted()}} over equivalents using \code{sort()}. The base function \code{is.unsorted()} exists to test the sortedness of a vector. Prefer it to inefficient and less-readable equivalents like \code{x != sort(x)}. The same goes for checking \code{x == sort(x)} -- use \code{!is.unsorted(x)} instead. Moreover, use of \code{x == sort(x)} can be risky because \code{\link[=sort]{sort()}} drops missing elements by default, meaning \code{==} might end up trying to compare vectors of differing lengths. } \examples{ # will produce lints lint( text = "x[order(x)]", linters = sort_linter() ) lint( text = "x[order(x, decreasing = TRUE)]", linters = sort_linter() ) lint( text = "sort(x) == x", linters = sort_linter() ) # okay lint( text = "x[sample(order(x))]", linters = sort_linter() ) lint( text = "y[order(x)]", linters = sort_linter() ) lint( text = "sort(x, decreasing = TRUE) == x", linters = sort_linter() ) # If you are sorting several objects based on the order of one of them, such # as: x <- sample(1:26) y <- letters newx <- x[order(x)] newy <- y[order(x)] # This will be flagged by the linter. However, in this very specific case, # it would be clearer and more efficient to run order() once and assign it # to an object, rather than mix and match order() and sort() index <- order(x) newx <- x[index] newy <- y[index] } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/xml_nodes_to_lints.Rd0000644000176200001440000000502014752731051016351 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/xml_nodes_to_lints.R \name{xml_nodes_to_lints} \alias{xml_nodes_to_lints} \title{Convert an XML node or nodeset into a Lint} \usage{ xml_nodes_to_lints( xml, source_expression, lint_message, type = c("style", "warning", "error"), column_number_xpath = range_start_xpath, range_start_xpath = "number(./@col1)", range_end_xpath = "number(./@col2)" ) } \arguments{ \item{xml}{An \code{xml_node} object (to generate one \code{Lint}) or an \code{xml_nodeset} object (to generate several \code{Lint}s), e.g. as returned by \code{\link[xml2:xml_find_all]{xml2::xml_find_all()}} or \code{\link[xml2:xml_find_all]{xml2::xml_find_first()}} or a list of \code{xml_node} objects.} \item{source_expression}{A source expression object, e.g. as returned typically by \code{\link[=lint]{lint()}}, or more generally by \code{\link[=get_source_expressions]{get_source_expressions()}}.} \item{lint_message}{The message to be included as the \code{message} to the \code{Lint} object. If \code{lint_message} is a character vector the same length as \code{xml}, the \code{i}-th lint will be given the \code{i}-th message.} \item{type}{type of lint.} \item{column_number_xpath}{XPath expression to return the column number location of the lint. Defaults to the start of the range matched by \code{range_start_xpath}. See details for more information.} \item{range_start_xpath}{XPath expression to return the range start location of the lint. Defaults to the start of the expression matched by \code{xml}. See details for more information.} \item{range_end_xpath}{XPath expression to return the range end location of the lint. Defaults to the end of the expression matched by \code{xml}. See details for more information.} } \value{ For \code{xml_node}s, a \code{lint}. For \code{xml_nodeset}s, \code{lints} (a list of \code{lint}s). } \description{ Convenience function for converting nodes matched by XPath-based linter logic into a \code{\link[=Lint]{Lint()}} object to return. } \details{ The location XPaths, \code{column_number_xpath}, \code{range_start_xpath} and \code{range_end_xpath} are evaluated using \code{\link[xml2:xml_find_all]{xml2::xml_find_num()}} and will usually be of the form \code{"number(./relative/xpath)"}. Note that the location line number cannot be changed and lints spanning multiple lines will ignore \code{range_end_xpath}. \code{column_number_xpath} and \code{range_start_xpath} are assumed to always refer to locations on the starting line of the \code{xml} node. } lintr/man/unreachable_code_linter.Rd0000644000176200001440000000515614752731051017300 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/unreachable_code_linter.R \name{unreachable_code_linter} \alias{unreachable_code_linter} \title{Block unreachable code and comments following return statements} \usage{ unreachable_code_linter( allow_comment_regex = getOption("covr.exclude_end", "# nocov end") ) } \arguments{ \item{allow_comment_regex}{Character vector of regular expressions which identify comments to exclude when finding unreachable terminal comments. By default, this includes the default "skip region" end marker for \code{{covr}} (option "covr.exclude_end", or \code{"# nocov end"} if unset). The end marker for \code{{lintr}} (\code{settings$exclude_end}) is always included. Note that the regexes should include the initial comment character \verb{#}.} } \description{ Code after e.g. a \code{\link[=return]{return()}} or \code{\link[=stop]{stop()}} or in deterministically false conditional loops like \verb{if (FALSE)} can't be reached; typically this is vestigial code left after refactoring or sandboxing code, which is fine for exploration, but shouldn't ultimately be checked in. Comments meant for posterity should be placed \emph{before} the final \code{return()}. } \examples{ # will produce lints code_lines <- "f <- function() {\n return(1 + 1)\n 2 + 2\n}" writeLines(code_lines) lint( text = code_lines, linters = unreachable_code_linter() ) code_lines <- "if (FALSE) {\n 2 + 2\n}" writeLines(code_lines) lint( text = code_lines, linters = unreachable_code_linter() ) code_lines <- "while (FALSE) {\n 2 + 2\n}" writeLines(code_lines) lint( text = code_lines, linters = unreachable_code_linter() ) code_lines <- "f <- function() {\n return(1)\n # end skip\n}" writeLines(code_lines) lint( text = code_lines, linters = unreachable_code_linter() ) # okay code_lines <- "f <- function() {\n return(1 + 1)\n}" writeLines(code_lines) lint( text = code_lines, linters = unreachable_code_linter() ) code_lines <- "if (foo) {\n 2 + 2\n}" writeLines(code_lines) lint( text = code_lines, linters = unreachable_code_linter() ) code_lines <- "while (foo) {\n 2 + 2\n}" writeLines(code_lines) lint( text = code_lines, linters = unreachable_code_linter() ) code_lines <- "f <- function() {\n return(1)\n # end skip\n}" writeLines(code_lines) lint( text = code_lines, linters = unreachable_code_linter(allow_comment_regex = "# end skip") ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=readability_linters]{readability} } lintr/man/vector_logic_linter.Rd0000644000176200001440000000441014752731051016504 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/vector_logic_linter.R \name{vector_logic_linter} \alias{vector_logic_linter} \title{Enforce usage of scalar logical operators in conditional statements} \usage{ vector_logic_linter() } \description{ Usage of \code{&} in conditional statements is error-prone and inefficient. \code{condition} in \code{if (condition) expr} must always be of length 1, in which case \code{&&} is to be preferred. Ditto for \code{|} vs. \code{||}. } \details{ This linter covers inputs to \verb{if()} and \verb{while()} conditions and to \code{\link[testthat:logical-expectations]{testthat::expect_true()}} and \code{\link[testthat:logical-expectations]{testthat::expect_false()}}. Note that because \code{&} and \code{|} are generics, it is possible that \code{&&} / \code{||} are not perfect substitutes because \code{&} is doing method dispatch in an incompatible way. Moreover, be wary of code that may have side effects, most commonly assignments. Consider \code{if ((a <- foo(x)) | (b <- bar(y))) { ... }} vs. \code{if ((a <- foo(x)) || (b <- bar(y))) { ... }}. Because \code{||} exits early, if \code{a} is \code{TRUE}, the second condition will never be evaluated and \code{b} will not be assigned. Such usage is not allowed by the Tidyverse style guide, and the code can easily be refactored by pulling the assignment outside the condition, so using \code{||} is still preferable. } \examples{ # will produce lints lint( text = "if (TRUE & FALSE) 1", linters = vector_logic_linter() ) lint( text = "if (TRUE && (TRUE | FALSE)) 4", linters = vector_logic_linter() ) lint( text = "filter(x, A && B)", linters = vector_logic_linter() ) # okay lint( text = "if (TRUE && FALSE) 1", linters = vector_logic_linter() ) lint( text = "if (TRUE && (TRUE || FALSE)) 4", linters = vector_logic_linter() ) lint( text = "filter(x, A & B)", linters = vector_logic_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#if-statements} } } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=common_mistakes_linters]{common_mistakes}, \link[=default_linters]{default}, \link[=efficiency_linters]{efficiency} } lintr/man/pipe_continuation_linter.Rd0000644000176200001440000000264414752731051017563 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe_continuation_linter.R \name{pipe_continuation_linter} \alias{pipe_continuation_linter} \title{Pipe continuation linter} \usage{ pipe_continuation_linter() } \description{ Check that each step in a pipeline is on a new line, or the entire pipe fits on one line. } \examples{ # will produce lints code_lines <- "1:3 \%>\%\n mean() \%>\% as.character()" writeLines(code_lines) lint( text = code_lines, linters = pipe_continuation_linter() ) code_lines <- "1:3 |> mean() |>\n as.character()" writeLines(code_lines) lint( text = code_lines, linters = pipe_continuation_linter() ) # okay lint( text = "1:3 \%>\% mean() \%>\% as.character()", linters = pipe_continuation_linter() ) code_lines <- "1:3 \%>\%\n mean() \%>\%\n as.character()" writeLines(code_lines) lint( text = code_lines, linters = pipe_continuation_linter() ) lint( text = "1:3 |> mean() |> as.character()", linters = pipe_continuation_linter() ) code_lines <- "1:3 |>\n mean() |>\n as.character()" writeLines(code_lines) lint( text = code_lines, linters = pipe_continuation_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/pipes.html#long-lines-2} } } \section{Tags}{ \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/make_linter_from_xpath.Rd0000644000176200001440000000315314752731051017174 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/make_linter_from_xpath.R \name{make_linter_from_xpath} \alias{make_linter_from_xpath} \alias{make_linter_from_function_xpath} \title{Create a linter from an XPath} \usage{ make_linter_from_xpath( xpath, lint_message, type = c("warning", "style", "error"), level = c("expression", "file") ) make_linter_from_function_xpath( function_names, xpath, lint_message, type = c("warning", "style", "error"), level = c("expression", "file") ) } \arguments{ \item{xpath}{Character string, an XPath identifying R code to lint. For \code{make_linter_from_function_xpath()}, the XPath is relative to the \code{parent::expr} of the \code{SYMBOL_FUNCTION_CALL} nodes of the selected functions. See \code{\link[xmlparsedata:xml_parse_data]{xmlparsedata::xml_parse_data()}} and \code{\link[=get_source_expressions]{get_source_expressions()}}.} \item{lint_message}{The message to be included as the \code{message} to the \code{Lint} object. If \code{lint_message} is a character vector the same length as \code{xml}, the \code{i}-th lint will be given the \code{i}-th message.} \item{type}{type of lint.} \item{level}{Which level of expression is being tested? \code{"expression"} means an individual expression, while \code{"file"} means all expressions in the current file are available.} \item{function_names}{Character vector, names of functions whose calls to examine..} } \description{ Create a linter from an XPath } \examples{ number_linter <- make_linter_from_xpath("//NUM_CONST", "This is a number.") lint(text = "1 + 2", linters = number_linter()) } lintr/man/absolute_path_linter.Rd0000644000176200001440000000220014752731051016652 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/absolute_path_linter.R \name{absolute_path_linter} \alias{absolute_path_linter} \title{Absolute path linter} \usage{ absolute_path_linter(lax = TRUE) } \arguments{ \item{lax}{Less stringent linting, leading to fewer false positives. If \code{TRUE}, only lint path strings, which \itemize{ \item contain at least two path elements, with one having at least two characters and \item contain only alphanumeric chars (including UTF-8), spaces, and win32-allowed punctuation }} } \description{ Check that no absolute paths are used (e.g. "/var", "C:\\System", "~/docs"). } \examples{ # will produce lints lint( text = 'R"--[/blah/file.txt]--"', linters = absolute_path_linter() ) # okay lint( text = 'R"(./blah)"', linters = absolute_path_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \code{\link[=nonportable_path_linter]{nonportable_path_linter()}} } } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=robustness_linters]{robustness} } lintr/man/get_r_string.Rd0000644000176200001440000000362314752731051015143 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{get_r_string} \alias{get_r_string} \title{Extract text from \code{STR_CONST} nodes} \usage{ get_r_string(s, xpath = NULL) } \arguments{ \item{s}{An input string or strings. If \code{s} is an \code{xml_node} or \code{xml_nodeset} and \code{xpath} is \code{NULL}, extract its string value with \code{\link[xml2:xml_text]{xml2::xml_text()}}. If \code{s} is an \code{xml_node} or \code{xml_nodeset} and \code{xpath} is specified, it is extracted with \code{\link[xml2:xml_find_all]{xml2::xml_find_chr()}}.} \item{xpath}{An XPath, passed on to \code{\link[xml2:xml_find_all]{xml2::xml_find_chr()}} after wrapping with \code{string()}.} } \description{ Convert \code{STR_CONST} \code{text()} values into R strings. This is useful to account for arbitrary character literals, e.g. \code{R"------[hello]------"}, which is parsed in R as \code{"hello"}. It is quite cumbersome to write XPaths allowing for strings like this, so whenever your linter logic requires testing a \code{STR_CONST} node's value, use this function. NB: this is also properly vectorized on \code{s}, and accepts a variety of inputs. Empty inputs will become \code{NA} outputs, which helps ensure that \code{length(get_r_string(s)) == length(s)}. } \examples{ tmp <- tempfile() writeLines("c('a', 'b')", tmp) expr_as_xml <- get_source_expressions(tmp)$expressions[[1L]]$xml_parsed_content writeLines(as.character(expr_as_xml)) get_r_string(expr_as_xml, "expr[2]") get_r_string(expr_as_xml, "expr[3]") unlink(tmp) # more importantly, extract raw strings correctly tmp_raw <- tempfile() writeLines("c(R'(a\\\\b)', R'--[a\\\\\"\'\"\\\\b]--')", tmp_raw) expr_as_xml_raw <- get_source_expressions(tmp_raw)$expressions[[1L]]$xml_parsed_content writeLines(as.character(expr_as_xml_raw)) get_r_string(expr_as_xml_raw, "expr[2]") get_r_string(expr_as_xml_raw, "expr[3]") unlink(tmp_raw) } lintr/man/print_linter.Rd0000644000176200001440000000253614752731051015170 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/print_linter.R \name{print_linter} \alias{print_linter} \title{Block usage of print() for logging} \usage{ print_linter() } \description{ The default print method for character vectors is appropriate for interactively inspecting objects, not for logging messages. Thus checked-in usage like \code{print(paste('Data has', nrow(DF), 'rows.'))} is better served by using \code{\link[=cat]{cat()}}, e.g. \code{cat(sprintf('Data has \%d rows.\\n', nrow(DF)))} (noting that using \code{cat()} entails supplying your own line returns, and that \code{\link[glue:glue]{glue::glue()}} might be preferable to \code{\link[=sprintf]{sprintf()}} for constructing templated strings). Lastly, note that \code{\link[=message]{message()}} differs slightly from \code{cat()} in that it prints to \code{stderr} by default, not \code{stdout}, but is still a good option to consider for logging purposes. } \examples{ # will produce lints lint( text = "print('a')", linters = print_linter() ) lint( text = "print(paste(x, 'y'))", linters = print_linter() ) # okay lint( text = "print(x)", linters = print_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency} } lintr/man/whitespace_linter.Rd0000644000176200001440000000167414752731051016172 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/whitespace_linter.R \name{whitespace_linter} \alias{whitespace_linter} \title{Whitespace linter} \usage{ whitespace_linter() } \description{ Check that the correct character is used for indentation. } \details{ Currently, only supports linting in the presence of tabs. Much ink has been spilled on this topic, and we encourage you to check out references for more information. } \examples{ # will produce lints lint( text = "\tx", linters = whitespace_linter() ) # okay lint( text = " x", linters = whitespace_linter() ) } \references{ \itemize{ \item https://www.jwz.org/doc/tabs-vs-spaces.html \item https://blog.codinghorror.com/death-to-the-space-infidels/ } } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=consistency_linters]{consistency}, \link[=default_linters]{default}, \link[=style_linters]{style} } lintr/man/expect_comparison_linter.Rd0000644000176200001440000000334014752731051017550 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/expect_comparison_linter.R \name{expect_comparison_linter} \alias{expect_comparison_linter} \title{Require usage of \code{expect_gt(x, y)} over \code{expect_true(x > y)} (and similar)} \usage{ expect_comparison_linter() } \description{ \code{\link[testthat:comparison-expectations]{testthat::expect_gt()}}, \code{\link[testthat:comparison-expectations]{testthat::expect_gte()}}, \code{\link[testthat:comparison-expectations]{testthat::expect_lt()}}, \code{\link[testthat:comparison-expectations]{testthat::expect_lte()}}, and \code{\link[testthat:equality-expectations]{testthat::expect_equal()}} exist specifically for testing comparisons between two objects. \code{\link[testthat:logical-expectations]{testthat::expect_true()}} can also be used for such tests, but it is better to use the tailored function instead. } \examples{ # will produce lints lint( text = "expect_true(x > y)", linters = expect_comparison_linter() ) lint( text = "expect_true(x <= y)", linters = expect_comparison_linter() ) lint( text = "expect_true(x == (y == 2))", linters = expect_comparison_linter() ) # okay lint( text = "expect_gt(x, y)", linters = expect_comparison_linter() ) lint( text = "expect_lte(x, y)", linters = expect_comparison_linter() ) lint( text = "expect_identical(x, y == 2)", linters = expect_comparison_linter() ) lint( text = "expect_true(x < y | x > y^2)", linters = expect_comparison_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat} } lintr/man/is_lint_level.Rd0000644000176200001440000000224414752731051015303 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/is_lint_level.R \name{is_lint_level} \alias{is_lint_level} \title{Is this an expression- or a file-level source object?} \usage{ is_lint_level(source_expression, level = c("expression", "file")) } \arguments{ \item{source_expression}{A parsed expression object, i.e., an element of the object returned by \code{\link[=get_source_expressions]{get_source_expressions()}}.} \item{level}{Which level of expression is being tested? \code{"expression"} means an individual expression, while \code{"file"} means all expressions in the current file are available.} } \description{ Helper for determining whether the current \code{source_expression} contains all expressions in the current file, or just a single expression. } \examples{ tmp <- tempfile() writeLines(c("x <- 1", "y <- x + 1"), tmp) source_exprs <- get_source_expressions(tmp) is_lint_level(source_exprs$expressions[[1L]], level = "expression") is_lint_level(source_exprs$expressions[[1L]], level = "file") is_lint_level(source_exprs$expressions[[3L]], level = "expression") is_lint_level(source_exprs$expressions[[3L]], level = "file") unlink(tmp) } lintr/man/indentation_linter.Rd0000644000176200001440000000676414752731051016357 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/indentation_linter.R \name{indentation_linter} \alias{indentation_linter} \title{Check that indentation is consistent} \usage{ indentation_linter( indent = 2L, hanging_indent_style = c("tidy", "always", "never"), assignment_as_infix = TRUE ) } \arguments{ \item{indent}{Number of spaces, that a code block should be indented by relative to its parent code block. Used for multi-line code blocks (\code{{ ... }}), function calls (\code{( ... )}) and extractions (\verb{[ ... ]}, \verb{[[ ... ]]}). Defaults to 2.} \item{hanging_indent_style}{Indentation style for multi-line function calls with arguments in their first line. Defaults to tidyverse style, i.e. a block indent is used if the function call terminates with \verb{)} on a separate line and a hanging indent if not. Note that function multi-line function calls without arguments on their first line will always be expected to have block-indented arguments. If \code{hanging_indent_style} is \code{"tidy"}, multi-line function definitions are expected to be double-indented if the first line of the function definition contains no arguments and the closing parenthesis is not on its own line. \if{html}{\out{
}}\preformatted{# complies to any style map( x, f, additional_arg = 42 ) # complies to "tidy" and "never" map(x, f, additional_arg = 42 ) # complies to "always" map(x, f, additional_arg = 42 ) # complies to "tidy" and "always" map(x, f, additional_arg = 42) # complies to "never" map(x, f, additional_arg = 42) # complies to "tidy" function( a, b) \{ # body \} }\if{html}{\out{
}}} \item{assignment_as_infix}{Treat \verb{<-} as a regular (i.e. left-associative) infix operator? This means, that infix operators on the right hand side of an assignment do not trigger a second level of indentation: \if{html}{\out{
}}\preformatted{# complies to any style variable <- a \%+\% b \%+\% c # complies to assignment_as_infix = TRUE variable <- a \%+\% b \%+\% c # complies to assignment_as_infix = FALSE variable <- a \%+\% b \%+\% c }\if{html}{\out{
}}} } \description{ Check that indentation is consistent } \examples{ # will produce lints code_lines <- "if (TRUE) {\n1 + 1\n}" writeLines(code_lines) lint( text = code_lines, linters = indentation_linter() ) code_lines <- "if (TRUE) {\n 1 + 1\n}" writeLines(code_lines) lint( text = code_lines, linters = indentation_linter() ) code_lines <- "map(x, f,\n additional_arg = 42\n)" writeLines(code_lines) lint( text = code_lines, linters = indentation_linter(hanging_indent_style = "always") ) code_lines <- "map(x, f,\n additional_arg = 42)" writeLines(code_lines) lint( text = code_lines, linters = indentation_linter(hanging_indent_style = "never") ) # okay code_lines <- "map(x, f,\n additional_arg = 42\n)" writeLines(code_lines) lint( text = code_lines, linters = indentation_linter() ) code_lines <- "if (TRUE) {\n 1 + 1\n}" writeLines(code_lines) lint( text = code_lines, linters = indentation_linter(indent = 4) ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#indenting} \item \url{https://style.tidyverse.org/functions.html#long-lines-1} } } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/any_duplicated_linter.Rd0000644000176200001440000000232414752731051017014 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/any_duplicated_linter.R \name{any_duplicated_linter} \alias{any_duplicated_linter} \title{Require usage of \code{anyDuplicated(x) > 0} over \code{any(duplicated(x))}} \usage{ any_duplicated_linter() } \description{ \code{\link[=anyDuplicated]{anyDuplicated()}} exists as a replacement for \code{any(duplicated(.))}, which is more efficient for simple objects, and is at worst equally efficient. Therefore, it should be used in all situations instead of the latter. } \details{ Also match usage like \code{length(unique(x$col)) == nrow(x)}, which can be replaced by \code{anyDuplicated(x$col) == 0L}. } \examples{ # will produce lints lint( text = "any(duplicated(x), na.rm = TRUE)", linters = any_duplicated_linter() ) lint( text = "length(unique(x)) == length(x)", linters = any_duplicated_linter() ) # okay lint( text = "anyDuplicated(x)", linters = any_duplicated_linter() ) lint( text = "anyDuplicated(x) == 0L", linters = any_duplicated_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=efficiency_linters]{efficiency} } lintr/man/if_switch_linter.Rd0000644000176200001440000000746514752731051016021 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/if_switch_linter.R \name{if_switch_linter} \alias{if_switch_linter} \title{Require usage of switch() over repeated if/else blocks} \usage{ if_switch_linter(max_branch_lines = 0L, max_branch_expressions = 0L) } \arguments{ \item{max_branch_lines, max_branch_expressions}{Integer, default 0 indicates "no maximum". If set any \code{if}/\verb{else if}/.../\verb{else} chain where any branch occupies more than this number of lines (resp. expressions) will not be linted. The conjugate applies to \code{switch()} statements -- if these parameters are set, any \code{switch()} statement with any overly-complicated branches will be linted. See examples.} } \description{ \code{\link[=switch]{switch()}} statements in R are used to delegate behavior based on the value of some input scalar string, e.g. \code{switch(x, a = 1, b = 3, c = 7, d = 8)} will be one of \code{1}, \code{3}, \code{7}, or \code{8}, depending on the value of \code{x}. } \details{ This can also be accomplished by repeated \code{if}/\verb{else} statements like so: \code{if (x == "a") 1 else if (x == "b") 2 else if (x == "c") 7 else 8} (implicitly, the last \verb{else} assumes x only takes 4 possible values), but this is more cluttered and slower (note that \code{switch()} takes the same time to evaluate regardless of the value of \code{x}, and is faster even when \code{x} takes the first value (here \code{a}), and that the \code{if}/\verb{else} approach is roughly linear in the number of conditions that need to be evaluated, here up to 3 times). } \examples{ # will produce lints lint( text = "if (x == 'a') 1 else if (x == 'b') 2 else 3", linters = if_switch_linter() ) code <- paste( "if (x == 'a') {", " 1", "} else if (x == 'b') {", " 2", "} else if (x == 'c') {", " y <- x", " z <- sqrt(match(y, letters))", " z", "}", sep = "\n" ) writeLines(code) lint( text = code, linters = if_switch_linter() ) code <- paste( "if (x == 'a') {", " 1", "} else if (x == 'b') {", " 2", "} else if (x == 'c') {", " y <- x", " z <- sqrt(", " match(y, letters)", " )", " z", "}", sep = "\n" ) writeLines(code) lint( text = code, linters = if_switch_linter() ) code <- paste( "switch(x,", " a = {", " 1", " 2", " 3", " },", " b = {", " 1", " 2", " }", ")", sep = "\n" ) writeLines(code) lint( text = code, linters = if_switch_linter(max_branch_lines = 2L) ) # okay lint( text = "switch(x, a = 1, b = 2, 3)", linters = if_switch_linter() ) # switch() version not as clear lint( text = "if (x == 'a') 1 else if (x == 'b' & y == 2) 2 else 3", linters = if_switch_linter() ) code <- paste( "if (x == 'a') {", " 1", "} else if (x == 'b') {", " 2", "} else if (x == 'c') {", " y <- x", " z <- sqrt(match(y, letters))", " z", "}", sep = "\n" ) writeLines(code) lint( text = code, linters = if_switch_linter(max_branch_lines = 2L) ) code <- paste( "if (x == 'a') {", " 1", "} else if (x == 'b') {", " 2", "} else if (x == 'c') {", " y <- x", " z <- sqrt(", " match(y, letters)", " )", " z", "}", sep = "\n" ) writeLines(code) lint( text = code, linters = if_switch_linter(max_branch_expressions = 2L) ) code <- paste( "switch(x,", " a = {", " 1", " 2", " 3", " },", " b = {", " 1", " 2", " }", ")", sep = "\n" ) writeLines(code) lint( text = code, linters = if_switch_linter(max_branch_lines = 3L) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/empty_assignment_linter.Rd0000644000176200001440000000172414752731051017420 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/empty_assignment_linter.R \name{empty_assignment_linter} \alias{empty_assignment_linter} \title{Block assignment of \code{{}}} \usage{ empty_assignment_linter() } \description{ Assignment of \code{{}} is the same as assignment of \code{NULL}; use the latter for clarity. Closely related: \code{\link[=unnecessary_concatenation_linter]{unnecessary_concatenation_linter()}}. } \examples{ # will produce lints lint( text = "x <- {}", linters = empty_assignment_linter() ) writeLines("x = {\n}") lint( text = "x = {\n}", linters = empty_assignment_linter() ) # okay lint( text = "x <- { 3 + 4 }", linters = empty_assignment_linter() ) lint( text = "x <- NULL", linters = empty_assignment_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=readability_linters]{readability} } lintr/man/expect_not_linter.Rd0000644000176200001440000000216514752731051016202 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/expect_not_linter.R \name{expect_not_linter} \alias{expect_not_linter} \title{Require usage of \code{expect_false(x)} over \code{expect_true(!x)}} \usage{ expect_not_linter() } \description{ \code{\link[testthat:logical-expectations]{testthat::expect_false()}} exists specifically for testing that an output is \code{FALSE}. \code{\link[testthat:logical-expectations]{testthat::expect_true()}} can also be used for such tests by negating the output, but it is better to use the tailored function instead. The reverse is also true -- use \code{expect_false(A)} instead of \code{expect_true(!A)}. } \examples{ # will produce lints lint( text = "expect_true(!x)", linters = expect_not_linter() ) # okay lint( text = "expect_false(x)", linters = expect_not_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat}, \link[=readability_linters]{readability} } lintr/man/inner_combine_linter.Rd0000644000176200001440000000324214752731051016636 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/inner_combine_linter.R \name{inner_combine_linter} \alias{inner_combine_linter} \title{Require \code{c()} to be applied before relatively expensive vectorized functions} \usage{ inner_combine_linter() } \description{ \code{as.Date(c(a, b))} is logically equivalent to \code{c(as.Date(a), as.Date(b))}. The same equivalence holds for several other vectorized functions like \code{\link[=as.POSIXct]{as.POSIXct()}} and math functions like \code{\link[=sin]{sin()}}. The former is to be preferred so that the most expensive part of the operation (\code{\link[=as.Date]{as.Date()}}) is applied only once. } \details{ Note that \code{\link[=strptime]{strptime()}} has one idiosyncrasy to be aware of, namely that auto-detected \verb{format=} is set by the first matching input, which means that a case like \code{c(as.POSIXct("2024-01-01"), as.POSIXct("2024-01-01 01:02:03"))} gives different results to \code{as.POSIXct(c("2024-01-01", "2024-01-01 01:02:03"))}. This false positive is rare; a workaround where possible is to use consistent formatting, i.e., \code{"2024-01-01 00:00:00"} in the example. } \examples{ # will produce lints lint( text = "c(log10(x), log10(y), log10(z))", linters = inner_combine_linter() ) # okay lint( text = "log10(c(x, y, z))", linters = inner_combine_linter() ) lint( text = "c(log(x, base = 10), log10(x, base = 2))", linters = inner_combine_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=consistency_linters]{consistency}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/lint.Rd0000644000176200001440000000743014752731051013423 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lint.R \name{lint} \alias{lint} \alias{lint_dir} \alias{lint_package} \title{Lint a file, directory, or package} \usage{ lint( filename, linters = NULL, ..., cache = FALSE, parse_settings = TRUE, text = NULL ) lint_dir( path = ".", ..., relative_path = TRUE, exclusions = list("renv", "packrat"), pattern = "(?i)[.](r|rmd|qmd|rnw|rhtml|rrst|rtex|rtxt)$", parse_settings = TRUE, show_progress = NULL ) lint_package( path = ".", ..., relative_path = TRUE, exclusions = list("R/RcppExports.R"), parse_settings = TRUE, show_progress = NULL ) } \arguments{ \item{filename}{Either the filename for a file to lint, or a character string of inline R code for linting. The latter (inline data) applies whenever \code{filename} has a newline character (\\n).} \item{linters}{A named list of linter functions to apply. See \link{linters} for a full list of default and available linters.} \item{...}{Provide additional arguments to be passed to: \itemize{ \item \code{\link[=exclude]{exclude()}} (in case of \code{lint()}; e.g. \code{lints} or \code{exclusions}) \item \code{\link[=lint]{lint()}} (in case of \code{lint_dir()} and \code{lint_package()}; e.g. \code{linters} or \code{cache}) }} \item{cache}{When logical, toggle caching of lint results. If passed a character string, store the cache in this directory.} \item{parse_settings}{Logical, default \code{TRUE}. Whether to try and parse the \link[=read_settings]{settings}. Otherwise, the \code{\link[=default_settings]{default_settings()}} are used.} \item{text}{Optional argument for supplying a string or lines directly, e.g. if the file is already in memory or linting is being done ad hoc.} \item{path}{For the base directory of the project (for \code{lint_dir()}) or package (for \code{lint_package()}).} \item{relative_path}{if \code{TRUE}, file paths are printed using their path relative to the base directory. If \code{FALSE}, use the full absolute path.} \item{exclusions}{exclusions for \code{\link[=exclude]{exclude()}}, relative to the package path.} \item{pattern}{pattern for files, by default it will take files with any of the extensions .R, .Rmd, .qmd, .Rnw, .Rhtml, .Rrst, .Rtex, .Rtxt allowing for lowercase r (.r, ...).} \item{show_progress}{Logical controlling whether to show linting progress with a simple text progress bar \emph{via} \code{\link[utils:txtProgressBar]{utils::txtProgressBar()}}. The default behavior is to show progress in \code{\link[=interactive]{interactive()}} sessions not running a testthat suite.} } \value{ An object of class \code{c("lints", "list")}, each element of which is a \code{"list"} object. } \description{ \itemize{ \item \code{lint()} lints a single file. \item \code{lint_dir()} lints all files in a directory. \item \code{lint_package()} lints all likely locations for R files in a package, i.e. \verb{R/}, \verb{tests/}, \verb{inst/}, \verb{vignettes/}, \verb{data-raw/}, \verb{demo/}, and \verb{exec/}. } } \details{ Read \code{vignette("lintr")} to learn how to configure which linters are run by default. Note that if files contain unparseable encoding problems, only the encoding problem will be linted to avoid unintelligible error messages from other linters. } \examples{ # linting inline-code lint("a = 123\n") lint(text = "a = 123") # linting a file f <- tempfile() writeLines("a=1", f) lint(f) unlink(f) if (FALSE) { lint_dir() lint_dir( linters = list(semicolon_linter()), exclusions = list( "inst/doc/creating_linters.R" = 1, "inst/example/bad.R", "renv" ) ) } if (FALSE) { lint_package() lint_package( linters = linters_with_defaults(semicolon_linter = semicolon_linter()), exclusions = list("inst/doc/creating_linters.R" = 1, "inst/example/bad.R") ) } } lintr/man/unnecessary_concatenation_linter.Rd0000644000176200001440000000367614752731051021306 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/unnecessary_concatenation_linter.R \name{unnecessary_concatenation_linter} \alias{unnecessary_concatenation_linter} \title{Unneeded concatenation linter} \usage{ unnecessary_concatenation_linter(allow_single_expression = TRUE) } \arguments{ \item{allow_single_expression}{Logical, default \code{TRUE}. If \code{FALSE}, one-expression usages of \code{c()} are always linted, e.g. \code{c(x)} and \code{c(matrix(...))}. In some such cases, \code{c()} is being used for its side-effect of stripping non-name attributes; it is usually preferable to use the more readable \code{\link[=as.vector]{as.vector()}} instead. \code{\link[=as.vector]{as.vector()}} is not always preferable, for example with environments (especially, \code{R6} objects), in which case \code{list()} is the better alternative.} } \description{ Check that the \code{\link[=c]{c()}} function is not used without arguments nor with a single constant. } \examples{ # will produce lints lint( text = "x <- c()", linters = unnecessary_concatenation_linter() ) lint( text = "x <- c(TRUE)", linters = unnecessary_concatenation_linter() ) lint( text = "x <- c(1.5 + 2.5)", linters = unnecessary_concatenation_linter(allow_single_expression = FALSE) ) # okay lint( text = "x <- NULL", linters = unnecessary_concatenation_linter() ) # In case the intent here was to seed a vector of known size lint( text = "x <- integer(4L)", linters = unnecessary_concatenation_linter() ) lint( text = "x <- TRUE", linters = unnecessary_concatenation_linter() ) lint( text = "x <- c(1.5 + 2.5)", linters = unnecessary_concatenation_linter(allow_single_expression = TRUE) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/lint-s3.Rd0000644000176200001440000000156014752731051013744 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lint.R \name{lint-s3} \alias{lint-s3} \alias{Lint} \title{Create a \code{lint} object} \usage{ Lint( filename, line_number = 1L, column_number = 1L, type = c("style", "warning", "error"), message = "", line = "", ranges = NULL, linter = "" ) } \arguments{ \item{filename}{path to the source file that was linted.} \item{line_number}{line number where the lint occurred.} \item{column_number}{column number where the lint occurred.} \item{type}{type of lint.} \item{message}{message used to describe the lint error} \item{line}{code source where the lint occurred} \item{ranges}{a list of ranges on the line that should be emphasized.} \item{linter}{deprecated. No longer used.} } \value{ an object of class \code{c("lint", "list")}. } \description{ Create a \code{lint} object } lintr/man/sample_int_linter.Rd0000644000176200001440000000207214752731051016162 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/sample_int_linter.R \name{sample_int_linter} \alias{sample_int_linter} \title{Require usage of sample.int(n, m, ...) over sample(1:n, m, ...)} \usage{ sample_int_linter() } \description{ \code{\link[=sample.int]{sample.int()}} is preferable to \code{sample()} for the case of sampling numbers between 1 and \code{n}. \code{sample} calls \code{sample.int()} "under the hood". } \examples{ # will produce lints lint( text = "sample(1:10, 2)", linters = sample_int_linter() ) lint( text = "sample(seq(4), 2)", linters = sample_int_linter() ) lint( text = "sample(seq_len(8), 2)", linters = sample_int_linter() ) # okay lint( text = "sample(seq(1, 5, by = 2), 2)", linters = sample_int_linter() ) lint( text = "sample(letters, 2)", linters = sample_int_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability}, \link[=robustness_linters]{robustness} } lintr/man/semicolon_linter.Rd0000644000176200001440000000323314752731051016017 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/semicolon_linter.R \name{semicolon_linter} \alias{semicolon_linter} \title{Semicolon linter} \usage{ semicolon_linter(allow_compound = FALSE, allow_trailing = FALSE) } \arguments{ \item{allow_compound}{Logical, default \code{FALSE}. If \code{TRUE}, "compound" semicolons (e.g. as in \verb{x; y}, i.e., on the same line of code) are allowed.} \item{allow_trailing}{Logical, default \code{FALSE}. If \code{TRUE}, "trailing" semicolons (i.e., those that terminate lines of code) are allowed.} } \description{ Check that no semicolons terminate expressions. } \examples{ # will produce lints lint( text = "a <- 1;", linters = semicolon_linter() ) lint( text = "a <- 1; b <- 1", linters = semicolon_linter() ) lint( text = "function() { a <- 1; b <- 1 }", linters = semicolon_linter() ) # okay lint( text = "a <- 1", linters = semicolon_linter() ) lint( text = "a <- 1;", linters = semicolon_linter(allow_trailing = TRUE) ) code_lines <- "a <- 1\nb <- 1" writeLines(code_lines) lint( text = code_lines, linters = semicolon_linter() ) lint( text = "a <- 1; b <- 1", linters = semicolon_linter(allow_compound = TRUE) ) code_lines <- "function() { \n a <- 1\n b <- 1\n}" writeLines(code_lines) lint( text = code_lines, linters = semicolon_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#semicolons} } } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/style_linters.Rd0000644000176200001440000000404714752731051015356 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{style_linters} \alias{style_linters} \title{Style linters} \description{ Linters highlighting code style issues. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'style': \itemize{ \item{\code{\link{assignment_linter}}} \item{\code{\link{brace_linter}}} \item{\code{\link{commas_linter}}} \item{\code{\link{commented_code_linter}}} \item{\code{\link{condition_call_linter}}} \item{\code{\link{consecutive_assertion_linter}}} \item{\code{\link{cyclocomp_linter}}} \item{\code{\link{function_argument_linter}}} \item{\code{\link{function_left_parentheses_linter}}} \item{\code{\link{implicit_assignment_linter}}} \item{\code{\link{implicit_integer_linter}}} \item{\code{\link{indentation_linter}}} \item{\code{\link{infix_spaces_linter}}} \item{\code{\link{keyword_quote_linter}}} \item{\code{\link{library_call_linter}}} \item{\code{\link{line_length_linter}}} \item{\code{\link{numeric_leading_zero_linter}}} \item{\code{\link{object_length_linter}}} \item{\code{\link{object_name_linter}}} \item{\code{\link{object_usage_linter}}} \item{\code{\link{one_call_pipe_linter}}} \item{\code{\link{package_hooks_linter}}} \item{\code{\link{paren_body_linter}}} \item{\code{\link{pipe_call_linter}}} \item{\code{\link{pipe_consistency_linter}}} \item{\code{\link{pipe_continuation_linter}}} \item{\code{\link{quotes_linter}}} \item{\code{\link{repeat_linter}}} \item{\code{\link{return_linter}}} \item{\code{\link{semicolon_linter}}} \item{\code{\link{spaces_inside_linter}}} \item{\code{\link{spaces_left_parentheses_linter}}} \item{\code{\link{T_and_F_symbol_linter}}} \item{\code{\link{todo_comment_linter}}} \item{\code{\link{trailing_blank_lines_linter}}} \item{\code{\link{trailing_whitespace_linter}}} \item{\code{\link{undesirable_function_linter}}} \item{\code{\link{undesirable_operator_linter}}} \item{\code{\link{unnecessary_concatenation_linter}}} \item{\code{\link{whitespace_linter}}} } } lintr/man/cyclocomp_linter.Rd0000644000176200001440000000215114752731051016015 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cyclocomp_linter.R \name{cyclocomp_linter} \alias{cyclocomp_linter} \title{Cyclomatic complexity linter} \usage{ cyclocomp_linter(complexity_limit = 15L) } \arguments{ \item{complexity_limit}{Maximum cyclomatic complexity, default \code{15}. Expressions more complex than this are linted.} } \description{ Check for overly complicated expressions. See \code{cyclocomp()} function from \code{{cyclocomp}}. } \examples{ \dontshow{if (requireNamespace("cyclocomp", quietly = TRUE)) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf} # will produce lints lint( text = "if (TRUE) 1 else 2", linters = cyclocomp_linter(complexity_limit = 1L) ) # okay lint( text = "if (TRUE) 1 else 2", linters = cyclocomp_linter(complexity_limit = 2L) ) \dontshow{\}) # examplesIf} } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/lintr-deprecated.Rd0000644000176200001440000000326414752731051015704 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lintr-deprecated.R, R/with.R \name{lintr-deprecated} \alias{lintr-deprecated} \alias{closed_curly_linter} \alias{open_curly_linter} \alias{paren_brace_linter} \alias{semicolon_terminator_linter} \alias{unneeded_concatenation_linter} \alias{single_quotes_linter} \alias{consecutive_stopifnot_linter} \alias{no_tab_linter} \alias{extraction_operator_linter} \alias{unnecessary_nested_if_linter} \alias{with_defaults} \title{Deprecated functions in lintr} \usage{ closed_curly_linter(allow_single_line = FALSE) open_curly_linter(allow_single_line = FALSE) paren_brace_linter() semicolon_terminator_linter(semicolon = c("compound", "trailing")) unneeded_concatenation_linter(allow_single_expression = TRUE) single_quotes_linter() consecutive_stopifnot_linter() no_tab_linter() extraction_operator_linter() unnecessary_nested_if_linter() with_defaults(..., default = default_linters) } \arguments{ \item{allow_single_line, semicolon}{Irrelevant parameters to defunct linters.} } \description{ These functions have been deprecated from lintr. \itemize{ \item \code{open_curly_linter()} (use \code{\link[=brace_linter]{brace_linter()}}) \item \code{closed_curly_linter()} (use \code{brace_linter()}) \item \code{paren_brace_linter()} (use \code{brace_linter()}) \item \code{semicolon_terminator_linter()} (use \code{\link[=semicolon_linter]{semicolon_linter()}}) } } \seealso{ \link{linters} for a complete list of linters available in lintr. } \keyword{internal} \section{Tags}{ \link[=consistency_linters]{consistency}, \link[=deprecated_linters]{deprecated}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/keyword_quote_linter.Rd0000644000176200001440000000264314752731051016734 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/keyword_quote_linter.R \name{keyword_quote_linter} \alias{keyword_quote_linter} \title{Block unnecessary quoting in calls} \usage{ keyword_quote_linter() } \description{ Any valid symbol can be used as a keyword argument to an R function call. Sometimes, it is necessary to quote (or backtick) an argument that is not an otherwise valid symbol (e.g. creating a vector whose names have spaces); besides this edge case, quoting should not be done. } \details{ The most common source of violation for this is creating named vectors, lists, or data.frame-alikes, but it can be observed in other calls as well. Similar reasoning applies to extractions with \code{$} or \code{@}. } \examples{ # will produce lints lint( text = 'data.frame("a" = 1)', linters = keyword_quote_linter() ) lint( text = "data.frame(`a` = 1)", linters = keyword_quote_linter() ) lint( text = 'my_list$"key"', linters = keyword_quote_linter() ) lint( text = 's4obj@"key"', linters = keyword_quote_linter() ) # okay lint( text = "data.frame(`a b` = 1)", linters = keyword_quote_linter() ) lint( text = "my_list$`a b`", linters = keyword_quote_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/boolean_arithmetic_linter.Rd0000644000176200001440000000177614752731051017671 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/boolean_arithmetic_linter.R \name{boolean_arithmetic_linter} \alias{boolean_arithmetic_linter} \title{Require usage of boolean operators over equivalent arithmetic} \usage{ boolean_arithmetic_linter() } \description{ \code{length(which(x == y)) == 0} is the same as \code{!any(x == y)}, but the latter is more readable and more efficient. } \examples{ # will produce lints lint( text = "length(which(x == y)) == 0L", linters = boolean_arithmetic_linter() ) lint( text = "sum(grepl(pattern, x)) == 0", linters = boolean_arithmetic_linter() ) # okay lint( text = "!any(x == y)", linters = boolean_arithmetic_linter() ) lint( text = "!any(grepl(pattern, x))", linters = boolean_arithmetic_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/linters.Rd0000644000176200001440000002765414752731051014147 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/AAA.R \name{linters} \alias{linters} \title{Available linters} \description{ A variety of linters are available in \pkg{lintr}. The most popular ones are readily accessible through \code{\link[=default_linters]{default_linters()}}. Within a \code{\link[=lint]{lint()}} function call, the linters in use are initialized with the provided arguments and fed with the source file (provided by \code{\link[=get_source_expressions]{get_source_expressions()}}). A data frame of all available linters can be retrieved using \code{\link[=available_linters]{available_linters()}}. Documentation for linters is structured into tags to allow for easier discovery; see also \code{\link[=available_tags]{available_tags()}}. } \section{Tags}{ The following tags exist: \itemize{ \item{\link[=best_practices_linters]{best_practices} (63 linters)} \item{\link[=common_mistakes_linters]{common_mistakes} (11 linters)} \item{\link[=configurable_linters]{configurable} (44 linters)} \item{\link[=consistency_linters]{consistency} (32 linters)} \item{\link[=correctness_linters]{correctness} (7 linters)} \item{\link[=default_linters]{default} (25 linters)} \item{\link[=deprecated_linters]{deprecated} (6 linters)} \item{\link[=efficiency_linters]{efficiency} (29 linters)} \item{\link[=executing_linters]{executing} (6 linters)} \item{\link[=package_development_linters]{package_development} (14 linters)} \item{\link[=pkg_testthat_linters]{pkg_testthat} (12 linters)} \item{\link[=readability_linters]{readability} (64 linters)} \item{\link[=regex_linters]{regex} (4 linters)} \item{\link[=robustness_linters]{robustness} (17 linters)} \item{\link[=style_linters]{style} (40 linters)} \item{\link[=tidy_design_linters]{tidy_design} (1 linters)} } } \section{Linters}{ The following linters exist: \itemize{ \item{\code{\link{absolute_path_linter}} (tags: best_practices, configurable, robustness)} \item{\code{\link{any_duplicated_linter}} (tags: best_practices, efficiency)} \item{\code{\link{any_is_na_linter}} (tags: best_practices, efficiency)} \item{\code{\link{assignment_linter}} (tags: configurable, consistency, default, style)} \item{\code{\link{backport_linter}} (tags: configurable, package_development, robustness)} \item{\code{\link{boolean_arithmetic_linter}} (tags: best_practices, efficiency, readability)} \item{\code{\link{brace_linter}} (tags: configurable, default, readability, style)} \item{\code{\link{class_equals_linter}} (tags: best_practices, consistency, robustness)} \item{\code{\link{commas_linter}} (tags: configurable, default, readability, style)} \item{\code{\link{commented_code_linter}} (tags: best_practices, default, readability, style)} \item{\code{\link{comparison_negation_linter}} (tags: consistency, readability)} \item{\code{\link{condition_call_linter}} (tags: best_practices, configurable, style, tidy_design)} \item{\code{\link{condition_message_linter}} (tags: best_practices, consistency)} \item{\code{\link{conjunct_test_linter}} (tags: best_practices, configurable, package_development, pkg_testthat, readability)} \item{\code{\link{consecutive_assertion_linter}} (tags: consistency, readability, style)} \item{\code{\link{consecutive_mutate_linter}} (tags: configurable, consistency, efficiency, readability)} \item{\code{\link{cyclocomp_linter}} (tags: best_practices, configurable, readability, style)} \item{\code{\link{duplicate_argument_linter}} (tags: common_mistakes, configurable, correctness)} \item{\code{\link{empty_assignment_linter}} (tags: best_practices, readability)} \item{\code{\link{equals_na_linter}} (tags: common_mistakes, correctness, default, robustness)} \item{\code{\link{expect_comparison_linter}} (tags: best_practices, package_development, pkg_testthat)} \item{\code{\link{expect_identical_linter}} (tags: package_development, pkg_testthat)} \item{\code{\link{expect_length_linter}} (tags: best_practices, package_development, pkg_testthat, readability)} \item{\code{\link{expect_named_linter}} (tags: best_practices, package_development, pkg_testthat, readability)} \item{\code{\link{expect_not_linter}} (tags: best_practices, package_development, pkg_testthat, readability)} \item{\code{\link{expect_null_linter}} (tags: best_practices, package_development, pkg_testthat)} \item{\code{\link{expect_s3_class_linter}} (tags: best_practices, package_development, pkg_testthat)} \item{\code{\link{expect_s4_class_linter}} (tags: best_practices, package_development, pkg_testthat)} \item{\code{\link{expect_true_false_linter}} (tags: best_practices, package_development, pkg_testthat, readability)} \item{\code{\link{expect_type_linter}} (tags: best_practices, package_development, pkg_testthat)} \item{\code{\link{fixed_regex_linter}} (tags: best_practices, configurable, efficiency, readability, regex)} \item{\code{\link{for_loop_index_linter}} (tags: best_practices, readability, robustness)} \item{\code{\link{function_argument_linter}} (tags: best_practices, consistency, style)} \item{\code{\link{function_left_parentheses_linter}} (tags: default, readability, style)} \item{\code{\link{function_return_linter}} (tags: best_practices, readability)} \item{\code{\link{if_not_else_linter}} (tags: configurable, consistency, readability)} \item{\code{\link{if_switch_linter}} (tags: best_practices, configurable, consistency, efficiency, readability)} \item{\code{\link{ifelse_censor_linter}} (tags: best_practices, efficiency)} \item{\code{\link{implicit_assignment_linter}} (tags: best_practices, configurable, readability, style)} \item{\code{\link{implicit_integer_linter}} (tags: best_practices, configurable, consistency, style)} \item{\code{\link{indentation_linter}} (tags: configurable, default, readability, style)} \item{\code{\link{infix_spaces_linter}} (tags: configurable, default, readability, style)} \item{\code{\link{inner_combine_linter}} (tags: consistency, efficiency, readability)} \item{\code{\link{is_numeric_linter}} (tags: best_practices, consistency, readability)} \item{\code{\link{keyword_quote_linter}} (tags: consistency, readability, style)} \item{\code{\link{length_levels_linter}} (tags: best_practices, consistency, readability)} \item{\code{\link{length_test_linter}} (tags: common_mistakes, efficiency)} \item{\code{\link{lengths_linter}} (tags: best_practices, efficiency, readability)} \item{\code{\link{library_call_linter}} (tags: best_practices, configurable, readability, style)} \item{\code{\link{line_length_linter}} (tags: configurable, default, readability, style)} \item{\code{\link{list_comparison_linter}} (tags: best_practices, common_mistakes)} \item{\code{\link{literal_coercion_linter}} (tags: best_practices, consistency, efficiency)} \item{\code{\link{matrix_apply_linter}} (tags: efficiency, readability)} \item{\code{\link{missing_argument_linter}} (tags: common_mistakes, configurable, correctness)} \item{\code{\link{missing_package_linter}} (tags: common_mistakes, robustness)} \item{\code{\link{namespace_linter}} (tags: configurable, correctness, executing, robustness)} \item{\code{\link{nested_ifelse_linter}} (tags: efficiency, readability)} \item{\code{\link{nested_pipe_linter}} (tags: configurable, consistency, readability)} \item{\code{\link{nonportable_path_linter}} (tags: best_practices, configurable, robustness)} \item{\code{\link{nrow_subset_linter}} (tags: best_practices, consistency, efficiency)} \item{\code{\link{numeric_leading_zero_linter}} (tags: consistency, readability, style)} \item{\code{\link{nzchar_linter}} (tags: best_practices, consistency, efficiency)} \item{\code{\link{object_length_linter}} (tags: configurable, default, executing, readability, style)} \item{\code{\link{object_name_linter}} (tags: configurable, consistency, default, executing, style)} \item{\code{\link{object_overwrite_linter}} (tags: best_practices, configurable, executing, readability, robustness)} \item{\code{\link{object_usage_linter}} (tags: configurable, correctness, default, executing, readability, style)} \item{\code{\link{one_call_pipe_linter}} (tags: readability, style)} \item{\code{\link{outer_negation_linter}} (tags: best_practices, efficiency, readability)} \item{\code{\link{package_hooks_linter}} (tags: correctness, package_development, style)} \item{\code{\link{paren_body_linter}} (tags: default, readability, style)} \item{\code{\link{paste_linter}} (tags: best_practices, configurable, consistency)} \item{\code{\link{pipe_call_linter}} (tags: readability, style)} \item{\code{\link{pipe_consistency_linter}} (tags: configurable, readability, style)} \item{\code{\link{pipe_continuation_linter}} (tags: default, readability, style)} \item{\code{\link{pipe_return_linter}} (tags: best_practices, common_mistakes)} \item{\code{\link{print_linter}} (tags: best_practices, consistency)} \item{\code{\link{quotes_linter}} (tags: configurable, consistency, default, readability, style)} \item{\code{\link{redundant_equals_linter}} (tags: best_practices, common_mistakes, efficiency, readability)} \item{\code{\link{redundant_ifelse_linter}} (tags: best_practices, configurable, consistency, efficiency)} \item{\code{\link{regex_subset_linter}} (tags: best_practices, efficiency, regex)} \item{\code{\link{rep_len_linter}} (tags: best_practices, consistency, readability)} \item{\code{\link{repeat_linter}} (tags: readability, style)} \item{\code{\link{return_linter}} (tags: configurable, default, style)} \item{\code{\link{routine_registration_linter}} (tags: best_practices, efficiency, robustness)} \item{\code{\link{sample_int_linter}} (tags: efficiency, readability, robustness)} \item{\code{\link{scalar_in_linter}} (tags: best_practices, configurable, consistency, efficiency, readability)} \item{\code{\link{semicolon_linter}} (tags: configurable, default, readability, style)} \item{\code{\link{seq_linter}} (tags: best_practices, consistency, default, efficiency, robustness)} \item{\code{\link{sort_linter}} (tags: best_practices, efficiency, readability)} \item{\code{\link{spaces_inside_linter}} (tags: default, readability, style)} \item{\code{\link{spaces_left_parentheses_linter}} (tags: default, readability, style)} \item{\code{\link{sprintf_linter}} (tags: common_mistakes, correctness)} \item{\code{\link{stopifnot_all_linter}} (tags: best_practices, readability)} \item{\code{\link{string_boundary_linter}} (tags: configurable, efficiency, readability, regex)} \item{\code{\link{strings_as_factors_linter}} (tags: robustness)} \item{\code{\link{system_file_linter}} (tags: best_practices, consistency, readability)} \item{\code{\link{T_and_F_symbol_linter}} (tags: best_practices, consistency, default, readability, robustness, style)} \item{\code{\link{terminal_close_linter}} (tags: best_practices, robustness)} \item{\code{\link{todo_comment_linter}} (tags: configurable, style)} \item{\code{\link{trailing_blank_lines_linter}} (tags: default, style)} \item{\code{\link{trailing_whitespace_linter}} (tags: configurable, default, style)} \item{\code{\link{undesirable_function_linter}} (tags: best_practices, configurable, robustness, style)} \item{\code{\link{undesirable_operator_linter}} (tags: best_practices, configurable, robustness, style)} \item{\code{\link{unnecessary_concatenation_linter}} (tags: configurable, efficiency, readability, style)} \item{\code{\link{unnecessary_lambda_linter}} (tags: best_practices, configurable, efficiency, readability)} \item{\code{\link{unnecessary_nesting_linter}} (tags: best_practices, configurable, consistency, readability)} \item{\code{\link{unnecessary_placeholder_linter}} (tags: best_practices, readability)} \item{\code{\link{unreachable_code_linter}} (tags: best_practices, configurable, readability)} \item{\code{\link{unused_import_linter}} (tags: best_practices, common_mistakes, configurable, executing)} \item{\code{\link{vector_logic_linter}} (tags: best_practices, common_mistakes, default, efficiency)} \item{\code{\link{which_grepl_linter}} (tags: consistency, efficiency, readability, regex)} \item{\code{\link{whitespace_linter}} (tags: consistency, default, style)} \item{\code{\link{yoda_test_linter}} (tags: best_practices, package_development, pkg_testthat, readability)} } } lintr/man/use_lintr.Rd0000644000176200001440000000230714752731051014457 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/use_lintr.R \name{use_lintr} \alias{use_lintr} \title{Use lintr in your project} \usage{ use_lintr(path = ".", type = c("tidyverse", "full")) } \arguments{ \item{path}{Path to project root, where a \code{.lintr} file should be created. If the \code{.lintr} file already exists, an error will be thrown.} \item{type}{What kind of configuration to create? \itemize{ \item \code{tidyverse} creates a minimal lintr config, based on the default linters (\code{\link[=linters_with_defaults]{linters_with_defaults()}}). These are suitable for following \href{https://style.tidyverse.org/}{the tidyverse style guide}. \item \code{full} creates a lintr config using all available linters via \code{\link[=all_linters]{all_linters()}}. }} } \value{ Path to the generated configuration, invisibly. } \description{ Create a minimal lintr config file as a starting point for customization } \examples{ if (FALSE) { # use the default set of linters lintr::use_lintr() # or try all linters lintr::use_lintr(type = "full") # then lintr::lint_dir() } } \seealso{ \code{vignette("lintr")} for detailed introduction to using and configuring lintr. } lintr/man/brace_linter.Rd0000644000176200001440000000370614752731051015110 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/brace_linter.R \name{brace_linter} \alias{brace_linter} \title{Brace linter} \usage{ brace_linter(allow_single_line = FALSE) } \arguments{ \item{allow_single_line}{if \code{TRUE}, allow an open and closed curly pair on the same line.} } \description{ Perform various style checks related to placement and spacing of curly braces: } \details{ \itemize{ \item Opening curly braces are never on their own line and are always followed by a newline. \item Opening curly braces have a space before them. \item Closing curly braces are on their own line unless they are followed by an \verb{else}. \item Closing curly braces in \code{if} conditions are on the same line as the corresponding \verb{else}. \item Either both or neither branch in \code{if}/\verb{else} use curly braces, i.e., either both branches use \code{{...}} or neither does. \item Functions spanning multiple lines use curly braces. } } \examples{ # will produce lints lint( text = "f <- function() { 1 }", linters = brace_linter() ) writeLines("if (TRUE) {\n return(1) }") lint( text = "if (TRUE) {\n return(1) }", linters = brace_linter() ) # okay writeLines("f <- function() {\n 1\n}") lint( text = "f <- function() {\n 1\n}", linters = brace_linter() ) writeLines("if (TRUE) { \n return(1) \n}") lint( text = "if (TRUE) { \n return(1) \n}", linters = brace_linter() ) # customizing using arguments writeLines("if (TRUE) { return(1) }") lint( text = "if (TRUE) { return(1) }", linters = brace_linter(allow_single_line = TRUE) ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#indenting} \item \url{https://style.tidyverse.org/syntax.html#if-statements} } } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/duplicate_argument_linter.Rd0000644000176200001440000000270614752731051017707 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/duplicate_argument_linter.R \name{duplicate_argument_linter} \alias{duplicate_argument_linter} \title{Duplicate argument linter} \usage{ duplicate_argument_linter(except = c("mutate", "transmute")) } \arguments{ \item{except}{A character vector of function names as exceptions. Defaults to functions that allow sequential updates to variables, currently \code{dplyr::mutate()} and \code{dplyr::transmute()}.} } \description{ Check for duplicate arguments in function calls. Some cases are run-time errors (e.g. \code{mean(x = 1:5, x = 2:3)}), otherwise this linter is used to discourage explicitly providing duplicate names to objects (e.g. \code{c(a = 1, a = 2)}). Duplicate-named objects are hard to work with programmatically and should typically be avoided. } \examples{ # will produce lints lint( text = "list(x = 1, x = 2)", linters = duplicate_argument_linter() ) lint( text = "fun(arg = 1, arg = 2)", linters = duplicate_argument_linter() ) # okay lint( text = "list(x = 1, x = 2)", linters = duplicate_argument_linter(except = "list") ) lint( text = "df \%>\% dplyr::mutate(x = a + b, x = x + d)", linters = duplicate_argument_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=common_mistakes_linters]{common_mistakes}, \link[=configurable_linters]{configurable}, \link[=correctness_linters]{correctness} } lintr/man/spaces_inside_linter.Rd0000644000176200001440000000175314752731051016645 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/spaces_inside_linter.R \name{spaces_inside_linter} \alias{spaces_inside_linter} \title{Spaces inside linter} \usage{ spaces_inside_linter() } \description{ Check that parentheses and square brackets do not have spaces directly inside them, i.e., directly following an opening delimiter or directly preceding a closing delimiter. } \examples{ # will produce lints lint( text = "c( TRUE, FALSE )", linters = spaces_inside_linter() ) lint( text = "x[ 1L ]", linters = spaces_inside_linter() ) # okay lint( text = "c(TRUE, FALSE)", linters = spaces_inside_linter() ) lint( text = "x[1L]", linters = spaces_inside_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#parentheses} } } \section{Tags}{ \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/undesirable_operator_linter.Rd0000644000176200001440000000332614752731051020242 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/undesirable_operator_linter.R \name{undesirable_operator_linter} \alias{undesirable_operator_linter} \title{Undesirable operator linter} \usage{ undesirable_operator_linter(op = default_undesirable_operators) } \arguments{ \item{op}{Named character vector. \code{names(op)} correspond to undesirable operators, while the values give a description of why the operator is undesirable. If \code{NA}, no additional information is given in the lint message. Defaults to \link{default_undesirable_operators}. To make small customizations to this list, use \code{\link[=modify_defaults]{modify_defaults()}}.} } \description{ Report the use of undesirable operators, e.g. \code{\link[base:ns-dblcolon]{:::}} or \code{\link[base:assignOps]{<<-}} and suggest an alternative. } \examples{ # defaults for which functions are considered undesirable names(default_undesirable_operators) # will produce lints lint( text = "a <<- log(10)", linters = undesirable_operator_linter() ) lint( text = "mtcars$wt", linters = undesirable_operator_linter(op = c("$" = "As an alternative, use the `[[` accessor.")) ) # okay lint( text = "a <- log(10)", linters = undesirable_operator_linter() ) lint( text = 'mtcars[["wt"]]', linters = undesirable_operator_linter(op = c("$" = NA)) ) lint( text = 'mtcars[["wt"]]', linters = undesirable_operator_linter(op = c("$" = "As an alternative, use the `[[` accessor.")) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=robustness_linters]{robustness}, \link[=style_linters]{style} } lintr/man/paste_linter.Rd0000644000176200001440000001020214752731051015135 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/paste_linter.R \name{paste_linter} \alias{paste_linter} \title{Raise lints for several common poor usages of \code{paste()}} \usage{ paste_linter( allow_empty_sep = FALSE, allow_to_string = FALSE, allow_file_path = c("double_slash", "always", "never") ) } \arguments{ \item{allow_empty_sep}{Logical, default \code{FALSE}. If \code{TRUE}, usage of \code{paste()} with \code{sep = ""} is not linted.} \item{allow_to_string}{Logical, default \code{FALSE}. If \code{TRUE}, usage of \code{paste()} and \code{paste0()} with \code{collapse = ", "} is not linted.} \item{allow_file_path}{String, one of \code{"never"}, \code{"double_slash"}, or \code{"always"}; \code{"double_slash"} by default. If \code{"never"}, usage of \code{paste()} and \code{paste0()} to construct file paths is not linted. If \code{"double_slash"}, strings containing consecutive forward slashes will not lint. The main use case here is for URLs -- "paths" like \code{"https://"} will not induce lints, since constructing them with \code{file.path()} might be deemed unnatural. Lastly, if \code{"always"}, strings with consecutive forward slashes will also lint. Note that \code{"//"} is never linted when it comes at the beginning or end of the input, to avoid requiring empty inputs like \code{file.path("", ...)} or \code{file.path(..., "")}.} } \description{ The following issues are linted by default by this linter (see arguments for which can be de-activated optionally): \enumerate{ \item Block usage of \code{\link[=paste]{paste()}} with \code{sep = ""}. \code{\link[=paste0]{paste0()}} is a faster, more concise alternative. \item Block usage of \code{paste()} or \code{paste0()} with \code{collapse = ", "}. \code{\link[=toString]{toString()}} is a direct wrapper for this, and alternatives like \code{\link[glue:glue_collapse]{glue::glue_collapse()}} might give better messages for humans. \item Block usage of \code{paste0()} that supplies \verb{sep=} -- this is not a formal argument to \code{paste0}, and is likely to be a mistake. \item Block usage of \code{paste()} / \code{paste0()} combined with \code{\link[=rep]{rep()}} that could be replaced by \code{\link[=strrep]{strrep()}}. \code{strrep()} can handle the task of building a block of repeated strings (e.g. often used to build "horizontal lines" for messages). This is both more readable and skips the (likely small) overhead of putting two strings into the global string cache when only one is needed. Only target scalar usages -- \code{strrep} can handle more complicated cases (e.g. \code{strrep(letters, 26:1)}, but those aren't as easily translated from a \code{paste(collapse=)} call. } } \examples{ # will produce lints lint( text = 'paste("a", "b", sep = "")', linters = paste_linter() ) lint( text = 'paste(c("a", "b"), collapse = ", ")', linters = paste_linter() ) lint( text = 'paste0(c("a", "b"), sep = " ")', linters = paste_linter() ) lint( text = 'paste0(rep("*", 10L), collapse = "")', linters = paste_linter() ) lint( text = 'paste0("http://site.com/", path)', linters = paste_linter(allow_file_path = "never") ) lint( text = 'paste0(x, collapse = "")', linters = paste_linter() ) # okay lint( text = 'paste0("a", "b")', linters = paste_linter() ) lint( text = 'paste("a", "b", sep = "")', linters = paste_linter(allow_empty_sep = TRUE) ) lint( text = 'toString(c("a", "b"))', linters = paste_linter() ) lint( text = 'paste(c("a", "b"), collapse = ", ")', linters = paste_linter(allow_to_string = TRUE) ) lint( text = 'paste(c("a", "b"))', linters = paste_linter() ) lint( text = 'strrep("*", 10L)', linters = paste_linter() ) lint( text = 'paste0(year, "/", month, "/", day)', linters = paste_linter(allow_file_path = "always") ) lint( text = 'paste0("http://site.com/", path)', linters = paste_linter() ) lint( text = 'paste(x, collapse = "")', linters = paste_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency} } lintr/man/deprecated_linters.Rd0000644000176200001440000000145014752731051016311 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{deprecated_linters} \alias{deprecated_linters} \title{Deprecated linters} \description{ Linters that are deprecated and provided for backwards compatibility only. These linters will be excluded from \code{\link[=linters_with_tags]{linters_with_tags()}} by default. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'deprecated': \itemize{ \item{\code{\link{consecutive_stopifnot_linter}}} \item{\code{\link{extraction_operator_linter}}} \item{\code{\link{no_tab_linter}}} \item{\code{\link{single_quotes_linter}}} \item{\code{\link{unnecessary_nested_if_linter}}} \item{\code{\link{unneeded_concatenation_linter}}} } } lintr/man/backport_linter.Rd0000644000176200001440000000240314752731051015632 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/backport_linter.R \name{backport_linter} \alias{backport_linter} \title{Backport linter} \usage{ backport_linter(r_version = getRversion(), except = character()) } \arguments{ \item{r_version}{Minimum R version to test for compatibility} \item{except}{Character vector of functions to be excluded from linting. Use this to list explicitly defined backports, e.g. those imported from the \code{{backports}} package or manually defined in your package.} } \description{ Check for usage of unavailable functions. Not reliable for testing r-devel dependencies. } \examples{ # will produce lints lint( text = "trimws(x)", linters = backport_linter("3.0.0") ) lint( text = "str2lang(x)", linters = backport_linter("3.2.0") ) # okay lint( text = "trimws(x)", linters = backport_linter("3.6.0") ) lint( text = "str2lang(x)", linters = backport_linter("4.0.0") ) lint( text = "str2lang(x)", linters = backport_linter("3.2.0", except = "str2lang") ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=package_development_linters]{package_development}, \link[=robustness_linters]{robustness} } lintr/man/correctness_linters.Rd0000644000176200001440000000132414752731051016543 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{correctness_linters} \alias{correctness_linters} \title{Correctness linters} \description{ Linters highlighting possible programming mistakes, such as unused variables. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'correctness': \itemize{ \item{\code{\link{duplicate_argument_linter}}} \item{\code{\link{equals_na_linter}}} \item{\code{\link{missing_argument_linter}}} \item{\code{\link{namespace_linter}}} \item{\code{\link{object_usage_linter}}} \item{\code{\link{package_hooks_linter}}} \item{\code{\link{sprintf_linter}}} } } lintr/man/which_grepl_linter.Rd0000644000176200001440000000151114752731051016317 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/which_grepl_linter.R \name{which_grepl_linter} \alias{which_grepl_linter} \title{Require usage of grep over which(grepl(.))} \usage{ which_grepl_linter() } \description{ \code{which(grepl(pattern, x))} is the same as \code{grep(pattern, x)}, but harder to read and requires two passes over the vector. } \examples{ # will produce lints lint( text = "which(grepl('^a', x))", linters = which_grepl_linter() ) # okay lint( text = "which(grepl('^a', x) | grepl('^b', x))", linters = which_grepl_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=consistency_linters]{consistency}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability}, \link[=regex_linters]{regex} } lintr/man/pipe_call_linter.Rd0000644000176200001440000000144314752731051015760 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe_call_linter.R \name{pipe_call_linter} \alias{pipe_call_linter} \title{Pipe call linter} \usage{ pipe_call_linter() } \description{ Force explicit calls in magrittr pipes, e.g., \code{1:3 \%>\% sum()} instead of \code{1:3 \%>\% sum}. Note that native pipe always requires a function call, i.e. \verb{1:3 |> sum} will produce an error. } \examples{ # will produce lints lint( text = "1:3 \%>\% mean \%>\% as.character", linters = pipe_call_linter() ) # okay lint( text = "1:3 \%>\% mean() \%>\% as.character()", linters = pipe_call_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/modify_defaults.Rd0000644000176200001440000000347514752731051015640 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/with.R \name{modify_defaults} \alias{modify_defaults} \title{Modify lintr defaults} \usage{ modify_defaults(defaults, ...) } \arguments{ \item{defaults}{named list of elements to modify.} \item{...}{arguments of elements to change. If unnamed, the argument is automatically named. If the named argument already exists in \code{defaults}, it is replaced by the new element. If it does not exist, it is added. If the value is \code{NULL}, the element is removed.} } \value{ A modified list of elements, sorted by name. To achieve this sort in a platform-independent way, two transformations are applied to the names: (1) replace \verb{_} with \code{0} and (2) convert \code{\link[=tolower]{tolower()}}. } \description{ Modify a list of defaults by name, allowing for replacement, deletion and addition of new elements. } \examples{ # custom list of undesirable functions: # remove `sapply` (using `NULL`) # add `cat` (with an accompanying message), # add `print` (unnamed, i.e. with no accompanying message) # add `source` (as taken from `all_undesirable_functions`) my_undesirable_functions <- modify_defaults( defaults = default_undesirable_functions, sapply = NULL, "cat" = "No cat allowed", "print", all_undesirable_functions[["source"]] ) # list names of functions specified as undesirable names(my_undesirable_functions) } \seealso{ \itemize{ \item \link{linters_with_defaults} for basing off lintr's set of default linters. \item \link{all_linters} for basing off all available linters in lintr. \item \link{linters_with_tags} for basing off tags attached to linters, possibly across multiple packages. \item \link{available_linters} to get a data frame of available linters. \item \link{linters} for a complete list of linters available in lintr. } } lintr/man/unnecessary_placeholder_linter.Rd0000644000176200001440000000224114752731051020726 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/unnecessary_placeholder_linter.R \name{unnecessary_placeholder_linter} \alias{unnecessary_placeholder_linter} \title{Block usage of pipeline placeholders if unnecessary} \usage{ unnecessary_placeholder_linter() } \description{ The argument placeholder \code{.} in magrittr pipelines is unnecessary if passed as the first positional argument; using it can cause confusion and impacts readability. } \details{ This is true for forward (\verb{\%>\%}), assignment (\verb{\%<>\%}), and tee (\verb{\%T>\%}) operators. } \examples{ # will produce lints lint( text = "x \%>\% sum(., na.rm = TRUE)", linters = unnecessary_placeholder_linter() ) # okay lint( text = "x \%>\% sum(na.rm = TRUE)", linters = unnecessary_placeholder_linter() ) lint( text = "x \%>\% lm(data = ., y ~ z)", linters = unnecessary_placeholder_linter() ) lint( text = "x \%>\% outer(., .)", linters = unnecessary_placeholder_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=readability_linters]{readability} } lintr/man/nested_ifelse_linter.Rd0000644000176200001440000000450714752731051016645 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/nested_ifelse_linter.R \name{nested_ifelse_linter} \alias{nested_ifelse_linter} \title{Block usage of nested \code{ifelse()} calls} \usage{ nested_ifelse_linter() } \description{ Calling \code{\link[=ifelse]{ifelse()}} in nested calls is problematic for two main reasons: \enumerate{ \item It can be hard to read -- mapping the code to the expected output for such code can be a messy task/require a lot of mental bandwidth, especially for code that nests more than once \item It is inefficient -- \code{ifelse()} can evaluate \emph{all} of its arguments at both yes and no (see \url{https://stackoverflow.com/q/16275149}); this issue is exacerbated for nested calls } } \details{ Users can instead rely on a more readable alternative modeled after SQL CASE WHEN statements. Let's say this is our original code: \if{html}{\out{
}}\preformatted{ifelse( x == "a", 2L, ifelse(x == "b", 3L, 1L) ) }\if{html}{\out{
}} Here are a few ways to avoid nesting and make the code more readable: \itemize{ \item Use \code{data.table::fcase()} \if{html}{\out{
}}\preformatted{data.table::fcase( x == "a", 2L, x == "b", 3L, default = 1L ) }\if{html}{\out{
}} \item Use \code{dplyr::case_match()} \if{html}{\out{
}}\preformatted{dplyr::case_match( x, "a" ~ 2L, "b" ~ 3L, .default = 1L ) }\if{html}{\out{
}} \item Use a look-up-and-merge approach (build a mapping table between values and outputs and merge this to the input) \if{html}{\out{
}}\preformatted{default <- 1L values <- data.frame( a = 2L, b = 3L ) found_value <- values[[x]] ifelse(is.null(found_value), default, found_value) }\if{html}{\out{
}} } } \examples{ # will produce lints lint( text = 'ifelse(x == "a", 1L, ifelse(x == "b", 2L, 3L))', linters = nested_ifelse_linter() ) # okay lint( text = 'dplyr::case_when(x == "a" ~ 1L, x == "b" ~ 2L, TRUE ~ 3L)', linters = nested_ifelse_linter() ) lint( text = 'data.table::fcase(x == "a", 1L, x == "b", 2L, default = 3L)', linters = nested_ifelse_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/is_numeric_linter.Rd0000644000176200001440000000244514752731051016170 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/is_numeric_linter.R \name{is_numeric_linter} \alias{is_numeric_linter} \title{Redirect \code{is.numeric(x) || is.integer(x)} to just use \code{is.numeric(x)}} \usage{ is_numeric_linter() } \description{ \code{\link[=is.numeric]{is.numeric()}} returns \code{TRUE} when \code{typeof(x)} is \code{double} or \code{integer} -- testing \code{is.numeric(x) || is.integer(x)} is thus redundant. } \details{ NB: This linter plays well with \code{\link[=class_equals_linter]{class_equals_linter()}}, which can help avoid further \code{is.numeric()} equivalents like \code{any(class(x) == c("numeric", "integer"))}. } \examples{ # will produce lints lint( text = "is.numeric(y) || is.integer(y)", linters = is_numeric_linter() ) lint( text = 'class(z) \%in\% c("numeric", "integer")', linters = is_numeric_linter() ) # okay lint( text = "is.numeric(y) || is.factor(y)", linters = is_numeric_linter() ) lint( text = 'class(z) \%in\% c("numeric", "integer", "factor")', linters = is_numeric_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability} } lintr/man/regex_subset_linter.Rd0000644000176200001440000000357014752731051016532 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/regex_subset_linter.R \name{regex_subset_linter} \alias{regex_subset_linter} \title{Require usage of direct methods for subsetting strings via regex} \usage{ regex_subset_linter() } \description{ Using \code{value = TRUE} in \code{\link[=grep]{grep()}} returns the subset of the input that matches the pattern, e.g. \code{grep("[a-m]", letters, value = TRUE)} will return the first 13 elements (\code{a} through \code{m}). } \details{ \code{letters[grep("[a-m]", letters)]} and \code{letters[grepl("[a-m]", letters)]} both return the same thing, but more circuitously and more verbosely. The \code{stringr} package also provides an even more readable alternative, namely \code{str_subset()}, which should be preferred to versions using \code{str_detect()} and \code{str_which()}. } \section{Exceptions}{ Note that \code{x[grep(pattern, x)]} and \code{grep(pattern, x, value = TRUE)} are not \emph{completely} interchangeable when \code{x} is not character (most commonly, when \code{x} is a factor), because the output of the latter will be a character vector while the former remains a factor. It still may be preferable to refactor such code, as it may be faster to match the pattern on \code{levels(x)} and use that to subset instead. } \examples{ # will produce lints lint( text = "x[grep(pattern, x)]", linters = regex_subset_linter() ) lint( text = "x[stringr::str_which(x, pattern)]", linters = regex_subset_linter() ) # okay lint( text = "grep(pattern, x, value = TRUE)", linters = regex_subset_linter() ) lint( text = "stringr::str_subset(x, pattern)", linters = regex_subset_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=efficiency_linters]{efficiency}, \link[=regex_linters]{regex} } lintr/man/expect_length_linter.Rd0000644000176200001440000000210414752731051016654 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/expect_length_linter.R \name{expect_length_linter} \alias{expect_length_linter} \title{Require usage of \code{expect_length(x, n)} over \code{expect_equal(length(x), n)}} \usage{ expect_length_linter() } \description{ \code{\link[testthat:expect_length]{testthat::expect_length()}} exists specifically for testing the \code{\link[=length]{length()}} of an object. \code{\link[testthat:equality-expectations]{testthat::expect_equal()}} can also be used for such tests, but it is better to use the tailored function instead. } \examples{ # will produce lints lint( text = "expect_equal(length(x), 2L)", linters = expect_length_linter() ) # okay lint( text = "expect_length(x, 2L)", linters = expect_length_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat}, \link[=readability_linters]{readability} } lintr/man/expect_type_linter.Rd0000644000176200001440000000240214752731051016355 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/expect_type_linter.R \name{expect_type_linter} \alias{expect_type_linter} \title{Require usage of \code{expect_type(x, type)} over \code{expect_equal(typeof(x), type)}} \usage{ expect_type_linter() } \description{ \code{\link[testthat:inheritance-expectations]{testthat::expect_type()}} exists specifically for testing the storage type of objects. \code{\link[testthat:equality-expectations]{testthat::expect_equal()}}, \code{\link[testthat:equality-expectations]{testthat::expect_identical()}}, and \code{\link[testthat:logical-expectations]{testthat::expect_true()}} can also be used for such tests, but it is better to use the tailored function instead. } \examples{ # will produce lints lint( text = 'expect_equal(typeof(x), "double")', linters = expect_type_linter() ) lint( text = 'expect_identical(typeof(x), "double")', linters = expect_type_linter() ) # okay lint( text = 'expect_type(x, "double")', linters = expect_type_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat} } lintr/man/paren_body_linter.Rd0000644000176200001440000000141014752731051016144 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/paren_body_linter.R \name{paren_body_linter} \alias{paren_body_linter} \title{Parenthesis before body linter} \usage{ paren_body_linter() } \description{ Check that there is a space between right parenthesis and a body expression. } \examples{ # will produce lints lint( text = "function(x)x + 1", linters = paren_body_linter() ) # okay lint( text = "function(x) x + 1", linters = paren_body_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#parentheses} } } \section{Tags}{ \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/checkstyle_output.Rd0000644000176200001440000000073314752731051016232 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lint.R \name{checkstyle_output} \alias{checkstyle_output} \title{Checkstyle Report for lint results} \usage{ checkstyle_output(lints, filename = "lintr_results.xml") } \arguments{ \item{lints}{the linting results.} \item{filename}{the name of the output report} } \description{ Generate a report of the linting results using the \href{https://checkstyle.sourceforge.io}{Checkstyle} XML format. } lintr/man/system_file_linter.Rd0000644000176200001440000000203714752731051016353 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/system_file_linter.R \name{system_file_linter} \alias{system_file_linter} \title{Block usage of \code{file.path()} with \code{system.file()}} \usage{ system_file_linter() } \description{ \code{\link[=system.file]{system.file()}} has a \code{...} argument which, internally, is passed to \code{\link[=file.path]{file.path()}}, so including it in user code is repetitive. } \examples{ # will produce lints lint( text = 'system.file(file.path("path", "to", "data"), package = "foo")', linters = system_file_linter() ) lint( text = 'file.path(system.file(package = "foo"), "path", "to", "data")', linters = system_file_linter() ) # okay lint( text = 'system.file("path", "to", "data", package = "foo")', linters = system_file_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability} } lintr/man/quotes_linter.Rd0000644000176200001440000000225314752731051015350 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/quotes_linter.R \name{quotes_linter} \alias{quotes_linter} \title{Character string quote linter} \usage{ quotes_linter(delimiter = c("\\"", "'")) } \arguments{ \item{delimiter}{Which quote delimiter to accept. Defaults to the tidyverse default of \verb{"} (double-quoted strings).} } \description{ Check that the desired quote delimiter is used for string constants. } \examples{ # will produce lints lint( text = "c('a', 'b')", linters = quotes_linter() ) # okay lint( text = 'c("a", "b")', linters = quotes_linter() ) code_lines <- "paste0(x, '\"this is fine\"')" writeLines(code_lines) lint( text = code_lines, linters = quotes_linter() ) # okay lint( text = "c('a', 'b')", linters = quotes_linter(delimiter = "'") ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#character-vectors} } } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/redundant_ifelse_linter.Rd0000644000176200001440000000325414752731051017345 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/redundant_ifelse_linter.R \name{redundant_ifelse_linter} \alias{redundant_ifelse_linter} \title{Prevent \code{ifelse()} from being used to produce \code{TRUE}/\code{FALSE} or \code{1}/\code{0}} \usage{ redundant_ifelse_linter(allow10 = FALSE) } \arguments{ \item{allow10}{Logical, default \code{FALSE}. If \code{TRUE}, usage like \code{ifelse(x, 1, 0)} is allowed, i.e., only usage like \code{ifelse(x, TRUE, FALSE)} is linted.} } \description{ Expressions like \code{ifelse(x, TRUE, FALSE)} and \code{ifelse(x, FALSE, TRUE)} are redundant; just \code{x} or \code{!x} suffice in R code where logical vectors are a core data structure. \code{ifelse(x, 1, 0)} is also \code{as.numeric(x)}, but even this should be needed only rarely. } \examples{ # will produce lints lint( text = "ifelse(x >= 2.5, TRUE, FALSE)", linters = redundant_ifelse_linter() ) lint( text = "ifelse(x < 2.5, 1L, 0L)", linters = redundant_ifelse_linter() ) # okay lint( text = "x >= 2.5", linters = redundant_ifelse_linter() ) # Note that this is just to show the strict equivalent of the example above; # converting to integer is often unnecessary and the logical vector itself # should suffice. lint( text = "as.integer(x < 2.5)", linters = redundant_ifelse_linter() ) lint( text = "ifelse(x < 2.5, 1L, 0L)", linters = redundant_ifelse_linter(allow10 = TRUE) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=efficiency_linters]{efficiency} } lintr/man/nested_pipe_linter.Rd0000644000176200001440000000374414752731051016335 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/nested_pipe_linter.R \name{nested_pipe_linter} \alias{nested_pipe_linter} \title{Block usage of pipes nested inside other calls} \usage{ nested_pipe_linter( allow_inline = TRUE, allow_outer_calls = c("try", "tryCatch", "withCallingHandlers") ) } \arguments{ \item{allow_inline}{Logical, default \code{TRUE}, in which case only "inner" pipelines which span more than one line are linted. If \code{FALSE}, even "inner" pipelines that fit in one line are linted.} \item{allow_outer_calls}{Character vector dictating which "outer" calls to exempt from the requirement to unnest (see examples). Defaults to \code{\link[=try]{try()}}, \code{\link[=tryCatch]{tryCatch()}}, and \code{\link[=withCallingHandlers]{withCallingHandlers()}}.} } \description{ Nesting pipes harms readability; extract sub-steps to separate variables, append further pipeline steps, or otherwise refactor such usage away. } \examples{ # will produce lints code <- "df1 \%>\%\n inner_join(df2 \%>\%\n select(a, b)\n )" writeLines(code) lint( text = code, linters = nested_pipe_linter() ) lint( text = "df1 \%>\% inner_join(df2 \%>\% select(a, b))", linters = nested_pipe_linter(allow_inline = FALSE) ) lint( text = "tryCatch(x \%>\% filter(grp == 'a'), error = identity)", linters = nested_pipe_linter(allow_outer_calls = character()) ) # okay lint( text = "df1 \%>\% inner_join(df2 \%>\% select(a, b))", linters = nested_pipe_linter() ) code <- "df1 \%>\%\n inner_join(df2 \%>\%\n select(a, b)\n )" writeLines(code) lint( text = code, linters = nested_pipe_linter(allow_outer_calls = "inner_join") ) lint( text = "tryCatch(x \%>\% filter(grp == 'a'), error = identity)", linters = nested_pipe_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability} } lintr/man/one_call_pipe_linter.Rd0000644000176200001440000000263714752731051016627 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/one_call_pipe_linter.R \name{one_call_pipe_linter} \alias{one_call_pipe_linter} \title{Block single-call magrittr pipes} \usage{ one_call_pipe_linter() } \description{ Prefer using a plain call instead of a pipe with only one call, i.e. \code{1:10 \%>\% sum()} should instead be \code{sum(1:10)}. Note that calls in the first \verb{\%>\%} argument count. \code{rowSums(x) \%>\% max()} is OK because there are two total calls (\code{rowSums()} and \code{max()}). } \details{ Note also that un-"called" steps are \emph{not} counted, since they should be calls (see \code{\link[=pipe_call_linter]{pipe_call_linter()}}). } \examples{ # will produce lints lint( text = "(1:10) \%>\% sum()", linters = one_call_pipe_linter() ) lint( text = "DT \%>\% .[grp == 'a', sum(v)]", linters = one_call_pipe_linter() ) # okay lint( text = "rowSums(x) \%>\% mean()", linters = one_call_pipe_linter() ) lint( text = "DT[src == 'a', .N, by = grp] \%>\% .[N > 10]", linters = one_call_pipe_linter() ) # assignment pipe is exempted lint( text = "DF \%<>\% mutate(a = 2)", linters = one_call_pipe_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/pipes.html#short-pipes} } } \section{Tags}{ \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/consistency_linters.Rd0000644000176200001440000000340414752731051016553 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{consistency_linters} \alias{consistency_linters} \title{Consistency linters} \description{ Linters checking enforcing a consistent alternative if there are multiple syntactically valid ways to write something. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'consistency': \itemize{ \item{\code{\link{assignment_linter}}} \item{\code{\link{class_equals_linter}}} \item{\code{\link{comparison_negation_linter}}} \item{\code{\link{condition_message_linter}}} \item{\code{\link{consecutive_assertion_linter}}} \item{\code{\link{consecutive_mutate_linter}}} \item{\code{\link{function_argument_linter}}} \item{\code{\link{if_not_else_linter}}} \item{\code{\link{if_switch_linter}}} \item{\code{\link{implicit_integer_linter}}} \item{\code{\link{inner_combine_linter}}} \item{\code{\link{is_numeric_linter}}} \item{\code{\link{keyword_quote_linter}}} \item{\code{\link{length_levels_linter}}} \item{\code{\link{literal_coercion_linter}}} \item{\code{\link{nested_pipe_linter}}} \item{\code{\link{nrow_subset_linter}}} \item{\code{\link{numeric_leading_zero_linter}}} \item{\code{\link{nzchar_linter}}} \item{\code{\link{object_name_linter}}} \item{\code{\link{paste_linter}}} \item{\code{\link{print_linter}}} \item{\code{\link{quotes_linter}}} \item{\code{\link{redundant_ifelse_linter}}} \item{\code{\link{rep_len_linter}}} \item{\code{\link{scalar_in_linter}}} \item{\code{\link{seq_linter}}} \item{\code{\link{system_file_linter}}} \item{\code{\link{T_and_F_symbol_linter}}} \item{\code{\link{unnecessary_nesting_linter}}} \item{\code{\link{which_grepl_linter}}} \item{\code{\link{whitespace_linter}}} } } lintr/man/undesirable_function_linter.Rd0000644000176200001440000000401714752731051020232 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/undesirable_function_linter.R \name{undesirable_function_linter} \alias{undesirable_function_linter} \title{Undesirable function linter} \usage{ undesirable_function_linter( fun = default_undesirable_functions, symbol_is_undesirable = TRUE ) } \arguments{ \item{fun}{Named character vector. \code{names(fun)} correspond to undesirable functions, while the values give a description of why the function is undesirable. If \code{NA}, no additional information is given in the lint message. Defaults to \link{default_undesirable_functions}. To make small customizations to this list, use \code{\link[=modify_defaults]{modify_defaults()}}.} \item{symbol_is_undesirable}{Whether to consider the use of an undesirable function name as a symbol undesirable or not.} } \description{ Report the use of undesirable functions and suggest an alternative. } \examples{ # defaults for which functions are considered undesirable names(default_undesirable_functions) # will produce lints lint( text = "sapply(x, mean)", linters = undesirable_function_linter() ) lint( text = "log10(x)", linters = undesirable_function_linter(fun = c("log10" = NA)) ) lint( text = "log10(x)", linters = undesirable_function_linter(fun = c("log10" = "use log()")) ) lint( text = 'dir <- "path/to/a/directory"', linters = undesirable_function_linter(fun = c("dir" = NA)) ) # okay lint( text = "vapply(x, mean, FUN.VALUE = numeric(1))", linters = undesirable_function_linter() ) lint( text = "log(x, base = 10)", linters = undesirable_function_linter(fun = c("log10" = "use log()")) ) lint( text = 'dir <- "path/to/a/directory"', linters = undesirable_function_linter(fun = c("dir" = NA), symbol_is_undesirable = FALSE) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=robustness_linters]{robustness}, \link[=style_linters]{style} } lintr/man/expect_s4_class_linter.Rd0000644000176200001440000000216614752731051017116 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/expect_s4_class_linter.R \name{expect_s4_class_linter} \alias{expect_s4_class_linter} \title{Require usage of \code{expect_s4_class(x, k)} over \code{expect_true(is(x, k))}} \usage{ expect_s4_class_linter() } \description{ \code{\link[testthat:inheritance-expectations]{testthat::expect_s4_class()}} exists specifically for testing the class of S4 objects. \code{\link[testthat:logical-expectations]{testthat::expect_true()}} can also be used for such tests, but it is better to use the tailored function instead. } \examples{ # will produce lints lint( text = 'expect_true(is(x, "Matrix"))', linters = expect_s4_class_linter() ) # okay lint( text = 'expect_s4_class(x, "Matrix")', linters = expect_s4_class_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \code{\link[=expect_s3_class_linter]{expect_s3_class_linter()}} } } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat} } lintr/man/list_comparison_linter.Rd0000644000176200001440000000156214752731051017237 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/list_comparison_linter.R \name{list_comparison_linter} \alias{list_comparison_linter} \title{Block usage of comparison operators with known-list() functions like lapply} \usage{ list_comparison_linter() } \description{ Usage like \code{lapply(x, sum) > 10} is awkward because the list must first be coerced to a vector for comparison. A function like \code{\link[=vapply]{vapply()}} should be preferred. } \examples{ # will produce lints lint( text = "lapply(x, sum) > 10", linters = list_comparison_linter() ) # okay lint( text = "unlist(lapply(x, sum)) > 10", linters = list_comparison_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=common_mistakes_linters]{common_mistakes} } lintr/man/matrix_apply_linter.Rd0000644000176200001440000000201214752731051016532 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/matrix_apply_linter.R \name{matrix_apply_linter} \alias{matrix_apply_linter} \title{Require usage of \code{colSums(x)} or \code{rowSums(x)} over \code{apply(x, ., sum)}} \usage{ matrix_apply_linter() } \description{ \code{\link[=colSums]{colSums()}} and \code{\link[=rowSums]{rowSums()}} are clearer and more performant alternatives to \code{apply(x, 2, sum)} and \code{apply(x, 1, sum)} respectively in the case of 2D arrays, or matrices } \examples{ # will produce lints lint( text = "apply(x, 1, sum)", linters = matrix_apply_linter() ) lint( text = "apply(x, 2, sum)", linters = matrix_apply_linter() ) lint( text = "apply(x, 2, sum, na.rm = TRUE)", linters = matrix_apply_linter() ) lint( text = "apply(x, 2:4, sum)", linters = matrix_apply_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/ifelse_censor_linter.Rd0000644000176200001440000000222614752731051016650 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ifelse_censor_linter.R \name{ifelse_censor_linter} \alias{ifelse_censor_linter} \title{Block usage of \code{ifelse()} where \code{pmin()} or \code{pmax()} is more appropriate} \usage{ ifelse_censor_linter() } \description{ \code{ifelse(x > M, M, x)} is the same as \code{pmin(x, M)}, but harder to read and requires several passes over the vector. } \details{ The same goes for other similar ways to censor a vector, e.g. \code{ifelse(x <= M, x, M)} is \code{pmin(x, M)}, \code{ifelse(x < m, m, x)} is \code{pmax(x, m)}, and \code{ifelse(x >= m, x, m)} is \code{pmax(x, m)}. } \examples{ # will produce lints lint( text = "ifelse(5:1 < pi, 5:1, pi)", linters = ifelse_censor_linter() ) lint( text = "ifelse(x > 0, x, 0)", linters = ifelse_censor_linter() ) # okay lint( text = "pmin(5:1, pi)", linters = ifelse_censor_linter() ) lint( text = "pmax(x, 0)", linters = ifelse_censor_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=efficiency_linters]{efficiency} } lintr/man/figures/0000755000176200001440000000000014752763366013644 5ustar liggesuserslintr/man/figures/demo.gif0000644000176200001440000101740414752731051015250 0ustar liggesusersGIF89aÌ¢÷jýôßýóáýîÛþòÔõôÜÕÍ»ÕѼibKd]FýíÔõöÙ™–‡x—§o²ÿÕé¨Rn—™•e]Kêó×øëå[nyš¤k\EÜúþĺ¥VsŠ´«•õù帤Šg{„öæÔŠ”yŒ”‹ŸPXi•§ôÒñÛØ»¬£x{„ÕÑÃ’wd–Švˆ§µôìÚýøâi]Kãùýcm…ãöýûëÌj…‰çÖºÖÎÄŠ”†«ekDds¸ÀžLcjÃËCdlœÃÒM{£¸ØñZ^PŒ¹ã;^f¾hˆ8{Qˆªf]mÿÖøÛi”¯õü–Éñ%¹!ÿ NETSCAPE2.0!ùÿ,Ì¢ÿH° Áƒ*\Ȱ¡C,&T1℉3j”ȱ£Ç CŠYq#É“(Sª\ɲ¥Ë—aÊœ9òÕc缂IÃŽ¾„HÔ¤Q…3$­8º0‘Ó§LiÆ”JµªÕ«X³jÝʵ«Vgæ8`$W®¥ WA+:€ŠdË0´DY¸#E£$!:¡¨KWˆ~Ҍу j&˜IåÈ ƒ2knÃÙ«çÏ C‹M—tÔ©¦S#5—N)C_Š ÈF“¦DUh€,âaÆ)ŠÐLƒ!Í)¤@ã*ÌŠ’AœJ!bŠ˜'Oİ`ÿ!Vlây+@SèÀ)ÞÔ„(I ‰aá[0ó“!¬ha’$üÉ0Û  #š r‘jVhá…f¨!†ÞdCN7Ýl#"N|Ý5 &Ö²°53ŠøR‹lÒ(’Ôx,C†¦¨À#&DØ’„ô2£@˜Ä–Ð 2 #Ð6 R©7æCÎaX’ƒ%:º˜cŽ68‘cŽ7Xj&•Ü8´"W`¥@XM¨iÆ‹ z uÚ†€*(jƒj¨h݈Â6æˆ΄C•±@Qv-ÅÄ)bE¯(âÆ"†"8âˆAà0J,A TÆe¡îÿ@ȧ `jD’ÉàÆOÛh©eÞ“9\ŠIŽ31èb¦›˜‰Â°jšÃ›>÷Æœ P'#n!ÍœÁO„¢×ÈF&¶€ ŒFj%‘!Î$$#¸®øÆ>úñ€7.F¤1ˆL¤"ÉÈ…Dá‘„`¼ØÈJZò’|ÄdT¸¨ÉNzò“ d#'BÉL†ò”¨LeÑTÉÊVºò•°Œ¥e9KZÚr•·Ì¥.wÉË^âÒ—À ¦0‡IÌbó˜ÈL¦)•ÉÌf:ó™Ë„¦4§IÍjZóšØÌ¦6£‘Znó›Ü§8ÇIÎrzÓœçü%:×ÉÎvºóðŒ§<çIÏtÖóžáħ>÷ÉÿÏ~æÓŸÿ¨@JЂô M¨BÊІªÓ¡¨D'JÑŠZô¢öĨF7ÊÑŽzô£ }hHGJÒ’šô¤(M©JWÊÒ–º4£/iLgJÓšÚô¦8Í©NwÊÓžúô§@ ªP‡JÔ¢õ¨HMªR—ÊT˜6õ©PªT§JÕªZõªXͪS·ÊU­zõ«` «XÇJÖ²šõ¬hM«Z×ÊÖ¶ºõ­p«\çJ׺Úõ®2Å«^÷Ê×¾úµ« ¬`PÂö°ˆÍkbËØÆ:ö±¬b +ÙÊZö²”Ŭf7ËÙÎzö³  ­hGKÚÒšö´¨Míd«ÚÖºöµ°­lgKÛÚÿÚö¶¸Í­nwËÛÞúö·À ®p‡KÜâ²Ö¸ÈM®r—ËÜæ:÷¹«…®t§KÝêZ÷ºØÍlv·ËÝîz÷»Ç¯xµ;Þòš÷¼èM¯z×]öº÷½á…¯|ç_úÚ÷¾øÍ¯~÷ËÆöò÷¿°€LàøÀNp}Ìà;øÁް„'Lá [øÂΰ†Ìá {øÃ ±ˆGLâ›øÄ(N±ŠWÌâw˜¼.ޱeLãÏØÆ8αŽwÌãûøÅ?²‡Lä"ùÈHN²’—Ìä&;ùÉP†q”§Lå*[ùÊXβ–·Ìå.{ùË`³˜ÇLæ2›ùÌhN³š×Ìæ6»ùÿÍp޳œ¥<ç:ÛÈtÆóõ¼ç>û9Ï4 -èBúЈN4¡ÍèF;úÑŽ´¤'MéJ[úҘδ¦7ÍéN{úÓ|µ¨GMêR›úÔ¨Nµª½êV»úհ޵¬gMëZÛúָε®wÍë^ûú×À¶°‡MìbûØÈN¶²—Íìf;ûÙÐŽv¨¥MíjGûÆØž¶¶­Íín{ûÛà·¸ÇMîl—ûÜèN·º×Íîv»ûÝðŽ·¼çMïzÛÛÜø¾·¾÷Íï~ûûßÏwÀ.p‚üàO¸ÂÎð†;üá7gÁ#NñŠ[üâÏ8«5ÎñŽ{üã ¹ÈGNò—üä(ÿß¶ÊWžò–³Üå0ùÄg.óšÛüæ/ǹÎwnržûœæ?z7.ô¢çÜèHOºÒ—Îô¦;èOºÔ§Nõª[ýêX?zÖ·Îõ®{ýë`»ØÇNö²›ýìhO»Ú×Îö¶»ýíp»ÜçN÷º÷ÜîxÏûÝõÎ÷¾ûýï{¼àµ>øÂþðˆO¼âÏx¨7þñ¼ä'OùÊ[þò˜w|æ7ÏùÎ{þó =áEOúÒ›þô¨O½êWÏúÖ»þõ°½ìgOûÚkÞö¸Ï½îwÏûÞûþ÷À¾ðo?üÀÿøÈO¾òG¿üæ;ÿùоô§O}â[¿úØÏ¾ö·}î{Ÿùß¿ÔøÇß}ò›ÿüèO¿ú×ÿ¿ò³ÿýð¿üÁ?÷Ó¿þøÏÿýõÏÿþûÿÿ€8€X€x€˜€ ¸€ûg ø€8Xx˜¸Øø‚"8‚$X‚&x‚(˜‚*¸‚,Ø‚.ø‚0ƒÆ‚2Xƒ6xƒ8˜ƒ:¸ƒ ȃ>øƒ@„B8„4H„Fx„H˜„J¸„LØ„Nø„P…R8…TX…Vx…X˜…Z¸…\Ø…^ø…`†b8†dX†fx†h˜†j¸†l؆nø†Ý!ùK,, „ !ù,@ÿl3àÀƒ P ¡CƒDD8‘EÅ‹¡dL¤c!,‰.ÎIˆñ ž ”\¹Q`|[PQÈt1J–l¦lXÆ×ª‹.B,“ ´„a–ôÂBÆ… ‹¸P¸øŠÆ+ ñ¼ºšu«Î”LÊ,Úõse-Zs”Åi¥e–‡ˆ`ô ×©‹ D5™(ck«¶ÄúÕ"çkÄÀ*W 3‹C`mŒ¹…ÈM/ ùñC¥b(ª¬ÚDœÓSÅe²T ZrË•ñ$Ju¢ò½`¶‚ Ô9À°FZøªú³Ë–1«vi<,¶L#’6 ‚RÉÖÆa*_†Bkæi¾þؘ2 –XÒàËcå)Ð0Fi™ô\z"G7¡¦2ÄsôÉZ ‰ T†1šfÌ«$èWv ‘FÃ*;ítÁ…O,´†dI´Ð"A¦%”Ä‰Ž˜˜"kA×b€FG’ ›ÍÄN8æ(#Œ;Öh£Ž@2äbبD&©dºpá’P²4d”)@eK ÅhÑ•Z:!ù,8€ÿ0@ÐÀÀ‚*\Ȱ¡Ã‡8±"ʼnN°°x‘cà #ŠI²¤CŽQj¬ˆ¥Ë AT™Ò¤Í›8Ov$xщ.2M&š)/(©&< €!§Ó§#9¾"˜†À yòð «#T8¥0tWª+A ªÛ· '0 BÂAUy´¼0+.+ÚèLvÙQ+"FaU ®ã·'pl€ãÑ„UÌPäÂ~ EbÁ)Sç´¸ŠÐƉ4‚dÀ %ÎBC3À˜-™“Ñ1ÑXµq‘m&¼¢‘`‹þÐvb†‚ ‚‹î­…Àñ‚†X|‡wzÑÀ`"æê‘ÁÓCHq8éù\˜àªTãó“çxì˜(ù÷Hg<’„ .dÉ9¢PŽü¢ß„KÑ”Rrñ‚ÈXÊå'Ð!–dá…)¡¢!Q)•⊑˜âE_E,ÖÑJ.¦øŸ€*eã ×N<‘X@&™#Ž™Áè¢C!ù,¼ÿHP`Aƒ*\XЀC¶‘H1ÀC °¸Å ‹„ ˆŒH²bE#M–”ø°¥K—a¾ä8°eÌ™W(2äD†+ÂXi1'I'l¦,9†**ZVª XõT8ÃCMœ3Y|t¨¨ãÀU€€Æ¨à†¨I‡ ÌÊ!äæeÁ28¦$Ùê±oJ1ºÌ•¢êÁ” ¿g¤J2õàRƒ+Áx<°œ8˜-üYÀÖ„¢`ÁÉÕQšdt 2IæD<ÄU&0M )` ”ä MЧ6ñ<<Òa‰)4$ñt KiWžjÀZN 4,ˆS2.D ÿÊ™(Ì0â¢Ù°1ÁØ4i¨aIIJÝbÔ%…Æ ƒŸL2ˆCƼR m øÆ.¡eÐ*|¦0qB+  ,9¼Ñh_‘a+‡™Px’À)¦¼qÂ"åRáM9¹DŽ7ÛhCN:¸ä.E (€7æHâMΈaŽ9ÝHsÃ@L,óÆ_áhM|å*´œ #)áÁ Àà)ÇhX<Ö aB–LÀ“írçC F¨[eÜ8Ð72QC#M(R J•À'h/†Ñ5˜åÐ4 ôH—7q"’KæèB9.‘M“Ju¥C¤'€«)Hÿ±£9Å™¸à¥µ,! 0´a 1PÐ%ŠèjVA–uÑÅ ;´¡ 3ÌómŸ‰$Á­ÌÚW ™©¬G[|PÐA¼!… nˆáÐ# Éà Œ¨ò´Shñ`'«|fL¶}n‹ã „¢Œº`-5KC5pm!Ç@ÒXÁÞ§R­T°ˆ‚ÌÐÖI“À@ÎÈÐ Rhã#9ݨêŒC7xS„7iãPj·äÌ2ß(…T¯«`y$E´BSK(ÿc-Dñ”XF"çÂH€xpm#zÀ“ŠÃEïEÖ.pyòäå®02dGÀ1ë ­ m «iòºN/§fÍÔÓçúõ×ó·'PŸBOô÷©÷\oúeňOþ( Lìè`u `nûèà„ Z_… !ù,° ÿÈ¢ Áƒ*\ˆ°¡Ã‚eV`ID‘"Ç$lˆc"^z(ø´«Ì*“‹jP@¨H@J¢R§A8Cú)¹+É* ã´RE+TDQͪ%…‘: D°ª@ÃVÑ(€cЦZ:ÆÙ”AP¦³ƒ&”yµcUJ„z‘Rà(0KŠz:m'·ejAiøÂW(GÝРµSD‚ M©jjO3z*V­‘›/¶ÃYr0 · ›4a Æ k?‚QvÈmþºhp£ñ…9ûw¨±xÐäiNÀ¸|0‘Ø)Tßà­ÂÛ¶ms ßÞœºy…åÏ_€0 !ù,¶ÿ H° Áƒ (ÈB  ˜ ¡Å‹3jÜ8¢Çˆ |²$žS2tH$•0cÊÄØÒ¥È´‚$Ò™¨$È-Ð$ŽœypÅB†G <h‹¨Ó§0)²Œh¢Ó„9\|r„'ÏÍ’§È8ˆ˜9PÕP`ÅÀ XKK·nA£<òôáH¤¬~T‡Ð9x†"­µ€ÌYÈ콸M²å§+hi™Qà‚*Z3Ì jÔæj¨¹xÑa…e]æØMÛìÛ)Mõš ” N4–HìàfdVkŸäxÅ-™óç‡Ðò§€à8Ž .=1kz&ÿ…ît›6IäÓŒ³jUŠE(‡C$["ÃXºªš‘Š À¦ž )Id‘sêM5‘uOqAAd )¤ p2 LDXŒŒ2JE,%(Ð=qŠ9“ ¶uNÍ8Ñ3S0¸àEŽLDÁ¤\‰b/‚dÑ :¼‘B ød¢’2qW“P> ©%HB×%B‡¨XÔ!@ÞG˜y¤àC>A´å \²£‰P}‰™Îte›WÁɈŸ-#‰têi'syVÉç¢=6úH Rš¦¤ií¹hM¥QZ§PêYIhš@zi¤jjjê©•~Šêª¬*µÑH!ù,¶ÿ€  Áƒ*\hpÀÀ†,F`°Í@(jÜȱ£G….Jœ8²¤C‘(JüȲ#A$E6\±Ã@Ö8sê„)Ò!†(_6Äà!¨Ä Qz%‘ÈUÐV`\¹“!Æ‚£86:8¡ª×¯Vìš%•k)GÅC‹#E`Q˜;hÐEˆªÒHZ6a› Pƒ R”Ûð²ß¾wžÌ¸KšŒ‘~…ªQPE¸Ä’¥¨.ÝA~ Vò%«Ydݸ½ž-9€„ ÑFÅYekI`d-HÁMÐF(Qéô\ŽŠhãÜFNºuP bóDÁUĹœÿPRð—Ï  ×´Ûë‘»‘#— ¾}b•„„ð‡m*‚³Å%ua zäaŦùQ×}`ɧ „V4Á5'ìÒ…/,³A4‚l2LrxÄa”àдL0"n4è`…™R KÑøÑ]ÄY%GŒ@dÑ@‘ 0ˆ {Œ¦(ÄÍ!5ÒEHŠá:–#G)ä ¥tÉÓH9TÐ#Lv3]Àf,q!§ 'YÔ/Œ}òˆŒ~t)— ‘å õF¥y‘›hž)R&UŠÒ–:RzS¢rH¢'™)Ó` ©)©D¦zi骗ʘ©JU [)…†”›‹ž:™·¦™;µ±HPŒª*”_©¢ebÌ.ë, ÐFû+°^!V!Z°â§UºFDh·1ÕJ-d!‰Ê-~¸²ê¬ºÄ’:î»ðZ7m¼ôÆ{lNA!ù, ÿH° Áƒ$ @`!CY0l3±bÃ/jŒ¨@"Ç?Š™1¤@…'¨D’¤Ë—_í0F°Ö+˜ ”ÈÒ⊙Q¶¬¨Ð‰„žg„YÔäP’ 1<-˜EÎÁ_M=â܊Й9х䀹.Ö0]Ó…:¦. Òùur˜ò›À/Œy?• g•mÌÁ1T ‹%Λ”Ie,Ð%”ŠÀ «X(‚NàÒ\%4¹I]ÕÓžñatDÿ€"Q¡ÝIZR··P|÷Äg ÝÂPz&ô¡MR‘CÅVâ%8Ä!Q‰f†d=¡BJÒŽô¤&-©…ºP¢ T¤/iJë) à&,*e)0pÓ—®„ ªiʰ0@–T]õÉiH=:Ó„ƒ‘d†SNÆAIw¹¨0q­0Á7º2†GJ:¨5õ¬hÍÊfHpL‘ÆR€,ã söú…ªš¡ˆAV±P@ s%†]òŠHä! ˆAf±Ã y@C 1°ŒÇR$ŠÕ,C”@ƒ4¶ ÒÂqú Út'©p) ŦÿÊT©i5a Öe• uo ©!6¢¡˜P„/>©A7üÇ· èˆFe âÖ"µ˜‚Ìä)P=d´švCˆfw¨˜Ü¦xÝÞQ {´®s]%8L‚'(hn÷Ë_(2P ЭÂt=á ”0%*q9ó™€.4°™«‚s±@`°Lê@ådF³†´Ì,²"-A kø¿øðB¼‚>TX!¬@!E¤Àû»mwŒÏ8À™…,£D&$ ³xA2à,ÚÅÀ–t;e7¬"“ݰWÇ*:@àPÂQªÐÊ‚½Œ À—ÃÜwîÿHEVp >Çx^j ^e‘­@Q„9H[0An‡8ì>˜Ê)T`[´ÊPo]/A:¼Vý„ðä(Á)\:ƒe3L  I-€02 ìœgþÂôž¥ò)ˆf¨ZÀ í ”OÂkd@¸Í¶ð!"Á VzÀ\ A"áAÒ¨öÇ,I½@‘¸Éö ª¥ n› s¤€!½…ÁÕúݸåH*yy’=\ ̈‚É*Ï‚Áø†§‚òow*„”0øfÂAðc\ߎèK.r”nº⎀HEQÉ lÆÞ:¾5ÈG `¡ÝÁÿÞ»lKò–»\ä2Õ(¿÷òšÛüæ8Ïù[Wh‚Ðk¼Û³œ~·5€íx<>ï…O|Bå®xÄ$84Z;Ôßøz¾¢ `náÿ`‚ÃS>ñèPRA»ØgaACQ(0+ZL¢,6fÊíLÿXÌPEô6-cû€z±ä¶xáý†0púÑg¨õ…‘ÂN’’@pûó’ÿy{«$êrÌÓõ%,Hàq€b¦‚!p÷á´ây Ø‹£ka@3pæ G‘Üo· Èm—  ‘#1Xö„±,_q6gA! Ðíæ3 Š€rŠ“fP4pp&gªæm!o€—}x׌`(q@X\Ø ×µ °ÿÆ$@YR6)PA ô¦ ¤à\`U&áA 4V³ ˆc6_»°±–z€ ´p#ó–ð„§6Šè ±`$8ðvN¡jŽ÷‹ï&%@mÛVdBBŒ°n #qGµ;Hm‚ Pl—Um2À:Ë{Ç8n0€‹ç1ɸH‘;07@ŒŠÂ ±n\X\%1´@moDˆçuPpqçpåq-sg GŽÐN“g¤TqÞd.0p ‰J2…ì´pÙ¸%OgKˆ¦y™VJø‘.‹ÀH’%™’&Ù’Ðl,96ç <Õÿ³’1é:¹“ÅÂD%vF5’>”UEVϦ$Ff{UÈ’=©D÷EI蓇'¥P5D‰LàŠC^GAœ7°  ûó8qЖeÀm2P NÀ(\àa›Kõ¸§È¬zg@|[5_ná×Ò%$‚+nÕ’$@^ðØÒVº/ЍtˆRb ‘óoéb‘Ðt>§Ó»qæ”. k ÿáJ:‹×"¾éM­´ùHbQ]Å»¤Š"áN©JæâM §¨) M¤ÁŠ:O¾õFsøÄ‘w¦Ë si÷’ • ¡¸!KVÒ0 ì›”>xà²ÂQdÁu'ÁºâÀTg¼i”,üw.yT”J“-fQÊÖ·ó· Ê•ÜÊa|Gm×Fj—Œ`AÐÉÉw¤:Né”滺Ôlö+@’ •!2Þ Çß,xr ËŒ2ŽBuÁÈLôGñLÏóìÃã´Â—û ˃Âxõ Ð Íu ÝO7ñ‰a¡6)3:ñÐ\'¹@oI)ï{[€€³ @dTEQ ܨÑO'€Õô$á ÑÿP ŸÓ=˜TÇ  òX Z €!… ,Ïx<š€²°Q ÿ|9µ }í'_ ^2S Ôòü‹ä*Fpè‡9@ÀÁX§Ú1§6,ª2ãb`Ò´C,Ö)L9CÐ/` ‡àeÍ?m¨0×J<(iÈLa*¡×cÍ׈ç°Àéòu*k`ÙŒP·¬¢¯ÖØ¢š¯¦BLÙGwÏ\}ðØÅpÆ´iìt§lÍË»¬t4ù`J;ÏÜF+y¼ÎBÜÛ{SÝÜÌtÏ ÝÑ]Ý“mÝ}½×ÝI§ ÿÐUžic•EúRPÌÝW,YBA¢{¯Û‘04®__X|Á—™,!šq@A®àA!ÄçY¡|Q Í÷ÊèÍ’¥ð Ÿò"³Œ +êiž ` ¼L}ùY_S¹Pé‰JOžb:›qŸ­‚^4$r@€~y€ËíÐ.Œ~m´±½jÐÊOj,c.¸ƒ8ζÛz pZ@§¡eÉà 8Ã@'ƒ†@„Fˆ|2² ¾“1`£¢0¶û#…iX ×°‡¹8Ém¸ ÚÁ«J^ÁUÄj D0%£¬foWÚíRˆÚâS¾SÛ»w=94[¶ŽküwŠt€ÄõÖ ´4Ýÿ;äh«¶æ™A¨¦}»¨INݽíÚœ€) a¸µÊÖéXHä¨bq+Ìá0"+X`Ú%áêÈR[pͼ}«ÛÌælÜñÄKæÌÖ‰KÆ=Ïý±ÂM×ëEYµ~çÓ­ì´LÇgÇ–þ⋼ÚÉÎìï¦ AÉGΙ¥ÏÂíTN_0Ñ?±<ÙÎ y"5EŸ¼îÑ>v_qp¢LâÕAÞ lï!— ˜ØÃ€ÒÜ8pé§ÀÖÄE}›mj*ä®Q¼€Ó¤) 6=š-‘WÎ ;µñûq *¢ÜVİ!Œy×D·`ã?Rj6xÿ`ÛÉyÙ8à NÕOm9J瀠ÒÄ£>Zàa=‰P]má^'pôCJ¹¡ ‰¨‡úòøÄ´Ë,·¬a ï1VG=1ª ”KýhGabjü©ú°'Qn0 .õö¤õJ9FpgkEö‘µg“fƒÀGVÛ]ÀdHÖKæ-=áÇ^HIžu÷P­( àv¯PZ¤”#|_´½ ÅP â—çZê¶p«nëÂPêÂ,j€Úž1k îÆà €À f²ù5—ˆÔتÓÌAXù¹œPƒ¸ tüŽ·ˆº=ÂÏÓ‰¼Q%µmêûƒ›p„ÿ÷ŠfW •J ¿óFÐ[Ò]…ìtš&G}ñpÚÏîn¡¸”ßîì®rÕ®ìÖ»ì;fþñ/íùÿÿˆWƒüíÿou!¸lâàãBqÿï’y@2Ý/ +ÍÿöŸÿØ­A@2ðƒ3 XfÿÿŸÿè®`w }è•Ãÿ/ÿd÷e¡ ÊøÿK(mAt ”þÿÿŠ÷HÍB+mÿÿÿâ—8oªÿoçP×9Ë{çvxÝoÿùÿÿöÿÿ-ÇSÞnÿwnçWì|Iÿÿö?we ‘ÿOËS÷ÿ¶ŽuZ'ÿùÿÿV‰éüÿùŸÿ,öÿóŒ Ëgÿ Íÿ‰' sNëùÏÿòí#iÚùÿoçYñ8~€ üoÿÿ?Ùß»¿ÿOíùÿÿùoÿW÷ Ï•áŒ$°|L…/ÿЮ+nO䑉@óì’ÀBÅAaA³ÝÄ „ÆxÆ &O–‹G S€-§ p’ÄI„ážtª!ŽÒxˆö_slËÇP¾"€Ò0Ûž¶‰3p ÖáCÎI }5„t5™À¹Íá$ÐAI³–€|ÍÓŠeWàáÙ@’ Þ ô ¢ Zå@#ýQ™¸*  }!„žÜ"âs72T,a4Þ3=LÑ#?¸s8UH”Ë%t  ûNÿ´h° {áe^I&fâY„&k² nx 'l‚lB'4Á/ÚÀ>3(S Ë ¸BqÏ@„+Ò(öŸÿÆ+ò+ÁBíÏâ•Ï‚ ÎA {±¤Q3~Š-ÕŒÀû-X2ð®Øb ½. ±6TûÂ/èC/Ùà ÂÄ/Ëü‚À² ûS 0Œb_Òh8ƒ`ÿ-Ç3;ð3ÛÀ BSÏeð¦•,À³9Q35î\Í8Ð4Iàr“ÌDIÁö!0>å30S(o³ ~2õ¢wCEÏà ‚a!]XR`ËIî<ÒIƒ@ˆ¢)À2;«ª¶3 Zÿ€,¸ó;Z Í"°0‡Ø‰<å}(: a=t1=ú Øã—%Ðzd£uíâ&j">Ûð6æ€é³>t²/æà ð/º° b?Ì©‚ãRýƒ ÄÌ(!4Ônç@7Î@릵ŠC2¤0Ä6¤9P³r8³@ „0DÔ@¬‘;ü—¦s% •2à4)>ï²EÀ’E[,ÛðFÛP/Îp7ÛðÀ7j¤S² Ðp”V<IÕfÿ6×IΞ¾×òtqÐ wpŽR]Þ‘KÀ@Ká päXþºäÑ@ ’K…¢T ubL7 Lº°>*‘Ñ0Î$ÆT'aLÒ´P5à :ëK­ËÒI~`ÿ}ûô§´ƒH‹ÌE“Ñ%uPA2RÒIƒ`ÿI½q„OûNQÁÎ ËSRòJÇÒ(öÿÿ.IÒ8ÿOËÜŸp„ÿÿÿŸÿÿÿÿÿŸÿÿÿÿÿÿÿÿoÿÿÿÿÿÿÿùÿÿÿŸÿÒþÿÿŸÿÿÿÿÿÿÿÿ[!ù,IW+” *@° Áƒ*\Ȱ¡Ã„<œH±¢E†/jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœ€Mš0ÜÄé’O”;®´I€P E’,šTéȈ,H5ê´ªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓ¾lÂT-F¢nãZl+— Tºrï6­[ð._„A«!ù,` @ q€‚ƒ„…†‡ˆ‰Šƒ‹‘’“ˆŽ”™š‰–—›Ÿ , ¥”¦©ª¨ª®‡—±¯³Œ±ž´¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ©|O¶¤Ð‚IµÖ‚¬¶ÛÜÔßÔÛ·ã˜âà¬êëß!ù,` @ m€‚ƒ„…†‡ˆ‰ŠƒŽ‹‘’ˆŽ“—˜”•™žŸ•¢Ÿ¤“¡¢¥ª‹§,«¯‰¡°´Œ­µ¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎϵœÐƒMÒ–Ô·Ô‚ÛÜݳܲáß¶æ…ÓÜ!ù,à’ÿ  ÁƒTȰaBJ Ñ¡‰XL„ȱ¢ÂŒCN°H²`G%S&ið¤Ë“mD²dñGŠgªDxs ‰œ%ËЩ“àM “¸‰ˆG™EìT¸c$ɪP‹¾ÜŠR¡7s’À¬nwË[QAa+»è‚©щŽ\‚µqÐéØ:{\Â*àÅ¥X5‡·-¢ŸmŠ¡h»tb×Ðêd{KÞòêV:N(ž8£WÊaªè„pŸ]´R ¼RQD折ìW,¨Øïp!„]àͼNðeM°™ŽB§A†q—×W®@Ø%KЋ]B DpBR~È@0j ”æ¾D…nAª— ƒ®š ޱŒ{ò 8d½¾5›WÃ… 8°Æn9ƶ È¥òÅ.qÄÜlxߊ‰…”]0ã*Ϙ•ÒÍò¿N‚]yj¹NûZ‹Ù‘ lu4!¥•ל`éXgÿËά–kèËfîxÌlM3›÷\ÞŒÞÙ˾MŸMèBW–¢ª,‹ ÍèFÃÕÏ1Þ‰£'MéÎZÒ•Î4¥Ï§gÖXÓšu¡A·jBzϧµª#¶syÑæÅe˜WMëHŸ$H¹r­wÍëG«’Î÷|-‚ÏzÏôÚʪyS¬áùgÌúy­Åm³ÝgF&¤kNkHz›Vjó¶ÓÈ&/T΋eo/;–•Ìã—¹[m•€ÔÝæ>7CŠS3{Ôàž5ZKïo§„¹XÕkË=lt'°Ë[¿ý½³ô׆[xRo±0l ("¯ ÏĦzïÕÌ!d. ŽÙ<É*tÿ|´/wa»™‚K4†UkPÆ šAXˆÌ(Ѱ…¹°Ùܼ¨°èBhá-EÂ?_¾„*ÖB‹å"²ÍDh@Þ¢åJ6¢nñt, –΢Œ¡²¾[D%w ß© •…ne/ià«°ZÇK%’)¨ãkу`§8æE —UäQPfå  .t<§À‘%K_&:`„ù(!…ÐÄ!TL °²Á :à@ïvS€0_ÎP=† ,‚' bLh)°gŸsYp(£_Ê“pyZÀXÿS>g Kà(’ t^Öó?€b=\8 ;Yeà~) CÂŒ@Hû¦bP [ÀK"‚sB÷y5‡5#ÈjºÅtòâsp  «° J0 µ~Ò5«à  01.Ðq/QN(qU76wç°puµÓÀE WÀÌ”»Ðð t Pn6"RÐ-P ±ŒseÐ O&g•´;H_à%‹5·$„À *0’` d@ {@A j’ögÈØB[R µàaQÖ’ h&` ¥z‰7W)CCkÅ5;°—p ÿaC 6û8LÎ&\+PªP Y3€ '¾ ÍàJ:§<œ@;]#ˆ@¹‘Q9;Cf‰äsãNH VÐMð2ð·<ùˆÊ •l#‚56 ÃX °sÖ¨[‡•#²¥o5‹Ð•#ðA²7 R0éw·Bx {¬Ð9 ÀvŒ©`j“$´ Kr¤@ Á‘{ˆ€A7HT„P ÐF¾%5ƒ†Æ·-”àÐ|ðÒ‰…@ˆ9•xh•ýè—_+Ÿp"±Ðdäº} V{0Hè¢KèeV+±Ë~´Ã’ PE{E°Àbœk ÿØGC$Qàd ™Õˆ…‰tÇ9'øOh‹uMUL‰áN3±|9hpÑ€r‘mViM38néXŸÕ‹ûæŸX˜J;91x‘rQ ˜4Ÿgj°¤üø—}—…بG!°Sq-——¦æzõ·€JlÚ‚qun.Á ºÆðò‚Ïôj7úz(bŸ/:O“io*êl  a(6x¥'Y‡!XÕVS„Ú¤L/Jp*mÃf…' (cjëØKšQk7€hJtî–Ñ 8èOA p–¦tÊv€èN†2 b&›uZ§é‰™D‹§5áár:gº¨¾ÿ9O¶¥p#ö(x'J>ʨ˜Š,KÊ¢ˆäÏ'’ ž3Zfy–©iêK(’$! S°Ðt ­Z¦ðiª WgQvK ¡u®gHÞ²›¶º~ÚQ¯w©Á*¬ÀŠ£°`–æq"_p¬¦Š]—Ä«ÅQäÔ´§¨ÒÚ|n…6)Q µ÷eêİ=á$òÙ­°w¦ x[Pa(=R›&yµ` ñÇ®$WKc¸ ž§£±ÚA¤üÚ®a"€¿qf8aà ó•Ms¤Mz°·†@ñ+Ò‰¢ÌQRç)]–j]†±Ó:"‰ž=j‘&Û²©W²Û²¶Ú‚<Ú¢2ÿ;³ŒG³7›©0ê¤;û§Dñ³B«“ž6´;;â%™(Á¤" Üj´Gw‰«'ŠXûe…cÓˆPµNã!ú{kÁO‹¡×µGg¯?U‚'ÁWÃÀzh›0€ ¨ÐT¾‚hï‚ XS´q›©§ŠÁ{vc>:Û·tZœ 0H0f¸Òjȸ@«mœj±‹° j‹•˨êVätR¹</'Qƒ” ºH Qe*¦Ë®†ÈãˆQ|·ºuê) Ô§gC8"»<˜&¹¸ºë­ñÒü–ù¬¿ËkˆG"v¼¶ZDzP¤ÌÛo:V¶s:½È Ø{t£º½tÊ‚ëÖº}Þ»k"›nãÛ¯¥{¾ê»¾ìÛ¾îû¾ð¿ò;¿ô[¿ö{¿ø›¿ú»¿üÛ¿þû¿À<À\À¿$vÀª&} ÜÀüÀÁ<ÁL]Ëu”•ÔP >…,  •„[q öó5ƒ¡âËð3S@ĸ9ÄÀ? D­áO–«BeKÓ4|·[Q Ä7 Fºà )yq‡ÄE¬,p·…‹·j•|, Žÿy¹¦¤¯–oGk¼|;r8ü®½(“Z¬pFÚ§ð i^\Áš«»!ù,`8€……OM†Š‹Œ…N‚Ž”‹!ù,`8€„…I…‰ŠŒŽ‹!ù,`8€‚…M‰Š‹ŒN‚Ž”Ž!ù,`8€„…I…‰ŠŒŽ‹!ù,`8€‚…M‰Š‹ŒN‚Ž”Ž!ù,`8€„…I…‰ŠŒŽ‹!ù,`8Þhÿ ° Áƒ*\Ȱ¡Ã‡#JœH±¢Å†MhÔx±£Ç CŠiÉ“(Sª\™Ò$Ë—0cÊ\9!ÀF'6gêÜɳ'Â} J´e΢H“*u8h€¥P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_¾×æSÎÛDwJ½ºõéA%6½ž½"öë Úÿþ“»ùóÛÑ«§N‘@úïÕН ¿þúõíïß7¨?~øçjÙ'à€åXRêñ‡ PîÇÖ€.T’Ç”s VÈB„‚W”}š$"¢ˆb8 Ý1$Šöá1‡ ²˜ t)¨…ŠUCŽxÑ#ЏáÇzBLø²JP¬P†¬Òˆ“«¬Š…ehSx†ÆØÒâ040hw$`Hi‰©bŒBMEBÂé•s4áF'Š@@$‘ ”щ#RÚòJ-Z¤¢ †vò Œ €Ç+‹nÉL¦Èi-yÊi˜„ %œ»”©Ñ˜n´é+LÿºC«pé++Ô(;4±ˆ£ØñJÃ*]28k*Ì„ú骷®ðÓŸæŠi«HaHÃ,ž¬@  JA#Æ€’e,9Ä(ð0Ø^ Láù+èÒÑÀ„ÏžÎÔ;€ÔON0Ç Ô£ˆ4¸Œ·ßÙ'oêék߈ÕkK;²‹‘Þ iŠj¸Ì½1P.ÌýÜ‹âXL¼” ¤]° <& ¡J ËY-F·ß}çRL°ðP¥T$mYéÔf¬rùbqexC*†4©cv«(Ã>¸>×°\ÿÒÎvU®rmA‡[Áæü %€2(IIÚ›B¬E0 :ªQœ{ƒæÃ‚0:KB7º68;ÒqÄÁF]$íŒAc,5Ƥ™Ñnc¬N~á«ÑYCŒW#ÇpÆ<²› d®ê˜Å³™îdç—âyÐSž¿ !ù,`8€„…I…‰ŠŒŽ‹!ù ,xÿH@AƒTH€á†¶‰ѡŊ.RÔ˜q#Ç5†ˆ¤É“(Sª\É’EË—#¼šI°Ö+˜"I”sE%{ò4IÈ ‘BSb0¹ãhRœP£"•:•*Kgæ$9 $W.[PÒ€fÑI ‡ž"dVaŒKn‚Ä€cÊ¢ªu…3a(ƾ$=°¢qFªEˆ„ì¶Ò£‡»”üµØEÕAŒÕ‚M+¥“$ ­("‡‘Z ÂÀÂ+¦…h¨j”¨Ê™@¡ «ø„ ¹-\Ar˜Å†„De˜CÈ^–ººð3ôrF_`§WCŠÈA5v°2 µ¨Aÿr`h 8ÜŽ'ŽøŠ`E5€Qˆb0ðÀ%¶è-Lô,‹2àÎ…®n´®Ü0ã®PŠy½ÈhËÆ‹º1ûá­#ÌÐ]0"† 0 ?CrbÕÀ¿± rЄXÑS€Œx  W€ÍÈ`¦#é7 ø\ ƒˆP É—`á WÉʃ”¢3¤!CšÐ„ ¸`"´tä`ËŒ8â—ˆòR iøb^ Ë–)¸$á—· €5>‘¨Dñ(ºxe ^© ]Ä©OÝô† !†y9C›ÞôÆ/~ÑÍ;"d)ˆDÌ’K‰$ øŒælÙÿÌOäs’qˆ°ìû.BKL3 ŽPe+'JÑÏ€¦ÎyKô'°²tÄ, ñUBZ5J$3!¨£hJ+ÊÒj¶”•±ˆE/+"|žˆaÍ)‰VúÒžòÔ§:ªP‡JÔ¢~H$ºP$õ}PqªR úSEÉǨLŪVUE )4qÈ’”@ÀŠRM5bŒYH`2!QÀ ŠT’nõ®¬œA%e`„U¬!ÆûR@ ,Ã!xƒ$0á( ƒ0ÿØÁ=21< H<è(hèzÌ‚eäÁ(1 ¬aÂ(Ö”a;Kùë)"Ùÿ` ãiˆâÀ»âõ·ÀUݸ6å*TA¦Š†-â´µH£˜ð‘H0æögr è†'™ŠËý¦Ž±)e¬¢¸S8•£ …ÛO#ÕµX-‚P;D´"¹Ÿrh±;DLb((èhUƒKàë´` )KIìhM"ÀLp`º`±N,8.;„ 61-ŸÁÀ¬Ø P…‘…Eëv6 Á„ëØðŠì‰ Ÿ ð"zâ 6°‡¬‘PX Ø…K’Éš0(!È@²\i‚w¡!—èD’;Á9·PBć+îÑü!ÉŒ£!,Öe3+Øÿg8àò5þð‡T¼5°| ‘÷Ìg¼ÄàÔ €©V ½Ù¸#TT#„áypá bð  ²‹Ð…‚–¹²ªÀå&ððÕœ¨²†¨,#Jðkqqf  ¡*Tí3tb¿‹X ˜Œ‚<÷ù×À.K•2Í´âÐYÎi9‡]µbûnÈWÈA2‹q EÈH?øÁ„ô6´4}‰Qd®š4þ&brSÛ{@-¶À·`Û»ÏWB¸p‚Âî—Fè¾û}äù3?Çà§/eM]4#üæðËræÐ-7xDÓ…:Kaõ¾·ÈGžÕ’çTAÿ ·Ng 9““<¨/9NÑ´Ï”s¦2ϹÎwÎóžW4  ªÏ]>ô¢‹¦]ø*ÑîR¦;=¨€ˆQÈŸNõ¦W}§d ëÕ·Îõa€[X:Ì»Nv«ã; knLÊÎö¶;D<»Ûç^ôdüîx—ûØ œŒbäýï€WH‚ ˆ/~ï‡çù>¯wÆ;¾ñˆ|%¿öµÿæ&”ÏüÓ™‘ L÷åÙ¢Žæ‹Ž ýõ²GyÅm¯ŠÒà@´ÙÂ(ÑZ¾”>&$éU{ØÌâV#¥gýEn_!™¬Þˆ)mï"… 6dдÙG/óý;ÊànÈ`µG9$tè®ÿ/Ræù`×s)—@ ôNA Ø×¾~OÕ]Ã'¤m‚ÈX>2ßú"c¾ýõ_‰ \Ì…Xo@½E¢G}#Oõ+ Cpwc8<–a,6R@`¹ç¦Ä€>· (¦dk*Cgo`n!U\^e«P~hV5Y4Ñfg¦iÓ6 ‰SgZ’@o܃C*§„SfCÀ†X8 ȦvC!o Òç„Ó'rÀ~%‚óÿµ Ž Zt!“'†–&B¡ÀÐdž ¹Wjj¿P\ذkq¸@ «áLÀ¤$ž†A¸–€`"hpwŸg…Xy†8dbPì†0î&ÕvI (™—Äm£×âl_2ƒÀŒ¡4JÎrŒ¶ð€ˆnŒÀ¡ ‡ØDƸ ³Œ˜$Žp‘S7ö7~4Œ<7` Pÿ¶q×OÁ´yàpÍôaýfü¶PøÈpÊ´q—Og‰x q§¡ åx!ö˜wŕޑב"YQ“7’&I+†S’!Y`²t’>7NBy+ÙSL |ÿƒs0d7©‘ö¸ˆ JW“Âø&ð_¤äVDt¨cŽA¶l¥”Ø¢-QU’àI•0uD9[9%&0ExfÐm„0Yp[0¶Xp ým© dÁ¼w/¶E!y‰v¹0J˜€<[¯•K¥—FP|q„:PX1(pZF "˜p w¹T °˜•G<‘˜7 d…( …XB¡?€ izÅoÞG0„{°¡é{â™È§$Œ¥$‘0PÞ'»õ˜?Y]úEh×ð~¨pl¦ä9§`_3h ú·” _Ìk×ÿ‡ „° ÓÃ}ðVqð_y0)qTRx»ãJ×ÙH—P —`Šà’‚•¢,úU5B0Òp^‘}ÇŒ”0i]ÍX~!x©¡0€à‹qa ¨`nŠ Ø#žáe~¥ °¶VÌ€d@¹0~i+dö†˜Föbâ( |u°inà’f Á6ˆƒ›¥2ù(5/˜cqÀ€0¯÷…  ©‚<1Ôf¤! $8wáÄ™°¡¢4 "RS†N€)J$zöjéIÈobÀ-&*4µqa]€аÅàwr6EÿJ@RЃ(† ¾ðzÃðE!•KQ …@ Jš¾v–yÌDX&0ÉȤq8‡i1 {Ãç×lXnHE¦@X$ °Â©7¶@+´Du ‡‚ ‡Á%vrQ'J[€¡X !ã5`–’ @6¤i&Àà^³f Ñ„NÚ_øV]È5jhÂ*©tJ°K°EX„ReR†Xˆp-Õt ?&’ö ‘^1}Ui· êÚ¯ኰ¸p4Ç„Xvk"´Š£pcÅÐ Ð ù ˆ À@0¶®¯¾4‹ Á#ÌJ4!!Ûjpp@ÂDÿQJ á @ V@a^3»thA‰Mth£À_Ê ”˜·e@â ò ‹8 sp Ų«¶P ÂеâÀ1PÕ@¦Ñk×J“EW G6Õ&bب4 ;s»èŽÙgSP£¨„ Ý¶I5{¶{— ©`´#D´ I¤£¤ mÔö©Ôèm9p^fá<ç–n[¡T~óU*aù””4Õ µêI#…@w JG•Ù&¸0š0 ^9zbÐP‘pd*qˆÇ'L9qp‘pƾ ¹öLÉsP.3µLÁ‘ü°Ö”Õëþ™kÿ9bPO‘»ÍbSM„¼Jz§IB8P»N*)Rh›¿'÷}«8! £Ps- ¬«¿Fg¿÷{"Nä[/%{/ )ìBø(8ì’”W.ŒÁˆu¦gIœFÁHñ’¹Á_y ‘À,ÐUVÀd!åƒ$•À ž`‚DAwÀ2'H ªÂ+üÅvüïé3/«‚NÛ¨nQ£ñ‘UAÇ|dž|:fÿ?zªy–çVÀ+ÃßIȇ|É÷7ª±6Y›¨ 5«gˆáj¿:€yuìŘ\uˆÛ?m‹0 ÓÏ&’`³ùÈ‚Gxž ܃Ëߗʪ¼ÊT‡»™‘ì«£Ô;âÜá+’`¾aÉÂ<Í\`IJJÒ°Gq rÈÍÔÎq•85S²°Ç0ÁâLÍ-¹Îîl"íŒx_ ‘[Š" 5aÊï,ÂŽ'¹h\¬ O)ÎÈr,ª •QÐû쯅à šá ÑP òYç™SQ `Ø€>pš¤™Q ÞØÐöø  ) ‘M" †²0 —ÿQŸÀ¬[P8ùe~ Ê6Ò"ùe»dW §33ëHzƒÍb¦€¦$»æfÞÂ}¬AÅBí„Ò 9þù-b»4R«º7È «ôKiɤÌ[ýÃôËpµF0qqíQ0ðŠà°8»ÈÖ±öÖþZ(‘´ e@n~W ¨I'ÃÅ,änˆƒ£¯‚-ÄmçÒ ûè°Ù¼’ßr½Ý[Ù¢=Ú¤]ڦÎħ½ÎÐn½Ú¶+ÐÁ„Æ23/ÍÀxz°ÍÏ÷fÑ-VX¹g—P|)Çg|Jlv¯U™zÑ:°Ä—”E|ká| ƒ Á¸Û<§ ˜âûÿG 0ÛÙ Ck£^èÝ]H™¥p*pg1^ý¢¶ ¢ª©´Ê€}rp€Ò]Í‚¬Ý÷HÔ) Á¨`v1h7F ~5èÔ§L*Õ•0©©F;Ï탆p„¨pAà‰± y`ÙþÚ!ÙÕ ¥i„Ð Ôj³W膵0gaðÌB0[ÉªÈ wH,.¿D «*€†USöüy®â(žâÊv×€]¢$$‹¸kV¬H0À°£L[ ä¤Ù¤~C ÿW‹~…‰ºÍäN3SØØõ`$KŽÌ–æ(û‡Ç‘¤)X`· ä8­NÑtÿDÁç;—oµÔ0é;Û~Ë»ÅÜÙæè8‡‘ps cérñaÓPPŒ>ê¤^ê¦~ê¨>Trä«n ̹;)3ó\Ï>Ù“Q¦¼ê©s ÍaõÂ<ñÓ‘6–`[ ˜ aˆ— ½€L°=^~¨f–A%мëÁåz±˜–Ûx‰ªíYò¨ÒÆ шµXŒÅ ‰énú‚â‰)˜d`©\ ˆñ?`jí¿ÕV9;]ÀÒÄs4,=.] àš5/x.jҾТ/£¼¨ÓQÞ¶ð@ÐV}>_¶Ÿ:RºÀˆýîïw•­bÇ¡fÿxဧÿ §0aú潎 ¾n.oiQ„mPá©~kaëÃpò(çxñˆ9Èl^cŽÎ J*ªŒÖ5ßd³Ðq*´ õ\ÏY½Ö+JɧÀ}MB°( àI\ÙzÍáò³J:柳³=+tÏçµà^«\ë÷_»È6B?¶f{Æà €À ö÷öXeW€qp›ëN_(Þ‚m… ð›VD׬méfr­Ë‚@Ù!Í`{õoTÍ,¼nC ‘Ù›}»˜J”ÆÛü¡m„ ÷7çé­_`)WÈJiºÐrïs[Í/8‡ÂË?ýÔÚn‘8)ýÕïvÿ©ªb¦„ ½ÛoÈy '}üãÏëA@Æ-ÃЮêßäëoTL ``gv @V XÀA„,.dØÐáCˆ#N¤XÑâEŒ5nTÈÑãG!E„ð§£&\$vÙ’€K˜1eΤYó¥MœHh:Øå Áy.\X™ÓèQ¤7“.eÚ$¨Lƒd=9¸EQQ§YµnåÚ«Wˆ\† ðÄW°iÕ®eÛ&žD‚p¹¥[×î]¼ Wì!‹6ï_À&\X©aÄW`Hƒ'ñcÈ,#ÛäsÔdÌ™5sTÆQ“Í’C&í’ŒÉÒ~S¯f}ø F[ZϦ]!ÿ Dnlïæ­±,C½…‡l©ŒoâÈ“/Gš¬sšN(‡^Ý5Ð ‚QÀÝúwðàë=üyôéÕ__Ÿ÷Õ{ñì YàøE ÌÌOÇ8ƒ‡öüÈs,™À/ r¹ê&žcÏ :Aˆ½ˆRIã¦R‘ð«0@™btIÀŠ2¤æ¡/RI‚Ž‚‹FÑm?[#0œgTó%—@Cñ@ˆ!•™á@ðá !5 拆0HèKˆ ˜Q.Y! ÐèQ y‰,° ¦WœÈ&ˆD øÒ›Ì !’ƒ4Hä 9±H#ôVäÿí I ù’U¢A.:1‚îj„ΛlÈ馛mB•äÀ‡ÊÀ4¾Š!b <ˆ9Mdà@‘UjñdNErø£u8M/ U:…VNqN`¶s¢n@í†o¶Ñ†œððÆlÍAç[s¼1FrÊýÖ™Ì1§Inè.|¡j¡J‰ƒ:\p­Zâ#¤ 5]”µnôt7ÔmÂ!Õ!Sã›.âZm$ Y¬à¡oVÇ[ˆFñÄ”jú£Øž‘aÆé>“ZN^Ú†œµ Aœõ¼áÛ²ñæžÍÑ¥;r¶A!›wÅ0‡Iµ‡UîMÿHŒöuÃê‚h€¤+Ly„?ƒ“sæIžÑ&Tn˜x¸¡2X€âZТE4Æ c‚,©„kƒ¾(YST ¨Œ*^J@B`Æ—æ—B Gœo—éJqÔœÑ%›ä ir´yÆss°F"ZIâºe(  ß•¼ +¸&»lÞ l·ñ¦ âÒb»WH@‹? ŃºïV$eXhu;irw|ƒ`™P• eZ–a E™“ ‘mqö4éÍÍñ¶o¾õ¦hgKzÿeÌ@ú…A˜°Œ7¼n!’(2Àˆ(,d¶óšãx·œÏ9£x#†"Áÿ€j σ9 Fô”‘·$Šn8@;¬Š`5€BB'òÀ%r8#L°¬2δä§n‹ZI4G¨–ñ;]„*t< Õ&0@iA:˜h ’5ÄV’êÂ@ p „Hç`¤M)b Åˆ4Ás< à@Ç6¼dŽ1û̽¢àÅ•x ¾p+æ€'Ì1Òé£Q¼Rƒq£3§ ]8£7 š.ò§E1슙Ô`0ù 8Î)‡P AT ’ƒ,k!„¡”‚±±4»£‘y¾2€äP`ØH-t@‹HçabPÎ¥Khª% cØ#/-ÂJœÿÄ €3ÈÛ¢ùMp†Sœã$g9͹Æs¦Sëdg;ÝùNxÆ3—ò¤g=íyÏ Ÿûìe?ùùO€tž"ñ@ zP„â… ap S—…¶Ä˜ÏF0 ±‡D”)¯ø îC›!‚ooÉ’F80=@€›ù R†%̳@ßá‡\E(…aKsŠœ^g§³{ÂNdw†C2ä„PÜPÿ–  §p+ˆrŠ›N…"Ëè"Dlq¡`ío)ÅX)R Z„B&hEC8@:hÕŸ‚™”XLÁ#‰h@¯Ó+ú€9U)XPò‡üÎKøÒAÊpؽ®`ÿJjjÈ ŠpŒ ÄÁ’ÊÊXÙ<$ã³™¯6`Y±θ, 4˽Ê(…¦hfPÌ¢¢­¸@32°‡^Å6º¸EjÛ 70B "áÀ¶`ÕÛ%Û1lh‰>$VËÅ(ò`(ɤ@ -EÑ4$X€DÒ €êFv!hå±Ù¤INÍm„ úÒ€)'š/M `‚!ØbÏ‹Ã$|Ä‹VK° ñ”ÏÀwC(áß‚è"Á žÍ_’óìÂÀ@ L PÏÀƒUsº N©²j…[h¥‹»^’ŽœâÜÄÚØÇƒ·OÄQœ.€’Ô¢EY† 2ŠC|Õ%¢ý g8ü‰8 !P€sG#å*Ÿ»pT=AD”Ù53*& >/¼r¹¿*&ž÷ò: Xº)¢ò ‚ïØJÆd ºö|µÿ»ìÑ&¤ …§ ƒ"x!iÄü>q3Á« ƒ „ÁÇ$$x¾BLà`‰ÉLd+pñ(P1 b·yƒé1³G(0rÑD’‘‡æj­GE*ÐZ>0†6X†=ȸ•/ªŠ9ƒ…8€9k::b€I¸剃õ[ˆ$dØ• `¥ÑŽ { E@£E!¦"ˆ“¤s¹…ƒŠAÐ/ˆ AÈÃIÁa·Kè9HÙ¡5`‘ñX… Ø—¥;b¡¹›Ñ¬‰ƒ‘‚Dع€¡B¹+@©3`:Â3<ãÛpªÊd=?@©`øBÙ«—è²Ó'ÿÝó&²ÂAxNƒ€‘ *?@¤[[ :‰0*ÙQ&„K@ñƒ:”†›*²‚Ò‰³høYF@:á€#9 $ø+ž?º£îH$²m2½±èÂS¤ ‘i‚G»š  ÓÛÄ‚°£@ Z$EZ>&ƒºK£Gx„¡8ˆU$[äÅE|A®Pľ‡8F߉…¡¸—rø€ì“ Y$Šˆ‚­q¬éF÷;„`ÄŠ`¼Åd”#ÓcÂr$‹b” Vô9p\'8Ükò'kC·pλ>(ȉ êˆê=_êGˆ¨Ç#ƒ|CŒ‰Gü¸ZBÀ÷sÇ¬ØÆtL#‹LŠÿyÜ ȃ¬„\H¢È¥øÇޤ’ü‹ŒL¨eô Šˆ·¢hÉ¥¨?Žœjcˆëè¶ ÉâQw+INÜIš<«‹ È2ЀWIIyÙQ8¦”!HƒèT°J±zEIi=*A«p†ªaZœ¨€¡!H¥8³R ?é€8PÂN D ¸ØGœÕ3Ÿ×) ôù0lå¼.L2‡S_¥°LCb©B°€ ØUu1ÁL€g0W•º~íTa:µSˆ(†S¡Î2"CÐ,€ÿCŽ“-ÔYƒX½ZXaP°À3ríÂ?½µ× B €_H.3ž" 62p’bXÍ™³"ˆÕÃ+ \C‹5‚M8ªKDµ…ôš+JÕ @8ñ?lx X£©0Ù]5Oxˆ½M˜ W€ ÝÐ:”õ7EµŠ=ÝðBTx8(H[`ÚK‰`Y@Â*¼a 0†°¥Ýh8ã#ÈÕs=S»FÂÝ ËS€‡S€£À‘»[ ‡À?޳E˜„}¥…}ヺ˜NàÛŠ48_í[`ÛðZˆÓlÕ;‚ȹ<8Kð1À€„ÃKƒÿ˜í û,“u€˜bÓÁµÛ4‚@ÇŠ)n»ž91„Ô<¾ A @#¯ó±Ï*‡ª4pÀŠJ¾à9¢ýƒ•Ûµ¥©<@&½ð€ X`h„EÈ·~,‰Nˆ=“‰ØÌ·ê‚N˜ƒ~µ¯Mp‚êqÀh\ú%û]1'¸„Ùû"Mc5Q¨]Jä’{ˆº+¼žÝ ŽÊ Ô œ¡€0À 7ø`„0$[<ùàD­Š½[‰?ø¬l=»?H_pX½[ÕW“*ⵦ¹·V ÙéЯ‚eÁ4Ø¿ÐÐ ˜…9p=ÝT¸Ø¦à 7M+f˜…XÕßÓÔŠ¼1^6$ðÌÿ@öý¢HP¾Ø>਀‚]¦Ü–7€b4öF88ÐÐΈ«-Xu½fH¦)9€„0†ÛîP5ñUpUÓ)€„$ØxA¢°Á ‚@LÄ×âaA$„"<)VpÂÛ4Ý|‘ÂÁL?˜*«r2ül¥®‰BÙ™ ÿAøA,Â-T^‚(¶esÞ¬DyN@†€b¹Ê€ <´Ä³tA=@[Ðß¹ãA­ÉKSIòMT¢-Cë½CÒ\ËÁ“Œ`+(z€æê2C=`œ6D5{Á¸iƒÞi °^ô/¬Éi.`ÙÉ€éIs_D`0«Æè«*­fD©€d >h„ÐK¤ƒŠ{ÞŽR ”â„I‘ºü¬@Fj?è1ÆSô;º#X‚ èÆƒ¸½ã#¸ŽÆEÒØhR¡¥mì„=Â'È`„lIDklhj¢Å±@Følw¿<òŸ;YL±ƒpEÜFibü#ÿU‹ ZZŠGfüì`üìTìm<¢m®¤$ZŒÆ PFR|ˆ1 &mJ.NPˆý«VáÎe¯f—PZc®Àãš—8w;Ò¬ÍóuÝ‚Cò3-äÛ`7OÚâ&÷lÎ9éòzN—šNP.…Tqİh&ˆ—m% k +ÿ΋Õ_FâzuÓ›€d¸|Õ×—øÙ†HJ ƒ±¦…hHEôEˆƒXf½•ï— {½IEL%¨wEÓNPU“g³…7Õ ? €™È U°UwgU+¨&Á8<4•:´c Ø5À€.ŠRØ©žK2&À@øQ2FVìPR€y]°À³Ü 远 ³Ë—XEˆ'Ëbððš/e̓W ˜\XÜãƒÛ8ÀFê"s+˜®H ñÃH?HÀ¬Û¡%ðƒ `+˜„þëÊÍïüHˆÕ¶Ê¿Í±°?¢[%Ø7Ôè:LöOãS Ê9Pé`XÀ[ÿ`êY@X…ÜüÕÓ‚<¨©I#È¡ÛA{öóî… õóbX€rK¶@úµVîWÎ×Ý"è„Màp Š5"@ÚÃ%Ü… †u3øÈ@«Tûž`ŽjaÂÇš¢€UPa´ã€jˆ'¤IEB£lèp@ RŒFmÖeà¥^Ãf-$ó‡aÃm@ø£AQÀ ˜AÑ–$'‚D“"ˆS§‹ˆüÙµÄEoXØ¢°(­?Jmµ|sØ¥]:Í òê„N8ð ŽKb«-lÄqÑ—-ôI€¨– døzXã¢*PPR/HJ„. ¬Å‘¤IZdTÿ²Ô¥BL(J&ýÀðŠ‘”=zxêWvG¿MðéÔªW³vˆ:5æ_¡.4†cC˜3âPŠf ]:·©DnœU ¸Ì ÌPH*A:¨bCºHØøÖDÏYxÒ¦zÝI¼ä?LŒ­$CDGŽ6x:¡÷Í]H@•ê×5'@ÇPHBa´D± l _‹¸QÀmaÜs#‘„vƒ2wÓ©¥J[:}(Wu  Í!½,D0 $xxÉ0¦ @‰Ç4 þ­÷ ¬ ß#MDHËt±ÊH%¶Gg¡`EhB¶VÿÚ˜ešy&šZ²`@ƒø‘ Lhâ+˜2/0Bx ,$ ~p&€$`êH{dlÁ@t(BZJôEH5Øeˆ >ã&+{Œö)¿ Æf.èèœ~b§2XÄÁi+*Ò@ "½ª°Ü ´ J¯|Ê2°²h %Bˆ\Xˆ›g¨à—PÕ¦›ÁàŠ›h€¤‚pŠœöIºYI¯  ‹oæ’:˜Ž¨*²Éh´t€ˆ®Ü âm)qðBA ¤5É!b¢ù0ÄòF<æ"ó‘  0ÈH`¸1QQ^” eü1eQtÙq„h ÿ%i”õ¥ œLØ'sF 5¤@L ¥Ø|ÌÈ ‰!ÆÇ®ÀÈ+£Ä#\8ÇnÝÆÇËåñÕ¢ `uÒpóñ¢öDs7»L„LḵØM2p\H­êËfCt·Þ K.F}5DhæöÆ» uαMÐOIL,ñä•[~¹˜Ó‰FÙæsî°+„¾SJ›‰íÒ–v޹C³Ž¹-ADözC”At“é´ë¾;ï -íðê—¯š»CŸo|[#<Äo9ofË÷ŽÖ!’_æïËÇÐ5ó½_ï=øá‹?>ùå›>úéw¯>ûí»ÿ>üñË??ýõÛ?þùë¿ÿ?ÿ”÷ÿ?(À°€\Ÿë¨À2°| !(Á &‚¼ 3¨Á rð{üà˜†ÂŽÐƒ%<¡ QHB²°….|a™†2ÉG¡_ 5À„†rp_ ¯Ss½PzÄí±/1©Bâ +L|âØR x±;îSE2€³Å.ç‰À!CT€D Ä ¿Aƒ!‹@j\\€-¬W H©í2 ‡8ñªW#ZÀc!H#«hA? ŽtXßbP/Aå"• DfÖHEpA”¤ÔDøqøW9?,aÿ|»²›)gW,, °`¥™Z&¸Ò·0Mü°RXÂ@v€…gJ ˜y¦2û 5Ó?1U@±büp )X‚ Ío•a™Íœæ:•–Î<¬ógXpÅ@$(ÁA®yÅ2±™zšÐ1°P”žÑ èhÈÙsC xK)"1ˆ.è@>q…0c†Šà š°[|A ,ŒL“€E6á†8ð¡ Ëh„õh€.ôd9Œ8ni7QÝT‘`„h¤‹íªž¸L7Á…AÔô!]¨bÍh± Œ´P0©Ý““rAíš•W sQž2å§âÿ‡zô#¯ŠÏ,+P€)0Ñ9¬‚”‰Ý$PƒN¸ÎsC\Ä€®fìPN¡"&¡ I*#O2M"b‚]È©mÅ–¸ÇÀ⢠€ Va‹ZLVJ¨Ã A²ÅN f™d±ê[äÁ±ýM"¢1ŠA4b²¡`îD#§ZD Ƶ"ZQŒ|Ò —@â( [E¥î„°­»Ä*˜ÀZŽL ¯š+-´°,—ëzˆ$<’T…e@˜q ŒéTA¨Ä¤t EòÅJu @¹Ô(ž)е¨Î#” æk¸¢Ÿ¢ðE*ÿKÓ\f‰A|£1_Ì(ÀÅØˆÿޏøþ^¨°¡rù7„Rq˜Vx¦â øê\‰ÚT$£zÏËW L@2lE— B2|@Ó]U@Ê#2MˆÜ„OÐÓQD/X´2g*˜Xh±Š S˜X}’„„ °‘*#¢¦"lƒ1\áf `áj‘‡¼'3³YÆt>fŸ¾È€P B@À¦ $##24:Ñ··0*³XÅE ¥T-D }> GS„Uõ†Á²„<˜A°ü[.Ø¿-Z 6ŒZÛ6¥Fð*M¸Ñ@£/r©v9€è´êáºz‰Ç` ÿsÇ"(Pí Àp +ô×2€à#D–ÝœðÙµ]‘˜]õRP@Öv‰H—¶rïË\C)oÅ® Žl»ÐRZkFåG< ds‘šÀ$LQª¼Á&üJÞhp…7ü!  M  .ìBuK´ òò ߆!.És$e”„/å¡Ya¸(.‘ñL `ÔNÆVÞÛVéaÈ(îÔ"(ºoÁ¤–1à”ÈD»Ô´ÓDFÚ Ql¡#¸ƒ–ðæ*Et L÷c¯á"\²Þ]¥ ž®ˆ$ЂíÓÉAtlFŠdˆØ¯×vtÑ0ÿ›é4 a …ȇŸ€ªD 7ê#„H‰ä 5ÖÌ5ÒMä)€áÄÍÈ #ÎPá<2Ûàx$× Ä7&ZÖ,„Ú@=vN„ ¤H"ä‘ed×ät´ÍBDH”hŽ5`¤<ÎJÞ¤ÞL@IÂÝ™æ8#á笎ýŽ3ê…Q>¥ñÐMeSJ%UîUÏê8eó<åªleVjãk †Wr¥ç\¥ZV¥¥âe£¹åWŠÏEå[Úekˆ%%p€1Œ%û`€¡ÉZ2A94Ä ¡åQ¦ìÀëÀBè´aZÎ ¦#Z&%æøÈR<Ò]­¥^Rÿ¥1ä¤%^Žè-ê˜i€ 8HÑ]ò!†‘\öÅvŸÌÀj–ekˆ‚?Ojˆ¥!b‚#àembeh&j_s ôMl*&ë•À)øˆ=Ã])“§±@a$14èxØÿ,ôAhh8Ó:¡3á$pTô€E$&TèBüègºF6u_;§˜Z èÀ„VT¨Åµ„SŠ.Á›z§Ÿ¤©b§ÿÜØˆaA-TV+LÀa˜€w-hÁo"cIÞŸ6¢h¤–*0AkÁcEVaø—q€D×ri\Bu)Âs9êQ’ÖíqLA(ªßÀ‘/<Ö¨:¥z\ðÕaØŠÀ¾˜* ¨z ‚/ü©#Ý*MŒAr¸Å TŠ<ÄÂ]¥jn‘JÀÖ`,Ÿ+:-PkÒÙJ@0ÜVˆCkUV-ÖSÌtµÂ¨nâW‰,˜ÿBÂØÂhA´`Ò}ÙæÁ¹—Ò,תʪg5¢&¨GW„ ðÉtôUé<à &Ä@²VtMMð¿ÈÎ!A¡>ŒkúÆÀ yB£¥Åw„lCäY HËr”ÙLø€•yM%øÂ•Uš˜x”}ŒD£=š¤4L\ð¬Ȉꀙp€"4ÇLÐî©NªM@aš¦ñ†“ÙÌ›çùITOÊꡉÌÒÂÒÖYîàà[T\税¶ÄÊtˆ‚Xêqœ%UÙXÕ.¦ÍÕDFÁ*(†øp@ØšA™M€Ë:,R8OT ° }¨ XÿŠT]"€(C-èD ×Þ*ÝŠ$¼ù1š!ÄPBŸdY¦Y$Ä€׉ÂÛ½ÊJ@°,7¥‚À¬$‚WðœÉÅÝ2ˆ+¨À®”AÉ! ^ÆÞ\‹5JB Môœ×T\-HÇ"Y†6ò†R¬Uœe¨É¾ùV¤J6vÞûÞêd@ØÈOXÉ($ÀÈ xHp•ñrëFîæ.qb !ÃõvÂ%EÏu1‘o‚(\ãÞDT\ÂaźG¨ŸæêTY€Ò ”„[‚¶ÐF‰…ð,P«¾<íÒ°öïÚ2”Èï\[a B\è¢Þ…)/3Ägº-ÿ‡¢HÞ.ìèMXÁý¼jUöY/‚yõÁU¬ž$‡Ñ‚@Bˆ^4HRªlÒ00ë!“ipÅ8AúŽ0è}@‚w•H(œÂt\Þl’“m—eÆ"PÖ¯½–ôSð¬eœ˜é ßžJo˜JÝ’Žã0 ÖñjQ1ém0&ÙN sÒU0r€ç %¼€"ç^4$—Ü.‚ÝjnóåÁ / ŸˆBw¢ÎÂߦxÃ&!ð[lÁmº^ËÝÕ%¬Öéy_ Zœ šÉ&á)‹ž\Ö~!¬pEÀ%¡îÖ@ˆxó° ¼ÀÀ5#áÂ@ΑA- ˆ7kÿnpHÄ8Š7Ä<‹=oBUT˯¼l&tÊí´a%-13x!d@ØÊ¿,!Až\!Ì!F1˯Pà,À¬]t"2o¾&1¸É |ÜÁ¤Z¢lšC$!¾ÔQêáâ¬pa›˜‚€À<´­ÅòÀ!ÉHC°œ’á®…IïI&˜.·˜¢¬jŠ’C“áàÚíÿöasø0`ªã©¼£©p ÛÅG.ÙB6Ä18ÙÞ¤ópdìÜd ÜÜMÚÜcM.}ˆcØ<Ä;¾$ÞD$IžÌ@¸Á#\MJ6$Þˆ ÉØL˜è#^‹äD>H„ÊpÏE¶5δ£e›uÓ¬ÿÍ/X aó$X{£KûÍhÿµÔi_6È`Œ`³€AÚõ´î:ÄiËõï¬d,ˆ JΣŽì¤a¿Í`Wvn[ b“diåøœ&á&h)·ÿxs‡Ou;§sPL>·ts7V²¥wÏn†wwÏw·Îugwû|Á+XhA€D(¨ZÚ¥ ©C°w«e ÑhÀ_2Dñ,éd2„ÀðäÐ’:7føt£¦ÄfŽ „gwŒ)TlýÖf•Ï»Ý0C( B­ÜÚ!4ÚÕjÜîw³Í)ôE-¼hÐF•Iٌ知¦mYø1moŒy ÿW.Zà󈕙ž F_ »öÕZíB!4 ø®' Mê˼šÓÀɈï*˜‰$ nYž~Âótàî×Vœü> #}¶)ŒÈc=©-M‰,ï‡YmëOêÍÞÛҰ亸¨®Üʈ mƒŽ!¨Vµ €À$Ü4ou?\Hè„Q€òLÄ&t!àR§^á À‰F7ÅP"ÀÁ„ði’dH·àÈáOV.Œùr#-5b6k…MQ!# LE'QÀJ†¼ésÊ‹-Cžòóe 6»tåItžT ²ÿè€%nØ Z6š?›ÄxS%¦¤§1Ýe ˆ?‹–8Q@¨QÛ·5kÑ*»êCFEôU ЬÈZx»4ŠXæÏÏŠƒàITæ„ Mëò²!"NPY·v’Ž" â Úta-º¼©»«  F¯3®Z`”ÔÁ-rF‚UøPá¶”ä4Ñ šqšA_$¼"¢!QÌm}3g—U äv%>ÒxMôFÑò OÏ»&¿ûõË‚¸O7<®á/™¤(‰‘Ês¯¦¨<`„* Ko½• ÔH€–SR†`¾P´ @d£C80dC‚Z’Po‚k´EÿÄð¤Ë0› ‘%Vùï/[^f@;Q…àŠ lA.& € c.ʺЫaŽÀÄ6У™Œ$‘æ½6Yت€ ‰Zâ`FôŒ&‚ €Ð`e„‚3TP©OSäs?ñ¥“ @$“.öÄSO1JaP¤>¶H‚8Hkï=ÅSAõÐ#ƒE!ýsÖ=vÅ pPE%< VO‰L£>F9„¸Rºø$S£`%Ö.}Ay {5ƒ`b¸4Ï ˜Q/Q@UBÏ``,dènÑü¶ ^ÖšClƒ FŸØ¥ ‚©t£+3"BWã3ÿ¼üS7ä åSd0å„+$ÛÅtQn;`*67E~ YLðÅÌò¸ –¿–T$\„©˜]€e›rCg3XÄ‘E2ÒùÇ(`†A 1r‘­Y¢{m¡czîð ¸ÚDú ž÷ÀÚjŽî¹è‘ÊæYé®Ðκ,E >ˆ‡eÿyäW>¤é¯ožúî½ÿþ5'šN—à¾zðËמµèš–y{óÕçý{ôýÉ}1àŸþùcÿÊwFkTì—¾Þ±Ï TàØ@>‚”à)XA ^ƒŒŸü2ØA~„aIXBž…)Tá 5ÈB¾†1”á iXCÞ‡9ÔáyØCþˆAâÝ„À!‰-Lâ™ØD'>ŠQ”â§XE+^‹TÌ⹈Åë 8H3X#F2bQd¨·Æš‘CxÛ\GÙ•A¯¨`aŽ”±¯˜€ÝȘ‘Y°ÆOSb =U‰»½$7­ÿiä#È„4´ ô ¡ âòmP›`ÉÖ@‘wLå+¶€$ô@ÈC€€R‚]ÐAF´$4‰Èˆ$Ë>Ôr#“å’ÞfLd¦`X †š¤©<¬ — (æ,‘©<à»Ù°€Ì—„X(/3òK•¥@Ni€ƒ(ÂZÌÂÆFÉVH„1òE ‹=ŽRJLGf>B&„0hpbŒ&aÆ‚1fš­"ÄÃzo®dŒ%ÑÏW­æ&¼ŠÕϤ9/i’C§>Ђ+I ›ëßóž/²0D-vI›ÅmkqhAcDX¡µ8 Ä&-‘-ÊÃm`V”žHA4›fM|Èu…hÀZÅyðK€†qbÿ\$'zµh¶`f7È(™QÍÊW×;‹¶^:œ ed3X†I¤÷bæ)_˜5­Îˆ”¡ ˜ /{>+žLF _»ˆõد&þpj?;B`Šë œÀëEÐ!)MLš}ïƒ\„ J¶@ˆx4±¶É£ë:E¶ILÈ—!Œ¡¥0 + °}B‰ Ïå §€•€˜Ö¸œ\*g±X)•Wf@‚Å´ÀÃŽ-·?ˆÆæ³x’ο3¢šdç|)Ê‘2xY G:î|‘W "CsñQ)s´%ø"’%ÅÖaâq§•ä&ïëÌ¿Bë+~½‰^‡4Bÿ`í,]–b ïeó$H9YñÜ÷ °U„²D>ÈHÒ”9:ÀŒPÔWñ!`áÆ0ÉÏ#Ó ŠïbtE· ]t’¾z˜)¾…'AxÉ]*WêYÑBhÌ„R \¥{ÚÛ¾µÁ& ŸjO–ØÿÞá%Dí…,D},*cZìsó^üiU´*Ø©¢µ†I!ƒðøÏ'là° Y§j\ 3çj À÷‹¤Sœ¬w(q,Qvng#ðB}.ÎzF5„œwç(È µ¨ Ç{øc}¨‰§„°ð»Hw‘W±ƒQ‡‘‹Ñ“Q—‘›Ñ]ñŸQ§‘¡‘ˆÿ|«Q³q»ñ½1ˆ¾Ç‘ËÑÏQÑÑÕ±Ý(‚ðH6" ÆHwØ(C!ª H&O“ì‘fæ‡Üqü‘ƒŒ‡aÈ@|e  éÞÑm@ÂP®'þ {b ©L&è—˜Ìw¾é5,é Ä@iÜ<…NR$%ãDÔʈÀ J øÐ#‡("Ü` L!`ÂHЍ°(a"¥˜-©2¢¨Z ”‰àP€–ÒÃ*) ˜†i›Š °ti`"aL4À¨bI;žªœÊ.è)'®ò¡Ê ¢Ò*±F‹Ð2©âI p ,EŠHÿØ)”`Lö©Ÿ¨”JýèR ÈÈ›äR¦Ò™^á¢DbŽr©ÊR¦ S—îãàò¡FJ;  ”à’ êä@ °€þ²*Šœ¶i(m¨.Ê‚èÀˆ˜KHóy&$l°(€ A¿<ë°Ã8­4+&n€:Œ^ŒU4„Úÿ˜õ ð¥û†ÍK-q>²ÈàÂzBÙ`"(¤m\ªm/ÎglKF¢$ ,´ÐOE‚°ˆ€*!#Ä bõ|ünRèåÖ¦U ü”D@€V5Y§áN¢Ûvm[¯P%ž¢$ƒ•Zß@Ê”âM­UPE`ÊàÁn4J´“ßΖHÉ<På¼L v 6‹d=Àž4<Mj>Nh„»¾n $°ÎEPÎ$¢a-*âг[ux.`?’@8ÈÕë²Î=‹ߖNåj…c ìƒf_ì4°zÁýöõ,Dnß6`aþ   j`v‰igNEÿ/AIb`pÃfV^¡hs"êrä p…ìÌÎ)ݦÀNG´À䔢º„$'öìäàâZ)ó CM¬ €õp1ªOþD$tk & åW”Þ¢÷eaEDÐN8EL0Ÿ…"÷JDð[Pý®¥ï%ˆÀš%"súGü¬W%Þ@kª³xAb]IaÆåSÎ/ý4B ‚€¦@4ZŠå|-#0$’aŠokàafø&`aN B¥vœÀYzl~Wc\(PQtküàR: mÁE4…raO`|_d˜rÓ‘~!eÄ0wtðuÿb¦”ŒGp. „¡! Ÿ0gª µ& [„tuäa?„_ñ ³G `h®p‡s$"avt~˜p -Ò+Šðö`t‘ehÑ&‡†|’Àx¸AâpÎGXÃjªvÓÆF¤ tÕ‹™xC ‡YX ƉÃlj‚…ÏçS‘±€0ƒ°‰×P†´]tˆ^øtÙq’+Ù’ÛçJ¹wHXqˆ†)¹„ 9/™”A‘A„¾`¨|ð‘àˆC„%$ BÊò’wT¹5´€,ETV™5ä@4 ¤xÔzä -î#‹ObECx#4ÿ‡9#2rƒH2:6è[PÒwjêá@¢ ÎŘ4#¤* ƒEzžydTÁ4‚{Ä CŽAÑ$½y¾HÉ8ûÙÛm‹l¡AÄÁ² ~)£ú ž†é˜ÿÔ©0ó2ŠN!¦‰3 `!61*6ªµŠÀzé—8Ó$ôÒ¡ Ê¡Š "ŸûËxÜàP€ xöá°€dGªÒ-3$€ .£ÉTš/ 4¡ˆd/óÑ%tЧdjtš§S!3ñ ŠÀ˜ƒ`ž"á à1kiŸ¾r¡¨ê4¯Ú¤Vêœf)/×2 °ÿŒGܼ!Os‹SP Ã©æîLŒD+8X„f¢<­ÚÍ£èÜ-Îaµ0=qo|\DÜñ—½U|i‹ç¿ª"JÀꌄqó¯Rú'å<¡o€ÑCH¡Ô;‰àDN:D·¨Eû´÷#g¥AF7àM!ØØÝƒ^0ø+‚§å],x44>K»o¤o&Q¡Ìi´9ÛTÏOÜ ö8pw0ܼWüäzóNe䭔¾E*Xrï-ØcÛñwçó¶>TÏöV€Gš7{Ï`äKOÞâ? !^ùf|Í%QÀÏ‹ì&$N¦|Væq(§e`ùtlxzΦŽÇ­{ÿ·˜—aiqg’`ïAÇ/¡'½B@Œ¯‘rfÃŠÙžëøæñEg!(?…݈/ï?ÁSQòóFïÅxŒ¨î÷æ` Bt°,§‡…fDÿ~ò†õÿlQvN9Ë!¨0$L%¡(­LûY¢Ç‡œÀ{_Œ•߃x?‚TØÃ¾ˆìÇù+èò;ù{–g÷M™˜™ßû·_…NY”“–¿_úwˆüQ9qù—úÝÿ‹ÌÀÙc‚ÊA‘ c9BN ² HPBNàp¡Ä‰ŒX±á€ŠY˜†4› †ï¿¯@LÉP(çÓ(C«Ì·AÜD1•EëåÁAh@‡…*£ \È2ŸD àÀÝÿ{< Çíà^Ë#s$Dg) A¡‘0,ùè]¹Q´€\MG äM„C N1rì¢w!ÓhK,°YF¢È[I1‚(JÎ7ÀzúVyv‡¼4RµØ‚H+­¢C°˜Æ{¶(¡ ƒDÑ"!qÞ$Õ{˜©Lš+ñ†-¤¸!%ŒÀà |<Á dNT‹™h"3h4£ Â—D¶`Q("œTzfš]¬¢ªL5Ñ›cˆGj(iNÄ-¥6CPŸnÂiK¤^Jé,RIDµN¡˜ á‡!¡(”°BÍu *¾¬0K)vÂðçÿ­Ú’G.x‡3Pî5r0㇫"‹È$ƒž©H'éš)šú”é(q²ˆ´U(H¨Àj0L 骊¥iª’Gë^çž¹ űÀ‚*0_Xlqú† …'€\àAâ%²Ä¼¦+ P€¨Í843CÃè°²2¨'ž"L¢&0ºP BKiE­ -Â4EZ{"ƒ',¡"†Tâ …4‘òB‰Þ¼2Ñ ]5C.àôøüÐ ´TÌÀÁ&r…ž *‘2Ö’()À2ÏrEá±`„…ÒXÓàŠ+ŒŒjµ0OàãOÄŒy <×Ò…yŒúwÿ‚÷ 4»EQ#‰€.Ua{}È!f© úÑ»)HP‹Ã7å=¶ÝŒ®òÁÎ=3ÞPо¦Ö_Ë0 ‘Ä>;ÊÕ_b,«ocŒ<¡[Ä{þB4p¼…(AðǬ^Ò³ P$„!»Õ0†ÐÏ~ ÁÕ°w‰NlóûCpp "°¢i_TÈEÔO" „–íjF½ôE# …R‰E*%€'‘ç6Ì¥nD’{ þ„¿Ó„~ñK_üJ¾€o~µ+àŒ.# vð(£à‚P—Qp{¡;`þÂ`™œ¸@:Ýê Âû“Hs/°ˆïà½Åp„=Ì\7‚»;±sW\_àØºûÍîYã¢Ñ¸Ã*N¯ø>úd“|ŠdI‰W”¡|e,gùÊ„Éb”ëºå‰xYËd³™Ï\æÞ @ F³›ß gïB&Lžð›çgÇyÏq&Ldø è@SMЄt¡èD+zÑŒn´£ éHKzÒ”®´¥/éLkÿzÓœîôŸ= êP‹zÔ¤.uMýiT«zÕ¬nµ«_ ëX§¬²®µ­íç[›G×p6ô¬ËLi'Ø$×½æu±l`'{Ù!6³• m.?{Úq¶§ñmB[[¾¦v¥ ðGÊ”¢}Á‹|5÷…[ÊHNMh e''X·¼Qâ»`AÙOAÆôg<r€sK&’\&Ýø^7£Ã—8d ¼ó>®Dò‰mkIÄŽ<Î ²ò‹WpqÈŶÐíËÀûÓKPмgÝ‚ìâv1c>¯˜` 9Fâ@?{AÁÍ6—…c Í1‘0Ir´-*¡'qh@&ÿ¯HKžô 'IÞP7¯Š ¡¯`Á5PÒAŽ^ò¥„Ì"˜ómA*ÑtþŒT “Ìú–ࣥ‚;.í1ò °`önf þ^"е @ìš(ÉßÿG¾ó}Ö€À ‘rÔÁo=W¦HÈ„ò0#t±]np{bN‘`a¤F¨{‡„… è]"|OAŽv4‘I]ILÂíûà¥Øþ!bļ ߦÿޣђtˆ‘w”YüŠZD¶(à,Z€ƒ|q€6MT>À†`Ð @Kp`6{3Yб xå‚#÷4B#7ŠBaàÓÐ9G³†m8 pø7É0½qÈFDƒ†Vˆn‡‡ˆ4Ø`а_P–dHLã7>@aHF×BG#H-æMñ71ЇÀÿ2z…4‹sY;H6sߢ4Üc@3°ƒeÄH4ÕsB؈ªÌX†–˜†ßåC?ÁŒuhÍ37¹ˆV˜$ ð а”D'çDP$E¾æBÐ ´ŽQ©P ŠàCïH?{c8>!²8´è~à ?,°Ìôg;pG=„Aô“ öoø>l˜ ¤±‡ÈcH09 dð÷˜< û˜%:€UZÖ¤‘@D‘‰P?áEoà4°x zˆ¶å~ÉÃoC6iúFÀ…(3Àt« T[PÏ3§[ô>ÑE)”ä”´Pì˜+Ê“E_¤G@))ÿ>tŽ€ ›c×@P§²*¾L›”ÅN×IP ɆšÈG’´7ˆ‹+e‘>¨4I` -r°Q­€Bž´ In˜~´0;m©^$0(~ûE£°†‰” µ 3ð2€+!+wCÔ•2—”Ƀ1s$`?¾ðŠxÍV í÷8ïA …é“Ä›“Ô‹&` µŠG™”Ê(FÂVqÉ–Á䤄?½ä”ù’K9 iiP§‰èĘËô›}ñ˜=W×"Z}èZqP\ Ã…G]¥?Ù†qÔUÔS x 2‡)VŸ1c˜ù5\pÅ¢Å8ò©‰aõÿVç( "%* :YºCR¼@='뢃R6œÝãVzÒDg¥\øW£ *ú9rnS µˆ"¼ÀÔ# ¾ðU¹öŸb¤š”rZ©•g•¶Ð‹äVëi@Z@Å9¤ÇPR€VÜržŠuÿ™wÅB*ŠÄaPèò:6b à =6kþÑdÔe°ž0’c b †'Nû™j †þµbWZC&d)†¦iš^"Ö^ÕF¦Fæ€ijËõU) æ‚1KƧ‚š5à¥V¡Å‚»ñNög ¶kŽjœzú`êa£¸d!b a.ÐcØ5ÿ¨2w”ê§ðbäâ ö•Š6v.1`gWVDp3©Øór—Á…À€'ë² ÔÆ€afcf_‰@eÐúk·¬ÛÚ­b¡¬! Ô:†½¦b¿ð ¨ù­Ÿ6—*µ]ÞF§aæKŠa7Ià® JkËö óê º®Õªrz¦®ëZÞöjû¯œöò¶'";À‡›¯ËZŒ!p_n!îÆi Wh ·m…1püh÷Æi ±Þêhp›I's`Ìps‹›d ˜/È¢KÁž¶È*æa ÷vq—_sAkšòÚ©3D° å] qÁP)Ûg/h@®bö³ ûkBaÿDųÃ6ЖœúQ°µA³D˵, ·aq—‡uNÂp­ŽW7#! ¼‘çrS"w{²gŒ` x.Xz³×u©·z2Ðz, Fð$ ðw²' Qâ{§ #¹¶˜—ÀsZ@ ¦ âP)<`Œ°-)0ñÛñxç$â!vËáªÁ! w|0‚¹cg²Ò³»»]RE€-ÃÂg ™Ëf% •%œ; 2Œ² Q ʸÛÛ!‘²«ÎHºG²·™ÆÄçDh Ò=N\ñ)Ñ0q`PM¯«ˆò ²Ð)r.Wÿ'BÀ¿ "¼Ë¡(î‡ð'“D/àÊ@±u+0…680~„Ç$Lµº \ñš`¦€}mpXþz-š2O_9Z½…­ –ª’A@2ùò}481ù0I*ÙrL®Ò+èD„\ ôQ½2'p1«B—ò€ý”kLì+ÿ( #‰ðþ²Åôt¿ãJo+¯ Q1`cJg×ù)€¡A^>ŸàF_9lT¥Èº7‚ü09 ±áÉ¢µh¤T|ÐS‚ìge:¥2& JÖµ«§Â,¼„€9€4)@­T“5®ÈpÓ܈ˆi“éÿ }ð‰¨ÌIhp‰Ë¬&13¤‘5ÁÈ|ã³>p‰(ˆy¥s:)]fˆ†m¬Âlˆ ¡cÜ;„ 6ÔÈaÇ]Íš¦¶M)IFz“Eyœk»‘H¬C<ÔV2>s3©B05¨ISŒŒF©Iêõo‰ð R l¥¤QG'L´d\ó1¡©ðÅ0n®kª°•0Vš•e°D A„"Ø *4@(X‰Ñ"¡” Ô=òÌHëXB†]“· ÍîãD$ÔŽ 1È*’°AJ¢0 ‰•÷KàÈÔiA¥ Ô¹™ßÕ \Q040\Œ"ݘ qÿûÆpMÙÔVþC)¸—}©Èn£› õ\Ìdý„î#NæDÐ PUµ`0,–YiX0ÑöÅýÔ“ò×I©t«ôˆ[­‘û'—‹Ð–šWhºD)ÕÆqÒ’˜ÿ6×ç´M}”…‘M™¯4HBC'ÉdÁÑ©Á8™’Å€”/Å]`PwlO¶•|‘ž“¥Z‚0¢XÐ *·X2\†£V.ÅXsž5j[[Å€ÉêÕ$“r*å¢n• qÂñGl‹%1%TØ\‹:¨dP•ÀÐóQ `:¼ÐJzüYÍ]Ö%ðSQ0e²‚(Ê[ó½Ùr§Y+:O€‰ÿ|ÁTÚÏæ!ÓA±Üƒ%R†“¤#w[ÑJ¥GGú’¤-,¢N:ß0žÁæg2^Aª}Z`^*sÖPÖLö¥Ef¨¯ZÂ^ʵfä0§Üævz 6]ƒ-dõ%©4¦^H®ä9›^..Ð¥]ë•©öâ‚¡bÚ•¥Â:«Rº^Í¥¨3¶DvcdÚå/^â!äó%b†§ùuãPS¨¡¨¸šå"¶yЫvÖ´SjäV°ÖÚk‰T ­ÛlŠèÓ–ÛëÆzäe)§j£˜Ûj†ªŽé›éÐæó:²¬FéOöé›®é¥.éq‹i ka`Œ#á°+ÿ ¨®l‹l£.>¶.ë¦n'À°zñ³´q­ áðUOÆiq“AMd ^®ëÕ.hu§ËTÇ$Ë:ï‘udg"wx: âÁ-e›@h\n»kÊk“'%‚ç$€· §T¢K_¦àîÖh‹ŽlXQ]`}'xÆVÔ‚_ ~ëÜÙ ± p}_A^¼Ãþ,€x`Ó”TGÀ/°XÝ)-Ô­¯òhv± +e1~ÿÑ §X¨‰&¡2>»«Ã ênÓÓPãÊ9ï>L»:8ZI'“7†þ1 9’Cê+êˆð$ÿ äh.mÔQ´IòCE D*5IäeÍÒiŒÎî#ö“ED½›ÄÒ‘(,~iõyÏòcY–›p–µí ™í– 00 ‰ò—…÷ÍæÕ-M˜”¢x@ Ó*`WQf}ÂRL&ŒÛ®÷Óâ QyØX¢‘EÜ©f:H÷™É½IÃdSluႪÏV;“〠ª¥[’Qáå#@Ô×¹îèUÿùÅŸhYZ¶0à«Ožªéa£©qÚ©=^¦çÖfØqÔ_äøõb6^dQç²züéÏìA€¬Lùrñ¨vTv¢ÑêÆc¯þ÷Oi*Öé˺ªàP’1.À@ÿ !† >„Q"€$Ž&^ĘQãF…=~RäH’,:–D™RåJ–-]¾„SæLš5mÞÄ™SçN“<}þTèP¢EEšô¤R¦M>…UêTªU­^ÅšUkÏ­]½~véÎ ÅžE‹²¬Ù´mǺ…Wî\ºuíÞÅ›Wï^®|û²õXðà™‰ &œø¯â¦ƒ?f¼8òä C¦œYóÏË~(lÚfg=¢MŸnI `Ô­]gTÍúõlÚbׯûvnÞ’7ï–Ý[8cÒ†MA¹çAÈ¿%<ÆÁéŸ_Çž]ûvîݽ‡>¼xòåÍŸÞ&=zöíÝ¿‡_þüñô×ÛÇŸ_ÿ~þýýÿ0À!ù,(hhÿH° Á‚*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£O2ÜtI²¤É“(Sª\ɲ KªZÊœI³¦Í›85XqIdΟ@ƒ JÔ!€E“*]Ê´éÆN£JJµªÕ«X³jÝʵ«×¯`‡K¶lEfKŽM˶­Û·pãj̃…Z¹càÝË·¯_ŒOÜýKx)¥Â£¬E̸ñUŽ#}$yáâÊ‘ß`ÞÌh࣠;‹Mº´éÓ’£þ;A°€Õ°c?¼,»¶í´oë^{·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vh¡qI\hÝZ½ièᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—Åu¦– ‰ùÛ`³AÚ˜`¹†¦pk2D eÚäšQÔ¹iÜ›ÊLe%'Šü¡Ÿ+IãR "Ú’%Z9S„K5õ`-Ê´Å¡é ¹)Ø.lþDÀ@¶Ðrˆ'FlÒ†jƒ:ÿÚ.J”Š“ I“£‹º„­·jª„ üªiC@”hÀÚ4ˆŠ€1AÄ ôªC€€àg ‘†kVŸQçF.¼Z­¬-æ‚ ¥}‹•»Ï‰(¼íDg¢áû¡¼óò*뜢¶{ê¡ÍæYðuôÒ0JP”C$N:Ã)DÌ E§‚ Eql%³uêT2DII#Ë€¢U1Ê3Œ*NQPd‚Ìa!â#ÑDA ‡æ Mí€ Éà‚?#L)qÄÆÔì6uÁwýšY£NÁš‘×iMÑ·`×o×YÏÆµÐw pŸ¥MØé¾ÍÒÂPÏ+QÖ¢¾ÿÒøN07iı·úë›3ƒcTö+•0&2r´…GX Ä­J®Yš ÁÉ#½Ô›ùEn0"‡âv ú83•DD„ÞÉ!¦ð!Ø µ7¥ªP€¼TJ¬2Á5˜¢â á«Ôp|Tˆ(ísi²<¡ãã–+øôh öj¦•=£½x¶:~|ߦ¯t³'¡lÛ-"ì±½>Sú»È·Þœ!œýîw–|lQ韭hµ¯È«+rCþ¤ò@¯T‚óC RªšÜ©(<‘ž„b>k$~Ž˜nJx1~#ÀCG5Àt}-PeÐÂÿ—¿¤ 0L?´Œ@ÿT±6•=… „øž&‚ħ9à" ¡÷† ´db~CDˆá¶0DB¨ÅW À]/(¨…B ÍÔË Rt³’¾…¨Ð^•Rö–ní.o‚Îö(†RR>Ñ ÉÈFÖ§55t¤$IÉJZFˆ@F/™’çm’“ lK#š¥ø!FƒàzÞ®&`&Hc .°®5á$n# (s’uía%!,bs>i•HžÅ˜Ž”xÖ—RöI€[á×3gžÉš¸± 8(D‹`3'_ÈbtT¨>SšÆD^X¨¦º‰1y—@à¹LÌâ\r7ÿ6­ O: p1:/ $‘¡TTÑ´„ …½U:Ñœ BÒY¼>g!ZnÀ «( ^n.ˆšÃDé^9ÌÈìð¥ÄäŸIáØ& v“-oB:8ÓsötnËy)ÃbEÂÜD,, KLú¿›|e;f›TŠÓ¦Õˆ&ÁæÙàÀ²üt‘=œ"V»¦:©:ª@u UãÓÀ5ó©U¹×R¹UšÌ—½*cî"W³Š”#<åê_ñ:X±Üg#¤kR½iS•À5%Í*Wœé( ÕEó+S±äç^% 3O‚ –è`Èga©Ò OmV+–ÃHÇjA ¦ÿÀ ²¶I‚)†#º®À€"½X,l 0Ǫˆq & hRjE“à@(£ˆÈêsÑ^E&DA„@4J‘Q4bc @J Lœì¬2XgHˆê’$–i-ʳdÀ…åònZ Aሔè÷ž!-kéræ•/¸]ÊaGZ™ÖL¯®fik_§Ù¢µ0¼Z°‚¥ÊΰI‡ªF›c(üÕ§`¦³Õ ±[* ÄÊM ^k^Q|7<­T¯Õ1Ž ÜÒøj/®éDX|ByÆPYq_lÖ¨xµP޲”/”XBÅx¯ÞÙžŒ˜ÑŠ0˨ E8²в]îÔ  °©ð®ÿSæê0fqÀ~Êj ÆŠ3AàŒ®dÖD|¸€p¡Ð r@ƒ0 » DÐ…^˜Hp‹gA¯Ù[SÉ‘^4A0ZXâAôÀ à9€gð Âé P d !Ü%v€GT­ÏϤÈ.›€[3„–¾šWvM`›¿ƒnp_yX·Î)7PðrU ÉetÐ6W ³™md¦¦o²¯â•yïÆ•¯Ž%rx×[g$«»É&~1ÝÆ­éöUNï¾7»áµS\¶µ©7¶ ˜ áÊ¥êÄw¶/"m†ã¥ÒàqˆAŒ{š (ÈCÄ·«Æn«íè-YbPRt!ÿ+HúÐ ,Ôßf²± ?¾Õ¤˜Òy3©‘x*ÅcÐa’ BCdʶpíײ©ïjSp¿ ‰ ’À*%fÐVˆ,ŒŽ…Àzé?N“Ø•\è0Yus´IrÜœ8qÿzÞ@«äÙê~ÞËbÛcL¢¶…QP!ú)>ÊÛi^¹vXEâ½YâXŸO)Pú©ij‘ZûG3籃;H5UÁ)_ù!岫w§†8äC§×­«Ÿ÷¸gÔpo·^Û: ÌÙìÏÛÞ€±÷ Œ¿¨kÛù˜¸Ð]Ž1 Ðe’1{N<¯’Š#š7Iÿø!b‚U¨‚ ßEŸ×Jï”ñOÅâל 8òõ“Ô?"˜Xź0 ",Æ5”ðOp¢{]†V¿sSQA òHÌg|¦zHævYÁ€)Aa½ süB î§`Å¡ZÍ7Úå‰0¦@|\j[PsÖ²0¤@ †\X__6±K¡>Ö/`k…ákák·fkÆF`§QyQåRþæc9Ñ{pÃYLGVõæbL,@6¾AC¼vCÿ¶mÀGRdo¢b95dCV†AXc sdøzy§6V¥†öõÉ'p\ÈtpHoxvöoŒ%V„å†2F…’Sÿˆcn‰Ö‡$ ޏpcmÇcFñ{6BCžYgøˆÛ$Sѧg¨˜Šª¸Šš†Ÿµd¬˜W!®H^„® BîÓ4DÐ ¡€€ú‡Ñ‘¨ äB¢p(©ò„¡HÑ à^q5-²±PÜ„ó…HmË#«@Ð5ƒ@¡¯VF hÊ'@×Xž°µ“CŽ?q QG9ˆ`Y6§ÈDÍ8YC'ov(µ‡†7&ŒØ‹Xd­X‹j£ñ¶T¶M³øâcéöñQ Ž>™vn©å—R%Á ]€I61!)’'‘ ­`’fcAÿG’†<j‹—nAâ=¡€iXƒ…æ  `sA )H$© V&sa°w$0Ë0 ‡0’%Â~šb(< 0À’aà<Øt—Е‹3ÂKpÉs vu/w™{yyˆ{ #mGæLxl[ ±‚¸ßÇ%'óXy`$€ ˜¢„é‹™v$29$­&ô–ñJ$mIÂc5Ø—Î×”ª©6'X"ˆ#õ>^gé$¢É‡Ùše¥‡„Ath%¹ÉËÆ‘B2œ¦ç›þcˆîVm釤(ãSnq×añU(ØY†°s\ƒ†¹Ûÿ‰27ž6Q“ƒSeY¥~· pØ›Ê ŸøHêÙéJ”¨{ãÉœô[öžXÓŸ™…·aÅIÅkô²0#äžJc  rÅ*M1$Æ@}ÁÉšYg”ü"‡Cz8'º¢ä›“ Ÿ±UØÁU(,ù‡ÿ ¡Yƒ(W†Nð5Ê7N€Ÿ Q`Ÿœ‰o Г¼E Iº0nÀº!Dr¦Ðx@p‰€k‰ipÄP °\7 Òã”v¦=ª‰@#zP:p¯rZÄ‚€‘` ”ö:‰P1XÐ=º)%ÿ§°À§cZ¦ƒ¦@*”v W€r Ч– ©+`à p.'¦dŠ¢sšª<€©*Ä |ã‰p\d…`ƒÐG¡}Ð3 T X ª_Êmí±-=„ó @tð^@ŽïÀ К  ¸ZD sb­q0­î`j@dpÁPœ‘ÐP “À  Rà­ÆÜZçz$P•ú D kï¯[`¤t Þº­5P©"ª¢0­Õ`­Ð°íPjæúP Œ`=õ k­ =  ˰†@8&@- 53ð± «I(ÿ@VP1Ö ŽTीwÀ©3»°~Рω5…-½\y²À§5 Ùš à­;Q [h€ `²°pÀðìÚ/(p{ÐMP` ¬`µ¶ øŠSPC,˜ ®;‘¶kû>ð¶q;·` S µ{[p)+µ¢p 0‡ `¤wpãB<ðF0›ð éЖÐÒF ã „c ŸAxpkp `+’гðè¹S›±b»œ ž³»Ð ­”=yŠM À®e =k áP3±Åp ¶4P¹ÏÿË©˜Â®n(( 4MKV°°ÖËr ¸° €½ãp‚±½ö’¾Æ-P t`­@·µp¿qr·™ e¼àå\©  ªŒ@•ð; ½;ºàË®V+­  ²¤É“(Sª\h( +cÊœI³¦Í››¼Äɳ§ÏŸŸJ´¨Ñ£H“*Uø²é€¥P£B @Õ)I©X³­jU«×¯=¯‚Kv%Õ²hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œ6êè£F*餔Vj饘fªé¦œvêé§ †*ꨤ–jꩨ¦ªêª¬¶ê꫰Ƨ*무Öjk˜\Y¥ë®îºk"ÀlSÀë@ƒ$«l‚YDÄ ¾*«¬Sæƒ%(2‰®Òê1H¹ °H#ƒ(­¤û­@Äúg%„0R‰,X¥."è pì’`ñ‡#pÍʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàË÷O¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œ6êè£F*餔Vj饘fªé¦œvêé§ †*ê¨.Eõ_!W !ù6,eÿmH° ÁƒÚ`Ç„H`bD‰ 3jÜȱ£Ç CŠI²¤É“(?6 p"A)e˜ÙreÊ›8sêÜɳ§ÏŸY°l)ó¢1fÆ 4æ¢@(@£JJµªÕª¯43ÐC 4) âé !„{˜æªÛ·pãÊ›ëÏ”‹µ@ dåEÀLD&,h¨V ÈÌ]̸±ãÇÁŠrQ `Q ñe†§8r¹´éÓ¨}VzR“Ž»¦¨1üsé¡$¦C¦ÞÍ»·o¹LQ«J<”«Qk€W21šÍïëØ³?¦Ó¤¦‚Ô¦ÿ•¡1B28ɬ¤½½û÷S›to)‡ƒ/`¬ Í”áÂ1p< C£ÁgàžäÒ@H“–"`x׆P¹%há…&„˜MOŇ.8Åà‚Aehâ‰× @âˆzWÑS,¢(㌥×"^@¨¸ b4ÐÒ(äSÙ¨cD•’‹#¹©’E!9â@‡°Dä•XöL´€& ÌK$yTJ$Œt‘‚s®ä&bä‰@ “ÑYæ©§I ‡LÐRK(z R!b{6ê¨J}ä ]P#! ÷覜$K¸AP±pKµ\3Ó8 p!¶tÿ*ë¬) $±´D®+œªÛSà *)¡€„Ъ쬈t`( ‘ÂȲÔV«ýBP9aí·à²ø¢B3•î¹²Ž œºš¢ën£=ºøî¼´ª[ª½ôæë¨‘"êëïžü®øïÀyLSM'|¢æ–¨ðÃzñÄÿJñÅ "¬!Æg×ïÆ‡Ü›•S‚,òɧ‘¼Ê§¢ì²‚âÞ(ó kgêËWÚh£Aµ+Ìðl°À±ŒsºRv˜tA²Ìl1jFsrj0uõчÕá`Ñ$M#¶&Ï6P½5Ù»%КÔD6G'ÑHÀˆÁŽ"Ð$&ò†q4ÿÃÒOíÒÅL&¨B%Œ»‘¢PZ ζ‰( ‹~XHp!œ ƒør‘šDD/3HP'üÌY…§" ÃQÚcÈL08¨tÓòÇ©ŒrðP»¦¾2àOíNê ì°Œ ê …Ú%¶Ð¾ÑÀ^û…Â*‘ŠîâåºÈ"É4°´Ë,@v¸ u",®xø bß½…ŠP*Û£8€4Œâ€9p`| 1”kt`2¸À"ˆò€B ºà´é¹vÒ[Hÿ0$†ôÇQMC‹Xô‡@ó ¸ÐÂ? á àšΆO` iÿD8B!=MC>#€à†÷4Öý°fÖKM‹h àÄÌFÖÌ6¡)jOŠ£¢{ÆD§AIbJ ˜ãcFÇ}Ñ'Q’×u–©¡\B …$ #­KWl¿Ø8³RÉá-f$IÀ„0”l^ˆ¡@þ0 ;ZriY””Þ袔‚ ”ñÙÊœT¤Dî¬%¡€ ÿÓ!”qŠÕ‚ dð”2`!ÉØì”µéÔOHl¢i°4T ¥ÐÕw‚9 ôÀWò°Ë AA09™™ÐÉ aüÖf`@1ò Ûš —¨5D•iJŒ|c cÍ–’¡2fÿ@C¹(ñÒ›- ñÁSø¡xP@-‚0[(J LèÒHœàAc ËàÃÝõŸ8Ä¢ (@f¢+t蘒áW„xF jtƒæÄþä` ó„@^Ç‚° _} ÔF5âhë^ùC~š˜GÚ€!" ôÀ4E ÏŠ¹Äiá@Ä&*•ÄN–ë)Èú $ Ê3¯dÉêF*è3+°“âL€ æ¬ätÁtº•ÝVyGƒXãIØY­TA‹ÒtPôfj¨H Üñ)UúСÝ-u`+úª»UÌá V,?â>]Ya«%†Rÿì•:¤S ›n4)x=•$Ò¸¹p•±z åB<@=pb1\ É7¨^-IJ„LBAè1 õ-¸JøˆG䯅ÀdBMv³fðÅ—[Ó= 2@ì  yZ%Qí¢»Øß‚øp!(ôæGäÄeF®èª‰€]„F'ÎS¾¹d8¥BßDj RC¹ç&‚I{‰dÜ0"5<[€¦Ñ¥r%G"bB×Â2¯m„1‹)/{5.…”‹ûá–Dfú*ªŽý([hÀ‘²ÍH-¼²¹È˜ÇV¦²‘{vd$¿+’9ƒù4l¨Ð‹*¯UL dŒ¤Yÿ±|:¥Œ­eYÊ  xŽœtË&g¢!NÍL'Îü"<ÌI“->cHIJ—®3ÉÒÞl--` WhèCQA'@k Òa˜—¨4_ÝÌ"bDY ^‡¥ê@ñE'gV¿ñ"K<ã‚0Šß8Õ €.H1Ÿ-|@&%]Äty·Ì*#ÄUs\òç lˆy«²K ‚’¢Ne@Â|„…6¹¨Ä’2™zujµ)VÂ.|”%%è.„pA¹Æ ·ª 0ÈÂs§ûÔëæEË;þc‡\ ¬|8ø{ jx°0á6ÄÑ`É„°ãzí+ƒ&ð×…(^ñW–ºËPÿ¹b>™‡lG¯4¹BèÒžÍå"ObÌIÜ/b@hù9Èq®/'è‚ Ÿ8ÒÁŒJ7‡PÔWœy»¤¡)öýagbЪ)†"@¢ -²œÑø @Ù®HD t…žâꃅ,>¨Ëd@ƒN0Å1b–¨XNå>;™â»)Äáu;<Üvm¥Ñ4„ŠÌ#‚éæ :Dz–Úí¡hqñóÆäY¢Wô‘¬D‰tB`]Y¼ôÿ%Q¹Ú‚4áäÙEVsÅw؃ž›ÆO¾ò—¯æ;ËÏ>Ã7ÂMäG?ät¼þ⵬ýía˜\k:ˆÿºú`Ú Å-.ù]þØqñà WH÷úU-VPã§dÀ²ÇóùSL4!!ÍÐWÃÂ?!)çÕ6cµo~0z4¡€÷!ÿQ'ÀFm‚èeØÎ±cb÷#B×$9ò_ð CÁ’€F$X‚ ?L”F€À@ñÕ@i1˜s@xTİmÇ•`v2ÁqàLÁÕƒ Cz_%7¢b¾@ s«Ð.ËqNH0PÈ›Gx&WÆÓ…?ž…:ô+opW˜g†EÇiø7»“zOgpø„1]1X”9 t[py(ƒ6,„Õ/‰ÿuˆˆ8gŠ=<‰çòaÙ';T‰–.;'"ŠÔ‰^¨k&Öb¢øe¥8‚§Xb©i«øŠ°‹²8‹´X‹¶x‹¸˜‹º¸‹¼Ø‹¾ø‹ÀŒÂ8ŒÄXŒÆxŒÈ¨}hs6’€)AsæŠÉˆHâvnD¦’&‚M8Æd¯Wl¶Ü(d­¨­(Žè8ŽÛ$G¡)€4eý—)cgG™¤ŽÄŽí(@Ú¸HË(góXöø^9aàV²EàÔŒ”UGId„¿‚oMG‰Ÿ‘PÆK=G<ž@ ævà€…€€hW&”0–Fmò×!^Å\@ÿx‘‹R;8V·²g È)Û ä æ@Ùrà Û@Ú`Π æ`Ú@ C7«àk*Ct!ÃC®w:i`Ià•`QIYâNÛ  Á QÙ€Û&ÖW­ –Õ˜s …Ljg¹Ž'ð/bp¦ÐoÕ99À ÎJ 1ž¼éPB½™$Îà ‚¡ ºP†A "FhÁ$^oƒ[©šÒàŸ3F®Ù†–b‚ÁbjV޼çœk(3Ô_[ÙcÒ+ŠhÈ£œ(£6cI@º/ÞÈ…C*#eƒGª'Eº¤ð£NÚ(רšQjDMZ¥Y2¥Ø8ŽXU4Žfeç‹}IŽ)¦½xjcz!ª ͉aiº‹]Z#÷ Ž*£t&3˜ø¡0לֈp$s¶pÓ—?ºŽqª%KÆ£kê?_ÿŠŠ~Ú“är@*©‚¹§oê«!ÝÅØ„GFú-§PPœ(qkeT yðvë)E@Cˆà9½_ÚA‹Úœ•/u@'hÀoÄU» Q”WðRèISE‰ù'8c§¬5’ŒiÀ† e¡N{X]èö)›×ÄP`YEÁ¬¤ŠHÜÄ*&2ñyl€;·U  ž¤WÙ)­,Bkl„õyŒïÚ{ù‡o#2 ÉS,Çr t· jÙ9\°n´¥¥”òA-È“sídc@‰TõN“‡{d#Ä@ŒÐƒVš#Ì$«fe‘‰ÂÀ)¡T«Ê˜ ÿ¡C.ðyŠØ0pB D³ºšRƒÃPˆ!cÄAÐ ÿÑ·=ñ=h»qµo–u- 1e M›»„Ô‡ ‘¼ÙµÚ—kçkt°>R ˆP‘hãØ‹˜;_á°Ð·ªQ mÇ äëu;4öNÈЯÑý™%Ïå€Ô"072I—_4Š ×`?¤h?k¦öEÚEa íâÂí(.2dk ñyh¹¹ˆt’.ñ†(‚„ØaˆOž9³eŽ|BG}YÂfš¥5‹-Dü‰òˆr¥T̨b¡8§'Js•ª¤ñB-p[¶¡ePLaa,¤ç¦ŠËõ¡ ǾµÆþÇ#coLaV;‚XÛŒ%§rg‰t”ÿJ‹cÇs ¥6Ñ6w «QrgGÆ.FÁ58‹‰+ƒg‡f@PzÁeëI;ðW1 CVp°wRI<@pL+ )€%j8°ËAh¿A'µPKð$ñ‹‹Ä7B@A±»§’É0©‰Â^…Y¶“pJE܇_º~ƒ(6ð~£ea¸oº² ‡„V¾hYP@]P%t" 9 Ã*‘Jy:Ü‚Ð΋|ðÍþšÌYc9Š`9•£³*'!¹~© \‹î6!®é# bWL“£òŒ` I@»¢S, ‘*·C8³û³ Éó) ;Æÿ%Å3ël¯\Øp —` t€*Ôš‹½mðBÑRÏ&ÕÐ?HV°>í³ªTMqðÝ’_£áÅ ’¼qЕéÖo°T9 Ž lWP ¾€ß%Äè­1ÐS/¬`€Ôf7¼ŸbVP'A6Ï€@¬àZ[K\´ÍBÄA'pÝ΋­Ó‰°¡ ʡɜË"5j^€BÁi¹ˆžÝf^µR¡^´áü ’.àØ:5z<‚B/„Bñ)  Œö¨q¼L.¢dÕ³Žr»3ýJÇþøt‡Z‹ð¨¥W ÈLÈ3<¿z^cȲ¥š¶XÚÝôÿ"ÌÞÞäǺâM$[ÞYJÞè=#ç½Þæ­Þî cßìýDYKßc4sø!ܱû1¬Ç_[¨ëÆ„þMªfüß§A0£àùã·z€Ãû2î}1 aÍŒpÙ6àO/3Ë0UÞýc¶îDHÓA<×,5-àb¤6ÕEæ|*s0“G£;½&¸p‡ØLAÕê+}ÄâO¼HlૌèV±‹Ð6€ãŽ=|`×'J0þÝ<^»üà b z†Ííà¢kdŽ"Szæ ·T¬æ‚ eW ' ç€ðÕ “pÖv%• øç²¼6ð„ÿŽ!fx(¼Ø$N‹~° Û ¤ÝíBã³é,42:=[kÏÖC¶£R;OÈèEŒª“†DÁ®xêÚ‘É1¢ ©‘Þ…ÍÆ)QÛtÅGž‹YÎÞPbƒ‰þ/òÁCQ ‰§º‚ 5;*$` îÜ„WˆD´ŠzßÇÎFÙ`]g¼åpj[¸, |ŸÒøí¼ÑÌç]@ÑqåÁøfÛ|hŽ2½£m}Øp ê7ÄÇ@ê.Ç}êÖ€×åhŪ¼n°žà6ìî¿ñßñÿñ ò"?òDê´$¿hÀqò»Á§*/E-ÿò0ó2ÿ?ó4_ó6ó±èg€óŽê<Ÿa?ôA?ôD_ôFôHŸôJ¿ôLßôNÿô‡xàþfr õ)ñˆÏ\*¼4â4µ”.ÕÇÉøLXÊ3bn7cn«} 5k?ŽÕ£ö2¢ øcÍQ(èö ;ÔLA­À„r° eYŒ$E:ïÝ*n ýÐO1½æfêø¾ê°ÑA:×[Qmé:ÍkŒ;$ÉALÃ@ –Öà;Õ€œÏ©YèÄÝeï öNô.ˆðqk§OøºùÁmõÿž0=›`ê"›C„Â" fè@‡a.MìÏÝ/,¢,ÿŸà’öÞŸj[¾;²þÕÆ(§qìÈ‹˜¨)éx´ÚÑ©‰L‹q$øãÂ×¹6Ø XÐ`€ƒ.dØÐáCˆÓPÑ"‹FäØÑãG!EŽ$Y¤&&,ÂäAQpA( 7š,sðb,Ë ðÊäO .`èÓGÅÄ`eÚÔéS¨Q!ÂbôhfÁ'KŠ‘æ'!Ç8RÅBD¶"Ñ›QcÕ®eÛ*%…3›˜ìEPÑ…‹nõÆ0‡¡}<Ú[Øðá½Î`Zl:“qÄ«ˆBø³kÉŠ8:IæÜÙsP„KI*)h¯ÖÏ{‡Mè‚¹ÊæÔ±e‹å€Ãÿ ƒø8•—q†žm’Á  –@V[¢‹O§>òQ¬ .ËîB€€'_ ¾ð±IâÕKÂÁºÐ{éêåÏ7oõâ« b)¨Ë&ýØÒ¨¼4p>2JpA‹pD&@;0¤ôHAý&Ô:mÂC eñ£7ÔCS„pÁ0îÓè¡*QE 02'œ±5¡<„Ð ¦ @ŒK±H$õŠI(ˈÁBzBÁ(ân¬¨”BŠ¢$Iʃ fì’CTAl“ˆÌ,Ä<ó£°ô‚í Ž#h‹7=ZR21 ’1ïÚÈ,Éd©kP>8ÿL•ûª;QÎ`£Hç«Â>AE™À†9!ˆbFlŒH+•-_B«ÁÔa ¨–)ôÒ²ÀíX-äÒ"9V:0… 89)7‚80Ȳm•Ðݳ­¹ÆS¶8WEe6Cƒ>y¤#AÝ«uZZ!ñF¶Æí\µŽ|Ô\l­•.Ftû|t¯ÑELAwAªrÅzíõ÷_€x`‚=›·`„Vxa†vøaˆ#–xbŠ+¶øbŒ3V²¡ƒ·ÔøãŠ;yäÙD&ùd…M6e–[v¹-4>÷eš¹fœsÖù°>vöùg ƒzh¢‹6úh¤“Vzi¦›vúi¨IŠ’A•ùŒÿ _ñ8ú0?·nv˜¢˜iLVº0ð (”0éËp£qEj·>¤·^0ÇÞ*iâ¼_0q–5½ Þ¨mÍh–Z„4ÈMùl¡†qö(HŠL|ñ² 2ò8¼ÑÆŠ$ð{)‰“FF꤃²„(o ea³°?9w ®…RˆÏQƒ>×)¢CLéE€go‹<×Ë%h†øNQ"Ù!Ú EþH T(uë5Keµ_{cðÜw¿÷Â!O!èv$ñ àlˆ#ÐiÙ}] Àø¹-’à²::x#ˆXÈÌ ‘ÓuDºItr‚Œ ½€Ãcî&(„T·‚—ƒà- )Zjqÿެ±[¾fÕR÷Z5o1Èþdû½Å!ù,X8 ÿ€‚ƒ„ˆ…Š‹ŒŽ‘’“”•–—˜™š–›žŸ ¡¢£¤¥“¦©ª«¬­®—¨¯²³´µ¶‹‰†·¼½¾¿œˆ‡»ÀÇÈÉÀŹÊÎÏЪ̱ÑÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pìãÊK·®Ý»xǶF-¯4c~S \Šß¾„Cæˆâ^aÌ‹ÚeŠåÆ’1á3Å€3‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ¹éœ {ož¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇠ†(âˆ$bt`‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã82@ !ù,X8ha€‚ƒ„…ˆ‰‡‰„Œ†’“”•–—•ƒ𛓠¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ¿”¡¢ÌŠ—Œ˜Ô–K‚ËŒLJÙ‘Œ!ù,H’ÿH° Áƒ*\XÇ b€ @Üȱ£A‹CŠI²¤É“(;‚<à ÆŒW¦œÙ@š8sêÜÉ“æ“Pj^$XhÆžH“*]Ê”'–ÞÔ¨™(AX4 °ÀL$̦`ÊKv¦7X{Žh‹mž™h5,K·.Í$ЬØõh.FÚžµt(0‘æ–·Ý´Ü˸1ǵކp¦‹Ü@µõ`‘NLºôÀ)¦j>0ÙsÁ9!­ ˜‚&­¿£Së.›C «‚1P²R¡Qç²M+r@´»¹s“.6ÔlòÉ+€(Oþ𠦏Òⱞ‹ÿOòèȘ<)ýN5=zòð7ÓôþWgîä‹sH[?¾ÿÿö±°Ÿ}h ß ˜T›åwàƒtaÒ„z îç~ë9á†&D‘Ršq!Nëuhâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çžœÉÔ’èaL^vY¡sê§’%*¤(B_驨… Úµè]¼GÐ ¢g$‘hP(iÉ!ÐXhÂX$a¤vQØ0ÿˆVP1³ì‡Gdz§A]¸‘€qØ V[´Bs®@«tÁ¯™Ð‰@*P"I‘€ÊËè¬ ºµ!Ib“Þ‡ÔE#…*€nI|DQ¼E#ˆ*x/xIƒÈ`FL’õÇÖUF¦¢×½y‘Æ €Ãî–EÄtµ‘ÕaüÈ!Úrdš–Ì°Ê 5ú²¡Ï ,sÌ4kK¤íZéXêñliÏ5첦V9FrÉH¯,#9ü¡ŠÒ ›'"Ô¤²¢dÝLtÔ ‘P„(± Ø,ÀDA¦@À3i]&×J¶Gq ÿÓ‰(éíÄÝ{ ‚!»Ì¤sáCVÁdʸ™‰ …Q“)ˆŠð[,Aù úÐÄáœù€qg–7ôé6¾$vHH3³ÃN㥠øú Iàþ»î±kM|—X—ô ÇÇëÈ|JÃ7OãÙJ¤Á– o=–Ünߥ 2x¿%¸â É#~p²JIl—¿û'±¤þËy¹»ÿ"¡öÒß¾ý1NÊ?”í*ÏÿpÄ2I ÐI1ÐE%»XÌâ<Ü VF°G£ðÔÖZÁÄe„¹ ‘$à BÐí[ * Ai?— ‚,© NBaÃqb¢¨!ÿ ã¨å´°‡4‚AtòÖ„à%@_qwÄJwSœþHæ¿,zñ‹` £ÇHÆ2.‹fL£×h#1x€ Œ ¬0€R°QFÌÌ#ŒuG¥pfséc‹Á2– ò}„:äÈEÖ¯‘(^ô IÉJZò’˜Ì¤&7ÉÉNzò“  ¥(GIÊRšò”¨L¥»¨Êñ°•®|,óÊQîo7¸y¤%ÙöŠšéÒ=FeÒ_þ2@²ì¤Ò/†H£"> K"!"H£é˜%0‚‡ß@ñEcÈQ„xÃÚ ÄC¼ÁIÜøF ЍF^¡ˆNL¤v1ÇÛ ÿˤÈF7ÌáOM懛)…@乃…¥1º`çB´¡ (ó4¶ÀƒÛ”‘—ÔE!Á žQ‰*ÄËxF(«!P(#tŒ@Î<´.Üà†IWfK=ÂÀ£½ÁâFo8£ ¤\Ô$Ïè;' No æ&¯¸¨ÊÌB@“ê,·ÊÕ®zõ«` «XÇJVÒ®¬f]*ZÁÒ§³®u/n}+ÑÚ»äÉ5,†¼«]†ð3½–ˆù‰_kÂC îno8DS8)ÔP ËHÓ~h ‘¼`u±KA¾r#l ²0Ä*#ìüb³¸„d°Õ†DC8&‡pŠ7ÿtk xà .ñÙ7q¦°!!ïÙ͆YEaë#P ®@_3£ì4E‡1â@žX÷J©#ŸŒžBºŒ —ñ„Uó”¡[¦èyéyIÖ‰÷.)¯Ä=€ð:ßdN Г$} ßù—)O¥ëzeÇ%Ñåiƒ"¢ç2oaãÝbBQÌ+i%¯x ~w Œl/hÖÖr¼™ÎX¹Ð² žÌ¢-­1Q܉ ‰ƒ_dñ@ PK …ÕÕ g3Á½âÀ@¢È'q’Hi¾A¨V"“¥Åˆ7A~gJ:1‰Î•¥—eYB¶V$ÿø2å<ò¼ýx ƒœ9ÅL p‰ã'ë‹HÉ”à ,A@ÕRZ¾›äšäos À2ÒðfÃ$ƒøQó‹Å² %h]èD‰dk$@("%hác×,„Y– "d SÙ+`²kvÝpÏÙ÷~®> vŒ…YÃnI@ªûJEd~ØQ¤f”JT§Äh«H­ ð|m%¬®¬Öæ¯ê`Ÿe„ëmÝÒÒË_§µ\Ø4ô„´8h³R<º6²)0ˆÎÅû hâp³È —cH`O…U {[ÂT÷¹Ž8ƒWó¶hH‚8 w!ªÂ”1ið¢ÿÆ‘á[Ì®!I~ˆ‘\r ,gäB@°¥ZÂú‚B†!˜ËHÂß‚­œ ƒML ŠÃH ’ˆ8Ó•#iH⤠‹ ¯jì þÅ-ÑA¡@2Ьł”ê%©‚=Bh;s¶ðÝ!!òž$Jm쀻ÜÄ1¡+ä6³!HyÛ˜“*Øâ"‘ã 3®°AÙ*TJO„ &Тß`EÞ &pKbÑQ»ŽÈ‘M˜ !]°Å dí‡ cÑDøä 3ç(J „œyïf¢°Úøáˆs%Qña4B’`ýÚeømϪ]|î;2PITÿ„ éâEºDhöf°“ÿ$#';ÛÜ×Ú¿õ3ØúÛÿþøÏ¿þ÷Ïÿþûÿÿ€8€X€ÈÍ0Îsç—u& \)‡;¾+îÆ½aË0 „4"„ ©gp@ZœÑâ¡^Ju€à 8@ «°MA »Æ÷j!\ö‘hw»‚ó×8Q ]2´$‚N•u¦@ 4]®c¼•?;YuÕ ôõ_€ Æd9CWy0 (êÄ>‰ç±R!Bq%ަ_&¦t4ˆs®§y~6»'7·“·6Y ÿ"3À’X3SwRŠ qu\k’_@**y÷C ¸  ³° I¢à…~)€ñq€sø¿ bñ9°1\U†—q"AüÆ Ø!f“ˆ *€!°`Ù~Iç:C´•[S{¸bcˆk`Am×^š˜˜Î±xba x~̧§8„Ø$?WƘ FñŒ¦ã`ÜF%ɉoaƒ‹Jó5À5™Èù›Ð$ÅÉj5ƒ²ÿÈVõØLÐ443a&R.ã‰Wl×;¶°qÄù« 9’ A±òL6‘ÿ˜a·V[—ø("&Óc:²aæ°4Ñ qQš0Ö…—#'¡€È€¡¶Ð7¶VÃr.s B}5òxQùIDÐ ³7± Ÿ`†Ñ”3EöI†Ð$ÔtõY©#¨0† €TfXoÍ‘f(U e;°,7{œ oÐ £7ÐZz³¶5Þ€™7BMú¢âá…xp b›f’´d‹À—&8ˆ ~ÑÆ@tPX°–}@˜%ˆ0e‡!páÿB$´,~€™8ˆ*7\P#ƒà$@{¶F$ O° UÀ7?¢šcÃ}áÕ¾¹AùD©£‰™Õu˜¸:À7l"á+1–‘ä‚Ô‡W¬£‹µ¨`!„9ŠT¥Ž2ù‹®R£bÁæædPUŠD1Kù^à—ŠÜy€Þú­à®â:®äZ®æz®èš®êº®ìÚ®îú®ð¯ò:¯ôZ¯öz¯øš¯úº¯üÚ¯þê*ßé®÷V¯Ù*°[qåû!`˜(â~=e‚g‹ò!'¦èŒKñ 1Ɖlå°‚nèE}PŽÿq— jð¡ Ì  šhNZI@yœe ™ÿš›Á˜ö©Iì`³‡òo0/ÐWe5•IÑ­P°uq­rxv GªH_€‡juÝJÌbkq“>s@3೺‰üé\€‰4‹±É§±B‘°«x:O†KmkaÌ60;VJË®n;¯ X þ üÊsýJ )ɯh8e†K F‰ÿÚ¸Žû¸¹’;¹”[¹–{¹˜›¹š»¹œÛ¹žû¹ º¢;º¤[º¦{$W‹V¢h¯6C"X4Ÿ!²ÿ—®€hðŠ§» ЯÀÓ¯©‹®¥÷‰£D.8Ѐ»Á|Ásž0KP §¡è¬Š¼x¥ž[(Ji 4ìA|ÑŠ;—„Ûÿ[”‚IÒë(å÷?1 b©ò1yføˆ¾+à‡Ç’|@D8ᲗʸàR£”ŠÅE+€à{ ëB½lD ‘æ]La©§I2pq'!qì£WéËM:d§xHLgÞû'Q d§ºÚI;4˜½Ó;nįPíù®õI)¦¯êÅœ ¨¹»Ã<ÜÃ>üÃ@ÄB<ÄD\ÄF|ÄHœÄJ¼ÄLÜÄNüÄq2 ñã—cáê U¬Š¬.ÃxõKÑÀµpy˜©Âƒ5BÐÅâÀ=0´29[|œq^Œ¾~x|°îÑ©D½ÁûÁµ‹+®/˜ P…pÓ4M®Ù®` d  ›#pŒÊ·>˜zÀ™œ|Âéú*€ÇÉz pwK®¶ :›ìªlÈØ»`ªÉ²ÌÉyë­b5P¨Ìo‰®Ì€‰•Ë£ìÉ‹¸ˆü†Êå;» £Ì³,¯ ÌP¶åzÍÏ,Ì“¼® £ˆŠHˈÈl €ûáfÚH°ÿj±æ!ù,ÜŽÿH° Áƒ*\Ȱ¡Ã‡#>TD¢Å‹3jÜȱ#F% xI²¤É“(Š ¥Ë—0c¾¬IŒÌ›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3CÀ¹sKÍ C‹Nª œÑTMØ"Xkê©—½Æzi`¯'³©ÊF`èÉçÜù4!@¼sQÅ€#L⛅碔# à™sQÒ§S>”evíÛ­ÿº})µÎ‚o‘ÐКð„(L¡ WȺð…0Œ¡ gHÃÚð†8Ì¡wÈÃ4‰N4ó àBÿ0/NGLYŠ^<„Ác À@xAÅ*ªÈ`…gT‘êì¢ £Zîôð5!CΙÀ–.}±J(Ä8Æ+`5èŒV‰x oØEZ1ÆLPÍŽ'g†:Ø¢»HzQÈC¦ˆ3‰l"-J¦[@„F9JD*²3Œ,-  €J‰’Ž* ")U ZŒ1ZBô°»Jþî’m¸@ÆÒÅ‚±‚˜à‚0}¹¢À'Hœ3ÍhÒÑ’(òAª¹2zSväfœ„iL„SœIŒR6ÓùLv¶(K›òQ@!ù,V’ÿH° Áƒ*\X0Ç,p(@Ň3jL8qB› CŠI²¤É“(SªÄØfà„˜yÐbÉWÖ °C§ÏŸ@ƒ ŠPÀIÓ´™ó$‹™‰JJµªUªH[iÎ¥†¥šœÆÌzµ¬Ù³hÓª]9eŠÄY+G D4v­Ý»D'á"¦Ô9MPx¯áÃ%C!fèí@¶®~gÄáW•ä˘ÚÊÌpź8ó¹¥®@Ê*Kã$åæ3çׇÀS£ –”2"Ã^hqPÔ»ƒ/&ëÒ¢£‘ƒ›4! ò€á™BŸ®ÖõRÝÈ õØòªôŸ³~ÿ§N~ªu”¡–oˆÓ4ø‰Ø×ËŸ¿>ýûø§k ŸxÐöù(àF¹8âÐx?9ßJ46àƒ Qü‡`„f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶IÒê5¸ãyÑ]Ø›¼¹tçŒr2”ÞxÒù‡çžpÚ¹Vsô-A–¡Q0(G8(0!bJ63:0”L+@± &œŠÉ±<ŠÑ)ƒ´¢*zÍ5Ÿÿ`*J’e"O8-’×ݬ"âÆuÅÐQÔp@¯à(}lìI´ÈUÜY¨ô]÷ :­@Ï-ÅB‚øå‹_PuD'Š bÅ·"‰ǵёšÞXë¢ø‘ŸÀR  ê™Swö¹ÅÁÞúëg ùº÷kŒâõ©ðÂ{Ökß`0<ñM 5øY…•¶¨ñÆA.a„"qq4!è©Á“|XÔEÌÃÛ"+Ÿx Ì&q«’§ƒa ô²øÒ‰N='ab9=§)=ФR¿¸¬³5…”±YÇè¼v&œçEaglµX "mÃi“زË?o4‘'qÓHÜÿšÿ÷Š#Ÿô £—èD)?ÉVø‹ºáS%‹÷xJäNJS3åNf€y“{l.£ÄÁuQ{8ƒ¦|0Övž:ˆwã\òë§·ôQà´Ïi;³¹ÿ¨ &ýš¤^ï&†vÚ»O¼‹ap €~Ìö²-¶ÄÌò7rÀW•Vq¼‹½Lëø ¤Šè㈈žp õ@‡$ô•èí£Ã"<óÖùcÑ"ê2¤\gm4‘kzµ·†Œ` Œ 'HÁ Zð‚ÜNk4ƒ zp‚ »Y@÷A(ሒP'Ù©B,4ÈÃ^¨¯ŠÑpD|»!s¨C ‡= ¢ÿ‡HÄ"ñˆHL¢—ÈÄ&:ñ‰PŒ¢§HÅ*Z±GêR××Ó-n‘÷ÉÿÏ~úóŸ ¨@JЂô MÉÚ(¥Áà$Žbä‡(éХ³±Ö ÇD€a,a$C'šM¢”†“¦8 å p2´Ž˜P‹Œ„½Pcˆ$*”“à™¨C·$©a¤çf·\¨“l€j S¿•*ùÁ©9èT%CDcpPYÜÀ6œÏ\ÒÊFw$,fmLTØ Qh0‡xܵ7z9sõ«0!ø×ø(5±­ûQÿt1áà83çì°QÇ£åbDÌr<ëŠn‘6$µòÍIÜ#öùÿ ;@Tp%ÑöFÉ FU’‡öEŠ3H¨pÅ[\¡uˆ¬“dØôHž ÚmžÕ` j·Q1¡„BVº¶ìÏ!Å‘‚ã%DëÊ)4P›%R¥D(pW¼éÏòá4yðˆnFƒ@¢Ã‘ß n“=nd —“îÚ5p-¤ŸõŠ®Et[üZFÉshbତn„Ob® ¨àšð+` ô²&ÜÈþ0„GÀxFÃ*B.щ^âß~Q³Xµô²’îá­¼ùjAìÝÈ㔈ÌÑä¼&×å a\#ìÀ&¼ï¼Sãhò‹â”'0†°¨ÿÆPeGÊt]„ÈLK¨ÌgNóšÛüæ8ϹÎwÎóžûüç@ºÐ‡>Œ"¢èà_³™Ÿta¶¨ETA²ŠÛB!Þ:É…TþlP#WŽ]¶§rꬾæ`c{ÜÈ›³À¥à()·@LQ® ¸å®0Á®Ãîj@ ·‹´T‚“Wˆb ÁT+dC‚W¥~®ˆV·pƒ+&ØaT°GC ŠÙ¥+A¦ˆR?ŒÂåRb/.¯"Ñ}¡Qr¯åI:à*©œÃ&“vZšá¡X(¯Ÿžˆ~èUNºØ'8~…rÜõò]I#ÔìN[æG.ÞnеaÈ;!¥öIˆ.£FLÀ`f²(Ág[F ÍâJr¤£ ˜—Ãl—W#A r@g´Ð™BY ’®A T³€±4 rðPÑ'n6 ›W=È0'µÐ_¡Ð^ò_D'‘yÚG/ñmb Äà >&8 Ã@« U>pªF%R€ £…ÐA» IŠÐ|%±4¯w61 ×€&j5…𠀑„rB \ÿa-Q —À2–Ñ€Ñ3°ài,¡Kˆ‡gÒ ÌP €èvÅðG‡nœÔJ¡“µ+…ÕÈ d‡ ‘< ЦiXO"¦&LÐ_·2² ‹RÎ"šãŠ\0µRL \3uw%&[W‘|\% q|àRÅWRœá[fM×aæç"s‡ÂSÙ‡U&xF2Oäw¸0ãgï8€]XGñX†öˆ$ ¤vÅqÛgíŠnòÝÇC†õqGÕ¥$f×ôX`=ˆqEbšP!Ðt&¢“W‰„G°uS˜Aà6¤"Šÿ±*éKÎ2 +@ ÍÃÀ0 ¤ Bã*¢¤ lÒkÛ'Ui‚Ò†Œp.} ^nP ‡+Q°s¦/ì8 Ñ!ci„°tlç”Vfƒ¨—à_£à”àˆ$eåxù¡o UeQ_'XЂ A ´À . Ze…$FÅ—QÂi™á]®Èxf×Áð"™ R%v*ð{è$9 Y|q.f(ˇW¾7bd@f "Ž q|+i)“B0€"(ÞçŠÓ‡ŸÑ@Ìñ‘ é²¹ÊIQŒâüS,øeD×Þùàžâÿ9žäYžæyžè™žê¹žìÙžîùžðŸF‚Û(Ÿ á›öY[ùIOûÙŸþùŸ : ã“.Ÿ¨xzð¹‚:çœÜÇ zõ%ñ§r[·I¹1­yvUÁaÆE4z[w‚W8´` óXæv$J™H„‡%z0,òõšM”Ø ŸÓa£ºAFÑ^ß'´Wº€ )D$P3”æ,àf‹¡nì6næ('€'?ºf·^úæX}³cW™qJ4¤»±dhJ,6Š77¹žM 1P §' ˆó¤* À@  +tÊn:3@hz¨ˆš¨B”¥ŠÿÚ¨Žú¨©’:©”Z©–z©˜š©šº©œÚ©žú© ª…ĨU4< ås ³Ž67§WS Õ ) ¤*ª@qó Hñ´Úd˜ôy“KlKe %oLäpKµþYœoz÷¶¨F¡~òØ¥UC­¡é¸¦%TjÝ!ƒL`EÑ Ï ,U!­0ØêAÊ€c°|ô¡­Fä¢ÖhEoG·&¡7t  Ũ<Ô­–•¥qÚl”™e­c¡Ž$qƒ%/9Xçˆ50ËŠŠµ®Bg Õ5xz01š»Z²&{²(›²*»²,Û².û²0³2;³4[³6ÿ{³8›³TÐJêp>Õ)„ Hž! áP tÀª‚}1 tÍò.‡7²À°OÔÐçI`Us T°]±k"AMdÉg® œ(¡…ø k[Yu¶D¬ªqúÊîıcD'åc­ÂÔ¬‡¥ ZÔEãTžñð®11;§å7‰0¹”žð £.L` B]¶ xêB¢ûoÀ·eü#BXJ°A0.°°…rà¶;ºV[PâV~p Qa°4ÍÐÓ ’Eº·kº« T?Ã)üe ž€S1 Éx0Èû«âY (²40 ï4@ÊöÀù·«¶k¹Ì‹.p9» Mç;º¤žKZnåf Að¤Áð“\#R’À¶ ÙÛ¤Ý9çX0PR± ‡@Zl¿Ñ˜Àe„záW\ÁDWFùHeáwÀíid<é pæ¸% cÓÂn‹¸§¸·Ê«»¹‘û3³jÓZÃ!ù, 8?Xÿ H° Áƒ*Løç €‡JœH±¢Å‹3jÜȱ£Ç +>‰1bÈ“(Sª\ɲ¥K•%M¾œI³¦Í›8gÆ$@ §ÏŸ@ƒ µ) @Ì¡H“*]Êô Ì¦P£JzÒ(ªX³jÝZÐêU®`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„¢ÕÆNnåUIrÅa‡Z €!ˆZMð‰R]èŠ[U1@_±}ÀEŒ€Œ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œ6êè£F*餔Vj饘fªé¦œvêé§ †*ꨅùÁg z>”*ޤ¶êê«°Æÿ*무Öjë­¸æªë®¼öêë¯À+ì°Äkì±È&«l_;.ëì³ÐF+í´ÔVkíµØf«í¶Üvëí·_6 î¸ä–kî¹è¦«îºì¶ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿,ðÀlðÁ'¬ð CºáN'ž qL‰Tl±š7NüPzPà1âšI@(äÁC§„E$rdòÂÇ ‡Üe+t•‡30Òħ ò†*PdâÇ Dnj櫸‚C&œÀ"$ ³ ªž9G"©0È&pÀÇüxÃÛ»‹Ç8V.O‘-s!ù,W’ÿH° Áƒ*\Ȱ¡Ã†mN8Á3jܸrI²¤É“(S¢ ²%GYz ‰p¥@Œ.(“³§ÏŸ@ƒêTäM*ÞT9Ó(ѧP£J:0Ì)©8zBЖ” iRK¶¬Ù³cM­eK ­<9U!˜‚`PR(hóê%Û¨ÉÞ’æJY|ZË­Pÿ*^ÌX/¹ws<¹‘ä˘GŽ’¹¡9sÞí³ðЬ)~j™Õ)kç×s€vUЄ”2X †1AÝ¢©y ç½á #¿$="xòô×Òá ÅBŸÎصD˜VZ÷ Ò)V¢awSÿv»øäwÍ“W(åêÉËŸ?•…}úøóë'?çûóîí'à€-aÒRÙ=•LîåFØbQqÕ „f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšlÂö`›j “ýôÞ›Õ ç`zÒ(C >èTŸmzÄÒk„æ•h8áI]{ŽÀ’…ñZØ8ˆÿ%HP1³d‡GËE:’q4ƒgÈ<šß Ï!ÿp›©PÚã œnÖ"´ªtÉC `ì!P4¿é÷_¯qñ—èO› RÈlGvJ£ƒÂgHMGŸ ˜P̵+=2ÐEѱCx3Õ:ßä>¢.º% ‰‰ÄÞaãþ‰orƒö'gbõÍk»l'D±÷/VŽ*ªÐÄ 3Õn¬\YZ_Å’aœñF,1’ê|Moòj¢£á÷ÉÿÏ~úóŸ ¨@JÐlô 9úŸäË í‰ Ÿ„ [HŸRÐè $/¸À‚FT‘¿å¢ˆ, H€}XÀ,~u&l¦#‘ÁôQ²T48eÓEJBô¢ÂÎT ‘§…î©lDR"  D ä”Q±_•.‹æÈ~z+Ëøã ¨<Á/Nåî !9Í av²ÏŸÒZ&xýNN礊ƒX®‘Z‰®©¦;å#ו¥1'GKÛÂìԆ͆ílyn·+‹=í—Å©4X­l4‘²ˆ‚@^p.…ä‹‹QÄ€ÙüU\ç[FH·qÿèÅ) 1~¹®Ü‚&ÀÒå„B4šà œlÕHVáJ¸¶MŽ*â šÐïµÅŠ †'¬± NK:q¢`¦{óšL@^Ž ’KéÂA®â2\"àÐ+‚`P³(Á `Þ ·¤Õ…0âº$So)AC€e0€.„ ôŒ"¶dišÐ…ööWJoôY ¬ê³è†&ÑŸ*øfùB±pä'€Y$ÑD€ïB×ëFL-ÑJv?÷Ášj/BÇHïP\ånýÓ¯xK~u“«—°^p† 2ïèØ£øk:?&Ë—í†b›DmY€Ê Ã\«ÃþåÿkQ œ°( I /¹J$4!Í- ÙýGœáHã ËšVnѬ ¢„[Æ Yñx9HM 8Ð:\V‘p à q”+m‘/0d:p¬@$¡$d³"*3“Ó³Ðb¤! 9k’2p2 Q„2ÑjÈØh…'ÐÄ& îü¬ÿwY0A/4)lB@xIwª ¨ bX‰G‚„‡}u“ äª}Eø8ÂÔ(`ÙŸÆ~±RV à–›ªH{ilE‹Ùé‚-(ã?d`0tÖ ¤ X¿bU˜Æy‚AA`ð.`ÓpÑÙöÅã.Vá¡›‘ÏÞÔÒÜÿr›'&¨tVY­kŽNž^‘“kÞ¶˜Êóžûüç@ºÐ‡Nô¢ýèHOºÒ—Îô¦“{Í`- ›PÅ«P˜*`ª.q-xÔBäÀÕNv·@ Á’à ÇP ¸O(—iY „UIÂ@åÂw*™ÙäÊf›÷òÞ^N¢Ÿ† „ôF<]r 4 ¥¬0nîé"Àq€ÞP Z `’¾XpH€–ø S ŠÌ £¥A|z0÷B‘Hcûƒ#@–¸!5TØ.\Ô /i…ˆ¢Ð„ˆá„%r]ÇÓr—ìm ŠÇKŽr©Ø¸C_–aÿXþYžJ*a*ßËâuþ*5~Ì'±Òç·Üc‰ƒa`€!‘ƒ% \Aƒ¼áx?æ VW ™¦<¡ƒ…)p5BåoQ oXú²i¥]ˆ°ï!y¥Æ_¶àwÓ¡Bíe ÅcU0`S–§)«à Äe¼…Ë@ «'À_ÉÐKi3laÇ•GÐ G¹wô_ÿÇmR˜&þb·°@‡Yñ++UéƒI7ÕWÔ‘:@-b0 °}Áö$gaSˆ ÈŠ0‚€ p5I°YÃ@‚²õð—QIÕ·%tqpaW8s°³‹{",6€¬pŒ’ˆà9ü• Ó ÀãrUêUi·gÓ¸I†ŠÏè}Ó—rv¢.ï˜x)xÖ°~XX*uxø([cñ~ш¢€ÔádyFrsy´È;ZDVl8 ˜e“E:Á.’~ûè!`׊eQdÏa!¦"qó‘ü×—4vNfzL‚("?ÈJÂ]X–}€\ÿ^)Ò  “EàxeÑéHšˆFi¼auÓ]X £€n` ¦—>£«ÈC ª&!{Xõó чÄaÉ@ÞB ‡à ósòEO«P”ådx‡|r eQT7uó1‘¨„Ð_“æ º7ƒ!y–7 heQwwÑÊ—¡ø¨Ú"EmÃY(\dÖ.J‡ÿøaE™Iµ2¯B+ÎØ§A"XÚ[“¨ÿ<¤À¨a c©ZÊZ prj b@ F9J©)ªúV¡z¡(Aê¹5Ç ÛA¤«²:«´Z«¶z«¸š«ºº«¼Ú«¾ú«À¬Â:¬Ä N?WMPA’ÇÚªú5t§qª-ñQ™Ésb1‡y´!t!ªýC©"!=ÅŸoDõ߇D8pœù±³–ú¶DiH Eº «ÅƒF÷„Eá¢Ü‘§1´ª|Ú¬Läm*ùrIįA_g‘7i¦R|@׸sSD•0Q@f¬D!zßJ®æD{›-!•xpffA!ö²±#[A'ú“þññªÓTPu#d+[ªøÿzŸ€$qòJªP73–±B;´D[´F{´H›´J»´LÛ´Nû´PµR;µT[µVkŸ’wÐ *aQñéðd8‹%ÐAo¸>ZŸ<Ѱð%¡ÛB^»á€T€5B0a[Ñ7vX¡AJ±Öw}ù2}°z ¶NôªW³8·û¸C1ª©è …•Š:WæYèãô/áY³ú( ¹yt;1[{|4»%KtÞÆrº`4‡«*ñ @Qp¶WpHG1I  s”y€’  °¼šÀI »Ñ®3 ÞEÕ¨ßÿk¥§kS¹ÆˆÔ¥¶Ðhu‘cÐ VWzœ‘Rº2[!!ø ¾~ ¯ôš¡¾Äg÷kP8n¬v¶YS0]•¤.X¿÷›¿¶Ç¿”½öÞzxp o0lœÀ[ƒä¬E{LÚX¼ƒ`ºQä¿‘zâ¸04xùKò1@ G <‚ qDæ ö;™ ¿¬t]£LŸfoíg´ãvbP $RàÄÛX \JŒ}'ˆ{Ì.«à¹±Ž]¼wGçEóä~rRz¡å:w<<¼HLP}å)Z4ä'@î$ÆÿsÇFœÇ{,P:ØTHC~3çEyŒ¦mœ7`ãrŒ|rm@q×›õ*XÛ €b$0Ùv³2ëÉžû-¡\0¡[@WÛs”KD!ù,@8XÿH° Áƒ \Ȱ¡Ã‡#JœH±¢Å‹3jœ`£Ç CŠI²$F&Sª\ɲ¥K‘(_ÊœI³¦ÍŒt¼É³§ÏŸ%uJ¨Ñ£H“Bd¡´©Ó§?…Æ„JµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿuµAÔTòD`7I…àL (Ô‚2I5 „/ 8‚—˜š Pt¨!…&ᑇ@uY;¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œú$È•\™b£”Vj饘fªé¦œvêé§ †*ꨤ–jꩨ¦ªêª¬¶êê«°Æÿ*무Öjë­¸æªë®¼öêë¯À+ì°T}Hì±È&«ì²Ì6ëì³ÐF+í´ÔVkíµØf«í¶Üvëí·à†+î¸ä–kî¹è¦«îºì¶ë.m& €ƒôÒKb¼:*¤¼D©F½9š˜Ü¦vÃ(=ÖÓÇq3ÖCe‘‰ pÂêêe¤¤ˆ E.4—‚MøAuKÐÛ@ HÂGBo¡áË¢g]ìÍ cùVVˆ!¥øÆB$Ñ2ň„8ˆ#MÜG,0À@ß*TŒ‹°˜žu5’.q#݈D$¤E D¡‹ƒüFßoHêq‘XR0cˆÛIY.y[˜d–ùI !ù,W’ÿ H° Áƒ,*\Ȱ¡Ã† @‘¢Ä3jܸpâ„68ŠI²¤É“(Sª\©±ÍÀ *Z4àä‰,Ø‘³§ÏŸ@ƒ  … L£)YTÊ´©Ó§P1sJ¨ŒjBI`bU¨`ÊK¬·§S¦HœÅrTPR¹òµ¬Ý»P'á-"ÆÕ¡spZ}¹·°á 9gÌfîÆLÅ·à  ‹*Ș3‹ ¥Ùag3êZæ¬çHn ÄáS©¹cË. ¨žµAIh6G¬ƒ¬²öMì§SÉr)‚ŠFd$(Dp¨„¹%0ØÎ2ø‰»œ bb£ÊÉðb‹8°ô<3ˆ¦´¿ålÄ$ų –¸aDèQqpß’dUƒEoöU†%„f*@ á…Ó® c3•.ÁÒ-e‹îe[H‡ì–8Æ M’ V8X ý]„>•PPø ˆRäbjHëÒ8E+H € ÐÌÜv€Áí“ÌÒš-öi½ Ã\0¾ ˆ ±žÏn|·‚–´ UHפºÍrÈË‹Â[Ǩ4âš'^VÆ ”Û˜·ß¬ÖÿO`~ÑóE[ÍÄY1ú*3B8Ë#~>èû´«šß¼DøÜ‰$1Ý“€!³-Š1G° äHêÔ.ðS‘ `’HR^$NƒTŠˆˆ‚Clq…FÔá¿Ä†ÁnLœ ª(\ …-sÚ@8ƒì €ÑÂ3 ¢f'4€%Aˆ"[ BAP-‡ÔBÕ «Ç’‘ u¡4€vJ’Z€Må8:æˆdhíƒÕÅÉ i­¶ƒo›’è59i„G6E‚µøb¤ak“X`€+èA *`‚&üÀŠš r ‰!€Ç—U!ØÐKvt° ¨D|…]FGÃp D¸/3P¯-ñ„p 2`0uµp ˜eÑ€~`R°Pl¡b AwQ–h&2Á )/ØA Åw=ªÀw‹@‘mÀ5ÆuÐØ’^è»°ß5Àæ/3t"q`Áh²Ž B‚°90~²A=¡–ZË#:á˜w[!íBt¥{õr^Åò'axTkf‹€CȈ~”…Dñe©uRÜHPÏáŒC¢i–z2ÈgL§Z1aÿÁo=‡ÅYÆ#f¤‘BMÿ¨GªÑŒŠ²b“dqˆÝQ $’ B…y`€{Öš  0vG"J0I)“a`icaVe0e<ÛCS©*=Œ nQWaVj" C ôÖ éFpÒ bUiàÑ2‰\¥_P "n°W§"íD5%y´ „@Œ° ë¨È—À’þC ³¨t^aV· JPUcQéêGe¾Q:qV°˜/ VŇ§Ø™O’jvÔAN~Âq0ï\:ýå!™ r§g p">» šJ’¹p‘&Q [‡b 1ç1 N `ùL¶Wpÿ¢dÖ0 Y'²˜\X†øW1h['x ˜s)…AxC²{,È:o7 Z z š  º  Ú ú ¡:¡Z¡z¡RtÊ繡éè¡ ¢":¢$Z¢&z¢1'Šƒu¢3i¡ðyvÈZMô;'©/º(ÁÂ’c—£#1cÑç`>:BÌgŸ‘1fw £”˜A§'¥&yï¤X„ H Ò)ƒà âIY°”é-áÔEÛÑ 3ªøHŽE9E#×5Áh2p Cª¥,I±²¦äñY`™¦%Á§jóá©ò7¨ è9ö1jkÿÓV4JY†'Sþ9*¸žØ&"v!4+H%*¥P ô‚¢¾W GªáÄ,¨* À( ]ïøX$jŽ©&««z«¸jdZ¢#u£»ã«‚³Jˆ¹Z¬Æz¬Èš¬Êº¬ÌÚ¬Îú¬Ð­Ò:­ÔZ­Öz­ØºPYÊNuº7m·&'^b· ˆÉ¨`Gv1†—ÛVu«ñc¬o°ª’F¢É d¯‚à›ðxEý 6C ›÷E 8Ť"Š)‰ EÀ 0-ú6Ýj5[ô[Mñ®ÇÃEù-ÔWô°"á\d¤h BñŽO¡¥IFÊ€c j÷a®‚4}:RÿÅF¬i†³]t °%ÕcxBò  ›Ÿ ª£#´±ØŽkš±NU£°3± ¨ zAV;¢¡Á£#Z,¸ªŸÃ™­h›¶j»¶lÛ¶nû¶p·r;·t[·v{·x›·z»·|;­[À @cˆw¨ à`¢ Lë TIV`²‹±^'”!¹"«åŠ v`L—”#Zûë@©"1¸ÆF5 ±Jvˆº7âgÛñH·¤ëOas£±ºÛ­— ‡€CfW“38‚ÊPÂZvx@‚ä&=¶¼ NW H‰°½“š»ßb ¹ÿ æ¡ ÉpmX 2‚ºe®¢3 ±v1 ²à® i)@ ‘Pà8³ pÄP…rà1œr)—t4PmbQ¸ƒ˜@ a@Xð ·e 1*Í  üq©Àût•Q«@—'À¿r¶@ DE\¶Aj)V¼0Âz PG ¶ç²‹à4KÀ¥ìÁâÆy§VÝ'™¨êJ…[2§H°)ý” ö×oçNܾŒÆ¼»ûP'ý 2fµÃz »°)J ªaR’`_³®X07@ƃ`ÆhG…º/ 9>¿P52IhËdW‘Üâ0TIÅ |ÆÅ¢Ô«¼3àk,àÆPÜÜÉz1°i ±Ãd|/Ǜɫ’9„ÊòÈX&£ØÊ™ì1{º|”RÜuZwËÀ¬ZiçÊÁ 1h±S\[”›Q «\!ù,8_hÿ H° Áƒ*\ȰaA>À¡Å‹3jÜȱ£Ç CŠ9òI“‰(Iª\ɲ¥Ë—0cÊLˆrâÌ›8sêÜɳ§A>ƒ J´¨QÔ<Ê´©Ó§P &]µªÕ«XgÚÌʵ«×¯ ·‚K¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vhá…f¨á†vè¡mÔ$Ö‡t@b‰'Â%U)¾5ˆ-²âT#ÆxVETñ"Ž6ªÕ yV=iä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œ6êè£F*餔Vj饘fªé¦œvêé§ †*ꨤ–jꩨ¦ªêª¬¶êê«°ÆÿÊž—º)‘”â*뮼öêë¯À+ì°Äkì±È&«ì²Ì6ëì³ÐF+í´ÔVkíµØf+iÚvëí·à†+î¸ä–kî¹è¦«îºì¶ëî»Vï¼ôÖkï½øæ«ï¾üöëï¿,ðÀlðÁ'¬ð 7ìðÃG,ñÄWlñÅg¬ñÆwìñÇ4)E#V4Šh²/ dbV&ÃØ£*–€´x²²U/ ÑrJ=æn-X¹ÁˆÊ;sû!#JÙ‚W8^4Ï)β+`Ñ ËM-XÍÂ.H±,ÄOL]¤ tBôÍWõ’öŠ;wècF!dMÄ ÐI-§xA Rý]'ÍaÝe•Ìx†,Þ¸×J#høAje²Ìc˜H!Ÿ¡ E7rnºË"¢ú ™ ¢Væ–It‹ˆ/¬ÂHiQ¾ XB‹"˜œ{îSýYrµ ¢ˆñŸ¼ PB)•¸½ôI Ê8b ]÷ô^=µùƒ ¨ã¶·Ž|÷ŽFÏ=éƒêJûî/jÿÝ蟢\@@P€‰‚þ¥@ý!ª‚`¤w©ò) !ù,X8hi€‚ƒƒM‡ˆ„ŠOˆ‡Š•—˜™—“Š–œ”Ÿ¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌ®–•£Ïщ ›ÖÒš˜¢KP‚¡LJàPž!ù,X8hg€‚ƒ„…ˆ‰‰…Œ†’“”•—–™—ƒ,œ˜Ÿ¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊÁm”£ŽÏ’Œ™Ô˜š–ØŸ&‚Ó‰xyß‘Œ!ù,8Xhÿ H° Áƒ*\Ȱ €†#Jœñ!Å‹3 @£Ç9 ²¤I‡Fª´x²eÆ•+]Êô¨r¦MŒ1oêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²åËE’lËRíæ³0 ¬Õü™¬æ ¥Ï.!…ãèÖ˜cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vhá…f¨á† q´j0èZX–lDЈtÆ•1•(ÒFGI³»Ðb‹i/¦ D#ÙÒÅA”e))AX4œ8GA&Œ)¦DÃ,3š–ä’ÑhâW‰ Ç àQÀ iò#LSV<ÛU+tÁ#¹C ¼CsÊyÈ,ÀIZh„¦VÕ …š¢Y&šÓ¡;XbŒfx1R"˜bJKhp¾Ò"¥dŒäǨBÁ ‚NâbŽ]@ *©£²„¦™ Ã€°Ò*°¦G&ƒôšIW#ma«JÃPIÀ®¼ö ,' ËQ-Æúê벫8@±¯ÂÚ WøÌA”z† ¥J»ìžs²€sJ«,WŽf;-¼ñÂúîVñ`j¹§Š´h¼ì² å¿ù>ª•£[> “AˆJ§K*ê•Áž |ÐK!ù,Ÿ_ÿ H° Áƒ*\Ȱ¡Ã‡#JœHñá3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6xÚ g8(!j`4á…f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)$b iä‘måä’L6éä“PF)å”TViå•Xf©å–\véå—`ºTd˜d–é‘’f¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œ6êè£F*餔Vj饘.J… ›¼yA›‡¸¹Á¨¶A¤Šj¬:Á*¯Æÿšê¬Ñ*И'±Ê 4ÌÄ*©NF…²Æ:± ’¬ æ" ¬©6bÉ H µÅÎjk¸.TáH&T³!¬ ,±@ª‡tCi0@AMÀ ÍC†ÄÅ  ª ««€Pе½!P+œ‚2¡ŒÙo`¼ëP·#=Aì¶¥°®‘R¡-X Ô‹’ÈrÁ«Æ„ˆp0±Ž,l!0·Çp,IRÑlÁi ÉÀ#4Ôpë±@@«<\@¤|H?7„ ,äh@Ç‚3Gˆ r+] "Ãöþaqx$"ˆ@¦8‡Yô¶ÊzhÉ…ÀÿÃ4'àw °:ø§¯=Ð~çksB9P\ .jk9´–p¹åð>~P"[4Q+Æ,º»y¶§_îЫ²ÀyéÛ¦>æÅ’; À£-’¤šH¡zNµXüѹpK¬-É(€7#P@{¬N¹CÞÞÊ*1JœK€~@=æKÜS¾ôY À'tB Ý2R!øzD/ö‘™·ÑäЯòþ?bÄA‚0í CyÑÈý±‰nt³{ h¿AP€IèSÞåN6 d@$¸Bô2ð< J u®cÜ ·¸^Ð[Ç{Q« »ÍµÎ‚ô{aönT,¢pL‚H —2¦7« ZPUZB¡ß‡Ä,1«u¯âÒ£¸¥)ÖPvL]ÍH‡ ÉuWÄ┬hE !ù,X8ÿ€‚ƒ„…ˆ‰Š‹ŒŽ‘’“”•–—˜˜™œžŸ ¡¢£¤¨©ª«¬­’¦°®²³´µ¶‹°¹›·¼½¾¿•º»ÀÆÇÈÆ,§ÉÎÏЬ˦ÑÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pêãÊK·®Ý»xó~k“Ko«b~Q- ÄI.ªj«âI¨l®I+Iªþid’¹$ ° •6‰ìHÀR‰Ù²”9»ë“N!ù, 8Hhÿ H° Áƒ*Løgà,œH±bÅ'Q J´È±£Eˆ ðH²$ Mª\) bÈ•0I¢Ü³fGˆ6sRt @§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžLyçL²/ÇòûðrØ (Á¶!˜RôŸ*öüЧéÕ•cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒ>i¥vMª Pg¯áTåÙD-‰D)-!U‚‡‘L„ª‘6 ˆ!µŠ@‚ "B~ 3Ð5"™àK ¼ðˆ‡F)ÒKj²¸Pã@MBA€#]0 #d !EÄ@†Àa‘$À%lE)1ÐO,ôDiƒpâBÎPpfTAøÁJŒ|¼ÙD€˜ðç0ÂEŠOýÉÅ0œé‚Ÿ,$ $O9ä‚$Tž0G $!%D»Ì˜¦3ÆB†Q4Á“#»2*©5’Cì‡ÂœªÀ"w\Êüv™ÕL>ò¨“O®ëÛ]eìj±jµs©/ÿœ™UçÖU¤q¨‘¿E!ù,X8hk€‚ƒ‚|Mˆ‰„‹O‰Š‹‹Ž–—˜™–”‘œ•“Ÿ¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍ£—¤ÐˆÒ¡„™œšÚÓ£KP‚œLJâPМ!ù, Ÿ?ÿH° Áƒ*\Ȱ¡Ã‡#Jœ8ð Š3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ¨ÒÃuQ‚ 6èàƒF(á„Vhá…f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4ÖÈÓ‚6樣Myìèã@)äDiä‘H&©ä’L6éä“PF)eD0å•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „jè¡aሤ UÀ@êØhUde4ji¥40é§”†* –*ꨓj¨è™šêê¤;àÿQei ª@€šá©­ºÚ+ª¢C‹”CAlzé…iPŠX D}4’DíPZÆŽ*Q‹§¤ÈAŽCLµ"ÒŠ@4s¶ä!Ç\ Æ)îÊzBÄÊp@)øÂÀ©µ EcˆHb) êRà†’(rA•žôQ€-qD!ÆêU: AÄfÂ@|TÄP0oÉŽJbÊ@N@ˆÈUnQƒAÅ–œ!*,3 @:@"—ÀÇňQ *D³ ±L0r ¢ZôÌJò´@ªÐ"³µ¼ÑDª`—‡U’@ ÿ⇠*tÂáF?ÿñ¹ðÍ·£Q$!ª «àœK%š 4¸ã|;2ï×bìiA§ŠZ [n‹&“lðj×^´×™Gñȧ+è=yãÊ®jᲯ£€€çn*æƒ8Í``­1HñJW$rËÛf®ëë¨r(u%Mý:"bw‚øá<딓Žá9C‚ú,²zšv#2\ ýöƒ|Ï‚î¿öž¡,Öó\¼@IØ}÷Ù32Z €—R9Âðà‹Ø9A­q´ŒщjCâ¿ Úbð’ÀQ‘ªJ ôžŒ³Ù.Tˆ¡ c„#À¡«wvc‹L8)¿=o ñƒ"tDDi~:¼ “d#Ê5„v@‚"ÂÄÄ!UÑŠWTQ@!ù,X8 ÿ€‚ƒ„…ˆ‰Š‹ŒŽ‘’“”•–—˜˜™œžŸ ¡¢£’¤§¨©ª«¬–¦­°±²³´›µº»¼½•¸Á¾ÄÅÆÇ,ÇÊËÌ­À¯ÍÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pçãÊK·n¶6 ÙE¥wï©g~C È ,0¨gy Â;°âP&{Ü OɆúJ,‹²çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏSÏn{ðÖhà&¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇗ âˆßôAâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ42‡K !ù,088hÿ H° Áƒ|€Â‡#LÒ°¢Ä‹ Èȱc =Š”²¢Ã‘(š4™²å@–.[ÂŒI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¬%>=ɔᣇ#XñÐÀŒ]b8äÒP6þÝ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàË÷O¾¼ùóèÓ«_Ͼ½û÷ðã[PÔW–U ;‘3ˆ‹`  UÔÅ*ú  H.ÿùdR-AÈ H(Q @54@EO\YPøÓ…° âJ X”$|”6TÈ‹…`qÅPt¢Ä!‡H°ˆƒP HA­"àRCÉ@Á£>RÔ ªÐáÈ A¼!AÈ4¹dP8²•8Ñ‹–>VXÒ.]¦ÈdÂeC‹ÌrqøÒæ›.ÆÇwš‰!.\Ðç‡$‚Ô£–~zh“‰®À xbä6º’FšZ(a–YªQRŠuŠXA¢ò4⦗þ!ù,088hÿ H° Áƒ @…#Jؤ¡Å‰3 ±£G ?ŠœèP€Å‡#S ,yR¥Kƒ!_ÊŒ)³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿\rTÚ†*”MižÐi–Š“š`)À3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ}PÈ-¯Œo´ñ@Æ…g­€A ,p„c³4âPP‚4Ãs\q!†$à 0HJ ÅJ˜PaaA]ÐP È"ˆFYñDLq ²‰ b|QÔ°bèÂÈJ B|‘ˆ³Ë»ð—Ò°dÂ* ( †9Ì× XºÐ–òØI¼t´(ÒäeØÄMÜxÒ› ©„æaL¾iË!+“ž.Á9ç›hB&e¥TÀ €Ÿð°Ã …DZˆ&‰Ø—+ØBŠ'‡•ôå— á Š ~øè#Ÿ.™rÁ‘ТIa䲡D…ŒZª©æä yx0…ªÁ„.îjjO&N°Š+ PàF-KDÙ'ÊþØAñÆ Ò®¢CC&¸aêƒôÔÅ*à°A‚¸±- 0Aйè–úXÂJ¦$-#z“‰ùú”'`ÙYf«GO¾yßÁ óT1¡'å«­ÆŒ¾éñÄ ‡\R–YRlrÈ*¯ (b-»ÜkÉ…ºYÒ{5D¨P9Û\S@!ù,@8(hÿ H° Áƒ›XȡÇŸ0\±¢Å3Bœ@£Ç)~ÌÀÈ“œ\i %Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·êì(ХωwíÞ,igÊ¿zu.B˜îM&Jê†Ë¸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN=9‰ (dðR Q¦Lu{Ü"ä&A©8¤üp‰†û  ß©>{¾€øQ€ø_ûøÒBh!Àƒ‚E"AQH_(1$Ê(‹8Ø ß…ˆÑJh  (pØÆ‡~èÑâ /5D(RG/f7‚žÐÇ~2lRŽ òXà—ì×E'Cê˜L¬€#LD èä‚Å' ¢HJZêÓˆ¸°P~d""ˆ–3ñUf‘F¨ ä Àœ0.H ‹[²ôg€ï½·—€4ñX“¢‰hX£|)K!ù,.Ÿ1ÿ H° Áƒ*\Ȱ¡Ã‡#JDøÀÄ‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßo÷ ÿœ0\ð_N, ˆS&¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0j@1Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’äÍÈä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé§TBühQB°Çˆ†X(‚±à¤C4h‡32:Ф"T鈕Ð)3‚*ꨟ i© ™šŸ§Ž–Ú)x€ÿ ‹ÌtŠŸrDã}¬öêj³ˆúФP̨Š4Ê€Ú¡˜:8h‰à¡`ÌžÎR‹ ^º§t±€¤)¤Ð1%Q³úÕì2ø"%/À*'+Ð5¡^‘ŠÁr)Cìîçé]0 # …²P©ºpkK¶@Aˆ0Y:ឪ{I1"wº3j  ©ø¡È;'²E®Vθ¯& ËÀÿ]Þ† öúZr«[nzæÄ ©ÁÊbîªÛ®ŸžnÇ›î÷eXkàžÏ¸ƒ±¿D"Ä'Bp¨ÜÈÇ.ï_©(”ŠG$qÄ¡ˆ`—퇷2øÇ¦À0i$ŽM@x D:¢õ§ßÁÅ1¬äBA÷~ òúCÊkO(¬°‚Ä¡!@T1?p¢TÖ A þ}-C¶°_Laˆe„K@æG¤ ¯ M°à *”«Š` Ñ 6±QJóëÒ&+Ààk@¤€…~jW1Tø‚‰†Ð¶„}Í/ ÒØÚ͵ î…oH ä`<ÎÆ’ ±¿ bQj(œ€J&7ˆvÖœÜÊÄ!ž®Zwt•…H¡<úQVTÔKÕ?3‚h¥ è@·¡ðMÄt àBP•#JâÈ’•¬Ü4I¡€!ù,X8 ÿ€‚ƒ„…ˆ‰Š‹ŒŽ‘’“”•–—˜˜™œžŸ ¡¢£’¤§¨©ª«¬–¦­°±²³´›µº»¼½•¸Á¾ÄÅÆÇ,ÇÊËÌ­À¯ÍÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pæãÊK·n¶6 ÙE¥wï©g~C È ,0¨gy Â;°âP&{Ü OɆúJ,‹²çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏSÏn{ðÖYnšñgà&¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇠ„Kˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4f!ù,X8ha€‚ƒ„…ˆ‰‡‰„Œ†’“”•–—•ƒ𛓠¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ¿”¡¢ÌŠ—Œ˜Ô–K‚ËŒLJÙ‘Œ!ù,P8hÿ H°`?O(\h°!Á( :œX "Å‹ `4( @Ä ~R$É’&¢\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝÊUçX¶¦G•-φ-y6£G”mÔJ\YŠÝµ!ñä!ˆ¶«ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íž—ÆÙíF>c“ fŽ|#^\Ék¬Ä•ˆ°®œ+!ù,LŸÿ H° Áƒ*\Ȱ¡Ã‡~±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹óçУKŸN½ºõëØ³kßν»÷ïàËÿO¾¼ùóèÓ«_Ͼ½ûãgÞ£„qA>JŠöóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vhá…f¨á†vèá‡+±âˆæAâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¸èèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©&=€†{ˆ_…=4§„mð¨çž|îiPŸû @Ÿ‚ú'A€êW§›ˆQ I Úg ¼0DA†*šÂ¸@)‘ð¢+ €énPऄ.Úß&b<ÿ#Ër4*„ ­Ô:è@´º«Fpâ„7`¬$ôê§B¿ög‚-bÀ€ y ‰Oð‰.Ûß%£DÇ1¿ö¢¬± Àµ¾þGH#¡‚Š Â Ôk’ÒÒH¤íú—Ä@Ž${ïÙòØP³Š²Àª¯øù±‰ˆÅf(Ãã×êÆF¼ðÆ'ÚŸ 3à Œ†Æ<^‘ˆÊ+wŒð~`Ò²k‚@ÁÎ<3 ±Ânª«"2σøü ‰²°cÃŒ CŠI²¤CMª\ɲ¥H”¸œI³æL =ÚÜɳgÆ”>ƒ *p!Ñ£H]æ´©Ó§P£JJµªÕ«X³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžM»¶íÛ¸sëÞÍ»·ïßÀƒ N¼¸ñãÈ“+_μ¹ó¹ ™în“Eð¾fŸ 3w›¥@qâ¬å7 + Hÿ\à¹û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æh€ À¹Èu:)äDiä‘H&©ä’L6éä“PF)å”TViåDF]ù`Zvéå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œ6êè£ûR”oV¸œÀ!ù,P8\×H° €7(`°áÀ(O.tè0€D…+^d˜±áFŽ5‚ é1É’Oª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ«X³jÝʵkBŒ,M  “@L²a-N@R­Û‘m.1û“³b½êÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµë×°cËžÝY†ÌKc º›—e@!ùÛ,À‚ÿ· H° A*\Ȱ¡Ã‡# 0€E/ÈÑ!;ŠI²¤É“(Sª\ɲ¥Ë—0cÊœI2!Í›/5NÔ‰s 2=ƒ J´¨Ñ£H“*]Êô(ÏIšJJµªÕ«X³jÝJõéD®`ÊK¶¬Ù³h zHç‚ÐFXB1äÆfÚ»xóêÝËwƾ °|ðÉàž'º ܸ±ãÇ#KNªñ¢?ƒ¨!*¸K'“C‹M2èÒj/¼Õªª=o!%5ë3êÛ¸sëÞMµÑ!Á·ÅðY4ïãÈ“+_Žòqá*Ä`w3óëØ³kÏM8cõ¡ª·‹ÿO¾<ÚÊè-öѼû÷ðãW i]¾ýûøóã¥ïW¿ÿÿÞ_hඤ^C$èàƒF(á„Vhá…f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšE f ›p²‰ÞKÄi'š•Ñyçždç×$ð)(˜£Hxƒ&ª¥EM4aQ**)•Pì4é¥Y.ˆé¦œ‚×é§Oòê¨HFJê©E€êª¬¶êê«°Æÿ*무ÖjëX|8ÊÞT~Þê+rO|Å”¦¿ËÝZHgì²ÇšªE TÄì´¨U¶”³ÔfûXÔYû¬¶àŠÀ`Øõ]¸è6.±é¶ëî»ðÆ+ï¼ôÖko½|Ôwï¾üöëï¿ÃtnÀlðÁ'¬ð 7|¢4IàðÄxqÅç%HÆŸåVÇ ‡,òÈ$—lòÉ(§¬òÊ2 ÌòË-Ã,óÌ4×lóÍ8ç¬óÎ<÷ìóÏ@-ôÐDmôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\wíõ×`‡-öØd—möÙh§­öÚl·íöÛpÇ-÷Üt×m÷Ýxç­÷Þ|÷ÿí÷߀.øà„nx…»|¸­Š/þ®Ž›8[‘Wn¹ƒ¢^Îlãšwîùç ‡.ú褗nú騧®úꬷîúë°Ç¾r¹²OJ{í²‹;§™ï.iܮۻï¿#J|¢6]r<¨Ý.ïüóÐG/ýôÔWoýõØg¯ýöÜwïý÷à‡/þøä—º-m˜/æ'Ÿp®>–·¿¿ü[®K?¡÷‰"ùo‰GýëÒ¸¥b@ $`¦z¥@*Ñ¢Œ 'HÁ Zð‚Ì 7ÈÁzðƒ ¡GHšð„(L¡ WȺð…0Œ¡ gHÃÚð†8Ì¡wÈÃúð‡@”&ÿü ƒ ’(8.0âˆ*¢;%:ñ‰PŒ¢§è¶FPñCW¸"‡h(-b«`Â,¼HÆ2šñŒhL£×ÈÆ6ºñpŒ£çHÇ:ÚñŽxÌ£÷ÈÇ>úñ€ ¤ IÈBòˆL¤"ÉÈF:ò‘Œ¤$'IIœO",HK&Ë3<ù Ï[ qßl"Êñ‘ =Ù¤Xš(Uæ"Y×+̲÷”R}ÞÒÂB˜°Êøá†n¨Å@SA#$£ yŠ+2 ÐHÂXĤ@›(TØðŽEæàåØÁA’XZx³Ñê€O.Bƒ†4¢‹\A*®#ÎÌS_HÄ AÿF ¢ãÆô•#ê`¢ ká€ü`P\Ò/vqèwvE#˜`Þy»d¿Ô‹••äÊi´™T®Ó—,z‚ :Ò–ºô¥0©LgJÓšÚô¦8Í©NwÊÓžúô§@ ªP‡JÔ¢õ¨HMªR—ÊÔ¦:õ©PªT§JÕªZõn‡¹ªTR‚>hµE¡xÓdÞà’ï„"bL _òÕ•|4ÐÁ*•ÇOnÁ1®t‰(î…ÔÂŸî ‚@”PW[ k·ÌEÿ˜XÜŒ´ý*J"›JÉJÅx–u f3Ë œl–³œA)hgÒÑZ²´¦%ígSËÚÖºöµ°­lgKÛÚÿÚö¶¸Í­nwËÛÞúö·À ®p‡KÜâ÷¸ÈM®r—Ë\RE©hîBáƒáãîB~@9íäÜYMK…Äa/9ÅbH²RŽŒ«5  †ƒ6'Àöö¶·#ܼ鹜õÐÀ¤g$«mˆªp*Úü‚Ò½ÞeÈ[3*Ý¿tt xX.´tGi³¹)@ ŠÀTà`¤yˆKsá1ÀB`ÐBp ‚W-¦Œ5%Q–.W¡Él0q ÄD!ïVnP‹$rõI†ÒȬm”ZÐ¨à  88ÄoJ åÖ²Z¥Ä&€Ãeß^¢•VÊeÔÖ¶ÿWmŽs—Mû—Yú@óy ‚' ÈIIßjÒÝšÃ1'ø‰fBZ‘õ€%¸»BT«`„抅#° DŒ ŒÂ„ yCÚ<É·ö•!5àÏ,º#‹AdžÑTsҨ蹥¤ðh¶ë cÖè„ K4¢ÔÛ`s¢{LÙ‡ôâ ¢ŠóK‘šÄú"ÇŒ'º-gßZÒžz þµuË`2«_ZRø $¸‚âl‚ì[ ‚àœ܇Q$AÏ· ™«Á6Ãà÷Äù»à™ÎA.vM“h Ë×v^ŠŒ¬–YÂ…ÿž÷64±…` E,vô£ÓÂDÎ<”ØÎvI­©B#ø 1ˆ›åÌ—„[ð“ÝB¸œI.sà¥'éMo3Ô£Nu¥WZ*rɱ½«{]ë^Ÿð ­î¸qiA+¨:4jqõ°·]æ ‘¹14` ·ïyìoÿ¤Gý’p5 ¦ZøE˜ö Ýîw?©Ñé&…¼ë§ÌD5˜N‚+@ øLÜ. L·”ÑTð‚œp»Tp‹L}H@É#R‹p„5¾øu£5"¾3Hæb(/ÆÐó­ODíè@%þx¸ŸRÏ8ñƒw?ý‰ˆùI.û6 Š+H_š‚ÿ%¨CŒ€¢†¾Z ƒ¢°H –!DŽý–°ý?t‚ E   x²¤:i§ '†’0.Ì€À#²gÆbyfÀõµ  ŒÐ ‰ `àw‡GkÛT~!æs»„ :Ð{@P€ @ j@¼é}0„XÀmæЃzÀ«àW'¸E¨ð éñ„‡‡%H RXQ˜J@içqAbi02x  Z¸†€÷„8kˆrÀƒíðƒ‚9'„`íàs€ÐíÀeð\D îð|pÿåµp¬ b—@n0ƒXaq@0~@¦p iWqà ¡çzÇÐ-—âð « Ó còÔ!ô`òÐÔ!`pøÐA¼˜ì7Ê€~ƒHo0­À „˜ Œˆ;Ðï 'PqA¶uì•ÀˆàEtГ T`ÌŠñ )@ ð‡3PíÀo` á8Ž^昕°èQ{…HÁÎhtà ¼€ À D ›6ˆ ð `ˆðîФð2À ÐÈŒŒhÕðî(@ÕP¯¶8}Ø Op 0@P]ÐÂÿPLÓøIÐp‚ Œb df`pEùHI²ˆãâíó<` FÀÇ¿0²øÇ` Ì  ñ0 ã"*p–/@ÉŒqÆØ~up瀰5€  “×5"€Ò`¬sÅ ®ð| Á~z)²ÀÐ I “ ©Ž•‘IðÔÆeÎ0¸°I “G™(pU†ð¢0› w™—.`—ðÍÀf€‚^àP‘- —ï &€ †ˆÕe­)Ð8 1É•y™W8ë²[pȘ ²ˆ`ˆn€ w Sÿ`’ٌЙë2ˆ¶€Š›½§gp(Qq\† püÐ^ÀÓ±HÁ`– Á ‹ñ`Ͱ šxf”S0ž¸ 3W`’iË÷«à$’¼P -f™ã¹Æ?9sÉ–`{pi™cæˆNøv`=ð—Û˜f”@žç¢ë( {PRáèj¡Óˆ ŒÈ×°›Ø9 2y**‰ • Å dpdÀV° 4€¡@™§àšÆÇ7ƒ”5ðgàJ'8™  >Г) }ìg €~ò'W` 4?p ±/xƒÿÀ’'5„„æ† n‰@ ¿0øò@ jâ[iÑ4;€€qù@—° £ÐëÕhÀ Ì—\w@âÀ*QE¸˜Øù¢ ˆìä†0Æh ÅP ^0¡P„\Ö£ç0.È*³*(À ­w…p­‰ ¯ª ²Z ¯«éºLðµ eʪAš¢u  й Ð¥‰h«¸ ¡uð›N`™­€±§‡ó“`~À µG2À/àæ(€ &@ õW¬/ íY&v?y£9º‰Œ@+™`¢v‰[†®Ÿþÿàø`–L€G ŸAŒ›V‹þÀl€ŸP Gpø°Ÿm@Œ•¦ë#æƒb&PšØsË£ÎH¬*š90)àƒD:¥pyÒy„=Ú ×ê£ 0¶Q ( C—' Šk±yø°zKb¦‡'ËT`=Àeúµ9`ûÊ¥²µ±? ¸³Áw€“›È±‡CœY©Ü²fœ)ª·”•Á>Zf ›*zq` Sy‰±Ð¹aº„ö ŸÀü0 þ¸›»ÂH×»üÐ>¸«»ã¢»¥_ Kjkqλ•á Ðr ëgà¹Ì ½àº*µtÿ »[ºb0p½Ü ¬p·_œù«ÒkÏ®«x ½0 =Ј‘½ÁššèÛz‹°iÚ+•ÜË>b'8n'lU)ˆG£À1ªàŠ[ÖÀ\6u5÷§“üvŒq¸Á,¶7jõ¥x ÌpusÂ*ÜÀÀм_g)Åç|„Çeþ‹x{šév,r;z„0Àç»Â•“w+\Ä Ük=LÄo‹E½ÎçÀJL•ïæ^Y§À \8rШ[kÄ¡iz ,‰xP, 3`wLQ¬{žUu&LÁ±dÄ789ðlçL4Ãa7vŒÇ}\ •ðºÀªŠp«€lUÿ,<~<klàˆ Õò—+†$<1ðÕfg‰ò<–¸Ÿuçɉ$‰ÁGÓb‰Î¶ víÃp Ѳ P Þ@·m¥,@'þg×ÏjUÅü»ÏÀEeÀ¡£`pMH2-ØÜ2k¡ÀŸqÔ—ÐÓfW “Г piV &PÓRh Z £ l›&Ï[@  J ·Ò›GÕï”vÉmØzln Àj(c`DÐ ϵŒÿ £0(Àd¨-×4Ý- €  Iز-ÃÍÛ)°?4&ÜHÝbỀ«&ŒÐßœÀ A€øúg¨À&jØÃÝbaP‘ß½¨Ûß ëÎécuõI@=Wá-ÌyŽro7»„¿ÖàtR‰¾pÀ(±Ëfâçt `À a{ñ«â+.Q€áúq9ŒÂqÄy挙G¸t˜ŒääÌ-AÐr} sœ°H,Çç v+¬R ÌäR©6RÈÒÄë¡áD寧ÅÃM„pÀÚÅß]Ç FZ_õgað;Ft1“s ”TkpzðÞ0½åâ GµMÐÿ0.aСóaæBeŸVV}Óáè)QŒÄ”>òŸëŸîþžJYÿ-r¦l÷ÄûžäÔ].?ÎlòÌ9Ô{ðªÆ‰7ó"?îüÎç•ôé\€˜[ ÎâêÕtˆwA/0•Qô4ßhÇuN wiØéHŸõ~ö_/L)eix¶¾’&³g˜ˆIhQ/÷N÷“Ì-6oiÏòõSÏNªúöFÚ~/>šUY¸Ù—„ÛyŽ˜ÜÎÃdF ê¹.«{‘l™v ~Fð=WŠ­,0)ð±oŒ¯øå®ñ\f¯œž°/ðíù(N°"¨óÍŽN |šØx¥ÝfeÀ-#™ d}·“WîtùÄ7g®ÿûdfýÁ„óM´&ñgÚ×wËØé ²Óì ÿ&ïû¿Ž-€Œå?ÅdÛ$XÐ A cô‚ÀCp880€BŒ Døp'…2%Òð”PíÎ]ÄhÆB«IƒD™Ô‘R‹!Ȩð¡)ÀFZwFA¹H¬fF:tHKˆ"ƒŒ‰<€$d†fÑ/~HX2Ë“gªÀ2%*JJ×Ë•J$K„ÃCÈ‘%ç$BÓVN‚D³¬€‡îÚ»iå!‰† tø½›ˆ™,%t´x5@@µL&L‘éÆŽWDž\YdáÃ#Ñ$ä×äHb†ø€ý“#ÿ*lLà*VûÖqÂ! žL‰‹¥Æ uÝî.Ù¹çé’£%¨ŒT$á’§WÖþó¯èŒ7ïøÁ2@ ‚ WPè†î3ˆ’½IS`°;–Ç}'?)fˆòªá!µ”»K¤4¨¨½€­âŽSˆ¶+bm0ª›!‘Ú#¾\¡‘ÂØ>C@”+Ž"®ƒ4PãAPñEÃ"ˆŽ/$ñKˆ±ÓÒ( ¥qp1ˆ„DñH‹Í<*#èjP4K’Ò;(%ôB8ù”0€—K³¢m¸…Žªá’Úáä’ù@CºÿH "˜bŠ XIÈ„YåKšq±ŒÒ‡”a¢–F9dÒJ!:î‚&y‚qÚ ¡il™@žxdm Ÿäi !qjµy €ž ' "m4>Áa&:RAÔ%f=ìF$P`#DšýK*X‡ àR‘f¹œBAäŒ *Ùâ"@®y¤åŒjt4"š>ˆ¤‡x'2ÞgŽÐížg£‰[ѱâóº¨äáZHÆ[G%x'Qê½·ÐÔGSéŒ Ž…V •Ã8V‹uT(`æ‘8Þy%ü„„(=>û•P2@®Ö–ð*ü\ÿdg˜'–jfˆ€D[ߺ¥‘î“”^†1f•pÎÓ#f Y*Æ^ªˆÈ–¬7vÇhßÈ2n.‡“o³–9F¾ØïVòî“i×U¼dº EÜZ:8PNè¥í9Öç„ywãh)DVá`ÆýµBj"––d–ÒSÞòwTðɺ=ˆ÷7ÿXeíkR¡˜æ½ÑKꌾ%$i|I°å ß-µ P*Ä¡h›­0|ç­ãè…Ñ}Òžrˆ^ñZ[nc&vÙvnå3Èå„.-! ŒâaëÛÙ°MÀŸ0•+, ‹ áÅý)ÁU(ŠC±Xȸ¾=ö±pI†H ùûÖºÚuDºýÏ\I˸DDArG¢P+´Qˆ4B Å@tqQ ¡D•ü¯»8ƒ PDÚ" µÜ¸>IPÁ ºä"5YJuØ’}DA¥*%$IO¼ƒŠ vªpžÿ¶p}&S7{ †L’Ò”Q¬' ׂVQ“hæŽÈñ’D,¸H!À‘•œÛEÉNwZJ5cç–©E(€Xâ(¨ d\ØîÏ œq »p œ\íu5qç¤î±À[Éð@à+1²ÆuÅí§¥®õ.jßzu_´D$œ¿ŽyuÀB-mðÜk© êÿ"@þˆûá¸9Ü}0g¥ÚO r«Žm/(Œàã®?Љ5JY1œ—0ò&dƒ–·•µB´êÕe ˆ›_ä°“=æúq$íðqkƒÁ->Àœs\Ö‰?Pa)MÁD@ 5´+ àÌQ´P)¾a ž«JðàW_ÀG_Ɇ{ȃ°ÁÀ/zuŒXTCõËAŽæ zhƒöBÇè BüaºÊø)T\ [œ@³™Ü™(Ä¥M$è  Ü\a-°b·Sz¶nœA…;ô¢¶pý€ßÀ‘^&ä[àä$È·í4Í ÀÅ^ UÔ"`7†Eÿ ëЦYì$úísxÀÙ×Àƒ*PÇVÚ)Jڎ̾‘ý†``év±ùý‡SŠ›¾¶ùÀµþ¥¤ 騴:t¦Ù_¾U Á”®m¬äyì»ß+ò1-¤\­ë{¹¤-ƒ\¬CºšMêP™ðl[HÜèÐÞ8³ðŒüáã¦÷Ñç…‡# ŒFqûÞÎjøQ‘=hæôe£gLÆÑ™pñɇ(û$ˆ^îÌB]ꃧ÷8€qi;¼à“„ÝÛÍ/Bñáäõ!ˆ”UöZE“Ñ /7n€õ2„ƒÃ;+¢Ž‹ÌŸœPYÀ¸Ž.ÿîsÛAÝdE;ÿaÓ’×ãý–6!rpGOÃH?<Å?…Éu<ì›SK^6žsRAx"1ALÎŒ °f_À-HÀn— ‡¨°ß‡Tü­DÚȪ7þD.ØÀ†V ø¿{È«aÁº¢•ÿó$°†bð4@bÁ“S°?Vˆ‚e¡Aر ¤‚ ¨¨è#.ûÛ¯àS¸ èlSˆ\­¸…väSºß‰€Ëx|H:Y=èœp[·=jVx‡hÁ1€-<‡ø> ܱkB÷ÛÀÌHûsÁ"È)ê²ýò€-¤€ÀÓ83A!XB1(…Làÿ êÀTºÎ³i¸ƒ€?$4 ,ŒA+0-Ð+ŒÂR€÷#1Õ€üÀ/|? ¹z,ƒP@e{aèºLD²ÁûDºÁ®CCûÛ@@ª?S0BÏÚ,+Ã,—-|Âeó+Ô;íƒ0²ƒ.4„OìD1?©;#*8ÅA^د=zš†!dî³ RÈ ð)|Â3ê?ð8LÂ(œ²äKC>ÜÅýG¤Å՚ĚÓ8dÂï„2L=Á>gÜA¹º1PѾf„«ëʳtd‚ˆšI M¼AqÜ8ULoŒÃü#…õi‚1¸µ@5ÃrÈqûk0•ÿQ±H¢ÐH¨ŠHràÈ„ðHW»ÈýS‹ä~˜†¾â‡=˜D\!‡TI•´†6°É¾bI<€(€Hh7ʑ䇤+–qµRJ"m‰ÈR+Ø„ºËP T+q È¢|+¦ 1`†|È…CðÙ¸€†„ŸPÊ·ÊGøŠ7\sHË0Ê£*»\:ð º$JØÊ»üʵdÊ•{¶L€¼1x„72KøI‡|­Ã\ŸR +˜„òI¿\Hȼˆ§\·ãp'°È»LJµ|LZJ`IÉT?…S>%ÔõÒA5ˆ(EÔ>=N2ÔBuT²‘T0=Ó/US¤¤T ‰S"TP UQUR-US=UVZÒ=-ÕU5Ò µQíTemPTÕ[ÍÕ!¥ÒƒÕYÕUðÑÕVåUEQ`eÔcµÑd%Ö!ÕSU=Ž0à€ éÕe­Vk½Vl Ö_ÝV/%UCÕa UújÑl-W`¥UkeÓO5×QeQ_e×\ÝÔ½VyTj=ÔG,‡.»òÜPxýW€ Xf=Õp ×]×;5U1Xƒ×t]×b½WMÕrýžÿ‰}W\=W^T¢Øˆ-†2 )Y½X’-YŒEX[EU‹W<…ØžTÖ–MØŠ=ÖV”õW–Ø“UØvíVM•Y•ÍÖ†MמÚgíX^mš•«VË0Y§]VD=×”mÖ.×@ÅVteX2ÍÚX5ZOÅÙ­µÙŒØ¹bZz X®Å“¬ÚƒÕV] @… Ó§­[»ÛžÕX{íZc}Y¬½[KMRŸEVÀ-ZÁ-ÜÁ…W¶u[oÝX…XD¦qXÛBÜÂ]\rm×¾mÛZ­Z¬åX‰\Ìí\ ×[=ÜÄ%ÜdM[šE[ÇÛ¼U[ˆP„ŒCÚdµ\ÑÕ])=Z%ÝÿåÙÔ%Ù²UÙWUÓœ=]Ð…Y¢mÞÝÞY•d@¹ÍÕ]ë½^ìÍ^íÝ^îí^ï5Ù¸!ƒ0`Ðý^ó=_ôM_õ]_öm_šõ?HÛu_ú­_û½_üÍ_ýZ–ÀÔ‘Ý_``.`ìÍSN`^`n`×y}` ž` ®` >_0mª¥½`î`þ`æß«d‚.è‚98ÒNa^anaW•·h‘8€]®a¾aàãhBmy(ýßb!b"ÎÞZ°„„0º-b&nb'~â]„$pÏÐ…b+¾b,ÎbÃåR-îb/þâ&ÎT0c2.ãÞàÌ5cÿ5^c6V`nc8Žc9¶_ÐM©˜•:¦VNÍc>vV&mÔ>.Ô-Ý;Þc²!Ô.ÞBä5äàÝb:õ]Gž+6UWKÆã*fà)± …†Z˜dP–ÒW°»ÉÅ×D ˜ÖFnÒ© /SkªˆGäŸåÐÔ‚4x –Ѐ4ß[2åMåúI(ƒ«¥X<6†Vfd0]uÅeXnP^öeÁ;á{åÞ]äUe1MeƒÀæÅ€e¦åòe‰Dö‰)%TuVETXÀç>ŽgÑ%@M1„wc‰”’‚B„;P7SLiEƒFö4°…Þg Uÿм±EX$Ð .¶'`„#€Ì² œ2]‡vÐC–‰€’¦‹Ø}>ä2¸„ï™Ô•>ɇx–)Ñ`ˆ S1©3 6ì2¹A-iÉMbš>Þ¯mæß$gLVW—Š6uFøiÛñgÑg•h+eÃ¥ŽBXÃv´hŒ …€.pP"èH&ë’þá|~Ó-—v‘FÔ·Vз¾çßä’Ðx ˆÔ Ž‘IiŸè¥IÐ>J; °›„V؉¢€ìtlÊ~e(ÌgPŠh A‚V6«hyÐè6ø7¯`‰°ˆÑdEðH†8ÇR éHtx…ÿ ¨ lx$iHŒ‘ë›Ï“8@Ðv¬aö湜s€ÐÛy‡ÐuÙ,Cp„ã>Yª±‚ f¸„¯Ùâ¡w¡€t!wqÙÈd' Ÿ˜–Ò´ÿfWs¡˜UÈ.y¦ùØ™®ë!,cšç±=>¨‡=§Ÿè)Æqxˆ7‚‚ç(ýyÉöÁI­X…«YD©u&·n/¶Ø‚:„ìa:ê•?8z0ý2°·~ìs7ÂØI†Ñxžq—Y¯ÃsÅqˆ– (@h«qçžsÊšž¯/¥ÇÓ?(æàX…'Iy(NÈ¥;ª@€’‡„À ˈ„tÖò{’&|‚Ð —I⫋؃ H¡‹‡¢•¦‰‡™äI$¥ ˇ‚†)#*‚6ê¢\¢¤@"„û¡ø¦R¨b¨zIöQ &ÉÝ™B)(†dÇÿ ¢qXÁàÇP"Å2—f#7šaÊ* (^Ø„ó€{Ü/‡+xqê$îpã‡þÈ&Iâ©(+’º¢:È’Q«ª£â?ßÍeB¤Q ¬KâAÐÄló%ýÑ~Ç3Lˆb¬dB¡Ë‡w¬j¸S£Ù'≰æC+"LŠõ.‡£að¥Å ã hÒ >t¦ÎÝĉ'·'‹Q Yå  ¢ÃŒ%æ!¤na d`1  P—vœ 8³§I“j(·i€$*n-Z* ÇÓ$ŒºYÀÎ$모mÝÙ»Ø žÈvâĉ»ÿ `,6³ Ò®Ýp²cÉ4*À8Ê#‰Š'ß©œw\U 8t˜=]ÕèÝEŠ%\t6îܺwóîíûwo HYòU 25Úq jÊ;œEOþ¹ò"¢ðœxÌØ ûûŒÝ_·,,`B¿÷øMÀÃû¯U ›&Q^ƒóââ5ëµjíw‚•ŽŒôàE1?WU¬"‘%éhK3€pE=î8ÁBNåAgäÐ&ŒdÇZ sÅ‚½$ÜFS„RR€¡ !×a€Ë•‡ ØA@1לW†ʳÇÅÕA£˜©€4?Tbū܅dZÍ’™)ØÿKE9AIçEœ.$Ü´Q(dÀJ9Œ§§¤›”ÂEç"œ  PædÀ îœ]äB‡"a\ƒÉ•БåQD`ˆ‹QˆQ¤itM.h ¡*‡›Ò½hUqÝIwhµH@•fd\ªef–Z± qŠò‚V¤Q‹V@,'yšeT­Xú’F8¡y ¤4'§t‘£ æœy( —>:b`§ÎÈ@¯·&`®mÅîxÅZ(È)ÉÅ  Ò&îDÀ|0 +¼ÍwÄ}ð—@mÁÚ$HfáÃJ-€ÂyuòG;½H”‚ZÀë¨Ð?vÿÊã¬ÌBËæ¡ñÈøôÓÞ¹¿üO<üØ78ù9 N¸`…0É–PØIDP³N/B#Å:ÕÐàƒ ÈƆÀ‰*d¸á¡á’Ë:Íx€ù ZT4³]ŒÊ”äÁ RÖ" ¥’÷]ZTTƒ\Ã$„ W²ÉDÜsh‘¸(ï C¢¼ñŽ+@~ÍÜ©D`…š›Iù;Âûd¿á€nb É©×?@CÌ:¸|¹à*@óÌb¤åËvZÀ z(_g¡N5³Ž­¶üj¶EåÈÈð(E–q‡ÀTñÇØeØ)ÃèöQö›Nî¥üß¾ÒÛ‘‡RÝÅvM×ÂÃY#Ùÿ½éåI4öÌÆ‡ýsØæ"vêQ¡i(p´À@`8!-†Ør¬ÐÍ}-lÐû@*ÚÑ9gÜ ½€Áĵ<;3aà$Ðr‡ ® pÂâßXÁ@x+ÙNïFe:¯ƒÉÎS’-¬‰N|âÀþw€.ÜAÛ!(ð9DâY«`¢áh ŒÈGLÄ(œ DˆpC¾ˆ@Š €v ‚¸/5f''Ÿ Ø€¡2h¡G<ì%xÒH°ÆŽ Hö€ ÐÍ ¥ aT@V %â"´ãÑ¥'õÀ¸¢Tä°\H@Ô  ÿ¸£ê" - †Z²¡ô0"3y€™°²E…½`¡ €/y±ÌÀí`#^`Œ;Ä!Dœˆæ, '*a+¬´f_ÄBå•_T“™ÐT&TÊÀ¬ÖŒr †q"K(á&ÒŽ_w R‡Ù°}e"ÊLçÚ*: "h¸£ÐE;b¸ñ0º Ö!#Jˆd0z®(ùhÇ,c@Ê ˜°F'AÅ::€qf@f"%Gå!Îvàq Ì8@7;ú%Ÿd‚ÎTvªI"d`‹¡¸eŠ.ÚŽ<Ê”£`¼_R·¢R ‘¾áP s2/¨Jd©2ÿȦü‰K’úaDZÍè3yhK€:O°©ÎèÕ•‡<4Á,„“T!±f…"d#{Ö]À J3 @š(í²ø„5 #Љ´kŒ\®˜6_\H-|6[#kXƒB£ä4n+‘ì,؃mmKÛàâvh…Ù¢‘dÖ³žíag—ÛÜ)@4‰9Dr±£Úi<ˆµŽx®TkœývHÂ&â'<"4žHscAGñÂf»ÝÍl{“0°8½]»À¸[üºW otï"18'œè¬½ª‹Þ0¸¹ùrÄ'èK^é¶ ‹P€&lØkW³0€ÿX0 _ ¶é͉‹ÍKb×ÆÂ³öl,!`ÂJÌÉ”Ëaðö1Æ-Ão¥p€1Œá²+ ð|ÓkâõbÅçñï}|— 7ù ‚'<’¥ Ì)ÐÂoè»âöV´âýðŒÜ_Ã^gQ±ˆ¡<¤¯6…´1kÁ!ɺÐQLkèèEÇFшf4)ãŠö. ƒ´ÿnÃLø;‰qô£C/Q£ÒŸ&uCêUl±.õ«9ÂM³ZÖ¶†ÍQG‚êC£Vu51µàehMüq¬{}k"Œ|†~¶d“èQ+ÔÒ¦ÍlÀcSº6¬Nز«ÿ‚Y[Ùª67¬{­mi£;Ý…áu¸‘ÝnjÇ{Þô%vk=kÜÔHßãZìoméSÏÛŽN̨ï}îz›gÓÐ~8[Mpvû»à¡Žð¾ÉUq½*Üâÿö¸bËGçX{Šá99˜É.py—䚆wÊ)þr‰£\æÎf­mp§uå6ôÄ{¾sˆýáÏÌM¾ƒ4£àÙº§~³qëŠÜåÓ¶úÅKsƒ»êšÖ+ÍWøs¬ÇÓ³)»Ê«îó—úßÇFôÚÉ®q·/¶èv¯¹ÜËWkcäB&o9³>wr_ãøƒ ¦Žö‘½Öq_8à]~t}"Šg{å /cÿ²ïÚS“ç|Ú1ùvÂG¾ñ:Ïüéï®z©‡yȃF¶,¸"&¯ÀÂÀCeLhPâ$ünåtÀ`ßòôö²ÏC ´}ûHí@~ìS‹ägúÕ·E Ї°|M( ú€‰ÄW—ê¨ÏtZþ~ÐÓßôa?{¿¿n†o^"¶©?WÁðë©ÏÙŸ²=äÝÜê5 Ù-¤D ƒ2$B4Œ)¸A#®’ZåžÄA™¬B `Ö,¬×Àl€@'ÜA#ÌJ+@ü- ‚rà¬LÂÀ”Â)ø2%](ð  ƒ*D 2Là Üÿ  ÕˆüA›Öå„´_×9 v¡~!†¡Ž!–¡®‚„™,ôb!¨-T€ B™„ضÄAmd¡TÁ F*ÐÁ.|ªÑ@É,BöÁ!H!¸ Až4‚T˜—h„Ç]Ѐ¼—"ôÂÄaÐab— DaN„A"@Â$‚œÜ§9–û™!.æ¢.î"/ö¢/þ"nÁ%´Ä@ØBT—(t Ü`–Ì`€LÀ1BÁ%äPìaVW4‚DDƒ¼Ñ'Š‚D 4X6‚bd 2™‰$d@ð„x(¬‚~…â„ãDÿâ4ã8*°â©¥ÂL4Ò"0¤A$B&¤B.dÑm 2ÅÁ0ì‚fcîÂ"@ƒ6>øß,(/èa @'tA@ àÁï €*IDX‚ÂÄ  ‚–Dc¤$-X$ Àá-Ÿw!×'Êä,¬B Zd2Œ„c™À àšèž¸ ä2$UV¥U^%Vf¥À[-A!“JE1_Æ" TB&œ $(‚Z2Î\¹@Š¢%"(ÂHäy\ òeì&¿ €4 °_–%X@? ÀbÛ'¶%PEh%gv¦g~&h†ÿ¦kAX„aØhjXX…&èY‚qVs­Ùj9F„1™Ò؆i2—Ù›‘M—m:‚û!š}a^h'q§q'J›á=£-.§Å%æØåœà-"§u^'vf§vö†sº[wÖÆÿ¡ãi.A&Ým§z®'{¶çgz'š§zܱp¤§{æ§~î'š!ÔÅgæ"~ö'¨h´@.ð¡Ÿ}çåÉgèÕÝÙ'‚V¨…^(†.–¨åvä×M§¡ (ÞA]†–¨‰ž¨{rÀ¼ã$À3¤Â.€°½‚ ƒ›¢Ã>è: ´hƒ6èÃ/̳ œÇ8í³8€ \÷8÷ôÐxK„>胸ôÉËX „ÄH ÃA A±@F‡ªí°ÃÅEs…9Æ(´püwVä’<ž5¯ŠfABÐ’‚ɦf¬E (fƒ\@øSPnGh¦K$uqèÍR7ÄC€ÁGÀH08qdÄ^løPŒšoÆXØ7'0ÄE@Ä4d„‹8rÃô€I ðTÀÿË E•ÔDM»ö”Äêd e\+T&„ð‚ ølE:ø…NÝ‹#¹{WEZl…;¹˜AåP3¬¤DtdKR\Àƒ…¨Á(Ô…;°¶Ò@Þˆˆ²0 ©è…@OuPÀ‹­‰8ƒw\êvt‡B˜6tÃ>ìƒ=|:ƒ3´³HÃ7D˜”7Œ7bxw¨¯×x£ƒ¨Ÿ7Èþ ÜBuQ  0 ؉hìH—˜“óÛdÑ, 0‹¥WŸ´A ·†“4”YNI¯X Cðn|³N”#ù•Ìtº­”Ô:Œ´Š]è 4©ÌzBÉ…¯àЏºö€3\H¸Çÿ 4»èGÔ‹'–¬B¹Snd‹¬ˆœI L¹‚uÀ£(B‘l´’l…·€Ë'¢„ôà“Õ9­ÀJ<;¦poªˆÇ„CîTÉ•d ©”™ð¹q–o)Ð,NÙOé‹-€Œÿ–²W‰$¤ÌÌ̼ÎK‚ˆÅÌß:£ƒ6¤3:tƒ>½zÓ3…mwí³œº¤ú:3As­µþØçÌÍ¢„Áòôõ¥ @¼PåÄÐçüÍobˆœP•À±8H¾Ä$àÁä,PÚŸ‰Ýÿ ƒæÐûxÁµïQc ¸ÌF€yç|}(œÂM„O-öýÚÞ°ÿCËŸÀÌ  Žà¤º¢Ž0¼BìÂ$0åß„ç@ÀÌ qˆ‚Eyœ˜TàÂlÏëØv[E@ dÁtvP¾!”Âðth¦uÁ•g$T€ÞÎÀó²Î¢DÃØ¼ yâý€Ðð?C àÐ](™ÿØtˆÐ¢hæTGï«|qöÑ „R˜‚qÑ8 ÂWDR+œø1…£|œÅ *íôˆS0À#bH¤R‘@C6–p#º6F¬´±ÏÞ>B¾=ààÁÅÐ…°ñsÎvþêö’åFm2M–Lab Rðj'Lií®Â˜Õÿ…O¹Jm @L)…£6Ôëç…²`$KEꌼ¾r Ž?œîö`0@ˆÕ \Î6®J«A„zŸâJSH‡ þ¸©ðÔ"Ûò0Zð¦C&Èfg\ä¡$ø©íšÀ·_¶ »q¹¾¹ÅÄ)7óÌ5ßœs£óÆÙñÐE?œô‹;?õÔU_õÖ]vÍ{þÚ·ÄwР€ÒóTÑî»%,‘ÔÑøâ?ùä•_~sál̘\Ñ]ÿm$I vçuÿ£‹˜ÿüðÅŸüòÇ Œ<°Ð€ÔÀ‚R³PŸ‡" 2pÃ*(™ DXAD¸2.©ixhL"7@E+l¡–@Ï#=!ƒ5‰€Ä® šM@…‡Ôæ6¹ÙMoªn Ðþ J,Á ÃÐaì2%,òI„VyN<  Ë ÀÕÚv‚ìåt¢&ù†?Øñc D: ÂÍ@ ØÂ!&GÌ´ µ6 òÄúF o@–9¿YR“ž¥)=Q# á¥.¬‚£+¸„-ÔùhÜ%`"-j!—Ê“$¶˜…ä 0F°ÍÐQÿNIBC‚ b¿Pá:FT£4ƒ.(I$G@jr,õRVq«6œ—°â0ùˆ¬lª®q•ë\_8€ bŠˆBZÝ IàµW+F(DD&x„€aX‚¯„8†ŽÑ?­ G¯¶Pá%úÊF ‚@½ãÚ Rt×Aä .ž-ÒºV¼ ±È@0hGWÛÞ·¹=©”µˆa) HCéD” …¸<À@VuI”´5LMª ©|Ù»ºöÕrNpM Öu…f]ÏI{rîÖt[^óž½/ú]v-§Ùç=îq ­­Î –½¢ .½ùÕï~ù‹¸Ñù¶˜Ú#/{/ÿ÷7SÏtüUð‚ W?xcò…°× |Íù6ÃÖp]<9—®aÎ[ÑÑ6\bŸ˜y€À_Ö✷¾Ss±Édb½µ fÎ1ŠyÜc§.q0 ‚†AÍîsŽ…‡äÿÊQ–rÄ´rPºxੈ´°‚W¼á)Ã23Òå¼b£fN…ûøå0«9ÍXF³˜Ï\f,à =s¤äà:ÑrlÊô –œMÆÁ HÁ%¨‰†4C~ôÍH!ŽÅ%PQMEs:ÓŸÆ´£/jb|`šh¢iaj´ fÞήGh[ß×%šƒ%ttÐÿ{io•Ú ºüë_+IÅ~™²Åì_¾›gÌ>_®©]mk³¨bÃB Ï,—8'wÜe›5­¯]nsOÜÝE>:mÞÞñöñÕ]=´y¸Þñ ±¼ùÝoÝNxvøFÙ¶ —¹që¸cþVøÂübßå{àJߟ^q‹Ïá2.IHàËñŽ}âOrÈÛMòûz»y{<#“‡\ã/o1Â#ìò Oàâ j@‡,ÜyüÃÛ¹³]üm y7xƒÍè«=f\ðhOבtÚb`ÁfTïyA ŽµÌ@G_èzÊ=9f¸¯„d·ož®Î^­£íêí>z‚Åò·KÿHÀ”»À—*Ì¢ƒ›i`Bݤ>¡Ôâe4—yž`±t¤ó7uæxÆr®ó¿mïnƒ,TtØú ¦àg‹‚'X š4ˆÓÜ&M¹6ßÁý@w1îutù0ˆɸÏ€ù^Waæ¾qçÏÑëz.=gè@%âÙäÿ QgŒïäÿ½"ç=ô"€yê!„qg¦°å'g¬ ×ор#}‘:?jËz`?`•ãTHtA…bà5B *OF’>àr4 á‚À’F©@*ZaxÁH‘XàÔš Iˆ!ÿbÿ®-$ÁZîàþT0OòØV@‘té ÂÀŠp" ¼R Dt ìáe"Áÿ| P üNx®1H Ðà t "p#(ñ¶aÑtÄP@ ‚@ €ã¤ÓDˆ‹º€B £ =ÀO¼€„M ¡êˆÏS±@ j€!(p@€,Ö¡ùa ‘  Õ‡΂Ô€"¶¨õ‡‹Òà@& ‚@}xn¼ ûB¢À?ÑÌFíeôpëÌ0mP)0e4E1ç0$¢IÃ)ÑôÃÐÞtÓ` «‰ r‘çæ@¸Pÿ¹,Ê€Ýè¯&î€â d ¡q!ü&`nžQæ q oˆ!–NI%©qèï0'@ˆ(I€±HpÆ¡pÉ ÖÁ ¾  ¸à @D²j`$XÒªDþ’ Îà0¢m+ F3s42 †ÈÅ€ãÈÀ0(«0[S0ýÃ1w86’ ®†0—QܲÞA~“ Æ!3”6‡h.#@’#Ý<Ó2‹©®TÀ1G’ÛJ 0 ŸÔ -}ó0ó>“2-3=’plïlØ@Ã.!2?2$³è‚ŽSt3# ‹Î£è2¢3M¼S=Ý8Å¡j*Óò¤ ªO@'SB;ã;'t|˺L,D"eä3'ê RRj@ ÿÚAJà:ÁÀó½À`4¤V¬Áã"a/®FIÌ0Ùâ+jT¨A]èFBöŠ Ð!(Ð@!)8@ÌdVBM’2¨rKBà!`+sB´TàDAxI‚ÁE7é ¦ÂÅäàx n7éðÖ x -*.Â?L”œd8 ÀEàÞÁM[¬7‹é3Ñ”|à$ Fùê²3 `¢à6¹mÎ÷J`$ Út"AöÀFÎâ#! >5õ¢‘SÁ4ƒQStE3õ,àTN߇t•9΀U› df5]Á¨€Jô L3$ÿ¶“T UÕb¼ë):Õ0žÂPßõ¨µW”•â4p2Üt;bM?gì* Þ9Øt:T ÔÅL耑2¡P5%y@EYôO£À\Ã&žÂT ã/ u`ŵ$´Õ aDÕ‹3fCfkÐR$ #B!TùOQçá aŸ¶n„iÚôh€h`¡þ ^‘e)º&¾*¿Á’BžN„"À”$¸”„‚(” ´Yüã-Àþca[ :à>ÜÏWñÂ<™õ/z*d¡N#°¨ïð,e§–$0¡.%#Ló)L<õ+t2ÊÀ8©•gÿÄ€Þì¢dc4P³VJ\U_äl«vj#_'ƒ0³ì@ÂWg,k FV.°¢7Õs+Bgc2á4õ)Ô–mG¥j§6Ð’މ:TeNÄ?þ3M÷ NöïN¡. v%@:þ"¦@F_¦ r@`;[× Ö–o?×^¥¶>;æx¥ƒ —n€ ª÷u÷Æ ó6–¾>óÞ ÀÁE· […oÙÁâ5Ú‘"wáì`Hò@G\”0à r€$òw(”áé ¶€, –‡ÀglK_‚*ѺaN¾ÒˆvKÄiAiG€„ÿ·2´ BÀøyæ{§–o£aNã²èžá@¬àˆ  ¡˜àŠ àˆí‡ç@ˆ/½`nnX¸¬p úRö¤à œ˜ ’بÃ4ë÷~'ô‹Xfø8U3> ®öe—CëwNx.ß8P™ õ¾@ˆÃ!X«¡3Ú#ãw~‰J®A‰1X\ÀÛaˆîøe𠊃XZ@~ǹ‰‘ù–®8‹Gå┋ô¬0Ř<, (OüCŒÀ}X‘má”í7g÷Æ&¢`€Žwó,­—u¤ W¶ó”­ 3’…Aÿ¥#ùD¤†ëu@³Huk˜”ó†@}a„"»à3¾"ôÄB”CÀ?Cb üâä ÄÁ¤oz*bÚ"x,x"äACn«Q‡ÿ²°¬‚š §í@*´ãC<éoõCئšBJã,>È©OáÚœ+äÞy2¸c¦¨ázj¼ú4—:œQ®Fn„\ŒÅSväX²À’dI²äYˆ Ô„Fôå–_ Kt4`MüdLäÆMH…¶ ¸Ë”MÜdÊ4$Ôdöê$£ñ$OÂ,µ¹À´3©WŒä÷FZf…Q&@¼>å»g¼œ¥1žàº—ë»WE¹ŽaP…¼-_J¬@Î`p‹NP÷O&rèÛ¾{ ¿ÃûOÞ[½Ÿ‹Y¼è|ÄeYŠËRº{Rl[¼c»Ræzqü[¶@Šå×þ \SܼŸ¥SÿtO2óè\N›`B¼V\IZ\R~$ÀRYhÜRZ|jö{TFûzúO>gøÒ­)Fà…ÿmF`àVÆìA,Åë;æNÉEîorÜŸCÁ¶ü´k/ƦæÀ:.È=nDRÀÐUÝÀCúJ>UnĈÎÿÆ\w€<ÎEnè,ö„œF^XD’[bÁLåZñŠœÏú¶ëàø®iú;rH,æLníú/Ò§;>W.ÿŒåìœÏíœapîÈòM,§|åªyÑÿÔ =áH[´ßMÌÐzPÒ›Ntj¬Ð]$ÏOŽÕXý8}ò\½Öaìñ>&ãýæ<ÝÕmNß.§˜AÕ½ÌÿœØ±æl*ŒÑÕ+×ÁÏ_.ÚïMصýbPœw†'ËEŽÜ+éýÎ;ä=z¦ÇÈ·Ñã}ÆÆÁ`Ü[cS=ßkÜv]â&ýÍCË}ÞÇ0ÖÕÝÿŽ€6¨}N~b`:h}ŽðG ùÇ&Ð €c¸Å^¡Þ  )^Å‚`fˆ#ƒ" R^ßçîe˜! L(RHÜ>ùнÐÃ<撽гÝ诼ßþý‚^íh}Î}}Õ•p^]á]ä‡Á¸h‡P!h6¨ètèˆbÒŸHbX² 6 ¦Ü<ØÚè†èȈâ@~èë‘AK¨n±ÿláÒ±Ž&£ì>ȆH‡Æè™¢í ±mâ¾sÒuu uX|$ßm–Lbf½ê™çºgZI‚`“Aš3Íâ±÷ :\Pp æ© ø úÀ”öJK Àó;i^©™Š õӱ塗ŠI€àçn_H‚‘&©’P_ ò€ReiÆ¢iš®Àz;šHšÞàv Êx0FˆÞçkŽf6Ÿx‰TJ”œ@­ÔÉ VÓà‰T^ßì7 §p`0bÛ6lÁ!Ÿ]](Àá†Æµ7R5€1c I‚:¤Ú`†"[’8™qÕŒŠþ £EÑb§†ÿU¡ÌHpU´›812,ØS Ð¡D‹=Š4Ò¥L› Ô©Ô©T«Z¥Ú3kF¦,¬â” Õ)¥<ÃFMºõªÚµlÛº} 7nÛF´ eU¶]À… .læÐ"‹`Ã1\pR»Ù’GU‚ €•Âe,_’‹VZ'&N^~©%AŽ8â_eÛuG ƒivùÄ/|ê¶è’±uÉæˆP$¥åEI¦pñ¥¥å¥¥©PG†Jj©¡š‡*Y@£‘Žž·#W®¾Ú*­zú$®ëej¯»Ú*é@À º©£¾‹l²JÎêcVX6;lN»#³Pк€ ¸úl´8bÊkÿ¥IöÊ鱺®”’Ž –·ÊU®²òÎKo½íbk­§œž4ﹿþè«¿N¾Ú]¸ìÚ‹p /l*¾3Ãì¥ /²ñ lÁ`IÌqÇüRhYðj2w[œ²[· sÌ2'Œjˆqt‡»ß6L­{оK.ÍÏLtÑF+[³rÒT”"©Ø€o¯¤’œoó[ïÅ/ytzZw vØb#œ4ª1a‹-qpÁA 5¸‚ÜÒ€ èØRŽÛ°Þgù xà‚«ºd-–`Æ*(%õâV›u“Çj.½+ç8xæšwMÐSæ¡k’¡Ý#ZöN¾kÅè²Ü¯ÿή3¹yìE_~òëÖªKë§=þ°¨înm{ï^q}ê¬áYj²ìÊ/ð­Áã-¬óXÁ®;íÂ>Ÿqvù¢T=ÐHk‡<¥Öß‹rµÄkÏ|úœël¾ÃãƒO,Z¢ç+?ôÔ‰ÏSûÛ—ïUüã.¼«ìrèSŸ™(ßï~!úöμh©åe™ÒÊ(H¾z¯T_; iÖª’i0w—òÜOè@fí(i&Ü`ýPX:ýQ¯‚”ûÙSÐU6oQîzö»!GDç(„,"Ãä ˆ%iÈ™÷œÇ?,)¯Ð€1\E¸“$‡=aFµ‚DeHaˆù4P å|)À€ÿk—./b°„2Lá°ÂªZi€ŒYibVÂø4”ÃcÂuiȶ°‡Fl$™)äÐ:1h8²B‚ø ¦ˆÂu4Ñ4eEèÈPÊ-Í]*¸’VÚ@$ á…8q‚^@ÛRž˜U–@1‚HáS8„@b‚d‚—.“V%{Q'”b¨Äè]Œc 8ù% ù&À,bd˜u­’ùsRÒ ë€&O†)IwAæLÀ<—™4b(ó›ÅÂŽ¨ Py ¸C ”A˜D$â‹§P(ÞqL"`“àE0²ˆqˆÃB `$“‡$IÿjR ¤×ytPŒ €8(i Í´HȈ1ò‡D~F+NÈ/|s"v[J€¼"@JX@A€ Ð$šá¢8ÀA1R |&ô_ìcV0‡D á _=E!Š‹¬p@ ‚*|a 9ˆZëW174À j¸Ã8"a¨DTõª ,ÔZèµ'3€ìW±ºP ¡X Ff1ûÅ(”óÉF;ؼ-zÕ@cÑš¤2¬(1ºŽ¸–6“¢0(i\{Ðd´ñB: 2€!Ô6i+cÕº‚>\¶.hžª© ÐkhQëÝÿ€Š×WÃÔŽLB£ïàÂ+"@W 7[XšC j1… \4& É$qLdMý%Èj S*ƒ '8€‚SC •öd( Äñ ˆ`¼”G<Ú€~œD7 €8âaJ|ÈcP GR8Ðh4"·3°ÀzDZ‰DBÕœ˜A|ª— Tàoù0_ÒP¤Ã* êfÕÐX@‘‡©j 7 ¨ækÂRH£9(ƒ*¦\ ŒÃÃÌ@5¨`ˆLÖ ê8‡J‡é#ÈžðD*º|ÞjHaq¨ÄÜ!ÑBCtÊt ²LÀ"@‚„@0ÞPçCÿüð NìëäN#XÑàxo2Šq/ t u„!X ˆk0™Ê5¨sY¾óö@Õ6–‚­ybß»ÁB²FI¬sxlì d8¯Hñ‡`áx•Saë÷XÎtv£Ù²¾¡Èh2¶#Ú³ñª›=¸nÅÎÀ ÂÔ@ íàD  QüzqöEÀÖ¡à#ÎPƒ0P}¥XÃ@A°)¯µ#Šz倊J¼©Á„–öЀ,Øâ{1¬ãáSãƒY“Œ1çuˆCÞFÀ1f:'„®£‘–jPsaÐ îD¼ÀsCÝ[—è, 8Ìûÿ›hð$\0Ž`øàù>ôÏ<à ˆjiè¡€ ø0Ld`@€)屇à¸QÉNƒÄ×!‹­ªý '§,ÑÁÀw@cê›0&ŠÑ’3lÝP+ð€€5| ¢Ìä%Oy—„ïÐhA'<Áw³ú×ÇžÀ½ó½o”hþ ‚ÁÒE¡8ççA'v¸J¯œº{~ðV”@ i,aëJh¼€ó=µ½O€»h_ïË×€ò‹7¾ ×}îàšÕ|/C—!PoK@ S€ò;ðHx´(KG¨ $;Gk‚'î¨~äàühDÐð eÐôÐqAb,vbCÐÿ «0l³’ TÀI.à}dPõE Ó€I§l-à{õ–IÅ” 9в¶vGVàd8±ËF s ÆjF'~r ©§Ea‡n¢Gu&zp9Àá `¶’`s±dÐyÜÇ4 ‚Ðw·„T ßWd2ÂskU —Ö3á[ZA†×°f4(„² ~PHƒ?ˆnº 3 ƒp…DÈlbØBpgÀ †‚{HWl1b Åö†uÀw€í@%¨‚VPÈ·ÑyGƒ Pd!†… Ò°‡qÙgŠì†€i^poñÈð€>`~tCÿC× 0V€) RÊ•`ëà‘5N@ÑpRm'c½ˆŒ”^‚"F—Hq üÀ€àa tàcPÉp3`¼`0Њ8@n€²w€ƒø%Š®(tÑ *àLP rà}V0 ¢Ðв°×å´ PáPw(”Ð=>p @8¬f#ÆÐNöI¤„¸3+€‰ì€m¼……Exw€  Ès ‘pfI†Ci 3–^‘T6R‘ìë Ô–ÙPgZ .i OI‹èöi5ÿ“Þ÷AyM=ñŽñxIzE×ð’e1¤4L‹2IŒCG†† é óˆ&$ Ö–8) E†”JI’ I yŒ§™Ý`]°‚yœ” ŒP E0u…n—Ðsp’iPSŒP°ŒP(` ¨™ZØ"€`²){P`邟 GÀøÀàlpüô€áaÄéHð @œÀ‰.FT¶Ñù° ‡p™¬@¨‰ Кâ‰x‡é@20/0™w Âpoãy|§À v 3çwã` / ž?Àj%èœI^WK ‘†`(€í ÿɆdfOóY!rÀë vŸ1 Ÿ :«Öj&lÄdvQçI/À“t𣑡õy6(9–-‰UÇŸSxr) ûÑ¢ jÚ³ùŸ‘x†Š 3*+jŸü6¢ùù>:›Nz›7Q„¶‰¡9 rÐp¡0l€©Ecvž``_˜ùºŽ/ªY.*qš¤™qZ$@%o¢~"Ž'§h2p>1q¸5}ªE °›¿Òj) ×9DüÀÝÈ{À›"_"©’ª(’: 8 ÝHTÇbtzyÚs(‚&O`%ÐgO ÿ'¯ú%`2~ò&Z§²º%°«·Zy¶!àr±·Šwz S‚(>!޶:ªSr&>r§®ôP`N¬Ú«pP¨IÐ(\¬¸z&‘’ºŠ&Q¨Ûb&»*Êz(ÇŠ®1Òà%†r'•7½ª§. ¯Â=×­l’«ºš¨äê&¶zLb@(m †š&ÕZ°»ê¨+§[A¤±À²Npbà™ôµ±Ø2I¤#E0T²'ë>*;²,û;bá²'‹±3 ³-k³!’¬Ó ªT+uÑô³+{³);´1˲‹Ä>\d´@Û;2K³O;§=‹5J›=?´´R‹=&ë0×â-Z;ÿCKôJXû-bËHäCÓ£At4P˶-ƒS 0̵=^K¶B˵SÄE„c·¼FeT+0°SZGvÄ"K´!4¡ Té&¨3A˜Ó?CÓ¶—û+qд!²,I£¸×Q¬2  ]Ð8Ùº¸,[ ð ·(Ûbº‡s«@‡ñU€P»ƒeP²"tðYQ¬E›0¼`CàO©óO¹Ï«¶«S¹raï³J˜«½B‘IÒŠy€†¤ 8€Qz…€¥ LÐRAå()°Y¤eŽÜUFÄ`5ºà ¹ð„a¾<€}°'±ê˾IƒîÛÿ³a  (P‘pEáÛ<gÃ] ¤q ê[ +•‚…‡æKÄð ¤Ñ4p-LTþ%aà'Ay41Eà'ˆài ÐŒe XÀ¾œD®°»ö„I’€a _Pº U¾0Á\À#¹ T´A4½E²½]œ!˜¡ÁQƒ­ð"Gú Nl&’©[+2†~Qvq0 ß‹•ª0 ½!Q¬J S0žt 6O.(h@m̳­—ðÈ(J&N@pbð Dp¥'QÈ­ \û ³€ `M`¨”àQÏq»‚!>¡9¡pÿÖ”¸¶€o` ¨pœ3riÅ&° «A·†d€ÌRLT¥ ¦'|¼YLDˆ[²Õ»¶^ãÅÙq±4! |€K0l’"ZÁ‰w>R]@ Æ=ч „´P†€ «€J°gð½R€Ã[tÈΕ'¥E vª¤å€F” P Ð a!•\à” p E ·¢!"|UB &±‡ñÊ7Ñ(ñÒ(ústµÜi#À„ô8Rá ŠÐ ˜à K0 *›±'uF…Øšм3Ök¸;´?ãq:£Í[ ÿ(¥ÀÒŽ± ÔI`HÈíXÐ!º@ PYUpf0ñ¾0 a°—p 2@ €y©qi55jÊR FQa !$:øþ± ðWPØâ‘é\"VPyÃa/›I­éÊê²7q»ÃP,Ñ&døØa ËðÖ¦P ¨³Ð B¼ ÒBðÑ\¶^SµgÛ¹N”ËÕÑ-%rðÕ ÐWà𽈱`¥T"h}²Ï¶!&àê¢ ÈaÒž@` —ö bP ¨0WçÏ~àÕ…ØD%Þ 0-—·L˜ –ÿÑÌø­¦¨œp%ÒßðÈ ÅP ¯\ ¨ 8± @8 ñ4ÁÇxáÌÓ5·KqÖ­9 ¨5ßKAP ÊÕ ¨’” ÈÀÄ ^ÀÐ(Þ¥h¶Ô¼`«Bª³7Ð-ÝI>1Ð-m"ò1¼â rØÈ +L€£ù±ZÀ¨—`¡F'¦ Kcåî’ ÌA±, „Ðl.¡ŒÐž*ÂÙ#uÜÞ¤&P Ü\Ð~®`#¬Œèƒ°è+¢q9æ®|²Ýà`¾–ƒ£ØRÙâj>B ðØÙ«ä§Žê!ª:ÅgbåŠÿ¯oþ?Haª»¯Øº©®$¨Ð° sÍM¸?¢%à:ÂÊ%bÒšQ€ÜŒš-§ ¹Ð,®zìv) @¨^1ÀO&ªÄÔ¬Š¯Õª­×j$A{ëQJUêS›êïï;D×§Pä·…+Dó~åŸk± FaÞî++ \^}›¶è2úÍOñÎð§~B”´W›<âä@úŽ/຺çG;<Á°éJ½ /ò¨C³3ÿµ4$@(ï*+ÚSÕ#/ó[=ñXµ37G®ÕB>@ßW¬ò7?ä3oôÛËòÀ22¿ÜÝ£·ÓÓóDþôŸÜ+?ëGõlëÿîN_ô^¡q`ŠQäV{õÏòdï)èóÀnêü½Y÷q(Òàd> T3ÁÊ05Uã;ð4Q#e€Ë€„~¶à]ü>rÏø#ÿŸæDö @ j57”7só6–ï6Wù7/ú£µm?†s¤èbDÙ­“u ¬oý¾óHOú·Ÿõy²³lðÎ=ô—+ô¸/ü$?:jïDµ)?³4üÍŸä2BõÆÿû¶ïüÕßðÚ"ÍʱÌoýÝôÄÛ¼­ÒûÚïýåoþS+ç¯þëÿ´'áù U‰@ûìOÿõ¯n'q"ñ›aÿýïÿu¼ ÿû¯ðÿÿÿÿêƒÿùŸèZûÿÿÿÿêƒÿ ‰ž*ÿÿÿÿŸ>ø u5Sýÿÿÿÿ²C’èz>àðÿÿÿÿé“ùŸèƒ0Õÿÿÿÿ;¡ÿ‰›@þÿÿÿÿúïè‚0à‹ÿÿÿÿÿz£ÿúo‹ÿÿÿÿÿbƒÿúß üÿÿÿÿÿ¤§Mpu0PŽðÿÿÿÿ”þÿÿÿÿïAÆóÿÿÿÿ”?ÿÿÿÿïH[ÿÿÿÿÿE!ùÿ,Ç¢ÿ€`AƒT8a!†*$@á‚'V”8ñ"LjCZI²$H“(S²P¹’¥Ë—aÊœI³¦Í›8sêÜÙg™4Æ2Á  cÄ2s.¾ú‚§LDO:,c+äÒ¯.Ú #ÕhI<‹†K¶¬Ù³hÓª]˶­[’ÆÈÈò8¡‘4(‹":™©ÉS©fI8$€+D\tê"r‰*‚ñhŠÃHјÂdèÈzrÑD1¯oC‹MºgiЧS«îºúm–žJ¢cÖãÙ,ŒiÿââÆ”mæž äÄhEë÷-cÂG-¾ýûøóë¯Ð“˜vÐ05´ )ÙD4Àt̰<'‡@”0òÈ@ÏœÐÈެ£¼ÐŒ-yÔ1à 04D(R âB4ÌR!Õ!´Œ/œíç#k?)äDiV#ƒØR- 4 $ÑrH]¼øEb-ÍÇ…t5Ô†‚SÑË«“‚‹'ˆr‘ /ÔÈ,WBD›%‘ÄAB¼Ñ£‘|öIŸŸ€*èh3TAK%„%tB=¹c8&Æ 9À %„XúÐ"JH@€"ÐÈ âÆÆEú¢lŸBVìÿQž² 8è­¸æªë®¼N¤Á¨»4á×C[AP-¨x:A§\2Ê‚1%hºÐSÐbÀ!]øò…qÑ  %É9:‡tF„B¬Õ×kòÎkï½ø:G r† ûö› »,á!«v œ8QŠ© iò 2\À„&‚È ƒ) œ9"›TI“¼ {-[Ü©X@æ³Ì4×lóÍ0À0M +¹óy)0À'\:",N8!K.ÁÀÅ@ °Ôô4Ô^´@[Tv™ÑÍd—möÙ>*ƒE-‰ÎL“. £-÷Üt×m·Ûµ·F$ÅÿóÝ«Õk럄nøáˆï Þc{%xâŠGùäSî'и÷Qx°æÄà•Ô¸ä ¥¢AP¤Ã3L̤àÊ©—dŒ–×nûÙ_´0X×ÅÀ˘­/w˜Òî@+$É('‹Q\ãbJZPÃ%±H4à|Isü0EŒ¬ò’±äÁôå ÜaY\:J¬ÏËñ·ç¯i¹_ £¿Jí P´Ã³iˆd&±?A f’ §)l‚)( Zð7¸Á\†æ"òl¤A yè€ 2x®¢ mø? –gä6B—¢"ð½ß ‰81ÿÜÀ*„Ĉ@M²¯\ 05Üa}X¶£„Q"Pü€ŠV@ŠE™Î2®ð -Q ÒâÑ Ç‹$¢ À¡H‚ „ h€‰ c ´à›<¤@€g "í$#H-PBŒX Îþ&IɶLPtèA5&´Ã ©˜G2ˆp@…£¡È@RAA L螃c‚Y<¥? žz`(y]à“8D0Ž1ˆ`U‘G<ªÒ€~G (ˆ8–é |ÈC ôÐÞQyÀîUâ ã@3@)ŒãŸëÉZд %¹CD%ÔáŽW 3štB$ƱÿÉæd) Lñ>Öè¢ï`ÀlaO÷©Ã ØgÈ ƒt/d‡jANp"c‚å '^A( ó.ã0Owt—`„Æ@jÎsij¥1@ú9¿Júô§ “]Vqˆ30@¨>™ Øbç4%°d„hñ9A˜'k|â–"xQP£ùs!0Eèµ_Ìá˜';F `‹xã"Ð,ˆ0âQ2ÄÙ,Ïv d¼C šq À5P+äØj0­#ì>’»I\À¨i8À(! @Tàïb´(\¯#Îx.ìÚQÿ6š(D †|`©›àhñZá‚P ` ‹áБШX&Ì3¨Å•|.|`*@uÔªö¬@M¯zgÂÑïé!e@@Ê4j‰p„"ô4¥x‡ªÖeÛëÜ^ͧX!¸hÀ=ø<0`mˆá*ð`@ò0-”ÙŒ^0Š êptÎWm}Ý÷ñÅ„:mG%^Ä;Ø¡Rœåa2 ´À½ä­1ˆ tPÁëаQ(![Ô×·M *¦ ÈÀ‰SìŽÌ\.së= d€4Ðq&Ð\ÐÿÌ•Æ*a+¬âWøžQËûÉô­÷ÏëMóR±Sí˜D|£áIÀuÕ(þðŽ‚¦ 2 åàÒñ±PK†¤@„¶’C r†gâ!{8™5&€{ÈcBËðS¦y XáA€E N‚ËTà€¯ˆÄ(ñpÄ÷ׄøÃH¸ƒâ]ÄgK@|pÄ2¯¹ œÎÂ:TpZ*4CÀMC5Ö‹‚`aØ aò9hˆ›ÜE`…âXT}Ò†Ë~(,”=Œ‡® €*‹}칪™Ín†3$ž= Q„ÊÛ9HjÏ=Púã~¾.»À‹×ÿ ‚)2AìQ@/æï½ Ui¥{ÆÉ ^ô€¼0A{’Ó#gJ †ªJD~‘ 6¸öްà§Ð °Å4àt$ü \¯:®>‘ØXß1ØçCvŠv´Öa‚E˜ÜŒnÛ<ãf§•vu»+“z‡U-"y„n§2 ,Óm•¿à.?² 6‘v·O>´nïik,éjÈ&ˆx1dÔv*d@5'1ÐÑóÉÜ• ½ìcò3ÿ‚ágVóÙ.2ë…LÉ«þAjßU¬ŠaQ¸½¦°ª,‚üâüàÇÎýè㥙Zõùa JŸÁ˜þÿH¯ük—_j½Þwß8@õ#ÄS½¾®ÆûO`Í+§ÐíøÅ ؃$ ý¶g- ¡|HC~P#p5Q{º@ V ëþ5ðvB4æwBã3õw€ |!7{"ˆ8=…¶:'1:A¥ÓW`!X8 q @½Ð)°‘Ô’ É•^Ù¥Ðÿ¶ &2× 5)sßAa@ ”10 &ðUP0 AÁ,β °N@ Š”á(P€*aà f‰—yt%“*‡‘–8е@ Ðb\§ •ù•žÙ•ù™iáZ –!´àr0 )É,UB†¶P Âà \ÒPF ª`’°—å’YQ!ÊU®R2©é!ÌÐ å" BœÆ¹<Ы–&Ð &Ó€àið.µ"šàž€ÿ–× #Ró›ä9æ‚€ ¾) ëÉ~ƒ€v¥@ S™ˆ ÿ’ö˜óÙ ¤‰—Gý" Œ¡žú1=ø*ƒâ9¡ÓH¡¤Q…vU«$Çg|V‚å6ÿG1Dó7 {Us¢OBAc4I£'Iéw!%Ú!zF`#¡¤B*„jŒ&7®·•Cº¤Lz7X8' šM:¥T*‚S‡c¥UZ¡[šJÚ¥`¦bêS ?ú±†cš¦j:r@趦p§”Ãað›!§xš§wãr£Å0_*¥z¨‚z$– -6¨ˆš¨ø2£ÿª¨᥎©’J…\:©–z©€Š©šº©œÚ©óR©žª¢*Zú#yq`¬Qª™z¥s³: ú§«Z>ªú©¯ZhZ«e1 ñ <1‡Êà¡%0°‚mð §Ã³ó9¡À!¡jeX/·ª8ZP¨xìQáÐÓº°ŒÁ તÌú­2@’Ã*1†qWê<Ьüö¦¾"¯Èƒ«­&Q®ãdȬn¨G–­vÈ9¡¯¯÷J–0°!®Z”‡¸4Z 0#¥@Žv,…0TÀxdXc¼ê{€ ÒI=•…¢³ H@CMXcw°²£óƒÿQfú§Ä01Ñzª¨*Nï;¸´óÃŒÐ\̓±¥Ä'¤™ZôF± ?» °uØ1Œ BS8»µ„˜‡Nðê8f ZzcïÙ|àMæÄ@/`´ ûªã$µʶí#m“/p À1à <ë $16IÓà€u{¶Ãªo«´†š³;—„ ƒå€…0@®P´±­b«0 ¼°  €QEC°TÀÄ“P¶p’™§;8›0ÔªÄBÄX0ä34epCÄ8RèjVö¾`•P‰NEPW@;ûÒHy`¦Õ[Ðˉ~ÿ‹w±/Zp½¯p½i` ²áí5'ãqaðw0HR8pYñF €Eðn+Àtt¾Èo‰C4N5p( whô‰p¾‰€:Cðà)Äà¹M˱ ZH›Ë˜öh<¹G',ï¦ {„ºˆF2ÜÀSÄH üŒQEGF¿ýƒ ØEÒ;@X`‹Qâ¿1ÌÀär¨S‰âq ‰@ ±ÁQ2 y伽޿…ã4^¡eäãÀÍ£·„± \¤¡µ?§D°´U° ä¯nÙÍß-ëC5ãræ]·ž@ TŸÈð-gP Tº~ Ä ÜîíÁðë«. ¯]bNÕŽeáNoîzÛ2ŠÐG€`0Ð$Gy­ N'w\æ~ˆ@ýà ÀeéŠ"[´Õh™êmQ-(KDN]"@¹¾Ò°Ðð’5ï^ØOþs`^›^æ‘íÀbÝÿZìmé¹0ìA€ é‰ÍžëÞí®^í/íõ €îPßœ ö5ù¥Ò?ЖŒÀ²) Ù #Kß9 Vuï\¿PH@Vö,àaÍ0dÂ| L`f9z<&g™A­€ìz6¹­´E/¬_Dñöþ£eiV $ÐdSk1OB„@’¥-Z†•q‰_l½í …¾ÛÈðtv¨[vá1ŠÀevoX¦ðdª×=rpøÉ=f?”gº0îjÜÕßÞÚÕ`gÝI—ð0ÐT¡/>—Ÿö¤g _f€?r†ü%®zë%ã=Z°=6guæbÅÿõåÒõ+6æy g7Ú8ÙÍø&÷ÉÏb.¶V6_Áe_ÕÏþ›¶¯e`²uÖ±nŠ„3¬ DÐEbܹŠ]SÀÒ93ÞŠ ãŽjPá4aÂD.¶c™£L‘ãÜ 8…ŠÐ‹ f,¸³ÑãOf0•¦•?« †’O‹?žaàåOK$@¹ÊÉ:+íÊa”Œ:« …«£‘cG_„"¬Š&Ž œL`€¹€¤Þ…¡† I'iA^cs´ûÖ”§¤!µN&Âg“êåqÕ©ÚUóq`‹Žq“^Âò5…ޏÿ´ñuÿDJé 3géP (+$Â`¶±uöà |ý&Ô’1Í$c|ñäY ¯Gqñb]°","†_ÖhíÅY¸Y2yyi˜¨?'L•¥,„YðТ²© ¡   °y’yãh*Ó ŸP`%ƒˆk¦ðj†kìèÅ…Æ«†UæÀœ0ê´v„)Â5éFð{%UTy½vt£uøl°—Ø‘¢‡j*ã€BŽ˜€ ŸZly)‹SÌ $[àã¾7ö꩚ ^‰€ŽQð[ñÂÈ[H” Ôa É%Uv²§Éy<¤ª6›’„ C˜XÀ:2˜ÿóäÔd‚Ã*×l±Ä?ˆ&š‡ ‡EÖÁE? 1)!‰TÊ+¬Å²v\j¡Ñ?J,á€ÛAQª®lí-¸v´e˜AMtÑK™œWÒâ¿pHEW¨àâ ‘L®™ã×ÉåŒ^^Ä!µ4Xx$²š”€:0¾ÑêS/§ ª4Ïu¼ð@i´•c_ zö|½¨L†\ÔÁ¥¾ßÃÒÖÜ ÐF Š—õšu Qþ ôH=ˆ†»ý—=(%à*å`¶Ja•WMH¡³Žfìâ?8Y• S(xÁMÚ‰C 0‘¨l”C^ÈG‚CLèÿB8 Z`i Xz(ŒÑš%ð ŠY„+ñŽ8îØ`~š¦'ž”ä‰Gn6ø¥·éN $˜Cƒ%`â€.¨D²äåqaýPĨ­@4ƒæŽ8Ô)›±Ÿb*dØ(ëå{!†"&·ÄÊs‰œ £gŠa^lNrDš/ÂuÃy¿*ä•Ä@NpÁd/P‚Äòª·-è¡s‡›ÜÄb¾Ö‘¨3ÛóßBaÿ)Pa RF&ÜÇ”YÁo"HC:T(\~ØÃ–Â'´-@Ћ„ãÚ½ô°”ã’M?ï­ ‡â רÎp¾ô!‚P6$‘ŒylML°”h&¼¾`T¤ÈG(6€¾å "9L9z7@îe †L©×[Ä îyo%g0Ÿ4~À= 0|´À+N£ãÍPh”"ÝÕÞõlŒTªµ4¦Yò œþöÀÅhx(&™VùXnn‚ŠLÉ%2Éá4! hh ƒ¥ã9-zÄ#Ѫ}â ØÊ0Ù†]òÒ˜I¦œ` k¨­1¿ø?ø1 îÿ`óšA‚tˆiXÓšÐg61„³=\˜‘Òù:Äb<øeEžÃL€˜.€A)R`ŸH¬D1¸¥ÇpË\âò'üĦŒ‘"PM€à'? uÒÒ#¶´hI×QŽ5©OØ©W§j’".GÔTGõÒˆˆ#¤ø ÄUåÚ‘çìt»äÎ!¡ÑÁº@˜+xE>rqˆ­Ìtÿ¯œyKïzT›öµtx aÃPYNišÐ𮕖bÈ‚c pˆÎpô «B}JÚ ¤(V=çs°Iº”Ú–£Ñ£¦V{܉&W¹È].Sä¡(î´ëµ•\*s- 5ÚZWº ÅòŒ¹åŽŠºÇe†1Çæ¦—ŽÚeŠtÙûÞÆ˜¾Zí®’x\ñÎW¿êåï~ýÛßÿx¹í*ïJ"`ù27îÚ{ ^GÀ¦pƒ³‹ÛäÞ2ºÖï Ëá@‘." ¶ðm››_‡µÂ+f±€jK ƒÀ2ž0‰[|cs¦]ºÍq‹Ql\÷XÈK©ñ‹LáYÉKÿfr“ñka'YÊSÖ‹ˆ£|ec™Êí¥q€ßhYÌc&s™Í|f4WØÆ[ŽòšÙœfüþ8Êaèrº ç7ãÙ½ó•óˆ­lÓ<ëÙÍ&t¡ }hD'ZÑü³ž-‘2HóÑYžô›û¬ÞK›9Ó®g¥íiþz”5”)]êW"V¨fu«]ýjXÇZÖw¦õ¬µZlÁÖ»æõ©{ýk`ÛÔÂ>.(1b'[ÙË6³ýlV+¢Ц¶¯«}mlg;ÛÒv·›ííûÓà&·¸ËÍ™dâÜëfw»Ýýn4Ï!ƒh¼í}o|ç[ßû-é¾­ío€|Ï'xÿÁ þïƒ'\á gxÃþp,C€§xÅ-~qË!]¨Æ=þq‡<"Ãdñ‘§\å+/x$€½M°\æ3G8Í]] h˜äưyÏ}þsgwZÒãzÑ~t' èE¯îÒkã§ÿ7ê57÷©¾¶kGÏéH纒•>^¸êS÷²ó{õv‰ÏjïzÛ»MöÃÝÞrw;ÝK½irã½î@±{»û¾wÀÿË[5áoøþèŠßzÕ® Ø/¾² 3âáû ðœê(ì8|¿Ã5 ._‹™FË! ¹‹4PzJ§¡ònJ10@ä)¾ì,püUÿ¯Œ¦W¯× ‚ù ë]¿Ê€:”ß³· ¨ÇY¨ß{åF÷ò÷k}ïöåžë1Ü1ÄcMý B¬‘)4Å_ßg‡“Ï· 6 P¸÷Fð…ˆ˜ƒ;À.ãJ¿h°2¸„ŠH?Hè„Ø¼ŸØ@»-kÀ«›ÜYŠ06 =6K€õi 1Ð…3U“4 D?9 üˆ›1´$ ° Ä/b`¦á)t¤œ9€:`<ýÒ^@¶Ásø¡‰é@#Ð*"¸š€R𘙂೮¼d ó{¯)”B*ľe« Q€„ð‹ …ÿ+Ð@ ?˜6¦(¯U˜„;Þ#ØØ‹td¸+ð?\ 3†IX¿…êÓH@ ›êc4` ~øŽ¸Èƒ<¸¾2ð›êEØ—‹8@H„+@ƒ¥èƒ4ȃx…Rƒîâi‚+ †¦¯> E &%X€¦ÉÄÀ Z@CI„Y0Æ`”†BXÃysØÐMHIÄ‚XLZ$FklÃ7tšÀ+À6”Œ¡i=V„C7„ÃЄ¸PЂȩFOÑ IPƒuTðF[‚WÀƒ @ƒD`ÇÀ,ðFÈ;àÿeT¢hÌnlÈ`HbÐG~d †tÈ}T ]„ÃS(‚P‡jxgY;áŒéÓªNm¶C­„-0ó„€qà‚@=ÙÏÊ0S.…TÕI UM‹6Xÿü‘àSå‚eQõ?J…bðÌh…'x‡ª‚P‚) [-±¤È¢ötGH»H8€v@U&¸À 8ÕŠ€¦‰‚ ¡]ú…9sÚƒH…Pˆ‡9jÎ ¨„xð¦†B·‹¼H¸œx9A 8ƒ=H‚&˜ ˜‚ž5¸„f€' €ÿEÈZÀ„%h @x%ÀBjIÕñˆJ¸ÐØ‚'ø“  Ày°ˆpÖ˜CÇ‘¥Í X7z ”•«0 # Yà Æá¹@VeO°g؈¨25ÀÑs˜de] ¨ÙŽæ“ sS£ ª8¬UYKÊÚÑWYÀ+P+ð? Úw`…U¡˜¬˜ˆX˜”ý“±Ý…‚%!Ö‘HŽÒèiÂ4 ‘% »GZƒ˜X ýÕ9”5(@™]„Ý) ¨lø‹AÙ„_š•É h܉Y…d­Š¨L°É3.Q£Ù–bÖ€ÿÔ¬ª`Ý‘ HÝ& —à]¹èܪ(Ý£]¥øúºn; 0ÕM¸[pØÔ±…¨95ð XŒ´ €ô-—3`ßæê‡¸‡ºÁwˆ_X… ‡`ày”ðÀ…^˜„T.3™K-ˆª ¨ŽÖc ‡€ˆ¸‚iŠUL ºÙáÈ70 DQÙ“€ 6µ^ @Q¨"à^ï€Fª¬H‰—ˆS’ÈÂCÀŒ_€^?ª:ðÒá #YèŠ ¦—§(íu‹ô,¬ÑBÉûØ3‰lJËÈ…èì1áØð`‡Ú•ÓM…\XEÿ,‚ÛÍp†€™T’äɈ¡µŒМp‚$F\芴±…Ð5 êaÃPŠ  6BN‹ò*îìßIœó°Ž9*æ=B¶‚U@bÕ^PY!°‰à¿,{aàÞ‘X¤àEÇ*Á ³@ ¥0e K°K^Æ¡`X€ÓTÎB_Ü#Âͳʨ/Ø˜Ž™„Jy…ˆ1ÄÔOðÎB €ÛpÁ€ jNkÞÔÐæãû„cˆN< W?Ãûåqp€ð ¥j0½Ä‰L½Ñ †ˆY8'h‰TM_ý˜@˜3À€ñ'”føÉqE‘ƒÿ*Ñ”V®ŠÀ; DDú÷•ŠV½“=橘jHß~1”ú(ãUŠÑ\aXG&˜,¨ÆXâØà€d1„͉W‰€dH€A)”¥`‚•…{Ñ“;]Ð=ãåøõhd03V„b¸‚–Ö‘"P…Zø‘_€gP—ш¡+Éc©]‚¤n-øç‰±Ýx9Žyaаî`‡—@’!LѨ,‚óic!¢¦‚†DXqk‚Žu^¸ƒŒ95Á¶Ž!—¢þÉ–yY‚XAãœ(1`h˜™ °(Ê–òbœ™æfcml{“ÞIO a„¡é!Þ¢¯qÞýÛQÿ ¨‚D#Çႈø÷UÕ!* ¯y7{„\î@‚#°_éÄйñ¿)˜~à½édŽ.•‚£ðià÷µí˜ž—u¯à %Ã&*ðÜùI ¤ÝmÎÁ?0)!Õ¶B 8U؆È„Úο¨H%nMð˜Tà™ïWÙ9 :_Ýÿ ?ÉFzÚ¨"(߈ZÐDBpTõ€Yp ú¾ãûóžJ _6 š¾ ¹$¡1E¨„°H  –ˆƒEJŸ7b ¢I£úðà $º !”Ø1Ÿ×ÓØØ=@U@c>³ ¼¸_®³¼¹jtÝ|½÷ûB{Ä_|Æ·8 €fЪ®o|ʯ|·3†\8E®ßü"ûƒ Ì{Ë}Ñ·6\ ÅÓbè›,PV ¨=,°J˜EhkD–F%(Kÿ’HÓ_™§…ÕׄHÇÎÀ0þ[EÞZÀI°ˆW43¸=ª…>Ü}ïÿ~_ÆVžÕDx[ˆƒ™¦…ƒˆ]k ¢1 ¨MH‰]HX‚NØ… ˆ-‡ˆt ÀàA T)¨NŸ&”ü¢cÃYciÿÉ•Œ¤ >âÉ!2P6ËÑ„‰I„[CQ ÙÇdC¶úH8dÂMh@°@ $P%]¹²àíû·ÕÝÀ‡/nüxoäÊ—#öaEE&,±YE•Â7RÑܽkaÓíÖà¨À¥î;t0âÂs Xâ©+PžFÄí¶€JÊ CJ ”¢ŶÅ%-P~üáK#»”Å×~@IñÆfA}'szø!ˆ!Š8"‰%ŽX $ZL€Ê*+Ö×׌AÍ(…Q‚ÍR ]øb ´¡¨ŒòÑA/´bÐM’"³ ³t]¤%# ÝÅv.´”7@Ž vÿ ”J¬ÂRId¹Ë^×ö^Å&‡&ÚI¢Mwê¹'Ÿ}úiU ƒ "Ë”E HÃ#h^‡&\ðÅ‚ú‘C  B)2xJ¥BÀQ ƒ>A§„$ÊÁ§2ˆCT…DÁªª¢‚Ê0}|¤~šªÛŸÅ{,²É*»¬S \À… …¶A’#MØ h@šåñl¶e«mŽÐR(Ǩ Gb&´Û"Ç`ð’;Uز묾ÔðI½L±Ì|0 +¼°TÊ™gÇA]0ÊK;ý4ÔCI³¡1`JA¶Ø²Öhýʇ@a‹\‹í2`{€N©¼‘õ \›ÕvYkñJ‹cß·NjO bÔ‹,8á…7[Ä( q" 1„ –,ð-k‚(µEžå‰l~‰æ—wþ¹m›~ù%W\‘ê¶U ºæ†3-;íµÛ^K2›m7mBmtäAIÀ#ÏÄçøà&Ïv­È‡¶|ÐÛ>=õÕCMÒfÖðn•ïÖ{ÿ=øá·ëüàG•”Ò¥/>ûí»?»ÉƒŸÿ>ýõÛíóã¿ÿ?ÿ ¯ÿ?üú'À°€À)ž ‡ÀÐv¡ÀÍìò¤l~Ý+0P ¤Aƒ äg â³h ((aG8èÁ²@ ÉŠ ‰ó¼p*3 Q4€´àAðXŽôw”7¥a‡ ÔX"0Š$D0‚‡Ï‹;\" ±I€ÚÑEðŠ'Y´CÕ€RÁš°°$7Іð¢ƒP€ÆKŠRð‚LQ(ÐO˜q€%ö&Žm< ZÀÇ2EŽn¬cSª³P厈€œ0wäQ‰cº¢.¨›¬,°xÈä&+ÉÇGE bx%ˆÄÔà €ŽlƒÂÿí¨LaZ0‰IÜA?YóŒtìrV8æ„™a´‚ ÇU r4Fo:@,¯àA` -ЉRp€htV€q’Ó…À†&^ÈÁ¡xáKÉ&ƒ,xî'ÙD¡†pH/’“ØXÁlB,”@xÅ Ñ…/– €?àJÀya íall#l&¢ù$ä® 9àŸ@A 1ñJHv:1Ò‰&˜€””œ–Q:‚†DàxÍ‘®Q†úÅ¢PPÆéOÛ¸bÀBʃ˜4$"·™çÞ©"—ÀµDe%5ZÔ›® Ìÿ „¨À ,¯#hèC$h Ù`á%\5@ ÄF¨*ë-ú95È5/µ€(îà £–G!ߠŰä:ðî%ÊcÙ@ˆõ¬O\'&„ƒYX'fä Yo"(D ÂtbÄ @5…&Õ,30@ß-@Vßñê+.‚‰;…79 0BÞÿÀ;DPɉWÈ?²¢Ï‡¬áÍ@W - NÄ[έ¸À8‚‘†“k’ÝBˆa„Yϼæ™aí.qs‹Ç6B0s~Nq ã"¨u'qê˶@ %¿íó, M> !&À„¤ãlâ[+hA¢pFëñû.Πr ÌúÏqF«ÏÀ ®å*ÏeÚ Ñt›_ Ö¢€ø× ÿ[ã2Õ£ñ3Á€nB€¶´np(Öê\ÒÀùðx4ƒxSY ³oùì´ñ€}ìãÚ8ï3ÐAÞ_tƒÆvÀÎM˜p`É@uÍ-€o7p NpƒÍ@ìñ_‹LO˜ëeF0…\@zÚ& 2 Ø»0‰ƒìÀ 04'Np€Ð·üúC¯쎭\ÁÅkñßÿ`ÞÿD»Õ‡þ…Â칃Ì\êýTè±ÚÕä€4´VZQ”¤‰Ÿ†ZYà5ŒéSöõ\ øYÁv0X(L3‘ÿý—è ªqÀkÕ‰ äBµ[€_ äÛ)Äÿ!¼€¼ „œÑ FPܬ]ÀYÈþ5„,„à. G¨™Ž] žÚÿÙà*à`-œA*yÃÐØè]5p|ôš Fƒ¸`2À*DÀ!XA;TƒA”gùŒÃ°°V­qœ§æ(œ:hC :tƒHyM€4¬Â/ˆÛuMŸÀ/0ß„€MDßu1Ã'¶ÔS…ÌG´ÄÝ\0Ã:dÚšeÁ¨— ô^}IÃ7¼ òDô™ƒ dæ´=_uy€4pÃ>Äÿ×Oh-P­É• ¨œr €pÙ!€A µ+°åÐiQ<žú”B&ØA°Ö8È#Ø“4nËmRAnþWp²å’åéá¦Ê½& Q¤€´Ã®DàƒqÊ)\çtþÄaÚcÄ åqæf `v®C/f_„ç¬fv¶#§€D;èÁ¬ÅlÖf[ªg~Ü…è»]'zJÈ@„\Rfw¾§{R@æR”''\Õ;ÈZ$ðÛ•„ @€€ÂmQÁZÚSx˜ÇÅž}vŠ\½Ÿ”#\'|yúÁ…Jç~¢Œ{jèX f€ Àkf¯¼åX6 Y.ÿKDÁÀ¸À#ìK”>º[†Â!|Â(þË'ŒTp¹ØD±!Ĉ齔)±üÂ)N€>è›¾é›æÈt)œÄ/Œ¢Èé›vižžÑ›Šfó­P4錽¸Àµh‹¥ LiºËÉ#ÝhË#D¸äÉÀˆË£¥•ÞK´œ‹¦ŽiQœ©“jöDË¢¦i½È™D)ºŒj $ˆÃ“¢ š^iÀ$ê´H€ˆjª~P•R麔K®j긔1ü0l(a«± ë½lI¬ê*£rjµ¶Ë—>AÛ¥†Ë+äC.ŒTÈ(¹ *«@±m«I¤‰¨šªppB² ÿ ˜êº\€Mä*ì‘Ò’&‹¿rE—"¡r(f¦=Ä‚õ ÝÚ,Ì]çû’ÄÚdBþ+ÆF -‡­6EŸìĹ:,¸Pã¨KÈf¬ÊK›šÌÆ®lÊÖÌÎ,P”%ƒ lÌÒ,Ïö,Ì\1äB¤0K'Í#¬Ï ÅË&mÒîS$”2¤@ ôAgñ•&HúàÀ"æ““DŠKaïà.Ø(FR5Æ6Ò‚d¸EÇÈõòayL@'(Aõ…ä`]쑆XÄ…' …Z¼*<Ó]Ff€)Á Å0,CXÂ*¬Ej´°º IBI=NîÌ óB/7ðSÔ‚ÎÌGu؇ -”~ÀÅ^ÁRMÀ*I„ï‹lR,ƒ~¾GOG›\I„„ðGd€¥ÍÈIèŒtX°vH®-ìÔÈ…at\Á°Š1ÿE#”I‹ÌB(€è¢É"ÐAwÌ“Ž@äÍ€0›Ô@B'”×v@ç6 Xð~tA‹´‰*X„^&oI—œÊ¯UK‹¦.óª±êÊKH}XIÁÐ@œŒ‘ÁžG²’&ñ¢ø­À^ð­ÈŠ©Dt¼_°øAS®‘ èCt " ‚$@1€pÃ…²"À@'L0 GršÐ©ÞJ.À@ H£¼Ÿ#ÿä®Ìí¨£B""21'q˜ÆËf˜Å.LY¾n†–šÇ½BjÐêAê½Ä  öì+2wOµ «»6…)•ì8;©É.‚±YЖÀ©³;¿ó±óVÿEÑ’ÏÔ³:Ï3<ïóó:‚^¶!#-?4A´A4B'´@+4C—Ñä5´DO´ÂÐhD%Eg´F'²žLÍTÙ@ß¼ óì@9²MÙXÙ”D@Ø’ôGÂŒ}dÜ0Ã~ôM*ÜtÜ„M5®€Lëeól´P+´ ÎæºAëXŽ+à@å˜Né¤Ò=ŽS{ŽèØÆÀŽRSÎêhœç<5(|P õB“5ââŽA $½Qô4 [CÏN˜\Ïópù¼Ëòè3G›5_cìSLY÷µ`oôúôó¶^2böQ,-c?6d;6ÍâsbG¶e/öeg¶f‡áUÿöf¶ÏþÐ^›„I6e{öÃm‡0Ã^ Å ½Ë,¢Š4 ryæÅ6ú(ÀÄk?3Hí ñ„cÇPLj¶PÜopKk›Ô‚.q›Ïg¤ì …‚t«66a´‰`@r+Ål7f/©’Æ&©œyè®\Ñk62PÈ!(Â_oÅ…H“P”}‡·Çqr˜}Œ~ËI|¯ •B\ÀÑ2…dR¼XÏÃÕ‰š%Ž /GÅçR'10•ÏŠMS~9—k'ÂÄOÀ…C´~÷h'˜TÄø»¼fĺs EV;ÙÆ,Ãhµx"Þ'a¸aÿ@ý!2ÜÁ3Ñ£­ÊÙ,„CH‚´ÜÁ‘bùÏ5}Ö §@7Ná€T À„:± 6y;€`ÁYñe¥ÔJ5\!ôSl,õfâ(OmVg¥'-°­œ© #%”ucÔˆÂaA®ÁË­-gÆP‘ÖUEºM…UQíTWVGPù;ø*ü>C‚6OyÕÔfhÀûÀ/‚£w:Y ¬ó„–"ðÓB5ÔCe:ÛZíS’Xwzìz®óD"`Á3[Ôßò•_ynJ¥KÉA>tpa 2PÃ<|þg5¸`ÙŽ‡~ýCÎÝ“ZŒ‡N`¼ï:è¯6ÖB¾†1,‘âpÍÌ¡T`^ ,P!ã0„DªÀˆä,K¤È„PD‰Ä T°ƒÄADD JЉI(ÆÑŽJ<+N¬Iâ 9dí6°Á>ìa5itm$f[AG¤Æ 5ÄL!Ç2!mìc‰ÂN8¶àžB¥€v(VˆJ‘ ^ð…ZyÿKL)"ÑE=l9lGb*… *\rFí°ƒ‰‘·KŽ1+¢fX’HN²§È¢Äs´’ ¯$i¨`‚3(FC”ÔH²!ÅbÅŽ(×)ƒKRæ UH©áćè‡Î&IÄ  G2aÖÄæ þ’ƒñ¦à§[E,‚:¿bŽBcØ@<åATÇ@Y¢B¶©È,f+ÙªRHA-(¬°‰ŒG°˜ÝQIË×Rœ¢µ‡i§±Íæ© µj,®jÙëµ Z,r'@YÞ’–¹“õl,öpÏ0Ö¹t¹JW…šÙT °=… 6[˜Ÿ¶¦².€,i³[’|ä½®fJ_ &/…å*vëûÔ ‰6™+ÀySÿàú¶ƒýiOÜ`?¸…N( >!VaˆuFfe¡‡š*“}¨Qbåp‡-\bŠi Å&n!Û!ƒ*¾Å(ï†sŠaC¸Â§ðEbÈ hÆÁÆñ‰,ä"óõÈ7N2ŠIlbtŒ`nUò”c¨\*Ol¾ÆØ€ÝÞ+9Å`ž²‘M|Øj§dó’ÙŒä6¿9§¡ql¬æ5‡ùÎM†óžùÜg?ÿÐô i‡1 hÀx&ô¢çF?Ò‘–ô¤­"Ôj7ÅÌ€€"*ma9ëTÏFñL@iSK¬Ðž¶ó©YÝêU»ÚÏèƒ40’¸ İ€…ÿZ8 í&Áix@×@Ãò0€‚<” ƒ‘ˆDdFŒ\ïzÖ@àV³y€ç0dÛ0´ˆ„¶W@ k÷¬[úˆ.¼ÚѰn4R-o{ßß{žÂ ‰ˆI C„˜„ÈÄa B¢Å$@fHd €Í/ÞÝÄN¬@BÔˆ ÄIio8Ág¡<„×[㥕×4 Z€¼à°ŠÃ$<…?ŒÜ@Zø´  íB LÌ÷Љ^t£Îs0B e1DÄ—ÿ¹ ÁˆËM˜8!|!‘-H<¨x.žT@cŽ˜ð °‘EÂ}ˆ¯‹i@‹$ÿ#W—I °0”ø~& ¨… tÔ§î>ð"àžu Ȁㅑ5-(m&U陵æ9ßù¡×yí,#€ ãÞ“K4â´ Û"OgÃ×â €#Þ€K\|Ð Z/âIö³`âÜP÷Tü!⺊]3 ƒTrþJxˆ~ÖýÈwÐwÕ…ÞÛx©¨·L¸iÏŸýéW¾ñš<œfð~ÁãK‡FH„Ô^-æ iÑ $b ¡of¡B $"ZDO"weJÓR$ ô½€œ„nzÈȪ=ñïôqò Ñê"ëZU"žM ÑÜtSkfGý ò3ÙÕ,¥2>‘®RÿÞÇwpn‡|,¨â\°bVB¡ù:CŒ@ü€ ü Oª â´@–el NàBylL€5:`ÀÀœ&€D`–G2€Þ 6Tvc2`:äA"è¡æÌÇ¢a Ä#B³uzŠ@2€ ”æˆ,°• ¨€ ¢C^FgtEPzG€ hèx¡ø¤¢ÄãÒ¡[_‹‘¤ar ùLV„ÈÇâ@IÜ)îå.b0eBŒd%Ê-ŒfÞ©Öa…4är6V[ñUxÁL)èàc”ÐvcØLiçE’gB¨tx@ ª6FÿbÖ$DAI¼ GêUAÄš86òƒW×Ⱦ‚ÞªögàG V!Ram?ˆK+Ia*å£^ë'A[#taü |Œ8w&sré5@‚¤4fc8 %ÌŸ¢(2  ô (A „¡2!O~áPë'€!^«ãÄ`€º`Äá~A6ö Ä/x–D – èA"Ö+ç ¡¦ŠjwzP`5¼J"pUè.£¨à?’‚:x£fZ@ žƒydÃ? `&!AV¢\¢dÂF¢–x|,@TZ ž@î‰üCížÂqYBë`":Øâ¦Ä ÿ6(6Œ€6L I €Æ9œ£*¬é„â«8nx("t,ƒ=A7´Eo›b`C„mAˆ¾3)dh8B,¦v¬Yz£)¬˜bœ…ZTP7ˆ”€”ÑžX€¹0#“˜×€7Aœj  G*.A?¦UZ®R¡ár _pE„k¡É2þô ¼– HÖÁ`) ‡"c$á“8¸ELàøAfµw¬a€‚á² @*6ä!p¡š¡÷¬ŸPÅdü…šˆe”;ÃYbù_jATøjÂÁ1¥Qþ-Õú¥fo–„D ¡tô„ >LB H@ˆÿ0W^1å`Å šg3(6À]R'~N8n—i#ráV#Ême@–Ø3Þù îâ6Ûƒx F!dÁ6jDˆ¸3„«%À[r a’βF¦ÇeG°Ø3´¸Z$ž?)®%Zh¹)&”j-àVô·Oêô¥í˜+Åq2!d £x„t(44•VÐndž¢ 0| r€¦2{h hÞ@˜McMÒ€¨ð¡&ð¡· "6’K|Y•««8ðÐ4Æò&ŽY¢HŠà¢à- ©xºg>`}®Ç…¦L@ïH‚¬/ ÿàºS^andZ œBk¢¥Î¡sÀBã ÔÄ ypaðÀoòAyoJ&ÂUN¢ç­ ‚*`'xg,gpÜÀp`K&^p çw`IN<èZ#€*@tv'°åy³`¥½ }*ç Bij¹‡®‡­‡£²Ég€àÔo/!ô°ÿà®ÿ ©34pWz&µ çu^Ä Nèê˜>Qºèhà àé†"`œ< ¡_¡ŠE’ˆ=% ˆ²!@ŒB’àå\)&àj°Î!Žà¤z< Ž “G‚ðKP™ üÁج€ Ø4è!Eÿi=)4‡vQPà_½9ê•<'Nª?.’6)&f*Wt¸@3áRa„öX¾ßAÎ@µ;Œ 4óXAˆØVü bhy =þ“4I‹ô©@_ ¶UŠ$pˆP"ÔdÁM ¨AÂàˆûIÆ È”$vù*ÉŸHJ—) €zŸö£ T¾t”D È)À;Iì6W)5fʺRµ¤Ú)”ri9, ¶é+]^9 @㤀þÑ„0Eª<šÒ¡—x¨ÈyA$ÎÇÀŠÞóŽÓ[½ó0/Ñ«þ»ºd‹8’W$I¿6 ¬ÒS "ñª$â³"+½ÔW©š÷¾>ÿøa”]¦AÚGa½&¨¢=Ú•ŠÛ•]}+yí5¨¢+ÀšëË»` ¾cÁ–}”+zýÊ¿À Øë»l,»¬×Ëì«„«:¦‹×ÀÝóDÂÞ=DÁÀ Ëˆ«°¼ªÃ¦ªºŒJ=CÞG"µˆb»J"6Á¾’ýÀf ±:×ÑL¸tÔ׸Q²Fp€*äk‹$(‘Þ‹jÀ qæÏJÖa÷ui½Á¤óÄ|¾+…>ÅÄaƒ”}¾çñ4‹ÞÎ5†˜^(ŸÞ7_²ék]«ê(‡¾Óö`Ú•¾Æ”Œ'ì)Œê³^ëÛ~Ö±líÙ¾ó>ëã^îÝžèï~1ÿñS°°¾ÊnŒ ÈMc0Sõ^ÕM¢õíŸÍâžéíïo±î±"’D;þ섹0/ëK r8çRcŒ!ë© ŠP`þÀ9xS¡®¾ë-ì\!ÀÈ :`~Îñ­þñ'?ï?’v6Ô °LÀE÷¦Mf Š"Ê ° FF÷Üb¶èò ÙµÖ\!7"rÁ5WÀ0V4Qà• œqXt/ƒ `A4 |-Á¢ª. XF‰&&R(Y@€3k¼ °bV-Œxò$ë¢À è¤ÄHn:Å™$r…HP§ÿ°3è*!†a"a)‰†!ÆcâÙT³˜åá‘/NÜ0òÀ4«Ö¢\·ŠdñÕkW±cÉšXölÌjÓº}Û¶ ܹaãÚ½‹7o]½|ûúý xo`bt½pckB#ZS”ÅiµK‰2]: 85ÈаLÊaëY AÞŒ"%¬c /M SVk±êP ⬲¥¤Î DQ`n6J]<Òü€NÐ%:„¬Á­e÷…ÏdI|2¡+ÊÌš àŒQè rŒÈ1¢2I 3HBbD4DžñÞh' à ’?ì¤'? ÊPвh Õ}¨eI¢ICb@ÛÍ Giáê×À v°"¡+a‹XZ–¯Œm¬`«X¨rH®€lb‹ÙËêUi0ñ4°‘£QV²­:J`Ò0&Òö+¨Å€j©i ”ÊN¤Ú:’ͼ60$Hƒn[€’8´ÃélŽvÈYÏ®•/–˜ƒf­ú…„æ-N(Å:z13`í…~öâÿ"˜h/˜€ÄA R^V~èÒ¨­c]AAåf™ÄxÁ ’ê—2PT"‰îH'd_ù"­w€êv¡IH†yGË"äcºÑ/iÓÚì†Å¿ÌC)¨ð]Wy˜ –É«" Þ MÌïÐ0X;úÜZF÷w ÙH°á£ XG »¢Ý-L‚ÀIŠŠŠt BŒÄ82 ‰;ÐfP‡rä¬`Ã@+HQrDŽᨚRТ@!h/´4«™KJš'4ˆš–ƒÒ@!q ¶`Çnæ¡‹2„û ¸ÉFžf*ÜŸèàKID ‚.ÿ¡$3¾C êW F`ÇÏ…(3--u- ŸI"P’>¨®€>èÊVHGDÒ-¸ˆ®²¼jÇÂEpßàø&+ÐÄ,0 :ÿ¤€«þô †½Rœ »Åu‰.@‘TÌ „¨à‡<äÕØšXµl k,7º+ìÛq«-ñjˆPâwàELà\áÞ3…Æ^Ä ,,EÓÌ&5"r 5`ã çÈlŒ·ùdBÐáÕ¨Õ.¼"d:ÜÑí gˆL'ªp˜8ÃtP…ÊÕâÄ#…Çÿ;BÄ<+@Ç.n€8 1˜A>ôáˆn]ÿp€ Êp¥OÀI7ÈÒŸáè#ë7x†Ø1²m¼¥¼96ŽW€ ã8Ç“Aþ]@@b™°òΠ‚»CÄ G*“/aï ¸»É¹ Ý樣Ñ; †TœPš)pd&`C€® nP˜P ðC±eÁ Q à_àŸ&ŸI‡/™ÿ û0Ú°…Ð e…ZÈÀ…jq”!A”6 Ïð :ॠÒp s` þ÷YðÏÐÐÀ>âÙ“ xP^µp^aã°Õà4j£05+xÀ£(¸˜-àÕ° ªðœð¡-ðÀб4z9rà~„ –I …‰,N* 7*Gš*U…LlJž¯€ÊÉq¯ R²Ç"x@ˆö Bwy 1ŒÀ ßÓ|"Á I&Àx¥×&‰-˜ëp‰ Äî%#`7p!€…!“À Ò°“`±¡`¡è`6@°Úpa°\( 0yv  û`I}·®—H çÊ `ài1Tö¬Ñ*ª¼ÐÒÇy™Ð­À±Ðú¸g!±!+OF]ù'w°7-Ë®µ˜zp{xÙ”zpG)P˜0 [à¦ð¢v³ƒ²pšW—T Ñ^ãÐz YÛÿ€‘çú”òcµÈhe !H˜T¶€~%É‚¨̺ Pãpµà¥ÀýæšA• ä¨`µX /0a9z›yGB˜åQ]}ëFÑËŠ>˜J­!Eð¬¼`ÓÊ Ž“±6 'ž+Ь=µFÀ³ 3BH9ø  â ž FP Bø5¾"„.¾FoD¼Nú0à¡¿P†È‹¼à1ʼlÁ¼¿àλ¼Ò«¥  È¢#`†˜Ø{TJ¯»EW$»y(ðFÓð7j¤K€D¹+J$€$HcF¾F[„¿¥»Â{¢»Ã»Ebÿ¿Ì{\°¿ü{1L¼òk¾laDv‚I@ Và ·r”G“ôÀq*‡pÀhÔºc¿ ÀP¹û ùÐ$Œ[`®‹Â…#F<Õ '¼Euñºô[H¬¿8üë‹Äðš!:æÄÄ_áB@°˜¼/öS{ÅŸ„ÅuÑcV»Ã²ÅDSz‚À;ËE"IŒÆ`ÆS…[!â×›½0¶Z0–ÅfÅk amŒ!èkÇ}Ii Èu¬Cs,ÈlȇTL@¿Ubb<à#xaY„\Èœ![xŒÈ™ÌVb Ó±’”kAw© e£+3"¥€.bQ¢H³ ³T ÿ>–$Ë- B•@òL D=+ð¹ªÉÁð?|[A'êÂAäÑ¥|û]„tAޏ&ë#@Üuá·l!ç±3Ÿ6ãÑÓî+dƒ !iC3ôc 7 TŽë ÏO‚^‘THqE|ľ¶^ì!a Ý=Ä “#™ÈÝ^ôÁòkñÊ”gÖDÜä"裾8RE 0D w„ytÀ~TñJ$Q€ò1ÝaO”DÁó E!_W˜æ\ò˜Ìð0õSÿÊ€¨¤Äª”ÿbwœ®Dõ\ÿõRöeáƒVž¥ÇÒK¿4ömïöo÷b÷;ôr_K¡<÷yÏð,BÉÊöz/øƒør ¨PÜfo÷y¼øŽõ÷„ùh| Fµ² UÞ EP¼Q© ù1ð Î"ÊÀP…_‘oú§ßC"µ qÀ5 ¨•)`S‰¢ž6ÅR®S—Ê)AàfúaüûÁ_Z´ŒÊ¥ïTwBÑ#¥/üÏý@ÓÝÔXiüÑýÙñxøÚïýßþáïûŠ/þtoýåþäŸþÝ¿þçõíÿã/ÿñOÿ¥'Æe<Ÿø;ô ¡‚Dhÿ0áB…,>dQbU–V8œhPƒ Óà‰h Ò:†D™± –4\¦TSæLšPŒ¥H‘e@Mž=}þTèP¢E…‰T©DflyÊ(F8†$ ²cjÏȆ"ÅqÑÐÉ)*í@Œ@¶,0>UÀ¸ ’ŸÆQa»tb£6(œ˜ ‡/^ rÛir[?…Рp«j@%&”&®¸ cn󂮈)ä7\ÄzP7®R)’WÂ#ˆbÜ-¹RoÂ+Ö î€®ð0<bl)¢%ÂpH ±X Å˜ƒ ‚0·"lˆ‡/w“DuAÅJ,( ‚€À⊖VÀ¢¹ñ5?ÿ4PAcô¨Ù¬X§š9 £‚vÜH2jP‡1‘ ¸£–Z2 BH $¹“Lž«T®¾¢d¢„˜u^À„..bè‚ÿ&‰¢c&XE„i”Bžx& ~’§‚ĉG ð‘g—èqVÊpü’æyÈ #Ñ.!‚BL1‘KÌ•¡FåÄ*hÞ âÕ—pd4Wiˆ ŽJf}%p{Pô‡Z$hÇ9¯ u’¡R…p·ÑqH † å9 XåL=ƒ "aðÈ——Vªê·šÜ9!’ÅÑ œ)B9#õEb…fx·.bz›ùÙDÁ± 2¨ˆ7Â…GŠyèxã Z ªxªu!+‡7lñj+ ð„/:¤¸ˆw2¨d‹BïÆ;o½MÛ5¾†IbžüÀˆÿG}ˆ@‚Q„6ˆ/æYG‚¬ùd$gª+Æç(Ÿ¬ˆtŒ>(’Ïà“ÊùVP©æ~QEØERo€[âÙ y×=ž Á‡žƒ¦É½!@‘àƒÒ8 “C7+±Â8é©÷C p0œ–ר™ ŽüV.ø™WA€¦ùçàwçqÎxãP8jPÂMÄÆrA%ÐBKÐÞ”ðŽMx ÈÂ:Äñ½ð=ç^|áUÇþ1P á˜×äq?#|à¬@»ÐaÀÌ|.ÀàÎ ’tpÌÅä±ĉ‚R(ÜŸ(¨æ3,fvÄÅfÿGB!Ò°‚DšÐ7*ªŠWÄ"êöF‚LÙ"²p@p¸„bŒ+_þp€ŒO!KGÚÑ™®ÌÀgdÀ€‡õÉD&¸?&€aM.XôÆ4˜•-h5£¾ÀXJ¤qC?eDâ :\ à¤"4†CœA–ô74"\a~5›‚2Á€ãÅr}°$Á¬£±PYyµX%BN¶€Sr€ /ìг0Ž‘4B@!2–h$Hü”‘4óQ@(¤ æ‘Á ˜DC¼iÌà@àš¸Ð¦ÀØ‚I]LwÈ¡*&PÎs®B€ñ?ÿJè/ID Ièi:Ø 2D%:QŠVÔOüªA½ÀlAˆÈ(òàý5I6‰ûƒzqH‡ú¡!6¸4gÀ@TÀQ Hb†.1)C< À˪D'×|ÄCŠÔ³F-×Ycú‰°Â!Š5^"¤<ˆ  d‹Jxr“e-†:*DaÀ"ªh„:¨²WD¢q…šÁlq†n‚P_ãÀ)$†wÎÁ!i0 r?¾c`BaCÁ/BäbVÝ‚ [8ƒ;Ü¡.¨«-€9ׄœ ‹|e,[°ƒÎZ!µ0ñ´ ªUˆ[áJ°Ÿ}ÿ@£Ò°-[ù2¯@#`|WkÛØWÔRH|åK[`Uå¢@-ˆ+‹v×»ßý®Uä8ïÁI™`D ä6ˆY) ¶²ÖÏrȈ|<%U¸"ˆ$ñˆ¤ë"@Áý—€·ƒGÀ%TÕkäâGÀTÙp„@†Šø•±&ì$X£Æ?Bù ®e‰ÃVZeŒ¦¬ ñb@xÒ]T „^6* ´+r302ÜeË`ÅUï;d0¿ûͱ"P¯‘0òá…ŒHä2¡à¡eØ/„Á2gbÇ E}‘äÿïR°%Èl ¼`ÿÈ/T¡<µd€k•U4±HÌÑòoY&¬˜ÙȆnKŸ#™FXÙÎ_0¨ a‡!ªG+B^r_î‚×Ô§FµÞ… ¸Ñ .XµKZ7Zã\Ù@òL÷—]$±À/N'k0ÀšØ­ÞI¯ü ~4ªü˜Æ4D$, .¸@³›mkmC5P…«‘=€XÌú¬>„#(çˆ$´ûtchõsŠýíp»Î’)ªK¸Pnìr!Þ™µ«ÿÝ•W¯º ׆­ ²ˆqœ¿¯ÈG.€ycw' W€Z‡'Ø··‹ï®€aī̼âïq³ü WÿyɱÍßl|á«vcÅemÁÒÝZ‹©z©ƒ>t½üçB' W å«ÒBy¥9:Ò‰®’¦øob[le¦¾u®wÝë_—y´¡îÞ±ƒÝè(9{Ml.u¶¥Ýf:Üå>wºCäâm—ˆiBU÷«»&îx”…ø>xÂ^/LD9>ô÷Aá3÷ºÌÝ„0d$ |Ñ/xÃwÞó`g<×`üa™G}ß R…ÓSìV¬IûAJ‰)J„ !bÊ,È€?àà轸ĖˆˆA" ¡ÇŒ~‘‹„š ªÿ|ô¥?ý‰š¡ŒAüY†HDb7ZpÅHÐð¡ì û‹ˆùÿÉ4‘¨B0?îCŒÛ$b܉%*lØg±ãÁ‚n ‰ñX¿¾£X€>ˆ0( ûP¯+èúcî ÀЮ0aß›Àƒ˜…ƒ!€È@x½ƒ ƒý&Á׋_àÂp?ñ@à¾<„Ó„ ¤‚”Ø;„(…H‡=0$7FÀÔ£¾&tÂ'” ÉS½Ð…8è[˜€F …Zƒ @@ Žé#„f@?°9=ÈɸŒ 8›8U‚Xb„-è‚aÐ&h„8ÐB¿è‚VЂ<¨ƒØ/‚2<×(…4\Ã#šˆ«®"[PÑÿÚ¯€Yˆ¤4Äÿ ™‹»?: „° „B\¸Jü (è$ Ù% X…P…90'¨ >¨TøŸ4Ä…na‚9´Dh…;ÌÃ_ 4 ƒdÈú‘ÂÍ`àŠeàƒ—ƒÂj´ÆkLÍèš;0Ì^ØåP€*CP„°ˆÀñ™ŠèAÌŒ> p‚ ¨€8è…º9X„‚.ˆ†-H±0íbÒà€³‰¸^9"èÁZ’7 E"X„UX€8È „sDs¤Æ‘Ý T@KJ0þZ8“ )JˆV” ©†«[” #@H”ãÿ€Y°‚d‚eèx?)T7™|ˆR¸jp£ H7I&ÄÆ«ÄJ(ŒRØÆƒQ ð…Vƒql„„i ‰Qá”U8¾PE¨…ー0IQ¨GZxƒ?H[ƒ% " :I¨JÈ'87HÒHË(XKIÐpKQ8TÔˆUh”ÌšZ'ðŸäµ,-äŠRHË`ɨ€E€É‡hÅÀ¨…à#€ÒŒ×#„DÍ-¾ (½0X†KLj`‰ƒÈx>r΄8ÔÌÊê´Î넾RhI¯Ôˆ·¤È‚„r¤Î‡¸\ ÿ€]£K…X÷ê7Ãv„)0€ (†!ð$DI`PLß ƒ8pƒQ±‚§ªš3„{L¶)jÏ‚H†?š¨H ÐMpJ0‚ñ¹³Ç“LP(†j0‚$ƒR„Ì‚˜€€dE“ÔÂP°K»Y<0†ƒèÞÔ'0jÔÂÛøÃÏÌOD`F„ÈB7†$ý±Ö1 i¬JäÃÎ(•ÒÎ+p„ÁàË P„8ЃfH(O  Dš:Ë,ž=Ð,Ðu/ „‘ƒ>BèS`1]K•0®bÈ…-€€9EV¸Ó(…åD õPÙ‚AðAP2н:ÿ0b¸³D=ÐÈÈ€"«¡l¢…Gå&’ðÒJ EòBWG,Sti ¾s”ƒDhÓI“‰ÏôR?`FMðÏ)õÕ_ÕJ1`·‚H€x“7œ#¶¢0ºa¹µóc‹ÍÚ[98 ¹'pU·[ƒ£Ë‘k‹ÒÙk5TpEˆ¢j5f¶\ðÔƒÀ6…‹Ö(råÐr£V’€€çpDs­Ê `¹ƒ8„äMš€×åÁ(€Š ´"`EX(MXЫFƒE> À‚-hP\ƒRiк@Bl!¢p‚ŒPØ…Ù YšB¿+Ù½9YŠ O˜X•‰ä'ƒµЍÙ‘ÅÙœÕÙåÙ›ÿµÊžÚ ýY¡%Ú¢5Ú£ý 8EÚ¥eÚ¦ÒPè‚. §¥Z†­ZŸ]ÚWåKÓ¼Ú®õÚ¯eX¯P]ÚƒÛ³-[´UÛçL‚à˵…Û¸•Û*jÇ¥šÛ»5[¼(ÎÓÛ¾õ[«Ü¿ÜÁ%ÜÂ5ÜÃEÜÄ]ÙÀK[Åu\ðÂÚÇ ÜÆí¼Èܾ•ƒÌ[ ˜¨ Üºœ ýè‹Jƒö¸\-ú Ð‰¼ fÐÜϵ=HÙ¯Ë\6ì‰Ì…GÉá¸Ø¦ŒÅbTeÒ ¡úв°U‚¬´LØOÇK‰»óS‹¹ð «²7¨[ ª‘ ÂxA› ¾ ºß}.žp‚uX©˜ÿø"]+]à…1<©P0P«mŠ:˜ßRk =]MíÕ]¿iQ¸"™4°)â0äp)¢ù7ð·ƒX—7;ØØ–ú¹ D õèÁé€ù(ˆºò?†á@†J¸Úz+“ÉÃ’Ú¸63Pƒ;ð9)a‘ðsWù 3‘‘ð’ :±ˆ`ÈB¨Mņ0b ™“Ü0A!Q_…X<Ñ“¸8QMÕeHfðáé 1`)Ü/  ¸¶¿"~]<¡…ŒÏtãú›Døá>‚È“= ã:‘]@ö 9˜5ÿˆ ±š‘Ñþ)^bè°â‡°awMd ]éÌä‹ ` QãBè–4Eæ’ “:ú_ߨ’P^ä".+þ_†Y†x“ãa!ÙÁþ5”y…p)˜Nzê€àå&`‚L考 µŸá…k^øÓŸô/Ôy„xØ`–4ÉP–ƒh–ƒƒ¿  Ë–àÀ§L ©y¾7‹™é…€áç(S‡EÞ.@”~ —X‹©š«™·IlB^hdpÞB€0(¦ ÁšŒ†¸1„)È—q°@sh(4ºÙff3@€XJñhŽ˜"%ÿ®˜Nœ®”¦xŠf°¦?î—!-„8¹ª˜Sµupi‰ê¤~pˆ+h¾ð—ˆ>i\ˆ}Áh›!醖Wù§d¹€–&h|3hX”ý[ ÞÝ+Cˆ¨fé˜êŽžèñuઙ’›¿††©á‚ Qê¨a°é¹6„RÐj"5ø ”^ßÃý›ÀÙ WèžPƒü¡Ÿ³›ƒpøðƒ赌&„r™+e àzàÒ6…P#h¸hÙ¡f˜‚xHçÞ1p €³¸…Èhšfz2ôÁAœ§Y€.7¸^¦F€ †câ °¡œÿÉ¡ê!¢„  ñ¡îŸ"o¶Ò8o:Qh¢Px8Oæ &°3؃UcžW;YhnY:†õ¹îű”É€î§jŸ§8p‚pæ)¡Xo.f„‘ˆ¡>bîàø®î€ep)"!õñ<² î^ z¾JVoý~!’©.;€bˆ÷„w ¡›¦›¯ û¹«ª¦iƈo#gqç2˜‘XÁ™ò?> (oü9„Êè΂·WíN"ŒiïkÝlÁå ç^'æ1#*Ðé“’±ø×ƒ1 íî 5D>\h€ #$ìú…`é‡DZ$f‰GjøÿÝ LÒƒç–tÞ)­ž¡ôXÒ WU¢ˆÀkç¥ü¨b*‡2:„6‡Jè§çWÒk8ÓgI¡“Ù–T_à2§†Ú#x§#š€‡r#ªƒõÉèÈ%šÁ$ÔBž3r‡ wŠ~•_ÊtgÏôJ.V· L0ÉahvK÷î)xŸ2(u£™€"P*èøn_Xª¾ƒ4÷Êq¿qsêö^‡Jñ%}·ìVj/.®ôo÷:òõŰöìõ9wt'&í%öÅZ¨}³ƒÉnpjw Pƒ`ç„S÷O}92ÕûxOÿ³€XGfÊøÐp`žÆšÄ")ư@ ÿä—N@”ï`’0|Sàv@Ο '€*Ë®íB¢:†£ú<tœ€_ˆ‡x€¶Ewª‚Øš,hЯùª°*8ÿvÐ(èêEPG€ø+¸ÉJ-Ç2†âzƒˆé’­7hÝÂ+¾€ù3بµr•»'.K8®äúÀgë ¡oÕ².7Úpƒ‰ö‘,xˆ§¾*AŠFü¼O†¯‚/°ù™-`$œI™ɒõQ}3ß"üºO§É'ˆÔ_fyŸ%¶‰ø™÷¾¢ƒQÆ+¼JýK0~[†Dù'µ7ìë"Vƒp|p %vHƒW²Y9‡ûi„2xÊç{åÿš}ÌOqQóþZ…1}VªA÷?`|'H"C Áãü jùé=€ˆCE'<-¨˜Êô"F¤v/Þ0ÀD ü%á#eªÄ!  (;íd€‘2KJïAa À#™o>Êu„ >~°9rÏgzøDʋԒO‚ö”H¯Áͪ Dh׎Î1B¨ØA)Àê‰S$dÊ!€˜I±¥™Üd“%‰ˆгNk¾x±â•;b ·ËÀɪĆvm2ƒ@ ä¿ £i{,b=\‚…<ÀŒ¬¬(,DÁàÂͯ'÷ĸõN† \ÏêQ[¤…3çX0ÿF,6…V±»Fì,N¤Í4ÀöÅz6íX›XQá-=î´`9\ÈDœaOÙPhsˆy·¼-êÊ8Ýv|¹ÁÁŠEÁŠ5c yoš Åv’oÚÉ¢Púñ€köÅqÜ!ZŠ€wÕ¼\Æ™fu½1Š ¬xˆ—¥@×¢ÍÔQ/£Œ3ÒX£7☣Ž;òØDð70øwÌYcHž@qˆŸ|"PŠ”ÀF‰ä'1‰qe†Zަ%?üL3DcNCýÄHšcò“$œD•£ w61Àüø%’‹@!% Arñx{~’%Àцò7èÿŒ%$Ÿz‚‘)¡Š2†å>ª¨¦y$šnÚ U£.zgU…iå£ì¨Eƒ¶*é‹°²æ¥¨w¦æ©.¸“ DÎ…Õ¬A^ ©¸*Ó1°¶ÑÆ­0tùH¢ Jð«·”žªi¥}îji®vbi夾IÄk»08û®ÒNª*slsŒËŒ¤K«œ¢‘¿Ä%1‹iÌc† fûß•¨Å4í•‹jÈ\Ô4«iÍkb3›ÚÜ&7»éÍo‚ÿ3œ´$&!Îs¢3ê„QºP‹!®“šñœ'=)0DÃÏg=ûéÏn!RŠÃ)ù Ѓ"4¡š„cË‘Œ˜„‹ ¨äJQ…BÏV]¨<7êÑVT›©EIjÒ“¢4¥*5èJ£×Ñ–Â4¦2)MkºÒY2 §.Ó©ÒxÊR›Þ4›¡Héd”¾ñȧAÛ˜áÒˆi@’ø)Œ Ôy€ ¢Z8ª5¬ÈÙ0¸ŽßLL2¼àPA‹µÊÂ^Ô$Cö °Á¯ƒ‘2=@ ?ÍeH@è°†5 à5O8%Æ 2° °Š°K;{é,gÖ´Á0ÂEÿ7QjŽJÁ‹¶B¶¤b­Ý0ò;¤@ Ð@"¼,  ˜¬<%´…-ðB0è¢+LB0YKo5‰;Œ 3Pƒ/±_,Š·06¤ÁP@8w8¢ ü ¬ß|Ç™ g’øm3¨P <áWØî¢¼)¹¢¸)@Èh„åaÒHÄRÀÖ ”%1dÛŽˆhà‰@à Hð_áe9­”Ñ¥bd‚9¬u­°ä‹†à 6wƒß 8C ¹!F¬`ãµ–#%-ÁWQXA^À*0N¼"d¨ÁYû{€ZLA2àÿj¬'¡ ϪrL´Š9<9 aÇ+¤ðP™ †AZñpá«Á4T«1Ã5€H¡JÄ‘ÌáƒM˜Š°Òðƒ: …R˜L%ÔáŽEUfhê°4W§Qgá…!ÀL‡TŒ£#ƒ¨Ñj“T `Éã8G’É@‡TcѸéôMÛ›$9 €HY6mT»z^ˆ ì`Ï%9oXu¯§ÝŠö8Û;2Ø¢0âæ H50B;8áƒH`Mڢ籆3ÈC$IbɤQq ^ L1™ H–½ô¹Ñw§Ð:êsFÒÿŽÑ€Wh!{°'Юx$ƒøÐsŠ¥SìZ2èÀÈñ„3ƒ%ÅØõXÂQPwš26°†˜¼0ÂFôÒsw¢«Žp'<±ÈÚÒçÀÈ¢€rH‡\çJø@;HôŠ pNº©ýdepšë8ºîº˜ è\Lf…Aî€s½†VÛr{’î2´ÃÞ ÂQ‡8:BøÃâ W»›bÁ–Mò Tq\ÛL Jð ¢È9Ï g‰ä•C ‹^¦ƒô'×A"€Y14LBd°¸ L\ÁÑÎ!ƒè°…Ñp} C€yÎ ÿ )ÌãïÄ&Y¢µrÃíÞ V¸ö]Û¡A½xyù¡>."lú<¶ƒ "‘FÞé`,΀WxpFé>÷÷-&‹®™½ÀLBã˜Þ³àƒÀÀ~5J'ÐA;Xp¤@qÉ|4Ø,ÑkEÃÔÂ,€ÂD ei8K MÈ@ÒüÂ/àC< KˆUL€Æ‰$ÜX„üÀüß™Eê‘ä/€2€3ÜÁ¿(Fø€‘,A#|NGˆ øF)ÄG¼GbÄÜ¢Ä/ GŽƒìÇ8ʵÞ@l¹­â:ˆ@‰@6bÁ; ‚£Å†:ÐF/¬E3€gÝA¹ @f¸ãŠ,ÆDX$2äì¤Ìô ² I¯Ì ´“P Ì O˜ ÿ\ sjM9K¤ê½˜§8Þ*¶þ)´r+bZ$ivk¸F+IÍRQ‰ë¹¢kºªëº&&»ºkš¾k¼*©F ÌÀ+ÆX˽FŒf6ªbÊ«1 •_ÕUÕÈ ešMô«ÃàÖÀ#ŽÔÝXX¾ÃW½”h@ôL¬ÿwÙ,s §¹B¨ÅèOÉZ ·±ÄlìÁÒ̓ÐËÒëŽh,É~ŒÌþkÄ܆”ª\FȬb tQ²D@…èA3 Œk€’†Ö hƒä1dBˆícâÕÈ“è(^F°¨DCfÅÑmBz|¯•’MÂ"l\Ãz"Q/˜ÓŽ̯u[˜êÙº 4aã[-cŒÌQçË,èÊŠÝîlØÖÐ׈½¬|Í–©Éœ´Â$ÆXt -€™0ˆÖùÜÖ qñ6¬§&"h!|U LÚ,¤ÀœBL€„€u$ àèØjÍW"ÌÀ¢DUŒCÿÖê\!8+´Ö-VI„d-0ý®>oô¾g2èÀ@\"̦ú‹˜‰Â¤–D A>ŽãbMkQ ¨Á@FÂìµÀ$B‡Å4tï+LÀó*ïø&Øj’B¾éhöø@ŽAŸ‹9«&t"øl  DïAs¦¯û¤D.à" V…¡Û $3Ä/ BýŽ1`¸B"O è—Ê|iðòŒ…É"X`ÀÊÜ<à/(4ðøÊX€¡Ñ£ïXp0ä"nâ¦L¿Z5ôÚ„_° ›äÞ-”e@XÐ… @:hJ˜@Q9a Wuš5æÿ Ã  ÃØ:<@ àAèƒ,ÃßÀ/8@|à ØÀL€ ƒ ,Š!S‚²!ßÀ3ò¢hÃ>ðmGYBÈí€$Ûy248Ú¢Aƒ‘Ý&ãŒ÷YZ\ ØO$¨CÁ$ âJIÙÝp`Ëš™=ZcVtíî8Ä\G1¬šÈ2-o„øÚÒÀ4“) €«ýº2,W/´‚AZ;(-3àòEX@ A0@¿ÅA£¹Ã¢Ms«u±à™I‡H³U æ0½™!ôÙ¤@(œ |M]´ó(+Ù/È;$3×3(ÓAP€0ÿÍ!€¯!C0¯Zˆá ; V¬(Ê)Œ[¹é\Е´L”…»ÁÁO8<ŠMçA:„ŸMWÅ> C¤:ìƒ> ( À 29hCOÀ …R³Ä"/Š0²(5w‰T€>8õ‹<_¥­Ñ‰€÷‚<˜ 4´ôÙ…ue¶Dƒ ÄKw,û‘ (V[Óu¹ÙÖøèšHT@ã€:¬^Ÿ*V H‚:Œ ,š›=Ý2àµ#$ù©:°‚sðÜ;Weój¹‚”[Û}Àšv3ôÊ`@'ƒ V˜Êvg—5º©Û0{L]4êÍ\êAØ‘YdÛbBÿ1(B5 Bˆ›þÉE8$ƒz.»ÍÃ$80ÂÓÝ¢8 wm!@JovS‰…œD¤¶ ¤Õ‰À¹uÝ\š´â"€éu²Þ½'” Ät·ÁaáÉ™f¦ahË <]ÈhC7ìÃ>ØÃ7,ò78Ã!;À>|ƒÙ8ÀXWSu@µd5†¯Wÿk÷]ñY·×Î<¯[‡\,C\‚áM´ç¢€X€å/‹ÄŒ×7ZL#‰—ßH”Œ˜ÝÝš¸Á!dˆ^ð´B2<ôùL}3ÙrÌì.ÜÞ5LkãÝ ô:ÿx&œ¸«ù^é—íy‹@ÿyè÷98Áv;ìM´3€ÀÊ™}{®Ä!iyŸ÷‰ozy˜ô›é‘š_[ykAœß^8èÞ¯öA:ÛÆwŒÔÅDÃã‘Ýw\³#Ú¯üÁ8”nÆ€K°9ØJ ùIÕ¥5"}½Ô"kƒ6„: C7ü‚6äCK~ÂL‡k¸ Hí`¸‡uÈA*ð±H¯†°¡[ýaD%¼ÁÂým(œü൷eÝՀÀ;sûñªþX; U „;LV˜a;Tƒ”û5l- Z!¢ÍÜá=ß0K"0ÙÃB¾Á¬&[@¸{ÿ"ª‚ÐõÂ+(¢D{À ˜û—EÆö£ÜÀ»(¼¨“z_’€Ûù¡¦Á)Þ]áBÈJD«õÊ9¨{®3F/ð‹Ñ[d@¸<¨Qƒàü¨í¾ƒC´"–74Ø|æ"óÃG|8¼¼»vj°óTÆAІ`ho¬M|ñGð‚”¸=´º8‹,ÂL)48¦YwßÄ ìº!€!ÛÀ><À>dU˜Í ,{VÛÀãþ…/ŠRCmáW²\r*Ô"[°bJ¸F+‚+¢†¡ñEbc£ —Ì"jL ôÑjí/DÇA\FP†Üt¬žx,Gh¢íoÂÿ*ÌÃy£ì—Rg¬å7vÀï7j]ŒCÚ{Àn<†< ¤Îñ>ø:ƒÙt¨æ{44³Ñæ~6îÌ[ d̹±"Ð,´ëw5²¯·À¨zl¨Ç Ø2@ 0À—qîÚ *Ä$èË8Bg Å(Ò®ž…§ça#…wî$¦T¹’eK—/aÆ$ “fM›7qæÔ¹“gÍ'‡.\¸çI, $ð×'(3ú䔀5k$páBâ#ªH“ `ë‰üš ïZ}oõ™U+-Sµà²ý5ÀÛRBÞÚˆàmY•MZªÌV¾Aap0æÂÿ££"+æ{øÑ†$C£X6¹+ŒiÓ@‹&`Ù1fšÀàÔðJ1±›Ð~*¡õ±ÄDé4cØ0}“Ž=[,7šdžV*8agàE]}¡¸ÒÅÌ%sÖ žïTÝ]§"n’úè«|¹mhyȨ“åč±îŸÐUrc«æ kìIÁÚlÐÁ!ŒP ŒÉ¬ )$h.š6d+´±Á{:ÃP'¨241E73Å›@qH0T\±FfðÃYºÐÆ RH‡,ÒÈÛÀêÅ%“¬ÑÉ'¡È-½¢’Ç#±Ì©18Â[É,ÂíJ0ij²J2ÑLSÍ/ÿÏ\ÓI6­tSÎ9é¬ÓÎ;ñ̳M=)ÜA€=ù4Î@-”ÐC‰DTÑDm´A]*)q—YžR’Ñ €t½ÿXÂÑK? UÔQI-ÕTF5b¤ PØeUZ|ð04ÁB0è ÊuWsÕ&’釈¹5eRÀWab¦Œ ñÈ#™.…óÔm¹íToÁ]1gL‰B ‚ˆÆ–A>BÄU h’Q$@dUh ¥{kÃC?r°¥Ra‹s»F &˜ ¥– ¦Xäxƒe+TBÛp9Nsão;Yä‘ rE$³¥  a!IP^$€‡+¨CÿN€5™›Uâ d„zJ4ÀT1¾å2:†À¡aˆ ÁSd1ˆD ¹âŠX–HãI[ì±É¹l)A™ ¯—èdøš†kÞøãQæþ#ŒTV A2hE¾‰Z>KÅH[²0–¸„VªÙB” øc UÞP[°ÏîÜóÏ9ãÄãH¹ – åí¸Íbâšõi_O‰½Bp¡àÔû¬ë(A䲜‹éE\ ÂË8V‰Ör ˜Zô驯Þú‘KaDûƒ7¿^þ€+dFÈGäüžbˆC{ql â„PÙñßAÔ~‰„ ü$®g¶ÿ€œnHÓ$G8b \* ~ÀÀœ?ñD+F ÏzS ˜xÇ€4”ABŽ„%4á Q˜B®…-ü _èBΆ5Œ¡ q˜CÞPH¸Ä壑ˆEÄ“ÜG#.‘‰MD¡4ö¦¶W¼¢RZxÅ±í »˜ÀùöEî0tN4ãɤ ÔË HÁ‚4¸Q¨#ÞH‹­¹ŽWHÆÑHARHø#ŠaŒÍˆ±dàѹ&Ò7@–ÑT”´$!1™I0ÉL œœ¤&AùÉPŽrXc"å)Q ÃT^r•­d%_éJYÎ’–µ¥-q¹¤Xæ’—ÿ¶â-{)º]sXЂIÑL…c‚©ip 3 54/¯å°œ™),³BP" ¹c¼1 /Ô@ÊÉ 9”`š,á€xÕ cÄS%ØäÑ;y` -'$(A(tΔ¤ŸvÚA:]ĦW ”˜¬”B!¦Ÿ–Øç$µ!A!ü@…rµs $ˆ/!ˆf°óòD8`‡v Ì”e’É ´Ñµ_S%âhJ'‡ÒK Æ 2¶€§PÉ)›€SQt*'b(E;:P‰ç *Ä)$µˆ¶ä§/&AÊ ½¬ŽÂw>¥@P’5º ÂŽhR…k°L­‰hÿÇ º(?ü*·Qªˆ°9§¾µ¥O…«@!X´ƒ4j¨L¤€QÜáXÐ~%4¨ë8Ç’ Ò dðB!†ÐQNTcÂH P 2"d¥„zÑ *XA «Dbkà²WƒÛR€ àVØÀÁN!<,ÃXAA ZЬ á (Ð?ÏÉ’9$b‰Å¹Š»€ß1¤²§]A"º@„Jù …Ю&º ^p ŽÚMÀ(0Íâr`%4àïÎû^%Ô`&3 o:Rp+bX ³¸P°~ÇË]8²æM;S" 5¬C¨\qÑÐ*,”@ bmÿ:œ‡Ç ^‰0c¸²ÆŠ¬•Àöµ¨½ÚŠÑÅb'¾ ˆ=ú;$X5†ŠYR+ÚÝ– ƒÐ„”ðâñ®à²…HqVò1­yÔXƒå‚ùÎd¨ðcKd¯à¢ŽÄ3T‚†Z¥ ùäA}A|h$?LÃKI%æL‰t9(MÂÀIw ÁÄœ¥aVƒ •øª,Í Y:Ôà '@ð.¼ɨÁ_±2ÔZL!¦0Ë%ÁÑpä@,&Øœ2˜àê)TÊ Éª@Š =¸:à€”ÂÙ@7l€U´Åϸ·=€ÿüÉåö€`nÀR@ Ô®³Ú/ž®o€7A›à da&6ÎK†ðÞᣬ$Áp–€0¡ BÍ ðÐóÄ$& "bÀ8Šfb Óoý`ï* ÖA4`Î0çvÌõ A%LŠAªABÍ."ü&±ù8!´.`‚¡G|dYQfð€ î ¸‚=©€þ/h¶ï%"K@¹ÈàÖÌïBa tQ"\í tÂLÿÀÎ-Eëø/O&´¡öaìáÔíœA0 h`.àB/pÝ#ÀAP,ÐDNàd‘,á ôU" ‘.clátqYÀ ¡^€e2Ô¤Ê šg €ó\±òá)”M–pÅôl²ë Þq(uR%G©Rr%Õp}üF«$` ©àBa uM)§›ð¦¬K&w jæ8AP€+êæ²äQ×F%{è¬à‚R%|D ¸q Êá8â r %] £$²ôåšÂáÆè±)WBP:à²õ`Ç´ÿÀ3SBål¶†0Òß@à­ ,b2Md1ž@1ÙÒ6awÖQ•lν€Z ŠÊ ¢¡tцk¿vÁ ì ‚Èt*´+¸Ó €" á¶Ž À´ò€%Ðá÷!ÜС& DFà¿á*@ÛøB#1pø@r!àɲ©'ó9ÙðÎoÖ` À<À_®lŠ ˜@øVJj×´î´BŸŽäàÒÁ €Aä’î .àä DCAël“ž3 |ÀC™`áæÀ’Ò,çáê7{Š”JÙáãda1JH!ÿÓD/ÔŠ t¨HTè”s º µ*”FëéTÊ \ Ô$§&ÆIƒ&L!¡Öi9›Ž3ñFç’6á¦j¢F±˜` Lr#rÔA³ŒÀ˜Äá°á FŠ h´ ŒkGöx“z”4 „.² !zÀÂ,E Ö6î9YTäÎ/M锿Òab Áhb :@î` €fÀ-† 8añº` bîÚ(à O<++€íO’ò‚MLÀ¦ ¨`b ÂØÌG8¢Pò£Ú!ç 5æjCo àMDr<@Œa/ö# $¹ADlàFÿÀ#E0DâsHöA¼\`@ÆÁôòB²‡È ÇÂU4Â!B9'Vëâ ËæÑ!˜Î§8"Jpcu¤þTнR YO"%3Ö+!Ó² Ê\IIYd„FØ´%|€´˜ÎdË•bªÆ å8YMaY¥á<VS‰2A`f`ÒâÒ«vöÃáe5꬘aHÉÕ\‹"Bóâ©Tj`0>nbˆaa6+t¤ò#0Ïe© ç*@îÀò­‚ ÎçÆAú–TA°°ªÖ#¡-¦„ˆ^¡-Ö"/ãâ‚F@êm-:$%’D ˆ(Ô±dbÃ)|G:þ$ "h1´×5üÃ4¾Cƒ£1‚†5c”#,ÎW6–+"„À ®#;'6~ã>$£5TB~­`ž|Ç7| ¸D¾ö¦‚vÀâtùW€¸Dþ£}k×|KiÎæ—6`ïô zÅc?X8ö`!äë¤ô8(ã TPL¶°`´ Ë"AÉ`½Vœ‰Ë¼ìOplÆ Ò®Öë Õ)$À»\NðŽò²ŽîœOôîÿ1×€¦,½µd !AÚÊ;Ù~€¬´nÆ…ü\¿ä:àŸðh@à ä!¦úáOä Å!r6è¡é´,OfÏ!<%ê<Ô4åF®ÞÓ®#(<âÜÁ£ Á¶µoþÜÏ íüÞƒôfkå~Îå*·®ëÊÖ(Æ&W9îdâ BÕ_°ñnÀIë â@xáë¦n¨Œ€õ"Ëå+ŠíÈ`€¾î¾ñ¤/éÕ¡Ö®è*a bžZÜÁãÝQ,1 @(ñü$`BµçaÖ[]7+6«å/ÿ\ áàÖ²ðÿ%` ié€(Ú Dà}¡˜Áâ5@šîâÿ-Fþvó Þïç©òxâ:ûÖàÄ SPüqp,åa’¿ÂaMV.Èœ  ¦Í›8sêdA`'OŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§Pöô)å Ë Xb£¥;uf¨sGSæ‰ ÿQˆ¥³T»S”P+” ˜ HÁÔÜýrÜã—7Ø´š¿Ê4 g¸¦<!ÅÅkÖ«•©é¶PTiˆ³¡HŒ3Ôñc\œfˆ@[àÀ¬ ´’©ñ1 ‚’¶v$CÇʪ©¯ŒÍ¹£Åìv‹È¸ ÓÒP°A‹v×ú5A@áB¿#‹SvW]‹[nüé›ÅÌoqê$¥íS'`šeó};_OrrÈ^‡ èþ HN%½ý†Âr5½bÁqy$NM#YÙÌ4× —YTvèᇠ†(−h"j|Å^”Á¬ƒŒVÑø a yÔDÃIÐÑN/2-#bÿP’I3R )Z Z[ئ$íTÃŽ;i! ±àÓO^ø<ˆ>÷Èsò4 “dÇÀ`E# ¦ÙL­ñÄ!Ÿ!Í)Û @¥!xœÀ3‘¨R‹:Õ¢ëT³Ð*Ó4o„£VV#ʰڈ:|è× 3 ²0'€V„%€ƒÉD>P@!O‚ ,Co !4Ák¸-3Qk#‹÷1ˆ›‚(»H0®ÈzÂ(qXH >+@È8Á_¥ ¼±/’su“`²8+ÿ;1‚øŒ©0ÒØ±a 1€ã@ 4Ðk´ƒ†àà0€ Œ7#qÚ‹ãH+•0¥PwCP Øü¸øhŒ¼ˆ$Ì026ç0”ÂQÐÃ2Ñ0‹»r^ãÄHé Æø‹àŽãP «àk iSç7zRwkº ïpŽÿ1´ÓñˆŠ ‘ðàuçäS’=‘ éSÜ¡ŒÅè©È’…&ÃáP†À¦(«ðï À ÐíÀ."푌6QÐ2ž(ù£5…pw }ÃFƒH]axl”` F@Þó LpG"ÔR ñp&i¢‰ÿÉP ø@=áD(r–Þæq5 œð$%!0]#vXP™1,áÍà3 I0Á¢y™·ñfâ"¢àZy,ãuÈ™¶ -g€ 1Ð ‚£ ! ´q›9!IÙžé›ÀI>’ c€wᨚuhŠà—qœÁ¹ŒžÉ203¥Á –4ˆQœœI²Pš pš= ³ð‰ ˜j´é²wT°§‰™I0›â©2PqZI%}ƒs5ŽîÈ‘¡éY'†à‹0ˆuP£± ʪ™bà ‹5‘{4Q‡­ÿ'¡ƒ™š^ º¢ÎE•°VÖ‘ÖH°©,´H'hA / c@Äb+sá3PBÀœAÑ P4s ‰k´ ‹Ñ‰ /€ •át§G•ZbCêðT¯±V@ìuÅÁ :q!¡¯ñaÞ§ ”»Q ¿v ¶R¨¾q:Üá!sÒCɪ,JB V$´ˆ¢¡(w‘ €ÆA¤„óp#±s•¥($àvž:b¨¿a‚1;ʧS"¶ -.ƒp¸!¶:ˆ£š':×ILØawðPЦ 1ºæÑÂ1ÿM²u©$J¬IP1@%Õe™Šu0 Z:X|Ä$q!“§¨*™Ò&Apvhw5ðŒÒ"Ð+ÂPY +=QLhð_Ã8€+VÑÀ = 2xíw <°/‡ƒ7á[²^’2 & D&fRâ &¿À&nr®en(BAe Òp Ä2ÂQ«ðŒY ' „ðU gà“@úr“5 ,³Jk ? ‹U« ›U´‡š"ã⌛u.Ûeà-g€±ÇS.›R6rÀ,hûž*-ï’ƒ4qO[%뢴‡—aZñ à0¦ó'â®YÑÿ|° ›’/—åx à b(…Ç$¾÷m{-à5`@µ€P)ÐP.~;ˆu[ ~â­µD-Ä⪰‘wë+jÕ'š‘tÃ8ó?»¦?` ¸L"P-¶PwÀK¸ªŒ”RµRëºÁ2,ð¼डP8uýºŠÒkÀ01Œ01ƒ¿¹U`P'­ À cW¯‡.¦’1ƒ¥ Žóˆò+u6a ˜Ð4SãCS4@ñ€‰LÃþ€Ö5l05@ Šw!„ø2"н 7…8 .Cb{ؘÓR‰É“ò@¨@hSÿ€“ ƒS<`±ƒ6¤™ ƒÃü8l$w'§àp‰“.Ò6ÄíÐ…FÉð #ws6cðP´(ƒ‹(‚ là ¾#1 Plu7 —­ï 6ƒ@3ng ¬¸3ÅÉÓ6O2:PÇdó:õ{¼ ZàÊ“]S!7¼G¹02fÂ7ñ9ªÃ ÿ¡𪌀óóKžÄŠ#ç@¸Ê*Èâ-¼-©“;ËÁ2~<“,A4<„`ÉMì2³´|›s½MQA+$F\Äcˆñ ·Glô ¬5ö>7WF;t—ea ä?gÒ@$HP@(„@ÿÖÐ D0Is‘¢ptbdD:´=8ÆB̼`¹¨=/ÄríÜcU‘c6†Î4¤Î/ö¼¼ùŒBñ¬E7Ñ&þüE”Ÿ/ææ¼FcYÊB6äB\ôÏdÕG;DcáÕ{4Ðc0 ½EmÀcIt=Fd`ìŒ/–CýÐ(4Ï­Ð8„—Oà˜(Ó¾ Æ ýT(æB‰…?”B=ÆÏ[45fÒ'”GOÐÓ=&D“ä̳¤Ë»¦HØy’˜& qQí£Oáq¯Á!üúWè¦jBª–uÞv †ÖN¬Z=ÕKÇÕrÝkR=X’„G¢ÖG1síP+€'t…%ÂÖÿJWævtuf¢؉Ý×ý؃Äü–aPÂ×apÙ²bUmòVõæ7ü¦‡ŸMÚÙ`­×¨mh И`Ó] a'ZR÷KŽ0_¸k€ð„m\røg6ÑÛÔ†7O§pL«ýÖ¤ÚŽíØ„ ×'âÜËíxKf·aŒÐëE>³'P E°Ýø4: 28ð NPÐÖ‹g…ËFšWÙÌ@I2Q \Æ$J@ á×ÄÂß4Xkn 7ˆ$ …°;Õ-Ý[ÝP·FÝÏÝà6± =:3^?…Zà¥5°°;?%)@)Â5ÏS‚² h ¦Šà ÿ°â•àV‚]÷M¹|Ë—±' 4± U6ºÀ} NáF®ËÃÜ`Óá2 &À= Rä Ê =.å×…A÷£å? Ðxr²5!Yqi3‘AŽsEÐ “€åGþæ°Ö\7ýäK‚Z„ *JUg2‡-nn&ØqÕèƒN/A‘[p `:ó{iÞÈ×°e„Ýp~éžFæW t.E²Zc$x¾ åežðé%]¶0n È ¶À° òÀȯô_9nUÍä ]–ư tÀ ˆéÄ^jVåa€±Ð-¶ä 6– ôá„P `C ÿüÅ¢è&Ð _—­\7¥¢D ¹PgžînePÄ>b¤2ì“ۅ̱0Ðõ ï÷žêN‘b(ÝÔ:¡8Ïe3Óì~ð¾iA`Zþ3€Ãñ}c /ØFAÔŸñßîßñÿñ ò7±e/òoòî`]PfŸð(ÿò­Æå ó6/ò(<œq€¦7ßóÏh2Q wêóDò._jLE>E¿ôL?Ö-ßôPõR?õToôUõoéX¿õ!ÂØsäõÎk`ÏõXmºe ÒI3[ãe(ó§-×Âòó$²R—mVOö¯ÊÌ-Ab°d9«iLÿÍÊpwÀ t¶AÑ;Q¼9‡¨·!4°q%°9é^63†Åä½êT{HÄvKÁØnÁóp÷¨¦(¢p€—W‰0{ú§ãy_ ÃÀw2À×®x°`îE†G Ë #|bk©üWxU½è§zÐm§yq’¢üÁíôOq²Ù× „W µ€§p: +æ/°GJò±•“A(€Á‡ÙX {µtƒuG@PRHryU ‡; ” 0䈂JÀ"Ä‹h ¡Ñô O"H< M%5TüôY12Q¢Š¤%:pªåEœ9uîäÙÿ£O A…%ZÔèQ¤I•þ\Ê”ES¨Q—>•ZÕ*TÑéQ@¨¸…€LwçtÒˆP«–Ÿm˜è€ž ½C&—î„»ÜþhÔÄâbvú¸DêfÎc¶xÊÁå×*ÓlA‘osƒ~€å5°(.ƒ- øäY¤Gz§¥p¨3°’r µ´-],ɉQëTØÅiæÀ”:ã }ôf2ƒtœ«%n÷ÕdhÏ]'ce]µUÇ%œYŽ€w/â€YéêÜéäNd®- ÂU&BïªQ…qª1&‰èR‘9[¹êA#”ª +´ðB 3ÔpòÿÚ"ŠD©QÚLJ$hD¾µæA`ž3ûä(,*„Š;ÖáÄ®klc¶FI°HÒiç†zt @åc.øeŽÌj ¤T”‰g‹äa ËxÈäz, „Ë–¹F‚ :x¡¶V.8#‹Šio˜¢Ñq-ñü0$”ÖøÒhA”Öa¥:ÝeE\J°@È9çh+¸s¾šlNõì„HšGÄWR ™RÄ4+äÈÓ Jå`,(UTj ô’f.`t*ƒvXb‹ÖXd‘5h¿v0 aÓe åøüãŠ8|Uï¢Wg¨ãŒ~µH×NYðÿÈàKquê§{ø `м¬zêÝÎpÁ7ÚÅ 6äÖýª`vÙk)!â äø¬ƒ„jà ù íîU~…­ŽP2þäu¨-Š{ù¢- f³“ö`«Ä :¶@*¨È¡Ð‘CÎ4‚‰Ee<ÄÀyÇTgæx€¸†Åd£–zjª«¶úØ«²ôç¼u‹D‘ñ/ N‡ÃZ°åv¬°èlõ0H‡fθðÀŒb®H¥C9ä ×R@'9J¸`|B›#4'pŸ{äASÒ&'ž=.°BëJàÉ¿|hÇ ¶ZeÀƒP.®e³pì§ÞÿÓÀå^)B•aäóÏ `Dùã×±ÓÈý‡0DýhNQne®OO€‰\f©%ÿþæ<†À¸À…'ŠOË 4ˆñ=œh²îfåÐý}áa‰„wuÄûð¬Îýù÷ÿ…-q¸ƒ8*˜‚/ð@êòX¤ PÏ EFäC0#©D ©‚cð#CQ ä/2° zpIŸÈÅŽ€.ÅÀ†ñ² =â!šxØÐHøÅlˆy 5 €\,r AŒÃOHÝ·r`(;Ø!D É`¹tƒ[PÁiià;Æ!ˆM ÀyvÐÃsƒ"°‘Œ¸k‡ ÿÀà,¼C‚PY8âÀF7`‘ëÑ3àFœ”‚çc#ŠvðÂŽN($Z˜Æ5¢ŽYDc }@P†²Ke)My¡'Dá{fúÞ#º>m)ɉP’’ºç½XÒ#©\eÀÀ…^Ê2'3â?¦¦iìaIDBhˆ ³˜Öhƒ4‘¹t|>’À*'Ë@ˆùÈ…'†´N|ï 0{éNmé—áÀâÞ ¾@ðûÌ#`p¦[zSž`ˆ àYu&É÷dh.O‰µ‡FT¢¥(DGyQŒŽrsUbÔ˜BÊŒöä=¤h ªÒЦ4¤*eiK]jÿ!s­T¦é@¥€CP¥ÀêÜL}:À\Ô cˆØKzT¤&U©KµÚNÊT¨FUªS-%ÂP9A±jÁ!†¸ç>ºjNðPÖÃ0ƒ8VýŸS©úV¸Æ•‰råŸ-L‘ Bh„]Œ1 ŒÈ!†ùäEÄ  L¸²(AåI%.a‘]Ô¥°ªHNÃvÀm>ÂΞ Q·ÒU´£%mi1ä %,"$("dÐ…Ž%Àzæ*@¹%@ ^¡‹"0¢ ¼e $0gE®r«Èv¡´Þ– ZâT‚Äñ%<RI`O0VhM{Þ¹ÿ¢W½ëåÉ*f¦Å¡›%A;‹ÀbŠ E2è@ÚÁÂŽZèÈpàå˜ ŠðONP€&âé  @ÀVŠ÷b¤ÆÉ2ø@Xœ6[PDQÙ{b§XÅÆšÀ0‹Wˆ9qÙ²ˆô‹_õ ‚±€C}KÜÉ9Šr@ü« D¸æ”Ò\¼A¥àÃs…£ñcó®XË[ær—}òä$ÇÀŠ%LJ`Y ˆ#à›fçd³ˆC2@0ÐÙÎöóId7c‚NXäÉ(=Å”µ"ÔI¯—ýhHk¹qÀc2Û7Ó4¶È2Šñ#x¢ÿ¾ˆˆs"k± `ȃ ¶8µ0„H9@²U ï {‚Co ª0Æ*ÈÀŠÅdù³‘&ö°‹mÑF#»´¬„2.1ƒ˜Í\¨±PÁˆAlÂ]`g†·‚ÛVXÙ¶,1‡ P@Ïî‰& Ó8[Þó¦7\Á©PÃBº5.2íœ(d…òÓØŒŠ©#œxï×ààQè‰^oˆG\âPÅS-r J]tâçxÇ‘úHàâ\³@=~r”§\å+gyË]þr˜Ç|à2oyX?:s äâ±4O6Ï}þó` {ØlŽº€~t¤'¢Hž,"öŒ7”KZxÅ„wa ìà 9ÿ¥/Εþu°{å D "Ü ‰A€€pðH\! ·ƒ{ÐPذç]ï{V- a‘¥E˜ÀÜìºzt'ð]ñ‹PLÛ5K±3^Ù’:åO\y¥&ÞòÅüæ=ÿyЇ^ô£'}éMzÔ§þ¼ŒM©Í'¯ú u>ò°¨]AÞ Ì€õ‘ßý±v µbMs/Š1,‘¡áA×úKÜí5Ôü,'_'¹Šô{,-ÄCÐ×3”?ûé[BÕ)€/ ´«ü(ÝAúÊ bøV\։ƦP?'ÐþR\ЀïKª÷ ƒ3‡µ¸? E°0F‘†¢ÿ†Û 8ê )ð¬Þk1$@Ⱥ¾†Ã)Z'Wx Ȳ?Ø® ‰bx‡À;q)À‘¿vYª@ÁŸH¼Ü8À|›¹÷«(^ð¨r”Ô‰?@›dÀÛ9 qÁ’='„Â@B "0¡8¬:ª„^Ø WP·…yA= ÂþѼ7Ò…û &´AFaC#´ÃbÉ „€B‰€ »@ €$\ø•¬@†I$õp…<°ß@†^PŒ·!.X†à4bÀŸxÀ†êʃ ­ò«ø~Áüʃ>@«2¨.úPƒJd/ȼ‚—¸;—¨ÿ‰–éZ-,D 0‰Èƒ 8¾éÛÅt Ýx ›øb¸p4+ È,€Ú¨€+ȃPp а‘Y¨KÆq| f̃j$ŽÆDЮ҉[Ä+,PÄI(Æ ó ŠàÇHHH€Ÿ\GsÔˆ+p†°JbÐH—„ÉJ‰•¸L`A™x‰­œÿ>°dùC^„¬˜Êv\>¸I†tH5*BäQ¸ƒbÔFë¢I@$Ê«ü®e”;âðGsšË^ì¿‡Ê á©æ .¸Žìèù(.˜‚3X”¹0¡0hVQÀ¹ÃðI¸LÈm©Ó”§xø؃)=،΀Ðh"/yŠÍ…Ôp¦%Ú @ˆCXIÝhîà ¯`ž9!"Ð ÈŠ8¨ò0¨„ù}®pKiµˆ„È2°™€ˆM)»)ŽPA OóœK¡ƒ8yÔÎs¨ :‚qN^hClæxŽ•©NÌ\Îï8˜ñ0„—QÿN°€F»ˆ¯€† x7RO …!˜ƒ] aO÷¼Ðç̉•‰ÌåùÏÄ êäÏ/" ˆæ´ ša‘Wh *¤ÏJ@O5 朅]¸ƒ¨ÎÌ …É/"¡&µNð4P)xR®\BäxžPPҌҕ½R…€†V𥵫´°Q€2(»¸Oç¶‹Ð…(™¿‰Ñ‰ÒU½Æ^Ø‚½†T 1ËÔŽeQµÀ hXšQ¨Ï¥eE€ôÙÔÇD€q ¨%0IÙ`ÀLŠtY P¼@à”°ÿjZgH‡F(Ö´a `#¨„žRŽš,Ñ4§óL†Æaˆcj‚I²˜ò”£šC¨”ámñVƒ˜„(˜“²7(™écBU«¢jAA#k¢(Å“ Г1S)X™Mù8ƒ=¸W ‘±x`xË1Q(ÐGAéîlŠu¶@×91[è„9Y–T@!UnY€1Bš(U"èZÀ„* hPU ÕW~Å‹Œå“•”ˆ}Sð˜pƒpXS½€íÔ‰Y‡EÀQŽeˆMϬHXÌ‚=Ø#³ Cée}Ó˜]‚÷ ”¤Õÿ L`È‹0×X‚‚Z 0Ú @!ñ\™8‡„ ‡ZñY‰Õ•ŒÕYQˆ“ƒΑ‡)¸˜Ò¨‹}#gH ƒÛÚ$ÐUo%Y@!yÐ7˜•†Kðy0‚D“Å”}Ú8€ x…›>WXÙClÛwÅ•N¡ »x‘A¹¾UÏŒ(ViYð €Nø9¬Ð;€k®|†`›Bd”%¸†?Z‡¸Šwá!*É'‹ø|ÑèÍèŒf8Ô/ä i¸!ù´:á  ˜o)š¸˜ÓžYÿ@˜wÔø 9 ˜BD;²¬5y"‡É0šœÙ™Úh¢ÿæ^¹âµ9ÎÐ+Xgp˜Cî¤_C¨"A€ÚpqÕVý˜ØPFq nÝ(ÝáE L"BÀÀtáÚÍñ¸¢PšØ˜Ž_‘ÕÕ;šä-VÐ`+ˆ­Ê`me™’aÎf—_Ô‘h R)>b9^™ýH˜˜)â Î’¦Á˜BÄ‚u=Aubž˜"ã „úMbʽ¨aAf@‚,j#va”u–É„¢f^9û½à„1Žßw5bÀÔùÍCÐé0ãSâî‘”-(afÄ´Y›v‚&ÊcPÿƒ?H¾¸åF¤SL¨øŽIDið§Æ™€Z`ø…  ËévÙœïùœü‚ÅœáñKÖQ»×=©†g˜Ÿ‡n†„ë± ë× ƒvuNì Ÿ²P`î=˜y¦¹ƒ;˜v'U~‡ô¸gîeeWöé€÷‰ŸÝ)gúxèEJõQ“tF’@g[ð,¨ç_ùšA†éÙg9†\¸„„¾p†,šÝaµúá“`]ppàå©¢ué=œù“éœÕQèíùÖAivºv¹ºé ¶`éûc[`bîb‚ŽÆ&8—®þ_ñ˜ÿ“÷‘7°l†O0\ø]Náêkðjžv‡¦Ÿ&g‚þ"¸¾ž(j£SQ‰&Ídê°háð€ësþfäÐå!„–îèi+€eœNé™;à€&HS-é*r×L¦ìRÀƒ³õjù±ëëàƒMði¼¡ÄžÓ iRúŠZ Ú:£tÍ–HCxé,!¼‚$* @ z1»èk À¯ÚR:"yY68jzÀ‡éŒéf" ƒJ¢á¼¹Yi‡8à‚ˤ¨äq°ƒIŠ„œi#A ºÕ‚—Y進Ь£1(£=R‹{.ªø  µxþ£l‹S¨Nÿ—¸mZ£‚÷¡8jã® yèdpânïzøohø,Ú¢8¢€µÐW ˆoVÀ‹0ؾÐö†Á 2p!Ù$âꤸa% ±ÄH 1ÀjJf†`³KZâp1$ó~p*@ñ_’?¼øƒ,EÓ5Æ;Ø@oÒ•rB í/É$jd=M¤<’vø™¡Ñ">ñBzo$Ùpaàñ s)FÈ¢óÕ;ÿ"®± §;z0p¤;€78v˜€¬ðHñ6÷q^ )Gpòkq4€;`–ÞË$qPô)2êqS÷$=Œ=#[‹ðC¨`Òÿ%¹È©_Ð%^¥ŠzÚ§$À7Œ‡Ã¯b½b2&d*&4i¦&:i’—_`ö$²) ´'mÙ§d (m™§Yÿ'4©´!+Pø~£ƒ€tê%“Óvz…| ‘ã X2ö8£uÅÂvõÐw_²§kצ©´†Ru/*wÿv“3VðQ,“ušêv\’x/'O÷_i\âökwoÚ mú¢ñ¦Cè&{¸ƒg’xú"~·’{/5â8ymG“œúxo‡¢”׉‚¯o‚ùŒÿõw§v2›Šõ ¨„¯±Žo'\’ pBxzŠ’gyõHwoÿ¿hŽ_§‰ßOgmz„€Wÿ€£×ø«w¡z”¿õWÏ«_ûžèŒ€!$ó¿«îHâ4‹)X«t{ ë{©@÷û¥_8§ŽÓ{‹j{¾ƒ¦m'|üÃ+¨wy¬qx ü‡{ÈíÍ¿|Ä÷8ͧ½ÎýØ“í- %Ó}Ò¯ŠÄq?Õ}Øÿ¼ÔÿûÕ—9@6‹7È:B€€ê€¼Ø?}”Ãü¸ú?Æýã~™šý×ã|e‹„†ï±†}›ûâ//æ¯}í—7-(YˆC[¯Tþí/óß<è_hD8ë]£.ç;ùŸÿ뇀ái[èƒ@ò,hð 2lè0Ĉÿ'R¬hñ"Æ„7rìèñ#È"G’,iò$Ê”iQ°¢‹¯6h¤páB%Μ:wòìéó'P…A‡-jô(€ übuAà0‘R­jõ*Ö¬Z·ríêUhÁ`Æ>ðÄTÒ~mËÖ-ܸrçÒ­k&D†Þ®µë—ïßÀ‚.ö¢zXa‹o `"13"‰+ØØŽ<$‹¥Áab¤dII¶ÈL ®”Ѥ“–„1=Ù‘F…ÑÁ(ŒV)ï€c…øAEqÔ‘ tHB…•<ñ&×ô‰‘ ÔµAHdXíØ¡È ýÑN¤ðJq€-JŠÚš‡*JP Œ0"Ÿqº3˜¡ÜáÆZ¥Ø¥\>´HiªjBkåÿz’ ¼Ó‹CkNqëCJ½ð‚›‰qlh1ÃH&£NdëDNL›A%V4G §,Z[î½JKmAÌ€mQ©B«Ñ°­ùÁ)°¨A"‰Œˆ† °+äÈLÂK-€BŽs´0ËÐÍ`A/û’1:d†ê‰@§,c_Øà€†@(Ä!ƒÆ&nŒrü8ºq‘P @ $I:½4CE%x-Pˆ¾ðD:Ï€W€"‡A(A‹B¢ƒ¤DA@sÐ…"_$âsÌ8'Í2…léÁàŠÆ+d¬+ŸâpGÑLëpˆüú+ý®¸¤Ø‡KÓ/1x+ÿŒtã[ P*‘@-8ÊfCxx±ªKM ¼×JA Âå†9.,€à®C8 Ö˜Hƒc¾s¿(ãEL"8dÍ* jP1eGÂy0±¤êÎuQC°~~¿W,°çÁŒ&M ÐórßÅö`úÕ©R¦“ª[õÀ~ÐâdÞ¨  ÛîÖ‡¶ï]&nY€î— íp0 2ú`;ÆnuyëV°8í%€Nø€Ó²–=:Éx‚@ŧ¿ˆ|n-üœK—”uO}gÛìw†sxPWÝX”ÁÛ ŽN3<êd¸¢¼|"ï¼ý\`–É€üUähá(Âæ%ôüuì9¼°ÃrÿÐÆP0û)m_€,9if ßyo…A$ô'^¿•îI×@¤Þ‹íÕAÿ=ߦý€.$`ùÑ+õéDç}Þ&D2ÁÀßà 8ÔOåe€q̼^H!Ráõ›ø^XP»¬ÂÑÜÂá 4¸Ä_øUƒÞ4ÞŽy+  å5¶ÀÐmÊÑ_©Íà*B¶û½E¡Ëß¹ AýJßÛqÑ™LÙ [k±ƒt›mÌ<ØÂð²¬Në$ÅÀ4ðÄ?„‚]@(ÿÅÂ#XA6áL ,_8|€PN!ÕµÃ8ÕÜy@À,ÌÁíFU‘ýM€1ÈÛ€|Šœ‚C¡€ò%Å Ð"hAÌÀPA/À©¢2–E¡­!L‚e£Z%+þÁ3-4³½Âs ã@ P_Ô±CÐa£CÍb>Ô‚ÄãÎ}ÁYÐEŒürJ5¸@kYÁ8N@6¾E*òbÎã5Dk…E†¡Dß@ü‰!èŽåâB!ü,Š-R˜,DÞ²ƒNyAB.ìFr$D03>>¾QMÞƒ ¼ÁŒq£0ôdÿöcZÀ‚åô^VY”œ,Lä:¨AÙ#á$$Ø"?²Dl#²­VÚbLæÀmã–M–3ØÁLc9WB›5CŠ‚PfˆØàµáKÊÁ2^CJöe3¶V4è” ÃÈäÉå8 æ*àL À¤Õ¡/¬¥q\•}åTÖÜdA: bú£DÈ-¦dXÚB^ÔÍ¥AZP!¡¡­ÁÔÛŒƒ)d#Ä€5Q»Ð €²#äC¨,R]JIýˆ¤PŠ"Ž0!g’@Ì‚ãˆ].Áàƒ„y×­=àCB`RwúXC1`'>t)¡[  žÿ\Àš Âè‘ ¤mÚ]ÑIÊ:ˆ@^$@¤t@r†Å)JäÂ!€ÌAô˜ÍÚl¿ò«ÆÿÚlÌí#féТìÈ"­ÑÖ, `l4™Ð„MäÈÑì|ô,Ö‚Ê&ÀÕËZ08øë£DÒ:!ɺ­Pl­#Ì+´îë×íHmÕDÖÚ+»ÊÄ…ímDœ,Á€ÀnBŒ­¼*mÚFÝ®âž,Ù¶mÊ­ÌN-Ôê­À"Y<‚L®ß¶+ ¼«¼ÂÎ.‚ÏöíϺååªÓ^Æí€åmá®ì^®k8­è nÀ®ëS˜.ÏV+At.CX®Í‚ÌØÄ»Nج 0mâ6Ýëæ«¶d¬ºdoF„’€i/C§„d(¼ß‚fD± „S•U\/Uˆœÿ‚„xoJÔŠxµhe¤/P„ï[€þf†I­ü®-Ûb¨Gø—ï~Ä…·‡º.oübEŸÊ_Dðûû^pðÛi°jd°i„@‰0 sp E9tÁŒ‚ Ÿ0Fœ¯ ǰ ; ”êΰU,°spÿâ°§dµ°ÿðqqxN ip#±?ñ ˆ¦ ‚Û ñ{`0[qû‡"Ü!«l1‡1P`±lBkŠ1§1cB1¨±¿± @H–“1ß1“Ýæ1÷±ÿ1 Gq Ûñ ²!²€¬!äÈ!7²#û†t '¦F§oJF)Ã6lÃ8€(º4ƒø–4:9pÃ6ØÃ”}çD9ì¶„ ª B`9å{«‚rÂÐècÕT³"ë j=–&Å (¼¨LG$Ô§4²E°RAŠ>—2}€?éæá[¬×ûýç*ܼ—Žôè§hÊÙ”#¨¥DOÄÐ}ŸÇÇ:íeïóŠÁ¥ìà+… èÀì>®Á6oáþÂy‘½¨¶ó6¦'E)TâeŒ¶3 ÃüÂhwÿh @9ó­ÈºÄè²íÑ>¿ÿì«d;.õrÓºëe­èJ-ÍptÝîüŒ .p0A‚XÇ(A„'80I `ÄšÎ͘=*ŽèÐѧ'Q&¶$àfL™3iÖ´ygN;yöôùèKŠA‰5ziÒ¡$6u Å)Ê¥J…RUZàG(¨™FµZuª×Ÿ\ ¶¡ÎÖÖ°b¿¶uûö ¸séÖµ{oÞµxÁÎmóôïÔ¾P<ée{øè"Ë7–ëø1dɈ'W¶<8ðeÍ{9'żthÑ£I—ž& Ó«‡fVÛÙ5ìÎRéf}wnÝ»‡É&mWÖŸÓ¦l|¶NÿâÇׯ–ÍúòèÓ©W›fÇkÈÉÚfN4aLéÜ…C&O·;åïÖÙ·wÿ>rh2à×_Þ~~ýûù—Æi‹þð> <Á§B7|p<%œBû±¢¼ ãŠp2ü4üÄíK†>MŒïÄŸS‘Å›ækÆW”‘F BfjÜ‘Ç}쯰‘~E"<É$•\’É"›tòÉ(g”’Ê! Ê*µÜ’K#刣‹Zœ²K2Ë<M3Õ4ŠƒrR1…¥1ÓÌrN:9¼sÍ<ñܰNc(b”]âpp½> µóÐDC«%™ƒþHEÑH%TOÈQ¬  <¤Ï”ÓN=ýÔPE51½QM­ôÔTUEtOVW}V«äŒ•VWk½×\uÍ-‘^}ÝX>ƒEsbñ‘Y•–ÙV›5m‡>0X!& ŒµvÙgQÕÖYn;ä E„ÖÚr)ðv[tÕM—´ZQ„\dË-tÝzíÍï B©„Ð ¯-6Û{7nù£‰•PÌDk&âˆu“w^‰-¾˜ÝÐþ=ãŽ=¶Î\l?î¬[[…e6~8å–]nkå—ef™f”q¡#8š™çžK–) !ùþ,Ç¢ÿ$ àÀƒ H¨¡Ã…#6œHP¢Å‹3jÜȱ£Ç CЬ8²¤É“(Sª\ɲ¥Ë—+ÃX*pP†@j4V`Æe0¥˜YÏŸ˜h ³©Ó§, JJ•dÕ«X³jÝj•)€W9dAYTOš]Ä(…©ÉAc³Æ8Ž"»â(H›ª„x‚Äa¤hL Id¬˜º0`…‰!^¹JžL¹²å˘3óÕ¼Cž0P"NÊa0Å’S ¡ELm¤Aq@ ôÐ…†\o¶,îÔÅ–äéÃ#x$%üFËÍ1YŠœò¥Fc.´Èå¼™»÷ÈßËÿO¾<øƒ€h)š5!  WÅU`+ÈÜ$€eŠ‹­6 PÇ#ôŒSüA-ot2ª,ãÄ ŒoP:XÜñÑH'ý«ÒL¤EO¥ ¥K7mõÕXgÍñ!Û^¹Ž‘¢à Óà™æ> „8¶ñ„@† Ì·†KhV €ÈAÊ 7d€{Ôì8‚ag*¢~x«(D¡Vÿà5 }•Ä<­ÙÑÞjÔ·Ø2-3Á ˜Sžn@k(¦ðKHÌóÃ2°¨†F³®œ@\5õ#÷àGðÀ€¥É  G0Ì{ʨ„¸ðEò‚{„U3ÁîˆÒàýaï”æ*¡ݶ#bëê3Áh´€–€nóE´Úá¥m ¢V:½F¸ýrˆqëGV`¿¥®Ááb\c´F­‡Ya‚\ij&ü3ù°ŠCBx¤ p‡Läˆ@÷Ñ88P:Œì² >ô;À‘<ø³gü@ë¼L3 Æ€‹¡ÌhHàÇG3ð0-ùÛ¾•è2Á‰[ÚAŒx°@Dp¸ ”ôñLíÀ»|ó°\F:€{s–S”@.a´Lä¹`ð!^ áá5’ê Ê#( ŽøƒÅ.z!)°Ã;X†Dbvÿ Ú)D®q°‰ ÙpLeymÙ‘†T_ÉK ÐYDæ¡a5%Öáj„\çú³õšp¹¨›Ý)ß„¤ÙnyX¸=hë_;Àìk×ÁÐVÄ !œ·ÜÇ_g€æ%r!ûÜpïèÆPØÐ}e×aÙ®nJ¡B|'À/fZ–mµ1€À³$%¾u¹)?øqxL~òwåž/Ï_übòÓhxåY=€c4>ÈY ¸ ¶c¬þ·1/ ,¦ªÆõŒgê Kû˜Ÿbö™´¯J†=¤îiüL‰ÿúÖÿ§0X})ˆa7œrQÀžU–„îÿ"ïÆÿöKÇ{“Mo;ìÕŸ5M=Db'i<ð!óÖþë‡É)PÄ’®ƒÿa2/QQ9bìw€Ö$Xè—A°zöÇ’¥BÕ3—á|¥“€Ø‡~¨ç"8‚ H‚R¡– %è¡-ÜFzÕ‚ÆiÒF$~e‘@&¨ƒ=øƒ³]q`cʱ‚¤Š@b–Ч •TI±j!îw7/àS@˜…Zx53PŒ J° Ê =h€8TyñaІaÀ €á…2`Rp†¨W†+ ‘`A;0ÀarŒÐä3f]°D€š@Np†Uä?—ÿ¢Bc?‘`=hȇ}  êŸ?Šó©YqAz¤HŠjè@š¤Nú¤0ѤP:¥TZŽUz¥Xš¥Zº¥œa¥R ‚\úK:ƒ"qšcô¥ ¦"1ßǤkãR|N/è¥a4¦pR}c§Á t¢t£ qq£ ž   ¨ ÿQ70¨6…~ê‹Z |ò§è¨©±¨™8tÊjʨ‡b¤N§8‚Safª@0¨%¨©5ª(!€Z’p©…ꓦ°]’C99g óõW¼P‘Ÿ4ÿ¡¤¤C¦©óqxsOèe°¡|Ê)ð™`p±€z”>Ùu1¶Ê¤ŒÓ«›ê N§s³vh#¸CaéÊ&Ä£¦¦*ëBep ›‘¯¯F¦¶ðw¨š€©x1@ 岤Ӻéj°¨ù;Á“gè­¿Ú°»à:§é2ÁhËZ¤Ò‘ ßZ÷:6Ýñ>5p8@BÔc=8²$ÿñÝó=Z2fØÐ)4ß’df>=7ë =KýŠÑ‚Ð?ÿc=Ì€dQ@Qdz꒽РT 3°‡„3ëQš E)À J ­¡¶*ÈA€ªFe€2Ú¡ ~ÃCðCàƒ”‡ƒèmqF¢°Eh¸°pE@¡·>`2/äF1E„FÔfð<¨€ÜF=„…@B~k2„£Np j=Ûƒq›k ¹ô3äs¶m[=48a u+CÔsB@”'di˸ÁåEð] € Ø0·‰`¹ëö¶â׺‹Û¨_rB|¹a Çÿëˆ 1/@IÔÚšE…0BP¹˜ ªzËhB1+h`®ËCtD+`>5ð¹0§…@¼ø•‰}é^P¾QE:°°½V´ä£|c«g‹´ (Ò€üûNðw@ ‰ê¾àZ4´‚P˜,¼ à@H0ßê +@·…pBX ¸c«¢[¬›¿& %|†(ÐÁ)_B«‘¢E#´CÜ@ŒÍŠäk¾A KÅ[º·Pïkd? XÆF òÄåTp49r}t¬ ‹ysÑ\‹d¾LàUØÅ+™&ir —ô Uœÿä/J†JJRKªDKnöJT¥¿W𦀳F`‰æU¥=ޤF“à D ZàUå¿Åo a>LîÐl¬êÄNÃZ/FP&¶ ›B¥Sž ME ¸LóOóÔF±|GðôÎ|€ði3w3€KÔ,QÉưƞì8KKã`FâbÂ8ÉPÊÄRç#Ë8«„Ú£áP  è‚Íã,·\ ìh•uPvNÃÆ=ÉŸs'ÇFP QÏÔ¹ÐQxô þ´¬…ËýLŒ0Ã` òqFˆ@ÊɺËýDvýÛÎãÀÍ-ʲhÍ ÌXr>Õ@hÿÎÍåÒtà ¼ÀK€ ²\N=l>&;¯kμ¼Æê,ǯltGB¦¬ âÑó¼€°lr„¾œ *ÐF…OÜCßüΟÖÒñMá4NåèP ZW@­Ñ½@T}F¾d@­Îfí>€Æ‰&]öeÏ"pÄœ.}P½ÐÍyS½ áP²èÙ£uÊÿqLî,©5 ö,5ÐíÀ o%*ÕשŒª S‘—’c¦+xcÈF#Ûq¦F6ÓIe^ÐãUF ¤Á¡” ÐPÉÍ—K0OÛÍ[àÙ €Vjõ"€³yÅoFíU««ÿUNÕ¨ó›0 ´œÏû‡ &-áP¯  haË€,|§¡=OŠõ$ò0 Ò¢°V¬0VeE{R·¥W-)gpÝVÏäìÖq°X¶pÓkˆª5Ý-PÝ"à`&kV—V®?úM¤eÀ0§µW‡ w¬9¼zµuHš%®|º¥I†y9€R³55îb´‚,ÝGÞkÝŠ ~X«àá!ÕãèAÒ°ÝóR«5à>r.Ôß1ýá÷+µÀá~ý5`V8{ß þ$4Žv×i°Ë{uÚc¾kqçRn½U Ð`€•ÿPº$ ¾••kM`ÇFžâÁ…X‹€VÐ }…áZîÞf«á#— 0åð×8ðåé£çö[#•è‹>æ•%d4õáÔmàºAKÀo½åFÙ=`€êa^ã°'\µÌ#V£m °sX¨³cG]áz(Bhed>Ž£&ðÐGõW¿ÀIêÅ^±$/Ð ñ5YVšVåŽãàÎô_[€Ø¶å»Ül¡ â”ÎÖ¨5•*È8¡pX“bwžþ«§—ÐÕ%gÔïµvkÁDbœ ÏO2Ê pNVàNù <ù…bCÍ`Ìþc^%ÌuÛÕÊ jÿþè`ït „Ù2[Ô…V;æNN{ðKe?–òÖ»Àî^ïñW~ö>Æ ~½ X¦eK‘j z-¢dÿ¦ ~ fE8>kV+ãfµ ö·ø^ä^UPVÐÏ[ËPæ > d^¥èçBm›2þ@0¥Î+˜@¸†G+ÒhñaÁº„h°êG²TÒˆí”:x PÈ Ä±ÃZ¡8³sÇŒ98ð!Z»j Š0Ø£Qš…-¢¨3öñÍ-þŒ"ôçU¤FÃPräh K§FêªQ”È ÌvYzŒÀÁJ…0=”‘êc+Wdš• LÔ’¨Ø±raG„©aIÀ±Î¼>TèÁ7í:xнìe˲š64CÞ |­øý£E‘k$äXyÅÿã699ÿTA‘P®u¸ Ü ­y!¤˜Ž×Rv´œÔ¯»Áñgä’RAFV Â??¢¥QgH3¬hä€ÉŠdÈá \²;‡q&I`;¨¸ =õÆqG3ž|Š.>X»Ž+1(yÂëL9Lb› ¿˜èâ•3<ûAÁò@lĈ7¤Ë¢?#ø@>pf¢Â&þka;a‚4HÕ€©j˜L®—ܸR‚ˆBq˘œ3(ºpVS €–í¶Bå?8©å*d`äŠx‘vü  F#‹€•ÀRVØÿ Úi§6TQéx¡#&Ý@³_r9â|¦qŒ PùQ”|“'RÙ@‘?>ÅÇTèi€Íÿ“ žødNŒqN Î(uRÔrH@;ºP'Ò,ÐHØ:/(EOú¤­±”½4R EÈ ¨‹5â 6ðH‡ Y2Á ]Á[bcˆdX!˳ º;à\„‚Íwàn Ñ … !XÓó;gùC±c”MùçÛ$×V†ÊöÍ7݈̈=’ÈÙtKÄRašU¹b^6Rx×L!ßPxE îÍ$%ƒT\f˜B™¥[ÿ¶(¼ä¥‚=^ølæ‰+Öì_ž7¡2 (pÖå:Çð€zû÷ òôƒ ƒ˜kF¤iôQ˜8 ùÑÚά%%™„ªP`‚4‚Š_¦â.pãÈDóˆAˆq¨€Ù’¿Ÿ.=R¶w•·ŒÚiRdÇá³s®f8 Ê9Q<ŸFЛ^ (Ð<²'s˜€ß=ä}éI ›€œ!;éç4¨jl3y@×Ä+‰(.À)0žxä_|ø}øþ÷uZ_TAÿ1`¤¥XÃérÌûøÁiàÜú¡‘ÿð€¿øÅ§A«ÿ +åëß6ÿö©¯âÛ”cú·¸ ƒQ@ KŠÕô`C,㠾¦+ýK Œ‘"Hà$Ó§CäÆ áÃÉ 9è¹j¤|+ÔÌ1¸@B²Ï‰!5r¾îa}DtB ›8Å xî|‡ð„µÐxÄ’Y«vBXM xEÛyôI@G`QèŸ/°B°´Ö¹)Aà‘xI$ UØ’‰oÔ£ø…êPbŒ¤NöX-n±dœcàðˆ0¡”#âà'ÛB*j2å«ß+€ÈF).‘”4¢*E3*Þ°•¸Äd%‹8I-r’“UÄ¡²¦ÿ Q4 <Ÿf@iÂ3ƉžØ€ ) Ëf¢3Kf ¦ ?賂ñ¤§óæyÏzjÓ›òH þp¥OrÖsM#¹bPÍ€ÂQF> fX@Xs¨=½ùÐx®£å¨;Ê…ŽcW­(IMÊÑ“–Tƒ*µ(KS*PA!@º{©KQŠ+›Æ3¢•«çˆjúÓœU¨C­§øÄáσÖÔàÃéP`ÅYþt’DjN|ZUªnÔ˜X½(W³úU¯ö4¬0åß0ÁÚU„¶4§-ªYÇúV´ž®s½)]åz×ÇØu¬iÍ«^ëêWÀªõ¯ì`QzU¼V±‹­+8P ÆF–ÿ«l-¬dOÊWËÆµ¯‰•gf=ûÙʂְ£mië†.L…³˜¥ì[[ WÄþÕ´Ÿ}-kkKÚÙžu°½ml]«Ù®^µ·¹õqW+W@”Á|ÇenXmk\ÙBWº .nC;]°ú6®„­.vƒÛ\â·»h…ÀÄ+]ï¦W½ãmêzÝ‹^ø¾W¾(Å$†1_üæW¿ûåoãë_ë²×%:ÐCæüß'XÁà]pƒ¾Ú¥ÃÚÛÔ‚ÅU K:øžõ¿J¾« €|´ÏQ‚|à P° \Ë õW<¸…IðÂI64ÿ‚tL¢T°Âµt`­ÃŸøÆ|Wp‡hAÒPpf AÒü¸UûŒ‘‡<Ž=f¡ÒíWHV°M” ‰xÅ>PPEhx=1¼™‡úÛ‰ °Zè‚X8J°€ÁÀà; …<˜ P‚ ÀH˜ ¼è=à@ HØk,(0øëƒ(®¼‚Ø3É8«€!èºp=¨X©lÁ †HÙ8…ÙcÍ5ØTX…9¸‚RH€ (À‚S¸‚ ¿×“˜5¸^Є÷Käˆt¿$ŒBhœÚÂdàÌ6ÿþCC€ËA£Aÿó¦ ÃèTˆ@C…H dð<%bPÚÛ;D€Ä8®¸ÃT”0<@C«s½ ˆ=ø#Á¨¿ÜÄ+,B?`À5lÃÄ?£Ó‚Fôb8>à@oÂ,ë*[ìª,AP|½ÌÂR$€9’=TC9€]4Á¬)Â-\)(„ûãC9|BþóÁ5ÉÅÑ»Å#B ƒµà : *pƒ,PƒdX€z¨=y“õ`…LIRSa ˜*0¯3ƒyÌ”.ø»ЇZä!€UA— ‡‡`Ðqˆ‡sÁyØ-[¹( ÿبF 2ðF/€HX‡ ¨„Iˆ¨d¨ á‰äâ…VHR‚90Š €W C‰ :(O ˆ8¨„­`†K(ðI œ!®(‡pà hG` É Èæ1›D—aÔ€ h7hE>Ð;„kðˆ¢ƒ7@‰Rã•ÄNð Ÿ\p@ÄÓ‰R€X…Qà ‰p·! Šœ0ä…4>¥pϞȠP¿‘ ©%IŠS¼: v8‰ ݈͡,@å$^¸õhxŠl# àĨFǸŠD«pçDª÷ß{½q¿À:Ä7~»â>„moöÿoŸøYk„ ˜Dh›þƒ´qU ´‰³ªD˜ hÉŽ€wØÇX‚NØ… ˆP"`»¬¹x-Èxø3y`øø'iž¬9µáÇ®ªZ`ŽŒ·xŒ— x[ˆƒ‚Š-x:p®R‚n§x¬gôH¬¥ƒ?t‘aZ¨_ .ô„ÓˆaÇ(½*`;%xÑN€ºÄ S…âKÝ$ØéLDàƒÿ¸…K}´À¶†Ã‹-ÐM‰°(û³ï°÷±× M Q¼¨ˆÏzÏÿüÈJŠÛ(¯E`ùK Zøƒ0H…§çŠÒS´ (˜€]a…Þ¿„50ÿ]}8»]ûX¾†2ø¦ I >)`Ø€EˆÐ+&Ç(/¢7þã·z(¨[(´»¨]ð{Љ¿úñç0‹W”#œáo„í^„dÈý0P·N˜hùÇ¥È ZP§ˆPh è€ hd”.«vuQ@€P'U´’lÔ!C.à aÀ€OŸ8NÀከV1¹æ ŠGŠRåd?~‚œPÑ"ѤJ—2mêtçÓ¨R§R­jõ*Ö¬,´ríêõ+X¨aÇ’-땃ŸAŠ\èTÐS€¤AƒdŒaXLQÈ u¸@"‘\= €GÐÁÂèÿ",b봌ֶ½ô‘#FŒ³Æ(ÑZ’éVv34¤ÓAôPÈL,j³²gÓ®mrÑÛºwóî;·ïàa¹\peÃ"‹Žš ÕÉ8Ã&Ž çá:QŠ£$(ÂXÇ´7ŸŽ0ÁxímÖXž8®#Á`÷î‚= ÷¿jŸ6 vK 8 x ‚ *¸ U¶(AÐ~ J8!…Zx!†¨!‡,ÒÒ¶¡Ô!‰%šx"Š)ª¸"‹-â¶¡‹1Ê8ã‹4Úx#g0f Ž=êè#9d´A@„IöÈ#‘M:ù$”Qj¥EqÌ ¥’_1‰%—]zùã—½ÿ3²ÀÃ3©x’€+¼òÆ.PØâÁ¯Ì©Ei*³ž;ø"ʸ §œƒÚ'3¶ÐçQÀhœ.š%˜aRj)¦™jÊa Eš'¤pÉW !êqj a*ª¥²š*¬®"k9£¾:뮀r몱Ûê®—nz,²É*‹áÐô‡1" Ê£¢Eiaˆ×ž×flÚ·…ºäí£ÜžGî²éÚV©ºíº‹í‡a±7"¶À½{/¾ùê‹`¼ì»ï¿ <0ÁZ|°½Ó[0à ;üpW[Âæ/Ä W|1Æ.JlqÆ{ü±Ãs<2Ä €|2Êj‘DMi@ÿŠxqšVhÍSÙ<³WÌhó¹%´¼ÓÎ:ãArRE#ýÔ%Ý•1ôá€n¼s‰7Á7<`ƒ, 6؉lð „`-EŠmìc)€€„E^!M:¬C™GÝQ‹„ÏlŒMö“†`s*X$ð.¼o¨ÄhH^ìdÌ”)j( ŽVÃ.)¥Þ CüD ¡€€/¢Q2ü¡C%ÖÑ ¤¦b©¼³!Q‚ ŒÒ°s‡!`š *´â«dÿ j"¸2“^-fWJi:Ó jç_ò "u‘—Ȫâ:×¥rUðÐè4« ‚®S¨ P¡ÐÜÊy H˜Â05)ò'[¸ô«Xí;¦JTpÖ júª(éQ:­_½,Z}šÔq £±±µ@d‰YLÕ¥(®[hBX±|@ í†`‹FH–!”CÀ20N•ˆ%é8)¬±(˜Ì¼èUÉ+²táèØ‡>Б P ÔÀ/CþÙ’èƒ! pœß<ŠÀùE•rQ¢­ë`€"ŒCÈc  n®kTy <ˆ†ÿ 䑈BÄ(8C ¤ÓF@Eh1'jøÜ3 &ÅHivðuH·©úɰìxÌ9d\€Ç%@€(Z,‚¯Nb ¶Ë-WàXÚq¸EÀ »8Cb©÷'ÛpÈ"p‚#$ãØË`n…_°†Kb̘04ºa×, l޲:ÝŒøv¯ÏN`VßJÂv å &¬ +ð5°.'J\h¬CT^3†Ð O 92×í—Ht|fE[@ nþ-f»üå0_`¥B‡ž,Qt·HËÑ5%Ý2DàHgÕ-gàÕ½ÒqóÚ0ƒ3ä`CGÛv“ÿDÑ}ìÃÚ0¨6þIÐn ãALæ``ð<Ï¡Ì;K?¦ðe/\ޱ‚;hÁ‘D9dBfK8f胻±À/¸›dN&„)æ/”ÿ‚$Œ€>#iþÈ#<ÂwtÀÁ}ÌaŽv<Âz¸æw€–¤æM„Ǥfx`[mÂÀm€]’#<Ásè¥ 'ìÁhS ‡w„Efzç'xW™5§r®&ˆC^6ÇsêevŽHqöË]^çSgw„§¨'q.ç4Ü1üÁ&ÀÖzJl:§Ÿñ'tƆ æPpw*¦j'Hèæ&AȦo¾B>ä‚”ÔÇ`™JæÄô¦uÂQ$v¨wÚJä¥XÆ%ÊèP|%Œ¸RDp؃/ÚŒºè»Ôå´ˆD3›UøMVPγáN ¨‘)‘©à˜ÿLU´Äd–'’2i’úÈnê(l"è‚ÌÇ”©ÓŠé–~E‹†)—–©™f  ™ž)›¶)\i—E. ’®)Âl ~ Í…º©n|iм©Ÿ^H @$4Ñe&`ԈŠà@ ÒiL^, ùÿ”6ôA…iÂÌ$@ ,À& 4êÏìJ”Á¡:øÏì@ôÏ”*¥&…`@RÔB$ŸöimH˜ ê ö†±ë„h„Æ2(CDƒ-0‚8„E:+½00B3xÈ*ètƒ,e'¬l(ÂîH-"B+H@´Ž"Tÿk„TNÂOX _±6-Ô?6ƒF,#èë¼ÆÁºnËÐÁèØË¸*«ÄNl†lü¥,ð2\’ ¸ÁЂø"ôB(ÉÀˆTiä*8‹y †Åb¬!8ÈMˆ‚½V@2Œ,&“%ÈÁÅ ÈBZ]Cˆ,Éö ¼…KX*Ъd#B´…°R,؆­UÔÂ%0¼Î€eÐ@´âÃ2D[€€®l×…e0D¬ºc+2DêíÄÙVF' Ã5ü!–«e@|–¶)<×olÁ ÄÙCÛúÙŒk¼-PØ«ØÆÿé熮lnLtAT)¸E'´kœx„E„ÁB0„`«Ê‚+EÔ@‚0Á§Š—TEÐ0 ‚É@ÂDÅ¡Mì|Q\@3Ш^L€D°n4¯QXÄìÎÂÅRˆk²Š®ùž/UHÃgPÓâÀei@%\ª-è_øÅjøAСbøAbÈÅfÂ¥&€gàÜ.gFÆqEç‚ DsAe|~ЋàÄZþBÚ×¢/‹m{~è|êæ¢(Áèq.§Ÿ fÎft0Çy|ô‹~ˆvp|ÀoBGì„~j„ôÇnp±HÄÿ±1œ2ñ+H^™ñ;±_qDqc1w±1{ð@@Ù†±ŸqºxÀ^ÜaŸj1¿1$•™ J¤hA¤‚áºI ÜÖœd- DÔ‰c@*T‹¡rФ KO2%s…Áª¡‚ ¯ð’¯à@©H'r¯€‚«¨ª¨Ê¬¨²¨ˆ+˰¸ÊÖV2-×òØZC@Ëi« [)* ºó¸ ³´l±-³ùÒpž"3è2sù:s Rñ3ψb»H34++6g37ws{38—Ì6ÿk8¯ ð”3:k5§óS¸1;L(|Shÿ3XàAø ‡Ï,E¬ªÕ,ŒÒ4ÅÖ´A>ª½(€ÓÀ’AO3°¯îH@‹<EDkÅ>Å@×Xpî¥Á­×\E?HHSHšbE*HÂAƒq\ùNtÖd!ð/TåoÄdÝ$ÅXu#WR^53WŽp*±‚§Dï@ád†¿˜åÁFêH±8V!ÄSSÅÙ,d%` gŽý„ظ4«¦@&dNWTuΈEž‡bˆLãUo;—Ž)Å_ð J˜5J¼å `_ŸGLnÆ4êè­AÍóSÚÐLÂ0\C¸ÂöäúPúJÔÐ,„ƒ¢Hÿ‚÷Âhõ(%Åö „ü`IeO€võ(Ðy`Ãk£Ä“5ÐÓØŒ®j*Ñ‘…dÛ ¹*A 1DÍ̸Ïñ´É„EÐã!€,µIÌÂq›Òo“Ñ0™ëÐ)‘ÑoóQ­ªHxö;ø*Du'@ ò+I`¬ZåÕØò|Ñ_ˆÂÌR!G]f ý’¹ªP ¼‚ ·~§PYOû¤n~÷Р÷O,É@©Rò8y÷Gç4ŒÔ2PÃ<EvÓ©.)6&Ž)avQ–m&Ñ'yR€'ˆóöá´‹S7wÒ…ƒÿ&Ðé)X@+¸ÁTKC$Lá8@ÖSžŠÔ‚`OhëLe·†V`(pŽï¬v#¨]D6Õ;M€<ÙÀ¾9Ý?ÁÓ/ÔÓB „ÕŸ3T~Ùš#òEÈ2ÅA5h•l BQÁF†FmÀ"Aà †NyçäÖÀX …qÕH§ëV A>´çÄ5À €c9 úN¬ú¢oÕG!ÖOèB ¼Xî+ð]X‰d䂾*-e‘AKîÄE™Œl ç‚n ôCXÂ5lL¤“5ÀT_%€BÞTN0‚¢œ–íÄ•§?úÎ!o›URÿ•vFº{W¹Ãªg•Úà•[ë*È ¥+ŠFåÐDþHz°¿U½sÙotÓh±!Ä•m¹Î2Aƒ²œ¢|Q”NUUyÖ<¼Öq &r¼ÚBêõsŽâØÜe×°iüHkƒŠf+º×1(u–ÙxÙÍ¿F{dgÖÌW$„Ã}9( ÀóíCvN@BMÀ"8Ø Š؀»éõEØgî‡Ø­BÙ`£µ´À‰õ€À¿]‘ž]‚˜¡”Q«Y«ùX¶¿ø¯Ml8ךé}Û°=Ù(Ûëü}àÙ:°‚ YY¸‰„´‡<Ùª]Y$À˜ŒÅ† ½ßßÿ½àK€’þØF+¿ÃâÚ¾FÀ‰½ƒŠQŽ  åÃp×UЧÍ]\!þæïÄ“›½¤ ¯TÙ# +š@Ô,S<¥`ÌAÈ<áɘ 8¾Ë»¤Äøy˜&ÐÁ¦eBµ˜tyZˆ ßûz„ô ð[˜Ë!~ªåRúp½p€0–bq²ñXþ,€Å„¥pufô0 @B„4~üaDá‚„àPÁ…焵,Þ›¸ñd€}ûºí³÷ oßlŒp ÍØ/„ | ObL(xúÔ‡®çŠŸ)Q.<0E¡žA«F„(ŒÈÈÿ!¦|X/B¸R2ì5¬$"4Šš µÒü¨dÅÊ*¦_ZT…[lnG¿uå4Wí†?BÕ‘Z_¦b(©Ã…jAQȈØ4$ã·cͼŽà:¼:P„N K¯˜ÌUDÈjP™]ij ˜faÝŽŒ¢qn <Øt 2xõ2MIømÝ»Vm‰ü|€uñlK•(œmª†'Ÿ‚$ªƒ‹Ó©#4ÈÔ„":ú¯Ôž÷8ÞÆ‡!É磝@PBK@‹VO]•W!8#‡É*s'¼ÙQQIdù¬)aÛÉ("f™Ã–AÃP±P_Y±È-ŒxG˜M;Õ4 ¨ ¢ù·IpZW[Ki†5ìh÷àOôá˘ê @ˆlP>n±ÆÙ—±PXãP[fi¸*ÖP†‚Sª KÄj鉛~ꨥ.ñÄ8¨8ƒÀ¨0%Fä(bAÚ9(KH±íWF ‘€B! ;ì €‹ðLx›GÖíá*P֭䉄îvz'œ‘£¦;mpi¤ù¦ ¬ŠRÀθ±Ìlð Î/÷©i‘´Ù'òhC¤X!Úá…= ¦¨”Lxù¨H¹ù.%’q¨ÐchZXïÅâ¸k€¿ê”Õ3Çi¾†/þ÷v‚w.ÿƒ<›‚’j—^„†5+–*Lè. +#;ÕíŽÞÃï€ïíù …Õ=ãk\A8ÁCk·_0Þó{Ä  äã#üÛZ&^0À˜‰Þô¶ö‚Tmwâò”ç:ÂQH}žI@òÚA·ZÇ ilò©LÍÐVŸÊUú ÁYZ†À*V¯vAgEk+ÅC _0’ŒÌ8€ ê6Vµ²õƒ%ÒjG×j×¾âõ¯ì]×z”tr°„M,EHªØ%À¦Ž]l^ÅX3Ê”²’eŠ ‘šÙÉ~´¡uªhÓJ@ˆ!¡a"“ ‚“ˆ!4 Ë»à]îIvý® hÀÂyCÿB M°7ºÞ /Ïú ß¯÷« °n£…ñôÔ­.w9Üaxà l-‚P ÄaÁâàC%­`Ê 1¥'d Ï À.4\7Ðx ‡ÁQòb[ BÆ+*6¡Š+Å®”CòTÀ65‚&Ž1–aœb,ؘȷÌЕ![YÄ!®mšÙÜf¿ªÙÍ´=66 EiHP…‹ƒPÄÁ m,$pE:[¸DB:ÑãN@!F¨À.-Q´éÎ+èƒ'íIÎ<ì8¯ùØÉVö²™½…ht›LЉ9ÐâÙæõi‹= CY„£Å‹lè¯)5à Â0⣠¶¹ƒfŠ` HHf "ùÕÏ@´çí){ÏâFT;‘b3â—øÄ=¼¼Ab±Ððø,S@43@'®…ó(ÜPØ$5‹N„¾肌û$rZï¨ zÙ¸‹¯Aé+!ÀEŸ ÆH~žd´°MV¥/ _Vª`‹ˆ®ÂhÆv’†)Þu¯ìÈ^¬41EDÇT·:"V@è˜ÆqD|®]öÍ$ÿs„–òN·Ã½e?;ÂÍö¹3sÆü`ö'$Àðž)ö¶ý¡/™pÃÞyÏôò§ `™G¸Ž+M€«¦/PQr"ä°è+W_Pz²ŽC,8+v߻ӟ²÷iér?¢{†ùÉÿ½ò™O"®s¾ùÑ—þô©¯ì”¹DÑ­þö±Ïýå{üáÿqÉ?þÑšýéWÿúÙß~è¿¶ €€)Ü_þúßÿÌ÷À º@‚ó—6ÿPPüÐ`[ževà  ¿RÁê”#Pío¿Í©lÁxGRà :ð‚-æ*ÐO“­’!ÿ¸ƒ"ö+Êìg0kÐ÷–ê»o{Ѓ-P‹Ð “P — ›þœ Ÿ¥°µ/¸t 7 ³ ßLëÊh »0 Çð¸ä@äΪռP Ð:^Œa ÷bÁ6"rðe¹VÀOÚ±‰§Ò4 €I,l ãæ0ŸF  7$™" \í9`A¤[©­ÃOv€ Ð5 ­áB Ä€ˆðòÖ¥u€N¼"!>¬Ãˆc*m¤á*¯C˜ŠôI Ãc† €±ÐœL`¾ÀÖ<±Šþ %¤àêÀ‡(^€þO«¾P‡ÿrHÌÞ¡*U°÷J|c#‘ IäADû䊫È2OÉ üe/`·"¢q`¼,è'Ñ®*ä7QÙØâî < A° ì F‘Bø¢&!¬Â#G^,`£¶$€-fa!$á@Gt`«v@H¤!rP€!Y +˜ B‡|1!ŒÁ¿ØK#n«·r´À ¡ :~Mä4Átà^!°  Í42¼˜Qª† @°à$ƒ !y ¤¡p@àÔÀoÖéu4@ Öá Áæ ÖRŒÁé rÿȾ(A Ö¥"º`òîëÚÐ Ô2Zì R€ ²,̼ ½|-DÎ’Àñ×Ϋ9*àPÀ"K˜jF~ Î`0«LÖÆ8j@n†‘.€4AæÁ>à”õhV žõg&! 6ÃêcZ‚…Ø# ÈãJ áDZaAêÊuÂÇ –J.†"Z“5f în"[Õ̃YG–h0Á m ³cÕÁØb DÕ˜‚Öàh¶9hV*äѬ‚/†e¶OšÑ ôS1öADÁcA¶×V¡C+Ju´ˆ!ê‚mz@ÿr–€0a RÖlFYa2¢à 8€Ç@"B>ðf¶¶kÝ¥ âv‹5¶¼'ZÄ¢0,õhé€ "ó zCÿÐEž‘-êQ<:ôøÁð êÊ è¡wU®CBâšaÂŒ§BÈv£76A:Ã–Ò R_*·/ž# h#€ è@B˜bB76v´-²#gØ–"Ž¥\C¸ôFá{Ð#lÁ ’‡y5–täDÊ#ŒœBPZ`bXÆe#î |]°ß΂eA øW2@æC0¦-œmû—}X}xB´U£7-îÈÿC<:x $)yˆ%À—:¦W¬Êᜑ(Ë×IÅqˆ ´B\s?Ï ‡Âea;&‡„äF}dd‚¤K  0¡àÇ ¤AŒ@E•¢DE=R<˜ ‰DaðA_#ðA¢©xD]ja(ÅÃäÆÜå`D^Ú§•nà^ZÖ\èUÞ 4`®À-\#Ud )ÂÖJ¥âžÒc@Ã}àD:P~sÞ ,@µ @9Ų%x€S½ÀQ˜¬ôs•P» *aW!! Ö€ˆæ*¥¼ È7:¡ÔÓ9ã xa>™ÿ:õQd[˜øcä3T&þ@U²®Ô^Á\žž%C7kUÍOüoÆò Ð¿UPi(Áä{伞öº+è’ÁŠ@C! d`ösà3æl(­|²l4QBõn:µêÕ¬[»~ ;¶ìÙ´kÛžÃÀ’,¢‚JKY(RªÆðùB3% 8yÔdÃH’t»¬¤µh `'h"¨YZTˆ6¹0¶ ÊŸò8zÚÉ\´ ð)zT’S«ÖªQ‡„!ˆP”ÄqœDðY4ÌYÎRŒJ¸5ÿÇ„d%Ì…0„²ÂoåñŠX`B'ÆT $ )± A|7ˆ!Õ"LŽâåà\( ž]v E‰d’F*Y“N> e”RâÃnq0È ŠÊ q„—€‚¥)C]D¨ˆå 2pa -$LQBU4Ku@ÈŠDòHZ2TA0 rá+°"F(q@"zfå‡ ••— V¤…È%@h¤ÁTAtšÁ§JQP‰\”øá†‘f %&JÒd¹¥2WÔg«{ŠÆéZ‚àb"0ÓMIl±Æ‹l²Ê.ËlEù]tÑ´‡´„=± l¿´¡ÀsŸ × ÿtN €5Ž@íµÙ¾–#çF@ºrá× ó±® r¹(AwŸ"9Øe/¿Õ‹î4ÜwL´QˆÁA f÷ï¹`‹TÃö6I.r¨éK®Ëì®%ŸŒrÊ*¯ÌrË.Û¦H±I3Š[&GYá&/ïÌsÏ>ÿ tз5 ô!ûÅv4²bT+tÓN? uÔR?ùØÔ¶}³ÕYkÍu×^ öÖb‡=6ÙfŸvÚjO9€"D¬ wÜXËMwÝeÛíšqÄÞ~ÿ xà‚ÛÍo€µÂ EâoŒÔ¸â¶4ƒâ;îVãsÎyçžzÞ‘HpH›h@Ì%Aÿê8¬îƒ |°zë©×.»ê¬‡Î{ï¾ÿz-– ôR ÙåÁeÉ™æÀ?}ôÒƒMñæwO}öÚoŸrE×s7·ße} |^þ}à¯Ï~’ê·?>Ÿé£??üö3ù>AùßýüÿÀ 05þ ¿ý©€„A¸ÉAP@Ÿú¦5ÚòÆÖÄñ58C/Ž’Äš)b(t5%]\rW‘bÙî#'ñˆ‚3À>pP4XH„BŒB€âO¼!V1 ^¡$)ÀRPPˆLÁR÷‰â5Àc"s˜ !¦þP@ ¬N!À€9¬ )°1“‡pÀ":èæ7P‚Dè ÔÀ+Cžºh W@A0ˆDø`•­|'¼àÆÉ‘ÄÎt4¥éJ‚`! :¸B‰Z™‚ã!ô•˜ÇÖàL uaå|š|àµÀÂ)RÿC„n %ÀnA„3h]Ðì,¸Ð†–ȳ(ÃÄH’‰Äù$FA3j‘’¢!)ЦJW0±’õ3QÄÁ"‘|úó"YI^˜ÎD õJýlˆ+dé`‘r{'ˆ€(¬ÐƒjD¸dÔ Ðr8®ÎÀ ”TÁA8D.ü`”T!CL Á<$Y[ÓNgµ›{€n  t<@¸p†o`áÞ@An`ƒüÂè°J`Ix ºÐ½Á3|û˜ÿ}”‘„DÛ¢_2Ð!³QÁzݱ٠ŒCW€pÑÜÊŽ)„â *˜èÐYEâz Ã` "’µ84ÐÐ.˜ò²ïh ê[Á$NXÍ_) °ŠMµ •`o8èPÇá'(À*®aŒy¼a Žo;ºR„dÀÀNð ’FØÿ’á’›•Bx6» 0½‚ömo‰E  ¢Äî0F 6Œ‹$†¶µ 2!Ö«ÙLÁ£E4K±‹t5 "+lÌI@ uà/‘LIb£`Ž™Ñ|g|YaFñhm9f'"™Í(­¡«|€Jˆ£¬ôd¥fJ‘ôÿ@è¬n, Ø¢‡òæqaTŒNjF121/Õ¥´]¤Áºø kìjè(B:б}  ˆî$ìÇ4w»°‡> lëN`Ùx€°ƒ€7¿xvh0ìÅî "Ѐ¨!i5PÂ|‘óÅÍÙâ<ÈÂ:ä±îôa“(Ä4¢Ób8(š èÂMÙŠC %€¸‚¬,ûq¤ö(ôUñ„0à‹¢ˆ¸ r5'c ¸B È Ž‰ÌÝ:CÁöP/ï-"4@h÷%CqjQ4ã F€Î ^d8npƒÆ~3l<]øj} îQp8ÐÿPl=æ_ e“i¶H0ˆ¾øa5gù PW¬ƒNø;ÊÍN(}ë:›¹-5½tQˆâí¤@Öq‡y  ;‡ºpðVDU¤–쥱WÚ¬ç`€€h9a‰pÔaÆšmÿŽ yÇ{0ñ%Åu¤{L»x3mØ`û°‡6ªû g[ÏøÅu€k#§º%Ñð `máN{Û[«ïc2"¥g^X‘Ko€Ï'pë¡@„°åÉpù lÿBæ…Â÷Ûì†(n¡Î (Iù¿X :X!Ä£Á:ûáo…—¤!và…!LEP~7$20z“tMpÿ}Î@á0u3@KQ~8f¥RYup- ^ó}SPjy t $ÐyðnŸa¹@D pXm¦3B„б¶zYÇ Çä6,ˆIˆf‚—d`t@eñr ‚îç€L}œ×e–öxqã_ðgà¡Ö‡ ;àP>0u°y`q¶ðí0(‘ée€ ¹`ëàtMæSa'4ˆ½´+Õ…²‡èÐ  {ÒÕ MèÀ§m@Ä—xÉgð Æ¶nòpp s  ÑÀ‡V o–ÿuÑ“ x°Eµ P$±w`½[°w“ ~ °0,¢Š¾jȘ‹_ b¨LðŒZ€^Và8àYcJȔ疲 ?@90Àâ ý÷_$È@z¬€ä5T0ÏP+1à ‘Ð¤+ ³à‹•õòÅ,AG8€|0 „ð Çj¸…gÿÈ óÀ§Ðy’0¾PD—Ñ0¨ ' ó0 0wpC0/$twàƒÈö¶"Ù 1Eáðjç ¢ð?ù‘´ªP fŽEùi°†UÓ…ÏSYqp‚02ÀÿnTã@‡f5•5 °“ShYc!%Á[‹DTЛ–D™`›†!pIè7p! l!0{ö° ½Gž¨¾%˜Ü`6  ƇÇÅܰ†IÚ°ª‡_„—›&)€—2 §ÐØ•TÀ ðÉ€jTà—Dâ™ F$uTÐ}b¹%%! áà›E_‰G{9V˜‡ýç—¬izÐõ÷’gGíâ€sobô([ öš¦0n„ˆSþE`éFXÐFp:-àê 1PTÐzéw¶ ÒùžTëÐa³fz[¹ÿ 0–2 Y SÄuj 詞÷Á ö“¡ zÀ§™š`PIÐ:CY9VŽ ;B=Ò2àD0ºœ {£zàH\x•tÓc@.Õ0 Àér0S=¿ k kq)±k¾'FÓŒø¢0÷‘k›£Ï–ú ¤[ ¦Uã{åâm_ê`ê¥Ï¦^JF[]÷±¥7ƒ-n`- s§`- £nDB/ž°QàCª/%Ñm@¥ÔrC s-0Z¤c•äSA‡z1Fz0“JšƒŠ/±©¨¤ÐA-yj-‘Ê/¥ ÞÈe@µ1›:ÿ-DZ0»2§± œê.šzЪ  §:;¹Ðz ¡AzªXêCØ¢©«:IBzªªPʪ÷Ø£Ý*v ‰©1¦D" •‰ jÚ@“Ä£³ô;ˆb£HòSøè­û:Jóª$‰Z⺥Jʯ±Q-к2{$„´ [°{¯Ÿq©þ*¯ž±‹±ÒÃ@ Ä=4à±ú*4k›±(›²žãqt°–+32 Œ  Á!šËD•”*¼2<¡ñbkôs Gq*•d*›@§œ ð—²²SKJ3L„`!†yÐïÿXÄ M§Ph寀dÀþb òLÑÀ­ÍkÄí]À§µ`‡²ÀtQhœ@eé„qù:A;7mr šf±É0KGy0‹ Ñ Àð± nŰbžGÁ…pÅ?¥î4²qÂVoc ®à åá_‘-0ÅÑ uÁS´P¤^a%b1p%¤P@œõ` ô·ž šC1ÅR $ †¾ J@tí§È¸c)0ÿ$GLË÷S%|º  Ñ $ç“3»’ÀQ1–{âËQl©ð¾0 —@¦Ð’°ŽÔ°œÂ¬¢'—Å<…ÈL2%a ˜ (e]A °l>Á,f¡ÈgÙ޼ÁbÆf¤<'¢(¬Ï˼–ò¬»ü€„P•pp `a$Q šÁ³\˽>1KŒ +0q0 pò +}óö¨K;•Ò >!¨€ÐÝQ ¾@¸Ðc䱫²#±,Ý€/¡*«àQÑ È°E©щl>8P ÅPS^1ÿ—Ý$ ¿ ¢Ã0"-Ót +ðëU12#ë!$a sà .zïY @"$ëÂÑ$LË3¥ ð2„´Â%~Ðã@D-Êf2 ŒÉŒàšn’+%¡ò+¦p(Œéü "9^n9` K~åkÎæ=à¤#® ú$2´£Ov^®sõ„:vnOm.èƒÞ3€<Êó¢DóF+ Ùœóä„.é¿S?i6ɉ„é•>ä“ÎéÞ°7éQêžNê¥nê§>꨾éªÎê¨^â­ÿë±¾êäc?©.%¯>4²NËwŒéŸADOó ` @ u!ô¶A•ÇsQÅ–C·ÁëT>ë2¤¶{«ëüe°÷Ãbxg…À v` {BX”€Ð `îš²í¶á1Z —bIE˜ð×N? yÎDU'uU6 ¹´K‰W(ˆ[Äð‡×„ ­pV€j0 Í@Vðu;€(@ºyð2 J`íRçÄñ~O} ¸USô° ÕKu;O…`Og•V@pVy°W°VX…pÿNrœOUZ5€ y"eO…•,…%FQ•ñDBUÿÄQ -åd×Xnå‡ @T‹…íö);ÏLoŸ?„?šE•%K€EU~kôwåë‚Mj°‚°ºa5Ve•XÅl9%•?@†Y^`kt°ãÀY€v5P—e$Ð0qg¹ ×€ °voÙ$”asM Ä0ø¼• *à(« {Ðò Ñý@òÐ!Ño ø@üýpý¾®yŒC{f]ÀD@E„p–—àf$0Fæ`oàØPô_©°½¦„ ï¥úA†N/L±5ÿ΀®P°A2êÜ1 €‘Ähd¨pbèpRæ[uM : ƹÁ`aKA*6ÒñEFŒã tWkb…vœ4„«¥eM–oòd8‡£GqP˜i:ÙF¬¨+šKNA@ëáÎG§ ¡Þ¤ª«Ä8©Fy@Ñ®Z(¡¥²˜ Òº d&YEœXñbÆ?†9£dÊ•-_fYófÎ7¯ÝÒ$ƒ¬@jt)šæ@§Q'G=0Áº¬}Êè,Ý$+™.0ü„{r$ íŽ1,R|ÏÈÛ_3„ÁÕ.pÚ (㱯lÅ« @†òâ‘I†ÿ(Ó¦%¶nÔ!öÐ_Ç  &+Šèøé"™béNûØj@æ··XƒÁ @‹â ŽC B詆  „Xsí9 i‡P@"– “% ü@”V(¤‚hÔÙD¨›yªµZ¹àòD[ÂáaGa|ˆ@”Þ±•(JH%Ä*4Aª<ÑÆM4@`>yöP͈)«dh$†®Ìr†w Ib$1Ž=4"èbMPdš$‚tÎ3C3;4QEe´QG-ô9DåPCbª„¢ ù!9ÏÑò+^8ª%‰£:ˆðH W˜AYÉk1ÿóîá'<²cï—U ‡í§ò2h¦—VÜÔ*Lä3°Œ£:d ‹\ñoÔZ*暘 ¨!N®(‘§ °cÎ"@ÈÂø°]ËÓ9C1¾:>µj\MS”ˆ²£Ý^™‡Œ‚B2pá*"îH—¡-RêRÈÍ#DX5þX¥ß8Nñ¹Îu^KËharºb ´°EšȰ‚d“~I J\sâ”2S­+èØbdpR©§¦ºj«¯Æzêµ>xã pDÜBL‰²ðÁµ°‰†lù£!2:›Å2¡F†u¼`/î[ÐOìュZ ÿcÂbÁ§Ÿ j‘Ὤ™ žxø‘|¼ ~'žc`°BØ!hYø&QÞç˜ÙyåîȨ„p;ØÖök  »I^)B•F*–Hlœw§%DeG ‚Vâ lC<¸H’zÝz«ìë]t&´ŸCµMÉ¡\Àsg îŽgŽO^KlUk¤ýî¸c^iAèV‡7ÏF‡ ð„÷å!€kwÓYþ^R€;üE,ü0)ŽBKK›ðdˆZ€VpÃQÀЍ  ÈZ e8CNª†7¬ÌZâpAˆC*T0^PŠ"¼ƒgÿA ˆ¨­`D>”!0¢Pb#1’*X‘x)X*è!<]\¤ñ‰\áøèÕØðÆ8Ò 1ÏýkÃp„=”ÕÄp€ vˆÃrRpHŒA $g;2@à0È8d D9hâØ„UˆØŽvèCˆr b jŒÝ !"Rö@1ÀÂ8q¯·„ˆBLÆ<iK…a ¾ó!2ñˆ"óå8JÊç¨-4ÉÚ¨ ƒ ÑG´EXY° pÁ* ú%3¯Íi2ã©:CYÎq¶ã•F›¦ ¯‚€m 1CsËJ1‹ÿ;ÜH¤¥VØB4²çt8„hD%:QŠjæ QØÃrÄb‹¸@HœBÙ‰¤8i›bÐ0‡rmâ‚HGÇÑBÄ¿ÈÕä>ÁžJÎ=˜Ëú‘™@‚§—Q;Adq3•ê±Æê ‘jG¬.¨)b¤ÚÕE´¡­“YD\·êQ 0#¹ð„'ÐW«H`£QåêÐÕÀº ª`…éE?j•µ®Ä [E,cðØÁ¶ÐM íhKÅ@Øç¢Ð¡éL[Øœ‡ê³¢®}mle;[ÚÎÑê\ÂÓ Ñÿð³­µÌ~+áRÆ~ØmNGw™â2W#-˜pk;]êV׺×5”r'šÑ¢êSô©ms*]¬‘öµ+Àªv±»^ö¶×½ïèÄ [ò2F½Ã…o~õ»_þö׿’ƒ4À«8á¾1œ/}gÈ ,÷t˜\ßÿVXÁÆp†•€äÀg ¾a â€@UäÁ°êŠêàæ–M`1TÆ·cÌâÄøƒ(Xtº^\"È¢èJ‚€‘ð+d×P Öp”¥<å gmX@!ŒP2 ä¡`Q 'œ¢ËX sbv0Û§ÀÂFW,D" ÿHçbÔn$€H áeId†tÖÌæÆH :pEŒ   wÆ%#º fu&°+–&ê )x…p·Wêd(aÇB2„<ȈE3(DLãP²ƒXp‹Ð†H yg†F§¼N« @D˜!ÊHľ0°H‘檘ÂTw¸Å}™\‰aqè„ ÀZ$Ȱ…«`‚N0ÌÍE®ðp ?ä œŽÑÄ$0bU\ÃʈC+L° -0¡àŸâˆ= O‘*üÆ÷x5ÂokütŸD%.Ñ’ØøÜ-……,¸à= "ãYÿ¿˜@Í}ZäÉäÍ@€ çò^T1¥IJAˆÆ(-4 "ãìv72ºÀp<4‚7*©_$F ¥0œ³ >êÛíÅï¸Õ¾ö({ `Ï0L íBÞU¨7Ù7aáLeõÀ³Kh-`Á°2pC-h±€  •ðf±Š´A Y *¢°ˆœÂŒpC$±w¿éˆ˜`<à ƒ"&¡ˆ À8½ÐdÑÒŒŒ¾…ù<€ HÄ4”xÁd3²ó Š'7 Y:ÂèJ !D§w@v’0ñä!èjlƒ#ÿ¬jÄ”âÔˆZ ÊÎvú×ßþð-E„6ˆXÒîiÄFI˜¿Ûº"#“UX÷!—-(+S1,@Zxƒ?x[¸"0j Úq@:)#(@QB@^ÃP„ЖTˆ¤F¨H„hX…„¢„\ˆá"@³» ƒˆ¨" H¡!„ú?åZÂZð1°$«XÂK¨7I0„ÜB`KÊ@"¸V¨I ZˆÈ@œš€ŠSx ô6ç:;«yÃû«2:´Ã©)p„¨¸¶] …)‚¦KAĸCX¼‘hõ'¨‚.èÅÛ…Eÿ€†Q Ábè—(TˆƒMx‚UÀøD¨ tÃç€\R³ElDžx½Ø£A)ÀCˆA=JH¤âBEž !€eÐD#8B^ä=†XBˆx¶çB«»&Tx¢1J5˜BüEØ‚ Ð3%X…LÜD\0º97†äj“H¨°"»T·9¼Ãx”G«‰.P2JC„AØ»…Aè€w»“B\±ÆØH¼„Ð ²FŠ·…¥ƒEð±¸MðVè-ÌFưé$ƒZ€v£VxS(R`Shè €I(™#„b(D—„É/ÉŒØÓI=ÿpžÌÇ’s3§åƒ*=_HÆ}te‚Z˜‚„zŒ‘zÊ$"Z˜„XœÇ°˱l”³Š,¸bÎò€ÓêŒTõSƱj.ŽÊŒ” Îj>wŒÃæ[£&,BJ¬ˆI€® ©ÃaKÀ„«=€K” 'ÈE˜”ÄŒªF¬«»z«Óâ¢ÌˆºrŽ=-•Â(¶4,´¬ŒÅ‰+ Xðz²½\ x$ËׄMꂲ´ó Ú,,×\M0@Ï‚аMÈ(è’BÜÔ sSIâ¬ã‰ßŒÍætN*®Òë 䔲ï¬ö#HÞRMƒÑêAž N'Ó®ð|Îò4ÏóDÏôÿTÏõdÏötÏ÷„Ïø”Oûƒ-œÏûÄÏüÔÏÍpŽoêXYÎýÐ%ÐýdÉT ½UÐeÐõŒà±…OlÐ ¥Ð ËF5Xã5 ­C%ÏõPñ QÎÜÌÍO5ѰDQ9LÑuÑ}QÖ”­ÑµÑ »¢ÕÑåÑõQCaÎRq›Í!…C#ER÷ …6k Ö[1•Ñ~Ñ€I«(Û°;«¿4Àƒ(ÕÒÇø&•!-à€4‚ÒÙ °«Œ.MÒת”Åø:½’B ‚«ˆ„TÉ’¡‚”l†½ôøN«$¸£*^x7¸NÍ*8JÇ † €ñÿ,Ó*ƒuè½Ô€j=ž(ƒQÄšR¸ƒ:mSµ4 wH*…£YÓ¬1ˆ¸NÓ€DH„6C5^F @†Iðƒ8 œ¹S+€*†Ð›¨7øŠÚ †¹CŒWÐ(ä 3‹ 4 $~(TÒñ2 À ¨V×â d †;øƒ•,„+@ƒS— @ƒ+2#“DàVJPƒCÂİAb8€<;/Èç[m³ÀwZåˆÄ([%†øWzM£Z½U†ø4|í»SJ“Xø@XW‘Wl8€TÃØwµA2KfÀ|- €°€]ÇÝ4¡‘…µvåÖÿØ›=6MÓ)° ˜9ƒ‚+›W}‹8 XuãÅ‚ГÙŒU¼¥•Ý(#Ã[‹ ¸‚<ØÒƒ}X ØŽ%ZH„³µ’µíÙ©­ÚWp­ˆ-„‰%€yE,0†•Å‘i;ØŒ¸µZŒÓç…YÁEYÝX•_†‡ÅXÓ¡„yòƒ~5[»ÒWíе…¯¨¡èˆ€™d˜’‹(Q ªÌVQ"™Ã ^ S†¨"ç®tHÐÚÈ€-ƒ8aÉŽ4$–ŒH–Œè›iœŒ$ØZž—™ˆÃ‰ƒJ¸‚xP*¨Ô’8]|I£€†4ÿx‡ÄC€³°w¢ƒ¶8'±pŠ­è ê– ³Šµxß–!)Ð -Ý•Œ È…-Ð^ꥠTŸÀ^pÐÞŠàJçÐß´p§  ^²„r9÷ ÔM "èCF"IáŠÏ ó% V‡Â@ଠ!Ѓ *°¾ð‰ý‡þU ¶È„fpß¶¸‰TàHA˜íÅ›®Tù½7 &‹Øˆ‰áÑ %þŽxÐ’Ïõ(`2Ø¡¾ô­à.F€Œ"Ú‹EÝùåÜG‘5h…C˜ X,á(‘€ÖXÍÊ@€y’›R,¬ E°pá œÿàùHÎ9#²ß`‚`P«( ˆ‡Ì ä=@ˆ‡¡ ÷€Þ@ç±Nè„3`“^„"¹Õð„Y1$hÁY؈¯äÉ1X!`H‚3I?饙hžÔ€Û{‰c~e>5yV!„±’àc…:ÅlÕ0 qå„0„!Áetäï)“'h2Iç\F‹m®åå,†‚U݈f\ysƒuÛˆ]ª„ Hšç¾úŽŠí†êFáŠò‚: Qgeµé„¶ÉT2á€S<ûp' „ÞÌHK 9†Åi^<€ùú…E° Bòpq€Ð…Œ לR›AÃÔ¸vØ‘êíÕ©~,àÞP”†pá#ŸPЙÞÉb ² Ú ž0ž¡Káøé‰ð úÅr˜á`?˜Ÿ|vd¨`߀"Ø=‡h`ò°ðl°l%ÿh˜ ¬.¶ðØ× /èžö ZW¨x•Äÿ.ãîkØø€<óàsAsF—ôÁ&!`9!FW äAóMX.¯Ÿjì4\¨ÓQu°ôméiÖç…b¡Œõ-®0¿^·o c tK˜hFv4ÏŸ7p'_YódÝÜ®Š'¡H§NÒ%AH¢KaW>„¢y >2ZmÝ¡ÚÈݵŠGh#6$˜#´zˆ‡òˆ‡9:$p?˜#@;jeR2~”¦ÕNr-è7iZ4Ó¾¥W'=äšõ_Ú¶Kξ­û¨˜‚ªwÃÿ|8ñâÆ¯ ?®œíëåΟ }:õêÖ¯{žÂCÃä™·cH΃ +ÄcO¯~=ûöîßÃ']]AE†Y…\©Ì"ùmþ\Òœ^Lbñ!˜ ‚ 2Ø ƒ`F!ŒÈ`Ä*d‘æ)€CDhx @h‚QàÆ"ކG€tÑÔ!´Ð…„7☣ŽþE'ÝŽ= ¨X 3Äщ 0Ä¡ ÒÊ.1`B' œ"H3¡à„.ˆ¸qÔ“A²e þÈ\™g¢™¦škC")@ƒ ( OÚBÀ]J¢HCYŠÁ¥—sbf"™l"š¨¢‹2ªh)&Ä"Ðÿdß"P^2%|x$F)‚Báß—` f¢šªª«²šžÔÈ!v±Ê.(#$šr*”vÉ£KHU¯ø¸-ˆµÚ,ÎB­´M•ÒELH3È ~&Ê qD&€$V<°E„dŒ” 2^cNkc½÷⛬¾ùb7Ÿ õR¹2­4ð;CRŠ$9üÙ½ü>K±ÅcÌf qÈñQÒœJ1 ²½£œ2*W,­¿nDáñ³I ÑM²±œ³Î+ïܳÏ?´ÐCïK´ÑG#]t¢¹jÒOCµÔNGÝMÝrÖ[s²4ÿa¼a 'w]¶Ùg§C£HGÂh÷ÜÖ’ŒP\8·Þ{ó½cPýÝ·àƒ^¸á‡#ž¸â‹3Þ¸ãd?¹äfN^¹å]“:´w6^v¹çsË‘ÆyIqÇsp;hÀ g+”äy•ŽW(¢‹ÅA὞û绳ùJ ÔˆYd!‡ÁðA®°€ó ð 5”Ox(hà A@ƒ-fPˆ%‚4ˆ€(®€ƒ<ÀŠN#Q!8D9ibaì¢@‹ މ\A ïà‡>D$´‹b!j@5ÿ0”ØÙ !èðŽjÔâ€X@;¸ $ï#P‹)è!©”ŒBÄ¡M! ¤ŒZœ€/aøA*²àj„— ëÀžqL€"˜†-!]Bÿ¡ýPˆ<*³° òðèaN¢Hãu¨ƒ °—8Tboõ"²ƒœÀ™£…ŒÌtð…!:¤B’ÉÊ+æK‰fd0e5¤p…%µÃ{GRŒkÅwÍå^yQwìeIgÀ…ïÈð‡Sª à(À"˜qhDÔ©\)A)Ê£Vg/Õ<+Àƒ(¡•>8@'FÁÒ‚" «ë@†P€‚! ¼øÃO¦€þÔÏihAPá‡üd+>:PA‡›üBÛÜÊð [Üc)ç`ã‘ hÄcœ`XQ–€R È R@ÀR‘~:$ÿˆÆ;6A9ƒRA¨Yý@3.°Ö.|@MÍÊTmaU\¬µXg°g!HP‡’pc¨§C¤ñØdðQã0E„^†HÀ¨Ro Û¹ØB"öTÇàÖCxPÃ@Њ– UiZ ozb*Ù>ã¨A;8a‰Ì@³ülþ‰7Ñw ç}gm"”\Oø®Ñ­ÆæÚÒăÀC0T3g  †Š<‚AΠࢭèQÊŽyÎöx2µìQ½À”¶p]LA¢ÀÂ!ѵV x£Ü{ë0‰B#SØo2Cñãs|¡Cž­@L,”´ÕØÿ1öÚq¾Ø†b–© EŒ ÑãóZ–ãà„@¤Ž Ðø™AelTòÂÙ8|Ã:ªÁlA¸ÂøC8ØáƒùjQtJò.þ `QÐ,˜B!DÁ}†£cÔð†%!`ÐhW]”Ùíã¤ATó à#Áia8ÞùÍ›XayÅ)W†p|àÏ^ñm ŒBh¶†áæ-Æ9á ÚcÿÖà7¤²‚ŒxŠÐ’ÉOšþe)x!”*0‚-U–¼P…Y¤4vhG¦+f^œ &ùW>‘6° öÎ,z€ó›G`ƒ?ð‰b ]çBq§õàÙèE¡òÔr°Öçµ<"ŒÈGr#Üb2ÈHNí`¥ !yqÀ¦]*>DÌ7ã»`± öp£‚ \zïʳ~Šçe€y¤‰ÄÛçkwOr¯ ¼´‰bƒJÏ£ÀÜ®wÏ`æùS8ç­ƒž„D!*È/¬QO|âÔðêH|ÖÀ ÓHKbÁ‘YÃôŸÈNøÁÙ;d¿§½8]rÿßû¾ ¿@þªÿ¾’ÜÞi ` ïa|fä#‡(Ve8Ñ‹\€± ™H²Ò“ó{$ c`H3ñÄ!¢Câ Žï'@%eEÈF:²‘èìuÞöL5…Y0Àª1‡ÁŒWU$Y&™"ÈþLZàç0 ðQŽ×mSÌÄ›áE j…Š^` âA Uç¨à R ‹@—™à$ˆ3Ì |È ÂàþŒ.hO „²çT8Ä­ŒNP4‚èPEª‡ ’… Z!báÏ€#Ä } u ,TÂP õyÄF,-¡Cø ,€RZÿú`â!Ë$,ˆMˆ(šuŒð!4RW”B•¨ )E¨N©ÁŒ‚ hÁ* œÓœ$Ýajb(Q‚Ÿ˜ *@Â4D'²X™a2 AìTŒ˜x‚'È@° Éuà&ÚbÂÙ»ÈBĸ #Ð….‚WúHH–õ”(‚­h ¡ˆB'8D#Tâ Þâ4fa ÀK§€B1 Áœ¼K€¦.ЂêÐLlpcŒÂ3Vb-Rã;Zà§Â lB¨£˜€xŠÕ<\+ÊGsŒ !tÂñh˨<"ä4úKüµ_WÁÉNÈŸfüÍŠßfbBbdFÚ¡FrdGzäÿG‚dHŠäH’dIšä0ÍIªäJÊAtA-üÏJÊäåpD±‚ ÄÀ3¤B±hì@*LIO¾PÎØLe5®Í!è(ÛÈ‘p(Ô@IƒÐB"HÃQr% >! æ@("Ä@!„Yv%.¦¥Z2NC²åZÂe\^ä\Ò¥R\aLÊ¥;Ö¥^fú¥¢¸`^ æ`â%Òl$aò¥hüå^âËa2Ê[ fd‡êé†cJæ`†÷y +NÅ]î‘`hÀ×Å*–c€!e…@![ÜÎi6àôÔÚ[ŽP0½ G` sd&ÀÇì(ƒbræe&fÿ„ ÛðF$@‡íÑÅ QÎß)OÉ‰Æ hÑ ÇÈМUŒL&$§Ó”‡ÈG’ÙO>P©ìÅ/–˜ ÅaðeäC ÆyêeoZ&—fRF|‹pÚ†§ð‚3¦'ÌhÄg"ç`ì…S*!¡!14PLÐA¤'X§…¢í€l¨Œ(8þÑ×eP $é€%×  @ ´@¢@p@D¬€€Â”¡‹ê€‰8ÄhE5„'<¥?%‚V „& „ íž§y… éÀüU"ôAFR‰˜G’(øá¼@TXiQ4©lP‚èÀ^TÀÿèÀ‘lhé—þ &ÐŽ’å5ðÇX¤©‹N žGä—Z—jåEÑŠZi,À…î“^ @Õ)#­@9ƒ›òœvEºa"¸Ž•^åy œ@tQ¤I¡TR¨([¤’¦64©jÚªuª‘Q"Óîj¥Xª4>hRG‘ @ÿ¸”,C)0U4AIP·àc¶%€[§U Œå@<:ÜÀ  ƒ  Cx€3„€>L@7œ«*´„%x€ Œ€C¬«@Ü@¾z@¼®k)P¿ …6hÃyX¡% ”rnT R T@>¹£Aó²“}…ÿ‡É” 4+Èg$œA¬½TO*9ëÑÒMX$=¬/A”›Ù øBDÄ ŒCGAA*ᓌžäÀ$LP1×OÑÙ´–B2µ,ÄýCµÂÀ’Œ¥ì œ Õ€ÈÚXYìµE<ÔT ØlPÈ…ÀÒd Y¸ð¬ÏRN0‚Êš!$°Ò(‘œ×AbUŒ­FqÔÄ-OíÞHq”OÕ¬ƒ „yÍÆr–C)ÔÒfÔKe$²ÊYTSÖi@ 蔹VÚ>î À<¬ƒ<ðžYõV ÀÌê>DXÀ:é±nhì:d%:ìƒ> ƒ,¿þ‚4ìÃ/lÅÿ ìô+ü+à«L€ò¢Ãˆ ò „>È+8–ØÃŠ®R2@Ñ…<œ€n{5ÙÃRŽh[g9ÿîˆb] @1xœP+¼/'(U\+?q/v‰XˆA YJÂlÍLÖ$<Á;XÏB@™(+Lj½ÃtùËÓF’þ¶DÀÖàÁ<ÜÁ% "YVBõø0ì–ì*ÎV§'—*n„ÌCe‘Ð’IFù,ðóe ƒ (€0™©gaÞP 3ÀTÑŸœ|NiÿÎpAj 0V½-’ — «ƒXñk%«bЧä@ÿ‰’ÆöØ‘EŸQ^=“IˆÁ‘Ø]hC7ìÃ>ØÃ7¬ë78ƒò:@7¬‚\á«@X/óÚ€B8õ€ôR/L²ÒpìZq—Ã5ÐÅ‘D«s,Q @ˆÂ›È±X‘ tÌC˜˜B( -ÿ*YtÁ?Y8TìR$@uÐŒ˜Á,#—MAÔT嘄¥Q`€FÁòŒÁô€F°ò ÚI ‘èWˆÙ˜A™3·Â{ýÚ›W&äÀé HT ³|ÄA.Ð"Ã,Óz­™*¬µîr Y¯a‹Ó×’}ïlÔ0cª‘±T7g„™³4×ñUµ±ÿ_xmDy4ˆ³p!¼ýÙDeQ2ÙÂMÉO HYR¤ D­`€¾)Īĺ¢ƒ6°+:tƒhC>èƒpÀ3¨Þ%Ä$7ïl²ôº+3 l$ñf‹ ›„­±ƒä%ÃÀÒTmAÈg(T5ZŽGò Á#¬Už‰hÜä×á䃰A[Sn ¤B;€Ã œÛ5”ïðœRôÛlº-B£À[ €´Â%üA‰þ»‘2‹ô38›ÁC³ÙB-Ì’¹›- P3C¯!L8!èÁ™&öŸ\Ý;´Šó‚)|·Om7=¾¸ßÉ7Û5ç,¬œ0ÕÁU‹³v¾@åaçR ˆÕ¶+|x’È·‚YœÙÉCŽp Ü ôl=ÁU’W^xché¾/‚‘ŒFTKòD wÿ>ßö,P}7 ·É”îe\ ÁÊb ø¸ù®%tòèABÄá%á™g%¹8¸]ŒyæbG¬ŸG\zLà„jxÕDvºîõFD–•XpA,ÌDîùÈ8€„È/èÃ/8öboç¼:¸úªË:öªž« €6`¯ƒÀ¬ÅœÄÜÞŸØ^̸DÌ|») D„žk˜Ÿ¦ƒ×è_è€ tBDò„ø»R$€#@¤ôÙ„ÇD¦F0ÅA`»µ^8;C5lL õ„©{DºEÀLEHÃäDHˆ:[„„£ºLŒÍ+dß+> L€ß©‚EâúE¦G<ÿ¦‡_Á„c>¨zfg@oSÔúhuÛÃí:(ÌÉy<^ø” ðøu·  Æú¼ºÊ&ç¼¼æÂ†µ—§ö Zæb©»U}ÒÓüÒ3ýLî~*}^D}ÓSýÎ÷|Q” D4¶É h½bHÐWýØû¼n”0BÀP' –iQhÈ‘`@á †ôÁ†Ü1‹A@Bš+xç ÀPhoJA v…‹T‚·’ý㋽s bq®À5„At9º•ä&4YL‚*,‹2x¾[ŽÐ)Üs¹–à I­0@#çS“ÈÁB®…ãC~ÙG~î+)²(;Å"¶xbÿÐ-T@0B/¬Â%CòwÅ­°1®"mSŽïó“/,CÐÔzÊ‚—%$”‘ˆ ¡ðþù/ˆXÿTâ%tɦxDñÿÞŒB-ÌBÌ?ê3ñ@ ÀCDÑ–$&CI „t"ªڪ!ü  €Æ„îêB€$H“'Q¦T¹’eK—/aÆ”9“fM%mæÔ¹“gOŸ?:”hÐ…ˆ\„T"AA—N 8ðy2aZžÐidµÓ"hPºÀE €Žm8ò¨C'‚ë%ÈÐ0Z+(Yµ1•Ç”³p<˜paÃ'V¼˜qcÇ‹)EŠ‘ÿ.¶F*¸ä&$+k¡2Š#cOçAƒ:›xÀäÊœl91§N7d W… Á#†<œxqãÇ‘'W¾œyð–bÎ6¹àpÉGŽˆÒä#—íI\ðîVøÌb¹HŠX=ÂñëYªŸ6­y}û÷ñç׿ŸÿìåôOÀ›t®ÀLPÁ}¢*@!Œ@ )œ°Â 1ÌPà 9ìÐÃA QÄI,ÑÄi‚€óPlÑÅaŒÑÂä<­•Ì’QÇyìÑÇyâ Œ2dIj‡ž’c…RéJ‹%_Q%Ÿ‰rÊ ÄRË-¹ü0†"lÙ%N4 æH®¦LÿP b2?¸"‘7‰Á!‘B|èRÏ=ùì3ÁZ’Ùèc[ÁƒB84!CAzÒÏG„TÒIk¡Eª£4KM9íÔSÅÌ1ÇH?-ÕÔSQMUÕUYmµ¦P]UÖYiµVZ¼UW?7íu×_ Ö%[ÒÀ+¥5 B&€(Ž 6}!9ŠýHƒ4š%uÑ©hW*„¾WÛ”˜I!…2vº6Œ©5ö¤Üýo§ríý(^á$Ñ Û—xPò\”H·¦oåE(qs–wY|åß… Ê€FÁêX1ÎèŤ9á… Sư€x9 (`5 “k2†ÊŽvŠÌ)S–ÿnЦ8ˆ.g˜Áø„bHá…L|%Wh{ÿ¨¢×RÞ9¡0pH%¨;¨Ä¯š…‚Lõ6‚Œ¯&æk«]*£ê“¾[cR8›å–NŽjÎ^ªâ †^‰„BÚy!&šcw(~Œˆ‘pân%£o„a<†Sff…‹Š »X”;ÖÖàNpÑP”ŽMŽ™I¨è`£°IˆN¬hG˜×u ‰ò9 JÔè¥;¬@¨Î|ÊCÑrOC“+ÂØe‚0ˆ %#IábÒ!{rÌ”RPø °`øÚIpóŠ˜@ô9O‚=;WrOD‰J*áNþ ?"èÿ¢¼ ‡þaáÕ²ÐÅ ˜‚CaA 5ÐÝœ %-  ‡Ô‚°¿ ¢! P’ÿò€"FjXGoZA€ù¡AP¡ðЉ.…ÕBlA’ÀsWÈÝ€0º„xáL1‰ý€?ùa!ÕÒD p%–d~ÐÚ5˜.°5Ã!ÐÇ lPŠgØ`žØ‡ÎØf=T¢îxÈÐK/ÇáÀƒΠ¼‚`ÊqÄ%=iDQ»j {S@Ðè e–G ˆ©/@RF¼ÇE‘©Lf\âœ7E@¨µ Õ€ =`@Ët!q0à £@ªFᨎ Tb ©AU@•š’ä¢íA5z*Šh¨£»ÿæ;ðVŒk o#@hÁê ˆ`Øu˜¶‰Ä:Æ:‰ ºtv]1{Jˆ^Î4+{]ÁÉrª©HdØKP„vÀ qø ŒA=Îí- @ã·ö HÀRMº¤&q © $°|õ­£íf…cF””¦XE 2k`Òá±\0ÃSÁz’2x$(iŽ8‚˜ ð.xð‡rPÓN„f§Ëƒ!À g`… k Û•ÀhÄN…S€y ïB¬„ ánÀæüoNa´dÀƒ?ñ‰¹dè˜Eб (`è/8  NÀ Š<ÿÿÐ8 ø…<Û™à+6IO'ñ„Ú¦á]9ƒ‚ãpð g8ðôJÀ5€ à‰2Ð"PßûàÊüz°åQ­¾Wå2$*|2d¸` ðA:1 eB9· ²`/:Š(´9@3Pæ"ˆ|7ÔÖ¼gÄu”ç=›ùÊ©ÔsmOfuÜWù•M-k9´@sÝ*k`„q|†n’ ÀÔµÈ,d$W6;o6B2g]sç&’¸4 P9ZH£ É@@˜ìk–S»¤m€¥@0Íþú¾&9@ ÿ$ó`]uÁ@è“`ŠhõZð ²f`ÓÞœ¸YZø¥† £M¾41®~S½ €Àv€¸B(¦à„Ð ˜ 6-$Á’Ê›1Â;(Ëmtcû°Ç7ê g0”žß°TôñÎì i1hqü€níøå ÂYÑQÚš$(0!.Ž—•d Gµ—΂fK@ ¸ÉZ'`n­ýá³VepÍõ סÍ…8ÔÑü–Ù‚½ Ì .´ÙB‰ ì¶EiæuQg3Ú²úÁŽQ†ÛFk5PÆ{ñ¶“aðpÄ{B¢®ðÇrâºSE&ø.Ä¡\g‰úMÓ+ÿ”ò 9 »¼a²»:Ô]éùÐüÙ‘+! ‚/pÁéÐS9ø9öëB.¨û‡k¹tàºÂ?õÚž ô£&šÜ©à‹'ˆÁׄŸ— ÊRð¢@ð £%òD1ê¶KÂ;MÁ"Õ¾‹?PÁc€¢ä¾2ĸý—Me4<º„¡ŒD :@lì ºÁ´Á @hàlNçfÎàjNFÀqìŒ! 0ÖÇçê®í¢! z@¤LÂ×îÀ `Àð òaä"Aþ  ¥¤>êd>@§\ ná£^!¬ä*urð ¼@!à\pì2@@°üÎ •P Nÿæï ¨PO!ä®·@PE*j&¢> më’ä  ‹ëаø üÚaÖ‰k!ˆîn¯àðvP€0N Ñðû®«tpB! ›©íø@·f^ཚa\(Ž(ªÚ¤¨Îˆ[œ£§|@ÔpAm0 € ð$fàØïÔ®²AâÌ¢r¡A¯ß°«ì˜g 5Ö` ¨ïƒæ$  ý´o(N&Úhvgd(à<@´¾f³”Ki(L4‚Èœ6b!â0¹H­ Œ z@ˆ¬”ÔÁ̾Ñ9h ê lÀLnìˆ^ÿîæÇl€òÚ©Â`LôÑ ªCö`~ÀÙ -Jéñ>B2 Á2æÛ¡·‘ô6#Û˜âà΀LÖÑ#1§ö uJò$ER˜0¾¤º±£Ú¡# õÚ´ª¬ @Ävj(²ðîáC×J)Û1•rR%g†4Ú†Að Àd€^Àæá tÒ$4î T! ²µQ)7"&¯Ñ(€¦±c2VÒ2r'0rf6 Zà ¶à…À-R ߨ'r’¢`.¹Ñ‚òÁ’4< ÔA“ v1‰af,˜Ðr àçzòó&ÿÃ7a®ÁÙî+2ÒùÄrù¢±(ž ãÀ@=Á=. 7Í"ÃÌ †F8 Â:¦£PŒ!ä#,E=öÃ4lÃÃ6PòÉô¡;õáPÁÂóz¬Ç¼³;I‚<=@F@XÎÆ|lÞ$ =`:–“-Ä@85``>Ìb7s“*ÐÃ?pS7û“>´c:$ 8'`@´†øÓ7ï“? (4AÁ „aèA(Å 7 ¤>áBÉ£<ð@Yf9Mô>/ÿòôã‚?y-I'À>­T!^!ra4@§lTJ=n³  Æc#l4=æF*ôóТ=^®B›t)ÂIk³?¬S(nfmE%VÂ’=±Äƒ²KyB 55â«&Ž?NAú„‚ÔÀ¬¯Pÿ4T!ƒ;GÈKÂãD!5R£àM+u5˜T_uM_õ%ÐTTq5WeUWyX ¦V{õGÕG†5XGD t¡xmî¢Âãµz“¯¤•%þ`š„X5[M¥Šº j:A \òNú B!Ê ’$/RhbL¢]åõ$Ä P`ÿEÊ]ûÀ\¾`zî#ð@ èÀZµ[)¤X6X`ðf4!l!lƒJ+qJŽê&Á*LS±Tô^@„ù`A.#d`¸©fa h¡™ôå èÀd)•aögÖg‹‚!¨Ã®‚d€38@7À.’!PÁ h | ¡x@‚naÍèY4 /’hSÍp V!N 3d’M¨öAD¢gìcWy„nƒönçVl \IÀÂ3Ê” á×ìb»Þ +Ê1G$Ad`p…jÀ ÄRo©F"A¶à" #Èå ´e .oI·tÿþâ ðb2£ Úë¤b›®" ´¢®S,t­>q²/-èmʃ’Ž#âbô`/º †`~uXù6DVhMWG÷zCÄ52asD—.áoQ0!pƒð®|{7E2âà5bƒf•67Võc‚àk6ÎzqµwŸUMa€ÞŽÓ…V»KôVÍã<:ÁIé<ÞÃj´4Wõ—)˜R v‚+8ƒ58&ävƒcÄn=ƒCx„I¸„Mø„ó…)¤PázV…a8†1„ ÆëFdø†q8B Âøj†I‚èI^á °¢_³7‡øˆEøjÀ¤RNhÁMÖÿDNh‰©8‰«x&¥¯RA_ʃˆ¯ø‹ïŒƒ€/XŒÍøŒ£ˆÑxÙØRÕ¸­ŽßXŽaxŽéøŽñØŽóø‹õ„SxÏ8Ì%\”%Ž9Xw@äˆKf`üå]FHTBZ"%]¨‡\c8q„cÀaFÌpFÆ @RÆä/” !f4á4~ƒ¯)%h ÀàÁxAJ¦eG‡ÅàÛÎÅl&9…YJDm•$$ã™´æ!\X1$ã&G“W8Œñï@‚PI‰Ìõ)u&aüÀpç?ðÀ jÇ0÷õˆvM(lZÀ  ã¤(ït@¤¡qPÿ d |€€È ,…j!^!ò §— | @ }ž$˜ž]1–LÂÞg舃´Y“‚ŠŠ¦¤¥á ¤o(‡8Ф%šb+  ~à ˜Ë¤ †¹q† ‰^XdbZ_©7öb‹¶y•ªè$x@Š9Ú’¶/f!RZ‡4‰”ÜHˆLްH¥5š{¨YU<‡芰¨@² xë‚)n ¦€Ÿ“s©é ˜ÖVM)c.—5'šV @Ž!j! T`sVAö ˆä!ž¤ú´äÁÌım;è¡ — âŽlwŽk¼‹ àf&ÿ.˜tÊÀ¬` ¡¡ºvg5ëb¢«®­ÕÙ먫¼k¬¶ ­4Š' ¡§â >h·Ó¬Åa#®Lô §¥x€†;¶›2÷ôš±h4ˆ)Ñ"€ þÀy‰µuJjv»&Á±Î:´¨€´|›®Â*±hºï¶ÃÚšåb¤à’­Òô‹ŒÚzOílž¬9ÀÜ6 ‚³:•&LvG °–À?X!›˜@4vR â¡% ²7b±+ âá²3t™Ü¦î۪rÊöÍÎÆ€Ï*-üPRÏäa¼,ÝX!àaߘÚÕ.­Ôöà:´Í¸í¸®ÿ«ÊÞÁÍúKÎzë¦CíפÁ¦„×ðìõÊžü÷z®†ª†fÀî€koúzvÛ‚lÈ`*Ý É—­Õ^­3dsÚ˜ÜîáÐÌ2Èk@Íç»wäb¶àOrÌNÌa…âªÕöæ¥ô&Ùm¦Ä œ ¶ì\ú!îª"ÔÊ èT¬ŽäápZ”{åºvq/t”)ôìµé®!¶¿®¶oðüŽžDëŒo/f€ùlGînGq/htÁÖqáàj ÂÁj!Ù¯­ñÎ '¸<@ÄîëÚÌ«|¢nœ¡”b7kÓáïæaè´Î ¬`/š½¯,ÿow÷ Þ§éž‘ÝT ¨½àûp`&á +ªœÓoý†à&ÎO™ãï# Èž%ð/‰NŒÐÿN‚ZÒòÛâ!Ôâd4ÄS}±OÔ tVè#‚Ö4hhQ³&q¥B¡[@™€ èÊ›Úð© ¼gñ L;žAþàbp@.£-«‘eÊ Bµ]ׇŽáÿ›m– ñç™ Ë]0@äàN°È}›ð`íc :wù#ºž¼°m°Í—~0‡P-9°Ç—Æe;Q¤þpGap²ý“òˆ^SNÆÝNò,ÝRÿKÚAà !íz*c^ Ì¿±:äN¾™Š8{ª”5VÀU4?~™ÇNC=m,’~ ñž>mÍÚìÖ,R=´Ád‚=xóŠiÒD2×] ÁÍÝ@ù%jj©§¦ªêªªÆP#]àÀ ®`áÆÄ` xË®@¶XVy›i)‘0‡+£EC®¬FÉÎU@QΑ ¢²*î¸ä–Û¨¹ãŠñŒ"n¬àP"ÑŒGRÙðÒ 42KEq SKü¶bŸ§d‘¥Â" ¶`Â*ªÿ0¡/+CA3 xMÓzµK¸è†|®È$—l²“NPò”w}xrˆ íò°0CÃ@RAqð±E$ƒŠ!öq2yõ¦…<ÌÀ¦Ê â‹}¤Rà :ð&‹!@rE‰”ౘž,öØd—möÒŠÝI¸&tB€$V"ƒ¤­»}4ú íð€L &Ä¢e0 ÀÊ'Á2h;b‹œàϼG5ÖYYúR%šð„(L¡ WÈBTµð…0Œ¡ gHÃÚð†8Ì¡wÈÃúð‡‹ªž— p‰Â ª=@L¢—:9t!µ`¢§HÅ“y`©Pä°::¤‚ª¢ÇèB2ªIÄøÀÖЕQH€~fŒ£ç¨'w5"Œ3÷ÈÇ>ŽÉ1 Y„ýHÈBòˆLä ÉÈF:ò‘#ƒ¤$'IÉJZò’˜lÿá‘X®M–QÊä¸äwq²=€ˆb[HóIOyr+¯Ð@…4cE²•K"¥)¿ÂŒ¤àO¸ÔJ-Ô¤^þ2˜Òå'¡O™‰ÊBfœŒ Ì·€Äüù8`Ë.J¢s¢ Ñ+" Äye3ïè¯à*\¢]Ù|ÈTL1†HÆ ¨`D;8±„±=Æ@^ –/„cí`W „€¾]æÈ™ÿ¤KÆ&]¬£•Þ-ÝäŠ d¡¾±h*¡N]ð"Òäz,¤±¨ˆ: ¸¾kŒ€¨Ü`†T`Ëî0¨7ÂæÐÌü<³¼H…V|Á]°—ãJ2Œš9¨D:ÁºjwÿÀ襢е\Rìp` Èâ8“±e/ @*#ÝÂK‹íLxšÛNE:K!uDÛ1@Á$ÇIæ${#Ì)Çœ¿‰ud;Üã8ÇKã lp$í¨Æ,o T3[Ü©5d&"Tö'dxƒ –ƒç›¹qE˜RƒƒáÌ‘²£B…j®±D€ÄX ða[Ö½Þg«KðŽs3GÓ†`9¿ß©¢Z ¸ ™‘r-Ž¹Ú·ŽÃ–z’ŸÈð>4|“â ƒ ÂqÔZyš@œ J¢taŸ>€é(ò=(–Ïg@†Cj3WÝê° ÝñLYœÿA£aÒD`:çLhnŽÑèÆ£êœx4¢ÉP‰{ÐÃ!%4‰ÛÀj\»f5Dˆ$=H](sIBz«d®A+žpëÙƒì­G.éQˆBõ¸tÓÞ„30à FP½fÎE$á (¾þ=Ž@ùª÷J1,E€Ó'ÿ%a>.)‰Qo@Óœ ÏÀ @£çç2±‡ë[@eÁK‰FÀ”ŸI°/µ O°iÞ—°·²W4ÅÀ Ÿ¦€³'½g7}3pwDsD² ¦ßÇ û÷g0}ÿ‡~DZ}+V`|'ÖzÇ!~Ž €?Pÿ~s0{¤ó°{ðln`NŸº× cÇrÈ0,(L05¥§d 2gußæAøu)Õj@ƒ °@fhס€ÑvðWÔåÁí¶A/` eáh÷Àm0 P `i¸áh 2#ÍÐ ¾@T¼Ô”‡8‚0f5@g[G$Z` ‘Qoð³‹]ámc1‹µ˜'>è,GŠ]ˆŠüÔ‹òqz¯˜ ;Ò†1P‚€e¡PÆg ÿˆH^´_ Ø!ÂèŸ q)ĸ1¾ð:Ø7¬HŒà5ZèõbˆƒrŽ'€»è"š¸°&Ðy5€ñR»@TT8€ ¤QáYÐ*PVg…\ÜôwgÅZ ܰ8x€ñ€ ˆ0#xa.Å[Ã!ç§¡× ± ñn >é•ÉÆ½·ñÇ¿¢ °.QoÐÕpz[Pf° ?àEmù–ÿÀ€µ`õÑp>ù‰ùbp‹Þá“@)C¹ò˜qÙj)'žù•És1‘ãp/ñôiŽyi“Ó“à‘ —P™ÀטšJ£Z`|£y—ÃÀe f)Ä©m5¶â£qH\ðR|iÀ…ñB¹‰5€pNP~¸Ð+L‰É)Ë'1—7›ŠsØy zIÜmQ,â©4„sž¶ÉR°*žI¸„ oÐi–8 ›«užÇ "áV'¹JX~PAC š c¼ “Y;r/îbgupvðßs#J}ÿãà>|ÆIŸ lÀø`‡€GP‡ B‰ÖˆvlàHàÅ`¤@ –¶QAQ‘ñTàp/àÒêƒS¡U7|‘• 1êRÑ]ÂðRgW̱C¡*AMá¥T¦ e]°UK¡Ma™ÁUí >œYw}ÚZÑ{T:}} N ~R Œpw±¶"Ì :¶ °7£oZ¨‡ú‘nèú4jhFƒq¨Ì¥‚ È¥Á, 1•Ñ ^×§â€! ìg>SÑ¥®º™: HJ&1¥TP£h1!kT` /0e.RšåxOÿœªo3øF«ªF0ð£¬v ½wx7})1¨c ›Óš¨\z mJך ó0qz*1‚¡¢ê¤ Ò14wÖàUž {·wØae+§‰qº±<ú1üÀ‹yù12è'&±ð ýA|!!`Ðï1 ì¡ÛA)2 ³,ç òÜA{ÉqJvA°Â‘²«i8±\AB‹'BDË@}ÑàÖ B{[´ù¡Æ!ä|8"´)‹E›ç3²¾Q¶Ìú´‘ñ³¿!p³Ïñ;Å‘†Wû)Ël›´DàÄù1åÓÿ›áý1ŸÀ¶ÿQA|á|úñO&qO+ O0¶˜!Œ°b3#5‚D®Ã'/SZÂSWx&·fºfr ñ("«kN¨;»fÑuNB»ž %m’ºqA%62¹¬Ô'È»E¼¬[á2«yJ6¥;æT¼­ä˼ ‚»Æëu¹‹H¶›.!²½Ùû½«ÂÕZ@ž€\t½Ë»IÛbYUw[M] ñkBÞD¼ûTdá¿Ù½àëL`a¹ðîi ß)œ²Q  dÆ DàÀ}çÂx4• b§ùC§0Á˜²¿ìk½),Á#6ž$Àÿ]A½lC ¶_Xà2:³B½Á,Î-ÌpV¹rO°BSí1a°Äa` $Xe _ }Ì©÷œ@ ]'AUŒŒ°¾]! … ‚Ÿ*¼Âlœ"0ܾ3Çná« ÁxÐ01@:ï¡.ôÔ1)@mê£0ÄS Ù( ”— ¶†d`8¾ ŒÌ`Aðòbu¼"40K¾­³¼ºàbþ#Ç¢,Ç5Se1ðÓ‘Ê‹ãÉ ÒÊ1ƒŒÛAÌå20ã5c()ÐÉRnÐf<ÊÆŒÆÔË,°&ÀÊrZw²|ÊŒ@${Ê¡E qÐÿz@ š•ÍP ¤B=—à6 Ì_q À¼žtÖctÚ¸ÝÛËMaq¾#"Ã#K‘¬ÙÙ Ç)¬ Kb¡LÍšߤھ}ݾ’…£ ®yl O„`ˆP±¥ÕZOÁˆu½A§3S(¬ŒÅÏf9PÈF”T×%Ûfíf†½U$ÑBNµÙC…ÝrÍrSU”›…ÀUåx.±“À 2À ®@“pk†Ð ¼ÐœJ —‡À…5ÍiWЩyå.:ÐW²Xÿ59XmÀ寀-Ý´X ÖVÐ wP ¬Ed3÷mâžÄ0¶‰É%0`µ%_lr 4ÖU(v +@…0-Iî[  %Bþc)¦;®…Xð °ç.I~aª•cã5Œ@æ>Àä®Ññnçe`&f›ˆŠ@“¶/U µp.&`É-p Ššà5ºZCR$3ॸª+ºñ0 0ß¿P5Ò0ˆ¦hŒ¦•â’FiNúh\ á°™` `e.·ˆß¦‰$0 g0”I|$ÀÞŠ ~`k ”{~\ø~qt\6QÊp6x ÊæŒhqð`—Øùˆú–iÿuoÈN Ô'tø–p€° í@qqþÎ,·~ QvñwzÝyŽ0g`êU‹äw°Qè°Pº– ftÛ$0À7 €¡»Ðx¶è†0yt€—Gð»§» ´€#2.Á_’ âWÀ—ëÈ[º¼Îx|«·ž-ÇùÖ{åd|Š µ×É Aˆ}êP¯@ ¹²:äd äXj4ˆ5ää ý‡ÈóSïÐ v‹ßåŽÕ:¤òz éŒÞ†ë82Xf†põk˜LòÔL„S ™Ò9¤‰Ç£¿° }XhÞ¡•ˆ† „øÒÄíÿuP¤òì'’†Š *¹Xö¨¦™Žar¹êÌça_Ÿ/ iƒµ   ñó@V°ãP~T0ߺ·ù™¯¸pùÆçɨ^ˆhM<ŸŠÃ®õYH×—^˜e† ¥“2)ÓQk Ð@Uác™YpëcQäM-p‰ÁMQVoõÏÒ€P¹éÐ+ V)Ï\¹Õ;€ãœä“PëPçZ¡0¡Î@w½. X°@§Þ‚IU#uàv øìß‚(.‹u¸Vy|µÎ к3pàb»j+ä@€T+Ô«V€‰z3`ÿ  .:fñ †•ÙI1éDÒ8\xtÔɳáÈSèÑëW°aÅŽ%[ÖìY´iÕ®eÛÖí[¸qåÎ¥[×î]-ãÜñà *¦(¼ˆi……«Z1áÄPHå“@`±F†©tस˄ ÌP¡ÒCDa;›ÝxÞøõS®#Gðñ àlÚèÅ-/ÞmHÚü‰=› ½,”U8ÎÔ”SêPÈ!-/;¦ `”oT’¯¨e´ë…ÚŽ dòÊ ®ukÔˆ§ -cø…zùrJÓ‚´öõ2Ø#¼HøŠHiÒ'";"MzLqUV[uõUXc•uÖ;TSM[Õ'´ôê‰\ƒ½uX³¤°@ÎbMXb» ¯”Ébv,hµöZl³Õv[n×ZV®o]mÕU¼kÚÿ5<Ÿ:lÝnã•w^zëµ÷^|óÕw_~ûõ÷_€Ýb"Œ÷äB& ƒÛýâ•Ö$i,#9$v–ˆA3اånÖcCyd’YUÅ’ }ŠC+¶ ¨ŒY„,“&ˆubæéª„'K™ U0ɨEà{Á jOÉ!ŠKvºé§£–zêyOQb Í(„”p9Y R—"‰ƒ+f°Ñ(…WȆälagƒ0€`ƒëf&¬uìÂZ¤Y{ ¬ ä’%)ð`ZI°€àRª#‡Wr¨)·ür¸`rF:±e‚¾x!–b€å¹ÏH!™bd˜ñÔ‡5 2ÈÿÈÅÐÀ|!ö„TZ " (XM™UbÖ‘†¼B`qÕ¥‹-qar̳׾òŽ·÷þéa”CŒ8-JL0?1(±>T ãS÷aKÎ&€œ3ÿõ?¶¥OxB«À0a«y%Ðë ã†I¼{ߣ`-xA€ÕB|P_éÒw¨úùD ˆ#¾3€‚% ³ˆC2@Æá¨†œ>¶ˆ%(¦ ßÄ‚+DÏY°-È 6ƒTâøD(–Hƒ2ëBÎPHû±q8Ô2Š1%x¢}X ‹-jAyÃŒn†<ÜÓ4|&Pÿ•'–ç1Í+ª0†/!a41Šƒ$d! ‰$bƒÈ@0躂@ a ± Í €H+)1.œ+‡À =P 9‹&qˆ°Ä …Ü;d-myK\¥N?©%‘‹HÊÈM6üÑŒx§»ØpŽ’.âBì’-qyMlfSO „hÍWé¢/àÔ&ËyNtzOšöŠ¹Ò¹ÍwÆžò¤g=íyO|æSŸûäg?ý¹ª\ îŸ%hAIö®‘0R1hCúPrNaxÃûÊŠ*Ãt©øœ-°ŒF¢#%iIE*¢ÂØ¢xnÐ@ j@ÿ‹ ,€ÄÀAbšP¼4¦&åiOÍéÓ5"¡Ã*Z#“\iaMJ=)PúT¨º%ÌüÙO£zU¬fU«[åjWçÅ1¯†U¬c%kYÍJV«žU­kekS}.·–ˆFÔ*)XÛV-¤Á‡cIC-¶EÌŽ½BÆ ‹,QŽ´|A%2,Î"½¦u.Ý+Ôû„™å²x¡l‰:‹.Å2ÖÛ3× nv._ÄXv@°³€)`Û°TkXÒº%³^ñ€^ç)ÙgVjÆ:áÇÄppÜ*‘ØQ½" ÒÐaš_Ñ„}Øâ¥5ë HÎàj–§ØA"Æ ^`Î?ÿ¥Ä @&Vð[â7.)nåÊ{@wÅ€!4f° "H:¦îÆ´¹Í2ƒ+Øún‘¨ô¥9¾ê_ß› þ»Ùlcäã…s†À©€…a"ä3'6X4 ðT¶"ןöI¸}Øñ˜ûáï­OK 5lÞ´ÿ¾41òðä,g…¸Âb'ÝòÅaÖÓ­ ÷žrýnhG¶_³¦ƒIæh@`\ÀI2j5mµhÄXáÈár ’xÌHâ˜ÈÄ LbÅ"Þ †8~Aƒ^)Õ7»€Bè±y82»ú>Àä<3¶8Ä¿PŒkt¥ïu¯ ðžŠv4#Æ e p8Ô%0LÓ@߃ÀùËo<· “J¸ìöصH0…3¨`ë¼@$z€ýIÔtXÀï®勆oˆˆú¡Aÿôü€>2 Þ»»ê#LȽ©@¿ è[¿ö# @È=ˆÿƒ?`žä¡yhNƒ XP?þó¥Ó?Qà=ca‡U`@åXÑ`£@€äsÁŒ@Þ;>@œ?Ma"ྠ¹¾ì»œÀwP.‚U0†‘ø?ôŠìW(¾÷Ò‹J˜A¤1²ÐšZACÀBÀ›Âƒ¦X>ô?|ƒà“+< ‚܈2@¬2dÃÌ]Pà(Ñ@B/؈´ÜÓ½ä= Ü‚ kH<þû;nS“ƒ+x‡jð@ ?xË;÷‹€8ÈB.”µõ¾I$Cß»¿qPCUÅ}9o2<àPìQ?¡DèÿÅuÐP<_T=Ué¹I(†Ê+ú0éºk†`p’؃à¨xðyHŽÕ‹‡dH†xx=r±+K˜=·Ûˆ"êŠþè„$8P¿;¨d”bÀ/ѨÇ`X@€ïX¸ ðÇ'H£ƒ¨¾@3„üD!\¨úÛxW  `X|€©Z4‚[°$H£ˆ·èVø‹;…f€Ç¨Gß‹EHI[èAˆÇŽLØÅu „ˆ]¤¸…qH@¸‚jQ"è‚À©‚Y¬’ìŒBÈušl™ü‚X…(8Hÿ¥<¼ç:w$K˜‡z|ÕóЧàð0˜0 Ë”… *H¨° IlÚƒG±M«)€KŽœK5Á„ D|Œ½”Ëþ0‚¿ ̦ÁK逊–ˆË€€BT´³Ä¹ô½5¨IpIz”IÁŒ¼¥l3P±¡®Ì"€[fjÇw,ÍÓ4@ ÄÅCØÇ\ˆÊÆôy@Ku`8 …($ˆ„GˆôhxŠü ¨ÅO$MÌŠ¿tŽÙ$—$„zìË¿TK~i éh$ hø;þ`¼)˜Îûƒ+xÙ|P¾ʃp ^P˜ƒšn¼Ú˜ƒ^±¡20½jDÿ½Òô \0_p.±Àt,Œ0Íᄌ: ˘"L |ŒÆãÇyXÑjÊ:¨½ð=] ¬@ë*ˆ¡œT þŒðZ÷,Y€"ÈÑø$¸ÅpíJ˜¿Up<€€ÀϵÒPÑ,KÆëR÷´ÑSüÐ:˜pÅî›O,ÏÄŽFêлÎF…¸½À#Å/Ì„œŒ€J°‚?¸2±Q·Œõ 1¨KêüÉ•(µ‚¢rH!Áѱ-C-Ë HðËD½2œ¹EÔPàK@•TB /4Ó0ÌTÐ ÃHÔÅ…,ÕÓ£”B ÿx‡P ‹<ÝÓŒ „1tUUýµ/…Ç6- ˆÔ–9ÇP`UxÊ€¤SÕÍ‚È@]ÒMˆŽ-ÍŒ°Ž@•Õdu ¨\ÕTÕ—ƒx /à€Ø¥†¡‰]T·³…?دWû: „øKxdPW³(L¨†ñH.(Ðׯ`iˆ×[„ZÈÑ6ø|ˆ,‘ÐØ•±Ú=«±p¸ˆ¸´P  ›PŠ’P«€ˆ˜˜‰šÐ‚!=Ô¨€vWƒXÃß 6W`@hЂ8@›@¡;àð &qwÍÇ+ZkLÉIPJV|„À‰ª°‚™Í ¯x…"hÿše K¥` 0–™Z¸—•¥(±}”¤WdµkøÂÇ „h\È[ÐNJ ÛQ Yxûà“ˆÝ‰Í˜í“pTUÔ§0¿âR?>\¨Ò|ÀL+V°Æ¯¨Üj†0…\˜±ƒÔ‚̥Ĺå[›ÈÙ>̉Qà †;Y¯pÛ ØRGÕƒ€d‚¹¥ Émωˆ°…X€›ÛEÜ9ø/c(3ºÛa<Ö]¥õ¨*½ÙµAÀ•ÝȵÄ{ÅO°t\˜ئ5m¹ÐÛoEÔ.]]Þ剸µR›`Þa‰˜‡h\°sWPÜ» ó*…"8 Mqÿ‚K8 6PÑCxã# ŽPˆ®è¹¼oYTPz< v ØÀ ‚¸ =| ߸ 6@‚_ƒØHaØóÆ+Òà¢þH í vhó@–sl‡v0 Ïe%°x¾¯€®v°9h`ˆ–¢½"Š"Ö˜ Úƒ·.¸Î¨âð½Í`ÂXûH á‚Ì bd!7†œ?Nã[‡ñ8‡.Óh`ÄÀ… ŒÁÈ|(bŸŒ¦PÃ2Æ6.£n=FRì‚5xã5F±Ô°!]¥g„WA`5vcq×,> 1&!‡v „=`‚œ` 9ÎÔÃüØc#ÿQ=`¥5nŸUŒ¥ ™â^ÈÙêø>5byâíÄ[,æcc„ÔÀPJÒŒ7VTjíŠUÞŒ10åì¸eÿ€æ:~åxYV7fc?~àIc‚°à{fó¼÷d%\ RgÓhcw¦7Âà£8hFa’MUÑOH’fjFOaÆ ¡$1ÐQTÐÀ3ñ•.¹‚ø’È’1¡_0“Ü(G\i‰‘49¦AáK™_Q 9X M8SbiGIsq§H „i°<  Ì“@¦„’J©¦ùiH –c˜jk¬–Ú"±bq€:¡ª¶â¯˜ŸB9ÿh¡Î¨’W€„³Í¯‹ (FAjE- .hvÁ‘jZ8±bKYiEñ§Þ¸¦¾”!¦Àö  (ë žiˆ“ÁƒS¨ñé7iì,Jlklkàé—ŽéaÁì·•éÊCQÝTìñék™^íÁfè©öjªþ)‘Í9ñi€…| ½>êXȱlÁÞϦ“¸¦ºv‘_ Ã%ßh€™fhÛŒ«¾® ¶#¸Ôå°k&$ÑØîìn ùúî9_¸±|êî7º+µ”ué–Öïoù¾J•ðŽ—$ø¦|jõîo¸¸oî™+µ²+ÿNÈr¬ßz(/ðªÿ³:Òöƒ‘|žo¿p ¿œÌxëu‰ Ïpצé˜÷eHY?H -:léxqY)ñ!ð ¢ñµÀñBÒñ¹àñ‡ <ȃ^0H†MÇʹÏ•ó ï't±q ¯§(ÿqÌ™èÐÌÐØ+Çr0¯ò0‘9¨Ì肞Øe8l1s7sné¯AxŽ®Xžisyñ¦Jp8_«/·@A¦7ˆ4<ïsC?tl µhÉn*÷saitŠ.$H¿œI§¤y‘ñ‚hrO‹Jÿs©YþV‹÷tªétÙtiAôu~±*RWuXõW—õY§u[¿ÿ«ù,ô[ßu^§ 9(!†ªª^vb¯u°à+H…ñÒõbovgWTì=„8 æg¯vkG¤¡€?(ƒkïvo¯‹‰¬owr/c/wfGwu_wvowww¯2ux?+ywôy¿÷°ÐsC…Óš `˜},Âb•èwɛǒ;cÿ¬³à €-±«Þ‘, Ó-ˆÏ ƒ÷¾* †×¬4ÈÈç v¾š(%ð¼ªw嘭ÚÂ,K€xÕ:©Žß£•4yYCp· / ‹:ƒ^¨±+„;på°HH8¡ðªóÖU±)믠îRùH /2ð²µ`0Ël+ c©ÿƒž7ÑŽÇJLøzJV)…; OU°°5ëúB+®¯q$ûLû= ó¯v Ž0T_-è”û²00¨„4W Ç‚—0>¶€²{V)|µÏû¶x×5(¶\»º¬»|°œ@3‚ž€à2È€‚Öï…IXßI7 35 …;(.tã³1ó3£€(¶ƒ¡ÎD“³m̓;+ˆ2À·±Uƒ^h* ƒD"’ý¼‚S¨99ÈŒY(œDj¹’KM«ùŠD´ìW¹‡+S{…ð¨C7‰ýYyý[ƒ““­^ì%%"¶„0(ATyÿB-L„f‰DrV$z%@€F  fÔ;C fDÓp£†Jê@H¬&™±”ÐqÀãÊ…yÍŒiqdМW.ÎÀ²à ¨šQC…$Jd@éL·º,@ÊÓ'ЕF/bZ+Q,§ J :$ÓHŽJˆ°´H·âÌ _±Ð2ŽÄ ¡Äàñ€„j=PáÊÄŠL¯l„ù®‚‘ N¦ „`àC2PÖ‡BüÇ +Í.ç2`ŒC­ãnœ!BR…<@˜§ *¡pÆMéAê¨ÞÖp‰îXÚqñOÑ›‡:½T±dõ+AF¹¢eË0èÞ;¢‡#P áàþÄ!^âxŸÿE€VC„2ìÿV‚B[b|Ö3\P$Aÿ…MlÀt/ìŸ Eá@òe¯]¢ü‚B%$2¹Š4ªª-\ ‰BŒZéàh=è1Ðcâ7GJ`…¼`7xE:F@Md eƒ,ÑIÉ£þ&P²\(y€XÂ~@ ¸Mp¤9´ 58'ÂʼnÔŒ3R²ˆEPÉIÄÛWÚ5F BŠPÄçÒH†yÐp¬^#'8þÅI,ž\ÇîðèÀH‚mQ d/Y"ä² vƒcdŠa0¤ †Yü@ਫD1ÀPÓ\ÜCQ¬¢íWÈ€ Œ'%uˆiy:C5GÏÔ…S!ýhÀ=ø!»`Lã1¿XEèAPÞÿAi>êE/&á!U¢%"€(BV ^:9é7Dˆœe8@ž2 :µ´ CʰÅCB1ƒ]¡@ÅKÞN‡K¼¼§œjzmYàœ›@`‡B!*UÀ£«À p‡Òh×ðUI¡g‰(z[ˆ€.¦€±’Aƒ«3ÍÎJhÆ>ì°£özŽP©txkX1TжŠ} °hW±®’3‘lBbÀ)Žô@më]Ÿ*LÌ)B¥èB ˆ Ø¡gÈHݸXÊq€[%;•¼Uù#i`·*Sa²Äª¡ÂS± Ûet¶E+•4D[sêJÿP;á:k¬“’Œ=*ä:Ô€´]F¥G+¼õ=” ên_Y?åP!áe€E¯º¶VÃ^²=ëƒZÔè”= qû¯Lv»öJ//D+%ʺG’õ©¥ŽŽöÓ…ø8PX œ'Í‚0žƒlhth‡²a˜‚ SÝf`&®…rF å@Ò¸À˜ô â‘>") I:F,¬¯TF¯‡+*ÐpÀÊ“Sfš€!Š7„VNL°ª„ ›Ñ,` UÍ ñ@ Ð8EiòzSàAú²T§jˆx®ÖŠÿÆçe±Wna™ZSó<4Ð*>hù°ˆD#jAÛg@š ·]ëIÙñ ¥êÍl¢3˜mñdvd­ á/oÝè¼]¥.8i–·œè³$ý€´é,((' ¨¼°!M \R4Eº ëFƒ:µÐB ÷ÚB¢FÂ’A.Ö ì ¸¶Uò Ìf”š4Vh„¬ÿEhQè·‡…u©ƒòhU4‚M°Õ“®oˆ¿ Îç5$æ êp`˜ªƒ-ô8„poÈ9XG/ƒŽå™ ½€Á¼‡q]|`ߪN·BÄðÝ¢Áš×^({<ßÌrøu°Þ·eo9ÓñÏÿv²èTÞáâbl)»ö/µš4±þI ñð¯ÍX¡F¹Ê5”Õr¶ Ë ÞJî NXÐ2 À Ä2APµ â&a_ ™ýV¸JD †Å¶#{}7ßÞŽ¸—èìAùD.ŽÀ|4l8B@B|„ÆG‡÷>a…ÃãC xRàÄg*˜â û¢ÂÖ°ù ˆcäÝVá.‚ЊNwè•ØY›rd2( ­ÝÏò}¤X;?Áf­ïNαyû×_@_ÏÚTô%} "¡ÞËý+úêÝ‚å„*È ÑWÇ×ÏA%Õ—â]d7µ8Ù'ºS8ô1ȇÁRÿ7úÝå³ (â`¸ŒÃë` ÿqÞÜ›¬”Ñ@/LH…ŽlžŒÁøíùäŸM›ˆÍØPµuÌ dD€êE`ÜÁVÂúuÖÖõGױ ¼ÑéX#\bÁõuàòqßXßíEÜîÙAÜy€ " çµ`ê¡XЬB»qP@hü^',‚õµƒ PÛ(ô±Ÿž`|××ÃUtñžˆ Ü`÷i þÌü áØ¡ Ť üÍ çÝêŽú€f¦T,Ž%aÜ©! `zVƒÅÈàØc€A<Â#ÄH P"ÿdp‚XéxbB¸€ lbdì%ÎO'’æÀ*¶¢Ýˆ"?ðñ „-Nƒå!Áð\@-Öâ/ÀA-ê"BÜ¢ýá˜)BˆDì¤b,pbhÀ€OM€4Ï*‰4–‚dY¯õYd,#%& cŒðY%Â*¾B>(Bk΀c9*Ä*N£%r" Œã^ᣴ­„>®Ž4:£)&ÀlÂ$5žâM©"4 †=ÂÎ8Á`"( d?ÀBJ‰.l£ŒÉTdP<ãBä{´#<Á>þ£E’cTcA¥dæudAòYê@£ˆäJ˜"*¤5’DM•8:¤ÝÌ£³ôd9^$Bÿüä&e8Öã^q‚J²$EâdPJc&®$:ÞTíä#U*€:A”ŽGÞd=~3Æâ{˜%L6dNBeZîU©¥VåcÈO3ªc.¬’;n%f)€A†eAb&#N¶d4òY,¬M$&fƒÙbîec6X’ÐŽcN¦c®ÏW>f?m_ &föÓ¾0Sg†¦hbeަ7–fæifìˆ&cš&j*¦ž¦k¾ælÖ¦m>š€$Ómö&m†f‚ì¦ogk§qú¦*ão6æ!\¦m:ä>ö¦\çrR§u%2F§<5&]§w~'xRçtgxZçx–'z¦guª'{¶§{¾'|ÿ®g|ÎçvÒ§}Þ'~bf¤Á ä§þ'€Î'y(Ög(‚&¨q–CüÁ(ȧ‚F¨„N(…V¨…^(†æ'&Žsf¨‡臆¨ˆhlލ‰ŽèvA艮¨Š²¨‹è‹Æ¨Œâ'ÐB³´èŒæ¨Žî(ö¨~g€Bâè©‘)’&)*­(©“>)”F©”Žh2üÁ”^)–f©–ni{Z —~)˜†©˜Ž©g^™¦©š®)›Â芪bw¶©œÎ)Ö©Þ)žæ)n¨›ê©Ÿþ) ª *(˜Â *¢&*¢2AtÁ©¢Fª¤Nê‘JÃ] ¥fª¦ÿ‚(§nêŒFÄgBª§–ª©žj€ÖB2DFw‘*ª¾*¬Æj{.B५Ê*®æª®î*¯öª¯þ*°«°+±«±+²&«².ëžö¦@2kŸB«´"¨¤AÙÍ86f‰Þª‡Æ©hjÀ£²¦¸†\81C ¤è¬¸N+¼Biªìá^Bä”ýÑU(Âÿ †UµˆÙA%4` \ƒ*ت·h)PÁ4ØøË³>¦ˆÁ¬Ø_bé‚ üÉ”èà¶t¦LQ¼Ž¬ŒÞÚ Ç~DBaâ-4ÆQŠÓ$LtA‹ÕX@‚c- X@DÝqÀÔ„ Ñ‹ÿ”ŽŒ•O „ÁGèÀ lÓªÁÓ~Å@»þχ €{¤µš‡F @[œÇFœF!…FÈAðg,†Ç€QtmA0…ÜV|mDÆb¸¬éĬm~P„IèĪ…Ü^„pŒ#´‚`$Â^IS A" YÄKÌ@!xG0ÃÎj]Vl§‚n…jŒ(XÁ8ðÛÊH¸Y™±“8‘À„ÜÞ¥ˆe~H*ˆÈÙ´I¨ÂŠ´ènP87Ä@)˜:èB7¯3@Fo)€6˜Ü€ñ"¯9|ƒ.L…6tƒ>E±ÃCð ˜l Ã$@"ìÔ„É–tÃ@Hÿ|š¸ ²0L×Ðáیﹴ è ú!D*„ Å:0€/ØÂ»–É™(¬ˆ/•Y@ˆI5`;ø‚õUlˆ.‡(IµÂ(d‚œð$I ÙoÍ‹É"UÌC‡xè¬)>lñÓ ¯DôžB ˜ƒ7è9ìÃ/|òvƒ|Äö d7/9hCŸÝ€lºP” ø€ó@O2„ !øÐ \…qÐxÐ+ÁøRBúˆQ+Í(Ô0­ÓωõpÐóÈ(ŽÉhqˆ%@*á‚#TEaBDqF9ÓÖž$@?Fèf0#ó)·QQmU)@Å¢MÀÀS³ÿJN BÓJˆäEYæbj7hƒ6<ƒh£1ôp”9¬2Bx÷@7hCF¢²»ÚM‚øÖ#£µx‰P‚ôœçô´•SY”KD" D løÂ{ÑdÙ NË4»®y]Ô´ ÀÈ9f1œªy°eê,lˆP²J4s#·3…BÈŸy¡}±0¸©iØ2|ÄVH@Õ Ác¤å¶r”ˆ  @»Ç@#@4ÜhBS:lƒÜ€4Ü€+ƒ³¸ò*ÐØ7˜ÃGàð ¼2+›W×ú‡§ƒ²EÀ!üB‚Bľýï¹mYªxÉhÏ  QÕ–ÿ¹ÜÜžÒÒ–ýA°ƒ¿ùڰþy3me¸Í±Ð€c…9GÀè¿q@6ìŠ5Œ¹3Z/²}B*¬A® #„ô_ß… 2‚HHÞÁŠê Ýé«‹œ]‚ôõà¸Ã6lÃü‚c4B¸2,×boÃ>¤29”³<ÆÛØõ`#žàêP8<› Ȭ œ'ÍŸ_—¡÷yÎÚÂ9 8È!6©BÐöé(ƒ Ú6æ`÷Q5Ó –r­žãð6hµ@hÝ&ð`Jˆ.0BgWZW÷&AY–#&"„Búä “ÄãHÌ04Á-vä$²¢(ú#,ÿÞÔ'Œô´•B) ƒ38À/ÈwÐX)doFë}OÀ}Ǹ¦rk‚# \#_údYºe‚?AÂ%D2ã?Æ€ü˜$@Æ¥v^¸?fAbeÈuw¶ž'Kòqƒ#8ÞÔ$¢¢H¤O©µu¿xŽBd´Z(„øn.Ï8iæ'IÙ8Œ÷ø“fvBขr6v߸'è 4§/¹‚¾«ž¶#“Gù©õOsë‘»xŽg9Ÿ^9zr¹”{ù—§g4(0$¬Äv«™§¹Å†9›o* ”A©¹œg*˜·¹_gŠ¢ùï9Ÿ hÞhŸº :¡×y¡:¢'º¢/:£7úœ;:¤Gº¤O:¥Wº¥s_:¦gº¦o:§wº§:¨‡º¨:©—:–›:ª§ºª¯:«·ú©»:¬Çº¬Ïº¡Óº­ß:®çº®ï:¯÷º¯ÿ:°»°û«»±û±'»²/;³7û£;;´G»´O;µW»µ×úµg»¶o;·w»·;¸{@!ù, 08ÿ H° Áƒ\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²bÂ’(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏŸ@ƒ J´¨Ñ£H“*]Ê´©Ó§P£JJµªÕ”'¯jÝʵ«×› hùJ¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈ+^̸±ãÇ#KžL¹²å˘3kÞ̹³çÏ C‹Mº´éÓ¨S«^ͺµëšlØ àµíÛDiãÞÍlXݽƒ oùøðãÈI ø¼¹sÅk?ŸNÝatãÕ³k/p}»÷ïàËÿO¾¼ùóèÓ«_Ͼ½û÷ðãËŸO¿¾ýûøóëßÏ¿¿ÿÿ(à€hà&¨à‚ 6èàƒF(á„Vhá…f¨á†vèᇠ†(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©ä’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜dÚÔ€”ùà  æšm¦ù&ƒg4pœxæ”Bzöé矀*è „j衈&ªè¢Œ6êè£F*餔Vj饘fªé¦œvêé§ †*ꨤ–jꩨ¦ªêªGZ±ÖI6°ÿªÕO¼Ê§¬RÝ*¶âškX$P@½úJ•-ı†±Í%T+³ÂaípPH7íµØf«í¶Üvëí·à†+î¸ä–kî¹è¦«îºì¶ëî»ðÆ+ï¼ôÖkï½øjvµùFFsýúK›PEÀ –b \™?¬kÄ‹E—7V\ÆwìñÇ ‡,òÈ$—lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬óÎ<÷ìóÏ@-ôÐDmôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\wíõ×`‡-öØd—möÙh§­öÚl·íöÛpÇ-÷Üt×m÷Ýxç­÷Þ|÷ÿí÷߀.øà„nøáˆ'®øâŒ7îøãG.ùä–Vð'­QƒŸf°E¶Psþ†fR„Þ'Ì,”3ĺ´±D{íU‹ûî¼÷îûïÀ/üðÄoüñÈ'¯üòÌ7ïüóÐG/ýôÔWoýõØg¯ýöÜwïý÷à‡/þøä—oþù觯þúì·ïþûðÇ/ÿüô×oÿýøç¯ÿþü÷ïÿÿ  HÀð€L ÈÀ:ðŒ 'HÁ Zð‚Ì 7H7vó¡…ú€ ˜|°“Þýkc$Z cHÃÚð†8Ì¡wÈÃúð‡@ "àÿþõ»ÛoBÜÙ ¼°O*€¿vWˆ€T…«’£h sÈQ€æ|å9^!§ ÂRÕo‚5¬æ ÀWÈRVð¬Þ±°ˆSL¢÷ÈÇ>úñ€ ¤ IÈBòˆL¤"ÉÈF:ò‘Œ¤$'IÉJZò’˜Ì¤&7ÉÉNzò“  ¥(GIÊRšò”¨L¥*WÉÊVºò•°Œ¥,gIËZÚò–¸Ì¥.wÉË^úò—À ¦0‡IÌb³(/,^y÷‚] /L<¦4§IÍjZóšØÌ¦ôº³»}ÍprK$¢ùL<‘rÜÔ&ª&fGuº³7ìô]4›ÏwJŠö̧>÷É4Ï~’Ä#ðØ8¼/„X[ãB°P”/Èik.àŽ…¢°pþ©`€åÔ"ŽÓL ’3 !@Ö 7Ö`Ä„V(†ÛTÈ ‡ †(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©äÿ’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œös@IQæ ”ÉÁ£vêé§ †*ꨤ–jꩨ¦ªêª¬¶êê«°Æ*무Öjë­¸æªë®¼öêë¯À+ì°Äkì±È&«ì²Ì6ëì³ÐF+í´ÔVkíµØf«í¶Üvëí·à†+î¸ä–kî¹è¦«îºì¶ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿,ðÀlðÁ)¢“æ’",›0c2Θ8¦«-hûh¤kðA™XP—lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬óÎ<÷ìóÏ@-ôÐDmôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\wíõ×`‡-öØd—möÙh§­¶R©IAl@æ‚(°öÞ|÷í÷߀.øà„nøáˆ'®øâŒ7îøãG.ùäw]àAd^P±Å—)L !ù,Q8›ÿÀ‰pH,£rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿U$xL.›Ïè´zÍ&Þðw{N¯Ûïø¼^È÷€‚ƒ„…s}I†Š‹ŒŽƒp b”•–—˜Rˆ™žŸ ‚›¡¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏÿŸ@ƒ J´(È4-؃K æxµ`ÒªX³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈû}sÆbh+pþ©`€åÔ"ŽÓL ’3 !@Ö 7Ö`Ä„V(†ÛTÈ ‡ †(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©äÿ’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œös@IQæ ”ÉÁ£vêé§ †*ꨤ–jꩨ¦ªêª¬¶êê«°Æ*무Öjë­¸æªë®¼öêë¯À+ì°Äkì±È&«ì²Ì6ëì³ÐF+í´ÔVkíµØf«í¶Üvëí·à†+î¸ä–kî¹è¦«îºì¶ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿,ðÀlðÁ)¢“æ’",›0c2Θ8¦«-hûh¤kðA™XP—lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬óÎ<÷ìóÏ@-ôÐDmôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\wíõ×`‡-öØd—möÙh§­¶R©IAl@æ‚(°öÞ|÷í÷߀.øà„nøáˆ'®øâŒ7îøãG.ùäw]àAd^P±Å—)L !ù,Q8›ÿÀ‰pH,£rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿U$xL.›Ïè´zÍ&Þðw{N¯Ûïø¼^È÷€‚ƒ„…s}I†Š‹ŒŽƒp b”•–—˜Rˆ™žŸ ‚›¡¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏÿŸ@ƒ J´(È4-؃K æxµ`ÒªX³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈû}sÆbh+pþ©`€åÔ"ŽÓL ’3 !@Ö 7Ö`Ä„V(†ÛTÈ ‡ †(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©äÿ’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œös@IQæ ”ÉÁ£vêé§ †*ꨤ–jꩨ¦ªêª¬¶êê«°Æ*무Öjë­¸æªë®¼öêë¯À+ì°Äkì±È&«ì²Ì6ëì³ÐF+í´ÔVkíµØf«í¶Üvëí·à†+î¸ä–kî¹è¦«îºì¶ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿,ðÀlðÁ)¢“æ’",›0c2Θ8¦«-hûh¤kðA™XP—lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬óÎ<÷ìóÏ@-ôÐDmôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\wíõ×`‡-öØd—möÙh§­¶R©IAl@æ‚(°öÞ|÷í÷߀.øà„nøáˆ'®øâŒ7îøãG.ùäw]àAd^P±Å—)L !ù,Q8›ÿÀ‰pH,£rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿U$xL.›Ïè´zÍ&Þðw{N¯Ûïø¼^È÷€‚ƒ„…s}I†Š‹ŒŽƒp b”•–—˜Rˆ™žŸ ‚›¡¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏÿŸ@ƒ J´(È4-؃K æxµ`ÒªX³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈû}sÆbh+pþ©`€åÔ"ŽÓL ’3 !@Ö 7Ö`Ä„V(†ÛTÈ ‡ †(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©äÿ’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œös@IQæ ”ÉÁ£vêé§ †*ꨤ–jꩨ¦ªêª¬¶êê«°Æ*무Öjë­¸æªë®¼öêë¯À+ì°Äkì±È&«ì²Ì6ëì³ÐF+í´ÔVkíµØf«í¶Üvëí·à†+î¸ä–kî¹è¦«îºì¶ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿,ðÀlðÁ)¢“æ’",›0c2Θ8¦«-hûh¤kðA™XP—lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬óÎ<÷ìóÏ@-ôÐDmôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\wíõ×`‡-öØd—möÙh§­¶R©IAl@æ‚(°öÞ|÷í÷߀.øà„nøáˆ'®øâŒ7îøãG.ùäw]àAd^P±Å—)L !ù,Q8›ÿÀ‰pH,£rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿U$xL.›Ïè´zÍ&Þðw{N¯Ûïø¼^È÷€‚ƒ„…s}I†Š‹ŒŽƒp b”•–—˜Rˆ™žŸ ‚›¡¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏÿŸ@ƒ J´(È4-؃K æxµ`ÒªX³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈû}sÆbh+pþ©`€åÔ"ŽÓL ’3 !@Ö 7Ö`Ä„V(†ÛTÈ ‡ †(âˆ$–hâ‰(¦¨âŠ,¶èâ‹0Æ(ãŒ4Öhã8æ¨ãŽ<öèã@)äDiä‘H&©äÿ’L6éä“PF)å”TViå•Xf©å–\véå—`†)æ˜d–iæ™h¦©æšl¶éæ›pÆ)çœtÖiçxæ©çž|öé矀*è „j衈&ªè¢Œös@IQæ ”ÉÁ£vêé§ †*ꨤ–jꩨ¦ªêª¬¶êê«°Æ*무Öjë­¸æªë®¼öêë¯À+ì°Äkì±È&«ì²Ì6ëì³ÐF+í´ÔVkíµØf«í¶Üvëí·à†+î¸ä–kî¹è¦«îºì¶ëî»ðÆ+ï¼ôÖkï½øæ«ï¾üöëï¿,ðÀlðÁ)¢“æ’",›0c2Θ8¦«-hûh¤kðA™XP—lòÉ(§¬òÊ,·ìòË0Ç,óÌ4×lóÍ8ç¬óÎ<÷ìóÏ@-ôÐDmôÑH'­ôÒL7íôÓPG-õÔTWmõÕXg­õÖ\wíõ×`‡-öØd—möÙh§­¶R©IAl@æ‚(°öÞ|÷í÷߀.øà„nøáˆ'®øâŒ7îøãG.ùäw]àAd^P±Å—)L !ù,Q8›ÿÀ‰pH,£rÉl:ŸÐ¨tJ­Z¯Ø¬vËíz¿U$xL.›Ïè´zÍ&Þðw{N¯Ûïø¼^È÷€‚ƒ„…s}I†Š‹ŒŽƒp b”•–—˜Rˆ™žŸ ‚›¡¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ H° Áƒ*\Ȱ¡Ã‡#JœH±¢Å‹3jÜȱ£Ç CŠI²¤É“(Sª\ɲ¥Ë—0cÊœI³¦Í›8sêÜɳ§ÏÿŸ@ƒ J´(È4-؃K æxµ`ÒªX³jÝʵ«×¯`ÊK¶¬Ù³hÓª]˶­Û·pãÊK·®Ý»xóêÝË·¯ß¿€ L¸°áÈû}sÆbh+= 4.0, where one of the biggest pain points will surely be the flipping of the default value of \code{stringsAsFactors} from \code{TRUE} to \code{FALSE}. } \details{ It's not always possible to tell statically whether the change will break existing code because R is dynamically typed -- e.g. in \code{data.frame(x)} if \code{x} is a string, this code will be affected, but if \code{x} is a number, this code will be unaffected. However, in \code{data.frame(x = "a")}, the output will unambiguously be affected. We can instead supply \code{stringsAsFactors = TRUE}, which will make this code backwards-compatible. See \url{https://developer.r-project.org/Blog/public/2020/02/16/stringsasfactors/}. } \examples{ # will produce lints lint( text = 'data.frame(x = "a")', linters = strings_as_factors_linter() ) # okay lint( text = 'data.frame(x = "a", stringsAsFactors = TRUE)', linters = strings_as_factors_linter() ) lint( text = 'data.frame(x = "a", stringsAsFactors = FALSE)', linters = strings_as_factors_linter() ) lint( text = "data.frame(x = 1.2)", linters = strings_as_factors_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=robustness_linters]{robustness} } lintr/man/trailing_blank_lines_linter.Rd0000644000176200001440000000150014752731051020174 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/trailing_blank_lines_linter.R \name{trailing_blank_lines_linter} \alias{trailing_blank_lines_linter} \title{Trailing blank lines linter} \usage{ trailing_blank_lines_linter() } \description{ Check that there are no trailing blank lines in source code. } \examples{ # will produce lints f <- tempfile() cat("x <- 1\n\n", file = f) writeLines(readChar(f, file.size(f))) lint( filename = f, linters = trailing_blank_lines_linter() ) unlink(f) # okay cat("x <- 1\n", file = f) writeLines(readChar(f, file.size(f))) lint( filename = f, linters = trailing_blank_lines_linter() ) unlink(f) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=default_linters]{default}, \link[=style_linters]{style} } lintr/man/expect_lint_free.Rd0000644000176200001440000000077014752731051015774 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/expect_lint.R \name{expect_lint_free} \alias{expect_lint_free} \title{Test that the package is lint free} \usage{ expect_lint_free(...) } \arguments{ \item{...}{arguments passed to \code{\link[=lint_package]{lint_package()}}} } \description{ This function is a thin wrapper around lint_package that simply tests there are no lints in the package. It can be used to ensure that your tests fail if the package contains lints. } lintr/man/yoda_test_linter.Rd0000644000176200001440000000225014752731051016020 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/yoda_test_linter.R \name{yoda_test_linter} \alias{yoda_test_linter} \title{Block obvious "yoda tests"} \usage{ yoda_test_linter() } \description{ Yoda tests use \verb{(expected, actual)} instead of the more common \verb{(actual, expected)}. This is not always possible to detect statically; this linter focuses on the simple case of testing an expression against a literal value, e.g. \verb{(1L, foo(x))} should be \verb{(foo(x), 1L)}. } \examples{ # will produce lints lint( text = "expect_equal(2, x)", linters = yoda_test_linter() ) lint( text = 'expect_identical("a", x)', linters = yoda_test_linter() ) # okay lint( text = "expect_equal(x, 2)", linters = yoda_test_linter() ) lint( text = 'expect_identical(x, "a")', linters = yoda_test_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. \url{https://en.wikipedia.org/wiki/Yoda_conditions} } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat}, \link[=readability_linters]{readability} } lintr/man/default_settings.Rd0000644000176200001440000000324514752731051016021 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/zzz.R \docType{data} \name{default_settings} \alias{default_settings} \alias{settings} \alias{config} \alias{lintr-config} \alias{lintr-settings} \alias{.lintr} \title{Default lintr settings} \format{ An object of class \code{list} of length 12. } \usage{ default_settings } \description{ The default settings consist of \itemize{ \item \code{linters}: a list of default linters (see \code{\link[=default_linters]{default_linters()}}) \item \code{encoding}: the character encoding assumed for the file \item \code{exclude}: pattern used to exclude a line of code \item \code{exclude_start}, \code{exclude_end}: patterns used to mark start and end of the code block to exclude \item \code{exclude_linter}, \code{exclude_linter_sep}: patterns used to exclude linters \item \code{exclusions}: a list of exclusions, see \code{\link[=exclude]{exclude()}} for a complete description of valid values. \item \code{cache_directory}: location of cache directory \item \code{comment_token}: a GitHub token character \item \code{error_on_lint}: decides if error should be produced when any lints are found } There are no settings without defaults, i.e., this list describes every valid setting. } \examples{ # available settings names(default_settings) # linters included by default names(default_settings$linters) # default values for a few of the other settings default_settings[c( "encoding", "exclude", "exclude_start", "exclude_end", "exclude_linter", "exclude_linter_sep", "exclusions", "error_on_lint" )] } \seealso{ \code{\link[=read_settings]{read_settings()}}, \link{default_linters} } \keyword{datasets} lintr/man/line_length_linter.Rd0000644000176200001440000000165414752731051016324 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/line_length_linter.R \name{line_length_linter} \alias{line_length_linter} \title{Line length linter} \usage{ line_length_linter(length = 80L) } \arguments{ \item{length}{maximum line length allowed. Default is 80L (Hollerith limit).} } \description{ Check that the line length of both comments and code is less than \code{length}. } \examples{ # will produce lints lint( text = strrep("x", 23L), linters = line_length_linter(length = 20L) ) # okay lint( text = strrep("x", 21L), linters = line_length_linter(length = 40L) ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#long-lines} } } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/T_and_F_symbol_linter.Rd0000644000176200001440000000232014752731051016702 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/T_and_F_symbol_linter.R \name{T_and_F_symbol_linter} \alias{T_and_F_symbol_linter} \title{\code{T} and \code{F} symbol linter} \usage{ T_and_F_symbol_linter() } \description{ Although they can be synonyms, avoid the symbols \code{T} and \code{F}, and use \code{TRUE} and \code{FALSE}, respectively, instead. \code{T} and \code{F} are not reserved keywords and can be assigned to any other values. } \examples{ # will produce lints lint( text = "x <- T; y <- F", linters = T_and_F_symbol_linter() ) lint( text = "T = 1.2; F = 2.4", linters = T_and_F_symbol_linter() ) # okay lint( text = "x <- c(TRUE, FALSE)", linters = T_and_F_symbol_linter() ) lint( text = "t = 1.2; f = 2.4", linters = T_and_F_symbol_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#logical-vectors} } } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=robustness_linters]{robustness}, \link[=style_linters]{style} } lintr/man/trailing_whitespace_linter.Rd0000644000176200001440000000251014752731051020051 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/trailing_whitespace_linter.R \name{trailing_whitespace_linter} \alias{trailing_whitespace_linter} \title{Trailing whitespace linter} \usage{ trailing_whitespace_linter(allow_empty_lines = FALSE, allow_in_strings = TRUE) } \arguments{ \item{allow_empty_lines}{Suppress lints for lines that contain only whitespace.} \item{allow_in_strings}{Suppress lints for trailing whitespace in string constants.} } \description{ Check that there are no space characters at the end of source lines. } \examples{ # will produce lints lint( text = "x <- 1.2 ", linters = trailing_whitespace_linter() ) code_lines <- "a <- TRUE\n \nb <- FALSE" writeLines(code_lines) lint( text = code_lines, linters = trailing_whitespace_linter() ) # okay lint( text = "x <- 1.2", linters = trailing_whitespace_linter() ) lint( text = "x <- 1.2 # comment about this assignment", linters = trailing_whitespace_linter() ) code_lines <- "a <- TRUE\n \nb <- FALSE" writeLines(code_lines) lint( text = code_lines, linters = trailing_whitespace_linter(allow_empty_lines = TRUE) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=default_linters]{default}, \link[=style_linters]{style} } lintr/man/equals_na_linter.Rd0000644000176200001440000000177514752731051016010 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/equals_na_linter.R \name{equals_na_linter} \alias{equals_na_linter} \title{Equality check with NA linter} \usage{ equals_na_linter() } \description{ Check for \code{x == NA}, \code{x != NA} and \code{x \%in\% NA}. Such usage is almost surely incorrect -- checks for missing values should be done with \code{\link[=is.na]{is.na()}}. } \examples{ # will produce lints lint( text = "x == NA", linters = equals_na_linter() ) lint( text = "x != NA", linters = equals_na_linter() ) lint( text = "x \%in\% NA", linters = equals_na_linter() ) # okay lint( text = "is.na(x)", linters = equals_na_linter() ) lint( text = "!is.na(x)", linters = equals_na_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=common_mistakes_linters]{common_mistakes}, \link[=correctness_linters]{correctness}, \link[=default_linters]{default}, \link[=robustness_linters]{robustness} } lintr/man/commented_code_linter.Rd0000644000176200001440000000167214752731051017001 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/commented_code_linter.R \name{commented_code_linter} \alias{commented_code_linter} \title{Commented code linter} \usage{ commented_code_linter() } \description{ Check that there is no commented code outside roxygen blocks. } \examples{ # will produce lints lint( text = "# x <- 1", linters = commented_code_linter() ) lint( text = "x <- f() # g()", linters = commented_code_linter() ) lint( text = "x + y # + z[1, 2]", linters = commented_code_linter() ) # okay lint( text = "x <- 1; x <- f(); x + y", linters = commented_code_linter() ) lint( text = "#' x <- 1", linters = commented_code_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/lintr-package.Rd0000644000176200001440000000156414752731051015200 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lintr-package.R \docType{package} \name{lintr-package} \alias{lintr} \alias{lintr-package} \title{Lintr} \description{ Checks adherence to a given style, syntax errors, and possible semantic issues. Supports on the fly checking of R code edited with Emacs, Vim, and Sublime Text. } \seealso{ \code{\link[=lint]{lint()}}, \code{\link[=lint_package]{lint_package()}}, \code{\link[=lint_dir]{lint_dir()}}, \link{linters} } \author{ \strong{Maintainer}: Michael Chirico \email{michaelchirico4@gmail.com} Authors: \itemize{ \item Jim Hester \item Florent Angly (fangly) \item Russ Hyde \item Kun Ren \item Alexander Rosenstock (AshesITR) \item Indrajeet Patil \email{patilindrajeet.science@gmail.com} (\href{https://orcid.org/0000-0003-1995-6531}{ORCID}) (@patilindrajeets) } } \keyword{internal} lintr/man/stopifnot_all_linter.Rd0000644000176200001440000000172414752731051016707 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/stopifnot_all_linter.R \name{stopifnot_all_linter} \alias{stopifnot_all_linter} \title{Block usage of all() within stopifnot()} \usage{ stopifnot_all_linter() } \description{ \code{stopifnot(A)} actually checks \code{all(A)} "under the hood" if \code{A} is a vector, and produces a better error message than \code{stopifnot(all(A))} does. } \examples{ # will produce lints lint( text = "stopifnot(all(x > 0))", linters = stopifnot_all_linter() ) lint( text = "stopifnot(y > 3, all(x < 0))", linters = stopifnot_all_linter() ) # okay lint( text = "stopifnot(is.null(x) || all(x > 0))", linters = stopifnot_all_linter() ) lint( text = "assert_that(all(x > 0))", linters = stopifnot_all_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=readability_linters]{readability} } lintr/man/package_development_linters.Rd0000644000176200001440000000204114752731051020203 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{package_development_linters} \alias{package_development_linters} \title{Package development linters} \description{ Linters useful to package developers, for example for writing consistent tests. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'package_development': \itemize{ \item{\code{\link{backport_linter}}} \item{\code{\link{conjunct_test_linter}}} \item{\code{\link{expect_comparison_linter}}} \item{\code{\link{expect_identical_linter}}} \item{\code{\link{expect_length_linter}}} \item{\code{\link{expect_named_linter}}} \item{\code{\link{expect_not_linter}}} \item{\code{\link{expect_null_linter}}} \item{\code{\link{expect_s3_class_linter}}} \item{\code{\link{expect_s4_class_linter}}} \item{\code{\link{expect_true_false_linter}}} \item{\code{\link{expect_type_linter}}} \item{\code{\link{package_hooks_linter}}} \item{\code{\link{yoda_test_linter}}} } } lintr/man/expect_named_linter.Rd0000644000176200001440000000234414752731051016465 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/expect_named_linter.R \name{expect_named_linter} \alias{expect_named_linter} \title{Require usage of \code{expect_named(x, n)} over \code{expect_equal(names(x), n)}} \usage{ expect_named_linter() } \description{ \code{\link[testthat:expect_named]{testthat::expect_named()}} exists specifically for testing the \code{\link[=names]{names()}} of an object. \code{\link[testthat:equality-expectations]{testthat::expect_equal()}} can also be used for such tests, but it is better to use the tailored function instead. } \examples{ # will produce lints lint( text = 'expect_equal(names(x), "a")', linters = expect_named_linter() ) # okay lint( text = 'expect_named(x, "a")', linters = expect_named_linter() ) lint( text = 'expect_equal(colnames(x), "a")', linters = expect_named_linter() ) lint( text = 'expect_equal(dimnames(x), "a")', linters = expect_named_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat}, \link[=readability_linters]{readability} } lintr/man/implicit_assignment_linter.Rd0000644000176200001440000000413314752731051020071 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/implicit_assignment_linter.R \name{implicit_assignment_linter} \alias{implicit_assignment_linter} \title{Avoid implicit assignment in function calls} \usage{ implicit_assignment_linter( except = c("bquote", "expression", "expr", "quo", "quos", "quote"), allow_lazy = FALSE, allow_scoped = FALSE ) } \arguments{ \item{except}{A character vector of functions to be excluded from linting.} \item{allow_lazy}{logical, default \code{FALSE}. If \code{TRUE}, assignments that only trigger conditionally (e.g. in the RHS of \code{&&} or \code{||} expressions) are skipped.} \item{allow_scoped}{Logical, default \code{FALSE}. If \code{TRUE}, "scoped assignments", where the object is assigned in the statement beginning a branch and used only within that branch, are skipped.} } \description{ Assigning inside function calls makes the code difficult to read, and should be avoided, except for functions that capture side-effects (e.g. \code{\link[=capture.output]{capture.output()}}). } \examples{ # will produce lints lint( text = "if (x <- 1L) TRUE", linters = implicit_assignment_linter() ) lint( text = "mean(x <- 1:4)", linters = implicit_assignment_linter() ) # okay lines <- "x <- 1L\nif (x) TRUE" writeLines(lines) lint( text = lines, linters = implicit_assignment_linter() ) lines <- "x <- 1:4\nmean(x)" writeLines(lines) lint( text = lines, linters = implicit_assignment_linter() ) lint( text = "A && (B <- foo(A))", linters = implicit_assignment_linter(allow_lazy = TRUE) ) lines <- c( "if (any(idx <- x < 0)) {", " stop('negative elements: ', toString(which(idx)))", "}" ) writeLines(lines) lint( text = lines, linters = implicit_assignment_linter(allow_scoped = TRUE) ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#assignment} } } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/outer_negation_linter.Rd0000644000176200001440000000204114752731051017045 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/outer_negation_linter.R \name{outer_negation_linter} \alias{outer_negation_linter} \title{Require usage of \code{!any(x)} over \code{all(!x)}, \code{!all(x)} over \code{any(!x)}} \usage{ outer_negation_linter() } \description{ \code{any(!x)} is logically equivalent to \code{!all(x)}; ditto for the equivalence of \code{all(!x)} and \code{!any(x)}. Negating after aggregation only requires inverting one logical value, and is typically more readable. } \examples{ # will produce lints lint( text = "all(!x)", linters = outer_negation_linter() ) lint( text = "any(!x)", linters = outer_negation_linter() ) # okay lint( text = "!any(x)", linters = outer_negation_linter() ) lint( text = "!all(x)", linters = outer_negation_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/pipe_consistency_linter.Rd0000644000176200001440000000233014752731051017402 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe_consistency_linter.R \name{pipe_consistency_linter} \alias{pipe_consistency_linter} \title{Pipe consistency linter} \usage{ pipe_consistency_linter(pipe = c("auto", "\%>\%", "|>")) } \arguments{ \item{pipe}{Which pipe operator is valid (either \code{"\%>\%"} or \code{"|>"}). By default (\code{"auto"}), the linter has no preference but will check that each file uses only one type of pipe operator.} } \description{ Check that pipe operators are used consistently by file, or optionally specify one valid pipe operator. } \examples{ # will produce lints lint( text = "1:3 |> mean() \%>\% as.character()", linters = pipe_consistency_linter() ) lint( text = "1:3 \%>\% mean() \%>\% as.character()", linters = pipe_consistency_linter("|>") ) # okay lint( text = "1:3 \%>\% mean() \%>\% as.character()", linters = pipe_consistency_linter() ) lint( text = "1:3 |> mean() |> as.character()", linters = pipe_consistency_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/string_boundary_linter.Rd0000644000176200001440000000475214752731051017247 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/string_boundary_linter.R \name{string_boundary_linter} \alias{string_boundary_linter} \title{Require usage of \code{startsWith()} and \code{endsWith()} over \code{grepl()}/\code{substr()} versions} \usage{ string_boundary_linter(allow_grepl = FALSE) } \arguments{ \item{allow_grepl}{Logical, default \code{FALSE}. If \code{TRUE}, usages with \code{grepl()} are ignored. Some authors may prefer the conciseness offered by \code{grepl()} whereby \code{NA} input maps to \code{FALSE} output, which doesn't have a direct equivalent with \code{startsWith()} or \code{endsWith()}.} } \description{ \code{\link[=startsWith]{startsWith()}} is used to detect fixed initial substrings; it is more readable and more efficient than equivalents using \code{\link[=grepl]{grepl()}} or \code{\link[=substr]{substr()}}. c.f. \code{startsWith(x, "abc")}, \code{grepl("^abc", x)}, \code{substr(x, 1L, 3L) == "abc"}. } \details{ Ditto for using \code{\link[=endsWith]{endsWith()}} to detect fixed terminal substrings. Note that there is a difference in behavior between how \code{grepl()} and \code{startsWith()} (and \code{endsWith()}) handle missing values. In particular, for \code{grepl()}, \code{NA} inputs are considered \code{FALSE}, while for \code{startsWith()}, \code{NA} inputs have \code{NA} outputs. That means the strict equivalent of \code{grepl("^abc", x)} is \code{!is.na(x) & startsWith(x, "abc")}. We lint \code{grepl()} usages by default because the \code{!is.na()} version is more explicit with respect to \code{NA} handling -- though documented, the way \code{grepl()} handles missing inputs may be surprising to some users. } \examples{ # will produce lints lint( text = 'grepl("^a", x)', linters = string_boundary_linter() ) lint( text = 'grepl("z$", x)', linters = string_boundary_linter() ) # okay lint( text = 'startsWith(x, "a")', linters = string_boundary_linter() ) lint( text = 'endsWith(x, "z")', linters = string_boundary_linter() ) # If missing values are present, the suggested alternative wouldn't be strictly # equivalent, so this linter can also be turned off in such cases. lint( text = 'grepl("z$", x)', linters = string_boundary_linter(allow_grepl = TRUE) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability}, \link[=regex_linters]{regex} } lintr/man/length_test_linter.Rd0000644000176200001440000000162714752731051016354 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/length_test_linter.R \name{length_test_linter} \alias{length_test_linter} \title{Check for a common mistake where length is applied in the wrong place} \usage{ length_test_linter() } \description{ Usage like \code{length(x == 0)} is a mistake. If you intended to check \code{x} is empty, use \code{length(x) == 0}. Other mistakes are possible, but running \code{length()} on the outcome of a logical comparison is never the best choice. } \examples{ # will produce lints lint( text = "length(x == 0)", linters = length_test_linter() ) # okay lint( text = "length(x) > 0", linters = length_test_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=robustness_linters]{robustness} } lintr/man/lengths_linter.Rd0000644000176200001440000000175314752731051015500 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/lengths_linter.R \name{lengths_linter} \alias{lengths_linter} \title{Require usage of \code{lengths()} where possible} \usage{ lengths_linter() } \description{ \code{\link[=lengths]{lengths()}} is a function that was added to base R in version 3.2.0 to get the length of each element of a list. It is equivalent to \code{sapply(x, length)}, but faster and more readable. } \examples{ # will produce lints lint( text = "sapply(x, length)", linters = lengths_linter() ) lint( text = "vapply(x, length, integer(1L))", linters = lengths_linter() ) lint( text = "purrr::map_int(x, length)", linters = lengths_linter() ) # okay lint( text = "lengths(x)", linters = lengths_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/terminal_close_linter.Rd0000644000176200001440000000211114752731051017021 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/terminal_close_linter.R \name{terminal_close_linter} \alias{terminal_close_linter} \title{Prohibit close() from terminating a function definition} \usage{ terminal_close_linter() } \description{ Functions that end in \code{close(x)} are almost always better written by using \code{on.exit(close(x))} close to where \code{x} is defined and/or opened. } \examples{ # will produce lints code <- paste( "f <- function(fl) {", " conn <- file(fl, open = 'r')", " readLines(conn)", " close(conn)", "}", sep = "\n" ) writeLines(code) lint( text = code, linters = terminal_close_linter() ) # okay code <- paste( "f <- function(fl) {", " conn <- file(fl, open = 'r')", " on.exit(close(conn))", " readLines(conn)", "}", sep = "\n" ) writeLines(code) lint( text = code, linters = terminal_close_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=robustness_linters]{robustness} } lintr/man/readability_linters.Rd0000644000176200001440000000607614752731051016513 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{readability_linters} \alias{readability_linters} \title{Readability linters} \description{ Linters highlighting readability issues, such as missing whitespace. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'readability': \itemize{ \item{\code{\link{boolean_arithmetic_linter}}} \item{\code{\link{brace_linter}}} \item{\code{\link{commas_linter}}} \item{\code{\link{commented_code_linter}}} \item{\code{\link{comparison_negation_linter}}} \item{\code{\link{conjunct_test_linter}}} \item{\code{\link{consecutive_assertion_linter}}} \item{\code{\link{consecutive_mutate_linter}}} \item{\code{\link{cyclocomp_linter}}} \item{\code{\link{empty_assignment_linter}}} \item{\code{\link{expect_length_linter}}} \item{\code{\link{expect_named_linter}}} \item{\code{\link{expect_not_linter}}} \item{\code{\link{expect_true_false_linter}}} \item{\code{\link{fixed_regex_linter}}} \item{\code{\link{for_loop_index_linter}}} \item{\code{\link{function_left_parentheses_linter}}} \item{\code{\link{function_return_linter}}} \item{\code{\link{if_not_else_linter}}} \item{\code{\link{if_switch_linter}}} \item{\code{\link{implicit_assignment_linter}}} \item{\code{\link{indentation_linter}}} \item{\code{\link{infix_spaces_linter}}} \item{\code{\link{inner_combine_linter}}} \item{\code{\link{is_numeric_linter}}} \item{\code{\link{keyword_quote_linter}}} \item{\code{\link{length_levels_linter}}} \item{\code{\link{lengths_linter}}} \item{\code{\link{library_call_linter}}} \item{\code{\link{line_length_linter}}} \item{\code{\link{matrix_apply_linter}}} \item{\code{\link{nested_ifelse_linter}}} \item{\code{\link{nested_pipe_linter}}} \item{\code{\link{numeric_leading_zero_linter}}} \item{\code{\link{object_length_linter}}} \item{\code{\link{object_overwrite_linter}}} \item{\code{\link{object_usage_linter}}} \item{\code{\link{one_call_pipe_linter}}} \item{\code{\link{outer_negation_linter}}} \item{\code{\link{paren_body_linter}}} \item{\code{\link{pipe_call_linter}}} \item{\code{\link{pipe_consistency_linter}}} \item{\code{\link{pipe_continuation_linter}}} \item{\code{\link{quotes_linter}}} \item{\code{\link{redundant_equals_linter}}} \item{\code{\link{rep_len_linter}}} \item{\code{\link{repeat_linter}}} \item{\code{\link{sample_int_linter}}} \item{\code{\link{scalar_in_linter}}} \item{\code{\link{semicolon_linter}}} \item{\code{\link{sort_linter}}} \item{\code{\link{spaces_inside_linter}}} \item{\code{\link{spaces_left_parentheses_linter}}} \item{\code{\link{stopifnot_all_linter}}} \item{\code{\link{string_boundary_linter}}} \item{\code{\link{system_file_linter}}} \item{\code{\link{T_and_F_symbol_linter}}} \item{\code{\link{unnecessary_concatenation_linter}}} \item{\code{\link{unnecessary_lambda_linter}}} \item{\code{\link{unnecessary_nesting_linter}}} \item{\code{\link{unnecessary_placeholder_linter}}} \item{\code{\link{unreachable_code_linter}}} \item{\code{\link{which_grepl_linter}}} \item{\code{\link{yoda_test_linter}}} } } lintr/man/condition_message_linter.Rd0000644000176200001440000000317414752731051017525 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/condition_message_linter.R \name{condition_message_linter} \alias{condition_message_linter} \title{Block usage of \code{paste()} and \code{paste0()} with messaging functions using \code{...}} \usage{ condition_message_linter() } \description{ This linter discourages combining condition functions like \code{\link[=stop]{stop()}} with string concatenation functions \code{\link[=paste]{paste()}} and \code{\link[=paste0]{paste0()}}. This is because \itemize{ \item \code{stop(paste0(...))} is redundant as it is exactly equivalent to \code{stop(...)} \item \code{stop(paste(...))} is similarly equivalent to \code{stop(...)} with separators (see examples) } The same applies to the other default condition functions as well, i.e., \code{\link[=warning]{warning()}}, \code{\link[=message]{message()}}, and \code{\link[=packageStartupMessage]{packageStartupMessage()}}. } \examples{ # will produce lints lint( text = 'stop(paste("a string", "another"))', linters = condition_message_linter() ) lint( text = 'warning(paste0("a string", " another"))', linters = condition_message_linter() ) # okay lint( text = 'stop("a string", " another")', linters = condition_message_linter() ) lint( text = 'warning("a string", " another")', linters = condition_message_linter() ) lint( text = 'warning(paste("a string", "another", sep = "-"))', linters = condition_message_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency} } lintr/man/for_loop_index_linter.Rd0000644000176200001440000000177014752731051017041 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/for_loop_index_linter.R \name{for_loop_index_linter} \alias{for_loop_index_linter} \title{Block usage of for loops directly overwriting the indexing variable} \usage{ for_loop_index_linter() } \description{ \verb{for (x in x)} is a poor choice of indexing variable. This overwrites \code{x} in the calling scope and is confusing to read. } \examples{ # will produce lints lint( text = "for (x in x) { TRUE }", linters = for_loop_index_linter() ) lint( text = "for (x in foo(x, y)) { TRUE }", linters = for_loop_index_linter() ) # okay lint( text = "for (xi in x) { TRUE }", linters = for_loop_index_linter() ) lint( text = "for (col in DF$col) { TRUE }", linters = for_loop_index_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=readability_linters]{readability}, \link[=robustness_linters]{robustness} } lintr/man/object_length_linter.Rd0000644000176200001440000000311414752731051016634 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/object_length_linter.R \name{object_length_linter} \alias{object_length_linter} \title{Object length linter} \usage{ object_length_linter(length = 30L) } \arguments{ \item{length}{maximum variable name length allowed.} } \description{ Check that object names are not too long. The length of an object name is defined as the length in characters, after removing extraneous parts: } \details{ \itemize{ \item generic prefixes for implementations of S3 generics, e.g. \code{as.data.frame.my_class} has length 8. \item leading \code{.}, e.g. \code{.my_hidden_function} has length 18. \item "\%\%" for infix operators, e.g. \verb{\%my_op\%} has length 5. \item trailing \verb{<-} for assignment functions, e.g. \verb{my_attr<-} has length 7. } Note that this behavior relies in part on having packages in your Imports available; see the detailed note in \code{\link[=object_name_linter]{object_name_linter()}} for more details. } \examples{ # will produce lints lint( text = "very_very_long_variable_name <- 1L", linters = object_length_linter(length = 10L) ) # okay lint( text = "very_very_long_variable_name <- 1L", linters = object_length_linter(length = 30L) ) lint( text = "var <- 1L", linters = object_length_linter(length = 10L) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=default_linters]{default}, \link[=executing_linters]{executing}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/scalar_in_linter.Rd0000644000176200001440000000240014752731051015755 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scalar_in_linter.R \name{scalar_in_linter} \alias{scalar_in_linter} \title{Block usage like x \%in\% "a"} \usage{ scalar_in_linter(in_operators = NULL) } \arguments{ \item{in_operators}{Character vector of additional infix operators that behave like the \code{\%in\%} operator, e.g. \code{{data.table}}'s \verb{\%chin\%} operator.} } \description{ \code{vector \%in\% set} is appropriate for matching a vector to a set, but if that set has size 1, \code{==} is more appropriate. } \details{ \code{scalar \%in\% vector} is OK, because the alternative (\code{any(vector == scalar)}) is more circuitous & potentially less clear. } \examples{ # will produce lints lint( text = "x \%in\% 1L", linters = scalar_in_linter() ) lint( text = "x \%chin\% 'a'", linters = scalar_in_linter(in_operators = "\%chin\%") ) # okay lint( text = "x \%in\% 1:10", linters = scalar_in_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/default_undesirable_functions.Rd0000644000176200001440000001411014752731051020537 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/zzz.R \docType{data} \name{all_undesirable_functions} \alias{all_undesirable_functions} \alias{default_undesirable_functions} \alias{all_undesirable_operators} \alias{default_undesirable_operators} \title{Default undesirable functions and operators} \format{ A named list of character strings. } \usage{ all_undesirable_functions default_undesirable_functions all_undesirable_operators default_undesirable_operators } \description{ Lists of function names and operators for \code{\link[=undesirable_function_linter]{undesirable_function_linter()}} and \code{\link[=undesirable_operator_linter]{undesirable_operator_linter()}}. There is a list for the default elements and another that contains all available elements. Use \code{\link[=modify_defaults]{modify_defaults()}} to produce a custom list. } \keyword{datasets} \details{ The following functions are sometimes regarded as undesirable: \itemize{ \item \code{\link[=.libPaths]{.libPaths()}} As an alternative, use \code{\link[withr:with_libpaths]{withr::with_libpaths()}} for a temporary change instead of permanently modifying the library location. \item \code{\link[=attach]{attach()}} As an alternative, use roxygen2's @importFrom statement in packages, or \code{::} in scripts. \code{\link[=attach]{attach()}} modifies the global search path. \item \code{\link[=browser]{browser()}} As an alternative, remove this likely leftover from debugging. It pauses execution when run. \item \code{\link[=debug]{debug()}} As an alternative, remove this likely leftover from debugging. It traps a function and causes execution to pause when that function is run. \item \code{\link[=debugcall]{debugcall()}} As an alternative, remove this likely leftover from debugging. It traps a function and causes execution to pause when that function is run. \item \code{\link[=debugonce]{debugonce()}} As an alternative, remove this likely leftover from debugging. It traps a function and causes execution to pause when that function is run. \item \code{\link[=detach]{detach()}} As an alternative, avoid modifying the global search path. Detaching environments from the search path is rarely necessary in production code. \item \code{\link[=library]{library()}} As an alternative, use roxygen2's @importFrom statement in packages and \code{::} in scripts, instead of modifying the global search path. \item \code{\link[=mapply]{mapply()}} As an alternative, use \code{\link[=Map]{Map()}} to guarantee a list is returned and simplify accordingly. \item \code{\link[=options]{options()}} As an alternative, use \code{\link[withr:with_options]{withr::with_options()}} for a temporary change instead of permanently modifying the session options. \item \code{\link[=par]{par()}} As an alternative, use \code{\link[withr:with_par]{withr::with_par()}} for a temporary change instead of permanently modifying the graphics device parameters. \item \code{\link[=require]{require()}} As an alternative, use roxygen2's @importFrom statement in packages and \code{\link[=library]{library()}} or \code{::} in scripts, instead of modifying the global search path. \item \code{\link[=sapply]{sapply()}} As an alternative, use \code{\link[=vapply]{vapply()}} with an appropriate \code{FUN.VALUE=} argument to obtain type-stable simplification. \item \code{\link[=setwd]{setwd()}} As an alternative, use \code{\link[withr:with_dir]{withr::with_dir()}} for a temporary change instead of modifying the global working directory. \item \code{\link[=sink]{sink()}} As an alternative, use \code{\link[withr:with_sink]{withr::with_sink()}} for a temporary redirection instead of permanently redirecting output. \item \code{\link[=source]{source()}} As an alternative, manage dependencies through packages. \code{\link[=source]{source()}} loads code into the global environment unless \code{local = TRUE} is used, which can cause hard-to-predict behavior. \item \code{\link[=structure]{structure()}} As an alternative, Use \code{class<-}, \code{names<-}, and \code{attr<-} to set attributes. \item \code{\link[=Sys.setenv]{Sys.setenv()}} As an alternative, use \code{\link[withr:with_envvar]{withr::with_envvar()}} for a temporary change instead of permanently modifying global environment variables. \item \code{\link[=Sys.setlocale]{Sys.setlocale()}} As an alternative, use \code{\link[withr:with_locale]{withr::with_locale()}} for a temporary change instead of permanently modifying the session locale. \item \code{\link[=trace]{trace()}} As an alternative, remove this likely leftover from debugging. It traps a function and causes execution of arbitrary code when that function is run. \item \code{\link[=undebug]{undebug()}} As an alternative, remove this likely leftover from debugging. It is only useful for interactive debugging with \code{\link[=debug]{debug()}}. \item \code{\link[=untrace]{untrace()}} As an alternative, remove this likely leftover from debugging. It is only useful for interactive debugging with \code{\link[=trace]{trace()}}. } The following operators are sometimes regarded as undesirable: \itemize{ \item \code{\link[base:assignOps]{<<-}}. It assigns outside the current environment in a way that can be hard to reason about. Prefer fully-encapsulated functions wherever possible, or, if necessary, assign to a specific environment with \code{\link[=assign]{assign()}}. Recall that you can create an environment at the desired scope with \code{\link[=new.env]{new.env()}}. \item \code{\link[base:ns-dblcolon]{:::}}. It accesses non-exported functions inside packages. Code relying on these is likely to break in future versions of the package because the functions are not part of the public interface and may be changed or removed by the maintainers without notice. Use public functions via \code{::} instead. \item \code{\link[base:assignOps]{<<-}}. It assigns outside the current environment in a way that can be hard to reason about. Prefer fully-encapsulated functions wherever possible, or, if necessary, assign to a specific environment with \code{\link[=assign]{assign()}}. Recall that you can create an environment at the desired scope with \code{\link[=new.env]{new.env()}}. } } lintr/man/infix_spaces_linter.Rd0000644000176200001440000000462714752731051016512 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/infix_spaces_linter.R \name{infix_spaces_linter} \alias{infix_spaces_linter} \title{Infix spaces linter} \usage{ infix_spaces_linter(exclude_operators = NULL, allow_multiple_spaces = TRUE) } \arguments{ \item{exclude_operators}{Character vector of operators to exclude from consideration for linting. Default is to include the following "low-precedence" operators: \code{+}, \code{-}, \code{~}, \code{>}, \code{>=}, \code{<}, \code{<=}, \code{==}, \code{!=}, \code{&}, \code{&&}, \code{|}, \code{||}, \verb{<-}, \verb{:=}, \verb{<<-}, \verb{->}, \verb{->>}, \code{=}, \code{/}, \code{*}, and any infix operator (exclude infixes by passing \code{"\%\%"}). Note that \code{"="} here includes three different operators, from the parser's point of view. To lint only some of these, pass the corresponding parse tags (i.e., some of \code{"EQ_ASSIGN"}, \code{"EQ_SUB"}, and \code{"EQ_FORMALS"}; see \code{\link[utils:getParseData]{utils::getParseData()}}).} \item{allow_multiple_spaces}{Logical, default \code{TRUE}. If \code{FALSE}, usage like \code{x = 2} will also be linted; excluded by default because such usage can sometimes be used for better code alignment, as is allowed by the style guide.} } \description{ Check that infix operators are surrounded by spaces. Enforces the corresponding Tidyverse style guide rule; see \url{https://style.tidyverse.org/syntax.html#infix-operators}. } \examples{ # will produce lints lint( text = "x<-1L", linters = infix_spaces_linter() ) lint( text = "1:4 \%>\%sum()", linters = infix_spaces_linter() ) # okay lint( text = "x <- 1L", linters = infix_spaces_linter() ) lint( text = "1:4 \%>\% sum()", linters = infix_spaces_linter() ) code_lines <- " ab <- 1L abcdef <- 2L " writeLines(code_lines) lint( text = code_lines, linters = infix_spaces_linter(allow_multiple_spaces = TRUE) ) lint( text = "a||b", linters = infix_spaces_linter(exclude_operators = "||") ) lint( text = "sum(1:10, na.rm=TRUE)", linters = infix_spaces_linter(exclude_operators = "EQ_SUB") ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#infix-operators} } } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/nzchar_linter.Rd0000644000176200001440000000262414752731051015317 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/nzchar_linter.R \name{nzchar_linter} \alias{nzchar_linter} \title{Require usage of nzchar where appropriate} \usage{ nzchar_linter() } \description{ \code{\link[=nzchar]{nzchar()}} efficiently determines which of a vector of strings are empty (i.e., are \code{""}). It should in most cases be used instead of constructions like \code{string == ""} or \code{nchar(string) == 0}. } \details{ One crucial difference is in the default handling of \code{NA_character_}, i.e., missing strings. \code{nzchar(NA_character_)} is \code{TRUE}, while \code{NA_character_ == ""} and \code{nchar(NA_character_) == 0} are both \code{NA}. Therefore, for strict compatibility, use \code{nzchar(x, keepNA = TRUE)}. If the input is known to be complete (no missing entries), this argument can be dropped for conciseness. } \examples{ # will produce lints lint( text = "x[x == '']", linters = nzchar_linter() ) lint( text = "x[nchar(x) > 0]", linters = nzchar_linter() ) # okay lint( text = "x[!nzchar(x, keepNA = TRUE)]", linters = nzchar_linter() ) lint( text = "x[nzchar(x, keepNA = TRUE)]", linters = nzchar_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=efficiency_linters]{efficiency} } lintr/man/numeric_leading_zero_linter.Rd0000644000176200001440000000166314752731051020220 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/numeric_leading_zero_linter.R \name{numeric_leading_zero_linter} \alias{numeric_leading_zero_linter} \title{Require usage of a leading zero in all fractional numerics} \usage{ numeric_leading_zero_linter() } \description{ While .1 and 0.1 mean the same thing, the latter is easier to read due to the small size of the '.' glyph. } \examples{ # will produce lints lint( text = "x <- .1", linters = numeric_leading_zero_linter() ) lint( text = "x <- -.1", linters = numeric_leading_zero_linter() ) # okay lint( text = "x <- 0.1", linters = numeric_leading_zero_linter() ) lint( text = "x <- -0.1", linters = numeric_leading_zero_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/pipe_return_linter.Rd0000644000176200001440000000206214752731051016362 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/pipe_return_linter.R \name{pipe_return_linter} \alias{pipe_return_linter} \title{Block usage of return() in magrittr pipelines} \usage{ pipe_return_linter() } \description{ \code{\link[=return]{return()}} inside a magrittr pipeline does not actually execute \code{return()} like you'd expect: \verb{\\(x) \{ x \%>\% return(); FALSE \}} will return \code{FALSE}! It will technically work "as expected" if this is the final statement in the function body, but such usage is misleading. Instead, assign the pipe outcome to a variable and return that. } \examples{ # will produce lints lint( text = "function(x) x \%>\% return()", linters = pipe_return_linter() ) # okay code <- "function(x) {\n y <- sum(x)\n return(y)\n}" writeLines(code) lint( text = code, linters = pipe_return_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=common_mistakes_linters]{common_mistakes} } lintr/man/object_usage_linter.Rd0000644000176200001440000000364314752731051016466 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/object_usage_linter.R \name{object_usage_linter} \alias{object_usage_linter} \title{Object usage linter} \usage{ object_usage_linter(interpret_glue = TRUE, skip_with = TRUE) } \arguments{ \item{interpret_glue}{If \code{TRUE}, interpret \code{\link[glue:glue]{glue::glue()}} calls to avoid false positives caused by local variables which are only used in a glue expression.} \item{skip_with}{A logical. If \code{TRUE} (default), code in \code{with()} expressions will be skipped. This argument will be passed to \code{skipWith} argument of \code{codetools::checkUsage()}.} } \description{ Check that closures have the proper usage using \code{\link[codetools:checkUsage]{codetools::checkUsage()}}. Note that this runs \code{\link[base:eval]{base::eval()}} on the code, so \strong{do not use with untrusted code}. } \examples{ # will produce lints lint( text = "foo <- function() { x <- 1 }", linters = object_usage_linter() ) # okay lint( text = "foo <- function(x) { x <- 1 }", linters = object_usage_linter() ) lint( text = "foo <- function() { x <- 1; return(x) }", linters = object_usage_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'package_development': \itemize{ \item{\code{\link{backport_linter}}} \item{\code{\link{conjunct_test_linter}}} \item{\code{\link{expect_comparison_linter}}} \item{\code{\link{expect_identical_linter}}} \item{\code{\link{expect_length_linter}}} \item{\code{\link{expect_named_linter}}} \item{\code{\link{expect_not_linter}}} \item{\code{\link{expect_null_linter}}} \item{\code{\link{expect_s3_class_linter}}} \item{\code{\link{expect_s4_class_linter}}} \item{\code{\link{expect_true_false_linter}}} \item{\code{\link{expect_type_linter}}} \item{\code{\link{package_hooks_linter}}} \item{\code{\link{yoda_test_linter}}} } } lintr/man/comparison_negation_linter.Rd0000644000176200001440000000204514752731051020065 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/comparison_negation_linter.R \name{comparison_negation_linter} \alias{comparison_negation_linter} \title{Block usages like !(x == y) where a direct relational operator is appropriate} \usage{ comparison_negation_linter() } \description{ \code{!(x == y)} is more readably expressed as \code{x != y}. The same is true of other negations of simple comparisons like \code{!(x > y)} and \code{!(x <= y)}. } \examples{ # will produce lints lint( text = "!x == 2", linters = comparison_negation_linter() ) lint( text = "!(x > 2)", linters = comparison_negation_linter() ) # okay lint( text = "!(x == 2 & y > 2)", linters = comparison_negation_linter() ) lint( text = "!(x & y)", linters = comparison_negation_linter() ) lint( text = "x != 2", linters = comparison_negation_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=consistency_linters]{consistency}, \link[=readability_linters]{readability} } lintr/man/parse_exclusions.Rd0000644000176200001440000000271014752731051016037 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/exclude.R \name{parse_exclusions} \alias{parse_exclusions} \title{read a source file and parse all the excluded lines from it} \usage{ parse_exclusions( file, exclude = settings$exclude, exclude_next = settings$exclude_next, exclude_start = settings$exclude_start, exclude_end = settings$exclude_end, exclude_linter = settings$exclude_linter, exclude_linter_sep = settings$exclude_linter_sep, lines = NULL, linter_names = NULL ) } \arguments{ \item{file}{R source file} \item{exclude}{Regular expression used to mark lines to exclude.} \item{exclude_next}{Regular expression used to mark lines immediately preceding excluded lines.} \item{exclude_start}{Regular expression used to mark the start of an excluded range.} \item{exclude_end}{Regular expression used to mark the end of an excluded range.} \item{exclude_linter}{Regular expression used to capture a list of to-be-excluded linters immediately following a \code{exclude} or \code{exclude_start} marker.} \item{exclude_linter_sep}{Regular expression used to split a linter list into individual linter names for exclusion.} \item{lines}{A character vector of the content lines of \code{file}.} \item{linter_names}{Names of active linters.} } \value{ A possibly named list of excluded lines, possibly for specific linters. } \description{ read a source file and parse all the excluded lines from it } \keyword{internal} lintr/man/consecutive_mutate_linter.Rd0000644000176200001440000000330114752731051017731 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/consecutive_mutate_linter.R \name{consecutive_mutate_linter} \alias{consecutive_mutate_linter} \title{Require consecutive calls to mutate() to be combined when possible} \usage{ consecutive_mutate_linter(invalid_backends = "dbplyr") } \arguments{ \item{invalid_backends}{Character vector of packages providing dplyr backends which may not be compatible with combining \code{mutate()} calls in all cases. Defaults to \code{"dbplyr"} since not all SQL backends can handle re-using a variable defined in the same \code{mutate()} expression.} } \description{ \code{dplyr::mutate()} accepts any number of columns, so sequences like \code{DF \%>\% dplyr::mutate(..1) \%>\% dplyr::mutate(..2)} are redundant -- they can always be expressed with a single call to \code{dplyr::mutate()}. } \details{ An exception is for some SQL back-ends, where the translation logic may not be as sophisticated as that in the default \code{dplyr}, for example in \code{DF \%>\% mutate(a = a + 1) \%>\% mutate(b = a - 2)}. } \examples{ # will produce lints lint( text = "x \%>\% mutate(a = 1) \%>\% mutate(b = 2)", linters = consecutive_mutate_linter() ) # okay lint( text = "x \%>\% mutate(a = 1, b = 2)", linters = consecutive_mutate_linter() ) code <- "library(dbplyr)\nx \%>\% mutate(a = 1) \%>\% mutate(a = a + 1)" writeLines(code) lint( text = code, linters = consecutive_mutate_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=efficiency_linters]{efficiency}, \link[=readability_linters]{readability} } lintr/man/assignment_linter.Rd0000644000176200001440000000536314752731051016205 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/assignment_linter.R \name{assignment_linter} \alias{assignment_linter} \title{Assignment linter} \usage{ assignment_linter( operator = c("<-", "<<-"), allow_cascading_assign = TRUE, allow_right_assign = FALSE, allow_trailing = TRUE, allow_pipe_assign = FALSE ) } \arguments{ \item{operator}{Character vector of valid assignment operators. Defaults to allowing \verb{<-} and \verb{<<-}; other valid options are \code{=}, \verb{->}, \verb{->>}, \verb{\%<>\%}; use \code{"any"} to denote "allow all operators", in which case this linter only considers \code{allow_trailing} for generating lints.} \item{allow_cascading_assign}{(Deprecated) Logical, default \code{TRUE}. If \code{FALSE}, \code{\link[base:assignOps]{<<-}} and \verb{->>} are not allowed.} \item{allow_right_assign}{(Deprecated) Logical, default \code{FALSE}. If \code{TRUE}, \verb{->} and \verb{->>} are allowed.} \item{allow_trailing}{Logical, default \code{TRUE}. If \code{FALSE} then assignments aren't allowed at end of lines.} \item{allow_pipe_assign}{(Deprecated) Logical, default \code{FALSE}. If \code{TRUE}, magrittr's \verb{\%<>\%} assignment is allowed.} } \description{ Check that the specified operator is used for assignment. } \examples{ # will produce lints lint( text = "x = mean(x)", linters = assignment_linter() ) code_lines <- "1 -> x\n2 ->> y" writeLines(code_lines) lint( text = code_lines, linters = assignment_linter() ) lint( text = "x \%<>\% as.character()", linters = assignment_linter() ) lint( text = "x <- 1", linters = assignment_linter(operator = "=") ) # okay lint( text = "x <- mean(x)", linters = assignment_linter() ) code_lines <- "x <- 1\ny <<- 2" writeLines(code_lines) lint( text = code_lines, linters = assignment_linter() ) # customizing using arguments code_lines <- "1 -> x\n2 ->> y" writeLines(code_lines) lint( text = code_lines, linters = assignment_linter(allow_right_assign = TRUE) ) lint( text = "x <<- 1", linters = assignment_linter(allow_cascading_assign = FALSE) ) writeLines("foo(bar = \n 1)") lint( text = "foo(bar = \n 1)", linters = assignment_linter(allow_trailing = FALSE) ) lint( text = "x \%<>\% as.character()", linters = assignment_linter(allow_pipe_assign = TRUE) ) lint( text = "x = 1", linters = assignment_linter(operator = "=") ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#assignment-1} \item \url{https://style.tidyverse.org/pipes.html#assignment-2} } } \section{Tags}{ \link[=configurable_linters]{configurable}, \link[=consistency_linters]{consistency}, \link[=default_linters]{default}, \link[=style_linters]{style} } lintr/man/unused_import_linter.Rd0000644000176200001440000000356614752731051016735 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/unused_import_linter.R \name{unused_import_linter} \alias{unused_import_linter} \title{Check that imported packages are actually used} \usage{ unused_import_linter( allow_ns_usage = FALSE, except_packages = c("bit64", "data.table", "tidyverse"), interpret_glue = TRUE ) } \arguments{ \item{allow_ns_usage}{Suppress lints for packages only used via namespace. This is \code{FALSE} by default because \code{pkg::fun()} doesn't require \code{library(pkg)}. You can use \link[=requireNamespace]{requireNamespace("pkg")} to ensure a package is installed without attaching it.} \item{except_packages}{Character vector of packages that are ignored. These are usually attached for their side effects.} \item{interpret_glue}{If \code{TRUE}, interpret \code{\link[glue:glue]{glue::glue()}} calls to avoid false positives caused by local variables which are only used in a glue expression.} } \description{ Check that imported packages are actually used } \examples{ # will produce lints code_lines <- "library(dplyr)\n1 + 1" writeLines(code_lines) lint( text = code_lines, linters = unused_import_linter() ) code_lines <- "library(dplyr)\ndplyr::tibble(a = 1)" writeLines(code_lines) lint( text = code_lines, linters = unused_import_linter() ) # okay code_lines <- "library(dplyr)\ntibble(a = 1)" writeLines(code_lines) lint( text = code_lines, linters = unused_import_linter() ) code_lines <- "library(dplyr)\ndplyr::tibble(a = 1)" writeLines(code_lines) lint( text = code_lines, linters = unused_import_linter(allow_ns_usage = TRUE) ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=common_mistakes_linters]{common_mistakes}, \link[=configurable_linters]{configurable}, \link[=executing_linters]{executing} } lintr/man/seq_linter.Rd0000644000176200001440000000305214752731051014616 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/seq_linter.R \name{seq_linter} \alias{seq_linter} \title{Sequence linter} \usage{ seq_linter() } \description{ This linter checks for \code{1:length(...)}, \code{1:nrow(...)}, \code{1:ncol(...)}, \code{1:NROW(...)} and \code{1:NCOL(...)} expressions in base-R, or their usage in conjunction with \code{seq()} (e.g., \code{seq(length(...))}, \code{seq(nrow(...))}, etc.). } \details{ Additionally, it checks for \code{1:n()} (from \code{{dplyr}}) and \code{1:.N} (from \code{{data.table}}). These often cause bugs when the right-hand side is zero. Instead, it is safer to use \code{\link[base:seq]{base::seq_len()}} (to create a sequence of a specified \emph{length}) or \code{\link[base:seq]{base::seq_along()}} (to create a sequence \emph{along} an object). } \examples{ # will produce lints lint( text = "seq(length(x))", linters = seq_linter() ) lint( text = "1:nrow(x)", linters = seq_linter() ) lint( text = "dplyr::mutate(x, .id = 1:n())", linters = seq_linter() ) # okay lint( text = "seq_along(x)", linters = seq_linter() ) lint( text = "seq_len(nrow(x))", linters = seq_linter() ) lint( text = "dplyr::mutate(x, .id = seq_len(n()))", linters = seq_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=consistency_linters]{consistency}, \link[=default_linters]{default}, \link[=efficiency_linters]{efficiency}, \link[=robustness_linters]{robustness} } lintr/man/clear_cache.Rd0000644000176200001440000000076714752731051014674 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/cache.R \name{clear_cache} \alias{clear_cache} \title{Clear the lintr cache} \usage{ clear_cache(file = NULL, path = NULL) } \arguments{ \item{file}{filename whose cache to clear. If you pass \code{NULL}, it will delete all of the caches.} \item{path}{directory to store caches. Reads option 'lintr.cache_directory' as the default.} } \value{ 0 for success, 1 for failure, invisibly. } \description{ Clear the lintr cache } lintr/man/function_left_parentheses_linter.Rd0000644000176200001440000000260114752731051021265 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/function_left_parentheses_linter.R \name{function_left_parentheses_linter} \alias{function_left_parentheses_linter} \title{Function left parentheses linter} \usage{ function_left_parentheses_linter() } \description{ Check that all left parentheses in a function call do not have spaces before them (e.g. \code{mean (1:3)}). Although this is syntactically valid, it makes the code difficult to read. } \details{ Exceptions are made for control flow functions (\code{if}, \code{for}, etc.). } \examples{ # will produce lints lint( text = "mean (x)", linters = function_left_parentheses_linter() ) lint( text = "stats::sd(c (x, y, z))", linters = function_left_parentheses_linter() ) # okay lint( text = "mean(x)", linters = function_left_parentheses_linter() ) lint( text = "stats::sd(c(x, y, z))", linters = function_left_parentheses_linter() ) lint( text = "foo <- function(x) (x + 1)", linters = function_left_parentheses_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#parentheses} \item \code{\link[=spaces_left_parentheses_linter]{spaces_left_parentheses_linter()}} } } \section{Tags}{ \link[=default_linters]{default}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/expect_null_linter.Rd0000644000176200001440000000255514752731051016357 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/expect_null_linter.R \name{expect_null_linter} \alias{expect_null_linter} \title{Require usage of \code{expect_null} for checking \code{NULL}} \usage{ expect_null_linter() } \description{ Require usage of \code{expect_null(x)} over \code{expect_equal(x, NULL)} and similar usages. } \details{ \code{\link[testthat:expect_null]{testthat::expect_null()}} exists specifically for testing for \code{NULL} objects. \code{\link[testthat:equality-expectations]{testthat::expect_equal()}}, \code{\link[testthat:equality-expectations]{testthat::expect_identical()}}, and \code{\link[testthat:logical-expectations]{testthat::expect_true()}} can also be used for such tests, but it is better to use the tailored function instead. } \examples{ # will produce lints lint( text = "expect_equal(x, NULL)", linters = expect_null_linter() ) lint( text = "expect_identical(x, NULL)", linters = expect_null_linter() ) lint( text = "expect_true(is.null(x))", linters = expect_null_linter() ) # okay lint( text = "expect_null(x)", linters = expect_null_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat} } lintr/man/xp_call_name.Rd0000644000176200001440000000310214752731051015067 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/xp_utils.R \name{xp_call_name} \alias{xp_call_name} \title{Get the name of the function matched by an XPath} \usage{ xp_call_name(expr, depth = 1L, condition = NULL) } \arguments{ \item{expr}{An \code{xml_node} or \code{xml_nodeset}, e.g. from \code{\link[xml2:xml_find_all]{xml2::xml_find_all()}}.} \item{depth}{Integer, default \code{1L}. How deep in the AST represented by \code{expr} should we look to find the call? By default, we assume \code{expr} is matched to an \verb{} node under which the corresponding \verb{} node is found directly. \code{depth = 0L} means \code{expr} is matched directly to the \code{SYMBOL_FUNCTION_CALL}; \code{depth > 1L} means \code{depth} total \verb{} nodes must be traversed before finding the call.} \item{condition}{An additional (XPath condition on the \code{SYMBOL_FUNCTION_CALL} required for a match. The default (\code{NULL}) is no condition. See examples.} } \description{ Often, it is more helpful to tailor the \code{message} of a lint to record which function was matched by the lint logic. This function encapsulates the logic to pull out the matched call in common situations. } \examples{ xml_from_code <- function(str) { xml2::read_xml(xmlparsedata::xml_parse_data(parse(text = str, keep.source = TRUE))) } xml <- xml_from_code("sum(1:10)") xp_call_name(xml, depth = 2L) xp_call_name(xml2::xml_find_first(xml, "expr")) xml <- xml_from_code(c("sum(1:10)", "sd(1:10)")) xp_call_name(xml, depth = 2L, condition = "text() = 'sum'") } lintr/man/common_mistakes_linters.Rd0000644000176200001440000000160714752731051017405 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{common_mistakes_linters} \alias{common_mistakes_linters} \title{Common mistake linters} \description{ Linters highlighting common mistakes, such as duplicate arguments. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'common_mistakes': \itemize{ \item{\code{\link{duplicate_argument_linter}}} \item{\code{\link{equals_na_linter}}} \item{\code{\link{length_test_linter}}} \item{\code{\link{list_comparison_linter}}} \item{\code{\link{missing_argument_linter}}} \item{\code{\link{missing_package_linter}}} \item{\code{\link{pipe_return_linter}}} \item{\code{\link{redundant_equals_linter}}} \item{\code{\link{sprintf_linter}}} \item{\code{\link{unused_import_linter}}} \item{\code{\link{vector_logic_linter}}} } } lintr/man/expect_identical_linter.Rd0000644000176200001440000000430514752731051017334 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/expect_identical_linter.R \name{expect_identical_linter} \alias{expect_identical_linter} \title{Require usage of \code{expect_identical(x, y)} where appropriate} \usage{ expect_identical_linter() } \description{ This linter enforces the usage of \code{\link[testthat:equality-expectations]{testthat::expect_identical()}} as the default expectation for comparisons in a testthat suite. \code{expect_true(identical(x, y))} is an equivalent but unadvised method of the same test. Further, \code{\link[testthat:equality-expectations]{testthat::expect_equal()}} should only be used when \code{expect_identical()} is inappropriate, i.e., when \code{x} and \code{y} need only be \emph{numerically equivalent} instead of fully identical (in which case, provide the \verb{tolerance=} argument to \code{expect_equal()} explicitly). This also applies when it's inconvenient to check full equality (e.g., names can be ignored, in which case \code{ignore_attr = "names"} should be supplied to \code{expect_equal()} (or, for 2nd edition, \code{check.attributes = FALSE}). } \section{Exceptions}{ The linter allows \code{expect_equal()} in three circumstances: \enumerate{ \item A named argument is set (e.g. \code{ignore_attr} or \code{tolerance}) \item Comparison is made to an explicit decimal, e.g. \code{expect_equal(x, 1.0)} (implicitly setting \code{tolerance}) \item \code{...} is passed (wrapper functions which might set arguments such as \code{ignore_attr} or \code{tolerance}) } } \examples{ # will produce lints lint( text = "expect_equal(x, y)", linters = expect_identical_linter() ) lint( text = "expect_true(identical(x, y))", linters = expect_identical_linter() ) # okay lint( text = "expect_identical(x, y)", linters = expect_identical_linter() ) lint( text = "expect_equal(x, y, check.attributes = FALSE)", linters = expect_identical_linter() ) lint( text = "expect_equal(x, y, tolerance = 1e-6)", linters = expect_identical_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=package_development_linters]{package_development}, \link[=pkg_testthat_linters]{pkg_testthat} } lintr/man/library_call_linter.Rd0000644000176200001440000000466414752731051016477 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/library_call_linter.R \name{library_call_linter} \alias{library_call_linter} \title{Library call linter} \usage{ library_call_linter(allow_preamble = TRUE) } \arguments{ \item{allow_preamble}{Logical, default \code{TRUE}. If \code{FALSE}, no code is allowed to precede the first \code{library()} call, otherwise some setup code is allowed, but all \code{library()} calls must follow consecutively after the first one.} } \description{ This linter covers several rules related to \code{\link[=library]{library()}} calls: } \details{ \itemize{ \item Enforce such calls to all be at the top of the script. \item Block usage of argument \code{character.only}, in particular for loading packages in a loop. \item Block consecutive calls to \code{suppressMessages(library(.))} in favor of using \code{\link[=suppressMessages]{suppressMessages()}} only once to suppress messages from all \code{library()} calls. Ditto \code{\link[=suppressPackageStartupMessages]{suppressPackageStartupMessages()}}. } } \examples{ # will produce lints code <- "library(dplyr)\nprint('test')\nlibrary(tidyr)" writeLines(code) lint( text = code, linters = library_call_linter() ) lint( text = "library('dplyr', character.only = TRUE)", linters = library_call_linter() ) code <- paste( "pkg <- c('dplyr', 'tibble')", "sapply(pkg, library, character.only = TRUE)", sep = "\n" ) writeLines(code) lint( text = code, linters = library_call_linter() ) code <- "suppressMessages(library(dplyr))\nsuppressMessages(library(tidyr))" writeLines(code) lint( text = code, linters = library_call_linter() ) # okay code <- "library(dplyr)\nprint('test')" writeLines(code) lint( text = code, linters = library_call_linter() ) code <- "# comment\nlibrary(dplyr)" lint( text = code, linters = library_call_linter() ) code <- paste( "foo <- function(pkg) {", " sapply(pkg, library, character.only = TRUE)", "}", sep = "\n" ) writeLines(code) lint( text = code, linters = library_call_linter() ) code <- "suppressMessages({\n library(dplyr)\n library(tidyr)\n})" writeLines(code) lint( text = code, linters = library_call_linter() ) } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=readability_linters]{readability}, \link[=style_linters]{style} } lintr/man/condition_call_linter.Rd0000644000176200001440000000361314752731051017012 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/condition_call_linter.R \name{condition_call_linter} \alias{condition_call_linter} \title{Recommend usage of \code{call. = FALSE} in conditions} \usage{ condition_call_linter(display_call = FALSE) } \arguments{ \item{display_call}{Logical specifying expected behavior regarding \code{call.} argument in conditions. \itemize{ \item \code{NA} forces providing \verb{call. =} but ignores its value (this can be used in cases where you expect a mix of \code{call. = FALSE} and \code{call. = TRUE}) \item \code{TRUE} lints \code{call. = FALSE} \item \code{FALSE} forces \code{call. = FALSE} (lints \code{call. = TRUE} or missing \verb{call. =} value) }} } \description{ This linter, with the default \code{display_call = FALSE}, enforces the recommendation of the tidyverse design guide regarding displaying error calls. } \examples{ # will produce lints lint( text = "stop('test')", linters = condition_call_linter() ) lint( text = "stop('test', call. = TRUE)", linters = condition_call_linter() ) lint( text = "stop('test', call. = FALSE)", linters = condition_call_linter(display_call = TRUE) ) lint( text = "stop('this is a', 'test', call. = FALSE)", linters = condition_call_linter(display_call = TRUE) ) # okay lint( text = "stop('test', call. = FALSE)", linters = condition_call_linter() ) lint( text = "stop('this is a', 'test', call. = FALSE)", linters = condition_call_linter() ) lint( text = "stop('test', call. = TRUE)", linters = condition_call_linter(display_call = TRUE) ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://design.tidyverse.org/err-call.html}> } } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=style_linters]{style}, \link[=tidy_design_linters]{tidy_design} } lintr/man/object_overwrite_linter.Rd0000644000176200001440000000376214752731051017412 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/object_overwrite_linter.R \name{object_overwrite_linter} \alias{object_overwrite_linter} \title{Block assigning any variables whose name clashes with a \code{base} R function} \usage{ object_overwrite_linter( packages = c("base", "stats", "utils", "tools", "methods", "graphics", "grDevices"), allow_names = character() ) } \arguments{ \item{packages}{Character vector of packages to search for names that should be avoided. Defaults to the most common default packages: base, stats, utils, tools, methods, graphics, and grDevices.} \item{allow_names}{Character vector of object names to ignore, i.e., which are allowed to collide with exports from \code{packages}.} } \description{ Re-using existing names creates a risk of subtle error best avoided. Avoiding this practice also encourages using better, more descriptive names. } \examples{ # will produce lints code <- "function(x) {\n data <- x\n data\n}" writeLines(code) lint( text = code, linters = object_overwrite_linter() ) code <- "function(x) {\n lint <- 'fun'\n lint\n}" writeLines(code) lint( text = code, linters = object_overwrite_linter(packages = "lintr") ) # okay code <- "function(x) {\n data('mtcars')\n}" writeLines(code) lint( text = code, linters = object_overwrite_linter() ) code <- "function(x) {\n data <- x\n data\n}" writeLines(code) lint( text = code, linters = object_overwrite_linter(packages = "base") ) # names in function signatures are ignored lint( text = "function(data) data <- subset(data, x > 0)", linters = object_overwrite_linter() ) } \seealso{ \itemize{ \item \link{linters} for a complete list of linters available in lintr. \item \url{https://style.tidyverse.org/syntax.html#object-names} } } \section{Tags}{ \link[=best_practices_linters]{best_practices}, \link[=configurable_linters]{configurable}, \link[=executing_linters]{executing}, \link[=readability_linters]{readability}, \link[=robustness_linters]{robustness} } lintr/man/configurable_linters.Rd0000644000176200001440000000434714752731051016661 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/linter_tag_docs.R \name{configurable_linters} \alias{configurable_linters} \title{Configurable linters} \description{ Generic linters which support custom configuration to your needs. } \seealso{ \link{linters} for a complete list of linters available in lintr. } \section{Linters}{ The following linters are tagged with 'configurable': \itemize{ \item{\code{\link{absolute_path_linter}}} \item{\code{\link{assignment_linter}}} \item{\code{\link{backport_linter}}} \item{\code{\link{brace_linter}}} \item{\code{\link{commas_linter}}} \item{\code{\link{condition_call_linter}}} \item{\code{\link{conjunct_test_linter}}} \item{\code{\link{consecutive_mutate_linter}}} \item{\code{\link{cyclocomp_linter}}} \item{\code{\link{duplicate_argument_linter}}} \item{\code{\link{fixed_regex_linter}}} \item{\code{\link{if_not_else_linter}}} \item{\code{\link{if_switch_linter}}} \item{\code{\link{implicit_assignment_linter}}} \item{\code{\link{implicit_integer_linter}}} \item{\code{\link{indentation_linter}}} \item{\code{\link{infix_spaces_linter}}} \item{\code{\link{library_call_linter}}} \item{\code{\link{line_length_linter}}} \item{\code{\link{missing_argument_linter}}} \item{\code{\link{namespace_linter}}} \item{\code{\link{nested_pipe_linter}}} \item{\code{\link{nonportable_path_linter}}} \item{\code{\link{object_length_linter}}} \item{\code{\link{object_name_linter}}} \item{\code{\link{object_overwrite_linter}}} \item{\code{\link{object_usage_linter}}} \item{\code{\link{paste_linter}}} \item{\code{\link{pipe_consistency_linter}}} \item{\code{\link{quotes_linter}}} \item{\code{\link{redundant_ifelse_linter}}} \item{\code{\link{return_linter}}} \item{\code{\link{scalar_in_linter}}} \item{\code{\link{semicolon_linter}}} \item{\code{\link{string_boundary_linter}}} \item{\code{\link{todo_comment_linter}}} \item{\code{\link{trailing_whitespace_linter}}} \item{\code{\link{undesirable_function_linter}}} \item{\code{\link{undesirable_operator_linter}}} \item{\code{\link{unnecessary_concatenation_linter}}} \item{\code{\link{unnecessary_lambda_linter}}} \item{\code{\link{unnecessary_nesting_linter}}} \item{\code{\link{unreachable_code_linter}}} \item{\code{\link{unused_import_linter}}} } } lintr/DESCRIPTION0000644000176200001440000001343714753133562013131 0ustar liggesusersPackage: lintr Title: A 'Linter' for R Code Version: 3.2.0 Authors@R: c( person("Jim", "Hester", , role = "aut"), person("Florent", "Angly", role = "aut", comment = "fangly"), person("Russ", "Hyde", role = "aut"), person("Michael", "Chirico", email = "michaelchirico4@gmail.com", role = c("aut", "cre")), person("Kun", "Ren", role = "aut"), person("Alexander", "Rosenstock", role = "aut", comment = "AshesITR"), person("Indrajeet", "Patil", , "patilindrajeet.science@gmail.com", role = "aut", comment = c(ORCID = "0000-0003-1995-6531", Twitter = "@patilindrajeets")) ) Description: Checks adherence to a given style, syntax errors and possible semantic issues. Supports on the fly checking of R code edited with 'RStudio IDE', 'Emacs', 'Vim', 'Sublime Text', 'Atom' and 'Visual Studio Code'. License: MIT + file LICENSE URL: https://lintr.r-lib.org, https://github.com/r-lib/lintr BugReports: https://github.com/r-lib/lintr/issues Depends: R (>= 4.0) Imports: backports (>= 1.4.0), cli (>= 3.4.0), codetools, digest, glue, knitr, rex, stats, utils, xml2 (>= 1.0.0), xmlparsedata (>= 1.0.5) Suggests: bookdown, cyclocomp, jsonlite, patrick (>= 0.2.0), rlang, rmarkdown, rstudioapi (>= 0.2), testthat (>= 3.2.1), tibble, tufte, withr (>= 2.5.0) Enhances: data.table VignetteBuilder: knitr Config/Needs/website: tidyverse/tidytemplate Config/Needs/development: pkgload, cli, testthat, patrick Config/testthat/edition: 3 Encoding: UTF-8 RoxygenNote: 7.3.2 Collate: 'make_linter_from_xpath.R' 'xp_utils.R' 'utils.R' 'AAA.R' 'T_and_F_symbol_linter.R' 'absolute_path_linter.R' 'actions.R' 'addins.R' 'any_duplicated_linter.R' 'any_is_na_linter.R' 'assignment_linter.R' 'backport_linter.R' 'boolean_arithmetic_linter.R' 'brace_linter.R' 'cache.R' 'class_equals_linter.R' 'commas_linter.R' 'commented_code_linter.R' 'comparison_negation_linter.R' 'condition_call_linter.R' 'condition_message_linter.R' 'conjunct_test_linter.R' 'consecutive_assertion_linter.R' 'consecutive_mutate_linter.R' 'cyclocomp_linter.R' 'declared_functions.R' 'deprecated.R' 'duplicate_argument_linter.R' 'empty_assignment_linter.R' 'equals_na_linter.R' 'exclude.R' 'expect_comparison_linter.R' 'expect_identical_linter.R' 'expect_length_linter.R' 'expect_lint.R' 'expect_named_linter.R' 'expect_not_linter.R' 'expect_null_linter.R' 'expect_s3_class_linter.R' 'expect_s4_class_linter.R' 'expect_true_false_linter.R' 'expect_type_linter.R' 'extract.R' 'fixed_regex_linter.R' 'for_loop_index_linter.R' 'function_argument_linter.R' 'function_left_parentheses_linter.R' 'function_return_linter.R' 'get_source_expressions.R' 'ids_with_token.R' 'if_not_else_linter.R' 'if_switch_linter.R' 'ifelse_censor_linter.R' 'implicit_assignment_linter.R' 'implicit_integer_linter.R' 'indentation_linter.R' 'infix_spaces_linter.R' 'inner_combine_linter.R' 'is_lint_level.R' 'is_numeric_linter.R' 'keyword_quote_linter.R' 'length_levels_linter.R' 'length_test_linter.R' 'lengths_linter.R' 'library_call_linter.R' 'line_length_linter.R' 'lint.R' 'linter_tag_docs.R' 'linter_tags.R' 'lintr-deprecated.R' 'lintr-package.R' 'list_comparison_linter.R' 'literal_coercion_linter.R' 'make_linter_from_regex.R' 'matrix_apply_linter.R' 'methods.R' 'missing_argument_linter.R' 'missing_package_linter.R' 'namespace.R' 'namespace_linter.R' 'nested_ifelse_linter.R' 'nested_pipe_linter.R' 'nonportable_path_linter.R' 'shared_constants.R' 'nrow_subset_linter.R' 'numeric_leading_zero_linter.R' 'nzchar_linter.R' 'object_length_linter.R' 'object_name_linter.R' 'object_overwrite_linter.R' 'object_usage_linter.R' 'one_call_pipe_linter.R' 'outer_negation_linter.R' 'package_hooks_linter.R' 'paren_body_linter.R' 'paste_linter.R' 'path_utils.R' 'pipe_call_linter.R' 'pipe_consistency_linter.R' 'pipe_continuation_linter.R' 'pipe_return_linter.R' 'print_linter.R' 'quotes_linter.R' 'redundant_equals_linter.R' 'redundant_ifelse_linter.R' 'regex_subset_linter.R' 'rep_len_linter.R' 'repeat_linter.R' 'return_linter.R' 'routine_registration_linter.R' 'sample_int_linter.R' 'scalar_in_linter.R' 'semicolon_linter.R' 'seq_linter.R' 'settings.R' 'settings_utils.R' 'sort_linter.R' 'source_utils.R' 'spaces_inside_linter.R' 'spaces_left_parentheses_linter.R' 'sprintf_linter.R' 'stopifnot_all_linter.R' 'string_boundary_linter.R' 'strings_as_factors_linter.R' 'system_file_linter.R' 'terminal_close_linter.R' 'todo_comment_linter.R' 'trailing_blank_lines_linter.R' 'trailing_whitespace_linter.R' 'tree_utils.R' 'undesirable_function_linter.R' 'undesirable_operator_linter.R' 'unnecessary_concatenation_linter.R' 'unnecessary_lambda_linter.R' 'unnecessary_nesting_linter.R' 'unnecessary_placeholder_linter.R' 'unreachable_code_linter.R' 'unused_import_linter.R' 'use_lintr.R' 'vector_logic_linter.R' 'which_grepl_linter.R' 'whitespace_linter.R' 'with.R' 'with_id.R' 'xml_nodes_to_lints.R' 'xml_utils.R' 'yoda_test_linter.R' 'zzz.R' Language: en-US NeedsCompilation: no Packaged: 2025-02-12 00:10:30 UTC; root Author: Jim Hester [aut], Florent Angly [aut] (fangly), Russ Hyde [aut], Michael Chirico [aut, cre], Kun Ren [aut], Alexander Rosenstock [aut] (AshesITR), Indrajeet Patil [aut] (, @patilindrajeets) Maintainer: Michael Chirico Repository: CRAN Date/Publication: 2025-02-12 15:00:02 UTC

For packages

First, take special note of the proviso in ?executing_linters about the need to have your package and its dependencies installed or loaded (e.g. with pkgload::load_all()) in order for certain linters (e.g. object_usage_linter()) to function as intended.

GitHub Actions

If your package is on GitHub, the easiest way to do this is with GitHub Actions. The workflow configuration files use YAML syntax. The usethis package has some great functionality that can help you with workflow files. The most straightforward way to add a lintr workflow to your package is to use the r-lib/actions’s lint example. To do this with usethis, you need to call

usethis::use_github_action("lint")

This will create a workflow file called lint.yaml and place it in the correct location, namely in the .github/workflows directory of your repository. This file configures all the steps required to run lintr::lint_package() on your package.

Alternatively you can use the eponymous lint-changed-files.yaml to only lint any changed files:

usethis::use_github_action("lint-changed-files")

Comments to the commit or pull request will be printed as annotations along side the status check on GitHub. If you want the builds to produce an error instead of just a warning, you can set the environment variable LINTR_ERROR_ON_LINT=true. This is set by default for both r-lib/actions’s lint.yaml and lint-changed-files.yaml. Note that this will kill the R process in case of a lint.

If your project is in a subdirectory and you would like to use GitHub Actions annotations, you can set options(lintr.github_annotation_project_dir = "path/to/project") which will make sure that the annotations point to the correct paths.