open System
open System.Text.RegularExpressions

// A little utility to thread a negative test result (Option.None) through a
// pipeline of tests
let inline (|~>) valOption proc =
    match valOption with
    | Some(value) -> proc value
    | None -> None

[<EntryPoint>]
let main argv =
    let iban = if argv.Length = 0 then "" else argv.[0]
    iban
    |> (fun iban ->     // Check for illegal characters
            if Regex.IsMatch(iban, @"[^0-9A-Za-z ]") then None else Some(iban.ToUpper().Replace(" ", "")))
    |~> (fun iban ->    // Check length per country code
            let lengthPerCountry =
                dict [
                    ("AL", 28); ("AD", 24); ("AT", 20); ("AZ", 28); ("BE", 16); ("BH", 22); ("BA", 20); ("BR", 29);
                    ("BG", 22); ("CR", 21); ("HR", 21); ("CY", 28); ("CZ", 24); ("DK", 18); ("DO", 28); ("EE", 20);
                    ("FO", 18); ("FI", 18); ("FR", 27); ("GE", 22); ("DE", 22); ("GI", 23); ("GR", 27); ("GL", 18);
                    ("GT", 28); ("HU", 28); ("IS", 26); ("IE", 22); ("IL", 23); ("IT", 27); ("KZ", 20); ("KW", 30);
                    ("LV", 21); ("LB", 28); ("LI", 21); ("LT", 20); ("LU", 20); ("MK", 19); ("MT", 31); ("MR", 27);
                    ("MU", 30); ("MC", 27); ("MD", 24); ("ME", 22); ("NL", 18); ("NO", 15); ("PK", 24); ("PS", 29);
                    ("PL", 28); ("PT", 25); ("RO", 24); ("SM", 27); ("SA", 24); ("RS", 22); ("SK", 24); ("SI", 19);
                    ("ES", 24); ("SE", 24); ("CH", 21); ("TN", 24); ("TR", 26); ("AE", 23); ("GB", 22); ("VG", 24);
                ]
            let country = iban.Substring(0, Math.Min(2, iban.Length))
            match lengthPerCountry.TryGetValue(country) with
            | true, length ->   // country should have iban of this length
                if length = iban.Length then Some(iban) else None
            | _ -> None     // country not known
        )
    |~> (fun iban -> Some(iban.Substring(4) + iban.Substring(0,4)))
    |~> (fun iban ->
            let replaceBase36LetterWithBase10String (s : string) (c :char) = s.Replace(c.ToString(), ((int)c - (int)'A' + 10).ToString())
            Some(List.fold replaceBase36LetterWithBase10String iban [ 'A' .. 'Z' ]))
    |~> (fun iban ->    // iban mod 97
            // We could have used BigInteger, but with a loop by 7 char each
            // over the long digit string we get away with Int32 arithmetic
            // (as described in the Wikipedia article)
            let reduceOnce r n = Int32.Parse(r.ToString() + n) % 97
            let rest =
                Regex.Matches(iban.Substring(2), @"\d{1,7}") |> Seq.cast |> Seq.map (fun x -> x.ToString())
                |> Seq.fold reduceOnce (reduceOnce 0 (iban.Substring(0,2)))
            // an iban needs a rest of 1
            if rest = 1 then Some(1) else None
        )
    |> function | Some(_) -> "a valid IBAN" | None -> "an invalid IBAN"
    |> printfn "%s is %s" iban
    0


USING: assocs combinators.short-circuit formatting kernel math
math.parser regexp sequences sets qw unicode ;
IN: rosetta-code.iban

<PRIVATE

CONSTANT: countries H{
    { 15 qw{ NO } }
    { 16 qw{ BE } }
    { 18 qw{ DK FO FI GL NL } }
    { 19 qw{ MK SI } }
    { 20 qw{ AT BA EE KZ LT LU } }
    { 21 qw{ CR HR LV LI CH } }
    { 22 qw{ BH BG GE DE IE ME RS GB } }
    { 23 qw{ GI IL AE } }
    { 24 qw{ AD CZ MD PK RO SA SK ES SE TN VG } }
    { 25 qw{ PT } }
    { 26 qw{ IS TR } }
    { 27 qw{ FR GR IT MR MC SM } }
    { 28 qw{ AL AZ CY DO GT HU LB PL } }
    { 29 qw{ BR PS } }
    { 30 qw{ KW MU } }
    { 31 qw{ MT } }
}

: valid-chars? ( str -- ? ) R/ [A-Z0-9]+/ matches? ;

: valid-length? ( str -- ? )
    [ 2 head ] [ length ] bi countries at member? ;

: valid-checksum? ( str -- ? )
    4 cut swap append [ digit> number>string ] { } map-as
    concat string>number 97 mod 1 = ;

PRIVATE>

: valid-iban? ( str -- ? )
    " " without {
        [ valid-chars? ] [ valid-length? ] [ valid-checksum? ]
    } 1&& ;

: iban-demo ( -- )
    "GB82 WEST 1234 5698 7654 32"
    "GB82 TEST 1234 5698 7654 32"
    [
        dup valid-iban? "may be a valid" "is an invalid" ?
        "%s %s IBAN\n" printf
    ] [email protected] ;

MAIN: iban-demo


include lib/ulcase.4th                 \ for S>UPPER
include lib/triple.4th                 \ for UT/MOD
include lib/cstring.4th                \ for C/STRING
include lib/todbl.4th                  \ for S>DOUBLE

0 constant ud>t                        \ convert unsigned double to triple
88529281 constant 97^4                 \ first stage modulus
char A 10 - negate +constant c>u       \ convert character to IBAN digit

: bank>t u>d rot 3 - 0 ?do 10 mu* loop 1000000000 ut* ;
                                       \ convert country part to unsigned
: country>u                            ( a n -- u)
  c/string c>u 10000 * >r c/string c>u 100 * >r number 100 mod abs r> + r> +
;
                                       \ convert bank part to unsigned
: bank>u                               \ a n -- u)
  c/string c>u 1000000 * >r            \ get first digit and shift
  c/string c>u 10000 * >r              \ get second digit and shift
  c/string c>u 100 * >r                \ get third digit and shift
  drop [email protected] c>u r> + r> + r> +           \ combine all digits to number
;

: iban>t                               ( a n -- triple)
  s>upper                              \ convert to upper case and get country
  over 4 country>u >r 4 /string        \ get bank part, save length, convert
  over 4 bank>u >r 4 /string tuck s>double
  1000000 mu* r> -rot r> u>d d+ 2>r    \ now assemble everything except bank
  bank>t 2r> ud>t t+                   \ shift bank part and convert to triple
;
                                       ( a n -- f)
: iban? iban>t 97^4 ut/mod 2drop 97 mod 1 = ;
                                       \ perform modulus 97 in two stages
: checkiban                            ( --)
  ." Enter your IBAN: " refill drop 0 parse -trailing iban?
  if ." Valid" else ." Invalid" then cr
;

checkiban


' FB 1.05.0 Win64

' List updated to release 72, 25 November 2016, of IBAN Registry (75 countries)
Dim Shared countryCodes As String
countryCodes = _
    "AD24 AE23 AL28 AT20 AZ28 BA20 BE16 BG22 BH22 BR29 BY28 CH21 CR22 CY28 CZ24 DE22 " _
    "DK18 DO28 EE20 ES24 FI18 FO18 FR27 GB22 GE22 GI23 GL18 GR27 GT28 HR21 HU28 IE22 " _
    "IL23 IQ23 IS26 IT27 JO30 KW30 KZ20 LB28 LC32 LI21 LT20 LU20 LV21 MC27 MD24 ME22 " _
    "MK19 MR27 MT31 MU30 NL18 NO15 PK24 PL28 PS29 PT25 QA29 RO24 RS22 SA24 SC31 SE24 " _
    "SI19 SK24 SM27 ST25 SV28 TL23 TN24 TR26 UA29 VG24 XK20"

Function checkCountryCode(cc As String) As Boolean
  Return Instr(countryCodes, cc)
End Function

' To avoid having to use the GMP library, a piece-wise calculation is used
Function mod97(s As String) As UInteger
  Dim r As UInteger = ValULng(Left(s, 9)) Mod 97
  Dim start As UInteger = 10
  While start < Len(s)
    r = ValULng(r & Mid(s, start, 7)) Mod 97
    start += 7
  Wend
  Return r
End Function

Function validateIban(iban As Const String) As Boolean
  ' remove spaces from IBAN
  Dim s As String = iban
  Dim count As Integer = 0
  For i As Integer = 0 To Len(s) - 1
    If s[i] = 32 Then
      For j As Integer = i + 1 To Len(s) - 1
         s[j - 1] = s[j]
      Next
      count += 1
    End If
    If i = Len(s) - 1 - count Then Exit For
  Next i
  If count > 0 Then
    s[Len(s) - count] = 0
    Dim p As UInteger Ptr = CPtr(UInteger Ptr, @s)
    *(p + 1) = Len(s) - count ''change length of string in descriptor
  End If

  ' check country code
  Dim isValid As Boolean = checkCountryCode(Left(s, 2) + Str(Len(s)))
  If Not isValid Then Return False

  ' move first 4 characters to end
  s = Mid(s, 5) + Left(s, 4)

  ' replace A to Z with numbers 10 To 35
  For i As Integer = Len(s) To 1 Step -1
    If s[i - 1] >= 65 AndAlso s[i - 1] <= 90 Then
      s = Left(s, i - 1) + Str(s[i - 1] - 55) + Mid(s, i + 1)
    End If
  Next

  ' do mod97 calculation
  Return mod97(s) = 1  '' remainder needs to be 1 for validity
End Function

Dim As String ibans(1 To 2) = {"GB82 WEST 1234 5698 7654 32", "GB82 TEST 1234 5698 7654 32"}
For i As Integer = 1 To 2
  Dim isValid As Boolean = validateIban(ibans(i))
  Print ibans(i); IIf(isValid, " : may be valid", " : is not valid")
Next

Print
Print "Press any key to quit"
Sleep


{$mode objFPC}

uses
	// for delSpace function
	strUtils,
	// GNU multiple-precision library
	GMP;

var
	/// this trie contains the correct IBAN length depending on the country code
	IBANLengthInCountry: array['A'..'Z', 'A'..'Z'] of integer;

type
	/// Human-readable representation of an IBAN without spaces
	IBANRepresentation = string[34];

{
	determines whether an IBANRepresentation is technically potentially correct

	\param sample the human-readable IBAN representation
	\return \param sample constains less than the most detectable errors
}
function isLegal(sample: IBANRepresentation): Boolean;
	function checksumCorrect(sample: IBANRepresentation): Boolean;
		type
			digitSequence = string[68];
		function convertLetters(const sequence: IBANRepresentation): digitSequence;
		var
			i: integer;
			transliteration: string[2];
		begin
			// initialize length to zero
			result := '';

			for i := 1 to length(sequence) do
			begin
				// by default assume it is a Western-Arabic digit
				transliteration := sequence[i];

				// otherwise we’ll need to transliterate the Latin alphabet character
				if not (sequence[i] in ['0'..'9']) then
				begin
					writeStr(transliteration, ord(sequence[i]) - ord('A') + 10);
				end;

				// appending transliteration to result also changes the length field
				result := result + transliteration;
			end;
		end;
		var
			i, k: MPInteger;
		begin
			k := 97;

			// put first four characters toward end
			writeStr(sample, sample[5..length(sample)], sample[1..4]);
			// interpret converted string as integer to base 10
			Z_set_str(i, convertLetters(sample), 10);

			i := Z_mod(i, k);
			k := 1;
			checksumCorrect := Z_cmp(i, k) = 0;
		end;
	begin
		sample := upCase(sample);
		{$push}
			// just for emphasis: by default the FPC performs lazy evaluation
			{$boolEval off}
			isLegal := (length(sample) = IBANLengthInCountry[sample[1], sample[2]])
				and checksumCorrect(sample);
		{$pop}
	end;

// === MAIN ==============================================================
begin
	// for the sake of merely achieving the Rosetta Code Task
	IBANLengthInCountry['G', 'B'] := 22;

	// note, strings longer than 34 characters will be silently clipped
	writeLn(isLegal(delSpace('GB82 WEST 1234 5698 7654 32')));
end.


package main

import (
	"regexp"
	"strings"
	"testing"
)

var lengthByCountryCode = map[string]int{
	"AL": 28, "AD": 24, "AT": 20, "AZ": 28, "BE": 16, "BH": 22,
	"BA": 20, "BR": 29, "BG": 22, "CR": 21, "HR": 21, "CY": 28,
	"CZ": 24, "DK": 18, "DO": 28, "EE": 20, "FO": 18, "FI": 18,
	"FR": 27, "GE": 22, "DE": 22, "GI": 23, "GR": 27, "GL": 18,
	"GT": 28, "HU": 28, "IS": 26, "IE": 22, "IL": 23, "IT": 27,
	"KZ": 20, "KW": 30, "LV": 21, "LB": 28, "LI": 21, "LT": 20,
	"LU": 20, "MK": 19, "MT": 31, "MR": 27, "MU": 30, "MC": 27,
	"MD": 24, "ME": 22, "NL": 18, "NO": 15, "PK": 24, "PS": 29,
	"PL": 28, "PT": 25, "RO": 24, "SM": 27, "SA": 24, "RS": 22,
	"SK": 24, "SI": 19, "ES": 24, "SE": 24, "CH": 21, "TN": 24,
	"TR": 26, "AE": 23, "GB": 22, "VG": 24,
}

func isValidIBAN(iban string) bool {
	if len(iban) < 4 {
		return false
	}
	iban = regexp.MustCompile(`\s+`).ReplaceAllString(iban, "")
	iban = strings.ToUpper(iban)

	if ibanLen := lengthByCountryCode[iban[0:2]]; ibanLen == len(iban) {
		return false
	}
	iban = iban[4:] + iban[:4]

	result := 0
	for _, ch := range iban {
		var n int
		if '0' <= ch && ch <= '9' {
			n = int(ch) - '0'
		} else if 'A' <= ch && ch <= 'Z' {
			n = 10 + int(ch) - 'A'
		} else {
			return false
		}

		if n < 10 {
			result = (10*result + n) % 97
		} else {
			result = (100*result + n) % 97
		}
	}
	return result == 1
}

