/* ARM assembly Raspberry PI  */
/*  program MD5.s   */

/* REMARK 1 : this program use routines in a include file
   see task Include a file language arm assembly
   for the routine affichageMess conversion10
   see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes                       */
/************************************/
.include "../constantes.inc"

.equ LGHASH, 16                  // result length
.equ ZWORKSIZE,        1000      // work area size

/*******************************************/
/* Structures                               */
/********************************************/
/* example structure  variables  */
    .struct  0
var_a:                     // a
    .struct  var_a + 4
var_b:                     // b
    .struct  var_b + 4
var_c:                     // c
    .struct  var_c + 4
var_d:                     // d
    .struct  var_d + 4
/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessTest1:           .asciz "abc"
szMessTest4:           .asciz "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
szMessTest2:           .asciz "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
szMessTest3:           .asciz "abcdefghijklmnopqrstuvwxyz"
szMessFinPgm:          .asciz "Program End ok.\n"
szMessResult:          .asciz "Result for "
szMessResult1:         .asciz " => "
szMessSizeError:       .asciz "\033[31mWork area too small !! \033[0m \n"
szCarriageReturn:   .asciz "\n"

.align 4
/* array constantes K */
tbConstK:  .int 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee
           .int 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501
           .int 0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be
           .int 0x6b901122,0xfd987193,0xa679438e,0x49b40821
           .int 0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa
           .int 0xd62f105d,0x2441453,0xd8a1e681,0xe7d3fbc8
           .int 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed
           .int 0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a
           .int 0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c
           .int 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70
           .int 0x289b7ec6,0xeaa127fa,0xd4ef3085,0x4881d05
           .int 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665
           .int 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039
           .int 0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1
           .int 0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1
           .int 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391

/* array rotation coef R */
tbRotaR:   .int  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22,  7, 12, 17, 22
           .int  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20,  5,  9, 14, 20
           .int  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23,  4, 11, 16, 23
           .int  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21,  6, 10, 15, 21

tbConstH:            .int 0x67452301       // H0
                     .int 0xEFCDAB89       // H1
                     .int 0x98BADCFE       // H2
                     .int 0x10325476       // H3

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4
sZoneConv:                   .skip 24
tbH:                         .skip 4 * 4         @ 4 variables H
tbabcd:                      .skip 4 * 4         @ 4 variables a b c d
sZoneTrav:                   .skip 1000
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main
main:                           @ entry of program

    ldr r0,iAdrszMessTest1
    bl computeExemple

    ldr r0,iAdrszMessTest2
    bl computeExemple

    ldr r0,iAdrszMessTest3
    bl computeExemple

    ldr r0,iAdrszMessTest4
    bl computeExemple

    ldr r0,iAdrszMessFinPgm
    bl affichageMess            @ display message

100:                            @ standard end of the program
    mov r0, #0                  @ return code
    mov r7, #EXIT               @ request to exit program
    svc #0                      @ perform the system call

iAdrszCarriageReturn:     .int szCarriageReturn
iAdrszMessResult:         .int szMessResult
iAdrszMessResult1:        .int szMessResult1
iAdrszMessTest1:          .int szMessTest1
iAdrszMessTest2:          .int szMessTest2
iAdrszMessTest3:          .int szMessTest3
iAdrszMessTest4:          .int szMessTest4
iAdrsZoneTrav:            .int sZoneTrav
iAdrsZoneConv:            .int sZoneConv
iAdrszMessFinPgm:         .int szMessFinPgm
iAdrszMessSizeError:      .int szMessSizeError
/***********************************************/
/*     compute exemple                         */
/***********************************************/
/* r0 contains the address of the message */
computeExemple:
    push {r1,lr}         @ save  registres
    mov r1,r0
    bl computeMD5        @ call routine MD5

    ldr r0,iAdrszMessResult
    bl affichageMess
    mov r0,r1
    bl affichageMess
    ldr r0,iAdrszMessResult1
    bl affichageMess
    ldr r0, iAdrtbH
    bl displayMD5

100:
    pop {r1,pc}           @ restaur registers

/******************************************************************/
/*     compute MD5                         */
/******************************************************************/
/* r0 contains the address of the message */
computeMD5:
    push {r1-r12,lr}         @ save  registres
    ldr r1,iAdrsZoneTrav
    mov r2,#0                @ counter length
1:                           @ copy string in work area
    cmp r2,#ZWORKSIZE        @ maxi ?
    bge 99f                  @ error
    ldrb r3,[r0,r2]
    strb r3,[r1,r2]
    cmp r3,#0
    addne r2,r2,#1
    bne 1b
    lsl r6,r2,#3             @ initial message length in bits
    mov r3,#0b10000000       @ add bit 1 at end of string
    strb r3,[r1,r2]
    add r2,r2,#1             @ length in bytes
    lsl r4,r2,#3             @ length in bits
    mov r3,#0
2:
    lsr r5,r2,#6
    lsl r5,r5,#6
    sub r5,r2,r5
    cmp r5,#56
    beq 3f                   @ yes -> end add
    strb r3,[r1,r2]          @ add zero at message end
    add r2,#1                @ increment lenght bytes
    add r4,#8                @ increment length in bits
    b 2b
3:
    str r6,[r1,r2]           @ and store length at end
    add r5,r2,#4
    str r3,[r1,r5]           @ store zero in hight bits for 64 bits

    ldr r7,iAdrtbConstH      @ constantes H address
    ldr r4,iAdrtbH           @ start area H
    mov r5,#0
