# validation.uk-modulus-table Reads the two files UK sort code modulus checking runs on, as Vocalink publishes them for Pay.UK, into the table that `validation.uk-sort-code-account` checks against: - **VALACDOS.txt**, the modulus weight table: one line per sort code range, giving the check to run (MOD10, MOD11 or DBLAL), fourteen weights and an optional exception number. - **SCSUBTAB.txt**, the sort code substitution table for exception 5: one line per sort code, with the sort code to weight in its place. **Neither file is in this package.** Both are Vocalink's copyright ("All rights reserved"), so the registry ships the algorithm and the parser, and you supply the data. Download both from Vocalink's modulus checking page, (Vocalink runs it for Pay.UK), and pass their text in. Vocalink updates VALACDOS.txt several times a year as banks add and retire sort codes, and the page lists the date of each release: fetch the new file when it changes, as you would any reference data. A table that is out of date answers "unchecked" for a new sort code rather than rejecting it, so a stale file fails safe, but it does stop checking. ## Usage Read the files, parse them once when your application starts, and pass the table to every check. Parsing the full file takes a few milliseconds; do not do it per request. TypeScript: ```ts import { readFileSync } from "node:fs"; import { parseUkModulusTable } from "#fune/validation.uk-modulus-table@^1"; import { validateUkSortCodeAccount } from "#fune/validation.uk-sort-code-account@^3"; const table = parseUkModulusTable( readFileSync("data/valacdos.txt", "utf8"), readFileSync("data/scsubtab.txt", "utf8"), ); validateUkSortCodeAccount("08-99-99", "66374958", table); ``` Python: ```python from pathlib import Path from fune.validation.uk_modulus_table import parse_uk_modulus_table # validation.uk-modulus-table@^1 from fune.validation.uk_sort_code_account import validate_uk_sort_code_account # validation.uk-sort-code-account@^3 table = parse_uk_modulus_table( Path("data/valacdos.txt").read_text(encoding="utf-8"), Path("data/scsubtab.txt").read_text(encoding="utf-8"), ) validate_uk_sort_code_account("08-99-99", "66374958", table) ``` Rust: ```rust fune!(validation.uk-modulus-table@^1); fune!(validation.uk-sort-code-account@^3); let table = parse_uk_modulus_table( &std::fs::read_to_string("data/valacdos.txt")?, &std::fs::read_to_string("data/scsubtab.txt")?, ); validate_uk_sort_code_account("08-99-99", "66374958", &table); ``` ## The format it reads Each non-blank line of VALACDOS.txt is 17 or 18 fields separated by spaces (Vocalink pads the columns; any run of spaces or tabs is one separator): ``` start end algorithm u v w x y z a b c d e f g h [exception] ``` `start` and `end` are six-digit sort codes, inclusive. The fourteen weights are whole numbers, and may be negative in a MOD10 or MOD11 row. The exception is 1 to 14. A sort code that falls in two rows gets two checks, the first row first, so **rows keep their file order**; do not sort or de-duplicate them. Each non-blank line of SCSUBTAB.txt is two six-digit sort codes: the original and its substitute. Pass `""` if you have no SCSUBTAB.txt; exception 5 rows then weight every sort code as itself, which is only right for sort codes the substitution table does not list. Windows line endings and a leading byte order mark are accepted. ## Errors Anything else is an error naming the file and the line (blank lines count, so the number matches your editor's): a wrong number of fields, a sort code that is not six ASCII digits, a range that ends before it starts, an unknown algorithm (they are upper case), a weight that is not a whole number of at most four digits, a negative weight in a DBLAL row (a digit sum of a negative product is not defined, and the specification never needs one), an exception outside 1 to 14, or a VALACDOS.txt with no rows at all. A parser that skipped a bad line would quietly turn a checkable sort code into an unchecked one. ## Tests The vectors use short invented lines in VALACDOS.txt's layout, not rows of the real file: invented sort code ranges, weights and exceptions. ## Sources - Vocalink, "Validating account numbers: UK Modulus Checking", section 2 (the file layouts and the meaning of each column), and the modulus checking page that links the current files: