func convert (magnitude, unit) {
     var factor = Hash(
        tochka     => 0.000254,
        liniya     => 0.00254,
        diuym      => 0.0254,
        vershok    => 0.04445,
        piad       => 0.1778,
        fut        => 0.3048,
        arshin     => 0.7112,
        sazhen     => 2.1336,
        versta     => 1066.8,
        milia      => 7467.6,
        centimeter => 0.01,
        meter      => 1,
        kilometer  => 1000,
    )

    var meters = (magnitude * factor{unit.lc})
    say("#{magnitude} #{unit} to:\n", '-' * 40)

    for u,f in (factor.sort_by { |_,v| v }) {
        printf("%10s: %s\n", u, meters / f) if (u != unit.lc)
    }
}

convert(1, 'meter')
say('')
convert(1, 'milia')


package require units

set russian_units {
      arshin  1.40607
  centimeter  100
       diuym  39.3701
         fut  3.28084
   kilometer  0.001
      liniya  393.701
       meter  1
       milia  0.000133912
        piad  5.6243
      sazhen  0.468691
      tochka  3937.01
     vershok  22.4972
      versta  0.000937383
}

proc add_russian_units {} {
    foreach {name factor} $::russian_units {
        if {$name eq "meter"} continue
        set factor [expr {1/$factor}]
        units::new $name "$factor meters"   ;# teach units about the new unit
    }
}

proc demo {} {  ;# show some examples
    foreach base {"1 meter" "1 milia"} {
        puts "$base to:"
        foreach {unit _} $::russian_units {
            puts [format " %-12s: %s" $unit [units::convert $base $unit]]
        }
        puts ""
    }
}

add_russian_units
demo


import "io" for Stdin, Stdout
import "/fmt" for Fmt
import "/str" for Str

var units = [
    "tochka", "liniya", "dyuim", "vershok", "piad", "fut",
    "arshin", "sazhen", "versta", "milia",
    "centimeter", "meter", "kilometer"
]

var convs = [
    0.0254, 0.254, 2.54, 4.445, 17.78, 30.48,
    71.12, 213.36, 10668, 74676,
    1, 100, 10000
]

while (true) {
    var i = 0
    for (u in units) {
        Fmt.print("$2d $s", i+1, u)
        i = i + 1
    }
    System.print()
    var unit
    while (true) {
        System.write("Please choose a unit 1 to 13   : ")
        Stdout.flush()
        unit = Num.fromString(Stdin.readLine())
        if (unit.type == Num && unit.isInteger && unit >= 1 && unit <= 13) break
    }
    unit = unit - 1
    var value
    while (true) {
        System.write("Now enter a value in that unit : ")
        Stdout.flush()
        value = Num.fromString(Stdin.readLine())
        if (value.type == Num && value >= 0) break
    }
    System.print("\nThe equivalent in the remaining units is:\n")
    i = 0
    for (u in units) {
        if (i != unit) Fmt.print(" $10s : $15.8g", u, value*convs[unit]/convs[i])
        i = i + 1
    }
    System.print()
    var yn = ""
    while (yn != "y" && yn != "n") {
        System.write("Do another one y/n : ")
        Stdout.flush()
        yn = Str.lower(Stdin.readLine())
    }
    if (yn == "n") break
    System.print()
}


F one_of_n(lines)
   V choice = 0
   L(line) lines
      I random:(0..L.index) == 0
         choice = line
   R choice

F one_of_n_test(n = 10, trials = 1000000)
   V bins = [0] * n
   I n != 0
      L 1..trials
         bins[one_of_n(0 .< n)]++
   R bins

print(one_of_n_test())


with Ada.Text_IO, Ada.Numerics.Float_Random;

procedure One_Of_N is

   Num_Of_Lines: constant Positive := 10;

   package Rnd renames Ada.Numerics.Float_Random;
   Gen: Rnd.Generator; -- used globally

   function Choose_One_Of_N(Last_Line_Number: Positive) return Natural is
      Current_Choice: Natural := 0;
   begin
      for Line_Number in 1 .. Last_Line_Number loop
        if (Rnd.Random(Gen) * Float(Line_Number) <= 1.0) then
           Current_Choice := Line_Number;
        end if;
      end loop;
      return Current_Choice;
   end Choose_One_Of_N;

   Results: array(1 .. Num_Of_Lines) of Natural := (others => 0);
   Index: Integer range 1 .. Num_Of_Lines;

begin
   Rnd.Reset(Gen);
   for I in 1 .. 1_000_000 loop    -- compute results
      Index := Choose_One_Of_N(Num_Of_Lines);
      Results(Index) := Results(Index) + 1;
   end loop;

   for R in Results'Range loop    -- output results
      Ada.Text_IO.Put(Integer'Image(Results(R)));
   end loop;
end One_Of_N;


one_of_n(integer n)
{
    integer i, r;

    i = r = 0;
    while ((r += 1) < n) {
        i = drand(r) ? i : r;
    }

    i;
}

main(void)
{
    integer i;
    index x;

    i = 1000000;
    do {
        x[one_of_n(10)] += 1;
    } while (i -= 1);

    x.ucall(o_winteger, 1, 7);
    o_newline();

    0;
}


BEGIN
   INT max lines = 10;		CO Should be read from a file. CO
   [max lines]INT stats;
   FOR i TO max lines DO stats[i] := 0 OD;
   first random (42);		CO Should have rather more entropy! CO
   PROC one of n = (INT n) INT :
   BEGIN
      INT result := 1;
      FOR i TO n DO (random < 1/i | result := i) OD;
      result
   END;
   TO 1000000 DO stats[one of n (max lines)] +:= 1 OD;
   print (("Line  Number times chosen", newline));
   FOR i TO max lines DO printf (($g(0)7xg(0)l$, i, stats[i])) OD
END


10 I = RND(0) : REMRANDOM SEED

20 FOR J = 1 TO 1000000 : REMMAYBE TRY 100 ON A 1MHZ APPLE II
30     N = 10 : GOSUB 100"ONE_OF_N
40     C(C) = C(C) + 1
50 NEXT

60 FOR J = 1 TO 10
70     PRINT J, C(J)
80 NEXT
90 END

100 REMONE_OF_N
110 FOR I = 1 TO N
120     IF INT(RND(1) * I) = 0 THEN C = I
130 NEXT I
140 RETURN


oneOfN: function [n][
    result: 0
    loop 0..dec n 'x [
        if zero? random 0 x ->
            result: x
    ]
    return result
]

oneOfNTest: function [n,trials][
    ret: array.of:n 0
    if n > 0 [
        loop 1..trials 'i [
            oon: oneOfN n
            ret\[oon]: ret\[oon] + 1
        ]
    ]
    return ret
]

print oneOfNTest 10 1000000


one_of_n(n){
    ; One based line numbers
    choice = 1
    Loop % n-1
    {
        Random, rnd, 1, % A_Index+1
        If rnd = 1
            choice := A_Index+1
    }
    return choice
}
one_of_n_test(n=10, trials=100000){
    bins := [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    Loop % trials
        bins[one_of_n(n)] += 1
    return bins
}

b := one_of_n_test()
Loop 10
   out .= A_Index ": " b[A_Index] "`n"
MsgBox % out


#!/usr/bin/gawk -f
#
# Usage:
#   gawk -v Seed=$RANDOM -f one_of_n_lines_in_a_file.awk
#
BEGIN {
   srand(Seed ? Seed : 1);
}
{
   if (NR*rand() < 1 ) {
      line = $0
   }
}
END {
   print line;
}


DECLARE FUNCTION oneofN& (n AS LONG)

DIM L0 AS LONG, c AS LONG
DIM chosen(1 TO 10) AS LONG

RANDOMIZE TIMER

FOR L0 = 1 TO 1000000
    c = oneofN&(10)
    chosen(c) = chosen(c) + 1
NEXT

FOR L0 = 1 TO 10
    PRINT L0, chosen(L0)
NEXT

FUNCTION oneofN& (n AS LONG)
    'assumes first line is 1
    DIM L1 AS LONG, choice AS LONG
    FOR L1 = 1 TO n
        IF INT(RND * L1) = 0 THEN choice = L1
    NEXT
    oneofN& = choice
END FUNCTION


@echo off

for /l %%i in (1,1,10000) do call one_of_n
:: To show progress add to the FOR loop code block -
:: title %%i

for /l %%i in (1,1,10) do (
	for /f "usebackq tokens=1,2 delims=:" %%j in (`find /c "%%i" output.txt`) do echo Line %%i =%%k
)
del output.txt
pause>nul


      @% = 7 : REM Column width
      DIM cnt%(10)
      FOR test% = 1 TO 1000000
        cnt%(FNone_of_n(10)) += 1
      NEXT
      FOR i% = 1 TO 10
        PRINT cnt%(i%);
      NEXT
      PRINT
      END

      DEF FNone_of_n(n%)
      LOCAL i%, l%
      FOR i% = 1 TO n%
        IF RND(1) <= 1/i% l% = i%
      NEXT
      = l%


#include <stdio.h>
#include <stdlib.h>

inline int irand(int n)
{
	int r, randmax = RAND_MAX/n * n;
	while ((r = rand()) >= randmax);
	return r / (randmax / n);
}

inline int one_of_n(int n)
{
	int i, r = 0;
	for (i = 1; i < n; i++) if (!irand(i + 1)) r = i;
	return r;
}

int main(void)
{
	int i, r[10] = {0};

	for (i = 0; i < 1000000; i++, r[one_of_n(10)]++);
	for (i = 0; i < 10; i++)
		printf("%d%c", r[i], i == 9 ? '\n':' ');

	return 0;
}


    class Program
    {
        private static Random rnd = new Random();
        public static int one_of_n(int n)
        {
            int currentChoice = 1;
            for (int i = 2; i <= n; i++)
            {
                double outerLimit = 1D / (double)i;
                if (rnd.NextDouble() < outerLimit)
                    currentChoice = i;
            }
            return currentChoice;
        }

        static void Main(string[] args)
        {
            Dictionary<int, int> results = new Dictionary<int, int>();
            for (int i = 1; i < 11; i++)
                results.Add(i, 0);

            for (int i = 0; i < 1000000; i++)
            {
                int result = one_of_n(10);
                results[result] = results[result] + 1;
            }

            for (int i = 1; i < 11; i++)
                Console.WriteLine("{0}\t{1}", i, results[i]);
            Console.ReadLine();
        }
    }


#include <random>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;

mt19937 engine; //mersenne twister

unsigned int one_of_n(unsigned int n) {
	unsigned int choice;
	for(unsigned int i = 0; i < n; ++i) {
		uniform_int_distribution<unsigned int> distribution(0, i);
		if(!distribution(engine))
			choice = i;
	}
	return choice;
}

int main() {
	engine = mt19937(random_device()()); //seed random generator from system
	unsigned int results[10] = {0};
	for(unsigned int i = 0; i < 1000000; ++i)
		results[one_of_n(10)]++;
	ostream_iterator<unsigned int> out_it(cout, " ");
	copy(results, results+10, out_it);
	cout << '\n';
}


use Random;

proc one_of_n(n) {
    var rand = new RandomStream();
    var keep = 1;

    for i in 2..n do
        if rand.getNext() < 1.0 / i then
            keep = i;

    delete rand;

    return keep;
}


(defn rand-seq-elem [sequence]
  (let [f (fn [[k old] new]
            [(inc k) (if (zero? (rand-int k)) new old)])]
    (->> sequence (reduce f [1 nil]) second)))

(defn one-of-n [n]
  (rand-seq-elem (range 1 (inc n))))

(let [countmap (frequencies (repeatedly 1000000 #(one-of-n 10)))]
  (doseq [[n cnt] (sort countmap)]
    (println n cnt)))


(defun one-of-n-fn ()
  (let ((cur 0) (sel nil))
    #'(lambda (v)
        (setq cur (+ cur 1))
        (if (eql 0 (random cur)) (setq sel v))
        sel)))

(defun test-one-of-n ()
  (let ((counts (make-array 10 :initial-contents '(0 0 0 0 0 0 0 0 0 0)))
        (fnt))
    (do ((test 0 (+ 1 test)))
        ((eql test 1000000) counts)
      (setq fnt (one-of-n-fn))
      (do ((probe 0 (+ 1 probe)))
          ((eql probe 9) t)
        (funcall fnt probe))
      (let* ((sel (funcall fnt 9)))
        (setf (aref counts sel) (+ 1 (aref counts sel)))))))


import std.stdio, std.random, std.algorithm;

// Zero-based line numbers.
int oneOfN(in int n) {
    int choice = 0;
    foreach (immutable i; 1 .. n)
        if (!uniform(0, i + 1))
            choice = i;
    return choice;
}

void main() {
    int[10] bins;
    foreach (immutable i; 0 .. 1_000_000)
        bins[10.oneOfN]++;

    bins.writeln;
    writeln("Total of bins: ", bins[].sum);
}


class
	APPLICATION

create
	make

feature

	make
			-- Simulates one_of_n_lines a 1000000 times.
		local
			t: INTEGER
			simulator: ARRAY [INTEGER]
		do
			create simulator.make_filled (0, 1, 10)
			create one.make
			across
				1 |..| 1000000 as c
			loop
				t := one.one_of_n_lines (10)
				simulator [t] := simulator [t] + 1
			end
			across
				simulator as s
			loop
				io.put_integer (s.item)
				io.new_line
			end
		end

	one: ONE_OF_N_LINES

end


defmodule One_of_n_lines_in_file do
  def task do
    dict = Enum.reduce(1..1000000, %{}, fn _,acc ->
      Map.update( acc, one_of_n(10), 1, &(&1+1) )
    end)
    Enum.each(Enum.sort(Map.keys(dict)), fn x ->
      :io.format "Line ~2w selected: ~6w~n", [x, dict[x]]
    end)
  end

  def one_of_n( n ), do: loop( n, 2, :rand.uniform, 1 )

  def loop( max, n, _random, acc ) when n == max + 1, do: acc
  def loop( max, n, random, _acc ) when random < (1/n), do: loop( max, n + 1, :rand.uniform, n )
  def loop( max, n, _random, acc ), do: loop( max, n + 1, :rand.uniform, acc )
end

One_of_n_lines_in_file.task


-module( one_of_n_lines_in_file  ).

-export( [one_of_n/1, task/0] ).

one_of_n( N ) -> loop( N, 2, random:uniform(), 1 ).

task() ->
	Dict = lists:foldl( fun update_counter/2,  dict:new(), lists:seq(1, 1000000) ),
	[io:fwrite("Line ~p selected: ~p~n", [X, dict:fetch(X, Dict)]) || X <- lists:sort(dict:fetch_keys(Dict))].

loop( Max, N, _Random, Acc ) when N =:= Max + 1 -> Acc;
loop( Max, N, Random, _Acc ) when Random < (1/N) -> loop( Max, N + 1, random:uniform(), N );
loop( Max, N, _Random, Acc ) -> loop( Max, N + 1, random:uniform(), Acc ).

update_counter( _N, Dict ) -> dict:update_counter( one_of_n(10), 1, Dict ).


PROGRAM ONE_OF_N

DIM CNT[10]

PROCEDURE ONE_OF_N(N->L)
  LOCAL I
  FOR I=1 TO N DO
     IF RND(1)<=1.0/I THEN L=I END IF
  END FOR
END PROCEDURE

BEGIN
  N=10
  RANDOMIZE(TIMER)       ! init
  FOR TEST=1 TO 1000000 DO
     ONE_OF_N(N->L)
     CNT[L]+=1
  END FOR
  FOR I=1 TO N DO
     PRINT(CNT[I];)
  END FOR
  PRINT
END PROGRAM


--  One of n lines in a file
include std/rand.e
include std/math.e

function one_of_n(integer n)
	integer line_num = 1
	for i = 2 to n do
		if rnd() < 1 / i then
			line_num = i
		end if
	end for
	return line_num
end function

procedure main()
	integer num_reps = 1000000, num_lines_in_file = 10
	sequence lines = repeat(0,num_lines_in_file)
	for i = 1 to num_reps do
		lines[one_of_n(num_lines_in_file)] += 1
	end for
	for i = 1 to num_lines_in_file do
		printf(1,"Number of times line %d was selected: %g\n", {i,lines[i]})
	end for
	printf(1,"Total number selected: %d\n", sum(lines) )
end procedure

main()


open System

[<EntryPoint>]
let main args =
    let rnd = new Random()

    let one_of_n n =
        let rec loop i r =
            if i >= n then r else
                if rnd.Next(i + 1) = 0
                then loop (i + 1) i
                else loop (i + 1) r
        loop 1 0

    let test n trials =
        let ar = Array.zeroCreate n
        for i = 1 to trials do
            let d = one_of_n n
            ar.[d] <- 1 + ar.[d]
        Console.WriteLine (String.Join(" ", ar))

    test 10 1000000
    0


! rosettacode/random-line/random-line.factor
USING: io kernel locals math random ;
IN: rosettacode.random-line

:: random-line ( -- line )
    readln :> choice! 1 :> count!
    [ readln dup ]
    [ count 1 + dup count! random zero?
        [ choice! ] [ drop ] if
    ] while drop
    choice ;


require random.fs

: frnd
   rnd 0 d>f [ s" MAX-U" environment? drop 0 d>f 1/f ] fliteral f* ;
: u>f 0 d>f ;
: one_of_n ( u1 -- u2 )
   1 swap  1+ 2 ?do  frnd  i u>f 1/f  f<  if drop i then  loop ;

create hist 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,  does> swap cells + ;
: simulate  1000000 0 do  1  10 one_of_n 1- hist  +!  loop ;
: .hist  cr 10 0 do  i 1+ 2 .r ." : "  i hist @ .  cr loop ;

simulate .hist bye


!> read lines one at a time and randomly choose one
!! using a Reservoir Sampling algorithm:
!! http://www.rosettacode.org/wiki/One_of_n_lines_in_a_file
program reservoir_sample
use, intrinsic :: iso_fortran_env, only : dp=>real64
implicit none
character(len=256)   :: line
integer              :: lun, n, i, count(10)
   call random_seed()
   !! create test file
   open(file='_data.txt',newunit=lun)
   do i=1,10
      write(lun,'(*(g0))')'test line ',i
   enddo
   !! run once and show result
   call one_of_n(line,n)
   write(*,'(i10,":",a)')n,trim(line)
   !! run 1 000 000, times on ten-line test file
   count=0
   do i=1,1000000
      call one_of_n(line,n)
      if(n.gt.0.and.n.le.10)then
         count(n)=count(n)+1
      else
         write(*,*)'<ERROR>'
      endif
   enddo
   write(*,*)count
   write(*,*)count-100000
contains
subroutine one_of_n(line,n)
character(len=256),intent(out) :: line
integer,intent(out)            :: n
real(kind=dp)                  :: rand_val
integer                        :: ios, ilines
   line=''
   ios=0
   ilines=1
   n=0
   rewind(lun)
   do
      call random_number(rand_val)
      if( rand_val < 1.0d0/(ilines) )then
         read(lun,'(a)',iostat=ios)line
         if(ios/=0)exit
         n=ilines
      else
         read(lun,'(a)',iostat=ios)
         if(ios/=0)exit
      endif
      ilines=ilines+1
   enddo
end subroutine one_of_n
end program reservoir_sample
}


Declare Function one_of_n (n As Long) As Long

Dim As Long L0, c, elegido(1 To 10)

Function one_of_n (n As Long) As Long

    'asume que la primera línea es 1
    Dim As Long L1, opcion
    For L1 = 1 To n
        If Int(Rnd * L1) = 0 Then opcion = L1
    Next L1
    one_of_n = opcion
End Function

Randomize Timer

For L0 = 1 To 1000000
    c = one_of_n(10)
    elegido(c) += 1
Next L0

For L0 = 1 To 10
    Print Using "##. #######"; L0; elegido(L0)
Next L0

Sleep


package main

import (
    "bufio"
    "fmt"
    "io"
    "math/rand"
    "time"
)

// choseLineRandomly implements the method described in the task.
// input is a an io.Reader, which could be an os.File, for example.
// Or, to implement a simulation, it could be anything else that implements
// io.Reader.  The method as described suggests saving and returning
// lines, but the rest of the task requires line numbers.  This function
// thus returns both.
func choseLineRandomly(r io.Reader) (s string, ln int, err error) {
    br := bufio.NewReader(r)
    s, err = br.ReadString('\n')
    if err != nil {
        return
    }
    ln = 1
    lnLast := 1.
    var sLast string
    for {
        // note bufio.ReadString used here.  This effectively defines a
        // line of the file as zero or more bytes followed by a newline.
        sLast, err = br.ReadString('\n')
        if err == io.EOF {
            return s, ln, nil // normal return
        }
        if err != nil {
            break
        }
        lnLast++
        if rand.Float64() < 1/lnLast {
            s = sLast
            ln = int(lnLast)
        }
    }
    return // error return
}

// oneOfN function required for task item 1.  Specified to take a number
// n, the number of lines in a file, but the method (above) specified to
// to be used does not need n, but rather the file itself.  This function
// thus takes both, ignoring n and passing the file to choseLineRandomly.
func oneOfN(n int, file io.Reader) int {
    _, ln, err := choseLineRandomly(file)
    if err != nil {
        panic(err)
    }
    return ln
}

// simulated file reader for task item 2
type simReader int

func (r *simReader) Read(b []byte) (int, error) {
    if *r <= 0 {
        return 0, io.EOF
    }
    b[0] = '\n'
    *r--
    return 1, nil
}

func main() {
    // task item 2 simulation consists of accumulating frequency statistic
    // on 1,000,000 calls of oneOfN on simulated file.
    n := 10
    freq := make([]int, n)
    rand.Seed(time.Now().UnixNano())
    for times := 0; times < 1e6; times++ {
        sr := simReader(n)
        freq[oneOfN(n, &sr)-1]++
    }

    // task item 3.  show frequencies.
    fmt.Println(freq)
}


import qualified Data.Map as M
import System.Random
import Data.List
import Control.Monad
import System.Environment

testFile = [1..10]

selItem g xs = foldl' f (head xs, 1, 2, g) $ tail xs
    where f :: RandomGen a => (b, Int, Int, a) -> b -> (b, Int, Int, a)
          f (c, cn, n, gen) l | v == 1    = (l, n, n+1, ngen)
                              | otherwise = (c, cn, n+1, ngen)
            where (v, ngen) = randomR (1, n) gen

oneOfN a = do
            g <- newStdGen
            let (r, _, _, _) = selItem g a
            return r

test = do
        x <- replicateM 1000000 (oneOfN testFile)
        let f m l = M.insertWith (+) l 1 m
        let results = foldl' f M.empty x
        forM_ (M.toList results) $ \(x, y) -> putStrLn $ "Line number " ++ show x ++
								 " had count :" ++ show y

main = do
        a <- getArgs
        g <- newStdGen
        if null a then test
                  else putStrLn.(\(l, n, _, _) -> "Line " ++
                               show n ++ ": " ++ l)
                       .selItem g.lines =<< (readFile $ head a)


procedure main() # one of n
   one_of_n_test(10,1000000)
end

procedure one_of_n(n)
   every i := 1 to n do
      choice := (?0  < 1. / i, i)
   return \choice | fail
end

procedure one_of_n_test(n,trials)
   bins := table(0)
   every i := 1 to trials do
         bins[one_of_n(n)] +:= 1
   every writes(bins[i := 1 to n]," ")
   return bins
end


randLineBig=:3 :0
  file=. boxopen y
  r=. ''
  n=. 1
  size=. fsize file
  blocksize=. 1e7
  buffer=. ''
  for_block. |: blocksize -~/\@(] <. [ * 0 1 +/[email protected]>[email protected]%~) size do.
    buffer=. buffer, fread file,<block
    linends=. LF = buffer
    lines=. linends <;.2 buffer
    buffer=. buffer }.~ {: 1+I.linends
    pick=. (0 [email protected]$~ #lines) < % n+i.#lines
    if. 1 e. pick do.
      r=. ({:I.pick) {:: lines
    end.
    n=. n+#lines
  end.
  r
)


import java.util.Arrays;
import java.util.Random;

public class OneOfNLines {

	static Random rand;

	public static int oneOfN(int n) {
		int choice = 0;

		for(int i = 1; i < n; i++) {
			if(rand.nextInt(i+1) == 0)
				choice = i;
		}

		return choice;
	}

	public static void main(String[] args) {
		int n = 10;
		int trials = 1000000;
		int[] bins = new int[n];
		rand = new Random();

		for(int i = 0; i < trials; i++)
			bins[oneOfN(n)]++;

		System.out.println(Arrays.toString(bins));
	}
}


export LC_ALL=C
< /dev/random tr -cd '0-9' | fold -w 4 | jq -Mnr -f program.jq


const N = 10
const GOAL = 10^6

function oneofn{T<:Integer}(n::T)
    0 < n || error("n = ", n, ", but it should be positive.")
    oon = 1
    for i in 2:n
        rand(1:i) == 1 || continue
        oon = i
    end
    return oon
end

nhist = zeros(Int, N)
for i in 1:GOAL
    nhist[oneofn(N)] += 1
end

println("Simulating oneofn(", N, ") ", GOAL, " times:")
for i in 1:N
    println(@sprintf "   %2d => %6d" i nhist[i])
end


// version 1.1.51

import java.util.Random

val r = Random()

fun oneOfN(n: Int): Int {
    var choice = 1
    for (i in 2..n) {
        if (r.nextDouble() < 1.0 / i) choice = i
    }
    return choice
}

fun main(args: Array<String>) {
    val n = 10
    val freqs = IntArray(n)
    val reps = 1_000_000
    repeat(reps) {
        val num = oneOfN(n)
        freqs[num - 1]++
    }
    for (i in 1..n) println("Line ${"%-2d".format(i)} = ${freqs[i - 1]}")
}


DIM chosen(10)

FOR i = 1 TO 10000'00
    c = oneofN(10)
    chosen(c) = chosen(c) + 1
NEXT

FOR i = 1 TO 10
    PRINT i, chosen(i)
NEXT

end

FUNCTION oneofN(n)
    FOR i = 1 TO n
        IF RND(1) < 1/i THEN oneofN = i
    NEXT
END FUNCTION


math.randomseed(os.time())

local n = 10
local trials = 1000000

function one(n)
    local chosen = 1
    for i = 1, n do
        if math.random() < 1/i then
            chosen = i
        end
    end

    return chosen
end

-- 0 filled table for storing results
local results = {}
for i = 1, n do results[i] = 0 end

-- run simulation
for i = 1, trials do
    local result = one(n)
    results[result] = results[result] + 1
end

print("Value","Occurrences")
print("-------------------")
for k, v in ipairs(results) do
    print(k,v)
end


with(RandomTools[MersenneTwister]);
one_of_n_lines_in_a_file := proc(fn)
	local fid, N, n, L, l, line;
	fid := fopen(fn,'READ');
	if fid<0 then
		return;
	end if;
	N := 0;
	n := 1;
	while not feof(fid) do
		N := N+1;
		L := FileTools[Text][ReadLine](fid);
		if (N*GenerateFloat() < 1) then
			n := N;
			line := L;
		end if;
	end do;
	fclose(fid);
	return(n);
end proc;


chooseLine[file_] := Block[{strm = OpenRead[file], n = 1, rec, selected},
  					     rec = selected = Read[strm];
  					     While[rec =!= EndOfFile,
                                                    rec=Read[strm];
                                                    n++;
                                                    If[RandomReal[] < 1/n, selected = rec]];
                                             Close[strm];
                                             selected]


function [n,line] = one_of_n_lines_in_a_file(fn)
fid = fopen(fn,'r');
if fid<0, return; end;
N = 0;
n = 1;
while ~feof(fid)
	N = N+1;
	L = fgetl(fid);
	if (N*rand() < 1)
		n = N;
		line = L;
	end;
end
fclose(fid);


import random
randomize()

proc oneOfN(n: int): int =
  result = 0
  for x in 0 ..< n:
    if random(x) == 0:
      result = x

proc oneOfNTest(n = 10, trials = 1_000_000): seq[int] =
  result = newSeq[int](n)
  if n > 0:
    for i in 1..trials:
      inc result[oneOfN(n)]

echo oneOfNTest()


let one_of_n n =
  let rec aux i r =
    if i >= n then r else
      if Random.int (i + 1) = 0
      then aux (succ i) i
      else aux (succ i) r
  in
  aux 1 0

let test ~n ~trials =
  let ar = Array.make n 0 in
  for i = 1 to trials do
    let d = one_of_n n in
    ar.(d) <- succ ar.(d)
  done;
  Array.iter (Printf.printf " %d") ar;
  print_newline ()

let () =
  Random.self_init ();
  test ~n:10 ~trials:1_000_000


one_of_n(n)={
  my(chosen=1);
  for(k=2,n,
    if(random(k)==0, chosen=k)
  );
  chosen;
}
v=vector(10); for(i=1,1e6, v[one_of_n(10)]++); v


Program OneOfNLines (Output);

{$IFDEF FPC}
  {$MODE DELPHI}
{$ENDIF}

function one_of_n(n: longint): longint;
  var
    i: longint;
  begin
    one_of_n := 1;
    for i := 2 to n do
      if random < 1.0 / i then
	one_of_n := i;
  end;

function sum(a: array of longint): longint;
  var
    i: integer;
  begin
    Result := 0;
    for i := low(a) to high(a) do
       Result := Result + a[i];
  end;

const
  num_reps = 1000000;
  num_lines_in_file = 10;

var
  lines: array[1..num_reps] of longint;
  i: longint;

begin
  randomize;
  for i := 1 to num_reps do
    lines[i] := 0;
  for i := 1 to num_reps do
    inc(lines[one_of_n(num_lines_in_file)]);
  for i := 1 to num_lines_in_file do
    writeln('Number of times line ', i, ' was selected: ', lines[i]);
  writeln('Total number selected: ', sum(lines));
end.


#!/usr/bin/perl
use warnings;
use strict;

sub one_of_n {
    my $n = shift;
    my $return = 1;
    for my $line (2 .. $n) {
        $return = $line if 1 > rand $line;
    }
    return $return;
}

my $repeat = 1_000_000;
my $size   = 10;

my @freq;
++$freq[ one_of_n($size) - 1 ] for 1 .. $repeat;
print "@freq\n";


with javascript_semantics
function one_of_n(integer n)
    integer line_num = 1
    for i=2 to n do
        if rnd()<1/i then
            line_num = i
        end if
    end for
    return line_num
end function

sequence counts = repeat(0,10)
for i=1 to 1000000 do
    integer cdx = one_of_n(10)
    counts[cdx] += 1
end for
?counts


(de one-of-n (N)
   (let R 1
      (for I N
         (when (= 1 (rand 1 I))
            (setq R I) ) )
      R ) )

(let L (need 10 0)
   (do 1000000
      (inc (nth L (one-of-n 10))) )
   L )


function Get-OneOfN ([int]$Number)
{
    $current = 1

    for ($i = 2; $i -le $Number; $i++)
    {
        $limit = 1 / $i

        if ((Get-Random -Minimum 0.0 -Maximum 1.0) -lt $limit)
        {
            $current = $i
        }
    }

    $current
}

$table = [ordered]@{}

for ($i = 1; $i -lt 11; $i++)
{
    $table.Add(("Line {0,2}" -f $i), 0)
}

for ($i = 0; $i -lt 1000000; $i++)
{
    $index = (Get-OneOfN -Number 10) - 1
    $table[$index] = $table[$index] + 1
}

[PSCustomObject]$table


Procedure.f randomFloat()
   ProcedureReturn Random(1000000) / 1000000
EndProcedure

Procedure one_of_n(n)
  Protected linesRead, lineChosen
  While linesRead < n
    linesRead + 1
    If randomFloat() <= (1.0 / (linesRead))
       lineChosen = linesRead
    EndIf
  Wend
  ProcedureReturn lineChosen
EndProcedure

If OpenConsole()
  #testFileLineCount = 10
  #simulationCount = 1000000
  Define i
  Dim a(#testFileLineCount) ;index 0 is not used
  For i = 1 To #simulationCount
    x = one_of_n(#testFileLineCount)
    a(x) + 1
  Next

  For i = 1 To #testFileLineCount
    Print(Str(a(i)) + "  ")
  Next
  PrintN("")

  Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input()
  CloseConsole()
EndIf


from random import randrange
try:
    range = xrange
except: pass

def one_of_n(lines): # lines is any iterable
    choice = None
    for i, line in enumerate(lines):
        if randrange(i+1) == 0:
            choice = line
    return choice

def one_of_n_test(n=10, trials=1000000):
    bins = [0] * n
    if n:
        for i in range(trials):
            bins[one_of_n(range(n))] += 1
    return bins

print(one_of_n_test())


one_of_n <- function(n)
{
  choice <- 1L

  for (i in 2:n)
  {
    if (i*runif(1) < 1)
      choice <- i
  }

  return(choice)
}

table(sapply(1:1000000, function(i) one_of_n(10)))


sub one_of_n($n) {
    my $choice;
    $choice = $_ if .rand < 1 for 1 .. $n;
    $choice - 1;
}

sub one_of_n_test($n = 10, $trials = 1_000_000) {
    my @bins;
    @bins[one_of_n($n)]++ for ^$trials;
    @bins;
}

say one_of_n_test();


/*REXX program simulates reading a  ten─line  file,  count the selection randomness.    */
N= 10                                            /*the number of lines in pseudo-file.  */
@.= 0                                            /*zero  all  the (ten)  "buckets".     */
      do 1000000                                 /*perform main loop  one million times.*/
      ?= 1
                    do k=1  for N                /*N  is the number of lines in the file*/
                    if random(0, 99999) / 100000  <  1/k  then ?= k      /*the criteria.*/
                    end   /*k*/
      @.?= @.? + 1                               /*bump the count in a particular bucket*/
      end                 /*1000000*/

   do j=1  for N                                 /*display randomness counts (buckets). */
   say "number of times line"       right(j, 2)       "was selected:"       right(@.j, 9)
   end   /*j*/                                   /*stick a fork in it,  we're all done. */


cnt = list(10)
for nr = 1 to 10000
    cnt[oneofn(10)] += 1
next
for m = 1 to 10
    see "" + m + " : " + cnt[m] + nl
next
see nl

func oneofn n
for i = 1 to n
    if random(1) <= 1/i d = i ok
next
return d


# Returns a random line from _io_, or nil if _io_ has no lines.
#  # Get a random line from /etc/passwd
#  line = open("/etc/passwd") {|f| random_line(f) }
def random_line(io)
  choice = io.gets; count = 1
  while line = io.gets
    rand(count += 1).zero? and choice = line
  end
  choice
end

def one_of_n(n)
  # Create a mock IO that provides line numbers instead of lines.
  # Assumes that #random_line calls #gets.
  (mock_io = Object.new).instance_eval do
    @count = 0
    @last = n
    def self.gets
      (@count < @last) ? (@count += 1) : nil
    end
  end
  random_line(mock_io)
end

chosen = Hash.new(0)
1_000_000.times { chosen[one_of_n(10)] += 1 }
chosen.keys.sort.each do |key|
  puts "#{key} chosen #{chosen[key]} times"
end


for i1 = 1 to 1000000
    c = oneOfN(10)
    chosen(c) = chosen(c) + 1
next

for i1 = 1 to 10
    print i1;" ";chosen(i1)
next

FUNCTION oneOfN(n)
    for i2 = 1 to n
        IF int(rnd(1) * i2) = 0 then choice = i2
    next
    oneOfN = choice
END FUNCTION


extern crate rand;

use rand::{Rng, thread_rng};

fn one_of_n<R: Rng>(rng: &mut R, n: usize) -> usize {
    (1..n).fold(0, |keep, cand| {
        // Note that this will break if n is larger than u32::MAX
        if rng.gen_weighted_bool(cand as u32 + 1) {
            cand
        } else {
            keep
        }
    })
}

fn main() {
    const LINES: usize = 10;

    let mut dist = [0; LINES];
    let mut rng = thread_rng();

    for _ in 0..1_000_000 {
        let num = one_of_n(&mut rng, LINES);
        dist[num] += 1;
    }

    println!("{:?}", dist);
}


def one_of_n(n: Int, i: Int = 1, j: Int = 1): Int =
  if (n < 1) i else one_of_n(n - 1, if (scala.util.Random.nextInt(j) == 0) n else i, j + 1)

def simulate(lines: Int, iterations: Int) = {
  val counts = new Array[Int](lines)
  for (_ <- 1 to iterations; i = one_of_n(lines) - 1) counts(i) = counts(i) + 1
  counts
}

println(simulate(10, 1000000) mkString "\n")


$ include "seed7_05.s7i";

const func integer: one_of_n (in integer: n) is func
  result
    var integer: r is 1;
  local
    var integer: i is 0;
  begin
    for i range 2 to n do
      if rand(1, i) = 1 then
        r := i;
      end if;
    end for;
  end func;

const proc: main is func
  local
    var array integer: r is 10 times 0;
    var integer: i is 0;
  begin
    for i range 1 to 1000000 do
      incr(r[one_of_n(10)]);
    end for;
    for i range 1 to 10 do
      write(r[i] <& " ");
    end for;
    writeln;
  end func;


func one_of_n(n) {
    var choice
    n.times { |i|
        choice = i if (1 > i.rand)
    }
    choice - 1
}

func one_of_n_test(n = 10, trials = 1_000_000) {
    var bins = []
    trials.times {
        bins[one_of_n(n)] := 0 ++
    }
    bins
}

say one_of_n_test()


func one_of_n(n: Int) -> Int {
  var result = 1
  for i in 2...n {
    if arc4random_uniform(UInt32(i)) < 1 {
      result = i
    }
  }
  return result
}

var counts = [0,0,0,0,0,0,0,0,0,0]
for _ in 1..1_000_000 {
  counts[one_of_n(10)-1]++
}

println(counts)


package require Tcl 8.5
proc 1ofN {n} {
    for {set line 1} {$line <= $n} {incr line} {
	if {rand() < 1.0/[incr fraction]} {
	    set result $line
	}
    }
    return $result
}

for {set i 0} {$i < 1000000} {incr i} {
    incr count([1ofN 10])
}
parray count;   # Alphabetic order, but convenient


Dim chosen(10)

For j = 1 To 1000000
	c = one_of_n(10)
	chosen(c) = chosen(c) + 1
Next

For k = 1 To 10
	WScript.StdOut.WriteLine k & ". " & chosen(k)
Next

Function one_of_n(n)
	Randomize
	For i = 1 To n
		If Rnd(1) < 1/i Then
			one_of_n = i
		End If
	Next
End Function


import "random" for Random
import "/fmt" for Fmt

var rand = Random.new()

var oneOfN = Fn.new { |n|
    var choice = 1
    for (i in 2..n) {
        if (rand.float() < 1/i) choice = i
    }
    return choice
}

var n = 10
var freqs = List.filled(n, 0)
var reps = 1e6
for (i in 0...reps) {
    var num = oneOfN.call(n)
    freqs[num-1] = freqs[num-1] + 1
}
for (i in 1..n) Fmt.print("Line $-2d = $,7d", i, freqs[i-1])


dim elegido(10)

sub one_of_n (n)
    //asume que la primera línea es 1
    local L1
    for L1 = 1 to n
        if int(ran(L1)) = 0 then opcion = L1 : endif
    next L1
    return opcion
end sub

for L0 = 1 to 1000000
    c = one_of_n(10)
    elegido(c) = elegido(c) + 1
next L0

for L0 = 1 to 10
    print L0, ".  ", elegido(L0)
next L0

end


fcn one_of_n(lines){ # lines is any iterable
#if 0  // iterative
   choice:=Void;
   foreach i,line in ([0..].zip(lines)){
      if((0).random(i+1)==0) choice=line;
   }
   return(choice);
#else  // functional
   [0..].zip(lines).pump(Ref(Void).set,fcn([(n,line)])
      { if((0).random(n+1)==0) line else Void.Skip }).value
#endif
}

fcn one_of_n_test(n=10, trials=0d1_000_000){
   bins:=n.pump(List(),0); // List(0,0,0...)
   if(n){ foreach i in (trials){ bins[one_of_n((n).walker())]+=1 } }
   return(bins);
}

println(one_of_n_test());


package main

import (
    "bufio"
    "crypto/rand"
    "fmt"
    "io/ioutil"
    "log"
    "math/big"
    "os"
    "strconv"
    "strings"
    "unicode"
)

const (
    charsPerLine = 48
    chunkSize    = 6
    cols         = 8
    demo         = true // would normally be set to false
)

type fileType int

const (
    otp fileType = iota
    enc
    dec
)

var scnr = bufio.NewScanner(os.Stdin)

func check(err error) {
    if err != nil {
        log.Fatal(err)
    }
}

func toAlpha(s string) string {
    var filtered []rune
    for _, r := range s {
        if unicode.IsUpper(r) {
            filtered = append(filtered, r)
        }
    }
    return string(filtered)
}

func isOtpRelated(s string) bool {
    return strings.HasSuffix(s, ".1tp") || strings.HasSuffix(s, "1tp_cpy") ||
        strings.HasSuffix(s, ".1tp_enc") || strings.HasSuffix(s, "1tp_dec")
}

func makePad(nLines int) string {
    nChars := nLines * charsPerLine
    bytes := make([]byte, nChars)
    /* generate random upper case letters */
    max := big.NewInt(26)
    for i := 0; i < nChars; i++ {
        n, err := rand.Int(rand.Reader, max)
        check(err)
        bytes[i] = byte(65 + n.Uint64())
    }
    return inChunks(string(bytes), nLines, otp)
}

func vigenere(text, key string, encrypt bool) string {
    bytes := make([]byte, len(text))
    var ci byte
    for i, c := range text {
        if encrypt {
            ci = (byte(c) + key[i] - 130) % 26
        } else {
            ci = (byte(c) + 26 - key[i]) % 26
        }
        bytes[i] = ci + 65
    }
    temp := len(bytes) % charsPerLine
    if temp > 0 { // pad with random characters so each line is a full one
        max := big.NewInt(26)
        for i := temp; i < charsPerLine; i++ {
            n, err := rand.Int(rand.Reader, max)
            check(err)
            bytes = append(bytes, byte(65+n.Uint64()))
        }
    }
    ft := enc
    if !encrypt {
        ft = dec
    }
    return inChunks(string(bytes), len(bytes)/charsPerLine, ft)
}

func inChunks(s string, nLines int, ft fileType) string {
    nChunks := len(s) / chunkSize
    remainder := len(s) % chunkSize
    chunks := make([]string, nChunks)
    for i := 0; i < nChunks; i++ {
        chunks[i] = s[i*chunkSize : (i+1)*chunkSize]
    }
    if remainder > 0 {
        chunks = append(chunks, s[nChunks*chunkSize:])
    }
    var sb strings.Builder
    for i := 0; i < nLines; i++ {
        j := i * cols
        sb.WriteString(" " + strings.Join(chunks[j:j+cols], " ") + "\n")
    }
    ss := " file\n" + sb.String()
    switch ft {
    case otp:
        return "# OTP" + ss
    case enc:
        return "# Encrypted" + ss
    default: // case dec:
        return "# Decrypted" + ss
    }
}

func menu() int {
    fmt.Println(`
1. Create one time pad file.

2. Delete one time pad file.

3. List one time pad files.

4. Encrypt plain text.

5. Decrypt cipher text.

6. Quit program.
`)
    choice := 0
    for choice < 1 || choice > 6 {
        fmt.Print("Your choice (1 to 6) : ")
        scnr.Scan()
        choice, _ = strconv.Atoi(scnr.Text())
        check(scnr.Err())
    }
    return choice
}

func main() {
    for {
        choice := menu()
        fmt.Println()
        switch choice {
        case 1: // Create OTP
            fmt.Println("Note that encrypted lines always contain 48 characters.\n")
            fmt.Print("OTP file name to create (without extension) : ")
            scnr.Scan()
            fileName := scnr.Text() + ".1tp"
            nLines := 0
            for nLines < 1 || nLines > 1000 {
                fmt.Print("Number of lines in OTP (max 1000) : ")
                scnr.Scan()
                nLines, _ = strconv.Atoi(scnr.Text())
            }
            check(scnr.Err())
            key := makePad(nLines)
            file, err := os.Create(fileName)
            check(err)
            _, err = file.WriteString(key)
            check(err)
            file.Close()
            fmt.Printf("\n'%s' has been created in the current directory.\n", fileName)
            if demo {
                // a copy of the OTP file would normally be on a different machine
                fileName2 := fileName + "_cpy" // copy for decryption
                file, err := os.Create(fileName2)
                check(err)
                _, err = file.WriteString(key)
                check(err)
                file.Close()
                fmt.Printf("'%s' has been created in the current directory.\n", fileName2)
                fmt.Println("\nThe contents of these files are :\n")
                fmt.Println(key)
            }
        case 2: // Delete OTP
            fmt.Println("Note that this will also delete ALL associated files.\n")
            fmt.Print("OTP file name to delete (without extension) : ")
            scnr.Scan()
            toDelete1 := scnr.Text() + ".1tp"
            check(scnr.Err())
            toDelete2 := toDelete1 + "_cpy"
            toDelete3 := toDelete1 + "_enc"
            toDelete4 := toDelete1 + "_dec"
            allToDelete := []string{toDelete1, toDelete2, toDelete3, toDelete4}
            deleted := 0
            fmt.Println()
            for _, name := range allToDelete {
                if _, err := os.Stat(name); !os.IsNotExist(err) {
                    err = os.Remove(name)
                    check(err)
                    deleted++
                    fmt.Printf("'%s' has been deleted from the current directory.\n", name)
                }
            }
            if deleted == 0 {
                fmt.Println("There are no files to delete.")
            }
        case 3: // List OTPs
            fmt.Println("The OTP (and related) files in the current directory are:\n")
            files, err := ioutil.ReadDir(".") // already sorted by file name
            check(err)
            for _, fi := range files {
                name := fi.Name()
                if !fi.IsDir() && isOtpRelated(name) {
                    fmt.Println(name)
                }
            }
        case 4: // Encrypt
            fmt.Print("OTP file name to use (without extension) : ")
            scnr.Scan()
            keyFile := scnr.Text() + ".1tp"
            if _, err := os.Stat(keyFile); !os.IsNotExist(err) {
                file, err := os.Open(keyFile)
                check(err)
                bytes, err := ioutil.ReadAll(file)
                check(err)
                file.Close()
                lines := strings.Split(string(bytes), "\n")
                le := len(lines)
                first := le
                for i := 0; i < le; i++ {
                    if strings.HasPrefix(lines[i], " ") {
                        first = i
                        break
                    }
                }
                if first == le {
                    fmt.Println("\nThat file has no unused lines.")
                    continue
                }
                lines2 := lines[first:] // get rid of comments and used lines

                fmt.Println("Text to encrypt :-\n")
                scnr.Scan()
                text := toAlpha(strings.ToUpper(scnr.Text()))
                check(scnr.Err())
                tl := len(text)
                nLines := tl / charsPerLine
                if tl%charsPerLine > 0 {
                    nLines++
                }
                if len(lines2) >= nLines {
                    key := toAlpha(strings.Join(lines2[0:nLines], ""))
                    encrypted := vigenere(text, key, true)
                    encFile := keyFile + "_enc"
                    file2, err := os.Create(encFile)
                    check(err)
                    _, err = file2.WriteString(encrypted)
                    check(err)
                    file2.Close()
                    fmt.Printf("\n'%s' has been created in the current directory.\n", encFile)
                    for i := first; i < first+nLines; i++ {
                        lines[i] = "-" + lines[i][1:]
                    }
                    file3, err := os.Create(keyFile)
                    check(err)
                    _, err = file3.WriteString(strings.Join(lines, "\n"))
                    check(err)
                    file3.Close()
                    if demo {
                        fmt.Println("\nThe contents of the encrypted file are :\n")
                        fmt.Println(encrypted)
                    }
                } else {
                    fmt.Println("Not enough lines left in that file to do encryption.")
                }
            } else {
                fmt.Println("\nThat file does not exist.")
            }
        case 5: // Decrypt
            fmt.Print("OTP file name to use (without extension) : ")
            scnr.Scan()
            keyFile := scnr.Text() + ".1tp_cpy"
            check(scnr.Err())
            if _, err := os.Stat(keyFile); !os.IsNotExist(err) {
                file, err := os.Open(keyFile)
                check(err)
                bytes, err := ioutil.ReadAll(file)
                check(err)
                file.Close()
                keyLines := strings.Split(string(bytes), "\n")
                le := len(keyLines)
                first := le
                for i := 0; i < le; i++ {
                    if strings.HasPrefix(keyLines[i], " ") {
                        first = i
                        break
                    }
                }
                if first == le {
                    fmt.Println("\nThat file has no unused lines.")
                    continue
                }
                keyLines2 := keyLines[first:] // get rid of comments and used lines

                encFile := keyFile[0:len(keyFile)-3] + "enc"
                if _, err := os.Stat(encFile); !os.IsNotExist(err) {
                    file2, err := os.Open(encFile)
                    check(err)
                    bytes, err := ioutil.ReadAll(file2)
                    check(err)
                    file2.Close()
                    encLines := strings.Split(string(bytes), "\n")[1:] // exclude comment line
                    nLines := len(encLines)
                    if len(keyLines2) >= nLines {
                        encrypted := toAlpha(strings.Join(encLines, ""))
                        key := toAlpha(strings.Join(keyLines2[0:nLines], ""))
                        decrypted := vigenere(encrypted, key, false)
                        decFile := keyFile[0:len(keyFile)-3] + "dec"
                        file3, err := os.Create(decFile)
                        check(err)
                        _, err = file3.WriteString(decrypted)
                        check(err)
                        file3.Close()
                        fmt.Printf("\n'%s' has been created in the current directory.\n", decFile)
                        for i := first; i < first+nLines; i++ {
                            keyLines[i] = "-" + keyLines[i][1:]
                        }
                        file4, err := os.Create(keyFile)
                        check(err)
                        _, err = file4.WriteString(strings.Join(keyLines, "\n"))
                        check(err)
                        file4.Close()
                        if demo {
                            fmt.Println("\nThe contents of the decrypted file are :\n")
                            fmt.Println(decrypted)
                        }
                    }
                } else {
                    fmt.Println("Not enough lines left in that file to do decryption.")
                }
            } else {
                fmt.Println("\nThat file does not exist.")
            }
        case 6: // Quit program
            return
        }
    }
}


-- To compile into an executable:
-- ghc -main-is OneTimePad OneTimePad.hs
-- To run:
-- ./OneTimePad --help

module OneTimePad (main) where

import           Control.Monad
import           Data.Char
import           Data.Function         (on)
import qualified Data.Text             as T
import qualified Data.Text.IO          as TI
import           Data.Time
import           System.Console.GetOpt
import           System.Environment
import           System.Exit
import           System.IO

-- Command-line options parsing
data Options = Options  { optCommand :: String
                        , optInput   :: IO T.Text
                        , optOutput  :: T.Text -> IO ()
                        , optPad     :: (IO T.Text, T.Text -> IO ())
                        , optLines   :: Int
                        }

startOptions :: Options
startOptions = Options  { optCommand    = "decrypt"
                        , optInput      = TI.getContents
                        , optOutput     = TI.putStr
                        , optPad        = (TI.getContents, TI.putStr)
                        , optLines      = 0
                        }

options :: [ OptDescr (Options -> IO Options) ]
options =
    [ Option "e" ["encrypt"]
        (NoArg
            (\opt -> return opt { optCommand = "encrypt" }))
        "Encrypt file"
    , Option "d" ["decrypt"]
        (NoArg
            (\opt -> return opt { optCommand = "decrypt" }))
        "Decrypt file (default)"
    , Option "g" ["generate"]
        (NoArg
            (\opt -> return opt { optCommand = "generate" }))
        "Generate a one-time pad"
    , Option "i" ["input"]
        (ReqArg
            (\arg opt -> return opt { optInput = TI.readFile arg })
            "FILE")
        "Input file (for decryption and encryption)"
    , Option "o" ["output"]
        (ReqArg
            (\arg opt -> return opt { optOutput = TI.writeFile arg })
            "FILE")
        "Output file (for generation, decryption, and encryption)"
    , Option "p" ["pad"]
        (ReqArg
            (\arg opt -> return opt { optPad = (TI.readFile arg,
                                                TI.writeFile arg) })
            "FILE")
        "One-time pad to use (for decryption and encryption)"
    , Option "l" ["lines"]
        (ReqArg
            (\arg opt -> return opt { optLines = read arg :: Int })
            "LINES")
        "New one-time pad's length (in lines of 48 characters) (for generation)"
    , Option "V" ["version"]
        (NoArg
            (\_ -> do
                hPutStrLn stderr "Version 0.01"
                exitWith ExitSuccess))
        "Print version"
    , Option "h" ["help"]
        (NoArg
            (\_ -> do
                prg <- getProgName
                putStrLn "usage: OneTimePad [-h] [-V] [--lines LINES] [-i FILE] [-o FILE] [-p FILE] [--encrypt | --decrypt | --generate]"
                hPutStrLn stderr (usageInfo prg options)
                exitWith ExitSuccess))
        "Show this help message and exit"
    ]

main :: IO ()
main = do
  args <- getArgs
  let (actions, nonOptions, errors) = getOpt RequireOrder options args
  opts <- Prelude.foldl (>>=) (return startOptions) actions
  let Options { optCommand = command
              , optInput   = input
              , optOutput  = output
              , optPad     = (inPad, outPad)
              , optLines   = linecnt } = opts

  case command of
    "generate" -> generate linecnt output
    "encrypt"  -> do
      inputContents <- clean <$> input
      padContents <- inPad
      output $ format $ encrypt inputContents $ unformat $ T.concat
        $ dropWhile (\t -> T.head t == '-' || T.head t == '#')
        $ T.lines padContents
    "decrypt"  -> do
      inputContents <- unformat <$> input
      padContents <- inPad
      output $ decrypt inputContents $ unformat $ T.concat
        $ dropWhile (\t -> T.head t == '-' || T.head t == '#')
        $ T.lines padContents
      let discardLines = ceiling
            $ ((/) `on` fromIntegral) (T.length inputContents) 48
      outPad $ discard discardLines $ T.lines padContents

{- | Discard used pad lines. Is only called at decryption to enable using the
same pad file for both encryption and decryption.
-}
discard :: Int -> [T.Text] -> T.Text
discard 0 ts = T.unlines ts
discard x (t:ts) = if (T.head t == '-' || T.head t == '#')
  then T.unlines [t, (discard x ts)]
  else T.unlines [(T.append (T.pack "- ") t), (discard (x-1) ts)]

{- | Clean the text from symbols that cannot be encrypted.
-}
clean :: T.Text -> T.Text
clean = T.map toUpper . T.filter (\c -> let oc = ord c
                                   in oc >= 65 && oc <= 122
                                   && (not $ oc >=91 && oc <= 96))

{- | Format text (usually encrypted text) for pretty-printing it in a similar
way to the example from Wikipedia (see Rosetta Code page for this task)
-}
format :: T.Text -> T.Text
format = T.unlines . map (T.intercalate (T.pack " ") . T.chunksOf 6)
  . T.chunksOf 48

{- | Unformat encrypted text, getting rid of characters that are irrelevant for
decryption.
-}
unformat :: T.Text -> T.Text
unformat = T.filter (\c -> c/='\n' && c/=' ')

{- | Generate a one-time pad and write it to file (specified as second
parameter). Note: this only works on operating systems that have the
"/dev/random" file.
-}
generate :: Int -> (T.Text -> IO ()) -> IO ()
generate lines output = do
  withBinaryFile "/dev/random" ReadMode
    (\handle -> do
        contents <- replicateM (48 * lines) $ hGetChar handle
        time <- getCurrentTime
        output
          $ T.unlines [ T.pack
                        $ "# OTP pad, generated by https://github.com/kssytsrk/one-time-pad on "
                        ++ show time
                      , format $ T.pack
                        $ map (chr . (65 +) . flip mod 26 . ord) contents
                      ])

-- Helper function for encryption/decryption.
crypt :: (Int -> Int -> Int) -> T.Text -> T.Text -> T.Text
crypt f = T.zipWith ((chr .) . f `on` ord)

-- Encrypt first parameter's contents, using the second parameter as a key.
encrypt :: T.Text -> T.Text -> T.Text
encrypt = crypt ((((+65) . flip mod 26 . subtract 130) .) . (+))

-- Decrypt first parameter's contents, using the second parameter as a key.
decrypt :: T.Text -> T.Text -> T.Text
decrypt = crypt ((((+65) . flip mod 26) .) . (-))


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class OneTimePad {

    public static void main(String[] args) {
        String controlName = "AtomicBlonde";
        generatePad(controlName, 5, 60, 65, 90);
        String text = "IT WAS THE BEST OF TIMES IT WAS THE WORST OF TIMES";
        String encrypted = parse(true, controlName, text.replaceAll(" ", ""));
        String decrypted = parse(false, controlName, encrypted);
        System.out.println("Input  text    = " + text);
        System.out.println("Encrypted text = " + encrypted);
        System.out.println("Decrypted text = " + decrypted);

        controlName = "AtomicBlondeCaseSensitive";
        generatePad(controlName, 5, 60, 32, 126);
        text = "It was the best of times, it was the worst of times.";
        encrypted = parse(true, controlName, text);
        decrypted = parse(false, controlName, encrypted);
        System.out.println();
        System.out.println("Input text     = " + text);
        System.out.println("Encrypted text = " + encrypted);
        System.out.println("Decrypted text = " + decrypted);
    }

    private static String parse(boolean encryptText, String controlName, String text) {
        StringBuilder sb = new StringBuilder();
        int minCh = 0;
        int maxCh = 0;
        Pattern minChPattern = Pattern.compile("^#  MIN_CH = ([\\d]+)$");
        Pattern maxChPattern = Pattern.compile("^#  MAX_CH = ([\\d]+)$");
        boolean validated = false;
        try (BufferedReader in = new BufferedReader(new FileReader(getFileName(controlName))); ) {
            String inLine = null;
            while ( (inLine = in.readLine()) != null ) {
                Matcher minMatcher = minChPattern.matcher(inLine);
                if ( minMatcher.matches() ) {
                    minCh = Integer.parseInt(minMatcher.group(1));
                    continue;
                }
                Matcher maxMatcher = maxChPattern.matcher(inLine);
                if ( maxMatcher.matches() ) {
                    maxCh = Integer.parseInt(maxMatcher.group(1));
                    continue;
                }
                if ( ! validated && minCh > 0 && maxCh > 0 ) {
                    validateText(text, minCh, maxCh);
                    validated = true;
                }
                //  # is comment.  - is used key.
                if ( inLine.startsWith("#") || inLine.startsWith("-") ) {
                    continue;
                }
                //  Have encryption key.
                String key = inLine;
                if ( encryptText ) {
                    for ( int i = 0 ; i < text.length(); i++) {
                        sb.append((char) (((text.charAt(i) - minCh + key.charAt(i) - minCh) % (maxCh - minCh + 1)) + minCh));
                    }
                }
                else {
                    for ( int i = 0 ; i < text.length(); i++) {
                        int decrypt = text.charAt(i) - key.charAt(i);
                        if ( decrypt < 0 ) {
                            decrypt += maxCh - minCh + 1;
                        }
                        decrypt += minCh;
                        sb.append((char) decrypt);
                    }
                }
                break;
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return sb.toString();
    }

    private static void validateText(String text, int minCh, int maxCh) {
        //  Validate text is in range
        for ( char ch : text.toCharArray() ) {
            if ( ch != ' ' && (ch < minCh || ch > maxCh) ) {
                throw new IllegalArgumentException("ERROR 103:  Invalid text.");
            }
        }

    }

    private static String getFileName(String controlName) {
        return controlName + ".1tp";
    }

    private static void generatePad(String controlName, int keys, int keyLength, int minCh, int maxCh) {
        Random random = new Random();
        try ( BufferedWriter writer = new BufferedWriter(new FileWriter(getFileName(controlName), false)); ) {
            writer.write("#  Lines starting with '#' are ignored.");
            writer.newLine();
            writer.write("#  Lines starting with '-' are previously used.");
            writer.newLine();
            writer.write("#  MIN_CH = " + minCh);
            writer.newLine();
            writer.write("#  MAX_CH = " + maxCh);
            writer.newLine();
            for ( int line = 0 ; line < keys ; line++ ) {
                StringBuilder sb = new StringBuilder();
                for ( int ch = 0 ; ch < keyLength ; ch++ ) {
                    sb.append((char) (random.nextInt(maxCh - minCh + 1) + minCh));
                }
                writer.write(sb.toString());
                writer.newLine();
            }
            writer.write("#  EOF");
            writer.newLine();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}


// version 1.2.31

import java.io.File
import java.security.SecureRandom

const val CHARS_PER_LINE = 48
const val CHUNK_SIZE = 6
const val COLS = 8
const val DEMO = true  // would normally be set to false

enum class FileType { OTP, ENC, DEC }

fun Char.isAlpha() = this in 'A'..'Z'

fun String.toAlpha() = this.filter { it.isAlpha() }

fun String.isOtpRelated() = endsWith(".1tp") || endsWith(".1tp_cpy") ||
                            endsWith(".1tp_enc") || endsWith(".1tp_dec")

fun makePad(nLines: Int): String {
    val nChars = nLines * CHARS_PER_LINE
    val sr = SecureRandom()
    val sb = StringBuilder(nChars)
    /* generate random upper case letters */
    for (i in 0 until nChars) sb.append((sr.nextInt(26) + 65).toChar())
    return sb.toString().inChunks(nLines, FileType.OTP)
}

fun vigenere(text: String, key: String, encrypt: Boolean = true): String {
    val sb = StringBuilder(text.length)
    for ((i, c) in text.withIndex()) {
        val ci = if (encrypt)
            (c.toInt() + key[i].toInt() - 130) % 26
        else
            (c.toInt() - key[i].toInt() +  26) % 26
        sb.append((ci + 65).toChar())
    }
    val temp = sb.length % CHARS_PER_LINE
    if (temp > 0) {  // pad with random characters so each line is a full one
        val sr = SecureRandom()
        for (i in temp until CHARS_PER_LINE) sb.append((sr.nextInt(26) + 65).toChar())
    }
    val ft = if (encrypt) FileType.ENC else FileType.DEC
    return sb.toString().inChunks(sb.length / CHARS_PER_LINE, ft)
}

fun String.inChunks(nLines: Int, ft: FileType): String {
    val chunks = this.chunked(CHUNK_SIZE)
    val sb = StringBuilder(this.length + nLines * (COLS + 1))
    for (i in 0 until nLines) {
        val j = i * COLS
        sb.append(" ${chunks.subList(j, j + COLS).joinToString(" ")}\n")
    }
    val s = " file\n" + sb.toString()
    return when (ft) {
        FileType.OTP -> "# OTP" + s
        FileType.ENC -> "# Encrypted" + s
        FileType.DEC -> "# Decrypted" + s
    }
}

fun menu(): Int {
    println("""
        |
        |1. Create one time pad file.
        |
        |2. Delete one time pad file.
        |
        |3. List one time pad files.
        |
        |4. Encrypt plain text.
        |
        |5. Decrypt cipher text.
        |
        |6. Quit program.
        |
        """.trimMargin())
    var choice: Int?
    do {
        print("Your choice (1 to 6) : ")
        choice = readLine()!!.toIntOrNull()
    }
    while (choice == null || choice !in 1..6)
    return choice
}

fun main(args: Array<String>) {
    mainLoop@ while (true) {
        val choice = menu()
        println()
        when (choice) {
            1 -> {  // Create OTP
                println("Note that encrypted lines always contain 48 characters.\n")
                print("OTP file name to create (without extension) : ")
                val fileName = readLine()!! + ".1tp"
                var nLines: Int?

                do {
                    print("Number of lines in OTP (max 1000) : ")
                    nLines = readLine()!!.toIntOrNull()
                }
                while (nLines == null || nLines !in 1..1000)

                val key = makePad(nLines)
                File(fileName).writeText(key)
                println("\n'$fileName' has been created in the current directory.")
                if (DEMO) {
                    // a copy of the OTP file would normally be on a different machine
                    val fileName2 = fileName + "_cpy"  // copy for decryption
                    File(fileName2).writeText(key)
                    println("'$fileName2' has been created in the current directory.")
                    println("\nThe contents of these files are :\n")
                    println(key)
                }
            }

            2 -> {  // Delete OTP
                println("Note that this will also delete ALL associated files.\n")
                print("OTP file name to delete (without extension) : ")
                val toDelete1 = readLine()!! + ".1tp"
                val toDelete2 = toDelete1 + "_cpy"
                val toDelete3 = toDelete1 + "_enc"
                val toDelete4 = toDelete1 + "_dec"
                val allToDelete = listOf(toDelete1, toDelete2, toDelete3, toDelete4)
                var deleted = 0
                println()
                for (name in allToDelete) {
                    val f = File(name)
                    if (f.exists()) {
                        f.delete()
                        deleted++
                        println("'$name' has been deleted from the current directory.")
                    }
                }
                if (deleted == 0) println("There are no files to delete.")
            }

            3 -> {  // List OTPs
                println("The OTP (and related) files in the current directory are:\n")
                val otpFiles = File(".").listFiles().filter {
                    it.isFile() && it.name.isOtpRelated()
                }.map { it.name }.toMutableList()
                otpFiles.sort()
                println(otpFiles.joinToString("\n"))
            }

            4 -> {  // Encrypt
                print("OTP file name to use (without extension) : ")
                val keyFile = readLine()!! + ".1tp"
                val kf = File(keyFile)
                if (kf.exists()) {
                    val lines = File(keyFile).readLines().toMutableList()
                    var first = lines.size
                    for (i in 0 until lines.size) {
                        if (lines[i].startsWith(" ")) {
                            first = i
                            break
                        }
                    }
                    if (first == lines.size) {
                        println("\nThat file has no unused lines.")
                        continue@mainLoop
                    }
                    val lines2 = lines.drop(first)  // get rid of comments and used lines

                    println("Text to encrypt :-\n")
                    val text = readLine()!!.toUpperCase().toAlpha()
                    val len = text.length
                    var nLines = len / CHARS_PER_LINE
                    if (len % CHARS_PER_LINE > 0) nLines++

                    if (lines2.size >= nLines) {
                        val key = lines2.take(nLines).joinToString("").toAlpha()
                        val encrypted = vigenere(text, key)
                        val encFile = keyFile + "_enc"
                        File(encFile).writeText(encrypted)
                        println("\n'$encFile' has been created in the current directory.")
                        for (i in first until first + nLines) {
                            lines[i] = "-" + lines[i].drop(1)
                        }
                        File(keyFile).writeText(lines.joinToString("\n"))
                        if (DEMO) {
                            println("\nThe contents of the encrypted file are :\n")
                            println(encrypted)
                        }
                    }
                    else println("Not enough lines left in that file to do encryption")
                }
                else println("\nThat file does not exist.")
            }

            5 -> {  // Decrypt
                print("OTP file name to use (without extension) : ")
                val keyFile = readLine()!! + ".1tp_cpy"
                val kf = File(keyFile)
                if (kf.exists()) {
                    val keyLines = File(keyFile).readLines().toMutableList()
                    var first = keyLines.size
                    for (i in 0 until keyLines.size) {
                        if (keyLines[i].startsWith(" ")) {
                            first = i
                            break
                        }
                    }
                    if (first == keyLines.size) {
                        println("\nThat file has no unused lines.")
                        continue@mainLoop
                    }
                    val keyLines2 = keyLines.drop(first)  // get rid of comments and used lines

                    val encFile = keyFile.dropLast(3) + "enc"
                    val ef = File(encFile)
                    if (ef.exists()) {
                        val encLines = File(encFile).readLines().drop(1)  // exclude comment line
                        val nLines = encLines.size
                        if (keyLines2.size >= nLines) {
                            val encrypted = encLines.joinToString("").toAlpha()
                            val key = keyLines2.take(nLines).joinToString("").toAlpha()
                            val decrypted = vigenere(encrypted, key, false)
                            val decFile = keyFile.dropLast(3) + "dec"
                            File(decFile).writeText(decrypted)
                            println("\n'$decFile' has been created in the current directory.")
                            for (i in first until first + nLines) {
                                keyLines[i] = "-" + keyLines[i].drop(1)
                            }
                            File(keyFile).writeText(keyLines.joinToString("\n"))
                            if (DEMO) {
                                println("\nThe contents of the decrypted file are :\n")
                                println(decrypted)
                            }
                        }
                        else println("Not enough lines left in that file to do decryption")
                    }
                    else println("\n'$encFile' is missing.")
                }
                else println("\nThat file does not exist.")
            }

            else -> return  // Quit
        }
    }
}


import os, re, sequtils, strformat, strutils
import nimcrypto

# One-time pad file signature.
const Magic = "#one-time pad"

# Suffix for pad files.
const Suffix = ".1tp"

proc log(msg: string) =
  ## Log a message.
  stderr.write msg
  stderr.write '\n'

proc makeKeys(n, size: Positive): seq[string] =
  ## Generate "n" secure, random keys of "size" bytes.

  # We're generating and storing keys in their hexadecimal form to make
  # one-time pad files a little more human readable and to ensure a key
  # can not start with a hyphen.
  var bytes = newSeq[byte](size)
  for _ in 1..n:
    if randomBytes(bytes) != size:
      raise newException(ValueError, "unable to build keys.")
    result.add bytes.mapIt(it.toHex).join()

proc makePad(name: string; padSize, keySize: Positive): string =
  ## Create a new one-time pad identified by the given name.
  ## Args:
  ##     name: unique one-time pad identifier.
  ##     padSize: the number of keys (or pages) in the pad.
  ##     keySize: the number of bytes per key.
  ## Returns:
  ##     the new one-time pad as a string.

  let pad = @[Magic, &"#name={name}", &"#size={padSize}"] & makeKeys(padSize, keySize)
  result = pad.join("\n")

proc `xor`(message, key: string): string =
  ## Return "message" XOR-ed with "key".
  ##
  ## Args:
  ##     message: plaintext or cyphertext to be encrypted or decrypted.
  ##     key: encryption and decryption key.
  ## Returns:
  ##     plaintext or cyphertext as a string.

  if key.len < message.len:
    quit("Key size is too short to encrypt/decrypt the message.", QuitFailure)
  result = newStringOfCap(message.len)
  var keyIndex = 0
  for msgChar in message:
    result.add chr(ord(msgChar) xor ord(key[keyIndex]))
    inc keyIndex

proc useKey(pad: var string): string =
  ## Use the next available key from the given one-time pad.
  ##
  ## Args:
  ##     pad: a one-time pad, updated.
  ## Returns:
  ##     the key.

  var matches: array[1, string]
  let pos = pad.find(re"(?m)(^[A-F0-9]+$)", matches)
  if pos < 0:
    quit("Pad is all used up.", QuitFailure)

  pad.insert("-", pos)
  result = matches[0]

proc writePad(path: string; padSize, keySize: Positive) =
  ## Write a new one-time pad to the given path.
  ##
  ## Args:
  ##     path: path to write one-time pad to.
  ##     padSize: the number of keys (or pages) in the pad.
  ##     keySize: the number of bytes per key.

  if fileExists(path):
    quit("Pad " & path & " already exists", QuitFailure)
  try:
    path.writeFile(makePad(path.extractFilename(), padSize, keySize))
  except IOError:
    quit("Unable to write file " & path, QuitFailure)
  log("New one-time pad written to " & path)

proc process(pad, message: string; outfile: File) =
  ## Encrypt or decrypt "message" using the given pad.
  ##
  ## Args:
  ##     pad: path to one-time pad.
  ##     message: plaintext or ciphertext message to encrypt or decrypt.
  ##     outfile: file-like object to write to.

  if not fileExists(pad):
    quit("No such pad: " & pad, QuitFailure)
  let start = pad.readLines(1)
  if start.len == 0 or start[0] != Magic:
    quit(&"file '{pad}' does not look like a one-time pad", QuitFailure)

  # Rewrites the entire one-time pad every time
  var padData = pad.readFile()
  let key = padData.useKey().parseHexStr()
  pad.writeFile(padData)

  outfile.write(message xor key)

when isMainModule:

  import parseopt

  proc printUsage() =
    echo "Usage: ", getAppFilename().lastPathPart,
         " [-h] [--length LENGTH] [--key-size KEY_SIZE] [-o OUTFILE]"
    echo "                    [--encrypt FILE | --decrypt FILE] pad"
    echo ""
    echo """One-time pad.

positional arguments:
  pad                   Path to one-time pad. If neither --encrypt or --decrypt
                        are given, will create a new pad.

optional arguments:
  -h, --help            show this help message and exit
  --length LENGTH       Pad size. Ignored if --encrypt or --decrypt are given.
                        Defaults to 10.
  --key-size KEY_SIZE   Key size in bytes. Ignored if --encrypt or --decrypt
                        are given. Defaults to 64.
  --outfile OUTFILE     Write encoded/decoded message to a file. Ignored if
                        --encrypt or --decrypt is not given. Defaults to
                        stdout.
  --encrypt FILE        Encrypt FILE using the next available key from pad.
  --decrypt FILE        Decrypt FILE using the next available key from pad.
  """

  var
    parser = initOptParser(shortNoVal = {'h'}, longNoval = @["help"])
    padPath: string
    length = 10
    outpath = ""
    encryptPath = ""
    decryptPath = ""
    keySize = 64
    encrypt = false
    decrypt = false

  for kind, key, val in parser.getopt():
    case kind

    of cmdShortOption:
      printUsage()
      if key != "h":
        quit("Wrong option: " & key, QuitFailure)
      elif val.len != 0:
        quit("Wrong value for option -h", QuitFailure)
      else:
        quit(QuitSuccess)

    of cmdLongOption:
      case key

      of "help":
        printUsage()
        quit(QuitSuccess)

      of "length":
        try:
          length = parseInt(val)
          if length < 2: raise newException(ValueError, "")
        except ValueError:
          quit("Wrong length: " & val, QuitFailure)

      of "encrypt":
        encryptPath = val
        encrypt = true

      of "decrypt":
        decryptPath = val
        decrypt = true

      of "outfile":
        outPath = val

      of "key-size":
        try:
          keySize = parseInt(val)
          if length < 2: raise newException(ValueError, "")
        except ValueError:
          quit("Wrong key size: " & val, QuitFailure)

      else:
        quit("Invalid option: " & key, QuitFailure)

    of cmdArgument:
      padPath = if key.endsWith(Suffix): key else: key & Suffix

    of cmdEnd:
      discard   # Cannot not occur.

  if padPath.len == 0:
    quit("Missing pad file.", QuitFailure)

  if encrypt and decrypt:
    quit("Incompatible options: encrypt and decrypt", QuitFailure)

  if encrypt or decrypt:

    var outfile: File
    if outpath.len == 0:
      outfile = stdout
    else:
      try:
        outfile = outpath.open(fmWrite)
      except IOError:
        quit("Unable to open output file.", QuitFailure)

    let message = try:
                    if encrypt: encryptPath.readFile()
                    else: decryptPath.readFile()
                  except IOError:
                    quit("Unable to open file to encrypt or decrypt.", QuitFailure)

    padPath.process(message, outfile)
    if outfile != stdout: outfile.close()

  else:
    padPath.writePad(length, keySize)


# 20200814 added Perl programming solution

use strict;
use warnings;

use Crypt::OTP;
use Bytes::Random::Secure qw( random_bytes );

print "Message     : ", my $message = "show me the monKey", "\n";

my $otp = random_bytes(length $message);
print "Ord(OTP)    : ", ( map { ord($_).' ' } (split //, $otp)   ) , "\n";

my $cipher = OTP( $otp, $message, 1 );
print "Ord(Cipher) : ", ( map { ord($_).' ' } (split //, $cipher) ) , "\n";

print "Decoded     : ",  OTP( $otp, $cipher, 1 ), "\n";


"""One-time pad using an XOR cipher. Requires Python >=3.6."""

import argparse
import itertools
import pathlib
import re
import secrets
import sys

# One-time pad file signature.
MAGIC = "#one-time pad"

def make_keys(n, size):
    """Generate ``n`` secure, random keys of ``size`` bytes."""
    # We're generating and storing keys in their hexadecimal form to make
    # one-time pad files a little more human readable and to ensure a key
    # can not start with a hyphen.
    return (secrets.token_hex(size) for _ in range(n))

def make_pad(name, pad_size, key_size):
    """Create a new one-time pad identified by the given name.

    Args:
        name (str): Unique one-time pad identifier.
        pad_size (int): The number of keys (or pages) in the pad.
        key_size (int): The number of bytes per key.
    Returns:
        The new one-time pad as a string.
    """
    pad = [
        MAGIC,
        f"#name={name}",
        f"#size={pad_size}",
        *make_keys(pad_size, key_size),
    ]

    return "\n".join(pad)

def xor(message, key):
    """Return ``message`` XOR-ed with ``key``.

    Args:
        message (bytes): Plaintext or cyphertext to be encrypted or decrypted.
        key (bytes): Encryption and decryption key.
    Returns:
        Plaintext or cyphertext as a byte string.
    """
    return bytes(mc ^ kc for mc, kc in zip(message, itertools.cycle(key)))

def use_key(pad):
    """Use the next available key from the given one-time pad.

    Args:
        pad (str): A one-time pad.
    Returns:
        (str, str) A two-tuple of updated pad and key.
    """
    match = re.search(r"^[a-f0-9]+$", pad, re.MULTILINE)
    if not match:
        error("pad is all used up")

    key = match.group()
    pos = match.start()

    return (f"{pad[:pos]}-{pad[pos:]}", key)

def log(msg):
    """Log a message."""
    sys.stderr.write(msg)
    sys.stderr.write("\n")

def error(msg):
    """Exit with an error message."""
    sys.stderr.write(msg)
    sys.stderr.write("\n")
    sys.exit(1)

def write_pad(path, pad_size, key_size):
    """Write a new one-time pad to the given path.

    Args:
        path (pathlib.Path): Path to write one-time pad to.
        length (int): Number of keys in the pad.
    """
    if path.exists():
        error(f"pad '{path}' already exists")

    with path.open("w") as fd:
        fd.write(make_pad(path.name, pad_size, key_size))

    log(f"New one-time pad written to {path}")

def main(pad, message, outfile):
    """Encrypt or decrypt ``message`` using the given pad.

    Args:
        pad (pathlib.Path): Path to one-time pad.
        message (bytes): Plaintext or ciphertext message to encrypt or decrypt.
        outfile: File-like object to write to.
    """
    if not pad.exists():
        error(f"no such pad '{pad}'")

    with pad.open("r") as fd:
        if fd.readline().strip() != MAGIC:
            error(f"file '{pad}' does not look like a one-time pad")

    # Rewrites the entire one-time pad every time
    with pad.open("r+") as fd:
        updated, key = use_key(fd.read())

        fd.seek(0)
        fd.write(updated)

    outfile.write(xor(message, bytes.fromhex(key)))

if __name__ == "__main__":
    # Command line interface
    parser = argparse.ArgumentParser(description="One-time pad.")

    parser.add_argument(
        "pad",
        help=(
            "Path to one-time pad. If neither --encrypt or --decrypt "
            "are given, will create a new pad."
        ),
    )

    parser.add_argument(
        "--length",
        type=int,
        default=10,
        help="Pad size. Ignored if --encrypt or --decrypt are given. Defaults to 10.",
    )

    parser.add_argument(
        "--key-size",
        type=int,
        default=64,
        help="Key size in bytes. Ignored if --encrypt or --decrypt are given. Defaults to 64.",
    )

    parser.add_argument(
        "-o",
        "--outfile",
        type=argparse.FileType("wb"),
        default=sys.stdout.buffer,
        help=(
            "Write encoded/decoded message to a file. Ignored if --encrypt or "
            "--decrypt is not given. Defaults to stdout."
        ),
    )

    group = parser.add_mutually_exclusive_group()

    group.add_argument(
        "--encrypt",
        metavar="FILE",
        type=argparse.FileType("rb"),
        help="Encrypt FILE using the next available key from pad.",
    )
    group.add_argument(
        "--decrypt",
        metavar="FILE",
        type=argparse.FileType("rb"),
        help="Decrypt FILE using the next available key from pad.",
    )

    args = parser.parse_args()

    if args.encrypt:
        message = args.encrypt.read()
    elif args.decrypt:
        message = args.decrypt.read()
    else:
        message = None

    # Sometimes necessary if message came from stdin
    if isinstance(message, str):
        message = message.encode()

    pad = pathlib.Path(args.pad).with_suffix(".1tp")

    if message:
        main(pad, message, args.outfile)
    else:
        write_pad(pad, args.length, args.key_size)


sub MAIN {
    put "Generate data for one time pad encryption.\n" ~
        "File will have .1tp extension.";
    my $fn;
    loop {
        $fn = prompt 'Filename for one time pad data: ';
        if $fn !~~ /'.1tp' $/ { $fn ~= '.1tp' }
        if $fn.IO.e {
            my $ow = prompt "$fn aready exists, over-write? y/[n] ";
            last if $ow ~~ m:i/'y'/;
            redo;
        }
        last;
    }

    put 'Each line will contain 48 characters of encyption data.';
    my $lines = prompt 'How many lines of data to generate? [1000] ';
    $lines ||= 1000;
    generate($fn, $lines);
    say "One-time-pad data saved to: ", $fn.IO.absolute;

    sub generate ( $fn, $lines) {
        use Crypt::Random;
        $fn.IO.spurt: "# one-time-pad encryption data\n" ~
          ((sprintf(" %s %s %s %s %s %s %s %s\n",
          ((('A'..'Z')[crypt_random_uniform(26)] xx 6).join) xx 8))
          xx $lines).join;
    }
}


puts "# True random chars for one-time pad"

proc randInt { min max } {
    set randDev [open /dev/urandom rb]
    set random [read $randDev 8]
    binary scan $random H16 random
    set random [expr {([scan $random %x] % (($max-$min) + 1) + $min)}]
    close $randDev
    return $random
}

proc randStr { sLen grp alfa } {
  set aLen [string length $alfa]; incr aLen -1
  set rs ""
  for {set i 0} {$i < $sLen} {incr i} {
    if { [expr {$i % $grp} ] == 0} { append rs " " }
    set r [randInt 0 $aLen]
    set char [string index $alfa $r]
    append rs $char
  ##puts "$i: $r $char"
  }
  return $rs
}

set alfa "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set len 48
set lines 4
set fn "test.1tp"

# Write file:
set fh [open $fn w]
puts $fh "# OTP"
for {set ln 0} {$ln < $lines} {incr ln} {
    set line [randStr $len 6 $alfa]
  ##puts "$ln :$line."
    puts $fh $line
}
close $fh

# Read file:
puts "# File $fn:"
set fh [open $fn]
puts [read $fh [file size $fn]]
close $fh

puts "# Done."


import "io" for File, Directory
import "/srandom" for SRandom
import "/ioutil" for FileUtil, Input
import "/dynamic" for Enum
import "/str" for Char, Str

var CHARS_PER_LINE = 48
var CHUNK_SIZE = 6
var COLS = 8
var DEMO = true  // would normally be set to false

var FileType = Enum.create("FileType", ["OTP", "ENC", "DEC"])

var toAlpha = Fn.new { |s| s.where { |c| Char.isAsciiUpper(c) }.join() }

var isOtpRelated = Fn.new { |s|
    return s.endsWith(".1tp") || s.endsWith(".1tp_cpy") ||
           s.endsWith(".1tp_enc") || s.endsWith(".1tp_dec")
}

var inChunks = Fn.new { |s, nLines, ft|
    var chunks = Str.chunks(s, CHUNK_SIZE)
    var sb = ""
    for (i in 0...nLines) {
        var j = i * COLS
        var ch = chunks[j...j+COLS].join(" ")
        sb = sb + " " + ch + "\n"
    }
    sb = " file\n" + sb
    return (ft == FileType.OTP) ? "# OTP" + sb :
           (ft == FileType.ENC) ? "# Encrypted" + sb :
           (ft == FileType.DEC) ? "# Decrypted" + sb : ""
}

var makePad = Fn.new { |nLines|
    var nChars = nLines * CHARS_PER_LINE
    var sb = ""
    /* generate random upper case letters */
    for (i in 0...nChars) sb = sb + String.fromByte(SRandom.int(65, 91))
    return inChunks.call(sb, nLines, FileType.OTP)
}

var vigenere = Fn.new { |text, key, encrypt|
    var sb = ""
    var i = 0
    for (c in text) {
        var ci = encrypt ? (c.bytes[0] + key[i].bytes[0] - 130) % 26 :
                           (c.bytes[0] - key[i].bytes[0] +  26) % 26
        sb = sb + String.fromByte(ci + 65)
        i = i + 1
    }
    var temp = sb.count % CHARS_PER_LINE
    if (temp > 0) {  // pad with random characters so each line is a full one
        for (i in temp...CHARS_PER_LINE) sb = sb + String.fromByte(SRandom.int(65, 91))
    }
    var ft = encrypt ? FileType.ENC : FileType.DEC
    return inChunks.call(sb, (sb.count / CHARS_PER_LINE).floor, ft)
}

var menu = Fn.new {
    System.print("""

1. Create one time pad file.

2. Delete one time pad file.

3. List one time pad files.

4. Encrypt plain text.

5. Decrypt cipher text.

6. Quit program.

""")
    return Input.integer("Your choice (1 to 6) : ", 1, 6)
}

while (true) {
    var choice = menu.call()
    System.print()
    if (choice == 1) {  // Create OTP
        System.print("Note that encrypted lines always contain 48 characters.\n")
        var fileName = Input.text("OTP file name to create (without extension) : ", 1) + ".1tp"
        var nLines = Input.integer("Number of lines in OTP (max 1000) : ", 1, 1000)
        var key = makePad.call(nLines)
        File.create(fileName) { |f| f.writeBytes(key) }
        System.print("\n'%(fileName)' has been created in the current directory.")
        if (DEMO) {
            // a copy of the OTP file would normally be on a different machine
            var fileName2 = fileName + "_cpy"  // copy for decryption
            File.create(fileName2) { |f| f.writeBytes(key) }
            System.print("'%(fileName2)' has been created in the current directory.")
            System.print("\nThe contents of these files are :\n")
            System.print(key)
        }
    } else if (choice == 2) {  // Delete OTP
        System.print("Note that this will also delete ALL associated files.\n")
        var toDelete1 = Input.text("OTP file name to delete (without extension) : ", 1) + ".1tp"
        var toDelete2 = toDelete1 + "_cpy"
        var toDelete3 = toDelete1 + "_enc"
        var toDelete4 = toDelete1 + "_dec"
        var allToDelete = [toDelete1, toDelete2, toDelete3, toDelete4]
        var deleted = 0
        System.print()
        for (name in allToDelete) {
            if (File.exists(name)) {
                File.delete(name)
                deleted = deleted + 1
                System.print("'%(name)' has been deleted from the current directory.")
            }
        }
        if (deleted == 0) System.print("There are no files to delete.")
    } else if (choice == 3) {  // List OTPs
        System.print("The OTP (and related) files in the current directory are:\n")
        var otpFiles = Directory.list("./").where { |f| File.exists(f) && isOtpRelated.call(f) }.toList
        System.print(otpFiles.join("\n")) // already sorted
    } else if (choice == 4) {  // Encrypt
        var keyFile = Input.text("OTP file name to use (without extension) : ", 1) + ".1tp"
        if (File.exists(keyFile)) {
            var lines = FileUtil.readLines(keyFile)
            var first = lines.count
            for (i in 0...lines.count) {
                if (lines[i].startsWith(" ")) {
                    first = i
                    break
                }
            }
            if (first == lines.count) {
                System.print("\nThat file has no unused lines.")
                continue
            }
            var lines2 = lines.skip(first).toList  // get rid of comments and used lines
            var text = toAlpha.call(Str.upper(Input.text("Text to encrypt :-\n\n", 1)))
            var len = text.count
            var nLines = (len / CHARS_PER_LINE).floor
            if (len % CHARS_PER_LINE > 0) nLines = nLines + 1
            if (lines2.count >= nLines) {
                var key = toAlpha.call(lines2.take(nLines).join(""))
                var encrypted = vigenere.call(text, key, true)
                var encFile = keyFile + "_enc"
                File.create(encFile) { |f| f.writeBytes(encrypted) }
                System.print("\n'%(encFile)' has been created in the current directory.")
                for (i in first...first + nLines) {
                    lines[i] = "-" + lines[i][1..-1]
                }
                File.create(keyFile) { |f| f.writeBytes(lines.join("\n")) }
                if (DEMO) {
                    System.print("\nThe contents of the encrypted file are :\n")
                    System.print(encrypted)
                }
            } else System.print("Not enough lines left in that file to do encryption")
        } else System.print("\nhat file does not exist.")
    } else if (choice == 5) {  // Decrypt
        var keyFile = Input.text("OTP file name to use (without extension) : ", 1) + ".1tp_cpy"
        if (File.exists(keyFile)) {
            var keyLines = FileUtil.readLines(keyFile)
            var first = keyLines.count
            for (i in 0...keyLines.count) {
                if (keyLines[i].startsWith(" ")) {
                    first = i
                    break
                }
            }
            if (first == keyLines.count) {
                System.print("\nThat file has no unused lines.")
                continue
            }
            var keyLines2 = keyLines[first..-1]  // get rid of comments and used lines
            var encFile = keyFile[0..-4] + "enc"
            if (File.exists(encFile)) {
                var encLines = FileUtil.readLines(encFile)[1..-1]  // exclude comment line
                var nLines = encLines.count
                if (keyLines2.count >= nLines) {
                    var encrypted = toAlpha.call(encLines.join(""))
                    var key = toAlpha.call(keyLines2.take(nLines).join(""))
                    var decrypted = vigenere.call(encrypted, key, false)
                    var decFile = keyFile[0..-4] + "dec"
                    File.create(decFile) { |f| f.writeBytes(decrypted) }
                    System.print("\n'%(decFile)' has been created in the current directory.")
                    for (i in first...first + nLines) {
                        keyLines[i] = "-" + keyLines[i][1..-1]
                    }
                    File.create(keyFile) { |f| f.writeBytes(keyLines.join("\n")) }
                    if (DEMO) {
                        System.print("\nThe contents of the decrypted file are :\n")
                        System.print(decrypted)
                    }
                } else System.print("Not enough lines left in that file to do decryption")
            } else System.print("\n'%(encFile)' is missing.")
        } else System.print("\nThat file does not exist.")
    } else {
        return  // Quit
    }
}