4:                           @ init array H with start constantes
    ldr r6,[r7,r5,lsl #2]    @ load constante
    str r6,[r4,r5,lsl #2]    @ and store
    add r5,r5,#1
    cmp r5,#4
    blt 4b
                             @ split into block of 64 bytes
    add r2,#4                @  TODO : à revoir
    lsr r4,r2,#6             @ blocks number

    ldr r0,iAdrtbH             @ variables H
    ldr r1,iAdrsZoneTrav
    ldr r5,iAdrtbConstK
    ldr r3,iAdrtbRotaR
    ldr r8,iAdrtbabcd
    mov r7,#0                @ n° de block et r1 contient l adresse zone de travail
5:                           @ begin loop of each block of 64 bytes
    add r2,r1,r7,lsl #6            @  compute block begin  indice * 4 * 16
    mov r6,#0                @ indice t
   /* COMPUTING THE MESSAGE DIGEST */
    /* r0  variables H address */
    /* r1  work area  */
    /* r2  block work area begin address  */
    /* r3  address constantes rotate */
    /* r4  block number  */
    /* r5  constance K address */
    /* r6  counter t */
    /* r7  block counter */
    /* r8  addresse variables a b c d   */
                                   @ init variable a b c d with variables H
    mov r10,#0
6:                                 @ loop init
    ldr r9,[r0,r10,lsl #2]         @ variables H
    str r9,[r8,r10,lsl #2]         @ variables a b c d
    add r10,r10,#1
    cmp r10,#4
    blt 6b

7:                                 @ loop begin
    cmp r6,#15
    bgt 8f
                                   @ cas 1 f := (b et c) ou ((non b) et d)
                                   @ g := i
    ldr r9,[r8,#var_b]
    ldr r10,[r8,#var_c]
    and r12,r10,r9
    mvn r9,r9
    ldr r10,[r8,#var_d]
    and r11,r9,r10
    orr r12,r12,r11                @ f
    mov r9,r6                      @ g
    b 11f
8:
    cmp r6,#31
    bgt 9f
                                   @ f := (d et b) ou ((non d) et c)
                                   @ g := (5×i + 1) mod 16
    ldr r9,[r8,#var_b]
    ldr r10,[r8,#var_d]
    and r12,r10,r9
    mvn r10,r10
    ldr r9,[r8,#var_c]
    and r11,r9,r10
    orr r12,r12,r11                @ f
    mov r9,#5
    mul r9,r6,r9
    add r9,r9,#1
    lsr r10,r9,#4
    lsl r10,r10,#4
    sub r9,r9,r10                  @ g

    b 11f
9:
    cmp r6,#47
    bgt 10f
                                   @ f := b xor c xor d
                                   @ g := (3×i + 5) mod 16
    ldr r9,[r8,#var_b]
    ldr r10,[r8,#var_c]
    eor r12,r10,r9
    ldr r10,[r8,#var_d]
    eor r12,r12,r10                @ f
    mov r9,#3
    mul r9,r6,r9
    add r9,r9,#5
    lsr r10,r9,#4
    lsl r10,r10,#4
    sub r9,r9,r10                  @ g
    b 11f
10:
                                   @ f := c xor (b ou (non d))
                                   @ g := (7×i) mod 16
    ldr r10,[r8,#var_d]
    mvn r12,r10
    ldr r10,[r8,#var_b]
    orr r12,r12,r10
    ldr r10,[r8,#var_c]
    eor r12,r12,r10                @ f
    mov r9,#7
    mul r9,r6,r9
    lsr r10,r9,#4
    lsl r10,r10,#4
    sub r9,r9,r10                  @ g

11:
    ldr r10,[r8,#var_d]
    mov r11,r10                    @ save old d
    ldr r10,[r8,#var_c]
    str r10,[r8,#var_d]            @ new d = c
    ldr r10,[r8,#var_b]
    str r10,[r8,#var_c]            @ new c = b
    ldr r10,[r8,#var_a]
    add r12,r12,r10                @ a + f
    ldr r10,[r2,r9,lsl #2]
    add r12,r12,r10                @ + valeur bloc g
    ldr r10,[r5,r6,lsl #2]
    add r12,r12,r10                @ + valeur constante K de i
    ldr r10,[r3,r6,lsl #2]         @ rotate left value
    rsb r10,r10,#32                @ compute right rotate
    ror r12,r12,r10
    ldr r10,[r8,#var_b]
    add r12,r12,r10
    str r12,[r8,#var_b]            @ new b
    str r11,[r8,#var_a]            @ new a = old d

    add r6,r6,#1
    cmp r6,#63
    ble 7b
                                   @ maj area H
    ldr r10,[r0]                   @ H0
    ldr r11,[r8,#var_a]
    add r10,r10,r11                @ + a
    str r10,[r0]
    ldr r10,[r0,#4]                @ H1
    ldr r11,[r8,#var_b]
    add r10,r10,r11                @ + b
    str r10,[r0,#4]
    ldr r10,[r0,#8]                @ H2
    ldr r11,[r8,#var_c]
    add r10,r10,r11                @ + c
    str r10,[r0,#8]
    ldr r10,[r0,#12]               @ H3
    ldr r11,[r8,#var_d]
    add r10,r10,r11                @ + d
    str r10,[r0,#12]

                                 @ loop other block
    add r7,r7,#1                 @ increment block
    cmp r7,r4                    @ maxi ?
    ble 5b

    mov r9,#0                    @ reverse bytes loop
12:
    ldr r10,[r0,r9,lsl #2]
    rev r10,r10                  @ reverse bytes
    str r10,[r0,r9,lsl #2]
    add r9,r9,#1
    cmp r9,#LGHASH / 4
    blt 12b
    mov r0,#0                    @ routine OK
    b 100f
99:                              @ size error
    ldr r0,iAdrszMessSizeError
    bl affichageMess
    mov r0,#-1                   @ error routine

100:
    pop {r1-r12,pc}              @ restaur registers
iAdrtbConstH:        .int tbConstH
iAdrtbConstK:        .int tbConstK
iAdrtbRotaR:         .int tbRotaR
iAdrtbH:             .int tbH
iAdrtbabcd:          .int tbabcd

/*************************************************/
/*     display hash  MD5                         */
/*************************************************/
/* r0 contains the address of hash  */
displayMD5:
    push {r1-r3,lr}                @ save  registres
    mov r3,r0
    mov r2,#0
1:
    ldr r0,[r3,r2,lsl #2]          @ load 4 bytes
    ldr r1,iAdrsZoneConv
    bl conversion16                @ conversion hexa
    ldr r0,iAdrsZoneConv
    bl affichageMess
    add r2,r2,#1
    cmp r2,#LGHASH / 4
    blt 1b                         @ and loop
    ldr r0,iAdrszCarriageReturn
    bl affichageMess               @ display message
100:
    pop {r1-r3,lr}                 @ restaur registers
    bx lr                          @ return
/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../affichage.inc"


data := "abc"
MsgBox % MD5(data,StrLen(data)) ; 900150983cd24fb0d6963f7d28e17f72

MD5( ByRef V, L=0 ) {
 VarSetCapacity( MD5_CTX,104,0 ), DllCall( "advapi32\MD5Init", Str,MD5_CTX )
 DllCall( "advapi32\MD5Update", Str,MD5_CTX, Str,V, UInt,L ? L : VarSetCapacity(V) )
 DllCall( "advapi32\MD5Final", Str,MD5_CTX )
 Loop % StrLen( Hex:="123456789ABCDEF0" )
  N := NumGet( MD5_CTX,87+A_Index,"Char"), MD5 .= SubStr(Hex,N>>4,1) . SubStr(Hex,N&15,1)
Return MD5
}


PRAGMA INCLUDE <stdio.h>
PRAGMA INCLUDE <stdlib.h>
PRAGMA INCLUDE <string.h>
PRAGMA INCLUDE <openssl/md5.h>
PRAGMA LDFLAGS -lcrypto -lm -w

DECLARE result TYPE unsigned char *
DECLARE string TYPE const char *

string = "Rosetta code"
strlenght = LEN(string)

result = MD5( string, strlenght , 0)

FOR  i = 0 TO MD5_DIGEST_LENGTH-1
    PRINT   result[i] FORMAT "%02x"
NEXT


print MD5("")
print MD5("a")
print MD5("abc")
print MD5("message digest")
print MD5("abcdefghijklmnopqrstuvwxyz")
print MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
print MD5("12345678901234567890123456789012345678901234567890123456789012345678901234567890")
end


-V
   UL = ‘╔’
   UC = ‘╦’
   UR = ‘╗’
   LL = ‘╚’
   LC = ‘╩’
   LR = ‘╝’
   HB = ‘═’
   VB = ‘║’

   Mayan = [‘    ’,
            ‘ ∙  ’,
            ‘ ∙∙ ’,
            ‘∙∙∙ ’,
            ‘∙∙∙∙’]

   M0 = ‘ @  ’
   M5 = ‘────’

F toBase20(=n)
   V result = [n % 20]
   n I/= 20
   L n != 0
      result [+]= n % 20
      n I/= 20
   R reversed(result)

F toMayanNumeral(=d)
   V result = [Mayan[0], Mayan[0], Mayan[0], Mayan[0]]
   I d == 0
      result[3] = :M0
      R result

   L(i) (3..0).step(-1)
      I d >= 5
         result[i] = :M5
         d -= 5
      E
         result[i] = Mayan[d]
         L.break

   R result

F draw(mayans)
   V idx = mayans.len - 1

   print(:UL, end' ‘’)
   L(i) 0 .. idx
      print(:HB * 4, end' ‘’)
      I i < idx
         print(:UC, end' ‘’)
      E
         print(:UR)

   L(i) 1..4
      print(:VB, end' ‘’)
      L(j) 0 .. idx
         print(mayans[j][i - 1]‘’:VB, end' ‘’)
      print()

   print(:LL, end' ‘’)
   L(i) 0 .. idx
      print(:HB * 4, end' ‘’)
      I i < idx
         print(:LC, end' ‘’)
      E
         print(:LR)

L(n) [4005, 8017, 326205, 886205, 1081439556]
   print(‘Converting ’n‘ to Mayan:’)
   V digits = toBase20(n)
   V mayans = digits.map(d -> toMayanNumeral(d))
   draw(mayans)
   print()


      PRINT FN_MD5("")
      PRINT FN_MD5("a")
      PRINT FN_MD5("abc")
      PRINT FN_MD5("message digest")
      PRINT FN_MD5("abcdefghijklmnopqrstuvwxyz")
      PRINT FN_MD5("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")
      PRINT FN_MD5(STRING$(8,"1234567890"))
      END

      DEF FN_MD5(message$)
      LOCAL I%, MD5$, MD5_CTX{}
      DIM MD5_CTX{i%(1), buf%(3), in&(63), digest&(15)}
      SYS "MD5Init", MD5_CTX{}
      SYS "MD5Update", MD5_CTX{}, message$, LEN(message$)
      SYS "MD5Final", MD5_CTX{}
      FOR I% = 0 TO 15
        MD5$ += RIGHT$("0"+STR$~(MD5_CTX.digest&(I%)),2)
      NEXT
      = MD5$


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/md5.h>

const char *string = "The quick brown fox jumped over the lazy dog's back";

int main()
{
  int i;
  unsigned char result[MD5_DIGEST_LENGTH];

  MD5(string, strlen(string), result);

  // output
  for(i = 0; i < MD5_DIGEST_LENGTH; i++)
    printf("%02x", result[i]);
  printf("\n");

  return EXIT_SUCCESS;
}


putch:	equ	2
puts:	equ	9
	org	100h
	lxi	h,80h	; Get length of command line input
	mov	a,m
	cpi	2
	rc		; If no input, stop
	add	l
	mov	l,a	; Go to end of numbers
	mov	c,l	; C = end of numbers
	inx	h
	mvi	m,0FFh	; Terminate digit sequence with FFh
	dcx	h
sub0:	mov	a,m
	cpi	32	; When space reached, we're at the beginning
	jz	to20
	sui	'0'	; Subtract '0' from each digit and make sure
	rc		; they are all valid
	cpi	10
	rnc
	mov	m,a
	dcx 	h
	jmp	sub0
to20:	mov	a,c	; Calculate amount of numbers
	sui	81h
	mov	c,a
to20l:	mov	e,c	; E = digit counter
	mvi	l,82h	; Start at beginning
div2:	mov	a,m	; Grab digit
	jnc	$+5	; If carry, add ten
	adi	10
	rar		; Divide by two
	mov	m,a	; Write back
	inx	h
	dcr	e
	jnz	div2	; Keep going
	dcx	h	; For the last number we want
	ral		; to keep the carry
	mov	m,a	; This digit is now base-20
	dcr	c	; One fewer digit left to do
	jnz	to20l
	mvi	l,81h	; Find start and end of numbers
start:	inx	h
	mov	a,m
	ana	a
	jz	start
	mov	b,l	; B = start
	inr	a	; If number is zero, output nothing
	rz
nend:	inx	h
	mov	a,m
	inr	a
	jnz	nend
	mov	a,l	; A = end
	sub	b
	mov	c,a	; C = amount
	call	edge
	mvi	d,3	; D=line
line:	push	b	; Save start and amount
	mov	l,b	; HL = first digit
	mvi	h,0
num:	call	dline	; Print line for digit
	inx	h	; Next digit
	dcr	c
	jnz	num
	push	d	; Save line number
	lxi	d,dn	; Print end of line
	call	print
	pop 	d	; Restore variables
	pop 	b
	dcr	d
	jp	line	; Print next line
edge:	push	b	; Print edge (top or bottom)
edge_l:	push	b	; Keep counter
	lxi	d,edges
	call 	print
	pop	b
	dcr 	c
	jnz	edge_l
	lxi	d,edgen
	call	print
	pop	b
	ret
dline:	push	h	; Print line for digit (D'th from bottom)
	push	d
	push	b
	mov	a,m
	ora	d	; Line and number both 0?
	jnz	$+9
	lxi	d,dz	; Then print line with @
	jmp	dnum
	mov	a,d	; 5 * line
	add	a
	add	a
	add	d
	mov	e,a
	mov	a,m	; A -= 5 * line
	sub	e
	lxi	d,d0	; If <0, empty
	jm	dnum
	cpi	5
	jc	$+9
	lxi	d,d5	; If >=5, ----
	jmp	dnum
	add	a	; Otherwise, d[n]
	mov	l,a
	add	a
	add	l
	mov	l,a
	mvi	h,0
	dad	d
	xchg
dnum:	call	print
	pop	b
	pop	d
	pop	h
	ret
print:	mvi	c,puts
	jmp	5
edges:	db	'+----$'
edgen:	db	'+',13,10,'$'
dz:	db	'| @  $'
d0:	db	'|    $| .  $| .. $|... $|....$'
d5:	db	'|----$'
dn:	db	'|',13,10,'$'


use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

-- MAYAN NUMBERS ------------------------------------------

-- mayanNumber:: Int -> [[String]]
on mayanNumber(n)
    showIntAtBase(20, my mayanDigit, n, {})
end mayanNumber

-- mayanDigit :: Int -> String
on mayanDigit(n)
    if 0 < n then
        set r to n mod 5
        bool({}, {concat(replicate(r, "●"))}, 0 < r) & ¬
            replicate(n div 5, "━━")
    else
        {"Θ"}
    end if
end mayanDigit

-- mayanFrame :: Int -> String
on mayanFrame(n)
    "Mayan " & (n as string) & ":\n" & wikiTable({|class|:¬
        "wikitable", colwidth:¬
        "3em", cell:¬
        "vertical-align:bottom;", |style|:¬
        "text-align:center;background-color:#F0EDDE;" & ¬
        "color:#605B4B;border:2px solid silver"})'s ¬
        |λ|({map(intercalateS("<br>"), mayanNumber(n))}) & "\n"
end mayanFrame

-- TEST ---------------------------------------------------

on run
    set str to unlines(map(mayanFrame, ¬
        {4005, 8017, 326205, 886205, 2978480}))

    set the clipboard to (str)
    return str
end run

-- GENERIC ------------------------------------------------

-- Just :: a -> Maybe a
on Just(x)
    {type:"Maybe", Nothing:false, Just:x}
end Just

-- Nothing :: Maybe a
on Nothing()
    {type:"Maybe", Nothing:true}
end Nothing

-- Tuple (,) :: a -> b -> (a, b)
on Tuple(a, b)
    {type:"Tuple", |1|:a, |2|:b, length:2}
end Tuple

-- bool :: a -> a -> Bool -> a
on bool(f, t, p)
    if p then
        t
    else
        f
    end if
end bool

-- concat :: [[a]] -> [a]
-- concat :: [String] -> String
on concat(xs)
    set lng to length of xs
    if 0 < lng and string is class of (item 1 of xs) then
        set acc to ""
    else
        set acc to {}
    end if
    repeat with i from 1 to lng
        set acc to acc & item i of xs
    end repeat
    acc
end concat

-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
    tell mReturn(f)
        set v to startValue
        set lng to length of xs
        repeat with i from 1 to lng
            set v to |λ|(v, item i of xs, i, xs)
        end repeat
        return v
    end tell
end foldl

-- intercalateS :: String -> [String] -> String
on intercalateS(sep)
    script
        on |λ|(xs)
            set {dlm, my text item delimiters} to {my text item delimiters, sep}
            set s to xs as text
            set my text item delimiters to dlm
            return s
        end |λ|
    end script
end intercalateS

-- lookupDict :: a -> Dict -> Maybe b
on lookupDict(k, dct)
    set ca to current application
    set v to (ca's NSDictionary's dictionaryWithDictionary:dct)'s objectForKey:k
    if missing value ≠ v then
        Just(item 1 of ((ca's NSArray's arrayWithObject:v) as list))
    else
        Nothing()
    end if
end lookupDict

-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property |λ| : f
        end script
    end if
end mReturn

-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
    tell mReturn(f)
        set lng to length of xs
        set lst to {}
        repeat with i from 1 to lng
            set end of lst to |λ|(item i of xs, i, xs)
        end repeat
        return lst
    end tell
end map

-- | The 'maybe' function takes a default value, a function, and a 'Maybe'
-- value.  If the 'Maybe' value is 'Nothing', the function returns the
-- default value.  Otherwise, it applies the function to the value inside
-- the 'Just' and returns the result.
-- maybe :: b -> (a -> b) -> Maybe a -> b
on maybe(v, f, mb)
    if Nothing of mb then
        v
    else
        tell mReturn(f) to |λ|(Just of mb)
    end if
end maybe

-- quotRem :: Int -> Int -> (Int, Int)
on quotRem(m, n)
    Tuple(m div n, m mod n)
end quotRem

-- Egyptian multiplication - progressively doubling a list, appending
-- stages of doubling to an accumulator where needed for binary
-- assembly of a target length
-- replicate :: Int -> a -> [a]
on replicate(n, a)
    set out to {}
    if n < 1 then return out
    set dbl to {a}

    repeat while (n > 1)
        if (n mod 2) > 0 then set out to out & dbl
        set n to (n div 2)
        set dbl to (dbl & dbl)
    end repeat
    return out & dbl
end replicate

-- showIntAtBase :: Int -> (Int -> [String]) -> Int -> String -> String
on showIntAtBase(base, toDigit, n, rs)
    script showIt
        property f : mReturn(toDigit)
        on |λ|(nd_, r)
            set {n, d} to ({|1|, |2|} of nd_)
            set r_ to {f's |λ|(d)} & r
            if n > 0 then
                |λ|(quotRem(n, base), r_)
            else
                r_
            end if
        end |λ|
    end script
    showIt's |λ|(quotRem(n, base), rs)
end showIntAtBase

-- unlines :: [String] -> String
on unlines(xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, linefeed}
    set str to xs as text
    set my text item delimiters to dlm
    str
end unlines

-- unwords :: [String] -> String
on unwords(xs)
    set {dlm, my text item delimiters} to ¬
        {my text item delimiters, space}
    set s to xs as text
    set my text item delimiters to dlm
    return s
end unwords

-- wikiTable :: Dict -> [[String]] -> String
on wikiTable(opts)
    script ksv
        on |λ|(k)
            script
                on |λ|(s)
                    script
                        on |λ|(v)
                            k & v & s
                        end |λ|
                    end script
                end |λ|
            end script
        end |λ|
    end script
    script
        on |λ|(rows)
            script boxStyle
                on |λ|(a, k)
                    maybe(a, ksv's |λ|(a & k & "=\"")'s |λ|("\" "), ¬
                        lookupDict(k, opts))
                end |λ|
            end script
            script rowText
                on |λ|(row, iRow)
                    script cellText
                        on |λ|(cell)
                            if 1 = iRow then
                                set w to maybe("", ksv's |λ|("width:")'s |λ|(";"), ¬
                                    lookupDict("colwidth", opts))
                            else
                                set w to ""
                            end if
                            set s to maybe(w, ksv's |λ|(w)'s |λ|(""), ¬
                                lookupDict("cell", opts))
                            if 0 < length of s then
                                "style=\"" & s & "\"|" & cell
                            else
                                cell
                            end if
                        end |λ|
                    end script
                    intercalateS("\n|")'s |λ|(map(cellText, row))
                end |λ|
            end script
            "{| " & unwords(foldl(boxStyle, "", {"class", "style"})) & "\n|" & ¬
                intercalateS("\n|-\n")'s |λ|(map(rowText, rows)) & "\n|}"
        end |λ|
    end script
end wikiTable


using System.Text;
using System.Security.Cryptography;

byte[] data = Encoding.ASCII.GetBytes("The quick brown fox jumped over the lazy dog's back");
byte[] hash = MD5.Create().ComputeHash(data);
Console.WriteLine(BitConverter.ToString(hash).Replace("-", "").ToLower());


#include <string>
#include <iostream>
#include "Poco/MD5Engine.h"
#include "Poco/DigestStream.h"

using Poco::DigestEngine ;
using Poco::MD5Engine ;
using Poco::DigestOutputStream ;

int main( ) {
   std::string myphrase ( "The quick brown fox jumped over the lazy dog's back" ) ;
   MD5Engine md5 ;
   DigestOutputStream outstr( md5 ) ;
   outstr << myphrase ;
   outstr.flush( ) ; //to pass everything to the digest engine
   const DigestEngine::Digest& digest = md5.digest( ) ;
   std::cout << myphrase << " as a MD5 digest :\n" << DigestEngine::digestToHex( digest )
      << " !" << std::endl ;
   return 0 ;
}


10 DEFINT A-Z: DIM L$(5)
15 FOR I=0 TO 5: READ L$(I): NEXT I
20 LINE INPUT I$
30 M=LEN(I$): DIM D(M)
40 FOR I=1 TO M: D(I)=VAL(MID$(I$,I,1)): NEXT I
50 FOR J=M-1 TO 1 STEP -1
60 FOR I=1 TO J
70 D(I+1) = D(I+1) + 10*(D(I) AND 1)
80 D(I) = D(I)\2
90 NEXT I,J
100 S=1
110 IF D(S)=0 AND S<M THEN S=S+1: GOTO 110
120 FOR I=S TO M: PRINT "+----";: NEXT I: PRINT "+"
130 FOR L=3 TO 0 STEP -1
140 FOR I=S TO M
150 IF (D(I) OR L)=0 THEN PRINT "| @  ";: GOTO 180
160 N=D(I)-5*L: IF N>5 THEN N=5 ELSE IF N<0 THEN N=0
170 PRINT "|";L$(N);
180 NEXT I
190 PRINT "|"
200 NEXT L
210 FOR I=S TO M: PRINT "+----";: NEXT I: PRINT "+"
220 END
230 DATA "    "," .  "," .. ","... ","....","----"


get "libhdr"

let reads(v) be
$(  v%0 := 0
    $(  let ch = rdch()
        if ch = '*N' | ch = endstreamch break
        v%0 := v%0 + 1
        v%(v%0) := ch
    $) repeat
$)

let digits(v) = valof
$(  for i=1 to v%0
    $(  unless '0' <= v%i <= '9' resultis false
        v%i := v%i - '0'
    $)
    resultis true
$)

let base20(v) be
$(  let i = ?
    for j=v%0-1 to 1 by -1
        for i=1 to j
        $(  v%(i+1) := v%(i+1) + 10*(v%i & 1)
            v%i := v%i >> 1
        $)
    i := 1
    while v%i=0 & i<v%0 do i := i+1
    for j=i to v%0 do v%(j-i+1) := v%j
    v%0 := v%0-i+1
$)

let mayan(v) be
$(  let border(n) be
    $(  for i=1 to n do writes("+----")
        writes("+*N")
    $)
    let part(num, line) be
        test num=0 do
            writes(line=0 -> " @  ", "    ")
        or
        $(  num := num - line*5
            writes(num<=0 -> "    ",
                   num =1 -> " .  ",
                   num =2 -> " .. ",
                   num =3 -> "... ",
                   num =4 -> "....",
                             "----")
        $)
    border(v%0)
    for l=3 to 0 by -1
    $(  for d=1 to v%0
        $(  wrch('|')
            part(v%d, l)
        $)
        writes("|*N")
    $)
    border(v%0)
$)

let start() be
$(  let v = vec 1+255/BYTESPERWORD
    $(  writes("Number? ")
        reads(v)
        if v%0=0 finish
        unless digits(v) loop
        base20(v)
        mayan(v)
    $) repeat
$)


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

#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define MIN(x,y) ((x) < (y) ? (x) : (y))

/* Find base-20 digits. */
size_t base20(unsigned int n, uint8_t *out) {
    /* generate digits */
    uint8_t *start = out;
    do {*out++ = n % 20;} while (n /= 20);
    size_t length = out - start;

    /* put digits in high-endian order */
    while (out > start) {
        uint8_t x = *--out;
        *out = *start;
        *start++ = x;
    }
    return length;
}

/* Write a Mayan digit */
void make_digit(int n, char *place, size_t line_length) {
    static const char *parts[] = {"    "," .  "," .. ","... ","....","----"};
    int i;

    /* write 4-part digit */
    for (i=4; i>0; i--, n -= 5)
        memcpy(place + i*line_length, parts[MAX(0, MIN(5, n))], 4);

    /* if digit was 0 we should put '@' in 2nd position of last line */
    if (n == -20) place[4 * line_length + 1] = '@';
}

/* Make a Mayan numeral */
char *mayan(unsigned int n) {
    if (n == 0) return NULL;

    uint8_t digits[15]; /* 2**64 is 15 Mayan digits long */
    size_t n_digits = base20(n, digits);

    /* a digit is 4 chars wide, plus N+1 divider lines, plus a newline
       makes for a length of 5*n+2 */
    size_t line_length = n_digits*5 + 2;

    /* we need 6 lines - four for the digits, plus top and bottom row */
    char *str = malloc(line_length * 6 + 1);
    if (str == NULL) return NULL;
    str[line_length * 6] = 0;

    /* make the cartouche divider lines */
    char *ptr;
    unsigned int i;
    /* top and bottom row */
    for (ptr=str, i=0; i<line_length; i+=5, ptr+=5)
        memcpy(ptr, "+----", 5);
    memcpy(ptr-5, "+\n", 2);
    memcpy(str+5*line_length, str, line_length);
    /* middle rows */
    for (ptr=str+line_length, i=0; i<line_length; i+=5, ptr+=5)
        memcpy(ptr, "|    ", 5);
    memcpy(ptr-5, "|\n", 2);
    memcpy(str+2*line_length, str+line_length, line_length);
    memcpy(str+3*line_length, str+line_length, 2*line_length);

    /* copy in the digits */
    for (i=0; i<n_digits; i++)
        make_digit(digits[i], str+1+5*i, line_length);

    return str;
}

int main(int argc, char **argv) {
    if (argc != 2) {
        fprintf(stderr, "usage: mayan <number>\n");
        return 1;
    }
    int i = atoi(argv[1]);
    if (i <= 0) {
        fprintf(stderr, "number must be positive\n");
        return 1;
    }
    char *m = mayan(i);
    printf("%s",m);
    free(m);
    return 0;
}


USER>set hash=$System.Encryption.MD5Hash("The quick brown fox jumped over the lazy dog's back")
USER>zzdump hash
0000: E3 8C A1 D9 20 C4 B8 B8 D3 94 6B 2C 72 F0 16 80


(apply str
  (map (partial format "%02x")
    (.digest (doto (java.security.MessageDigest/getInstance "MD5")
                   .reset
                   (.update (.getBytes "The quick brown fox jumps over the lazy dog"))))))


       IDENTIFICATION DIVISION.
       PROGRAM-ID. MD5.
       AUTHOR.  Bill Gunshannon
       INSTALLATION.  Home.
       DATE-WRITTEN.  16 December 2021.
      ************************************************************
      ** Program Abstract:
      **   Use the md5sum utility and pass the HASH back using
      **     a temp file.  Not elegant, but it works.
      ************************************************************

       ENVIRONMENT DIVISION.

       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
            SELECT Tmp-MD5 ASSIGN TO "/tmp/MD5"
                 ORGANIZATION IS LINE SEQUENTIAL.

       DATA DIVISION.

       FILE SECTION.

       FD  Tmp-MD5
           DATA RECORD IS MD5-Rec.
       01  MD5-Rec       PIC X(32).

       WORKING-STORAGE SECTION.

       01 Eof                   PIC X     VALUE 'F'.
       01 Str1.
          05  Pre-cmd   PIC X(8)
              VALUE 'echo -n '.
          05  Str1-complete.
              10  Str1-Part1  PIC X(26)
                  VALUE  'The quick brown fox jumps'.
              10  Str1-Part2  PIC X(19)
                  VALUE  ' over the lazy dog'.
          05  Post-cmd    PIC X(20)
              VALUE  ' | md5sum > /tmp/MD5'.
       01  Str1-MD5          PIC X(32).

       PROCEDURE DIVISION.

       Main-Program.

           DISPLAY Str1-complete.
           PERFORM Get-MD5.
           DISPLAY Str1-MD5.

           STOP RUN.

       Get-MD5.

           CALL "SYSTEM" USING Str1.
           OPEN INPUT Tmp-MD5.
           READ Tmp-MD5 INTO Str1-MD5.
           CLOSE Tmp-MD5.
           CALL "CBL_DELETE_FILE" USING '/tmp/MD5'.


% This program must be linked with PCLU's "misc.lib" and "useful.lib"

base20 = proc (n: bigint) returns (sequence[int])
    own zero: bigint := bigint$i2bi(0)
    own twenty: bigint := bigint$i2bi(20)
    if n=zero then return(sequence[int]$[0]) end

    digits: array[int] := array[int]$[]
    while n>zero do
        array[int]$addl(digits, bigint$bi2i(n//twenty))
        n := n/twenty
    end
    return(sequence[int]$a2s(digits))
end base20

mayan = proc (digits: sequence[int]) returns (string)
    own parts: array[string] := array[string]$[0:
        "    ", " .  ", " .. ", "... ", "....", "----"
    ]
    % generate edges
    edge: stream := stream$create_output()
    for i: int in int$from_to(1, sequence[int]$size(digits)) do
        stream$puts(edge, "+----")
    end
    stream$putl(edge, "+")

    % generate digits
    lines: stream := stream$create_output()
    for i: int in int$from_to_by(15, 0, -5) do
        for d: int in sequence[int]$elements(digits) do
            p: int := d-i
            if p<0 then p:=0 end
            if p>5 then p:=5 end
            if i=0 & p=0
                then stream$puts(lines, "| @  ")
                else stream$puts(lines, "|" || parts[p])
            end
        end
        stream$putl(lines, "|")
    end

    s_edge: string := stream$get_contents(edge)
    return(s_edge || stream$get_contents(lines) || s_edge)
end mayan

start_up = proc ()
    po: stream := stream$primary_output()
    n: bigint := bigint$parse(sequence[string]$bottom(get_argv()))
    stream$puts(po, mayan(base20(n)))
end start_up


include "cowgol.coh";
include "argv.coh";

# convert number to base 20
sub base20(n: uint32, out: [uint8]): (n_digits: uint8) is
    n_digits := 0;
    loop
        [out] := (n % 20) as uint8;
        n := n / 20;
        out := @next out;
        n_digits := n_digits + 1;
        if n == 0 then break; end if;
    end loop;
end sub;

# get the N'th line (from the top) for a Mayan digit
sub digit_line(n: uint8, line: uint8): (s: [uint8]) is
    var parts: [uint8][] := {"    "," .  "," .. ","... ","....","----"};
    if n == 0 then
        if line == 3 then s := " @  ";
        else s := parts[0];
        end if;
    else
        var nn := n - 5*(3-line);
        if nn > 128 then s := parts[0];
        elseif nn > 5 then s := parts[5];
        else s := parts[nn];
        end if;
    end if;
end sub;

# print Mayan number
sub print_mayan(n: uint32) is
    sub edge(n: uint8) is
        while n>0 loop
            print("+----");
            n := n-1;
        end loop;
        print_char('+');
        print_nl();
    end sub;

    var digits: uint8[8]; # 8 digits is enough for 2**32
    var size := base20(n, &digits[0]);

    edge(size);
    var line: uint8 := 0;
    while line < 4 loop
        var d: uint8 := size-1;
        loop
            print_char('|');
            print(digit_line(digits[d], line));
            if d==0 then break; end if;
            d := d - 1;
        end loop;
        print_char('|');
        print_nl();
        line := line + 1;
    end loop;
    edge(size);
end sub;

sub Error() is
    print("usage: mayan <number>. number must be positive");
    print_nl();
    ExitWithError();
end sub;

# read number from command line
ArgvInit();
var arg := ArgvNext();
if arg == 0 as [uint8] then Error(); end if;
var n: int32;
(n, arg) := AToI(arg);
if n <= 0 then Error(); end if;
print_mayan(n as uint32);


// Mayan numerals. Nigel Galloway: February 19th., 2021
let N=[|"│    ";"│.   ";"│..  ";"│... ";"│....";"│~~~~"|]
let     fN g=(fun(n)->if g=0 && n=0 then "│ Θ  " else N.[let g=g-5*n in if g>4 then 5 else if g<0 then 0 else g])
let rec fG n g=match n/20L,n%20L with (0L,0L)->(g,List.length g) |(i,n)->fG i ((fN(int n))::g)
let mayan n=let n,g=fG n []
            printf "┌────"; for _ in 2..g do printf "┬────"
            printfn "┐"; for g in 3.. -1 ..0 do n|>List.iter(fun n->printf "%s" (n(g))); printfn "│"
            printf "└────"; for _ in 2..g do printf "┴────"
            printfn "┘"
[4005L;8017L;326205L;886205L]|>List.iter(fun n->printfn "%d" n; mayan n)


(ql:quickload 'ironclad)
(defun md5 (str)
  (ironclad:byte-array-to-hex-string
    (ironclad:digest-sequence :md5
                              (ironclad:ascii-string-to-byte-array str))))
(defvar *tests* '(""
                  "a"
                  "abc"
                  "message digest"
                  "abcdefghijklmnopqrstuvwxyz"
                  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
                  "12345678901234567890123456789012345678901234567890123456789012345678901234567890"))
(dolist (msg *tests*)
  (format T "~s: ~a~%" msg (md5 msg)))


require "digest/md5"

puts Digest::MD5.hexdigest("The quick brown fox jumped over the lazy dog's back")


void main() {
    import std.stdio, std.digest.md;

    auto txt = "The quick brown fox jumped over the lazy dog's back";
    writefln("%-(%02x%)", txt.md5Of);
}


USING: arrays formatting io kernel make math math.extras
sequences ;
IN: rosetta-code.mayan-numerals

: mayan-digit ( n -- m pair ) 20 /mod 5 /mod swap 2array ;

: integer>mayan ( n -- seq )
    [ [ mayan-digit , ] until-zero ] { } make reverse ;

: ones ( n -- str ) [ CHAR: ● ] "" replicate-as ;
: fives ( n -- str ) [ "——" ] replicate "
" join ;

: numeral ( pair -- str )
    dup sum zero? [ drop "Θ" ]
    [ first2 [ ones ] [ fives ] bi* 2array harvest "
" join ]
    if ;

: .table-row ( pair -- )
    "|style=\"width:3em;vertical-align:bottom;\"|" write numeral
    print ;

: .table-head ( -- )
    "class=\"wikitable\" style=\"text-align:center;\"" print ;

: .table-body ( n -- ) integer>mayan [ .table-row ] each ;

: .mayan ( n -- )
    [ "Mayan %d:\n" printf ]
    [ "{|" write .table-head .table-body "|}" print ] bi ;

: mayan-numerals ( -- )
    { 4005 8017 326205 886205 } [ .mayan ] each ;

MAIN: mayan-numerals


package main

import (
    "fmt"
    "strconv"
)

const (
    ul = "╔"
    uc = "╦"
    ur = "╗"
    ll = "╚"
    lc = "╩"
    lr = "╝"
    hb = "═"
    vb = "║"
)

var mayan = [5]string{
    "    ",
    " ∙  ",
    " ∙∙ ",
    "∙∙∙ ",
    "∙∙∙∙",
}

const (
    m0 = " Θ  "
    m5 = "────"
)

func dec2vig(n uint64) []uint64 {
    vig := strconv.FormatUint(n, 20)
    res := make([]uint64, len(vig))
    for i, d := range vig {
        res[i], _ = strconv.ParseUint(string(d), 20, 64)
    }
    return res
}

func vig2quin(n uint64) [4]string {
    if n >= 20 {
        panic("Cant't convert a number >= 20")
    }
    res := [4]string{mayan[0], mayan[0], mayan[0], mayan[0]}
    if n == 0 {
        res[3] = m0
        return res
    }
    fives := n / 5
    rem := n % 5
    res[3-fives] = mayan[rem]
    for i := 3; i > 3-int(fives); i-- {
        res[i] = m5
    }
    return res
}

func draw(mayans [][4]string) {
    lm := len(mayans)
    fmt.Print(ul)
    for i := 0; i < lm; i++ {
        for j := 0; j < 4; j++ {
            fmt.Print(hb)
        }
        if i < lm-1 {
            fmt.Print(uc)
        } else {
            fmt.Println(ur)
        }
    }
    for i := 1; i < 5; i++ {
        fmt.Print(vb)
        for j := 0; j < lm; j++ {
            fmt.Print(mayans[j][i-1])
            fmt.Print(vb)
        }
        fmt.Println()
    }
    fmt.Print(ll)
    for i := 0; i < lm; i++ {
        for j := 0; j < 4; j++ {
            fmt.Print(hb)
        }
        if i < lm-1 {
            fmt.Print(lc)
        } else {
            fmt.Println(lr)
        }
    }
}

func main() {
    numbers := []uint64{4005, 8017, 326205, 886205, 1081439556}
    for _, n := range numbers {
        fmt.Printf("Converting %d to Mayan:\n", n)
        vigs := dec2vig(n)
        lv := len(vigs)
        mayans := make([][4]string, lv)
        for i, vig := range vigs {
            mayans[i] = vig2quin(vig)
        }
        draw(mayans)
        fmt.Println()
    }
}


program MD5Hash;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  IdHashMessageDigest;

function MD5(aValue: string): string;
begin
  with TIdHashMessageDigest5.Create do
  begin
    Result:= HashStringAsHex(aValue);
    Free;
  end;
end;

begin
  Writeln(MD5(''));
  Writeln(MD5('a'));
  Writeln(MD5('abc'));
  Writeln(MD5('message digest'));
  Writeln(MD5('abcdefghijklmnopqrstuvwxyz'));
  Writeln(MD5('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'));
  Writeln(MD5('12345678901234567890123456789012345678901234567890123456789012345678901234567890'));
  Readln;
end.


def makeMessageDigest := <import:java.security.makeMessageDigest>
def sprintf := <import:java.lang.makeString>.format

def digest := makeMessageDigest.getInstance("MD5") \
  .digest("The quick brown fox jumped over the lazy dog's back".getBytes("iso-8859-1"))

for b in digest {
  print(sprintf("%02x", [b]))
}
println()


(md5 "The quick brown fox jumped over the lazy dog's back") ;=> "e38ca1d920c4b8b8d3946b2c72f01680"
(secure-hash 'md5 "The quick brown fox jumped over the lazy dog's back") ;=> "e38ca1d920c4b8b8d3946b2c72f01680"


-module(tests).
-export([md5/1]).

md5(S) ->
 string:to_upper(
  lists:flatten([io_lib:format("~2.16.0b",[N]) || <<N>> <= erlang:md5(S)])
 ).


let md5ootb (msg: string) =
  use md5 = System.Security.Cryptography.MD5.Create()
  msg
  |> System.Text.Encoding.ASCII.GetBytes
  |> md5.ComputeHash
  |> Seq.map (fun c -> c.ToString("X2"))
  |> Seq.reduce ( + )

md5ootb @"The quick brown fox jumped over the lazy dog's back"


import Data.Bool (bool)
import Data.List (intercalate, transpose)
import qualified Data.Map.Strict as M
import Data.Maybe (maybe)

--------------------------- MAIN -------------------------
main :: IO ()
main =
  (putStrLn . unlines) $
    mayanFramed
      <$> [ 4005,
            8017,
            326205,
            886205,
            1081439556,
            1000000,
            1000000000
          ]

---------------------- MAYAN NUMBERS ---------------------
mayanGlyph :: Int -> [[String]]
mayanGlyph =
  filter (any (not . null))
    . transpose
    . leftPadded
    . flip (showIntAtBaseS 20 mayanDigit) []

mayanDigit :: Int -> [String]
mayanDigit n
  | 0 /= n =
    replicate (rem n 5) mayaOne :
    concat
      ( replicate (quot n 5) [mayaFive]
      )
  | otherwise = [[mayaZero]]

mayanFramed :: Int -> String
mayanFramed =
  ("Mayan " <>)
    . ( (<>) <$> show
          <*> ( (":\n\n" <>)
                  . wikiTable
                    ( M.fromList
                        [ ( "style",
                            concat
                              [ "text-align:center;",
                                "background-color:#F0EDDE;",
                                "color:#605B4B;",
                                "border:2px solid silver;"
                              ]
                          ),
                          ("colwidth", "3em;")
                        ]
                    )
                  . mayanGlyph
              )
      )

mayaZero, mayaOne :: Char
mayaZero = '\920'
mayaOne = '\9679'

mayaFive :: String
mayaFive = "\9473\9473"

---------------------- NUMERIC BASES ---------------------
-- Based on the Prelude showIntAtBase but uses an
-- (Int -> [String]) (rather than Int -> Char) function
-- as its second argument.
--
-- Shows a /non-negative/ 'Integral' number using the base
-- specified by the first argument, and the **String**
-- representation specified by the second.
showIntAtBaseS ::
  Integral a =>
  a ->
  (Int -> [String]) ->
  a ->
  [[String]] ->
  [[String]]
showIntAtBaseS base toStr n0 r0 =
  let go (n, d) r =
        seq s $
          case n of
            0 -> r_
            _ -> go (quotRem n base) r_
        where
          s = toStr (fromIntegral d)
          r_ = s : r
   in go (quotRem n0 base) r0

------------------------- DISPLAY ------------------------
wikiTable :: M.Map String String -> [[String]] -> String
wikiTable opts rows
  | null rows = []
  | otherwise =
    "{| "
      <> foldr
        ( \k a ->
            maybe
              a
              ( ((a <> k <> "=\"") <>)
                  . ( <> "\" "
                    )
              )
              (M.lookup k opts)
        )
        []
        ["class", "style"]
      <> ( '\n' :
           intercalate
             "|-\n"
             ( zipWith renderedRow rows [0 ..]
             )
         )
      <> "|}\n\n"
  where
    renderedRow row i =
      unlines
        ( fmap
            ( ( bool
                  []
                  ( maybe
                      "|"
                      (("|style=\"width:" <>) . (<> "\""))
                      (M.lookup "colwidth" opts)
                  )
                  (0 == i)
                  <>
              )
                . ('|' :)
            )
            row
        )

leftPadded :: [[String]] -> [[String]]
leftPadded xs =
  let w = maximum (length <$> xs)
   in ((<>) =<< flip replicate [] . (-) w . length) <$> xs


USING: kernel strings io checksums checksums.md5 ;
"The quick brown fox jumps over the lazy dog"
md5 checksum-bytes hex-string print


include ffl/md5.fs

\ Create a MD5 variable md1 in the dictionary

md5-create md1

\ Update the variable with data

s" The quick brown fox jumps over the lazy dog" md1 md5-update

\ Finish the MD5 calculation resulting in four unsigned 32 bit words
\ on the stack representing the hash value

md1 md5-finish

\ Convert the hash value to a hex string and print it

md5+to-string type cr


module md5_mod
    use kernel32
    use advapi32
    implicit none
    integer, parameter :: MD5LEN = 16
contains
    subroutine md5hash(name, hash, dwStatus, filesize)
        implicit none
        character(*) :: name
        integer, parameter :: BUFLEN = 32768
        integer(HANDLE) :: hFile, hProv, hHash
        integer(DWORD) :: dwStatus, nRead
        integer(BOOL) :: status
        integer(BYTE) :: buffer(BUFLEN)
        integer(BYTE) :: hash(MD5LEN)
        integer(UINT64) :: filesize

        dwStatus = 0
        filesize = 0
        hFile = CreateFile(trim(name) // char(0), GENERIC_READ, FILE_SHARE_READ, NULL, &
                           OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL)

        if (hFile == INVALID_HANDLE_VALUE) then
            dwStatus = GetLastError()
            print *, "CreateFile failed."
            return
        end if

        if (CryptAcquireContext(hProv, NULL, NULL, PROV_RSA_FULL, &
                                CRYPT_VERIFYCONTEXT) == FALSE) then
            dwStatus = GetLastError()
            print *, "CryptAcquireContext failed."
            goto 3
        end if

        if (CryptCreateHash(hProv, CALG_MD5, 0_ULONG_PTR, 0_DWORD, hHash) == FALSE) then
            dwStatus = GetLastError()
            print *, "CryptCreateHash failed."
            go to 2
        end if

        do
            status = ReadFile(hFile, loc(buffer), BUFLEN, nRead, NULL)
            if (status == FALSE .or. nRead == 0) exit
            filesize = filesize + nRead
            if (CryptHashData(hHash, buffer, nRead, 0) == FALSE) then
                dwStatus = GetLastError()
                print *, "CryptHashData failed."
                go to 1
            end if
        end do

        if (status == FALSE) then
            dwStatus = GetLastError()
            print *, "ReadFile failed."
            go to 1
        end if

        nRead = MD5LEN
        if (CryptGetHashParam(hHash, HP_HASHVAL, hash, nRead, 0) == FALSE) then
            dwStatus = GetLastError()
            print *, "CryptGetHashParam failed.", status, nRead, dwStatus
        end if

      1 status = CryptDestroyHash(hHash)
      2 status = CryptReleaseContext(hProv, 0)
      3 status = CloseHandle(hFile)
    end subroutine
end module

program md5
    use md5_mod
    implicit none
    integer :: n, m, i, j
    character(:), allocatable :: name
    integer(DWORD) :: dwStatus
    integer(BYTE) :: hash(MD5LEN)
    integer(UINT64) :: filesize

    n = command_argument_count()
    do i = 1, n
        call get_command_argument(i, length=m)
        allocate(character(m) :: name)
        call get_command_argument(i, name)
        call md5hash(name, hash, dwStatus, filesize)
        if (dwStatus == 0) then
            do j = 1, MD5LEN
                write(*, "(Z2.2)", advance="NO") hash(j)
            end do
            write(*, "(' ',A,' (',G0,' bytes)')") name, filesize
        end if
        deallocate(name)
    end do
end program


import java.math.BigInteger;

public class MayanNumerals {

    public static void main(String[] args) {
        for ( long base10 : new long[] {4005, 8017, 326205, 886205, 1000000000, 1081439556L, 26960840421L, 503491211079L }) {
            displayMyan(BigInteger.valueOf(base10));
            System.out.printf("%n");
        }
    }

    private static char[] digits = "0123456789ABCDEFGHJK".toCharArray();
    private static BigInteger TWENTY = BigInteger.valueOf(20);

    private static void displayMyan(BigInteger numBase10) {
        System.out.printf("As base 10:  %s%n", numBase10);
        String numBase20 = "";
        while ( numBase10.compareTo(BigInteger.ZERO) > 0 ) {
            numBase20 = digits[numBase10.mod(TWENTY).intValue()] + numBase20;
            numBase10 = numBase10.divide(TWENTY);
        }
        System.out.printf("As base 20:  %s%nAs Mayan:%n", numBase20);
        displayMyanLine1(numBase20);
        displayMyanLine2(numBase20);
        displayMyanLine3(numBase20);
        displayMyanLine4(numBase20);
        displayMyanLine5(numBase20);
        displayMyanLine6(numBase20);
    }

    private static char boxUL = Character.toChars(9556)[0];
    private static char boxTeeUp = Character.toChars(9574)[0];
    private static char boxUR = Character.toChars(9559)[0];
    private static char boxHorz = Character.toChars(9552)[0];
    private static char boxVert = Character.toChars(9553)[0];
    private static char theta = Character.toChars(952)[0];
    private static char boxLL = Character.toChars(9562)[0];
    private static char boxLR = Character.toChars(9565)[0];
    private static char boxTeeLow = Character.toChars(9577)[0];
    private static char bullet = Character.toChars(8729)[0];
    private static char dash = Character.toChars(9472)[0];

    private static void displayMyanLine1(String base20) {
        char[] chars = base20.toCharArray();
        StringBuilder sb = new StringBuilder();
        for ( int i = 0 ; i < chars.length ; i++ ) {
            if ( i == 0 ) {
                sb.append(boxUL);
            }
            for ( int j = 0 ; j < 4 ; j++ ) {
                sb.append(boxHorz);
            }
            sb.append(i < chars.length-1 ? boxTeeUp : boxUR);
        }
        System.out.println(sb.toString());
    }

    private static String getBullet(int count) {
        StringBuilder sb = new StringBuilder();
        switch ( count ) {
        case 1:  sb.append(" " + bullet + "  "); break;
        case 2:  sb.append(" " + bullet + bullet + " "); break;
        case 3:  sb.append("" + bullet + bullet + bullet + " "); break;
        case 4:  sb.append("" + bullet + bullet + bullet + bullet); break;
        default:  throw new IllegalArgumentException("Must be 1-4:  " + count);
        }
        return sb.toString();
    }

    private static void displayMyanLine2(String base20) {
        char[] chars = base20.toCharArray();
        StringBuilder sb = new StringBuilder();
        for ( int i = 0 ; i < chars.length ; i++ ) {
            if ( i == 0 ) {
                sb.append(boxVert);
            }
            switch ( chars[i] ) {
            case 'G':  sb.append(getBullet(1)); break;
            case 'H':  sb.append(getBullet(2)); break;
            case 'J':  sb.append(getBullet(3)); break;
            case 'K':  sb.append(getBullet(4)); break;
            default :  sb.append("    ");
            }
            sb.append(boxVert);
        }
        System.out.println(sb.toString());
    }

    private static String DASH = getDash();

    private static String getDash() {
        StringBuilder sb = new StringBuilder();
        for ( int i = 0 ; i < 4 ; i++ ) {
            sb.append(dash);
        }
        return sb.toString();
    }

    private static void displayMyanLine3(String base20) {
        char[] chars = base20.toCharArray();
        StringBuilder sb = new StringBuilder();
        for ( int i = 0 ; i < chars.length ; i++ ) {
            if ( i == 0 ) {
                sb.append(boxVert);
            }
            switch ( chars[i] ) {
            case 'B':  sb.append(getBullet(1)); break;
            case 'C':  sb.append(getBullet(2)); break;
            case 'D':  sb.append(getBullet(3)); break;
            case 'E':  sb.append(getBullet(4)); break;
            case 'F': case 'G': case 'H': case 'J': case 'K':
                sb.append(DASH); break;
            default :  sb.append("    ");
            }
            sb.append(boxVert);
        }
        System.out.println(sb.toString());
    }

    private static void displayMyanLine4(String base20) {
        char[] chars = base20.toCharArray();
        StringBuilder sb = new StringBuilder();
        for ( int i = 0 ; i < chars.length ; i++ ) {
            if ( i == 0 ) {
                sb.append(boxVert);
            }
            switch ( chars[i] ) {
            case '6':  sb.append(getBullet(1)); break;
            case '7':  sb.append(getBullet(2)); break;
            case '8':  sb.append(getBullet(3)); break;
            case '9':  sb.append(getBullet(4)); break;
            case 'A': case 'B': case 'C': case 'D': case 'E':
            case 'F': case 'G': case 'H': case 'J': case 'K':
                sb.append(DASH); break;
            default :  sb.append("    ");
            }
            sb.append(boxVert);
        }
        System.out.println(sb.toString());
    }

    private static void displayMyanLine5(String base20) {
        char[] chars = base20.toCharArray();
        StringBuilder sb = new StringBuilder();
        for ( int i = 0 ; i < chars.length ; i++ ) {
            if ( i == 0 ) {
                sb.append(boxVert);
            }
            switch ( chars[i] ) {
            case '0':  sb.append(" " + theta + "  "); break;
            case '1':  sb.append(getBullet(1)); break;
            case '2':  sb.append(getBullet(2)); break;
            case '3':  sb.append(getBullet(3)); break;
            case '4':  sb.append(getBullet(4)); break;
            case '5': case '6': case '7': case '8': case '9':
            case 'A': case 'B': case 'C': case 'D': case 'E':
            case 'F': case 'G': case 'H': case 'J': case 'K':
                sb.append(DASH); break;
            default :  sb.append("    ");
            }
            sb.append(boxVert);
        }
        System.out.println(sb.toString());
    }

    private static void displayMyanLine6(String base20) {
        char[] chars = base20.toCharArray();
        StringBuilder sb = new StringBuilder();
        for ( int i = 0 ; i < chars.length ; i++ ) {
            if ( i == 0 ) {
                sb.append(boxLL);
            }
            for ( int j = 0 ; j < 4 ; j++ ) {
                sb.append(boxHorz);
            }
            sb.append(i < chars.length-1 ? boxTeeLow : boxLR);
        }
        System.out.println(sb.toString());
    }

}


println[messageDigest["The quick brown fox", "MD5"]]


(() => {
    'use strict';

    const main = () =>
        unlines(
            map(mayanFramed,
                [4005, 8017, 326205, 886205, 1081439556, 1000000, 1000000000]
            )
        );

    // MAYAN NUMBERS --------------------------------------

    // mayanFramed :: Int -> String
    const mayanFramed = n =>
        '\nMayan ' + n.toString() + ':\n\n' +
        wikiTable({
            style: 'text-align:center; background-color:#F0EDDE; ' +
            'color:#605B4B; border:2px solid silver',
            colwidth: '3em'
        })(
            mayanGlyph(n)
        );

    // mayanGlyph :: Int -> [[String]]
    const mayanGlyph = n =>
        filter(any(compose(not, isNull)),
            transpose(leftPadded(
                showIntAtBase(20, mayanDigit, n, [])
            ))
        );

    // mayanDigit :: Int -> [String]
    const mayanDigit = n =>
        0 !== n ? cons(
            replicateString(rem(n, 5), '●'),
            replicate(quot(n, 5), '━━')
        ) : ['Θ'];

    // FORMATTING -----------------------------------------

    // wikiTable :: Dict -> [[a]] -> String
    const wikiTable = opts => rows => {
        const colWidth = () =>
            'colwidth' in opts ? (
                '|style="width:' + opts.colwidth + ';"'
            ) : '';
        return 0 < rows.length ? (
            '{| ' + ['class', 'style'].reduce(
                (a, k) => k in opts ? (
                    a + k + '="' + opts[k] + '" '
                ) : a, ''
            ) + '\n' + rows.map(
                (row, i) => row.map(
                    x => (0 === i ? (
                        colWidth() + '| '
                    ) : '|') + (x.toString() || ' ')
                ).join('\n')
            ).join('\n|-\n') + '\n|}\n\n'
        ) : '';
    };

    // leftPadded :: [[String]] -> [[String]]
    const leftPadded = xs => {
        const w = maximum(map(length, xs));
        return map(
            x => replicate(w - x.length, '').concat(x),
            xs
        );
    };

    // GENERIC FUNCTIONS ----------------------------------

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = (a, b) => ({
        type: 'Tuple',
        '0': a,
        '1': b,
        length: 2
    });

    // any :: (a -> Bool) -> [a] -> Bool
    const any = p => xs => xs.some(p);

    // comparing :: (a -> b) -> (a -> a -> Ordering)
    const comparing = f =>
        (x, y) => {
            const
                a = f(x),
                b = f(y);
            return a < b ? -1 : (a > b ? 1 : 0);
        };

    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (f, g) => x => f(g(x));

    // concatMap :: (a -> [b]) -> [a] -> [b]
    const concatMap = (f, xs) =>
        xs.reduce((a, x) => a.concat(f(x)), []);

    // cons :: a -> [a] -> [a]
    const cons = (x, xs) =>
        Array.isArray(xs) ? (
            [x].concat(xs)
        ) : 'GeneratorFunction' !== xs.constructor.constructor.name ? (
            x + xs
        ) : ( // Existing generator wrapped with one additional element
            function*() {
                yield x;
                let nxt = xs.next()
                while (!nxt.done) {
                    yield nxt.value;
                    nxt = xs.next();
                }
            }
        )();

    // filter :: (a -> Bool) -> [a] -> [a]
    const filter = (f, xs) => xs.filter(f);

    // foldl1 :: (a -> a -> a) -> [a] -> a
    const foldl1 = (f, xs) =>
        1 < xs.length ? xs.slice(1)
        .reduce(f, xs[0]) : xs[0];

    // isNull :: [a] -> Bool
    // isNull :: String -> Bool
    const isNull = xs =>
        Array.isArray(xs) || ('string' === typeof xs) ? (
            1 > xs.length
        ) : undefined;

    // Returns Infinity over objects without finite length.
    // This enables zip and zipWith to choose the shorter
    // argument when one is non-finite, like cycle, repeat etc

    // length :: [a] -> Int
    const length = xs =>
        (Array.isArray(xs) || 'string' === typeof xs) ? (
            xs.length
        ) : Infinity;

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) =>
        (Array.isArray(xs) ? (
            xs
        ) : xs.split('')).map(f);

    // maximum :: Ord a => [a] -> a
    const maximum = xs =>
        0 < xs.length ? (
            foldl1((a, x) => x > a ? x : a, xs)
        ) : undefined;

    //  Ordering: (LT|EQ|GT):
    //  GT: 1 (or other positive n)
    //    EQ: 0
    //  LT: -1 (or other negative n)

    // maximumBy :: (a -> a -> Ordering) -> [a] -> a
    const maximumBy = (f, xs) =>
        0 < xs.length ? (
            xs.slice(1)
            .reduce((a, x) => 0 < f(x, a) ? x : a, xs[0])
        ) : undefined;

    // not :: Bool -> Bool
    const not = b => !b;

    // quot :: Int -> Int -> Int
    const quot = (n, m) => Math.floor(n / m);

    // quotRem :: Int -> Int -> (Int, Int)
    const quotRem = (m, n) =>
        Tuple(Math.floor(m / n), m % n);

    // rem :: Int -> Int -> Int
    const rem = (n, m) => n % m;

    // replicate :: Int -> a -> [a]
    const replicate = (n, x) =>
        Array.from({
            length: n
        }, () => x);

    // replicateString :: Int -> String -> String
    const replicateString = (n, s) => s.repeat(n);

    // showIntAtBase :: Int -> (Int -> [String])
    //               -> Int -> [[String]] -> [[String]]
    const showIntAtBase = (base, toStr, n, rs) => {
        const go = ([n, d], r) => {
            const r_ = cons(toStr(d), r);
            return 0 !== n ? (
                go(Array.from(quotRem(n, base)), r_)
            ) : r_;
        };
        return go(Array.from(quotRem(n, base)), rs);
    };

    // transpose :: [[a]] -> [[a]]
    const transpose = tbl => {
        const
            gaps = replicate(
                length(maximumBy(comparing(length), tbl)), []
            ),
            rows = map(xs => xs.concat(gaps.slice(xs.length)), tbl);
        return map(
            (_, col) => concatMap(row => [row[col]], rows),
            rows[0]
        );
    };

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // MAIN ---
    return main();
})();


package main

import (
    "crypto/md5"
    "fmt"
)

func main() {
    for _, p := range [][2]string{
        // RFC 1321 test cases
        {"d41d8cd98f00b204e9800998ecf8427e", ""},
        {"0cc175b9c0f1b6a831c399e269772661", "a"},
        {"900150983cd24fb0d6963f7d28e17f72", "abc"},
        {"f96b697d7cb7938d525a2f31aaf161d0", "message digest"},
        {"c3fcd3d76192e4007dfb496cca67e13b", "abcdefghijklmnopqrstuvwxyz"},
        {"d174ab98d277d9f5a5611c2c9f419d9f",
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
        {"57edf4a22be3c955ac49da2e2107b67a", "12345678901234567890" +
            "123456789012345678901234567890123456789012345678901234567890"},
        // test case popular with other RC solutions
        {"e38ca1d920c4b8b8d3946b2c72f01680",
            "The quick brown fox jumped over the lazy dog's back"},
    } {
        validate(p[0], p[1])
    }
}

var h = md5.New()

func validate(check, s string) {
    h.Reset()
    h.Write([]byte(s))
    sum := fmt.Sprintf("%x", h.Sum(nil))
    if sum != check {
        fmt.Println("MD5 fail")
        fmt.Println("  for string,", s)
        fmt.Println("  expected:  ", check)
        fmt.Println("  got:       ", sum)
    }
}


import java.security.MessageDigest

String.metaClass.md5Checksum = {
    MessageDigest.getInstance('md5').digest(delegate.bytes).collect { String.format("%02x", it) }.join('')
}


def m:
{ ul: "╔",
  uc: "╦",
  ur: "╗",
  ll: "╚",
  lc: "╩",
  lr: "╝",
  hb: "═",
  vb: "║",

  m0: " Θ  ",
  m5: "────"
};

def mayan: [
    "    ",
    " ∙  ",
    " ∙∙ ",
    "∙∙∙ ",
    "∙∙∙∙"
];

# decimal number to base-20 array, most significant digit first
def dec2vig:
  [recurse(if . > 0 then ./20|floor else empty end) | . % 20]
  | if length > 1 then .[:-1] else . end
  | reverse;

def vig2quin:
  if . >= 20 then "Cannot convert a number >= 20." | error
  else . as $n
  | [mayan[0], mayan[0], mayan[0], mayan[0]]
  | if $n == 0
    then .[3] = m.m0
    else (($n/5)|floor) as $fives
    | ($n % 5) as $rem
    | .[3-$fives] = mayan[$rem]
    | reduce range(3; 3-$fives; -1) as $i (.; .[$i] = m.m5)
    end
  end;

def draw($mayans):
  ($mayans|length) as $lm
  | (reduce range(0; $lm) as $i (m.ul;
       . + m.hb * 4 + if $i < $lm - 1 then m.uc else m.ur + "\n" end ) )
    + (reduce range(1; 5) as $i ("";
         . + m.vb
         + (reduce range(0; $lm) as $j ("";
              . + $mayans[$j][$i-1] + m.vb)) + "\n" ) )
    + (reduce range(0; $lm) as $i (m.ll;
        . + (m.hb * 4)
          + if ($i < $lm - 1) then m.lc else m.lr + "\n" end ) );

def decimal2mayan:
  "Converting \(.) to Mayan:",
  draw(dec2vig | map( vig2quin ) ),
  "" ;

4005, 8017, 326205, 886205, 1081439556
| decimal2mayan


using Gumbo

mayan_glyphs(x, y) = (x == 0 && y == 0) ? "\nΘ	\n" : "\n" * "●" ^ x * "
\n───" ^ y * "	\n"

inttomayan(n) = (s = string(n, base=20); map(ch -> reverse(divrem(parse(Int, ch, base=20), 5)), split(s, "")))

function testmayan()
    startstring = """\n

\n"""

    txt = startstring

    for n in [4005, 8017, 326205, 886205, 70913241, 2147483647]
    txt *= "
The Mayan representation for the integer $n is:

" *
            join(map(x -> mayan_glyphs(x[1], x[2]), inttomayan(n))) * "

\n\n"
    end

    println(parsehtml(txt))
end

testmayan()


ClearAll[MakeLengthFive, MayanNumeral]
MakeLengthFive[ci_String] := Module[{c},
  c = If[EvenQ[StringLength[ci]], ci <> " ", ci];
  While[StringLength[c] < 5, c = " " <> c <> " "];
  c
  ]
MayanNumeral[n_Integer?Positive] := Module[{nums, q, r, c},
  nums = IntegerDigits[n, 20];
  Row[Table[
    {q, r} = QuotientRemainder[m, 5];
    If[{q, r} =!= {0, 0},
     c = Prepend[ConstantArray["-----", q], StringJoin[ConstantArray[".", r]]];
     c = Join[ConstantArray["", 4 - Length[c]], c];
     c
     ,
     c = {"", "", "", "\[Theta]"}
     ];
    Column[MakeLengthFive /@ c, Frame -> True]
    ,
    {m, nums}
    ], Spacer[1]]
  ]
MayanNumeral[4005]
MayanNumeral[8017]
MayanNumeral[326205]
MayanNumeral[886205]
MayanNumeral[1337]


import algorithm

type Border = enum UL = "╔", UC = "╦", UR = "╗", LL = "╚", LC = "╩", LR = "╝", HB = "═", VB = "║"

const

  Mayan = ["    ", " ∙  ", " ∙∙ ", "∙∙∙ ", "∙∙∙∙"]

  M0 = " Θ  "
  M5 = "────"

type
  Digit = range[0..19]
  Numeral = array[4, string]
  MayanNumber = seq[Numeral]

func toBase20(n: Natural): seq[Digit] =
  ## Return "n" expressed as a sequence of base 20 digits.
  result.add(n mod 20)
  var n = n div 20
  while n != 0:
    result.add n mod 20
    n = n div 20
  result.reverse()

func toMayanNumeral(d: Digit): Numeral =
  ## Return the Numeral representing a base 20 digits.

  result = [Mayan[0], Mayan[0], Mayan[0], Mayan[0]]
  if d == 0:
    result[3] = M0
    return

  var d = d
  for i in countdown(3, 0):
    if d >= 5:
      result[i] = M5
      dec d, 5
    else:
      result[i] = Mayan[d]
      break

proc draw(mayans: MayanNumber) =
  ## Draw the representation fo a mayan number.

  let idx = mayans.high

  stdout.write UL
  for i in 0..idx:
    for j in 0..3: stdout.write HB
    if i < idx: stdout.write UC else: echo UR

  for i in 1..4:
    stdout.write VB
    for j in 0..idx: stdout.write mayans[j][i-1], VB
    stdout.write '\n'

  stdout.write LL
  for i in 0..idx:
    for j in 0..3: stdout.write HB
    if i < idx: stdout.write LC else: echo LR

when isMainModule:

  import sequtils, strutils

  for n in [4005, 8017, 326205, 886205, 1081439556]:
    echo "Converting $1 to Mayan:".format(n)
    let digits = n.toBase20()
    let mayans = digits.mapIt(it.toMayanNumeral)
    mayans.draw()
    echo ""


use ntheory qw/fromdigits todigitstring/;

my $t_style = '"border-collapse: separate; text-align: center; border-spacing: 3px 0px;"';
my $c_style = '"border: solid black 2px;background-color: #fffff0;border-bottom: double 6px;'.
  'border-radius: 1em;-moz-border-radius: 1em;-webkit-border-radius: 1em;'.
  'vertical-align: bottom;width: 3.25em;"';

sub cartouches {
    my($num, @digits) = @_;
    my $render;
    for my $d (@digits) {
        $render .= "| style=$c_style | $_\n" for glyphs(@$d);
    }
    chomp $render;
    join "\n", "\{| style=$t_style", "|+ $num", '|-', $render, '|}'
}

sub glyphs {
    return 'Θ' unless $_[0] || $_[1];
    join '
', '●' x $_[0], ('───') x $_[1];
}

sub mmod {
    my($n,$b) = @_;
    my @nb;
    return 0 unless $n;
    push @nb, fromdigits($_, $b) for split '', todigitstring($n, $b);
    return @nb;
}

for $n (qw<4005 8017 326205 886205 26960840421>) {
    push @output, cartouches($n, map { [reverse mmod($_,5)] } mmod($n,20) );
}

print join "\n
\n", @output;


import Data.Digest.OpenSSL.MD5 (md5sum)
import Data.ByteString (pack)
import Data.Char (ord)

main = do
  let message = "The quick brown fox jumped over the lazy dog's back"
      digest  = (md5sum . pack . map (fromIntegral . ord)) message
  putStrLn digest


import haxe.crypto.Md5;

class Main {
  static function main() {
    var md5 = Md5.encode("The quick brown fox jumped over the lazy dog's back");
    Sys.println(md5);
  }
}


/* MAYAN NUMERALS IN PL/M

   THIS PROGRAM RUNS UNDER CP/M AND TAKES THE NUMBER ON THE COMMAND LINE */
100H:
/* CP/M CALLS */
BDOS: PROCEDURE (FN, ARG); DECLARE FN BYTE, ARG ADDRESS; GO TO 5; END BDOS;
EXIT: PROCEDURE; CALL BDOS(0,0); END EXIT;
PRINT: PROCEDURE (S); DECLARE S ADDRESS; CALL BDOS(9,S); END PRINT;

/* CP/M COMMAND LINE */
DECLARE CL$PTR ADDRESS INITIAL (80H), CMD$LEN BASED CL$PTR BYTE;
DECLARE CMD$PTR ADDRESS INITIAL (81H), CMD$LINE BASED CMD$PTR BYTE;

/* THE PIPE AND AT SYMBOLS ARE NOT INCLUDED IN THE PL/M CHARSET */
DECLARE PIPE LITERALLY '7CH', AT LITERALLY '40H';

/* PRINT BORDER FOR N DIGITS */
BORDER: PROCEDURE (N);
    DECLARE (I, N) BYTE;
    DO I=1 TO N;
        CALL PRINT(.'+----$');
    END;
    CALL PRINT(.('+',13,10,'$'));
END BORDER;

/* PRINT LINE FOR GIVEN DIGIT */
DIGIT$LINE: PROCEDURE (LINE, DIGIT);
    DECLARE (I, LINE, DIGIT, UPB) BYTE;
    DECLARE PARTS (6) ADDRESS;
    PARTS(0) = .(PIPE,'    $'); PARTS(1) = .(PIPE,' .  $');
    PARTS(2) = .(PIPE,' .. $'); PARTS(3) = .(PIPE,'... $');
    PARTS(4) = .(PIPE,'....$'); PARTS(5) = .(PIPE,'----$');

    IF DIGIT = 0 THEN DO;
        IF LINE = 3 THEN CALL PRINT(.(PIPE,' ',AT,'  $'));
        ELSE CALL PRINT(PARTS(0));
    END;
    ELSE DO;
        UPB = 15-LINE*5;
        IF DIGIT < UPB THEN CALL PRINT(PARTS(0));
        ELSE IF DIGIT >= UPB+5 THEN CALL PRINT(PARTS(5));
        ELSE CALL PRINT(PARTS(DIGIT-UPB));
    END;
END DIGIT$LINE;

/* PRINT LINE GIVEN DIGITS */
LINE: PROCEDURE (L, DIGITS, NDIGITS);
    DECLARE DIGITS ADDRESS;
    DECLARE (L, I, D BASED DIGITS, NDIGITS) BYTE;
    DO I=0 TO NDIGITS-1;
        CALL DIGIT$LINE(L, D(I));
    END;
    CALL PRINT(.(PIPE,13,10,'$'));
END LINE;

/* CHECK FOR ARGUMENT */
IF CMD$LEN < 2 THEN DO;
    CALL PRINT(.'NO INPUT$');
    CALL EXIT;
END;

/* PREPROCESS COMMAND LINE - TURN EACH ASCII DIGIT INTO 0-9 */
DECLARE (I, J) BYTE;
DO I = 1 TO CMD$LEN-1;
    CMD$LINE(I) = CMD$LINE(I) - '0';
    IF CMD$LINE(I) > 9 THEN DO;
        /* ERROR MESSAGE FOR INVALID INPUT */
        CALL PRINT(.'INVALID DIGIT IN INPUT$');
        CALL EXIT;
    END;
END;

/* CONVERT TO BASE 20 DIGIT BY DIGIT */
J = CMD$LEN-2;
DO WHILE J > 0;
    DO I = 1 TO J;
        CMD$LINE(I+1) = CMD$LINE(I+1) + 10*(CMD$LINE(I) AND 1);
        CMD$LINE(I) = CMD$LINE(I) / 2;
    END;
    J = J - 1;
END;

/* FIND FIRST NONZERO DIGIT */
J = 1;
DO WHILE CMD$LINE(J) = 0 AND J < CMD$LEN-1;
    J = J + 1;
END;

/* PRINT CARTOUCHES */
DECLARE SIZE BYTE;
SIZE = CMD$LEN-J;
CALL BORDER(SIZE);
DO I=0 TO 3;
    CALL LINE(I, .CMD$LINE(J), SIZE);
END;
CALL BORDER(SIZE);

CALL EXIT;
EOF


-- demo\rosetta\Mayan_numerals.exw
without js -- (file i/o [when as_html is true])
constant as_html = true,        -- false == nasty ascii
         inline_css = true      -- also uses wiki tables ({| etc) if false

string html = ""

constant t_style = "border-collapse: separate; text-align: center; border-spacing: 3px 0px;",
         c_style = "border: solid black 2px;background-color: #fffff0;border-bottom: double 6px;"&
                   "border-radius: 1em;-moz-border-radius: 1em;-webkit-border-radius: 1em;"&
                   "vertical-align: bottom;width: 3.25em;",
         dot = "●",
         bar = "───",
         zero = "Θ",
         digits = {" 0  "," .  "," .. ","... ","...."}

function to_seq(atom a)
    sequence s = {}
    while true do
        s = prepend(s,remainder(a,20))
        a = floor(a/20)
        if a=0 then exit end if
    end while
    return s
end function

procedure show_mayan(atom a)
    sequence s = to_seq(a)
    if not as_html then
        string tb = join(repeat('+',length(s)+1),"------"),
               ln = join(repeat('|',length(s)+1),"      ")
        sequence res = {tb,ln,ln,ln,ln,tb}
        for i=1 to length(s) do
            integer si = s[i], l = 5, m = i*7-4
            while true do
                res[l][m..m+3] = digits[min(si+1,5)]
                si -= 5
                if si<=0 then exit end if
                l -= 1
            end while
        end for
        printf(1,"%d\n%s\n\n",{a,join(res,"\n")})
    else
        for i=1 to length(s) do
            sequence res = repeat("",4)
            integer si = s[i], l = 4
            while true do
                res[l] = iff(si>=5?bar:iff(si?join(repeat(dot,si),""):zero))
                si -= 5
                if si<=0 then exit end if
                l -= 1
            end while
            s[i] = join(res,"
")
        end for
        if inline_css then
            html &= sprintf("
\n
%d
\n
\n",a)
            for i=1 to length(s) do
                html &= sprintf("    %s	\n",{s[i]})
            end for
            html &= "
\n
\n"
        else
            html &= sprintf("{| style=\"%s\"\n|+ %d\n|-\n",{t_style,a})
            for i=1 to length(s) do
                html &= sprintf("| style=\"%s\" | %s\n",{c_style,s[i]})
            end for
            html &= "|}\n"
        end if
    end if
end procedure

constant html_header = """
<!DOCTYPE html>

  <meta charset="utf-8" />
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>Mayan numerals</title>

Mayan numerals

""",
wiki_header = """
The following is intended to be pasted into the rosettacode wiki, or similar

""",
html_footer = """

"""

constant tests = {4005, 8017, 326205, 886205, 26960840421, 126524984376952}

for i=1 to length(tests) do show_mayan(tests[i]) end for

if as_html then
    string filename = "Mayan_numerals.html"
    integer fn = open(filename,"w")
    if inline_css then
        printf(fn,html_header,{t_style,c_style})
    else
        printf(fn,wiki_header)
    end if
    puts(fn,html)
    if inline_css then
        puts(fn,html_footer)
    end if
    close(fn)
    if inline_css then
        system(filename)
    else
        printf(1,"See %s\n",{filename})
        {} = wait_key()
    end if
else
    ?"done"
    {} = wait_key()
end if


procedure main()  # validate against the RFC test strings and more
   testMD5("The quick brown fox jumps over the lazy dog", 16r9e107d9d372bb6826bd81d3542a419d6)
   testMD5("The quick brown fox jumps over the lazy dog.", 16re4d909c290d0fb1ca068ffaddf22cbd0)
   testMD5("", 16rd41d8cd98f00b204e9800998ecf8427e)
end

procedure testMD5(s,rh)  # compute the MD5 hash and compare it to reference value
   write("Message(length=",*s,") = ",image(s))
   write("Digest = ",hexstring(h := MD5(s)),if h = rh then " matches reference hash" else (" does not match reference hash = " || hexstring(rh)),"\n")
end


Io> MD5
==>  MD5_0x97663e0:
  appendSeq        = MD5_appendSeq()
  md5              = MD5_md5()
  md5String        = MD5_md5String()
Io> MD5 clone appendSeq("The quick brown fox jumped over the lazy dog's back") md5String
==> e38ca1d920c4b8b8d3946b2c72f01680


#START_X=-4 : #START_Y=2
Dim pl$(5)
pl$(0)=" Θ  " : pl$(1)=" •  " : pl$(2)=" •• "
pl$(3)="••• " : pl$(4)="••••" : pl$(5)="‒‒‒‒"
If OpenConsole() : EnableGraphicalConsole(1) : Else : End 1 : EndIf

Procedure.s Dec2Mayan(wert.i)
  result$=""
  If wert=0 : result$="0;" : EndIf
  While wert : result$=Str(wert%20)+";"+result$ : wert/20 : Wend
  ProcedureReturn result$
EndProcedure

Procedure PutMayan(may$)
  Shared pl$()
  X=#START_X+6 : Y=#START_Y
  For i=1 To CountString(may$,";")
    m=Val(StringField(may$,i,";"))
    yp=Y+4
    If m=0 : ConsoleLocate(X,yp) : Print(pl$(0)) : X+5 : Continue : EndIf
    While m
      If m-5>=0
        ConsoleLocate(X,yp) : Print(pl$(5)) : yp-1 : m-5
      ElseIf m-4>=0
        ConsoleLocate(X,yp) : Print(pl$(4)) : yp-1 : m-4
      ElseIf m-3>=0
        ConsoleLocate(X,yp) : Print(pl$(3)) : yp-1 : m-3
      ElseIf m-2>=0
        ConsoleLocate(X,yp) : Print(pl$(2)) : yp-1 : m-2
      ElseIf m-1>=0
        ConsoleLocate(X,yp) : Print(pl$(1)) : yp-1 : m-1
      EndIf
    Wend
    X+5
  Next
EndProcedure

Procedure MayanNumerals(may$)
  X=#START_X : Y=#START_Y
  m.i=CountString(may$,";")
  For i=1 To m
    X+5
    ConsoleLocate(X,Y)    : Print("╔════╗")
    ConsoleLocate(X,Y+1)  : Print("║    ║")
    ConsoleLocate(X,Y+2)  : Print("║    ║")
    ConsoleLocate(X,Y+3)  : Print("║    ║")
    ConsoleLocate(X,Y+4)  : Print("║    ║")
    ConsoleLocate(X,Y+5)  : Print("╚════╝")
  Next
  X=#START_X
  For i=1 To m
    X+5
    If i<m
      ConsoleLocate(X+5,Y)   : Print("╦")
      ConsoleLocate(X+5,Y+5) : Print("╩")
    EndIf
  Next
  PutMayan(may$)
EndProcedure

Repeat
  ConsoleLocate(0,0)          : Print(LSet(" ",60))
  ConsoleLocate(0,0)          : Print("MAYAN: ? ") : i$=Input()
  ClearConsole()              : If i$="" : End : EndIf
  j$=Dec2Mayan(Val(i$))       : MayanNumerals(j$)
  ConsoleLocate(0,#START_Y+7) : Print("Dezimal  = "+i$)
  ConsoleLocate(0,#START_Y+8) : Print("Vigesimal= "+j$)
ForEver


   require 'convert/misc/md5'
   md5 'The quick brown fox jumped over the lazy dog''s back'
e38ca1d920c4b8b8d3946b2c72f01680


import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Digester {

    public static void main(String[] args) {
        System.out.println(hexDigest("Rosetta code", "MD5"));
    }

    static String hexDigest(String str, String digestName) {
        try {
            MessageDigest md = MessageDigest.getInstance(digestName);
            byte[] digest = md.digest(str.getBytes(StandardCharsets.UTF_8));
            char[] hex = new char[digest.length * 2];
            for (int i = 0; i < digest.length; i++) {
                hex[2 * i] = "0123456789abcdef".charAt((digest[i] & 0xf0) >> 4);
                hex[2 * i + 1] = "0123456789abcdef".charAt(digest[i] & 0x0f);
            }
            return new String(hex);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException(e);
        }
    }
}


'''Mayan numerals'''

from functools import (reduce)

# -------------------- MAYAN NUMERALS --------------------

# mayanNumerals :: Int -> [[String]]
def mayanNumerals(n):
    '''Rows of Mayan digit cells,
       representing the integer n.
    '''
    return showIntAtBase(20)(
        mayanDigit
    )(n)([])

# mayanDigit :: Int -> [String]
def mayanDigit(n):
    '''List of strings representing a Mayan digit.'''
    if 0 < n:
        r = n % 5
        return [
            (['●' * r] if 0 < r else []) +
            (['━━'] * (n // 5))
        ]
    else:
        return ['Θ']

# mayanFramed :: Int -> String
def mayanFramed(n):
    '''Mayan integer in the form of a
       Wiki table source string.
    '''
    return 'Mayan ' + str(n) + ':\n\n' + (
        wikiTable({
            'class': 'wikitable',
            'style': cssFromDict({
                'text-align': 'center',
                'background-color': '#F0EDDE',
                'color': '#605B4B',
                'border': '2px solid silver'
            }),
            'colwidth': '3em',
            'cell': 'vertical-align: bottom;'
        })([[
            '<br>'.join(col) for col in mayanNumerals(n)
        ]])
    )

# ------------------------- TEST -------------------------

# main :: IO ()
def main():
    '''Mayan numeral representations of various integers'''
    print(
        main.__doc__ + ':\n\n' +
        '\n'.join(mayanFramed(n) for n in [
            4005, 8017, 326205, 886205, 1081439556,
            1000000, 1000000000
        ])
    )

# ------------------------ BOXES -------------------------

# wikiTable :: Dict -> [[a]] -> String
def wikiTable(opts):
    '''Source text for wiki-table display of rows of cells,
       using CSS key-value pairs in the opts dictionary.
    '''
    def colWidth():
        return 'width:' + opts['colwidth'] + '; ' if (
            'colwidth' in opts
        ) else ''

    def cellStyle():
        return opts['cell'] if 'cell' in opts else ''

    return lambda rows: '{| ' + reduce(
        lambda a, k: (
            a + k + '="' + opts[k] + '" ' if (
                k in opts
            ) else a
        ),
        ['class', 'style'],
        ''
    ) + '\n' + '\n|-\n'.join(
        '\n'.join(
            ('|' if (
                0 != i and ('cell' not in opts)
            ) else (
                '|style="' + colWidth() + cellStyle() + '"|'
            )) + (
                str(x) or ' '
            ) for x in row
        ) for i, row in enumerate(rows)
    ) + '\n|}\n\n'

# ----------------------- GENERIC ------------------------

# cssFromDict :: Dict -> String
def cssFromDict(dct):
    '''CSS string from a dictinary of key-value pairs'''
    return reduce(
        lambda a, k: a + k + ':' + dct[k] + '; ',
        dct.keys(),
        ''
    )

# showIntAtBase :: Int -> (Int -> String)
# -> Int -> String -> String
def showIntAtBase(base):
    '''String representation of an integer in a given base,
       using a supplied function for the string
       representation of digits.
    '''
    def wrap(toChr, n, rs):
        def go(nd, r):
            n, d = nd
            r_ = toChr(d) + r
            return go(divmod(n, base), r_) if 0 != n else r_
        return 'unsupported base' if 1 >= base else (
            'negative number' if 0 > n else (
                go(divmod(n, base), rs))
        )
    return lambda toChr: lambda n: lambda rs: (
        wrap(toChr, n, rs)
    )

# MAIN ---
if __name__ == '__main__':
    main()


using Nettle

function Base.trunc(s::AbstractString, n::Integer)
    n > 0 || throw(DomainError())
    l = length(s)
    l > n || return s
    n > 3 || return s[1:n]
    return s[1:n-3] * "..."
end

tests = [""    => "d41d8cd98f00b204e9800998ecf8427e",
         "a"   => "0cc175b9c0f1b6a831c399e269772661",
         "abc" => "900150983cd24fb0d6963f7d28e17f72",
         "message digest" => "f96b697d7cb7938d525a2f31aaf161d0",
         "abcdefghijklmnopqrstuvwxyz" => "c3fcd3d76192e4007dfb496cca67e13b",
         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" =>
         "d174ab98d277d9f5a5611c2c9f419d9f",
         "12345678901234567890123456789012345678901234567890123456789012345678901234567890" =>
         "57edf4a22be3c955ac49da2e2107b67a",
         "foobad" => "3858f62230ac3c915f300c664312c63f"]

println("Testing Julia's MD5 hash against RFC 1321.")
for (k, h) in sort(tests, by = length ∘ first)
    md5sum = hexdigest("md5", k)
    @printf("%20s → %s ", trunc(k, 15), md5sum)
    if md5sum == h
        println("MD5 OK")
    else
        println("MD5 Bad")
        println("* The sum should be  ", h)
    end
end


// version 1.0.6

import java.security.MessageDigest

fun main(args: Array<String>) {
    val text  = "The quick brown fox jumped over the lazy dog's back"
    val bytes = text.toByteArray()
    val md = MessageDigest.getInstance("MD5")
    val digest = md.digest(bytes)
    for (byte in digest) print("%02x".format(byte))
    println()
}


### Formatting ###
my $t-style = '"border-collapse: separate; text-align: center; border-spacing: 3px 0px;"';
my $c-style = '"border: solid black 2px;background-color: #fffff0;border-bottom: double 6px;'~
  'border-radius: 1em;-moz-border-radius: 1em;-webkit-border-radius: 1em;'~
  'vertical-align: bottom;width: 3.25em;"';
my $joiner = '<br>';

sub display ($num, @digits) { join "\n", "\{| style=$t-style", "|+ $num", '|-', (|@digits.map: {"| style=$c-style | $_"}), '|}' }

### Logic ###

sub mayan ($int) { $int.polymod(20 xx *).reverse.map: *.polymod(5) }

my @output = <4005 8017 326205 886205 16160025 1081439556 503491211079>.map: {
  display $_, .&mayan.map: { [flat '' xx 3, '●' x .[0], '───' xx .[1], ('Θ' if !.[0,1].sum)].tail(4).join: $joiner }
}

say @output.join: "\n$joiner\n";


/*REXX program converts decimal numbers to the Mayan numbering system (with cartouches).*/
parse arg $                                      /*obtain optional arguments from the CL*/
if $=''  then $= 4005  8017  326205  886205,     /*Not specified?  Then use the default.*/
                 172037122592320200101           /*Morse code for MAYAN; egg is a blank.*/

  do j=1  for words($)                           /*convert each of the numbers specified*/
  #= word($, j)                                  /*extract a number from (possible) list*/
  say
  say  center('converting the decimal number '     #     " to a Mayan number:", 90,  '─')
  say
  call $MAYAN   #   '(overlap)'                  /*invoke the  $MAYAN (REXX) subroutine.*/
  say
  end   /*j*/                                    /*stick a fork in it,  we're all done. */


Encrypt_MD5('Welcome all Rhinos!')
//80ba88ee2600e9e9b36e739458c39ebd


'[RC]MD5
    'from tsh73's January 2008 code

    text$="The quick brown fox jumps over the lazy dog"
    checkSum$="9e107d9d372bb6826bd81d3542a419d6"

    print text$
    print checkSum$

    test$=md5$(text$)

    if test$=checkSum$ then
        print "passed"
        print test$
    else
        print "failed"
    end if
    end

    function md5$(text$)

        dim r(64)
        dim k(64)
        dim w(16)
        global two32
        two32=2^32

        'prepare the MD5 checksum table
        restore [perRoundShiftAmounts]
        for i=0 to 63
            read x
            r(i)=x
        next

        'prepare constants
        for i=0 to 63
            k(i) =  int(abs(sin(i+1)) * two32)
        next

        'initialise variables
        h0 = HEXDEC("67452301")
        h1 = HEXDEC("EFCDAB89")
        h2 = HEXDEC("98BADCFE")
        h3 = HEXDEC("10325476")

        'find num bits in message
        numbits=len(text$)*8

        'add bits "10000000"
        text$=text$+chr$(128)

        'add bits "00000000"
        while len(text$) mod 64 <> 56
            text$=text$+chr$(0)
        wend

        'add original length in bits
        text$=text$+dec2asc$(numbits)

        'MD5 rounds
        'process in 64 byte chunks 512bits
        for chunk = 1 to len(text$) step 64
            chunk$ = mid$(text$, chunk, 64)
            for word = 0 TO 15
                'invert byte order
                b0 = asc(mid$(chunk$, word*4+1, 1))
                b1 = asc(mid$(chunk$, word*4+2, 1))
                b2 = asc(mid$(chunk$, word*4+3, 1))
                b3 = asc(mid$(chunk$, word*4+4, 1))
                w(word) = ((b3*256+b2)*256+b1)*256+b0
            next word
            a = h0
            b = h1
            c = h2
            d = h3
            for i = 0 to 63
                select case
                    case 0 <= i and i <= 15
                        f = (b and c) or (bitNot(b) and d)
                        g = i
                    case 16 <= i and i <= 31
                        f = (d and b) or (bitNot(d) and c)
                        g = (5 * i + 1) mod 16
                    case 32 <= i and i <= 47
                        f = b xor c xor d
                        g = (3 * i + 5) mod 16
                    case 48 <= i and i <= 63
                        f = c xor (b or bitNot(d))
                        g = (7 * i) mod 16
                end select
                temp = d
                d = c
                c = b
                b=b+leftrotate(a + f + k(i) + w(g),r(i))
                b = b mod two32
                a = temp
            next i
            h0 = (h0 + a) mod two32
            h1 = (h1 + b) mod two32
            h2 = (h2 + c) mod two32
            h3 = (h3 + d) mod two32
        next chunk

        md5$ =  revOrd$(DECHEX$(h0))+_
                revOrd$(DECHEX$(h1))+_
                revOrd$(DECHEX$(h2))+_
                revOrd$(DECHEX$(h3))

        [perRoundShiftAmounts]
        DATA 7,12,17,22, 7,12,17,22, 7,12,17,22, 7,12,17,22
        DATA 5, 9,14,20, 5, 9,14,20, 5, 9,14,20, 5, 9,14,20
        DATA 4,11,16,23, 4,11,16,23, 4,11,16,23, 4,11,16,23
        DATA 6,10,15,21, 6,10,15,21, 6,10,15,21, 6,10,15,21

    end function

    ' dec2asc: dec to 8 byte asc
    function dec2asc$(n)
        h$ = ""
        for i = 1 to 8
            h$ = h$ + chr$(n mod 256)
            n = int(n/256)
        next
        dec2asc$= h$
    end function

    ' bitNot
    function bitNot(num)
        bitNot = two32 -1 -num
    end function

    ' leftrotate: spins bits left n times
    function leftrotate(num,times)
        num=num mod two32
        r = (num*2^times) mod two32
        l = int(num/(2^(32-times)))
        leftrotate = r+l
    end function

    ' reverse the HEXDEC$ order
    function revOrd$(a$)
        a$=left$("00000000", 8-len(a$))+a$
        revOrd$ = lower$(mid$(a$,7,2)+mid$(a$,5,2)+mid$(a$,3,2)+mid$(a$,1,2))
    end function


numbers = ARGV.map(&:to_i)
if numbers.length == 0
  puts
  puts("usage: #{File.basename(__FILE__)} number...")
  exit
end

def maya_print(number)
  digits5s1s = number.to_s(20).chars.map { |ch| ch.to_i(20) }.map { |dig| dig.divmod(5) }
  puts(('+----' * digits5s1s.length) + '+')
  3.downto(0) do |row|
    digits5s1s.each do |d5s1s|
      if row < d5s1s[0]
        print('|----')
      elsif row == d5s1s[0]
        print("|#{[(d5s1s[0] == 0 ? ' @  ' : '    '), ' .  ', ' .. ', '... ', '....'][d5s1s[1]]}")
      else
        print('|    ')
      end
    end
    puts('|')
  end
  puts(('+----' * digits5s1s.length) + '+')
end

numbers.each do |num|
  puts(num)
  maya_print(num)
end


const ONE: &str = "●";
const FIVE: &str = "——";
const ZERO: &str = "Θ";

fn main() {
    println!("{}", mayan(4005));
    println!("{}", mayan(8017));
    println!("{}", mayan(326_205));
    println!("{}", mayan(886_205));
    println!("{}", mayan(69));
    println!("{}", mayan(420));
    println!("{}", mayan(1_063_715_456));
}

fn mayan(dec: i64) -> String {
    let mut digits = vec![];
    let mut num = dec;
    while num > 0 {
        digits.push(num % 20);
        num /= 20;
    }
    digits = digits.into_iter().rev().collect();
    let mut boxes = vec!["".to_string(); 6];
    let n = digits.len();
    for (i, digit) in digits.iter().enumerate() {
        if i == 0 {
            boxes[0] = "┏━━━━".to_string();
            if i == n - 1 {
                boxes[0] += "┓";
            }
        } else if i == n - 1 {
            boxes[0] += "┳━━━━┓";
        } else {
            boxes[0] += "┳━━━━";
        }
        for j in 1..5 {
            boxes[j] += "┃";
            let elem = 0.max(digit - (4 - j as i64) * 5);
            if elem >= 5 {
                boxes[j] += &format!("{: ^4}", FIVE);
            } else if elem > 0 {
                boxes[j] += &format!("{: ^4}", ONE.repeat(elem as usize % 15));
            } else if j == 4 {
                boxes[j] += &format!("{: ^4}", ZERO);
            } else {
                boxes[j] += &"    ";
            }
            if i == n - 1 {
                boxes[j] += "┃";
            }
        }
        if i == 0 {
            boxes[5] = "┗━━━━".to_string();
            if i == n - 1 {
                boxes[5] += "┛";
            }
        } else if i == n - 1 {
            boxes[5] += "┻━━━━┛";
        } else {
            boxes[5] += "┻━━━━";
        }
    }

    let mut mayan = format!("Mayan {}:\n", dec);
    for b in boxes {
        mayan += &(b + "\n");
    }
    mayan
}


import "/fmt" for Conv

var ul = "╔"
var uc = "╦"
var ur = "╗"
var ll = "╚"
var lc = "╩"
var lr = "╝"
var hb = "═"
var vb = "║"

var mayan= [
    "    ",
    " ∙  ",
    " ∙∙ ",
    "∙∙∙ ",
    "∙∙∙∙"
]

var m0 = " Θ  "
var m5 = "────"

var dec2vig = Fn.new { |n| Conv.itoa(n, 20).map { |c| Conv.atoi(c, 20) }.toList }

var vig2quin = Fn.new { |n|
    if (n >= 20) Fiber.abort("Cant't convert a number >= 20.")
    var res = [mayan[0], mayan[0], mayan[0], mayan[0]]
    if (n == 0) {
        res[3] = m0
        return res
    }
    var fives = (n/5).floor
    var rem = n % 5
    res[3-fives] = mayan[rem]
    for (i in 3...3-fives) res[i] = m5
    return res
}

var draw = Fn.new { |mayans|
    var lm = mayans.count
    System.write(ul)
    for (i in 0...lm) {
        for (j in 0..3) System.write(hb)
        if (i < lm - 1) {
            System.write(uc)
        } else {
            System.print(ur)
        }
    }
    for (i in 1..4) {
        System.write(vb)
        for (j in 0...lm) {
            System.write(mayans[j][i-1])
            System.write(vb)
        }
        System.print()
    }
    System.write(ll)
    for (i in 0...lm) {
        for (j in 0..3) System.write(hb)
        if (i < lm - 1) {
            System.write(lc)
        } else {
            System.print(lr)
        }
    }
}

var numbers = [4005, 8017, 326205, 886205, 1081439556]
for (n in numbers) {
    System.print("Converting %(n) to Mayan:")
    var vigs = dec2vig.call(n)
    var mayans = vigs.map { |vig| vig2quin.call(vig) }.toList
    draw.call(mayans)
    System.print()
}


function md5sum hashtext
    local md5, mdhex
    put md5Digest(hashtext) into md5
    get binaryDecode("H*",md5,mdhex)
    return mdhex
end md5sum


require "md5"

--printing a sum:
print(md5.sumhexa"The quick brown fox jumps over the lazy dog")

--running the test suite:

local function test(msg,sum) assert(md5.sumhexa(msg)==sum) end

test("","d41d8cd98f00b204e9800998ecf8427e")
test("a","0cc175b9c0f1b6a831c399e269772661")
test("abc","900150983cd24fb0d6963f7d28e17f72")
test("message digest","f96b697d7cb7938d525a2f31aaf161d0")
test("abcdefghijklmnopqrstuvwxyz","c3fcd3d76192e4007dfb496cca67e13b")
test("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789","d174ab98d277d9f5a5611c2c9f419d9f")
test("12345678901234567890123456789012345678901234567890123456789012345678901234567890","57edf4a22be3c955ac49da2e2107b67a")


Hash["The quick brown fox jumped over the lazy dog's back","MD5","HexString"]


function digest = md5(message)
    % digest = md5(message)
    %  Compute the MD5 digest of the message, as a hexadecimal digest.

    % Follow the MD5 algorithm from RFC 1321 [1] and Wikipedia [2].
    %  [1] http://tools.ietf.org/html/rfc1321
    %  [2] http://en.wikipedia.org/wiki/MD5

    % m is the modulus for 32-bit unsigned arithmetic.
    m = 2 ^ 32;

    % s is the shift table for circshift(). Each shift is negative
    % because it is a left shift.
    s = [-7, -12, -17, -22
         -5,  -9, -14, -20
         -4, -11, -16, -23
         -6, -10, -15, -21];

    % t is the sine table. Each sine is a 32-bit integer, unsigned.
    t = floor(abs(sin(1:64)) .* m);

    % Initialize the hash, as a row vector of 32-bit integers.
    digest = [hex2dec('67452301') ...
              hex2dec('EFCDAB89') ...
              hex2dec('98BADCFE') ...
              hex2dec('10325476')];

    % If message contains characters, convert them to ASCII values.
    message = double(message);
    bytelen = numel(message);

    % Pad the message by appending a 1, then appending enough 0s to make
    % the bit length congruent to 448 mod 512. Because we have bytes, we
    % append 128 '10000000', then append enough 0s '00000000's to make
    % the byte length congruent to 56 mod 64.
    message = [message, 128, zeros(1, mod(55 - bytelen, 64))];

    % Convert the message to 32-bit integers, little endian.
    % For little endian, first byte is least significant byte.
    message = reshape(message, 4, numel(message) / 4);
    message = message(1,:) + ...            % least significant byte
              message(2,:) * 256 + ...
              message(3,:) * 65536 + ...
              message(4,:) * 16777216;      % most significant byte

    % Append the bit length as a 64-bit integer, little endian.
    bitlen = bytelen * 8;
    message = [message, mod(bitlen, m), mod(bitlen / m, m)];

    % Process each 512-bit block. Because we have 32-bit integers, each
    % block has 16 elements, message(k + (0:15)).
    for k = 1:16:numel(message)
        % Copy hash.
        a = digest(1); b = digest(2); c = digest(3); d = digest(4);

        % Do 64 operations.
        for i = (1:64)
            % Convert b, c, d to row vectors of bits (0s and 1s).
            bv = dec2bin(b, 32) - '0';
            cv = dec2bin(c, 32) - '0';
            dv = dec2bin(d, 32) - '0';

            % Find f  = mix of b, c, d.
            %      ki = index in 0:15, to message(k + ki).
            %      sr = row in 1:4, to s(sr, :).
            if i <= 16          % Round 1
                f = (bv & cv) | (~bv & dv);
                ki = i - 1;
                sr = 1;
            elseif i <= 32      % Round 2
                f = (bv & dv) | (cv & ~dv);
                ki = mod(5 * i - 4, 16);
                sr = 2;
            elseif i <= 48      % Round 3
                f = xor(bv, xor(cv, dv));
                ki = mod(3 * i + 2, 16);
                sr = 3;
            else                % Round 4
                f = xor(cv, bv | ~dv);
                ki = mod(7 * i - 7, 16);
                sr = 4;
            end

            % Convert f, from row vector of bits, to 32-bit integer.
            f = bin2dec(char(f + '0'));

            % Do circular shift of sum.
            sc = mod(i - 1, 4) + 1;
            sum = mod(a + f + message(k + ki) + t(i), m);
            sum = dec2bin(sum, 32);
            sum = circshift(sum, [0, s(sr, sc)]);
            sum = bin2dec(sum);

            % Update a, b, c, d.
            temp = d;
            d = c;
            c = b;
            b = mod(b + sum, m);
            a = temp;
        end %for i

        % Add hash of this block to hash of previous blocks.
        digest = mod(digest + [a, b, c, d], m);
    end %for k

    % Convert hash from 32-bit integers, little endian, to bytes.
    digest = [digest                % least significant byte
              digest / 256
              digest / 65536
              digest / 16777216];   % most significant byte
    digest = reshape(mod(floor(digest), 256), 1, numel(digest));

    % Convert hash to hexadecimal.
    digest = dec2hex(digest);
    digest = reshape(transpose(digest), 1, numel(digest));
end %md5


"The quick brown fox jumps over the lazy dog" md5 puts!


string = "The quick brown fox jumped over the lazy dog's back";
player:tell(string_hash(string));


/**
 MD5 in Neko
 Tectonics:
   nekoc md5.neko
   neko md5
*/

var MD5 = $loader.loadprim("[email protected]_md5", 1);
var base_encode = $loader.loadprim("[email protected]_encode", 2);

var result = MD5("The quick brown fox jumps over the lazy dog");

/* Output in lowercase hex */
$print(base_encode(result, "0123456789abcdef"));