├── .Rbuildignore
├── .github
├── .gitignore
└── workflows
│ ├── check-standard.yaml
│ └── test-coverage.yaml
├── .gitignore
├── DESCRIPTION
├── LICENSE
├── LICENSE.md
├── NAMESPACE
├── NEWS.md
├── R
├── get_checksum.R
├── is_number_valid.R
└── is_valid.R
├── README.md
├── cran-comments.md
├── docs
├── 404.html
├── CNAME
├── LICENSE-text.html
├── LICENSE.html
├── authors.html
├── bootstrap-toc.css
├── bootstrap-toc.js
├── docsearch.css
├── docsearch.js
├── index.html
├── link.svg
├── news
│ └── index.html
├── pkgdown.css
├── pkgdown.js
├── pkgdown.yml
├── reference
│ ├── Rplot001.png
│ ├── get_checksum.html
│ ├── index.html
│ ├── is_number_valid.html
│ └── is_valid.html
└── sitemap.xml
├── man
├── get_checksum.Rd
├── is_number_valid.Rd
└── is_valid.Rd
├── nhsnumber.Rproj
└── tests
├── testthat.R
└── testthat
├── test-get_checksum.R
├── test-is_number_valid.R
└── test-is_valid.R
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^.*\.Rproj$
2 | ^\.Rproj\.user$
3 | ^LICENSE\.md$
4 | ^CRAN-RELEASE$
5 | ^cran-comments\.md$
6 | ^\.github$
7 | docs
8 |
--------------------------------------------------------------------------------
/.github/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 |
--------------------------------------------------------------------------------
/.github/workflows/check-standard.yaml:
--------------------------------------------------------------------------------
1 | # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag.
2 | # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - master
8 | pull_request:
9 | branches:
10 | - main
11 | - master
12 |
13 | name: R-CMD-check
14 |
15 | jobs:
16 | R-CMD-check:
17 | runs-on: ${{ matrix.config.os }}
18 |
19 | name: ${{ matrix.config.os }} (${{ matrix.config.r }})
20 |
21 | strategy:
22 | fail-fast: false
23 | matrix:
24 | config:
25 | # - {os: windows-latest, r: 'release'}
26 | # - {os: macOS-latest, r: 'release'}
27 | - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
28 | # - {os: ubuntu-20.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
29 |
30 | env:
31 | R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
32 | RSPM: ${{ matrix.config.rspm }}
33 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
34 |
35 | steps:
36 | - uses: actions/checkout@v2
37 |
38 | - uses: r-lib/actions/setup-r@v1
39 | with:
40 | r-version: ${{ matrix.config.r }}
41 |
42 | - uses: r-lib/actions/setup-pandoc@v1
43 |
44 | - name: Query dependencies
45 | run: |
46 | install.packages('remotes')
47 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
48 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
49 | shell: Rscript {0}
50 |
51 | - name: Cache R packages
52 | if: runner.os != 'Windows'
53 | uses: actions/cache@v2
54 | with:
55 | path: ${{ env.R_LIBS_USER }}
56 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
57 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
58 |
59 | - name: Install system dependencies
60 | if: runner.os == 'Linux'
61 | run: |
62 | while read -r cmd
63 | do
64 | eval sudo $cmd
65 | done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))')
66 |
67 | - name: Install dependencies
68 | run: |
69 | remotes::install_deps(dependencies = TRUE)
70 | remotes::install_cran("rcmdcheck")
71 | shell: Rscript {0}
72 |
73 | - name: Check
74 | env:
75 | _R_CHECK_CRAN_INCOMING_REMOTE_: false
76 | run: rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "warning", check_dir = "check")
77 | shell: Rscript {0}
78 |
79 | - name: Upload check results
80 | if: failure()
81 | uses: actions/upload-artifact@main
82 | with:
83 | name: ${{ runner.os }}-r${{ matrix.config.r }}-results
84 | path: check
85 |
--------------------------------------------------------------------------------
/.github/workflows/test-coverage.yaml:
--------------------------------------------------------------------------------
1 | on:
2 | push:
3 | branches:
4 | - main
5 | - master
6 | pull_request:
7 | branches:
8 | - main
9 | - master
10 |
11 | name: test-coverage
12 |
13 | jobs:
14 | test-coverage:
15 | runs-on: ubuntu-20.04
16 | env:
17 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
18 | steps:
19 | - uses: actions/checkout@v2
20 |
21 | - uses: r-lib/actions/setup-r@v1
22 |
23 | # - uses: r-lib/actions/setup-pandoc@v1
24 |
25 | - name: Query dependencies
26 | run: |
27 | cran_mirror <- "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"
28 | install.packages('remotes', repos = cran_mirror)
29 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
30 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
31 | shell: Rscript {0}
32 |
33 | - name: Cache R packages
34 | uses: actions/cache@v2
35 | with:
36 | path: ${{ env.R_LIBS_USER }}
37 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
38 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
39 |
40 | - name: Install dependencies
41 | run: |
42 | cran_mirror <- "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"
43 | install.packages(c("remotes"), repos = cran_mirror)
44 | remotes::install_deps(dependencies = TRUE, repos = cran_mirror)
45 | remotes::install_cran("covr", repos = cran_mirror)
46 | shell: Rscript {0}
47 |
48 | - name: Test coverage
49 | run: covr::codecov()
50 | shell: Rscript {0}
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .RData
4 | .Ruserdata
5 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: nhsnumber
2 | Type: Package
3 | Title: Tools for Working with NHS Number Checksums
4 | Version: 0.1.2
5 | Authors@R: c(
6 | person("Mark", "Sellors", , "rstats@5vcc.com", c("aut", "cre", "cph"))
7 | )
8 | Description: Provides functions for working with NHS number checksums.
9 | The UK's National Health Service issues NHS numbers to all users of its
10 | services and this package implements functions for verifying that the
11 | numbers are valid according to the checksum scheme the NHS use.
12 | Numbers can be validated and checksums created.
13 | URL: https://github.com/sellorm/nhsnumber
14 | BugReports: https://github.com/sellorm/nhsnumber/issues
15 | License: MIT + file LICENSE
16 | Encoding: UTF-8
17 | LazyData: true
18 | Roxygen: list(markdown = TRUE)
19 | RoxygenNote: 7.1.2
20 | Suggests:
21 | testthat (>= 2.1.0)
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | YEAR: 2019
2 | COPYRIGHT HOLDER: Mark Sellors
3 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2019 Mark Sellors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | export(get_checksum)
4 | export(is_valid)
5 |
--------------------------------------------------------------------------------
/NEWS.md:
--------------------------------------------------------------------------------
1 | # nhsnumber 0.1.2
2 |
3 | * Properly handles `NA` in input data (#3)
4 | * Consolidated email addresses used on CRAN - now matches my other package, rlog
5 |
6 | # nhsnumber 0.1.1
7 |
8 | * Added a `NEWS.md` file to track changes to the package.
9 | * Preparing for first CRAN submission
10 |
--------------------------------------------------------------------------------
/R/get_checksum.R:
--------------------------------------------------------------------------------
1 | #' Calculates NHS number checksums
2 | #'
3 | #' NHS numbers are 10 digit numbers where the 10th digit is a checksum.
4 | #' This function takes the 9 core digits of the NHS number and calculates the
5 | #' checksums.
6 | #'
7 | #' This function has been created using information from:
8 | #' https://en.wikipedia.org/wiki/NHS_number
9 | #' and various NHS sources
10 | #'
11 | #' @param nhs_number A 9 digit NHS numbers to validate
12 | #' @param full_output Boolean that controls display of warning messages
13 | #' @return Checksum or the complete NHS number including the checksum.
14 | #' @examples
15 | #' get_checksum(123456788)
16 | #' get_checksum(123456788, full_output = TRUE)
17 | #' @export
18 |
19 | get_checksum <- function(nhs_number, full_output = FALSE) {
20 | if (is.na(
21 | suppressWarnings(
22 | as.numeric(nhs_number)
23 | )
24 | )
25 | ) {
26 | stop("nhs_number is invalid -
27 | should be a 9 digit number, not text")
28 | }
29 | if (nchar(nhs_number) != 9) {
30 | stop("nhs_number is incorrect length -
31 | should be 9 digits as checksum is not required")
32 | }
33 | split_number <- as.numeric(strsplit(as.character(nhs_number), "")[[1]])
34 | multipliers <- c(10, 9, 8, 7, 6, 5, 4, 3, 2)
35 | multiplied <- split_number * multipliers
36 | remainder <- sum(multiplied) %% 11
37 | check_digit <- 11 - remainder
38 |
39 | # A check digit of 10 is not permitted
40 | # an example number with a checksum of 10 is 123456789
41 | if (check_digit == 10) {
42 | stop("Input sequence is invalid
43 | Checksum was 10 which is not permissable")
44 | }
45 |
46 | # A check digit of 11 is re-written as a 0
47 | if (check_digit == 11) {
48 | check_digit <- 0
49 | }
50 | if (full_output) {
51 | as.numeric(paste0(nhs_number, check_digit))
52 | } else {
53 | check_digit
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/R/is_number_valid.R:
--------------------------------------------------------------------------------
1 | #' Checks validity of an NHS number
2 | #'
3 | #' NHS numbers are 10 digit numbers where the 10th digit is a checksum.
4 | #' This function validates the checksums of the supplied NHS numbers.
5 | #'
6 | #' @param nhs_number A 10 digit NHS number to validate
7 | #' @param warn Boolean that controls display of warning messages
8 | #' @examples
9 | #' is_valid(1234567881)
10 | #' is_valid(1234567890, warn = FALSE)
11 | is_number_valid <- function(nhs_number, warn = TRUE) {
12 | if (is.na(nhs_number)) {
13 | if (warn == TRUE) {
14 | warning("nhs_number contains 'NA', corresponding result will be FALSE")
15 | }
16 | return(FALSE)
17 | }
18 |
19 | if (nchar(nhs_number) != 10) {
20 | if (warn == TRUE) {
21 | warning("nhs_number is incorrect length - should be 10 digits")
22 | }
23 | }
24 |
25 | no_checksum <- substr(nhs_number, 1, 9)
26 | # returns FALSE if get_checksum throws an error
27 | checksum <- tryCatch(
28 | {
29 | nhsnumber::get_checksum(no_checksum)
30 | },
31 | error = function(e) {
32 | FALSE
33 | }
34 | )
35 |
36 | if (checksum == substr(nhs_number, 10, 10)) {
37 | TRUE
38 | } else {
39 | FALSE
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/R/is_valid.R:
--------------------------------------------------------------------------------
1 | #' Checks validity of NHS numbers
2 | #'
3 | #' NHS numbers are 10 digit numbers where the 10th digit is a checksum.
4 | #' This function validates the checksums of the supplied NHS numbers.
5 | #'
6 | #' @param nhs_number A vector of 10 digit NHS numbers to validate
7 | #' @param warn Boolean that controls display of warning messages
8 | #' @return A logical vector indicating the validity of each input value
9 | #' @examples
10 | #' is_valid(1234567881)
11 | #' is_valid(c(1234567881, 1234512345, 123456789))
12 | #' is_valid(1234567890, warn = FALSE)
13 | #' @export
14 |
15 | is_valid <- function(nhs_number, warn = TRUE) {
16 | if (!is.vector(nhs_number)) {
17 | stop("nhs_number must be a vector")
18 | }
19 | unlist(lapply(nhs_number, function(x) {
20 | is_number_valid(x, warn = warn)
21 | }))
22 | }
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # nhsnumber
3 |
4 |
5 | [](https://CRAN.R-project.org/package=nhsnumber)
6 | [](https://github.com/sellorm/nhsnumber/actions?query=workflow%3AR-CMD-check)
7 | [](https://app.codecov.io/gh/sellorm/nhsnumber)
8 | [](https://lifecycle.r-lib.org/articles/stages.html#stable)
9 |
10 |
11 | The goal of nhsnumber is to provide some simple functions for working with NHS numbers in R.
12 |
13 | ## NHS Number Overview
14 |
15 | NHS numbers are issued to patients of the NHS in the UK.
16 |
17 | The number consists of 9 digits and a single digit checksum.
18 |
19 | For more information, please see the [NHS number Wikipedia article](https://en.wikipedia.org/wiki/NHS_number) on the subject.
20 |
21 | ## Installation
22 |
23 | You can install the released version of nhsnumber from [CRAN](https://cran.r-project.org/package=nhsnumber) with:
24 |
25 | ``` r
26 | install.packages("nhsnumber")
27 | ```
28 |
29 | You can install the development version of nhsnumber from [GitHub](https://github.com/sellorm/nhsnumber) with:
30 |
31 | ``` r
32 | devtools::install_github("sellorm/nhsnumber")
33 | ```
34 |
35 | ## Example
36 |
37 | The `is_valid` function takes a vector of NHS numbers and returns TRUE or FALSE depending on whether the checksum is successfully validated.
38 |
39 | ``` r
40 | x <- c(9876543210, 1234567890, 1234567881)
41 | nhsnumber::is_valid(x)
42 | ```
43 |
44 | Which returns:
45 |
46 | ```
47 | TRUE FALSE TRUE
48 | ```
49 |
50 | It's also possible to generate the checksums using the `get_checksum` function. This function uses the 9 core digits and returns either the checksum on its own, or the full 10 digit number.
51 |
52 | ``` r
53 | nhsnumber::get_checksum(123456788)
54 | ```
55 |
56 | which returns:
57 |
58 | ```
59 | 1
60 | ```
61 |
62 | or with the full output:
63 |
64 | ``` r
65 | nhsnumber::get_checksum(123456788, full_output = TRUE)
66 | ```
67 |
68 | Which returns:
69 |
70 | ```
71 | 1234567881
72 | ```
73 |
74 | Some number combinations are invalid and these will throw an error, for example:
75 |
76 | ``` r
77 | nhsnumber::get_checksum(123456789)
78 | ```
79 |
80 | Which results in this:
81 |
82 | ```
83 | Error in nhsnumber::get_checksum(123456789) : Input sequence is invalid
84 | Checksum was 10 which is not permissable
85 | ```
86 |
87 |
88 |
--------------------------------------------------------------------------------
/cran-comments.md:
--------------------------------------------------------------------------------
1 | ## Resubmission
2 |
3 | * Fixes URL redirects as requested.
4 |
5 | ## Test environment
6 |
7 | * MacOS 12.0.1 (x86) with R 4.1.2
8 | * Windows Server 2008 R2 SP1, R-devel, 32/64 bit
9 | * Ubuntu Linux 20.04.1 LTS, R-release, GCC
10 | * Fedora Linux, R-devel, clang, gfortran
11 |
12 | ## R CMD check results
13 |
14 | 0 errors | 0 warnings | 1 notes
15 |
16 | * This is an update to an existing release.
17 |
18 | The note relates to a change in the maintainer email address. I have two
19 | packages on CRAN, this one and `rlog`, both using a different valid email
20 | address. This change consolidates my CRAN presence into a single email address.
21 |
--------------------------------------------------------------------------------
/docs/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Page not found (404) • nhsnumber
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
66 |
67 |
70 |
71 | Content not found. Please use links in the navbar.
72 |
73 |
74 |
75 |
79 |
80 |
81 |
82 |
83 |
84 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | nhsnumber.sellorm.com
--------------------------------------------------------------------------------
/docs/LICENSE-text.html:
--------------------------------------------------------------------------------
1 |
2 | License • nhsnumber
6 |
7 |
8 |
9 |
44 |
45 |
48 |
49 |
YEAR: 2019
50 | COPYRIGHT HOLDER: Mark Sellors
51 |
52 |
53 |
54 |
55 |
58 |
59 |
60 |
61 |
62 |
63 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/docs/LICENSE.html:
--------------------------------------------------------------------------------
1 |
2 | MIT License • nhsnumber
6 |
7 |
8 |
9 |
44 |
45 |
48 |
49 |
50 |
51 |
Copyright (c) 2019 Mark Sellors
52 |
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:
53 |
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
54 |
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.
55 |
56 |
57 |
58 |
59 |
62 |
63 |
64 |
65 |
66 |
67 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/docs/authors.html:
--------------------------------------------------------------------------------
1 |
2 | Authors and Citation • nhsnumber
6 |
7 |
8 |
9 |
44 |
45 |
56 |
62 |
63 |
64 |
Sellors M (2021).
65 | nhsnumber: Tools for Working with NHS Number Checksums .
66 | R package version 0.1.2, https://github.com/sellorm/nhsnumber .
67 |
68 |
@Manual{,
69 | title = {nhsnumber: Tools for Working with NHS Number Checksums},
70 | author = {Mark Sellors},
71 | year = {2021},
72 | note = {R package version 0.1.2},
73 | url = {https://github.com/sellorm/nhsnumber},
74 | }
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/docs/bootstrap-toc.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
3 | * Copyright 2015 Aidan Feldman
4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
5 |
6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */
7 |
8 | /* All levels of nav */
9 | nav[data-toggle='toc'] .nav > li > a {
10 | display: block;
11 | padding: 4px 20px;
12 | font-size: 13px;
13 | font-weight: 500;
14 | color: #767676;
15 | }
16 | nav[data-toggle='toc'] .nav > li > a:hover,
17 | nav[data-toggle='toc'] .nav > li > a:focus {
18 | padding-left: 19px;
19 | color: #563d7c;
20 | text-decoration: none;
21 | background-color: transparent;
22 | border-left: 1px solid #563d7c;
23 | }
24 | nav[data-toggle='toc'] .nav > .active > a,
25 | nav[data-toggle='toc'] .nav > .active:hover > a,
26 | nav[data-toggle='toc'] .nav > .active:focus > a {
27 | padding-left: 18px;
28 | font-weight: bold;
29 | color: #563d7c;
30 | background-color: transparent;
31 | border-left: 2px solid #563d7c;
32 | }
33 |
34 | /* Nav: second level (shown on .active) */
35 | nav[data-toggle='toc'] .nav .nav {
36 | display: none; /* Hide by default, but at >768px, show it */
37 | padding-bottom: 10px;
38 | }
39 | nav[data-toggle='toc'] .nav .nav > li > a {
40 | padding-top: 1px;
41 | padding-bottom: 1px;
42 | padding-left: 30px;
43 | font-size: 12px;
44 | font-weight: normal;
45 | }
46 | nav[data-toggle='toc'] .nav .nav > li > a:hover,
47 | nav[data-toggle='toc'] .nav .nav > li > a:focus {
48 | padding-left: 29px;
49 | }
50 | nav[data-toggle='toc'] .nav .nav > .active > a,
51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a,
52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a {
53 | padding-left: 28px;
54 | font-weight: 500;
55 | }
56 |
57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */
58 | nav[data-toggle='toc'] .nav > .active > ul {
59 | display: block;
60 | }
61 |
--------------------------------------------------------------------------------
/docs/bootstrap-toc.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/)
3 | * Copyright 2015 Aidan Feldman
4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */
5 | (function() {
6 | 'use strict';
7 |
8 | window.Toc = {
9 | helpers: {
10 | // return all matching elements in the set, or their descendants
11 | findOrFilter: function($el, selector) {
12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/
13 | // http://stackoverflow.com/a/12731439/358804
14 | var $descendants = $el.find(selector);
15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])');
16 | },
17 |
18 | generateUniqueIdBase: function(el) {
19 | var text = $(el).text();
20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-');
21 | return anchor || el.tagName.toLowerCase();
22 | },
23 |
24 | generateUniqueId: function(el) {
25 | var anchorBase = this.generateUniqueIdBase(el);
26 | for (var i = 0; ; i++) {
27 | var anchor = anchorBase;
28 | if (i > 0) {
29 | // add suffix
30 | anchor += '-' + i;
31 | }
32 | // check if ID already exists
33 | if (!document.getElementById(anchor)) {
34 | return anchor;
35 | }
36 | }
37 | },
38 |
39 | generateAnchor: function(el) {
40 | if (el.id) {
41 | return el.id;
42 | } else {
43 | var anchor = this.generateUniqueId(el);
44 | el.id = anchor;
45 | return anchor;
46 | }
47 | },
48 |
49 | createNavList: function() {
50 | return $('');
51 | },
52 |
53 | createChildNavList: function($parent) {
54 | var $childList = this.createNavList();
55 | $parent.append($childList);
56 | return $childList;
57 | },
58 |
59 | generateNavEl: function(anchor, text) {
60 | var $a = $(' ');
61 | $a.attr('href', '#' + anchor);
62 | $a.text(text);
63 | var $li = $(' ');
64 | $li.append($a);
65 | return $li;
66 | },
67 |
68 | generateNavItem: function(headingEl) {
69 | var anchor = this.generateAnchor(headingEl);
70 | var $heading = $(headingEl);
71 | var text = $heading.data('toc-text') || $heading.text();
72 | return this.generateNavEl(anchor, text);
73 | },
74 |
75 | // Find the first heading level (``, then ``, etc.) that has more than one element. Defaults to 1 (for ``).
76 | getTopLevel: function($scope) {
77 | for (var i = 1; i <= 6; i++) {
78 | var $headings = this.findOrFilter($scope, 'h' + i);
79 | if ($headings.length > 1) {
80 | return i;
81 | }
82 | }
83 |
84 | return 1;
85 | },
86 |
87 | // returns the elements for the top level, and the next below it
88 | getHeadings: function($scope, topLevel) {
89 | var topSelector = 'h' + topLevel;
90 |
91 | var secondaryLevel = topLevel + 1;
92 | var secondarySelector = 'h' + secondaryLevel;
93 |
94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector);
95 | },
96 |
97 | getNavLevel: function(el) {
98 | return parseInt(el.tagName.charAt(1), 10);
99 | },
100 |
101 | populateNav: function($topContext, topLevel, $headings) {
102 | var $context = $topContext;
103 | var $prevNav;
104 |
105 | var helpers = this;
106 | $headings.each(function(i, el) {
107 | var $newNav = helpers.generateNavItem(el);
108 | var navLevel = helpers.getNavLevel(el);
109 |
110 | // determine the proper $context
111 | if (navLevel === topLevel) {
112 | // use top level
113 | $context = $topContext;
114 | } else if ($prevNav && $context === $topContext) {
115 | // create a new level of the tree and switch to it
116 | $context = helpers.createChildNavList($prevNav);
117 | } // else use the current $context
118 |
119 | $context.append($newNav);
120 |
121 | $prevNav = $newNav;
122 | });
123 | },
124 |
125 | parseOps: function(arg) {
126 | var opts;
127 | if (arg.jquery) {
128 | opts = {
129 | $nav: arg
130 | };
131 | } else {
132 | opts = arg;
133 | }
134 | opts.$scope = opts.$scope || $(document.body);
135 | return opts;
136 | }
137 | },
138 |
139 | // accepts a jQuery object, or an options object
140 | init: function(opts) {
141 | opts = this.helpers.parseOps(opts);
142 |
143 | // ensure that the data attribute is in place for styling
144 | opts.$nav.attr('data-toggle', 'toc');
145 |
146 | var $topContext = this.helpers.createChildNavList(opts.$nav);
147 | var topLevel = this.helpers.getTopLevel(opts.$scope);
148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel);
149 | this.helpers.populateNav($topContext, topLevel, $headings);
150 | }
151 | };
152 |
153 | $(function() {
154 | $('nav[data-toggle="toc"]').each(function(i, el) {
155 | var $nav = $(el);
156 | Toc.init($nav);
157 | });
158 | });
159 | })();
160 |
--------------------------------------------------------------------------------
/docs/docsearch.css:
--------------------------------------------------------------------------------
1 | /* Docsearch -------------------------------------------------------------- */
2 | /*
3 | Source: https://github.com/algolia/docsearch/
4 | License: MIT
5 | */
6 |
7 | .algolia-autocomplete {
8 | display: block;
9 | -webkit-box-flex: 1;
10 | -ms-flex: 1;
11 | flex: 1
12 | }
13 |
14 | .algolia-autocomplete .ds-dropdown-menu {
15 | width: 100%;
16 | min-width: none;
17 | max-width: none;
18 | padding: .75rem 0;
19 | background-color: #fff;
20 | background-clip: padding-box;
21 | border: 1px solid rgba(0, 0, 0, .1);
22 | box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175);
23 | }
24 |
25 | @media (min-width:768px) {
26 | .algolia-autocomplete .ds-dropdown-menu {
27 | width: 175%
28 | }
29 | }
30 |
31 | .algolia-autocomplete .ds-dropdown-menu::before {
32 | display: none
33 | }
34 |
35 | .algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] {
36 | padding: 0;
37 | background-color: rgb(255,255,255);
38 | border: 0;
39 | max-height: 80vh;
40 | }
41 |
42 | .algolia-autocomplete .ds-dropdown-menu .ds-suggestions {
43 | margin-top: 0
44 | }
45 |
46 | .algolia-autocomplete .algolia-docsearch-suggestion {
47 | padding: 0;
48 | overflow: visible
49 | }
50 |
51 | .algolia-autocomplete .algolia-docsearch-suggestion--category-header {
52 | padding: .125rem 1rem;
53 | margin-top: 0;
54 | font-size: 1.3em;
55 | font-weight: 500;
56 | color: #00008B;
57 | border-bottom: 0
58 | }
59 |
60 | .algolia-autocomplete .algolia-docsearch-suggestion--wrapper {
61 | float: none;
62 | padding-top: 0
63 | }
64 |
65 | .algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column {
66 | float: none;
67 | width: auto;
68 | padding: 0;
69 | text-align: left
70 | }
71 |
72 | .algolia-autocomplete .algolia-docsearch-suggestion--content {
73 | float: none;
74 | width: auto;
75 | padding: 0
76 | }
77 |
78 | .algolia-autocomplete .algolia-docsearch-suggestion--content::before {
79 | display: none
80 | }
81 |
82 | .algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header {
83 | padding-top: .75rem;
84 | margin-top: .75rem;
85 | border-top: 1px solid rgba(0, 0, 0, .1)
86 | }
87 |
88 | .algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column {
89 | display: block;
90 | padding: .1rem 1rem;
91 | margin-bottom: 0.1;
92 | font-size: 1.0em;
93 | font-weight: 400
94 | /* display: none */
95 | }
96 |
97 | .algolia-autocomplete .algolia-docsearch-suggestion--title {
98 | display: block;
99 | padding: .25rem 1rem;
100 | margin-bottom: 0;
101 | font-size: 0.9em;
102 | font-weight: 400
103 | }
104 |
105 | .algolia-autocomplete .algolia-docsearch-suggestion--text {
106 | padding: 0 1rem .5rem;
107 | margin-top: -.25rem;
108 | font-size: 0.8em;
109 | font-weight: 400;
110 | line-height: 1.25
111 | }
112 |
113 | .algolia-autocomplete .algolia-docsearch-footer {
114 | width: 110px;
115 | height: 20px;
116 | z-index: 3;
117 | margin-top: 10.66667px;
118 | float: right;
119 | font-size: 0;
120 | line-height: 0;
121 | }
122 |
123 | .algolia-autocomplete .algolia-docsearch-footer--logo {
124 | background-image: url("data:image/svg+xml;utf8, ");
125 | background-repeat: no-repeat;
126 | background-position: 50%;
127 | background-size: 100%;
128 | overflow: hidden;
129 | text-indent: -9000px;
130 | width: 100%;
131 | height: 100%;
132 | display: block;
133 | transform: translate(-8px);
134 | }
135 |
136 | .algolia-autocomplete .algolia-docsearch-suggestion--highlight {
137 | color: #FF8C00;
138 | background: rgba(232, 189, 54, 0.1)
139 | }
140 |
141 |
142 | .algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight {
143 | box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5)
144 | }
145 |
146 | .algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content {
147 | background-color: rgba(192, 192, 192, .15)
148 | }
149 |
--------------------------------------------------------------------------------
/docs/docsearch.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 |
3 | // register a handler to move the focus to the search bar
4 | // upon pressing shift + "/" (i.e. "?")
5 | $(document).on('keydown', function(e) {
6 | if (e.shiftKey && e.keyCode == 191) {
7 | e.preventDefault();
8 | $("#search-input").focus();
9 | }
10 | });
11 |
12 | $(document).ready(function() {
13 | // do keyword highlighting
14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */
15 | var mark = function() {
16 |
17 | var referrer = document.URL ;
18 | var paramKey = "q" ;
19 |
20 | if (referrer.indexOf("?") !== -1) {
21 | var qs = referrer.substr(referrer.indexOf('?') + 1);
22 | var qs_noanchor = qs.split('#')[0];
23 | var qsa = qs_noanchor.split('&');
24 | var keyword = "";
25 |
26 | for (var i = 0; i < qsa.length; i++) {
27 | var currentParam = qsa[i].split('=');
28 |
29 | if (currentParam.length !== 2) {
30 | continue;
31 | }
32 |
33 | if (currentParam[0] == paramKey) {
34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20"));
35 | }
36 | }
37 |
38 | if (keyword !== "") {
39 | $(".contents").unmark({
40 | done: function() {
41 | $(".contents").mark(keyword);
42 | }
43 | });
44 | }
45 | }
46 | };
47 |
48 | mark();
49 | });
50 | });
51 |
52 | /* Search term highlighting ------------------------------*/
53 |
54 | function matchedWords(hit) {
55 | var words = [];
56 |
57 | var hierarchy = hit._highlightResult.hierarchy;
58 | // loop to fetch from lvl0, lvl1, etc.
59 | for (var idx in hierarchy) {
60 | words = words.concat(hierarchy[idx].matchedWords);
61 | }
62 |
63 | var content = hit._highlightResult.content;
64 | if (content) {
65 | words = words.concat(content.matchedWords);
66 | }
67 |
68 | // return unique words
69 | var words_uniq = [...new Set(words)];
70 | return words_uniq;
71 | }
72 |
73 | function updateHitURL(hit) {
74 |
75 | var words = matchedWords(hit);
76 | var url = "";
77 |
78 | if (hit.anchor) {
79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor;
80 | } else {
81 | url = hit.url + '?q=' + escape(words.join(" "));
82 | }
83 |
84 | return url;
85 | }
86 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Tools for Working with NHS Number Checksums • nhsnumber
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
71 |
72 |
73 |
75 |
76 |
77 |
The goal of nhsnumber is to provide some simple functions for working with NHS numbers in R.
78 |
79 |
NHS Number Overview
80 |
81 |
NHS numbers are issued to patients of the NHS in the UK.
82 |
The number consists of 9 digits and a single digit checksum.
83 |
For more information, please see the NHS number Wikipedia article on the subject.
84 |
85 |
86 |
Installation
87 |
88 |
You can install the released version of nhsnumber from CRAN with:
89 |
91 |
You can install the development version of nhsnumber from GitHub with:
92 |
94 |
95 |
96 |
Example
97 |
98 |
The is_valid
function takes a vector of NHS numbers and returns TRUE or FALSE depending on whether the checksum is successfully validated.
99 |
100 | x <- c ( 9876543210 , 1234567890 , 1234567881 )
101 | nhsnumber :: is_valid ( x )
102 |
Which returns:
103 |
TRUE FALSE TRUE
104 |
It’s also possible to generate the checksums using the get_checksum
function. This function uses the 9 core digits and returns either the checksum on its own, or the full 10 digit number.
105 |
107 |
which returns:
108 |
1
109 |
or with the full output:
110 |
111 | nhsnumber :: get_checksum ( 123456788 , full_output = TRUE )
112 |
Which returns:
113 |
1234567881
114 |
Some number combinations are invalid and these will throw an error, for example:
115 |
117 |
Which results in this:
118 |
Error in nhsnumber::get_checksum(123456789) : Input sequence is invalid
119 | Checksum was 10 which is not permissable
120 |
121 |
122 |
123 |
124 |
168 |
169 |
170 |
171 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/docs/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/news/index.html:
--------------------------------------------------------------------------------
1 |
2 | Changelog • nhsnumber
6 |
7 |
8 |
9 |
44 |
45 |
49 |
50 |
51 |
52 |
Properly handles NA
in input data (#3 )
53 | Consolidated email addresses used on CRAN - now matches my other package, rlog
54 |
55 |
56 |
57 |
Added a NEWS.md
file to track changes to the package.
58 | Preparing for first CRAN submission
59 |
60 |
61 |
62 |
65 |
66 |
67 |
68 |
69 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/docs/pkgdown.css:
--------------------------------------------------------------------------------
1 | /* Sticky footer */
2 |
3 | /**
4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/
5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css
6 | *
7 | * .Site -> body > .container
8 | * .Site-content -> body > .container .row
9 | * .footer -> footer
10 | *
11 | * Key idea seems to be to ensure that .container and __all its parents__
12 | * have height set to 100%
13 | *
14 | */
15 |
16 | html, body {
17 | height: 100%;
18 | }
19 |
20 | body {
21 | position: relative;
22 | }
23 |
24 | body > .container {
25 | display: flex;
26 | height: 100%;
27 | flex-direction: column;
28 | }
29 |
30 | body > .container .row {
31 | flex: 1 0 auto;
32 | }
33 |
34 | footer {
35 | margin-top: 45px;
36 | padding: 35px 0 36px;
37 | border-top: 1px solid #e5e5e5;
38 | color: #666;
39 | display: flex;
40 | flex-shrink: 0;
41 | }
42 | footer p {
43 | margin-bottom: 0;
44 | }
45 | footer div {
46 | flex: 1;
47 | }
48 | footer .pkgdown {
49 | text-align: right;
50 | }
51 | footer p {
52 | margin-bottom: 0;
53 | }
54 |
55 | img.icon {
56 | float: right;
57 | }
58 |
59 | /* Ensure in-page images don't run outside their container */
60 | .contents img {
61 | max-width: 100%;
62 | height: auto;
63 | }
64 |
65 | /* Fix bug in bootstrap (only seen in firefox) */
66 | summary {
67 | display: list-item;
68 | }
69 |
70 | /* Typographic tweaking ---------------------------------*/
71 |
72 | .contents .page-header {
73 | margin-top: calc(-60px + 1em);
74 | }
75 |
76 | dd {
77 | margin-left: 3em;
78 | }
79 |
80 | /* Section anchors ---------------------------------*/
81 |
82 | a.anchor {
83 | display: none;
84 | margin-left: 5px;
85 | width: 20px;
86 | height: 20px;
87 |
88 | background-image: url(./link.svg);
89 | background-repeat: no-repeat;
90 | background-size: 20px 20px;
91 | background-position: center center;
92 | }
93 |
94 | h1:hover .anchor,
95 | h2:hover .anchor,
96 | h3:hover .anchor,
97 | h4:hover .anchor,
98 | h5:hover .anchor,
99 | h6:hover .anchor {
100 | display: inline-block;
101 | }
102 |
103 | /* Fixes for fixed navbar --------------------------*/
104 |
105 | .contents h1, .contents h2, .contents h3, .contents h4 {
106 | padding-top: 60px;
107 | margin-top: -40px;
108 | }
109 |
110 | /* Navbar submenu --------------------------*/
111 |
112 | .dropdown-submenu {
113 | position: relative;
114 | }
115 |
116 | .dropdown-submenu>.dropdown-menu {
117 | top: 0;
118 | left: 100%;
119 | margin-top: -6px;
120 | margin-left: -1px;
121 | border-radius: 0 6px 6px 6px;
122 | }
123 |
124 | .dropdown-submenu:hover>.dropdown-menu {
125 | display: block;
126 | }
127 |
128 | .dropdown-submenu>a:after {
129 | display: block;
130 | content: " ";
131 | float: right;
132 | width: 0;
133 | height: 0;
134 | border-color: transparent;
135 | border-style: solid;
136 | border-width: 5px 0 5px 5px;
137 | border-left-color: #cccccc;
138 | margin-top: 5px;
139 | margin-right: -10px;
140 | }
141 |
142 | .dropdown-submenu:hover>a:after {
143 | border-left-color: #ffffff;
144 | }
145 |
146 | .dropdown-submenu.pull-left {
147 | float: none;
148 | }
149 |
150 | .dropdown-submenu.pull-left>.dropdown-menu {
151 | left: -100%;
152 | margin-left: 10px;
153 | border-radius: 6px 0 6px 6px;
154 | }
155 |
156 | /* Sidebar --------------------------*/
157 |
158 | #pkgdown-sidebar {
159 | margin-top: 30px;
160 | position: -webkit-sticky;
161 | position: sticky;
162 | top: 70px;
163 | }
164 |
165 | #pkgdown-sidebar h2 {
166 | font-size: 1.5em;
167 | margin-top: 1em;
168 | }
169 |
170 | #pkgdown-sidebar h2:first-child {
171 | margin-top: 0;
172 | }
173 |
174 | #pkgdown-sidebar .list-unstyled li {
175 | margin-bottom: 0.5em;
176 | }
177 |
178 | /* bootstrap-toc tweaks ------------------------------------------------------*/
179 |
180 | /* All levels of nav */
181 |
182 | nav[data-toggle='toc'] .nav > li > a {
183 | padding: 4px 20px 4px 6px;
184 | font-size: 1.5rem;
185 | font-weight: 400;
186 | color: inherit;
187 | }
188 |
189 | nav[data-toggle='toc'] .nav > li > a:hover,
190 | nav[data-toggle='toc'] .nav > li > a:focus {
191 | padding-left: 5px;
192 | color: inherit;
193 | border-left: 1px solid #878787;
194 | }
195 |
196 | nav[data-toggle='toc'] .nav > .active > a,
197 | nav[data-toggle='toc'] .nav > .active:hover > a,
198 | nav[data-toggle='toc'] .nav > .active:focus > a {
199 | padding-left: 5px;
200 | font-size: 1.5rem;
201 | font-weight: 400;
202 | color: inherit;
203 | border-left: 2px solid #878787;
204 | }
205 |
206 | /* Nav: second level (shown on .active) */
207 |
208 | nav[data-toggle='toc'] .nav .nav {
209 | display: none; /* Hide by default, but at >768px, show it */
210 | padding-bottom: 10px;
211 | }
212 |
213 | nav[data-toggle='toc'] .nav .nav > li > a {
214 | padding-left: 16px;
215 | font-size: 1.35rem;
216 | }
217 |
218 | nav[data-toggle='toc'] .nav .nav > li > a:hover,
219 | nav[data-toggle='toc'] .nav .nav > li > a:focus {
220 | padding-left: 15px;
221 | }
222 |
223 | nav[data-toggle='toc'] .nav .nav > .active > a,
224 | nav[data-toggle='toc'] .nav .nav > .active:hover > a,
225 | nav[data-toggle='toc'] .nav .nav > .active:focus > a {
226 | padding-left: 15px;
227 | font-weight: 500;
228 | font-size: 1.35rem;
229 | }
230 |
231 | /* orcid ------------------------------------------------------------------- */
232 |
233 | .orcid {
234 | font-size: 16px;
235 | color: #A6CE39;
236 | /* margins are required by official ORCID trademark and display guidelines */
237 | margin-left:4px;
238 | margin-right:4px;
239 | vertical-align: middle;
240 | }
241 |
242 | /* Reference index & topics ----------------------------------------------- */
243 |
244 | .ref-index th {font-weight: normal;}
245 |
246 | .ref-index td {vertical-align: top; min-width: 100px}
247 | .ref-index .icon {width: 40px;}
248 | .ref-index .alias {width: 40%;}
249 | .ref-index-icons .alias {width: calc(40% - 40px);}
250 | .ref-index .title {width: 60%;}
251 |
252 | .ref-arguments th {text-align: right; padding-right: 10px;}
253 | .ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px}
254 | .ref-arguments .name {width: 20%;}
255 | .ref-arguments .desc {width: 80%;}
256 |
257 | /* Nice scrolling for wide elements --------------------------------------- */
258 |
259 | table {
260 | display: block;
261 | overflow: auto;
262 | }
263 |
264 | /* Syntax highlighting ---------------------------------------------------- */
265 |
266 | pre, code, pre code {
267 | background-color: #f8f8f8;
268 | color: #333;
269 | }
270 | pre, pre code {
271 | white-space: pre-wrap;
272 | word-break: break-all;
273 | overflow-wrap: break-word;
274 | }
275 |
276 | pre {
277 | border: 1px solid #eee;
278 | }
279 |
280 | pre .img, pre .r-plt {
281 | margin: 5px 0;
282 | }
283 |
284 | pre .img img, pre .r-plt img {
285 | background-color: #fff;
286 | }
287 |
288 | code a, pre a {
289 | color: #375f84;
290 | }
291 |
292 | a.sourceLine:hover {
293 | text-decoration: none;
294 | }
295 |
296 | .fl {color: #1514b5;}
297 | .fu {color: #000000;} /* function */
298 | .ch,.st {color: #036a07;} /* string */
299 | .kw {color: #264D66;} /* keyword */
300 | .co {color: #888888;} /* comment */
301 |
302 | .error {font-weight: bolder;}
303 | .warning {font-weight: bolder;}
304 |
305 | /* Clipboard --------------------------*/
306 |
307 | .hasCopyButton {
308 | position: relative;
309 | }
310 |
311 | .btn-copy-ex {
312 | position: absolute;
313 | right: 0;
314 | top: 0;
315 | visibility: hidden;
316 | }
317 |
318 | .hasCopyButton:hover button.btn-copy-ex {
319 | visibility: visible;
320 | }
321 |
322 | /* headroom.js ------------------------ */
323 |
324 | .headroom {
325 | will-change: transform;
326 | transition: transform 200ms linear;
327 | }
328 | .headroom--pinned {
329 | transform: translateY(0%);
330 | }
331 | .headroom--unpinned {
332 | transform: translateY(-100%);
333 | }
334 |
335 | /* mark.js ----------------------------*/
336 |
337 | mark {
338 | background-color: rgba(255, 255, 51, 0.5);
339 | border-bottom: 2px solid rgba(255, 153, 51, 0.3);
340 | padding: 1px;
341 | }
342 |
343 | /* vertical spacing after htmlwidgets */
344 | .html-widget {
345 | margin-bottom: 10px;
346 | }
347 |
348 | /* fontawesome ------------------------ */
349 |
350 | .fab {
351 | font-family: "Font Awesome 5 Brands" !important;
352 | }
353 |
354 | /* don't display links in code chunks when printing */
355 | /* source: https://stackoverflow.com/a/10781533 */
356 | @media print {
357 | code a:link:after, code a:visited:after {
358 | content: "";
359 | }
360 | }
361 |
362 | /* Section anchors ---------------------------------
363 | Added in pandoc 2.11: https://github.com/jgm/pandoc-templates/commit/9904bf71
364 | */
365 |
366 | div.csl-bib-body { }
367 | div.csl-entry {
368 | clear: both;
369 | }
370 | .hanging-indent div.csl-entry {
371 | margin-left:2em;
372 | text-indent:-2em;
373 | }
374 | div.csl-left-margin {
375 | min-width:2em;
376 | float:left;
377 | }
378 | div.csl-right-inline {
379 | margin-left:2em;
380 | padding-left:1em;
381 | }
382 | div.csl-indent {
383 | margin-left: 2em;
384 | }
385 |
--------------------------------------------------------------------------------
/docs/pkgdown.js:
--------------------------------------------------------------------------------
1 | /* http://gregfranko.com/blog/jquery-best-practices/ */
2 | (function($) {
3 | $(function() {
4 |
5 | $('.navbar-fixed-top').headroom();
6 |
7 | $('body').css('padding-top', $('.navbar').height() + 10);
8 | $(window).resize(function(){
9 | $('body').css('padding-top', $('.navbar').height() + 10);
10 | });
11 |
12 | $('[data-toggle="tooltip"]').tooltip();
13 |
14 | var cur_path = paths(location.pathname);
15 | var links = $("#navbar ul li a");
16 | var max_length = -1;
17 | var pos = -1;
18 | for (var i = 0; i < links.length; i++) {
19 | if (links[i].getAttribute("href") === "#")
20 | continue;
21 | // Ignore external links
22 | if (links[i].host !== location.host)
23 | continue;
24 |
25 | var nav_path = paths(links[i].pathname);
26 |
27 | var length = prefix_length(nav_path, cur_path);
28 | if (length > max_length) {
29 | max_length = length;
30 | pos = i;
31 | }
32 | }
33 |
34 | // Add class to parent , and enclosing if in dropdown
35 | if (pos >= 0) {
36 | var menu_anchor = $(links[pos]);
37 | menu_anchor.parent().addClass("active");
38 | menu_anchor.closest("li.dropdown").addClass("active");
39 | }
40 | });
41 |
42 | function paths(pathname) {
43 | var pieces = pathname.split("/");
44 | pieces.shift(); // always starts with /
45 |
46 | var end = pieces[pieces.length - 1];
47 | if (end === "index.html" || end === "")
48 | pieces.pop();
49 | return(pieces);
50 | }
51 |
52 | // Returns -1 if not found
53 | function prefix_length(needle, haystack) {
54 | if (needle.length > haystack.length)
55 | return(-1);
56 |
57 | // Special case for length-0 haystack, since for loop won't run
58 | if (haystack.length === 0) {
59 | return(needle.length === 0 ? 0 : -1);
60 | }
61 |
62 | for (var i = 0; i < haystack.length; i++) {
63 | if (needle[i] != haystack[i])
64 | return(i);
65 | }
66 |
67 | return(haystack.length);
68 | }
69 |
70 | /* Clipboard --------------------------*/
71 |
72 | function changeTooltipMessage(element, msg) {
73 | var tooltipOriginalTitle=element.getAttribute('data-original-title');
74 | element.setAttribute('data-original-title', msg);
75 | $(element).tooltip('show');
76 | element.setAttribute('data-original-title', tooltipOriginalTitle);
77 | }
78 |
79 | if(ClipboardJS.isSupported()) {
80 | $(document).ready(function() {
81 | var copyButton = " ";
82 |
83 | $("div.sourceCode").addClass("hasCopyButton");
84 |
85 | // Insert copy buttons:
86 | $(copyButton).prependTo(".hasCopyButton");
87 |
88 | // Initialize tooltips:
89 | $('.btn-copy-ex').tooltip({container: 'body'});
90 |
91 | // Initialize clipboard:
92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', {
93 | text: function(trigger) {
94 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, "");
95 | }
96 | });
97 |
98 | clipboardBtnCopies.on('success', function(e) {
99 | changeTooltipMessage(e.trigger, 'Copied!');
100 | e.clearSelection();
101 | });
102 |
103 | clipboardBtnCopies.on('error', function() {
104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy');
105 | });
106 | });
107 | }
108 | })(window.jQuery || window.$)
109 |
--------------------------------------------------------------------------------
/docs/pkgdown.yml:
--------------------------------------------------------------------------------
1 | pandoc: 2.16.2
2 | pkgdown: 2.0.1
3 | pkgdown_sha: ~
4 | articles: {}
5 | last_built: 2021-12-06T15:42Z
6 |
7 |
--------------------------------------------------------------------------------
/docs/reference/Rplot001.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sellorm/nhsnumber/3cca298c95e1efd101b39915024123e29d1213c3/docs/reference/Rplot001.png
--------------------------------------------------------------------------------
/docs/reference/get_checksum.html:
--------------------------------------------------------------------------------
1 |
2 | Calculates NHS number checksums — get_checksum • nhsnumber
8 |
9 |
10 |
11 |
46 |
47 |
52 |
53 |
54 |
NHS numbers are 10 digit numbers where the 10th digit is a checksum.
55 | This function takes the 9 core digits of the NHS number and calculates the
56 | checksums.
57 |
58 |
59 |
60 |
get_checksum ( nhs_number , full_output = FALSE )
61 |
62 |
63 |
64 |
Arguments
65 |
nhs_number
66 | A 9 digit NHS numbers to validate
67 | full_output
68 | Boolean that controls display of warning messages
69 |
70 |
71 |
Value
72 |
Checksum or the complete NHS number including the checksum.
73 |
74 |
75 |
Details
76 |
This function has been created using information from:
77 | https://en.wikipedia.org/wiki/NHS_number
78 | and various NHS sources
79 |
80 |
81 |
82 |
Examples
83 |
get_checksum ( 123456788 )
84 | #> [1] 1
85 | get_checksum ( 123456788 , full_output = TRUE )
86 | #> [1] 1234567881
87 |
88 |
89 |
90 |
93 |
94 |
95 |
96 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/docs/reference/index.html:
--------------------------------------------------------------------------------
1 |
2 | Function reference • nhsnumber
6 |
7 |
8 |
9 |
44 |
45 |
48 |
49 |
50 | All functions
51 |
52 |
53 |
54 | get_checksum()
55 |
56 | Calculates NHS number checksums
57 |
58 | is_number_valid()
59 |
60 | Checks validity of an NHS number
61 |
62 | is_valid()
63 |
64 | Checks validity of NHS numbers
65 |
66 |
67 |
70 |
71 |
72 |
73 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/docs/reference/is_number_valid.html:
--------------------------------------------------------------------------------
1 |
2 | Checks validity of an NHS number — is_number_valid • nhsnumber
7 |
8 |
9 |
10 |
45 |
46 |
51 |
52 |
53 |
NHS numbers are 10 digit numbers where the 10th digit is a checksum.
54 | This function validates the checksums of the supplied NHS numbers.
55 |
56 |
57 |
58 |
is_number_valid ( nhs_number , warn = TRUE )
59 |
60 |
61 |
62 |
Arguments
63 |
nhs_number
64 | A 10 digit NHS number to validate
65 | warn
66 | Boolean that controls display of warning messages
67 |
68 |
69 |
70 |
Examples
71 |
is_valid ( 1234567881 )
72 | #> [1] TRUE
73 | is_valid ( 1234567890 , warn = FALSE )
74 | #> [1] FALSE
75 |
76 |
77 |
78 |
81 |
82 |
83 |
84 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/docs/reference/is_valid.html:
--------------------------------------------------------------------------------
1 |
2 | Checks validity of NHS numbers — is_valid • nhsnumber
7 |
8 |
9 |
10 |
45 |
46 |
51 |
52 |
53 |
NHS numbers are 10 digit numbers where the 10th digit is a checksum.
54 | This function validates the checksums of the supplied NHS numbers.
55 |
56 |
57 |
58 |
is_valid ( nhs_number , warn = TRUE )
59 |
60 |
61 |
62 |
Arguments
63 |
nhs_number
64 | A vector of 10 digit NHS numbers to validate
65 | warn
66 | Boolean that controls display of warning messages
67 |
68 |
69 |
Value
70 |
A logical vector indicating the validity of each input value
71 |
72 |
73 |
74 |
Examples
75 |
is_valid ( 1234567881 )
76 | #> [1] TRUE
77 | is_valid ( c ( 1234567881 , 1234512345 , 123456789 ) )
78 | #> Warning: nhs_number is incorrect length - should be 10 digits
79 | #> [1] TRUE FALSE FALSE
80 | is_valid ( 1234567890 , warn = FALSE )
81 | #> [1] FALSE
82 |
83 |
84 |
85 |
88 |
89 |
90 |
91 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/docs/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | /404.html
5 |
6 |
7 | /LICENSE-text.html
8 |
9 |
10 | /LICENSE.html
11 |
12 |
13 | /authors.html
14 |
15 |
16 | /index.html
17 |
18 |
19 | /news/index.html
20 |
21 |
22 | /reference/get_checksum.html
23 |
24 |
25 | /reference/index.html
26 |
27 |
28 | /reference/is_number_valid.html
29 |
30 |
31 | /reference/is_valid.html
32 |
33 |
34 |
--------------------------------------------------------------------------------
/man/get_checksum.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/get_checksum.R
3 | \name{get_checksum}
4 | \alias{get_checksum}
5 | \title{Calculates NHS number checksums}
6 | \usage{
7 | get_checksum(nhs_number, full_output = FALSE)
8 | }
9 | \arguments{
10 | \item{nhs_number}{A 9 digit NHS numbers to validate}
11 |
12 | \item{full_output}{Boolean that controls display of warning messages}
13 | }
14 | \value{
15 | Checksum or the complete NHS number including the checksum.
16 | }
17 | \description{
18 | NHS numbers are 10 digit numbers where the 10th digit is a checksum.
19 | This function takes the 9 core digits of the NHS number and calculates the
20 | checksums.
21 | }
22 | \details{
23 | This function has been created using information from:
24 | https://en.wikipedia.org/wiki/NHS_number
25 | and various NHS sources
26 | }
27 | \examples{
28 | get_checksum(123456788)
29 | get_checksum(123456788, full_output = TRUE)
30 | }
31 |
--------------------------------------------------------------------------------
/man/is_number_valid.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/is_number_valid.R
3 | \name{is_number_valid}
4 | \alias{is_number_valid}
5 | \title{Checks validity of an NHS number}
6 | \usage{
7 | is_number_valid(nhs_number, warn = TRUE)
8 | }
9 | \arguments{
10 | \item{nhs_number}{A 10 digit NHS number to validate}
11 |
12 | \item{warn}{Boolean that controls display of warning messages}
13 | }
14 | \description{
15 | NHS numbers are 10 digit numbers where the 10th digit is a checksum.
16 | This function validates the checksums of the supplied NHS numbers.
17 | }
18 | \examples{
19 | is_valid(1234567881)
20 | is_valid(1234567890, warn = FALSE)
21 | }
22 |
--------------------------------------------------------------------------------
/man/is_valid.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/is_valid.R
3 | \name{is_valid}
4 | \alias{is_valid}
5 | \title{Checks validity of NHS numbers}
6 | \usage{
7 | is_valid(nhs_number, warn = TRUE)
8 | }
9 | \arguments{
10 | \item{nhs_number}{A vector of 10 digit NHS numbers to validate}
11 |
12 | \item{warn}{Boolean that controls display of warning messages}
13 | }
14 | \value{
15 | A logical vector indicating the validity of each input value
16 | }
17 | \description{
18 | NHS numbers are 10 digit numbers where the 10th digit is a checksum.
19 | This function validates the checksums of the supplied NHS numbers.
20 | }
21 | \examples{
22 | is_valid(1234567881)
23 | is_valid(c(1234567881, 1234512345, 123456789))
24 | is_valid(1234567890, warn = FALSE)
25 | }
26 |
--------------------------------------------------------------------------------
/nhsnumber.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
15 | AutoAppendNewline: Yes
16 | StripTrailingWhitespace: Yes
17 |
18 | BuildType: Package
19 | PackageUseDevtools: Yes
20 | PackageInstallArgs: --no-multiarch --with-keep.source
21 |
--------------------------------------------------------------------------------
/tests/testthat.R:
--------------------------------------------------------------------------------
1 | library(testthat)
2 | library(nhsnumber)
3 |
4 | test_check("nhsnumber")
5 |
--------------------------------------------------------------------------------
/tests/testthat/test-get_checksum.R:
--------------------------------------------------------------------------------
1 | context("Checks correct output")
2 | test_that("Test for correct checksums", {
3 | expect_equal(get_checksum(123456788), 1)
4 | expect_equal(get_checksum(987654321), 0)
5 | expect_equal(get_checksum(234567890), 9)
6 | expect_equal(get_checksum(345678901), 7)
7 | expect_equal(get_checksum(456789012), 4)
8 | expect_equal(get_checksum(567890123), 0)
9 | expect_equal(get_checksum(678901234), 6)
10 | expect_equal(get_checksum(789012345), 0)
11 | expect_equal(get_checksum(890123456), 4)
12 | expect_equal(get_checksum(901234567), 7)
13 | expect_equal(get_checksum("012345678"), 9)
14 | expect_equal(get_checksum(123456788, full_output = TRUE), 1234567881)
15 | })
16 |
17 | context("Checks for errors")
18 | test_that("Test for errors in correct places", {
19 | expect_error(get_checksum(12345))
20 | expect_error(get_checksum(123456789))
21 | expect_error(get_checksum("hatstand"))
22 | expect_error(get_checksum("hatstands"))
23 | })
24 |
--------------------------------------------------------------------------------
/tests/testthat/test-is_number_valid.R:
--------------------------------------------------------------------------------
1 | context("Is that NHS Number valid?")
2 | test_that("10 digit numbers return correct responses", {
3 | expect_equal(is_number_valid(1234567881), TRUE)
4 | expect_equal(is_number_valid(1234567890), FALSE)
5 | expect_equal(is_number_valid(2345678909), TRUE)
6 | expect_equal(is_number_valid(2345678901), FALSE)
7 | expect_equal(is_number_valid(NA, warn = FALSE), FALSE)
8 | })
9 |
10 | context("Garbage input")
11 | test_that("Incorrect input still provides the expected output", {
12 | expect_equal(is_number_valid(12345, warn = FALSE), FALSE)
13 | expect_equal(is_number_valid("hat", warn = FALSE), FALSE)
14 | expect_equal(is_number_valid(12345678901, warn = FALSE), FALSE)
15 | expect_warning(is_number_valid(1))
16 | expect_warning(is_number_valid(NA))
17 | })
18 |
--------------------------------------------------------------------------------
/tests/testthat/test-is_valid.R:
--------------------------------------------------------------------------------
1 | context("is_valid and the vectors")
2 | test_that("we can accept vectors", {
3 | expect_equal(
4 | is_valid(c(1234567881, 1234567890, 9876543210, 2345678901)),
5 | c(TRUE, FALSE, TRUE, FALSE)
6 | )
7 | })
8 |
9 | context("is_valid and dodgy inputs")
10 | test_that("We don't accept these incorrect inputs", {
11 | expect_error(is_valid(as.data.frame("hat")))
12 | })
13 |
--------------------------------------------------------------------------------