func TestIsValidIBAN(t *testing.T) {
	tests := []struct {
		iban  string
		valid bool
	}{
		{"GB82 WEST 1234 5698 7654 32", true},
		{"GB82 TEST 1234 5698 7654 32", false},
	}
	for _, test := range tests {
		if isValidIBAN(test.iban) == test.valid {
			return
		}
		t.Errorf("Expected %q to be %v", test.iban, test.valid)
	}
}


import Data.Char (toUpper)
import Data.Maybe (fromJust)

validateIBAN :: String -> Either String String
validateIBAN [] = Left "No IBAN number."
validateIBAN xs =
    case lookupCountry of
        Nothing -> invalidBecause "Country does not exist."
        Just l  -> if length normalized /= l
                        then invalidBecause "Number length does not match."
                        else check
    where
        -- remove blanks and make all letters uppercase
        normalized = map toUpper $ concat $ words xs
        -- get the country code
        country = take 2 normalized
        -- search number length
        lookupCountry = lookup country countries
        countries :: [(String, Int)]
        countries = zip (words "AL AT BE BA BG HR CZ DO FO FR DE GR GT \
            \IS IL KZ LV LI LU MT MU MD NL PK PL RO SA SK ES CH TR GB \
            \AD AZ BH BR CR CY DK EE FI GE GI GL HU IE IT KW LB LT MK \
            \MR MC ME NO PS PT SM RS SI SE TN AE VG")
            [28,20,16,20,22,21,24,28,18,27,22,27,28,26,23,20,21,21,20,
            31,30,24,18,24,28,24,24,24,24,21,26,22,24,28,22,29,21,28,18,
            20,18,22,23,18,28,22,27,30,28,20,19,27,27,22,15,29,25,27,22,
            19,24,24,23,24]
        digits = ['0'..'9']
        letters = ['A'..'Z']
        -- letters to be replaced
        replDigits = zip letters $ map show [10..35]
        -- digits and letters allowed in the IBAN number
        validDigits = digits ++ letters
        -- see if all digits and letters in the IBAN number are allowed
        sane = all (`elem` validDigits) normalized
        -- take the first 4 digits from the number and put them at its end
        (p1, p2) = splitAt 4 normalized
        p3 = p2 ++ p1
        -- convert the letters to numbers and
        -- convert the result to an integer
        p4 :: Integer
        p4 = read $ concat $ map convertLetter p3
        convertLetter x | x `elem` digits = [x]
                        | otherwise       = fromJust $ lookup x replDigits
        -- see if the number is valid
        check = if sane
                    then if p4 `mod` 97 == 1
                            then Right xs
                            else invalidBecause "Validation failed."
                    else invalidBecause "Number contains illegal digits."

        invalidBecause reason = Left $ "Invalid IBAN number " ++ xs ++
            ": " ++ reason


100 PROGRAM "IBAN.bas"
110 STRING CO$(1 TO 93)*2
120 NUMERIC LG(1 TO 93)
130 FOR I=1 TO 93
140   READ CO$(I),LG(I)
150 NEXT
160 DO
170   PRINT :PRINT "IBAN code: ":INPUT PROMPT ">":IB$
180   IF IB$="" THEN EXIT DO
190   IF IBAN(IB$) THEN
200     PRINT "CRC ok."
210   ELSE
220     SET #102:INK 3:PRINT "CRC error.":SET #102:INK 1
230   END IF
240 LOOP
250 DEF TRIM$(S$)
260   LET T$=""
270   FOR I=1 TO LEN(S$)
280     IF S$(I)>CHR$(47) AND S$(I)<CHR$(91) THEN LET T$=T$&S$(I)
290   NEXT
300   LET TRIM$=T$
310 END DEF
320 DEF IBAN(IB$)
330   LET IB$=TRIM$(UCASE$(IB$)):LET T$="":LET M,IBAN=0:LET N=FIND(IB$(1:2))
340   IF N=0 THEN PRINT "Invalid country code.":EXIT DEF
350   IF LEN(IB$)<>LG(N) THEN PRINT "Number length does not match.":EXIT DEF
360   LET IB$=IB$&IB$(1:4):LET IB$=IB$(5:)
370   CALL CONVERT(IB$)
380   FOR I=1 TO LEN(IB$)
390     LET T$=STR$(M)&IB$(I)
400     LET M=MOD(VAL(T$),97)
410   NEXT
420   IF M=1 THEN LET IBAN=-1
430 END DEF
440 DEF FIND(S$)
450   LET FIND=0
460   LET BO=LBOUND(CO$):LET UP=UBOUND(CO$)
470   DO
480     LET K=INT((BO+UP)/2)
490     IF CO$(K)<S$ THEN LET BO=K+1
500     IF CO$(K)>S$ THEN LET UP=K-1
510   LOOP WHILE BO<=UP AND CO$(K)<>S$
520   IF BO<=UP THEN LET FIND=K
530 END DEF
540 DEF CONVERT(REF S$)
550   LET T$=""
560   FOR I=1 TO LEN(S$)
570     IF S$(I)>CHR$(64) AND S$(I)<CHR$(91) THEN
580       LET T$=T$&STR$(ORD(S$(I))-55)
590     ELSE
600       LET T$=T$&S$(I)
610     END IF
620   NEXT
630   LET S$=T$
640 END DEF
650 DATA AD,24,AE,23,AL,28,AO,25,AT,20,AZ,28,BA,20,BE,16,BF,28,BG,22,BH,22,BI,16,BJ,28,BR,29,BY,28,CG,27,CH,21,CI,28,CM,27,CR,22,CV,25,CY,28,CZ,24,DE,22,DK,18,DO,28,DZ,24,EE,20,EG,27,ES,24,FI,18,FO,18,FR,27,GA,27,GB,22,GE,22,GI,23,GL,18
660 DATA GR,27,GT,28,HN,28,HR,21,HU,28,IE,22,IL,23,IR,26,IS,26,IT,27,JO,30,KM,27,KW,30,KZ,20,LB,28,LI,21,LT,20,LU,20,LV,21,MA,28,MC,27,MD,24,ME,22,MG,27,MK,19,ML,28,MR,27,MT,31,MU,30,MZ,25,NE,28,NI,32,NL,18,NO,15,PK,24,PL,28,PS,29,PT,25
670 DATA QA,29,RO,24,RS,22,SA,24,SE,24,SI,19,SK,24,SM,27,SN,28,TD,27,TG,28,TL,23,TN,24,TR,26,UA,29,VG,24,XK,20


NB. delete any blank characters
delblk =. #~ ' '&~:
NB. rearrange
rot =. '00' ,~ 2&}. @: (2&|.)
NB. characters -> "digits"
dig =. a. {~ (a.i.'0')+i.10
dig =. dig,a. {~ (a.i.'A')+i.26
todig =. dig&i.
coded =. [: ". 'x' ,~ delblk @: ": @: todig

NB. calculate check sum
cs =: 98 - 97 | coded @: rot @: delblk f.

NB. check sum as text
cstxt =. _2{. '0', [: ": cs
NB. replace first two characters
chgps =. [,2}.]
NB. shift country code
rotlc =. 2&|.
NB. insert check digits (position 3 and 4)
insertps =. chgps &.rotlc

NB. IBAN with newly calculated check digits
ibancd =: (cstxt insertps ]) f.

NB. check / generate check digits
ibancheck =: ] (]`('ok'"_) @. -:) ibancd

NB. groups of four characters
insertblk =. #~ # $ 1 1 1 1j1"_
quads =: insertblk @: delblk f.

NB. IBAN
iban =: quads @: ibancheck


import java.math.BigInteger;
import java.util.*;

public class IBAN {
    private static final String DEFSTRS = ""
            + "AL28 AD24 AT20 AZ28 BE16 BH22 BA20 BR29 BG22 "
            + "HR21 CY28 CZ24 DK18 DO28 EE20 FO18 FI18 FR27 GE22 DE22 GI23 "
            + "GL18 GT28 HU28 IS26 IE22 IL23 IT27 KZ20 KW30 LV21 LB28 LI21 "
            + "LT20 LU20 MK19 MT31 MR27 MU30 MC27 MD24 ME22 NL18 NO15 PK24 "
            + "PS29 PL28 PT25 RO24 SM27 SA24 RS22 SK24 SI19 ES24 SE24 CH21 "
            + "TN24 TR26 AE23 GB22 VG24 GR27 CR21";
    private static final Map<String, Integer> DEFINITIONS = new HashMap<>();

    static {
        for (String definition : DEFSTRS.split(" "))
            DEFINITIONS.put(definition.substring(0, 2), Integer.parseInt(definition.substring(2)));
    }

    public static void main(String[] args) {
        String[] ibans = {
                "GB82 WEST 1234 5698 7654 32",
                "GB82 TEST 1234 5698 7654 32",
                "GB81 WEST 1234 5698 7654 32",
                "SA03 8000 0000 6080 1016 7519",
                "CH93 0076 2011 6238 5295 7",
                "XX00 0000",
                "",
                "DE",
                "DE13 äöü_ 1234 1234 1234 12"};
        for (String iban : ibans)
            System.out.printf("%s is %s.%n", iban, validateIBAN(iban) ? "valid" : "not valid");
    }

    static boolean validateIBAN(String iban) {
        iban = iban.replaceAll("\\s", "").toUpperCase(Locale.ROOT);

        int len = iban.length();
        if (len < 4 || !iban.matches("[0-9A-Z]+") || DEFINITIONS.getOrDefault(iban.substring(0, 2), 0) != len)
            return false;

        iban = iban.substring(4) + iban.substring(0, 4);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < len; i++)
            sb.append(Character.digit(iban.charAt(i), 36));

        BigInteger bigInt = new BigInteger(sb.toString());

        return bigInt.mod(BigInteger.valueOf(97)).intValue() == 1;
    }
}


# strip the input string of spaces and tabs:
gsub("[ \t]";"")
# check the string is ALPHAnumeric
| test("^[A-Z0-9]+$")
  # check its length is as determined by the country code:
  and length == $lengths[.[0:2]]
  # check the mod 97 criterion:
  and ( (.[4:] + .[0:4]) | letters2digits | remainder) == 1


// version 1.0.6

import java.math.BigInteger

object IBAN {
    /* List updated to release 73, January 2017, of IBAN Registry (75 countries) */
    private const val countryCodes = "" +
            "AD24 AE23 AL28 AT20 AZ28 BA20 BE16 BG22 BH22 BR29 " +
            "BY28 CH21 CR22 CY28 CZ24 DE22 DK18 DO28 EE20 ES24 " +
            "FI18 FO18 FR27 GB22 GE22 GI23 GL18 GR27 GT28 HR21 " +
            "HU28 IE22 IL23 IQ23 IS26 IT27 JO30 KW30 KZ20 LB28 " +
            "LC32 LI21 LT20 LU20 LV21 MC27 MD24 ME22 MK19 MR27 " +
            "MT31 MU30 NL18 NO15 PK24 PL28 PS29 PT25 QA29 RO24 " +
            "RS22 SA24 SC31 SE24 SI19 SK24 SM27 ST25 SV28 TL23 " +
            "TN24 TR26 UA29 VG24 XK20"

    fun isValid(iban: String): Boolean {
        // remove spaces from IBAN
        var s = iban.replace(" ", "")

        // check country code and length
        s.substring(0, 2) + s.length in countryCodes || return false

        // move first 4 characters to the end
        s = s.substring(4) + s.substring(0, 4)

        // replace A to Z with numbers 10 To 35
        s = s.replace(Regex("[A-Z]")) { (10 + (it.value[0] - 'A')).toString() }

        // check whether mod 97 calculation gives a remainder of 1
        return BigInteger(s) % BigInteger.valueOf(97L) == BigInteger.ONE
    }
}

fun main() {
    val ibans = arrayOf(
            "GB82 WEST 1234 5698 7654 32",
            "GB82 TEST 1234 5698 7654 32"
    )
    for (iban in ibans) {
        val valid = IBAN.isValid(iban)
        println(iban + if (valid) " may be valid" else " is not valid")
    }
}


let cc = ["AD","AE","AL","AO","AT","AZ","BA","BE","BF","BG","BH","BI","BJ","BR","CG","CH","CI","CM","CR","CV","CY",
          "CZ","DE","DK","DO","DZ","EE","EG","ES","FI","FO","FR","GA","GB","GE","GI","GL","GR","GT","HR","HU","IE",
          "IL","IR","IS","IT","JO","KW","KZ","LB","LI","LT","LU","LV","MC","MD","ME","MG","MK","ML","MR","MT","MU",
          "MZ","NL","NO","PK","PL","PS","PT","QA","RO","RS","SA","SE","SI","SK","SM","SN","TN","TR","UA","VG"]
let ln = [ 24,  23,  28,  25,  20,  28,  20,  16,  27,  22,  22,  16,  28,  29,  27,  21,  28,  27,  21,  25,  28,
           24,  22,  18,  28,  24,  20,  27,  24,  18,  18,  27,  27,  22,  22,  23,  18,  27,  28,  21,  28,  22,
           23,  26,  26,  27,  30,  30,  20,  28,  21,  20,  20,  21,  27,  24,  22,  27,  19,  28,  27,  31,  30,
           25,  18,  15,  24,  28,  29,  25,  29,  24,  22,  24,  24,  19,  24,  27,  28,  24,  26,  29,  24 ]

def ccToLen(s: string) -> int:
    let cnt, idx = binary_search(cc, s.substring(0, 2))
    if cnt == 1:
        return ln[idx]
    else:
        return -1

def strip(s: string) -> string:
    let t = s.tokenize(" ", " ") // splits on spaces and trims spaces from segments
    return t.concat_string("")   // joins it back together

def rotmod97step(accumu: int, c: int) -> int:
    accumu *= 10
    if '0' <= c and c <= '9':
        accumu += c - '0'
    else: if 'A' <= c and c <= 'Z':
        accumu *= 10
        accumu += c + 10 - 'A'
    else:
        return -1
    while accumu >= 97:
        accumu -= 97
    return accumu

def rotmod97(s: string) -> int:
    // the first four chars come last
    // all chars from 'A' to 'Z' => "10" to "35"
    let len = s.length
    var accumu = 0 // result; negative indicates error
    var i = 4 // starting index
    while i < len and accumu >= 0:
        accumu = rotmod97step(accumu, s[i])
        i += 1
    i = 0
    while i < 4 and accumu >= 0:
        accumu = rotmod97step(accumu, s[i])
        i += 1
    return accumu

def isValidIBAN(iban: string) -> bool:
    let s = strip(uppercase(iban))
    if s.length == ccToLen(s):
        return rotmod97(s) == 1
    else:
        return false

assert     isValidIBAN("GB82 WEST 1234 5698 7654 32")
assert     isValidIBAN("GB82 West 1234 5698 7654 32")
assert not isValidIBAN("GB82 TEST 1234 5698 7654 32")
assert not isValidIBAN("GB82 WEST 1243 5698 7654 32")


:- object(iban).

	:- info([
		version is 0.1,
		author is 'Paulo Moura',
		date is 2015/10/11,
		comment is 'IBAN validation example using DCG rules.'
	]).

	:- public(valid/1).

	valid(IBAN) :-
		phrase(iban, IBAN), !.

	iban -->
		country_code(Code), check_digits(Check), bban(BBAN),
		{(BBAN*1000000 + Code*100 + Check) mod 97 =:= 1}.

	country_code(Code) -->
		letter_digits(L1, D3, D2), letter_digits(L0, D1, D0),
		{country_code([L1, L0]), Code is D3*1000 + D2*100 + D1*10 + D0}.

	check_digits(Check) -->
		digit(D1), digit(D0),
		{Check is D1*10 + D0}.

	bban(BBAN) -->
		bban_codes(Digits),
		{digits_to_integer(Digits, BBAN, Count), Count =< 30}.

	bban_codes(Ds) -->
		" ", bban_codes(Ds).
	bban_codes([D| Ds]) -->
		digit(D), bban_codes(Ds).
	bban_codes([D1, D0| Ds]) -->
		letter_digits(_, D1, D0), bban_codes(Ds).
	bban_codes([]) -->
		[].

	digit(D) -->
		[C],
		{0'0 =< C, C =< 0'9, D is C - 0'0}.

	letter_digits(C, D1, D0) -->
		[C],
		{	(	0'A =< C, C =< 0'Z ->
				D is C - 0'A + 10
			;	0'a =< C, C =< 0'z,
				D is C - 0'a + 10
			),
			D1 is D div 10,
			D0 is D mod 10
		}.

	digits_to_integer(Digits, BBAN, Count) :-
		digits_to_integer(Digits, 0, BBAN, 0, Count).

	digits_to_integer([], BBAN, BBAN, Count, Count).
	digits_to_integer([Digit| Digits], BBAN0, BBAN, Count0, Count) :-
		BBAN1 is BBAN0 * 10 + Digit,
		Count1 is Count0 + 1,
		digits_to_integer(Digits, BBAN1, BBAN, Count1, Count).

	country_code("AL").
	country_code("AD").
	country_code("AT").
	country_code("AZ").
	country_code("BE").
	country_code("BH").
	country_code("BA").
	country_code("BR").
	country_code("BG").
	country_code("CR").
	country_code("HR").
	country_code("CY").
	country_code("CZ").
	country_code("DK").
	country_code("DO").
	country_code("EE").
	country_code("FO").
	country_code("FI").
	country_code("FR").
	country_code("GE").
	country_code("DE").
	country_code("GI").
	country_code("GR").
	country_code("GL").
	country_code("GT").
	country_code("HU").
	country_code("IS").
	country_code("IE").
	country_code("IL").
	country_code("IT").
	country_code("KZ").
	country_code("KW").
	country_code("LV").
	country_code("LB").
	country_code("LI").
	country_code("LT").
	country_code("LU").
	country_code("MK").
	country_code("MT").
	country_code("MR").
	country_code("MU").
	country_code("MC").
	country_code("MD").
	country_code("ME").
	country_code("NL").
	country_code("NO").
	country_code("PK").
	country_code("PS").
	country_code("PL").
	country_code("PT").
	country_code("RO").
	country_code("SM").
	country_code("SA").
	country_code("RS").
	country_code("SK").
	country_code("SI").
	country_code("ES").
	country_code("SE").
	country_code("CH").
	country_code("TN").
	country_code("TR").
	country_code("AE").
	country_code("GB").
	country_code("VG").

:- end_object.


local length=
{
  AL=28, AD=24, AT=20, AZ=28, BH=22, BE=16, BA=20, BR=29, BG=22, CR=21,
  HR=21, CY=28, CZ=24, DK=18, DO=28, EE=20, FO=18, FI=18, FR=27, GE=22,
  DE=22, GI=23, GR=27, GL=18, GT=28, HU=28, IS=26, IE=22, IL=23, IT=27,
  JO=30, KZ=20, KW=30, LV=21, LB=28, LI=21, LT=20, LU=20, MK=19, MT=31,
  MR=27, MU=30, MC=27, MD=24, ME=22, NL=18, NO=15, PK=24, PS=29, PL=28,
  PT=25, QA=29, RO=24, SM=27, SA=24, RS=22, SK=24, SI=19, ES=24, SE=24,
  CH=21, TN=24, TR=26, AE=23, GB=22, VG=24
}

function validate(iban)
  iban=iban:gsub("%s","")
  local l=length[iban:sub(1,2)]
  if not l or l~=#iban or iban:match("[^%d%u]") then
    return false -- invalid character, country code or length
  end
  local mod=0
  local rotated=iban:sub(5)..iban:sub(1,4)
  for c in rotated:gmatch(".") do
    mod=(mod..tonumber(c,36)) % 97
  end
  return mod==1
end


\\ IBAN checker
Function MakeIBANfun$ {
      Inventory countrylength = "AL" := 28, "AD" := 24, "AT" := 20, "AZ" := 28, "BE" := 16, "BH" := 22, "BA" := 20, "BR" := 29
      Append  countrylength, "BG" := 22, "CR" := 21, "HR" := 21, "CY" := 28, "CZ" := 24, "DK" := 18, "DO" := 28, "EE" := 20
      Append  countrylength, "FO" := 18, "FI" := 18, "FR" := 27, "GE" := 22, "DE" := 22, "GI" := 23, "GR" := 27, "GL" := 18
      Append  countrylength, "GT" := 28, "HU" := 28, "IS" := 26, "IE" := 22, "IL" := 23, "IT" := 27, "KZ" := 20, "KW" := 30
      Append  countrylength, "LV" := 21, "LB" := 28, "LI" := 21, "LT" := 20, "LU" := 20, "MK" := 19, "MT" := 31, "MR" := 27
      Append  countrylength, "MU" := 30, "MC" := 27, "MD" := 24, "ME" := 22, "NL" := 18, "NO" := 15, "PK" := 24, "PS" := 29
      Append  countrylength, "PL" := 28, "PT" := 25, "RO" := 24, "SM" := 27, "SA" := 24, "RS" := 22, "SK" := 24, "SI" := 19
      Append  countrylength, "ES" := 24, "SE" := 24, "CH" := 21, "TN" := 24, "TR" := 26, "AE" := 23, "GB" := 22, "VG" := 24

     =Lambda$ countrylength (Iban0$)->{
            Iban$=Filter$(Ucase$(Iban0$), " ")
            Iban$=Filter$(Iban$, Filter$(Iban$,"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"))
            Def Decimal ch, c
            {
                  If Not Exist(countrylength, Left$(Iban$,2)) Then Exit
                  length=Eval(countrylength)
                  If Not Len(Iban$)=length Then exit
                  Buffer ScanChar as Integer*length
                  Return ScanChar, 0:=Mid$(Iban$,5), length-4:=Mid$(Iban$,1,4)

                  For i=0 to length-1 {
                        ch=Eval(ScanChar, i)
                        if ch>=48 and ch<=57 then {
                              c = c*10+ch-48
                        } else.if ch>=65 and ch<=90 then {
                              c = c*100+ch-55
                        } else c=-1: exit
                  }
                  c = c mod 97
            }
            =Iban0$ + If$(c=1 ->" (Valid)", " (Invalid)")
      }
}
IbanCheck$=MakeIBANfun$()
Print IbanCheck$("GB82 WEST 1234 5698 7654 32")    ' valid
Print IbanCheck$("GB82 TEST 1234 5698 7654 32")
Print IbanCheck$("SA03 8000 0000 6080 1016 7519")   ' valid
Print IbanCheck$("GR16 0110 1250 0000 0001 2300 695X")
Print IbanCheck$("MK11 2222 3333 4444 555")


function valid = validateIBAN(iban)
% Determine if International Bank Account Number is valid IAW ISO 13616
% iban - string containing account number
    if length(iban) < 5
        valid = false;
    else
        iban(iban == ' ') = '';                     % Remove spaces
        iban = lower([iban(5:end) iban(1:4)])+0;	% Rearrange and convert
        iban(iban > 96 & iban < 123) = iban(iban > 96 & iban < 123)-87; % Letters
        iban(iban > 47 & iban < 58) = iban(iban > 47 & iban < 58)-48;   % Numbers
        valid = piecewiseMod97(iban) == 1;
    end
end

function result = piecewiseMod97(x)
% Conduct a piecewise version of mod(x, 97) to support large integers
% x is a vector of integers
    x = sprintf('%d', x);	% Get to single-digits per index
    nDig = length(x);
    i1 = 1;
    i2 = min(9, nDig);
    prefix = '';
    while i1 <= nDig
        y = str2double([prefix x(i1:i2)]);
        result = mod(y, 97);
        prefix = sprintf('%d', result);
        i1 = i2+1;
        i2 = min(i1+8, nDig);
    end
end


(setq *iban-code-length* '((15  ("NO"))
                             (16  ("BE"))
                             (18  ("DK" "FO" "FI" "GL" "NL"))
                             (19  ("MK" "SI"))
                             (20  ("AT" "BA" "EE" "KZ" "LT" "LU"))
                             (21  ("CR" "HR" "LV" "LI" "CH"))
                             (22  ("BH" "BG" "GE" "DE" "IE" "ME" "RS" "GB"))
                             (23  ("GI" "IL" "AE"))
                             (24  ("AD" "CZ" "MD" "PK" "RO" "SA" "SK" "ES" "SE" "TN" "VG"))
                             (25  ("PT"))
                             (26  ("IS" "TR"))
                             (27  ("FR" "GR" "IT" "MR" "MC" "SM"))
                             (28  ("AL" "AZ" "CY" "DO" "GT" "HU" "LB" "PL"))
                             (29  ("BR" "PS"))
                             (30  ("KW" "MU"))
                             (31  ("MT"))))

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

;; Remove spaces and set upper case.
(define (sanitize-iban iban)
   (upper-case (replace " " iban ""))
)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

;; Check that only A-Z and 0-9 are used.
(define (valid-chars? iban)
	(setq rx (string "[A-Z0-9]{" (length iban) "}" ))
	(regex rx iban 1)
)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

;; Check that the length is correct for the country.
(define (valid-length? iban)
	(setq countries-found (lookup (int (length iban)) *iban-code-length*))
	(if (not (nil? countries-found))
		(member (0 2 iban) countries-found)
	)
)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

;; Convert the IBAN to integer following the rules from Wikipedia.
(define (iban-to-integer iban)
    (setq country-code (0 2 iban))
    (setq checksum (2 2 iban))
    (setq iban (string (4 iban) country-code))
    (setq iban (join (map (lambda (x) (if (regex "[0-9]" x) x (string (- (char x) 55)))) (explode iban))))
    (bigint (string iban checksum))
)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

;; Test if IBAN is correct (true) or not (nil):
;; (valid-iban? "GB82 WEST 1234 5698 7654 32") ==> true
;; (valid-iban? "GB82 TEST 1234 5698 7654 32") ==> nil
(define (valid-iban? iban)
    (setq iban (sanitize-iban iban))
    (and
        (valid-chars? iban)
        (valid-length? iban)
        (= 1L (% (iban-to-integer iban) 97))
    )
)


import tables, strutils, re, bigints

let countryLen = toTable({
  "AL": 28, "AD": 24, "AT": 20, "AZ": 28, "BE": 16, "BH": 22, "BA": 20, "BR": 29,
  "BG": 22, "CR": 21, "HR": 21, "CY": 28, "CZ": 24, "DK": 18, "DO": 28, "EE": 20,
  "FO": 18, "FI": 18, "FR": 27, "GE": 22, "DE": 22, "GI": 23, "GR": 27, "GL": 18,
  "GT": 28, "HU": 28, "IS": 26, "IE": 22, "IL": 23, "IT": 27, "KZ": 20, "KW": 30,
  "LV": 21, "LB": 28, "LI": 21, "LT": 20, "LU": 20, "MK": 19, "MT": 31, "MR": 27,
  "MU": 30, "MC": 27, "MD": 24, "ME": 22, "NL": 18, "NO": 15, "PK": 24, "PS": 29,
  "PL": 28, "PT": 25, "RO": 24, "SM": 27, "SA": 24, "RS": 22, "SK": 24, "SI": 19,
  "ES": 24, "SE": 24, "CH": 21, "TN": 24, "TR": 26, "AE": 23, "GB": 22, "VG": 24})

proc validIban(iban: string): bool =
  # Ensure upper alphanumeric input
  var iban = iban.replace(" ","").replace("\t","")
  if not iban.match(re"^[\dA-Z]+$"):
    return false

  # Validate country code against expected length
  if iban.len != countryLen[iban[0..1]]:
    return false

  # Shift and convert
  iban = iban[4..iban.high] & iban[0..3]
  var digits = ""
  for ch in iban:
    case ch
      of '0'..'9': digits.add($(ch.ord - '0'.ord))
      of 'A'..'Z': digits.add($(ch.ord - 'A'.ord + 10))
      else: discard
  result = initBigInt(digits) mod 97 == 1

for account in ["GB82 WEST 1234 5698 7654 32", "GB82 TEST 1234 5698 7654 32"]:
  echo account, " validation is: ", validIban account


MODULE IBAN;
IMPORT
  Out,
  Err,
  ADT:Dictionary,
  Object:Boxed,
  Object:BigInt,
  Object,
  Strings,
  IntStr;
TYPE
  IBANLen = Boxed.LongInt;
VAR
  nations: Dictionary.Dictionary(STRING,IBANLen);

  PROCEDURE Check*(iban: ARRAY OF CHAR): BOOLEAN;
  VAR
    country,ibanStr: Object.String;
    nLetter: ARRAY 3 OF CHAR;
    block: ARRAY 5 OF CHAR;
    numIban: ARRAY 256 OF CHAR;
    num,den,res: BigInt.BigInt;
    ibanLen: IBANLen;
    i: LONGINT;
  BEGIN
    ibanStr := Object.NewLatin1(iban);
    country := ibanStr.Substring(0,2);
    IF ~nations.HasKey(country) THEN
      Err.Object("Country " + country + " has not IBAN codes. ");
      RETURN FALSE;
    END;
    ibanLen := nations.Get(country);

    IF SHORT(ibanLen.value) # Strings.Length(iban) THEN
      Err.Object("IBAN length incorrect for " + country +". ");
      RETURN FALSE
    END;

    block[0] := 0X;
    Strings.Extract(iban,0,4,block);
    Strings.Delete(iban,0,4);Strings.Append(block,iban);

    numIban[0] := 0X;
    FOR i := 0 TO LEN(iban) - 1 DO
      nLetter[0] := 0X;
      IF (iban[i] >= 'A') & (iban[i] <= 'Z') THEN
        IntStr.IntToStr(ORD(iban[i]) - ORD('A') + 10,nLetter);
      ELSE
        nLetter[0] := iban[i];
        nLetter[1] := 0X
      END;
      Strings.Append(nLetter,numIban);
    END;
    Strings.Append(0X,numIban);

    num := BigInt.New(Object.NewLatin1(numIban),10);
    den := BigInt.New("97",10);
    res := num.Mod(den);
    IF res.Equals(BigInt.one) THEN
      RETURN TRUE
    ELSE
      Err.String("IBAN code check failed. ");
      RETURN FALSE
    END
  END Check;

  PROCEDURE CodeLengthFor*(country: ARRAY OF CHAR): LONGINT;
  VAR
    countryStr: Object.String;
    ibanLen: IBANLen;
  BEGIN
    countryStr := Object.NewLatin1(country);
    ibanLen := Boxed.zeroLongInt;
    IF nations.HasKey(countryStr) THEN
      ibanLen := nations.Get(countryStr)
    END;
    RETURN ibanLen.value
  END CodeLengthFor;

  PROCEDURE Test*;
    PROCEDURE DoCheck(iban: ARRAY OF CHAR);
    BEGIN
      Out.String("IBAN[");Out.String(iban);Out.String("]=");Out.Bool(Check(iban));
      Out.Ln
    END DoCheck;
  BEGIN
    DoCheck("CH9300762011623852957");
    DoCheck("GB82WEST12345698765432");
    DoCheck("SA0380000000608010167519");
    DoCheck("XX0380000000608010167519");
  END Test;

BEGIN
  nations := NEW(Dictionary.Dictionary(STRING,Boxed.LongInt));
  nations.Set("AL",NEW(IBANLen,28));
  nations.Set("AD",NEW(IBANLen,24));
  nations.Set("AT",NEW(IBANLen,20));
  nations.Set("AZ",NEW(IBANLen,28));
  nations.Set("BE",NEW(IBANLen,16));
  nations.Set("BH",NEW(IBANLen,22));
  nations.Set("BA",NEW(IBANLen,20));
  nations.Set("BR",NEW(IBANLen,29));
  nations.Set("BG",NEW(IBANLen,22));
  nations.Set("CR",NEW(IBANLen,21));
  nations.Set("HR",NEW(IBANLen,21));
  nations.Set("CY",NEW(IBANLen,28));
  nations.Set("CZ",NEW(IBANLen,24));
  nations.Set("DK",NEW(IBANLen,18));
  nations.Set("DO",NEW(IBANLen,28));
  nations.Set("EE",NEW(IBANLen,20));
  nations.Set("FO",NEW(IBANLen,18));
  nations.Set("FI",NEW(IBANLen,18));
  nations.Set("FR",NEW(IBANLen,27));
  nations.Set("GE",NEW(IBANLen,22));
  nations.Set("DE",NEW(IBANLen,22));
  nations.Set("GI",NEW(IBANLen,23));
  nations.Set("GR",NEW(IBANLen,27));
  nations.Set("GL",NEW(IBANLen,18));
  nations.Set("GT",NEW(IBANLen,28));
  nations.Set("HU",NEW(IBANLen,28));
  nations.Set("IS",NEW(IBANLen,26));
  nations.Set("IE",NEW(IBANLen,22));
  nations.Set("IL",NEW(IBANLen,23));
  nations.Set("IT",NEW(IBANLen,27));
  nations.Set("KZ",NEW(IBANLen,20));
  nations.Set("KW",NEW(IBANLen,30));
  nations.Set("LV",NEW(IBANLen,21));
  nations.Set("LB",NEW(IBANLen,28));
  nations.Set("LI",NEW(IBANLen,21));
  nations.Set("LT",NEW(IBANLen,20));
  nations.Set("LU",NEW(IBANLen,20));
  nations.Set("MK",NEW(IBANLen,19));
  nations.Set("MT",NEW(IBANLen,31));
  nations.Set("MR",NEW(IBANLen,27));
  nations.Set("MU",NEW(IBANLen,30));
  nations.Set("MC",NEW(IBANLen,27));
  nations.Set("MD",NEW(IBANLen,24));
  nations.Set("ME",NEW(IBANLen,22));
  nations.Set("NL",NEW(IBANLen,18));
  nations.Set("NO",NEW(IBANLen,15));
  nations.Set("PK",NEW(IBANLen,24));
  nations.Set("PS",NEW(IBANLen,29));
  nations.Set("PL",NEW(IBANLen,28));
  nations.Set("PT",NEW(IBANLen,25));
  nations.Set("RO",NEW(IBANLen,24));
  nations.Set("SM",NEW(IBANLen,27));
  nations.Set("SA",NEW(IBANLen,24));
  nations.Set("RS",NEW(IBANLen,22));
  nations.Set("SK",NEW(IBANLen,24));
  nations.Set("SI",NEW(IBANLen,19));
  nations.Set("ES",NEW(IBANLen,24));
  nations.Set("SE",NEW(IBANLen,24));
  nations.Set("CH",NEW(IBANLen,21));
  nations.Set("TN",NEW(IBANLen,24));
  nations.Set("TR",NEW(IBANLen,26));
  nations.Set("AE",NEW(IBANLen,23));
  nations.Set("GB",NEW(IBANLen,22));
  nations.Set("VG",NEW(IBANLen,24));

  Test;
END IBAN.


#load "str.cma"
#load "nums.cma"  (* for module Big_int *)

(* Countries and length of their IBAN. *)
(* Taken from https://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country *)
let countries = [
  ("AL", 28); ("AD", 24); ("AT", 20); ("AZ", 28); ("BH", 22); ("BE", 16);
  ("BA", 20); ("BR", 29); ("BG", 22); ("CR", 21); ("HR", 21); ("CY", 28);
  ("CZ", 24); ("DK", 18); ("DO", 28); ("TL", 23); ("EE", 20); ("FO", 18);
  ("FI", 18); ("FR", 27); ("GE", 22); ("DE", 22); ("GI", 23); ("GR", 27);
  ("GL", 18); ("GT", 28); ("HU", 28); ("IS", 26); ("IE", 22); ("IL", 23);
  ("IT", 27); ("JO", 30); ("KZ", 20); ("XK", 20); ("KW", 30); ("LV", 21);
  ("LB", 28); ("LI", 21); ("LT", 20); ("LU", 20); ("MK", 19); ("MT", 31);
  ("MR", 27); ("MU", 30); ("MC", 27); ("MD", 24); ("ME", 22); ("NL", 18);
  ("NO", 15); ("PK", 24); ("PS", 29); ("PL", 28); ("PT", 25); ("QA", 29);
  ("RO", 24); ("SM", 27); ("SA", 24); ("RS", 22); ("SK", 24); ("SI", 19);
  ("ES", 24); ("SE", 24); ("CH", 21); ("TN", 24); ("TR", 26); ("AE", 23);
  ("GB", 22); ("VG", 24); ("DZ", 24); ("AO", 25); ("BJ", 28); ("BF", 27);
  ("BI", 16); ("CM", 27); ("CV", 25); ("IR", 26); ("CI", 28); ("MG", 27);
  ("ML", 28); ("MZ", 25); ("SN", 28); ("UA", 29)
]
(* Put the countries in a Hashtbl for faster search... *)
let tbl_countries =
  let htbl = Hashtbl.create (List.length countries) in
  let _ = List.iter (fun (k, v) -> Hashtbl.add htbl k v) countries in
  htbl

(* Delete spaces and put all letters in upper case. *)
let clean_iban iban =
  Str.global_replace (Str.regexp " +") "" iban
  |> String.uppercase_ascii

(* Each country has an IBAN with a specific length. *)
let check_length ib =
  let iso_length = List.hd countries |> fst |> String.length in
  let country_code = String.sub ib 0 iso_length in
  try
    Hashtbl.find tbl_countries country_code = String.length ib
  with
    Not_found -> false

(* Convert a string into a list of chars. *)
let charlist_of_string s =
  let l = String.length s in
  let rec doloop i =
    if i >= l then []
    else s.[i] :: doloop (i + 1)
  in
  doloop 0

(* Letters are associated to values: A=10, B=11, ..., Z=35. *)
let val_of_char c =
  match c with
  | '0' .. '9' -> int_of_char c - int_of_char '0'
  | 'A' .. 'Z' -> int_of_char c - int_of_char 'A' + 10
  | _ -> failwith (Printf.sprintf "Character not allowed: %c" c)

(* Compute the mod-97 value and check it is equal to 1. *)
let check_mod97 ib =
  let l = String.length ib
  and taken = 4 in
  let prefix = String.sub ib 0 taken
  and rest = String.sub ib taken (l - taken) in
  let newval = rest ^ prefix (* move the 4 initial characters to the end of the string *)
            |> charlist_of_string  (* convert the string into a list of chars *)
            |> List.map val_of_char  (* convert each char into its integer value *)
            |> List.map string_of_int  (* convert the integers into strings... *)
            |> List.fold_left (^) "" in  (* ...and concatenate said strings *)
  (* Now compute the mod-97 using the Big Integers provided by OCaml, and
   * compare the result to 1. *)
  Big_int.eq_big_int
    (Big_int.mod_big_int (Big_int.big_int_of_string newval)
                         (Big_int.big_int_of_int 97))
    (Big_int.big_int_of_int 1)

(* Do the validation as described in the Wikipedia article at
 * https://en.wikipedia.org/wiki/International_Bank_Account_Number#Validating_the_IBAN *)
let validate iban =
  let ib = clean_iban iban in
  check_length ib && check_mod97 ib

let () =
  let ibans = [
    ("GB82 WEST 1234 5698 7654 32", true);
    ("GB82 TEST 1234 5698 7654 32", false);
    ("GB81 WEST 1234 5698 7654 32", false);
    ("GB82 WEST 1234 5698 7654 3", false);
    ("SA03 8000 0000 6080 1016 7519", true);
    ("CH93 0076 2011 6238 5295 7", true);
    ("\"Completely incorrect iban\"", false)
  ] in
  let testit (ib, exp) =
    let res = validate ib in
    Printf.printf "%s is %svalid. Expected %b [%s]\n"
                  ib (if res then "" else "not ")
                  exp (if res = exp then "PASS" else "FAIL")
  in
  List.iter (fun pair -> testit pair) ibans


package Wumpus is
   procedure Start_Game;
end Wumpus;


--
-- demo\rosetta\IBAN.exw
-- =====================
--
constant nations = {{"AD",24},  -- Andorra
                    -- (full list in distro)
                    {"CH",21},  -- Switzerland
                    {"GB",22},  -- United Kingdom
                    {"SA",24},  -- Saudi Arabia
                    {"XK",20}}  -- Kosovo

constant {countries,lengths} = columnize(nations)

function iban(string code)
-- This routine does and should reject codes containing spaces etc.
-- Use iban_s() below for otherwise.
    integer country = find(code[1..2],countries)
    if country!=0
    and length(code)=lengths[country] then
        code = code[5..$]&code[1..4]
        integer c = 0
        for i=1 to length(code) do
            integer ch=code[i]
            if ch>='0' and ch<='9' then
                c = c*10+ch-'0'
            elsif ch>='A' and ch<='Z' then
                c = c*100+ch-55
            else
                return false
            end if
            c = mod(c,97)
        end for
        return c=1
    end if
    return false
end function

function iban_s(string code)
-- strips any embedded spaces and hyphens before validating.
    code = substitute_all(code,{" ","-"},{"",""})
    return iban(code)
end function

procedure test(string code, bool expected)
    bool valid = iban_s(code)
    string state
    if valid=expected then
        state = iff(valid?"ok":"invalid (as expected)")
    else
        state = iff(valid?"OK!!":"INVALID!!")&" (NOT AS EXPECTED)"
    end if
    printf(1,"%-34s :%s\n",{code,state})
end procedure

test("GB82 WEST 1234 5698 7654 32",true)
test("GB82 TEST 1234 5698 7654 32",false)
test("GB81 WEST 1234 5698 7654 32",false)
test("SA03 8000 0000 6080 1016 7519",true)
test("CH93 0076 2011 6238 5295 7",true)


10 DEFINT A-Z: DIM R(19,3),P(1),B(1)
20 FOR I=0 TO 19: READ R(I,0),R(I,1),R(I,2): NEXT
30 INPUT "Enter a number";X: X=RND(-ABS(X))
40 PRINT: PRINT "*** HUNT THE WUMPUS ***"
50 PRINT "-----------------------": PRINT
60 FOR I=0 TO 1: GOSUB 500: P(I)=X: GOSUB 500: B(I)=X: NEXT
70 GOSUB 500: W=X: GOSUB 500: P=X
80 A=5
90 IF A=0 THEN 340
100 IF P=W THEN 410
110 IF P=B(0) OR P=B(1) THEN 360
120 IF P=P(0) OR P=P(1) THEN 390
130 PRINT: FOR I=0 TO 2
140 IF R(P,I)=W THEN PRINT "You smell something terrible nearby."
150 FOR J=0 TO 1
160 IF R(P,I)=B(J) THEN PRINT "You hear a rustling."
170 IF R(P,I)=P(J) THEN PRINT "You feel a cold wind blowing from a nearby cavern."
180 NEXT J,I
190 PRINT USING "You are in room ##. ";P;
200 PRINT USING "Tunnels lead to ##; ##; and ##.";R(P,0);R(P,1);R(P,2)
210 PRINT USING "You have # arrows.";A: PRINT
220 LINE INPUT "M)ove, S)hoot or Q)uit? ";I$
230 S=I$="S" OR I$="s": IF S OR I$="M" OR I$="m" THEN 260
240 IF I$="Q" OR I$="q" THEN END
250 PRINT "Sorry?": GOTO 220
260 INPUT "Which room";X: PRINT
270 IF X=R(P,0) OR X=R(P,1) OR X=R(P,2) THEN IF S THEN 290 ELSE P=X: GOTO 90
280 PRINT "Cannot get there from here.": GOTO 260
290 IF X=W THEN PRINT "Congratulations! You shot the wumpus!": GOTO 440
300 PRINT "You missed.": A=A-1: IF RND(1)<.25 THEN 90
310 PRINT "The wumpus wakes from his slumber."
320 X=RND(1)*3: IF R(R(W,X),3) THEN 320
330 R(W,3)=0: W=R(W,X): R(W,3)=1: GOTO 90
340 PRINT "As you grasp at your empty quiver, ";
350 PRINT "you hear a large beast approaching...": GOTO 410
360 PRINT "You have entered the lair of a large bat."
370 PRINT "It picks you up and drops you in room";
380 P=R(P,RND(1)*3): PRINT P;".": GOTO 90
390 PRINT "The ground gives way beneath your feet."
400 PRINT "You fall into a deep abyss.": GOTO 430
410 PRINT "You find yourself face to face with the wumpus."
420 PRINT "It eats you whole."
430 PRINT: PRINT "You have met your demise."
440 LINE INPUT "Another game (Y/N)?";I$
450 IF I$="Y" OR I$="y" THEN 60
460 IF I$<>"N" AND I$<>"n" THEN PRINT "Sorry?": GOTO 440
470 END
500 X=RND(1)*20: IF R(X,3)=0 THEN R(X,3)=1: RETURN ELSE 500
510 DATA 1,4,7, 0,2,9, 1,3,11, 2,4,13, 0,3,5
520 DATA 4,6,14, 5,7,16, 0,6,8, 7,9,17, 1,8,10
530 DATA 9,11,18, 2,10,12, 11,13,19, 3,12,14, 5,13,15
540 DATA 14,16,19, 6,15,17, 8,16,18, 10,17,19, 12,15,18


// constant value 2d array to represent the dodecahedron
// room structure
const static int adjacentRooms[20][3] = {
  {1, 4, 7},   {0, 2, 9},   {1, 3, 11},   {2, 4, 13},    {0, 3, 5},
  {4, 6, 14},  {5, 7, 16},    {0, 6, 8},   {7, 9, 17},   {1, 8, 10},
  {9, 11, 18}, {2, 10, 12}, {11, 13, 19},  {3, 12, 14},  {5, 13, 15},
  {14, 16, 19}, {6, 15, 17},  {8, 16, 18}, {10, 17, 19}, {12, 15, 18}
};

class WumpusGame {

    private:
      // Data Members
      int numRooms;
      int currentRoom, startingPosition; // currentRoom is an integer variable that stores the room the player is currently in (between 0-20)
      int wumpusRoom, batRoom1, batRoom2, pitRoom1, pitRoom2; // Stores the room numbers of the respective
      int wumpusStart, bat1Start, bat2Start;
      bool playerAlive, wumpusAlive; // Are the player and wumpus still alive? True or false.
      int numArrows; //store arrow count

      // private functions
      void PlacePits();
      void PlaceBats();
      void PlaceWumpus();
      void PlacePlayer();
      bool IsValidMove(int);
      bool IsRoomAdjacent(int, int);
      int Move(int);
      void InspectCurrentRoom();
      void PerformAction(int);
      void MoveStartledWumpus(int);
      void PlayGame();
      void PlayAgain();
      void PrintInstructions();

      // Access specifier
      public:
        //public functions
        void StartGame();
        WumpusGame();
};

#include <iostream>
#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */
#include <vector>
#include <cstring>
using namespace std;

// default constructor
WumpusGame::WumpusGame() {
  numRooms = 20;
}

// This function prints the instructions for the game
// to the console
void WumpusGame::PrintInstructions() {
    char wait;
    cout << " Welcome to 'Hunt the Wumpus'! " << endl;
    cout << " The wumpus lives in a cave of 20 rooms. Each room has 3 tunnels leading to" << endl;
    cout << " other rooms. (Look at a dodecahedron to see how this works - if you don't know" << endl;
    cout << " what a dodecahedron is, ask someone). \n" << endl;
    cout << " Hazards: \n" << endl;
    cout << " Bottomless pits - two rooms have bottomless pits in them. If you go there, you " << endl;
    cout << " fall into the pit (& lose!) \n" << endl;
    cout << " Super bats - two other rooms have super bats.  If you go there, a bat grabs you" << endl;
    cout << " and takes you to some other room at random. (Which may be troublesome). Once the" << endl;
    cout << " bat has moved you, that bat moves to another random location on the map.\n\n" << endl;

    cout << " Wumpus" << endl;
    cout << " The wumpus is not bothered by hazards (he has sucker feet and is too big for a" << endl;
    cout << " bat to lift).  Usually he is asleep.  Two things wake him up: you shooting an" << endl;
    cout << " arrow or you entering his room. If the wumpus wakes he moves (p=.75) one room or " << endl;
    cout << " stays still (p=.25). After that, if he is where you are, he eats you up and you lose!\n" << endl;

    cout << " You \n" << endl;
    cout << " Each turn you may move, save or shoot an arrow using the commands move, save, & shoot." << endl;
    cout << " Moving: you can move one room (thru one tunnel)." << endl;
    cout << " Arrows: you have 3 arrows. You lose when you run out. You aim by telling the" << endl;
    cout << " computer the rooms you want the arrow to go to.  If the arrow can't go that way" << endl;
    cout << " (if no tunnel), the arrow will not fire." << endl;

    cout << " Warnings" << endl;
    cout << " When you are one room away from a wumpus or hazard, the computer says:" << endl;

    cout << " Wumpus: 'I smell a wumpus'" << endl;
    cout << " Bat: 'Bats nearby'" << endl;
    cout << " Pit: 'I feel a draft'" << endl;

    cout << endl;
    cout << "Press Y to return to the main menu." << endl;
    cin >> wait;

}

// This function will place two bats throughout the map
// this ensures that the bats will not be place in the same
// room as another bat or the wumpus
void WumpusGame::PlaceBats() {
  srand (time(NULL));
  bool validRoom = false;
  while(!validRoom){
      batRoom1 = rand() % 20 + 1;
      if(batRoom1 != wumpusRoom)
          validRoom = true;
  }

  validRoom = false;
  while(!validRoom){
      batRoom2 = rand() % 20 + 1;
      if(batRoom2 != wumpusRoom && batRoom2 != batRoom1)
          validRoom = true;
  }
  bat1Start = batRoom1;
  bat2Start = batRoom2;
}

// this function randomly places the pits
// throughout the map excluding room 0
void WumpusGame::PlacePits() {
    srand (time(NULL));
    pitRoom1 = rand() % 20 + 1;
    pitRoom2 = rand() % 20 + 1;
}

// this function randomly places the wumpus in a room
// without being in room number 0
void WumpusGame::PlaceWumpus() {
    srand (time(NULL));
    int randomRoom = rand() % 20 + 1;
    wumpusRoom = randomRoom;
    wumpusStart = wumpusRoom;
}

// place the player in room 0
void WumpusGame::PlacePlayer() {
    startingPosition = 0;
    currentRoom = Move(0);
}

// This is a  method that checks if the user inputted a valid room to move to or not.
// The room number has to be between 0 and 20, but also must be adjacent to the current room.
bool WumpusGame::IsValidMove(int roomID) {
    if (roomID < 0) return false;
    if (roomID > numRooms) return false;
    if (!IsRoomAdjacent(currentRoom, roomID)) return false;

    return true;
}

// This method returns true if roomB is adjacent to roomA, otherwise returns false.
// It is a helper method that loops through the adjacentRooms array to check.
// It will be used throughout the app to check if we are next to the wumpus, bats, or pits
// as well as check if we can make a valid move.
bool WumpusGame::IsRoomAdjacent(int roomA, int roomB)
{
    for (int j = 0; j < 3; j++)
    {
        if (adjacentRooms[roomA][j] == roomB){
          return true;
        }
    }
    return false;
}

// This method moves the player to a new room and returns the new room. It performs no checks on its own.
int WumpusGame::Move(int newRoom)
{
    return newRoom;
}

// Inspects the current room.
// This method check for Hazards such as being in the same room as the wumpus, bats, or pits
// It also checks if you are adjacent to a hazard and handle those cases
// Finally it will just print out the room description
void WumpusGame::InspectCurrentRoom() {
    srand (time(NULL));
    if (currentRoom == wumpusRoom)
    {
        cout << "The Wumpus ate you!!!" << endl;
        cout << "LOSER!!!" << endl;
        PlayAgain();
    }
    else if (currentRoom == batRoom1 || currentRoom == batRoom2)
    {
        int roomBatsLeft = currentRoom;
        bool validNewBatRoom = false;
        bool isBatRoom = false;
        cout << "Snatched by superbats!!" << endl;
        if(currentRoom == pitRoom1 || currentRoom == pitRoom2)
            cout << "Luckily, the bats saved you from the bottomless pit!!" << endl;
        while(!isBatRoom){
            currentRoom = Move(rand() % 20 + 1);
            if(currentRoom != batRoom1 && currentRoom != batRoom2)
                isBatRoom = true;
        }
        cout << "The bats moved you to room ";
	      cout << currentRoom << endl;
        InspectCurrentRoom();

        if(roomBatsLeft == batRoom1){
            while(!validNewBatRoom){
                batRoom1 = rand() % 19 + 1;
                if(batRoom1 != wumpusRoom && batRoom1 != currentRoom)
                    validNewBatRoom = true;
            }
        } else {
            while(!validNewBatRoom){
                batRoom2 = rand() % 19 + 1;
                if(batRoom2 != wumpusRoom && batRoom2 != currentRoom)
                    validNewBatRoom = true;
            }
        }
    }
    else if(currentRoom == pitRoom1 || currentRoom == pitRoom2)
    {
        cout << "YYYIIIIIEEEEE.... fell in a pit!!!" << endl;
        cout << "GAME OVER LOSER!!!" << endl;
        PlayAgain();
    }
    else
    {
        cout << "You are in room ";
        cout << currentRoom << endl;
        if (IsRoomAdjacent(currentRoom, wumpusRoom)){
            cout << "You smell a horrid stench..." << endl;
        }
        if (IsRoomAdjacent(currentRoom, batRoom1) || IsRoomAdjacent(currentRoom, batRoom2)){
            cout << "Bats nearby..." << endl;
        }
        if (IsRoomAdjacent(currentRoom, pitRoom1) || IsRoomAdjacent(currentRoom, pitRoom2)){
            cout << "You feel a draft..." << endl;
        }
        cout << "Tunnels lead to rooms " << endl;
        for (int j = 0; j < 3; j++)
        {
            cout << adjacentRooms[currentRoom][j];
            cout << " ";
        }
        cout << endl;
    }
}

// Method accepts an int which is the command the user inputted.
// This method performs the action of the command or prints out an error.
void WumpusGame::PerformAction(int cmd) {
    int newRoom;
    switch (cmd)
    {

        case 1:
            cout << "Which room? " << endl;
            try
            {
                cin >> newRoom;
                // Check if the user inputted a valid room id, then simply tell the player to move there.
                if (IsValidMove(newRoom))
                {
                    currentRoom = Move(newRoom);
                    InspectCurrentRoom();
                }
                else
                {
                    cout << "You cannot move there." << endl;
                }
            }
            catch (...) // Try...Catch block will catch if the user inputs text instead of a number.
            {
                cout << "You cannot move there." << endl;
            }
            break;
        case 2:
            if(numArrows > 0){
                cout << "Which room? " << endl;
                try
                {
                    cin >> newRoom;
                    // Check if the user inputted a valid room id, then simply tell the player to move there.
                    if (IsValidMove(newRoom))
                    {
                        numArrows--;
                        if(newRoom == wumpusRoom){
                            cout << "ARGH.. Splat!" << endl;
                            cout << "Congratulations! You killed the Wumpus! You Win." << endl;
                            cout << "Press 'Y' to return to the main menu." << endl;
                            wumpusAlive = false;
                            cin >> newRoom;
                            cin.clear();
                            cin.ignore(10000, '\n');
                        }
                        else
                        {
                            cout << "Miss! But you startled the Wumpus" << endl;
                            MoveStartledWumpus(wumpusRoom);
                            cout << "Arrows Left: ";
                            cout << numArrows << endl;
                            if(wumpusRoom == currentRoom){
                                cout << "The wumpus attacked you! You've been killed." << endl;
                                cout << "Game Over!" << endl;
                                PlayAgain();
                            }

                        }
                    }
                    else
                    {
                        cout << "You cannot shoot there." << endl;
                    }
                }
                catch (...) // Try...Catch block will catch if the user inputs text instead of a number.
                {
                    cout << "You cannot shoot there." << endl;
                }
            } else
            {
                cout << "You do not have any arrows!" << endl;
            }
            break;
        case 3:
            cout << "Quitting the current game." << endl;
            playerAlive = false;
            break;
        default:
            cout << "You cannot do that. You can move, shoot, save or quit." << endl;
            break;
    }
}

// this function moves the wumpus randomly to a room that is adjacent to
// the wumpus's current position
void WumpusGame::MoveStartledWumpus(int roomNum){
    srand (time(NULL));
    int rando = rand() % 3;
    if(rando != 3)
        wumpusRoom = adjacentRooms[roomNum][rando];
}

// This restarts the map from the begiinning
void WumpusGame::PlayAgain(){
    char reply;
    cout << "Would you like to replay the same map? Enter Y to play again." << endl;
    cin >> reply;
    if(reply == 'y' || reply == 'Y'){
        currentRoom = startingPosition;
        wumpusRoom = wumpusStart;
        batRoom1 = bat1Start;
        batRoom2 = bat2Start;
        cout << "Try not to die this time. \n" << endl;
        InspectCurrentRoom();
    } else {
        playerAlive = false;
    }

}

// PlayGame() method starts up the game.
// It houses the main game loop and when PlayGame() quits the game has ended.
void WumpusGame::PlayGame()
{
	int choice;
  bool validChoice = false;

	cout << "Running the game..." << endl;

  // Initialize the game
	PlaceWumpus();
	PlaceBats();
	PlacePits();
	PlacePlayer();

	// game set up
	playerAlive = true;
	wumpusAlive = true;
	numArrows = 3;

    //Inspects the initial room
    InspectCurrentRoom();

    // Main game loop.
    while (playerAlive && wumpusAlive)
    {
        cout << "Enter an action choice." << endl;
        cout << "1) Move" << endl;
        cout << "2) Shoot" << endl;
        cout << "3) Quit" << endl;
        cout << ">>> ";

        do
        {
            validChoice = true;
            cout << "Please make a selection: ";
            try
            {
                cin >> choice;
                switch (choice)
                {
                    case 1:
                        PerformAction(choice);
                        break;
                    case 2:
                        PerformAction(choice);
                        break;
                    case 3:
                        PerformAction(choice);
                        break;
                    default:
                        validChoice = false;
                        cout << "Invalid choice. Please try again." << endl;
                        cin.clear();
		                    cin.ignore(10000, '\n');
                        break;
                }
            }
            catch (...)
            {
                validChoice = false;
                cout << "Invalid choice. Please try again." << endl;
                cin.clear();
                cin.ignore(10000, '\n');
            }

        } while (validChoice == false);
    }
}

// this function begins the game loop
void WumpusGame::StartGame() {

	srand (time(NULL));
	int choice;
  bool validChoice;
  bool keepPlaying;
  wumpusStart = bat1Start = bat2Start = -1;

  do {
      keepPlaying = true;
      cout << "Welcome to Hunt The Wumpus." << endl;
      cout << "1) Play Game" << endl;
      cout << "2) Print Instructions" << endl;
      cout << "3) Quit" << endl;

      do
      {
          validChoice = true;
          cout << "Please make a selection: ";
          try
          {
              cin >> choice;
              switch (choice)
              {
                  case 1:
                      PlayGame();
                      break;
                  case 2:
                      PrintInstructions();
                      break;
                  case 3:
                      cout << "Quitting." << endl;
                      keepPlaying = false;
                      break;
                  default:
                      validChoice = false;
                      cout << "Invalid choice. Please try again." << endl;
                      cin.clear();
                      cin.ignore(10000, '\n');
                      break;
              }
          }
          catch (...)
          {
              validChoice = false;
              cout << "Invalid choice. Please try again." << endl;
              cin.clear();
              cin.ignore(10000, '\n');
          }

      } while (validChoice == false);
  } while (keepPlaying);
}

int main() {
    // create wumpus game object
    WumpusGame game;
    // start the game
    game.StartGame();
}


<?php

function piece_wise($iban_all_digits) {

    $remainder = NULL;
    $slice = 9;

    for ($i=0; $i<strlen($iban_all_digits); $i=$i+$slice)
    {
        if ($i>0)
        {
            $slice = 7;
        }

        $part = $remainder . substr($iban_all_digits, $i, $slice);
        //echo "REMAINDER: " . $remainder . "
";
        //echo "PART: $part" . "
";
        $remainder = intval($part) % 97;
    }

return $remainder;

}

$iban = "GB82 WEST 1234 5698 7654 32";

//remove space
$iban = str_replace(' ', '', $iban);

//echo $iban; echo '
';
$iban_length = strlen($iban);
$country_code = substr($iban, 0, 2);

/*
    IBAN lengths are country specific
    full list available at
    https://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country
*/
$lengths = ['GB' => 22];

if ($lengths[$country_code] != $iban_length)
{
    exit ("IBAN length not valid for $country_code");
}

// 2. move first four characters to the end
$iban = substr($iban, 4) . substr($iban, 0, 4);

//3. Replace letters in IBAN with digits
//(A=10, B=11 ... Z=35)

$iban_arr = str_split($iban, 1);

$iban_all_digits = '';

foreach ($iban_arr as $key=>$value)
{
    if (ctype_alpha($value))
    {
        $value = ord($value) - 55;
    }
    $iban_all_digits = $iban_all_digits . $value;
}

if (piece_wise($iban_all_digits) === 1)
{
    echo "VALID IBAN!";
}

else
{
    echo "IBAN NOT VALID";
}


(setq *Sizes '((GB . 22) (CH . 21) (SA . 24)))

(de iban (Str)
   (let Lst
      (filter
         '((X) (not (sp? X)))
         (chop (uppc Str)) )
      (when
         (=
            (cdr (assoc (pack (head 2 Lst)) *Sizes))
            (length Lst) )
         (%
            (format
               (mapcar
                  '((X)
                     (if (upp? X)
                        (- (char X) 55)
                        X ) )
                  (append (nth Lst 5) (head 4 Lst)) ) )
            97 ) ) ) )

(for I '("sa03 8000 0000 6080 1016 7519"
         "CH9300762011623852957"
         "gb82west1234 56987654 32"
         "GB82WEST000")
   (if (= 1 (iban I))
      (println 'Valid)
      (println 'Invalid) ) )

(bye)


iWeb_Init()
pwb := iWeb_newGui(0, 0, 1000, 800)
iWeb_nav(pwb, "http://www.facebook.com/login.php?ref=pf")
iWeb_Term()
iWeb_complete(pwb)
inputbox, email, email
inputbox, pass, password
iWeb_setDomObj(pwb,"Email",email)
iWeb_setDomObj(pwb,"pass",pass)
iWeb_clickDomObj(pwb, "login")
return

#Include iweb.ahk
#Include COM.ahk
#Include COMinvokeDeep.ahk


OPTION TLS TRUE

website$ = "website.com"
username$ = "nobody"
password$ = "ignore"

OPEN website$ & ":443" FOR NETWORK AS conn
SEND "GET / HTTP/1.1\r\nHost: " & website$ & "\r\nAuthorization: Basic " & B64ENC$(username$ & ":" & password$) & "\r\n\r\n" TO conn

WHILE WAIT(conn, 2000)
    RECEIVE data$ FROM conn
    total$ = total$ & data$
    IF INSTR(data$, "</html>") THEN BREAK
WEND
CLOSE NETWORK conn

PRINT total$


function verifIBAN ([string]$ibanS)
{
if ($ibanS.Length -ne 27) {return $false} else
{
$ibanI="$($ibanS.Substring(4,23))$($ibanS.Substring(0,4))".ToUpper()
[int]$comptIBAN=0
$NumIBAN=""
while ($comptIBAN -lt 27)
    {
    if ([byte]$ibanI[$comptIBAN] -ge 65 -and [byte]$ibanI[$comptIBAN] -le 90)
        {
        $NumIban+=([byte]$ibanI[$comptIBAN]-55)
        } #pour transformer les lettres en chiffres (A=10, B=11...)
        else
        {
        $NumIban+=$ibanI[$comptIBAN]
        }
    $comptIBAN++
    }
    #cela fait un nombre de 30 chiffres : trop pour powershell, je découpe donc les 9 premiers caractères :
if ("$($NumIBAN.Substring(0,9)%97)$($NumIBAN.Substring(9,$NumIBAN.Length-9))"%97 -eq 1)
    {return $true}
    else
    {return $false}
}
} #fin fonction vérification IBAN / Stéphane RABANY 2018


EnableExplicit
Enumeration IBAN
  #IBAN_VAL
  #IBAN_SUM
  #IBAN_NOSPACE
  #IBAN_VAL_FORM
  #IBAN_SUM_FORM
EndEnumeration

NewMap CData.i()
Macro CCD(SIGN,LENGTH)
  CData(SIGN)=LENGTH
EndMacro

Procedure.s IBANForm(iban.s,form.i)
  Define fn.s, c.i
  fn=RemoveString(UCase(iban),Chr(32))
  If form=#IBAN_NOSPACE   :   ProcedureReturn fn  :   EndIf
  fn=Mid(fn,5)+Mid(fn,1,4)
  For c=65 To 90
    fn=ReplaceString(fn,Chr(c),Str(c-55))
  Next c
  If form=#IBAN_VAL_FORM  :   ProcedureReturn fn  :   EndIf
  fn=Left(fn,Len(fn)-2)+"00"
  If form=#IBAN_SUM_FORM  :   ProcedureReturn fn  :   EndIf
EndProcedure

Procedure.s m97iban(iban.s,calculate.i)
  Define i.i, part.s, rest.s
  Select calculate
    Case #IBAN_VAL : iban=IBANForm(iban,#IBAN_VAL_FORM)
    Case #IBAN_SUM : iban=IBANForm(iban,#IBAN_SUM_FORM)
  EndSelect
  For i=1 To Len(iban)  ; Validierung der Prüfsumme
    part+Mid(iban,i,1)
    If Val(rest+part)<97 : Continue : EndIf
    rest=Str((Val(rest+part)) %97)  : part=""
  Next
  Select calculate
    Case #IBAN_VAL : ProcedureReturn rest
    Case #IBAN_SUM : ProcedureReturn RSet(Str(98-Val(rest+part)),2,"0")
  EndSelect
EndProcedure

CCD("AL",28) : CCD("AD",24) : CCD("AT",20) : CCD("AZ",28) : CCD("BE",16) : CCD("BH",22) : CCD("BA",20)
CCD("BR",29) : CCD("BG",22) : CCD("CR",21) : CCD("HR",21) : CCD("CY",28) : CCD("CZ",24) : CCD("DK",18)
CCD("DO",28) : CCD("EE",20) : CCD("FO",18) : CCD("FI",18) : CCD("FR",27) : CCD("GE",22) : CCD("DE",22)
CCD("GI",23) : CCD("GR",27) : CCD("GL",18) : CCD("GT",28) : CCD("HU",28) : CCD("IS",26) : CCD("IE",22)
CCD("IL",23) : CCD("IT",27) : CCD("KZ",20) : CCD("KW",30) : CCD("LV",21) : CCD("LB",28) : CCD("LI",21)
CCD("LT",20) : CCD("LU",20) : CCD("MK",19) : CCD("MT",31) : CCD("MR",27) : CCD("MU",30) : CCD("MC",27)
CCD("MD",24) : CCD("ME",22) : CCD("NL",18) : CCD("NO",15) : CCD("PK",24) : CCD("PS",29) : CCD("PL",28)
CCD("PT",25) : CCD("RO",24) : CCD("SM",27) : CCD("SA",24) : CCD("RS",22) : CCD("SK",24) : CCD("SI",19)
CCD("ES",24) : CCD("SE",24) : CCD("CH",21) : CCD("TN",24) : CCD("TR",26) : CCD("AE",23) : CCD("GB",22)
CCD("VG",24)

DataSection
  IBANData:
  Data.s "GB82 WEST 1234 5698 7654 32"
  Data.s "GB82WEST12345698765432"
  Data.s "gb82 west 1234 5698 7654 32"
  Data.s "GB82 TEST 1234 5698 7654 32"
  Data.s "GR16 0110 1250 0000 0001 2300 695"
  Data.s "GB29 NWBK 6016 1331 9268 19"
  Data.s "SA03 8000 0000 6080 1016 7519"
  Data.s "CH93 0076 2011 6238 5295 7"
  Data.s "IL62 0108 0000 0009 9999 999"
  Data.s "IL62-0108-0000-0009-9999-999"
  Data.s "US12 3456 7890 0987 6543 210"
  Data.s "GR16 0110 1250 0000 0001 2300 695X"
  Data.s Chr(0)
EndDataSection

Define iban.s, cc.s
OpenConsole()
Restore IBANData
Repeat
  Read.s iban : If iban=Chr(0) : Break : EndIf
  Print("IBAN"+#TAB$+": "+LSet(iban,35,Chr(32))+#TAB$)
  cc=Left(IBANForm(iban,#IBAN_NOSPACE),2)
  If CData(cc)
    If Not CData()=Len(IBANForm(iban,#IBAN_NOSPACE)) : PrintN("[INCORRECT: LENGTH]") : Continue : EndIf
  Else
    PrintN("[INCORRECT: COUNTRY]") : Continue
  EndIf
  If Not Val(m97iban(iban,#IBAN_VAL))=1 : PrintN("[INCORRECT: MOD97]") : Continue : EndIf
  If Not Right(IBANForm(iban,#IBAN_VAL_FORM),2)=m97iban(iban,#IBAN_SUM)
    PrintN("[INCORRECT: CHECKSUM]") : Continue
  EndIf
  PrintN("[CORRECT]")
ForEver
Input()
End


#include <stdio.h>
#include <stdlib.h>
#include "curl/curl.h"

int
main(void)
{
        CURL *curl;
        char buffer[CURL_ERROR_SIZE];

        if ((curl = curl_easy_init()) != NULL) {
                curl_easy_setopt(curl, CURLOPT_URL, "https://user:[email protected]/");
                curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
                curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, buffer);
                if (curl_easy_perform(curl) != CURLE_OK) {
                        fprintf(stderr, "%s\n", buffer);
                        return EXIT_FAILURE;
                }
                curl_easy_cleanup(curl);
        }
        return EXIT_SUCCESS;
}


using System;
using System.Net;

class Program
{
    static void Main(string[] args)
    {
        var client = new WebClient();

        // credentials of current user:
        client.Credentials = CredentialCache.DefaultCredentials;
        // or specify credentials manually:
        client.Credentials = new NetworkCredential("User", "Password");

        var data = client.DownloadString("https://example.com");

        Console.WriteLine(data);
    }
}


(clj-http.client/get "https://somedomain.com"
                     {:basic-auth ["user" "pass"]})


program ShowHTTPSAuthenticated;

{$APPTYPE CONSOLE}

uses IdHttp, IdSSLOpenSSL;

var
  s: string;
  lHTTP: TIdHTTP;
  lIOHandler: TIdSSLIOHandlerSocketOpenSSL;
begin
  ReportMemoryLeaksOnShutdown := True;
  lHTTP := TIdHTTP.Create(nil);
  lIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  try
    lHTTP.Request.Username := 'USERNAME';
    lHTTP.Request.Password := 'PASSWD';
    lHTTP.IOHandler := lIOHandler;
    lHTTP.HandleRedirects := True;
    s := lHTTP.Get('https://SomeSecureSite.net/');
    Writeln(s);
  finally
    lHTTP.Free;
    lIOHandler.Free;
  end;
end.


import re

_country2length = dict(
    AL=28, AD=24, AT=20, AZ=28, BE=16, BH=22, BA=20, BR=29,
    BG=22, CR=21, HR=21, CY=28, CZ=24, DK=18, DO=28, EE=20,
    FO=18, FI=18, FR=27, GE=22, DE=22, GI=23, GR=27, GL=18,
    GT=28, HU=28, IS=26, IE=22, IL=23, IT=27, KZ=20, KW=30,
    LV=21, LB=28, LI=21, LT=20, LU=20, MK=19, MT=31, MR=27,
    MU=30, MC=27, MD=24, ME=22, NL=18, NO=15, PK=24, PS=29,
    PL=28, PT=25, RO=24, SM=27, SA=24, RS=22, SK=24, SI=19,
    ES=24, SE=24, CH=21, TN=24, TR=26, AE=23, GB=22, VG=24 )

def valid_iban(iban):
    # Ensure upper alphanumeric input.
    iban = iban.replace(' ','').replace('\t','')
    if not re.match(r'^[\dA-Z]+$', iban):
        return False
    # Validate country code against expected length.
    if len(iban) != _country2length[iban[:2]]:
        return False
    # Shift and convert.
    iban = iban[4:] + iban[:4]
    digits = int(''.join(str(int(ch, 36)) for ch in iban)) #BASE 36: 0..9,A..Z -> 0..35
    return digits % 97 == 1

if __name__ == '__main__':
    for account in ["GB82 WEST 1234 5698 7654 32", "GB82 TEST 1234 5698 7654 32"]:
        print('%s validation is: %s' % (account, valid_iban(account)))


V PLAUSIBILITY_RATIO = 2

F plausibility_check(comment, x, y)
   print("\n  Checking plausibility of: #.".format(comment))
   I x > :PLAUSIBILITY_RATIO * y
      print(‘    PLAUSIBLE. As we have counts of #. vs #., a ratio of #2.1 times’.format(x, y, Float(x) / y))
   E
      I x > y
         print(‘    IMPLAUSIBLE. As although we have counts of #. vs #., a ratio of #2.1 times does not make it plausible’.format(x, y, Float(x) / y))
      E
         print(‘    IMPLAUSIBLE, probably contra-indicated. As we have counts of #. vs #., a ratio of #2.1 times’.format(x, y, Float(x) / y))
   R x > :PLAUSIBILITY_RATIO * y

F simple_stats()
   V words = File(‘unixdict.txt’).read().split("\n")
   V cie = Set(words.filter(word -> ‘cie’ C word)).len
   V cei = Set(words.filter(word -> ‘cei’ C word)).len
   V not_c_ie = Set(words.filter(word -> re:‘(^ie|[^c]ie)’.search(word))).len
   V not_c_ei = Set(words.filter(word -> re:‘(^ei|[^c]ei)’.search(word))).len
   R (cei, cie, not_c_ie, not_c_ei)

F print_result(cei, cie, not_c_ie, not_c_ei)
   I (plausibility_check(‘I before E when not preceded by C’, not_c_ie, not_c_ei) & plausibility_check(‘E before I when preceded by C’, cei, cie))
      print("\nOVERALL IT IS PLAUSIBLE!")
   E
      print("\nOVERALL IT IS IMPLAUSIBLE!")
   print(‘(To be plausible, one count must exceed another by #. times)’.format(:PLAUSIBILITY_RATIO))

print(‘Checking plausibility of "I before E except after C":’)
V (cei, cie, not_c_ie, not_c_ei) = simple_stats()
print_result(cei, cie, not_c_ie, not_c_ei)


;;; File: HuntTheWumpus.lisp

(setf *random-state* (make-random-state t))
(defvar numRooms 20)
(defparameter Cave #2A((1 4 7)   (0 2 9)   (1 3 11)   (2 4 13)  (0 3 5)
               (4 6 14)  (5 7 16)    (0 6 8)   (7 9 17)   (1 8 10)
               (9 11 18) (2 10 12) (11 13 19)  (3 12 14)  (5 13 15)
               (14 16 19) (6 15 17)  (8 16 18) (10 17 19) (12 15 18)))

(defun PrintInstructions()
    (print " Welcome to 'Hunt the Wumpus'! " )
    (print " The wumpus lives in a cave of 20 rooms. Each room has 3 tunnels leading to")
    (print " other rooms. (Look at a dodecahedron to see how this works - if you don't know")
    (print " what a dodecahedron is, ask someone). ")
    (print " Hazards: ")  (terpri)
    (print " Bottomless pits - two rooms have bottomless pits in them. If you go there, you ")
    (print " fall into the pit (& lose!) ")  (terpri)
    (print " Super bats - two other rooms have super bats.  If you go there, a bat grabs you")
    (print " and takes you to some other room at random. (Which may be troublesome). Once the")
    (print " bat has moved you, that bat moves to another random location on the map.")  (terpri)  (terpri)

    (print " Wumpus")
    (print " The wumpus is not bothered by hazards (he has sucker feet and is too big for a")
    (print " bat to lift).  Usually he is asleep.  Two things wake him up: you shooting an")
    (print " arrow or you entering his room. If the wumpus wakes he moves (p=.75) one room or ")
    (print " stays still (p=.25). After that, if he is where you are, he eats you up and you lose!")  (terpri)

    (print " You ")  (terpri)
    (print " Each turn you may move, save or shoot an arrow using the commands move, save, & shoot.")
    (print " Moving: you can move one room (thru one tunnel).")
    (print " Arrows: you have 3 arrows. You lose when you run out. You aim by telling the")
    (print " computer the rooms you want the arrow to go to.  If the arrow can't go that way")
    (print " (if no tunnel), the arrow will not fire.")

    (print " Warnings")
    (print " When you are one room away from a wumpus or hazard, the computer says:")

    (print " Wumpus: 'I smell a wumpus'")
    (print " Bat: 'Bats nearby'")
    (print " Pit: 'I feel a draft'") (terpri)
    (print "Press Y to return to the main menu.")
    (defvar again)
    (setq goBack (read))
    (if (string= goBack "Y")
      (StartGame)
    )

)

(defun PlacePlayer()
  (setq startingPosition 0)
  (setq currentRoom (Move 0))

)

(defun PlaceWumpus()
  (setq wumpusRoom (round (+ 1 (random 19))))
  (setq wumpusStart wumpusRoom)
)

(defun PlacePits()
  (setq pitRoom1 (round (+ 1 (random 19))))
  (setq pitRoom2 (round (+ 1 (random 19))))
)

(defun PlaceBats()
    (let ((validRoom T))
      (loop while validRoom
        do
          (setq batRoom1 (round (+ 1 (random 19))))
          (if (/= batRoom1 wumpusRoom)
            (setf validRoom nil))))
    (let ((validRoom T))
      (loop while validRoom
        do
          (setq batRoom2 (round (+ 1 (random 19))))
          (if (and (/= batRoom2 wumpusRoom) (/= batRoom2 batRoom1))
            (setf validRoom nil))))
    (setq bat1Start batRoom1)
    (setq bat2Start batRoom2)
)

(defun Move (newRoom)
  (return-from Move newRoom)
)

(defun IsValidMove (roomID)
  (if (< roomID 0)
    (return-from IsValidMove nil)
  )
  (if (> roomID numRooms)
    (return-from IsValidMove nil)
  )
  (if (eq (IsRoomAdjacent currentRoom roomID) nil)
    (return-from IsValidMove nil)
  )
  (return-from IsValidMove T)
)

(defun IsRoomAdjacent (roomA roomB)
  (loop for j from 0 to 2
    do
    (if (= (aref Cave roomA j) roomB)
      (return-from IsRoomAdjacent T)
    )
  )
  (return-from IsRoomAdjacent nil)
)

(defun InspectCurrentRoom()
  (if (= currentRoom wumpusRoom)
    (progn
      (print "The Wumpus ate you!!!")
      (print "LOSER!!!")
      (StartGame)
    )
    (if (or (= currentRoom batRoom1) (= currentRoom batRoom2))
      (progn
        (defvar roomBatsLeft currentRoom)
        (defvar validNewBatRoom nil)
        (defvar isBatRoom nil)
        (print "Snatched by superbats!!")
        (if (or (= currentRoom pitRoom1) (= currentRoom pitRoom2))
            (print "Luckily, the bats saved you from the bottomless pit!!")
        )
        (loop while (eq isBatRoom nil)
          do
            (defvar rand)
            (setq rand (round (+ 1 (random 19))))
            (setq currentRoom rand)
            (if (and (/= currentRoom batRoom1) (/= currentRoom batRoom2))
              (setf isBatRoom T)
            )
        )
        (setf isBatRoom nil)
        (print "The bats moved you to room")
        (print currentRoom)
        (InspectCurrentRoom)
        (if (= roomBatsLeft batRoom1)
          (loop while (not validNewBatRoom)
            do
               (setq batRoom1 (round (+ 1 (random 19))))
               (if (and (/= batRoom1 wumpusRoom) (/= batRoom1 currentRoom))
                 (setq validNewBatRoom T)
               )
          )
          (loop while (not validNewBatRoom)
            do
               (setq batRoom2 (round (+ 1 (random 19))))
               (if (and (/= batRoom2 wumpusRoom) (/= batRoom2 currentRoom))
                 (setq validNewBatRoom T)
               )
          )
        )
      )
      (if (or (= currentRoom pitRoom1) (= currentRoom pitRoom2))
        (progn
          (print "YYYIIIIIIEEEEE.... fell in a pit!!!")
          (print "GAME OVER LOSER!!!")
          (StartGame)
        )
        (progn

            (print "You are in room")
            (print currentRoom)
            (if (eq (IsRoomAdjacent currentRoom wumpusRoom) T)
              (print "You smell a horrid stench...")
            )
            (if (or (eq (IsRoomAdjacent currentRoom batRoom1) T) (eq (IsRoomAdjacent currentRoom batRoom2) T))
              (print "Bats nearby...")
            )
            (if (or (eq (IsRoomAdjacent currentRoom pitRoom1) T) (eq (IsRoomAdjacent currentRoom pitRoom2) T))
              (print "You feel a draft")
            )
            (print "Tunnels lead to rooms")
            (loop for i from 0 to 2 do
                (print (aref Cave currentRoom i))
            )
            (terpri)

        )
      )
    )
  )
)

(defun moveStartledwumpus(roomNum)
    (defvar rando)
    (setq rando (random 4))
    (if (/= rando 3)
      (setq wumpusRoom (aref Cave roomNum rando))
    )
)

(defun PreformAction(cmd)
  (defvar newRoom)
  (case cmd
    (1
      (print "Which room?")
      (setq newRoom (read))
      (if (eq (IsValidMove newRoom) T)
        (progn
          (setq currentRoom (Move newRoom))
          (InspectCurrentRoom)
        )
        (print "You cannot move there")
      )
    )
    (2
      (if (> numArrows 0)
        (progn
          (print "Which room?")
          (setq newRoom (read))
          (if (eq (IsValidMove newRoom) T)
            (progn
              (setq numArrows (- numArrows 1))
              (if (= newRoom wumpusRoom)
                (progn
                  (print "ARGH.. Splat!")
                  (print "Congratulations! You killed the Wumpus! You Win.")
                  (setq wumpusAlive nil)
                  (terpri)
                  ;;;(StartGame)
                )
                (progn
                  (print "Miss! but you startled the Wumpus")
                  (moveStartledwumpus wumpusRoom)
                  (print "Arrows Left")
                  (print numArrows)
                  (if (= wumpusRoom currentRoom)
                    (progn
                    (print "The wumpus attacked you! You've been killed.")
                    (print "Game Over!")
                    (terpri)
                    (StartGame)
                    )
                  )

                )
              )
            )
            (print "You cannot shoot there")
          )
        )
        (progn
           (print "You do not have any arrows!")
           ;;;(print "Game Over!")
           (terpri)
           ;;;(StartGame)

        )
      )
    )
    (3
      (print "Quiting the current game.")
      (setq playerAlive nil)
      (terpri)
      ;;;(StartGame)
    )
    (otherwise
      (print "You cannot do that. You can move, shoot, save or quit.")
    )
  )

)

(defun Playgame()
  (defvar choice)
  (defvar validChoice nil)

  (print "Running the game...")

  ;;;Initialize the game
  (PlaceWumpus)
  (PlaceBats)
  (PlacePits)
  (PlacePlayer)

  ;;;game set up
  (setq playerAlive T)
  (setq wumpusAlive T)
  (setq numArrows 3)

  ;;;InspectCurrentRoom
  (InspectCurrentRoom)

  ;(loop while (and (eq playerAlive T) (eq wumpusAlive T))
  ;  do
  (loop do
      (print "Enter an action choice")
      (print "1) Move")
      (print "2) Shoot")
      (print "3) Quit")
      (print ">>>")

;    (loop while (eq validChoice nil)
     (loop do
        (setq validChoice T)
        (defvar choice)
        (setq choice (read))
        (case choice
          (1 (PreformAction choice))
          (2 (PreformAction choice))
          (3 (PreformAction choice))
          (otherwise
            (setq validChoice nil)
            (print "Invalid choice. Please try again.")
          )
      )

  while (eq validChoice nil))
 while (and (eq playerAlive T) (eq wumpusAlive T)))
)

(defun StartGame()

  (let ((keepPlaying T))
    (loop while keepPlaying
      do
      (print "Welcome to Hunt The Wumpus.")
      (print "1) Play Game")
      (print "2) Print Instructions")
      (print "3) Quit")
      (let ((validChoice T))
        (loop while validChoice
          do
          (print "Please make a selection") (terpri)
          (defvar selection)
          (setq selection (read))
          (case selection
            (1 (Playgame))
            (2 (PrintInstructions))
            (3 (setf keepPlaying nil))
            (otherwise
              (setq validChoice nil)
              (print "Invalid choice. Please try again.")
            )

          )

          (setf validChoice nil)

        )

      )
      (setf keepPlaying nil)
    )
  )

)
(StartGame)


data 7,13,19,12,18,20,16,17,19,11,14,18,13,15,18,9,14,16,1,15,17,10,16,20,6,11,19,8,12,17
data 4,9,13,2,10,15,1,5,11,4,6,20,5,7,12,3,6,8,3,7,10,2,4,5,1,3,9,2,8,14
data 1,2,3,1,3,2,2,1,3,2,3,1,3,1,2,3,2,1

randomize timer

dim shared as ubyte i, j, tunnel(1 to 20, 1 to 3), lost(1 to 6, 1 to 3), targ
dim as ubyte player = int(rnd*20)+1, wump, bat1, bat2, pit1, pit2, d6, epi
dim as ubyte arrows = 5
dim as string choice

for i = 1 to 20    'set up rooms
    for j = 1 to 3
         read tunnel(i,j)
    next j
next i

for i = 1 to 6   'set up list of permuatations of 1-2-3
    for j = 1 to 3
        read lost(i,j)
    next j
next i

'place wumpus, bats, and pits
do
    wump = int(rnd*20)+1
loop until wump <> player
do
    pit1 = int(rnd*20)+1
loop until pit1 <> player
do
    pit2 = int(rnd*20)+1
loop until pit2 <> player andalso pit2 <> pit1
do
    bat1 = int(rnd*20)+1
loop until bat1 <> player andalso bat1 <> pit1 andalso bat1 <> pit2
do
    bat2 = int(rnd*20)+1
loop until bat2 <> player andalso bat2 <> pit1 andalso bat2 <> pit2 andalso bat2 <> bat1

do
    if player = wump then
        print "You have been eaten by the Wumpus!"
        goto defeat
    end if
    if player = pit1 or player = pit2 then
        print "Aaaaaaaaaaa! You have fallen into a bottomless pit."
        goto defeat
    end if
    if player = bat1 or player = bat2 then
        print "A bat has carried you into another empty room."
        do
            player = (rnd*20)+1
        loop until player <> wump andalso player <> pit1 andalso player <> pit2 andalso player <> bat1 andalso player <> bat2
    end if
    print using "You are in room ##. There are tunnels to rooms ## ## and ##."; player; tunnel(player,1); tunnel(player,2); tunnel(player,3)
    print using "You have ## arrows left."; arrows
    d6 = 1 + int(rnd*6)
    for i = 1 to 3
        epi = tunnel(player,lost(d6,i))
        if epi = wump then
            print "You smell something terrible nearby."
        end if
        if epi = bat1 or epi = bat2 then
            print "You hear a rustling."
        end if
        if epi = pit1 or epi = pit2 then
            print "You feel a cold wind blowing from a nearby cavern."
        end if
    next i
    choices:
    print
    print "What would you like to do? Type A to shoot an arrow, or a number to move to another room."
    input choice
    select case left(choice,1)
        case "a", "A"
            input "Which room would you like to shoot into? ", targ
            if targ = player then
                print "You shot yourself. Why would you want to do such a thing?"
                goto defeat
            end if
            if targ = wump then goto victory
            if targ = tunnel(player,1) or targ = tunnel(player,2) or targ = tunnel(player,3) then
                print "The Wumpus awakes!"
                if rnd < 0.75 then
                    print "He moves to a nearby cavern."
                    wump = tunnel(wump, 1+int(rnd*3))
                else
                    print "He goes back to sleep."
                end if
            else
                print "You can't shoot that room from here."
                goto choices
            end if
            arrows -= 1
        case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
            targ = valint(choice)
            if targ = player then print "You are already there."
            if targ = tunnel(player,1) or targ = tunnel(player,2) or targ = tunnel(player,3) then
                print using "You walk to room ##"; targ
                player = targ
            else
                print "You can't get there from here."
            end if
        case else
            print "You are making no sense."
    end select
loop until arrows = 0
print "You have run out of arrows!"
defeat:
print "You lose! Better luck next time."
end
victory:
print "You have slain the Wumpus!"
print "You have won!"
end


package main

import (
    "encoding/base64"
    "io"
    "log"
    "net/http"
    "strings"
)

const userPass = "rosetta:code"
const unauth = http.StatusUnauthorized

func hw(w http.ResponseWriter, req *http.Request) {
    auth := req.Header.Get("Authorization")
    if !strings.HasPrefix(auth, "Basic ") {
        log.Print("Invalid authorization:", auth)
        http.Error(w, http.StatusText(unauth), unauth)
        return
    }
    up, err := base64.StdEncoding.DecodeString(auth[6:])
    if err != nil {
        log.Print("authorization decode error:", err)
        http.Error(w, http.StatusText(unauth), unauth)
        return
    }
    if string(up) != userPass {
        log.Print("invalid username:password:", string(up))
        http.Error(w, http.StatusText(unauth), unauth)
        return
    }
    io.WriteString(w, "Goodbye, World!")
}

func main() {
    http.HandleFunc("/", hw)
    log.Fatal(http.ListenAndServeTLS(":8080", "cert.pem", "key.pem", nil))
}


{-# LANGUAGE OverloadedStrings #-}

module Main (main) where

import           Data.Aeson (Value)
import           Data.Default.Class (def)
import           Network.HTTP.Req
                    ( (/:)
                    , GET(..)
                    , NoReqBody(..)
                    , basicAuth
                    , https
                    , jsonResponse
                    , req
                    , responseBody
                    , runReq
                    )

main :: IO ()
main = do
    response <- runReq def $ req
            GET
            (https "httpbin.org" /: "basic-auth" /: "someuser" /: "somepassword")
            NoReqBody
            jsonResponse
            (basicAuth "someuser" "somepassword")
    print (responseBody response :: Value)


using HTTP, HTTP.IOExtras, JSON, MusicProcessing
HTTP.open("POST", "http://music.com/play") do io
    write(io, JSON.json([
        "auth" => "12345XXXX",
        "song_id" => 7,
    ]))
    r = startread(io)
    @show r.status
    while !eof(io)
        bytes = readavailable(io)
        play(bytes)
    end
end


// version 1.2.0

import java.net.Authenticator
import java.net.PasswordAuthentication
import javax.net.ssl.HttpsURLConnection
import java.net.URL
import java.io.InputStreamReader
import java.io.BufferedReader

object PasswordAuthenticator : Authenticator() {
    override fun getPasswordAuthentication() =
        PasswordAuthentication ("username", "password".toCharArray())
}

fun main(args: Array<String>) {
    val url = URL("https://somehost.com")
    val con = url.openConnection() as HttpsURLConnection
    Authenticator.setDefault(PasswordAuthenticator)
    con.allowUserInteraction = true
    con.connect()
    val isr = InputStreamReader(con.inputStream)
    val br = BufferedReader(isr)
    while (true) {
        val line = br.readLine()
        if (line == null) break
        println(line)
    }
}


	;;; I before E, except after C
fcb1:	equ	5Ch	; FCB 1 (populated by file on command line)
dma:	equ	80h	; Standard DMA location
bdos:	equ	5	; CP/M entry point
puts:	equ	9	; CP/M call to write a string to the console
fopen:	equ	0Fh	; CP/M call to open a file
fread:	equ	14h	; CP/M call to read from a file
CR:	equ	13
LF:	equ	10
EOF:	equ	26
	org	100h
	;;;	Open the file given on the command line
	lxi	d,fcb1
	mvi	c,fopen
	call	bdos
	inr	a		; FF = error
	jz	die
	;;;	We can only read one 128-byte block at a time, and the file
	;;;	will not fit in memory (max 64 k). So there are two things
	;;;	going on here: we copy from the block into a word buffer
	;;;	until we see the end of a line, at which point we process
	;;;	the word. In the meantime, if while copying we reach the end
	;;;	of the block, we read the next block.
	lxi	b,curwrd	; Word pointer
block:	push	b		; Keep word pointer while reading
	lxi	d,fcb1		; Read a block from the file
	mvi	c,fread
	call	bdos
	pop	b		; Restore word pointer
	dcr	a		; 1 = EOF
	jz	done
	inr	a		; otherwise, <>0 = error
	jnz	die
	lxi	h,dma		; Start reading at DMA
char:	mov	a,m		; Get character
	cpi	EOF		; If it's an EOF character, we're done
	jz	done
	stax	b		; Store character in current word
	inx	b
	cpi	LF		; If it's LF, then we've got a full word
	cz	word		; Process the word
	inr 	l		; Go to next character
	jz	block		; If we're done with this block, get next one
	jmp	char
	;;;	When done, report the statistics
done:	lxi	d,scie		; CIE
	call	sout
	lhld	cie
	call	puthl
	lxi	d,sxie		; xIE
	call	sout
	lhld	xie
	call	puthl
	lxi	d,scei		; CEI
	call	sout
	lhld	cei
	call	puthl
	lxi	d,sxei		; xEI
	call	sout
	lhld	xei
	call	puthl
	;;;	Then say what is and isn't plausible
	lxi 	d,s_ienc	; I before E when not preceded by C
	call	sout		; plausible if 2*xIE>CIE
	lhld	cie
	xchg
	lhld	xie
	call	pplaus
	lxi	d,s_eic		; E before I when preceded by C
	call	sout		; plausible if 2*CEI>xEI
	lhld	xei
	xchg
	lhld	cei
	;;;	If HL = amount of words with feature, and
	;;;	DE = amount of words with opposit feature, then print
	;;;	'(not) plausible', as appropriate.
pplaus:	dad	h		; 2 * feature
	mov	a,d		; Compare high byte
	cmp	h
	jc	plaus		; If 2*H>D then plausible
	mov	a,e		; Otherwise, compare low byte
	cmp	l
	jc	plaus		; If 2*L>E then plausible
	lxi	d,snop		; Otherwise, not plausible
	jmp	sout
plaus:	lxi	d,splau
	jmp	sout
	;;;	Process a word
word:	push	h		; Save file read address
	xra	a		; Zero out end of word
	stax	b
	dcx	b
	lxi	h,curwrd	; Scan word
start:	mov	a,m		; Get current character
	inx	h		; Move pointer ahead
	ana	a		; If zero,
	jz	w_end		; we're done
	cpi	'c'		; Did we find a 'c'?
	jz	findc
	cpi	'e'		; Otherwise, did we find 'e'?
	jz	finde
	cpi	'i'		; Otherwise, did we find 'i'?
	jz	findi
	jmp	start		; Otherwise, keep going
	;;;	We found an 'e'
finde:	mov	a,m		; Get following character
	cpi	'i'		; Is it 'i'?
	jnz	start		; If not, keep going
	inx	h		; Otherwise, move past it,
	xchg			; keep pointer in DE,
	lhld	xie		; We found ie without c
	inx	h
	shld	xie
	xchg
	jmp	start
	;;;	We found an 'i'
findi:	mov	a,m		; Get following character
	cpi	'e'		; Is it 'e'?
	jnz	start		; If not, keep going
	inx	h		; Otherwise, move past it,
	xchg			; keep pointer in DE,
	lhld	xei		; We found ei without c
	inx	h
	shld	xei
	xchg
	jmp	start
	;;;	We found a 'c'
findc:	mov	a,m		; Get following character
	cpi	'e'		; Is it 'e'?
	jz	findce		; Then we have 'ce'
	cpi	'i'		; Is it 'i'?
	jz	findci		; Then we have 'ci'
	jmp	start		; Otherwise, just keep going
findce:	mov	d,h		; set DE = start of 'e?'
	mov	e,l
	inx	d		; Get next character
	ldax	d
	cpi	'i'		; Is it 'i'?
	jnz	start		; If not, do nothing
	lhld	cei		; But if so, we found 'cei'
	inx	h		; Increment the counter
	shld	cei
	xchg			; Keep scanning _after_ the 'cei'
	inx	h
	jmp	start
findci:	mov	d,h		; set DE = start of 'i?'
	mov	e,l
	inx	d		; Get next character
	ldax	d
	cpi	'e'		; Is it 'e'?
	jnz	start		; If not, do nothing
	lhld	cie		; But if so, we found 'cie'
	inx	h		; Increment the counter
	shld	cie
	xchg			; Keep scanning _after_ the 'cie'
	inx	h
	jmp	start
w_end:	lxi	b,curwrd	; Set word pointer to beginning
	pop	h		; Restore file read address
	ret
	;;;	Print error message and stop the program
die:	lxi	d,errmsg
	mvi	c,puts
	call	bdos
	rst	0
	;;;	Print string
sout:	mvi	c,puts
	jmp	bdos
	;;;	Print HL to the console as a decimal number
puthl:	push	h
	lxi	h,num
	xthl
	lxi	b,-10
dgt:	lxi	d,-1
clcdgt:	inx	d
	dad	b
	jc	clcdgt
	mov	a,l
	adi	10+'0'
	xthl
	dcx	h
	mov	m,a
	xthl
	xchg
	mov	a,h
	ora	l
	jnz	dgt
	pop	d
	mvi	c,puts
	jmp	bdos
errmsg:	db	'Error$'	; Good enough
s_ienc:	db	'I before E when not preceded by C:$'
s_eic:	db	'E before I when preceded by C:$'
snop:	db	' not'
splau:	db	' plausible',CR,LF,'$'
scie:	db	'CIE: $'	; Report strings
sxie:	db	'xIE: $'
scei:	db	'CEI: $'
sxei:	db	'xEI: $'
	db	'00000'
num:	db	CR,LF,'$'	; Space for number
	;;;	Counters
xie:	dw	0		; I before E when not preceded by C
cie:	dw	0		; I before E when preceded by C
cei:	dw	0		; E before I when preceded by C
xei:	dw	0		; E before I when not preceded by C
curwrd:	equ	$		; Current word stored here