[med-svn] [r-cran-progress] 05/07: New upstream version 1.1.2

Andreas Tille tille at debian.org
Sat Sep 30 08:24:26 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-progress.

commit 8786a043357fb30929a8de2237498f0c547d4e62
Author: Andreas Tille <tille at debian.org>
Date:   Sat Sep 30 10:21:59 2017 +0200

    New upstream version 1.1.2
---
 DESCRIPTION                           |  22 ++
 LICENSE                               |   2 +
 MD5                                   |  23 ++
 NAMESPACE                             |   7 +
 R/progress.R                          | 406 ++++++++++++++++++++++++++++++++++
 R/utils.R                             | 105 +++++++++
 debian/README.test                    |   8 -
 debian/changelog                      |   5 -
 debian/compat                         |   1 -
 debian/control                        |  27 ---
 debian/copyright                      |  32 ---
 debian/docs                           |   3 -
 debian/rules                          |   8 -
 debian/source/format                  |   1 -
 debian/tests/control                  |   5 -
 debian/tests/run-unit-test            |  17 --
 debian/watch                          |   2 -
 inst/NEWS.md                          |  22 ++
 inst/README.metacran                  | 217 ++++++++++++++++++
 inst/include/RProgress.h              | 369 ++++++++++++++++++++++++++++++
 inst/logo.png                         | Bin 0 -> 5935 bytes
 inst/logo.svg                         | 199 +++++++++++++++++
 inst/progresstest/DESCRIPTION         |  12 +
 inst/progresstest/LICENSE             |   2 +
 inst/progresstest/NAMESPACE           |   6 +
 inst/progresstest/R/RcppExports.R     |  11 +
 inst/progresstest/R/test.R            |   9 +
 inst/progresstest/README.md           |  10 +
 inst/progresstest/src/RcppExports.cpp |  28 +++
 inst/progresstest/src/test.cpp        |  58 +++++
 man/progress_bar.Rd                   | 156 +++++++++++++
 tests/testthat.R                      |   6 +
 tests/testthat/helper.R               |  39 ++++
 tests/testthat/test-cpp.R             |  42 ++++
 tests/testthat/test-progress.R        | 389 ++++++++++++++++++++++++++++++++
 35 files changed, 2140 insertions(+), 109 deletions(-)

diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000..440cbb2
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,22 @@
+Package: progress
+Title: Terminal Progress Bars
+Version: 1.1.2
+Author: Gábor Csárdi [aut, cre], Rich FitzJohn [aut]
+Maintainer: Gábor Csárdi <csardi.gabor at gmail.com>
+Description: Configurable Progress bars, they may include percentage,
+    elapsed time, and/or the estimated completion time. They work in
+    terminals, in 'Emacs' 'ESS', 'RStudio', 'Windows' 'Rgui' and the
+    'macOS' 'R.app'. The package also provides a 'C++' 'API', that works
+    with or without 'Rcpp'.
+License: MIT + file LICENSE
+LazyData: true
+URL: https://github.com/gaborcsardi/progress#readme
+BugReports: https://github.com/gaborcsardi/progress/issues
+Imports: prettyunits, R6
+Suggests: testthat
+RoxygenNote: 5.0.1.9000
+Encoding: UTF-8
+NeedsCompilation: no
+Packaged: 2016-12-14 09:09:03 UTC; gaborcsardi
+Repository: CRAN
+Date/Publication: 2016-12-14 17:23:33
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..99ce77d
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,2 @@
+YEAR: 2015-2016
+COPYRIGHT HOLDER: Gábor Csárdi
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..8d629af
--- /dev/null
+++ b/MD5
@@ -0,0 +1,23 @@
+22a1bb1188d47dcba16533993a530159 *DESCRIPTION
+e4c81207cdbd596c9e35a231e630e872 *LICENSE
+8c924c80c47fd4b443134b51ba5ffcd9 *NAMESPACE
+b814ea50b680ffb9db27ad4baaf7b94f *R/progress.R
+35e20d402c9bd0054a782d01fc4b61dd *R/utils.R
+0c9e74abc8221a0c1c9b5b5d6a6a4dae *inst/NEWS.md
+b8e0ee67cec086fe5622fc959d3c8e97 *inst/README.metacran
+6ddb5651141969fda582967e204cd0e2 *inst/include/RProgress.h
+76f1f04c00cae388f24f4ff00636c2ae *inst/logo.png
+4a607a53806f2e5afe5a834bcace11eb *inst/logo.svg
+b5981f6a5d933fb66575a38a8a15d187 *inst/progresstest/DESCRIPTION
+8488c7e8cbfc04df9ff69dd011f878da *inst/progresstest/LICENSE
+1906d818824028e3d8c5a38121018524 *inst/progresstest/NAMESPACE
+9d75ffa9d3665660c3cdcf39ad5065b8 *inst/progresstest/R/RcppExports.R
+1db6705374372ff537ad6a1856de075a *inst/progresstest/R/test.R
+7c0b75a11963c889f7f87acfd22660c4 *inst/progresstest/README.md
+7d4c5db3fbe2c2b7c93be3062b280604 *inst/progresstest/src/RcppExports.cpp
+8a6f1090313e7c4b076ef60cd0838175 *inst/progresstest/src/test.cpp
+22fa2206d93e2b35d881c622a29a4751 *man/progress_bar.Rd
+95d3bb15732f376a121c2d619708824e *tests/testthat.R
+13dc299450724118ac82173b952468fd *tests/testthat/helper.R
+367aa8feade5b32c0307395662836aaf *tests/testthat/test-cpp.R
+62bfdd32271e3f6a629473f52d792de8 *tests/testthat/test-progress.R
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000..99b6f69
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,7 @@
+# Generated by roxygen2: do not edit by hand
+
+export(progress_bar)
+importFrom(R6,R6Class)
+importFrom(prettyunits,pretty_bytes)
+importFrom(prettyunits,vague_dt)
+importFrom(utils,flush.console)
diff --git a/R/progress.R b/R/progress.R
new file mode 100644
index 0000000..5bb2c9e
--- /dev/null
+++ b/R/progress.R
@@ -0,0 +1,406 @@
+
+#' Progress bar in the terminal
+#'
+#' Progress bars are configurable, may include percentage, elapsed time,
+#' and/or the estimated completion time. They work in the command line,
+#' in Emacs and in R Studio. The progress package was heavily influenced by
+#' https://github.com/tj/node-progress
+#'
+#' @section Creating the progress bar:
+#' A progress bar is an R6 object, that can be created with
+#' \code{progress_bar$new()}. It has the following arguments:
+#' \describe{
+#'   \item{format}{The format of the progress bar. A number of
+#'     tokens can be used here, see them below. It defaults to
+#'     \code{"[:bar] :percent"}, which means that the progress
+#'     bar is within brackets on the left, and the percentage
+#'     is printed on the right.}
+#'   \item{total}{Total number of ticks to complete. Defaults to 100.}
+#'   \item{width}{Width of the progress bar. Default is the current
+#'     terminal width (see \code{options()} and \code{width}) minus two.}
+#'   \item{stream}{The output stream to put the progress bar on.
+#'     It defaults to \code{stderr()}, except in R Studio that has
+#'     a bug when printing on the standard error, so there we use
+#'     \code{stdout}. If the output stream is not a terminal and
+#'     we are not in R Studio, then no progress bar is printed.}
+#'   \item{complete}{Completion character, defaults to \code{=}.}
+#'   \item{incomplete}{Incomplete character, defaults to \code{-}.}
+#'   \item{callback}{Callback function to call when the progress
+#'     bar finishes. The progress bar object itself is passed to it
+#'     as the single parameter.}
+#'   \item{clear}{Whether to clear the progress bar on completion.
+#'     Defaults to \code{TRUE}.}
+#'   \item{show_after}{Amount of time in seconds, after which the progress
+#'     bar is shown on the screen. For very short processes,
+#'     it is probably not worth showing it at all. Defaults to two
+#'     tenth of a second.}
+#'   \item{force}{Whether to force showing the progress bar,
+#'     even if the given (or default) stream does not seem support it.}
+#' }
+#'
+#' @section Using the progress bar:
+#' Two functions can update a progress bar. \code{progress_bar$tick()}
+#' increases the number of ticks by one (or another specified value).
+#' \code{progress_bar$update()} sets a given ratio.
+#'
+#' The progress bar is displayed after the first `tick` command.
+#' This might not be desirable for long computations, because
+#' nothing is shown before the first tick. It is good practice to
+#' call `tick(0)` at the beginning of the computation or download,
+#' which shows the progress bar immediately.
+#'
+#' @section Tokens:
+#' They can be used in the \code{format} argument when creating the
+#' progress bar.
+#' \describe{
+#'   \item{:bar}{The progress bar itself.}
+#'   \item{:current}{Current tick number.}
+#'   \item{:total}{Total ticks.}
+#'   \item{:elapsed}{Elapsed time in seconds.}
+#'   \item{:eta}{Estimated completion time in seconds.}
+#'   \item{:percent}{Completion percentage.}
+#'   \item{:rate}{Download rate, bytes per second. See example below.}
+#'   \item{:bytes}{Shows :current, formatted as bytes. Useful
+#'      for downloads or file reads if you don't know the size of the
+#'      file in advance. See example below.}
+#'   \item{:spin}{Shows a spinner that updates even when progress is
+#'      advanced by zero.}
+#' }
+#'
+#' Custom tokens are also supported, and you need to pass their
+#' values to \code{progress_bar$tick()} or \code{progress_bar$update()},
+#' in a named list. See example below.
+#'
+#' @importFrom R6 R6Class
+#'
+#' @export
+#' @examples
+#'
+#' ## We don't run the examples on CRAN, because they takes >10s
+#' ## altogether. Unfortunately it is hard to create a set of
+#' ## meaningful progress bar examples that also run quickly.
+#' \dontrun{
+#' 
+#' ## Basic
+#' pb <- progress_bar$new(total = 100)
+#' for (i in 1:100) {
+#'   pb$tick()
+#'   Sys.sleep(1 / 100)
+#' }
+#'
+#' ## ETA
+#' pb <- progress_bar$new(
+#'   format = "  downloading [:bar] :percent eta: :eta",
+#'   total = 100, clear = FALSE, width= 60)
+#' for (i in 1:100) {
+#'   pb$tick()
+#'   Sys.sleep(1 / 100)
+#' }
+#'
+#' ## Elapsed time
+#' pb <- progress_bar$new(
+#'   format = "  downloading [:bar] :percent in :elapsed",
+#'   total = 100, clear = FALSE, width= 60)
+#' for (i in 1:100) {
+#'   pb$tick()
+#'   Sys.sleep(1 / 100)
+#' }
+#'
+#' ## Spinner
+#' pb <- progress_bar$new(
+#'   format = "(:spin) [:bar] :percent",
+#'   total = 30, clear = FALSE, width = 60)
+#' for (i in 1:30) {
+#'   pb$tick()
+#'   Sys.sleep(3 / 100)
+#' }
+#'
+#' ## Custom tokens
+#' pb <- progress_bar$new(
+#'   format = "  downloading :what [:bar] :percent eta: :eta",
+#'   clear = FALSE, total = 200, width = 60)
+#' f <- function() {
+#'   for (i in 1:100) {
+#'     pb$tick(tokens = list(what = "foo   "))
+#'     Sys.sleep(2 / 100)
+#'   }
+#'   for (i in 1:100) {
+#'     pb$tick(tokens = list(what = "foobar"))
+#'     Sys.sleep(2 / 100)
+#'   }
+#' }
+#' f()
+#'
+#' ## Download (or other) rates
+#' pb <- progress_bar$new(
+#'   format = "  downloading foobar at :rate, got :bytes in :elapsed",
+#'   clear = FALSE, total = 1e7, width = 60)
+#' f <- function() {
+#'   for (i in 1:100) {
+#'     pb$tick(sample(1:100 * 1000, 1))
+#'     Sys.sleep(2/100)
+#'   }
+#'   pb$tick(1e7)
+#'   invisible()
+#' }
+#' f()
+#'
+#' }
+#'
+#' @name progress_bar
+NULL
+
+progress_bar <- R6Class("progress_bar",
+
+  public = list(
+
+    initialize = function(format = "[:bar] :percent", total = 100,
+      width = getOption("width") - 2, stream = NULL, complete = "=",
+      incomplete = "-", callback = function(self) {}, clear = TRUE,
+      show_after = 0.2, force = FALSE) {
+        pb_init(self, private, format, total, width, stream, complete,
+          incomplete, callback, clear, show_after, force)
+    },
+    tick = function(len = 1, tokens = list()) {
+      pb_tick(self, private, len, tokens) },
+    update = function(ratio, tokens = list()) { 
+      pb_update(self, private, ratio, tokens) }
+  ),
+
+  private = list(
+
+    render = function(tokens) { pb_render(self, private, tokens) },
+    terminate = function() { pb_terminate(self, private) },
+    ratio = function() { pb_ratio(self, private) },
+
+    first = TRUE,
+    supported = NA,
+    format = NULL,
+    total = NULL,
+    current = 0,
+    width = NULL,
+    stream = NULL,
+    chars = list(
+      complete = "=",
+      incomplete = "-"
+    ),
+    callback = NULL,
+    clear = NULL,
+    show_after = NULL,
+    last_draw = "",
+
+    start = NULL,
+    toupdate = FALSE,
+    complete = FALSE,
+
+    spin = NULL,
+
+    has_token = c(current = FALSE, total = FALSE, elapsed = FALSE,
+      eta = FALSE, percent = FALSE, rate = FALSE, bytes = FALSE,
+      bar = FALSE, spin = FALSE)
+  )
+)
+
+pb_init <- function(self, private, format, total, width, stream,
+                    complete, incomplete, callback, clear, show_after,
+                    force) {
+
+  stream <- default_stream(stream)
+
+  assert_character_scalar(format)
+  assert_positive_scalar(total)
+  assert_nonzero_count(width)
+  assert_connection(stream)
+  assert_single_char(complete)
+  assert_single_char(incomplete)
+  assert_function(callback)
+  assert_flag(clear)
+  assert_nonnegative_scalar(show_after)
+
+  private$first <- TRUE
+  private$supported <- force || is_supported(stream)
+  private$format <- format
+  private$total <- total
+  private$width <- width
+  private$stream <- stream
+  private$chars$complete <- complete
+  private$chars$incomplete <- incomplete
+  private$callback <- callback
+  private$clear <- clear
+  private$show_after <- as.difftime(show_after, units = "secs")
+  private$spin <- spin_symbols()
+
+  private$has_token <- pb_update_has_token(private$has_token, format)
+
+  self
+}
+
+pb_update_has_token <- function(tokens, format) {
+  for (n in names(tokens)) {
+    tokens[n] <- grepl(paste0(":", n), format, fixed = TRUE)
+  }
+
+  tokens
+}
+
+pb_tick <- function(self, private, len, tokens) {
+
+  assert_scalar(len)
+  assert_named_or_empty_list(tokens)
+
+  if (private$first) {
+    private$first <- FALSE
+    private$start <- Sys.time()
+  }
+
+  private$current <- private$current + len
+
+  if (!private$toupdate) {
+    if (Sys.time() - private$start >= private$show_after) {
+      private$toupdate <- TRUE
+    }
+  }
+
+  if (private$current >= private$total) private$complete <- TRUE
+
+  if (private$toupdate) private$render(tokens)
+
+  if (private$complete) {
+    private$terminate()
+    private$callback()
+  }
+
+  self
+}
+
+#' @importFrom prettyunits vague_dt pretty_bytes
+#' @importFrom utils flush.console
+
+pb_ratio <- function(self, private) {
+  ratio <- (private$current / private$total)
+  ratio <- max(ratio, 0)
+  ratio <- min(ratio, 1)
+  ratio
+}
+
+pb_render <- function(self, private, tokens) {
+
+  if (! private$supported) return(invisible())
+
+  str <- private$format
+
+  if (private$has_token["percent"]) {
+    percent <- private$ratio() * 100
+    str <- sub(str, pattern = ":percent", replacement =
+                 paste0(format(round(percent), width = 3), "%"))
+  }
+
+  if (private$has_token["elapsed"]) {
+    elapsed_secs <- Sys.time() - private$start
+    elapsed <- vague_dt(elapsed_secs, format = "terse")
+    str <- sub(str, pattern = ":elapsed", replacement = elapsed)
+  }
+
+  if (private$has_token["eta"]) {
+    percent <- private$ratio() * 100
+    elapsed_secs <- Sys.time() - private$start
+    eta_secs <- if (percent == 100) {
+      0
+    } else {
+      elapsed_secs * (private$total / private$current - 1.0)
+    }
+    eta <- as.difftime(eta_secs, units = "secs")
+    if (is.nan(eta) || eta == Inf) {
+      eta <- " ?s"
+    } else {
+      eta <- vague_dt(eta, format = "terse")
+    }
+    str <- sub(str, pattern = ":eta", replacement = eta)
+  }
+
+  if (private$has_token["rate"]) {
+    elapsed_secs <- Sys.time() - private$start
+    rate <- private$current / as.double(elapsed_secs, units = "secs")
+    if (is.nan(rate)) rate <- 0
+    rate <- paste0(pretty_bytes(round(rate)), "/s")
+    str <- sub(str, pattern = ":rate", replacement = rate)
+  }
+
+  if (private$has_token["current"]) {
+    str <- sub(str, pattern = ":current",
+               replacement = round(private$current))
+  }
+
+  if (private$has_token["total"]) {
+    str <- sub(str, pattern = ":total", replacement = round(private$total))
+  }
+
+  if (private$has_token["bytes"]) {
+    bytes <- pretty_bytes(round(private$current))
+    str <- sub(str, pattern = ":bytes", replacement = bytes)
+  }
+
+  if (private$has_token["spin"]) {
+    ## NOTE: fixed = TRUE is needed here or "\\" causes trouble with
+    ## the replacement (I think it's interpreted as an invalid
+    ## backreference).
+    str <- sub(str, pattern = ":spin", replacement = private$spin(), fixed = TRUE)
+  }
+
+  for (t in names(tokens)) {
+    str <- gsub(paste0(":", t), tokens[[t]], str, fixed = TRUE)
+  }
+
+  if (private$has_token["bar"]) {
+    bar_width <- nchar(sub(str, pattern = ":bar", replacement = ""))
+    bar_width <- private$width - bar_width
+    bar_width <- max(0, bar_width)
+
+    ratio <- private$ratio()
+    complete_len <- round(bar_width * ratio)
+    complete <- paste(rep("", complete_len + 1),
+                      collapse = private$chars$complete)
+    incomplete <- paste(rep("", bar_width - complete_len + 1),
+                        collapse = private$chars$incomplete)
+
+    str <- sub(":bar", paste0(complete, incomplete), str)
+  }
+
+  if (private$last_draw != str) {
+    if (nchar(private$last_draw) > nchar(str)) {
+      clear_line(private$stream, private$width)
+    }
+    cursor_to_start(private$stream)
+    cat(str, file = private$stream)
+    private$last_draw <- str
+  }
+
+  flush.console()
+
+  self
+}
+
+pb_update <- function(self, private, ratio, tokens) {
+  assert_ratio(ratio)
+  goal <- floor(ratio * private$total)
+  self$tick(goal - private$current, tokens)
+}
+
+pb_terminate <- function(self, private) {
+  if (!private$supported || !private$toupdate) return(invisible())
+  if (private$clear) {
+    clear_line(private$stream, private$width)
+    cursor_to_start(private$stream)
+  } else {
+    cat("\n", file = private$stream)
+  }
+}
+
+spin_symbols <- function() {
+  sym <- c("-", "\\", "|", "/")
+  i <- 0L
+  n <- length(sym)
+  function() {
+    sym[[i <<- if (i >= n) 1L else i + 1L]]
+  }
+}
diff --git a/R/utils.R b/R/utils.R
new file mode 100644
index 0000000..6ef3fe6
--- /dev/null
+++ b/R/utils.R
@@ -0,0 +1,105 @@
+
+clear_line <- function(tty, width) {
+  str <- paste0(c("\r", rep(" ", width)), collapse = "")
+  cat(str, file = tty)
+}
+
+cursor_to_start <- function(tty) {
+  cat("\r", file = tty)
+}
+
+is_stdout <- function(stream) {
+  identical(stream, stdout()) && sink.number() == 0
+}
+
+is_stderr <- function(stream) {
+  identical(stream, stderr())
+}
+
+is_r_studio <- function() {
+  Sys.getenv("RSTUDIO") == 1
+}
+
+r_studio_stdout <- function(stream) {
+  interactive() &&
+    is_r_studio() &&
+    identical(stream, stdout()) &&
+    is_stdout(stream)
+}
+
+is_r_app <- function() {
+  Sys.getenv("R_GUI_APP_VERSION") != ""
+}
+
+r_app_stdx <- function(stream) {
+  interactive() &&
+    is_r_app() &&
+    (is_stdout(stream) || is_stderr(stream))
+}
+
+is_supported <- function(stream) {
+  isatty(stream) || r_studio_stdout(stream) || r_app_stdx(stream)
+}
+
+default_stream <- function(stream) {
+  if (! is.null(stream)) {
+    stream
+  } else {
+    if (is_r_studio()) stdout() else stderr()
+  }
+}
+
+assert_character_scalar <- function(x) {
+  stopifnot(is.character(x),
+            length(x) == 1,
+            !is.na(x))
+}
+
+assert_scalar <- function(x, finite = TRUE) {
+  stopifnot(is.numeric(x),
+            length(x) == 1,
+            !is.na(x),
+            !finite || is.finite(x))
+}
+
+assert_positive_scalar <- function(x, finite = TRUE) {
+  assert_scalar(x, finite = finite)
+  stopifnot(x > 0)
+}
+
+assert_nonnegative_scalar <- function(x, finite = TRUE) {
+  assert_scalar(x, finite = finite)
+  stopifnot(x >= 0)
+}
+
+
+assert_ratio <- function(x) {
+  assert_nonnegative_scalar(x)
+  stopifnot(x <= 1)
+}
+
+assert_nonzero_count <- function(x, finite = TRUE) {
+  assert_positive_scalar(x, finite = TRUE)
+  stopifnot(as.integer(x) == x)
+}
+
+assert_connection <- function(x) {
+  stopifnot(inherits(x, "connection"))
+}
+
+assert_single_char <- function(x) {
+  assert_character_scalar(x)
+  stopifnot(nchar(x) == 1)
+}
+
+assert_function <- function(x) {
+  stopifnot(is.function(x))
+}
+
+assert_flag <- function(x) {
+  stopifnot(is.logical(x), length(x) == 1, !is.na(x))
+}
+
+assert_named_or_empty_list <- function(x) {
+  stopifnot(length(x) == 0 || !is.null(names(x)))
+}
diff --git a/debian/README.test b/debian/README.test
deleted file mode 100644
index 53fb4d7..0000000
--- a/debian/README.test
+++ /dev/null
@@ -1,8 +0,0 @@
-Notes on how this package can be tested.
-────────────────────────────────────────
-
-This package can be tested by running the provided test:
-
-   sh ./run-unit-test
-
-in order to confirm its integrity.
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 8e4f417..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-r-cran-progress (1.1.2-1) unstable; urgency=medium
-
-  * Initial release (closes: #848659)
-
- -- Andreas Tille <tille at debian.org>  Mon, 19 Dec 2016 11:43:31 +0100
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index f599e28..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-10
diff --git a/debian/control b/debian/control
deleted file mode 100644
index cb8431e..0000000
--- a/debian/control
+++ /dev/null
@@ -1,27 +0,0 @@
-Source: r-cran-progress
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Andreas Tille <tille at debian.org>
-Section: gnu-r
-Priority: optional
-Build-Depends: debhelper (>= 10),
-               dh-r,
-               r-base-dev,
-               r-cran-r6,
-               r-cran-prettyunits
-Standards-Version: 3.9.8
-Vcs-Browser: https://anonscm.debian.org/viewvc/debian-med/trunk/packages/R/r-cran-progress/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/R/r-cran-progress/trunk/
-Homepage: https://cran.r-project.org/package=progress
-
-Package: r-cran-progress
-Architecture: all
-Depends: ${R:Depends},
-         ${misc:Depends}
-Recommends: ${R:Recommends}
-Suggests: ${R:Suggests}
-Description: GNU R terminal progress bars
- Configurable Progress bars for GNU R, they may include percentage,
- elapsed time, and/or the estimated completion time. They work in
- terminals, in 'Emacs' 'ESS', 'RStudio', 'Windows' 'Rgui' and the
- 'macOS' 'R.app'. The package also provides a 'C++' 'API', that works
- with or without 'Rcpp'.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 2959ed2..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,32 +0,0 @@
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: progress
-Upstream-Contact: Gábor Csárdi <csardi.gabor at gmail.com>
-Source: https://cran.r-project.org/package=progress
-
-Files: *
-Copyright: 2015-2016 Gábor Csárdi, Rich FitzJohn
-License: MIT
-
-Files: debian/*
-Copyright: 2016 Andreas Tille <tille at debian.org>
-License: MIT
-
-License: MIT
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
- .
- The above copyright notice and this permission notice shall be
- included in all copies or substantial portions of the Software.
- .
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/debian/docs b/debian/docs
deleted file mode 100644
index 6466d39..0000000
--- a/debian/docs
+++ /dev/null
@@ -1,3 +0,0 @@
-debian/tests/run-unit-test
-debian/README.test
-tests
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index ae86733..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/make -f
-
-%:
-	dh $@ --buildsystem R
-
-override_dh_install:
-	dh_install
-	find debian -name LICENSE -delete
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/tests/control b/debian/tests/control
deleted file mode 100644
index a62fb6e..0000000
--- a/debian/tests/control
+++ /dev/null
@@ -1,5 +0,0 @@
-Tests: run-unit-test
-Depends: @, r-cran-testthat,
-Restrictions: allow-stderr
-
-
diff --git a/debian/tests/run-unit-test b/debian/tests/run-unit-test
deleted file mode 100644
index a8e03f0..0000000
--- a/debian/tests/run-unit-test
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/sh -e
-
-pkgname=progress
-debname=r-cran-progress
-
-if [ "$ADTTMP" = "" ] ; then
-    ADTTMP=`mktemp -d /tmp/${debname}-test.XXXXXX`
-    trap "rm -rf $ADTTMP" 0 INT QUIT ABRT PIPE TERM
-fi
-cd $ADTTMP
-cp -a /usr/share/doc/$debname/tests/* $ADTTMP
-gunzip -r *
-for testfile in *.R; do
-    echo "BEGIN TEST $testfile"
-    LC_ALL=C R --no-save < $testfile
-done
-
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index a30a454..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,2 +0,0 @@
-version=4
-https://cran.r-project.org/src/contrib/progress_([-\d.]*)\.tar\.gz
diff --git a/inst/NEWS.md b/inst/NEWS.md
new file mode 100644
index 0000000..d5b96fe
--- /dev/null
+++ b/inst/NEWS.md
@@ -0,0 +1,22 @@
+
+# 1.1.2
+
+* Do not run tests on CRAN, Solaris does not have microbenchmark
+
+# 1.1.1
+
+* Move README.md, so that it is not parsed on CRAN
+* Use https URLs instead of http, whenever possible
+
+# 1.1.0
+
+* Support for the `:spin` token which adds a simple ASCII spinner, @richfitz
+* Respect custom token width for calculation of the bar width, @mllg
+
+# 1.0.2
+
+* Fix the C++ API on Windows, and on older compilers in general.
+
+# 1.0.1
+
+First version on CRAN.
diff --git a/inst/README.metacran b/inst/README.metacran
new file mode 100644
index 0000000..a0ba8a3
--- /dev/null
+++ b/inst/README.metacran
@@ -0,0 +1,217 @@
+
+<h1 align="center">
+    <br>
+    <br>
+    <img width="400" src="./inst/logo.png" alt="progress">
+    <br>
+    <br>
+    <br>
+</h1>
+
+[![Linux Build Status](https://travis-ci.org/gaborcsardi/progress.svg?branch=master)](https://travis-ci.org/gaborcsardi/progress)
+[![Windows Build status](https://ci.appveyor.com/api/projects/status/github/gaborcsardi/progress?svg=true)](https://ci.appveyor.com/project/gaborcsardi/progress)
+[![](https://www.r-pkg.org/badges/version/progress)](https://r-pkg.org/pkg/progress)
+
+> Progress bar in your R terminal
+
+An R package to show ASCII progress bars. Heavily influenced by
+the https://github.com/tj/node-progress JavaScript project.
+
+## Installation
+
+```r
+devtools::install_github("gaborcsardi/progress")
+```
+
+## Usage
+
+Use the `progress_bar` R6 class:
+
+```r
+library(progress)
+pb <- progress_bar$new(total = 100)
+for (i in 1:100) {
+  pb$tick()
+  Sys.sleep(1 / 100)
+}
+```
+
+```
+[==========================================================-------------]  81%
+```
+
+The progress bar is displayed after the first `tick` command.
+This might not be desirable for long computations, because
+nothing is shown before the first tick. It is good practice to
+call `tick(0)` at the beginning of the computation or download,
+which shows the progress bar immediately.
+
+```r
+pb <- progress_bar$new(total = 100)
+f <- function() {
+  pb$tick(0)
+  Sys.sleep(3)
+  for (i in 1:100) {
+    pb$tick()
+    Sys.sleep(1 / 100)
+  }
+}
+f()
+```
+
+Custom format, with estimated time of completion:
+
+```r
+pb <- progress_bar$new(
+  format = "  downloading [:bar] :percent eta: :eta",
+  total = 100, clear = FALSE, width= 60)
+for (i in 1:100) {
+  pb$tick()
+  Sys.sleep(1 / 100)
+}
+```
+
+```
+  downloading [========----------------------]  28% eta:  1s
+```
+
+With elapsed time:
+
+```r
+pb <- progress_bar$new(
+  format = "  downloading [:bar] :percent in :elapsed",
+  total = 100, clear = FALSE, width= 60)
+for (i in 1:100) {
+  pb$tick()
+  Sys.sleep(1 / 100)
+}
+```
+
+```
+  downloading [==========================------]  80% in  1s
+```
+
+With custom tokens:
+
+```r
+pb <- progress_bar$new(
+  format = "  downloading :what [:bar] :percent eta: :eta",
+  clear = FALSE, total = 200, width = 60)
+f <- function() {
+  for (i in 1:100) {
+    pb$tick(tokens = list(what = "foo   "))
+    Sys.sleep(2 / 100)
+  }
+  for (i in 1:100) {
+    pb$tick(tokens = list(what = "foobar"))
+    Sys.sleep(2 / 100)
+  }
+}
+f()
+```
+
+```
+  downloading foo    [======------------------]  27% eta:  4s
+```
+
+It can show download rates for files with unknown sizes:
+
+```r
+pb <- progress_bar$new(
+  format = "  downloading foobar at :rate, got :bytes in :elapsed",
+  clear = FALSE, total = 1e7, width = 60)
+f <- function() {
+  for (i in 1:100) {
+    pb$tick(sample(1:100 * 1000, 1))
+    Sys.sleep(2/100)
+  }
+  pb$tick(1e7)
+  invisible()
+}
+f()
+```
+
+```
+  downloading foobar at 5.42 MB/s, got 15.45 MB in  3s
+```
+
+Progress bars can also digress, by supplying negative values to `tick()`:
+
+```r
+pb <- progress_bar$new()
+f <- function() {
+  pb$tick(50)  ; Sys.sleep(1)
+  pb$tick(-20) ; Sys.sleep(1)
+  pb$tick(50)  ; Sys.sleep(1)
+  pb$tick(-30) ; Sys.sleep(1)
+  pb$tick(100)
+}
+f()
+```
+
+See the manual for details and other options.
+
+## Creating a plyr compatible progress bar
+
+It is easy to create progress bars for
+[plyr](https://github.com/hadley/plyr):
+
+```r
+progress_progress <- function(...) {
+  pb <- NULL
+  list(
+    init = function(x, ...) {
+      pb <<- progress_bar$new(total = x, ...)
+    },
+	step = function() {
+      pb$tick()
+    },
+	term = function() NULL
+  )
+}
+```
+
+You can try it with
+
+```r
+plyr::l_ply(
+  1:100,
+  .fun = function(...) Sys.sleep(0.01),
+  .progress = 'progress'
+)
+```
+
+## C++ API
+
+The package also provides a C++ API, that can be used with or
+without Rcpp. See [the example package](inst/progresstest/src/test.cpp) that
+is [included](inst/progresstest) within `progress`. Here is a short excerpt
+that shows how it works:
+
+```CPP
+
+#include <RProgress.h>
+
+...
+
+RProgress::RProgress pb("Downloading [:bar] ETA: :eta");
+
+  pb.tick(0);
+  for (int i = 0; i < 100; i++) {
+    usleep(2.0 / 100 * 1000000);
+    pb.tick();
+  }
+
+...
+
+```
+
+The C++ API has almost the same functionality as the R API, except that it
+does not currently support custom tokens, custom streams, and callback functions.
+
+Note that the C++ and the R APIs are independent and for a
+single progress bar you need to use either one exclusively.
+
+## License
+
+MIT
diff --git a/inst/include/RProgress.h b/inst/include/RProgress.h
new file mode 100644
index 0000000..a8da98c
--- /dev/null
+++ b/inst/include/RProgress.h
@@ -0,0 +1,369 @@
+/* -*- mode: c++ -*- */
+
+#ifndef R_PROGRESS_H
+#define R_PROGRESS_H
+
+#include <unistd.h>
+#include <sys/time.h>
+
+#ifdef Win32
+#  include <io.h>
+#endif
+
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <cmath>
+#include <cstring>
+#include <cstdlib>
+
+#include <Rinternals.h>
+#include <R_ext/Print.h>
+
+// For gettimeofday implementation on windows
+#ifdef Win32
+
+// MSVC defines this in winsock2.h!?
+typedef struct timeval {
+    long tv_sec;
+    long tv_usec;
+} timeval;
+int gettimeofday(struct timeval * tp, struct timezone * tzp);
+
+#endif
+
+namespace RProgress {
+
+class RProgress {
+
+ public:
+
+  RProgress(std::string format = "[:bar] :percent",
+	    double total = 100,
+	    int width = Rf_GetOptionWidth() - 2,
+	    char complete_char = '=',
+	    char incomplete_char = '-',
+	    bool clear = true,
+	    double show_after = 0.2) :
+
+    first(true), format(format), total(total), current(0), width(width),
+    complete_char(complete_char), incomplete_char(incomplete_char),
+    clear(clear), show_after(show_after), last_draw(""), start(0),
+    toupdate(false), complete(false) {
+
+    supported = is_supported();
+    use_stderr = default_stderr();
+  }
+
+  ~RProgress() { }
+
+  void set_format(std::string format)    { this->format = format;         }
+  void set_total(double total)           { this->total = total;           }
+  void set_width(int width)              { this->width = width;           }
+  void set_complete_char(char complete_char) {
+    this->complete_char = complete_char;
+  }
+  void set_incomplete_char(char incomplete_char) {
+    this->incomplete_char = incomplete_char;
+  }
+  void set_clear(bool clear)             { this->clear = clear;           }
+  void set_show_after(double show_after) { this->show_after = show_after; }
+
+  void tick(double len = 1) {
+    // Start the timer
+    if (first) { start = time_now(); }
+
+    current += len;
+    count++;
+
+    // We only update after show_after secs
+    toupdate = toupdate || time_now() - start > show_after;
+
+    if (current >= total) complete = true;
+
+    // Need to render at the beginning and at the end, always
+    if (first || toupdate || complete) this->render();
+
+    if (complete) this->terminate();
+
+    first = false;
+  }
+
+  void update(double ratio) {
+    double goal = ratio * total;
+    this->tick(goal - current);
+  }
+
+ private:
+
+  bool first;			// Is the next one the first tick?
+  bool supported;		// \r supported at all?
+  std::string format;		// Format template
+  double total;			// Total number of ticks
+  double current;		// Current number of ticks
+  int count;                    // Total number of calls
+  int width;			// Width of progress bar
+  bool use_stderr;		// Whether to print to stderr
+  char complete_char;		// Character for completed ticks
+  char incomplete_char;		// Character for incomplete ticks
+  bool clear;			// Should we clear the line at the end?
+  double show_after;		// Delay to show/increase the progress bar
+  std::string last_draw;	// Last progress bar drawn
+
+  double start;			// Start time
+  bool toupdate;		// Are we updating? (After show_after.)
+  bool complete;		// Are we complete?
+
+  void render() {
+    if (!supported) return;
+
+    std::string str = format;
+
+    std::stringstream buffer;
+
+    double ratio_now = ratio();
+
+    // percent
+    buffer << std::setw(3) << ratio_now * 100 << "%";
+    replace_all(str, ":percent", buffer.str());
+    buffer.str(""); buffer.clear();
+
+    // elapsed
+    double elapsed_secs = time_now() - start;
+    std::string elapsed = vague_dt(elapsed_secs);
+    replace_all(str, ":elapsed", elapsed);
+
+    // eta
+    double percent = round(ratio_now * 100);
+    double eta_secs = percent == 100 ? 0 :
+      elapsed_secs * (total / current - 1.0);
+    std::string eta = std::isinf(eta_secs) ? "?s" : vague_dt(eta_secs);
+    replace_all(str, ":eta", eta);
+
+    // rate
+    double rate_num = current / elapsed_secs;
+    buffer << pretty_bytes(round(rate_num)) << "/s";
+    replace_all(str, ":rate", buffer.str());
+    buffer.str(""); buffer.clear();
+
+    // current
+    buffer << round(current);
+    replace_all(str, ":current", buffer.str());
+    buffer.str(""); buffer.clear();
+
+    // total
+    buffer << round(total);
+    replace_all(str, ":total", buffer.str());
+    buffer.str(""); buffer.clear();
+
+    // bytes
+    replace_all(str, ":bytes", pretty_bytes(round(current)));
+
+    // spin
+    replace_all(str, ":spin", spin_symbol());
+
+    // bar
+    std::string str_no_bar = str;
+    replace_all(str_no_bar, ":bar", "");
+    int bar_width = width - str_no_bar.length();
+    if (bar_width < 0) bar_width = 0;
+
+    double complete_len = round(bar_width * ratio_now);
+    char bar[bar_width + 1];
+    for (int i = 0; i < complete_len; i++) { bar[i] = complete_char; }
+    for (int i = complete_len; i < bar_width; i++) {
+      bar[i] = incomplete_char;
+    }
+    bar[bar_width] = '\0';
+    replace_all(str, ":bar", bar);
+
+    if (last_draw != str) {
+      if (last_draw.length() > str.length()) { clear_line(use_stderr, width); }
+      cursor_to_start(use_stderr);
+      if (use_stderr) {
+	REprintf(str.c_str());
+      } else {
+	Rprintf(str.c_str());
+      }
+      last_draw = str;
+    }
+  }
+
+  void terminate() {
+    if (! supported) return;
+    if (clear) {
+      clear_line(use_stderr, width);
+      cursor_to_start(use_stderr);
+    } else {
+      if (use_stderr) {
+	REprintf("\n");
+      } else {
+	Rprintf("\n");
+      }
+    }
+  }
+
+  double ratio() {
+    double ratio = current / total;
+    if (ratio < 0) ratio = 0;
+    if (ratio > 1) ratio = 1;
+    return ratio;
+  }
+
+  std::string spin_symbol() {
+    const char symbols[4] = {'-', '\\', '|', '/'};
+    return std::string(1, symbols[(count - 1) % 4]);
+  }
+
+  void clear_line(bool use_stderr, int width) {
+
+    char spaces[width + 2];
+    for (int i = 1; i <= width; i++) spaces[i] = ' ';
+    spaces[0] = '\r';
+    spaces[width + 1] = '\0';
+
+    if (use_stderr) {
+      REprintf(spaces);
+    } else {
+      Rprintf(spaces);
+    }
+  }
+
+  void cursor_to_start(bool use_stderr) {
+
+    if (use_stderr) {
+      REprintf("\r");
+    } else {
+      Rprintf("\r");
+    }
+  }
+
+  bool is_r_studio() {
+
+    char *v = std::getenv("RSTUDIO");
+
+    return v != 0 && v[0] == '1' && v[1] == '\0';
+  }
+
+  bool is_r_app() {
+
+    char *v = std::getenv("R_GUI_APP_VERSION");
+
+    return v != 0;
+  }
+
+  // In R Studio we should print to stdout, because priting a \r
+  // to stderr is buggy (reported)
+
+  bool default_stderr() {
+
+    return !is_r_studio();
+  }
+
+  // If stdout is a terminal, or R Studio or macOS R.app
+  // On windows, stdout is a terminal, apparently
+
+  bool is_supported() {
+
+    return isatty(1) || is_r_studio() || is_r_app();
+  }
+
+  // gettimeofday for windows, from
+  // https://stackoverflow.com/questions/10905892
+
+#ifdef Win32
+
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <stdint.h> // portable: uint64_t   MSVC: __int64
+
+  int gettimeofday(struct timeval * tp, struct timezone * tzp) {
+    // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
+    static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
+
+    SYSTEMTIME  system_time;
+    FILETIME    file_time;
+    uint64_t    time;
+
+    GetSystemTime( &system_time );
+    SystemTimeToFileTime( &system_time, &file_time );
+    time =  ((uint64_t)file_time.dwLowDateTime )      ;
+    time += ((uint64_t)file_time.dwHighDateTime) << 32;
+
+    tp->tv_sec  = (long) ((time - EPOCH) / 10000000L);
+    tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
+    return 0;
+  }
+
+#endif
+
+  static double time_now() {
+    struct timeval now;
+    gettimeofday(&now, /* tzp = */ 0);
+    return now.tv_sec + now.tv_usec / 1000000.0;
+  }
+
+  static void replace_all(std::string& str, const std::string& from,
+		   const std::string& to) {
+    if (from.empty()) return;
+
+    size_t start_pos = 0;
+
+    while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
+      str.replace(start_pos, from.length(), to);
+      start_pos += to.length();
+    }
+  }
+
+public:
+
+  static std::string vague_dt(double seconds) {
+    double minutes = seconds / 60;
+    double hours = minutes / 60;
+    double days = hours / 24;
+    double years = days / 365.25;
+
+    std::stringstream buffer;
+
+    buffer << std::setw(2);
+
+    if (seconds < 50) {
+      buffer << round(seconds) << "s";
+    } else if (minutes < 50) {
+      buffer << round(minutes) << "m";
+    } else if (hours < 18) {
+      buffer << round(hours) << "h";
+    } else if (days < 30) {
+      buffer << round(days) << "d";
+    } else if (days < 335) {
+      buffer << round(days/30) << "M";
+    } else {
+      buffer << round(years) << "y";
+    }
+
+    return buffer.str();
+  }
+
+  static std::string pretty_bytes(long bytes) {
+
+    if (bytes == 0) { return "0B"; }
+
+    std::string units[] = { "B", "kB", "MB", "GB", "TB", "PB", "EB",
+			    "ZB", "YB" };
+    int num_units = std::floor(sizeof(units) / sizeof(units[0]));
+    double idx = std::floor(std::log(bytes) / std::log(1000.0));
+    if (idx >= num_units) { idx = num_units - 1; }
+
+    double res = round(bytes / std::pow(1000.0, idx) * 100.0) / 100.0;
+    std::stringstream buffer;
+
+    buffer.precision(2);
+    buffer << std::fixed << res << units[(long) idx];
+    return buffer.str();
+  }
+
+}; // class RProgress
+
+}  // namespace RProgress
+
+#endif
diff --git a/inst/logo.png b/inst/logo.png
new file mode 100644
index 0000000..5d80b4c
Binary files /dev/null and b/inst/logo.png differ
diff --git a/inst/logo.svg b/inst/logo.svg
new file mode 100644
index 0000000..6301496
--- /dev/null
+++ b/inst/logo.svg
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="46.846344mm"
+   height="15.024148mm"
+   viewBox="0 0 165.99098 53.23517"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="logo.svg">
+  <defs
+     id="defs4" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="4.0042847"
+     inkscape:cx="77.616416"
+     inkscape:cy="16.931869"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="1"
+     fit-margin-left="1"
+     fit-margin-right="1"
+     fit-margin-bottom="1"
+     inkscape:window-width="1676"
+     inkscape:window-height="1005"
+     inkscape:window-x="4"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-138.8815,-336.25359)">
+    <g
+       id="g4348">
+      <g
+         id="g4191">
+        <path
+           inkscape:connector-curvature="0"
+           id="path4143"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 169.02881,355.1689 -10.188,0 -1.08,10.296 -5.184,0 2.7,-25.668 15.372,0 -1.62,15.372 z m -4.572,-5.148 0.504,-5.076 -5.076,0 -0.54,5.076 5.112,0 z m -11.808,-7.704 -10.224,0 0.252,-2.52 10.224,0 -0.252,2.52 z m -0.54,5.148 -8.532,0 0.288,-2.52 8.496,0 -0.252,2.52 z m -0.54,5.148 -6.804,0 0.252,-2.52 6.804,0 -0.252,2.52 z m -0.54,5.112 -5.076,0 0.252,-2.52 5.076,0 -0.252,2.52 z m -0.54,5.148 -3.384,0 0.288,-2.52 3.348,0 -0.252,2.52 z" />
+        <path
+           inkscape:connector-curvature="0"
+           id="path4145"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 184.84574,365.4649 -5.112,0 0.324,-3.312 -2.664,-6.984 -1.692,0 -1.08,10.296 -5.184,0 2.7,-25.668 15.372,0 -1.62,15.372 -2.412,0 1.836,5.58 -0.468,4.716 z m -3.528,-15.444 0.504,-5.076 -5.076,0 -0.54,5.076 5.112,0 z" />
+        <path
+           inkscape:connector-curvature="0"
+           id="path4147"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 202.45818,365.4649 -15.372,0 2.7,-25.668 15.372,0 -2.7,25.668 z m -4.572,-5.148 1.584,-15.372 -5.076,0 -1.62,15.372 5.112,0 z" />
+        <path
+           inkscape:connector-curvature="0"
+           id="path4149"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 220.10662,365.4649 -15.372,0 2.7,-25.668 15.372,0 -0.54,5.076 -10.224,0 -1.62,15.444 5.112,0 0.54,-5.076 -2.556,0 0.54,-5.148 7.668,0 -1.62,15.372 z" />
+        <path
+           inkscape:connector-curvature="0"
+           id="path4151"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 237.79106,365.4649 -5.112,0 0.324,-3.312 -2.664,-6.984 -1.692,0 -1.08,10.296 -5.184,0 2.7,-25.668 15.372,0 -1.62,15.372 -2.412,0 1.836,5.58 -0.468,4.716 z m -3.528,-15.444 0.504,-5.076 -5.076,0 -0.54,5.076 5.112,0 z" />
+        <path
+           inkscape:connector-curvature="0"
+           id="path4153"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 255.40349,365.4649 -15.372,0 2.7,-25.668 15.372,0 -0.54,5.076 -10.224,0 -0.54,5.112 10.26,0 -0.576,5.184 -10.224,0 -0.54,5.112 10.26,0 -0.576,5.184 z" />
+        <path
+           inkscape:connector-curvature="0"
+           id="path4155"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 272.63006,365.4649 -15.372,0 0.54,-5.112 10.26,0 0.54,-5.112 -10.26,0 1.62,-15.444 15.372,0 -0.54,5.076 -10.224,0 -0.54,5.112 10.26,0 -1.656,15.48 z" />
+        <path
+           inkscape:connector-curvature="0"
+           id="path4157"
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 290.27849,365.4649 -15.372,0 0.54,-5.112 10.26,0 0.54,-5.112 -10.26,0 1.62,-15.444 15.372,0 -0.54,5.076 -10.224,0 -0.54,5.112 10.26,0 -1.656,15.48 z" />
+      </g>
+      <g
+         transform="translate(-0.49946499,-0.24973254)"
+         id="g4328">
+        <g
+           id="g4310">
+          <path
+             inkscape:connector-curvature="0"
+             id="path4280"
+             d="m 167.16147,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4251"
+             d="m 166.02155,381.79886 -16.22484,0 0.56996,-5.112 16.22484,0 -0.56996,5.112 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4284"
+             d="m 184.75006,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4253"
+             d="m 183.61014,381.79886 -16.22484,0 0.56996,-5.112 16.22484,0 -0.56996,5.112 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4288"
+             d="m 202.33865,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4255"
+             d="m 201.19873,381.79886 -16.22484,0 0.56996,-5.112 16.22484,0 -0.56996,5.112 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4292"
+             d="m 219.92725,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4257"
+             d="m 218.78733,381.79886 -16.22484,0 0.56996,-5.112 16.22484,0 -0.56996,5.112 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4296"
+             d="m 237.51584,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4259"
+             d="m 236.37593,381.79886 -16.22485,0 0.56996,-5.112 16.22484,0 -0.56995,5.112 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4300"
+             d="m 255.10443,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4261"
+             d="m 253.96452,381.79886 -16.22485,0 0.56996,-5.112 16.22484,0 -0.56995,5.112 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4304"
+             d="m 272.69302,374.75152 -16.22484,0 0.56996,-5.076 16.22484,0 -0.56996,5.076 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4263"
+             d="m 271.55311,381.79886 -16.22485,0 0.56996,-5.112 16.22485,0 -0.56996,5.112 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4308"
+             d="m 290.28163,374.75152 -16.22485,0 0.56996,-5.076 16.22485,0 -0.56996,5.076 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+          <path
+             inkscape:connector-curvature="0"
+             id="path4265"
+             d="m 289.14171,381.79886 -16.22485,0 0.56996,-5.112 16.22485,0 -0.56996,5.112 z"
+             style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+        </g>
+        <path
+           style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:125%;font-family:'Electric Boots';-inkscape-font-specification:'Electric Boots';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+           inkscape:connector-curvature="0"
+           id="path4267"
+           d="m 292.21533,367.72719 3.26777,7.992 -5.01565,7.992 4.52168,2.484 6.83952,-10.476 -4.52168,-10.44 -5.09164,2.448 z" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/inst/progresstest/DESCRIPTION b/inst/progresstest/DESCRIPTION
new file mode 100644
index 0000000..bdfeb7a
--- /dev/null
+++ b/inst/progresstest/DESCRIPTION
@@ -0,0 +1,12 @@
+Package: progresstest
+Title: Testing Terminal Progress Bars
+Version: 1.0.0
+Authors at R: person("Gabor", "Csardi", , "csardi.gabort at gmail.com", role = c("aut", "cre"))
+Description: Test progress bars from the progress package.
+License: MIT + file LICENSE
+Imports:
+    progress,
+    Rcpp
+LinkingTo:
+    progress,
+    Rcpp
diff --git a/inst/progresstest/LICENSE b/inst/progresstest/LICENSE
new file mode 100644
index 0000000..9236fad
--- /dev/null
+++ b/inst/progresstest/LICENSE
@@ -0,0 +1,2 @@
+YEAR: 2015
+COPYRIGHT HOLDER: Gabor Csardi
diff --git a/inst/progresstest/NAMESPACE b/inst/progresstest/NAMESPACE
new file mode 100644
index 0000000..6b525d9
--- /dev/null
+++ b/inst/progresstest/NAMESPACE
@@ -0,0 +1,6 @@
+# Generated by roxygen2 (4.1.0): do not edit by hand
+
+importFrom(Rcpp,loadRcppModules)
+importFrom(progress,progress_bar)
+useDynLib(progresstest)
+export(my_test_progress)
diff --git a/inst/progresstest/R/RcppExports.R b/inst/progresstest/R/RcppExports.R
new file mode 100644
index 0000000..c1257d2
--- /dev/null
+++ b/inst/progresstest/R/RcppExports.R
@@ -0,0 +1,11 @@
+# This file was generated by Rcpp::compileAttributes
+# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
+
+test_progress <- function(formatSEXP = "[:bar] :percent ") {
+    .Call('progresstest_test_progress', PACKAGE = 'progresstest', formatSEXP)
+}
+
+test_units <- function() {
+    .Call('progresstest_test_units', PACKAGE = 'progresstest')
+}
+
diff --git a/inst/progresstest/R/test.R b/inst/progresstest/R/test.R
new file mode 100644
index 0000000..0c077fe
--- /dev/null
+++ b/inst/progresstest/R/test.R
@@ -0,0 +1,9 @@
+
+#' @importFrom progress progress_bar
+#' @importFrom Rcpp loadRcppModules
+#' @useDynLib progresstest
+#' @export
+
+my_test_progress <- function(format = "[:bar] :percent ") {
+  test_progress(format)
+}
diff --git a/inst/progresstest/README.md b/inst/progresstest/README.md
new file mode 100644
index 0000000..70377f4
--- /dev/null
+++ b/inst/progresstest/README.md
@@ -0,0 +1,10 @@
+
+## Example package for the C++ API of `progress`
+
+Progress bars for your C++ code in R packages.
+The `progress` package has a pure C++ API for
+managing progress bars. This is an example package
+that shows how to use it.
+
+The test package uses Rcpp, for simplicity, but this
+is not necessary, the API itself does not rely on Rcpp.
diff --git a/inst/progresstest/src/RcppExports.cpp b/inst/progresstest/src/RcppExports.cpp
new file mode 100644
index 0000000..59ce6f2
--- /dev/null
+++ b/inst/progresstest/src/RcppExports.cpp
@@ -0,0 +1,28 @@
+// This file was generated by Rcpp::compileAttributes
+// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
+
+#include <Rcpp.h>
+
+using namespace Rcpp;
+
+// test_progress
+Rcpp::CharacterVector test_progress(Rcpp::CharacterVector formatSEXP);
+RcppExport SEXP progresstest_test_progress(SEXP formatSEXPSEXP) {
+BEGIN_RCPP
+    Rcpp::RObject __result;
+    Rcpp::RNGScope __rngScope;
+    Rcpp::traits::input_parameter< Rcpp::CharacterVector >::type formatSEXP(formatSEXPSEXP);
+    __result = Rcpp::wrap(test_progress(formatSEXP));
+    return __result;
+END_RCPP
+}
+// test_units
+Rcpp::CharacterVector test_units();
+RcppExport SEXP progresstest_test_units() {
+BEGIN_RCPP
+    Rcpp::RObject __result;
+    Rcpp::RNGScope __rngScope;
+    __result = Rcpp::wrap(test_units());
+    return __result;
+END_RCPP
+}
diff --git a/inst/progresstest/src/test.cpp b/inst/progresstest/src/test.cpp
new file mode 100644
index 0000000..aa189d9
--- /dev/null
+++ b/inst/progresstest/src/test.cpp
@@ -0,0 +1,58 @@
+
+#include <Rcpp.h>
+#include <RProgress.h>
+#include <unistd.h>
+
+// [[Rcpp::export]]
+Rcpp::CharacterVector test_progress(Rcpp::CharacterVector formatSEXP =
+				    "[:bar] :percent ") {
+  BEGIN_RCPP
+
+  const char *format = formatSEXP[0];
+  RProgress::RProgress pb(format);
+
+  pb.tick(0);
+  for (int i = 0; i < 100; i++) {
+    usleep(2.0 / 100 * 1000000);
+    pb.tick();
+  }
+
+  Rcpp::CharacterVector result(1);
+  result[0] = "DONE";
+  return result;
+
+  END_RCPP
+}
+
+// [[Rcpp::export]]
+Rcpp::CharacterVector test_units() {
+  BEGIN_RCPP
+
+  Rcpp::CharacterVector result(20);
+
+  result[0] = RProgress::RProgress::vague_dt(0);
+  result[1] = RProgress::RProgress::vague_dt(1);
+  result[2] = RProgress::RProgress::vague_dt(1.1);
+  result[3] = RProgress::RProgress::vague_dt(51);
+  result[4] = RProgress::RProgress::vague_dt(2 * 60);
+  result[5] = RProgress::RProgress::vague_dt(3 * 60 * 60);
+  result[6] = RProgress::RProgress::vague_dt(3 * 60 * 60 * 24);
+  result[7] = RProgress::RProgress::vague_dt(31 * 60 * 60 * 24);
+  result[8] = RProgress::RProgress::vague_dt(400 * 60 * 60 * 24);
+  result[9] = RProgress::RProgress::vague_dt(1500 * 60 * 60 * 24);
+
+  result[10] = RProgress::RProgress::pretty_bytes(0);
+  result[11] = RProgress::RProgress::pretty_bytes(133);
+  result[12] = RProgress::RProgress::pretty_bytes(1337);
+  result[13] = RProgress::RProgress::pretty_bytes(13337);
+  result[14] = RProgress::RProgress::pretty_bytes(133337);
+  result[15] = RProgress::RProgress::pretty_bytes(1333337);
+  result[16] = RProgress::RProgress::pretty_bytes(13333337);
+  result[17] = RProgress::RProgress::pretty_bytes(133333337);
+  result[18] = RProgress::RProgress::pretty_bytes(1333333337);
+  result[19] = RProgress::RProgress::pretty_bytes(13333333337);
+
+  return result;
+
+  END_RCPP
+}
diff --git a/man/progress_bar.Rd b/man/progress_bar.Rd
new file mode 100644
index 0000000..c78afb4
--- /dev/null
+++ b/man/progress_bar.Rd
@@ -0,0 +1,156 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/progress.R
+\name{progress_bar}
+\alias{progress_bar}
+\title{Progress bar in the terminal}
+\description{
+Progress bars are configurable, may include percentage, elapsed time,
+and/or the estimated completion time. They work in the command line,
+in Emacs and in R Studio. The progress package was heavily influenced by
+https://github.com/tj/node-progress
+}
+\section{Creating the progress bar}{
+
+A progress bar is an R6 object, that can be created with
+\code{progress_bar$new()}. It has the following arguments:
+\describe{
+  \item{format}{The format of the progress bar. A number of
+    tokens can be used here, see them below. It defaults to
+    \code{"[:bar] :percent"}, which means that the progress
+    bar is within brackets on the left, and the percentage
+    is printed on the right.}
+  \item{total}{Total number of ticks to complete. Defaults to 100.}
+  \item{width}{Width of the progress bar. Default is the current
+    terminal width (see \code{options()} and \code{width}) minus two.}
+  \item{stream}{The output stream to put the progress bar on.
+    It defaults to \code{stderr()}, except in R Studio that has
+    a bug when printing on the standard error, so there we use
+    \code{stdout}. If the output stream is not a terminal and
+    we are not in R Studio, then no progress bar is printed.}
+  \item{complete}{Completion character, defaults to \code{=}.}
+  \item{incomplete}{Incomplete character, defaults to \code{-}.}
+  \item{callback}{Callback function to call when the progress
+    bar finishes. The progress bar object itself is passed to it
+    as the single parameter.}
+  \item{clear}{Whether to clear the progress bar on completion.
+    Defaults to \code{TRUE}.}
+  \item{show_after}{Amount of time in seconds, after which the progress
+    bar is shown on the screen. For very short processes,
+    it is probably not worth showing it at all. Defaults to two
+    tenth of a second.}
+  \item{force}{Whether to force showing the progress bar,
+    even if the given (or default) stream does not seem support it.}
+}
+}
+
+\section{Using the progress bar}{
+
+Two functions can update a progress bar. \code{progress_bar$tick()}
+increases the number of ticks by one (or another specified value).
+\code{progress_bar$update()} sets a given ratio.
+
+The progress bar is displayed after the first `tick` command.
+This might not be desirable for long computations, because
+nothing is shown before the first tick. It is good practice to
+call `tick(0)` at the beginning of the computation or download,
+which shows the progress bar immediately.
+}
+
+\section{Tokens}{
+
+They can be used in the \code{format} argument when creating the
+progress bar.
+\describe{
+  \item{:bar}{The progress bar itself.}
+  \item{:current}{Current tick number.}
+  \item{:total}{Total ticks.}
+  \item{:elapsed}{Elapsed time in seconds.}
+  \item{:eta}{Estimated completion time in seconds.}
+  \item{:percent}{Completion percentage.}
+  \item{:rate}{Download rate, bytes per second. See example below.}
+  \item{:bytes}{Shows :current, formatted as bytes. Useful
+     for downloads or file reads if you don't know the size of the
+     file in advance. See example below.}
+  \item{:spin}{Shows a spinner that updates even when progress is
+     advanced by zero.}
+}
+
+Custom tokens are also supported, and you need to pass their
+values to \code{progress_bar$tick()} or \code{progress_bar$update()},
+in a named list. See example below.
+}
+\examples{
+
+## We don't run the examples on CRAN, because they takes >10s
+## altogether. Unfortunately it is hard to create a set of
+## meaningful progress bar examples that also run quickly.
+\dontrun{
+
+## Basic
+pb <- progress_bar$new(total = 100)
+for (i in 1:100) {
+  pb$tick()
+  Sys.sleep(1 / 100)
+}
+
+## ETA
+pb <- progress_bar$new(
+  format = "  downloading [:bar] :percent eta: :eta",
+  total = 100, clear = FALSE, width= 60)
+for (i in 1:100) {
+  pb$tick()
+  Sys.sleep(1 / 100)
+}
+
+## Elapsed time
+pb <- progress_bar$new(
+  format = "  downloading [:bar] :percent in :elapsed",
+  total = 100, clear = FALSE, width= 60)
+for (i in 1:100) {
+  pb$tick()
+  Sys.sleep(1 / 100)
+}
+
+## Spinner
+pb <- progress_bar$new(
+  format = "(:spin) [:bar] :percent",
+  total = 30, clear = FALSE, width = 60)
+for (i in 1:30) {
+  pb$tick()
+  Sys.sleep(3 / 100)
+}
+
+## Custom tokens
+pb <- progress_bar$new(
+  format = "  downloading :what [:bar] :percent eta: :eta",
+  clear = FALSE, total = 200, width = 60)
+f <- function() {
+  for (i in 1:100) {
+    pb$tick(tokens = list(what = "foo   "))
+    Sys.sleep(2 / 100)
+  }
+  for (i in 1:100) {
+    pb$tick(tokens = list(what = "foobar"))
+    Sys.sleep(2 / 100)
+  }
+}
+f()
+
+## Download (or other) rates
+pb <- progress_bar$new(
+  format = "  downloading foobar at :rate, got :bytes in :elapsed",
+  clear = FALSE, total = 1e7, width = 60)
+f <- function() {
+  for (i in 1:100) {
+    pb$tick(sample(1:100 * 1000, 1))
+    Sys.sleep(2/100)
+  }
+  pb$tick(1e7)
+  invisible()
+}
+f()
+
+}
+
+}
+
diff --git a/tests/testthat.R b/tests/testthat.R
new file mode 100644
index 0000000..cb63df2
--- /dev/null
+++ b/tests/testthat.R
@@ -0,0 +1,6 @@
+
+if (Sys.getenv("NOT_CRAN", "") != "") {
+  library(testthat)
+  library(progress)
+  test_check("progress")
+}
diff --git a/tests/testthat/helper.R b/tests/testthat/helper.R
new file mode 100644
index 0000000..d89ac9f
--- /dev/null
+++ b/tests/testthat/helper.R
@@ -0,0 +1,39 @@
+
+get_output <- function(..., stream = stdout()) {
+
+  if (identical(stream, stdout())) {
+    type <- "output"
+  } else if (identical(stream, stderr())) {
+    type <- "message"
+  }
+
+  cleanup <- function() {
+    unlink(tmp)
+    sink(NULL, type = type)
+  }
+
+  tmp <- tempfile()
+  on.exit(cleanup())
+
+  sink(tmp, type = type)
+  force(...)
+
+  ## Windows has some strange readBin and sink interplay,
+  ## so we need to remove the sink before reading the file
+  sink(NULL, type = type)
+  x <- readBin(tmp, raw(0), n = file.info(tmp)$size)
+  unlink(tmp)
+
+  ## No cleanup is needed any more
+  on.exit(force(1))
+
+  rawToChar(x)
+}
+
+win_newline <- function(..., collapse = NULL) {
+  x <- paste0(...)
+  if (.Platform$OS.type == "windows") {
+    x <- gsub("\n", "\r\n", x, fixed = TRUE)
+  }
+  x
+}
diff --git a/tests/testthat/test-cpp.R b/tests/testthat/test-cpp.R
new file mode 100644
index 0000000..6453a94
--- /dev/null
+++ b/tests/testthat/test-cpp.R
@@ -0,0 +1,42 @@
+
+context("C++ API")
+
+test_that("C++ API works", {
+
+  skip_on_cran()
+
+  Sys.setenv("R_TESTS" = "")
+
+  ## Need to "link to" the current package
+  test_pkg_dir <- system.file("progresstest", package = "progress")
+
+  f <- file(tempfile(), open = "w")
+  sink(f)
+  sink(f, type = "message")
+  install.packages("Rcpp", repos = c(CRAN = "https://cran.rstudio.com"),
+                   quiet = TRUE)
+  sink(NULL, type = "message")
+  sink(NULL)
+  close(f)
+  unlink(f)
+
+  ## OK, we could install it
+  try(silent = TRUE, unloadNamespace("progresstest"))
+  install.packages(test_pkg_dir, repos = NULL, type = "source",
+                   quiet = TRUE)
+
+  ## OK, we could load it
+  do.call("library", list("progresstest", character.only = TRUE))
+
+  f <- file(tempfile(), open = "w")
+  sink(f)
+  sink(f, type = "message")
+  my_test_progress()
+  sink(NULL, type = "message")
+  sink(NULL)
+  close(f)
+  unlink(f)
+
+  try(silent = TRUE, unloadNamespace("progresstest"))
+
+})
diff --git a/tests/testthat/test-progress.R b/tests/testthat/test-progress.R
new file mode 100644
index 0000000..14c67b9
--- /dev/null
+++ b/tests/testthat/test-progress.R
@@ -0,0 +1,389 @@
+
+context("Progress bar")
+
+test_that("Vanilla progress bar works", {
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20)
+    for (i in 1:5) {
+      pb$tick(20)
+    }
+  })
+
+  sout <- win_newline(
+    "\r[===----------]  20%",
+    "\r[=====--------]  40%",
+    "\r[========-----]  60%",
+    "\r[==========---]  80%",
+    "\r[=============] 100%",
+    "\r                    ",
+    "\r"
+  )
+
+  expect_equal(out, sout)
+
+})
+
+test_that("Update method works", {
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20)
+    updates = c(20, 40, 20, 80, 100) / 100
+    for (i in 1:5) {
+      pb$update(updates[i])
+    }
+  })
+
+  sout <- win_newline(
+    "\r[===----------]  20%",
+    "\r[=====--------]  40%",
+    "\r[===----------]  20%",
+    "\r[==========---]  80%",
+    "\r[=============] 100%",
+    "\r                    ",
+    "\r"
+  )
+
+  expect_equal(out, sout)
+
+})
+
+test_that("Calling tick(0)", {
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20)
+    pb$tick(0)
+    for (i in 1:5) {
+      pb$tick(20)
+    }
+  })
+
+  sout <- win_newline(
+    "\r[-------------]   0%",
+    "\r[===----------]  20%",
+    "\r[=====--------]  40%",
+    "\r[========-----]  60%",
+    "\r[==========---]  80%",
+    "\r[=============] 100%",
+    "\r                    ",
+    "\r"
+  )
+
+  expect_equal(out, sout)
+
+})
+
+test_that("Digress", {
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20)
+    f <- function() {
+      pb$tick(50)
+      pb$tick(-20)
+      pb$tick(50)
+      pb$tick(-30)
+      pb$tick(100)
+    }
+    f()
+  })
+
+  sout <- win_newline(
+    "\r[======-------]  50%",
+    "\r[====---------]  30%",
+    "\r[==========---]  80%",
+    "\r[======-------]  50%",
+    "\r[=============] 100%",
+    "\r                    ",
+    "\r"
+  )
+
+  expect_equal(out, sout)
+})
+
+test_that("No :bar item, :current and :total tokens", {
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20, total = 10,
+                           clear = FALSE, format = ":current/:total")
+    pb$tick(2)
+    pb$tick(5)
+    pb$tick(3)
+  })
+
+  sout <- win_newline(
+    "\r2/10",
+    "\r7/10",
+    "\r10/10\n"
+  )
+
+  expect_equal(out, sout)
+})
+
+## This is somewhat timing dependent, but
+## should work in general
+
+test_that(":eta and :elapsed tokens", {
+
+  skip_on_cran()
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20, total = 4,
+                           format = "[:eta :elapsed]")
+    pb$tick(0)
+    Sys.sleep(1)    # 1 sec per tick
+    pb$tick(1)      # So 3 more ticks is 3 secs
+    Sys.sleep(1)
+    pb$tick(1)      # 2 more is 2 secs
+    pb$tick(2)
+  })
+
+  sout <- win_newline(
+    "\r[ ?s  0s]",
+    "\r[ 3s  1s]",
+    "\r[ 2s  2s]",
+    "\r[ 0s  2s]",
+    "\r                    ",
+    "\r"
+  )
+
+  expect_equal(out, sout)
+})
+
+test_that("complete and incomplete chars", {
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20, total = 5,
+                           complete = "#", incomplete = " ",
+                           clear = FALSE)
+    for (i in 1:5) pb$tick(1)
+  })
+
+  sout <- win_newline(
+    "\r[###          ]  20%",
+    "\r[#####        ]  40%",
+    "\r[########     ]  60%",
+    "\r[##########   ]  80%",
+    "\r[#############] 100%",
+    "\n"
+  )
+
+  expect_equal(out, sout)
+})
+
+test_that("callback function", {
+
+  x <- ""
+  cb <- function() {
+    x <<- "done"
+  }
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20, callback = cb)
+    pb$tick(0)
+    pb$tick(50)
+    pb$tick(50)
+  })
+
+  expect_equal(x, "done")
+
+  x <- ""
+
+  str <- file(tmp <- tempfile(), open = "w")
+  on.exit(unlink(tmp), add = TRUE)
+  pb <- progress_bar$new(stream = str,
+                         show_after = 0, width = 20, callback = cb)
+  pb$tick(0)
+  pb$tick(50)
+  pb$tick(50)
+  close(str)
+
+  expect_equal(x, "done")
+
+})
+
+test_that("clearing and not clearing", {
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20, clear = TRUE)
+    pb$tick(0)
+    pb$tick(50)
+    pb$tick(50)
+  })
+
+  sout <- win_newline(
+    "\r[-------------]   0%",
+    "\r[======-------]  50%",
+    "\r[=============] 100%",
+    "\r                    ",
+    "\r"
+  )
+
+  expect_equal(out, sout)
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20, clear = FALSE)
+    pb$tick(0)
+    pb$tick(50)
+    pb$tick(50)
+  })
+
+  sout <- win_newline(
+    "\r[-------------]   0%",
+    "\r[======-------]  50%",
+    "\r[=============] 100%",
+    "\n"
+  )
+
+  expect_equal(out, sout)
+})
+
+test_that("show_after argument", {
+
+  skip_on_cran()
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = .1, width = 20, clear = TRUE)
+    pb$tick(0)
+    pb$tick(25)
+    pb$tick(25)
+    Sys.sleep(.1)
+    pb$tick(25)
+    pb$tick(25)
+  })
+
+  sout <- win_newline(
+    "\r[==========---]  75%",
+    "\r[=============] 100%",
+    "\r                    ",
+    "\r"
+  )
+
+  expect_equal(out, sout)
+
+})
+
+test_that("custom tokens", {
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20,
+                           format = ":what [:bar] :percent",
+                           clear = FALSE, total = 200)
+    pb$tick(50, tokens = list(what = "foo   "))
+    pb$tick(50, tokens = list(what = "foo   "))
+    pb$tick(50, tokens = list(what = "foobar"))
+    pb$tick(50, tokens = list(what = "foobar"))
+  })
+
+  sout <- win_newline(
+    "\rfoo    [==----]  25%",
+    "\rfoo    [===---]  50%",
+    "\rfoobar [====--]  75%",
+    "\rfoobar [======] 100%",
+    "\n"
+  )
+
+  expect_equal(out, sout)
+})
+
+test_that("bar adepts to width of custom tokens", {
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20,
+                           format = ":what [:bar] :percent",
+                           clear = FALSE, total = 200)
+    pb$tick(50, tokens = list(what = "text"))
+    pb$tick(50, tokens = list(what = "long text"))
+    pb$tick(100, tokens = list(what = "text"))
+  })
+
+  sout <- win_newline(
+    "\rtext [==------]  25%",
+    "\rlong text [==-]  50%",
+    "\rtext [========] 100%",
+    "\n"
+  )
+
+  expect_equal(out, sout)
+})
+
+test_that("custom streams", {
+
+  str <- file(tmp <- tempfile(), open = "w")
+  on.exit(unlink(tmp), add = TRUE)
+  pb <- progress_bar$new(stream = str, force = TRUE,
+                         show_after = 0, width = 20)
+  pb$tick(0)
+  pb$tick(50)
+  pb$tick(50)
+  close(str)
+
+  out <- rawToChar(readBin(tmp, raw(0), n = file.info(tmp)$size))
+
+  sout <- win_newline(
+    "\r[-------------]   0%",
+    "\r[======-------]  50%",
+    "\r[=============] 100%",
+    "\r                    ",
+    "\r"
+  )
+
+  expect_equal(out, sout)
+})
+
+test_that(":rate and :bytes tokens", {
+
+  skip_on_cran()
+
+  out <- get_output({
+    pb <- progress_bar$new(stream = stdout(), force = TRUE,
+                           show_after = 0, width = 20, total = 4 * 1024,
+                           format = "[:rate :bytes]")
+    pb$tick(0)
+    Sys.sleep(1)       # 1 sec per 1000 bytes
+    pb$tick(1024)      # So 3000 more bytes is 3 secs
+    Sys.sleep(1)
+    pb$tick(1024)      # 2000 more is 2 secs
+    pb$tick(2048)
+  })
+
+  ## Next output line might be shorter, so 'progress_bar$render'
+  ## might to erase it first
+  soutm <- win_newline(
+    "^\\r\\[0 B/s 0 B\\]",
+    "\\r?[ ]*",
+    "\\r\\[[0-9\\.]+ k?B/s [0-9\\.]+ k?B\\]",
+    "\\r?[ ]*",
+    "\\r\\[[0-9\\.]+ k?B/s [0-9\\.]+ kB\\]",
+    "\\r?[ ]*",
+    "\\r\\[[0-9\\.]+ k?B/s [0-9\\.]+ kB\\]",
+    "\\r[ ]*",
+    "\\r$"
+  )
+
+  expect_match(out, soutm)
+})
+
+test_that("very quick loops, only the nothing is shown", {
+
+  out <- get_output({
+    pb <- progress_bar$new(total = 100, stream = stdout(), force = TRUE,
+                           width = 20)
+    for (i in 1:100) pb$tick()
+  })
+
+  sout <- win_newline("")
+  expect_equal(out, sout)
+
+})

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-progress.git



More information about the debian-med-commit mailing list