summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorOri Bernstein <ori@eigenstate.org>2015-08-26 12:20:58 -0700
committerOri Bernstein <ori@eigenstate.org>2015-08-26 12:20:58 -0700
commit2bc852bda98762d3bc01548bf972e3f1b137fbfb (patch)
tree74831deed3c9057c5fe0cbb8790d220e855bc792 /lib
parent3de952510eb2a23350d24ed926f19c0cf72a12f2 (diff)
downloadmc-2bc852bda98762d3bc01548bf972e3f1b137fbfb.tar.gz
Move Myrddin libs to lib/ subdirectory.
Diffstat (limited to 'lib')
-rw-r--r--lib/bio/bio.myr502
-rw-r--r--lib/bio/bld.sub7
-rwxr-xr-xlib/bio/configure52
-rw-r--r--lib/bio/geti.myr63
-rw-r--r--lib/bio/puti.myr62
-rw-r--r--lib/bio/test/Makefile20
-rw-r--r--lib/bio/test/bio-create.myr13
-rw-r--r--lib/bio/test/bio-delim.myr70
-rw-r--r--lib/bio/test/bio-endianrd.myr57
-rw-r--r--lib/bio/test/bio-endianwr.myr42
-rw-r--r--lib/bio/test/bio-peek.myr45
-rw-r--r--lib/bio/test/bio-read.myr46
-rw-r--r--lib/bio/test/bio-unitwr.myr14
-rw-r--r--lib/bio/test/bio-write.myr33
-rw-r--r--lib/bio/test/data/bio-create-expected0
-rw-r--r--lib/bio/test/data/bio-delim-expected10
-rw-r--r--lib/bio/test/data/bio-endianrd-expected1
-rwxr-xr-xlib/bio/test/data/bio-endianwr-expected1
-rw-r--r--lib/bio/test/data/bio-peek-expected1
-rw-r--r--lib/bio/test/data/bio-read-expected6
-rw-r--r--lib/bio/test/data/bio-unitwr-expected1
-rwxr-xr-xlib/bio/test/data/bio-write-expected3
-rw-r--r--lib/bio/test/data/datafile1
-rw-r--r--lib/bio/test/data/lines4
-rwxr-xr-xlib/bio/test/runtest.sh124
-rw-r--r--lib/bio/test/tests31
-rw-r--r--lib/cryptohash/bld.sub7
-rw-r--r--lib/cryptohash/md5.myr215
-rw-r--r--lib/cryptohash/sha1.myr243
-rw-r--r--lib/cryptohash/sha256.myr415
-rw-r--r--lib/cryptohash/sha512.myr474
-rw-r--r--lib/cryptohash/test/md5.myr18
-rw-r--r--lib/cryptohash/test/sha1.myr18
-rw-r--r--lib/cryptohash/test/sha256.myr29
-rw-r--r--lib/cryptohash/test/sha512.myr29
-rw-r--r--lib/cryptohash/test/util.myr19
-rw-r--r--lib/regex/bld.sub21
-rw-r--r--lib/regex/compile.myr848
-rwxr-xr-xlib/regex/configure52
-rw-r--r--lib/regex/doc/Makefile5
-rw-r--r--lib/regex/doc/myr-regex.3198
-rw-r--r--lib/regex/interp.myr311
-rw-r--r--lib/regex/ranges.myr2386
-rw-r--r--lib/regex/redump.myr87
-rw-r--r--lib/regex/test/basic.myr39
-rw-r--r--lib/regex/test/bld.sub7
-rw-r--r--lib/regex/test/boundaries.myr36
-rw-r--r--lib/regex/test/capture.myr17
-rw-r--r--lib/regex/test/class.myr67
-rw-r--r--lib/regex/test/failmatch.myr7
-rw-r--r--lib/regex/test/negclass.myr72
-rwxr-xr-xlib/regex/test/runtest.sh124
-rw-r--r--lib/regex/test/testmatch.myr58
-rw-r--r--lib/regex/test/tests29
-rw-r--r--lib/regex/test/unicode.myr19
-rw-r--r--lib/regex/types.myr88
-rw-r--r--lib/std/alloc.myr423
-rw-r--r--lib/std/bigint.myr742
-rw-r--r--lib/std/bitset.myr155
-rw-r--r--lib/std/blat.myr32
-rw-r--r--lib/std/bld.sub103
-rwxr-xr-xlib/std/build.sh8
-rw-r--r--lib/std/chartype.myr1242
-rw-r--r--lib/std/clear.myr12
-rw-r--r--lib/std/cmp.myr54
-rw-r--r--lib/std/cstrconv.myr40
-rw-r--r--lib/std/dial+plan9.myr165
-rw-r--r--lib/std/dial+posixy.myr147
-rw-r--r--lib/std/die.myr19
-rw-r--r--lib/std/dir+freebsd.myr0
-rw-r--r--lib/std/dir+linux.myr66
-rw-r--r--lib/std/dir+osx.myr60
-rw-r--r--lib/std/dir+plan9.myr66
-rw-r--r--lib/std/dirname.myr37
-rw-r--r--lib/std/endian.myr32
-rw-r--r--lib/std/env+plan9.myr56
-rw-r--r--lib/std/env+posixy.myr28
-rw-r--r--lib/std/errno+plan9.myr6
-rw-r--r--lib/std/errno.myr40
-rw-r--r--lib/std/execvp.myr57
-rw-r--r--lib/std/extremum.myr40
-rw-r--r--lib/std/fltbits.myr60
-rw-r--r--lib/std/fltfmt.myr239
-rw-r--r--lib/std/fmt.myr499
-rw-r--r--lib/std/fmtfuncs.myr54
-rw-r--r--lib/std/getcwd.myr31
-rw-r--r--lib/std/getint.myr64
-rw-r--r--lib/std/hashfuncs.myr106
-rw-r--r--lib/std/hasprefix.myr12
-rw-r--r--lib/std/hassuffix.myr15
-rw-r--r--lib/std/htab.myr209
-rw-r--r--lib/std/ifreq+freebsd.myr0
-rw-r--r--lib/std/ifreq+linux.myr67
-rw-r--r--lib/std/ifreq+osx.myr77
-rw-r--r--lib/std/ifreq+plan9.myr2
-rw-r--r--lib/std/intparse.myr70
-rw-r--r--lib/std/introspect.myr365
-rw-r--r--lib/std/ipparse.myr147
-rw-r--r--lib/std/mk.myr22
-rw-r--r--lib/std/mkfile107
-rw-r--r--lib/std/mkpath.myr22
-rw-r--r--lib/std/now.myr11
-rw-r--r--lib/std/option.myr7
-rw-r--r--lib/std/optparse.myr210
-rw-r--r--lib/std/pathjoin.myr105
-rw-r--r--lib/std/putint.myr44
-rw-r--r--lib/std/rand.myr185
-rw-r--r--lib/std/resolve+plan9.myr2
-rw-r--r--lib/std/resolve+posixy.myr443
-rw-r--r--lib/std/result.myr9
-rw-r--r--lib/std/search.myr43
-rw-r--r--lib/std/slcp.myr26
-rw-r--r--lib/std/sldup.myr15
-rw-r--r--lib/std/sleq.myr18
-rw-r--r--lib/std/slfill.myr12
-rw-r--r--lib/std/sljoin.myr15
-rw-r--r--lib/std/slpush.myr20
-rw-r--r--lib/std/slput.myr20
-rw-r--r--lib/std/slurp.myr43
-rw-r--r--lib/std/sort.myr61
-rw-r--r--lib/std/spork.myr62
-rw-r--r--lib/std/strbuf.myr107
-rw-r--r--lib/std/strfind.myr51
-rw-r--r--lib/std/strjoin.myr41
-rw-r--r--lib/std/strsplit.myr35
-rw-r--r--lib/std/strstrip.myr43
-rw-r--r--lib/std/swap.myr11
-rw-r--r--lib/std/sys+freebsd-x64.myr805
-rw-r--r--lib/std/sys+linux-x64.myr816
-rw-r--r--lib/std/sys+osx-x64.myr947
-rw-r--r--lib/std/sys+plan9-x64.myr242
-rw-r--r--lib/std/syscall+freebsd-x64.s21
-rw-r--r--lib/std/syscall+linux-x64.s22
-rw-r--r--lib/std/syscall+osx-x64.s96
-rw-r--r--lib/std/syscall+plan9-x64.s33
-rw-r--r--lib/std/syserrno+linux.myr38
-rw-r--r--lib/std/syserrno+osx.myr54
-rw-r--r--lib/std/syserrno+plan9.myr38
-rw-r--r--lib/std/systypes.myr7
-rw-r--r--lib/std/syswrap+plan9-x6.myr104
-rw-r--r--lib/std/syswrap+plan9.myr220
-rw-r--r--lib/std/syswrap+posixy.myr148
-rw-r--r--lib/std/syswrap-ss+linux.myr22
-rw-r--r--lib/std/syswrap-ss+osx.myr35
-rw-r--r--lib/std/syswrap-ss+plan9.myr56
-rw-r--r--lib/std/test/bigint.myr136
-rw-r--r--lib/std/test/bytebuf.myr72
-rw-r--r--lib/std/test/chartype.myr23
-rw-r--r--lib/std/test/fmt.myr34
-rw-r--r--lib/std/test/htab.myr104
-rw-r--r--lib/std/test/ipparse.myr64
-rw-r--r--lib/std/test/option.myr43
-rw-r--r--lib/std/test/pathjoin.myr61
-rw-r--r--lib/std/test/search.myr34
-rw-r--r--lib/std/test/slcp.myr14
-rw-r--r--lib/std/test/sort.myr38
-rw-r--r--lib/std/test/strbuf.myr40
-rw-r--r--lib/std/test/try.myr8
-rw-r--r--lib/std/try.myr38
-rw-r--r--lib/std/types.myr9
-rw-r--r--lib/std/units.myr11
-rw-r--r--lib/std/utf.myr103
-rw-r--r--lib/std/util+plan9-x64.s64
-rw-r--r--lib/std/util+posixy-x64.s72
-rw-r--r--lib/std/varargs.myr105
-rw-r--r--lib/std/wait+plan9.myr94
-rw-r--r--lib/std/wait+posixy.myr41
167 files changed, 19496 insertions, 0 deletions
diff --git a/lib/bio/bio.myr b/lib/bio/bio.myr
new file mode 100644
index 0000000..3ad9760
--- /dev/null
+++ b/lib/bio/bio.myr
@@ -0,0 +1,502 @@
+use std
+
+pkg bio =
+ type mode = int
+ const Rd : mode = 1
+ const Wr : mode = 2
+ const Rw : mode = 1 | 2
+
+ type file = struct
+ /* backing fd */
+ fd : std.fd
+ mode : mode
+
+ /* read buffer */
+ rbuf : byte[:]
+ rstart : std.size
+ rend : std.size
+
+ /* write buffer */
+ wbuf : byte[:]
+ wend : std.size
+ ;;
+
+ /* creation */
+ const mkfile : (fd : std.fd, mode : mode -> file#)
+ const open : (path : byte[:], mode : mode -> std.result(file#, byte[:]))
+ const dial : (srv : byte[:], mode : mode -> std.result(file#, byte[:]))
+ const create : (path : byte[:], mode : mode, perm : int -> std.result(file#, byte[:]))
+ const close : (f : file# -> bool)
+ const free : (f : file# -> void)
+
+ /* basic i/o. Returns sub-buffer when applicable. */
+ const write : (f : file#, src : byte[:] -> std.size)
+ const read : (f : file#, dst : byte[:] -> std.option(byte[:]))
+ const flush : (f : file# -> bool)
+
+ /* seeking */
+
+ /* single unit operations */
+ const putb : (f : file#, b : byte -> std.size)
+ const putc : (f : file#, c : char -> std.size)
+ const getb : (f : file# -> std.option(byte))
+ const getc : (f : file# -> std.option(char))
+
+ /* peeking */
+ const peekb : (f : file# -> std.option(byte))
+ const peekc : (f : file# -> std.option(char))
+
+ /* delimited read; returns freshly allocated buffer. */
+ const readln : (f : file# -> std.option(byte[:]))
+ const readto : (f : file#, delim : byte[:] -> std.option(byte[:]))
+ const skipto : (f : file#, delim : byte[:] -> bool)
+
+ /* formatted i/o */
+ const put : (f : file#, fmt : byte[:], args : ... -> std.size)
+
+ /* pkg funcs */
+ pkglocal const ensureread : (f : file#, n : std.size -> bool)
+ pkglocal const ensurewrite : (f : file#, n : std.size -> bool)
+;;
+
+const Bufsz = 16*std.KiB
+const Small = 512
+
+/* Creates a file from an fd, opened in the given mode. */
+const mkfile = {fd, mode
+ var f
+
+ f = std.alloc()
+
+ f.fd = fd
+ f.mode = mode
+ if mode & Rd != 0
+ f.rbuf = std.slalloc(Bufsz)
+ f.rstart = 0
+ f.rend = 0
+ ;;
+ if mode & Wr != 0
+ f.wbuf = std.slalloc(Bufsz)
+ f.wend = 0
+ ;;
+ -> f
+}
+
+/* Opens a file with mode provided. */
+const open = {path, mode
+ -> sysopen(path, mode, sysmode(mode), 0o777)
+}
+
+/*
+ Creates a file for the provided path, with opened in
+ the requested mode, with the requested permissions
+*/
+const create = {path, mode, perm
+ -> sysopen(path, mode, sysmode(mode) | std.Ocreat | std.Otrunc, perm)
+}
+
+/* dial the server, and open a file using the returned fd */
+const dial = {srv, mode
+ match std.dial(srv)
+ | `std.Ok sock: -> `std.Ok mkfile(sock, mode)
+ | `std.Fail m: -> `std.Fail m
+ ;;
+}
+
+/* map from the bio modes to the unix open modes */
+const sysmode = {mode
+ match mode
+ | Rd: -> std.Ordonly
+ | Wr: -> std.Owronly
+ | Rw: -> std.Ordwr
+ | _: std.fatal("bio: bad file mode")
+ ;;
+ -> 0
+}
+
+/* open the file, and return it */
+const sysopen = {path, mode, openmode, perm
+ var fd
+
+ fd = std.openmode(path, openmode, perm castto(int64))
+ if fd < 0
+ -> `std.Fail "could not open fd"
+ else
+ -> `std.Ok mkfile(fd, mode)
+ ;;
+}
+
+/* closes a file, flushing it to the output fd */
+const close = {f
+ var fd
+
+ fd = f.fd
+ free(f)
+ -> std.close(fd) == 0
+}
+
+const free = {f
+ flush(f)
+ if f.mode & Rd != 0
+ std.slfree(f.rbuf)
+ ;;
+
+ if f.mode & Wr != 0
+ std.slfree(f.wbuf)
+ ;;
+ std.free(f)
+}
+
+/*
+writes to as much from `src` as possible to a file,
+returning the number of bytes written.
+*/
+const write = {f, src
+ std.assert(f.mode & Wr != 0, "File is not in write mode")
+ /*
+ Tack small writes onto the buffer end. Big ones
+ flush the buffer and then go right to kernel.
+ */
+ if src.len < (f.wbuf.len - f.wend)
+ std.slcp(f.wbuf[f.wend:f.wend+src.len], src)
+ f.wend += src.len
+ -> src.len
+ else
+ flush(f)
+ -> writebuf(f.fd, src)
+ ;;
+}
+
+/*
+reads as much into 'dst' as possible, up to the size of 'dst',
+returning the number of bytes read.
+*/
+const read = {f, dst
+ var n
+ var d
+ var count
+
+ std.assert(f.mode & Rd != 0, "File is not in read mode")
+ /*
+ * small reads should try to fill, so we don't have to make a
+ * syscall for every read
+ */
+ if dst.len < Small
+ fill(f, f.rbuf.len - f.rend)
+ ;;
+ /* Read as much as we can from the buffer */
+ count = std.min(dst.len, f.rend - f.rstart)
+ std.slcp(dst[:count], f.rbuf[f.rstart:f.rstart+count])
+ f.rstart += count
+
+ /* if we drained the buffer, reset it */
+ if f.rstart == f.rend
+ f.rstart = 0
+ f.rend = 0
+ ;;
+
+ /* Read the rest directly from the fd */
+ d = dst[count:]
+ while dst.len > 0
+ n = std.read(f.fd, d)
+ if n <= 0
+ goto readdone
+ ;;
+ count += n
+ d = d[n:]
+ ;;
+:readdone
+ if count > 0
+ -> `std.Some dst[:count]
+ else
+ -> `std.None
+ ;;
+}
+
+/* flushes f out to the backing fd */
+const flush = {f
+ var ret
+
+ ret = true
+ if f.mode & Wr != 0
+ ret = (writebuf(f.fd, f.wbuf[:f.wend]) == f.wend)
+ f.wend = 0
+ ;;
+ -> ret
+}
+
+/* writes a single byte to the output stream */
+const putb = {f, b
+ ensurewrite(f, 1)
+ f.wbuf[f.wend++] = b
+ -> 1
+}
+
+/* writes a single character to the output stream, encoded in utf8 */
+const putc = {f, c
+ var sz
+
+ sz = std.charlen(c)
+ ensurewrite(f, sz)
+ std.encode(f.wbuf[f.wend:], c)
+ f.wend += sz
+ -> sz
+}
+
+/* reads a single byte from the input stream */
+const getb = {f
+ if ensureread(f, 1)
+ -> `std.Some f.rbuf[f.rstart++]
+ ;;
+ -> `std.None
+}
+
+/* reads a single character from the input stream, encoded in utf8 */
+const getc = {f
+ var c
+
+ if ensurecodepoint(f)
+ c = std.decode(f.rbuf[f.rstart:f.rend])
+ f.rstart += std.charlen(c)
+ -> `std.Some c
+ ;;
+ -> `std.None
+}
+
+/* ensures we have enough to read a single codepoint in the buffer */
+const ensurecodepoint = {f
+ var b
+ var len
+
+ if !ensureread(f, 1)
+ -> false
+ ;;
+ b = f.rbuf[f.rstart]
+ if b & 0x80 == 0 /* 0b0xxx_xxxx */
+ len = 1
+ elif b & 0xe0 == 0xc0 /* 0b110x_xxxx */
+ len = 2
+ elif b & 0xf0 == 0xe0 /* 0b1110_xxxx */
+ len = 3
+ elif b & 0xf8 == 0xf0 /* 0b1111_0xxx */
+ len = 4
+ else
+ len = 1 /* invalid unicode char */
+ ;;
+ -> ensureread(f, len)
+}
+
+/*
+ writes a single integer-like value to the output stream, in
+ little endian format
+*/
+generic putle = {f, v : @a::(numeric,integral)
+ var i
+
+ for i = 0; i < sizeof(@a); i++
+ putb(f, (v & 0xff) castto(byte))
+ v >>= 8
+ ;;
+ -> sizeof(@a)
+}
+
+/*
+ writes a single integer-like value to the output stream, in
+ big endian format
+*/
+generic putbe = {f, v : @a::(numeric,integral)
+ var i
+
+ for i = sizeof(@a); i != 0; i--
+ putb(f, ((v >> ((i-1)*8)) & 0xff) castto(byte))
+ ;;
+ -> sizeof(@a)
+}
+
+
+/* peeks a single byte from an input stream */
+const peekb = {f
+ if !ensureread(f, 1)
+ -> `std.None
+ else
+ -> `std.Some f.rbuf[f.rstart]
+ ;;
+}
+
+/* peeks a single character from a utf8 encoded input stream */
+const peekc = {f
+ if !ensurecodepoint(f)
+ -> `std.None
+ else
+ -> `std.Some std.decode(f.rbuf[f.rstart:f.rend])
+ ;;
+}
+
+/*
+ reads up to a single character delimiter. drops the delimiter
+ from the input stream. EOF always counts as a delimiter.
+
+ Eg, with the input "foo,bar\n"
+
+ bio.readto(f, ',') -> "foo"
+ bio.readto(f, ',') -> "bar\n"
+*/
+const readto = {f, delim
+ -> readdelim(f, delim, false)
+}
+
+/* same as readto, but drops the read data. */
+const skipto = {f, delim
+ match readdelim(f, delim, true)
+ | `std.Some ret: -> true
+ | `std.None: -> false
+ ;;
+}
+
+/* Same as readto, but the delimiter is always a '\n' */
+const readln = {f
+ -> readto(f, "\n")
+}
+
+const readdelim = {f, delim, drop
+ var ret
+ var i, j
+
+ ret = [][:]
+ while true
+ if !ensureread(f, delim.len)
+ if !drop
+ ret = readinto(f, ret, f.rend - f.rstart)
+ ;;
+ if ret.len > 0
+ -> `std.Some ret
+ else
+ -> `std.None
+ ;;
+ ;;
+ for i = f.rstart; i < f.rend; i++
+ if f.rbuf[i] == delim[0]
+ for j = 0; j < delim.len; j++
+ if f.rbuf[i + j] != delim[j]
+ goto nextiterread
+ ;;
+ ;;
+ if !drop
+ ret = readinto(f, ret, i - f.rstart)
+ ;;
+ f.rstart += delim.len
+ -> `std.Some ret
+ ;;
+:nextiterread
+ ;;
+ if !drop
+ ret = readinto(f, ret, f.rend - f.rstart)
+ ;;
+ ;;
+ std.die("unreachable")
+}
+
+/*
+Same as std.put, but buffered. Returns the number of bytes written.
+
+FIXME: depends on std.fmt() having a flush buffer API. Until then,
+we're stuck with a small static buffer.
+*/
+const put = {f, fmt, args
+ var sl, ap, n
+
+ ap = std.vastart(&args)
+ sl = std.fmtv(fmt, &ap)
+ n = write(f, sl)
+ std.slfree(sl)
+ -> n
+}
+
+/*
+reads n bytes from the read buffer onto the heap-allocated slice
+provided.
+*/
+const readinto = {f, buf, n
+ var ret
+
+ std.assert(f.rstart + n <= f.rend, "Reading too much from buffer")
+ ret = std.sljoin(buf, f.rbuf[f.rstart:f.rstart + n])
+ f.rstart += n
+ -> ret
+}
+
+/* makes sure we can bufferedly write at least n bytes */
+const ensurewrite = {f, n
+ std.assert(n < f.wbuf.len, "ensured write capacity > buffer size")
+ if n > f.wbuf.len - f.wend
+ -> flush(f)
+ ;;
+ -> true
+}
+
+/*
+makes sure we have at least n bytes buffered. returns true if we succeed
+in buffering n bytes, false if we fail.
+*/
+const ensureread = {f, n
+ var held
+ var cap
+
+ std.assert(n < f.rbuf.len, "ensured read capacity > buffer size")
+ held = f.rend - f.rstart
+ if n > held
+ /* if we need to shift the slice down to the start, do it */
+ cap = f.rend - f.rstart
+ if n > (cap + held)
+ std.slcp(f.rbuf[:cap], f.rbuf[f.rstart:f.rend])
+ f.rstart = 0
+ f.rend = cap
+ ;;
+ -> fill(f, n) > n
+ else
+ -> true
+ ;;
+}
+
+/* blats a buffer to an fd */
+const writebuf = {fd, src
+ var n
+ var count
+
+ count = 0
+ while src.len != 0
+ n = std.write(fd, src)
+ if n <= 0
+ goto writedone
+ ;;
+ count += n
+ src = src[n:]
+ ;;
+:writedone
+ -> count
+}
+
+
+
+/*
+Reads as many bytes as possible from the file into
+the read buffer.
+*/
+const fill = {f, min
+ var n
+ var count
+
+ count = 0
+ while count < min
+ n = std.read(f.fd, f.rbuf[f.rend:])
+ if n <= 0
+ goto filldone
+ ;;
+ count += n
+ f.rend += n
+ ;;
+:filldone
+ -> count
+}
+
+
diff --git a/lib/bio/bld.sub b/lib/bio/bld.sub
new file mode 100644
index 0000000..ad2e04d
--- /dev/null
+++ b/lib/bio/bld.sub
@@ -0,0 +1,7 @@
+lib bio =
+ bio.myr
+ geti.myr
+ puti.myr
+
+ lib ../std:std
+;;
diff --git a/lib/bio/configure b/lib/bio/configure
new file mode 100755
index 0000000..37fe623
--- /dev/null
+++ b/lib/bio/configure
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+prefix="/usr/local"
+
+for i in `seq 300`; do
+ echo "Lots of output to emulate automake... ok"
+ echo "Testing for things you'll never use... fail"
+ echo "Satisfying the fortran77 lobby... ok"
+ echo "Burning CPU time checking for the bloody obvious... ok"
+done
+echo "Automake emulated successfully"
+
+INST_ROOT='/usr/local'
+
+for arg in $*; do
+ shift 1
+ case $arg in
+ "--prefix" | "-p")
+ prefix=shift $*
+ ;;
+ --prefix=*)
+ prefix=`echo $arg | sed 's/^--prefix=//g'`
+ ;;
+ "--help" | "-h")
+ echo "Usage:"
+ echo " --prefix | -p: The prefix to install to"
+ break;
+ ;;
+ *) echo "Unrecognized argument $arg";;
+ esac
+done
+
+OS=`uname`
+
+echo export INST_ROOT=$prefix > config.mk
+case $OS in
+ *Linux*)
+ echo 'export SYS=linux' >> config.mk
+ ;;
+ *Darwin*)
+ echo 'export SYS=osx' >> config.mk
+ ;;
+ *)
+ echo 'Unknown architecture.'
+ ;;
+esac
+
+cat << EOF
+ Building with:
+ prefix=$prefix
+EOF
+
diff --git a/lib/bio/geti.myr b/lib/bio/geti.myr
new file mode 100644
index 0000000..48de2bc
--- /dev/null
+++ b/lib/bio/geti.myr
@@ -0,0 +1,63 @@
+use std
+
+use "bio.use"
+
+pkg bio =
+ /* unsigned big endian */
+ generic getbe8 : (f : file# -> std.option(@a::(numeric,integral)))
+ generic getbe16 : (f : file# -> std.option(@a::(numeric,integral)))
+ generic getbe32 : (f : file# -> std.option(@a::(numeric,integral)))
+ generic getbe64 : (f : file# -> std.option(@a::(numeric,integral)))
+
+ /* signed big endian */
+ generic getle8 : (f : file# -> std.option(@a::(numeric,integral)))
+ generic getle16 : (f : file# -> std.option(@a::(numeric,integral)))
+ generic getle32 : (f : file# -> std.option(@a::(numeric,integral)))
+ generic getle64 : (f : file# -> std.option(@a::(numeric,integral)))
+;;
+
+/*
+ reads a single integer-like value to the output stream, in
+ little endian format
+*/
+generic getle = {f, n -> std.option(@a::(numeric,integral))
+ var v, i
+
+ v = 0
+ if !ensureread(f, n)
+ -> `std.None
+ ;;
+ for i = 0; i < n; i++
+ v |= (f.rbuf[f.rstart++] castto(uint64)) << (8*(i castto(uint64)))
+ ;;
+ -> `std.Some v castto(@a::(numeric,integral))
+}
+
+/*
+ reads a single integer-like value to the output stream, in
+ big endian format
+*/
+generic getbe = {f, n -> std.option(@a::(numeric,integral))
+ var v, i
+
+ v = 0
+ if !ensureread(f,n)
+ -> `std.None
+ ;;
+ for i = 0; i < n; i++
+ v <<= 8
+ v |= (f.rbuf[f.rstart++] castto(uint64))
+ ;;
+ -> `std.Some v castto(@a::(numeric,integral))
+}
+
+generic getbe8 = {f; -> getbe(f, 1)}
+generic getbe16 = {f; -> getbe(f, 2)}
+generic getbe32 = {f; -> getbe(f, 4)}
+generic getbe64 = {f; -> getbe(f, 8)}
+
+generic getle8 = {f; -> getle(f, 1)}
+generic getle16 = {f; -> getle(f, 2)}
+generic getle32 = {f; -> getle(f, 4)}
+generic getle64 = {f; -> getle(f, 8)}
+
diff --git a/lib/bio/puti.myr b/lib/bio/puti.myr
new file mode 100644
index 0000000..16f014a
--- /dev/null
+++ b/lib/bio/puti.myr
@@ -0,0 +1,62 @@
+use std
+
+use "bio.use"
+
+pkg bio =
+ /* unsigned big endian */
+ generic putbe8 : (f : file#, v : @a::(numeric,integral) -> std.size)
+ generic putbe16 : (f : file#, v : @a::(numeric,integral) -> std.size)
+ generic putbe32 : (f : file#, v : @a::(numeric,integral) -> std.size)
+ generic putbe64 : (f : file#, v : @a::(numeric,integral) -> std.size)
+
+ /* unsigned little endian */
+ generic putle8 : (f : file#, v : @a::(numeric,integral) -> std.size)
+ generic putle16 : (f : file#, v : @a::(numeric,integral) -> std.size)
+ generic putle32 : (f : file#, v : @a::(numeric,integral) -> std.size)
+ generic putle64 : (f : file#, v : @a::(numeric,integral) -> std.size)
+;;
+
+generic putbe8 = {f, v; -> putbe(f, v castto(uint64), 1)}
+generic putbe16 = {f, v; -> putbe(f, v castto(uint64), 2)}
+generic putbe32 = {f, v; -> putbe(f, v castto(uint64), 4)}
+generic putbe64 = {f, v; -> putbe(f, v castto(uint64), 8)}
+
+generic putle8 = {f, v; -> putle(f, v castto(uint64), 1)}
+generic putle16 = {f, v; -> putle(f, v castto(uint64), 2)}
+generic putle32 = {f, v; -> putle(f, v castto(uint64), 4)}
+generic putle64 = {f, v; -> putle(f, v castto(uint64), 8)}
+
+const putle = {f, v, n
+ var buf : byte[8]
+
+ if !ensurewrite(f, n)
+ -> 0
+ ;;
+ buf[0] = (v >> 0) & 0xff castto(byte)
+ buf[1] = (v >> 8) & 0xff castto(byte)
+ buf[2] = (v >> 16) & 0xff castto(byte)
+ buf[3] = (v >> 24) & 0xff castto(byte)
+ buf[4] = (v >> 32) & 0xff castto(byte)
+ buf[5] = (v >> 40) & 0xff castto(byte)
+ buf[6] = (v >> 48) & 0xff castto(byte)
+ buf[7] = (v >> 56) & 0xff castto(byte)
+ -> write(f, buf[:n])
+}
+
+const putbe = {f, v, n
+ var buf : byte[8]
+
+ if !ensurewrite(f, n)
+ -> 0
+ ;;
+ buf[0] = (v >> 56) & 0xff castto(byte)
+ buf[1] = (v >> 48) & 0xff castto(byte)
+ buf[2] = (v >> 40) & 0xff castto(byte)
+ buf[3] = (v >> 32) & 0xff castto(byte)
+ buf[4] = (v >> 24) & 0xff castto(byte)
+ buf[5] = (v >> 16) & 0xff castto(byte)
+ buf[6] = (v >> 8) & 0xff castto(byte)
+ buf[7] = (v >> 0) & 0xff castto(byte)
+ -> write(f, buf[8-n:])
+}
+
diff --git a/lib/bio/test/Makefile b/lib/bio/test/Makefile
new file mode 100644
index 0000000..e559327
--- /dev/null
+++ b/lib/bio/test/Makefile
@@ -0,0 +1,20 @@
+# don't build anything for 'all'
+all:
+ $(MAKE) -C ..
+
+check:
+ ./runtest.sh
+
+.PHONY: %
+%:
+ ./runtest.sh $@
+
+.PHONY: clean
+clean:
+ rm -f testmatch.use testmatch.o
+ @for i in `awk '/^[A-Z]/{print $$2}' tests`; do \
+ echo rm -f $$i; \
+ rm -f $$i; \
+ done
+
+install:
diff --git a/lib/bio/test/bio-create.myr b/lib/bio/test/bio-create.myr
new file mode 100644
index 0000000..6954e32
--- /dev/null
+++ b/lib/bio/test/bio-create.myr
@@ -0,0 +1,13 @@
+use std
+use bio
+
+const main = {
+ var f
+
+ std.mkdir("tmpout", 0o755);
+ match bio.create("tmpout/test-create", bio.Wr, 0o644)
+ | `std.Some bio: f = bio
+ | `std.None: std.fatal(1, "Failed to open file\n")
+ ;;
+ bio.close(f)
+}
diff --git a/lib/bio/test/bio-delim.myr b/lib/bio/test/bio-delim.myr
new file mode 100644
index 0000000..231c469
--- /dev/null
+++ b/lib/bio/test/bio-delim.myr
@@ -0,0 +1,70 @@
+use std
+use bio
+
+const main = {
+ var f
+ var d
+
+ match bio.open("data/lines", bio.Rd)
+ | `std.Some bio: f = bio
+ | `std.None: std.fatal(1, "Unable to open data file\n")
+ ;;
+
+ /* read first line */
+ d = readln(f)
+ std.write(1, d)
+ std.write(1, "\n")
+ std.slfree(d)
+
+ /* read second line, should not include \n */
+ d = readln(f)
+ std.write(1, d)
+ std.write(1, "\n")
+ std.slfree(d)
+
+ /* read to ';' */
+ d = readto(f, ";")
+ std.write(1, d)
+ std.write(1, "\n")
+ std.slfree(d)
+
+ /* read to ';' again */
+ d = readto(f, ";")
+ std.write(1, d)
+ std.write(1, "\n")
+ std.slfree(d)
+
+ /* '--' this time */
+ d = readto(f, "--")
+ std.write(1, d)
+ std.write(1, "\n")
+ std.slfree(d)
+
+ /* and without the terminator, we should get the remaining text */
+ d = readto(f, "not-there")
+ std.write(1, d)
+ std.write(1, "\n")
+ std.slfree(d)
+
+ /* and now, eof */
+ d = readln(f)
+ d = readto(f, "actually, eof")
+
+ bio.close(f)
+}
+
+const readln = {f
+ match bio.readln(f)
+ | `std.Some d: -> d
+ | `std.None: std.put("eof\n")
+ -> [][:]
+ ;;
+}
+
+const readto = {f, delim
+ match bio.readto(f, delim)
+ | `std.Some d: -> d
+ | `std.None: std.put("eof\n")
+ -> [][:]
+ ;;
+}
diff --git a/lib/bio/test/bio-endianrd.myr b/lib/bio/test/bio-endianrd.myr
new file mode 100644
index 0000000..53743d8
--- /dev/null
+++ b/lib/bio/test/bio-endianrd.myr
@@ -0,0 +1,57 @@
+use std
+use bio
+
+generic try = {opt : std.option(@a::(integral,numeric))-> @a::(integral,numeric)
+ match opt
+ | `std.Some val: -> val
+ | `std.None: std.fatal(1, "read failed")
+ ;;
+}
+const main = {
+ var b : byte
+ var w : uint16
+ var l : uint32
+ var q : uint64
+ var f
+
+ /* use the expected write data as read data */
+ match bio.open("data/bio-endianwr-expected", bio.Rd)
+ | `std.Some bio: f = bio
+ | `std.None: std.fatal(1, "Unable to open data file")
+ ;;
+
+ /* byte */
+ /*
+ /* FIXME: compiler bug. multiplication on byte
+ values is currently broken. */
+ b = 0xaa
+ std.assert(try(bio.getle8(f)) == b, "le byte broken\n")
+ std.assert(try(bio.getbe8(f)) == b, "be byte broken\n")
+ */
+
+ /* word */
+ w = 0xaabb
+ std.assert(try(bio.getle16(f)) == w, "le word broken\n")
+ std.assert(try(bio.getbe16(f)) == w, "be word broken\n")
+
+ /* long */
+ l = 0xaabbccdd
+ std.assert(try(bio.getle32(f)) == l, "le long broken\n")
+ std.assert(try(bio.getbe32(f)) == l, "be long broken\n")
+
+ /* quad */
+ q = 0x11223344aabbccdd castto(uint64)
+ std.assert(try(bio.getle64(f)) == q, "le quad broken\n")
+ std.assert(try(bio.getbe64(f)) == q, "be quad broken\n")
+
+ /* end of file */
+ match bio.getle64(f)
+ | `std.None:
+ | `std.Some v: std.die("read past end of file\n")
+ ;;
+
+ bio.close(f);
+
+ std.put("success: all reads matched\n")
+}
+
diff --git a/lib/bio/test/bio-endianwr.myr b/lib/bio/test/bio-endianwr.myr
new file mode 100644
index 0000000..e44db49
--- /dev/null
+++ b/lib/bio/test/bio-endianwr.myr
@@ -0,0 +1,42 @@
+use std
+use bio
+
+const main = {
+ var b : byte
+ var w : uint16
+ var l : uint32
+ var q : uint64
+ var f
+
+ match bio.create("tmpout/test-endianwr", bio.Wr, 0o644)
+ | `std.Some bio: f = bio
+ | `std.None: std.fatal(1, "Unable to open data file")
+ ;;
+
+ /* byte */
+ /*
+ /* FIXME: compiler bug. multiplication on byte
+ values is currently broken. */
+ b = 0xaa
+ bio.putle(f, b)
+ bio.putbe(f, b)
+ */
+
+ /* word */
+ w = 0xaabb
+ bio.putle16(f, w)
+ bio.putbe16(f, w)
+
+ /* long */
+ l = 0xaabbccdd
+ bio.putle32(f, l)
+ bio.putbe32(f, l)
+
+ /* quad */
+ q = 0x11223344aabbccdd castto(uint64)
+ bio.putle64(f, q)
+ bio.putbe64(f, q)
+
+ /* and test for flush on close */
+ bio.close(f);
+}
diff --git a/lib/bio/test/bio-peek.myr b/lib/bio/test/bio-peek.myr
new file mode 100644
index 0000000..2125c9b
--- /dev/null
+++ b/lib/bio/test/bio-peek.myr
@@ -0,0 +1,45 @@
+use std
+use bio
+
+const main = {
+ var f
+ /* Must be bigger than a bio buffer (ie, > 64k) */
+ var buf : byte[64*1024]
+
+ match bio.open("data/datafile", bio.Rd)
+ | `std.Some bio: f = bio
+ | `std.None: std.fatal(1, "Unable to open data file")
+ ;;
+
+ std.assert(peekb(f) == 0x30, "wrong byte value read from datafile")
+ std.assert(peekc(f) == '0', "wrong char value read from datafile")
+
+ bio.read(f, buf[:4]) /* skip ahead 4 bytes */
+ std.assert(peekb(f) == 0x34, "wrong byte value read from datafile")
+ std.assert(peekc(f) == '4', "wrong char value read from datafile")
+
+ bio.read(f, buf[:]) /* skip ahead 64k */
+ std.assert(peekb(f) == 0x30, "wrong byte value read from datafile")
+ std.assert(peekc(f) == '0', "wrong char value read from datafile")
+
+ bio.close(f);
+ std.put("Succeded peeeking values\n")
+}
+
+const peekc = {f
+ match bio.peekc(f)
+ | `std.Some c: -> c
+ | `std.None:
+ std.put("eof")
+ -> -1
+ ;;
+}
+
+const peekb = {f
+ match bio.peekb(f)
+ | `std.Some b: -> b
+ | `std.None:
+ std.put("eof")
+ -> -1
+ ;;
+}
diff --git a/lib/bio/test/bio-read.myr b/lib/bio/test/bio-read.myr
new file mode 100644
index 0000000..eafdb4a
--- /dev/null
+++ b/lib/bio/test/bio-read.myr
@@ -0,0 +1,46 @@
+use std
+use bio
+
+const main = {
+ var f
+ /* Must be bigger than a bio buffer (ie, > 64k) */
+ var buf : byte[64*1024]
+ var b
+
+ match bio.open("data/datafile", bio.Rd)
+ | `std.Some bio: f = bio
+ | `std.None: std.fatal(1, "Unable to open data file")
+ ;;
+
+ /* read a 4 byte chunk j*/
+ b = r(f, buf[:4])
+ std.write(1, b)
+ std.write(1, "\n")
+
+ /* read the next 32 bytes */
+ b = r(f, buf[:32])
+ std.write(1, b)
+ std.write(1, "\n")
+
+ /* read a 64k chunk */
+ b = r(f, buf[:])
+ std.write(1, b)
+ std.write(1, "\n")
+
+ /* read to EOF */
+ b = r(f, buf[:])
+ std.write(1, b)
+ std.write(1, "\n")
+
+ /* and fail */
+ b = r(f, buf[:])
+
+ bio.close(f)
+}
+
+const r = {f, buf
+ match bio.read(f, buf)
+ | `std.Some b: -> b
+ | `std.None: std.put("eof\n")
+ ;;
+}
diff --git a/lib/bio/test/bio-unitwr.myr b/lib/bio/test/bio-unitwr.myr
new file mode 100644
index 0000000..8a1774c
--- /dev/null
+++ b/lib/bio/test/bio-unitwr.myr
@@ -0,0 +1,14 @@
+use std
+use bio
+
+const main = {
+ var f
+ match bio.create("tmpout/test-unitwr", bio.Wr, 0o644)
+ | `std.Some bio: f = bio
+ | `std.None: std.fatal(1, "Unable to open data file")
+ ;;
+ bio.putb(f, 42)
+ bio.putc(f, 'ה')
+ bio.putb(f, 0xa)
+ bio.close(f);
+}
diff --git a/lib/bio/test/bio-write.myr b/lib/bio/test/bio-write.myr
new file mode 100644
index 0000000..cbe7441
--- /dev/null
+++ b/lib/bio/test/bio-write.myr
@@ -0,0 +1,33 @@
+use std
+use bio
+
+const main = {
+ var i
+ var f
+ /* Must be bigger than a bio buffer (ie, > 64k) */
+ var buf : byte[64*1024]
+
+ match bio.create("tmpout/test-write", bio.Wr, 0o644)
+ | `std.Some bio: f = bio
+ | `std.None: std.fatal(1, "Unable to open data file")
+ ;;
+
+ /* write a 5 byte chunk */
+ bio.write(f, "test\n")
+
+ /* again */
+ bio.write(f, "test\n")
+
+ /* write a 64k chunk */
+ for i = 0; i < 64*1024; i++
+ buf[i] = 0x31
+ ;;
+ bio.write(f, buf[:])
+
+ /* final message after a big burst */
+ bio.write(f, "goodbye\n")
+ bio.flush(f)
+
+ /* and test for flush on close */
+ bio.close(f);
+}
diff --git a/lib/bio/test/data/bio-create-expected b/lib/bio/test/data/bio-create-expected
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/bio/test/data/bio-create-expected
diff --git a/lib/bio/test/data/bio-delim-expected b/lib/bio/test/data/bio-delim-expected
new file mode 100644
index 0000000..b90f595
--- /dev/null
+++ b/lib/bio/test/data/bio-delim-expected
@@ -0,0 +1,10 @@
+first line
+second line
+data with
+semicolons
+
+and
+no-terminator
+
+eof
+eof
diff --git a/lib/bio/test/data/bio-endianrd-expected b/lib/bio/test/data/bio-endianrd-expected
new file mode 100644
index 0000000..cd9a251
--- /dev/null
+++ b/lib/bio/test/data/bio-endianrd-expected
@@ -0,0 +1 @@
+success: all reads matched
diff --git a/lib/bio/test/data/bio-endianwr-expected b/lib/bio/test/data/bio-endianwr-expected
new file mode 100755
index 0000000..8baa404
--- /dev/null
+++ b/lib/bio/test/data/bio-endianwr-expected
@@ -0,0 +1 @@
+̻̻D3""3D \ No newline at end of file
diff --git a/lib/bio/test/data/bio-peek-expected b/lib/bio/test/data/bio-peek-expected
new file mode 100644
index 0000000..153efdb
--- /dev/null
+++ b/lib/bio/test/data/bio-peek-expected
@@ -0,0 +1 @@
+Succeded peeeking values
diff --git a/lib/bio/test/data/bio-read-expected b/lib/bio/test/data/bio-read-expected
new file mode 100644
index 0000000..9bf4703
--- /dev/null
+++ b/lib/bio/test/data/bio-read-expected
@@ -0,0 +1,6 @@
+0123
+45678901234567890123456789012345
+6789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901
+2345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+
+eof
diff --git a/lib/bio/test/data/bio-unitwr-expected b/lib/bio/test/data/bio-unitwr-expected
new file mode 100644
index 0000000..581c0f6
--- /dev/null
+++ b/lib/bio/test/data/bio-unitwr-expected
@@ -0,0 +1 @@
+*ה
diff --git a/lib/bio/test/data/bio-write-expected b/lib/bio/test/data/bio-write-expected
new file mode 100755
index 0000000..ced6c96
--- /dev/null
+++ b/lib/bio/test/data/bio-write-expected
@@ -0,0 +1,3 @@
+test
+test
+1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111goodbye
diff --git a/lib/bio/test/data/datafile b/lib/bio/test/data/datafile
new file mode 100644
index 0000000..52a47f6
--- /dev/null
+++ b/lib/bio/test/data/datafile
@@ -0,0 +1 @@
+01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
diff --git a/lib/bio/test/data/lines b/lib/bio/test/data/lines
new file mode 100644
index 0000000..781db66
--- /dev/null
+++ b/lib/bio/test/data/lines
@@ -0,0 +1,4 @@
+first line
+second line
+data with;semicolons;
+and--no-terminator
diff --git a/lib/bio/test/runtest.sh b/lib/bio/test/runtest.sh
new file mode 100755
index 0000000..95f548f
--- /dev/null
+++ b/lib/bio/test/runtest.sh
@@ -0,0 +1,124 @@
+#!/bin/bash
+NFAILURES=0
+NPASSES=0
+
+function build {
+ rm -f $1 $1.o $1.s $1.use
+ myrbuild $FLAGS -b $1 $1.myr $EXTRA_SRC
+}
+
+function pass {
+ PASSED="$PASSED $1"
+ NPASSED=$[$NPASSED + 1]
+}
+
+function fail {
+ echo "FAIL: $1"
+ FAILED="$FAILED $1"
+ NFAILED=$[$NFAILED + 1]
+}
+
+function expectstatus {
+ ./$1 $3
+ if [ $? -eq $2 ]; then
+ pass $1
+ return
+ else
+ fail $1
+ fi
+}
+
+function expectprint {
+ if [ "`./$1 $3`" != "$2" ]; then
+ fail $1
+ else
+ pass $1
+ fi
+}
+
+
+function expectcompare {
+ if [ x"" != x"$TMPDIR" ]; then
+ t=$TMPDIR/myrtest-$1-$RANDOM
+ else
+ t=/tmp/myrtest-$1-$RANDOM
+ fi
+ ./$1 $3 > $t
+ if cmp $t data/$1-expected; then
+ pass $1
+ else
+ fail $1
+ fi
+ rm -f $t
+}
+
+function expectfcompare {
+ ./$1 $3
+ if cmp data/$1-expected $2; then
+ pass $1
+ else
+ fail $1
+ fi
+}
+
+function shouldskip {
+ if [ -z $ARGS ]; then
+ return 1
+ fi
+
+ for i in $ARGS; do
+ if [ $i = $1 ]; then
+ return 1
+ fi
+ done
+ return 0
+}
+
+
+# Should build and run
+function B {
+ if shouldskip $1; then
+ return
+ fi
+
+ test="$1"; shift
+ type="$1"; shift
+ res="$1"; shift
+ if [ $# > 0 ]; then
+ args="$1"; shift
+ fi
+ build $test
+ case $type in
+ "E") expectstatus "$test" "$res" "$input";;
+ "P") expectprint "$test" "$res" "$input";;
+ "C") expectcompare "$test" "$res" "$input";;
+ "F") expectfcompare "$test" "$res" "$args";;
+ esac
+}
+
+# Should fail
+function F {
+ if shouldskip $1; then
+ return
+ fi
+ (build $1) > /dev/null
+ if [ $? -eq '1' ]; then
+ pass $1
+ else
+ fail $1
+ fi
+}
+
+# Should generate a usefile
+function U {
+ return
+}
+
+source tests
+
+echo "PASSED ($NPASSED): $PASSED"
+if [ -z "$NFAILED" ]; then
+ echo "SUCCESS"
+else
+ echo "FAILURES ($NFAILED): $FAILED"
+fi
diff --git a/lib/bio/test/tests b/lib/bio/test/tests
new file mode 100644
index 0000000..81c1087
--- /dev/null
+++ b/lib/bio/test/tests
@@ -0,0 +1,31 @@
+FLAGS=-I../
+mkdir -p tmpout
+# Format:
+# [B|F] testname [E|P] result
+# [B|F]: Compiler outcome.
+# B: Expect that this test will build.
+# F: Expect that this test will not build.
+# testname: Test case
+# The test that will run. We will try to
+# compile 'testname.myr' to 'testname',
+# and then execute it, verifying the result
+# [E|P|C]: Result type
+# E tells us that the result is an exit status
+# P tells us that the result is on stdout,
+# and should be compared to the value on the
+# line
+# C tells us that the result is on stdout,
+# and should be compared to the contents of
+# the file passed on the line.
+# result: Result value
+# What we compare with. This should be self-
+# evident.
+B bio-create F tmpout/test-create
+B bio-read C
+B bio-write F tmpout/test-write
+B bio-delim C
+B bio-endianwr F tmpout/test-endianwr
+B bio-endianrd C
+B bio-unitwr F tmpout/test-unitwr
+B bio-peek C
+#B bio-fmt C
diff --git a/lib/cryptohash/bld.sub b/lib/cryptohash/bld.sub
new file mode 100644
index 0000000..b6056f7
--- /dev/null
+++ b/lib/cryptohash/bld.sub
@@ -0,0 +1,7 @@
+lib cryptohash =
+ md5.myr
+ sha1.myr
+ sha256.myr
+ sha512.myr
+;;
+
diff --git a/lib/cryptohash/md5.myr b/lib/cryptohash/md5.myr
new file mode 100644
index 0000000..5f4b600
--- /dev/null
+++ b/lib/cryptohash/md5.myr
@@ -0,0 +1,215 @@
+use std
+
+pkg cryptohash =
+ type md5
+
+ const md5 : (data : byte[:] -> byte[16])
+ const md5init : (st : md5# -> void)
+ const md5add : (st : md5#, data : byte[:] -> void)
+ const md5fin : (st : md5# -> byte[16])
+;;
+
+type md5 = struct
+ a : uint32
+ b : uint32
+ c : uint32
+ d : uint32
+ tail : byte[64]
+ msglen : uint64
+
+;;
+
+const md5 = {data
+ var st
+
+ md5init(&st)
+ md5add(&st, data)
+ -> md5fin(&st)
+}
+
+const md5init = {st
+ st.a = 0x67452301
+ st.b = 0xefcdab89
+ st.c = 0x98badcfe
+ st.d = 0x10325476
+ st.msglen = 0
+}
+
+const md5add = {st, data
+ var n, ntail
+
+ ntail = st.msglen % 64
+ st.msglen += data.len
+ if ntail > 0
+ n = std.min(64 - ntail, data.len)
+ std.slcp(st.tail[ntail:ntail + n], data[:n])
+ data = data[n:]
+ if n + ntail < 64
+ ->
+ ;;
+ step(st, st.tail[:])
+ ;;
+ while data.len >= 64
+ step(st, data[:64])
+ data = data[64:]
+ ;;
+ std.slcp(st.tail[:data.len], data)
+}
+
+const md5fin = {st
+ var r : byte[16]
+ var ntail
+
+ /* append first padding block */
+ ntail = st.msglen % 64
+ st.tail[ntail++] = 0x80
+ std.slfill(st.tail[ntail:], 0)
+ if 64 - ntail < 8
+ step(st, st.tail[:])
+ std.slfill(st.tail[:], 0)
+ ;;
+
+ /* append size block */
+ st.tail[56] = ((st.msglen * 8) >> 0) castto(byte)
+ st.tail[57] = ((st.msglen * 8) >> 8) castto(byte)
+ st.tail[58] = ((st.msglen * 8) >> 16) castto(byte)
+ st.tail[59] = ((st.msglen * 8) >> 24) castto(byte)
+ st.tail[60] = ((st.msglen * 8) >> 32) castto(byte)
+ st.tail[61] = ((st.msglen * 8) >> 40) castto(byte)
+ st.tail[62] = ((st.msglen * 8) >> 48) castto(byte)
+ st.tail[63] = ((st.msglen * 8) >> 56) castto(byte)
+ step(st, st.tail[:])
+
+ r[0] = (st.a >> 0) castto(byte)
+ r[1] = (st.a >> 8) castto(byte)
+ r[2] = (st.a >> 16) castto(byte)
+ r[3] = (st.a >> 24) castto(byte)
+ r[4] = (st.b >> 0) castto(byte)
+ r[5] = (st.b >> 8) castto(byte)
+ r[6] = (st.b >> 16) castto(byte)
+ r[7] = (st.b >> 24) castto(byte)
+ r[8] = (st.c >> 0) castto(byte)
+ r[9] = (st.c >> 8) castto(byte)
+ r[10] = (st.c >> 16) castto(byte)
+ r[11] = (st.c >> 24) castto(byte)
+ r[12] = (st.d >> 0) castto(byte)
+ r[13] = (st.d >> 8) castto(byte)
+ r[14] = (st.d >> 16) castto(byte)
+ r[15] = (st.d >> 24) castto(byte)
+ -> r
+}
+
+const step = {st, blk
+ var a, b, c, d
+ var s00, s01, s02, s03, s04, s05, s06, s07
+ var s08, s09, s10, s11, s12, s13, s14, s15
+
+ a = st.a
+ b = st.b
+ c = st.c
+ d = st.d
+
+ s00 = unpack(blk[0:4])
+ s01 = unpack(blk[4:8])
+ s02 = unpack(blk[8:12])
+ s03 = unpack(blk[12:16])
+ s04 = unpack(blk[16:20])
+ s05 = unpack(blk[20:24])
+ s06 = unpack(blk[24:28])
+ s07 = unpack(blk[28:32])
+ s08 = unpack(blk[32:36])
+ s09 = unpack(blk[36:40])
+ s10 = unpack(blk[40:44])
+ s11 = unpack(blk[44:48])
+ s12 = unpack(blk[48:52])
+ s13 = unpack(blk[52:56])
+ s14 = unpack(blk[56:60])
+ s15 = unpack(blk[60:64])
+
+ /* round 1 */
+ a += (d ^ (b & (c ^ d))) + 0xd76aa478 + s00; a = b + (a << 7 | a >> 25)
+ d += (c ^ (a & (b ^ c))) + 0xe8c7b756 + s01; d = a + (d << 12 | d >> 20)
+ c += (b ^ (d & (a ^ b))) + 0x242070db + s02; c = d + (c << 17 | c >> 15)
+ b += (a ^ (c & (d ^ a))) + 0xc1bdceee + s03; b = c + (b << 22 | b >> 10)
+ a += (d ^ (b & (c ^ d))) + 0xf57c0faf + s04; a = b + (a << 7 | a >> 25)
+ d += (c ^ (a & (b ^ c))) + 0x4787c62a + s05; d = a + (d << 12 | d >> 20)
+ c += (b ^ (d & (a ^ b))) + 0xa8304613 + s06; c = d + (c << 17 | c >> 15)
+ b += (a ^ (c & (d ^ a))) + 0xfd469501 + s07; b = c + (b << 22 | b >> 10)
+ a += (d ^ (b & (c ^ d))) + 0x698098d8 + s08; a = b + (a << 7 | a >> 25)
+ d += (c ^ (a & (b ^ c))) + 0x8b44f7af + s09; d = a + (d << 12 | d >> 20)
+ c += (b ^ (d & (a ^ b))) + 0xffff5bb1 + s10; c = d + (c << 17 | c >> 15)
+ b += (a ^ (c & (d ^ a))) + 0x895cd7be + s11; b = c + (b << 22 | b >> 10)
+ a += (d ^ (b & (c ^ d))) + 0x6b901122 + s12; a = b + (a << 7 | a >> 25)
+ d += (c ^ (a & (b ^ c))) + 0xfd987193 + s13; d = a + (d << 12 | d >> 20)
+ c += (b ^ (d & (a ^ b))) + 0xa679438e + s14; c = d + (c << 17 | c >> 15)
+ b += (a ^ (c & (d ^ a))) + 0x49b40821 + s15; b = c + (b << 22 | b >> 10)
+
+ /* round 2 */
+ a += (c ^ (d & (b ^ c))) + 0xf61e2562 + s01; a = b + (a << 5 | a >> 27)
+ d += (b ^ (c & (a ^ b))) + 0xc040b340 + s06; d = a + (d << 9 | d >> 23)
+ c += (a ^ (b & (d ^ a))) + 0x265e5a51 + s11; c = d + (c << 14 | c >> 18)
+ b += (d ^ (a & (c ^ d))) + 0xe9b6c7aa + s00; b = c + (b << 20 | b >> 12)
+ a += (c ^ (d & (b ^ c))) + 0xd62f105d + s05; a = b + (a << 5 | a >> 27)
+ d += (b ^ (c & (a ^ b))) + 0x02441453 + s10; d = a + (d << 9 | d >> 23)
+ c += (a ^ (b & (d ^ a))) + 0xd8a1e681 + s15; c = d + (c << 14 | c >> 18)
+ b += (d ^ (a & (c ^ d))) + 0xe7d3fbc8 + s04; b = c + (b << 20 | b >> 12)
+ a += (c ^ (d & (b ^ c))) + 0x21e1cde6 + s09; a = b + (a << 5 | a >> 27)
+ d += (b ^ (c & (a ^ b))) + 0xc33707d6 + s14; d = a + (d << 9 | d >> 23)
+ c += (a ^ (b & (d ^ a))) + 0xf4d50d87 + s03; c = d + (c << 14 | c >> 18)
+ b += (d ^ (a & (c ^ d))) + 0x455a14ed + s08; b = c + (b << 20 | b >> 12)
+ a += (c ^ (d & (b ^ c))) + 0xa9e3e905 + s13; a = b + (a << 5 | a >> 27)
+ d += (b ^ (c & (a ^ b))) + 0xfcefa3f8 + s02; d = a + (d << 9 | d >> 23)
+ c += (a ^ (b & (d ^ a))) + 0x676f02d9 + s07; c = d + (c << 14 | c >> 18)
+ b += (d ^ (a & (c ^ d))) + 0x8d2a4c8a + s12; b = c + (b << 20 | b >> 12)
+
+ /* round 3 */
+ a += (b ^ c ^ d) + 0xfffa3942 + s05; a = b + (a << 4 | a >> 28)
+ d += (a ^ b ^ c) + 0x8771f681 + s08; d = a + (d << 11 | d >> 21)
+ c += (d ^ a ^ b) + 0x6d9d6122 + s11; c = d + (c << 16 | c >> 16)
+ b += (c ^ d ^ a) + 0xfde5380c + s14; b = c + (b << 23 | b >> 9)
+ a += (b ^ c ^ d) + 0xa4beea44 + s01; a = b + (a << 4 | a >> 28)
+ d += (a ^ b ^ c) + 0x4bdecfa9 + s04; d = a + (d << 11 | d >> 21)
+ c += (d ^ a ^ b) + 0xf6bb4b60 + s07; c = d + (c << 16 | c >> 16)
+ b += (c ^ d ^ a) + 0xbebfbc70 + s10; b = c + (b << 23 | b >> 9)
+ a += (b ^ c ^ d) + 0x289b7ec6 + s13; a = b + (a << 4 | a >> 28)
+ d += (a ^ b ^ c) + 0xeaa127fa + s00; d = a + (d << 11 | d >> 21)
+ c += (d ^ a ^ b) + 0xd4ef3085 + s03; c = d + (c << 16 | c >> 16)
+ b += (c ^ d ^ a) + 0x04881d05 + s06; b = c + (b << 23 | b >> 9)
+ a += (b ^ c ^ d) + 0xd9d4d039 + s09; a = b + (a << 4 | a >> 28)
+ d += (a ^ b ^ c) + 0xe6db99e5 + s12; d = a + (d << 11 | d >> 21)
+ c += (d ^ a ^ b) + 0x1fa27cf8 + s15; c = d + (c << 16 | c >> 16)
+ b += (c ^ d ^ a) + 0xc4ac5665 + s02; b = c + (b << 23 | b >> 9)
+
+ /* round 4 */
+ a += (c ^ (b | ~d)) + 0xf4292244 + s00; a = b + (a << 6 | a >> 26)
+ d += (b ^ (a | ~c)) + 0x432aff97 + s07; d = a + (d << 10 | d >> 22)
+ c += (a ^ (d | ~b)) + 0xab9423a7 + s14; c = d + (c << 15 | c >> 17)
+ b += (d ^ (c | ~a)) + 0xfc93a039 + s05; b = c + (b << 21 | b >> 11)
+ a += (c ^ (b | ~d)) + 0x655b59c3 + s12; a = b + (a << 6 | a >> 26)
+ d += (b ^ (a | ~c)) + 0x8f0ccc92 + s03; d = a + (d << 10 | d >> 22)
+ c += (a ^ (d | ~b)) + 0xffeff47d + s10; c = d + (c << 15 | c >> 17)
+ b += (d ^ (c | ~a)) + 0x85845dd1 + s01; b = c + (b << 21 | b >> 11)
+ a += (c ^ (b | ~d)) + 0x6fa87e4f + s08; a = b + (a << 6 | a >> 26)
+ d += (b ^ (a | ~c)) + 0xfe2ce6e0 + s15; d = a + (d << 10 | d >> 22)
+ c += (a ^ (d | ~b)) + 0xa3014314 + s06; c = d + (c << 15 | c >> 17)
+ b += (d ^ (c | ~a)) + 0x4e0811a1 + s13; b = c + (b << 21 | b >> 11)
+ a += (c ^ (b | ~d)) + 0xf7537e82 + s04; a = b + (a << 6 | a >> 26)
+ d += (b ^ (a | ~c)) + 0xbd3af235 + s11; d = a + (d << 10 | d >> 22)
+ c += (a ^ (d | ~b)) + 0x2ad7d2bb + s02; c = d + (c << 15 | c >> 17)
+ b += (d ^ (c | ~a)) + 0xeb86d391 + s09; b = c + (b << 21 | b >> 11)
+
+ st.a += a
+ st.b += b
+ st.c += c
+ st.d += d
+}
+
+const unpack = {b
+ var v : uint32
+
+ v = ((b[0] castto(uint32)) << 0)
+ v |= ((b[1] castto(uint32)) << 8)
+ v |= ((b[2] castto(uint32)) << 16)
+ v |= ((b[3] castto(uint32)) << 24)
+ -> v
+}
diff --git a/lib/cryptohash/sha1.myr b/lib/cryptohash/sha1.myr
new file mode 100644
index 0000000..ecf0ec3
--- /dev/null
+++ b/lib/cryptohash/sha1.myr
@@ -0,0 +1,243 @@
+use std
+
+pkg cryptohash =
+ type sha1
+
+ const sha1 : (data : byte[:] -> byte[20])
+ const sha1init : (st : sha1# -> void)
+ const sha1add : (st : sha1#, data : byte[:] -> void)
+ const sha1fin : (st : sha1# -> byte[20])
+;;
+
+type sha1 = struct
+ a : uint32
+ b : uint32
+ c : uint32
+ d : uint32
+ e : uint32
+ tail : byte[64]
+ msglen : uint64
+;;
+
+const sha1 = {data
+ var st
+
+ sha1init(&st)
+ sha1add(&st, data)
+ -> sha1fin(&st)
+}
+
+const sha1init = {st
+ st.a = 0x67452301
+ st.b = 0xefcdab89
+ st.c = 0x98badcfe
+ st.d = 0x10325476
+ st.e = 0xc3d2e1f0
+ st.msglen = 0
+}
+
+const sha1add = {st, data
+ var n, ntail
+
+ ntail = st.msglen % 64
+ st.msglen += data.len
+ if ntail > 0
+ n = std.min(64 - ntail, data.len)
+ std.slcp(st.tail[ntail:ntail + n], data[:n])
+ data = data[n:]
+ if n + ntail < 64
+ ->
+ ;;
+ step(st, st.tail[:])
+ ;;
+
+ while data.len >= 64
+ step(st, data[:64])
+ data = data[64:]
+ ;;
+
+ std.slcp(st.tail[:data.len], data)
+}
+
+const sha1fin = {st
+ var r : byte[20]
+ var ntail
+
+ /* append first padding block */
+ ntail = st.msglen % 64
+ st.tail[ntail++] = 0x80
+ std.slfill(st.tail[ntail:], 0)
+ if 64 - ntail < 8
+ step(st, st.tail[:])
+ std.slfill(st.tail[:], 0)
+ ;;
+
+
+ /* append size block */
+ st.tail[56] = ((st.msglen * 8) >> 56) castto(byte)
+ st.tail[57] = ((st.msglen * 8) >> 48) castto(byte)
+ st.tail[58] = ((st.msglen * 8) >> 40) castto(byte)
+ st.tail[59] = ((st.msglen * 8) >> 32) castto(byte)
+ st.tail[60] = ((st.msglen * 8) >> 24) castto(byte)
+ st.tail[61] = ((st.msglen * 8) >> 16) castto(byte)
+ st.tail[62] = ((st.msglen * 8) >> 8) castto(byte)
+ st.tail[63] = ((st.msglen * 8) >> 0) castto(byte)
+ step(st, st.tail[:])
+
+ r[0] = (st.a >> 24) castto(byte)
+ r[1] = (st.a >> 16) castto(byte)
+ r[2] = (st.a >> 8) castto(byte)
+ r[3] = (st.a >> 0) castto(byte)
+ r[4] = (st.b >> 24) castto(byte)
+ r[5] = (st.b >> 16) castto(byte)
+ r[6] = (st.b >> 8) castto(byte)
+ r[7] = (st.b >> 0) castto(byte)
+ r[8] = (st.c >> 24) castto(byte)
+ r[9] = (st.c >> 16) castto(byte)
+ r[10] = (st.c >> 8) castto(byte)
+ r[11] = (st.c >> 0) castto(byte)
+ r[12] = (st.d >> 16) castto(byte)
+ r[13] = (st.d >> 24) castto(byte)
+ r[14] = (st.d >> 8) castto(byte)
+ r[15] = (st.d >> 0) castto(byte)
+ r[16] = (st.e >> 16) castto(byte)
+ r[17] = (st.e >> 24) castto(byte)
+ r[18] = (st.e >> 8) castto(byte)
+ r[19] = (st.e >> 0) castto(byte)
+ -> r
+}
+
+const K0 = 0x5a827999
+const K1 = 0x6ed9eba1
+const K2 = 0x8f1bbcdc
+const K3 = 0xCA62C1D6
+const step = {st, msg
+ var a, b, c, d, e
+ var s00, s01, s02, s03, s04, s05, s06, s07
+ var s08, s09, s10, s11, s12, s13, s14, s15
+ var t
+
+ a = st.a
+ b = st.b
+ c = st.c
+ d = st.d
+ e = st.e
+
+ s00 = unpack(msg[ 0: 4])
+ s01 = unpack(msg[ 4: 8])
+ s02 = unpack(msg[ 8:12])
+ s03 = unpack(msg[12:16])
+ s04 = unpack(msg[16:20])
+ s05 = unpack(msg[20:24])
+ s06 = unpack(msg[24:28])
+ s07 = unpack(msg[28:32])
+ s08 = unpack(msg[32:36])
+ s09 = unpack(msg[36:40])
+ s10 = unpack(msg[40:44])
+ s11 = unpack(msg[44:48])
+ s12 = unpack(msg[48:52])
+ s13 = unpack(msg[52:56])
+ s14 = unpack(msg[56:60])
+ s15 = unpack(msg[60:64])
+
+ e += (a << 5 | a >> 27) + (d ^ (b & (c ^ d))) + s00 + K0; b = b << 30 | b >> 2
+ d += (e << 5 | e >> 27) + (c ^ (a & (b ^ c))) + s01 + K0; a = a << 30 | a >> 2
+ c += (d << 5 | d >> 27) + (b ^ (e & (a ^ b))) + s02 + K0; e = e << 30 | e >> 2
+ b += (c << 5 | c >> 27) + (a ^ (d & (e ^ a))) + s03 + K0; d = d << 30 | d >> 2
+ a += (b << 5 | b >> 27) + (e ^ (c & (d ^ e))) + s04 + K0; c = c << 30 | c >> 2
+ e += (a << 5 | a >> 27) + (d ^ (b & (c ^ d))) + s05 + K0; b = b << 30 | b >> 2
+ d += (e << 5 | e >> 27) + (c ^ (a & (b ^ c))) + s06 + K0; a = a << 30 | a >> 2
+ c += (d << 5 | d >> 27) + (b ^ (e & (a ^ b))) + s07 + K0; e = e << 30 | e >> 2
+ b += (c << 5 | c >> 27) + (a ^ (d & (e ^ a))) + s08 + K0; d = d << 30 | d >> 2
+ a += (b << 5 | b >> 27) + (e ^ (c & (d ^ e))) + s09 + K0; c = c << 30 | c >> 2
+ e += (a << 5 | a >> 27) + (d ^ (b & (c ^ d))) + s10 + K0; b = b << 30 | b >> 2
+ d += (e << 5 | e >> 27) + (c ^ (a & (b ^ c))) + s11 + K0; a = a << 30 | a >> 2
+ c += (d << 5 | d >> 27) + (b ^ (e & (a ^ b))) + s12 + K0; e = e << 30 | e >> 2
+ b += (c << 5 | c >> 27) + (a ^ (d & (e ^ a))) + s13 + K0; d = d << 30 | d >> 2
+ a += (b << 5 | b >> 27) + (e ^ (c & (d ^ e))) + s14 + K0; c = c << 30 | c >> 2
+ e += (a << 5 | a >> 27) + (d ^ (b & (c ^ d))) + s15 + K0; b = b << 30 | b >> 2
+
+
+ t = s13 ^ s08 ^ s02 ^ s00; s00 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + (c ^ (a & (b ^ c))) + s00 + K0; a = a << 30 | a >> 2
+ t = s14 ^ s09 ^ s03 ^ s01; s01 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + (b ^ (e & (a ^ b))) + s01 + K0; e = e << 30 | e >> 2
+ t = s15 ^ s10 ^ s04 ^ s02; s02 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + (a ^ (d & (e ^ a))) + s02 + K0; d = d << 30 | d >> 2
+ t = s00 ^ s11 ^ s05 ^ s03; s03 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + (e ^ (c & (d ^ e))) + s03 + K0; c = c << 30 | c >> 2
+ t = s01 ^ s12 ^ s06 ^ s04; s04 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + (b ^ c ^ d) + s04 + K1; b = b << 30 | b >> 2
+ t = s02 ^ s13 ^ s07 ^ s05; s05 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + (a ^ b ^ c) + s05 + K1; a = a << 30 | a >> 2
+ t = s03 ^ s14 ^ s08 ^ s06; s06 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + (e ^ a ^ b) + s06 + K1; e = e << 30 | e >> 2
+ t = s04 ^ s15 ^ s09 ^ s07; s07 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + (d ^ e ^ a) + s07 + K1; d = d << 30 | d >> 2
+ t = s05 ^ s00 ^ s10 ^ s08; s08 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + (c ^ d ^ e) + s08 + K1; c = c << 30 | c >> 2
+ t = s06 ^ s01 ^ s11 ^ s09; s09 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + (b ^ c ^ d) + s09 + K1; b = b << 30 | b >> 2
+ t = s07 ^ s02 ^ s12 ^ s10; s10 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + (a ^ b ^ c) + s10 + K1; a = a << 30 | a >> 2
+ t = s08 ^ s03 ^ s13 ^ s11; s11 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + (e ^ a ^ b) + s11 + K1; e = e << 30 | e >> 2
+ t = s09 ^ s04 ^ s14 ^ s12; s12 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + (d ^ e ^ a) + s12 + K1; d = d << 30 | d >> 2
+ t = s10 ^ s05 ^ s15 ^ s13; s13 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + (c ^ d ^ e) + s13 + K1; c = c << 30 | c >> 2
+ t = s11 ^ s06 ^ s00 ^ s14; s14 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + (b ^ c ^ d) + s14 + K1; b = b << 30 | b >> 2
+ t = s12 ^ s07 ^ s01 ^ s15; s15 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + (a ^ b ^ c) + s15 + K1; a = a << 30 | a >> 2
+ t = s13 ^ s08 ^ s02 ^ s00; s00 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + (e ^ a ^ b) + s00 + K1; e = e << 30 | e >> 2
+ t = s14 ^ s09 ^ s03 ^ s01; s01 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + (d ^ e ^ a) + s01 + K1; d = d << 30 | d >> 2
+ t = s15 ^ s10 ^ s04 ^ s02; s02 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + (c ^ d ^ e) + s02 + K1; c = c << 30 | c >> 2
+ t = s00 ^ s11 ^ s05 ^ s03; s03 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + (b ^ c ^ d) + s03 + K1; b = b << 30 | b >> 2
+ t = s01 ^ s12 ^ s06 ^ s04; s04 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + (a ^ b ^ c) + s04 + K1; a = a << 30 | a >> 2
+ t = s02 ^ s13 ^ s07 ^ s05; s05 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + (e ^ a ^ b) + s05 + K1; e = e << 30 | e >> 2
+ t = s03 ^ s14 ^ s08 ^ s06; s06 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + (d ^ e ^ a) + s06 + K1; d = d << 30 | d >> 2
+ t = s04 ^ s15 ^ s09 ^ s07; s07 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + (c ^ d ^ e) + s07 + K1; c = c << 30 | c >> 2
+
+ t = s05 ^ s00 ^ s10 ^ s08; s08 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + ((b & (c | d)) | (c & d)) + s08 + K2; b = b << 30 | b >> 2
+ t = s06 ^ s01 ^ s11 ^ s09; s09 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + ((a & (b | c)) | (b & c)) + s09 + K2; a = a << 30 | a >> 2
+ t = s07 ^ s02 ^ s12 ^ s10; s10 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + ((e & (a | b)) | (a & b)) + s10 + K2; e = e << 30 | e >> 2
+ t = s08 ^ s03 ^ s13 ^ s11; s11 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + ((d & (e | a)) | (e & a)) + s11 + K2; d = d << 30 | d >> 2
+ t = s09 ^ s04 ^ s14 ^ s12; s12 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + ((c & (d | e)) | (d & e)) + s12 + K2; c = c << 30 | c >> 2
+ t = s10 ^ s05 ^ s15 ^ s13; s13 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + ((b & (c | d)) | (c & d)) + s13 + K2; b = b << 30 | b >> 2
+ t = s11 ^ s06 ^ s00 ^ s14; s14 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + ((a & (b | c)) | (b & c)) + s14 + K2; a = a << 30 | a >> 2
+ t = s12 ^ s07 ^ s01 ^ s15; s15 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + ((e & (a | b)) | (a & b)) + s15 + K2; e = e << 30 | e >> 2
+ t = s13 ^ s08 ^ s02 ^ s00; s00 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + ((d & (e | a)) | (e & a)) + s00 + K2; d = d << 30 | d >> 2
+ t = s14 ^ s09 ^ s03 ^ s01; s01 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + ((c & (d | e)) | (d & e)) + s01 + K2; c = c << 30 | c >> 2
+ t = s15 ^ s10 ^ s04 ^ s02; s02 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + ((b & (c | d)) | (c & d)) + s02 + K2; b = b << 30 | b >> 2
+ t = s00 ^ s11 ^ s05 ^ s03; s03 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + ((a & (b | c)) | (b & c)) + s03 + K2; a = a << 30 | a >> 2
+ t = s01 ^ s12 ^ s06 ^ s04; s04 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + ((e & (a | b)) | (a & b)) + s04 + K2; e = e << 30 | e >> 2
+ t = s02 ^ s13 ^ s07 ^ s05; s05 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + ((d & (e | a)) | (e & a)) + s05 + K2; d = d << 30 | d >> 2
+ t = s03 ^ s14 ^ s08 ^ s06; s06 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + ((c & (d | e)) | (d & e)) + s06 + K2; c = c << 30 | c >> 2
+ t = s04 ^ s15 ^ s09 ^ s07; s07 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + ((b & (c | d)) | (c & d)) + s07 + K2; b = b << 30 | b >> 2
+ t = s05 ^ s00 ^ s10 ^ s08; s08 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + ((a & (b | c)) | (b & c)) + s08 + K2; a = a << 30 | a >> 2
+ t = s06 ^ s01 ^ s11 ^ s09; s09 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + ((e & (a | b)) | (a & b)) + s09 + K2; e = e << 30 | e >> 2
+ t = s07 ^ s02 ^ s12 ^ s10; s10 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + ((d & (e | a)) | (e & a)) + s10 + K2; d = d << 30 | d >> 2
+ t = s08 ^ s03 ^ s13 ^ s11; s11 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + ((c & (d | e)) | (d & e)) + s11 + K2; c = c << 30 | c >> 2
+
+ t = s09 ^ s04 ^ s14 ^ s12; s12 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + (b ^ c ^ d) + s12 + K3; b = b << 30 | b >> 2
+ t = s10 ^ s05 ^ s15 ^ s13; s13 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + (a ^ b ^ c) + s13 + K3; a = a << 30 | a >> 2
+ t = s11 ^ s06 ^ s00 ^ s14; s14 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + (e ^ a ^ b) + s14 + K3; e = e << 30 | e >> 2
+ t = s12 ^ s07 ^ s01 ^ s15; s15 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + (d ^ e ^ a) + s15 + K3; d = d << 30 | d >> 2
+ t = s13 ^ s08 ^ s02 ^ s00; s00 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + (c ^ d ^ e) + s00 + K3; c = c << 30 | c >> 2
+ t = s14 ^ s09 ^ s03 ^ s01; s01 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + (b ^ c ^ d) + s01 + K3; b = b << 30 | b >> 2
+ t = s15 ^ s10 ^ s04 ^ s02; s02 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + (a ^ b ^ c) + s02 + K3; a = a << 30 | a >> 2
+ t = s00 ^ s11 ^ s05 ^ s03; s03 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + (e ^ a ^ b) + s03 + K3; e = e << 30 | e >> 2
+ t = s01 ^ s12 ^ s06 ^ s04; s04 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + (d ^ e ^ a) + s04 + K3; d = d << 30 | d >> 2
+ t = s02 ^ s13 ^ s07 ^ s05; s05 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + (c ^ d ^ e) + s05 + K3; c = c << 30 | c >> 2
+ t = s03 ^ s14 ^ s08 ^ s06; s06 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + (b ^ c ^ d) + s06 + K3; b = b << 30 | b >> 2
+ t = s04 ^ s15 ^ s09 ^ s07; s07 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + (a ^ b ^ c) + s07 + K3; a = a << 30 | a >> 2
+ t = s05 ^ s00 ^ s10 ^ s08; s08 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + (e ^ a ^ b) + s08 + K3; e = e << 30 | e >> 2
+ t = s06 ^ s01 ^ s11 ^ s09; s09 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + (d ^ e ^ a) + s09 + K3; d = d << 30 | d >> 2
+ t = s07 ^ s02 ^ s12 ^ s10; s10 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + (c ^ d ^ e) + s10 + K3; c = c << 30 | c >> 2
+ t = s08 ^ s03 ^ s13 ^ s11; s11 = t << 1 | t >> 31; e += (a << 5 | a >> 27) + (b ^ c ^ d) + s11 + K3; b = b << 30 | b >> 2
+ t = s09 ^ s04 ^ s14 ^ s12; s12 = t << 1 | t >> 31; d += (e << 5 | e >> 27) + (a ^ b ^ c) + s12 + K3; a = a << 30 | a >> 2
+ t = s10 ^ s05 ^ s15 ^ s13; s13 = t << 1 | t >> 31; c += (d << 5 | d >> 27) + (e ^ a ^ b) + s13 + K3; e = e << 30 | e >> 2
+ t = s11 ^ s06 ^ s00 ^ s14; s14 = t << 1 | t >> 31; b += (c << 5 | c >> 27) + (d ^ e ^ a) + s14 + K3; d = d << 30 | d >> 2
+ t = s12 ^ s07 ^ s01 ^ s15; s15 = t << 1 | t >> 31; a += (b << 5 | b >> 27) + (c ^ d ^ e) + s15 + K3; c = c << 30 | c >> 2
+
+ st.a += a
+ st.b += b
+ st.c += c
+ st.d += d
+ st.e += e
+}
+
+const unpack = {b
+ var v : uint32
+
+ v = ((b[0] castto(uint32)) << 24)
+ v |= ((b[1] castto(uint32)) << 16)
+ v |= ((b[2] castto(uint32)) << 8)
+ v |= ((b[3] castto(uint32)) << 0)
+ -> v
+}
diff --git a/lib/cryptohash/sha256.myr b/lib/cryptohash/sha256.myr
new file mode 100644
index 0000000..5939fa8
--- /dev/null
+++ b/lib/cryptohash/sha256.myr
@@ -0,0 +1,415 @@
+use std
+
+pkg cryptohash =
+ type sha256
+ type sha224
+
+ const sha256 : (data : byte[:] -> byte[32])
+ const sha256init : (st : sha256# -> void)
+ const sha256add : (st : sha256#, data : byte[:] -> void)
+ const sha256fin : (st : sha256# -> byte[32])
+
+ const sha224 : (data : byte[:] -> byte[28])
+ const sha224init : (st : sha224# -> void)
+ const sha224add : (st : sha224#, data : byte[:] -> void)
+ const sha224fin : (st : sha224# -> byte[28])
+;;
+
+type sha256 = struct
+ x : uint32[8]
+ tail : byte[64]
+ msglen : uint64
+;;
+
+const sha256 = {data
+ var st
+
+ sha256init(&st)
+ sha256add(&st, data)
+ -> sha256fin(&st)
+}
+
+const sha256init = {st
+ st.x[0] = 0x6A09E667
+ st.x[1] = 0xBB67AE85
+ st.x[2] = 0x3C6EF372
+ st.x[3] = 0xA54FF53A
+ st.x[4] = 0x510e527f
+ st.x[5] = 0x9b05688c
+ st.x[6] = 0x1f83d9ab
+ st.x[7] = 0x5be0cd19
+ st.msglen = 0
+}
+
+const sha256add = {st, data
+ var n, ntail
+
+ ntail = st.msglen % 64
+ st.msglen += data.len
+ if ntail > 0
+ n = std.min(64 - ntail, data.len)
+ std.slcp(st.tail[ntail:ntail + n], data[:n])
+ data = data[n:]
+ if n + ntail < 64
+ ->
+ ;;
+ step(st.x[:], st.tail[:])
+ ;;
+
+ while data.len >= 64
+ step(st.x[:], data[:64])
+ data = data[64:]
+ ;;
+
+ ntail = st.msglen % 64
+ std.slcp(st.tail[:ntail], data)
+}
+
+const sha256fin = {st
+ var r : byte[32]
+
+ tail(st.x[:], st.msglen, st.tail[:])
+
+ pack(r[0:4], st.x[0])
+ pack(r[4:8], st.x[1])
+ pack(r[8:12], st.x[2])
+ pack(r[12:16], st.x[3])
+ pack(r[16:20], st.x[4])
+ pack(r[20:24], st.x[5])
+ pack(r[24:28], st.x[6])
+ pack(r[28:32], st.x[7])
+ -> r
+}
+
+type sha224 = struct
+ x : uint32[8]
+ tail : byte[64]
+ msglen : uint64
+;;
+
+const sha224 = {data
+ var st
+
+ sha224init(&st)
+ sha224add(&st, data)
+ -> sha224fin(&st)
+}
+
+const sha224init = {st
+ st.x[0] = 0xc1059ed8
+ st.x[1] = 0x367cd507
+ st.x[2] = 0x3070dd17
+ st.x[3] = 0xf70e5939
+ st.x[4] = 0xffc00b31
+ st.x[5] = 0x68581511
+ st.x[6] = 0x64f98fa7
+ st.x[7] = 0xbefa4fa4
+ st.msglen = 0
+}
+
+const sha224add = {st, data
+ var n, ntail
+
+ ntail = st.msglen % 64
+ st.msglen += data.len
+ if ntail > 0
+ n = std.min(64 - ntail, data.len)
+ std.slcp(st.tail[ntail:ntail + n], data[:n])
+ data = data[n:]
+ if n + ntail < 64
+ ->
+ ;;
+ step(st.x[:], st.tail[:])
+ ;;
+
+ while data.len >= 64
+ step(st.x[:], data[:64])
+ data = data[64:]
+ ;;
+
+ ntail = st.msglen % 64
+ std.slcp(st.tail[:ntail], data)
+}
+
+const sha224fin = {st
+ var r : byte[28]
+
+ tail(st.x[:], st.msglen, st.tail[:])
+
+ pack(r[0:4], st.x[0])
+ pack(r[4:8], st.x[1])
+ pack(r[8:12], st.x[2])
+ pack(r[12:16], st.x[3])
+ pack(r[16:20], st.x[4])
+ pack(r[20:24], st.x[5])
+ pack(r[24:28], st.x[6])
+ -> r
+}
+
+
+const tail = {x, msglen, tail
+ var ntail
+
+ /* append first padding block */
+ ntail = msglen % 64
+ tail[ntail++] = 0x80
+ std.slfill(tail[ntail:], 0)
+ if 64 - ntail < 8
+ step(x, tail)
+ std.slfill(tail, 0)
+ ;;
+
+ /* append size block */
+ tail[56] = ((msglen * 8) >> 56) castto(byte)
+ tail[57] = ((msglen * 8) >> 48) castto(byte)
+ tail[58] = ((msglen * 8) >> 40) castto(byte)
+ tail[59] = ((msglen * 8) >> 32) castto(byte)
+ tail[60] = ((msglen * 8) >> 24) castto(byte)
+ tail[61] = ((msglen * 8) >> 16) castto(byte)
+ tail[62] = ((msglen * 8) >> 8) castto(byte)
+ tail[63] = ((msglen * 8) >> 0) castto(byte)
+ step(x, tail)
+}
+
+const step = {x, msg
+ var a, b, c, d, e, f, g, h
+ var s00, s01, s02, s03, s04, s05, s06, s07
+ var s08, s09, s10, s11, s12, s13, s14, s15
+ var s16, s17, s18, s19, s20, s21, s22, s23
+ var s24, s25, s26, s27, s28, s29, s30, s31
+ var s32, s33, s34, s35, s36, s37, s38, s39
+ var s40, s41, s42, s43, s44, s45, s46, s47
+ var s48, s49, s50, s51, s52, s53, s54, s55
+ var s56, s57, s58, s59, s60, s61, s62, s63
+
+ a = x[0]
+ b = x[1]
+ c = x[2]
+ d = x[3]
+ e = x[4]
+ f = x[5]
+ g = x[6]
+ h = x[7]
+
+ s00 = unpack(msg[ 0: 4])
+ s01 = unpack(msg[ 4: 8])
+ s02 = unpack(msg[ 8:12])
+ s03 = unpack(msg[12:16])
+ s04 = unpack(msg[16:20])
+ s05 = unpack(msg[20:24])
+ s06 = unpack(msg[24:28])
+ s07 = unpack(msg[28:32])
+ s08 = unpack(msg[32:36])
+ s09 = unpack(msg[36:40])
+ s10 = unpack(msg[40:44])
+ s11 = unpack(msg[44:48])
+ s12 = unpack(msg[48:52])
+ s13 = unpack(msg[52:56])
+ s14 = unpack(msg[56:60])
+ s15 = unpack(msg[60:64])
+
+ s16 = s00 + s09 + (((s01 << 25) | (s01 >> 7)) ^ ((s01 << 14) | (s01 >> 18)) ^ (s01 >> 3)) + (((s14 << 15) | (s14 >> 17)) ^ ((s14 << (32- 19)) | (s14 >> 19)) ^ (s14 >> 10));
+ s17 = s01 + s10 + (((s02 << 25) | (s02 >> 7)) ^ ((s02 << 14) | (s02 >> 18)) ^ (s02 >> 3)) + (((s15 << 15) | (s15 >> 17)) ^ ((s15 << (32- 19)) | (s15 >> 19)) ^ (s15 >> 10));
+ s18 = s02 + s11 + (((s03 << 25) | (s03 >> 7)) ^ ((s03 << 14) | (s03 >> 18)) ^ (s03 >> 3)) + (((s16 << 15) | (s16 >> 17)) ^ ((s16 << (32- 19)) | (s16 >> 19)) ^ (s16 >> 10));
+ s19 = s03 + s12 + (((s04 << 25) | (s04 >> 7)) ^ ((s04 << 14) | (s04 >> 18)) ^ (s04 >> 3)) + (((s17 << 15) | (s17 >> 17)) ^ ((s17 << (32- 19)) | (s17 >> 19)) ^ (s17 >> 10));
+ s20 = s04 + s13 + (((s05 << 25) | (s05 >> 7)) ^ ((s05 << 14) | (s05 >> 18)) ^ (s05 >> 3)) + (((s18 << 15) | (s18 >> 17)) ^ ((s18 << (32- 19)) | (s18 >> 19)) ^ (s18 >> 10));
+ s21 = s05 + s14 + (((s06 << 25) | (s06 >> 7)) ^ ((s06 << 14) | (s06 >> 18)) ^ (s06 >> 3)) + (((s19 << 15) | (s19 >> 17)) ^ ((s19 << (32- 19)) | (s19 >> 19)) ^ (s19 >> 10));
+ s22 = s06 + s15 + (((s07 << 25) | (s07 >> 7)) ^ ((s07 << 14) | (s07 >> 18)) ^ (s07 >> 3)) + (((s20 << 15) | (s20 >> 17)) ^ ((s20 << (32- 19)) | (s20 >> 19)) ^ (s20 >> 10));
+ s23 = s07 + s16 + (((s08 << 25) | (s08 >> 7)) ^ ((s08 << 14) | (s08 >> 18)) ^ (s08 >> 3)) + (((s21 << 15) | (s21 >> 17)) ^ ((s21 << (32- 19)) | (s21 >> 19)) ^ (s21 >> 10));
+ s24 = s08 + s17 + (((s09 << 25) | (s09 >> 7)) ^ ((s09 << 14) | (s09 >> 18)) ^ (s09 >> 3)) + (((s22 << 15) | (s22 >> 17)) ^ ((s22 << (32- 19)) | (s22 >> 19)) ^ (s22 >> 10));
+ s25 = s09 + s18 + (((s10 << 25) | (s10 >> 7)) ^ ((s10 << 14) | (s10 >> 18)) ^ (s10 >> 3)) + (((s23 << 15) | (s23 >> 17)) ^ ((s23 << (32- 19)) | (s23 >> 19)) ^ (s23 >> 10));
+ s26 = s10 + s19 + (((s11 << 25) | (s11 >> 7)) ^ ((s11 << 14) | (s11 >> 18)) ^ (s11 >> 3)) + (((s24 << 15) | (s24 >> 17)) ^ ((s24 << (32- 19)) | (s24 >> 19)) ^ (s24 >> 10));
+ s27 = s11 + s20 + (((s12 << 25) | (s12 >> 7)) ^ ((s12 << 14) | (s12 >> 18)) ^ (s12 >> 3)) + (((s25 << 15) | (s25 >> 17)) ^ ((s25 << (32- 19)) | (s25 >> 19)) ^ (s25 >> 10));
+ s28 = s12 + s21 + (((s13 << 25) | (s13 >> 7)) ^ ((s13 << 14) | (s13 >> 18)) ^ (s13 >> 3)) + (((s26 << 15) | (s26 >> 17)) ^ ((s26 << (32- 19)) | (s26 >> 19)) ^ (s26 >> 10));
+ s29 = s13 + s22 + (((s14 << 25) | (s14 >> 7)) ^ ((s14 << 14) | (s14 >> 18)) ^ (s14 >> 3)) + (((s27 << 15) | (s27 >> 17)) ^ ((s27 << (32- 19)) | (s27 >> 19)) ^ (s27 >> 10));
+ s30 = s14 + s23 + (((s15 << 25) | (s15 >> 7)) ^ ((s15 << 14) | (s15 >> 18)) ^ (s15 >> 3)) + (((s28 << 15) | (s28 >> 17)) ^ ((s28 << (32- 19)) | (s28 >> 19)) ^ (s28 >> 10));
+ s31 = s15 + s24 + (((s16 << 25) | (s16 >> 7)) ^ ((s16 << 14) | (s16 >> 18)) ^ (s16 >> 3)) + (((s29 << 15) | (s29 >> 17)) ^ ((s29 << (32- 19)) | (s29 >> 19)) ^ (s29 >> 10));
+ s32 = s16 + s25 + (((s17 << 25) | (s17 >> 7)) ^ ((s17 << 14) | (s17 >> 18)) ^ (s17 >> 3)) + (((s30 << 15) | (s30 >> 17)) ^ ((s30 << (32- 19)) | (s30 >> 19)) ^ (s30 >> 10));
+ s33 = s17 + s26 + (((s18 << 25) | (s18 >> 7)) ^ ((s18 << 14) | (s18 >> 18)) ^ (s18 >> 3)) + (((s31 << 15) | (s31 >> 17)) ^ ((s31 << (32- 19)) | (s31 >> 19)) ^ (s31 >> 10));
+ s34 = s18 + s27 + (((s19 << 25) | (s19 >> 7)) ^ ((s19 << 14) | (s19 >> 18)) ^ (s19 >> 3)) + (((s32 << 15) | (s32 >> 17)) ^ ((s32 << (32- 19)) | (s32 >> 19)) ^ (s32 >> 10));
+ s35 = s19 + s28 + (((s20 << 25) | (s20 >> 7)) ^ ((s20 << 14) | (s20 >> 18)) ^ (s20 >> 3)) + (((s33 << 15) | (s33 >> 17)) ^ ((s33 << (32- 19)) | (s33 >> 19)) ^ (s33 >> 10));
+ s36 = s20 + s29 + (((s21 << 25) | (s21 >> 7)) ^ ((s21 << 14) | (s21 >> 18)) ^ (s21 >> 3)) + (((s34 << 15) | (s34 >> 17)) ^ ((s34 << (32- 19)) | (s34 >> 19)) ^ (s34 >> 10));
+ s37 = s21 + s30 + (((s22 << 25) | (s22 >> 7)) ^ ((s22 << 14) | (s22 >> 18)) ^ (s22 >> 3)) + (((s35 << 15) | (s35 >> 17)) ^ ((s35 << (32- 19)) | (s35 >> 19)) ^ (s35 >> 10));
+ s38 = s22 + s31 + (((s23 << 25) | (s23 >> 7)) ^ ((s23 << 14) | (s23 >> 18)) ^ (s23 >> 3)) + (((s36 << 15) | (s36 >> 17)) ^ ((s36 << (32- 19)) | (s36 >> 19)) ^ (s36 >> 10));
+ s39 = s23 + s32 + (((s24 << 25) | (s24 >> 7)) ^ ((s24 << 14) | (s24 >> 18)) ^ (s24 >> 3)) + (((s37 << 15) | (s37 >> 17)) ^ ((s37 << (32- 19)) | (s37 >> 19)) ^ (s37 >> 10));
+ s40 = s24 + s33 + (((s25 << 25) | (s25 >> 7)) ^ ((s25 << 14) | (s25 >> 18)) ^ (s25 >> 3)) + (((s38 << 15) | (s38 >> 17)) ^ ((s38 << (32- 19)) | (s38 >> 19)) ^ (s38 >> 10));
+ s41 = s25 + s34 + (((s26 << 25) | (s26 >> 7)) ^ ((s26 << 14) | (s26 >> 18)) ^ (s26 >> 3)) + (((s39 << 15) | (s39 >> 17)) ^ ((s39 << (32- 19)) | (s39 >> 19)) ^ (s39 >> 10));
+ s42 = s26 + s35 + (((s27 << 25) | (s27 >> 7)) ^ ((s27 << 14) | (s27 >> 18)) ^ (s27 >> 3)) + (((s40 << 15) | (s40 >> 17)) ^ ((s40 << (32- 19)) | (s40 >> 19)) ^ (s40 >> 10));
+ s43 = s27 + s36 + (((s28 << 25) | (s28 >> 7)) ^ ((s28 << 14) | (s28 >> 18)) ^ (s28 >> 3)) + (((s41 << 15) | (s41 >> 17)) ^ ((s41 << (32- 19)) | (s41 >> 19)) ^ (s41 >> 10));
+ s44 = s28 + s37 + (((s29 << 25) | (s29 >> 7)) ^ ((s29 << 14) | (s29 >> 18)) ^ (s29 >> 3)) + (((s42 << 15) | (s42 >> 17)) ^ ((s42 << (32- 19)) | (s42 >> 19)) ^ (s42 >> 10));
+ s45 = s29 + s38 + (((s30 << 25) | (s30 >> 7)) ^ ((s30 << 14) | (s30 >> 18)) ^ (s30 >> 3)) + (((s43 << 15) | (s43 >> 17)) ^ ((s43 << (32- 19)) | (s43 >> 19)) ^ (s43 >> 10));
+ s46 = s30 + s39 + (((s31 << 25) | (s31 >> 7)) ^ ((s31 << 14) | (s31 >> 18)) ^ (s31 >> 3)) + (((s44 << 15) | (s44 >> 17)) ^ ((s44 << (32- 19)) | (s44 >> 19)) ^ (s44 >> 10));
+ s47 = s31 + s40 + (((s32 << 25) | (s32 >> 7)) ^ ((s32 << 14) | (s32 >> 18)) ^ (s32 >> 3)) + (((s45 << 15) | (s45 >> 17)) ^ ((s45 << (32- 19)) | (s45 >> 19)) ^ (s45 >> 10));
+ s48 = s32 + s41 + (((s33 << 25) | (s33 >> 7)) ^ ((s33 << 14) | (s33 >> 18)) ^ (s33 >> 3)) + (((s46 << 15) | (s46 >> 17)) ^ ((s46 << (32- 19)) | (s46 >> 19)) ^ (s46 >> 10));
+ s49 = s33 + s42 + (((s34 << 25) | (s34 >> 7)) ^ ((s34 << 14) | (s34 >> 18)) ^ (s34 >> 3)) + (((s47 << 15) | (s47 >> 17)) ^ ((s47 << (32- 19)) | (s47 >> 19)) ^ (s47 >> 10));
+ s50 = s34 + s43 + (((s35 << 25) | (s35 >> 7)) ^ ((s35 << 14) | (s35 >> 18)) ^ (s35 >> 3)) + (((s48 << 15) | (s48 >> 17)) ^ ((s48 << (32- 19)) | (s48 >> 19)) ^ (s48 >> 10));
+ s51 = s35 + s44 + (((s36 << 25) | (s36 >> 7)) ^ ((s36 << 14) | (s36 >> 18)) ^ (s36 >> 3)) + (((s49 << 15) | (s49 >> 17)) ^ ((s49 << (32- 19)) | (s49 >> 19)) ^ (s49 >> 10));
+ s52 = s36 + s45 + (((s37 << 25) | (s37 >> 7)) ^ ((s37 << 14) | (s37 >> 18)) ^ (s37 >> 3)) + (((s50 << 15) | (s50 >> 17)) ^ ((s50 << (32- 19)) | (s50 >> 19)) ^ (s50 >> 10));
+ s53 = s37 + s46 + (((s38 << 25) | (s38 >> 7)) ^ ((s38 << 14) | (s38 >> 18)) ^ (s38 >> 3)) + (((s51 << 15) | (s51 >> 17)) ^ ((s51 << (32- 19)) | (s51 >> 19)) ^ (s51 >> 10));
+ s54 = s38 + s47 + (((s39 << 25) | (s39 >> 7)) ^ ((s39 << 14) | (s39 >> 18)) ^ (s39 >> 3)) + (((s52 << 15) | (s52 >> 17)) ^ ((s52 << (32- 19)) | (s52 >> 19)) ^ (s52 >> 10));
+ s55 = s39 + s48 + (((s40 << 25) | (s40 >> 7)) ^ ((s40 << 14) | (s40 >> 18)) ^ (s40 >> 3)) + (((s53 << 15) | (s53 >> 17)) ^ ((s53 << (32- 19)) | (s53 >> 19)) ^ (s53 >> 10));
+ s56 = s40 + s49 + (((s41 << 25) | (s41 >> 7)) ^ ((s41 << 14) | (s41 >> 18)) ^ (s41 >> 3)) + (((s54 << 15) | (s54 >> 17)) ^ ((s54 << (32- 19)) | (s54 >> 19)) ^ (s54 >> 10));
+ s57 = s41 + s50 + (((s42 << 25) | (s42 >> 7)) ^ ((s42 << 14) | (s42 >> 18)) ^ (s42 >> 3)) + (((s55 << 15) | (s55 >> 17)) ^ ((s55 << (32- 19)) | (s55 >> 19)) ^ (s55 >> 10));
+ s58 = s42 + s51 + (((s43 << 25) | (s43 >> 7)) ^ ((s43 << 14) | (s43 >> 18)) ^ (s43 >> 3)) + (((s56 << 15) | (s56 >> 17)) ^ ((s56 << (32- 19)) | (s56 >> 19)) ^ (s56 >> 10));
+ s59 = s43 + s52 + (((s44 << 25) | (s44 >> 7)) ^ ((s44 << 14) | (s44 >> 18)) ^ (s44 >> 3)) + (((s57 << 15) | (s57 >> 17)) ^ ((s57 << (32- 19)) | (s57 >> 19)) ^ (s57 >> 10));
+ s60 = s44 + s53 + (((s45 << 25) | (s45 >> 7)) ^ ((s45 << 14) | (s45 >> 18)) ^ (s45 >> 3)) + (((s58 << 15) | (s58 >> 17)) ^ ((s58 << (32- 19)) | (s58 >> 19)) ^ (s58 >> 10));
+ s61 = s45 + s54 + (((s46 << 25) | (s46 >> 7)) ^ ((s46 << 14) | (s46 >> 18)) ^ (s46 >> 3)) + (((s59 << 15) | (s59 >> 17)) ^ ((s59 << (32- 19)) | (s59 >> 19)) ^ (s59 >> 10));
+ s62 = s46 + s55 + (((s47 << 25) | (s47 >> 7)) ^ ((s47 << 14) | (s47 >> 18)) ^ (s47 >> 3)) + (((s60 << 15) | (s60 >> 17)) ^ ((s60 << (32- 19)) | (s60 >> 19)) ^ (s60 >> 10));
+ s63 = s47 + s56 + (((s48 << 25) | (s48 >> 7)) ^ ((s48 << 14) | (s48 >> 18)) ^ (s48 >> 3)) + (((s61 << 15) | (s61 >> 17)) ^ ((s61 << (32- 19)) | (s61 >> 19)) ^ (s61 >> 10));
+
+
+ h += (((e << 26) | (e >> 6)) ^ ((e << 21) | (e >> 11)) ^ ((e << 7) | (e >> 25))) + (g ^ (e & (f ^ g))) + 0x428a2f98 + s00;
+ d += h; h += (((a << 30) | (a >> 2)) ^ ((a << 19) | (a >> 13)) ^ ((a << 10) | (a >> 22))) + ((a & (b | c)) | (b & c));
+ g += (((d << 26) | (d >> 6)) ^ ((d << 21) | (d >> 11)) ^ ((d << 7) | (d >> 25))) + (f ^ (d & (e ^ f))) + 0x71374491 + s01;
+ c += g; g += (((h << 30) | (h >> 2)) ^ ((h << 19) | (h >> 13)) ^ ((h << 10) | (h >> 22))) + ((h & (a | b)) | (a & b));
+ f += (((c << 26) | (c >> 6)) ^ ((c << 21) | (c >> 11)) ^ ((c << 7) | (c >> 25))) + (e ^ (c & (d ^ e))) + 0xb5c0fbcf + s02;
+ b += f; f += (((g << 30) | (g >> 2)) ^ ((g << 19) | (g >> 13)) ^ ((g << 10) | (g >> 22))) + ((g & (h | a)) | (h & a));
+ e += (((b << 26) | (b >> 6)) ^ ((b << 21) | (b >> 11)) ^ ((b << 7) | (b >> 25))) + (d ^ (b & (c ^ d))) + 0xe9b5dba5 + s03;
+ a += e; e += (((f << 30) | (f >> 2)) ^ ((f << 19) | (f >> 13)) ^ ((f << 10) | (f >> 22))) + ((f & (g | h)) | (g & h));
+ d += (((a << 26) | (a >> 6)) ^ ((a << 21) | (a >> 11)) ^ ((a << 7) | (a >> 25))) + (c ^ (a & (b ^ c))) + 0x3956c25b + s04;
+ h += d; d += (((e << 30) | (e >> 2)) ^ ((e << 19) | (e >> 13)) ^ ((e << 10) | (e >> 22))) + ((e & (f | g)) | (f & g));
+ c += (((h << 26) | (h >> 6)) ^ ((h << 21) | (h >> 11)) ^ ((h << 7) | (h >> 25))) + (b ^ (h & (a ^ b))) + 0x59f111f1 + s05;
+ g += c; c += (((d << 30) | (d >> 2)) ^ ((d << 19) | (d >> 13)) ^ ((d << 10) | (d >> 22))) + ((d & (e | f)) | (e & f));
+ b += (((g << 26) | (g >> 6)) ^ ((g << 21) | (g >> 11)) ^ ((g << 7) | (g >> 25))) + (a ^ (g & (h ^ a))) + 0x923f82a4 + s06;
+ f += b; b += (((c << 30) | (c >> 2)) ^ ((c << 19) | (c >> 13)) ^ ((c << 10) | (c >> 22))) + ((c & (d | e)) | (d & e));
+ a += (((f << 26) | (f >> 6)) ^ ((f << 21) | (f >> 11)) ^ ((f << 7) | (f >> 25))) + (h ^ (f & (g ^ h))) + 0xab1c5ed5 + s07;
+ e += a; a += (((b << 30) | (b >> 2)) ^ ((b << 19) | (b >> 13)) ^ ((b << 10) | (b >> 22))) + ((b & (c | d)) | (c & d));
+ h += (((e << 26) | (e >> 6)) ^ ((e << 21) | (e >> 11)) ^ ((e << 7) | (e >> 25))) + (g ^ (e & (f ^ g))) + 0xd807aa98 + s08;
+ d += h; h += (((a << 30) | (a >> 2)) ^ ((a << 19) | (a >> 13)) ^ ((a << 10) | (a >> 22))) + ((a & (b | c)) | (b & c));
+ g += (((d << 26) | (d >> 6)) ^ ((d << 21) | (d >> 11)) ^ ((d << 7) | (d >> 25))) + (f ^ (d & (e ^ f))) + 0x12835b01 + s09;
+ c += g; g += (((h << 30) | (h >> 2)) ^ ((h << 19) | (h >> 13)) ^ ((h << 10) | (h >> 22))) + ((h & (a | b)) | (a & b));
+ f += (((c << 26) | (c >> 6)) ^ ((c << 21) | (c >> 11)) ^ ((c << 7) | (c >> 25))) + (e ^ (c & (d ^ e))) + 0x243185be + s10;
+ b += f; f += (((g << 30) | (g >> 2)) ^ ((g << 19) | (g >> 13)) ^ ((g << 10) | (g >> 22))) + ((g & (h | a)) | (h & a));
+ e += (((b << 26) | (b >> 6)) ^ ((b << 21) | (b >> 11)) ^ ((b << 7) | (b >> 25))) + (d ^ (b & (c ^ d))) + 0x550c7dc3 + s11;
+ a += e; e += (((f << 30) | (f >> 2)) ^ ((f << 19) | (f >> 13)) ^ ((f << 10) | (f >> 22))) + ((f & (g | h)) | (g & h));
+ d += (((a << 26) | (a >> 6)) ^ ((a << 21) | (a >> 11)) ^ ((a << 7) | (a >> 25))) + (c ^ (a & (b ^ c))) + 0x72be5d74 + s12;
+ h += d; d += (((e << 30) | (e >> 2)) ^ ((e << 19) | (e >> 13)) ^ ((e << 10) | (e >> 22))) + ((e & (f | g)) | (f & g));
+ c += (((h << 26) | (h >> 6)) ^ ((h << 21) | (h >> 11)) ^ ((h << 7) | (h >> 25))) + (b ^ (h & (a ^ b))) + 0x80deb1fe + s13;
+ g += c; c += (((d << 30) | (d >> 2)) ^ ((d << 19) | (d >> 13)) ^ ((d << 10) | (d >> 22))) + ((d & (e | f)) | (e & f));
+ b += (((g << 26) | (g >> 6)) ^ ((g << 21) | (g >> 11)) ^ ((g << 7) | (g >> 25))) + (a ^ (g & (h ^ a))) + 0x9bdc06a7 + s14;
+ f += b; b += (((c << 30) | (c >> 2)) ^ ((c << 19) | (c >> 13)) ^ ((c << 10) | (c >> 22))) + ((c & (d | e)) | (d & e));
+ a += (((f << 26) | (f >> 6)) ^ ((f << 21) | (f >> 11)) ^ ((f << 7) | (f >> 25))) + (h ^ (f & (g ^ h))) + 0xc19bf174 + s15;
+ e += a; a += (((b << 30) | (b >> 2)) ^ ((b << 19) | (b >> 13)) ^ ((b << 10) | (b >> 22))) + ((b & (c | d)) | (c & d));
+ h += (((e << 26) | (e >> 6)) ^ ((e << 21) | (e >> 11)) ^ ((e << 7) | (e >> 25))) + (g ^ (e & (f ^ g))) + 0xe49b69c1 + s16;
+ d += h; h += (((a << 30) | (a >> 2)) ^ ((a << 19) | (a >> 13)) ^ ((a << 10) | (a >> 22))) + ((a & (b | c)) | (b & c));
+ g += (((d << 26) | (d >> 6)) ^ ((d << 21) | (d >> 11)) ^ ((d << 7) | (d >> 25))) + (f ^ (d & (e ^ f))) + 0xefbe4786 + s17;
+ c += g; g += (((h << 30) | (h >> 2)) ^ ((h << 19) | (h >> 13)) ^ ((h << 10) | (h >> 22))) + ((h & (a | b)) | (a & b));
+ f += (((c << 26) | (c >> 6)) ^ ((c << 21) | (c >> 11)) ^ ((c << 7) | (c >> 25))) + (e ^ (c & (d ^ e))) + 0x0fc19dc6 + s18;
+ b += f; f += (((g << 30) | (g >> 2)) ^ ((g << 19) | (g >> 13)) ^ ((g << 10) | (g >> 22))) + ((g & (h | a)) | (h & a));
+ e += (((b << 26) | (b >> 6)) ^ ((b << 21) | (b >> 11)) ^ ((b << 7) | (b >> 25))) + (d ^ (b & (c ^ d))) + 0x240ca1cc + s19;
+ a += e; e += (((f << 30) | (f >> 2)) ^ ((f << 19) | (f >> 13)) ^ ((f << 10) | (f >> 22))) + ((f & (g | h)) | (g & h));
+ d += (((a << 26) | (a >> 6)) ^ ((a << 21) | (a >> 11)) ^ ((a << 7) | (a >> 25))) + (c ^ (a & (b ^ c))) + 0x2de92c6f + s20;
+ h += d; d += (((e << 30) | (e >> 2)) ^ ((e << 19) | (e >> 13)) ^ ((e << 10) | (e >> 22))) + ((e & (f | g)) | (f & g));
+ c += (((h << 26) | (h >> 6)) ^ ((h << 21) | (h >> 11)) ^ ((h << 7) | (h >> 25))) + (b ^ (h & (a ^ b))) + 0x4a7484aa + s21;
+ g += c; c += (((d << 30) | (d >> 2)) ^ ((d << 19) | (d >> 13)) ^ ((d << 10) | (d >> 22))) + ((d & (e | f)) | (e & f));
+ b += (((g << 26) | (g >> 6)) ^ ((g << 21) | (g >> 11)) ^ ((g << 7) | (g >> 25))) + (a ^ (g & (h ^ a))) + 0x5cb0a9dc + s22;
+ f += b; b += (((c << 30) | (c >> 2)) ^ ((c << 19) | (c >> 13)) ^ ((c << 10) | (c >> 22))) + ((c & (d | e)) | (d & e));
+ a += (((f << 26) | (f >> 6)) ^ ((f << 21) | (f >> 11)) ^ ((f << 7) | (f >> 25))) + (h ^ (f & (g ^ h))) + 0x76f988da + s23;
+ e += a; a += (((b << 30) | (b >> 2)) ^ ((b << 19) | (b >> 13)) ^ ((b << 10) | (b >> 22))) + ((b & (c | d)) | (c & d));
+ h += (((e << 26) | (e >> 6)) ^ ((e << 21) | (e >> 11)) ^ ((e << 7) | (e >> 25))) + (g ^ (e & (f ^ g))) + 0x983e5152 + s24;
+ d += h; h += (((a << 30) | (a >> 2)) ^ ((a << 19) | (a >> 13)) ^ ((a << 10) | (a >> 22))) + ((a & (b | c)) | (b & c));
+ g += (((d << 26) | (d >> 6)) ^ ((d << 21) | (d >> 11)) ^ ((d << 7) | (d >> 25))) + (f ^ (d & (e ^ f))) + 0xa831c66d + s25;
+ c += g; g += (((h << 30) | (h >> 2)) ^ ((h << 19) | (h >> 13)) ^ ((h << 10) | (h >> 22))) + ((h & (a | b)) | (a & b));
+ f += (((c << 26) | (c >> 6)) ^ ((c << 21) | (c >> 11)) ^ ((c << 7) | (c >> 25))) + (e ^ (c & (d ^ e))) + 0xb00327c8 + s26;
+ b += f; f += (((g << 30) | (g >> 2)) ^ ((g << 19) | (g >> 13)) ^ ((g << 10) | (g >> 22))) + ((g & (h | a)) | (h & a));
+ e += (((b << 26) | (b >> 6)) ^ ((b << 21) | (b >> 11)) ^ ((b << 7) | (b >> 25))) + (d ^ (b & (c ^ d))) + 0xbf597fc7 + s27;
+ a += e; e += (((f << 30) | (f >> 2)) ^ ((f << 19) | (f >> 13)) ^ ((f << 10) | (f >> 22))) + ((f & (g | h)) | (g & h));
+ d += (((a << 26) | (a >> 6)) ^ ((a << 21) | (a >> 11)) ^ ((a << 7) | (a >> 25))) + (c ^ (a & (b ^ c))) + 0xc6e00bf3 + s28;
+ h += d; d += (((e << 30) | (e >> 2)) ^ ((e << 19) | (e >> 13)) ^ ((e << 10) | (e >> 22))) + ((e & (f | g)) | (f & g));
+ c += (((h << 26) | (h >> 6)) ^ ((h << 21) | (h >> 11)) ^ ((h << 7) | (h >> 25))) + (b ^ (h & (a ^ b))) + 0xd5a79147 + s29;
+ g += c; c += (((d << 30) | (d >> 2)) ^ ((d << 19) | (d >> 13)) ^ ((d << 10) | (d >> 22))) + ((d & (e | f)) | (e & f));
+ b += (((g << 26) | (g >> 6)) ^ ((g << 21) | (g >> 11)) ^ ((g << 7) | (g >> 25))) + (a ^ (g & (h ^ a))) + 0x06ca6351 + s30;
+ f += b; b += (((c << 30) | (c >> 2)) ^ ((c << 19) | (c >> 13)) ^ ((c << 10) | (c >> 22))) + ((c & (d | e)) | (d & e));
+ a += (((f << 26) | (f >> 6)) ^ ((f << 21) | (f >> 11)) ^ ((f << 7) | (f >> 25))) + (h ^ (f & (g ^ h))) + 0x14292967 + s31;
+ e += a; a += (((b << 30) | (b >> 2)) ^ ((b << 19) | (b >> 13)) ^ ((b << 10) | (b >> 22))) + ((b & (c | d)) | (c & d));
+ h += (((e << 26) | (e >> 6)) ^ ((e << 21) | (e >> 11)) ^ ((e << 7) | (e >> 25))) + (g ^ (e & (f ^ g))) + 0x27b70a85 + s32;
+ d += h; h += (((a << 30) | (a >> 2)) ^ ((a << 19) | (a >> 13)) ^ ((a << 10) | (a >> 22))) + ((a & (b | c)) | (b & c));
+ g += (((d << 26) | (d >> 6)) ^ ((d << 21) | (d >> 11)) ^ ((d << 7) | (d >> 25))) + (f ^ (d & (e ^ f))) + 0x2e1b2138 + s33;
+ c += g; g += (((h << 30) | (h >> 2)) ^ ((h << 19) | (h >> 13)) ^ ((h << 10) | (h >> 22))) + ((h & (a | b)) | (a & b));
+ f += (((c << 26) | (c >> 6)) ^ ((c << 21) | (c >> 11)) ^ ((c << 7) | (c >> 25))) + (e ^ (c & (d ^ e))) + 0x4d2c6dfc + s34;
+ b += f; f += (((g << 30) | (g >> 2)) ^ ((g << 19) | (g >> 13)) ^ ((g << 10) | (g >> 22))) + ((g & (h | a)) | (h & a));
+ e += (((b << 26) | (b >> 6)) ^ ((b << 21) | (b >> 11)) ^ ((b << 7) | (b >> 25))) + (d ^ (b & (c ^ d))) + 0x53380d13 + s35;
+ a += e; e += (((f << 30) | (f >> 2)) ^ ((f << 19) | (f >> 13)) ^ ((f << 10) | (f >> 22))) + ((f & (g | h)) | (g & h));
+ d += (((a << 26) | (a >> 6)) ^ ((a << 21) | (a >> 11)) ^ ((a << 7) | (a >> 25))) + (c ^ (a & (b ^ c))) + 0x650a7354 + s36;
+ h += d; d += (((e << 30) | (e >> 2)) ^ ((e << 19) | (e >> 13)) ^ ((e << 10) | (e >> 22))) + ((e & (f | g)) | (f & g));
+ c += (((h << 26) | (h >> 6)) ^ ((h << 21) | (h >> 11)) ^ ((h << 7) | (h >> 25))) + (b ^ (h & (a ^ b))) + 0x766a0abb + s37;
+ g += c; c += (((d << 30) | (d >> 2)) ^ ((d << 19) | (d >> 13)) ^ ((d << 10) | (d >> 22))) + ((d & (e | f)) | (e & f));
+ b += (((g << 26) | (g >> 6)) ^ ((g << 21) | (g >> 11)) ^ ((g << 7) | (g >> 25))) + (a ^ (g & (h ^ a))) + 0x81c2c92e + s38;
+ f += b; b += (((c << 30) | (c >> 2)) ^ ((c << 19) | (c >> 13)) ^ ((c << 10) | (c >> 22))) + ((c & (d | e)) | (d & e));
+ a += (((f << 26) | (f >> 6)) ^ ((f << 21) | (f >> 11)) ^ ((f << 7) | (f >> 25))) + (h ^ (f & (g ^ h))) + 0x92722c85 + s39;
+ e += a; a += (((b << 30) | (b >> 2)) ^ ((b << 19) | (b >> 13)) ^ ((b << 10) | (b >> 22))) + ((b & (c | d)) | (c & d));
+ h += (((e << 26) | (e >> 6)) ^ ((e << 21) | (e >> 11)) ^ ((e << 7) | (e >> 25))) + (g ^ (e & (f ^ g))) + 0xa2bfe8a1 + s40;
+ d += h; h += (((a << 30) | (a >> 2)) ^ ((a << 19) | (a >> 13)) ^ ((a << 10) | (a >> 22))) + ((a & (b | c)) | (b & c));
+ g += (((d << 26) | (d >> 6)) ^ ((d << 21) | (d >> 11)) ^ ((d << 7) | (d >> 25))) + (f ^ (d & (e ^ f))) + 0xa81a664b + s41;
+ c += g; g += (((h << 30) | (h >> 2)) ^ ((h << 19) | (h >> 13)) ^ ((h << 10) | (h >> 22))) + ((h & (a | b)) | (a & b));
+ f += (((c << 26) | (c >> 6)) ^ ((c << 21) | (c >> 11)) ^ ((c << 7) | (c >> 25))) + (e ^ (c & (d ^ e))) + 0xc24b8b70 + s42;
+ b += f; f += (((g << 30) | (g >> 2)) ^ ((g << 19) | (g >> 13)) ^ ((g << 10) | (g >> 22))) + ((g & (h | a)) | (h & a));
+ e += (((b << 26) | (b >> 6)) ^ ((b << 21) | (b >> 11)) ^ ((b << 7) | (b >> 25))) + (d ^ (b & (c ^ d))) + 0xc76c51a3 + s43;
+ a += e; e += (((f << 30) | (f >> 2)) ^ ((f << 19) | (f >> 13)) ^ ((f << 10) | (f >> 22))) + ((f & (g | h)) | (g & h));
+ d += (((a << 26) | (a >> 6)) ^ ((a << 21) | (a >> 11)) ^ ((a << 7) | (a >> 25))) + (c ^ (a & (b ^ c))) + 0xd192e819 + s44;
+ h += d; d += (((e << 30) | (e >> 2)) ^ ((e << 19) | (e >> 13)) ^ ((e << 10) | (e >> 22))) + ((e & (f | g)) | (f & g));
+ c += (((h << 26) | (h >> 6)) ^ ((h << 21) | (h >> 11)) ^ ((h << 7) | (h >> 25))) + (b ^ (h & (a ^ b))) + 0xd6990624 + s45;
+ g += c; c += (((d << 30) | (d >> 2)) ^ ((d << 19) | (d >> 13)) ^ ((d << 10) | (d >> 22))) + ((d & (e | f)) | (e & f));
+ b += (((g << 26) | (g >> 6)) ^ ((g << 21) | (g >> 11)) ^ ((g << 7) | (g >> 25))) + (a ^ (g & (h ^ a))) + 0xf40e3585 + s46;
+ f += b; b += (((c << 30) | (c >> 2)) ^ ((c << 19) | (c >> 13)) ^ ((c << 10) | (c >> 22))) + ((c & (d | e)) | (d & e));
+ a += (((f << 26) | (f >> 6)) ^ ((f << 21) | (f >> 11)) ^ ((f << 7) | (f >> 25))) + (h ^ (f & (g ^ h))) + 0x106aa070 + s47;
+ e += a; a += (((b << 30) | (b >> 2)) ^ ((b << 19) | (b >> 13)) ^ ((b << 10) | (b >> 22))) + ((b & (c | d)) | (c & d));
+ h += (((e << 26) | (e >> 6)) ^ ((e << 21) | (e >> 11)) ^ ((e << 7) | (e >> 25))) + (g ^ (e & (f ^ g))) + 0x19a4c116 + s48;
+ d += h; h += (((a << 30) | (a >> 2)) ^ ((a << 19) | (a >> 13)) ^ ((a << 10) | (a >> 22))) + ((a & (b | c)) | (b & c));
+ g += (((d << 26) | (d >> 6)) ^ ((d << 21) | (d >> 11)) ^ ((d << 7) | (d >> 25))) + (f ^ (d & (e ^ f))) + 0x1e376c08 + s49;
+ c += g; g += (((h << 30) | (h >> 2)) ^ ((h << 19) | (h >> 13)) ^ ((h << 10) | (h >> 22))) + ((h & (a | b)) | (a & b));
+ f += (((c << 26) | (c >> 6)) ^ ((c << 21) | (c >> 11)) ^ ((c << 7) | (c >> 25))) + (e ^ (c & (d ^ e))) + 0x2748774c + s50;
+ b += f; f += (((g << 30) | (g >> 2)) ^ ((g << 19) | (g >> 13)) ^ ((g << 10) | (g >> 22))) + ((g & (h | a)) | (h & a));
+ e += (((b << 26) | (b >> 6)) ^ ((b << 21) | (b >> 11)) ^ ((b << 7) | (b >> 25))) + (d ^ (b & (c ^ d))) + 0x34b0bcb5 + s51;
+ a += e; e += (((f << 30) | (f >> 2)) ^ ((f << 19) | (f >> 13)) ^ ((f << 10) | (f >> 22))) + ((f & (g | h)) | (g & h));
+ d += (((a << 26) | (a >> 6)) ^ ((a << 21) | (a >> 11)) ^ ((a << 7) | (a >> 25))) + (c ^ (a & (b ^ c))) + 0x391c0cb3 + s52;
+ h += d; d += (((e << 30) | (e >> 2)) ^ ((e << 19) | (e >> 13)) ^ ((e << 10) | (e >> 22))) + ((e & (f | g)) | (f & g));
+ c += (((h << 26) | (h >> 6)) ^ ((h << 21) | (h >> 11)) ^ ((h << 7) | (h >> 25))) + (b ^ (h & (a ^ b))) + 0x4ed8aa4a + s53;
+ g += c; c += (((d << 30) | (d >> 2)) ^ ((d << 19) | (d >> 13)) ^ ((d << 10) | (d >> 22))) + ((d & (e | f)) | (e & f));
+ b += (((g << 26) | (g >> 6)) ^ ((g << 21) | (g >> 11)) ^ ((g << 7) | (g >> 25))) + (a ^ (g & (h ^ a))) + 0x5b9cca4f + s54;
+ f += b; b += (((c << 30) | (c >> 2)) ^ ((c << 19) | (c >> 13)) ^ ((c << 10) | (c >> 22))) + ((c & (d | e)) | (d & e));
+ a += (((f << 26) | (f >> 6)) ^ ((f << 21) | (f >> 11)) ^ ((f << 7) | (f >> 25))) + (h ^ (f & (g ^ h))) + 0x682e6ff3 + s55;
+ e += a; a += (((b << 30) | (b >> 2)) ^ ((b << 19) | (b >> 13)) ^ ((b << 10) | (b >> 22))) + ((b & (c | d)) | (c & d));
+ h += (((e << 26) | (e >> 6)) ^ ((e << 21) | (e >> 11)) ^ ((e << 7) | (e >> 25))) + (g ^ (e & (f ^ g))) + 0x748f82ee + s56;
+ d += h; h += (((a << 30) | (a >> 2)) ^ ((a << 19) | (a >> 13)) ^ ((a << 10) | (a >> 22))) + ((a & (b | c)) | (b & c));
+ g += (((d << 26) | (d >> 6)) ^ ((d << 21) | (d >> 11)) ^ ((d << 7) | (d >> 25))) + (f ^ (d & (e ^ f))) + 0x78a5636f + s57;
+ c += g; g += (((h << 30) | (h >> 2)) ^ ((h << 19) | (h >> 13)) ^ ((h << 10) | (h >> 22))) + ((h & (a | b)) | (a & b));
+ f += (((c << 26) | (c >> 6)) ^ ((c << 21) | (c >> 11)) ^ ((c << 7) | (c >> 25))) + (e ^ (c & (d ^ e))) + 0x84c87814 + s58;
+ b += f; f += (((g << 30) | (g >> 2)) ^ ((g << 19) | (g >> 13)) ^ ((g << 10) | (g >> 22))) + ((g & (h | a)) | (h & a));
+ e += (((b << 26) | (b >> 6)) ^ ((b << 21) | (b >> 11)) ^ ((b << 7) | (b >> 25))) + (d ^ (b & (c ^ d))) + 0x8cc70208 + s59;
+ a += e; e += (((f << 30) | (f >> 2)) ^ ((f << 19) | (f >> 13)) ^ ((f << 10) | (f >> 22))) + ((f & (g | h)) | (g & h));
+ d += (((a << 26) | (a >> 6)) ^ ((a << 21) | (a >> 11)) ^ ((a << 7) | (a >> 25))) + (c ^ (a & (b ^ c))) + 0x90befffa + s60;
+ h += d; d += (((e << 30) | (e >> 2)) ^ ((e << 19) | (e >> 13)) ^ ((e << 10) | (e >> 22))) + ((e & (f | g)) | (f & g));
+ c += (((h << 26) | (h >> 6)) ^ ((h << 21) | (h >> 11)) ^ ((h << 7) | (h >> 25))) + (b ^ (h & (a ^ b))) + 0xa4506ceb + s61;
+ g += c; c += (((d << 30) | (d >> 2)) ^ ((d << 19) | (d >> 13)) ^ ((d << 10) | (d >> 22))) + ((d & (e | f)) | (e & f));
+ b += (((g << 26) | (g >> 6)) ^ ((g << 21) | (g >> 11)) ^ ((g << 7) | (g >> 25))) + (a ^ (g & (h ^ a))) + 0xbef9a3f7 + s62;
+ f += b; b += (((c << 30) | (c >> 2)) ^ ((c << 19) | (c >> 13)) ^ ((c << 10) | (c >> 22))) + ((c & (d | e)) | (d & e));
+ a += (((f << 26) | (f >> 6)) ^ ((f << 21) | (f >> 11)) ^ ((f << 7) | (f >> 25))) + (h ^ (f & (g ^ h))) + 0xc67178f2 + s63;
+ e += a; a += (((b << 30) | (b >> 2)) ^ ((b << 19) | (b >> 13)) ^ ((b << 10) | (b >> 22))) + ((b & (c | d)) | (c & d));
+
+ x[0] += a
+ x[1] += b
+ x[2] += c
+ x[3] += d
+ x[4] += e
+ x[5] += f
+ x[6] += g
+ x[7] += h
+}
+
+const unpack = {b
+ var v : uint32
+
+ v = ((b[0] castto(uint32)) << 24)
+ v |= ((b[1] castto(uint32)) << 16)
+ v |= ((b[2] castto(uint32)) << 8)
+ v |= ((b[3] castto(uint32)) << 0)
+ -> v
+}
+
+const pack = {out, v
+ out[0] = (v >> 24) castto(byte)
+ out[1] = (v >> 16) castto(byte)
+ out[2] = (v >> 8) castto(byte)
+ out[3] = (v >> 0) castto(byte)
+}
diff --git a/lib/cryptohash/sha512.myr b/lib/cryptohash/sha512.myr
new file mode 100644
index 0000000..e5d9543
--- /dev/null
+++ b/lib/cryptohash/sha512.myr
@@ -0,0 +1,474 @@
+use std
+
+pkg cryptohash =
+ type sha512
+ type sha384
+
+ const sha512 : (data : byte[:] -> byte[64])
+ const sha512init : (st : sha512# -> void)
+ const sha512add : (st : sha512#, data : byte[:] -> void)
+ const sha512fin : (st : sha512# -> byte[64])
+
+ const sha384 : (data : byte[:] -> byte[48])
+ const sha384init : (st : sha384# -> void)
+ const sha384add : (st : sha384#, data : byte[:] -> void)
+ const sha384fin : (st : sha384# -> byte[48])
+;;
+
+
+type sha512 = struct
+ x : uint64[8]
+ tail : byte[128]
+ msglen : uint64
+;;
+
+type sha384 = struct
+ x : uint64[8]
+ tail : byte[128]
+ msglen : uint64
+;;
+
+const sha512 = {data
+ var st
+
+ sha512init(&st)
+ sha512add(&st, data)
+ -> sha512fin(&st)
+}
+
+const sha512init = {st
+ st.x[0] = 0x6a09e667f3bcc908ul
+ st.x[1] = 0xbb67ae8584caa73bul
+ st.x[2] = 0x3c6ef372fe94f82bul
+ st.x[3] = 0xa54ff53a5f1d36f1ul
+ st.x[4] = 0x510e527fade682d1ul
+ st.x[5] = 0x9b05688c2b3e6c1ful
+ st.x[6] = 0x1f83d9abfb41bd6bul
+ st.x[7] = 0x5be0cd19137e2179ul
+ st.msglen = 0
+}
+
+const sha512add = {st, data
+ var n, ntail
+
+ ntail = st.msglen % 128
+ st.msglen += data.len
+ if ntail > 0
+ n = std.min(128 - ntail, data.len)
+ std.slcp(st.tail[ntail:ntail+n], data[:n])
+ data = data[n:]
+ if n + ntail < 128
+ ->
+ ;;
+ step(st.x[:], st.tail[:])
+ ;;
+
+ while data.len >= 128
+ step(st.x[:], data[:128])
+ data = data[128:]
+ ;;
+
+ ntail = st.msglen % 128
+ std.slcp(st.tail[:ntail], data)
+}
+
+const sha512fin = {st
+ var r : byte[64]
+
+ tail(st.x[:], st.msglen, st.tail[:])
+
+ pack(r[ 0: 8], st.x[0])
+ pack(r[ 8:16], st.x[1])
+ pack(r[16:24], st.x[2])
+ pack(r[24:32], st.x[3])
+ pack(r[32:40], st.x[4])
+ pack(r[40:48], st.x[5])
+ pack(r[48:56], st.x[6])
+ pack(r[56:64], st.x[7])
+ -> r
+}
+
+const sha384 = {data
+ var st
+
+ sha384init(&st)
+ sha384add(&st, data)
+ -> sha384fin(&st)
+}
+
+const sha384init = {st
+ st.x[0] = 0xCBBB9D5DC1059ED8ul
+ st.x[1] = 0x629A292A367CD507ul
+ st.x[2] = 0x9159015A3070DD17ul
+ st.x[3] = 0x152FECD8F70E5939ul
+ st.x[4] = 0x67332667FFC00B31ul
+ st.x[5] = 0x8EB44A8768581511ul
+ st.x[6] = 0xDB0C2E0D64F98FA7ul
+ st.x[7] = 0x47B5481DBEFA4FA4ul
+ st.msglen = 0
+}
+
+const sha384add = {st, data
+ var n, ntail
+
+ ntail = st.msglen % 128
+ st.msglen += data.len
+ if ntail > 0
+ n = std.min(128 - ntail, data.len)
+ std.slcp(st.tail[ntail:ntail+n], data[:n])
+ data = data[n:]
+ if n + ntail < 128
+ ->
+ ;;
+ step(st.x[:], st.tail[:])
+ ;;
+
+ while data.len >= 128
+ step(st.x[:], data[:128])
+ data = data[128:]
+ ;;
+
+ ntail = st.msglen % 128
+ std.slcp(st.tail[:ntail], data)
+}
+
+const sha384fin = {st
+ var r : byte[48]
+
+ tail(st.x[:], st.msglen, st.tail[:])
+
+ pack(r[ 0: 8], st.x[0])
+ pack(r[ 8:16], st.x[1])
+ pack(r[16:24], st.x[2])
+ pack(r[24:32], st.x[3])
+ pack(r[32:40], st.x[4])
+ pack(r[40:48], st.x[5])
+ -> r
+}
+
+
+const tail = {x, msglen, tail
+ var ntail
+
+ /* append first padding block */
+ ntail = msglen % 128
+ tail[ntail++] = 0x80
+ std.slfill(tail[ntail:], 0)
+ if 128 - ntail < 16
+ step(x, tail)
+ std.slfill(tail, 0)
+ ;;
+
+ /* append size block */
+ tail[120] = ((msglen * 8) >> 56) castto(byte)
+ tail[121] = ((msglen * 8) >> 48) castto(byte)
+ tail[122] = ((msglen * 8) >> 40) castto(byte)
+ tail[123] = ((msglen * 8) >> 32) castto(byte)
+ tail[124] = ((msglen * 8) >> 24) castto(byte)
+ tail[125] = ((msglen * 8) >> 16) castto(byte)
+ tail[126] = ((msglen * 8) >> 8) castto(byte)
+ tail[127] = ((msglen * 8) >> 0) castto(byte)
+ step(x, tail)
+}
+
+const step = {x : uint64[:], msg
+ var a, b, c, d, e, f, g, h
+ var s00, s01, s02, s03, s04, s05, s06, s07
+ var s08, s09, s10, s11, s12, s13, s14, s15
+ var s16, s17, s18, s19, s20, s21, s22, s23
+ var s24, s25, s26, s27, s28, s29, s30, s31
+ var s32, s33, s34, s35, s36, s37, s38, s39
+ var s40, s41, s42, s43, s44, s45, s46, s47
+ var s48, s49, s50, s51, s52, s53, s54, s55
+ var s56, s57, s58, s59, s60, s61, s62, s63
+ var s64, s65, s66, s67, s68, s69, s70, s71
+ var s72, s73, s74, s75, s76, s77, s78, s79
+
+ a = x[0]
+ b = x[1]
+ c = x[2]
+ d = x[3]
+ e = x[4]
+ f = x[5]
+ g = x[6]
+ h = x[7]
+
+ s00 = unpack(msg[ 0: 8])
+ s01 = unpack(msg[ 8: 16])
+ s02 = unpack(msg[ 16: 24])
+ s03 = unpack(msg[ 24: 32])
+ s04 = unpack(msg[ 32: 40])
+ s05 = unpack(msg[ 40: 48])
+ s06 = unpack(msg[ 48: 56])
+ s07 = unpack(msg[ 56: 64])
+ s08 = unpack(msg[ 64: 72])
+ s09 = unpack(msg[ 72: 80])
+ s10 = unpack(msg[ 80: 88])
+ s11 = unpack(msg[ 88: 96])
+ s12 = unpack(msg[ 96:104])
+ s13 = unpack(msg[104:112])
+ s14 = unpack(msg[112:120])
+ s15 = unpack(msg[120:128])
+
+ s16 = s00 + s09 + (((s01 << 63) | (s01 >> 1))^((s01 << 56) | (s01 >> 8))^(s01 >> 7)) + (((s14 << 45) | (s14 >> 19))^((s14 << 3) | (s14 >> 61))^(s14 >> 6))
+ s17 = s01 + s10 + (((s02 << 63) | (s02 >> 1))^((s02 << 56) | (s02 >> 8))^(s02 >> 7)) + (((s15 << 45) | (s15 >> 19))^((s15 << 3) | (s15 >> 61))^(s15 >> 6))
+ s18 = s02 + s11 + (((s03 << 63) | (s03 >> 1))^((s03 << 56) | (s03 >> 8))^(s03 >> 7)) + (((s16 << 45) | (s16 >> 19))^((s16 << 3) | (s16 >> 61))^(s16 >> 6))
+ s19 = s03 + s12 + (((s04 << 63) | (s04 >> 1))^((s04 << 56) | (s04 >> 8))^(s04 >> 7)) + (((s17 << 45) | (s17 >> 19))^((s17 << 3) | (s17 >> 61))^(s17 >> 6))
+ s20 = s04 + s13 + (((s05 << 63) | (s05 >> 1))^((s05 << 56) | (s05 >> 8))^(s05 >> 7)) + (((s18 << 45) | (s18 >> 19))^((s18 << 3) | (s18 >> 61))^(s18 >> 6))
+ s21 = s05 + s14 + (((s06 << 63) | (s06 >> 1))^((s06 << 56) | (s06 >> 8))^(s06 >> 7)) + (((s19 << 45) | (s19 >> 19))^((s19 << 3) | (s19 >> 61))^(s19 >> 6))
+ s22 = s06 + s15 + (((s07 << 63) | (s07 >> 1))^((s07 << 56) | (s07 >> 8))^(s07 >> 7)) + (((s20 << 45) | (s20 >> 19))^((s20 << 3) | (s20 >> 61))^(s20 >> 6))
+ s23 = s07 + s16 + (((s08 << 63) | (s08 >> 1))^((s08 << 56) | (s08 >> 8))^(s08 >> 7)) + (((s21 << 45) | (s21 >> 19))^((s21 << 3) | (s21 >> 61))^(s21 >> 6))
+ s24 = s08 + s17 + (((s09 << 63) | (s09 >> 1))^((s09 << 56) | (s09 >> 8))^(s09 >> 7)) + (((s22 << 45) | (s22 >> 19))^((s22 << 3) | (s22 >> 61))^(s22 >> 6))
+ s25 = s09 + s18 + (((s10 << 63) | (s10 >> 1))^((s10 << 56) | (s10 >> 8))^(s10 >> 7)) + (((s23 << 45) | (s23 >> 19))^((s23 << 3) | (s23 >> 61))^(s23 >> 6))
+ s26 = s10 + s19 + (((s11 << 63) | (s11 >> 1))^((s11 << 56) | (s11 >> 8))^(s11 >> 7)) + (((s24 << 45) | (s24 >> 19))^((s24 << 3) | (s24 >> 61))^(s24 >> 6))
+ s27 = s11 + s20 + (((s12 << 63) | (s12 >> 1))^((s12 << 56) | (s12 >> 8))^(s12 >> 7)) + (((s25 << 45) | (s25 >> 19))^((s25 << 3) | (s25 >> 61))^(s25 >> 6))
+ s28 = s12 + s21 + (((s13 << 63) | (s13 >> 1))^((s13 << 56) | (s13 >> 8))^(s13 >> 7)) + (((s26 << 45) | (s26 >> 19))^((s26 << 3) | (s26 >> 61))^(s26 >> 6))
+ s29 = s13 + s22 + (((s14 << 63) | (s14 >> 1))^((s14 << 56) | (s14 >> 8))^(s14 >> 7)) + (((s27 << 45) | (s27 >> 19))^((s27 << 3) | (s27 >> 61))^(s27 >> 6))
+ s30 = s14 + s23 + (((s15 << 63) | (s15 >> 1))^((s15 << 56) | (s15 >> 8))^(s15 >> 7)) + (((s28 << 45) | (s28 >> 19))^((s28 << 3) | (s28 >> 61))^(s28 >> 6))
+ s31 = s15 + s24 + (((s16 << 63) | (s16 >> 1))^((s16 << 56) | (s16 >> 8))^(s16 >> 7)) + (((s29 << 45) | (s29 >> 19))^((s29 << 3) | (s29 >> 61))^(s29 >> 6))
+ s32 = s16 + s25 + (((s17 << 63) | (s17 >> 1))^((s17 << 56) | (s17 >> 8))^(s17 >> 7)) + (((s30 << 45) | (s30 >> 19))^((s30 << 3) | (s30 >> 61))^(s30 >> 6))
+ s33 = s17 + s26 + (((s18 << 63) | (s18 >> 1))^((s18 << 56) | (s18 >> 8))^(s18 >> 7)) + (((s31 << 45) | (s31 >> 19))^((s31 << 3) | (s31 >> 61))^(s31 >> 6))
+ s34 = s18 + s27 + (((s19 << 63) | (s19 >> 1))^((s19 << 56) | (s19 >> 8))^(s19 >> 7)) + (((s32 << 45) | (s32 >> 19))^((s32 << 3) | (s32 >> 61))^(s32 >> 6))
+ s35 = s19 + s28 + (((s20 << 63) | (s20 >> 1))^((s20 << 56) | (s20 >> 8))^(s20 >> 7)) + (((s33 << 45) | (s33 >> 19))^((s33 << 3) | (s33 >> 61))^(s33 >> 6))
+ s36 = s20 + s29 + (((s21 << 63) | (s21 >> 1))^((s21 << 56) | (s21 >> 8))^(s21 >> 7)) + (((s34 << 45) | (s34 >> 19))^((s34 << 3) | (s34 >> 61))^(s34 >> 6))
+ s37 = s21 + s30 + (((s22 << 63) | (s22 >> 1))^((s22 << 56) | (s22 >> 8))^(s22 >> 7)) + (((s35 << 45) | (s35 >> 19))^((s35 << 3) | (s35 >> 61))^(s35 >> 6))
+ s38 = s22 + s31 + (((s23 << 63) | (s23 >> 1))^((s23 << 56) | (s23 >> 8))^(s23 >> 7)) + (((s36 << 45) | (s36 >> 19))^((s36 << 3) | (s36 >> 61))^(s36 >> 6))
+ s39 = s23 + s32 + (((s24 << 63) | (s24 >> 1))^((s24 << 56) | (s24 >> 8))^(s24 >> 7)) + (((s37 << 45) | (s37 >> 19))^((s37 << 3) | (s37 >> 61))^(s37 >> 6))
+ s40 = s24 + s33 + (((s25 << 63) | (s25 >> 1))^((s25 << 56) | (s25 >> 8))^(s25 >> 7)) + (((s38 << 45) | (s38 >> 19))^((s38 << 3) | (s38 >> 61))^(s38 >> 6))
+ s41 = s25 + s34 + (((s26 << 63) | (s26 >> 1))^((s26 << 56) | (s26 >> 8))^(s26 >> 7)) + (((s39 << 45) | (s39 >> 19))^((s39 << 3) | (s39 >> 61))^(s39 >> 6))
+ s42 = s26 + s35 + (((s27 << 63) | (s27 >> 1))^((s27 << 56) | (s27 >> 8))^(s27 >> 7)) + (((s40 << 45) | (s40 >> 19))^((s40 << 3) | (s40 >> 61))^(s40 >> 6))
+ s43 = s27 + s36 + (((s28 << 63) | (s28 >> 1))^((s28 << 56) | (s28 >> 8))^(s28 >> 7)) + (((s41 << 45) | (s41 >> 19))^((s41 << 3) | (s41 >> 61))^(s41 >> 6))
+ s44 = s28 + s37 + (((s29 << 63) | (s29 >> 1))^((s29 << 56) | (s29 >> 8))^(s29 >> 7)) + (((s42 << 45) | (s42 >> 19))^((s42 << 3) | (s42 >> 61))^(s42 >> 6))
+ s45 = s29 + s38 + (((s30 << 63) | (s30 >> 1))^((s30 << 56) | (s30 >> 8))^(s30 >> 7)) + (((s43 << 45) | (s43 >> 19))^((s43 << 3) | (s43 >> 61))^(s43 >> 6))
+ s46 = s30 + s39 + (((s31 << 63) | (s31 >> 1))^((s31 << 56) | (s31 >> 8))^(s31 >> 7)) + (((s44 << 45) | (s44 >> 19))^((s44 << 3) | (s44 >> 61))^(s44 >> 6))
+ s47 = s31 + s40 + (((s32 << 63) | (s32 >> 1))^((s32 << 56) | (s32 >> 8))^(s32 >> 7)) + (((s45 << 45) | (s45 >> 19))^((s45 << 3) | (s45 >> 61))^(s45 >> 6))
+ s48 = s32 + s41 + (((s33 << 63) | (s33 >> 1))^((s33 << 56) | (s33 >> 8))^(s33 >> 7)) + (((s46 << 45) | (s46 >> 19))^((s46 << 3) | (s46 >> 61))^(s46 >> 6))
+ s49 = s33 + s42 + (((s34 << 63) | (s34 >> 1))^((s34 << 56) | (s34 >> 8))^(s34 >> 7)) + (((s47 << 45) | (s47 >> 19))^((s47 << 3) | (s47 >> 61))^(s47 >> 6))
+ s50 = s34 + s43 + (((s35 << 63) | (s35 >> 1))^((s35 << 56) | (s35 >> 8))^(s35 >> 7)) + (((s48 << 45) | (s48 >> 19))^((s48 << 3) | (s48 >> 61))^(s48 >> 6))
+ s51 = s35 + s44 + (((s36 << 63) | (s36 >> 1))^((s36 << 56) | (s36 >> 8))^(s36 >> 7)) + (((s49 << 45) | (s49 >> 19))^((s49 << 3) | (s49 >> 61))^(s49 >> 6))
+ s52 = s36 + s45 + (((s37 << 63) | (s37 >> 1))^((s37 << 56) | (s37 >> 8))^(s37 >> 7)) + (((s50 << 45) | (s50 >> 19))^((s50 << 3) | (s50 >> 61))^(s50 >> 6))
+ s53 = s37 + s46 + (((s38 << 63) | (s38 >> 1))^((s38 << 56) | (s38 >> 8))^(s38 >> 7)) + (((s51 << 45) | (s51 >> 19))^((s51 << 3) | (s51 >> 61))^(s51 >> 6))
+ s54 = s38 + s47 + (((s39 << 63) | (s39 >> 1))^((s39 << 56) | (s39 >> 8))^(s39 >> 7)) + (((s52 << 45) | (s52 >> 19))^((s52 << 3) | (s52 >> 61))^(s52 >> 6))
+ s55 = s39 + s48 + (((s40 << 63) | (s40 >> 1))^((s40 << 56) | (s40 >> 8))^(s40 >> 7)) + (((s53 << 45) | (s53 >> 19))^((s53 << 3) | (s53 >> 61))^(s53 >> 6))
+ s56 = s40 + s49 + (((s41 << 63) | (s41 >> 1))^((s41 << 56) | (s41 >> 8))^(s41 >> 7)) + (((s54 << 45) | (s54 >> 19))^((s54 << 3) | (s54 >> 61))^(s54 >> 6))
+ s57 = s41 + s50 + (((s42 << 63) | (s42 >> 1))^((s42 << 56) | (s42 >> 8))^(s42 >> 7)) + (((s55 << 45) | (s55 >> 19))^((s55 << 3) | (s55 >> 61))^(s55 >> 6))
+ s58 = s42 + s51 + (((s43 << 63) | (s43 >> 1))^((s43 << 56) | (s43 >> 8))^(s43 >> 7)) + (((s56 << 45) | (s56 >> 19))^((s56 << 3) | (s56 >> 61))^(s56 >> 6))
+ s59 = s43 + s52 + (((s44 << 63) | (s44 >> 1))^((s44 << 56) | (s44 >> 8))^(s44 >> 7)) + (((s57 << 45) | (s57 >> 19))^((s57 << 3) | (s57 >> 61))^(s57 >> 6))
+ s60 = s44 + s53 + (((s45 << 63) | (s45 >> 1))^((s45 << 56) | (s45 >> 8))^(s45 >> 7)) + (((s58 << 45) | (s58 >> 19))^((s58 << 3) | (s58 >> 61))^(s58 >> 6))
+ s61 = s45 + s54 + (((s46 << 63) | (s46 >> 1))^((s46 << 56) | (s46 >> 8))^(s46 >> 7)) + (((s59 << 45) | (s59 >> 19))^((s59 << 3) | (s59 >> 61))^(s59 >> 6))
+ s62 = s46 + s55 + (((s47 << 63) | (s47 >> 1))^((s47 << 56) | (s47 >> 8))^(s47 >> 7)) + (((s60 << 45) | (s60 >> 19))^((s60 << 3) | (s60 >> 61))^(s60 >> 6))
+ s63 = s47 + s56 + (((s48 << 63) | (s48 >> 1))^((s48 << 56) | (s48 >> 8))^(s48 >> 7)) + (((s61 << 45) | (s61 >> 19))^((s61 << 3) | (s61 >> 61))^(s61 >> 6))
+ s64 = s48 + s57 + (((s49 << 63) | (s49 >> 1))^((s49 << 56) | (s49 >> 8))^(s49 >> 7)) + (((s62 << 45) | (s62 >> 19))^((s62 << 3) | (s62 >> 61))^(s62 >> 6))
+ s65 = s49 + s58 + (((s50 << 63) | (s50 >> 1))^((s50 << 56) | (s50 >> 8))^(s50 >> 7)) + (((s63 << 45) | (s63 >> 19))^((s63 << 3) | (s63 >> 61))^(s63 >> 6))
+ s66 = s50 + s59 + (((s51 << 63) | (s51 >> 1))^((s51 << 56) | (s51 >> 8))^(s51 >> 7)) + (((s64 << 45) | (s64 >> 19))^((s64 << 3) | (s64 >> 61))^(s64 >> 6))
+ s67 = s51 + s60 + (((s52 << 63) | (s52 >> 1))^((s52 << 56) | (s52 >> 8))^(s52 >> 7)) + (((s65 << 45) | (s65 >> 19))^((s65 << 3) | (s65 >> 61))^(s65 >> 6))
+ s68 = s52 + s61 + (((s53 << 63) | (s53 >> 1))^((s53 << 56) | (s53 >> 8))^(s53 >> 7)) + (((s66 << 45) | (s66 >> 19))^((s66 << 3) | (s66 >> 61))^(s66 >> 6))
+ s69 = s53 + s62 + (((s54 << 63) | (s54 >> 1))^((s54 << 56) | (s54 >> 8))^(s54 >> 7)) + (((s67 << 45) | (s67 >> 19))^((s67 << 3) | (s67 >> 61))^(s67 >> 6))
+ s70 = s54 + s63 + (((s55 << 63) | (s55 >> 1))^((s55 << 56) | (s55 >> 8))^(s55 >> 7)) + (((s68 << 45) | (s68 >> 19))^((s68 << 3) | (s68 >> 61))^(s68 >> 6))
+ s71 = s55 + s64 + (((s56 << 63) | (s56 >> 1))^((s56 << 56) | (s56 >> 8))^(s56 >> 7)) + (((s69 << 45) | (s69 >> 19))^((s69 << 3) | (s69 >> 61))^(s69 >> 6))
+ s72 = s56 + s65 + (((s57 << 63) | (s57 >> 1))^((s57 << 56) | (s57 >> 8))^(s57 >> 7)) + (((s70 << 45) | (s70 >> 19))^((s70 << 3) | (s70 >> 61))^(s70 >> 6))
+ s73 = s57 + s66 + (((s58 << 63) | (s58 >> 1))^((s58 << 56) | (s58 >> 8))^(s58 >> 7)) + (((s71 << 45) | (s71 >> 19))^((s71 << 3) | (s71 >> 61))^(s71 >> 6))
+ s74 = s58 + s67 + (((s59 << 63) | (s59 >> 1))^((s59 << 56) | (s59 >> 8))^(s59 >> 7)) + (((s72 << 45) | (s72 >> 19))^((s72 << 3) | (s72 >> 61))^(s72 >> 6))
+ s75 = s59 + s68 + (((s60 << 63) | (s60 >> 1))^((s60 << 56) | (s60 >> 8))^(s60 >> 7)) + (((s73 << 45) | (s73 >> 19))^((s73 << 3) | (s73 >> 61))^(s73 >> 6))
+ s76 = s60 + s69 + (((s61 << 63) | (s61 >> 1))^((s61 << 56) | (s61 >> 8))^(s61 >> 7)) + (((s74 << 45) | (s74 >> 19))^((s74 << 3) | (s74 >> 61))^(s74 >> 6))
+ s77 = s61 + s70 + (((s62 << 63) | (s62 >> 1))^((s62 << 56) | (s62 >> 8))^(s62 >> 7)) + (((s75 << 45) | (s75 >> 19))^((s75 << 3) | (s75 >> 61))^(s75 >> 6))
+ s78 = s62 + s71 + (((s63 << 63) | (s63 >> 1))^((s63 << 56) | (s63 >> 8))^(s63 >> 7)) + (((s76 << 45) | (s76 >> 19))^((s76 << 3) | (s76 >> 61))^(s76 >> 6))
+ s79 = s63 + s72 + (((s64 << 63) | (s64 >> 1))^((s64 << 56) | (s64 >> 8))^(s64 >> 7)) + (((s77 << 45) | (s77 >> 19))^((s77 << 3) | (s77 >> 61))^(s77 >> 6))
+
+
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0x428a2f98d728ae22ul + s00
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0x7137449123ef65cdul + s01
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0xb5c0fbcfec4d3b2ful + s02
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0xe9b5dba58189dbbcul + s03
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0x3956c25bf348b538ul + s04
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0x59f111f1b605d019ul + s05
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0x923f82a4af194f9bul + s06
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0xab1c5ed5da6d8118ul + s07
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0xd807aa98a3030242ul + s08
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0x12835b0145706fbeul + s09
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0x243185be4ee4b28cul + s10
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0x550c7dc3d5ffb4e2ul + s11
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0x72be5d74f27b896ful + s12
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0x80deb1fe3b1696b1ul + s13
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0x9bdc06a725c71235ul + s14
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0xc19bf174cf692694ul + s15
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0xe49b69c19ef14ad2ul + s16
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0xefbe4786384f25e3ul + s17
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0x0fc19dc68b8cd5b5ul + s18
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0x240ca1cc77ac9c65ul + s19
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0x2de92c6f592b0275ul + s20
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0x4a7484aa6ea6e483ul + s21
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0x5cb0a9dcbd41fbd4ul + s22
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0x76f988da831153b5ul + s23
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0x983e5152ee66dfabul + s24
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0xa831c66d2db43210ul + s25
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0xb00327c898fb213ful + s26
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0xbf597fc7beef0ee4ul + s27
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0xc6e00bf33da88fc2ul + s28
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0xd5a79147930aa725ul + s29
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0x06ca6351e003826ful + s30
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0x142929670a0e6e70ul + s31
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0x27b70a8546d22ffcul + s32
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0x2e1b21385c26c926ul + s33
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0x4d2c6dfc5ac42aedul + s34
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0x53380d139d95b3dful + s35
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0x650a73548baf63deul + s36
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0x766a0abb3c77b2a8ul + s37
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0x81c2c92e47edaee6ul + s38
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0x92722c851482353bul + s39
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0xa2bfe8a14cf10364ul + s40
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0xa81a664bbc423001ul + s41
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0xc24b8b70d0f89791ul + s42
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0xc76c51a30654be30ul + s43
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0xd192e819d6ef5218ul + s44
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0xd69906245565a910ul + s45
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0xf40e35855771202aul + s46
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0x106aa07032bbd1b8ul + s47
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0x19a4c116b8d2d0c8ul + s48
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0x1e376c085141ab53ul + s49
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0x2748774cdf8eeb99ul + s50
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0x34b0bcb5e19b48a8ul + s51
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0x391c0cb3c5c95a63ul + s52
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0x4ed8aa4ae3418acbul + s53
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0x5b9cca4f7763e373ul + s54
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0x682e6ff3d6b2b8a3ul + s55
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0x748f82ee5defb2fcul + s56
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0x78a5636f43172f60ul + s57
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0x84c87814a1f0ab72ul + s58
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0x8cc702081a6439ecul + s59
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0x90befffa23631e28ul + s60
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0xa4506cebde82bde9ul + s61
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0xbef9a3f7b2c67915ul + s62
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0xc67178f2e372532bul + s63
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0xca273eceea26619cul + s64
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0xd186b8c721c0c207ul + s65
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0xeada7dd6cde0eb1eul + s66
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0xf57d4f7fee6ed178ul + s67
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0x06f067aa72176fbaul + s68
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0x0a637dc5a2c898a6ul + s69
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0x113f9804bef90daeul + s70
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0x1b710b35131c471bul + s71
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+ h += (((e << 50) | (e >> 14)) ^ ((e << (64 - 18)) | (e >> 18)) ^ ((e << 23) | (e >> 41))) + (g ^ (e & (f ^ g))) + 0x28db77f523047d84ul + s72
+ d += h; h += (((a << 36) | (a >> 28)) ^ ((a << (64 - 34)) | (a >> 34)) ^ ((a << 25) | (a >> 39))) + ((a & (b | c)) | (b & c));
+ g += (((d << 50) | (d >> 14)) ^ ((d << (64 - 18)) | (d >> 18)) ^ ((d << 23) | (d >> 41))) + (f ^ (d & (e ^ f))) + 0x32caab7b40c72493ul + s73
+ c += g; g += (((h << 36) | (h >> 28)) ^ ((h << (64 - 34)) | (h >> 34)) ^ ((h << 25) | (h >> 39))) + ((h & (a | b)) | (a & b));
+ f += (((c << 50) | (c >> 14)) ^ ((c << (64 - 18)) | (c >> 18)) ^ ((c << 23) | (c >> 41))) + (e ^ (c & (d ^ e))) + 0x3c9ebe0a15c9bebcul + s74
+ b += f; f += (((g << 36) | (g >> 28)) ^ ((g << (64 - 34)) | (g >> 34)) ^ ((g << 25) | (g >> 39))) + ((g & (h | a)) | (h & a));
+ e += (((b << 50) | (b >> 14)) ^ ((b << (64 - 18)) | (b >> 18)) ^ ((b << 23) | (b >> 41))) + (d ^ (b & (c ^ d))) + 0x431d67c49c100d4cul + s75
+ a += e; e += (((f << 36) | (f >> 28)) ^ ((f << (64 - 34)) | (f >> 34)) ^ ((f << 25) | (f >> 39))) + ((f & (g | h)) | (g & h));
+ d += (((a << 50) | (a >> 14)) ^ ((a << (64 - 18)) | (a >> 18)) ^ ((a << 23) | (a >> 41))) + (c ^ (a & (b ^ c))) + 0x4cc5d4becb3e42b6ul + s76
+ h += d; d += (((e << 36) | (e >> 28)) ^ ((e << (64 - 34)) | (e >> 34)) ^ ((e << 25) | (e >> 39))) + ((e & (f | g)) | (f & g));
+ c += (((h << 50) | (h >> 14)) ^ ((h << (64 - 18)) | (h >> 18)) ^ ((h << 23) | (h >> 41))) + (b ^ (h & (a ^ b))) + 0x597f299cfc657e2aul + s77
+ g += c; c += (((d << 36) | (d >> 28)) ^ ((d << (64 - 34)) | (d >> 34)) ^ ((d << 25) | (d >> 39))) + ((d & (e | f)) | (e & f));
+ b += (((g << 50) | (g >> 14)) ^ ((g << (64 - 18)) | (g >> 18)) ^ ((g << 23) | (g >> 41))) + (a ^ (g & (h ^ a))) + 0x5fcb6fab3ad6faecul + s78
+ f += b; b += (((c << 36) | (c >> 28)) ^ ((c << (64 - 34)) | (c >> 34)) ^ ((c << 25) | (c >> 39))) + ((c & (d | e)) | (d & e));
+ a += (((f << 50) | (f >> 14)) ^ ((f << (64 - 18)) | (f >> 18)) ^ ((f << 23) | (f >> 41))) + (h ^ (f & (g ^ h))) + 0x6c44198c4a475817ul + s79
+ e += a; a += (((b << 36) | (b >> 28)) ^ ((b << (64 - 34)) | (b >> 34)) ^ ((b << 25) | (b >> 39))) + ((b & (c | d)) | (c & d));
+
+ x[0] += a
+ x[1] += b
+ x[2] += c
+ x[3] += d
+ x[4] += e
+ x[5] += f
+ x[6] += g
+ x[7] += h
+}
+
+const unpack = {b
+ var v : uint64
+
+ v = ((b[0] castto(uint64)) << 56)
+ v |= ((b[1] castto(uint64)) << 48)
+ v |= ((b[2] castto(uint64)) << 40)
+ v |= ((b[3] castto(uint64)) << 32)
+ v |= ((b[4] castto(uint64)) << 24)
+ v |= ((b[5] castto(uint64)) << 16)
+ v |= ((b[6] castto(uint64)) << 8)
+ v |= ((b[7] castto(uint64)) << 0)
+ -> v
+}
+
+const pack = {out, v
+ out[0] = (v >> 56) castto(byte)
+ out[1] = (v >> 48) castto(byte)
+ out[2] = (v >> 40) castto(byte)
+ out[3] = (v >> 32) castto(byte)
+ out[4] = (v >> 24) castto(byte)
+ out[5] = (v >> 16) castto(byte)
+ out[6] = (v >> 8) castto(byte)
+ out[7] = (v >> 0) castto(byte)
+}
+
diff --git a/lib/cryptohash/test/md5.myr b/lib/cryptohash/test/md5.myr
new file mode 100644
index 0000000..42d1089
--- /dev/null
+++ b/lib/cryptohash/test/md5.myr
@@ -0,0 +1,18 @@
+use std
+use cryptohash
+
+use "test/util.use"
+
+const main = {
+ hasheq(cryptohash.md5("")[:], \
+ "d41d8cd98f00b204e9800998ecf8427e")
+ hasheq(cryptohash.md5("h")[:], \
+ "2510c39011c5be704182423e3a695e91")
+ /* 64 byte block */
+ hasheq(cryptohash.md5("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")[:], \
+ "014842d480b571495a4a0363793f7367")
+ /* tail spanning */
+ hasheq(cryptohash.md5("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb")[:], \
+ "3b0bb4c5ece4a6568caa7266e740a140")
+}
+
diff --git a/lib/cryptohash/test/sha1.myr b/lib/cryptohash/test/sha1.myr
new file mode 100644
index 0000000..d2ccfb8
--- /dev/null
+++ b/lib/cryptohash/test/sha1.myr
@@ -0,0 +1,18 @@
+use std
+use cryptohash
+
+use "test/util.use"
+
+const main = {
+ hasheq(cryptohash.sha1("")[:], \
+ "da39a3ee5e6b4b0d3255bfef60951890d8af0709")
+ hasheq(cryptohash.sha1("h")[:], \
+ "27d5482eebd075de44389774e2fc8c695cf48a75")
+ /* 64 byte block */
+ hasheq(cryptohash.sha1("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")[:], \
+ "0098ba824b5c16427bd7a1125a2a442aec25644d")
+ /* tail spanning */
+ hasheq(cryptohash.sha1("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb")[:], \
+ "4eb17e52bb55910b037869438f69d9c87643d75a")
+}
+
diff --git a/lib/cryptohash/test/sha256.myr b/lib/cryptohash/test/sha256.myr
new file mode 100644
index 0000000..e3981b4
--- /dev/null
+++ b/lib/cryptohash/test/sha256.myr
@@ -0,0 +1,29 @@
+use std
+use cryptohash
+
+use "test/util.use"
+
+const main = {
+ hasheq(cryptohash.sha224("")[:], \
+ "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f")
+ hasheq(cryptohash.sha224("h")[:], \
+ "e0ccaeadfef916630c35576679e4cd4b438e7fc95a60b7361705f708")
+ /* 64 byte block */
+ hasheq(cryptohash.sha224("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")[:], \
+ "a88cd5cde6d6fe9136a4e58b49167461ea95d388ca2bdb7afdc3cbf4")
+ /* tail spanning */
+ hasheq(cryptohash.sha224("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb")[:], \
+ "4a5859b7efa22c3b25710520fc97b0a901f5cdba3e4f0becfeea725e")
+
+ hasheq(cryptohash.sha256("")[:], \
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
+ hasheq(cryptohash.sha256("h")[:], \
+ "aaa9402664f1a41f40ebbc52c9993eb66aeb366602958fdfaa283b71e64db123")
+ /* 64 byte block */
+ hasheq(cryptohash.sha256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")[:], \
+ "ffe054fe7ae0cb6dc65c3af9b61d5209f439851db43d0ba5997337df154668eb")
+ /* tail spanning */
+ hasheq(cryptohash.sha256("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb")[:], \
+ "bac8bf0f9794a520a5bf0ec64d3206edd1b9f2ef5ea118c9cad5365d84578de4")
+}
+
diff --git a/lib/cryptohash/test/sha512.myr b/lib/cryptohash/test/sha512.myr
new file mode 100644
index 0000000..f58f96e
--- /dev/null
+++ b/lib/cryptohash/test/sha512.myr
@@ -0,0 +1,29 @@
+use std
+use cryptohash
+
+use "test/util.use"
+
+const main = {
+ hasheq(cryptohash.sha384("")[:], \
+ "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b")
+ hasheq(cryptohash.sha384("h")[:], \
+ "a4eb0778c79fce94c02126543cba398d645b2fd4c6ff6a02eecc026bbe0cc0dd666279722b7615bc15b4c9126b941c04")
+ /* 64 byte block */
+ hasheq(cryptohash.sha384("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")[:], \
+ "2e404b9339da795776e510d96930b3be2904c500395b8cb7413334b82d4dec413b4b8113045a05bbbcff846f027423f6")
+ /* tail spanning */
+ hasheq(cryptohash.sha384("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb")[:], \
+ "f8f4b55a0fb1ac8506d2e5195c714a1ad16c3bf61ad8b2d544344b105a49a77ff3b8eb61e8f970a71864e9dad87042b1")
+
+ hasheq(cryptohash.sha512("")[:], \
+ "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e")
+ hasheq(cryptohash.sha512("h")[:], \
+ "2241bc8fc70705b42efead371fd4982c5ba69917e5b4b895810002644f0386da9c3131793458c2bf47608480d64a07278133c99912e0ba2daf23098f3520eb97")
+ /* 64 byte block */
+ hasheq(cryptohash.sha512("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")[:], \
+ "01d35c10c6c38c2dcf48f7eebb3235fb5ad74a65ec4cd016e2354c637a8fb49b695ef3c1d6f7ae4cd74d78cc9c9bcac9d4f23a73019998a7f73038a5c9b2dbde")
+ /* tail spanning */
+ hasheq(cryptohash.sha512("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbb")[:], \
+ "d5c989d2e41299b6bfd57562b4b09cd2efa56f13c8fa109e0ce5ddbd6bfb5b34f8563608d6162104bef750023732581f22704d5df43feecbb05742be1d7c34fa")
+}
+
diff --git a/lib/cryptohash/test/util.myr b/lib/cryptohash/test/util.myr
new file mode 100644
index 0000000..ceb411c
--- /dev/null
+++ b/lib/cryptohash/test/util.myr
@@ -0,0 +1,19 @@
+use std
+
+pkg =
+ const hasheq : (got : byte[:], expected : byte[:] -> void)
+;;
+
+const hasheq = {got, expected
+ var sb, str
+
+ sb = std.mksb()
+ for x in got
+ std.sbfmt(sb, "{p=0,w=2,x}", x)
+ ;;
+ str = std.sbfin(sb)
+ if (!std.sleq(str, expected))
+ std.fatal("mismatched hashes:\n\tgot:\t{}\n\texpected:\t{}\n", str, expected)
+ ;;
+ std.slfree(str)
+}
diff --git a/lib/regex/bld.sub b/lib/regex/bld.sub
new file mode 100644
index 0000000..0078d09
--- /dev/null
+++ b/lib/regex/bld.sub
@@ -0,0 +1,21 @@
+lib regex =
+ compile.myr
+ interp.myr
+ ranges.myr
+ types.myr
+
+ lib ../std:std
+;;
+
+bin redump {noinst} =
+ redump.myr
+ lib ../std:std
+ lib ../bio:bio
+ lib regex
+;;
+
+gen ranges.myr {durable} =
+ mkchartab -a -p_ranges UnicodeData.txt -o ranges.myr
+;;
+
+sub = test ;;
diff --git a/lib/regex/compile.myr b/lib/regex/compile.myr
new file mode 100644
index 0000000..28d7ce8
--- /dev/null
+++ b/lib/regex/compile.myr
@@ -0,0 +1,848 @@
+use std
+
+use "types.use"
+use "ranges.use"
+
+pkg regex =
+ const parse : (re : byte[:] -> std.result(ast#, status))
+ const compile : (re : byte[:] -> std.result(regex#, status))
+ const dbgcompile : (re : byte[:] -> std.result(regex#, status))
+ const free : (re : regex# -> void)
+ const failmsg : (st : status -> byte[:])
+;;
+
+type parseresult = union
+ `Some ast#
+ `None
+ `Fail status
+;;
+
+/* Compiles a pattern into a regex */
+const compile = {pat
+ -> regexcompile(std.mk([.pat = pat, .nmatch = 1]), 0)
+}
+
+const parse = {pat
+ var re
+
+ re = std.mk([.pat = pat, .nmatch = 1])
+ match regexparse(re)
+ | `None: -> `std.Fail `Incomplete
+ | `Fail f: -> `std.Fail f
+ | `Some t:
+ if re.pat.len > 0
+ -> `std.Fail `Incomplete
+ else
+ -> `std.Ok t
+ ;;
+ ;;
+}
+
+/* Compiles a pattern into a debug regex. This can be verbose. */
+const dbgcompile = {pat
+ var re
+
+ re = std.mk([.pat = pat, .nmatch = 1, .debug = true])
+ -> regexcompile(re, 0)
+}
+
+/* compiles a pattern into an allocated regex */
+const regexcompile = {re, id
+ match regexparse(re)
+ | `None: -> `std.Fail (`Incomplete)
+ | `Fail f: -> `std.Fail f
+ | `Some t:
+ /*
+ we can stop early if we get
+ an incorrectly encoded char
+ */
+ if re.pat.len > 0
+ astfree(t)
+ -> `std.Fail (`Incomplete)
+ ;;
+ dump(re, t, 0)
+ append(re, `Ilbra 0)
+ gen(re, t)
+ append(re, `Irbra 0)
+ append(re, `Imatch id)
+ idump(re)
+ astfree(t)
+ -> `std.Ok re
+ ;;
+ -> `std.Fail (`Noimpl)
+}
+
+const free = {re
+ /* all the threads should be dead,
+ so we shouldn't have to free any*/
+ std.slfree(re.prog)
+ std.free(re)
+}
+
+
+/* generates bytecode from an AST */
+const gen = {re, t
+ match t#
+ |`Alt (a, b): genalt(re, a, b)
+ |`Cat (a, b): gen(re, a); gen(re, b)
+ /* repetition */
+ |`Star a: genstar(re, a, false)
+ |`Rstar a: genstar(re, a, true)
+ |`Plus a: gen(re, a); genstar(re, a, false)
+ |`Rplus a: gen(re, a); genstar(re, a, true)
+ |`Quest a: genquest(re, a)
+
+ /* end matches */
+ |`Chr c: genchar(re, c)
+ |`Ranges sl: genranges(re, sl)
+
+ /* meta */
+ |`Bol: append(re, `Ibol)
+ |`Eol: append(re, `Ibol)
+ |`Bow: append(re, `Ibow)
+ |`Eow: append(re, `Ieow)
+ |`Cap (m, a):
+ append(re, `Ilbra m)
+ gen(re, a)
+ append(re, `Irbra m)
+ ;;
+ -> re.proglen
+}
+
+const genranges = {re, sl
+ var lbuf : byte[4], hbuf : byte[4], boundbuf : byte[4]
+ var lsz, hsz, bsz, i
+ var rt : rangetrie#
+
+ /* generate a trie of ranges */
+ rt = std.zalloc()
+ for r in sl
+ /*
+ encode:
+ lo => bounds[loidx] - 1
+ bounds[loidx] => bounds[loidx + 1] - 1
+ ...
+ bounds[hiidx - 1] => hi
+ */
+ lsz = std.encode(lbuf[:], r[0])
+ hsz = std.encode(hbuf[:], r[1])
+ for i = lsz; i < hsz; i++
+ bsz = bound(boundbuf[:], i, 0xff)
+ rtinsert(rt, lbuf[:lsz], boundbuf[:bsz])
+ lsz = bound(lbuf[:], i + 1, 0x00)
+ ;;
+ rtinsert(rt, lbuf[:lsz], hbuf[:hsz])
+ ;;
+ if re.debug
+ rtdump(rt, 0)
+ ;;
+ rangegen(re, rt, rt.ranges, rt.link, rangeprogsize(rt) + re.proglen)
+ rtfree(rt)
+ -> re.proglen
+}
+
+const bound = {buf, len, fill
+ var i, s
+
+ if len == 1
+ buf[0] = 0x7f
+ else
+ s = len castto(byte)
+ buf[0] = (0xff << (8 - s)) | (fill >> (s + 1))
+ for i = 1; i < len; i++
+ buf[i] = 0x80 | (fill >> 2)
+ ;;
+ ;;
+ -> len
+}
+
+type rangetrie = struct
+ ranges : (byte, byte)[:]
+ link : rangetrie#[:]
+ end : bool
+;;
+
+const rtdump = {rt, ind
+ var i
+ var l, h
+
+ indent(ind)
+ std.put("Range (end = {}) {{\n", rt.end)
+ for i = 0; i < rt.ranges.len; i++
+ indent(ind + 1)
+ (l, h) = rt.ranges[i]
+ std.put("0x{x}-0x{x}: \n", l, h)
+ rtdump(rt.link[i], ind + 1)
+ ;;
+ indent(ind)
+ std.put("}\n")
+}
+
+const indent = {ind
+ var i
+ for i = 0; i < ind; i++
+ std.put("\t")
+ ;;
+}
+
+const rtinsert = {rt, lo, hi
+ var a, b
+ var n
+
+ std.assert(lo.len == hi.len, "range sizes differ")
+ if lo.len == 0
+ rt.end = true
+ ->
+ ;;
+
+ n = rt.ranges.len
+ if n == 0
+ rt.ranges = std.slpush(rt.ranges, (lo[0], hi[0]))
+ rt.link = std.slpush(rt.link, std.zalloc())
+ else
+ /*
+ this is a safe way to compare because we know that ranges
+ should always be coming in ordered. This means that equal
+ values will be added one after the other.
+ */
+ (a, b) = rt.ranges[n - 1]
+ if a != lo[0] || b != hi[0]
+ rt.ranges = std.slpush(rt.ranges, (lo[0], hi[0]))
+ rt.link = std.slpush(rt.link, std.zalloc())
+ ;;
+ ;;
+
+ rtinsert(rt.link[rt.link.len - 1], lo[1:], hi[1:])
+}
+
+const rtfree = {rt
+ for l in rt.link
+ rtfree(l)
+ ;;
+ std.slfree(rt.link)
+ std.slfree(rt.ranges)
+ std.free(rt)
+}
+
+const rangegen = {re, rt, ranges, links, end
+ var alt, l0, l1, l2
+ var a, b
+ var n
+
+ n = ranges.len
+ if n == 0
+ -> re.proglen
+ elif n == 1
+ (a, b) = ranges[0]
+ append(re, `Irange (a, b))
+ if links[0].end
+ if links[0].ranges.len > 0
+ append(re, `Ifork (re.prog.len + 1, end))
+ else
+ append(re, `Ijmp end)
+ ;;
+ ;;
+ rangegen(re, links[0], links[0].ranges, links[0].link, end)
+ else
+ alt = re.proglen
+ l0 = append(re, `Ifork (-1, -1))
+ l1 = rangegen(re, rt, ranges[0:n/2], links[0:n/2], end)
+ l2 = rangegen(re, rt, ranges[n/2:n], links[n/2:n], end)
+ re.prog[alt] = `Ifork (l0, l1)
+ ;;
+ -> re.proglen
+}
+
+const rangeprogsize = {rt
+ var sz
+
+ if rt.ranges.len == 0
+ sz = 0
+ else
+ sz = 2*rt.ranges.len - 1
+ for l in rt.link
+ sz += rangeprogsize(l)
+ ;;
+ ;;
+ if rt.end
+ sz += 1
+ ;;
+ -> sz
+}
+
+/* calculates the forward jump distance for a utf8 character range */
+const jmpdist = {n
+ var d
+ var i
+
+ d = n - 1
+ for i = n - 1; i > 0; i--
+ d += i
+ ;;
+ -> d
+}
+
+/* generates an alternation */
+const genalt = {re, l, r
+ var alt
+ var jmp
+ var l0
+ var l1
+ var l2
+
+ alt = re.proglen
+ l0 = append(re, `Ifork (-1, -1)) /* needs to be replaced */
+ gen(re, l)
+ jmp = re.proglen
+ l1 = append(re, `Ijmp -1) /* needs to be replaced */
+ l2 = gen(re, r)
+
+ re.prog[alt] = `Ifork(l0, l1)
+ re.prog[jmp] = `Ijmp l2
+ -> re.proglen
+}
+
+/* generates a repetition operator */
+const genstar = {re, rep, reluct
+ var alt
+ var jmp
+ var l0
+ var l1
+ var l2
+
+ l0 = re.proglen
+ alt = re.proglen
+ l1 = append(re, `Ifork (-1, -1)) /* needs to be replaced */
+ jmp = gen(re, rep)
+ l2 = append(re, `Ijmp -1)
+
+
+ /* reluctant matches should prefer jumping to the end. */
+ if reluct
+ re.prog[alt] = `Ifork (l2, l1)
+ else
+ re.prog[alt] = `Ifork (l1, l2)
+ ;;
+ re.prog[jmp] = `Ijmp l0
+ -> re.proglen
+}
+
+/* generates a question mark operator */
+const genquest = {re, q
+ var alt
+ var l0
+ var l1
+
+ alt = re.proglen
+ l0 = append(re, `Ifork (-1, -1)) /* needs to be replaced */
+ l1 = gen(re, q)
+ re.prog[alt] = `Ifork (l0, l1)
+ -> re.proglen
+}
+
+/* generates a single char match */
+const genchar = {re, c
+ var b : byte[4]
+ var n
+ var i
+
+ n = std.encode(b[:], c)
+ std.assert(n > 0 && n < 4, "non-utf character in regex\n")
+ for i = 0; i < n; i++
+ append(re, `Ibyte b[i])
+ ;;
+ -> re.proglen
+}
+
+/* appends an instructon to an re program */
+const append = {re, insn
+ if re.proglen == re.prog.len
+ re.prog = std.slgrow(re.prog, std.max(1, 2*re.proglen))
+ ;;
+ re.prog[re.proglen] = insn
+ re.proglen++
+ -> re.proglen
+}
+
+/* instruction dump */
+const idump = {re
+ var i
+
+ if !re.debug
+ ->
+ ;;
+ for i = 0; i < re.proglen; i++
+ std.put("{}:\t", i)
+ match re.prog[i]
+ /* Char matching. Consume exactly one byte from the string. */
+ | `Ibyte b: std.put("`Ibyte {} ({})\n", b, b castto(char))
+ | `Irange (start, end):
+ std.put("`Irange ({},{})", start, end)
+ if std.isalnum(start castto(char)) && std.isalnum(end castto(char))
+ std.put("\t/* {}-{} */", start castto(char), end castto(char))
+ ;;
+ std.put("\n")
+ /* capture groups */
+ | `Ilbra m: std.put("`Ilbra {}\n", m)
+ | `Irbra m: std.put("`Irbra {}\n", m)
+ /* anchors */
+ | `Ibol: std.put("`Ibol\n")
+ | `Ieol: std.put("`Ieol\n")
+ | `Ibow: std.put("`Ibow\n")
+ | `Ieow: std.put("`Ieow\n")
+ /* control flow */
+ | `Ifork (lip, rip): std.put("`Ifork ({},{})\n", lip, rip)
+ | `Ijmp ip: std.put("`Ijmp {}\n", ip)
+ | `Imatch id: std.put("`Imatch {}\n", id)
+ ;;
+ ;;
+}
+
+/* AST dump */
+const dump = {re, t, indent
+ var i
+
+ if !re.debug
+ ->
+ ;;
+ for i = 0; i < indent; i++
+ std.put(" ")
+ ;;
+ match t#
+ | `Alt (a, b):
+ std.put("Alt\n")
+ dump(re, a, indent + 1)
+ dump(re, b, indent + 1)
+ | `Cat (a, b):
+ std.put("Cat\n")
+ dump(re, a, indent + 1)
+ dump(re, b, indent + 1)
+ /* repetition */
+ | `Star a:
+ std.put("Star\n")
+ dump(re, a, indent + 1)
+ | `Rstar a:
+ std.put("Rstar\n")
+ dump(re, a, indent + 1)
+ | `Plus a:
+ std.put("Plus\n")
+ dump(re, a, indent + 1)
+ | `Rplus a:
+ std.put("Rplus\n")
+ dump(re, a, indent + 1)
+ | `Quest a:
+ std.put("Quest\n")
+ dump(re, a, indent + 1)
+ | `Bol:
+ std.put("Bol\n")
+ | `Eol:
+ std.put("Eol\n")
+ | `Bow:
+ std.put("Bow\n")
+ | `Eow:
+ std.put("Eow\n")
+ /* end matches */
+ | `Chr c:
+ std.put("Char {}\n", c)
+ | `Ranges rl:
+ std.put("Ranges")
+ for r in rl
+ for i = 0; i < indent + 1; i++
+ std.put(" ")
+ ;;
+ std.put("\t({}-{})\n", r[0], r[1])
+ ;;
+
+ /* meta */
+ | `Cap (m, a):
+ std.put("Cap {}\n", m)
+ dump(re, a, indent + 1)
+ ;;
+}
+
+/* parses an expression */
+const regexparse = {re
+ match altexpr(re)
+ | `Some t:
+ if re.pat.len == 0
+ -> `Some t
+ else
+ astfree(t)
+ -> `Fail `Incomplete
+ ;;
+ | `None:
+ -> `None
+ | `Fail st:
+ -> `Fail st
+ ;;
+}
+
+const altexpr = {re
+ var ret
+
+ match catexpr(re)
+ | `Some t:
+ ret = t
+ if matchc(re, '|')
+ match altexpr(re)
+ | `Some rhs:
+ ret = mk(`Alt (ret, rhs))
+ | `None:
+ astfree(ret)
+ -> `Fail (`Incomplete)
+ | `Fail f:
+ -> `Fail f
+ ;;
+ ;;
+ | other:
+ -> other
+ ;;
+ -> `Some ret
+}
+
+const catexpr = {re
+ var ret
+
+ match repexpr(re)
+ | `Some t:
+ ret = t
+ match catexpr(re)
+ | `Some rhs:
+ ret = mk(`Cat (t, rhs))
+ | `Fail f: -> `Fail f
+ | `None: /* nothing */
+ ;;
+ | other:
+ -> other
+ ;;
+ -> `Some ret
+}
+
+const repexpr = {re
+ var ret
+
+ match baseexpr(re)
+ | `Some t:
+ if matchc(re, '*')
+ if matchc(re, '?')
+ ret = mk(`Rstar t)
+ else
+ ret = mk(`Star t)
+ ;;
+ elif matchc(re, '+')
+ if matchc(re, '?')
+ ret = mk(`Rplus t)
+ else
+ ret = mk(`Plus t)
+ ;;
+ elif matchc(re, '?')
+ ret = mk(`Quest t)
+ else
+ ret = t
+ ;;
+ | other:
+ -> other
+ ;;
+ -> `Some ret
+}
+
+const baseexpr = {re
+ var ret, m
+
+ if re.pat.len == 0
+ -> `None
+ ;;
+ match peekc(re)
+ /* lower prec operators */
+ | '|': -> `None
+ | ')': -> `None
+ | '*': -> `Fail `Badrep
+ | '+': -> `Fail `Badrep
+ | '?': -> `Fail `Badrep
+ | '[': -> chrclass(re)
+ | '.': getc(re); ret = mk(`Ranges std.slpush([][:], [0, std.Maxcharval]))
+ | '^': getc(re); ret = mk(`Bol)
+ | '$': getc(re); ret = mk(`Eol)
+ | '(':
+ m = re.nmatch++
+ getc(re)
+ match altexpr(re)
+ | `Some s:
+ if matchc(re, ')')
+ -> `Some mk(`Cap (m, s))
+ else
+ -> `Fail `Unbalanced
+ ;;
+ | `None: -> `Fail `Emptyparen
+ | `Fail st: -> `Fail st
+ ;;
+ | '\\':
+ getc(re) /* consume the slash */
+ if re.pat.len == 0
+ -> `Fail `Incomplete
+ ;;
+ -> escaped(re)
+ | c:
+ getc(re)
+ ret = mk(`Chr c)
+ ;;
+ -> `Some ret
+}
+
+const escaped = {re
+ var ret
+
+ match getc(re)
+ /* character classes */
+ | 'd': ret = `Some mk(`Ranges std.sldup(_ranges.tabasciidigit[:]))
+ | 'x': ret = `Some mk(`Ranges std.sldup(_ranges.tabasciixdigit[:]))
+ | 's': ret = `Some mk(`Ranges std.sldup(_ranges.tabasciispace[:]))
+ | 'w': ret = `Some mk(`Ranges std.sldup(_ranges.tabasciiword[:]))
+ | 'h': ret = `Some mk(`Ranges std.sldup(_ranges.tabasciiblank[:]))
+
+ /* negated character classes */
+ | 'W': ret = `Some mk(`Ranges negate(_ranges.tabasciiword[:]))
+ | 'S': ret = `Some mk(`Ranges negate(_ranges.tabasciispace[:]))
+ | 'D': ret = `Some mk(`Ranges negate(_ranges.tabasciidigit[:]))
+ | 'X': ret = `Some mk(`Ranges negate(_ranges.tabasciixdigit[:]))
+ | 'H': ret = `Some mk(`Ranges negate(_ranges.tabasciiblank[:]))
+
+ /* unicode character classes */
+ | 'p': ret = unicodeclass(re, false)
+ | 'P': ret = unicodeclass(re, true)
+
+ /* operators that need an escape */
+ | '<': ret = `Some mk(`Bow)
+ | '>': ret = `Some mk(`Eow)
+
+ /* escaped metachars */
+ | '^': ret = `Some mk(`Chr '^')
+ | '$': ret = `Some mk(`Chr '$')
+ | '.': ret = `Some mk(`Chr '.')
+ | '+': ret = `Some mk(`Chr '+')
+ | '?': ret = `Some mk(`Chr '?')
+ | chr: ret = `Fail `Badescape
+ ;;
+ -> ret
+}
+
+const unicodeclass = {re, neg
+ var c, s
+ var tab
+ var t
+ var n
+
+ if re.pat.len == 0
+ -> `Fail (`Incomplete)
+ ;;
+ n = 0
+ s = re.pat
+ /* either a single char pattern, or {pat} */
+ match getc(re)
+ | '{':
+ s = s[1:]
+ while re.pat.len > 0
+ c = getc(re)
+ if c == '}'
+ break
+ ;;
+ n += std.charlen(c)
+ ;;
+ | r:
+ n += std.charlen(r)
+ ;;
+ s = s[:n]
+ /* letters */
+ if std.sleq(s, "L") || std.sleq(s, "Letter")
+ tab = _ranges.tabalpha[:]
+ elif std.sleq(s, "Lu") || std.sleq(s, "Uppercase_Letter")
+ tab = _ranges.tabupper[:]
+ elif std.sleq(s, "Ll") || std.sleq(s, "Lowercase_Letter")
+ tab = _ranges.tablower[:]
+ elif std.sleq(s, "Lt") || std.sleq(s, "Titlecase_Letter")
+ tab = _ranges.tablower[:]
+ /* numbers (incomplete) */
+ elif std.sleq(s, "N") || std.sleq(s, "Number")
+ tab = _ranges.tabdigit[:]
+ elif std.sleq(s, "Z") || std.sleq(s, "Separator")
+ tab = _ranges.tabspace[:]
+ elif std.sleq(s, "Zs") || std.sleq(s, "Space_Separator")
+ tab = _ranges.tabblank[:]
+ else
+ -> `Fail (`Badrange)
+ ;;
+ if !neg
+ t = mk(`Ranges std.sldup(tab))
+ else
+ t = mk(`Ranges negate(tab))
+ ;;
+ -> `Some t
+}
+
+const chrclass = {re
+ var rl, m, n
+ var neg
+ var t
+
+ /* we know we saw '[' on entry */
+ matchc(re, '[')
+ neg = false
+ if matchc(re, '^')
+ neg = true
+ ;;
+ rl = rangematch(re, [][:])
+ while peekc(re) != ']' && re.pat.len > 0
+ rl = rangematch(re, rl)
+ ;;
+ if !matchc(re, ']')
+ std.slfree(rl)
+ -> `Fail `Unbalanced
+ ;;
+
+ std.sort(rl, {a, b;
+ if a[0] < b[0]
+ -> `std.Before
+ elif a[0] == b[0]
+ -> `std.Equal
+ else
+ -> `std.After
+ ;;})
+ m = merge(rl)
+ std.slfree(rl)
+ if neg
+ n = negate(m)
+ std.slfree(m)
+ t = mk(`Ranges n)
+ else
+ t = mk(`Ranges m)
+ ;;
+ -> `Some t
+}
+
+const rangematch = {re, sl
+ var lo
+ var hi
+
+ lo = getc(re)
+ if matchc(re, '-')
+ hi = getc(re)
+ if lo <= hi
+ -> std.slpush(sl, [lo, hi])
+ else
+ -> std.slpush(sl, [hi, lo])
+ ;;
+ else
+ -> std.slpush(sl, [lo, lo])
+ ;;
+}
+
+const negate = {rng
+ var start, end, next
+ var neg
+
+ neg = [][:]
+ start = 0
+ next = 0 /* if we have no ranges */
+ for r in rng
+ (end, next) = (r[0], r[1])
+ neg = std.slpush(neg, [start, end - 1])
+ start = next + 1
+ ;;
+ neg = std.slpush(neg, [next + 1, std.Maxcharval])
+ -> neg
+}
+
+/* rl is a sorted list of ranges */
+const merge = {rl
+ var lo, hi
+ var ret
+
+ if rl.len == 0
+ -> [][:]
+ ;;
+ ret = [][:]
+ lo = rl[0][0]
+ hi = rl[0][1]
+ for r in rl[1:]
+ /* if it overlaps or abuts, merge */
+ if r[0] <= hi + 1
+ hi = r[1]
+ else
+ ret = std.slpush(ret, [lo, hi])
+ lo = r[0]
+ hi = r[1]
+ ;;
+ ;;
+ -> std.slpush(ret, [lo, hi])
+}
+
+
+const matchc = {re, c
+ var str
+ var chr
+
+ (chr, str) = std.striter(re.pat)
+ if chr != c
+ -> false
+ ;;
+ re.pat = str
+ -> true
+}
+
+const getc = {re
+ var c
+
+ (c, re.pat) = std.striter(re.pat)
+ -> c
+}
+
+const peekc = {re
+ var c
+
+ (c, _) = std.striter(re.pat)
+ -> c
+}
+
+const mk = {v
+ var t
+
+ t = std.alloc()
+ t# = v
+ -> t
+}
+
+const astfree = {t
+ match t#
+ | `Alt (a, b): astfree(a); astfree(b)
+ | `Cat (a, b): astfree(a); astfree(b)
+ /* repetition */
+ | `Star a: astfree(a)
+ | `Rstar a: astfree(a)
+ | `Plus a: astfree(a)
+ | `Rplus a: astfree(a)
+ | `Quest a: astfree(a)
+
+ /* end matches */
+ | `Chr c:
+ | `Ranges rl: std.slfree(rl)
+
+ /* meta */
+ | `Cap (m, a): astfree(a)
+ | _: /* other types have no suballocations */
+ ;;
+ std.free(t)
+}
+
+const failmsg = {st
+ match st
+ | `Noimpl: -> "no implementation"
+ | `Incomplete: -> "regex ended before input fully parsed"
+ | `Unbalanced: -> "unbalanced bracket"
+ | `Emptyparen: -> "empty parentheses"
+ | `Badrep: -> "invalid repetition"
+ | `Badrange: -> "invalid range"
+ | `Badescape: -> "invalid escape code"
+
+ ;;
+}
+
diff --git a/lib/regex/configure b/lib/regex/configure
new file mode 100755
index 0000000..37fe623
--- /dev/null
+++ b/lib/regex/configure
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+prefix="/usr/local"
+
+for i in `seq 300`; do
+ echo "Lots of output to emulate automake... ok"
+ echo "Testing for things you'll never use... fail"
+ echo "Satisfying the fortran77 lobby... ok"
+ echo "Burning CPU time checking for the bloody obvious... ok"
+done
+echo "Automake emulated successfully"
+
+INST_ROOT='/usr/local'
+
+for arg in $*; do
+ shift 1
+ case $arg in
+ "--prefix" | "-p")
+ prefix=shift $*
+ ;;
+ --prefix=*)
+ prefix=`echo $arg | sed 's/^--prefix=//g'`
+ ;;
+ "--help" | "-h")
+ echo "Usage:"
+ echo " --prefix | -p: The prefix to install to"
+ break;
+ ;;
+ *) echo "Unrecognized argument $arg";;
+ esac
+done
+
+OS=`uname`
+
+echo export INST_ROOT=$prefix > config.mk
+case $OS in
+ *Linux*)
+ echo 'export SYS=linux' >> config.mk
+ ;;
+ *Darwin*)
+ echo 'export SYS=osx' >> config.mk
+ ;;
+ *)
+ echo 'Unknown architecture.'
+ ;;
+esac
+
+cat << EOF
+ Building with:
+ prefix=$prefix
+EOF
+
diff --git a/lib/regex/doc/Makefile b/lib/regex/doc/Makefile
new file mode 100644
index 0000000..c1749d3
--- /dev/null
+++ b/lib/regex/doc/Makefile
@@ -0,0 +1,5 @@
+MAN=myr-regex.3 \
+
+include ../config.mk
+include ../mk/myr.mk
+
diff --git a/lib/regex/doc/myr-regex.3 b/lib/regex/doc/myr-regex.3
new file mode 100644
index 0000000..c0d0da0
--- /dev/null
+++ b/lib/regex/doc/myr-regex.3
@@ -0,0 +1,198 @@
+.TH MYR REGEX 1
+.SH NAME
+regex myr-regex
+.SH LIBRARY
+regex
+.SH SYNOPSIS
+.B use regex
+.I const compile : (re : byte[:] -> std.error(regex#, status))
+.I const dbgcompile : (re : byte[:] -> std.error(regex#, status))
+.I const free : (re : regex# -> void)
+.br
+.I const exec : (re : regex#, str : byte[:] -> bool)
+.I const search : (re : regex#, str : byte[:] -> bool)
+.SH DESCRIPTION
+.PP
+The regex library provides functions for compiling and evaluating regular
+expressions, as described later in this document, or in myr-regex(7).
+.PP
+.I regex.compile will take a string describing a regex, and will attempt
+to compile it, returing
+.I `std.Success regex#
+if the regex is valid, and there were no error conditions encountered during
+compilation. If the compilation failed,
+.I `std.Failure regex.status
+will be returned, where regex.status is a failure code.
+
+.PP
+.I regex.dbgcompile
+is identical to
+.I regex.compile,
+however, it will print debugging information as it compiles, and each
+time the regex is evaluated.
+
+.PP
+.I regex.exec
+will take the regex passed to it, and evaluate it over the text provided,
+returning the
+.I `std.Some matches,
+or
+.I `std.None
+if there were no matches found. The matches must span the whole string.
+
+.PP
+.I regex.search
+is similar to regex.exec, but it will attempt to find a match somewhere
+within the string, instead of attempting to find a match spanning the whole
+string.
+
+.SH REGEX SYNTAX
+.PP
+The grammar used by libregex is below:
+
+.EX
+ regex : altexpr
+ altexpr : catexpr ('|' altexpr)+
+ catexpr : repexpr (catexpr)+
+ repexpr : baseexpr[*+?]
+ baseexpr : literal
+ | charclass
+ | charrange
+ | escaped
+ | '.'
+ | '^'
+ | '$'
+ | '(' regex ')'
+ charclass : see below
+ charrange : '[' (literal('-' literal)?)+']'
+.EE
+
+The following metacharacters have the meanings listed below:
+.TP
+.
+Matches a single unicode character
+.TP
+^
+Matches the beginning of a line. Does not consume any characters.
+.TP
+$
+Matches the end of a line. Does not consume any characters.
+.TP
+*
+Matches any number of repetitions of the preceding regex fragment.
+.TP
+*?
+Reluctantly matches any number of repetitions of the preceding regex fragment.
+.TP
++
+Matches one or more repetitions of the preceding regex fragment.
+.TP
++?
+Reluctantly matches one or more repetitions of the preceding regex fragment.
+.TP
+?
+Matches zero or one of the preceding regex fragment.
+
+.PP
+In order to match a literal metacharacter, it needs to be preceded by
+a '\\' character.
+
+The following character classes are supported:
+.TP
+\\d
+ASCII digits
+.TP
+\\D
+Negation of ASCII digits
+.TP
+\\x
+ASCII Hex digits
+.TP
+\\X
+Negation of ASCII Hex digits
+.TP
+\\s
+ASCII spaces
+.TP
+\\S
+Negation of ASCII spaces
+.TP
+\\w
+ASCII word characters
+.TP
+\\W
+Negation of ASCII word characters
+.TP
+\\h
+ASCII whitespace characters
+.TP
+\\H
+Negation of ASCII whitespace characters
+.TP
+\\pX, \\p{X}
+Characters with unicode property 'X'
+.TP
+\\PX, \\P{X}
+Negation of characters with unicode property 'X'
+
+.PP
+Unicode properties that are supported are listed below:
+
+.TP
+L, Letter
+Unicode letter property
+.TP
+Lu, Uppercase_Letter
+Uppercase letter unicode property
+.TP
+Ll, Lowercase_Letter
+Lowercase letter unicode property
+.TP
+Lt, Titlecase_Letter
+Titlecase letter unicode property
+.TP
+N, Number
+Number unicode property
+.TP
+Z, Separator
+Any separator character unicode property
+.TP
+Zs, Space_Separator
+Space separator unicode property
+
+
+.SH EXAMPLE
+.EX
+ use std
+ use regex
+
+ const main = {
+ match regex.compile(pat)
+ var i
+ | `std.Success re:
+ match regex.exec(re, text)
+ | `std.Some matches:
+ for i = 0; i < matches.len; i++
+ std.put("Match %i: %s\n", i, match[i])
+ ;;
+ | `std.None: std.put("Text did not match\n")
+ ;;
+ | `std.Failure err:
+ std.put("failed to compile regex")
+ ;;
+ }
+.EE
+
+.SH FILES
+The source code for this compiler is available from
+.B git://git.eigenstate.org/git/ori/libregex.git
+
+.SH SEE ALSO
+.IR mc(1)
+
+.SH BUGS
+.PP
+This code is insufficiently tested.
+
+.PP
+This code does not support all of the regex features that one would expect.
diff --git a/lib/regex/interp.myr b/lib/regex/interp.myr
new file mode 100644
index 0000000..fc179c0
--- /dev/null
+++ b/lib/regex/interp.myr
@@ -0,0 +1,311 @@
+use std
+
+use "types.use"
+
+pkg regex =
+ const exec : (re : regex#, str : byte[:] -> std.option(byte[:][:]))
+ /*
+ FIXME: implement. This should scan for a possible start char in the
+ regex and use that to optimize.
+ const search : (re : regex#, str : byte[:] -> std.option(byte[:][:]))
+ */
+;;
+
+/* Ugly: for performance. std.option() should be used instead when unions get faster. */
+const Zthr = 0 castto(rethread#)
+
+const exec = {re, str
+ var thr
+ var m
+
+ re.str = str
+ re.strp = 0
+ thr = run(re)
+ if thr != Zthr
+ m = getmatches(re, thr)
+ cleanup(re)
+ -> `std.Some m
+ else
+ cleanup(re)
+ -> `std.None
+ ;;
+}
+
+const cleanup = {re
+ var thr, next
+
+ for thr = re.runq; thr != Zthr; thr = next
+ next = thr.next
+ thrfree(re, thr)
+ ;;
+ for thr = re.expired; thr != Zthr; thr = next
+ next = thr.next
+ thrfree(re, thr)
+ ;;
+}
+
+const getmatches = {re, thr
+ var ret
+ var i
+
+ ret = std.slalloc(re.nmatch)
+ for i = 0; i < re.nmatch; i++
+ if thr.mstart[i] != -1 && thr.mend[i] != -1
+ ret[i] = re.str[thr.mstart[i]:thr.mend[i]]
+ else
+ ret[i] = [][:]
+ ;;
+ ;;
+ -> ret
+}
+
+
+/* returns a matching thread, or Zthr if no threads matched */
+const run = {re
+ var i, ip
+ var consumed
+ var thr
+ var states
+
+ states = std.mkbs()
+ re.runq = mkthread(re, 0)
+ re.runq.mstart = std.slalloc(re.nmatch)
+ re.runq.mend = std.slalloc(re.nmatch)
+ for i = 0; i < re.nmatch; i++
+ re.runq.mstart[i] = -1
+ re.runq.mend[i] = -1
+ ;;
+ while re.nthr > 0
+ while re.runq != Zthr
+ /* set up the next thread */
+ thr = re.runq
+ re.runq = thr.next
+
+ trace(re, thr, "\nrunning tid={}, ip={}, s[{}]={}\n", thr.tid, thr.ip, re.strp, std.decode(re.str[re.strp:]))
+ ip = thr.ip
+ consumed = step(re, thr, -1)
+ while !consumed
+ consumed = step(re, thr, ip)
+ ;;
+
+ if std.bshas(states, thr.ip)
+ die(re, thr, "there can be only one")
+ ;;
+
+ if thr.dead
+ thrfree(re, thr)
+ elif thr.matched && re.strp == re.str.len
+ -> thr
+ elif !thr.matched
+ std.bsput(states, thr.ip)
+ if re.expired == Zthr
+ re.expired = thr
+ ;;
+ if re.expiredtail != Zthr
+ re.expiredtail.next = thr
+ ;;
+ re.expiredtail = thr
+ thr.next = Zthr
+
+ ;;
+ ;;
+ std.bsclear(states)
+ trace(re, thr, "switch\n")
+ re.runq = re.expired
+ re.expired = Zthr
+ re.expiredtail = Zthr
+ re.strp++
+ ;;
+ -> Zthr
+}
+
+/*
+ Steps forward one instruction. Returns true if a byte of input was
+ consumed, false otherwise.
+*/
+const step = {re, thr, curip
+ var str
+ var mstart
+ var mend
+
+ str = re.str
+ match re.prog[thr.ip]
+ /* Char matching. Consume exactly one byte from the string. */
+ | `Ibyte b:
+ trace(re, thr, "\t{}:\tByte {} ({})\n", thr.ip, b, b castto(char))
+ if !within(re, str)
+ die(re, thr, "end of string")
+ elif b != str[re.strp]
+ die(re, thr, "not right char")
+ else
+ thr.ip++
+ trace(re, thr, "\t\tmatched {} with {}\n", b, str[re.strp])
+ ;;
+ | `Irange (start, end):
+ trace(re, thr, "\t{}:\tRange ({}, {}) /* {} - {} */\n", thr.ip, start, end, start castto(char), end castto(char))
+ if !within(re, str) || start > str[re.strp] || end < str[re.strp]
+ die(re, thr, "bad range")
+ else
+ thr.ip++
+ ;;
+ /*
+ Non-consuming. All of these return false, and expect step to be
+ called again until exactly one byte is consumed from the string.
+ */
+ | `Ibol:
+ trace(re, thr, "\t{}:\tBol\n", thr.ip)
+ if re.strp == 0 || str[re.strp - 1] == '\n' castto(byte)
+ thr.ip++
+ -> false
+ else
+ die(re, thr, "not beginning of line")
+ ;;
+ | `Ieol:
+ trace(re, thr, "\t{}:\tEol\n", thr.ip)
+ if re.strp == str.len || str[re.strp] == '\n' castto(byte)
+ thr.ip++
+ -> false
+ else
+ die(re, thr, "not end of line")
+ ;;
+ /* check for word characters */
+ | `Ibow:
+ trace(re, thr, "\t{}:\tBow\n", thr.ip)
+ if iswordchar(str[re.strp:]) && (re.strp == 0 || !iswordchar(prevchar(str, re.strp)))
+ thr.ip++
+ -> false
+ else
+ die(re, thr, "not beginning of word")
+ ;;
+ | `Ieow:
+ trace(re, thr, "\t{}:\tEow\n", thr.ip)
+ if re.strp == str.len && iswordchar(prevchar(str, re.strp))
+ thr.ip++
+ -> false
+ elif re.strp > 0 && !iswordchar(str[re.strp:]) && iswordchar(prevchar(str, re.strp))
+ thr.ip++
+ -> false
+ else
+ die(re, thr, "not end of word")
+ ;;
+ | `Ilbra m:
+ trace(re, thr, "\t{}:\tLbra {}\n", thr.ip, m)
+ trace(re, thr, "\t\tmatch start = {}\n", re.strp)
+ thr.mstart[m] = re.strp
+ thr.ip++
+ -> false
+ | `Irbra m:
+ trace(re, thr, "\t{}:\tRbra {}\n", thr.ip, m)
+ thr.mend[m] = re.strp
+ thr.ip++
+ -> false
+ | `Ifork (lip, rip):
+ trace(re, thr, "\t{}:\tFork ({}, {})\n", thr.ip, lip, rip)
+ mstart = std.sldup(thr.mstart)
+ mend = std.sldup(thr.mend)
+ fork(re, thr, rip, curip, mstart, mend)
+ thr.ip = lip
+ -> false
+ | `Ijmp ip:
+ trace(re, thr, "\t{}:\tJmp {}\n", thr.ip, ip)
+ thr.ip = ip
+ -> false
+ | `Imatch id:
+ trace(re, thr, "\t{}:\tMatch\n", thr.ip)
+ finish(re, thr)
+ -> true
+ ;;
+ -> true
+}
+
+const fork = {re, thr, ip, curip, mstart, mend
+ var thr
+
+ if ip == curip /* loop detection */
+ ->
+ ;;
+ thr = mkthread(re, ip)
+ thr.next = re.runq
+ thr.mstart = mstart
+ thr.mend = mend
+ re.runq = thr
+}
+
+const die = {re, thr, msg
+ /*
+ we can have die called on a thread
+ multiple times, eg, if it has a bad
+ range *and* end in a state that another
+ thread is in. We should only decrement
+ the number of threads for that once.
+ */
+ trace(re, thr, "\t\tdie {}: {}\n", thr.tid, msg)
+ if !thr.dead
+ re.nthr--
+ ;;
+ thr.dead = true
+}
+
+const finish = {re, thr
+ trace(re, thr, "finish {}\n", thr.tid)
+ thr.matched = true
+ re.nthr--
+}
+
+var nexttid = 0
+const mkthread = {re, ip
+ var thr : rethread#
+
+ thr = std.alloc()
+
+ thr.next = Zthr
+
+ thr.ip = ip
+ thr.tid = nexttid++
+ thr.dead = false
+ thr.matched = false
+
+ thr.mstart = [][:]
+ thr.mend = [][:]
+
+ re.nthr++
+
+ -> thr
+}
+
+const thrfree = {re, thr
+ trace(re, thr, "\t\tcleanup {}\n", thr.tid)
+ std.slfree(thr.mstart)
+ std.slfree(thr.mend)
+ std.free(thr)
+}
+
+const within = {re, str
+ -> re.strp < str.len
+}
+
+const trace : (re : regex#, thr : rethread#, msg : byte[:], args : ... -> void) = {re, thr, msg, args
+ var ap
+
+ if re.debug
+ ap = std.vastart(&args)
+ std.putv(msg, &ap)
+ ;;
+}
+
+/* must be called with i >= 1 */
+const prevchar = {s, i
+ std.assert(i != 0, "prevchar must be called with i >= 1\n")
+ i--
+ while i != 0 && s[i] >= 0x80
+ i--
+ ;;
+ -> s[i:]
+}
+
+const iswordchar = {s
+ var c
+
+ c = std.decode(s)
+ -> std.isalpha(c) || std.isdigit(c) || c == '_'
+}
diff --git a/lib/regex/ranges.myr b/lib/regex/ranges.myr
new file mode 100644
index 0000000..3efae43
--- /dev/null
+++ b/lib/regex/ranges.myr
@@ -0,0 +1,2386 @@
+/*
+ This set of unicode tables was automatically generated
+ by the following command:
+ mkchartab -a -p_ranges UnicodeData.txt -o ranges.myr
+ editing it manually is probably a waste of time.
+*/
+
+pkg _ranges =
+ const tabasciialpha
+ const tabasciiupper
+ const tabasciilower
+ const tabasciiword
+ const tabasciidigit
+ const tabasciixdigit
+ const tabasciispace
+ const tabasciiblank
+ const tabalpha
+ const tabupper
+ const tablower
+ const tabtitle
+ const tabword
+ const tabdigit
+ const tabxdigit
+ const tabspace
+ const tabblank
+;;
+const tabasciialpha = [
+ ['\u{41}','\u{5a}'],
+ ['\u{61}','\u{7a}'],
+]
+
+const tabasciiupper = [
+ ['\u{41}','\u{5a}'],
+]
+
+const tabasciilower = [
+ ['\u{61}','\u{7a}'],
+]
+
+const tabasciiword = [
+ ['\u{30}','\u{39}'],
+ ['\u{41}','\u{5a}'],
+ ['\u{5f}','\u{5f}'],
+ ['\u{61}','\u{7a}'],
+]
+
+const tabasciidigit = [
+ ['\u{30}','\u{39}'],
+]
+
+const tabasciixdigit = [
+ ['\u{30}','\u{39}'],
+ ['\u{41}','\u{46}'],
+ ['\u{61}','\u{66}'],
+]
+
+const tabasciispace = [
+ ['\u{9}','\u{d}'],
+ ['\u{20}','\u{20}'],
+]
+
+const tabasciiblank = [
+ ['\u{9}','\u{9}'],
+ ['\u{20}','\u{20}'],
+]
+
+const tabalpha = [
+ ['\u{41}','\u{5a}'],
+ ['\u{61}','\u{7a}'],
+ ['\u{aa}','\u{aa}'],
+ ['\u{b5}','\u{b5}'],
+ ['\u{ba}','\u{ba}'],
+ ['\u{c0}','\u{d6}'],
+ ['\u{d8}','\u{f6}'],
+ ['\u{f8}','\u{2c1}'],
+ ['\u{2c6}','\u{2d1}'],
+ ['\u{2e0}','\u{2e4}'],
+ ['\u{2ec}','\u{2ec}'],
+ ['\u{2ee}','\u{2ee}'],
+ ['\u{370}','\u{374}'],
+ ['\u{376}','\u{377}'],
+ ['\u{37a}','\u{37d}'],
+ ['\u{386}','\u{386}'],
+ ['\u{388}','\u{38a}'],
+ ['\u{38c}','\u{38c}'],
+ ['\u{38e}','\u{3a1}'],
+ ['\u{3a3}','\u{3f5}'],
+ ['\u{3f7}','\u{481}'],
+ ['\u{48a}','\u{527}'],
+ ['\u{531}','\u{556}'],
+ ['\u{559}','\u{559}'],
+ ['\u{561}','\u{587}'],
+ ['\u{5d0}','\u{5ea}'],
+ ['\u{5f0}','\u{5f2}'],
+ ['\u{620}','\u{64a}'],
+ ['\u{66e}','\u{66f}'],
+ ['\u{671}','\u{6d3}'],
+ ['\u{6d5}','\u{6d5}'],
+ ['\u{6e5}','\u{6e6}'],
+ ['\u{6ee}','\u{6ef}'],
+ ['\u{6fa}','\u{6fc}'],
+ ['\u{6ff}','\u{6ff}'],
+ ['\u{710}','\u{710}'],
+ ['\u{712}','\u{72f}'],
+ ['\u{74d}','\u{7a5}'],
+ ['\u{7b1}','\u{7b1}'],
+ ['\u{7ca}','\u{7ea}'],
+ ['\u{7f4}','\u{7f5}'],
+ ['\u{7fa}','\u{7fa}'],
+ ['\u{800}','\u{815}'],
+ ['\u{81a}','\u{81a}'],
+ ['\u{824}','\u{824}'],
+ ['\u{828}','\u{828}'],
+ ['\u{840}','\u{858}'],
+ ['\u{8a0}','\u{8a0}'],
+ ['\u{8a2}','\u{8ac}'],
+ ['\u{904}','\u{939}'],
+ ['\u{93d}','\u{93d}'],
+ ['\u{950}','\u{950}'],
+ ['\u{958}','\u{961}'],
+ ['\u{971}','\u{977}'],
+ ['\u{979}','\u{97f}'],
+ ['\u{985}','\u{98c}'],
+ ['\u{98f}','\u{990}'],
+ ['\u{993}','\u{9a8}'],
+ ['\u{9aa}','\u{9b0}'],
+ ['\u{9b2}','\u{9b2}'],
+ ['\u{9b6}','\u{9b9}'],
+ ['\u{9bd}','\u{9bd}'],
+ ['\u{9ce}','\u{9ce}'],
+ ['\u{9dc}','\u{9dd}'],
+ ['\u{9df}','\u{9e1}'],
+ ['\u{9f0}','\u{9f1}'],
+ ['\u{a05}','\u{a0a}'],
+ ['\u{a0f}','\u{a10}'],
+ ['\u{a13}','\u{a28}'],
+ ['\u{a2a}','\u{a30}'],
+ ['\u{a32}','\u{a33}'],
+ ['\u{a35}','\u{a36}'],
+ ['\u{a38}','\u{a39}'],
+ ['\u{a59}','\u{a5c}'],
+ ['\u{a5e}','\u{a5e}'],
+ ['\u{a72}','\u{a74}'],
+ ['\u{a85}','\u{a8d}'],
+ ['\u{a8f}','\u{a91}'],
+ ['\u{a93}','\u{aa8}'],
+ ['\u{aaa}','\u{ab0}'],
+ ['\u{ab2}','\u{ab3}'],
+ ['\u{ab5}','\u{ab9}'],
+ ['\u{abd}','\u{abd}'],
+ ['\u{ad0}','\u{ad0}'],
+ ['\u{ae0}','\u{ae1}'],
+ ['\u{b05}','\u{b0c}'],
+ ['\u{b0f}','\u{b10}'],
+ ['\u{b13}','\u{b28}'],
+ ['\u{b2a}','\u{b30}'],
+ ['\u{b32}','\u{b33}'],
+ ['\u{b35}','\u{b39}'],
+ ['\u{b3d}','\u{b3d}'],
+ ['\u{b5c}','\u{b5d}'],
+ ['\u{b5f}','\u{b61}'],
+ ['\u{b71}','\u{b71}'],
+ ['\u{b83}','\u{b83}'],
+ ['\u{b85}','\u{b8a}'],
+ ['\u{b8e}','\u{b90}'],
+ ['\u{b92}','\u{b95}'],
+ ['\u{b99}','\u{b9a}'],
+ ['\u{b9c}','\u{b9c}'],
+ ['\u{b9e}','\u{b9f}'],
+ ['\u{ba3}','\u{ba4}'],
+ ['\u{ba8}','\u{baa}'],
+ ['\u{bae}','\u{bb9}'],
+ ['\u{bd0}','\u{bd0}'],
+ ['\u{c05}','\u{c0c}'],
+ ['\u{c0e}','\u{c10}'],
+ ['\u{c12}','\u{c28}'],
+ ['\u{c2a}','\u{c33}'],
+ ['\u{c35}','\u{c39}'],
+ ['\u{c3d}','\u{c3d}'],
+ ['\u{c58}','\u{c59}'],
+ ['\u{c60}','\u{c61}'],
+ ['\u{c85}','\u{c8c}'],
+ ['\u{c8e}','\u{c90}'],
+ ['\u{c92}','\u{ca8}'],
+ ['\u{caa}','\u{cb3}'],
+ ['\u{cb5}','\u{cb9}'],
+ ['\u{cbd}','\u{cbd}'],
+ ['\u{cde}','\u{cde}'],
+ ['\u{ce0}','\u{ce1}'],
+ ['\u{cf1}','\u{cf2}'],
+ ['\u{d05}','\u{d0c}'],
+ ['\u{d0e}','\u{d10}'],
+ ['\u{d12}','\u{d3a}'],
+ ['\u{d3d}','\u{d3d}'],
+ ['\u{d4e}','\u{d4e}'],
+ ['\u{d60}','\u{d61}'],
+ ['\u{d7a}','\u{d7f}'],
+ ['\u{d85}','\u{d96}'],
+ ['\u{d9a}','\u{db1}'],
+ ['\u{db3}','\u{dbb}'],
+ ['\u{dbd}','\u{dbd}'],
+ ['\u{dc0}','\u{dc6}'],
+ ['\u{e01}','\u{e30}'],
+ ['\u{e32}','\u{e33}'],
+ ['\u{e40}','\u{e46}'],
+ ['\u{e81}','\u{e82}'],
+ ['\u{e84}','\u{e84}'],
+ ['\u{e87}','\u{e88}'],
+ ['\u{e8a}','\u{e8a}'],
+ ['\u{e8d}','\u{e8d}'],
+ ['\u{e94}','\u{e97}'],
+ ['\u{e99}','\u{e9f}'],
+ ['\u{ea1}','\u{ea3}'],
+ ['\u{ea5}','\u{ea5}'],
+ ['\u{ea7}','\u{ea7}'],
+ ['\u{eaa}','\u{eab}'],
+ ['\u{ead}','\u{eb0}'],
+ ['\u{eb2}','\u{eb3}'],
+ ['\u{ebd}','\u{ebd}'],
+ ['\u{ec0}','\u{ec4}'],
+ ['\u{ec6}','\u{ec6}'],
+ ['\u{edc}','\u{edf}'],
+ ['\u{f00}','\u{f00}'],
+ ['\u{f40}','\u{f47}'],
+ ['\u{f49}','\u{f6c}'],
+ ['\u{f88}','\u{f8c}'],
+ ['\u{1000}','\u{102a}'],
+ ['\u{103f}','\u{103f}'],
+ ['\u{1050}','\u{1055}'],
+ ['\u{105a}','\u{105d}'],
+ ['\u{1061}','\u{1061}'],
+ ['\u{1065}','\u{1066}'],
+ ['\u{106e}','\u{1070}'],
+ ['\u{1075}','\u{1081}'],
+ ['\u{108e}','\u{108e}'],
+ ['\u{10a0}','\u{10c5}'],
+ ['\u{10c7}','\u{10c7}'],
+ ['\u{10cd}','\u{10cd}'],
+ ['\u{10d0}','\u{10fa}'],
+ ['\u{10fc}','\u{1248}'],
+ ['\u{124a}','\u{124d}'],
+ ['\u{1250}','\u{1256}'],
+ ['\u{1258}','\u{1258}'],
+ ['\u{125a}','\u{125d}'],
+ ['\u{1260}','\u{1288}'],
+ ['\u{128a}','\u{128d}'],
+ ['\u{1290}','\u{12b0}'],
+ ['\u{12b2}','\u{12b5}'],
+ ['\u{12b8}','\u{12be}'],
+ ['\u{12c0}','\u{12c0}'],
+ ['\u{12c2}','\u{12c5}'],
+ ['\u{12c8}','\u{12d6}'],
+ ['\u{12d8}','\u{1310}'],
+ ['\u{1312}','\u{1315}'],
+ ['\u{1318}','\u{135a}'],
+ ['\u{1380}','\u{138f}'],
+ ['\u{13a0}','\u{13f4}'],
+ ['\u{1401}','\u{166c}'],
+ ['\u{166f}','\u{167f}'],
+ ['\u{1681}','\u{169a}'],
+ ['\u{16a0}','\u{16ea}'],
+ ['\u{1700}','\u{170c}'],
+ ['\u{170e}','\u{1711}'],
+ ['\u{1720}','\u{1731}'],
+ ['\u{1740}','\u{1751}'],
+ ['\u{1760}','\u{176c}'],
+ ['\u{176e}','\u{1770}'],
+ ['\u{1780}','\u{17b3}'],
+ ['\u{17d7}','\u{17d7}'],
+ ['\u{17dc}','\u{17dc}'],
+ ['\u{1820}','\u{1877}'],
+ ['\u{1880}','\u{18a8}'],
+ ['\u{18aa}','\u{18aa}'],
+ ['\u{18b0}','\u{18f5}'],
+ ['\u{1900}','\u{191c}'],
+ ['\u{1950}','\u{196d}'],
+ ['\u{1970}','\u{1974}'],
+ ['\u{1980}','\u{19ab}'],
+ ['\u{19c1}','\u{19c7}'],
+ ['\u{1a00}','\u{1a16}'],
+ ['\u{1a20}','\u{1a54}'],
+ ['\u{1aa7}','\u{1aa7}'],
+ ['\u{1b05}','\u{1b33}'],
+ ['\u{1b45}','\u{1b4b}'],
+ ['\u{1b83}','\u{1ba0}'],
+ ['\u{1bae}','\u{1baf}'],
+ ['\u{1bba}','\u{1be5}'],
+ ['\u{1c00}','\u{1c23}'],
+ ['\u{1c4d}','\u{1c4f}'],
+ ['\u{1c5a}','\u{1c7d}'],
+ ['\u{1ce9}','\u{1cec}'],
+ ['\u{1cee}','\u{1cf1}'],
+ ['\u{1cf5}','\u{1cf6}'],
+ ['\u{1d00}','\u{1dbf}'],
+ ['\u{1e00}','\u{1f15}'],
+ ['\u{1f18}','\u{1f1d}'],
+ ['\u{1f20}','\u{1f45}'],
+ ['\u{1f48}','\u{1f4d}'],
+ ['\u{1f50}','\u{1f57}'],
+ ['\u{1f59}','\u{1f59}'],
+ ['\u{1f5b}','\u{1f5b}'],
+ ['\u{1f5d}','\u{1f5d}'],
+ ['\u{1f5f}','\u{1f7d}'],
+ ['\u{1f80}','\u{1fb4}'],
+ ['\u{1fb6}','\u{1fbc}'],
+ ['\u{1fbe}','\u{1fbe}'],
+ ['\u{1fc2}','\u{1fc4}'],
+ ['\u{1fc6}','\u{1fcc}'],
+ ['\u{1fd0}','\u{1fd3}'],
+ ['\u{1fd6}','\u{1fdb}'],
+ ['\u{1fe0}','\u{1fec}'],
+ ['\u{1ff2}','\u{1ff4}'],
+ ['\u{1ff6}','\u{1ffc}'],
+ ['\u{2071}','\u{2071}'],
+ ['\u{207f}','\u{207f}'],
+ ['\u{2090}','\u{209c}'],
+ ['\u{2102}','\u{2102}'],
+ ['\u{2107}','\u{2107}'],
+ ['\u{210a}','\u{2113}'],
+ ['\u{2115}','\u{2115}'],
+ ['\u{2119}','\u{211d}'],
+ ['\u{2124}','\u{2124}'],
+ ['\u{2126}','\u{2126}'],
+ ['\u{2128}','\u{2128}'],
+ ['\u{212a}','\u{212d}'],
+ ['\u{212f}','\u{2139}'],
+ ['\u{213c}','\u{213f}'],
+ ['\u{2145}','\u{2149}'],
+ ['\u{214e}','\u{214e}'],
+ ['\u{2183}','\u{2184}'],
+ ['\u{2c00}','\u{2c2e}'],
+ ['\u{2c30}','\u{2c5e}'],
+ ['\u{2c60}','\u{2ce4}'],
+ ['\u{2ceb}','\u{2cee}'],
+ ['\u{2cf2}','\u{2cf3}'],
+ ['\u{2d00}','\u{2d25}'],
+ ['\u{2d27}','\u{2d27}'],
+ ['\u{2d2d}','\u{2d2d}'],
+ ['\u{2d30}','\u{2d67}'],
+ ['\u{2d6f}','\u{2d6f}'],
+ ['\u{2d80}','\u{2d96}'],
+ ['\u{2da0}','\u{2da6}'],
+ ['\u{2da8}','\u{2dae}'],
+ ['\u{2db0}','\u{2db6}'],
+ ['\u{2db8}','\u{2dbe}'],
+ ['\u{2dc0}','\u{2dc6}'],
+ ['\u{2dc8}','\u{2dce}'],
+ ['\u{2dd0}','\u{2dd6}'],
+ ['\u{2dd8}','\u{2dde}'],
+ ['\u{2e2f}','\u{2e2f}'],
+ ['\u{3005}','\u{3006}'],
+ ['\u{3031}','\u{3035}'],
+ ['\u{303b}','\u{303c}'],
+ ['\u{3041}','\u{3096}'],
+ ['\u{309d}','\u{309f}'],
+ ['\u{30a1}','\u{30fa}'],
+ ['\u{30fc}','\u{30ff}'],
+ ['\u{3105}','\u{312d}'],
+ ['\u{3131}','\u{318e}'],
+ ['\u{31a0}','\u{31ba}'],
+ ['\u{31f0}','\u{31ff}'],
+ ['\u{3400}','\u{4db5}'],
+ ['\u{4e00}','\u{9fcc}'],
+ ['\u{a000}','\u{a48c}'],
+ ['\u{a4d0}','\u{a4fd}'],
+ ['\u{a500}','\u{a60c}'],
+ ['\u{a610}','\u{a61f}'],
+ ['\u{a62a}','\u{a62b}'],
+ ['\u{a640}','\u{a66e}'],
+ ['\u{a67f}','\u{a697}'],
+ ['\u{a6a0}','\u{a6e5}'],
+ ['\u{a717}','\u{a71f}'],
+ ['\u{a722}','\u{a788}'],
+ ['\u{a78b}','\u{a78e}'],
+ ['\u{a790}','\u{a793}'],
+ ['\u{a7a0}','\u{a7aa}'],
+ ['\u{a7f8}','\u{a801}'],
+ ['\u{a803}','\u{a805}'],
+ ['\u{a807}','\u{a80a}'],
+ ['\u{a80c}','\u{a822}'],
+ ['\u{a840}','\u{a873}'],
+ ['\u{a882}','\u{a8b3}'],
+ ['\u{a8f2}','\u{a8f7}'],
+ ['\u{a8fb}','\u{a8fb}'],
+ ['\u{a90a}','\u{a925}'],
+ ['\u{a930}','\u{a946}'],
+ ['\u{a960}','\u{a97c}'],
+ ['\u{a984}','\u{a9b2}'],
+ ['\u{a9cf}','\u{a9cf}'],
+ ['\u{aa00}','\u{aa28}'],
+ ['\u{aa40}','\u{aa42}'],
+ ['\u{aa44}','\u{aa4b}'],
+ ['\u{aa60}','\u{aa76}'],
+ ['\u{aa7a}','\u{aa7a}'],
+ ['\u{aa80}','\u{aaaf}'],
+ ['\u{aab1}','\u{aab1}'],
+ ['\u{aab5}','\u{aab6}'],
+ ['\u{aab9}','\u{aabd}'],
+ ['\u{aac0}','\u{aac0}'],
+ ['\u{aac2}','\u{aac2}'],
+ ['\u{aadb}','\u{aadd}'],
+ ['\u{aae0}','\u{aaea}'],
+ ['\u{aaf2}','\u{aaf4}'],
+ ['\u{ab01}','\u{ab06}'],
+ ['\u{ab09}','\u{ab0e}'],
+ ['\u{ab11}','\u{ab16}'],
+ ['\u{ab20}','\u{ab26}'],
+ ['\u{ab28}','\u{ab2e}'],
+ ['\u{abc0}','\u{abe2}'],
+ ['\u{ac00}','\u{d7a3}'],
+ ['\u{d7b0}','\u{d7c6}'],
+ ['\u{d7cb}','\u{d7fb}'],
+ ['\u{f900}','\u{fa6d}'],
+ ['\u{fa70}','\u{fad9}'],
+ ['\u{fb00}','\u{fb06}'],
+ ['\u{fb13}','\u{fb17}'],
+ ['\u{fb1d}','\u{fb1d}'],
+ ['\u{fb1f}','\u{fb28}'],
+ ['\u{fb2a}','\u{fb36}'],
+ ['\u{fb38}','\u{fb3c}'],
+ ['\u{fb3e}','\u{fb3e}'],
+ ['\u{fb40}','\u{fb41}'],
+ ['\u{fb43}','\u{fb44}'],
+ ['\u{fb46}','\u{fbb1}'],
+ ['\u{fbd3}','\u{fd3d}'],
+ ['\u{fd50}','\u{fd8f}'],
+ ['\u{fd92}','\u{fdc7}'],
+ ['\u{fdf0}','\u{fdfb}'],
+ ['\u{fe70}','\u{fe74}'],
+ ['\u{fe76}','\u{fefc}'],
+ ['\u{ff21}','\u{ff3a}'],
+ ['\u{ff41}','\u{ff5a}'],
+ ['\u{ff66}','\u{ffbe}'],
+ ['\u{ffc2}','\u{ffc7}'],
+ ['\u{ffca}','\u{ffcf}'],
+ ['\u{ffd2}','\u{ffd7}'],
+ ['\u{ffda}','\u{ffdc}'],
+ ['\u{10000}','\u{1000b}'],
+ ['\u{1000d}','\u{10026}'],
+ ['\u{10028}','\u{1003a}'],
+ ['\u{1003c}','\u{1003d}'],
+ ['\u{1003f}','\u{1004d}'],
+ ['\u{10050}','\u{1005d}'],
+ ['\u{10080}','\u{100fa}'],
+ ['\u{10280}','\u{1029c}'],
+ ['\u{102a0}','\u{102d0}'],
+ ['\u{10300}','\u{1031e}'],
+ ['\u{10330}','\u{10340}'],
+ ['\u{10342}','\u{10349}'],
+ ['\u{10380}','\u{1039d}'],
+ ['\u{103a0}','\u{103c3}'],
+ ['\u{103c8}','\u{103cf}'],
+ ['\u{10400}','\u{1049d}'],
+ ['\u{10800}','\u{10805}'],
+ ['\u{10808}','\u{10808}'],
+ ['\u{1080a}','\u{10835}'],
+ ['\u{10837}','\u{10838}'],
+ ['\u{1083c}','\u{1083c}'],
+ ['\u{1083f}','\u{10855}'],
+ ['\u{10900}','\u{10915}'],
+ ['\u{10920}','\u{10939}'],
+ ['\u{10980}','\u{109b7}'],
+ ['\u{109be}','\u{109bf}'],
+ ['\u{10a00}','\u{10a00}'],
+ ['\u{10a10}','\u{10a13}'],
+ ['\u{10a15}','\u{10a17}'],
+ ['\u{10a19}','\u{10a33}'],
+ ['\u{10a60}','\u{10a7c}'],
+ ['\u{10b00}','\u{10b35}'],
+ ['\u{10b40}','\u{10b55}'],
+ ['\u{10b60}','\u{10b72}'],
+ ['\u{10c00}','\u{10c48}'],
+ ['\u{11003}','\u{11037}'],
+ ['\u{11083}','\u{110af}'],
+ ['\u{110d0}','\u{110e8}'],
+ ['\u{11103}','\u{11126}'],
+ ['\u{11183}','\u{111b2}'],
+ ['\u{111c1}','\u{111c4}'],
+ ['\u{11680}','\u{116aa}'],
+ ['\u{12000}','\u{1236e}'],
+ ['\u{13000}','\u{1342e}'],
+ ['\u{16800}','\u{16a38}'],
+ ['\u{16f00}','\u{16f44}'],
+ ['\u{16f50}','\u{16f50}'],
+ ['\u{16f93}','\u{16f9f}'],
+ ['\u{1b000}','\u{1b001}'],
+ ['\u{1d400}','\u{1d454}'],
+ ['\u{1d456}','\u{1d49c}'],
+ ['\u{1d49e}','\u{1d49f}'],
+ ['\u{1d4a2}','\u{1d4a2}'],
+ ['\u{1d4a5}','\u{1d4a6}'],
+ ['\u{1d4a9}','\u{1d4ac}'],
+ ['\u{1d4ae}','\u{1d4b9}'],
+ ['\u{1d4bb}','\u{1d4bb}'],
+ ['\u{1d4bd}','\u{1d4c3}'],
+ ['\u{1d4c5}','\u{1d505}'],
+ ['\u{1d507}','\u{1d50a}'],
+ ['\u{1d50d}','\u{1d514}'],
+ ['\u{1d516}','\u{1d51c}'],
+ ['\u{1d51e}','\u{1d539}'],
+ ['\u{1d53b}','\u{1d53e}'],
+ ['\u{1d540}','\u{1d544}'],
+ ['\u{1d546}','\u{1d546}'],
+ ['\u{1d54a}','\u{1d550}'],
+ ['\u{1d552}','\u{1d6a5}'],
+ ['\u{1d6a8}','\u{1d6c0}'],
+ ['\u{1d6c2}','\u{1d6da}'],
+ ['\u{1d6dc}','\u{1d6fa}'],
+ ['\u{1d6fc}','\u{1d714}'],
+ ['\u{1d716}','\u{1d734}'],
+ ['\u{1d736}','\u{1d74e}'],
+ ['\u{1d750}','\u{1d76e}'],
+ ['\u{1d770}','\u{1d788}'],
+ ['\u{1d78a}','\u{1d7a8}'],
+ ['\u{1d7aa}','\u{1d7c2}'],
+ ['\u{1d7c4}','\u{1d7cb}'],
+ ['\u{1ee00}','\u{1ee03}'],
+ ['\u{1ee05}','\u{1ee1f}'],
+ ['\u{1ee21}','\u{1ee22}'],
+ ['\u{1ee24}','\u{1ee24}'],
+ ['\u{1ee27}','\u{1ee27}'],
+ ['\u{1ee29}','\u{1ee32}'],
+ ['\u{1ee34}','\u{1ee37}'],
+ ['\u{1ee39}','\u{1ee39}'],
+ ['\u{1ee3b}','\u{1ee3b}'],
+ ['\u{1ee42}','\u{1ee42}'],
+ ['\u{1ee47}','\u{1ee47}'],
+ ['\u{1ee49}','\u{1ee49}'],
+ ['\u{1ee4b}','\u{1ee4b}'],
+ ['\u{1ee4d}','\u{1ee4f}'],
+ ['\u{1ee51}','\u{1ee52}'],
+ ['\u{1ee54}','\u{1ee54}'],
+ ['\u{1ee57}','\u{1ee57}'],
+ ['\u{1ee59}','\u{1ee59}'],
+ ['\u{1ee5b}','\u{1ee5b}'],
+ ['\u{1ee5d}','\u{1ee5d}'],
+ ['\u{1ee5f}','\u{1ee5f}'],
+ ['\u{1ee61}','\u{1ee62}'],
+ ['\u{1ee64}','\u{1ee64}'],
+ ['\u{1ee67}','\u{1ee6a}'],
+ ['\u{1ee6c}','\u{1ee72}'],
+ ['\u{1ee74}','\u{1ee77}'],
+ ['\u{1ee79}','\u{1ee7c}'],
+ ['\u{1ee7e}','\u{1ee7e}'],
+ ['\u{1ee80}','\u{1ee89}'],
+ ['\u{1ee8b}','\u{1ee9b}'],
+ ['\u{1eea1}','\u{1eea3}'],
+ ['\u{1eea5}','\u{1eea9}'],
+ ['\u{1eeab}','\u{1eebb}'],
+ ['\u{20000}','\u{2a6d6}'],
+ ['\u{2a700}','\u{2b734}'],
+ ['\u{2b740}','\u{2b81d}'],
+ ['\u{2f800}','\u{2fa1d}'],
+]
+
+const tabupper = [
+ ['\u{41}','\u{5a}'],
+ ['\u{c0}','\u{d6}'],
+ ['\u{d8}','\u{de}'],
+ ['\u{100}','\u{100}'],
+ ['\u{102}','\u{102}'],
+ ['\u{104}','\u{104}'],
+ ['\u{106}','\u{106}'],
+ ['\u{108}','\u{108}'],
+ ['\u{10a}','\u{10a}'],
+ ['\u{10c}','\u{10c}'],
+ ['\u{10e}','\u{10e}'],
+ ['\u{110}','\u{110}'],
+ ['\u{112}','\u{112}'],
+ ['\u{114}','\u{114}'],
+ ['\u{116}','\u{116}'],
+ ['\u{118}','\u{118}'],
+ ['\u{11a}','\u{11a}'],
+ ['\u{11c}','\u{11c}'],
+ ['\u{11e}','\u{11e}'],
+ ['\u{120}','\u{120}'],
+ ['\u{122}','\u{122}'],
+ ['\u{124}','\u{124}'],
+ ['\u{126}','\u{126}'],
+ ['\u{128}','\u{128}'],
+ ['\u{12a}','\u{12a}'],
+ ['\u{12c}','\u{12c}'],
+ ['\u{12e}','\u{12e}'],
+ ['\u{130}','\u{130}'],
+ ['\u{132}','\u{132}'],
+ ['\u{134}','\u{134}'],
+ ['\u{136}','\u{136}'],
+ ['\u{139}','\u{139}'],
+ ['\u{13b}','\u{13b}'],
+ ['\u{13d}','\u{13d}'],
+ ['\u{13f}','\u{13f}'],
+ ['\u{141}','\u{141}'],
+ ['\u{143}','\u{143}'],
+ ['\u{145}','\u{145}'],
+ ['\u{147}','\u{147}'],
+ ['\u{14a}','\u{14a}'],
+ ['\u{14c}','\u{14c}'],
+ ['\u{14e}','\u{14e}'],
+ ['\u{150}','\u{150}'],
+ ['\u{152}','\u{152}'],
+ ['\u{154}','\u{154}'],
+ ['\u{156}','\u{156}'],
+ ['\u{158}','\u{158}'],
+ ['\u{15a}','\u{15a}'],
+ ['\u{15c}','\u{15c}'],
+ ['\u{15e}','\u{15e}'],
+ ['\u{160}','\u{160}'],
+ ['\u{162}','\u{162}'],
+ ['\u{164}','\u{164}'],
+ ['\u{166}','\u{166}'],
+ ['\u{168}','\u{168}'],
+ ['\u{16a}','\u{16a}'],
+ ['\u{16c}','\u{16c}'],
+ ['\u{16e}','\u{16e}'],
+ ['\u{170}','\u{170}'],
+ ['\u{172}','\u{172}'],
+ ['\u{174}','\u{174}'],
+ ['\u{176}','\u{176}'],
+ ['\u{178}','\u{179}'],
+ ['\u{17b}','\u{17b}'],
+ ['\u{17d}','\u{17d}'],
+ ['\u{181}','\u{182}'],
+ ['\u{184}','\u{184}'],
+ ['\u{186}','\u{187}'],
+ ['\u{189}','\u{18b}'],
+ ['\u{18e}','\u{191}'],
+ ['\u{193}','\u{194}'],
+ ['\u{196}','\u{198}'],
+ ['\u{19c}','\u{19d}'],
+ ['\u{19f}','\u{1a0}'],
+ ['\u{1a2}','\u{1a2}'],
+ ['\u{1a4}','\u{1a4}'],
+ ['\u{1a6}','\u{1a7}'],
+ ['\u{1a9}','\u{1a9}'],
+ ['\u{1ac}','\u{1ac}'],
+ ['\u{1ae}','\u{1af}'],
+ ['\u{1b1}','\u{1b3}'],
+ ['\u{1b5}','\u{1b5}'],
+ ['\u{1b7}','\u{1b8}'],
+ ['\u{1bc}','\u{1bc}'],
+ ['\u{1c4}','\u{1c4}'],
+ ['\u{1c7}','\u{1c7}'],
+ ['\u{1ca}','\u{1ca}'],
+ ['\u{1cd}','\u{1cd}'],
+ ['\u{1cf}','\u{1cf}'],
+ ['\u{1d1}','\u{1d1}'],
+ ['\u{1d3}','\u{1d3}'],
+ ['\u{1d5}','\u{1d5}'],
+ ['\u{1d7}','\u{1d7}'],
+ ['\u{1d9}','\u{1d9}'],
+ ['\u{1db}','\u{1db}'],
+ ['\u{1de}','\u{1de}'],
+ ['\u{1e0}','\u{1e0}'],
+ ['\u{1e2}','\u{1e2}'],
+ ['\u{1e4}','\u{1e4}'],
+ ['\u{1e6}','\u{1e6}'],
+ ['\u{1e8}','\u{1e8}'],
+ ['\u{1ea}','\u{1ea}'],
+ ['\u{1ec}','\u{1ec}'],
+ ['\u{1ee}','\u{1ee}'],
+ ['\u{1f1}','\u{1f1}'],
+ ['\u{1f4}','\u{1f4}'],
+ ['\u{1f6}','\u{1f8}'],
+ ['\u{1fa}','\u{1fa}'],
+ ['\u{1fc}','\u{1fc}'],
+ ['\u{1fe}','\u{1fe}'],
+ ['\u{200}','\u{200}'],
+ ['\u{202}','\u{202}'],
+ ['\u{204}','\u{204}'],
+ ['\u{206}','\u{206}'],
+ ['\u{208}','\u{208}'],
+ ['\u{20a}','\u{20a}'],
+ ['\u{20c}','\u{20c}'],
+ ['\u{20e}','\u{20e}'],
+ ['\u{210}','\u{210}'],
+ ['\u{212}','\u{212}'],
+ ['\u{214}','\u{214}'],
+ ['\u{216}','\u{216}'],
+ ['\u{218}','\u{218}'],
+ ['\u{21a}','\u{21a}'],
+ ['\u{21c}','\u{21c}'],
+ ['\u{21e}','\u{21e}'],
+ ['\u{220}','\u{220}'],
+ ['\u{222}','\u{222}'],
+ ['\u{224}','\u{224}'],
+ ['\u{226}','\u{226}'],
+ ['\u{228}','\u{228}'],
+ ['\u{22a}','\u{22a}'],
+ ['\u{22c}','\u{22c}'],
+ ['\u{22e}','\u{22e}'],
+ ['\u{230}','\u{230}'],
+ ['\u{232}','\u{232}'],
+ ['\u{23a}','\u{23b}'],
+ ['\u{23d}','\u{23e}'],
+ ['\u{241}','\u{241}'],
+ ['\u{243}','\u{246}'],
+ ['\u{248}','\u{248}'],
+ ['\u{24a}','\u{24a}'],
+ ['\u{24c}','\u{24c}'],
+ ['\u{24e}','\u{24e}'],
+ ['\u{370}','\u{370}'],
+ ['\u{372}','\u{372}'],
+ ['\u{376}','\u{376}'],
+ ['\u{386}','\u{386}'],
+ ['\u{388}','\u{38a}'],
+ ['\u{38c}','\u{38c}'],
+ ['\u{38e}','\u{38f}'],
+ ['\u{391}','\u{3a1}'],
+ ['\u{3a3}','\u{3ab}'],
+ ['\u{3cf}','\u{3cf}'],
+ ['\u{3d2}','\u{3d4}'],
+ ['\u{3d8}','\u{3d8}'],
+ ['\u{3da}','\u{3da}'],
+ ['\u{3dc}','\u{3dc}'],
+ ['\u{3de}','\u{3de}'],
+ ['\u{3e0}','\u{3e0}'],
+ ['\u{3e2}','\u{3e2}'],
+ ['\u{3e4}','\u{3e4}'],
+ ['\u{3e6}','\u{3e6}'],
+ ['\u{3e8}','\u{3e8}'],
+ ['\u{3ea}','\u{3ea}'],
+ ['\u{3ec}','\u{3ec}'],
+ ['\u{3ee}','\u{3ee}'],
+ ['\u{3f4}','\u{3f4}'],
+ ['\u{3f7}','\u{3f7}'],
+ ['\u{3f9}','\u{3fa}'],
+ ['\u{3fd}','\u{42f}'],
+ ['\u{460}','\u{460}'],
+ ['\u{462}','\u{462}'],
+ ['\u{464}','\u{464}'],
+ ['\u{466}','\u{466}'],
+ ['\u{468}','\u{468}'],
+ ['\u{46a}','\u{46a}'],
+ ['\u{46c}','\u{46c}'],
+ ['\u{46e}','\u{46e}'],
+ ['\u{470}','\u{470}'],
+ ['\u{472}','\u{472}'],
+ ['\u{474}','\u{474}'],
+ ['\u{476}','\u{476}'],
+ ['\u{478}','\u{478}'],
+ ['\u{47a}','\u{47a}'],
+ ['\u{47c}','\u{47c}'],
+ ['\u{47e}','\u{47e}'],
+ ['\u{480}','\u{480}'],
+ ['\u{48a}','\u{48a}'],
+ ['\u{48c}','\u{48c}'],
+ ['\u{48e}','\u{48e}'],
+ ['\u{490}','\u{490}'],
+ ['\u{492}','\u{492}'],
+ ['\u{494}','\u{494}'],
+ ['\u{496}','\u{496}'],
+ ['\u{498}','\u{498}'],
+ ['\u{49a}','\u{49a}'],
+ ['\u{49c}','\u{49c}'],
+ ['\u{49e}','\u{49e}'],
+ ['\u{4a0}','\u{4a0}'],
+ ['\u{4a2}','\u{4a2}'],
+ ['\u{4a4}','\u{4a4}'],
+ ['\u{4a6}','\u{4a6}'],
+ ['\u{4a8}','\u{4a8}'],
+ ['\u{4aa}','\u{4aa}'],
+ ['\u{4ac}','\u{4ac}'],
+ ['\u{4ae}','\u{4ae}'],
+ ['\u{4b0}','\u{4b0}'],
+ ['\u{4b2}','\u{4b2}'],
+ ['\u{4b4}','\u{4b4}'],
+ ['\u{4b6}','\u{4b6}'],
+ ['\u{4b8}','\u{4b8}'],
+ ['\u{4ba}','\u{4ba}'],
+ ['\u{4bc}','\u{4bc}'],
+ ['\u{4be}','\u{4be}'],
+ ['\u{4c0}','\u{4c1}'],
+ ['\u{4c3}','\u{4c3}'],
+ ['\u{4c5}','\u{4c5}'],
+ ['\u{4c7}','\u{4c7}'],
+ ['\u{4c9}','\u{4c9}'],
+ ['\u{4cb}','\u{4cb}'],
+ ['\u{4cd}','\u{4cd}'],
+ ['\u{4d0}','\u{4d0}'],
+ ['\u{4d2}','\u{4d2}'],
+ ['\u{4d4}','\u{4d4}'],
+ ['\u{4d6}','\u{4d6}'],
+ ['\u{4d8}','\u{4d8}'],
+ ['\u{4da}','\u{4da}'],
+ ['\u{4dc}','\u{4dc}'],
+ ['\u{4de}','\u{4de}'],
+ ['\u{4e0}','\u{4e0}'],
+ ['\u{4e2}','\u{4e2}'],
+ ['\u{4e4}','\u{4e4}'],
+ ['\u{4e6}','\u{4e6}'],
+ ['\u{4e8}','\u{4e8}'],
+ ['\u{4ea}','\u{4ea}'],
+ ['\u{4ec}','\u{4ec}'],
+ ['\u{4ee}','\u{4ee}'],
+ ['\u{4f0}','\u{4f0}'],
+ ['\u{4f2}','\u{4f2}'],
+ ['\u{4f4}','\u{4f4}'],
+ ['\u{4f6}','\u{4f6}'],
+ ['\u{4f8}','\u{4f8}'],
+ ['\u{4fa}','\u{4fa}'],
+ ['\u{4fc}','\u{4fc}'],
+ ['\u{4fe}','\u{4fe}'],
+ ['\u{500}','\u{500}'],
+ ['\u{502}','\u{502}'],
+ ['\u{504}','\u{504}'],
+ ['\u{506}','\u{506}'],
+ ['\u{508}','\u{508}'],
+ ['\u{50a}','\u{50a}'],
+ ['\u{50c}','\u{50c}'],
+ ['\u{50e}','\u{50e}'],
+ ['\u{510}','\u{510}'],
+ ['\u{512}','\u{512}'],
+ ['\u{514}','\u{514}'],
+ ['\u{516}','\u{516}'],
+ ['\u{518}','\u{518}'],
+ ['\u{51a}','\u{51a}'],
+ ['\u{51c}','\u{51c}'],
+ ['\u{51e}','\u{51e}'],
+ ['\u{520}','\u{520}'],
+ ['\u{522}','\u{522}'],
+ ['\u{524}','\u{524}'],
+ ['\u{526}','\u{526}'],
+ ['\u{531}','\u{556}'],
+ ['\u{10a0}','\u{10c5}'],
+ ['\u{10c7}','\u{10c7}'],
+ ['\u{10cd}','\u{10cd}'],
+ ['\u{1e00}','\u{1e00}'],
+ ['\u{1e02}','\u{1e02}'],
+ ['\u{1e04}','\u{1e04}'],
+ ['\u{1e06}','\u{1e06}'],
+ ['\u{1e08}','\u{1e08}'],
+ ['\u{1e0a}','\u{1e0a}'],
+ ['\u{1e0c}','\u{1e0c}'],
+ ['\u{1e0e}','\u{1e0e}'],
+ ['\u{1e10}','\u{1e10}'],
+ ['\u{1e12}','\u{1e12}'],
+ ['\u{1e14}','\u{1e14}'],
+ ['\u{1e16}','\u{1e16}'],
+ ['\u{1e18}','\u{1e18}'],
+ ['\u{1e1a}','\u{1e1a}'],
+ ['\u{1e1c}','\u{1e1c}'],
+ ['\u{1e1e}','\u{1e1e}'],
+ ['\u{1e20}','\u{1e20}'],
+ ['\u{1e22}','\u{1e22}'],
+ ['\u{1e24}','\u{1e24}'],
+ ['\u{1e26}','\u{1e26}'],
+ ['\u{1e28}','\u{1e28}'],
+ ['\u{1e2a}','\u{1e2a}'],
+ ['\u{1e2c}','\u{1e2c}'],
+ ['\u{1e2e}','\u{1e2e}'],
+ ['\u{1e30}','\u{1e30}'],
+ ['\u{1e32}','\u{1e32}'],
+ ['\u{1e34}','\u{1e34}'],
+ ['\u{1e36}','\u{1e36}'],
+ ['\u{1e38}','\u{1e38}'],
+ ['\u{1e3a}','\u{1e3a}'],
+ ['\u{1e3c}','\u{1e3c}'],
+ ['\u{1e3e}','\u{1e3e}'],
+ ['\u{1e40}','\u{1e40}'],
+ ['\u{1e42}','\u{1e42}'],
+ ['\u{1e44}','\u{1e44}'],
+ ['\u{1e46}','\u{1e46}'],
+ ['\u{1e48}','\u{1e48}'],
+ ['\u{1e4a}','\u{1e4a}'],
+ ['\u{1e4c}','\u{1e4c}'],
+ ['\u{1e4e}','\u{1e4e}'],
+ ['\u{1e50}','\u{1e50}'],
+ ['\u{1e52}','\u{1e52}'],
+ ['\u{1e54}','\u{1e54}'],
+ ['\u{1e56}','\u{1e56}'],
+ ['\u{1e58}','\u{1e58}'],
+ ['\u{1e5a}','\u{1e5a}'],
+ ['\u{1e5c}','\u{1e5c}'],
+ ['\u{1e5e}','\u{1e5e}'],
+ ['\u{1e60}','\u{1e60}'],
+ ['\u{1e62}','\u{1e62}'],
+ ['\u{1e64}','\u{1e64}'],
+ ['\u{1e66}','\u{1e66}'],
+ ['\u{1e68}','\u{1e68}'],
+ ['\u{1e6a}','\u{1e6a}'],
+ ['\u{1e6c}','\u{1e6c}'],
+ ['\u{1e6e}','\u{1e6e}'],
+ ['\u{1e70}','\u{1e70}'],
+ ['\u{1e72}','\u{1e72}'],
+ ['\u{1e74}','\u{1e74}'],
+ ['\u{1e76}','\u{1e76}'],
+ ['\u{1e78}','\u{1e78}'],
+ ['\u{1e7a}','\u{1e7a}'],
+ ['\u{1e7c}','\u{1e7c}'],
+ ['\u{1e7e}','\u{1e7e}'],
+ ['\u{1e80}','\u{1e80}'],
+ ['\u{1e82}','\u{1e82}'],
+ ['\u{1e84}','\u{1e84}'],
+ ['\u{1e86}','\u{1e86}'],
+ ['\u{1e88}','\u{1e88}'],
+ ['\u{1e8a}','\u{1e8a}'],
+ ['\u{1e8c}','\u{1e8c}'],
+ ['\u{1e8e}','\u{1e8e}'],
+ ['\u{1e90}','\u{1e90}'],
+ ['\u{1e92}','\u{1e92}'],
+ ['\u{1e94}','\u{1e94}'],
+ ['\u{1e9e}','\u{1e9e}'],
+ ['\u{1ea0}','\u{1ea0}'],
+ ['\u{1ea2}','\u{1ea2}'],
+ ['\u{1ea4}','\u{1ea4}'],
+ ['\u{1ea6}','\u{1ea6}'],
+ ['\u{1ea8}','\u{1ea8}'],
+ ['\u{1eaa}','\u{1eaa}'],
+ ['\u{1eac}','\u{1eac}'],
+ ['\u{1eae}','\u{1eae}'],
+ ['\u{1eb0}','\u{1eb0}'],
+ ['\u{1eb2}','\u{1eb2}'],
+ ['\u{1eb4}','\u{1eb4}'],
+ ['\u{1eb6}','\u{1eb6}'],
+ ['\u{1eb8}','\u{1eb8}'],
+ ['\u{1eba}','\u{1eba}'],
+ ['\u{1ebc}','\u{1ebc}'],
+ ['\u{1ebe}','\u{1ebe}'],
+ ['\u{1ec0}','\u{1ec0}'],
+ ['\u{1ec2}','\u{1ec2}'],
+ ['\u{1ec4}','\u{1ec4}'],
+ ['\u{1ec6}','\u{1ec6}'],
+ ['\u{1ec8}','\u{1ec8}'],
+ ['\u{1eca}','\u{1eca}'],
+ ['\u{1ecc}','\u{1ecc}'],
+ ['\u{1ece}','\u{1ece}'],
+ ['\u{1ed0}','\u{1ed0}'],
+ ['\u{1ed2}','\u{1ed2}'],
+ ['\u{1ed4}','\u{1ed4}'],
+ ['\u{1ed6}','\u{1ed6}'],
+ ['\u{1ed8}','\u{1ed8}'],
+ ['\u{1eda}','\u{1eda}'],
+ ['\u{1edc}','\u{1edc}'],
+ ['\u{1ede}','\u{1ede}'],
+ ['\u{1ee0}','\u{1ee0}'],
+ ['\u{1ee2}','\u{1ee2}'],
+ ['\u{1ee4}','\u{1ee4}'],
+ ['\u{1ee6}','\u{1ee6}'],
+ ['\u{1ee8}','\u{1ee8}'],
+ ['\u{1eea}','\u{1eea}'],
+ ['\u{1eec}','\u{1eec}'],
+ ['\u{1eee}','\u{1eee}'],
+ ['\u{1ef0}','\u{1ef0}'],
+ ['\u{1ef2}','\u{1ef2}'],
+ ['\u{1ef4}','\u{1ef4}'],
+ ['\u{1ef6}','\u{1ef6}'],
+ ['\u{1ef8}','\u{1ef8}'],
+ ['\u{1efa}','\u{1efa}'],
+ ['\u{1efc}','\u{1efc}'],
+ ['\u{1efe}','\u{1efe}'],
+ ['\u{1f08}','\u{1f0f}'],
+ ['\u{1f18}','\u{1f1d}'],
+ ['\u{1f28}','\u{1f2f}'],
+ ['\u{1f38}','\u{1f3f}'],
+ ['\u{1f48}','\u{1f4d}'],
+ ['\u{1f59}','\u{1f59}'],
+ ['\u{1f5b}','\u{1f5b}'],
+ ['\u{1f5d}','\u{1f5d}'],
+ ['\u{1f5f}','\u{1f5f}'],
+ ['\u{1f68}','\u{1f6f}'],
+ ['\u{1fb8}','\u{1fbb}'],
+ ['\u{1fc8}','\u{1fcb}'],
+ ['\u{1fd8}','\u{1fdb}'],
+ ['\u{1fe8}','\u{1fec}'],
+ ['\u{1ff8}','\u{1ffb}'],
+ ['\u{2102}','\u{2102}'],
+ ['\u{2107}','\u{2107}'],
+ ['\u{210b}','\u{210d}'],
+ ['\u{2110}','\u{2112}'],
+ ['\u{2115}','\u{2115}'],
+ ['\u{2119}','\u{211d}'],
+ ['\u{2124}','\u{2124}'],
+ ['\u{2126}','\u{2126}'],
+ ['\u{2128}','\u{2128}'],
+ ['\u{212a}','\u{212d}'],
+ ['\u{2130}','\u{2133}'],
+ ['\u{213e}','\u{213f}'],
+ ['\u{2145}','\u{2145}'],
+ ['\u{2183}','\u{2183}'],
+ ['\u{2c00}','\u{2c2e}'],
+ ['\u{2c60}','\u{2c60}'],
+ ['\u{2c62}','\u{2c64}'],
+ ['\u{2c67}','\u{2c67}'],
+ ['\u{2c69}','\u{2c69}'],
+ ['\u{2c6b}','\u{2c6b}'],
+ ['\u{2c6d}','\u{2c70}'],
+ ['\u{2c72}','\u{2c72}'],
+ ['\u{2c75}','\u{2c75}'],
+ ['\u{2c7e}','\u{2c80}'],
+ ['\u{2c82}','\u{2c82}'],
+ ['\u{2c84}','\u{2c84}'],
+ ['\u{2c86}','\u{2c86}'],
+ ['\u{2c88}','\u{2c88}'],
+ ['\u{2c8a}','\u{2c8a}'],
+ ['\u{2c8c}','\u{2c8c}'],
+ ['\u{2c8e}','\u{2c8e}'],
+ ['\u{2c90}','\u{2c90}'],
+ ['\u{2c92}','\u{2c92}'],
+ ['\u{2c94}','\u{2c94}'],
+ ['\u{2c96}','\u{2c96}'],
+ ['\u{2c98}','\u{2c98}'],
+ ['\u{2c9a}','\u{2c9a}'],
+ ['\u{2c9c}','\u{2c9c}'],
+ ['\u{2c9e}','\u{2c9e}'],
+ ['\u{2ca0}','\u{2ca0}'],
+ ['\u{2ca2}','\u{2ca2}'],
+ ['\u{2ca4}','\u{2ca4}'],
+ ['\u{2ca6}','\u{2ca6}'],
+ ['\u{2ca8}','\u{2ca8}'],
+ ['\u{2caa}','\u{2caa}'],
+ ['\u{2cac}','\u{2cac}'],
+ ['\u{2cae}','\u{2cae}'],
+ ['\u{2cb0}','\u{2cb0}'],
+ ['\u{2cb2}','\u{2cb2}'],
+ ['\u{2cb4}','\u{2cb4}'],
+ ['\u{2cb6}','\u{2cb6}'],
+ ['\u{2cb8}','\u{2cb8}'],
+ ['\u{2cba}','\u{2cba}'],
+ ['\u{2cbc}','\u{2cbc}'],
+ ['\u{2cbe}','\u{2cbe}'],
+ ['\u{2cc0}','\u{2cc0}'],
+ ['\u{2cc2}','\u{2cc2}'],
+ ['\u{2cc4}','\u{2cc4}'],
+ ['\u{2cc6}','\u{2cc6}'],
+ ['\u{2cc8}','\u{2cc8}'],
+ ['\u{2cca}','\u{2cca}'],
+ ['\u{2ccc}','\u{2ccc}'],
+ ['\u{2cce}','\u{2cce}'],
+ ['\u{2cd0}','\u{2cd0}'],
+ ['\u{2cd2}','\u{2cd2}'],
+ ['\u{2cd4}','\u{2cd4}'],
+ ['\u{2cd6}','\u{2cd6}'],
+ ['\u{2cd8}','\u{2cd8}'],
+ ['\u{2cda}','\u{2cda}'],
+ ['\u{2cdc}','\u{2cdc}'],
+ ['\u{2cde}','\u{2cde}'],
+ ['\u{2ce0}','\u{2ce0}'],
+ ['\u{2ce2}','\u{2ce2}'],
+ ['\u{2ceb}','\u{2ceb}'],
+ ['\u{2ced}','\u{2ced}'],
+ ['\u{2cf2}','\u{2cf2}'],
+ ['\u{a640}','\u{a640}'],
+ ['\u{a642}','\u{a642}'],
+ ['\u{a644}','\u{a644}'],
+ ['\u{a646}','\u{a646}'],
+ ['\u{a648}','\u{a648}'],
+ ['\u{a64a}','\u{a64a}'],
+ ['\u{a64c}','\u{a64c}'],
+ ['\u{a64e}','\u{a64e}'],
+ ['\u{a650}','\u{a650}'],
+ ['\u{a652}','\u{a652}'],
+ ['\u{a654}','\u{a654}'],
+ ['\u{a656}','\u{a656}'],
+ ['\u{a658}','\u{a658}'],
+ ['\u{a65a}','\u{a65a}'],
+ ['\u{a65c}','\u{a65c}'],
+ ['\u{a65e}','\u{a65e}'],
+ ['\u{a660}','\u{a660}'],
+ ['\u{a662}','\u{a662}'],
+ ['\u{a664}','\u{a664}'],
+ ['\u{a666}','\u{a666}'],
+ ['\u{a668}','\u{a668}'],
+ ['\u{a66a}','\u{a66a}'],
+ ['\u{a66c}','\u{a66c}'],
+ ['\u{a680}','\u{a680}'],
+ ['\u{a682}','\u{a682}'],
+ ['\u{a684}','\u{a684}'],
+ ['\u{a686}','\u{a686}'],
+ ['\u{a688}','\u{a688}'],
+ ['\u{a68a}','\u{a68a}'],
+ ['\u{a68c}','\u{a68c}'],
+ ['\u{a68e}','\u{a68e}'],
+ ['\u{a690}','\u{a690}'],
+ ['\u{a692}','\u{a692}'],
+ ['\u{a694}','\u{a694}'],
+ ['\u{a696}','\u{a696}'],
+ ['\u{a722}','\u{a722}'],
+ ['\u{a724}','\u{a724}'],
+ ['\u{a726}','\u{a726}'],
+ ['\u{a728}','\u{a728}'],
+ ['\u{a72a}','\u{a72a}'],
+ ['\u{a72c}','\u{a72c}'],
+ ['\u{a72e}','\u{a72e}'],
+ ['\u{a732}','\u{a732}'],
+ ['\u{a734}','\u{a734}'],
+ ['\u{a736}','\u{a736}'],
+ ['\u{a738}','\u{a738}'],
+ ['\u{a73a}','\u{a73a}'],
+ ['\u{a73c}','\u{a73c}'],
+ ['\u{a73e}','\u{a73e}'],
+ ['\u{a740}','\u{a740}'],
+ ['\u{a742}','\u{a742}'],
+ ['\u{a744}','\u{a744}'],
+ ['\u{a746}','\u{a746}'],
+ ['\u{a748}','\u{a748}'],
+ ['\u{a74a}','\u{a74a}'],
+ ['\u{a74c}','\u{a74c}'],
+ ['\u{a74e}','\u{a74e}'],
+ ['\u{a750}','\u{a750}'],
+ ['\u{a752}','\u{a752}'],
+ ['\u{a754}','\u{a754}'],
+ ['\u{a756}','\u{a756}'],
+ ['\u{a758}','\u{a758}'],
+ ['\u{a75a}','\u{a75a}'],
+ ['\u{a75c}','\u{a75c}'],
+ ['\u{a75e}','\u{a75e}'],
+ ['\u{a760}','\u{a760}'],
+ ['\u{a762}','\u{a762}'],
+ ['\u{a764}','\u{a764}'],
+ ['\u{a766}','\u{a766}'],
+ ['\u{a768}','\u{a768}'],
+ ['\u{a76a}','\u{a76a}'],
+ ['\u{a76c}','\u{a76c}'],
+ ['\u{a76e}','\u{a76e}'],
+ ['\u{a779}','\u{a779}'],
+ ['\u{a77b}','\u{a77b}'],
+ ['\u{a77d}','\u{a77e}'],
+ ['\u{a780}','\u{a780}'],
+ ['\u{a782}','\u{a782}'],
+ ['\u{a784}','\u{a784}'],
+ ['\u{a786}','\u{a786}'],
+ ['\u{a78b}','\u{a78b}'],
+ ['\u{a78d}','\u{a78d}'],
+ ['\u{a790}','\u{a790}'],
+ ['\u{a792}','\u{a792}'],
+ ['\u{a7a0}','\u{a7a0}'],
+ ['\u{a7a2}','\u{a7a2}'],
+ ['\u{a7a4}','\u{a7a4}'],
+ ['\u{a7a6}','\u{a7a6}'],
+ ['\u{a7a8}','\u{a7a8}'],
+ ['\u{a7aa}','\u{a7aa}'],
+ ['\u{ff21}','\u{ff3a}'],
+ ['\u{10400}','\u{10427}'],
+ ['\u{1d400}','\u{1d419}'],
+ ['\u{1d434}','\u{1d44d}'],
+ ['\u{1d468}','\u{1d481}'],
+ ['\u{1d49c}','\u{1d49c}'],
+ ['\u{1d49e}','\u{1d49f}'],
+ ['\u{1d4a2}','\u{1d4a2}'],
+ ['\u{1d4a5}','\u{1d4a6}'],
+ ['\u{1d4a9}','\u{1d4ac}'],
+ ['\u{1d4ae}','\u{1d4b5}'],
+ ['\u{1d4d0}','\u{1d4e9}'],
+ ['\u{1d504}','\u{1d505}'],
+ ['\u{1d507}','\u{1d50a}'],
+ ['\u{1d50d}','\u{1d514}'],
+ ['\u{1d516}','\u{1d51c}'],
+ ['\u{1d538}','\u{1d539}'],
+ ['\u{1d53b}','\u{1d53e}'],
+ ['\u{1d540}','\u{1d544}'],
+ ['\u{1d546}','\u{1d546}'],
+ ['\u{1d54a}','\u{1d550}'],
+ ['\u{1d56c}','\u{1d585}'],
+ ['\u{1d5a0}','\u{1d5b9}'],
+ ['\u{1d5d4}','\u{1d5ed}'],
+ ['\u{1d608}','\u{1d621}'],
+ ['\u{1d63c}','\u{1d655}'],
+ ['\u{1d670}','\u{1d689}'],
+ ['\u{1d6a8}','\u{1d6c0}'],
+ ['\u{1d6e2}','\u{1d6fa}'],
+ ['\u{1d71c}','\u{1d734}'],
+ ['\u{1d756}','\u{1d76e}'],
+ ['\u{1d790}','\u{1d7a8}'],
+ ['\u{1d7ca}','\u{1d7ca}'],
+]
+
+const tablower = [
+ ['\u{61}','\u{7a}'],
+ ['\u{b5}','\u{b5}'],
+ ['\u{df}','\u{f6}'],
+ ['\u{f8}','\u{ff}'],
+ ['\u{101}','\u{101}'],
+ ['\u{103}','\u{103}'],
+ ['\u{105}','\u{105}'],
+ ['\u{107}','\u{107}'],
+ ['\u{109}','\u{109}'],
+ ['\u{10b}','\u{10b}'],
+ ['\u{10d}','\u{10d}'],
+ ['\u{10f}','\u{10f}'],
+ ['\u{111}','\u{111}'],
+ ['\u{113}','\u{113}'],
+ ['\u{115}','\u{115}'],
+ ['\u{117}','\u{117}'],
+ ['\u{119}','\u{119}'],
+ ['\u{11b}','\u{11b}'],
+ ['\u{11d}','\u{11d}'],
+ ['\u{11f}','\u{11f}'],
+ ['\u{121}','\u{121}'],
+ ['\u{123}','\u{123}'],
+ ['\u{125}','\u{125}'],
+ ['\u{127}','\u{127}'],
+ ['\u{129}','\u{129}'],
+ ['\u{12b}','\u{12b}'],
+ ['\u{12d}','\u{12d}'],
+ ['\u{12f}','\u{12f}'],
+ ['\u{131}','\u{131}'],
+ ['\u{133}','\u{133}'],
+ ['\u{135}','\u{135}'],
+ ['\u{137}','\u{138}'],
+ ['\u{13a}','\u{13a}'],
+ ['\u{13c}','\u{13c}'],
+ ['\u{13e}','\u{13e}'],
+ ['\u{140}','\u{140}'],
+ ['\u{142}','\u{142}'],
+ ['\u{144}','\u{144}'],
+ ['\u{146}','\u{146}'],
+ ['\u{148}','\u{149}'],
+ ['\u{14b}','\u{14b}'],
+ ['\u{14d}','\u{14d}'],
+ ['\u{14f}','\u{14f}'],
+ ['\u{151}','\u{151}'],
+ ['\u{153}','\u{153}'],
+ ['\u{155}','\u{155}'],
+ ['\u{157}','\u{157}'],
+ ['\u{159}','\u{159}'],
+ ['\u{15b}','\u{15b}'],
+ ['\u{15d}','\u{15d}'],
+ ['\u{15f}','\u{15f}'],
+ ['\u{161}','\u{161}'],
+ ['\u{163}','\u{163}'],
+ ['\u{165}','\u{165}'],
+ ['\u{167}','\u{167}'],
+ ['\u{169}','\u{169}'],
+ ['\u{16b}','\u{16b}'],
+ ['\u{16d}','\u{16d}'],
+ ['\u{16f}','\u{16f}'],
+ ['\u{171}','\u{171}'],
+ ['\u{173}','\u{173}'],
+ ['\u{175}','\u{175}'],
+ ['\u{177}','\u{177}'],
+ ['\u{17a}','\u{17a}'],
+ ['\u{17c}','\u{17c}'],
+ ['\u{17e}','\u{180}'],
+ ['\u{183}','\u{183}'],
+ ['\u{185}','\u{185}'],
+ ['\u{188}','\u{188}'],
+ ['\u{18c}','\u{18d}'],
+ ['\u{192}','\u{192}'],
+ ['\u{195}','\u{195}'],
+ ['\u{199}','\u{19b}'],
+ ['\u{19e}','\u{19e}'],
+ ['\u{1a1}','\u{1a1}'],
+ ['\u{1a3}','\u{1a3}'],
+ ['\u{1a5}','\u{1a5}'],
+ ['\u{1a8}','\u{1a8}'],
+ ['\u{1aa}','\u{1ab}'],
+ ['\u{1ad}','\u{1ad}'],
+ ['\u{1b0}','\u{1b0}'],
+ ['\u{1b4}','\u{1b4}'],
+ ['\u{1b6}','\u{1b6}'],
+ ['\u{1b9}','\u{1ba}'],
+ ['\u{1bd}','\u{1bf}'],
+ ['\u{1c6}','\u{1c6}'],
+ ['\u{1c9}','\u{1c9}'],
+ ['\u{1cc}','\u{1cc}'],
+ ['\u{1ce}','\u{1ce}'],
+ ['\u{1d0}','\u{1d0}'],
+ ['\u{1d2}','\u{1d2}'],
+ ['\u{1d4}','\u{1d4}'],
+ ['\u{1d6}','\u{1d6}'],
+ ['\u{1d8}','\u{1d8}'],
+ ['\u{1da}','\u{1da}'],
+ ['\u{1dc}','\u{1dd}'],
+ ['\u{1df}','\u{1df}'],
+ ['\u{1e1}','\u{1e1}'],
+ ['\u{1e3}','\u{1e3}'],
+ ['\u{1e5}','\u{1e5}'],
+ ['\u{1e7}','\u{1e7}'],
+ ['\u{1e9}','\u{1e9}'],
+ ['\u{1eb}','\u{1eb}'],
+ ['\u{1ed}','\u{1ed}'],
+ ['\u{1ef}','\u{1f0}'],
+ ['\u{1f3}','\u{1f3}'],
+ ['\u{1f5}','\u{1f5}'],
+ ['\u{1f9}','\u{1f9}'],
+ ['\u{1fb}','\u{1fb}'],
+ ['\u{1fd}','\u{1fd}'],
+ ['\u{1ff}','\u{1ff}'],
+ ['\u{201}','\u{201}'],
+ ['\u{203}','\u{203}'],
+ ['\u{205}','\u{205}'],
+ ['\u{207}','\u{207}'],
+ ['\u{209}','\u{209}'],
+ ['\u{20b}','\u{20b}'],
+ ['\u{20d}','\u{20d}'],
+ ['\u{20f}','\u{20f}'],
+ ['\u{211}','\u{211}'],
+ ['\u{213}','\u{213}'],
+ ['\u{215}','\u{215}'],
+ ['\u{217}','\u{217}'],
+ ['\u{219}','\u{219}'],
+ ['\u{21b}','\u{21b}'],
+ ['\u{21d}','\u{21d}'],
+ ['\u{21f}','\u{21f}'],
+ ['\u{221}','\u{221}'],
+ ['\u{223}','\u{223}'],
+ ['\u{225}','\u{225}'],
+ ['\u{227}','\u{227}'],
+ ['\u{229}','\u{229}'],
+ ['\u{22b}','\u{22b}'],
+ ['\u{22d}','\u{22d}'],
+ ['\u{22f}','\u{22f}'],
+ ['\u{231}','\u{231}'],
+ ['\u{233}','\u{239}'],
+ ['\u{23c}','\u{23c}'],
+ ['\u{23f}','\u{240}'],
+ ['\u{242}','\u{242}'],
+ ['\u{247}','\u{247}'],
+ ['\u{249}','\u{249}'],
+ ['\u{24b}','\u{24b}'],
+ ['\u{24d}','\u{24d}'],
+ ['\u{24f}','\u{293}'],
+ ['\u{295}','\u{2af}'],
+ ['\u{371}','\u{371}'],
+ ['\u{373}','\u{373}'],
+ ['\u{377}','\u{377}'],
+ ['\u{37b}','\u{37d}'],
+ ['\u{390}','\u{390}'],
+ ['\u{3ac}','\u{3ce}'],
+ ['\u{3d0}','\u{3d1}'],
+ ['\u{3d5}','\u{3d7}'],
+ ['\u{3d9}','\u{3d9}'],
+ ['\u{3db}','\u{3db}'],
+ ['\u{3dd}','\u{3dd}'],
+ ['\u{3df}','\u{3df}'],
+ ['\u{3e1}','\u{3e1}'],
+ ['\u{3e3}','\u{3e3}'],
+ ['\u{3e5}','\u{3e5}'],
+ ['\u{3e7}','\u{3e7}'],
+ ['\u{3e9}','\u{3e9}'],
+ ['\u{3eb}','\u{3eb}'],
+ ['\u{3ed}','\u{3ed}'],
+ ['\u{3ef}','\u{3f3}'],
+ ['\u{3f5}','\u{3f5}'],
+ ['\u{3f8}','\u{3f8}'],
+ ['\u{3fb}','\u{3fc}'],
+ ['\u{430}','\u{45f}'],
+ ['\u{461}','\u{461}'],
+ ['\u{463}','\u{463}'],
+ ['\u{465}','\u{465}'],
+ ['\u{467}','\u{467}'],
+ ['\u{469}','\u{469}'],
+ ['\u{46b}','\u{46b}'],
+ ['\u{46d}','\u{46d}'],
+ ['\u{46f}','\u{46f}'],
+ ['\u{471}','\u{471}'],
+ ['\u{473}','\u{473}'],
+ ['\u{475}','\u{475}'],
+ ['\u{477}','\u{477}'],
+ ['\u{479}','\u{479}'],
+ ['\u{47b}','\u{47b}'],
+ ['\u{47d}','\u{47d}'],
+ ['\u{47f}','\u{47f}'],
+ ['\u{481}','\u{481}'],
+ ['\u{48b}','\u{48b}'],
+ ['\u{48d}','\u{48d}'],
+ ['\u{48f}','\u{48f}'],
+ ['\u{491}','\u{491}'],
+ ['\u{493}','\u{493}'],
+ ['\u{495}','\u{495}'],
+ ['\u{497}','\u{497}'],
+ ['\u{499}','\u{499}'],
+ ['\u{49b}','\u{49b}'],
+ ['\u{49d}','\u{49d}'],
+ ['\u{49f}','\u{49f}'],
+ ['\u{4a1}','\u{4a1}'],
+ ['\u{4a3}','\u{4a3}'],
+ ['\u{4a5}','\u{4a5}'],
+ ['\u{4a7}','\u{4a7}'],
+ ['\u{4a9}','\u{4a9}'],
+ ['\u{4ab}','\u{4ab}'],
+ ['\u{4ad}','\u{4ad}'],
+ ['\u{4af}','\u{4af}'],
+ ['\u{4b1}','\u{4b1}'],
+ ['\u{4b3}','\u{4b3}'],
+ ['\u{4b5}','\u{4b5}'],
+ ['\u{4b7}','\u{4b7}'],
+ ['\u{4b9}','\u{4b9}'],
+ ['\u{4bb}','\u{4bb}'],
+ ['\u{4bd}','\u{4bd}'],
+ ['\u{4bf}','\u{4bf}'],
+ ['\u{4c2}','\u{4c2}'],
+ ['\u{4c4}','\u{4c4}'],
+ ['\u{4c6}','\u{4c6}'],
+ ['\u{4c8}','\u{4c8}'],
+ ['\u{4ca}','\u{4ca}'],
+ ['\u{4cc}','\u{4cc}'],
+ ['\u{4ce}','\u{4cf}'],
+ ['\u{4d1}','\u{4d1}'],
+ ['\u{4d3}','\u{4d3}'],
+ ['\u{4d5}','\u{4d5}'],
+ ['\u{4d7}','\u{4d7}'],
+ ['\u{4d9}','\u{4d9}'],
+ ['\u{4db}','\u{4db}'],
+ ['\u{4dd}','\u{4dd}'],
+ ['\u{4df}','\u{4df}'],
+ ['\u{4e1}','\u{4e1}'],
+ ['\u{4e3}','\u{4e3}'],
+ ['\u{4e5}','\u{4e5}'],
+ ['\u{4e7}','\u{4e7}'],
+ ['\u{4e9}','\u{4e9}'],
+ ['\u{4eb}','\u{4eb}'],
+ ['\u{4ed}','\u{4ed}'],
+ ['\u{4ef}','\u{4ef}'],
+ ['\u{4f1}','\u{4f1}'],
+ ['\u{4f3}','\u{4f3}'],
+ ['\u{4f5}','\u{4f5}'],
+ ['\u{4f7}','\u{4f7}'],
+ ['\u{4f9}','\u{4f9}'],
+ ['\u{4fb}','\u{4fb}'],
+ ['\u{4fd}','\u{4fd}'],
+ ['\u{4ff}','\u{4ff}'],
+ ['\u{501}','\u{501}'],
+ ['\u{503}','\u{503}'],
+ ['\u{505}','\u{505}'],
+ ['\u{507}','\u{507}'],
+ ['\u{509}','\u{509}'],
+ ['\u{50b}','\u{50b}'],
+ ['\u{50d}','\u{50d}'],
+ ['\u{50f}','\u{50f}'],
+ ['\u{511}','\u{511}'],
+ ['\u{513}','\u{513}'],
+ ['\u{515}','\u{515}'],
+ ['\u{517}','\u{517}'],
+ ['\u{519}','\u{519}'],
+ ['\u{51b}','\u{51b}'],
+ ['\u{51d}','\u{51d}'],
+ ['\u{51f}','\u{51f}'],
+ ['\u{521}','\u{521}'],
+ ['\u{523}','\u{523}'],
+ ['\u{525}','\u{525}'],
+ ['\u{527}','\u{527}'],
+ ['\u{561}','\u{587}'],
+ ['\u{1d00}','\u{1d2b}'],
+ ['\u{1d6b}','\u{1d77}'],
+ ['\u{1d79}','\u{1d9a}'],
+ ['\u{1e01}','\u{1e01}'],
+ ['\u{1e03}','\u{1e03}'],
+ ['\u{1e05}','\u{1e05}'],
+ ['\u{1e07}','\u{1e07}'],
+ ['\u{1e09}','\u{1e09}'],
+ ['\u{1e0b}','\u{1e0b}'],
+ ['\u{1e0d}','\u{1e0d}'],
+ ['\u{1e0f}','\u{1e0f}'],
+ ['\u{1e11}','\u{1e11}'],
+ ['\u{1e13}','\u{1e13}'],
+ ['\u{1e15}','\u{1e15}'],
+ ['\u{1e17}','\u{1e17}'],
+ ['\u{1e19}','\u{1e19}'],
+ ['\u{1e1b}','\u{1e1b}'],
+ ['\u{1e1d}','\u{1e1d}'],
+ ['\u{1e1f}','\u{1e1f}'],
+ ['\u{1e21}','\u{1e21}'],
+ ['\u{1e23}','\u{1e23}'],
+ ['\u{1e25}','\u{1e25}'],
+ ['\u{1e27}','\u{1e27}'],
+ ['\u{1e29}','\u{1e29}'],
+ ['\u{1e2b}','\u{1e2b}'],
+ ['\u{1e2d}','\u{1e2d}'],
+ ['\u{1e2f}','\u{1e2f}'],
+ ['\u{1e31}','\u{1e31}'],
+ ['\u{1e33}','\u{1e33}'],
+ ['\u{1e35}','\u{1e35}'],
+ ['\u{1e37}','\u{1e37}'],
+ ['\u{1e39}','\u{1e39}'],
+ ['\u{1e3b}','\u{1e3b}'],
+ ['\u{1e3d}','\u{1e3d}'],
+ ['\u{1e3f}','\u{1e3f}'],
+ ['\u{1e41}','\u{1e41}'],
+ ['\u{1e43}','\u{1e43}'],
+ ['\u{1e45}','\u{1e45}'],
+ ['\u{1e47}','\u{1e47}'],
+ ['\u{1e49}','\u{1e49}'],
+ ['\u{1e4b}','\u{1e4b}'],
+ ['\u{1e4d}','\u{1e4d}'],
+ ['\u{1e4f}','\u{1e4f}'],
+ ['\u{1e51}','\u{1e51}'],
+ ['\u{1e53}','\u{1e53}'],
+ ['\u{1e55}','\u{1e55}'],
+ ['\u{1e57}','\u{1e57}'],
+ ['\u{1e59}','\u{1e59}'],
+ ['\u{1e5b}','\u{1e5b}'],
+ ['\u{1e5d}','\u{1e5d}'],
+ ['\u{1e5f}','\u{1e5f}'],
+ ['\u{1e61}','\u{1e61}'],
+ ['\u{1e63}','\u{1e63}'],
+ ['\u{1e65}','\u{1e65}'],
+ ['\u{1e67}','\u{1e67}'],
+ ['\u{1e69}','\u{1e69}'],
+ ['\u{1e6b}','\u{1e6b}'],
+ ['\u{1e6d}','\u{1e6d}'],
+ ['\u{1e6f}','\u{1e6f}'],
+ ['\u{1e71}','\u{1e71}'],
+ ['\u{1e73}','\u{1e73}'],
+ ['\u{1e75}','\u{1e75}'],
+ ['\u{1e77}','\u{1e77}'],
+ ['\u{1e79}','\u{1e79}'],
+ ['\u{1e7b}','\u{1e7b}'],
+ ['\u{1e7d}','\u{1e7d}'],
+ ['\u{1e7f}','\u{1e7f}'],
+ ['\u{1e81}','\u{1e81}'],
+ ['\u{1e83}','\u{1e83}'],
+ ['\u{1e85}','\u{1e85}'],
+ ['\u{1e87}','\u{1e87}'],
+ ['\u{1e89}','\u{1e89}'],
+ ['\u{1e8b}','\u{1e8b}'],
+ ['\u{1e8d}','\u{1e8d}'],
+ ['\u{1e8f}','\u{1e8f}'],
+ ['\u{1e91}','\u{1e91}'],
+ ['\u{1e93}','\u{1e93}'],
+ ['\u{1e95}','\u{1e9d}'],
+ ['\u{1e9f}','\u{1e9f}'],
+ ['\u{1ea1}','\u{1ea1}'],
+ ['\u{1ea3}','\u{1ea3}'],
+ ['\u{1ea5}','\u{1ea5}'],
+ ['\u{1ea7}','\u{1ea7}'],
+ ['\u{1ea9}','\u{1ea9}'],
+ ['\u{1eab}','\u{1eab}'],
+ ['\u{1ead}','\u{1ead}'],
+ ['\u{1eaf}','\u{1eaf}'],
+ ['\u{1eb1}','\u{1eb1}'],
+ ['\u{1eb3}','\u{1eb3}'],
+ ['\u{1eb5}','\u{1eb5}'],
+ ['\u{1eb7}','\u{1eb7}'],
+ ['\u{1eb9}','\u{1eb9}'],
+ ['\u{1ebb}','\u{1ebb}'],
+ ['\u{1ebd}','\u{1ebd}'],
+ ['\u{1ebf}','\u{1ebf}'],
+ ['\u{1ec1}','\u{1ec1}'],
+ ['\u{1ec3}','\u{1ec3}'],
+ ['\u{1ec5}','\u{1ec5}'],
+ ['\u{1ec7}','\u{1ec7}'],
+ ['\u{1ec9}','\u{1ec9}'],
+ ['\u{1ecb}','\u{1ecb}'],
+ ['\u{1ecd}','\u{1ecd}'],
+ ['\u{1ecf}','\u{1ecf}'],
+ ['\u{1ed1}','\u{1ed1}'],
+ ['\u{1ed3}','\u{1ed3}'],
+ ['\u{1ed5}','\u{1ed5}'],
+ ['\u{1ed7}','\u{1ed7}'],
+ ['\u{1ed9}','\u{1ed9}'],
+ ['\u{1edb}','\u{1edb}'],
+ ['\u{1edd}','\u{1edd}'],
+ ['\u{1edf}','\u{1edf}'],
+ ['\u{1ee1}','\u{1ee1}'],
+ ['\u{1ee3}','\u{1ee3}'],
+ ['\u{1ee5}','\u{1ee5}'],
+ ['\u{1ee7}','\u{1ee7}'],
+ ['\u{1ee9}','\u{1ee9}'],
+ ['\u{1eeb}','\u{1eeb}'],
+ ['\u{1eed}','\u{1eed}'],
+ ['\u{1eef}','\u{1eef}'],
+ ['\u{1ef1}','\u{1ef1}'],
+ ['\u{1ef3}','\u{1ef3}'],
+ ['\u{1ef5}','\u{1ef5}'],
+ ['\u{1ef7}','\u{1ef7}'],
+ ['\u{1ef9}','\u{1ef9}'],
+ ['\u{1efb}','\u{1efb}'],
+ ['\u{1efd}','\u{1efd}'],
+ ['\u{1eff}','\u{1f07}'],
+ ['\u{1f10}','\u{1f15}'],
+ ['\u{1f20}','\u{1f27}'],
+ ['\u{1f30}','\u{1f37}'],
+ ['\u{1f40}','\u{1f45}'],
+ ['\u{1f50}','\u{1f57}'],
+ ['\u{1f60}','\u{1f67}'],
+ ['\u{1f70}','\u{1f7d}'],
+ ['\u{1f80}','\u{1f87}'],
+ ['\u{1f90}','\u{1f97}'],
+ ['\u{1fa0}','\u{1fa7}'],
+ ['\u{1fb0}','\u{1fb4}'],
+ ['\u{1fb6}','\u{1fb7}'],
+ ['\u{1fbe}','\u{1fbe}'],
+ ['\u{1fc2}','\u{1fc4}'],
+ ['\u{1fc6}','\u{1fc7}'],
+ ['\u{1fd0}','\u{1fd3}'],
+ ['\u{1fd6}','\u{1fd7}'],
+ ['\u{1fe0}','\u{1fe7}'],
+ ['\u{1ff2}','\u{1ff4}'],
+ ['\u{1ff6}','\u{1ff7}'],
+ ['\u{210a}','\u{210a}'],
+ ['\u{210e}','\u{210f}'],
+ ['\u{2113}','\u{2113}'],
+ ['\u{212f}','\u{212f}'],
+ ['\u{2134}','\u{2134}'],
+ ['\u{2139}','\u{2139}'],
+ ['\u{213c}','\u{213d}'],
+ ['\u{2146}','\u{2149}'],
+ ['\u{214e}','\u{214e}'],
+ ['\u{2184}','\u{2184}'],
+ ['\u{2c30}','\u{2c5e}'],
+ ['\u{2c61}','\u{2c61}'],
+ ['\u{2c65}','\u{2c66}'],
+ ['\u{2c68}','\u{2c68}'],
+ ['\u{2c6a}','\u{2c6a}'],
+ ['\u{2c6c}','\u{2c6c}'],
+ ['\u{2c71}','\u{2c71}'],
+ ['\u{2c73}','\u{2c74}'],
+ ['\u{2c76}','\u{2c7b}'],
+ ['\u{2c81}','\u{2c81}'],
+ ['\u{2c83}','\u{2c83}'],
+ ['\u{2c85}','\u{2c85}'],
+ ['\u{2c87}','\u{2c87}'],
+ ['\u{2c89}','\u{2c89}'],
+ ['\u{2c8b}','\u{2c8b}'],
+ ['\u{2c8d}','\u{2c8d}'],
+ ['\u{2c8f}','\u{2c8f}'],
+ ['\u{2c91}','\u{2c91}'],
+ ['\u{2c93}','\u{2c93}'],
+ ['\u{2c95}','\u{2c95}'],
+ ['\u{2c97}','\u{2c97}'],
+ ['\u{2c99}','\u{2c99}'],
+ ['\u{2c9b}','\u{2c9b}'],
+ ['\u{2c9d}','\u{2c9d}'],
+ ['\u{2c9f}','\u{2c9f}'],
+ ['\u{2ca1}','\u{2ca1}'],
+ ['\u{2ca3}','\u{2ca3}'],
+ ['\u{2ca5}','\u{2ca5}'],
+ ['\u{2ca7}','\u{2ca7}'],
+ ['\u{2ca9}','\u{2ca9}'],
+ ['\u{2cab}','\u{2cab}'],
+ ['\u{2cad}','\u{2cad}'],
+ ['\u{2caf}','\u{2caf}'],
+ ['\u{2cb1}','\u{2cb1}'],
+ ['\u{2cb3}','\u{2cb3}'],
+ ['\u{2cb5}','\u{2cb5}'],
+ ['\u{2cb7}','\u{2cb7}'],
+ ['\u{2cb9}','\u{2cb9}'],
+ ['\u{2cbb}','\u{2cbb}'],
+ ['\u{2cbd}','\u{2cbd}'],
+ ['\u{2cbf}','\u{2cbf}'],
+ ['\u{2cc1}','\u{2cc1}'],
+ ['\u{2cc3}','\u{2cc3}'],
+ ['\u{2cc5}','\u{2cc5}'],
+ ['\u{2cc7}','\u{2cc7}'],
+ ['\u{2cc9}','\u{2cc9}'],
+ ['\u{2ccb}','\u{2ccb}'],
+ ['\u{2ccd}','\u{2ccd}'],
+ ['\u{2ccf}','\u{2ccf}'],
+ ['\u{2cd1}','\u{2cd1}'],
+ ['\u{2cd3}','\u{2cd3}'],
+ ['\u{2cd5}','\u{2cd5}'],
+ ['\u{2cd7}','\u{2cd7}'],
+ ['\u{2cd9}','\u{2cd9}'],
+ ['\u{2cdb}','\u{2cdb}'],
+ ['\u{2cdd}','\u{2cdd}'],
+ ['\u{2cdf}','\u{2cdf}'],
+ ['\u{2ce1}','\u{2ce1}'],
+ ['\u{2ce3}','\u{2ce4}'],
+ ['\u{2cec}','\u{2cec}'],
+ ['\u{2cee}','\u{2cee}'],
+ ['\u{2cf3}','\u{2cf3}'],
+ ['\u{2d00}','\u{2d25}'],
+ ['\u{2d27}','\u{2d27}'],
+ ['\u{2d2d}','\u{2d2d}'],
+ ['\u{a641}','\u{a641}'],
+ ['\u{a643}','\u{a643}'],
+ ['\u{a645}','\u{a645}'],
+ ['\u{a647}','\u{a647}'],
+ ['\u{a649}','\u{a649}'],
+ ['\u{a64b}','\u{a64b}'],
+ ['\u{a64d}','\u{a64d}'],
+ ['\u{a64f}','\u{a64f}'],
+ ['\u{a651}','\u{a651}'],
+ ['\u{a653}','\u{a653}'],
+ ['\u{a655}','\u{a655}'],
+ ['\u{a657}','\u{a657}'],
+ ['\u{a659}','\u{a659}'],
+ ['\u{a65b}','\u{a65b}'],
+ ['\u{a65d}','\u{a65d}'],
+ ['\u{a65f}','\u{a65f}'],
+ ['\u{a661}','\u{a661}'],
+ ['\u{a663}','\u{a663}'],
+ ['\u{a665}','\u{a665}'],
+ ['\u{a667}','\u{a667}'],
+ ['\u{a669}','\u{a669}'],
+ ['\u{a66b}','\u{a66b}'],
+ ['\u{a66d}','\u{a66d}'],
+ ['\u{a681}','\u{a681}'],
+ ['\u{a683}','\u{a683}'],
+ ['\u{a685}','\u{a685}'],
+ ['\u{a687}','\u{a687}'],
+ ['\u{a689}','\u{a689}'],
+ ['\u{a68b}','\u{a68b}'],
+ ['\u{a68d}','\u{a68d}'],
+ ['\u{a68f}','\u{a68f}'],
+ ['\u{a691}','\u{a691}'],
+ ['\u{a693}','\u{a693}'],
+ ['\u{a695}','\u{a695}'],
+ ['\u{a697}','\u{a697}'],
+ ['\u{a723}','\u{a723}'],
+ ['\u{a725}','\u{a725}'],
+ ['\u{a727}','\u{a727}'],
+ ['\u{a729}','\u{a729}'],
+ ['\u{a72b}','\u{a72b}'],
+ ['\u{a72d}','\u{a72d}'],
+ ['\u{a72f}','\u{a731}'],
+ ['\u{a733}','\u{a733}'],
+ ['\u{a735}','\u{a735}'],
+ ['\u{a737}','\u{a737}'],
+ ['\u{a739}','\u{a739}'],
+ ['\u{a73b}','\u{a73b}'],
+ ['\u{a73d}','\u{a73d}'],
+ ['\u{a73f}','\u{a73f}'],
+ ['\u{a741}','\u{a741}'],
+ ['\u{a743}','\u{a743}'],
+ ['\u{a745}','\u{a745}'],
+ ['\u{a747}','\u{a747}'],
+ ['\u{a749}','\u{a749}'],
+ ['\u{a74b}','\u{a74b}'],
+ ['\u{a74d}','\u{a74d}'],
+ ['\u{a74f}','\u{a74f}'],
+ ['\u{a751}','\u{a751}'],
+ ['\u{a753}','\u{a753}'],
+ ['\u{a755}','\u{a755}'],
+ ['\u{a757}','\u{a757}'],
+ ['\u{a759}','\u{a759}'],
+ ['\u{a75b}','\u{a75b}'],
+ ['\u{a75d}','\u{a75d}'],
+ ['\u{a75f}','\u{a75f}'],
+ ['\u{a761}','\u{a761}'],
+ ['\u{a763}','\u{a763}'],
+ ['\u{a765}','\u{a765}'],
+ ['\u{a767}','\u{a767}'],
+ ['\u{a769}','\u{a769}'],
+ ['\u{a76b}','\u{a76b}'],
+ ['\u{a76d}','\u{a76d}'],
+ ['\u{a76f}','\u{a76f}'],
+ ['\u{a771}','\u{a778}'],
+ ['\u{a77a}','\u{a77a}'],
+ ['\u{a77c}','\u{a77c}'],
+ ['\u{a77f}','\u{a77f}'],
+ ['\u{a781}','\u{a781}'],
+ ['\u{a783}','\u{a783}'],
+ ['\u{a785}','\u{a785}'],
+ ['\u{a787}','\u{a787}'],
+ ['\u{a78c}','\u{a78c}'],
+ ['\u{a78e}','\u{a78e}'],
+ ['\u{a791}','\u{a791}'],
+ ['\u{a793}','\u{a793}'],
+ ['\u{a7a1}','\u{a7a1}'],
+ ['\u{a7a3}','\u{a7a3}'],
+ ['\u{a7a5}','\u{a7a5}'],
+ ['\u{a7a7}','\u{a7a7}'],
+ ['\u{a7a9}','\u{a7a9}'],
+ ['\u{a7fa}','\u{a7fa}'],
+ ['\u{fb00}','\u{fb06}'],
+ ['\u{fb13}','\u{fb17}'],
+ ['\u{ff41}','\u{ff5a}'],
+ ['\u{10428}','\u{1044f}'],
+ ['\u{1d41a}','\u{1d433}'],
+ ['\u{1d44e}','\u{1d454}'],
+ ['\u{1d456}','\u{1d467}'],
+ ['\u{1d482}','\u{1d49b}'],
+ ['\u{1d4b6}','\u{1d4b9}'],
+ ['\u{1d4bb}','\u{1d4bb}'],
+ ['\u{1d4bd}','\u{1d4c3}'],
+ ['\u{1d4c5}','\u{1d4cf}'],
+ ['\u{1d4ea}','\u{1d503}'],
+ ['\u{1d51e}','\u{1d537}'],
+ ['\u{1d552}','\u{1d56b}'],
+ ['\u{1d586}','\u{1d59f}'],
+ ['\u{1d5ba}','\u{1d5d3}'],
+ ['\u{1d5ee}','\u{1d607}'],
+ ['\u{1d622}','\u{1d63b}'],
+ ['\u{1d656}','\u{1d66f}'],
+ ['\u{1d68a}','\u{1d6a5}'],
+ ['\u{1d6c2}','\u{1d6da}'],
+ ['\u{1d6dc}','\u{1d6e1}'],
+ ['\u{1d6fc}','\u{1d714}'],
+ ['\u{1d716}','\u{1d71b}'],
+ ['\u{1d736}','\u{1d74e}'],
+ ['\u{1d750}','\u{1d755}'],
+ ['\u{1d770}','\u{1d788}'],
+ ['\u{1d78a}','\u{1d78f}'],
+ ['\u{1d7aa}','\u{1d7c2}'],
+ ['\u{1d7c4}','\u{1d7c9}'],
+ ['\u{1d7cb}','\u{1d7cb}'],
+]
+
+const tabtitle = [
+ ['\u{1c5}','\u{1c5}'],
+ ['\u{1c8}','\u{1c8}'],
+ ['\u{1cb}','\u{1cb}'],
+ ['\u{1f2}','\u{1f2}'],
+ ['\u{1f88}','\u{1f8f}'],
+ ['\u{1f98}','\u{1f9f}'],
+ ['\u{1fa8}','\u{1faf}'],
+ ['\u{1fbc}','\u{1fbc}'],
+ ['\u{1fcc}','\u{1fcc}'],
+ ['\u{1ffc}','\u{1ffc}'],
+]
+
+const tabword = [
+ ['\u{30}','\u{39}'],
+ ['\u{41}','\u{5a}'],
+ ['\u{5f}','\u{5f}'],
+ ['\u{61}','\u{7a}'],
+ ['\u{aa}','\u{aa}'],
+ ['\u{b5}','\u{b5}'],
+ ['\u{ba}','\u{ba}'],
+ ['\u{c0}','\u{d6}'],
+ ['\u{d8}','\u{f6}'],
+ ['\u{f8}','\u{2c1}'],
+ ['\u{2c6}','\u{2d1}'],
+ ['\u{2e0}','\u{2e4}'],
+ ['\u{2ec}','\u{2ec}'],
+ ['\u{2ee}','\u{2ee}'],
+ ['\u{370}','\u{374}'],
+ ['\u{376}','\u{377}'],
+ ['\u{37a}','\u{37d}'],
+ ['\u{386}','\u{386}'],
+ ['\u{388}','\u{38a}'],
+ ['\u{38c}','\u{38c}'],
+ ['\u{38e}','\u{3a1}'],
+ ['\u{3a3}','\u{3f5}'],
+ ['\u{3f7}','\u{481}'],
+ ['\u{48a}','\u{527}'],
+ ['\u{531}','\u{556}'],
+ ['\u{559}','\u{559}'],
+ ['\u{561}','\u{587}'],
+ ['\u{5d0}','\u{5ea}'],
+ ['\u{5f0}','\u{5f2}'],
+ ['\u{620}','\u{64a}'],
+ ['\u{660}','\u{669}'],
+ ['\u{66e}','\u{66f}'],
+ ['\u{671}','\u{6d3}'],
+ ['\u{6d5}','\u{6d5}'],
+ ['\u{6e5}','\u{6e6}'],
+ ['\u{6ee}','\u{6fc}'],
+ ['\u{6ff}','\u{6ff}'],
+ ['\u{710}','\u{710}'],
+ ['\u{712}','\u{72f}'],
+ ['\u{74d}','\u{7a5}'],
+ ['\u{7b1}','\u{7b1}'],
+ ['\u{7c0}','\u{7ea}'],
+ ['\u{7f4}','\u{7f5}'],
+ ['\u{7fa}','\u{7fa}'],
+ ['\u{800}','\u{815}'],
+ ['\u{81a}','\u{81a}'],
+ ['\u{824}','\u{824}'],
+ ['\u{828}','\u{828}'],
+ ['\u{840}','\u{858}'],
+ ['\u{8a0}','\u{8a0}'],
+ ['\u{8a2}','\u{8ac}'],
+ ['\u{904}','\u{939}'],
+ ['\u{93d}','\u{93d}'],
+ ['\u{950}','\u{950}'],
+ ['\u{958}','\u{961}'],
+ ['\u{966}','\u{96f}'],
+ ['\u{971}','\u{977}'],
+ ['\u{979}','\u{97f}'],
+ ['\u{985}','\u{98c}'],
+ ['\u{98f}','\u{990}'],
+ ['\u{993}','\u{9a8}'],
+ ['\u{9aa}','\u{9b0}'],
+ ['\u{9b2}','\u{9b2}'],
+ ['\u{9b6}','\u{9b9}'],
+ ['\u{9bd}','\u{9bd}'],
+ ['\u{9ce}','\u{9ce}'],
+ ['\u{9dc}','\u{9dd}'],
+ ['\u{9df}','\u{9e1}'],
+ ['\u{9e6}','\u{9f1}'],
+ ['\u{a05}','\u{a0a}'],
+ ['\u{a0f}','\u{a10}'],
+ ['\u{a13}','\u{a28}'],
+ ['\u{a2a}','\u{a30}'],
+ ['\u{a32}','\u{a33}'],
+ ['\u{a35}','\u{a36}'],
+ ['\u{a38}','\u{a39}'],
+ ['\u{a59}','\u{a5c}'],
+ ['\u{a5e}','\u{a5e}'],
+ ['\u{a66}','\u{a6f}'],
+ ['\u{a72}','\u{a74}'],
+ ['\u{a85}','\u{a8d}'],
+ ['\u{a8f}','\u{a91}'],
+ ['\u{a93}','\u{aa8}'],
+ ['\u{aaa}','\u{ab0}'],
+ ['\u{ab2}','\u{ab3}'],
+ ['\u{ab5}','\u{ab9}'],
+ ['\u{abd}','\u{abd}'],
+ ['\u{ad0}','\u{ad0}'],
+ ['\u{ae0}','\u{ae1}'],
+ ['\u{ae6}','\u{aef}'],
+ ['\u{b05}','\u{b0c}'],
+ ['\u{b0f}','\u{b10}'],
+ ['\u{b13}','\u{b28}'],
+ ['\u{b2a}','\u{b30}'],
+ ['\u{b32}','\u{b33}'],
+ ['\u{b35}','\u{b39}'],
+ ['\u{b3d}','\u{b3d}'],
+ ['\u{b5c}','\u{b5d}'],
+ ['\u{b5f}','\u{b61}'],
+ ['\u{b66}','\u{b6f}'],
+ ['\u{b71}','\u{b71}'],
+ ['\u{b83}','\u{b83}'],
+ ['\u{b85}','\u{b8a}'],
+ ['\u{b8e}','\u{b90}'],
+ ['\u{b92}','\u{b95}'],
+ ['\u{b99}','\u{b9a}'],
+ ['\u{b9c}','\u{b9c}'],
+ ['\u{b9e}','\u{b9f}'],
+ ['\u{ba3}','\u{ba4}'],
+ ['\u{ba8}','\u{baa}'],
+ ['\u{bae}','\u{bb9}'],
+ ['\u{bd0}','\u{bd0}'],
+ ['\u{be6}','\u{bef}'],
+ ['\u{c05}','\u{c0c}'],
+ ['\u{c0e}','\u{c10}'],
+ ['\u{c12}','\u{c28}'],
+ ['\u{c2a}','\u{c33}'],
+ ['\u{c35}','\u{c39}'],
+ ['\u{c3d}','\u{c3d}'],
+ ['\u{c58}','\u{c59}'],
+ ['\u{c60}','\u{c61}'],
+ ['\u{c66}','\u{c6f}'],
+ ['\u{c85}','\u{c8c}'],
+ ['\u{c8e}','\u{c90}'],
+ ['\u{c92}','\u{ca8}'],
+ ['\u{caa}','\u{cb3}'],
+ ['\u{cb5}','\u{cb9}'],
+ ['\u{cbd}','\u{cbd}'],
+ ['\u{cde}','\u{cde}'],
+ ['\u{ce0}','\u{ce1}'],
+ ['\u{ce6}','\u{cef}'],
+ ['\u{cf1}','\u{cf2}'],
+ ['\u{d05}','\u{d0c}'],
+ ['\u{d0e}','\u{d10}'],
+ ['\u{d12}','\u{d3a}'],
+ ['\u{d3d}','\u{d3d}'],
+ ['\u{d4e}','\u{d4e}'],
+ ['\u{d60}','\u{d61}'],
+ ['\u{d66}','\u{d6f}'],
+ ['\u{d7a}','\u{d7f}'],
+ ['\u{d85}','\u{d96}'],
+ ['\u{d9a}','\u{db1}'],
+ ['\u{db3}','\u{dbb}'],
+ ['\u{dbd}','\u{dbd}'],
+ ['\u{dc0}','\u{dc6}'],
+ ['\u{e01}','\u{e30}'],
+ ['\u{e32}','\u{e33}'],
+ ['\u{e40}','\u{e46}'],
+ ['\u{e50}','\u{e59}'],
+ ['\u{e81}','\u{e82}'],
+ ['\u{e84}','\u{e84}'],
+ ['\u{e87}','\u{e88}'],
+ ['\u{e8a}','\u{e8a}'],
+ ['\u{e8d}','\u{e8d}'],
+ ['\u{e94}','\u{e97}'],
+ ['\u{e99}','\u{e9f}'],
+ ['\u{ea1}','\u{ea3}'],
+ ['\u{ea5}','\u{ea5}'],
+ ['\u{ea7}','\u{ea7}'],
+ ['\u{eaa}','\u{eab}'],
+ ['\u{ead}','\u{eb0}'],
+ ['\u{eb2}','\u{eb3}'],
+ ['\u{ebd}','\u{ebd}'],
+ ['\u{ec0}','\u{ec4}'],
+ ['\u{ec6}','\u{ec6}'],
+ ['\u{ed0}','\u{ed9}'],
+ ['\u{edc}','\u{edf}'],
+ ['\u{f00}','\u{f00}'],
+ ['\u{f20}','\u{f29}'],
+ ['\u{f40}','\u{f47}'],
+ ['\u{f49}','\u{f6c}'],
+ ['\u{f88}','\u{f8c}'],
+ ['\u{1000}','\u{102a}'],
+ ['\u{103f}','\u{1049}'],
+ ['\u{1050}','\u{1055}'],
+ ['\u{105a}','\u{105d}'],
+ ['\u{1061}','\u{1061}'],
+ ['\u{1065}','\u{1066}'],
+ ['\u{106e}','\u{1070}'],
+ ['\u{1075}','\u{1081}'],
+ ['\u{108e}','\u{108e}'],
+ ['\u{1090}','\u{1099}'],
+ ['\u{10a0}','\u{10c5}'],
+ ['\u{10c7}','\u{10c7}'],
+ ['\u{10cd}','\u{10cd}'],
+ ['\u{10d0}','\u{10fa}'],
+ ['\u{10fc}','\u{1248}'],
+ ['\u{124a}','\u{124d}'],
+ ['\u{1250}','\u{1256}'],
+ ['\u{1258}','\u{1258}'],
+ ['\u{125a}','\u{125d}'],
+ ['\u{1260}','\u{1288}'],
+ ['\u{128a}','\u{128d}'],
+ ['\u{1290}','\u{12b0}'],
+ ['\u{12b2}','\u{12b5}'],
+ ['\u{12b8}','\u{12be}'],
+ ['\u{12c0}','\u{12c0}'],
+ ['\u{12c2}','\u{12c5}'],
+ ['\u{12c8}','\u{12d6}'],
+ ['\u{12d8}','\u{1310}'],
+ ['\u{1312}','\u{1315}'],
+ ['\u{1318}','\u{135a}'],
+ ['\u{1380}','\u{138f}'],
+ ['\u{13a0}','\u{13f4}'],
+ ['\u{1401}','\u{166c}'],
+ ['\u{166f}','\u{167f}'],
+ ['\u{1681}','\u{169a}'],
+ ['\u{16a0}','\u{16ea}'],
+ ['\u{1700}','\u{170c}'],
+ ['\u{170e}','\u{1711}'],
+ ['\u{1720}','\u{1731}'],
+ ['\u{1740}','\u{1751}'],
+ ['\u{1760}','\u{176c}'],
+ ['\u{176e}','\u{1770}'],
+ ['\u{1780}','\u{17b3}'],
+ ['\u{17d7}','\u{17d7}'],
+ ['\u{17dc}','\u{17dc}'],
+ ['\u{17e0}','\u{17e9}'],
+ ['\u{1810}','\u{1819}'],
+ ['\u{1820}','\u{1877}'],
+ ['\u{1880}','\u{18a8}'],
+ ['\u{18aa}','\u{18aa}'],
+ ['\u{18b0}','\u{18f5}'],
+ ['\u{1900}','\u{191c}'],
+ ['\u{1946}','\u{196d}'],
+ ['\u{1970}','\u{1974}'],
+ ['\u{1980}','\u{19ab}'],
+ ['\u{19c1}','\u{19c7}'],
+ ['\u{19d0}','\u{19d9}'],
+ ['\u{1a00}','\u{1a16}'],
+ ['\u{1a20}','\u{1a54}'],
+ ['\u{1a80}','\u{1a89}'],
+ ['\u{1a90}','\u{1a99}'],
+ ['\u{1aa7}','\u{1aa7}'],
+ ['\u{1b05}','\u{1b33}'],
+ ['\u{1b45}','\u{1b4b}'],
+ ['\u{1b50}','\u{1b59}'],
+ ['\u{1b83}','\u{1ba0}'],
+ ['\u{1bae}','\u{1be5}'],
+ ['\u{1c00}','\u{1c23}'],
+ ['\u{1c40}','\u{1c49}'],
+ ['\u{1c4d}','\u{1c7d}'],
+ ['\u{1ce9}','\u{1cec}'],
+ ['\u{1cee}','\u{1cf1}'],
+ ['\u{1cf5}','\u{1cf6}'],
+ ['\u{1d00}','\u{1dbf}'],
+ ['\u{1e00}','\u{1f15}'],
+ ['\u{1f18}','\u{1f1d}'],
+ ['\u{1f20}','\u{1f45}'],
+ ['\u{1f48}','\u{1f4d}'],
+ ['\u{1f50}','\u{1f57}'],
+ ['\u{1f59}','\u{1f59}'],
+ ['\u{1f5b}','\u{1f5b}'],
+ ['\u{1f5d}','\u{1f5d}'],
+ ['\u{1f5f}','\u{1f7d}'],
+ ['\u{1f80}','\u{1fb4}'],
+ ['\u{1fb6}','\u{1fbc}'],
+ ['\u{1fbe}','\u{1fbe}'],
+ ['\u{1fc2}','\u{1fc4}'],
+ ['\u{1fc6}','\u{1fcc}'],
+ ['\u{1fd0}','\u{1fd3}'],
+ ['\u{1fd6}','\u{1fdb}'],
+ ['\u{1fe0}','\u{1fec}'],
+ ['\u{1ff2}','\u{1ff4}'],
+ ['\u{1ff6}','\u{1ffc}'],
+ ['\u{2071}','\u{2071}'],
+ ['\u{207f}','\u{207f}'],
+ ['\u{2090}','\u{209c}'],
+ ['\u{2102}','\u{2102}'],
+ ['\u{2107}','\u{2107}'],
+ ['\u{210a}','\u{2113}'],
+ ['\u{2115}','\u{2115}'],
+ ['\u{2119}','\u{211d}'],
+ ['\u{2124}','\u{2124}'],
+ ['\u{2126}','\u{2126}'],
+ ['\u{2128}','\u{2128}'],
+ ['\u{212a}','\u{212d}'],
+ ['\u{212f}','\u{2139}'],
+ ['\u{213c}','\u{213f}'],
+ ['\u{2145}','\u{2149}'],
+ ['\u{214e}','\u{214e}'],
+ ['\u{2183}','\u{2184}'],
+ ['\u{2c00}','\u{2c2e}'],
+ ['\u{2c30}','\u{2c5e}'],
+ ['\u{2c60}','\u{2ce4}'],
+ ['\u{2ceb}','\u{2cee}'],
+ ['\u{2cf2}','\u{2cf3}'],
+ ['\u{2d00}','\u{2d25}'],
+ ['\u{2d27}','\u{2d27}'],
+ ['\u{2d2d}','\u{2d2d}'],
+ ['\u{2d30}','\u{2d67}'],
+ ['\u{2d6f}','\u{2d6f}'],
+ ['\u{2d80}','\u{2d96}'],
+ ['\u{2da0}','\u{2da6}'],
+ ['\u{2da8}','\u{2dae}'],
+ ['\u{2db0}','\u{2db6}'],
+ ['\u{2db8}','\u{2dbe}'],
+ ['\u{2dc0}','\u{2dc6}'],
+ ['\u{2dc8}','\u{2dce}'],
+ ['\u{2dd0}','\u{2dd6}'],
+ ['\u{2dd8}','\u{2dde}'],
+ ['\u{2e2f}','\u{2e2f}'],
+ ['\u{3005}','\u{3006}'],
+ ['\u{3031}','\u{3035}'],
+ ['\u{303b}','\u{303c}'],
+ ['\u{3041}','\u{3096}'],
+ ['\u{309d}','\u{309f}'],
+ ['\u{30a1}','\u{30fa}'],
+ ['\u{30fc}','\u{30ff}'],
+ ['\u{3105}','\u{312d}'],
+ ['\u{3131}','\u{318e}'],
+ ['\u{31a0}','\u{31ba}'],
+ ['\u{31f0}','\u{31ff}'],
+ ['\u{3400}','\u{4db5}'],
+ ['\u{4e00}','\u{9fcc}'],
+ ['\u{a000}','\u{a48c}'],
+ ['\u{a4d0}','\u{a4fd}'],
+ ['\u{a500}','\u{a60c}'],
+ ['\u{a610}','\u{a62b}'],
+ ['\u{a640}','\u{a66e}'],
+ ['\u{a67f}','\u{a697}'],
+ ['\u{a6a0}','\u{a6e5}'],
+ ['\u{a717}','\u{a71f}'],
+ ['\u{a722}','\u{a788}'],
+ ['\u{a78b}','\u{a78e}'],
+ ['\u{a790}','\u{a793}'],
+ ['\u{a7a0}','\u{a7aa}'],
+ ['\u{a7f8}','\u{a801}'],
+ ['\u{a803}','\u{a805}'],
+ ['\u{a807}','\u{a80a}'],
+ ['\u{a80c}','\u{a822}'],
+ ['\u{a840}','\u{a873}'],
+ ['\u{a882}','\u{a8b3}'],
+ ['\u{a8d0}','\u{a8d9}'],
+ ['\u{a8f2}','\u{a8f7}'],
+ ['\u{a8fb}','\u{a8fb}'],
+ ['\u{a900}','\u{a925}'],
+ ['\u{a930}','\u{a946}'],
+ ['\u{a960}','\u{a97c}'],
+ ['\u{a984}','\u{a9b2}'],
+ ['\u{a9cf}','\u{a9d9}'],
+ ['\u{aa00}','\u{aa28}'],
+ ['\u{aa40}','\u{aa42}'],
+ ['\u{aa44}','\u{aa4b}'],
+ ['\u{aa50}','\u{aa59}'],
+ ['\u{aa60}','\u{aa76}'],
+ ['\u{aa7a}','\u{aa7a}'],
+ ['\u{aa80}','\u{aaaf}'],
+ ['\u{aab1}','\u{aab1}'],
+ ['\u{aab5}','\u{aab6}'],
+ ['\u{aab9}','\u{aabd}'],
+ ['\u{aac0}','\u{aac0}'],
+ ['\u{aac2}','\u{aac2}'],
+ ['\u{aadb}','\u{aadd}'],
+ ['\u{aae0}','\u{aaea}'],
+ ['\u{aaf2}','\u{aaf4}'],
+ ['\u{ab01}','\u{ab06}'],
+ ['\u{ab09}','\u{ab0e}'],
+ ['\u{ab11}','\u{ab16}'],
+ ['\u{ab20}','\u{ab26}'],
+ ['\u{ab28}','\u{ab2e}'],
+ ['\u{abc0}','\u{abe2}'],
+ ['\u{abf0}','\u{abf9}'],
+ ['\u{ac00}','\u{d7a3}'],
+ ['\u{d7b0}','\u{d7c6}'],
+ ['\u{d7cb}','\u{d7fb}'],
+ ['\u{f900}','\u{fa6d}'],
+ ['\u{fa70}','\u{fad9}'],
+ ['\u{fb00}','\u{fb06}'],
+ ['\u{fb13}','\u{fb17}'],
+ ['\u{fb1d}','\u{fb1d}'],
+ ['\u{fb1f}','\u{fb28}'],
+ ['\u{fb2a}','\u{fb36}'],
+ ['\u{fb38}','\u{fb3c}'],
+ ['\u{fb3e}','\u{fb3e}'],
+ ['\u{fb40}','\u{fb41}'],
+ ['\u{fb43}','\u{fb44}'],
+ ['\u{fb46}','\u{fbb1}'],
+ ['\u{fbd3}','\u{fd3d}'],
+ ['\u{fd50}','\u{fd8f}'],
+ ['\u{fd92}','\u{fdc7}'],
+ ['\u{fdf0}','\u{fdfb}'],
+ ['\u{fe70}','\u{fe74}'],
+ ['\u{fe76}','\u{fefc}'],
+ ['\u{ff10}','\u{ff19}'],
+ ['\u{ff21}','\u{ff3a}'],
+ ['\u{ff41}','\u{ff5a}'],
+ ['\u{ff66}','\u{ffbe}'],
+ ['\u{ffc2}','\u{ffc7}'],
+ ['\u{ffca}','\u{ffcf}'],
+ ['\u{ffd2}','\u{ffd7}'],
+ ['\u{ffda}','\u{ffdc}'],
+ ['\u{10000}','\u{1000b}'],
+ ['\u{1000d}','\u{10026}'],
+ ['\u{10028}','\u{1003a}'],
+ ['\u{1003c}','\u{1003d}'],
+ ['\u{1003f}','\u{1004d}'],
+ ['\u{10050}','\u{1005d}'],
+ ['\u{10080}','\u{100fa}'],
+ ['\u{10280}','\u{1029c}'],
+ ['\u{102a0}','\u{102d0}'],
+ ['\u{10300}','\u{1031e}'],
+ ['\u{10330}','\u{10340}'],
+ ['\u{10342}','\u{10349}'],
+ ['\u{10380}','\u{1039d}'],
+ ['\u{103a0}','\u{103c3}'],
+ ['\u{103c8}','\u{103cf}'],
+ ['\u{10400}','\u{1049d}'],
+ ['\u{104a0}','\u{104a9}'],
+ ['\u{10800}','\u{10805}'],
+ ['\u{10808}','\u{10808}'],
+ ['\u{1080a}','\u{10835}'],
+ ['\u{10837}','\u{10838}'],
+ ['\u{1083c}','\u{1083c}'],
+ ['\u{1083f}','\u{10855}'],
+ ['\u{10900}','\u{10915}'],
+ ['\u{10920}','\u{10939}'],
+ ['\u{10980}','\u{109b7}'],
+ ['\u{109be}','\u{109bf}'],
+ ['\u{10a00}','\u{10a00}'],
+ ['\u{10a10}','\u{10a13}'],
+ ['\u{10a15}','\u{10a17}'],
+ ['\u{10a19}','\u{10a33}'],
+ ['\u{10a60}','\u{10a7c}'],
+ ['\u{10b00}','\u{10b35}'],
+ ['\u{10b40}','\u{10b55}'],
+ ['\u{10b60}','\u{10b72}'],
+ ['\u{10c00}','\u{10c48}'],
+ ['\u{11003}','\u{11037}'],
+ ['\u{11066}','\u{1106f}'],
+ ['\u{11083}','\u{110af}'],
+ ['\u{110d0}','\u{110e8}'],
+ ['\u{110f0}','\u{110f9}'],
+ ['\u{11103}','\u{11126}'],
+ ['\u{11136}','\u{1113f}'],
+ ['\u{11183}','\u{111b2}'],
+ ['\u{111c1}','\u{111c4}'],
+ ['\u{111d0}','\u{111d9}'],
+ ['\u{11680}','\u{116aa}'],
+ ['\u{116c0}','\u{116c9}'],
+ ['\u{12000}','\u{1236e}'],
+ ['\u{13000}','\u{1342e}'],
+ ['\u{16800}','\u{16a38}'],
+ ['\u{16f00}','\u{16f44}'],
+ ['\u{16f50}','\u{16f50}'],
+ ['\u{16f93}','\u{16f9f}'],
+ ['\u{1b000}','\u{1b001}'],
+ ['\u{1d400}','\u{1d454}'],
+ ['\u{1d456}','\u{1d49c}'],
+ ['\u{1d49e}','\u{1d49f}'],
+ ['\u{1d4a2}','\u{1d4a2}'],
+ ['\u{1d4a5}','\u{1d4a6}'],
+ ['\u{1d4a9}','\u{1d4ac}'],
+ ['\u{1d4ae}','\u{1d4b9}'],
+ ['\u{1d4bb}','\u{1d4bb}'],
+ ['\u{1d4bd}','\u{1d4c3}'],
+ ['\u{1d4c5}','\u{1d505}'],
+ ['\u{1d507}','\u{1d50a}'],
+ ['\u{1d50d}','\u{1d514}'],
+ ['\u{1d516}','\u{1d51c}'],
+ ['\u{1d51e}','\u{1d539}'],
+ ['\u{1d53b}','\u{1d53e}'],
+ ['\u{1d540}','\u{1d544}'],
+ ['\u{1d546}','\u{1d546}'],
+ ['\u{1d54a}','\u{1d550}'],
+ ['\u{1d552}','\u{1d6a5}'],
+ ['\u{1d6a8}','\u{1d6c0}'],
+ ['\u{1d6c2}','\u{1d6da}'],
+ ['\u{1d6dc}','\u{1d6fa}'],
+ ['\u{1d6fc}','\u{1d714}'],
+ ['\u{1d716}','\u{1d734}'],
+ ['\u{1d736}','\u{1d74e}'],
+ ['\u{1d750}','\u{1d76e}'],
+ ['\u{1d770}','\u{1d788}'],
+ ['\u{1d78a}','\u{1d7a8}'],
+ ['\u{1d7aa}','\u{1d7c2}'],
+ ['\u{1d7c4}','\u{1d7cb}'],
+ ['\u{1d7ce}','\u{1d7ff}'],
+ ['\u{1ee00}','\u{1ee03}'],
+ ['\u{1ee05}','\u{1ee1f}'],
+ ['\u{1ee21}','\u{1ee22}'],
+ ['\u{1ee24}','\u{1ee24}'],
+ ['\u{1ee27}','\u{1ee27}'],
+ ['\u{1ee29}','\u{1ee32}'],
+ ['\u{1ee34}','\u{1ee37}'],
+ ['\u{1ee39}','\u{1ee39}'],
+ ['\u{1ee3b}','\u{1ee3b}'],
+ ['\u{1ee42}','\u{1ee42}'],
+ ['\u{1ee47}','\u{1ee47}'],
+ ['\u{1ee49}','\u{1ee49}'],
+ ['\u{1ee4b}','\u{1ee4b}'],
+ ['\u{1ee4d}','\u{1ee4f}'],
+ ['\u{1ee51}','\u{1ee52}'],
+ ['\u{1ee54}','\u{1ee54}'],
+ ['\u{1ee57}','\u{1ee57}'],
+ ['\u{1ee59}','\u{1ee59}'],
+ ['\u{1ee5b}','\u{1ee5b}'],
+ ['\u{1ee5d}','\u{1ee5d}'],
+ ['\u{1ee5f}','\u{1ee5f}'],
+ ['\u{1ee61}','\u{1ee62}'],
+ ['\u{1ee64}','\u{1ee64}'],
+ ['\u{1ee67}','\u{1ee6a}'],
+ ['\u{1ee6c}','\u{1ee72}'],
+ ['\u{1ee74}','\u{1ee77}'],
+ ['\u{1ee79}','\u{1ee7c}'],
+ ['\u{1ee7e}','\u{1ee7e}'],
+ ['\u{1ee80}','\u{1ee89}'],
+ ['\u{1ee8b}','\u{1ee9b}'],
+ ['\u{1eea1}','\u{1eea3}'],
+ ['\u{1eea5}','\u{1eea9}'],
+ ['\u{1eeab}','\u{1eebb}'],
+ ['\u{20000}','\u{2a6d6}'],
+ ['\u{2a700}','\u{2b734}'],
+ ['\u{2b740}','\u{2b81d}'],
+ ['\u{2f800}','\u{2fa1d}'],
+]
+
+const tabdigit = [
+ ['\u{30}','\u{39}'],
+ ['\u{660}','\u{669}'],
+ ['\u{6f0}','\u{6f9}'],
+ ['\u{7c0}','\u{7c9}'],
+ ['\u{966}','\u{96f}'],
+ ['\u{9e6}','\u{9ef}'],
+ ['\u{a66}','\u{a6f}'],
+ ['\u{ae6}','\u{aef}'],
+ ['\u{b66}','\u{b6f}'],
+ ['\u{be6}','\u{bef}'],
+ ['\u{c66}','\u{c6f}'],
+ ['\u{ce6}','\u{cef}'],
+ ['\u{d66}','\u{d6f}'],
+ ['\u{e50}','\u{e59}'],
+ ['\u{ed0}','\u{ed9}'],
+ ['\u{f20}','\u{f29}'],
+ ['\u{1040}','\u{1049}'],
+ ['\u{1090}','\u{1099}'],
+ ['\u{17e0}','\u{17e9}'],
+ ['\u{1810}','\u{1819}'],
+ ['\u{1946}','\u{194f}'],
+ ['\u{19d0}','\u{19d9}'],
+ ['\u{1a80}','\u{1a89}'],
+ ['\u{1a90}','\u{1a99}'],
+ ['\u{1b50}','\u{1b59}'],
+ ['\u{1bb0}','\u{1bb9}'],
+ ['\u{1c40}','\u{1c49}'],
+ ['\u{1c50}','\u{1c59}'],
+ ['\u{a620}','\u{a629}'],
+ ['\u{a8d0}','\u{a8d9}'],
+ ['\u{a900}','\u{a909}'],
+ ['\u{a9d0}','\u{a9d9}'],
+ ['\u{aa50}','\u{aa59}'],
+ ['\u{abf0}','\u{abf9}'],
+ ['\u{ff10}','\u{ff19}'],
+ ['\u{104a0}','\u{104a9}'],
+ ['\u{11066}','\u{1106f}'],
+ ['\u{110f0}','\u{110f9}'],
+ ['\u{11136}','\u{1113f}'],
+ ['\u{111d0}','\u{111d9}'],
+ ['\u{116c0}','\u{116c9}'],
+ ['\u{1d7ce}','\u{1d7ff}'],
+]
+
+const tabxdigit = [
+ ['\u{30}','\u{39}'],
+ ['\u{41}','\u{46}'],
+ ['\u{61}','\u{66}'],
+]
+
+const tabspace = [
+ ['\u{9}','\u{d}'],
+ ['\u{20}','\u{20}'],
+ ['\u{85}','\u{85}'],
+ ['\u{a0}','\u{a0}'],
+ ['\u{1680}','\u{1680}'],
+ ['\u{2000}','\u{200a}'],
+ ['\u{2028}','\u{2029}'],
+ ['\u{202f}','\u{202f}'],
+ ['\u{205f}','\u{205f}'],
+ ['\u{3000}','\u{3000}'],
+]
+
+const tabblank = [
+ ['\u{9}','\u{9}'],
+ ['\u{20}','\u{20}'],
+ ['\u{a0}','\u{a0}'],
+ ['\u{1680}','\u{1680}'],
+ ['\u{2000}','\u{200a}'],
+ ['\u{202f}','\u{202f}'],
+ ['\u{205f}','\u{205f}'],
+ ['\u{3000}','\u{3000}'],
+]
+
diff --git a/lib/regex/redump.myr b/lib/regex/redump.myr
new file mode 100644
index 0000000..7233864
--- /dev/null
+++ b/lib/regex/redump.myr
@@ -0,0 +1,87 @@
+use std
+use bio
+use regex
+
+const main = {args
+ var cmd, comp
+ var verbose
+ var fd
+
+ verbose = false
+ cmd = std.optparse(args, &[
+ .argdesc = "regex [inputs...]",
+ .minargs = 1,
+ .maxargs = 1,
+ .opts = [
+ [.opt='v', .desc="dump verbose regex output"]
+ ][:],
+ ])
+ for opt in cmd.opts
+ match opt
+ | ('v', _): verbose = true
+ | _: std.fatal("Unknown argument")
+ ;;
+ ;;
+ if verbose
+ comp = regex.dbgcompile(cmd.args[0])
+ else
+ comp = regex.compile(cmd.args[0])
+ ;;
+ match comp
+ | `std.Fail m:
+ std.fatal("unable to compile regex: {}\n", regex.failmsg(m))
+ | `std.Ok re:
+ if cmd.args.len > 1
+ runall(re, cmd.args)
+ else
+ fd = bio.mkfile(0, bio.Rd)
+ dump(re, fd)
+ bio.close(fd)
+ ;;
+ ;;
+}
+
+const runall = {re, files
+
+ for f in files
+ match bio.open(f, bio.Rd)
+ | `std.Ok fd:
+ dump(re, fd)
+ bio.close(fd)
+ | `std.Fail m:
+ std.fatal("failed to open {}: {}\n", f, m)
+ ;;
+ ;;
+}
+
+const dump = {re, fd
+ while true
+ match bio.readln(fd)
+ | `std.Some ln:
+ show(re, ln, regex.exec(re, ln))
+ std.slfree(ln)
+ | `std.None:
+ break
+ ;;
+ ;;
+}
+
+const show = {re, ln, mg
+ var i
+
+ match mg
+ | `std.Some rl:
+ std.put("Matched: {}\n", rl[0])
+ for i = 1; i < rl.len; i++
+ std.put("\tgroup {}: {}\n", i, rl[i])
+ ;;
+ | `std.None:
+ std.put("Match failed:\n")
+ std.put("\t{}\n", ln)
+ std.put("\t")
+ for i = 0; i < re.strp - 1; i++
+ std.put("~")
+ ;;
+ std.put("^\n")
+ ;;
+}
diff --git a/lib/regex/test/basic.myr b/lib/regex/test/basic.myr
new file mode 100644
index 0000000..168b547
--- /dev/null
+++ b/lib/regex/test/basic.myr
@@ -0,0 +1,39 @@
+use std
+
+use "testmatch.use"
+
+const main = {
+ var s : byte[:]
+
+ s = std.strjoin([
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ ][:], "")
+ testmatch(".*bc", "Abc", `std.Some [][:])
+ testmatch("(a*)*", "a", `std.Some ["a"][:])
+ testmatch("(aa|aab?)*", s, `std.Some ["aa"][:])
+ /* greedy matches */
+ testmatch("(<.*>).*", "<a foo> blah <bar>", `std.Some [
+ "<a foo> blah <bar>",
+ ][:])
+ testmatch("(<.+>).*", "<a foo> blah <bar>", `std.Some [
+ "<a foo> blah <bar>",
+ ][:])
+ /* reluctant matches */
+ testmatch("(<.*?>).*", "<a foo> blah <bar>", `std.Some [
+ "<a foo>",
+ ][:])
+ testmatch("(<.+?>).*", "<a foo> blah <bar>", `std.Some [
+ "<a foo>",
+ ][:])
+}
diff --git a/lib/regex/test/bld.sub b/lib/regex/test/bld.sub
new file mode 100644
index 0000000..12f8056
--- /dev/null
+++ b/lib/regex/test/bld.sub
@@ -0,0 +1,7 @@
+test basic {inc=../libstd,inc=..} = basic.myr testmatch.myr;;
+test boundaries {inc=../libstd,inc=..} = boundaries.myr testmatch.myr;;
+test capture {inc=../libstd,inc=..} = capture.myr testmatch.myr;;
+test class {inc=../libstd,inc=..} = class.myr testmatch.myr;;
+test failmatch {inc=../libstd,inc=..} = failmatch.myr testmatch.myr;;
+test negclass {inc=../libstd,inc=..} = negclass.myr testmatch.myr;;
+test unicode {inc=../libstd,inc=..} = unicode.myr testmatch.myr;;
diff --git a/lib/regex/test/boundaries.myr b/lib/regex/test/boundaries.myr
new file mode 100644
index 0000000..196d197
--- /dev/null
+++ b/lib/regex/test/boundaries.myr
@@ -0,0 +1,36 @@
+use std
+use "testmatch.use"
+
+const main = {
+ /* expected matches */
+ testmatch("\\<([a-z]*)\\>", "abcdef", `std.Some [
+ "abcdef",
+ ][:])
+ testmatch(".*(\\<.*\\>).*", "!m!", `std.Some [ /* single char word in midstring */
+ "m",
+ ][:])
+ testmatch(".*(\\<.*\\>).*", "!m", `std.Some [ /* single char word at end of string */
+ "m",
+ ][:])
+ testmatch(".*(\\<.*\\>).*", "m!", `std.Some [ /* single char word at start of string */
+ "m",
+ ][:])
+ testmatch(".*(\\<.*\\>).*", "!@#!!matches!!%!", `std.Some [ /* word in midstring */
+ "matches",
+ ][:])
+ testmatch(".*(\\<.*\\>).*", "matches!!%!", `std.Some [ /* word at start of string */
+ "matches",
+ ][:])
+ testmatch(".*(\\<.*\\>).*", "!@#!!matches", `std.Some [ /* word at end of string */
+ "matches",
+ ][:])
+ testmatch(".*(\\<.*\\>).*", "!@#!!matches!!%!foo", `std.Some [ /* matches last word in string */
+ "foo",
+ ][:])
+ testmatch(".*(\\<.*\\>).*", "123", `std.Some [ /* numbers are also word bounds */
+ "123",
+ ][:])
+
+ /* nonmatches */
+ testmatch("\\<([a-z]*)\\>foo", "abcdefoo", `std.None) /* word boundary needed in midstring */
+}
diff --git a/lib/regex/test/capture.myr b/lib/regex/test/capture.myr
new file mode 100644
index 0000000..f270428
--- /dev/null
+++ b/lib/regex/test/capture.myr
@@ -0,0 +1,17 @@
+use std
+use "testmatch.use"
+
+const main = {
+ testmatch("A(.*)", "Abc", `std.Some ["bc"][:])
+ testmatch("A(.*)e", "Abcde", `std.Some ["bcd"][:])
+ testmatch("(a|b)+", "abab", `std.Some ["b"][:])
+ testmatch("A(b(.*)d)e", "Abcde", `std.Some [
+ "bcd",
+ "c"
+ ][:])
+ testmatch("(a?)(a*)(a?)", "aaaa", `std.Some [
+ "a",
+ "aaa",
+ ""
+ ][:])
+}
diff --git a/lib/regex/test/class.myr b/lib/regex/test/class.myr
new file mode 100644
index 0000000..284f440
--- /dev/null
+++ b/lib/regex/test/class.myr
@@ -0,0 +1,67 @@
+use std
+
+use "testmatch.use"
+
+const main = {
+ asciiclass()
+ set()
+ /*
+ unicodeclass()
+ negasciiclass()
+ negasciirange()
+ negset()
+ */
+}
+
+const asciiclass = {
+ /* \d success */
+ testmatch("\\d", "1", `std.Some [][:])
+ testmatch("\\d\\d", "13", `std.Some [][:])
+ testmatch("\\d+", "13688", `std.Some [][:])
+ /* \d fail */
+ testmatch("\\d", "x", `std.None)
+ testmatch("\\d\\d", "x3", `std.None)
+ testmatch("\\d+", "1368f", `std.None)
+
+ /* \x success */
+ testmatch("\\x", "a", `std.Some [][:])
+ testmatch("\\x\\x", "1F", `std.Some [][:])
+ testmatch("\\x+", "13b8cDEf", `std.Some [][:])
+ /* \x fail */
+ testmatch("\\x", "Z", `std.None)
+ testmatch("\\x\\x", "fg", `std.None)
+ testmatch("\\x+", "13b8cg", `std.None)
+
+ /* \s success */
+ testmatch("\\s", " ", `std.Some [][:])
+ testmatch("\\s\\s", "\t\n", `std.Some [][:])
+ testmatch("\\s+", "\t\n\r \t", `std.Some [][:])
+ /* \s fail */
+ testmatch("\\s", "a", `std.None)
+ testmatch("\\s\\s", "i\n", `std.None)
+ testmatch("\\s+", "\t\n\r.\t", `std.None)
+
+ /* word success */
+ testmatch("\\w+", "abcABC0123_", `std.Some [][:])
+ /* word fail */
+ testmatch("\\w+", "abcABC0123_.", `std.None)
+
+ /* \h success */
+ testmatch("\\h", " ", `std.Some [][:])
+ testmatch("\\h\\h", "\t ", `std.Some [][:])
+ testmatch("\\h+", "\t \t ", `std.Some [][:])
+ /* \h fail */
+ testmatch("\\h", "\n", `std.None)
+ testmatch("\\h\\h", "\t\r", `std.None)
+ testmatch("\\h+", "\t \t.", `std.None)
+}
+
+const set = {
+ /* ranges */
+ testmatch("[a-z]*", "abcd", `std.Some [][:])
+ testmatch("[a-zA-Z]*", "abCD", `std.Some [][:])
+ testmatch("[a-zA-Z0-9_]*", "_abCD018", `std.Some [][:])
+
+ testmatch("[abc]*", "abba", `std.Some [][:])
+ testmatch("[a-zABC]*", "abBa", `std.Some [][:])
+}
diff --git a/lib/regex/test/failmatch.myr b/lib/regex/test/failmatch.myr
new file mode 100644
index 0000000..c501d00
--- /dev/null
+++ b/lib/regex/test/failmatch.myr
@@ -0,0 +1,7 @@
+use std
+
+use "testmatch.use"
+
+const main = {
+ testmatch(".*bcd", "Abc", `std.None)
+}
diff --git a/lib/regex/test/negclass.myr b/lib/regex/test/negclass.myr
new file mode 100644
index 0000000..19404fa
--- /dev/null
+++ b/lib/regex/test/negclass.myr
@@ -0,0 +1,72 @@
+use std
+
+use "testmatch.use"
+
+const main = {
+ asciiclass()
+ set()
+ /*
+ unicodeclass()
+ negasciiclass()
+ negasciirange()
+ negset()
+ */
+}
+
+const asciiclass = {
+ /* \D success */
+ testmatch("\\D", "x", `std.Some [][:])
+ testmatch("\\D+", "xa!#^cs", `std.Some [][:])
+
+ /* \D fail: end of ranges chars */
+ testmatch("\\D", "0", `std.None)
+ testmatch("\\D", "9", `std.None)
+ testmatch("\\D+", "a35x", `std.None)
+ testmatch("\\D+", "13688", `std.None)
+
+ /* \X success */
+ testmatch("\\X", "Z", `std.Some [][:])
+ testmatch("\\X\\X", "gg", `std.Some [][:])
+ /* \X fail */
+ testmatch("\\X", "a", `std.None)
+ testmatch("\\X+", "zz13b8cDEf", `std.None)
+
+ /* \S success */
+ testmatch("\\S", "a", `std.Some [][:])
+ testmatch("\\S\\S", "i%", `std.Some [][:])
+ testmatch("\\S+", "alskd690!#!!", `std.Some [][:])
+
+ /* \S fail */
+ testmatch("\\S", " ", `std.None)
+ testmatch("\\S\\S", "\t\n", `std.None)
+ testmatch("\\S+", "\t \nkait", `std.None)
+
+ /* word success */
+ testmatch("\\W+", "!%!^^@@!^", `std.Some [][:])
+ /* word fail */
+ testmatch("\\W+", "a^#$bcABC0123_", `std.None)
+
+ /* \H success */
+ testmatch("\\H", "\n", `std.Some [][:])
+ testmatch("\\H\\H", "\n\r", `std.Some [][:])
+ /* \H fail */
+ testmatch("\\H+", "\t \t.", `std.None)
+ testmatch("\\H\\H", "\t ", `std.None)
+ testmatch("\\H+", "\ta35 \t ", `std.None)
+}
+
+const set = {
+ /* ranges: should succeed */
+ testmatch("[^a-z]*", "ABCD", `std.Some [][:])
+ testmatch("[^a-zA-Z]*", "1234", `std.Some [][:])
+ testmatch("[^a-zA-Z0-9_]*", "-^^-", `std.Some [][:])
+ testmatch("[^abc]*", "d6d", `std.Some [][:])
+ testmatch("[^a-zABC]*", "!^!!))#", `std.Some [][:])
+
+ /* ranges: should fail */
+ testmatch("[^a-z]*", "abcd", `std.None)
+ testmatch("[^a-zA-Z]*", "abCD", `std.None)
+ testmatch("[^a-zA-Z0-9_]*", "_abCD018", `std.None)
+ testmatch("[^abc]*", "abba", `std.None)
+ testmatch("[^a-zABC]*", "abBa", `std.None)
+}
diff --git a/lib/regex/test/runtest.sh b/lib/regex/test/runtest.sh
new file mode 100755
index 0000000..95f548f
--- /dev/null
+++ b/lib/regex/test/runtest.sh
@@ -0,0 +1,124 @@
+#!/bin/bash
+NFAILURES=0
+NPASSES=0
+
+function build {
+ rm -f $1 $1.o $1.s $1.use
+ myrbuild $FLAGS -b $1 $1.myr $EXTRA_SRC
+}
+
+function pass {
+ PASSED="$PASSED $1"
+ NPASSED=$[$NPASSED + 1]
+}
+
+function fail {
+ echo "FAIL: $1"
+ FAILED="$FAILED $1"
+ NFAILED=$[$NFAILED + 1]
+}
+
+function expectstatus {
+ ./$1 $3
+ if [ $? -eq $2 ]; then
+ pass $1
+ return
+ else
+ fail $1
+ fi
+}
+
+function expectprint {
+ if [ "`./$1 $3`" != "$2" ]; then
+ fail $1
+ else
+ pass $1
+ fi
+}
+
+
+function expectcompare {
+ if [ x"" != x"$TMPDIR" ]; then
+ t=$TMPDIR/myrtest-$1-$RANDOM
+ else
+ t=/tmp/myrtest-$1-$RANDOM
+ fi
+ ./$1 $3 > $t
+ if cmp $t data/$1-expected; then
+ pass $1
+ else
+ fail $1
+ fi
+ rm -f $t
+}
+
+function expectfcompare {
+ ./$1 $3
+ if cmp data/$1-expected $2; then
+ pass $1
+ else
+ fail $1
+ fi
+}
+
+function shouldskip {
+ if [ -z $ARGS ]; then
+ return 1
+ fi
+
+ for i in $ARGS; do
+ if [ $i = $1 ]; then
+ return 1
+ fi
+ done
+ return 0
+}
+
+
+# Should build and run
+function B {
+ if shouldskip $1; then
+ return
+ fi
+
+ test="$1"; shift
+ type="$1"; shift
+ res="$1"; shift
+ if [ $# > 0 ]; then
+ args="$1"; shift
+ fi
+ build $test
+ case $type in
+ "E") expectstatus "$test" "$res" "$input";;
+ "P") expectprint "$test" "$res" "$input";;
+ "C") expectcompare "$test" "$res" "$input";;
+ "F") expectfcompare "$test" "$res" "$args";;
+ esac
+}
+
+# Should fail
+function F {
+ if shouldskip $1; then
+ return
+ fi
+ (build $1) > /dev/null
+ if [ $? -eq '1' ]; then
+ pass $1
+ else
+ fail $1
+ fi
+}
+
+# Should generate a usefile
+function U {
+ return
+}
+
+source tests
+
+echo "PASSED ($NPASSED): $PASSED"
+if [ -z "$NFAILED" ]; then
+ echo "SUCCESS"
+else
+ echo "FAILURES ($NFAILED): $FAILED"
+fi
diff --git a/lib/regex/test/testmatch.myr b/lib/regex/test/testmatch.myr
new file mode 100644
index 0000000..4600410
--- /dev/null
+++ b/lib/regex/test/testmatch.myr
@@ -0,0 +1,58 @@
+use std
+use regex
+
+pkg =
+ const testmatch : (pat : byte[:], text : byte[:], expected : std.option(byte[:][:]) -> void)
+ const dbgmatch : (pat : byte[:], text : byte[:], expected : std.option(byte[:][:]) -> void)
+;;
+
+const testmatch = {pat, text, expected
+ run(regex.compile(pat), pat, text, expected)
+}
+
+const dbgmatch = {pat, text, expected
+ run(regex.dbgcompile(pat), pat, text, expected)
+}
+
+const run = {regex, pat, text, expected
+ var i, re
+
+ re = std.try(regex)
+ match regex.exec(re, text)
+ | `std.Some res:
+ match expected
+ | `std.None:
+ std.fatal("expected no match, got:")
+ for i = 0; i < res.len; i++
+ std.put("\t{}: {}\n", i, res[i])
+ ;;
+ | `std.Some exp:
+ if !std.sleq(res[0], text)
+ std.put("whole match does not match text!\n")
+ std.fatal("failed matching {} over {}\n", pat, text)
+ ;;
+ res = res[1:]
+ if res.len != exp.len
+ std.put("mismatch: expected {} matches, got {}\n", exp.len, res.len)
+ std.fatal("failed matching {} over {}\n", pat, text)
+ ;;
+ for i = 0; i < exp.len; i++
+ if !std.sleq(res[i], exp[i])
+ std.put("mismatch on {}: expected {}, got {}\n", i, exp[i], res[i])
+ std.fatal("failed matching {} over {}\n", pat, text)
+ ;;
+ ;;
+ ;;
+ | `std.None:
+ match expected
+ | `std.None: /* : expected failure */
+ | `std.Some matches:
+ std.put("expected matches:\n")
+ for i = 0; i < matches.len; i++
+ std.put("\t{}: {}\n", i, matches[i])
+ ;;
+ std.fatal("no match found\n")
+ ;;
+ ;;
+ regex.free(re)
+}
diff --git a/lib/regex/test/tests b/lib/regex/test/tests
new file mode 100644
index 0000000..a5f70f7
--- /dev/null
+++ b/lib/regex/test/tests
@@ -0,0 +1,29 @@
+FLAGS=-I../
+EXTRA_SRC=testmatch.myr
+# Format:
+# [B|F] testname [E|P] result
+# [B|F]: Compiler outcome.
+# B: Expect that this test will build.
+# F: Expect that this test will not build.
+# testname: Test case
+# The test that will run. We will try to
+# compile 'testname.myr' to 'testname',
+# and then execute it, verifying the result
+# [E|P|C]: Result type
+# E tells us that the result is an exit status
+# P tells us that the result is on stdout,
+# and should be compared to the value on the
+# line
+# C tells us that the result is on stdout,
+# and should be compared to the contents of
+# the file passed on the line.
+# result: Result value
+# What we compare with. This should be self-
+# evident.
+B basic C
+B boundaries C
+B capture C
+B class C
+B failmatch C
+B negclass C
+B unicode C
diff --git a/lib/regex/test/unicode.myr b/lib/regex/test/unicode.myr
new file mode 100644
index 0000000..5916a1c
--- /dev/null
+++ b/lib/regex/test/unicode.myr
@@ -0,0 +1,19 @@
+use std
+use regex
+
+use "testmatch.use"
+
+const main = {
+ testmatch(".*bæc", "Abæc", `std.Some [][:])
+ testmatch("(\\p{L}*)bæc\\P{L}*", \
+ "Aabæc%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", \
+ `std.Some ["Aa"][:])
+ /* test various syntaxen */
+ testmatch("(\\pL*)bæc\\PL*", \
+ "Aabæc%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", \
+ `std.Some ["Aa"][:])
+ testmatch("(\\p{Letter}*)bæc\\P{Uppercase_Letter}*", \
+ "Aabæc%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", \
+ `std.Some ["Aa"][:])
+ testmatch(".", "æ", `std.Some [][:])
+}
diff --git a/lib/regex/types.myr b/lib/regex/types.myr
new file mode 100644
index 0000000..b283d2a
--- /dev/null
+++ b/lib/regex/types.myr
@@ -0,0 +1,88 @@
+use std
+
+pkg regex =
+ type status = union
+ `Noimpl
+ `Incomplete
+ `Unbalanced
+ `Emptyparen
+ `Badrep
+ `Badrange
+ `Badescape
+ ;;
+
+ type ast = union
+ /* basic string building */
+ `Alt (ast#, ast#)
+ `Cat (ast#, ast#)
+
+ /* repetition */
+ `Star ast#
+ `Rstar ast#
+ `Plus ast#
+ `Rplus ast#
+ `Quest ast#
+
+ /* end matches */
+ `Chr char
+ `Ranges char[2][:]
+
+ /* meta */
+ `Cap (std.size, ast#) /* id, ast */
+ `Bol /* beginning of line */
+ `Eol /* end of line */
+ `Bow /* beginning of word */
+ `Eow /* end of word */
+ ;;
+
+
+ type regex = struct
+ /* compile state */
+ debug : bool
+ pat : byte[:]
+ nmatch : std.size
+
+ /* VM state */
+ runq : rethread#
+ expired : rethread#
+ expiredtail : rethread#
+ proglen : std.size
+ prog : reinst[:]
+ nthr : std.size
+ str : byte[:]
+ strp : std.size
+ ;;
+
+ type rethread = struct
+ next : rethread# /* run queue link */
+
+ tid : std.size /* just for debugging */
+ ip : std.size /* the instruction pointer */
+ dead : bool /* thread died */
+ matched : bool /* thread matched */
+
+ mstart : std.size[:] /* match starts */
+ mend : std.size[:] /* match ends */
+ ;;
+
+ pkglocal type reinst = union
+ /* direct consumers */
+ `Ibyte byte
+ `Irange (byte, byte)
+
+ /* groups */
+ `Ilbra std.size
+ `Irbra std.size
+
+ /* anchors */
+ `Ibol
+ `Ieol
+ `Ibow
+ `Ieow
+
+ /* control flow */
+ `Ifork (std.size, std.size)
+ `Ijmp std.size
+ `Imatch std.size
+ ;;
+;;
diff --git a/lib/std/alloc.myr b/lib/std/alloc.myr
new file mode 100644
index 0000000..ed3b023
--- /dev/null
+++ b/lib/std/alloc.myr
@@ -0,0 +1,423 @@
+use "die.use"
+use "extremum.use"
+use "types.use"
+use "units.use"
+use "syswrap.use"
+
+/*
+The allocator implementation here is based on Bonwick's slab allocator.
+
+For small allocations (up to Bktmax), it works by requesting large,
+power of two aligned chunks from the operating system, and breaking
+them into a linked list of equal sized chunks. Allocations are then
+satisfied by taking the head of the list of chunks. Empty slabs
+are removed from the freelist.
+
+The data structure looks something like this:
+ Bkts:
+ [16 byte] -> [slab hdr | chunk -> chunk -> chunk] -> [slab hdr | chunk -> chunk -> chunk]
+ [32 byte] -> Zslab
+ [64 byte] -> [slab hdr | chunk -> chunk]
+ ...
+ [32k byte] -> ...
+
+Large allocations are simply satisfied by mmap().
+
+*/
+
+pkg std =
+ generic alloc : ( -> @a#)
+ generic zalloc : ( -> @a#)
+ generic free : (v:@a# -> void)
+
+ generic slalloc : (len : size -> @a[:])
+ generic slzalloc : (len : size -> @a[:])
+ generic slgrow : (sl : @a[:], len : size -> @a[:])
+ generic slzgrow : (sl : @a[:], len : size -> @a[:])
+ generic slfree : (sl : @a[:] -> void)
+
+ const bytealloc : (sz:size -> byte#)
+ const zbytealloc : (sz:size -> byte#)
+ const bytefree : (m:byte#, sz:size -> void)
+
+
+;;
+
+/* null pointers. only used internally. */
+const Zslab = 0 castto(slab#)
+const Zchunk = 0 castto(chunk#)
+
+const Slabsz = 1*MiB /* 1 meg slabs */
+const Cachemax = 16 /* maximum number of slabs in the cache */
+const Bktmax = 32*KiB /* Slabsz / 8; a balance. */
+const Pagesz = 4*KiB
+const Align = 16 /* minimum allocation alignment */
+
+var buckets : bucket[32] /* excessive */
+
+type slheader = struct
+ cap : size /* capacity in bytes */
+ magic : size /* magic check value */
+;;
+
+type bucket = struct
+ sz : size /* aligned size */
+ nper : size /* max number of elements per slab */
+ slabs : slab# /* partially filled or free slabs */
+ cache : slab# /* cache of empty slabs, to prevent thrashing */
+ ncache : size /* size of cache */
+;;
+
+type slab = struct
+ head : byte# /* head of virtual addresses, so we don't leak address space */
+ next : slab# /* the next slab on the chain */
+ freehd : chunk# /* the nodes we're allocating */
+ nfree : size /* the number of free nodes */
+;;
+
+type chunk = struct /* NB: must be smaller than sizeof(slab) */
+ next : chunk# /* the next chunk in the free list */
+;;
+
+const __init__ = {
+ var i
+
+ for i = 0; i < buckets.len && (Align << i) <= Bktmax; i++
+ bktinit(&buckets[i], Align << i)
+ ;;
+}
+
+/* Allocates an object of type @a, returning a pointer to it. */
+generic alloc = {-> @a#
+ -> bytealloc(sizeof(@a)) castto(@a#)
+}
+
+generic zalloc = {-> @a#
+ -> zbytealloc(sizeof(@a)) castto(@a#)
+}
+
+/* Frees a value of type @a */
+generic free = {v:@a# -> void
+ bytefree(v castto(byte#), sizeof(@a))
+}
+
+/* allocates a slice of 'len' elements. */
+generic slalloc = {len
+ var p, sz
+
+ if len == 0
+ -> [][:]
+ ;;
+ sz = len*sizeof(@a) + align(sizeof(slheader), Align)
+ p = bytealloc(sz)
+ p = inithdr(p, sz)
+ -> (p castto(@a#))[0:len]
+}
+
+generic slzalloc = {len
+ var p, sz
+
+ if len == 0
+ -> [][:]
+ ;;
+ sz = len*sizeof(@a) + align(sizeof(slheader), Align)
+ p = zbytealloc(sz)
+ p = inithdr(p, sz)
+ -> (p castto(@a#))[0:len]
+}
+
+const inithdr = {p, sz
+ var phdr, prest
+
+ phdr = p castto(slheader#)
+ phdr.cap = allocsz(sz) - align(sizeof(slheader), Align)
+ phdr.magic = (0xdeadbeefbadf00d castto(size))
+
+ prest = (p castto(size)) + align(sizeof(slheader), Align)
+ -> prest castto(byte#)
+}
+
+const checkhdr = {p
+ var phdr, addr
+
+ addr = p castto(size)
+ addr -= align(sizeof(slheader), Align)
+ phdr = addr castto(slheader#)
+ assert(phdr.magic == (0xdeadbeefbadf00d castto(size)), "corrupt memory\n")
+}
+
+/* Frees a slice */
+generic slfree = {sl
+ var head
+
+ if sl.len == 0
+ ->
+ ;;
+
+ checkhdr(sl castto(byte#))
+ head = (sl castto(byte#)) castto(size)
+ head -= align(sizeof(slheader), Align)
+ bytefree(head castto(byte#), slcap(sl castto(byte#)))
+}
+
+/* Grows a slice */
+generic slgrow = {sl : @a[:], len
+ var i, n
+ var new
+
+ /* if the slice doesn't need a bigger bucket, we don't need to realloc. */
+ if sl.len > 0 && slcap(sl castto(byte#)) >= allocsz(len*sizeof(@a))
+ -> (sl castto(@a#))[:len]
+ ;;
+
+ new = slalloc(len)
+ n = min(len, sl.len)
+ for i = 0; i < n; i++
+ new[i] = sl[i]
+ ;;
+ if sl.len > 0
+ slfree(sl)
+ ;;
+ -> new
+}
+
+/* Grows a slice, filling new entries with zero bytes */
+generic slzgrow = {sl : @a[:], len
+ var oldsz
+
+ oldsz = sl.len*sizeof(@a)
+ sl = slgrow(sl, len)
+ zfill((sl castto(byte#))[oldsz:len*sizeof(@a)])
+ -> sl
+}
+
+const slcap = {p
+ var phdr
+
+ phdr = (p castto(size)) - align(sizeof(slheader), Align) castto(slheader#)
+ -> phdr.cap
+}
+
+const zbytealloc = {sz
+ var p
+
+ p = bytealloc(sz)
+ zfill(p[0:sz])
+ -> p
+}
+
+const zfill = {sl
+ var i
+
+ for i = 0; i < sl.len; i++
+ sl[i] = 0
+ ;;
+}
+
+/* Allocates a blob that is 'sz' bytes long. Dies if the allocation fails */
+const bytealloc = {sz
+ var bkt, p
+
+ if (sz <= Bktmax)
+ bkt = &buckets[bktnum(sz)]
+ p = bktalloc(bkt)
+ else
+ p = getmem(sz)
+ if p == Failmem
+ die("could not get memory\n")
+ ;;
+ ;;
+ -> p
+}
+
+/* frees a blob that is 'sz' bytes long. */
+const bytefree = {p, sz
+ var bkt
+ var b, i
+
+ b = p[:sz]
+ for i = 0; i < sz; i++
+ b[i] = 0xa8
+ ;;
+ if (sz < Bktmax)
+ bkt = &buckets[bktnum(sz)]
+ bktfree(bkt, p)
+ else
+ freemem(p, sz)
+ ;;
+}
+
+/* Sets up a single empty bucket */
+const bktinit = {b, sz
+ b.sz = align(sz, Align)
+ b.nper = (Slabsz - sizeof(slab))/b.sz
+ b.slabs = Zslab
+ b.cache = Zslab
+ b.ncache = 0
+}
+
+/* Creates a slab for bucket 'bkt', and fills the chunk list */
+const mkslab = {bkt
+ var i, p, s
+ var b, bnext
+ var off /* offset of chunk head */
+
+ if bkt.ncache > 0
+ s = bkt.cache
+ bkt.cache = s.next
+ bkt.ncache--
+ ;;
+ /*
+ tricky: we need power of two alignment, so we allocate double the
+ needed size, chop off the unaligned ends, and waste the address
+ space. Since the OS is "smart enough", this shouldn't actually
+ cost us memory, and 64 bits of address space means that we're not
+ going to have issues with running out of address space for a
+ while. On a 32 bit system this would be a bad idea.
+ */
+ p = getmem(Slabsz*2)
+ if p == Failmem
+ die("Unable to mmap")
+ ;;
+
+ s = align(p castto(size), Slabsz) castto(slab#)
+ s.head = p
+ s.nfree = bkt.nper
+ /* skip past the slab header */
+ off = align(sizeof(slab), Align)
+ bnext = nextchunk(s castto(chunk#), off)
+ s.freehd = bnext
+ for i = 0; i < bkt.nper; i++
+ b = bnext
+ bnext = nextchunk(b, bkt.sz)
+ b.next = bnext
+ ;;
+ b.next = Zchunk
+ -> s
+}
+
+/*
+Allocates a node from bucket 'bkt', crashing if the
+allocation cannot be satisfied. Will create a new slab
+if there are no slabs on the freelist.
+*/
+const bktalloc = {bkt
+ var s
+ var b
+
+ /* find a slab */
+ s = bkt.slabs
+ if s == Zslab
+ s = mkslab(bkt)
+ if s == Zslab
+ die("No memory left")
+ ;;
+ bkt.slabs = s
+ ;;
+
+ /* grab the first chunk on the slab */
+ b = s.freehd
+ s.freehd = b.next
+ s.nfree--
+ if s.nfree == 0
+ bkt.slabs = s.next
+ s.next = Zslab
+ ;;
+
+ -> b castto(byte#)
+}
+
+/*
+Frees a chunk of memory 'm' into bucket 'bkt'.
+Assumes that the memory already came from a slab
+that was created for bucket 'bkt'. Will crash
+if this is not the case.
+*/
+const bktfree = {bkt, m
+ var s, b
+
+ s = mtrunc(m, Slabsz) castto(slab#)
+ b = m castto(chunk#)
+ if s.nfree == 0
+ s.next = bkt.slabs
+ bkt.slabs = s
+ elif s.nfree == bkt.nper
+ /*
+ HACK HACK HACK: if we can't unmap, keep an infinite cache per slab size.
+ We should solve this better somehow.
+ */
+ if bkt.ncache < Cachemax || !Canunmap
+ s.next = bkt.cache
+ bkt.cache = s
+ else
+ /* we mapped 2*Slabsz so we could align it,
+ so we need to unmap the same */
+ freemem(s.head, Slabsz*2)
+ ;;
+ ;;
+ s.nfree++
+ b.next = s.freehd
+ s.freehd = b
+}
+
+/*
+Finds the correct bucket index to allocate from
+for allocations of size 'sz'
+*/
+const bktnum = {sz
+ var i, bktsz
+
+ bktsz = Align
+ for i = 0; bktsz <= Bktmax; i++
+ if bktsz >= sz
+ -> i
+ ;;
+ bktsz *= 2
+ ;;
+ die("Size does not match any buckets")
+}
+
+/*
+returns the actual size we allocated for a given
+size request
+*/
+const allocsz = {sz
+ var i, bktsz
+
+ if sz <= Bktmax
+ bktsz = Align
+ for i = 0; bktsz <= Bktmax; i++
+ if bktsz >= sz
+ -> bktsz
+ ;;
+ bktsz *= 2
+ ;;
+ else
+ -> align(sz, Pagesz)
+ ;;
+ die("Size does not match any buckets")
+}
+
+/*
+aligns a size to a requested alignment.
+'align' must be a power of two
+*/
+const align = {v, align
+ -> (v + align - 1) & ~(align - 1)
+}
+
+/*
+chunks are variable sizes, so we can't just
+index to get to the next one
+*/
+const nextchunk = {b, sz : size
+ -> ((b castto(intptr)) + (sz castto(intptr))) castto(chunk#)
+}
+
+/*
+truncates a pointer to 'align'. 'align' must
+be a power of two.
+*/
+const mtrunc = {m, align
+ -> ((m castto(intptr)) & ~((align castto(intptr)) - 1)) castto(byte#)
+}
diff --git a/lib/std/bigint.myr b/lib/std/bigint.myr
new file mode 100644
index 0000000..719fd69
--- /dev/null
+++ b/lib/std/bigint.myr
@@ -0,0 +1,742 @@
+use "alloc.use"
+use "chartype.use"
+use "cmp.use"
+use "die.use"
+use "extremum.use"
+use "hasprefix.use"
+use "option.use"
+use "slcp.use"
+use "sldup.use"
+use "slfill.use"
+use "slpush.use"
+use "types.use"
+use "utf.use"
+use "errno.use"
+
+pkg std =
+ type bigint = struct
+ dig : uint32[:] /* little endian, no leading zeros. */
+ sign : int /* -1 for -ve, 0 for zero, 1 for +ve. */
+ ;;
+
+ /* administrivia */
+ generic mkbigint : (v : @a::(numeric,integral) -> bigint#)
+ const bigfree : (a : bigint# -> void)
+ const bigdup : (a : bigint# -> bigint#)
+ const bigassign : (d : bigint#, s : bigint# -> bigint#)
+ const bigmove : (d : bigint#, s : bigint# -> bigint#)
+ const bigparse : (s : byte[:] -> option(bigint#))
+ const bigclear : (a : bigint# -> bigint#)
+ const bigbfmt : (b : byte[:], a : bigint#, base : int -> size)
+ /*
+ const bigtoint : (a : bigint# -> @a::(numeric,integral))
+ */
+
+ /* some useful predicates */
+ const bigiszero : (a : bigint# -> bool)
+ const bigeq : (a : bigint#, b : bigint# -> bool)
+ generic bigeqi : (a : bigint#, b : @a::(numeric,integral) -> bool)
+ const bigcmp : (a : bigint#, b : bigint# -> order)
+
+ /* bigint*bigint -> bigint ops */
+ const bigadd : (a : bigint#, b : bigint# -> bigint#)
+ const bigsub : (a : bigint#, b : bigint# -> bigint#)
+ const bigmul : (a : bigint#, b : bigint# -> bigint#)
+ const bigdiv : (a : bigint#, b : bigint# -> bigint#)
+ const bigmod : (a : bigint#, b : bigint# -> bigint#)
+ const bigdivmod : (a : bigint#, b : bigint# -> (bigint#, bigint#))
+ const bigshl : (a : bigint#, b : bigint# -> bigint#)
+ const bigshr : (a : bigint#, b : bigint# -> bigint#)
+ const bigmodpow : (b : bigint#, e : bigint#, m : bigint# -> bigint#)
+ /*
+ const bigpow : (a : bigint#, b : bigint# -> bigint#)
+ */
+
+ /* bigint*int -> bigint ops */
+ generic bigaddi : (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+ generic bigsubi : (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+ generic bigmuli : (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+ generic bigdivi : (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+ generic bigshli : (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+ generic bigshri : (a : bigint#, b : @a::(integral,numeric) -> bigint#)
+ /*
+ const bigpowi : (a : bigint#, b : uint64 -> bigint#)
+ */
+;;
+
+const Base = 0x100000000ul
+generic mkbigint = {v : @a::(integral,numeric)
+ var a
+ var val
+
+ a = zalloc()
+
+ if v < 0
+ a.sign = -1
+ v = -v
+ elif v > 0
+ a.sign = 1
+ ;;
+ val = v castto(uint64)
+ a.dig = slpush([][:], val castto(uint32))
+ if val > Base
+ a.dig = slpush(a.dig, (val/Base) castto(uint32))
+ ;;
+ -> trim(a)
+}
+
+const bigfree = {a
+ slfree(a.dig)
+ free(a)
+}
+
+const bigdup = {a
+ -> bigassign(zalloc(), a)
+}
+
+const bigassign = {d, s
+ slfree(d.dig)
+ d# = s#
+ d.dig = sldup(s.dig)
+ -> d
+}
+
+const bigmove = {d, s
+ slfree(d.dig)
+ d# = s#
+ s.dig = [][:]
+ s.sign = 0
+ -> d
+}
+
+const bigclear = {v
+ std.slfree(v.dig)
+ v.sign = 0
+ v.dig = [][:]
+ -> v
+}
+
+/* for now, just dump out something for debugging... */
+const bigbfmt = {buf, x, base
+ const digitchars = [
+ '0','1','2','3','4','5','6','7','8','9',
+ 'a','b','c','d','e','f', 'g', 'h', 'i', 'j',
+ 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
+ 't', 'u', 'v', 'w', 'x', 'y', 'z']
+ var v, val
+ var n, i
+ var tmp, rem, b
+
+ if base < 0 || base > 36
+ die("invalid base in bigbfmt\n")
+ ;;
+
+ if bigiszero(x)
+ n
+ ;;
+
+ if base == 0
+ b = mkbigint(10)
+ else
+ b = mkbigint(base)
+ ;;
+ n = 0
+ val = bigdup(x)
+ /* generate the digits in reverse order */
+ while !bigiszero(val)
+ (v, rem) = bigdivmod(val, b)
+ if rem.dig.len > 0
+ n += encode(buf[n:], digitchars[rem.dig[0]])
+ else
+ n += encode(buf[n:], '0')
+ ;;
+ bigfree(val)
+ bigfree(rem)
+ val = v
+ ;;
+ bigfree(val)
+ bigfree(b)
+
+ /* this is done last, so we get things right when we reverse the string */
+ if x.sign == 0
+ n += encode(buf[n:], '0')
+ elif x.sign == -1
+ n += encode(buf[n:], '-')
+ ;;
+
+ /* we only generated ascii digits, so this works for reversing. */
+ for i = 0; i < n/2; i++
+ tmp = buf[i]
+ buf[i] = buf[n - i - 1]
+ buf[n - i - 1] = tmp
+ ;;
+ -> n
+}
+
+const bigparse = {str
+ var c, val : int, base
+ var v, b
+ var a
+
+ if hasprefix(str, "0x") || hasprefix(str, "0X")
+ base = 16
+ elif hasprefix(str, "0o") || hasprefix(str, "0O")
+ base = 8
+ elif hasprefix(str, "0b") || hasprefix(str, "0B")
+ base = 2
+ else
+ base = 10
+ ;;
+ if base != 10
+ str = str[2:]
+ ;;
+
+ a = mkbigint(0)
+ b = mkbigint(base)
+ /*
+ efficiency hack: to save allocations,
+ just mutate v[0]. The value will always
+ fit in one digit.
+ */
+ v = mkbigint(1)
+ while str.len != 0
+ (c, str) = striter(str)
+ if c == '_'
+ continue
+ ;;
+ val = charval(c, base)
+ if val < 0 || val > base
+ bigfree(a)
+ bigfree(b)
+ bigfree(v)
+ -> `None
+ ;;
+ v.dig[0] = val castto(uint32)
+ if val == 0
+ v.sign = 0
+ else
+ v.sign = 1
+ ;;
+ bigmul(a, b)
+ bigadd(a, v)
+
+ ;;
+ -> `Some a
+}
+
+const bigiszero = {v
+ -> v.dig.len == 0
+}
+
+const bigeq = {a, b
+ var i
+
+ if a.sign != b.sign || a.dig.len != b.dig.len
+ -> false
+ ;;
+ for i = 0; i < a.dig.len; i++
+ if a.dig[i] != b.dig[i]
+ -> false
+ ;;
+ ;;
+ -> true
+}
+
+generic bigeqi = {a, b
+ var v
+ var dig : uint32[2]
+
+ bigdigit(&v, b < 0, b castto(uint64), dig[:])
+ -> bigeq(a, &v)
+}
+
+const bigcmp = {a, b
+ var i
+ var da, db, sa, sb
+
+ sa = a.sign castto(int64)
+ sb = b.sign castto(int64)
+ if sa < sb
+ -> `Before
+ elif sa > sb
+ -> `After
+ elif a.dig.len < b.dig.len
+ -> signedorder(-sa)
+ elif a.dig.len > b.dig.len
+ -> signedorder(sa)
+ else
+ /* otherwise, the one with the first larger digit is bigger */
+ for i = a.dig.len; i > 0; i--
+ da = a.dig[i - 1] castto(int64)
+ db = b.dig[i - 1] castto(int64)
+ -> signedorder(sa * (da - db))
+ ;;
+ ;;
+ -> `Equal
+}
+
+const signedorder = {sign
+ if sign < 0
+ -> `Before
+ elif sign == 0
+ -> `Equal
+ else
+ -> `After
+ ;;
+}
+
+/* a += b */
+const bigadd = {a, b
+ if a.sign == b.sign || a.sign == 0
+ a.sign = b.sign
+ -> uadd(a, b)
+ elif b.sign == 0
+ -> a
+ else
+ match bigcmp(a, b)
+ | `Before: /* a is negative */
+ a.sign = b.sign
+ -> usub(b, a)
+ | `After: /* b is negative */
+ -> usub(a, b)
+ | `Equal:
+ die("Impossible. Equal vals with different sign.")
+ ;;
+ ;;
+}
+
+/* adds two unsigned values together. */
+const uadd = {a, b
+ var v, i
+ var carry
+ var n
+
+ carry = 0
+ n = max(a.dig.len, b.dig.len)
+ /* guaranteed to carry no more than one value */
+ a.dig = slzgrow(a.dig, n + 1)
+ for i = 0; i < n; i++
+ v = (a.dig[i] castto(uint64)) + carry;
+ if i < b.dig.len
+ v += (b.dig[i] castto(uint64))
+ ;;
+
+ if v >= Base
+ carry = 1
+ else
+ carry = 0
+ ;;
+ a.dig[i] = v castto(uint32)
+ ;;
+ a.dig[i] += carry castto(uint32)
+ -> trim(a)
+}
+
+/* a -= b */
+const bigsub = {a, b
+ /* 0 - x = -x */
+ if a.sign == 0
+ bigassign(a, b)
+ a.sign = -b.sign
+ -> a
+ /* x - 0 = x */
+ elif b.sign == 0
+ -> a
+ elif a.sign != b.sign
+ -> uadd(a, b)
+ else
+ match bigcmp(a, b)
+ | `Before: /* a is negative */
+ a.sign = b.sign
+ -> usub(b, a)
+ | `After: /* b is negative */
+ -> usub(a, b)
+ | `Equal:
+ -> bigclear(a)
+ ;;
+ ;;
+ -> a
+}
+
+/* subtracts two unsigned values, where 'a' is strictly greater than 'b' */
+const usub = {a, b
+ var carry
+ var v, i
+
+ carry = 0
+ for i = 0; i < a.dig.len; i++
+ v = (a.dig[i] castto(int64)) - carry
+ if i < b.dig.len
+ v -= (b.dig[i] castto(int64))
+ ;;
+ if v < 0
+ carry = 1
+ else
+ carry = 0
+ ;;
+ a.dig[i] = v castto(uint32)
+ ;;
+ -> trim(a)
+}
+
+/* a *= b */
+const bigmul = {a, b
+ var i, j
+ var ai, bj, wij
+ var carry, t
+ var w
+
+ if a.sign == 0 || b.sign == 0
+ a.sign = 0
+ slfree(a.dig)
+ a.dig = [][:]
+ -> a
+ elif a.sign != b.sign
+ a.sign = -1
+ else
+ a.sign = 1
+ ;;
+ w = slzalloc(a.dig.len + b.dig.len)
+ for j = 0; j < b.dig.len; j++
+ carry = 0
+ for i = 0; i < a.dig.len; i++
+ ai = a.dig[i] castto(uint64)
+ bj = b.dig[j] castto(uint64)
+ wij = w[i+j] castto(uint64)
+ t = ai * bj + wij + carry
+ w[i + j] = (t castto(uint32))
+ carry = t >> 32
+ ;;
+ w[i+j] = carry castto(uint32)
+ ;;
+ slfree(a.dig)
+ a.dig = w
+ -> trim(a)
+}
+
+const bigdiv = {a : bigint#, b : bigint# -> bigint#
+ var q, r
+
+ (q, r) = bigdivmod(a, b)
+ bigfree(r)
+ -> bigmove(a, q)
+}
+const bigmod = {a : bigint#, b : bigint# -> bigint#
+ var q, r
+
+ (q, r) = bigdivmod(a, b)
+ bigfree(q)
+ -> bigmove(a, r)
+}
+
+/* a /= b */
+const bigdivmod = {a : bigint#, b : bigint# -> (bigint#, bigint#)
+ /*
+ Implements bigint division using Algorithm D from
+ Knuth: Seminumerical algorithms, Section 4.3.1.
+ */
+ var m : int64, n : int64
+ var qhat, rhat, carry, shift
+ var x, y, z, w, p, t /* temporaries */
+ var b0, aj
+ var u, v
+ var i, j : int64
+ var q
+
+ if bigiszero(b)
+ die("divide by zero\n")
+ ;;
+ /* if b > a, we trucate to 0, with remainder 'a' */
+ if a.dig.len < b.dig.len
+ -> (mkbigint(0), bigdup(a))
+ ;;
+
+ q = zalloc()
+ q.dig = slzalloc(max(a.dig.len, b.dig.len) + 1)
+ if a.sign != b.sign
+ q.sign = -1
+ else
+ q.sign = 1
+ ;;
+
+ /* handle single digit divisor separately: the knuth algorithm needs at least 2 digits. */
+ if b.dig.len == 1
+ carry = 0
+ b0 = (b.dig[0] castto(uint64))
+ for j = a.dig.len; j > 0; j--
+ aj = (a.dig[j - 1] castto(uint64))
+ q.dig[j - 1] = (((carry << 32) + aj)/b0) castto(uint32)
+ carry = (carry << 32) + aj - (q.dig[j-1] castto(uint64))*b0
+ ;;
+ q = trim(q)
+ -> (q, trim(mkbigint(carry castto(int32))))
+ ;;
+
+ u = bigdup(a)
+ v = bigdup(b)
+ m = u.dig.len
+ n = v.dig.len
+
+ shift = nlz(v.dig[n - 1])
+ bigshli(u, shift)
+ bigshli(v, shift)
+ u.dig = slzgrow(u.dig, u.dig.len + 1)
+
+ for j = m - n; j >= 0; j--
+ /* load a few temps */
+ x = u.dig[j + n] castto(uint64)
+ y = u.dig[j + n - 1] castto(uint64)
+ z = v.dig[n - 1] castto(uint64)
+ w = v.dig[n - 2] castto(uint64)
+ t = u.dig[j + n - 2] castto(uint64)
+
+ /* estimate qhat */
+ qhat = (x*Base + y)/z
+ rhat = (x*Base + y) - qhat*z
+:divagain
+ if qhat >= Base || (qhat * w) > (rhat*Base + t)
+ qhat--
+ rhat += z
+ if rhat < Base
+ goto divagain
+ ;;
+ ;;
+
+ /* multiply and subtract */
+ carry = 0
+ for i = 0; i < n; i++
+ p = qhat * (v.dig[i] castto(uint64))
+
+ t = (u.dig[i+j] castto(uint64)) - carry - (p % Base)
+ u.dig[i+j] = t castto(uint32)
+
+ carry = (((p castto(int64)) >> 32) - ((t castto(int64)) >> 32)) castto(uint64);
+ ;;
+ t = (u.dig[j + n] castto(uint64)) - carry
+ u.dig[j + n] = t castto(uint32)
+ q.dig[j] = qhat castto(uint32)
+ /* adjust */
+ if t castto(int64) < 0
+ q.dig[j]--
+ carry = 0
+ for i = 0; i < n; i++
+ t = (u.dig[i+j] castto(uint64)) + (v.dig[i] castto(uint64)) + carry
+ u.dig[i+j] = t castto(uint32)
+ carry = t >> 32
+ ;;
+ u.dig[j+n] = u.dig[j+n] + (carry castto(uint32));
+ ;;
+
+ ;;
+ /* undo the biasing for remainder */
+ u = bigshri(u, shift)
+ -> (trim(q), trim(u))
+}
+
+/* computes b^e % m */
+const bigmodpow = {base, exp, mod
+ var r, n
+
+ r = mkbigint(1)
+ n = 0
+ while !bigiszero(exp)
+ if (exp.dig[0] & 1) != 0
+ bigmul(r, base)
+ bigmod(r, mod)
+ ;;
+ bigshri(exp, 1)
+ bigmul(base, base)
+ bigmod(base, mod)
+ ;;
+ -> bigmove(base, r)
+}
+
+/* returns the number of leading zeros */
+const nlz = {a : uint32
+ var n
+
+ if a == 0
+ -> 32
+ ;;
+ n = 0
+ if a <= 0x0000ffff
+ n += 16
+ a <<= 16
+ ;;
+ if a <= 0x00ffffff
+ n += 8
+ a <<= 8
+ ;;
+ if a <= 0x0fffffff
+ n += 4
+ a <<= 4
+ ;;
+ if a <= 0x3fffffff
+ n += 2
+ a <<= 2
+ ;;
+ if a <= 0x7fffffff
+ n += 1
+ a <<= 1
+ ;;
+ -> n
+}
+
+
+/* a <<= b */
+const bigshl = {a, b
+ match b.dig.len
+ | 0: -> a
+ | 1: -> bigshli(a, b.dig[0] castto(uint64))
+ | n: die("shift by way too much\n")
+ ;;
+}
+
+/* a >>= b, unsigned */
+const bigshr = {a, b
+ match b.dig.len
+ | 0: -> a
+ | 1: -> bigshri(a, b.dig[0] castto(uint64))
+ | n: die("shift by way too much\n")
+ ;;
+}
+
+/* a + b, b is integer.
+FIXME: acually make this a performace improvement
+*/
+generic bigaddi = {a, b
+ var bigb : bigint
+ var dig : uint32[2]
+
+ bigdigit(&bigb, b < 0, b castto(uint64), dig[:])
+ bigadd(a, &bigb)
+ -> a
+}
+
+generic bigsubi = {a, b : @a::(numeric,integral)
+ var bigb : bigint
+ var dig : uint32[2]
+
+ bigdigit(&bigb, b < 0, b castto(uint64), dig[:])
+ bigsub(a, &bigb)
+ -> a
+}
+
+generic bigmuli = {a, b
+ var bigb : bigint
+ var dig : uint32[2]
+
+ bigdigit(&bigb, b < 0, b castto(uint64), dig[:])
+ bigmul(a, &bigb)
+ -> a
+}
+
+generic bigdivi = {a, b
+ var bigb : bigint
+ var dig : uint32[2]
+
+ bigdigit(&bigb, b < 0, b castto(uint64), dig[:])
+ bigdiv(a, &bigb)
+ -> a
+}
+
+/*
+ a << s, with integer arg.
+ logical left shift. any other type would be illogical.
+ */
+generic bigshli = {a, s : @a::(numeric,integral)
+ var off, shift
+ var t, carry
+ var i
+
+ assert(s >= 0, "shift amount must be positive")
+ off = (s castto(uint64)) / 32
+ shift = (s castto(uint64)) % 32
+
+ /* zero shifted by anything is zero */
+ if a.sign == 0
+ -> a
+ ;;
+ a.dig = slzgrow(a.dig, 1 + a.dig.len + off castto(size))
+ /* blit over the base values */
+ for i = a.dig.len; i > off; i--
+ a.dig[i - 1] = a.dig[i - 1 - off]
+ ;;
+ for i = 0; i < off; i++
+ a.dig[i] = 0
+ ;;
+ /* and shift over by the remainder */
+ carry = 0
+ for i = 0; i < a.dig.len; i++
+ t = (a.dig[i] castto(uint64)) << shift
+ a.dig[i] = (t | carry) castto(uint32)
+ carry = t >> 32
+ ;;
+ -> trim(a)
+}
+
+/* logical shift right, zero fills. sign remains untouched. */
+generic bigshri = {a, s
+ var off, shift
+ var t, carry
+ var i
+
+ assert(s >= 0, "shift amount must be positive")
+ off = (s castto(uint64)) / 32
+ shift = (s castto(uint64)) % 32
+
+ /* blit over the base values */
+ for i = 0; i < a.dig.len - off; i++
+ a.dig[i] = a.dig[i + off]
+ ;;
+ for i = a.dig.len - off; i < a.dig.len; i++
+ a.dig[i] = 0
+ ;;
+ /* and shift over by the remainder */
+ carry = 0
+ for i = a.dig.len; i > 0; i--
+ t = (a.dig[i - 1] castto(uint64))
+ a.dig[i - 1] = (carry | (t >> shift)) castto(uint32)
+ carry = t << (32 - shift)
+ ;;
+ -> trim(a)
+}
+
+/* creates a bigint on the stack; should not be modified. */
+const bigdigit = {v, isneg : bool, val : uint64, dig
+ v.sign = 1
+ if isneg
+ val = -val
+ v.sign = -1
+ ;;
+ if val == 0
+ v.sign = 0
+ v.dig = [][:]
+ elif val < Base
+ v.dig = dig[:1]
+ v.dig[0] = val castto(uint32)
+ else
+ v.dig = dig
+ v.dig[0] = val castto(uint32)
+ v.dig[1] = (val >> 32) castto(uint32)
+ ;;
+}
+
+/* trims leading zeros */
+const trim = {a
+ var i
+
+ for i = a.dig.len; i > 0; i--
+ if a.dig[i - 1] != 0
+ break
+ ;;
+ ;;
+ a.dig = slgrow(a.dig, i)
+ if i == 0
+ a.sign = 0
+ elif a.sign == 0
+ a.sign = 1
+ ;;
+ -> a
+}
+
diff --git a/lib/std/bitset.myr b/lib/std/bitset.myr
new file mode 100644
index 0000000..7843c7d
--- /dev/null
+++ b/lib/std/bitset.myr
@@ -0,0 +1,155 @@
+use "alloc.use"
+use "die.use"
+use "extremum.use"
+use "mk.use"
+use "slcp.use"
+use "sldup.use"
+use "slfill.use"
+use "types.use"
+
+pkg std =
+ type bitset = struct
+ bits : size[:]
+ ;;
+
+ const mkbs : (-> bitset#)
+ const bsdup : (bs : bitset# -> bitset#)
+ const bsfree : (bs : bitset# -> void)
+
+ const bsmax : (a : bitset# -> size)
+
+ generic bsput : (bs : bitset#, v : @a::(integral,numeric) -> void)
+ generic bsdel : (bs : bitset#, v : @a::(integral,numeric) -> void)
+ generic bshas : (bs : bitset#, v : @a::(integral,numeric) -> bool)
+
+ const bsdiff : (a : bitset#, b : bitset# -> void)
+ const bsintersect : (a : bitset#, b : bitset# -> void)
+ const bsunion : (a : bitset#, b : bitset# -> void)
+ const bseq : (a : bitset#, b : bitset# -> bool)
+ const bsissubset : (a : bitset#, b : bitset# -> bool)
+
+
+ const bsclear : (bs : bitset# -> bitset#)
+;;
+
+const mkbs = {
+ -> zalloc()
+}
+
+const bsdup = {bs
+ -> mk([.bits=sldup(bs.bits)])
+}
+
+const bsfree = {bs
+ slfree(bs.bits)
+ free(bs)
+}
+
+const bsclear = {bs
+ slfill(bs.bits, 0)
+ -> bs
+}
+
+const bsmax = {bs
+ -> bs.bits.len * sizeof(size) * 8
+}
+
+generic bsput = {bs, v
+ var idx
+ var off
+
+ idx = (v castto(size)) / (8*sizeof(size))
+ off = (v castto(size)) % (8*sizeof(size))
+ ensurelen(bs, idx)
+ bs.bits[idx] |= (1 << off)
+}
+
+generic bsdel = {bs, v
+ var idx
+ var off
+
+ idx = (v castto(size)) / (8*sizeof(size))
+ off = (v castto(size)) % (8*sizeof(size))
+ if idx >= bs.bits.len
+ ->
+ ;;
+ bs.bits[idx] &= ~(1 << off)
+}
+
+generic bshas = {bs, v
+ var idx
+ var off
+
+ idx = (v castto(size)) / (8*sizeof(size))
+ off = (v castto(size)) % (8*sizeof(size))
+ if idx >= bs.bits.len
+ -> false
+ ;;
+ -> (bs.bits[idx] & (1 << off)) != 0
+}
+
+const bsunion = {a, b
+ var i
+
+ eqsz(a, b)
+ for i = 0; i < b.bits.len; i++
+ a.bits[i] |= b.bits[i]
+ ;;
+}
+
+const bsintersect = {a, b
+ var i, n
+
+ n = min(a.bits.len, b.bits.len)
+ for i = 0; i < n; i++
+ a.bits[i] &= b.bits[i]
+ ;;
+}
+
+const bsdiff = {a, b
+ var i, n
+
+ n = min(b.bits.len, a.bits.len)
+ for i = 0; i < n; i++
+ a.bits[i] &= ~b.bits[i]
+ ;;
+}
+
+const bsissubset = {a, b
+ var i
+
+ eqsz(a, b);
+ for i = 0; i < a.bits.len; i++
+ if (b.bits[i] & a.bits[i]) != b.bits[i]
+ -> false
+ ;;
+ ;;
+ -> true
+}
+
+const bseq = {a, b
+ var i
+
+ eqsz(a, b)
+ for i = 0; i < a.bits.len; i++
+ if a.bits[i] != b.bits[i]
+ -> false
+ ;;
+ ;;
+ -> true
+}
+
+const ensurelen = {bs, len
+ if bs.bits.len <= len
+ bs.bits = slzgrow(bs.bits, len + 1)
+ ;;
+}
+
+const eqsz = {a, b
+ var sz
+
+ sz = max(a.bits.len, b.bits.len)
+ ensurelen(a, sz)
+ ensurelen(b, sz)
+}
+
diff --git a/lib/std/blat.myr b/lib/std/blat.myr
new file mode 100644
index 0000000..90c0f94
--- /dev/null
+++ b/lib/std/blat.myr
@@ -0,0 +1,32 @@
+use "syswrap.use"
+
+pkg std =
+ const blat : (path : byte[:], buf : byte[:], perm : int64 -> bool)
+ const fblat : (f : fd, buf : byte[:] -> bool)
+;;
+
+const blat = {path, buf, perm
+ var fd
+
+ fd = openmode(path, Ocreat|Owronly, perm)
+ if fd < 0
+ -> false
+ ;;
+ -> fblat(fd, buf)
+}
+
+
+const fblat = {fd, buf
+ var written, n
+
+ n = 0
+ while true
+ written = write(fd, buf[n:])
+ if written <= 0
+ goto done
+ ;;
+ n += written
+ ;;
+:done
+ -> written == 0 && n == buf.len
+}
diff --git a/lib/std/bld.sub b/lib/std/bld.sub
new file mode 100644
index 0000000..b84be64
--- /dev/null
+++ b/lib/std/bld.sub
@@ -0,0 +1,103 @@
+lib sys =
+ sys+freebsd-x64.myr
+ sys+linux-x64.myr
+ sys+osx-x64.myr
+ sys+plan9-x64.myr
+ syscall+freebsd-x64.s
+ syscall+linux-x64.s
+ syscall+osx-x64.s
+ syscall+plan9-x64.s
+ syserrno+linux.myr
+ syserrno+osx.myr
+ systypes.myr
+ ifreq+freebsd.myr
+ ifreq+linux.myr
+ ifreq+osx.myr
+ ifreq+plan9.myr
+ ifreq.myr # dummy file: plan9 doesn't have ifreq
+ util+plan9-x64.s
+ util+posixy-x64.s
+;;
+
+lib std {inc=.} =
+ lib sys
+
+ # portable files
+ alloc.myr
+ bigint.myr
+ bitset.myr
+ blat.myr
+ chartype.myr
+ clear.myr
+ cmp.myr
+ cstrconv.myr
+ die.myr
+ dirname.myr
+ endian.myr
+ errno.myr
+ execvp.myr
+ extremum.myr
+ fltbits.myr
+ fltfmt.myr
+ fmt.myr
+ fmtfuncs.myr
+ getcwd.myr
+ getint.myr
+ hashfuncs.myr
+ hasprefix.myr
+ hassuffix.myr
+ htab.myr
+ intparse.myr
+ introspect.myr
+ ipparse.myr
+ mk.myr
+ mkpath.myr
+ now.myr
+ option.myr
+ optparse.myr
+ pathjoin.myr
+ putint.myr
+ rand.myr
+ result.myr
+ search.myr
+ slcp.myr
+ sldup.myr
+ sleq.myr
+ slfill.myr
+ sljoin.myr
+ slpush.myr
+ slput.myr
+ slurp.myr
+ sort.myr
+ spork.myr
+ strbuf.myr
+ strfind.myr
+ strjoin.myr
+ strsplit.myr
+ strstrip.myr
+ swap.myr
+ try.myr
+ types.myr
+ units.myr
+ utf.myr
+ varargs.myr
+
+ # platform specific files
+ env+plan9.myr
+ env+posixy.myr
+ errno+plan9.myr
+ dir+freebsd.myr
+ dir+linux.myr
+ dir+osx.myr
+ wait+posixy.myr
+ wait+plan9.myr
+ dial+posixy.myr
+ dial+plan9.myr
+ resolve+posixy.myr
+ resolve+plan9.myr
+ syswrap-ss+linux.myr
+ syswrap-ss+osx.myr
+ syswrap-ss+plan9.myr
+ syswrap+plan9.myr
+ syswrap+posixy.myr
+;;
diff --git a/lib/std/build.sh b/lib/std/build.sh
new file mode 100755
index 0000000..3c1aa99
--- /dev/null
+++ b/lib/std/build.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+if [ -z "`which mbld`" ]; then
+ ../myrbuild/myrbuild -I. -C$MYR_MC -M$MYR_MUSE $@
+else
+ mbld
+fi
+
diff --git a/lib/std/chartype.myr b/lib/std/chartype.myr
new file mode 100644
index 0000000..fe59202
--- /dev/null
+++ b/lib/std/chartype.myr
@@ -0,0 +1,1242 @@
+use "die.use"
+use "types.use"
+
+/*
+ Tables adapted from plan 9's runetype.c,
+ which lives in sys/src/libc/port/runetype.c
+*/
+
+pkg std =
+ /* predicates */
+ const isalpha : (c : char -> bool)
+ const isdigit : (c : char -> bool)
+ const isxdigit : (c : char -> bool)
+ const isnum : (c : char -> bool)
+ const isalnum : (c : char -> bool)
+ const isspace : (c : char -> bool)
+ const isblank : (c : char -> bool)
+ const islower : (c : char -> bool)
+ const isupper : (c : char -> bool)
+ const istitle : (c : char -> bool)
+
+ /* transforms */
+ const tolower : (c : char -> char)
+ const toupper : (c : char -> char)
+ const totitle : (c : char -> char)
+
+ generic charval : (c : char, base : int -> @a::(integral,numeric))
+;;
+
+extern const put : (fmt : byte[:], args : ... -> size)
+
+/*
+ * alpha ranges -
+ * only covers ranges not in lower||upper
+ */
+const ralpha2 = [
+ 0x00d8, 0x00f6, /* Ø - ö */
+ 0x00f8, 0x01f5, /* ø - ǵ */
+ 0x0250, 0x02a8, /* ɐ - ʨ */
+ 0x038e, 0x03a1, /* Ύ - Ρ */
+ 0x03a3, 0x03ce, /* Σ - ώ */
+ 0x03d0, 0x03d6, /* ϐ - ϖ */
+ 0x03e2, 0x03f3, /* Ϣ - ϳ */
+ 0x0490, 0x04c4, /* Ґ - ӄ */
+ 0x0561, 0x0587, /* ա - և */
+ 0x05d0, 0x05ea, /* א - ת */
+ 0x05f0, 0x05f2, /* װ - ײ */
+ 0x0621, 0x063a, /* ء - غ */
+ 0x0640, 0x064a, /* ـ - ي */
+ 0x0671, 0x06b7, /* ٱ - ڷ */
+ 0x06ba, 0x06be, /* ں - ھ */
+ 0x06c0, 0x06ce, /* ۀ - ێ */
+ 0x06d0, 0x06d3, /* ې - ۓ */
+ 0x0905, 0x0939, /* अ - ह */
+ 0x0958, 0x0961, /* क़ - ॡ */
+ 0x0985, 0x098c, /* অ - ঌ */
+ 0x098f, 0x0990, /* এ - ঐ */
+ 0x0993, 0x09a8, /* ও - ন */
+ 0x09aa, 0x09b0, /* প - র */
+ 0x09b6, 0x09b9, /* শ - হ */
+ 0x09dc, 0x09dd, /* ড় - ঢ় */
+ 0x09df, 0x09e1, /* য় - ৡ */
+ 0x09f0, 0x09f1, /* ৰ - ৱ */
+ 0x0a05, 0x0a0a, /* ਅ - ਊ */
+ 0x0a0f, 0x0a10, /* ਏ - ਐ */
+ 0x0a13, 0x0a28, /* ਓ - ਨ */
+ 0x0a2a, 0x0a30, /* ਪ - ਰ */
+ 0x0a32, 0x0a33, /* ਲ - ਲ਼ */
+ 0x0a35, 0x0a36, /* ਵ - ਸ਼ */
+ 0x0a38, 0x0a39, /* ਸ - ਹ */
+ 0x0a59, 0x0a5c, /* ਖ਼ - ੜ */
+ 0x0a85, 0x0a8b, /* અ - ઋ */
+ 0x0a8f, 0x0a91, /* એ - ઑ */
+ 0x0a93, 0x0aa8, /* ઓ - ન */
+ 0x0aaa, 0x0ab0, /* પ - ર */
+ 0x0ab2, 0x0ab3, /* લ - ળ */
+ 0x0ab5, 0x0ab9, /* વ - હ */
+ 0x0b05, 0x0b0c, /* ଅ - ଌ */
+ 0x0b0f, 0x0b10, /* ଏ - ଐ */
+ 0x0b13, 0x0b28, /* ଓ - ନ */
+ 0x0b2a, 0x0b30, /* ପ - ର */
+ 0x0b32, 0x0b33, /* ଲ - ଳ */
+ 0x0b36, 0x0b39, /* ଶ - ହ */
+ 0x0b5c, 0x0b5d, /* ଡ଼ - ଢ଼ */
+ 0x0b5f, 0x0b61, /* ୟ - ୡ */
+ 0x0b85, 0x0b8a, /* அ - ஊ */
+ 0x0b8e, 0x0b90, /* எ - ஐ */
+ 0x0b92, 0x0b95, /* ஒ - க */
+ 0x0b99, 0x0b9a, /* ங - ச */
+ 0x0b9e, 0x0b9f, /* ஞ - ட */
+ 0x0ba3, 0x0ba4, /* ண - த */
+ 0x0ba8, 0x0baa, /* ந - ப */
+ 0x0bae, 0x0bb5, /* ம - வ */
+ 0x0bb7, 0x0bb9, /* ஷ - ஹ */
+ 0x0c05, 0x0c0c, /* అ - ఌ */
+ 0x0c0e, 0x0c10, /* ఎ - ఐ */
+ 0x0c12, 0x0c28, /* ఒ - న */
+ 0x0c2a, 0x0c33, /* ప - ళ */
+ 0x0c35, 0x0c39, /* వ - హ */
+ 0x0c60, 0x0c61, /* ౠ - ౡ */
+ 0x0c85, 0x0c8c, /* ಅ - ಌ */
+ 0x0c8e, 0x0c90, /* ಎ - ಐ */
+ 0x0c92, 0x0ca8, /* ಒ - ನ */
+ 0x0caa, 0x0cb3, /* ಪ - ಳ */
+ 0x0cb5, 0x0cb9, /* ವ - ಹ */
+ 0x0ce0, 0x0ce1, /* ೠ - ೡ */
+ 0x0d05, 0x0d0c, /* അ - ഌ */
+ 0x0d0e, 0x0d10, /* എ - ഐ */
+ 0x0d12, 0x0d28, /* ഒ - ന */
+ 0x0d2a, 0x0d39, /* പ - ഹ */
+ 0x0d60, 0x0d61, /* ൠ - ൡ */
+ 0x0e01, 0x0e30, /* ก - ะ */
+ 0x0e32, 0x0e33, /* า - ำ */
+ 0x0e40, 0x0e46, /* เ - ๆ */
+ 0x0e5a, 0x0e5b, /* ๚ - ๛ */
+ 0x0e81, 0x0e82, /* ກ - ຂ */
+ 0x0e87, 0x0e88, /* ງ - ຈ */
+ 0x0e94, 0x0e97, /* ດ - ທ */
+ 0x0e99, 0x0e9f, /* ນ - ຟ */
+ 0x0ea1, 0x0ea3, /* ມ - ຣ */
+ 0x0eaa, 0x0eab, /* ສ - ຫ */
+ 0x0ead, 0x0eae, /* ອ - ຮ */
+ 0x0eb2, 0x0eb3, /* າ - ຳ */
+ 0x0ec0, 0x0ec4, /* ເ - ໄ */
+ 0x0edc, 0x0edd, /* ໜ - ໝ */
+ 0x0f18, 0x0f19, /* ༘ - ༙ */
+ 0x0f40, 0x0f47, /* ཀ - ཇ */
+ 0x0f49, 0x0f69, /* ཉ - ཀྵ */
+ 0x10d0, 0x10f6, /* ა - ჶ */
+ 0x1100, 0x1159, /* ᄀ - ᅙ */
+ 0x115f, 0x11a2, /* ᅟ - ᆢ */
+ 0x11a8, 0x11f9, /* ᆨ - ᇹ */
+ 0x1e00, 0x1e9b, /* Ḁ - ẛ */
+ 0x1f50, 0x1f57, /* ὐ - ὗ */
+ 0x1f80, 0x1fb4, /* ᾀ - ᾴ */
+ 0x1fb6, 0x1fbc, /* ᾶ - ᾼ */
+ 0x1fc2, 0x1fc4, /* ῂ - ῄ */
+ 0x1fc6, 0x1fcc, /* ῆ - ῌ */
+ 0x1fd0, 0x1fd3, /* ῐ - ΐ */
+ 0x1fd6, 0x1fdb, /* ῖ - Ί */
+ 0x1fe0, 0x1fec, /* ῠ - Ῥ */
+ 0x1ff2, 0x1ff4, /* ῲ - ῴ */
+ 0x1ff6, 0x1ffc, /* ῶ - ῼ */
+ 0x210a, 0x2113, /* ℊ - ℓ */
+ 0x2115, 0x211d, /* ℕ - ℝ */
+ 0x2120, 0x2122, /* ℠ - ™ */
+ 0x212a, 0x2131, /* K - ℱ */
+ 0x2133, 0x2138, /* ℳ - ℸ */
+ 0x3041, 0x3094, /* ぁ - ゔ */
+ 0x30a1, 0x30fa, /* ァ - ヺ */
+ 0x3105, 0x312c, /* ㄅ - ㄬ */
+ 0x3131, 0x318e, /* ㄱ - ㆎ */
+ 0x3192, 0x319f, /* ㆒ - ㆟ */
+ 0x3260, 0x327b, /* ㉠ - ㉻ */
+ 0x328a, 0x32b0, /* ㊊ - ㊰ */
+ 0x32d0, 0x32fe, /* ㋐ - ㋾ */
+ 0x3300, 0x3357, /* ㌀ - ㍗ */
+ 0x3371, 0x3376, /* ㍱ - ㍶ */
+ 0x337b, 0x3394, /* ㍻ - ㎔ */
+ 0x3399, 0x339e, /* ㎙ - ㎞ */
+ 0x33a9, 0x33ad, /* ㎩ - ㎭ */
+ 0x33b0, 0x33c1, /* ㎰ - ㏁ */
+ 0x33c3, 0x33c5, /* ㏃ - ㏅ */
+ 0x33c7, 0x33d7, /* ㏇ - ㏗ */
+ 0x33d9, 0x33dd, /* ㏙ - ㏝ */
+ 0x4e00, 0x9fff, /* 一 - 鿿 */
+ 0xac00, 0xd7a3, /* 가 - 힣 */
+ 0xf900, 0xfb06, /* 豈 - st */
+ 0xfb13, 0xfb17, /* ﬓ - ﬗ */
+ 0xfb1f, 0xfb28, /* ײַ - ﬨ */
+ 0xfb2a, 0xfb36, /* שׁ - זּ */
+ 0xfb38, 0xfb3c, /* טּ - לּ */
+ 0xfb40, 0xfb41, /* נּ - סּ */
+ 0xfb43, 0xfb44, /* ףּ - פּ */
+ 0xfb46, 0xfbb1, /* צּ - ﮱ */
+ 0xfbd3, 0xfd3d, /* ﯓ - ﴽ */
+ 0xfd50, 0xfd8f, /* ﵐ - ﶏ */
+ 0xfd92, 0xfdc7, /* ﶒ - ﷇ */
+ 0xfdf0, 0xfdf9, /* ﷰ - ﷹ */
+ 0xfe70, 0xfe72, /* ﹰ - ﹲ */
+ 0xfe76, 0xfefc, /* ﹶ - ﻼ */
+ 0xff66, 0xff6f, /* ヲ - ッ */
+ 0xff71, 0xff9d, /* ア - ン */
+ 0xffa0, 0xffbe, /* ᅠ - ᄒ */
+ 0xffc2, 0xffc7, /* ᅡ - ᅦ */
+ 0xffca, 0xffcf, /* ᅧ - ᅬ */
+ 0xffd2, 0xffd7, /* ᅭ - ᅲ */
+ 0xffda, 0xffdc /* ᅳ - ᅵ */
+]
+
+/*
+ * alpha singlets -
+ * only covers ranges not in lower||upper
+ */
+const ralpha1 = [
+ 0x00aa, /* ª */
+ 0x00b5, /* µ */
+ 0x00ba, /* º */
+ 0x03da, /* Ϛ */
+ 0x03dc, /* Ϝ */
+ 0x03de, /* Ϟ */
+ 0x03e0, /* Ϡ */
+ 0x06d5, /* ە */
+ 0x09b2, /* ল */
+ 0x0a5e, /* ਫ਼ */
+ 0x0a8d, /* ઍ */
+ 0x0ae0, /* ૠ */
+ 0x0b9c, /* ஜ */
+ 0x0cde, /* ೞ */
+ 0x0e4f, /* ๏ */
+ 0x0e84, /* ຄ */
+ 0x0e8a, /* ຊ */
+ 0x0e8d, /* ຍ */
+ 0x0ea5, /* ລ */
+ 0x0ea7, /* ວ */
+ 0x0eb0, /* ະ */
+ 0x0ebd, /* ຽ */
+ 0x1fbe, /* ι */
+ 0x207f, /* ⁿ */
+ 0x20a8, /* ₨ */
+ 0x2102, /* ℂ */
+ 0x2107, /* ℇ */
+ 0x2124, /* ℤ */
+ 0x2126, /* Ω */
+ 0x2128, /* ℨ */
+ 0xfb3e, /* מּ */
+ 0xfe74 /* ﹴ */
+]
+
+/*
+ * space ranges
+ */
+const rspace2 = [
+ 0x0009, 0x0009, /* tab */
+ 0x0020, 0x0020, /* space */
+ 0x0085, 0x0085,
+ 0x00a0, 0x00a0, /* */
+ 0x1680, 0x1680,
+ 0x180e, 0x180e,
+ 0x2000, 0x200b, /*   - ​ */
+ 0x2028, 0x2029, /* 
 - 
 */
+ 0x202f, 0x202f,
+ 0x205f, 0x205f,
+ 0x3000, 0x3000, /*   */
+ 0xfeff, 0xfeff /*  */
+]
+
+/*
+ * lower case ranges
+ * 3rd col is conversion excess 500
+ */
+const rtoupper2 = [
+ 0x0061, 0x007a, 468, /* a-z A-Z */
+ 0x00e0, 0x00f6, 468, /* à-ö À-Ö */
+ 0x00f8, 0x00fe, 468, /* ø-þ Ø-Þ */
+ 0x0256, 0x0257, 295, /* ɖ-ɗ Ɖ-Ɗ */
+ 0x0258, 0x0259, 298, /* ɘ-ə Ǝ-Ə */
+ 0x028a, 0x028b, 283, /* ʊ-ʋ Ʊ-Ʋ */
+ 0x03ad, 0x03af, 463, /* έ-ί Έ-Ί */
+ 0x03b1, 0x03c1, 468, /* α-ρ Α-Ρ */
+ 0x03c3, 0x03cb, 468, /* σ-ϋ Σ-Ϋ */
+ 0x03cd, 0x03ce, 437, /* ύ-ώ Ύ-Ώ */
+ 0x0430, 0x044f, 468, /* а-я А-Я */
+ 0x0451, 0x045c, 420, /* ё-ќ Ё-Ќ */
+ 0x045e, 0x045f, 420, /* ў-џ Ў-Џ */
+ 0x0561, 0x0586, 452, /* ա-ֆ Ա-Ֆ */
+ 0x1f00, 0x1f07, 508, /* ἀ-ἇ Ἀ-Ἇ */
+ 0x1f10, 0x1f15, 508, /* ἐ-ἕ Ἐ-Ἕ */
+ 0x1f20, 0x1f27, 508, /* ἠ-ἧ Ἠ-Ἧ */
+ 0x1f30, 0x1f37, 508, /* ἰ-ἷ Ἰ-Ἷ */
+ 0x1f40, 0x1f45, 508, /* ὀ-ὅ Ὀ-Ὅ */
+ 0x1f60, 0x1f67, 508, /* ὠ-ὧ Ὠ-Ὧ */
+ 0x1f70, 0x1f71, 574, /* ὰ-ά Ὰ-Ά */
+ 0x1f72, 0x1f75, 586, /* ὲ-ή Ὲ-Ή */
+ 0x1f76, 0x1f77, 600, /* ὶ-ί Ὶ-Ί */
+ 0x1f78, 0x1f79, 628, /* ὸ-ό Ὸ-Ό */
+ 0x1f7a, 0x1f7b, 612, /* ὺ-ύ Ὺ-Ύ */
+ 0x1f7c, 0x1f7d, 626, /* ὼ-ώ Ὼ-Ώ */
+ 0x1f80, 0x1f87, 508, /* ᾀ-ᾇ ᾈ-ᾏ */
+ 0x1f90, 0x1f97, 508, /* ᾐ-ᾗ ᾘ-ᾟ */
+ 0x1fa0, 0x1fa7, 508, /* ᾠ-ᾧ ᾨ-ᾯ */
+ 0x1fb0, 0x1fb1, 508, /* ᾰ-ᾱ Ᾰ-Ᾱ */
+ 0x1fd0, 0x1fd1, 508, /* ῐ-ῑ Ῐ-Ῑ */
+ 0x1fe0, 0x1fe1, 508, /* ῠ-ῡ Ῠ-Ῡ */
+ 0x2170, 0x217f, 484, /* ⅰ-ⅿ Ⅰ-Ⅿ */
+ 0x24d0, 0x24e9, 474, /* ⓐ-ⓩ Ⓐ-Ⓩ */
+ 0xff41, 0xff5a, 468 /* a-z A-Z */
+]
+
+/*
+ * lower case singlets
+ * 2nd col is conversion excess 500
+ */
+const rtoupper1 = [
+ 0x00ff, 621, /* ÿ Ÿ */
+ 0x0101, 499, /* ā Ā */
+ 0x0103, 499, /* ă Ă */
+ 0x0105, 499, /* ą Ą */
+ 0x0107, 499, /* ć Ć */
+ 0x0109, 499, /* ĉ Ĉ */
+ 0x010b, 499, /* ċ Ċ */
+ 0x010d, 499, /* č Č */
+ 0x010f, 499, /* ď Ď */
+ 0x0111, 499, /* đ Đ */
+ 0x0113, 499, /* ē Ē */
+ 0x0115, 499, /* ĕ Ĕ */
+ 0x0117, 499, /* ė Ė */
+ 0x0119, 499, /* ę Ę */
+ 0x011b, 499, /* ě Ě */
+ 0x011d, 499, /* ĝ Ĝ */
+ 0x011f, 499, /* ğ Ğ */
+ 0x0121, 499, /* ġ Ġ */
+ 0x0123, 499, /* ģ Ģ */
+ 0x0125, 499, /* ĥ Ĥ */
+ 0x0127, 499, /* ħ Ħ */
+ 0x0129, 499, /* ĩ Ĩ */
+ 0x012b, 499, /* ī Ī */
+ 0x012d, 499, /* ĭ Ĭ */
+ 0x012f, 499, /* į Į */
+ 0x0131, 268, /* ı I */
+ 0x0133, 499, /* ij IJ */
+ 0x0135, 499, /* ĵ Ĵ */
+ 0x0137, 499, /* ķ Ķ */
+ 0x013a, 499, /* ĺ Ĺ */
+ 0x013c, 499, /* ļ Ļ */
+ 0x013e, 499, /* ľ Ľ */
+ 0x0140, 499, /* ŀ Ŀ */
+ 0x0142, 499, /* ł Ł */
+ 0x0144, 499, /* ń Ń */
+ 0x0146, 499, /* ņ Ņ */
+ 0x0148, 499, /* ň Ň */
+ 0x014b, 499, /* ŋ Ŋ */
+ 0x014d, 499, /* ō Ō */
+ 0x014f, 499, /* ŏ Ŏ */
+ 0x0151, 499, /* ő Ő */
+ 0x0153, 499, /* œ Œ */
+ 0x0155, 499, /* ŕ Ŕ */
+ 0x0157, 499, /* ŗ Ŗ */
+ 0x0159, 499, /* ř Ř */
+ 0x015b, 499, /* ś Ś */
+ 0x015d, 499, /* ŝ Ŝ */
+ 0x015f, 499, /* ş Ş */
+ 0x0161, 499, /* š Š */
+ 0x0163, 499, /* ţ Ţ */
+ 0x0165, 499, /* ť Ť */
+ 0x0167, 499, /* ŧ Ŧ */
+ 0x0169, 499, /* ũ Ũ */
+ 0x016b, 499, /* ū Ū */
+ 0x016d, 499, /* ŭ Ŭ */
+ 0x016f, 499, /* ů Ů */
+ 0x0171, 499, /* ű Ű */
+ 0x0173, 499, /* ų Ų */
+ 0x0175, 499, /* ŵ Ŵ */
+ 0x0177, 499, /* ŷ Ŷ */
+ 0x017a, 499, /* ź Ź */
+ 0x017c, 499, /* ż Ż */
+ 0x017e, 499, /* ž Ž */
+ 0x017f, 200, /* ſ S */
+ 0x0183, 499, /* ƃ Ƃ */
+ 0x0185, 499, /* ƅ Ƅ */
+ 0x0188, 499, /* ƈ Ƈ */
+ 0x018c, 499, /* ƌ Ƌ */
+ 0x0192, 499, /* ƒ Ƒ */
+ 0x0199, 499, /* ƙ Ƙ */
+ 0x01a1, 499, /* ơ Ơ */
+ 0x01a3, 499, /* ƣ Ƣ */
+ 0x01a5, 499, /* ƥ Ƥ */
+ 0x01a8, 499, /* ƨ Ƨ */
+ 0x01ad, 499, /* ƭ Ƭ */
+ 0x01b0, 499, /* ư Ư */
+ 0x01b4, 499, /* ƴ Ƴ */
+ 0x01b6, 499, /* ƶ Ƶ */
+ 0x01b9, 499, /* ƹ Ƹ */
+ 0x01bd, 499, /* ƽ Ƽ */
+ 0x01c5, 499, /* Dž DŽ */
+ 0x01c6, 498, /* dž DŽ */
+ 0x01c8, 499, /* Lj LJ */
+ 0x01c9, 498, /* lj LJ */
+ 0x01cb, 499, /* Nj NJ */
+ 0x01cc, 498, /* nj NJ */
+ 0x01ce, 499, /* ǎ Ǎ */
+ 0x01d0, 499, /* ǐ Ǐ */
+ 0x01d2, 499, /* ǒ Ǒ */
+ 0x01d4, 499, /* ǔ Ǔ */
+ 0x01d6, 499, /* ǖ Ǖ */
+ 0x01d8, 499, /* ǘ Ǘ */
+ 0x01da, 499, /* ǚ Ǚ */
+ 0x01dc, 499, /* ǜ Ǜ */
+ 0x01df, 499, /* ǟ Ǟ */
+ 0x01e1, 499, /* ǡ Ǡ */
+ 0x01e3, 499, /* ǣ Ǣ */
+ 0x01e5, 499, /* ǥ Ǥ */
+ 0x01e7, 499, /* ǧ Ǧ */
+ 0x01e9, 499, /* ǩ Ǩ */
+ 0x01eb, 499, /* ǫ Ǫ */
+ 0x01ed, 499, /* ǭ Ǭ */
+ 0x01ef, 499, /* ǯ Ǯ */
+ 0x01f2, 499, /* Dz DZ */
+ 0x01f3, 498, /* dz DZ */
+ 0x01f5, 499, /* ǵ Ǵ */
+ 0x01fb, 499, /* ǻ Ǻ */
+ 0x01fd, 499, /* ǽ Ǽ */
+ 0x01ff, 499, /* ǿ Ǿ */
+ 0x0201, 499, /* ȁ Ȁ */
+ 0x0203, 499, /* ȃ Ȃ */
+ 0x0205, 499, /* ȅ Ȅ */
+ 0x0207, 499, /* ȇ Ȇ */
+ 0x0209, 499, /* ȉ Ȉ */
+ 0x020b, 499, /* ȋ Ȋ */
+ 0x020d, 499, /* ȍ Ȍ */
+ 0x020f, 499, /* ȏ Ȏ */
+ 0x0211, 499, /* ȑ Ȑ */
+ 0x0213, 499, /* ȓ Ȓ */
+ 0x0215, 499, /* ȕ Ȕ */
+ 0x0217, 499, /* ȗ Ȗ */
+ 0x0253, 290, /* ɓ Ɓ */
+ 0x0254, 294, /* ɔ Ɔ */
+ 0x025b, 297, /* ɛ Ɛ */
+ 0x0260, 295, /* ɠ Ɠ */
+ 0x0263, 293, /* ɣ Ɣ */
+ 0x0268, 291, /* ɨ Ɨ */
+ 0x0269, 289, /* ɩ Ɩ */
+ 0x026f, 289, /* ɯ Ɯ */
+ 0x0272, 287, /* ɲ Ɲ */
+ 0x0283, 282, /* ʃ Ʃ */
+ 0x0288, 282, /* ʈ Ʈ */
+ 0x0292, 281, /* ʒ Ʒ */
+ 0x03ac, 462, /* ά Ά */
+ 0x03cc, 436, /* ό Ό */
+ 0x03d0, 438, /* ϐ Β */
+ 0x03d1, 443, /* ϑ Θ */
+ 0x03d5, 453, /* ϕ Φ */
+ 0x03d6, 446, /* ϖ Π */
+ 0x03e3, 499, /* ϣ Ϣ */
+ 0x03e5, 499, /* ϥ Ϥ */
+ 0x03e7, 499, /* ϧ Ϧ */
+ 0x03e9, 499, /* ϩ Ϩ */
+ 0x03eb, 499, /* ϫ Ϫ */
+ 0x03ed, 499, /* ϭ Ϭ */
+ 0x03ef, 499, /* ϯ Ϯ */
+ 0x03f0, 414, /* ϰ Κ */
+ 0x03f1, 420, /* ϱ Ρ */
+ 0x0461, 499, /* ѡ Ѡ */
+ 0x0463, 499, /* ѣ Ѣ */
+ 0x0465, 499, /* ѥ Ѥ */
+ 0x0467, 499, /* ѧ Ѧ */
+ 0x0469, 499, /* ѩ Ѩ */
+ 0x046b, 499, /* ѫ Ѫ */
+ 0x046d, 499, /* ѭ Ѭ */
+ 0x046f, 499, /* ѯ Ѯ */
+ 0x0471, 499, /* ѱ Ѱ */
+ 0x0473, 499, /* ѳ Ѳ */
+ 0x0475, 499, /* ѵ Ѵ */
+ 0x0477, 499, /* ѷ Ѷ */
+ 0x0479, 499, /* ѹ Ѹ */
+ 0x047b, 499, /* ѻ Ѻ */
+ 0x047d, 499, /* ѽ Ѽ */
+ 0x047f, 499, /* ѿ Ѿ */
+ 0x0481, 499, /* ҁ Ҁ */
+ 0x0491, 499, /* ґ Ґ */
+ 0x0493, 499, /* ғ Ғ */
+ 0x0495, 499, /* ҕ Ҕ */
+ 0x0497, 499, /* җ Җ */
+ 0x0499, 499, /* ҙ Ҙ */
+ 0x049b, 499, /* қ Қ */
+ 0x049d, 499, /* ҝ Ҝ */
+ 0x049f, 499, /* ҟ Ҟ */
+ 0x04a1, 499, /* ҡ Ҡ */
+ 0x04a3, 499, /* ң Ң */
+ 0x04a5, 499, /* ҥ Ҥ */
+ 0x04a7, 499, /* ҧ Ҧ */
+ 0x04a9, 499, /* ҩ Ҩ */
+ 0x04ab, 499, /* ҫ Ҫ */
+ 0x04ad, 499, /* ҭ Ҭ */
+ 0x04af, 499, /* ү Ү */
+ 0x04b1, 499, /* ұ Ұ */
+ 0x04b3, 499, /* ҳ Ҳ */
+ 0x04b5, 499, /* ҵ Ҵ */
+ 0x04b7, 499, /* ҷ Ҷ */
+ 0x04b9, 499, /* ҹ Ҹ */
+ 0x04bb, 499, /* һ Һ */
+ 0x04bd, 499, /* ҽ Ҽ */
+ 0x04bf, 499, /* ҿ Ҿ */
+ 0x04c2, 499, /* ӂ Ӂ */
+ 0x04c4, 499, /* ӄ Ӄ */
+ 0x04c8, 499, /* ӈ Ӈ */
+ 0x04cc, 499, /* ӌ Ӌ */
+ 0x04d1, 499, /* ӑ Ӑ */
+ 0x04d3, 499, /* ӓ Ӓ */
+ 0x04d5, 499, /* ӕ Ӕ */
+ 0x04d7, 499, /* ӗ Ӗ */
+ 0x04d9, 499, /* ә Ә */
+ 0x04db, 499, /* ӛ Ӛ */
+ 0x04dd, 499, /* ӝ Ӝ */
+ 0x04df, 499, /* ӟ Ӟ */
+ 0x04e1, 499, /* ӡ Ӡ */
+ 0x04e3, 499, /* ӣ Ӣ */
+ 0x04e5, 499, /* ӥ Ӥ */
+ 0x04e7, 499, /* ӧ Ӧ */
+ 0x04e9, 499, /* ө Ө */
+ 0x04eb, 499, /* ӫ Ӫ */
+ 0x04ef, 499, /* ӯ Ӯ */
+ 0x04f1, 499, /* ӱ Ӱ */
+ 0x04f3, 499, /* ӳ Ӳ */
+ 0x04f5, 499, /* ӵ Ӵ */
+ 0x04f9, 499, /* ӹ Ӹ */
+ 0x1e01, 499, /* ḁ Ḁ */
+ 0x1e03, 499, /* ḃ Ḃ */
+ 0x1e05, 499, /* ḅ Ḅ */
+ 0x1e07, 499, /* ḇ Ḇ */
+ 0x1e09, 499, /* ḉ Ḉ */
+ 0x1e0b, 499, /* ḋ Ḋ */
+ 0x1e0d, 499, /* ḍ Ḍ */
+ 0x1e0f, 499, /* ḏ Ḏ */
+ 0x1e11, 499, /* ḑ Ḑ */
+ 0x1e13, 499, /* ḓ Ḓ */
+ 0x1e15, 499, /* ḕ Ḕ */
+ 0x1e17, 499, /* ḗ Ḗ */
+ 0x1e19, 499, /* ḙ Ḙ */
+ 0x1e1b, 499, /* ḛ Ḛ */
+ 0x1e1d, 499, /* ḝ Ḝ */
+ 0x1e1f, 499, /* ḟ Ḟ */
+ 0x1e21, 499, /* ḡ Ḡ */
+ 0x1e23, 499, /* ḣ Ḣ */
+ 0x1e25, 499, /* ḥ Ḥ */
+ 0x1e27, 499, /* ḧ Ḧ */
+ 0x1e29, 499, /* ḩ Ḩ */
+ 0x1e2b, 499, /* ḫ Ḫ */
+ 0x1e2d, 499, /* ḭ Ḭ */
+ 0x1e2f, 499, /* ḯ Ḯ */
+ 0x1e31, 499, /* ḱ Ḱ */
+ 0x1e33, 499, /* ḳ Ḳ */
+ 0x1e35, 499, /* ḵ Ḵ */
+ 0x1e37, 499, /* ḷ Ḷ */
+ 0x1e39, 499, /* ḹ Ḹ */
+ 0x1e3b, 499, /* ḻ Ḻ */
+ 0x1e3d, 499, /* ḽ Ḽ */
+ 0x1e3f, 499, /* ḿ Ḿ */
+ 0x1e41, 499, /* ṁ Ṁ */
+ 0x1e43, 499, /* ṃ Ṃ */
+ 0x1e45, 499, /* ṅ Ṅ */
+ 0x1e47, 499, /* ṇ Ṇ */
+ 0x1e49, 499, /* ṉ Ṉ */
+ 0x1e4b, 499, /* ṋ Ṋ */
+ 0x1e4d, 499, /* ṍ Ṍ */
+ 0x1e4f, 499, /* ṏ Ṏ */
+ 0x1e51, 499, /* ṑ Ṑ */
+ 0x1e53, 499, /* ṓ Ṓ */
+ 0x1e55, 499, /* ṕ Ṕ */
+ 0x1e57, 499, /* ṗ Ṗ */
+ 0x1e59, 499, /* ṙ Ṙ */
+ 0x1e5b, 499, /* ṛ Ṛ */
+ 0x1e5d, 499, /* ṝ Ṝ */
+ 0x1e5f, 499, /* ṟ Ṟ */
+ 0x1e61, 499, /* ṡ Ṡ */
+ 0x1e63, 499, /* ṣ Ṣ */
+ 0x1e65, 499, /* ṥ Ṥ */
+ 0x1e67, 499, /* ṧ Ṧ */
+ 0x1e69, 499, /* ṩ Ṩ */
+ 0x1e6b, 499, /* ṫ Ṫ */
+ 0x1e6d, 499, /* ṭ Ṭ */
+ 0x1e6f, 499, /* ṯ Ṯ */
+ 0x1e71, 499, /* ṱ Ṱ */
+ 0x1e73, 499, /* ṳ Ṳ */
+ 0x1e75, 499, /* ṵ Ṵ */
+ 0x1e77, 499, /* ṷ Ṷ */
+ 0x1e79, 499, /* ṹ Ṹ */
+ 0x1e7b, 499, /* ṻ Ṻ */
+ 0x1e7d, 499, /* ṽ Ṽ */
+ 0x1e7f, 499, /* ṿ Ṿ */
+ 0x1e81, 499, /* ẁ Ẁ */
+ 0x1e83, 499, /* ẃ Ẃ */
+ 0x1e85, 499, /* ẅ Ẅ */
+ 0x1e87, 499, /* ẇ Ẇ */
+ 0x1e89, 499, /* ẉ Ẉ */
+ 0x1e8b, 499, /* ẋ Ẋ */
+ 0x1e8d, 499, /* ẍ Ẍ */
+ 0x1e8f, 499, /* ẏ Ẏ */
+ 0x1e91, 499, /* ẑ Ẑ */
+ 0x1e93, 499, /* ẓ Ẓ */
+ 0x1e95, 499, /* ẕ Ẕ */
+ 0x1ea1, 499, /* ạ Ạ */
+ 0x1ea3, 499, /* ả Ả */
+ 0x1ea5, 499, /* ấ Ấ */
+ 0x1ea7, 499, /* ầ Ầ */
+ 0x1ea9, 499, /* ẩ Ẩ */
+ 0x1eab, 499, /* ẫ Ẫ */
+ 0x1ead, 499, /* ậ Ậ */
+ 0x1eaf, 499, /* ắ Ắ */
+ 0x1eb1, 499, /* ằ Ằ */
+ 0x1eb3, 499, /* ẳ Ẳ */
+ 0x1eb5, 499, /* ẵ Ẵ */
+ 0x1eb7, 499, /* ặ Ặ */
+ 0x1eb9, 499, /* ẹ Ẹ */
+ 0x1ebb, 499, /* ẻ Ẻ */
+ 0x1ebd, 499, /* ẽ Ẽ */
+ 0x1ebf, 499, /* ế Ế */
+ 0x1ec1, 499, /* ề Ề */
+ 0x1ec3, 499, /* ể Ể */
+ 0x1ec5, 499, /* ễ Ễ */
+ 0x1ec7, 499, /* ệ Ệ */
+ 0x1ec9, 499, /* ỉ Ỉ */
+ 0x1ecb, 499, /* ị Ị */
+ 0x1ecd, 499, /* ọ Ọ */
+ 0x1ecf, 499, /* ỏ Ỏ */
+ 0x1ed1, 499, /* ố Ố */
+ 0x1ed3, 499, /* ồ Ồ */
+ 0x1ed5, 499, /* ổ Ổ */
+ 0x1ed7, 499, /* ỗ Ỗ */
+ 0x1ed9, 499, /* ộ Ộ */
+ 0x1edb, 499, /* ớ Ớ */
+ 0x1edd, 499, /* ờ Ờ */
+ 0x1edf, 499, /* ở Ở */
+ 0x1ee1, 499, /* ỡ Ỡ */
+ 0x1ee3, 499, /* ợ Ợ */
+ 0x1ee5, 499, /* ụ Ụ */
+ 0x1ee7, 499, /* ủ Ủ */
+ 0x1ee9, 499, /* ứ Ứ */
+ 0x1eeb, 499, /* ừ Ừ */
+ 0x1eed, 499, /* ử Ử */
+ 0x1eef, 499, /* ữ Ữ */
+ 0x1ef1, 499, /* ự Ự */
+ 0x1ef3, 499, /* ỳ Ỳ */
+ 0x1ef5, 499, /* ỵ Ỵ */
+ 0x1ef7, 499, /* ỷ Ỷ */
+ 0x1ef9, 499, /* ỹ Ỹ */
+ 0x1f51, 508, /* ὑ Ὑ */
+ 0x1f53, 508, /* ὓ Ὓ */
+ 0x1f55, 508, /* ὕ Ὕ */
+ 0x1f57, 508, /* ὗ Ὗ */
+ 0x1fb3, 509, /* ᾳ ᾼ */
+ 0x1fc3, 509, /* ῃ ῌ */
+ 0x1fe5, 507, /* ῥ Ῥ */
+ 0x1ff3, 509 /* ῳ ῼ */
+]
+
+const rnums = [
+ 0x0030, 0x0039,
+ 0x0660, 0x0669,
+ 0x06f0, 0x06f9,
+ 0x07c0, 0x07c9,
+ 0x0966, 0x096f,
+ 0x09e6, 0x09ef,
+ 0x0a66, 0x0a6f,
+ 0x0ae6, 0x0aef,
+ 0x0b66, 0x0b6f,
+ 0x0be6, 0x0bef,
+ 0x0c66, 0x0c6f,
+ 0x0ce6, 0x0cef,
+ 0x0d66, 0x0d6f,
+ 0x0e50, 0x0e59,
+ 0x0ed0, 0x0ed9,
+ 0x0f20, 0x0f29,
+ 0x1040, 0x1049,
+ 0x17e0, 0x17e9,
+ 0x1810, 0x1819,
+ 0x1946, 0x194f,
+ 0x19d0, 0x19d9,
+ 0x1b50, 0x1b59,
+ 0xff10, 0xff19,
+ 0x104a0, 0x104a9,
+ 0x1d7ce, 0x1d7ff
+]
+
+/*
+ * upper case ranges
+ * 3rd col is conversion excess 500
+ */
+const rtolower2 = [
+ 0x0041, 0x005a, 532, /* A-Z a-z */
+ 0x00c0, 0x00d6, 532, /* À-Ö à-ö */
+ 0x00d8, 0x00de, 532, /* Ø-Þ ø-þ */
+ 0x0189, 0x018a, 705, /* Ɖ-Ɗ ɖ-ɗ */
+ 0x018e, 0x018f, 702, /* Ǝ-Ə ɘ-ə */
+ 0x01b1, 0x01b2, 717, /* Ʊ-Ʋ ʊ-ʋ */
+ 0x0388, 0x038a, 537, /* Έ-Ί έ-ί */
+ 0x038e, 0x038f, 563, /* Ύ-Ώ ύ-ώ */
+ 0x0391, 0x03a1, 532, /* Α-Ρ α-ρ */
+ 0x03a3, 0x03ab, 532, /* Σ-Ϋ σ-ϋ */
+ 0x0401, 0x040c, 580, /* Ё-Ќ ё-ќ */
+ 0x040e, 0x040f, 580, /* Ў-Џ ў-џ */
+ 0x0410, 0x042f, 532, /* А-Я а-я */
+ 0x0531, 0x0556, 548, /* Ա-Ֆ ա-ֆ */
+ 0x10a0, 0x10c5, 548, /* Ⴀ-Ⴥ ა-ჵ */
+ 0x1f08, 0x1f0f, 492, /* Ἀ-Ἇ ἀ-ἇ */
+ 0x1f18, 0x1f1d, 492, /* Ἐ-Ἕ ἐ-ἕ */
+ 0x1f28, 0x1f2f, 492, /* Ἠ-Ἧ ἠ-ἧ */
+ 0x1f38, 0x1f3f, 492, /* Ἰ-Ἷ ἰ-ἷ */
+ 0x1f48, 0x1f4d, 492, /* Ὀ-Ὅ ὀ-ὅ */
+ 0x1f68, 0x1f6f, 492, /* Ὠ-Ὧ ὠ-ὧ */
+ 0x1f88, 0x1f8f, 492, /* ᾈ-ᾏ ᾀ-ᾇ */
+ 0x1f98, 0x1f9f, 492, /* ᾘ-ᾟ ᾐ-ᾗ */
+ 0x1fa8, 0x1faf, 492, /* ᾨ-ᾯ ᾠ-ᾧ */
+ 0x1fb8, 0x1fb9, 492, /* Ᾰ-Ᾱ ᾰ-ᾱ */
+ 0x1fba, 0x1fbb, 426, /* Ὰ-Ά ὰ-ά */
+ 0x1fc8, 0x1fcb, 414, /* Ὲ-Ή ὲ-ή */
+ 0x1fd8, 0x1fd9, 492, /* Ῐ-Ῑ ῐ-ῑ */
+ 0x1fda, 0x1fdb, 400, /* Ὶ-Ί ὶ-ί */
+ 0x1fe8, 0x1fe9, 492, /* Ῠ-Ῡ ῠ-ῡ */
+ 0x1fea, 0x1feb, 388, /* Ὺ-Ύ ὺ-ύ */
+ 0x1ff8, 0x1ff9, 372, /* Ὸ-Ό ὸ-ό */
+ 0x1ffa, 0x1ffb, 374, /* Ὼ-Ώ ὼ-ώ */
+ 0x2160, 0x216f, 516, /* Ⅰ-Ⅿ ⅰ-ⅿ */
+ 0x24b6, 0x24cf, 526, /* Ⓐ-Ⓩ ⓐ-ⓩ */
+ 0xff21, 0xff3a, 532 /* A-Z a-z */
+]
+
+/*
+ * upper case singlets
+ * 2nd col is conversion excess 500
+ */
+const rtolower1 = [
+ 0x0100, 501, /* Ā ā */
+ 0x0102, 501, /* Ă ă */
+ 0x0104, 501, /* Ą ą */
+ 0x0106, 501, /* Ć ć */
+ 0x0108, 501, /* Ĉ ĉ */
+ 0x010a, 501, /* Ċ ċ */
+ 0x010c, 501, /* Č č */
+ 0x010e, 501, /* Ď ď */
+ 0x0110, 501, /* Đ đ */
+ 0x0112, 501, /* Ē ē */
+ 0x0114, 501, /* Ĕ ĕ */
+ 0x0116, 501, /* Ė ė */
+ 0x0118, 501, /* Ę ę */
+ 0x011a, 501, /* Ě ě */
+ 0x011c, 501, /* Ĝ ĝ */
+ 0x011e, 501, /* Ğ ğ */
+ 0x0120, 501, /* Ġ ġ */
+ 0x0122, 501, /* Ģ ģ */
+ 0x0124, 501, /* Ĥ ĥ */
+ 0x0126, 501, /* Ħ ħ */
+ 0x0128, 501, /* Ĩ ĩ */
+ 0x012a, 501, /* Ī ī */
+ 0x012c, 501, /* Ĭ ĭ */
+ 0x012e, 501, /* Į į */
+ 0x0130, 301, /* İ i */
+ 0x0132, 501, /* IJ ij */
+ 0x0134, 501, /* Ĵ ĵ */
+ 0x0136, 501, /* Ķ ķ */
+ 0x0139, 501, /* Ĺ ĺ */
+ 0x013b, 501, /* Ļ ļ */
+ 0x013d, 501, /* Ľ ľ */
+ 0x013f, 501, /* Ŀ ŀ */
+ 0x0141, 501, /* Ł ł */
+ 0x0143, 501, /* Ń ń */
+ 0x0145, 501, /* Ņ ņ */
+ 0x0147, 501, /* Ň ň */
+ 0x014a, 501, /* Ŋ ŋ */
+ 0x014c, 501, /* Ō ō */
+ 0x014e, 501, /* Ŏ ŏ */
+ 0x0150, 501, /* Ő ő */
+ 0x0152, 501, /* Œ œ */
+ 0x0154, 501, /* Ŕ ŕ */
+ 0x0156, 501, /* Ŗ ŗ */
+ 0x0158, 501, /* Ř ř */
+ 0x015a, 501, /* Ś ś */
+ 0x015c, 501, /* Ŝ ŝ */
+ 0x015e, 501, /* Ş ş */
+ 0x0160, 501, /* Š š */
+ 0x0162, 501, /* Ţ ţ */
+ 0x0164, 501, /* Ť ť */
+ 0x0166, 501, /* Ŧ ŧ */
+ 0x0168, 501, /* Ũ ũ */
+ 0x016a, 501, /* Ū ū */
+ 0x016c, 501, /* Ŭ ŭ */
+ 0x016e, 501, /* Ů ů */
+ 0x0170, 501, /* Ű ű */
+ 0x0172, 501, /* Ų ų */
+ 0x0174, 501, /* Ŵ ŵ */
+ 0x0176, 501, /* Ŷ ŷ */
+ 0x0178, 379, /* Ÿ ÿ */
+ 0x0179, 501, /* Ź ź */
+ 0x017b, 501, /* Ż ż */
+ 0x017d, 501, /* Ž ž */
+ 0x0181, 710, /* Ɓ ɓ */
+ 0x0182, 501, /* Ƃ ƃ */
+ 0x0184, 501, /* Ƅ ƅ */
+ 0x0186, 706, /* Ɔ ɔ */
+ 0x0187, 501, /* Ƈ ƈ */
+ 0x018b, 501, /* Ƌ ƌ */
+ 0x0190, 703, /* Ɛ ɛ */
+ 0x0191, 501, /* Ƒ ƒ */
+ 0x0193, 705, /* Ɠ ɠ */
+ 0x0194, 707, /* Ɣ ɣ */
+ 0x0196, 711, /* Ɩ ɩ */
+ 0x0197, 709, /* Ɨ ɨ */
+ 0x0198, 501, /* Ƙ ƙ */
+ 0x019c, 711, /* Ɯ ɯ */
+ 0x019d, 713, /* Ɲ ɲ */
+ 0x01a0, 501, /* Ơ ơ */
+ 0x01a2, 501, /* Ƣ ƣ */
+ 0x01a4, 501, /* Ƥ ƥ */
+ 0x01a7, 501, /* Ƨ ƨ */
+ 0x01a9, 718, /* Ʃ ʃ */
+ 0x01ac, 501, /* Ƭ ƭ */
+ 0x01ae, 718, /* Ʈ ʈ */
+ 0x01af, 501, /* Ư ư */
+ 0x01b3, 501, /* Ƴ ƴ */
+ 0x01b5, 501, /* Ƶ ƶ */
+ 0x01b7, 719, /* Ʒ ʒ */
+ 0x01b8, 501, /* Ƹ ƹ */
+ 0x01bc, 501, /* Ƽ ƽ */
+ 0x01c4, 502, /* DŽ dž */
+ 0x01c5, 501, /* Dž dž */
+ 0x01c7, 502, /* LJ lj */
+ 0x01c8, 501, /* Lj lj */
+ 0x01ca, 502, /* NJ nj */
+ 0x01cb, 501, /* Nj nj */
+ 0x01cd, 501, /* Ǎ ǎ */
+ 0x01cf, 501, /* Ǐ ǐ */
+ 0x01d1, 501, /* Ǒ ǒ */
+ 0x01d3, 501, /* Ǔ ǔ */
+ 0x01d5, 501, /* Ǖ ǖ */
+ 0x01d7, 501, /* Ǘ ǘ */
+ 0x01d9, 501, /* Ǚ ǚ */
+ 0x01db, 501, /* Ǜ ǜ */
+ 0x01de, 501, /* Ǟ ǟ */
+ 0x01e0, 501, /* Ǡ ǡ */
+ 0x01e2, 501, /* Ǣ ǣ */
+ 0x01e4, 501, /* Ǥ ǥ */
+ 0x01e6, 501, /* Ǧ ǧ */
+ 0x01e8, 501, /* Ǩ ǩ */
+ 0x01ea, 501, /* Ǫ ǫ */
+ 0x01ec, 501, /* Ǭ ǭ */
+ 0x01ee, 501, /* Ǯ ǯ */
+ 0x01f1, 502, /* DZ dz */
+ 0x01f2, 501, /* Dz dz */
+ 0x01f4, 501, /* Ǵ ǵ */
+ 0x01fa, 501, /* Ǻ ǻ */
+ 0x01fc, 501, /* Ǽ ǽ */
+ 0x01fe, 501, /* Ǿ ǿ */
+ 0x0200, 501, /* Ȁ ȁ */
+ 0x0202, 501, /* Ȃ ȃ */
+ 0x0204, 501, /* Ȅ ȅ */
+ 0x0206, 501, /* Ȇ ȇ */
+ 0x0208, 501, /* Ȉ ȉ */
+ 0x020a, 501, /* Ȋ ȋ */
+ 0x020c, 501, /* Ȍ ȍ */
+ 0x020e, 501, /* Ȏ ȏ */
+ 0x0210, 501, /* Ȑ ȑ */
+ 0x0212, 501, /* Ȓ ȓ */
+ 0x0214, 501, /* Ȕ ȕ */
+ 0x0216, 501, /* Ȗ ȗ */
+ 0x0386, 538, /* Ά ά */
+ 0x038c, 564, /* Ό ό */
+ 0x03e2, 501, /* Ϣ ϣ */
+ 0x03e4, 501, /* Ϥ ϥ */
+ 0x03e6, 501, /* Ϧ ϧ */
+ 0x03e8, 501, /* Ϩ ϩ */
+ 0x03ea, 501, /* Ϫ ϫ */
+ 0x03ec, 501, /* Ϭ ϭ */
+ 0x03ee, 501, /* Ϯ ϯ */
+ 0x0460, 501, /* Ѡ ѡ */
+ 0x0462, 501, /* Ѣ ѣ */
+ 0x0464, 501, /* Ѥ ѥ */
+ 0x0466, 501, /* Ѧ ѧ */
+ 0x0468, 501, /* Ѩ ѩ */
+ 0x046a, 501, /* Ѫ ѫ */
+ 0x046c, 501, /* Ѭ ѭ */
+ 0x046e, 501, /* Ѯ ѯ */
+ 0x0470, 501, /* Ѱ ѱ */
+ 0x0472, 501, /* Ѳ ѳ */
+ 0x0474, 501, /* Ѵ ѵ */
+ 0x0476, 501, /* Ѷ ѷ */
+ 0x0478, 501, /* Ѹ ѹ */
+ 0x047a, 501, /* Ѻ ѻ */
+ 0x047c, 501, /* Ѽ ѽ */
+ 0x047e, 501, /* Ѿ ѿ */
+ 0x0480, 501, /* Ҁ ҁ */
+ 0x0490, 501, /* Ґ ґ */
+ 0x0492, 501, /* Ғ ғ */
+ 0x0494, 501, /* Ҕ ҕ */
+ 0x0496, 501, /* Җ җ */
+ 0x0498, 501, /* Ҙ ҙ */
+ 0x049a, 501, /* Қ қ */
+ 0x049c, 501, /* Ҝ ҝ */
+ 0x049e, 501, /* Ҟ ҟ */
+ 0x04a0, 501, /* Ҡ ҡ */
+ 0x04a2, 501, /* Ң ң */
+ 0x04a4, 501, /* Ҥ ҥ */
+ 0x04a6, 501, /* Ҧ ҧ */
+ 0x04a8, 501, /* Ҩ ҩ */
+ 0x04aa, 501, /* Ҫ ҫ */
+ 0x04ac, 501, /* Ҭ ҭ */
+ 0x04ae, 501, /* Ү ү */
+ 0x04b0, 501, /* Ұ ұ */
+ 0x04b2, 501, /* Ҳ ҳ */
+ 0x04b4, 501, /* Ҵ ҵ */
+ 0x04b6, 501, /* Ҷ ҷ */
+ 0x04b8, 501, /* Ҹ ҹ */
+ 0x04ba, 501, /* Һ һ */
+ 0x04bc, 501, /* Ҽ ҽ */
+ 0x04be, 501, /* Ҿ ҿ */
+ 0x04c1, 501, /* Ӂ ӂ */
+ 0x04c3, 501, /* Ӄ ӄ */
+ 0x04c7, 501, /* Ӈ ӈ */
+ 0x04cb, 501, /* Ӌ ӌ */
+ 0x04d0, 501, /* Ӑ ӑ */
+ 0x04d2, 501, /* Ӓ ӓ */
+ 0x04d4, 501, /* Ӕ ӕ */
+ 0x04d6, 501, /* Ӗ ӗ */
+ 0x04d8, 501, /* Ә ә */
+ 0x04da, 501, /* Ӛ ӛ */
+ 0x04dc, 501, /* Ӝ ӝ */
+ 0x04de, 501, /* Ӟ ӟ */
+ 0x04e0, 501, /* Ӡ ӡ */
+ 0x04e2, 501, /* Ӣ ӣ */
+ 0x04e4, 501, /* Ӥ ӥ */
+ 0x04e6, 501, /* Ӧ ӧ */
+ 0x04e8, 501, /* Ө ө */
+ 0x04ea, 501, /* Ӫ ӫ */
+ 0x04ee, 501, /* Ӯ ӯ */
+ 0x04f0, 501, /* Ӱ ӱ */
+ 0x04f2, 501, /* Ӳ ӳ */
+ 0x04f4, 501, /* Ӵ ӵ */
+ 0x04f8, 501, /* Ӹ ӹ */
+ 0x1e00, 501, /* Ḁ ḁ */
+ 0x1e02, 501, /* Ḃ ḃ */
+ 0x1e04, 501, /* Ḅ ḅ */
+ 0x1e06, 501, /* Ḇ ḇ */
+ 0x1e08, 501, /* Ḉ ḉ */
+ 0x1e0a, 501, /* Ḋ ḋ */
+ 0x1e0c, 501, /* Ḍ ḍ */
+ 0x1e0e, 501, /* Ḏ ḏ */
+ 0x1e10, 501, /* Ḑ ḑ */
+ 0x1e12, 501, /* Ḓ ḓ */
+ 0x1e14, 501, /* Ḕ ḕ */
+ 0x1e16, 501, /* Ḗ ḗ */
+ 0x1e18, 501, /* Ḙ ḙ */
+ 0x1e1a, 501, /* Ḛ ḛ */
+ 0x1e1c, 501, /* Ḝ ḝ */
+ 0x1e1e, 501, /* Ḟ ḟ */
+ 0x1e20, 501, /* Ḡ ḡ */
+ 0x1e22, 501, /* Ḣ ḣ */
+ 0x1e24, 501, /* Ḥ ḥ */
+ 0x1e26, 501, /* Ḧ ḧ */
+ 0x1e28, 501, /* Ḩ ḩ */
+ 0x1e2a, 501, /* Ḫ ḫ */
+ 0x1e2c, 501, /* Ḭ ḭ */
+ 0x1e2e, 501, /* Ḯ ḯ */
+ 0x1e30, 501, /* Ḱ ḱ */
+ 0x1e32, 501, /* Ḳ ḳ */
+ 0x1e34, 501, /* Ḵ ḵ */
+ 0x1e36, 501, /* Ḷ ḷ */
+ 0x1e38, 501, /* Ḹ ḹ */
+ 0x1e3a, 501, /* Ḻ ḻ */
+ 0x1e3c, 501, /* Ḽ ḽ */
+ 0x1e3e, 501, /* Ḿ ḿ */
+ 0x1e40, 501, /* Ṁ ṁ */
+ 0x1e42, 501, /* Ṃ ṃ */
+ 0x1e44, 501, /* Ṅ ṅ */
+ 0x1e46, 501, /* Ṇ ṇ */
+ 0x1e48, 501, /* Ṉ ṉ */
+ 0x1e4a, 501, /* Ṋ ṋ */
+ 0x1e4c, 501, /* Ṍ ṍ */
+ 0x1e4e, 501, /* Ṏ ṏ */
+ 0x1e50, 501, /* Ṑ ṑ */
+ 0x1e52, 501, /* Ṓ ṓ */
+ 0x1e54, 501, /* Ṕ ṕ */
+ 0x1e56, 501, /* Ṗ ṗ */
+ 0x1e58, 501, /* Ṙ ṙ */
+ 0x1e5a, 501, /* Ṛ ṛ */
+ 0x1e5c, 501, /* Ṝ ṝ */
+ 0x1e5e, 501, /* Ṟ ṟ */
+ 0x1e60, 501, /* Ṡ ṡ */
+ 0x1e62, 501, /* Ṣ ṣ */
+ 0x1e64, 501, /* Ṥ ṥ */
+ 0x1e66, 501, /* Ṧ ṧ */
+ 0x1e68, 501, /* Ṩ ṩ */
+ 0x1e6a, 501, /* Ṫ ṫ */
+ 0x1e6c, 501, /* Ṭ ṭ */
+ 0x1e6e, 501, /* Ṯ ṯ */
+ 0x1e70, 501, /* Ṱ ṱ */
+ 0x1e72, 501, /* Ṳ ṳ */
+ 0x1e74, 501, /* Ṵ ṵ */
+ 0x1e76, 501, /* Ṷ ṷ */
+ 0x1e78, 501, /* Ṹ ṹ */
+ 0x1e7a, 501, /* Ṻ ṻ */
+ 0x1e7c, 501, /* Ṽ ṽ */
+ 0x1e7e, 501, /* Ṿ ṿ */
+ 0x1e80, 501, /* Ẁ ẁ */
+ 0x1e82, 501, /* Ẃ ẃ */
+ 0x1e84, 501, /* Ẅ ẅ */
+ 0x1e86, 501, /* Ẇ ẇ */
+ 0x1e88, 501, /* Ẉ ẉ */
+ 0x1e8a, 501, /* Ẋ ẋ */
+ 0x1e8c, 501, /* Ẍ ẍ */
+ 0x1e8e, 501, /* Ẏ ẏ */
+ 0x1e90, 501, /* Ẑ ẑ */
+ 0x1e92, 501, /* Ẓ ẓ */
+ 0x1e94, 501, /* Ẕ ẕ */
+ 0x1ea0, 501, /* Ạ ạ */
+ 0x1ea2, 501, /* Ả ả */
+ 0x1ea4, 501, /* Ấ ấ */
+ 0x1ea6, 501, /* Ầ ầ */
+ 0x1ea8, 501, /* Ẩ ẩ */
+ 0x1eaa, 501, /* Ẫ ẫ */
+ 0x1eac, 501, /* Ậ ậ */
+ 0x1eae, 501, /* Ắ ắ */
+ 0x1eb0, 501, /* Ằ ằ */
+ 0x1eb2, 501, /* Ẳ ẳ */
+ 0x1eb4, 501, /* Ẵ ẵ */
+ 0x1eb6, 501, /* Ặ ặ */
+ 0x1eb8, 501, /* Ẹ ẹ */
+ 0x1eba, 501, /* Ẻ ẻ */
+ 0x1ebc, 501, /* Ẽ ẽ */
+ 0x1ebe, 501, /* Ế ế */
+ 0x1ec0, 501, /* Ề ề */
+ 0x1ec2, 501, /* Ể ể */
+ 0x1ec4, 501, /* Ễ ễ */
+ 0x1ec6, 501, /* Ệ ệ */
+ 0x1ec8, 501, /* Ỉ ỉ */
+ 0x1eca, 501, /* Ị ị */
+ 0x1ecc, 501, /* Ọ ọ */
+ 0x1ece, 501, /* Ỏ ỏ */
+ 0x1ed0, 501, /* Ố ố */
+ 0x1ed2, 501, /* Ồ ồ */
+ 0x1ed4, 501, /* Ổ ổ */
+ 0x1ed6, 501, /* Ỗ ỗ */
+ 0x1ed8, 501, /* Ộ ộ */
+ 0x1eda, 501, /* Ớ ớ */
+ 0x1edc, 501, /* Ờ ờ */
+ 0x1ede, 501, /* Ở ở */
+ 0x1ee0, 501, /* Ỡ ỡ */
+ 0x1ee2, 501, /* Ợ ợ */
+ 0x1ee4, 501, /* Ụ ụ */
+ 0x1ee6, 501, /* Ủ ủ */
+ 0x1ee8, 501, /* Ứ ứ */
+ 0x1eea, 501, /* Ừ ừ */
+ 0x1eec, 501, /* Ử ử */
+ 0x1eee, 501, /* Ữ ữ */
+ 0x1ef0, 501, /* Ự ự */
+ 0x1ef2, 501, /* Ỳ ỳ */
+ 0x1ef4, 501, /* Ỵ ỵ */
+ 0x1ef6, 501, /* Ỷ ỷ */
+ 0x1ef8, 501, /* Ỹ ỹ */
+ 0x1f59, 492, /* Ὑ ὑ */
+ 0x1f5b, 492, /* Ὓ ὓ */
+ 0x1f5d, 492, /* Ὕ ὕ */
+ 0x1f5f, 492, /* Ὗ ὗ */
+ 0x1fbc, 491, /* ᾼ ᾳ */
+ 0x1fcc, 491, /* ῌ ῃ */
+ 0x1fec, 493, /* Ῥ ῥ */
+ 0x1ffc, 491 /* ῼ ῳ */
+]
+
+/*
+ * title characters are those between
+ * upper and lower case. ie DZ Dz dz
+ */
+const rtotitle1 = [
+ 0x01c4, 501, /* DŽ Dž */
+ 0x01c6, 499, /* dž Dž */
+ 0x01c7, 501, /* LJ Lj */
+ 0x01c9, 499, /* lj Lj */
+ 0x01ca, 501, /* NJ Nj */
+ 0x01cc, 499, /* nj Nj */
+ 0x01f1, 501, /* DZ Dz */
+ 0x01f3, 499 /* dz Dz */
+]
+
+const findc = {c, t, n, nelt, ret
+ var p, m
+
+ /*
+ we're processing in chunks of size
+ nelt, so 1 chunk is of length 'nelt'
+ */
+ while n > 1
+ m = n/2
+ p = t[m*nelt:]
+ if c >= p[0]
+ t = p
+ n = n - m
+ else
+ n = m
+ ;;
+ ;;
+
+ if t.len != 0 && c >= t[0]
+ ret# = t
+ -> true
+ else
+ -> false
+ ;;
+}
+
+
+const isalpha = {c
+ var l
+
+ if isupper(c) || islower(c)
+ -> true
+ elif findc(c, ralpha2[:], ralpha2.len/2, 2, &l)
+ if (c >= l[0] && c <= l[1])
+ -> true
+ ;;
+ elif findc(c, ralpha1[:], ralpha1.len, 1, &l)
+ if (c == l[0])
+ -> true
+ ;;
+ ;;
+ -> false
+}
+
+const isdigit = {c
+ -> c >= '0' && c <= '9'
+}
+
+const isxdigit = {c
+ -> c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F'
+}
+
+const isnum = {c
+ var l
+
+ if findc(c, rnums[:], rnums.len/2, 2, &l)
+ if(c >= l[0] && c <= l[1])
+ -> true
+ ;;
+ ;;
+ -> false
+}
+
+const isalnum = {c
+ -> isalpha(c) || isnum(c)
+}
+
+const isblank = {c
+ var l
+ var sl
+ var len
+
+ l = rspace2[:]
+ sl = rspace2[:]
+ len = rspace2.len/2
+ if findc(c, sl, len, 2, &l)
+ if(c >= l[0] && c <= l[1])
+ -> true
+ ;;
+ ;;
+ -> false
+}
+
+const isspace = {c
+ -> c == '\n' || isblank(c)
+}
+
+const islower = {c
+ var l
+
+ /* the first character in the toupper table is the lowercase char */
+ if findc(c, rtoupper2[:], rtoupper2.len/3, 3, &l)
+ if (c >= l[0] && c <= l[1])
+ -> true
+ ;;
+ elif findc(c, rtoupper1[:], rtoupper1.len/2, 2, &l)
+ if (c == l[0])
+ -> true
+ ;;
+ ;;
+ -> false
+}
+
+const isupper = {c
+ var l
+
+ /* the first character in the tolower table is the uppercase char */
+ if findc(c, rtolower2[:], rtolower2.len/3, 3, &l)
+ if (c >= l[0] && c <= l[1])
+ -> true
+ ;;
+ elif findc(c, rtolower1[:], rtolower1.len/2, 2, &l)
+ if (c == l[0])
+ -> true
+ ;;
+ ;;
+ -> false
+}
+
+const istitle = {c
+ -> isupper(c) && islower(c)
+}
+
+const tolower = {c
+ var l
+
+ if findc(c, rtolower2[:], rtolower2.len/3, 3, &l)
+ if c >= l[0] && c <= l[1]
+ -> c + l[2] - 500;
+ ;;
+ elif findc(c, rtolower1[:], rtolower1.len/2, 2, &l)
+ if c == l[0]
+ -> c + l[1] - 500;
+ ;;
+ ;;
+ -> c
+}
+
+const toupper = {c
+ var l
+
+ if findc(c, rtoupper2[:], rtoupper2.len/3, 3, &l);
+ if c >= l[0] && c <= l[1]
+ -> c + l[2] - 500;
+ ;;
+ elif findc(c, rtoupper1[:], rtoupper1.len/2, 2, &l);
+ if c == l[0]
+ -> c + l[1] - 500;
+ ;;
+ ;;
+ -> c
+}
+
+const totitle = {c
+ var l
+
+ if findc(c, rtotitle1[:], rtotitle1.len/2, 2, &l);
+ if c == l[0]
+ -> c + l[1] - 500;
+ ;;
+ ;;
+ -> c
+}
+
+generic charval = {c, base -> @a::(numeric,integral)
+ var v = -1
+
+ if c >= '0' && c <= '9'
+ v = (c - '0') castto(@a::(integral,numeric))
+ elif c >= 'a' && c <= 'z'
+ v = (c - 'a' + 10) castto(@a::(integral,numeric))
+ elif c >= 'A' && c <= 'Z'
+ v = (c - 'A' + 10) castto(@a::(integral,numeric))
+ ;;
+
+ if v < 0 || v > (base castto(@a::(integral,numeric)))
+ -> -1
+ ;;
+ -> v
+}
diff --git a/lib/std/clear.myr b/lib/std/clear.myr
new file mode 100644
index 0000000..c16c851
--- /dev/null
+++ b/lib/std/clear.myr
@@ -0,0 +1,12 @@
+use "slfill.use"
+pkg std =
+ generic clear : (p : @a# -> void)
+;;
+
+generic clear = {p : @a#
+ var bp
+
+ bp = p castto(byte#)
+ slfill(bp[:sizeof(@a)], 0)
+}
+
diff --git a/lib/std/cmp.myr b/lib/std/cmp.myr
new file mode 100644
index 0000000..edc5fe3
--- /dev/null
+++ b/lib/std/cmp.myr
@@ -0,0 +1,54 @@
+use "extremum.use"
+use "types.use"
+
+pkg std =
+ type order = union
+ `Before
+ `Equal
+ `After
+ ;;
+
+ generic numcmp : (a : @a, b : @a -> order)
+ const strcmp : (a : byte[:], b : byte[:] -> order)
+ const strncmp : (a : byte[:], b : byte[:], n : size -> order)
+;;
+
+generic numcmp = {a, b
+ if a < b
+ -> `Before
+ elif a == b
+ -> `Equal
+ else
+ -> `After
+ ;;
+}
+
+const strcmp = {a, b
+ var l
+ var i
+
+ l = min(a.len, b.len)
+ for i = 0; i < l; i++
+ if a[i] < b[i]
+ -> `Before
+ elif a[i] > b[i]
+ -> `After
+ ;;
+ ;;
+
+ if a.len < b.len
+ -> `Before
+ elif a.len > b.len
+ -> `After
+ else
+ -> `Equal
+ ;;
+
+}
+
+const strncmp = {a, b, n
+ a = a[:min(a.len, n)]
+ b = b[:min(b.len, n)]
+ -> strcmp(a, b)
+}
+
diff --git a/lib/std/cstrconv.myr b/lib/std/cstrconv.myr
new file mode 100644
index 0000000..fa9e0bf
--- /dev/null
+++ b/lib/std/cstrconv.myr
@@ -0,0 +1,40 @@
+use "types.use"
+
+pkg std =
+ const cstrlen : (buf : byte[:] -> size)
+ const cstrconv : (buf : byte[:] -> byte[:])
+ const cstrconvp : (p : byte# -> byte[:])
+;;
+
+const cstrconv = {buf
+ var i
+
+ for i = 0; i < buf.len; i++
+ if buf[i] == 0
+ -> buf[:i]
+ ;;
+ ;;
+ -> buf
+}
+
+const cstrconvp = {p
+ var i, base
+
+ i = 0
+ base = p castto(intptr)
+ while ((base + i) castto(byte#))# != 0
+ i++
+ ;;
+ -> p[:i]
+}
+
+const cstrlen = {buf
+ var i
+
+ for i = 0; i < buf.len; i++
+ if buf[i] == 0
+ break
+ ;;
+ ;;
+ -> i
+}
diff --git a/lib/std/dial+plan9.myr b/lib/std/dial+plan9.myr
new file mode 100644
index 0000000..35d97e9
--- /dev/null
+++ b/lib/std/dial+plan9.myr
@@ -0,0 +1,165 @@
+use sys
+
+use "alloc.use"
+use "die.use"
+use "fmt.use"
+use "option.use"
+use "pathjoin.use"
+use "result.use"
+use "sleq.use"
+use "strfind.use"
+use "strstrip.use"
+use "syswrap.use"
+use "utf.use"
+
+
+pkg std =
+ const dial : (dialstr : byte[:] -> result(fd, byte[:]))
+;;
+
+const Maxpath = 512
+
+const dial = {str
+ var netdir, proto, rem
+
+ (netdir, proto, rem) = parsedial(str)
+ if netdir.len != 0
+ -> csdial(netdir, proto, rem)
+ ;;
+
+ match csdial("/net", proto, rem)
+ | `Ok fd: -> `Ok fd
+ | `Fail m:
+ -> csdial("/net.alt", proto, rem)
+ ;;
+}
+
+const csdial = {netdir, proto, rem
+ var dir, clone, addr, csaddr
+ var ret, csfd, n
+ var buf : byte[Maxpath]
+
+ /* Try using the connection server */
+ dir = fmt("{}/cs", netdir)
+ csfd = open(dir, Ordwr)
+ if csfd < 0
+ clone = fmt("{}/{}/clone", netdir, proto)
+ ret = call(clone, rem, netdir)
+ slfree(clone)
+ if ret == -1
+ -> `Fail "unable to dial without cs"
+ else
+ -> `Ok ret
+ ;;
+ ;;
+ slfree(dir)
+
+ csaddr = fmt("{}!{}", proto, rem)
+ if write(csfd, csaddr) < 0
+ close(csfd)
+ -> `Fail "couldn't blah cs"
+ ;;
+ slfree(csaddr)
+
+ seek(csfd, 0, 0)
+ while true
+ n = read(csfd, buf[:])
+ if n <= 0
+ break
+ ;;
+
+ match strfind(buf[:n], " ")
+ | `None: continue
+ | `Some i:
+ clone = buf[:i]
+ addr = buf[i+1:n]
+ ;;
+
+ ret = call(clone, addr, netdir)
+ if ret >= 0
+ break
+ ;;
+ ;;
+
+ close(csfd)
+ if ret < 0
+ -> `Fail "unable to dial"
+ ;;
+ -> `Ok ret
+}
+
+const call = {clone, addr, netdir
+ var namebuf : byte[Maxpath]
+ var databuf : byte[Maxpath]
+ var name, base, dpath
+ var cfd, datafd
+ var c, n
+
+ datafd = -1
+ c = nsclonestr(clone, netdir)
+ cfd = open(c, Ordwr)
+ if cfd < 0
+ goto cleanup
+ ;;
+
+ n = read(cfd, namebuf[:])
+ if n < 0
+ goto cleanup
+ ;;
+ fput(cfd, "connect {}", addr)
+ name = strstrip(namebuf[:n])
+ match strrfind(c, "/")
+ | `None: die("there should be a '/' here\n")
+ | `Some i: base = c[:i]
+ ;;
+ dpath = bfmt(databuf[:], "{}/{}/data", base, name)
+ datafd = open(dpath, Ordwr)
+:cleanup
+ close(cfd)
+ slfree(c)
+ -> datafd
+}
+
+const nsclonestr = {clone, netdir
+ if decode(clone) == '#' || decode(clone) == '/'
+ match std.strfind(clone[1:], "/")
+ | `Some i: clone = clone[i+1:]
+ | `None: /* nothing */
+ ;;
+ ;;
+ -> pathcat(netdir, clone)
+}
+
+const parsedial = {str
+ var netdir, proto, rem, hd, tl
+
+ netdir=""
+ proto = ""
+ rem = ""
+ match strfind(str, "!")
+ | `None:
+ proto = "net"
+ rem = str
+ | `Some sep:
+ hd = str[:sep]
+ tl = str[sep+1:]
+ if decode(hd) == '#' || decode(hd) == '/'
+ match strrfind(hd, "/")
+ | `Some idx:
+ netdir = hd[:idx]
+ proto = hd[idx+1:]
+ | `None:
+ netdir = ""
+ proto = hd
+ ;;
+ else
+ netdir = ""
+ proto = hd
+
+ ;;
+ rem = tl
+ ;;
+
+ -> (netdir, proto, rem)
+}
+
diff --git a/lib/std/dial+posixy.myr b/lib/std/dial+posixy.myr
new file mode 100644
index 0000000..13f0257
--- /dev/null
+++ b/lib/std/dial+posixy.myr
@@ -0,0 +1,147 @@
+use sys
+
+use "alloc.use"
+use "chartype.use"
+use "die.use"
+use "endian.use"
+use "hasprefix.use"
+use "intparse.use"
+use "ipparse.use"
+use "option.use"
+use "resolve.use"
+use "result.use"
+use "sleq.use"
+use "strfind.use"
+use "syswrap.use"
+use "utf.use"
+
+pkg std =
+ const dial : (dialstr : byte[:] -> result(fd, byte[:]))
+;;
+
+/*
+ a map from service name to a list of (port,proto)
+ pairs in order of preference
+*/
+/* FIXME: implement
+var services : htab(byte[:], [int, byte[:]][:])#
+var inited = false
+*/
+
+/* takes a plan 9 style dial string */
+const dial = {str
+ var proto, host, port
+ var sa4 : sys.sockaddr_in
+ var sa6 : sys.sockaddr_in6
+ var sa : sys.sockaddr#
+ var sock
+
+ match parsedial(str)
+ | `Ok val: (proto, host, port) = val
+ | `Fail m: -> `Fail m
+ ;;
+
+ match getaddr(host)
+ | `Ipv4 bits:
+ sa4.fam = sys.Afinet
+ sa4.addr = bits
+ sa4.port = hosttonet(port)
+ sa = &sa4 castto(sys.sockaddr#)
+ | `Ipv6 bits:
+ sa6.fam = sys.Afinet6
+ sa6.addr = bits
+ sa6.port = hosttonet(port)
+ sa = &sa6 castto(sys.sockaddr#)
+ ;;
+ sock = sys.socket(sa.fam, proto, 0)
+
+ if sock < 0
+ -> `Fail "failed to connect to socket"
+ ;;
+ var err
+ err = sys.connect(sock, sa, sizeof(sys.sockaddr_in))
+ if err < 0
+ sys.close(sock)
+ -> `Fail "Failed to bind socket"
+ ;;
+
+ -> `Ok (sock castto(fd))
+}
+
+const parsedial = {str
+ var proto, host, port
+ var socktype, portnum
+
+ (proto, str) = nameseg(str)
+ (host, str) = nameseg(str)
+ (port, str) = nameseg(str)
+
+ if proto.len == 0
+ -> `Fail "missing proto"
+ elif host.len == 0
+ -> `Fail "missing host"
+ elif port.len == 0
+ -> `Fail "missing port"
+ ;;
+
+ if sleq(proto, "net")
+ -> `Fail "net wildcard proto not yet supported\n"
+ elif sleq(proto, "unix")
+ -> `Fail "net unix proto not yet supported\n"
+ elif sleq(proto, "tcp")
+ socktype = sys.Sockstream
+ elif sleq(proto, "udp")
+ socktype = sys.Sockdgram
+ ;;
+
+ match parseport(port)
+ | `Some n: portnum = n
+ | `None: -> `Fail "bad port"
+ ;;
+
+ -> `Ok (socktype, host, portnum)
+}
+
+const parseport = {port
+ match intparse(port)
+ | `Some n: -> `Some n
+ | `None:
+ /* a small number of hardcoded ports */
+ if sleq(port, "http")
+ -> `Some 80
+ elif sleq(port, "https")
+ -> `Some 443
+ elif sleq(port, "ircd")
+ -> `Some 6667
+ elif sleq(port, "dns")
+ -> `Some 53
+ ;;
+ ;;
+ -> `None
+}
+
+const getaddr = {addr
+ var ip
+
+ match ipparse(addr)
+ | `Some a: ip = a
+ | `None:
+ match resolve(addr)
+ | `Ok hi:
+ ip = hi[0].addr
+ slfree(hi)
+ | `Fail m:
+ ;;
+ ;;
+ -> ip
+}
+
+const nameseg = {str
+ match strfind(str, "!")
+ | `Some idx:
+ -> (str[:idx], str[idx+1:])
+ | `None:
+ -> (str, "")
+ ;;
+}
+
diff --git a/lib/std/die.myr b/lib/std/die.myr
new file mode 100644
index 0000000..87135f1
--- /dev/null
+++ b/lib/std/die.myr
@@ -0,0 +1,19 @@
+use "syswrap.use"
+use "types.use"
+
+pkg std =
+ $noret const die : (msg : byte[:] -> void)
+ const assert : (cond : bool, msg : byte[:] -> void)
+;;
+
+const die = {msg
+ write(2, msg)
+ suicide()
+}
+
+const assert = {cond, msg
+ if !cond
+ die(msg)
+ ;;
+}
+
diff --git a/lib/std/dir+freebsd.myr b/lib/std/dir+freebsd.myr
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/std/dir+freebsd.myr
diff --git a/lib/std/dir+linux.myr b/lib/std/dir+linux.myr
new file mode 100644
index 0000000..60ef6f9
--- /dev/null
+++ b/lib/std/dir+linux.myr
@@ -0,0 +1,66 @@
+use sys
+
+use "alloc.use"
+use "die.use"
+use "option.use"
+use "result.use"
+use "slcp.use"
+use "sldup.use"
+use "types.use"
+
+pkg std =
+ type dir = struct
+ fd : sys.fd
+ buf : byte[16384]
+ len : int64
+ off : int64
+ ;;
+
+ const diropen : (p : byte[:] -> std.result(dir#, byte[:]))
+ const dirread : (d : dir# -> std.option(byte[:]))
+ const dirclose : (d : dir# -> void)
+;;
+
+const Direntoverhead = 20
+
+const diropen = {p
+ var fd
+ var dir
+
+ fd = sys.open(p, sys.Ordonly | sys.Odir)
+ if fd < 0
+ -> `Fail "couldn't open directory"
+ ;;
+ dir = zalloc()
+ dir.fd = fd
+ -> `Ok dir
+}
+
+const dirread = {d
+ var len
+ var dent
+ var namelen
+
+ if d.off >= d.len
+ len = sys.getdents64(d.fd, d.buf[:])
+ if len <= 0
+ -> `None
+ ;;
+ d.len = len
+ d.off = 0
+ ;;
+
+ dent = &d.buf[d.off] castto(sys.dirent64#)
+ namelen = 0
+ d.off += dent.reclen castto(int64)
+ while dent.name[namelen] != 0
+ namelen++
+ ;;
+ -> `Some sldup(dent.name[:namelen])
+}
+
+const dirclose = {d
+ sys.close(d.fd)
+ free(d)
+}
+
diff --git a/lib/std/dir+osx.myr b/lib/std/dir+osx.myr
new file mode 100644
index 0000000..28ef26b
--- /dev/null
+++ b/lib/std/dir+osx.myr
@@ -0,0 +1,60 @@
+use sys
+
+use "alloc.use"
+use "die.use"
+use "option.use"
+use "result.use"
+use "slcp.use"
+use "sldup.use"
+use "types.use"
+
+pkg std =
+ type dir = struct
+ fd : sys.fd
+ buf : byte[16384]
+ len : int64
+ off : int64
+ base : int64
+ ;;
+
+ const diropen : (p : byte[:] -> std.result(dir#, byte[:]))
+ const dirread : (d : dir# -> std.option(byte[:]))
+ const dirclose : (d : dir# -> void)
+;;
+
+const diropen = {p
+ var fd
+ var dir
+
+ fd = sys.open(p, sys.Ordonly | sys.Odir)
+ if fd < 0
+ -> `Fail "couldn't open directory"
+ ;;
+ dir = zalloc()
+ dir.fd = fd
+ -> `Ok dir
+}
+
+const dirread = {d
+ var len
+ var dent
+
+ if d.off >= d.len
+ len = sys.getdirentries64(d.fd, d.buf[:], &d.base)
+ if len <= 0
+ -> `None
+ ;;
+ d.len = len
+ d.off = 0
+ ;;
+
+ dent = &d.buf[d.off] castto(sys.dirent64#)
+ d.off += dent.reclen castto(int64)
+ -> `Some sldup(dent.name[:dent.namlen])
+}
+
+const dirclose = {d
+ sys.close(d.fd)
+ free(d)
+}
+
diff --git a/lib/std/dir+plan9.myr b/lib/std/dir+plan9.myr
new file mode 100644
index 0000000..41a579f
--- /dev/null
+++ b/lib/std/dir+plan9.myr
@@ -0,0 +1,66 @@
+use sys
+
+use "alloc.use"
+use "die.use"
+use "option.use"
+use "result.use"
+use "slcp.use"
+use "sldup.use"
+use "syswrap.use"
+use "types.use"
+
+pkg std =
+ type dir = struct
+ fd : fd
+ buf : byte[65536] /* a big big, but at least it will always hold a directory entry... */
+ len : int64
+ off : int64
+ ;;
+
+ const diropen : (p : byte[:] -> std.result(dir#, byte[:]))
+ const dirread : (d : dir# -> std.option(byte[:]))
+ const dirclose : (d : dir# -> void)
+;;
+
+const diropen = {p
+ var fd
+ var dir
+
+ fd = open(p, Ordonly)
+ if fd < 0
+ -> `Fail "couldn't open directory"
+ ;;
+
+ dir = zalloc()
+ dir.fd = fd
+ -> `Ok dir
+}
+
+
+const dirread = {d
+ var len : int64, name, base, namelen, dirlen
+
+ /* NB: On Plan 9, read(2) will always return whole directory entries */
+ if d.off >= d.len
+ len = read(d.fd, d.buf[:]) castto(int64)
+ if len <= 0
+ -> `None
+ ;;
+ d.len = len
+ d.off = 0
+ ;;
+
+ namelen = (d.buf[d.off + Stringsoff] castto(int64)) | \
+ ((d.buf[d.off + Stringsoff + 1] castto(int64)) << 8)
+ base = d.off + Stringsoff + 2
+ dirlen = (d.buf[d.off] castto(int64)) | \
+ ((d.buf[d.off + 1] castto(int64)) << 8)
+ name = d.buf[base:base + namelen]
+ d.off += dirlen + 2
+ -> `Some std.sldup(name)
+}
+
+const dirclose = {d
+ close(d.fd)
+ free(d)
+}
diff --git a/lib/std/dirname.myr b/lib/std/dirname.myr
new file mode 100644
index 0000000..5e80771
--- /dev/null
+++ b/lib/std/dirname.myr
@@ -0,0 +1,37 @@
+use "alloc.use"
+use "slcp.use"
+use "die.use"
+use "sldup.use"
+use "strfind.use"
+use "option.use"
+
+pkg std =
+ const dirname : (p : byte[:] -> byte[:])
+ const basename : (p : byte[:] -> byte[:])
+;;
+
+const dirname = {p
+ match std.strrfind(p, "/")
+ | `std.Some idx:
+ -> std.sldup(p[:idx])
+ | `std.None:
+ -> std.sldup(".")
+ ;;
+}
+
+const basename = {p
+:again
+ if p.len == 0
+ -> std.sldup(".")
+ ;;
+
+ match std.strrfind(p, "/")
+ | `std.Some idx:
+ if idx == p.len - 1
+ goto again
+ ;;
+ -> std.sldup(p[idx+1:])
+ | `std.None:
+ -> std.sldup(p)
+ ;;
+}
diff --git a/lib/std/endian.myr b/lib/std/endian.myr
new file mode 100644
index 0000000..8bac74f
--- /dev/null
+++ b/lib/std/endian.myr
@@ -0,0 +1,32 @@
+pkg std =
+ generic hosttonet : (v : @a -> @a)
+ generic nettohost : (v : @a -> @a)
+;;
+
+/* FIXME: we only support little endian platforms right now,
+ so we assume a little endian machine. FIX THIS. */
+generic hosttonet = {v : @a::(integral,numeric)
+ var i
+ var ret
+
+ ret = 0
+ for i = 0; i < sizeof(@a); i++
+ ret <<= 8
+ ret |= v & 0xff
+ v >>= 8
+ ;;
+ -> ret
+}
+
+generic nettohost = {v : @a::(integral,numeric)
+ var i
+ var ret
+
+ ret = 0
+ for i = 0; i < sizeof(@a); i++
+ ret <<= 8
+ ret |= v & 0xff
+ v >>= 8
+ ;;
+ -> ret
+}
diff --git a/lib/std/env+plan9.myr b/lib/std/env+plan9.myr
new file mode 100644
index 0000000..4a95ed7
--- /dev/null
+++ b/lib/std/env+plan9.myr
@@ -0,0 +1,56 @@
+use sys
+
+use "alloc.use"
+use "die.use"
+use "extremum.use"
+use "fmt.use"
+use "option.use"
+use "result.use"
+use "slcp.use"
+use "sldup.use"
+use "sleq.use"
+use "slpush.use"
+use "slurp.use"
+
+pkg std =
+ const getenv : (name : byte[:] -> option(byte[:]))
+ const getenvv : (name : byte[:], default : byte[:] -> byte[:])
+;;
+
+var envkey : byte[:][:]
+var envval : byte[:][:]
+
+const envfind = {key
+ var i
+ for i = 0; i < envkey.len; i++
+ if std.sleq(envkey[i], key)
+ -> `Some envval[i]
+ ;;
+ ;;
+ -> `None
+}
+
+const getenv = {name
+ var buf : byte[128]
+ var s
+
+ match envfind(name)
+ | `Some val: -> `Some val
+ | `None:
+ s = bfmt(buf[:], "/env/{}", name)
+ match std.slurp(s)
+ | `Fail m: -> `None
+ | `Ok data:
+ envkey = slpush(envkey, sldup(name))
+ envval = slpush(envval, data)
+ -> `Some data
+ ;;
+ ;;
+}
+
+const getenvv = {name, default
+ match getenv(name)
+ | `Some val: -> val
+ | `None: -> default
+ ;;
+}
diff --git a/lib/std/env+posixy.myr b/lib/std/env+posixy.myr
new file mode 100644
index 0000000..d7b0e5e
--- /dev/null
+++ b/lib/std/env+posixy.myr
@@ -0,0 +1,28 @@
+use sys
+
+use "extremum.use"
+use "option.use"
+use "sleq.use"
+
+pkg std =
+ const getenv : (name : byte[:] -> option(byte[:]))
+ const getenvv : (name : byte[:], default : byte[:] -> byte[:])
+;;
+
+const getenv = {name
+ var n
+ for env in sys.__environment
+ n = min(name.len, env.len)
+ if sleq(name, env[:n]) && sleq(env[n:n+1], "=")
+ -> `Some env[n+1:]
+ ;;
+ ;;
+ -> `None
+}
+
+const getenvv = {name, default
+ match getenv(name)
+ | `Some v: -> v
+ | `None: -> default
+ ;;
+}
diff --git a/lib/std/errno+plan9.myr b/lib/std/errno+plan9.myr
new file mode 100644
index 0000000..c911349
--- /dev/null
+++ b/lib/std/errno+plan9.myr
@@ -0,0 +1,6 @@
+pkg std =
+ type errno = int
+ const Erange : errno = 1
+ const Emisc : errno = 2
+ const Eexist : errno = 3
+;;
diff --git a/lib/std/errno.myr b/lib/std/errno.myr
new file mode 100644
index 0000000..c14c469
--- /dev/null
+++ b/lib/std/errno.myr
@@ -0,0 +1,40 @@
+use sys
+
+pkg std =
+ type errno = int
+
+ const Eperm : errno = sys.Eperm castto(errno)
+ const Enoent : errno = sys.Enoent castto(errno)
+ const Esrch : errno = sys.Esrch castto(errno)
+ const Eintr : errno = sys.Eintr castto(errno)
+ const Eio : errno = sys.Eio castto(errno)
+ const Enxio : errno = sys.Enxio castto(errno)
+ const E2big : errno = sys.E2big castto(errno)
+ const Enoexec : errno = sys.Enoexec castto(errno)
+ const Ebadf : errno = sys.Ebadf castto(errno)
+ const Echild : errno = sys.Echild castto(errno)
+ const Eagain : errno = sys.Eagain castto(errno)
+ const Enomem : errno = sys.Enomem castto(errno)
+ const Eacces : errno = sys.Eacces castto(errno)
+ const Efault : errno = sys.Efault castto(errno)
+ const Enotblk : errno = sys.Enotblk castto(errno)
+ const Ebusy : errno = sys.Ebusy castto(errno)
+ const Eexist : errno = sys.Eexist castto(errno)
+ const Exdev : errno = sys.Exdev castto(errno)
+ const Enodev : errno = sys.Enodev castto(errno)
+ const Enotdir : errno = sys.Enotdir castto(errno)
+ const Eisdir : errno = sys.Eisdir castto(errno)
+ const Einval : errno = sys.Einval castto(errno)
+ const Enfile : errno = sys.Enfile castto(errno)
+ const Emfile : errno = sys.Emfile castto(errno)
+ const Enotty : errno = sys.Enotty castto(errno)
+ const Etxtbsy : errno = sys.Etxtbsy castto(errno)
+ const Efbig : errno = sys.Efbig castto(errno)
+ const Enospc : errno = sys.Enospc castto(errno)
+ const Espipe : errno = sys.Espipe castto(errno)
+ const Erofs : errno = sys.Erofs castto(errno)
+ const Emlink : errno = sys.Emlink castto(errno)
+ const Epipe : errno = sys.Epipe castto(errno)
+ const Edom : errno = sys.Edom castto(errno)
+ const Erange : errno = sys.Erange castto(errno)
+;;
diff --git a/lib/std/execvp.myr b/lib/std/execvp.myr
new file mode 100644
index 0000000..38d9fc5
--- /dev/null
+++ b/lib/std/execvp.myr
@@ -0,0 +1,57 @@
+use "alloc.use"
+use "env.use"
+use "fmt.use"
+use "option.use"
+use "strfind.use"
+use "strsplit.use"
+use "syswrap.use"
+
+pkg std =
+ const execvp : (cmd : byte[:], args : byte[:][:] -> int64)
+ const execvpe : (cmd : byte[:], args : byte[:][:], env : byte[:][:] -> int64)
+;;
+
+const execvp = {cmd, args
+ var paths, binpath
+ var buf : byte[512]
+
+ match strfind(cmd, "/")
+ | `Some _:
+ -> execv(cmd, args)
+ | `None:
+ paths = getpaths()
+ for p in paths
+ binpath = bfmt(buf[:], "{}/{}", p, cmd)
+ execv(binpath, args)
+ ;;
+ slfree(paths)
+ ;;
+ -> -1
+}
+
+const execvpe = {cmd, args, env
+ var paths, binpath
+ var buf : byte[512]
+
+ match strfind(cmd, "/")
+ | `Some _:
+ -> execve(cmd, args, env)
+ | `None:
+ paths = getpaths()
+ for p in paths
+ binpath = bfmt(buf[:], "{}/{}", p, cmd)
+ execve(binpath, args, env)
+ ;;
+ slfree(paths)
+ ;;
+ -> -1
+}
+
+const getpaths = {
+ var path
+ match getenv("PATH")
+ | `Some p: path = p
+ | `None: path = "/usr/local/bin:/bin:/usr/bin"
+ ;;
+ -> strsplit(path, ":")
+}
diff --git a/lib/std/extremum.myr b/lib/std/extremum.myr
new file mode 100644
index 0000000..9675915
--- /dev/null
+++ b/lib/std/extremum.myr
@@ -0,0 +1,40 @@
+pkg std =
+ generic min : (a : @a::numeric, b : @a::numeric -> @a::numeric)
+ generic max : (a : @a::numeric, b : @a::numeric -> @a::numeric)
+ generic clamp : (a : @a::numeric, min : @a::numeric, max : @a::numeric -> @a::numeric)
+ generic abs : (a : @a::numeric -> @a::numeric)
+;;
+
+generic min = {a, b
+ if a < b
+ -> a
+ else
+ -> b
+ ;;
+}
+
+generic max = {a, b
+ if a > b
+ -> a
+ else
+ -> b
+ ;;
+}
+
+generic clamp = {a, min, max
+ if a < min
+ -> min
+ elif a > max
+ -> max
+ else
+ -> a
+ ;;
+}
+
+generic abs = {a : @a::numeric
+ if a < (0 castto(@a::numeric))
+ -> -a
+ else
+ -> a
+ ;;
+}
diff --git a/lib/std/fltbits.myr b/lib/std/fltbits.myr
new file mode 100644
index 0000000..2f77ee9
--- /dev/null
+++ b/lib/std/fltbits.myr
@@ -0,0 +1,60 @@
+pkg std =
+ const flt64bits : (flt : flt64 -> int64)
+ const flt32bits : (flt : flt32 -> int32)
+ const flt64frombits : (bits : uint64 -> flt64)
+ const flt32frombits : (bits : uint32 -> flt32)
+ const flt64explode : (flt : flt64 -> (bool, int64, int64))
+ const flt32explode : (flt : flt32 -> (bool, int32, int32))
+;;
+
+const flt64bits = {flt; -> (&flt castto(int64#))#}
+const flt32bits = {flt; -> (&flt castto(int32#))#}
+const flt64frombits = {bits; -> (&bits castto(flt64#))#}
+const flt32frombits = {bits; -> (&bits castto(flt32#))#}
+
+const flt64explode = {flt
+ var bits, isneg, mant, exp
+
+ bits = flt64bits(flt)
+ isneg = (bits >> 63) != 0 /* msb is sign bit */
+ exp = (bits >> 52) & 0x7ff /* exp is in bits [52..63] */
+ mant = bits & ((1l << 52) - 1) /* msb is in bits [..51] */
+
+ /* add back the implicit bit if this is not a denormal */
+ if exp != 0
+ mant |= 1l << 52
+ else
+ exp = 1
+ ;;
+ /*
+ adjust for exponent bias. nb: because we are
+ treating the mantissa as m.0 instead of 0.m,
+ our exponent bias needs to be offset by the
+ size of m
+ */
+ -> (isneg, mant, exp)
+}
+
+const flt32explode = {flt
+ var bits, isneg, mant, exp
+
+ bits = flt32bits(flt)
+ isneg = (bits >> 31) != 0 /* msb is sign bit */
+ exp = (bits >> 22) & 0xff /* exp is in bits [23..30] */
+ mant = bits & ((1 << 22) - 1) /* msb is in bits [0..22] */
+
+ /* add back the implicit bit if this is not a denormal */
+ if exp != 0
+ mant |= 1 << 22
+ else
+ exp = 1
+ ;;
+ /*
+ adjust for exponent bias. nb: because we are
+ treating the mantissa as m.0 instead of 0.m,
+ our exponent bias needs to be offset by the
+ size of m
+ */
+ -> (isneg, mant, exp)
+}
+
diff --git a/lib/std/fltfmt.myr b/lib/std/fltfmt.myr
new file mode 100644
index 0000000..395ade4
--- /dev/null
+++ b/lib/std/fltfmt.myr
@@ -0,0 +1,239 @@
+use "alloc.use"
+use "bigint.use"
+use "die.use"
+use "extremum.use"
+use "fltbits.use"
+use "slpush.use"
+use "strbuf.use"
+use "types.use"
+use "utf.use"
+
+pkg std =
+ pkglocal const MNormal = 0
+ pkglocal const MAbsolute = 1
+ pkglocal const MRelative = 2
+
+ pkglocal const flt64bfmt : (sb : strbuf#, val : flt64, mode : int, precision : int -> void)
+ pkglocal const flt32bfmt : (sb : strbuf#, val : flt32, mode : int, precision : int -> void)
+;;
+
+const Dblbias = 1023
+const Fltbias = 127
+
+const flt64bfmt = {sb, val, mode, precision
+ var isneg, exp, mant
+
+ (isneg, mant, exp) = flt64explode(val)
+ dragon4(sb, isneg, mant, (exp - 52) castto(int64), Dblbias, mode, precision)
+}
+
+const flt32bfmt = {sb, val, mode, precision
+ var isneg, exp, mant
+
+ (isneg, mant, exp) = flt32explode(val)
+ dragon4(sb, isneg, mant castto(int64), (exp - 52) castto(int64), Fltbias, mode, precision)
+}
+
+/*
+sb: output buffer
+e: exponent
+p: precision
+f: mantissa
+
+flting value: x = f^(e - p)
+*/
+const dragon4 = {sb, isneg, f, e, p, mode, cutoff
+ var r, s, t, u, v, y
+ var udig
+ var mm, mp /* margins above and below */
+ var roundup
+ var low, high
+ var k, n
+ var a, i
+
+ /* if we have zero for the mantissa, we can return early */
+ n = 0
+ if isneg
+ sbputs(sb, "-")
+ ;;
+ if f == 0
+ sbputs(sb, "0.0")
+ ;;
+
+ /* initialize */
+ roundup = false
+ r = mkbigint(f)
+ r = bigshli(r, max(e - p, 0))
+ s = bigshli(mkbigint(1), max(0, -(e - p)))
+ mm = bigshli(mkbigint(1), max((e - p), 0))
+ mp = bigdup(mm)
+
+ /* fixup: unequal gaps */
+ t = mkbigint(1)
+ bigshli(t, p - 1)
+ if bigeqi(t, f)
+ bigshli(mp, 1)
+ bigshli(r, 1)
+ bigshli(s, 1)
+ ;;
+ bigfree(t)
+
+ k = 0
+ while true
+ /* r < ceil(s/b) */
+ t = bigdup(s)
+ bigaddi(t, 9)
+ bigdivi(t, 10)
+ match bigcmp(r, t)
+ | `Before:
+ k--
+ bigmuli(r, 10)
+ bigmuli(mm, 10)
+ bigmuli(mp, 10)
+ | _:
+ bigfree(t)
+ break
+ ;;
+ bigfree(t)
+ ;;
+
+ while true
+ t = bigdup(r)
+ bigshli(t, 1)
+ bigadd(t, mp)
+ while true
+ u = bigdup(s)
+ bigshli(u, 1)
+ match bigcmp(t, u)
+ | `Before:
+ bigfree(u)
+ break
+ | _:
+ k++
+ bigmuli(s, 10)
+ bigfree(u)
+ ;;
+ ;;
+ if mode == MNormal
+ cutoff = k
+ else
+ if mode == MRelative
+ cutoff += k - 1
+ ;;
+ /* common between relative and absolute */
+ a = cutoff - k - 1
+ y = bigdup(s)
+ if a < 0
+ for i = 0; i < a; i++
+ bigmuli(y, 10)
+ ;;
+ else
+ for i = 0; i < -a; i++
+ bigaddi(y, 9)
+ bigdivi(y, 10)
+ ;;
+ ;;
+ match bigcmp(y, mm)
+ | `Before: /* nothing */
+ | _:
+ bigfree(mm)
+ mm = y
+ ;;
+ match bigcmp(y, mp)
+ | `Before: /* nothing */
+ | _:
+ bigfree(mp)
+ mp = y
+ roundup = true
+ ;;
+ ;;
+ u = bigdup(s)
+ bigshli(u, 1)
+ match bigcmp(t, u)
+ | `Before:
+ bigfree(t)
+ bigfree(u)
+ break
+ | _:
+ ;;
+ ;;
+
+ if k <= 0
+ sbputs(sb, "0.")
+ ;;
+ while true
+ k--
+ bigmuli(r, 10)
+ u = bigdup(r);
+ bigdiv(u, s)
+
+ bigmod(r, s)
+ bigmuli(mm, 10)
+ bigmuli(mp, 10)
+
+ low = false
+ t = bigdup(r)
+ bigshli(t, 1)
+ match bigcmp(t, mm)
+ | `Before: low = true
+ | _:
+ ;;
+ bigfree(t)
+
+ v = bigdup(r)
+ bigshli(v, 1)
+ t = bigdup(s)
+ bigshli(t, 1)
+ bigsub(t, mp)
+ match bigcmp(v, t)
+ | `After: high = true
+ | `Equal: high = roundup
+ | `Before: high = false
+ ;;
+ bigfree(v)
+ bigfree(t)
+ if low || high || k == cutoff
+ break
+ ;;
+ format(sb, lowdig(u), k)
+ bigfree(u)
+ ;;
+
+ /* format the last digit */
+ udig = lowdig(u)
+ if low && !high
+ format(sb, udig, k)
+ elif high && !low
+ format(sb, udig + 1, k)
+ else
+ bigmuli(r, 2)
+ match bigcmp(r, s)
+ | `Before: format(sb, udig, k)
+ | `Equal: format(sb, udig, k)
+ | `After: format(sb, udig + 1, k)
+ ;;
+ ;;
+ -> n
+}
+
+const lowdig = {u
+ if u.dig.len > 0
+ -> u.dig[0]
+ ;;
+ -> 0
+}
+
+const format = {sb, d, k
+ const dig = "0123456789"
+ var i
+
+ if k < 0
+ for i = 0; i < -k - 1; i++
+ sbputs(sb, "0")
+ ;;
+ ;;
+ sbputb(sb, dig[d])
+ if k == 0
+ sbputs(sb, ".")
+ ;;
+}
diff --git a/lib/std/fmt.myr b/lib/std/fmt.myr
new file mode 100644
index 0000000..b786e98
--- /dev/null
+++ b/lib/std/fmt.myr
@@ -0,0 +1,499 @@
+use "alloc.use"
+use "chartype.use"
+use "die.use"
+use "extremum.use"
+use "fltfmt.use"
+use "hashfuncs.use"
+use "hasprefix.use"
+use "htab.use"
+use "introspect.use"
+use "intparse.use"
+use "option.use"
+use "sleq.use"
+use "slpush.use"
+use "strbuf.use"
+use "strfind.use"
+use "strsplit.use"
+use "syswrap-ss.use"
+use "syswrap.use"
+use "types.use"
+use "utf.use"
+use "varargs.use"
+
+pkg std =
+ /* write to fd */
+ const put : (fmt : byte[:], args : ... -> size)
+ const fput : (fd : fd, fmt : byte[:], args : ... -> size)
+ const putv : (fmt : byte[:], ap : valist# -> size)
+ const fputv : (fd : fd, fmt : byte[:], ap : valist# -> size)
+
+ /* write to buffer */
+ const fmt : (fmt : byte[:], args : ... -> byte[:])
+ const fmtv : (fmt : byte[:], ap : valist# -> byte[:])
+ const bfmt : (buf : byte[:], fmt : byte[:], args : ... -> byte[:])
+ const bfmtv : (buf : byte[:], fmt : byte[:], ap : valist# -> byte[:])
+
+ /* write to strbuf */
+ const sbfmt : (buf : strbuf#, fmt : byte[:], args : ... -> size)
+ const sbfmtv : (buf : strbuf#, fmt : byte[:], ap : valist# -> size)
+
+ /* add a formatter function */
+ const fmtinstall : (ty : byte[:], \
+ fn : (sb : strbuf#, ap : valist#, opts : (byte[:],byte[:])[:] -> void), \
+ optdesc : (byte[:], bool)[:] \
+ -> void)
+
+ $noret const fatal : (fmt : byte[:], args : ... -> void)
+ $noret const fatalv : (fmt : byte[:], ap : valist# -> void)
+;;
+
+const __init__ = {
+ fmtmap = mkht(strhash, streq)
+}
+
+type fmtdesc = struct
+ fn : (sb : strbuf#, ap : valist#, opts : (byte[:],byte[:])[:] -> void)
+ optdesc : (byte[:], bool)[:]
+;;
+
+/* same as 'put', but exits the program after printing */
+const fatal = {fmt, args
+ var ap
+
+ ap = vastart(&args)
+ putv(fmt, &ap)
+ exit(1)
+}
+
+/* same as 'putv', but exits the program after printing */
+const fatalv = {fmt, ap
+ putv(fmt, ap)
+ exit(1)
+}
+
+var fmtmap : htab(byte[:], fmtdesc)#
+
+const fmtinstall = {ty, fn, optdesc
+ htput(fmtmap, ty, [.fn=fn, .optdesc=optdesc])
+}
+
+const put = {fmt, args
+ var ap
+
+ ap = vastart(&args)
+ -> fputv(1, fmt, &ap)
+}
+
+const putv = {fmt, ap
+ -> fputv(1, fmt, ap)
+}
+
+const fput = {fd, fmt, args
+ var ap
+
+ ap = vastart(&args)
+ -> fputv(fd, fmt, &ap)
+}
+
+const fputv = {fd, fmt, ap
+ var sb, s
+
+ sb = mksb()
+ sbfmtv(sb, fmt, ap)
+ s = sbfin(sb)
+ -> writeall(fd, s)
+}
+
+const fmt = {fmt, args
+ var ap
+
+ ap = vastart(&args)
+ -> fmtv(fmt, &ap)
+}
+
+const fmtv = {fmt, ap
+ var sb
+
+ sb = mksb()
+ sbfmtv(sb, fmt, ap)
+ -> sbfin(sb)
+}
+
+const bfmt = {buf, fmt, args
+ var ap
+
+ ap = vastart(&args)
+ -> bfmtv(buf, fmt, &ap)
+}
+
+const bfmtv = {buf, fmt, ap
+ var sb
+
+ sb = mkbufsb(buf)
+ sbfmtv(sb, fmt, ap)
+ -> sbfin(sb)
+}
+
+const sbfmt = {sb, fmt, args
+ var ap
+
+ ap = vastart(&args)
+ -> sbfmtv(sb, fmt, &ap)
+}
+
+const sbfmtv = {sb, fmt, ap -> size
+ var nfmt, nparams, pl, orig
+ var c, params, ty
+
+ orig = fmt
+ nparams = ap.tc.nelt
+ nfmt = 0
+ while fmt.len != 0
+ (c, fmt) = striter(fmt)
+ match c
+ | '{':
+ if decode(fmt) == '{'
+ (c, fmt) = striter(fmt)
+ sbputc(sb, '{')
+ else
+ (params, fmt) = getparams(fmt)
+ nfmt++
+ if nfmt > nparams
+ die("too few params for fmt\n")
+ ;;
+
+ ty = vatype(ap)
+ match htget(fmtmap, ty)
+ | `Some f:
+ pl = parseparams(params, f.optdesc)
+ f.fn(sb, ap, pl)
+ std.slfree(pl)
+ | `None:
+ fallbackfmt(sb, params, ty, ap)
+ ;;
+ ;;
+ | '}':
+ if decode(fmt) == '}'
+ sbputc(sb, '}')
+ ;;
+ | chr:
+ sbputc(sb, chr)
+ ;;
+:fmtdone
+ ;;
+ if nfmt != nparams
+ write(1, orig)
+ die("too many params for fmt\n")
+ ;;
+ -> sb.len
+}
+
+const parseparams = {paramstr, optdesc
+ var params, opts
+ var o, a, ha : bool, gotarg : bool
+
+ opts = [][:]
+ params = strsplit(paramstr, ",")
+ for p in params
+ /* parse out the key/value pair */
+ match std.strfind(p, "=")
+ | `std.Some idx:
+ o = p[:idx]
+ a = p[idx+1:]
+ gotarg = true
+ | `std.None:
+ o = p
+ a = ""
+ gotarg = false
+ ;;
+
+ /* verify and add the arg */
+ for (opt, hasarg) in optdesc
+ if !std.sleq(opt, o)
+ continue
+ ;;
+ ha = hasarg
+ if ha == gotarg
+ opts = std.slpush(opts, (o, a))
+ else
+ std.fatal("invalid option {}", o)
+ ;;
+ ;;
+ ;;
+ slfree(params)
+ -> opts
+}
+
+
+const fallbackfmt = {sb, params, tyenc, ap : valist# -> void
+ /* value types */
+ var t_val : bool
+ var b_val : int8, ub_val : uint8
+ var w_val : int16, uw_val : uint16
+ var i_val : int32, ui_val : uint32
+ var l_val : int64, ul_val : uint64
+ var z_val : size
+ var p_val : byte#
+ var c_val : char
+ var s_val : byte[:]
+ var f32_val : flt32, f64_val : flt64
+ var i8 : int8, i16: int16, i32 : int32
+ var by : byte
+ var i : int, i64 : int64, l : long
+ var ui8 : int8, ui16: int16, ui32 : int32
+ var ui : int, ui64 : int64, ul : long
+
+ match typedesc(tyenc)
+ | `Tynone: /* nothing */
+ /* atomic types */
+ | `Tyvoid:
+ sbputs(sb, "void")
+ | `Tybool:
+ t_val = vanext(ap)
+ if t_val
+ sbputs(sb ,"true")
+ else
+ sbputs(sb, "false")
+ ;;
+ | `Tychar:
+ c_val = vanext(ap)
+ sbputc(sb, c_val)
+ | `Tyint8:
+ b_val = vanext(ap)
+ intfmt(sb, intparams(params), true, b_val)
+ | `Tyint16:
+ w_val = vanext(ap)
+ intfmt(sb, intparams(params), true, w_val)
+ | `Tyint:
+ i_val = vanext(ap)
+ intfmt(sb, intparams(params), true, i_val)
+ | `Tyint32:
+ i_val = vanext(ap)
+ intfmt(sb, intparams(params), true, i_val)
+ | `Tyint64:
+ l_val = vanext(ap)
+ intfmt(sb, intparams(params), true, l_val)
+ | `Tylong:
+ l_val = vanext(ap)
+ intfmt(sb, intparams(params), true, l_val)
+
+ | `Tybyte:
+ ub_val = vanext(ap)
+ intfmt(sb, intparams(params), false, ub_val)
+ | `Tyuint8:
+ ub_val = vanext(ap)
+ intfmt(sb, intparams(params), false, ub_val)
+ | `Tyuint16:
+ uw_val = vanext(ap)
+ intfmt(sb, intparams(params), false, uw_val)
+ | `Tyuint:
+ ui_val = vanext(ap)
+ intfmt(sb, intparams(params), false, ui_val)
+ | `Tyuint32:
+ ui_val = vanext(ap)
+ intfmt(sb, intparams(params), false, ui_val)
+ | `Tyuint64:
+ ul_val = vanext(ap)
+ intfmt(sb, intparams(params), false, ul_val)
+ | `Tyulong:
+ ul_val = vanext(ap)
+ intfmt(sb, intparams(params), false, ul_val)
+ | `Tyflt32:
+ f32_val = vanext(ap)
+ flt32bfmt(sb, f32_val, MNormal, 0)
+ | `Tyflt64:
+ f64_val = vanext(ap)
+ flt64bfmt(sb, f64_val, MNormal, 0)
+ | `Tyvalist:
+ sbputs(sb, "...")
+
+ /* compound types */
+ | `Typtr desc:
+ p_val = vanext(ap)
+ sbputs(sb, "0x")
+ intfmt(sb, \
+ [.base=16, .padto=2*sizeof(void#), .padfill='0'], \
+ false, p_val castto(intptr))
+ | `Tyslice desc:
+ match typedesc(desc)
+ | `Tybyte:
+ s_val = vanext(ap)
+ strfmt(sb, s_val, params)
+ | _:
+ sbputs(sb, "slice[:]")
+ ;;
+ | `Tyfunc tc:
+ p_val = vanext(ap)
+ sbputs(sb, "func{")
+ intfmt(sb, \
+ [.base=16, .padto=2*sizeof(void#), .padfill='0'], \
+ false, p_val castto(intptr))
+ sbputs(sb, "}")
+ | `Tyarray (sz, data):
+ sbputs(sb, "array")
+ /* aggregate types */
+ | `Tytuple typecursor:
+ vabytes(ap)
+ sbputs(sb, "tuple")
+ | `Tystruct namecursor:
+ vabytes(ap)
+ sbputs(sb, "struct")
+ | `Tyunion namecursor:
+ vabytes(ap)
+ sbputs(sb, "union")
+ | `Tyname (name, desc):
+ fallbackfmt(sb, params, desc, ap)
+ ;;
+}
+
+const getparams = {fmt
+ var i
+
+ for i = 0; i < fmt.len; i++
+ if fmt[i] == '}' castto(byte)
+ goto foundparams
+ ;;
+ ;;
+ die("invalid format string")
+:foundparams
+ -> (fmt[:i], fmt[i+1:])
+}
+
+type intparams = struct
+ base : size
+ padto : size
+ padfill : char
+;;
+
+const intparams = {params
+ var ip : intparams
+ var opts
+
+ ip = [
+ .base = 10,
+ .padfill = ' ',
+ .padto = 0
+ ]
+
+ opts = parseparams(params, [
+ ("x", false),
+ ("w", true),
+ ("p", true)][:])
+ for o in opts
+ match o
+ | ("x", ""): ip.base = 16
+ | ("w", wid): ip.padto = getint(wid, "fmt: width must be integer")
+ | ("p", pad): ip.padfill = decode(pad)
+ | _: std.die("unreachable")
+ ;;
+ ;;
+ std.assert(ip.padto >= 0, "pad must be >= 0")
+ std.slfree(opts)
+ -> ip
+}
+
+const strfmt = {sb, str, params
+ var opts
+ var w, p, i
+
+ p = ' '
+ w = 0
+ opts = parseparams(params, [
+ ("w", true),
+ ("p", true)][:])
+ for o in opts
+ match o
+ | ("w", wid): w = getint(wid, "fmt: width must be integer")
+ | ("p", pad): p = decode(pad)
+ | _: std.die("unreachable")
+ ;;
+ ;;
+ std.assert(p >= 0, "pad must be >= 0")
+ std.slfree(opts)
+ for i = 0; i < w - graphemewidth(str); i++
+ sbputc(sb, p)
+ ;;
+ sbputs(sb, str)
+}
+
+/*
+Hah. like we're going to put in the work to actually
+count graphemes.
+*/
+const graphemewidth = {str
+ -> str.len
+}
+
+const digitchars = [
+ '0','1','2','3','4',
+ '5','6','7','8','9',
+ 'a','b','c','d','e','f'
+]
+generic intfmt = {sb, opts, signed, bits : @a::(integral,numeric)
+ var isneg
+ var val
+ var b : char[32]
+ var i, j, npad
+ var base
+
+ base = opts.base castto(uint64)
+ if signed && bits < 0
+ val = -bits castto(uint64)
+ isneg = true
+ else
+ val = bits castto(uint64)
+ val &= ~0 >> (8*(sizeof(uint64)-sizeof(@a)))
+ isneg = false
+ ;;
+
+ i = 0
+ if val == 0
+ b[0] = '0'
+ i++
+ ;;
+ while val != 0
+ b[i] = digitchars[val % base]
+ val /= base
+ i++
+ ;;
+
+ npad = clamp(opts.padto - i, 0, opts.padto)
+ if isneg
+ npad--
+ ;;
+ if opts.padfill == '0' && isneg
+ sbputc(sb, '-')
+ ;;
+ for j = 0; j < npad; j++
+ sbputc(sb, opts.padfill)
+ ;;
+ if opts.padfill != '0' && isneg
+ sbputc(sb, '-')
+ ;;
+ for j = i; j != 0; j--
+ sbputc(sb, b[j - 1])
+ ;;
+}
+
+const writeall = {fd, buf
+ var n, len
+
+ len = 0
+ while true
+ n = write(fd, buf)
+ if n <= 0 || n >= len
+ break
+ ;;
+ len += n
+ ;;
+ -> len
+}
+
+
+/* would use std.get(), but that's a dependency loop */
+const getint = {s, msg
+ match std.intparse(s)
+ | `Some w: -> w;
+ | `None: die(msg)
+ ;;
+}
diff --git a/lib/std/fmtfuncs.myr b/lib/std/fmtfuncs.myr
new file mode 100644
index 0000000..abe5e75
--- /dev/null
+++ b/lib/std/fmtfuncs.myr
@@ -0,0 +1,54 @@
+use "alloc.use"
+use "bigint.use"
+use "bitset.use"
+use "fmt.use"
+use "introspect.use"
+use "strbuf.use"
+use "varargs.use"
+
+pkg std =
+;;
+
+const __init__ = {
+ var bigint : bigint#
+ var bitset : bitset#
+
+ fmtinstall(typeof(bigint), bigfmt, [][:])
+ fmtinstall(typeof(bitset), bsfmt, [][:])
+}
+
+const bigfmt = {sb, ap, opts
+ var a, n, buf
+
+ a = vanext(ap)
+ /*
+ allocate a buffer guaranteed to be big enough.
+ that's
+ 2 + floor(nbits/(log_2(10)))
+ or
+ 2 + a.dig.len * 32/3.32...
+ or
+ 2 + a.dig.len * 10
+ plus one for the - sign.
+ */
+ buf = slalloc(3 + a.dig.len * 10)
+ n = bigbfmt(buf, a, 10)
+ sbputs(sb, buf[:n])
+ slfree(buf)
+}
+
+const bsfmt = {sb, ap, opts
+ var i, bs, sep
+
+ bs = vanext(ap)
+ sep = ""
+ sbputs(sb, "bitset{")
+ for i = 0; i < bsmax(bs); i++
+ if bshas(bs, i)
+ sbfmt(sb, sep)
+ sbfmt(sb, "{}", i)
+ sep = ", "
+ ;;
+ ;;
+ sbputs(sb, "}")
+}
diff --git a/lib/std/getcwd.myr b/lib/std/getcwd.myr
new file mode 100644
index 0000000..c9dbbea
--- /dev/null
+++ b/lib/std/getcwd.myr
@@ -0,0 +1,31 @@
+
+use "alloc.use"
+use "errno.use"
+use "extremum.use"
+use "syswrap.use"
+use "syswrap-ss.use"
+pkg std =
+ const getcwd : (-> byte[:])
+;;
+
+const getcwd = {
+ var len, n, buf
+
+ len = 128
+ while true
+ buf = std.slalloc(len)
+ n = bgetcwd(buf)
+ if n >= 0
+ /* n is the length of the nul terminated c string */
+ -> buf[:n]
+ elif n != Erange
+ std.slfree(buf)
+ -> ""
+ else
+ len *= 2
+ ;;
+ ;;
+ /* unreachable; shut up return without value analysis */
+ -> ""
+}
+
diff --git a/lib/std/getint.myr b/lib/std/getint.myr
new file mode 100644
index 0000000..cd3d50b
--- /dev/null
+++ b/lib/std/getint.myr
@@ -0,0 +1,64 @@
+pkg std =
+ generic getle64 : (buf : byte[:] -> @a::(numeric,integral))
+ generic getbe64 : (buf : byte[:] -> @a::(numeric,integral))
+ generic getle32 : (buf : byte[:] -> @a::(numeric,integral))
+ generic getbe32 : (buf : byte[:] -> @a::(numeric,integral))
+ generic getle16 : (buf : byte[:] -> @a::(numeric,integral))
+ generic getbe16 : (buf : byte[:] -> @a::(numeric,integral))
+ generic getle8 : (buf : byte[:] -> @a::(numeric,integral))
+ generic getbe8 : (buf : byte[:] -> @a::(numeric,integral))
+;;
+
+generic getbe64 = {buf -> @a::(numeric,integral)
+ -> ((buf[0] castto(@a::(numeric,integral))) << 56) | \
+ ((buf[1] castto(@a::(numeric,integral))) << 48) | \
+ ((buf[2] castto(@a::(numeric,integral))) << 40) | \
+ ((buf[3] castto(@a::(numeric,integral))) << 32) | \
+ ((buf[4] castto(@a::(numeric,integral))) << 24) | \
+ ((buf[5] castto(@a::(numeric,integral))) << 16) | \
+ ((buf[6] castto(@a::(numeric,integral))) << 8) | \
+ ((buf[7] castto(@a::(numeric,integral))) << 0)
+}
+
+generic getle64 = {buf
+ -> ((buf[0] castto(@a::(numeric,integral))) << 0) | \
+ ((buf[1] castto(@a::(numeric,integral))) << 8) | \
+ ((buf[2] castto(@a::(numeric,integral))) << 16) | \
+ ((buf[3] castto(@a::(numeric,integral))) << 24) | \
+ ((buf[4] castto(@a::(numeric,integral))) << 32) | \
+ ((buf[5] castto(@a::(numeric,integral))) << 40) | \
+ ((buf[6] castto(@a::(numeric,integral))) << 48) | \
+ ((buf[7] castto(@a::(numeric,integral))) << 56)
+}
+
+generic getbe32 = {buf
+ -> ((buf[0] castto(@a::(numeric,integral))) << 24) | \
+ ((buf[1] castto(@a::(numeric,integral))) << 16) | \
+ ((buf[2] castto(@a::(numeric,integral))) << 8) | \
+ ((buf[3] castto(@a::(numeric,integral))) << 0)
+}
+
+generic getle32 = {buf
+ -> ((buf[0] castto(@a::(numeric,integral))) << 0) | \
+ ((buf[1] castto(@a::(numeric,integral))) << 8) | \
+ ((buf[2] castto(@a::(numeric,integral))) << 16) | \
+ ((buf[3] castto(@a::(numeric,integral))) << 24)
+}
+
+generic getbe16 = {buf
+ -> ((buf[0] castto(@a::(numeric,integral))) << 8) | \
+ ((buf[1] castto(@a::(numeric,integral))) << 0)
+}
+
+generic getle16 = {buf
+ -> ((buf[0] castto(@a::(numeric,integral))) << 0) | \
+ ((buf[1] castto(@a::(numeric,integral))) << 8)
+}
+
+generic getbe8 = {buf
+ -> (buf[0] castto(@a::(numeric,integral))) << 0
+}
+
+generic getle8 = {buf
+ -> (buf[0] castto(@a::(numeric,integral))) << 0
+}
diff --git a/lib/std/hashfuncs.myr b/lib/std/hashfuncs.myr
new file mode 100644
index 0000000..00c44c4
--- /dev/null
+++ b/lib/std/hashfuncs.myr
@@ -0,0 +1,106 @@
+use "die.use"
+use "sleq.use"
+use "types.use"
+
+pkg std =
+ const strhash : (s : byte[:] -> uint32)
+ const streq : (a : byte[:], b : byte[:] -> bool)
+
+ generic ptrhash : (p : @a# -> uint32)
+ generic ptreq : (a : @a#, b : @a# -> bool)
+
+ generic inthash : (v : @a::(integral,numeric) -> uint32)
+ generic inteq : (a : @a::(integral,numeric), b : @a::(integral,numeric) -> bool)
+
+ const murmurhash2 : (data : byte[:], seed : uint32 -> uint32)
+
+ generic slhash : (sl : @a[:] -> uint32)
+ generic tobytes : (sl : @a[:] -> byte[:])
+;;
+
+const Seed = 1234
+
+generic slhash = {data : @a[:]
+ -> strhash(slbytes(data))
+}
+
+generic slbytes = {data : @a[:]
+ var n
+
+ n = data.len * sizeof(@a)
+ -> (data castto(byte#))[:n]
+}
+
+/* Supremely simple djb hash. */
+const strhash = {s
+ -> murmurhash2(s, Seed)
+}
+
+const streq = {a, b
+ -> sleq(a, b)
+}
+
+generic ptrhash = {p : @a#
+ var x
+
+ x = &p castto(byte#)
+ -> murmurhash2(x[0:sizeof(@a)], Seed)
+}
+
+generic ptreq = {a, b
+ -> a == b
+}
+
+generic inthash = {v : @a::(integral,numeric)
+ var p
+
+ p = &v castto(byte#)
+ -> murmurhash2(p[0:sizeof(@a)], Seed)
+}
+
+generic inteq = {a, b
+ -> a == b
+}
+
+const murmurhash2 = {data, seed
+ const m = 0x5bd1e995;
+ const r = 24
+ var h, k
+
+ h = seed ^ data.len
+ while data.len >= 4
+ k = (data[0] castto(uint32))
+ k |= (data[1] castto(uint32)) << 8
+ k |= (data[2] castto(uint32)) << 16
+ k |= (data[3] castto(uint32)) << 24
+
+ k *= m
+ k ^= k >> r
+ k *= m
+
+ h *= m
+ h ^= k
+ data = data[4:]
+ ;;
+
+ match data.len
+ | 3:
+ h ^= (data[2] castto(uint32)) << 16
+ h ^= (data[1] castto(uint32)) <<8
+ h ^= (data[0] castto(uint32))
+ | 2:
+ h ^= (data[1] castto(uint32)) <<8
+ h ^= (data[0] castto(uint32))
+ | 1:
+ h ^= (data[0] castto(uint32))
+ | 0: /* nothing */
+ | _: die("0 < len < 4 must be true")
+ ;;
+ h *= m
+
+ h ^= h >> 13
+ h *= m
+ h ^= h >> 15
+
+ -> h
+}
diff --git a/lib/std/hasprefix.myr b/lib/std/hasprefix.myr
new file mode 100644
index 0000000..c9749f6
--- /dev/null
+++ b/lib/std/hasprefix.myr
@@ -0,0 +1,12 @@
+use "cmp.use"
+pkg std =
+ const hasprefix : (s : byte[:], pre : byte[:] -> bool)
+;;
+
+const hasprefix = {s, pre
+ match strncmp(s, pre, pre.len)
+ | `Equal: -> true
+ | _: -> false
+ ;;
+}
+
diff --git a/lib/std/hassuffix.myr b/lib/std/hassuffix.myr
new file mode 100644
index 0000000..87369af
--- /dev/null
+++ b/lib/std/hassuffix.myr
@@ -0,0 +1,15 @@
+use "sleq.use"
+pkg std =
+ const hassuffix : (s : byte[:], suff : byte[:] -> bool)
+;;
+
+const hassuffix = {s, suff
+ var tail
+
+ if suff.len <= s.len
+ tail = s[s.len - suff.len:]
+ -> sleq(tail, suff)
+ ;;
+ -> false
+}
+
diff --git a/lib/std/htab.myr b/lib/std/htab.myr
new file mode 100644
index 0000000..ac2e7aa
--- /dev/null
+++ b/lib/std/htab.myr
@@ -0,0 +1,209 @@
+use "alloc.use"
+use "die.use"
+use "extremum.use"
+use "option.use"
+use "types.use"
+
+pkg std =
+ type htab(@k, @v) = struct
+ hash : (k : @k -> uint32)
+ eq : (a : @k, b : @k -> bool)
+
+ nelt : size
+ ndead : size
+ keys : @k[:]
+ vals : @v[:]
+ hashes : uint32[:]
+ dead : bool[:]
+ ;;
+
+ generic mkht : (h : (k : @k -> uint32), eq : (a : @k, b : @k -> bool) -> htab(@k, @v)#)
+ generic htfree : (ht : htab(@k, @v)# -> void)
+ generic htput : (ht : htab(@k, @v)#, k : @k, v : @v -> void)
+ generic htdel : (ht : htab(@k, @v)#, k : @k -> void)
+ generic htget : (ht : htab(@k, @v)#, k : @k -> option(@v))
+ generic htgetv : (ht : htab(@k, @v)#, k : @k, fallback : @v-> @v)
+ generic hthas : (ht : htab(@k, @v)#, k : @k -> bool)
+ generic htkeys : (ht : htab(@k, @v)# -> @k[:])
+;;
+
+const Initsz = 32
+
+extern const put : (fmt : byte[:], args : ... -> size)
+
+generic hash = {ht, k
+ var h
+
+ h = ht.hash(k)
+ if h == 0
+ -> 1
+ else
+ -> h
+ ;;
+}
+
+generic resize = {ht, sz
+ var oldk
+ var oldv
+ var oldh
+ var oldd
+ var i
+
+ oldk = ht.keys
+ oldv = ht.vals
+ oldh = ht.hashes
+ oldd = ht.dead
+ ht.keys = slalloc(sz)
+ ht.vals = slalloc(sz)
+ ht.hashes = slzalloc(sz)
+ ht.dead = slzalloc(sz)
+
+ ht.nelt = 0
+ ht.ndead = 0
+ for i = 0; i < oldk.len; i++
+ if oldh[i] != 0 && !oldd[i]
+ htput(ht, oldk[i], oldv[i])
+ ;;
+ ;;
+ slfree(oldk)
+ slfree(oldv)
+ slfree(oldh)
+ slfree(oldd)
+}
+
+generic idx = {ht, k
+ var i, di
+ var h
+
+ di = 0
+ h = hash(ht, k)
+ i = h & (ht.keys.len - 1)
+ while true
+ while ht.hashes[i] != 0 && !ht.dead[i] && ht.hashes[i] != h
+ di++
+ i = (h + di) & (ht.keys.len - 1)
+ ;;
+
+ if ht.hashes[i] == 0
+ -> `None
+ ;;
+ if ht.hashes[i] == h && !ht.dead[i] && ht.eq(ht.keys[i], k)
+ break
+ ;;
+ di++
+ i = (h + di) & (ht.keys.len - 1)
+ ;;
+ -> `Some i
+}
+
+generic mkht = {h, eq
+ var ht
+
+ ht = alloc()
+
+ ht.hash = h
+ ht.eq = eq
+
+ ht.nelt = 0
+ ht.ndead = 0
+ ht.keys = slalloc(Initsz)
+ ht.vals = slalloc(Initsz)
+ ht.hashes = slzalloc(Initsz)
+ ht.dead = slzalloc(Initsz)
+ -> ht
+}
+
+generic htfree = {ht
+ slfree(ht.keys)
+ slfree(ht.vals)
+ slfree(ht.hashes)
+ slfree(ht.dead)
+ free(ht)
+}
+
+generic htput = {ht, k, v
+ var i, di
+ var h
+ var neltincr
+
+ di = 0
+ h = hash(ht, k)
+ i = h & (ht.keys.len - 1)
+ neltincr = 1
+ while ht.hashes[i] != 0 && !ht.dead[i]
+ /* second insertion overwrites */
+ if ht.hashes[i] == h && !ht.dead[i]
+ /* dead key, we can just insert here */
+ if ht.dead[i]
+ break
+ /* replacing a key */
+ elif ht.eq(ht.keys[i], k)
+ neltincr = 0
+ break
+ ;;
+ ;;
+ di++
+ i = (h + di) & (ht.keys.len - 1)
+ ;;
+ ht.nelt += neltincr
+ ht.hashes[i] = h
+ ht.keys[i] = k
+ ht.vals[i] = v
+ ht.dead[i] = false
+ if ht.keys.len < ht.nelt * 2
+ resize(ht, 2*ht.keys.len)
+ ;;
+}
+
+generic htdel = {ht, k
+ match idx(ht, k)
+ | `Some i:
+ ht.dead[i] = true
+ ht.nelt--
+ ht.ndead++
+ std.put("ndead = {}\n", ht.ndead)
+ /* remove tombstones if we shrink enough */
+ if ht.keys.len < ht.ndead * 4
+ resize(ht, ht.keys.len)
+ ;;
+ | _:
+ /* do nothing */
+ ;;
+}
+
+generic htget = {ht, k
+ match idx(ht, k)
+ | `Some i: -> `Some ht.vals[i]
+ | `None: -> `None
+ ;;
+}
+
+generic htgetv = {ht, k, v
+ match idx(ht, k)
+ | `Some i: -> ht.vals[i]
+ | `None: -> v
+ ;;
+}
+
+generic hthas = {ht, k
+ match idx(ht, k)
+ | `Some i: -> true
+ | `None: -> false
+ ;;
+}
+
+generic htkeys = {ht
+ var keys
+ var i
+ var j
+
+ keys = slalloc(ht.nelt)
+ j = 0
+ for i = 0; i < ht.keys.len; i++
+ if ht.hashes[i] != 0 && !ht.dead[i]
+ keys[j++] = ht.keys[i]
+ ;;
+ ;;
+ -> keys
+}
+
diff --git a/lib/std/ifreq+freebsd.myr b/lib/std/ifreq+freebsd.myr
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/std/ifreq+freebsd.myr
diff --git a/lib/std/ifreq+linux.myr b/lib/std/ifreq+linux.myr
new file mode 100644
index 0000000..62be8ee
--- /dev/null
+++ b/lib/std/ifreq+linux.myr
@@ -0,0 +1,67 @@
+use "sys.use"
+
+pkg sys =
+ const Ifnamesz = 16
+
+ type ifreq_addr = struct
+ name : byte[Ifnamesz]
+ addr : sockaddr
+ ;;
+
+ type ifreq_dstaddr = struct
+ name : byte[Ifnamesz]
+ dstaddr : sockaddr
+ ;;
+
+ type ifreq_broadaddr = struct
+ name : byte[Ifnamesz]
+ broadaddr : sockaddr
+ ;;
+
+ type ifreq_netmask = struct
+ name : byte[Ifnamesz]
+ netmask : sockaddr
+ ;;
+
+
+ type ifreq_hwaddr = struct
+ name : byte[Ifnamesz]
+ hwaddr : sockaddr
+ ;;
+
+ type ifreq_flags = struct
+ name : byte[Ifnamesz]
+ flags : int16
+ ;;
+
+ type ifreq_ifindex = struct
+ name : byte[Ifnamesz]
+ index : int32
+ ;;
+
+ type ifreq_metric = struct
+ name : byte[Ifnamesz]
+ metric : int32
+ ;;
+
+
+ type ifreq_mtu = struct
+ name : byte[Ifnamesz]
+ mtu : int32
+ ;;
+
+ type ifreq_slave = struct
+ name : byte[Ifnamesz]
+ slave : byte[Ifnamesz]
+ ;;
+
+ type ifreq_newname = struct
+ name : byte[Ifnamesz]
+ newname : byte[Ifnamesz]
+ ;;
+
+ type ifreq_data = struct
+ name : byte[Ifnamesz]
+ data : void#
+ ;;
+;;
diff --git a/lib/std/ifreq+osx.myr b/lib/std/ifreq+osx.myr
new file mode 100644
index 0000000..f5205bf
--- /dev/null
+++ b/lib/std/ifreq+osx.myr
@@ -0,0 +1,77 @@
+use "sys.use"
+
+pkg sys =
+ const Ifnamesz = 16
+
+ type ifreq_addr = struct
+ name : byte[Ifnamesz]
+ addr : sockaddr
+ ;;
+
+ type ifreq_dstaddr = struct
+ name : byte[Ifnamesz]
+ dstaddr : sockaddr
+ ;;
+
+ type ifreq_broadaddr = struct
+ name : byte[Ifnamesz]
+ broadaddr : sockaddr
+ ;;
+
+ type ifreq_flags = struct
+ name : byte[Ifnamesz]
+ flags : int16
+ ;;
+
+ type ifreq_metric = struct
+ name : byte[Ifnamesz]
+ metric : int32
+ ;;
+
+
+ type ifreq_phys = struct
+ name : byte[Ifnamesz]
+ phys : int32
+ ;;
+
+ type ifreq_media = struct
+ name : byte[Ifnamesz]
+ media : int32
+ ;;
+
+ type ifreq_data = struct
+ name : byte[Ifnamesz]
+ data : void#
+ ;;
+
+ type ifreq_devmtu = struct
+ name : byte[Ifnamesz]
+ cur : uint32
+ min : uint32
+ max : uint32
+ ;;
+
+ type ifreq_kpi = struct
+ name : byte[Ifnamesz]
+ modid : uint32
+ typeid : uint32
+ ptr : void#
+ ;;
+
+ type ifreq_wakeflg = struct
+ name : byte[Ifnamesz]
+ wakeflg : uint32
+ ;;
+
+ type ifreq_routerefs = struct
+ name : byte[Ifnamesz]
+ refs : uint32
+ ;;
+
+ type ifreq_icaps = struct
+ name : byte[Ifnamesz]
+ req : uint32
+ cur : uint32
+ ;;
+
+;;
diff --git a/lib/std/ifreq+plan9.myr b/lib/std/ifreq+plan9.myr
new file mode 100644
index 0000000..ef73843
--- /dev/null
+++ b/lib/std/ifreq+plan9.myr
@@ -0,0 +1,2 @@
+pkg std =
+;;
diff --git a/lib/std/intparse.myr b/lib/std/intparse.myr
new file mode 100644
index 0000000..4180f8c
--- /dev/null
+++ b/lib/std/intparse.myr
@@ -0,0 +1,70 @@
+use "chartype.use"
+use "die.use"
+use "hasprefix.use"
+use "option.use"
+use "types.use"
+use "utf.use"
+
+pkg std =
+ generic intparsebase : (s : byte[:], base : int -> option(@a::(integral,numeric)))
+ generic intparse : (s : byte[:] -> option(@a::(integral,numeric)))
+;;
+
+generic intparse = {s
+ var isneg
+
+ isneg = false
+ if hasprefix(s, "-")
+ s = s[1:]
+ isneg = true
+ ;;
+
+ if hasprefix(s, "0x")
+ -> doparse(s[2:], isneg, 16)
+ elif hasprefix(s, "0o")
+ -> doparse(s[2:], isneg, 8)
+ elif hasprefix(s, "0b")
+ -> doparse(s[2:], isneg, 2)
+ else
+ -> doparse(s, isneg, 10)
+ ;;
+}
+
+generic intparsebase = {s, base
+ var isneg
+
+ isneg = false
+ if hasprefix(s, "-")
+ s = s[1:]
+ isneg = true
+ ;;
+
+ -> doparse(s, isneg, base)
+}
+
+generic doparse = {s, isneg, base
+ var c
+ var v
+ var cv : int32
+
+ v = 0
+ while s.len != 0
+ (c, s) = striter(s)
+ if c == '_'
+ continue
+ ;;
+ cv = charval(c, base)
+ if cv >= 0
+ v *= (base castto(@a::(integral,numeric)))
+ v += cv castto(@a::(integral,numeric))
+ else
+ -> `None
+ ;;
+ ;;
+
+ if isneg
+ -> `Some -v
+ else
+ -> `Some v
+ ;;
+}
diff --git a/lib/std/introspect.myr b/lib/std/introspect.myr
new file mode 100644
index 0000000..1da7af0
--- /dev/null
+++ b/lib/std/introspect.myr
@@ -0,0 +1,365 @@
+use "types.use"
+use "die.use"
+
+pkg std =
+ type typedesc = union
+ `Tynone
+
+ /* atomic types */
+ `Tyvoid
+ `Tybool
+ `Tychar
+
+ `Tyint8
+ `Tyint16
+ `Tyint
+ `Tyint32
+ `Tyint64
+ `Tylong
+
+ `Tybyte
+ `Tyuint8
+ `Tyuint16
+ `Tyuint
+ `Tyuint32
+ `Tyuint64
+ `Tyulong
+ `Tyflt32
+ `Tyflt64
+ `Tyvalist
+
+ /* compound types */
+ `Typtr byte[:]
+ `Tyfunc typecursor
+ `Tyslice byte[:]
+ `Tyarray (size, byte[:])
+
+ /* aggregate types */
+ `Tytuple typecursor
+ `Tystruct namecursor
+ `Tyunion namecursor
+ /* name info */
+ `Tyname (byte[:], byte[:])
+ ;;
+
+ type typecursor = struct
+ nelt : size
+ rem : byte[:]
+ ;;
+
+ type namecursor = struct
+ nelt : size
+ rem : byte[:]
+ ;;
+
+ type typeinfo = struct
+ size : size
+ align : size
+ ;;
+
+ generic typeof : (v : @a -> byte[:])
+ const typeenc : (p : ...# -> typecursor)
+ const typedecode : (e : byte[:] -> typedesc)
+ const typedesc : (e : byte[:] -> typedesc)
+ const typeinfo : (e : byte[:] -> typeinfo)
+
+ const tcnext : (t : typecursor# -> byte[:])
+ const tcpeek : (t : typecursor# -> byte[:])
+ const ncnext : (t : namecursor# -> (byte[:], byte[:]))
+;;
+
+extern const put : (fmt : byte[:], args : ... -> size)
+
+const Encnone : byte = 0
+const Encvoid : byte = 1
+const Encbool : byte = 2
+const Encchar : byte = 3
+
+const Encint8 : byte = 4
+const Encint16 : byte = 5
+const Encint : byte = 6
+const Encint32 : byte = 7
+const Encint64 : byte = 8
+const Enclong : byte = 9
+
+const Encbyte : byte = 10
+const Encuint8 : byte = 11
+const Encuint16 : byte = 12
+const Encuint : byte = 13
+const Encuint32 : byte = 14
+const Encuint64 : byte = 15
+const Enculong : byte = 16
+const Encflt32 : byte = 17
+const Encflt64 : byte = 18
+const Encvalist : byte = 19
+
+/* compound types */
+const Encptr : byte = 20
+const Encfunc : byte = 21
+const Encslice : byte = 22
+const Encarray : byte = 23
+
+/* aggregate types */
+const Enctuple : byte = 24
+const Encstruct : byte = 25
+const Encunion : byte = 26
+const Encname : byte = 30
+const Encindname :byte = 30 | 0x80
+
+generic typeof = {v : @a -> byte[:]
+ var tc
+
+ tc = typesof(v)
+ -> tcnext(&tc)
+}
+
+const typeenc = {ap : ...#
+ var e
+
+ e = getenc(ap castto(byte##))
+ e = skiptypeinfo(e[1:])
+ -> lentypecursor(e)
+}
+
+const typesof : (a : ... -> typecursor) = {a : ...
+ -> typeenc(&a)
+}
+
+const tcnext = {tc
+ var n, sz, cur
+
+ if tc.rem.len == 0
+ -> ""
+ ;;
+ (n, sz) = getipacked(tc.rem)
+ cur = tc.rem[sz:sz+n]
+ tc.rem = tc.rem[sz+n:]
+ -> cur
+}
+
+const tcpeek = {tc
+ var n, sz
+
+ if tc.rem.len == 0
+ -> ""
+ ;;
+ (n, sz) = getipacked(tc.rem)
+ -> tc.rem[sz:sz+n]
+}
+
+const ncnext = {nc
+ var n, sz, name, enc
+
+ if nc.rem.len == 0
+ -> ("", "")
+ ;;
+
+ /* get the name */
+ (n, sz) = getipacked(nc.rem)
+ name = nc.rem[sz:sz+n]
+ nc.rem = nc.rem[sz+n:]
+
+ /* and the type */
+ (n, sz) = getipacked(nc.rem)
+ enc = nc.rem[sz:sz+n]
+ nc.rem = nc.rem[sz+n:]
+ -> (name, enc)
+}
+
+
+const getenc = {p : byte##
+ var val, sz, x
+
+ (val, sz) = getipacked(p#[:8])
+ x = &sz castto(byte#)
+ -> p#[sz:sz+val]
+}
+
+const typedesc = {ti
+ var len,sz, p
+
+ match ti[0]
+ | Encnone: -> `Tynone
+ | Encvoid: -> `Tyvoid
+ | Encbool: -> `Tybool
+ | Encchar: -> `Tychar
+
+ | Encint8: -> `Tyint8
+ | Encint16: -> `Tyint16
+ | Encint: -> `Tyint
+ | Encint32: -> `Tyint32
+ | Encint64: -> `Tyint64
+ | Enclong: -> `Tylong
+
+ | Encbyte: -> `Tybyte
+ | Encuint8: -> `Tyuint8
+ | Encuint16: -> `Tyuint16
+ | Encuint: -> `Tyuint
+ | Encuint32: -> `Tyuint32
+ | Encuint64: -> `Tyuint64
+ | Enculong: -> `Tyulong
+ | Encflt32: -> `Tyflt32
+ | Encflt64: -> `Tyflt64
+ | Encvalist: -> `Tyvalist
+
+ /* compound types */
+ | Encptr: -> `Typtr getsub(ti[1:])
+ | Encfunc: -> `Tyfunc lentypecursor(ti[1:])
+ | Encslice: -> `Tyslice getsub(ti[1:])
+ | Encarray:
+ ti = skiptypeinfo(ti[1:])
+ (len, sz) = getipacked(ti)
+ -> `Tyarray (len, getsub(ti[sz:]))
+
+
+ /* aggregate types */
+ | Enctuple:
+ ti = skiptypeinfo(ti[1:])
+ -> `Tytuple lentypecursor(ti)
+ | Encstruct:
+ ti = skiptypeinfo(ti[1:])
+ -> `Tystruct lennamecursor(ti)
+ | Encunion:
+ ti = skiptypeinfo(ti[1:])
+ -> `Tyunion lennamecursor(ti)
+ | Encname:
+ -> `Tyname namedesc(ti[1:])
+ | Encindname:
+ /*
+ ugly hack: the slice contains a pointer to the
+ value, so if we cast it to a byte##, we can
+ pull the indirect value out of the pointer.
+ */
+ p = ti[1:] castto(byte##)
+ -> typedesc(getenc(p))
+ | _:
+ std.die("unknown type encoding")
+ ;;
+}
+
+const typeinfo = {ti
+ var p
+
+ match ti[0]
+ | Encnone: -> [.size=0, .align=1]
+ | Encvoid: -> [.size=0, .align=1]
+ | Encbool: -> [.size=0, .align=1]
+ | Encchar: -> [.size=4, .align=4]
+
+ | Encint8: -> [.size=1, .align=1]
+ | Encint16: -> [.size=2, .align=2]
+ | Encint: -> [.size=4, .align=4]
+ | Encint32: -> [.size=4, .align=4]
+ | Encint64: -> [.size=8, .align=8]
+ | Enclong: -> [.size=8, .align=8]
+
+ | Encbyte: -> [.size=1, .align=1]
+ | Encuint8: -> [.size=1, .align=1]
+ | Encuint16: -> [.size=2, .align=2]
+ | Encuint: -> [.size=4, .align=4]
+ | Encuint32: -> [.size=4, .align=4]
+ | Encuint64: -> [.size=8, .align=8]
+ | Enculong: -> [.size=8, .align=8]
+ | Encflt32: -> [.size=4, .align=4]
+ | Encflt64: -> [.size=8, .align=8]
+ | Encvalist: -> [.size=8, .align=8]
+
+ /* compound types */
+ | Encptr: -> [.size=8, .align=8]
+ | Encfunc: -> [.size=8, .align=8]
+ | Encslice: -> [.size=16, .align=8]
+
+ | Encarray: -> gettypeinfo(ti[1:])
+ | Enctuple: -> gettypeinfo(ti[1:])
+ | Encstruct: -> gettypeinfo(ti[1:])
+ | Encunion: -> gettypeinfo(ti[1:])
+ | Encname: -> getnameinfo(ti[1:])
+ | Encindname:
+ p = ti[1:] castto(byte##)
+ -> typeinfo(getenc(p))
+ | _:
+ std.die("unknown type encoding")
+ ;;
+}
+
+const gettypeinfo = {e
+ var size, align, sz
+
+ (size, sz) = getipacked(e) /* size */
+ e = e[sz:]
+ (align, sz) = getipacked(e) /* align */
+ -> [.size = size, .align = align]
+}
+
+const skiptypeinfo = {e
+ var ignore, sz
+
+ (ignore, sz) = getipacked(e) /* size */
+ e = e[sz:]
+ (ignore, sz) = getipacked(e) /* align */
+ -> e[sz:]
+}
+
+const getnameinfo = {e
+ var n, name, sz, enc
+
+ (n, sz) = getipacked(e)
+ name = e[sz:n+sz]
+ e = e[n+sz:]
+ (n, sz) = getipacked(e)
+ enc = e[sz:n+sz]
+
+ -> typeinfo(enc)
+}
+
+const namedesc = {e
+ var n, sz, name, enc
+
+ (n, sz) = getipacked(e)
+ name = e[sz:n+sz]
+ e = e[n+sz:]
+ (n, sz) = getipacked(e)
+ enc = e[sz:n+sz]
+
+ -> (name, enc)
+}
+
+const lentypecursor = {e
+ var n, sz
+
+ (n, sz) = getipacked(e)
+ -> [.nelt=n, .rem=e[sz:]]
+}
+
+const lennamecursor = {e
+ var n, sz
+
+ (n, sz) = getipacked(e)
+ -> [.nelt=n, .rem=e[sz:]]
+}
+
+const getsub = {e
+ var n, sz
+
+ (n, sz) = getipacked(e)
+ -> e[sz:sz+n]
+}
+
+const getipacked : (p : byte[:] -> (size, size)) = {p : byte[:]
+ var mask, val, len, i
+
+ mask = 0x80
+ val = 0
+ len = 1
+ while p[0] & mask != mask << 1
+ len++
+ mask >>= 1
+ mask |= 0x80
+ ;;
+
+ val = (p[0] castto(size)) & ~(1 << (8 - len))
+ for i = 1; i < len; i++
+ val |= (p[i] castto(size)) << (i*8 - len)
+ ;;
+ -> (val, len)
+}
diff --git a/lib/std/ipparse.myr b/lib/std/ipparse.myr
new file mode 100644
index 0000000..17bc6f0
--- /dev/null
+++ b/lib/std/ipparse.myr
@@ -0,0 +1,147 @@
+use "die.use"
+use "intparse.use"
+use "option.use"
+use "strfind.use"
+use "types.use"
+use "chartype.use"
+use "fmt.use"
+use "slcp.use"
+use "slfill.use"
+use "sleq.use"
+
+ /* FIXME: needed for decls which should be pulled in as hidden */
+use "hasprefix.use"
+use "utf.use"
+
+pkg std =
+
+ type netaddr = union
+ `Ipv4 byte[4]
+ `Ipv6 byte[16]
+ ;;
+
+ const ipparse : (ip : byte[:] -> option(netaddr))
+ const ip4parse : (ip : byte[:] -> option(netaddr))
+ const ip6parse : (ip : byte[:] -> option(netaddr))
+;;
+
+const ipparse = {ip
+ match strfind(ip, ":")
+ | `Some _: -> ip6parse(ip)
+ | `None: -> ip4parse(ip)
+ ;;
+}
+
+const ip4parse = {ip
+ var a, b, c, d
+ var ok
+ /*
+ var addr
+ var last : size
+ var x : option(int32)
+ var val : int32 /* need int32 to check for overflow */
+ var i
+ var j : size
+ */
+
+ (a, ip, ok) = num(ip, 0, 255, 10, '.', true)
+ (ip, ok) = delim(ip, '.', ok)
+ (b, ip, ok) = num(ip, 0, 255, 10, '.', ok)
+ (ip, ok) = delim(ip, '.', ok)
+ (c, ip, ok) = num(ip, 0, 255, 10, '.', ok)
+ (ip, ok) = delim(ip, '.', ok)
+ (d, ip, ok) = num(ip, 0, 255, 10, '.', ok)
+
+ if ok && ip.len == 0
+ -> `Some (`Ipv4 [a, b, c, d])
+ else
+ -> `None
+ ;;
+}
+
+const ip6parse = {ip
+ var val : byte[16]
+ var expand, split
+ var v, ok
+ var i, nseg
+
+ ok = true
+ expand = false
+ split = 0
+ if ip.len > 2 && std.sleq(ip[:2], "::")
+ expand = true
+ split = 0
+ ;;
+ nseg = 0
+ for i = 0; ip.len > 0 && ok; i++
+ /* parse 'num' segment */
+ (v, ip, ok) = num(ip, 0, 65536, 16, ':', ok)
+ nseg++
+ if ip.len == 0 || nseg == 8
+ break
+ ;;
+ (ip, ok) = delim(ip, ':', ok)
+ /* only one '::' allowed once */
+ if ip.len > 0 && ip[0] == ':'castto(byte) && !expand
+ expand = true
+ split = i
+ (ip, ok) = delim(ip, ':', ok)
+ ;;
+
+ /* pack it into the bytes */
+ val[i*2] = ((v & 0xff00) >> 8) castto(byte)
+ val[i*2 + 1] = (v & 0xff) castto(byte)
+ ;;
+
+ if ok && ip.len == 0
+ if expand
+ expandsplit(val[:], split, i)
+ elif nseg != 8
+ -> `None
+ ;;
+ -> `Some `Ipv6 val
+ else
+ -> `None
+ ;;
+}
+
+/* take "a:b::c:d" and expand it to "a:b:0:0:...:0:c:d" */
+const expandsplit = {ip, split, len
+ var width
+
+ width = 16 - len
+ std.slcp(ip[split:len], ip[split+width:len+width])
+ std.slfill(ip[len:len+width], 0)
+}
+
+const delim = {ip, sep, ok
+ if ip.len > 0 && ip[0] == sep castto(byte)
+ -> (ip[1:], ok)
+ else
+ -> ("", false)
+ ;;
+}
+
+generic num = {ip, lo, hi, base, sep, ok -> (@a::(numeric,integral), byte[:], bool)
+ var len
+
+ if !ok
+ -> (0, "", false)
+ ;;
+
+ for len = 0; len < ip.len; len++
+ if ip[len] == sep castto(byte)
+ break
+ ;;
+ ;;
+ match intparsebase(ip[:len], base)
+ | `std.Some v:
+ if v < lo || v > hi
+ -> (0, "", false)
+ ;;
+ -> (v castto(@a::(numeric,integral)), ip[len:], true)
+ | `std.None:
+ -> (0, "", false)
+ ;;
+}
+
diff --git a/lib/std/mk.myr b/lib/std/mk.myr
new file mode 100644
index 0000000..19b46d2
--- /dev/null
+++ b/lib/std/mk.myr
@@ -0,0 +1,22 @@
+use "alloc.use"
+
+pkg std =
+ generic mk : (val : @a -> @a#)
+;;
+
+/* Takes a value, and heapifies it.
+
+FIXME: This depends on inlining and copy propagation
+in order to be efficient. Neither of those are
+currently implemented. That means that this function
+is not efficient.
+
+It's still damn convenient, though, so it's in.
+*/
+generic mk = {val
+ var p
+
+ p = alloc()
+ p# = val
+ -> p
+}
diff --git a/lib/std/mkfile b/lib/std/mkfile
new file mode 100644
index 0000000..36c6bb2
--- /dev/null
+++ b/lib/std/mkfile
@@ -0,0 +1,107 @@
+</$objtype/mkfile
+
+SYSLIB=sys
+SYSSRC= \
+ sys.myr \
+ systypes.myr \
+ ifreq.myr \
+
+SYSASMSRC= \
+ syscall.s \
+ util.s
+
+
+STDLIB=std
+STDSRC= \
+ alloc.myr \
+ bigint.myr \
+ bitset.myr \
+ blat.myr \
+ chartype.myr \
+ cmp.myr \
+ dial.myr \
+ die.myr \
+ dir.myr \
+ endian.myr \
+ env.myr \
+ execvp.myr \
+ extremum.myr \
+ fltbits.myr \
+ fmt.myr \
+ fltfmt.myr \
+ hashfuncs.myr \
+ hasprefix.myr \
+ hassuffix.myr \
+ htab.myr \
+ intparse.myr \
+ ipparse.myr \
+ mk.myr \
+ now.myr \
+ option.myr \
+ optparse.myr \
+ pathjoin.myr \
+ rand.myr \
+ resolve.myr \
+ result.myr \
+ search.myr \
+ slcp.myr \
+ sldup.myr \
+ sleq.myr \
+ slfill.myr \
+ sljoin.myr \
+ slpush.myr \
+ slput.myr \
+ slurp.myr \
+ sort.myr \
+ spork.myr \
+ strfind.myr \
+ strjoin.myr \
+ strsplit.myr \
+ strstrip.myr \
+ syswrap.myr \
+ swap.myr \
+ try.myr \
+ types.myr \
+ units.myr \
+ utf.myr \
+ varargs.myr \
+ wait.myr \
+
+all:V: lib$STDLIB.a lib$SYSLIB.a
+
+install:V: all
+ mkdir -p /$objtype/lib/myr/
+ cp lib$STDLIB.a lib$SYSLIB.a /$objtype/lib/myr/
+ cp $STDLIB $SYSLIB /$objtype/lib/myr/
+
+lib$STDLIB.a: $STDSRC $ASMSRC lib$SYSLIB.a
+ ../myrbuild/$O.out -I. -C../6/$O.out -M../muse/$O.out -l $STDLIB $STDSRC $STDASMSRC
+
+lib$SYSLIB.a: $SYSSRC $SYSASMSRC
+ ../myrbuild/$O.out -C../6/$O.out -M../muse/$O.out -l $SYSLIB $SYSSRC $SYSASMSRC
+
+%.myr: %+plan9-x64.myr
+ cp $stem+plan9-x64.myr $stem.myr
+
+%.myr: %+plan9.myr
+ cp $stem+plan9.myr $stem.myr
+
+%.myr: %+x64.myr
+ cp $stem+x64.myr $stem.myr
+
+%.s: %+plan9-x64.s
+ cp $stem+plan9-x64.s $stem.s
+
+%.s: %+x64.s
+ cp $stem+x64.s $stem.s
+
+OBJ=${STDSRC:%.myr=%.$O} ${SYSSRC:%.myr=%.$O} ${STDASMSRC:%.s=%.$O} ${SYSASMSRC:%.s=%.$O}
+USE=${STDSRC:%.myr=%.use} ${SYSSRC:%.myr=%.use} ${STDLIB}
+LIBS=lib$STDLIB.a lib$SYSLIB.a
+.PHONY: clean
+clean:V:
+ rm -f $OBJ
+ rm -f $USE
+ rm -f $LIBS $STDLIB $SYSLIB
+
+nuke:V: clean
diff --git a/lib/std/mkpath.myr b/lib/std/mkpath.myr
new file mode 100644
index 0000000..b7e8e24
--- /dev/null
+++ b/lib/std/mkpath.myr
@@ -0,0 +1,22 @@
+use "syswrap.use"
+use "errno.use"
+
+pkg std =
+ const mkpath : (p : byte[:] -> bool)
+;;
+
+const mkpath = {p
+ var st
+ var i
+
+ for i = 0; i < p.len; i++
+ if p[i] == '/' castto(byte) && i != 0
+ st = mkdir(p[:i], 0o777)
+ if st != 0 && (st castto(errno)) != Eexist
+ -> false
+ ;;
+ ;;
+ ;;
+
+ -> true
+}
diff --git a/lib/std/now.myr b/lib/std/now.myr
new file mode 100644
index 0000000..5f6d8d1
--- /dev/null
+++ b/lib/std/now.myr
@@ -0,0 +1,11 @@
+use "types.use"
+use "syswrap.use"
+
+pkg std =
+ const now : (-> time)
+;;
+
+/* microseconds since epoch */
+const now = {
+ -> curtime()
+}
diff --git a/lib/std/option.myr b/lib/std/option.myr
new file mode 100644
index 0000000..271355d
--- /dev/null
+++ b/lib/std/option.myr
@@ -0,0 +1,7 @@
+pkg std =
+ type option(@a) = union
+ `Some @a
+ `None
+ ;;
+;;
+
diff --git a/lib/std/optparse.myr b/lib/std/optparse.myr
new file mode 100644
index 0000000..ae65b77
--- /dev/null
+++ b/lib/std/optparse.myr
@@ -0,0 +1,210 @@
+use "alloc.use"
+use "die.use"
+use "extremum.use"
+use "fmt.use"
+use "strbuf.use"
+use "option.use"
+use "sleq.use"
+use "slpush.use"
+use "syswrap-ss.use"
+use "syswrap.use"
+use "types.use"
+use "utf.use"
+
+pkg std =
+ type optdef = struct
+ argdesc : byte[:] /* the description for the usage */
+ minargs : std.size /* the minimum number of positional args */
+ maxargs : std.size /* the maximum number of positional args (0 = unlimited) */
+ noargs : std.bool /* whether we accept args at all */
+ opts : optdesc[:] /* the description of the options */
+ ;;
+
+ type optdesc = struct
+ opt : char
+ arg : byte[:]
+ desc : byte[:]
+ optional : bool
+ ;;
+
+ type optparsed = struct
+ opts : (char, byte[:])[:]
+ args : byte[:][:]
+ ;;
+
+ const optparse : (optargs : byte[:][:], def : optdef# -> optparsed)
+ const optusage : (prog : byte[:], def : optdef# -> void)
+;;
+
+type optctx = struct
+ /* public variables */
+ args : byte[:][:]
+
+ /* data passed in */
+ optdef : optdef#
+ optargs : byte[:][:]
+
+ /* state */
+ argidx : size
+ curarg : byte[:]
+ optdone : bool /* if we've seen '--', everything's an arg */
+ finished : bool /* if we've processed all the optargs */
+;;
+
+
+const optparse = {args, def
+ var ctx : optctx
+ var parsed
+
+ parsed = [
+ .opts=[][:],
+ .args=[][:]
+ ]
+ optinit(&ctx, args, def)
+ while !optdone(&ctx)
+ parsed.opts = slpush(parsed.opts, optnext(&ctx))
+ ;;
+ if ctx.args.len < def.minargs
+ put("error: expected at least {} args, got {}\n", def.minargs, ctx.args.len)
+ optusage(ctx.optargs[0], ctx.optdef)
+ exit(1)
+ ;;
+ if def.maxargs > 0 && ctx.args.len < def.minargs
+ put("error: expected at most {} args, got {}\n", def.minargs, ctx.args.len)
+ optusage(ctx.optargs[0], ctx.optdef)
+ exit(1)
+ ;;
+ if def.noargs && ctx.args.len != 0
+ put("error: expected no args, got {}\n", ctx.args.len)
+ optusage(ctx.optargs[0], ctx.optdef)
+ exit(1)
+ ;;
+ parsed.args = ctx.args
+ -> parsed
+}
+
+const optinit = {ctx, args, def
+ ctx# = [
+ .optargs = args,
+ .optdef = def,
+ .optdone = false,
+ .finished = false,
+ .argidx = 0,
+ .curarg = [][:],
+ .args = [][:],
+ ]
+
+ next(ctx)
+ -> ctx
+}
+
+const optnext = {ctx
+ var c
+ var arg
+
+ (c, ctx.curarg) = striter(ctx.curarg)
+
+ match optinfo(ctx, c)
+ | `None:
+ if c == 'h' || c == '?'
+ optusage(ctx.optargs[0], ctx.optdef)
+ exit(0)
+ else
+ fatal("unexpected argument '{}'\n", c)
+ ;;
+ | `Some (true, needed):
+ /* -arg => '-a' 'rg' */
+ if ctx.curarg.len > 0
+ arg = ctx.curarg
+ ctx.curarg = ctx.curarg[ctx.curarg.len:]
+ next(ctx)
+ /* '-a rg' => '-a' 'rg' */
+ elif ctx.argidx < (ctx.optargs.len - 1)
+ arg = ctx.optargs[ctx.argidx + 1]
+ ctx.argidx++
+ next(ctx)
+ elif needed
+ put("Expected argument for {}\n", c)
+ exit(1)
+ ;;
+ | `Some (false, _):
+ arg = ""
+ if ctx.curarg.len == 0
+ next(ctx)
+ ;;
+ ;;
+
+
+ -> (c, arg)
+}
+
+const optdone = {ctx
+ -> ctx.curarg.len == 0 && ctx.finished
+}
+
+const optinfo = {ctx, opt
+ for o in ctx.optdef.opts
+ if o.opt == opt
+ -> `Some (o.arg.len != 0, !o.optional)
+ ;;
+ ;;
+ -> `None
+}
+
+const next = {ctx
+ var i
+
+ for i = ctx.argidx + 1; i < ctx.optargs.len; i++
+ if !ctx.optdone && decode(ctx.optargs[i]) == '-'
+ if sleq(ctx.optargs[i], "--")
+ ctx.optdone = true
+ else
+ goto foundopt
+ ;;
+ else
+ ctx.args = slpush(ctx.args, ctx.optargs[i])
+ ;;
+ ;;
+:finishedopt
+ ctx.finished = true
+ -> false
+:foundopt
+ ctx.argidx = i
+ ctx.curarg = ctx.optargs[i][1:]
+ -> true
+}
+
+const optusage = {prog, def
+ var sb, s
+
+ sb = mksb()
+ std.sbfmt(sb, "usage: {} [-h?", prog)
+ for o in def.opts
+ if o.arg.len == 0
+ std.sbfmt(sb, "{}", o.opt)
+ ;;
+ ;;
+ std.sbfmt(sb, "] ")
+ for o in def.opts
+ if o.arg.len != 0
+ std.sbfmt(sb, "[-{} {}] ", o.opt, o.arg)
+ ;;
+ ;;
+ std.sbfmt(sb, "{}\n", def.argdesc)
+ std.sbfmt(sb, "\t-h\tprint this help message\n")
+ std.sbfmt(sb, "\t-?\tprint this help message\n")
+ for o in def.opts
+ std.sbfmt(sb, "\t-{}{}{}\t{}\n", o.opt, sep(o.arg), o.arg, o.desc)
+ ;;
+ s = sbfin(sb)
+ write(1, s)
+ slfree(s)
+}
+
+const sep = {s
+ if s.len > 0
+ -> " "
+ else
+ -> ""
+ ;;
+}
diff --git a/lib/std/pathjoin.myr b/lib/std/pathjoin.myr
new file mode 100644
index 0000000..f9df8aa
--- /dev/null
+++ b/lib/std/pathjoin.myr
@@ -0,0 +1,105 @@
+use "alloc.use"
+use "extremum.use"
+use "strjoin.use"
+use "strsplit.use"
+use "sleq.use"
+use "sljoin.use"
+use "sldup.use"
+use "slcp.use"
+use "die.use"
+use "fmt.use"
+
+pkg std =
+ const pathcat : (a : byte[:], b : byte[:] -> byte[:])
+ const pathjoin : (p : byte[:][:] -> byte[:])
+ const pathnorm : (p : byte[:] -> byte[:])
+;;
+
+const pathcat = {a, b
+ -> pathjoin([a, b][:])
+}
+
+const pathjoin = {l
+ var p, i, q
+
+ for i = 0; i < l.len; i++
+ if l[i].len != 0
+ break
+ ;;
+ ;;
+ p = strjoin(l[i:], "/")
+ q = pathnorm(p)
+ slfree(p)
+ -> q
+}
+
+const pathnorm = {p
+ var comps
+ var i, del, dst
+ var s, ret
+
+ comps = strsplit(p, "/")
+ /*
+ "." is a no-op component, so we drop it. In order
+ to drop a component, we set it to the empty string,
+ and remove it later on in the code.
+ */
+ for i = 0; i < comps.len; i++
+ if sleq(comps[i], ".")
+ comps[i] = ""
+ ;;
+ ;;
+
+ /*
+ then, resolve '..' by cancelling out previous components. Scan
+ backwards in the component list for the first real component,
+ and delete both it and the '..' that lead to it.
+
+ Leave in extra '..' components, so that, eg, ../foo doesn't
+ get mangled.
+ */
+ for i = 0; i < comps.len; i++
+ if !sleq(comps[i], "..")
+ continue
+ ;;
+ for del = 1; del <= i; del++
+ if comps[i - del].len > 0 && !sleq(comps[i-del], "..")
+ comps[i - del] = ""
+ comps[i] = ""
+ break
+ ;;
+ ;;
+ ;;
+
+ /* clear out the path nodes we decided to drop */
+ dst = 0
+ for i = 0; i < comps.len; i++
+ if comps[i].len > 0
+ comps[dst++] = comps[i]
+ ;;
+ ;;
+ comps = comps[:dst]
+
+ /*
+ and reassemble. If we have an absolute path,
+ make it absolute. If we have an empty path, return
+ ".". Otherwise, just return the path.
+ */
+ if p.len > 0 && sleq(p[:1], "/")
+ for i = 0; i < comps.len; i++
+ if !sleq(comps[i], "..")
+ break
+ ;;
+ ;;
+ s = strjoin(comps[i:], "/")
+ ret = fmt("/{}", s)
+ slfree(s)
+ elif comps.len == 0
+ ret = sldup(".")
+ else
+ ret = strjoin(comps, "/")
+ ;;
+ slfree(comps)
+ -> ret
+}
+
diff --git a/lib/std/putint.myr b/lib/std/putint.myr
new file mode 100644
index 0000000..711001d
--- /dev/null
+++ b/lib/std/putint.myr
@@ -0,0 +1,44 @@
+use "types.use"
+use "die.use"
+
+pkg std =
+ generic putle64 : (buf : byte[:], v : @a::(numeric,integral) -> size)
+ generic putbe64 : (buf : byte[:], v : @a::(numeric,integral) -> size)
+ generic putle32 : (buf : byte[:], v : @a::(numeric,integral) -> size)
+ generic putbe32 : (buf : byte[:], v : @a::(numeric,integral) -> size)
+ generic putle16 : (buf : byte[:], v : @a::(numeric,integral) -> size)
+ generic putbe16 : (buf : byte[:], v : @a::(numeric,integral) -> size)
+ generic putle8 : (buf : byte[:], v : @a::(numeric,integral) -> size)
+ generic putbe8 : (buf : byte[:], v : @a::(numeric,integral) -> size)
+;;
+
+generic putle64 = {buf, v; -> putle(buf, v castto(uint64), 8)}
+generic putbe64 = {buf, v; -> putbe(buf, v castto(uint64), 8)}
+generic putle32 = {buf, v; -> putle(buf, v castto(uint64), 4)}
+generic putbe32 = {buf, v; -> putbe(buf, v castto(uint64), 4)}
+generic putle16 = {buf, v; -> putle(buf, v castto(uint64), 2)}
+generic putbe16 = {buf, v; -> putbe(buf, v castto(uint64), 2)}
+generic putle8 = {buf, v; -> putle(buf, v castto(uint64), 1)}
+generic putbe8 = {buf, v; -> putbe(buf, v castto(uint64), 1)}
+
+const putbe = {buf, val, n
+ var i, k
+
+ assert(buf.len >= n, "buffer too small")
+ for i = 0; i < n; i++
+ k = val >> (8*(n-i-1))
+ buf[i] = (k & 0xff) castto(byte)
+ ;;
+ -> n castto(size)
+}
+
+const putle = {buf, val, n
+ var i
+
+ assert(buf.len >= n, "buffer too small")
+ for i = 0; i < n; i++
+ buf[i] = (val & 0xff) castto(byte)
+ val >>= 8
+ ;;
+ -> n castto(size)
+}
diff --git a/lib/std/rand.myr b/lib/std/rand.myr
new file mode 100644
index 0000000..2e8c73e
--- /dev/null
+++ b/lib/std/rand.myr
@@ -0,0 +1,185 @@
+use "die.use"
+use "types.use"
+use "alloc.use"
+/*
+ Translated from C by Ori Bernstein
+ */
+
+/*
+ A C-program for MT19937, with initialization improved 2002/1/26.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The names of its contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ Any feedback is very welcome.
+ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+ */
+
+pkg std =
+ type rng
+
+ const mksrng : (seed : uint32 -> rng#)
+ const delrng : (rng : rng# -> void)
+ generic rand : (rng : rng#, lo : @a::(numeric,integral), hi : @a::(numeric,integral) -> @a::(numeric,integral))
+ generic randN : (rng : rng# -> @a::(numeric,integral))
+ const randbytes : (rng : rng#, buf : byte[:] -> size)
+ const rand32 : (rng : rng# -> uint32)
+;;
+
+type rng = struct
+ state : uint32[624]
+ i : uint32
+;;
+
+/* allocates and initializes a random number generator */
+const mksrng = {seed
+ var rng
+
+ rng = alloc()
+ init(rng, seed)
+ -> rng
+}
+
+const delrng = {rng
+ free(rng)
+}
+
+/* initializes a random number generator from the seed `seed`. */
+const init = {rng, seed
+ var i
+
+ for i = 0; i < 624; i++
+ rng.state[i] = seed
+ seed = 1812433253 * (seed ^ (seed >> 30)) + i + 1
+ ;;
+ rng.i = i
+}
+
+/*
+ Generates a random integer from `rng` in the range [lo, hi),
+ returning the value. The range [lo, hi) must be positive,
+ nonempty, and the difference between hi and lo must be
+ less then 2^(type_bits - 1)
+*/
+generic rand = {rng, lo, hi -> @a::(integral,numeric)
+ var span, lim
+ var maxrand
+ var val
+
+ assert(hi - lo > 0, "rand.myr: range for random values must be >= 1")
+
+ span = hi - lo
+ maxrand = (1 << (8*sizeof(@a))) - 1 /* max for signed value */
+ if maxrand < 0 /* signed */
+ maxrand = (1 << (8*sizeof(@a)-1)) - 1 /* max for signed value */
+ ;;
+
+ lim = (maxrand/span)*span
+ val = (randN(rng) & maxrand)
+ while val > lim
+ val = (randN(rng) & maxrand)
+ ;;
+ -> val % span + lo
+}
+
+/*
+ Generates a random integer of any size from the
+ random number generator `rng`. The returned value
+ may be negative, if the type is signed.
+*/
+generic randN = {rng -> @a::(integral,numeric)
+ var i, val
+
+ val = 0
+ for i = 0; i < sizeof(@a)/4; i++
+ val <<= 8*sizeof(@a)
+ val |= rand32(rng) castto(@a::(integral,numeric))
+ ;;
+ -> val
+}
+
+/*
+ generates a 32 bit unsigned random number
+ from the random number generator `rng`.
+*/
+const rand32 = {rng
+ var x
+
+ if rng.i == 624
+ next(rng)
+ ;;
+ x = rng.state[rng.i]
+ rng.i++
+
+ x ^= x >> 11
+ x ^= (x << 7) & 0x9D2C5680
+ x ^= (x << 15) & 0xEFC60000
+ -> x ^ (x >> 18)
+}
+
+const randbytes = {rng, buf
+ var i, n, r
+
+ n = 0
+ for i = 0; i < buf.len/4; i++
+ r = rand32(rng)
+ buf[n++] = (r >> 0 & 0xff) castto(byte)
+ buf[n++] = (r >> 8 & 0xff) castto(byte)
+ buf[n++] = (r >> 16 & 0xff) castto(byte)
+ buf[n++] = (r >> 32 & 0xff) castto(byte)
+ ;;
+ r = rand32(rng)
+ for ; n != buf.len; n++
+ buf[n++] = (r & 0xff) castto(byte)
+ r >>= 8
+ ;;
+ -> n
+
+}
+
+/* updates random number generator state when we tick over. */
+const next = {rng
+ var k
+ var y
+
+ for k = 0; k < 227; k++
+ y = (rng.state[k] & 0x80000000) | (rng.state[k + 1] & 0x7FFFFFFF)
+ rng.state[k] = rng.state[k + 397] ^ (y >> 1) ^ ((y & 1) * 0x9908B0DF)
+ ;;
+ for ; k < 623; k++
+ y = (rng.state[k] & 0x80000000) | (rng.state[k + 1] & 0x7FFFFFFF)
+ rng.state[k] = rng.state[k - 227] ^ (y >> 1) ^ ((y & 1) * 0x9908B0DF);
+ ;;
+ y = (rng.state[623] & 0x80000000) | (rng.state[0] & 0x7FFFFFFF)
+ rng.state[623] = rng.state[396] ^ (y >> 1) ^ ((y & 1) * 0x9908B0DF);
+ rng.i = 0
+}
diff --git a/lib/std/resolve+plan9.myr b/lib/std/resolve+plan9.myr
new file mode 100644
index 0000000..ef73843
--- /dev/null
+++ b/lib/std/resolve+plan9.myr
@@ -0,0 +1,2 @@
+pkg std =
+;;
diff --git a/lib/std/resolve+posixy.myr b/lib/std/resolve+posixy.myr
new file mode 100644
index 0000000..185c9d7
--- /dev/null
+++ b/lib/std/resolve+posixy.myr
@@ -0,0 +1,443 @@
+use sys
+use "alloc.use"
+use "chartype.use"
+use "die.use"
+use "endian.use"
+use "result.use"
+use "extremum.use"
+use "hashfuncs.use"
+use "htab.use"
+use "ipparse.use"
+use "option.use"
+use "slcp.use"
+use "sleq.use"
+use "slpush.use"
+use "slurp.use"
+use "strfind.use"
+use "strsplit.use"
+use "strstrip.use"
+use "types.use"
+use "utf.use"
+
+pkg std =
+ type rectype = uint16
+
+ const DnsA : rectype = 1 /* host address */
+ const DnsNS : rectype = 2 /* authoritative name server */
+ const DnsMD : rectype = 3 /* mail destination (Obsolete - use MX) */
+ const DnsMF : rectype = 4 /* mail forwarder (Obsolete - use MX) */
+ const DnsCNAME : rectype = 5 /* canonical name for an alias */
+ const DnsSOA : rectype = 6 /* marks the start of a zone of authority */
+ const DnsMB : rectype = 7 /* mailbox domain name (EXPERIMENTAL) */
+ const DnsMG : rectype = 8 /* mail group member (EXPERIMENTAL) */
+ const DnsMR : rectype = 9 /* mail rename domain name (EXPERIMENTAL) */
+ const DnsNULL : rectype = 10 /* null RR (EXPERIMENTAL) */
+ const DnsWKS : rectype = 11 /* well known service description */
+ const DnsPTR : rectype = 12 /* domain name pointer */
+ const DnsHINFO : rectype = 13 /* host information */
+ const DnsMINFO : rectype = 14 /* mailbox or mail list information */
+ const DnsMX : rectype = 15 /* mail exchange */
+ const DnsTXT : rectype = 16 /* text strings */
+ const DnsAAAA : rectype = 28 /* ipv6 host address */
+
+
+ type resolveerr = union
+ `Badhost
+ `Badsrv
+ `Badquery
+ `Badresp
+ ;;
+
+ type hostinfo = struct
+ fam : sys.sockfam
+ stype : sys.socktype
+ ttl : uint32
+ addr : netaddr
+ /*
+ flags : uint32
+ addr : sockaddr[:]
+ canon : byte[:]
+ */
+ ;;
+
+ const resolve : (host : byte[:] -> result(hostinfo[:], resolveerr))
+ const resolvemx : (host : byte[:] -> result(hostinfo[:], resolveerr))
+ const resolverec : (host : byte[:], t : rectype -> result(hostinfo[:], resolveerr))
+;;
+
+const Hostfile = "/etc/hosts"
+const Resolvfile = "/etc/resolv.conf"
+
+var hostmap : htab(byte[:], hostinfo)#
+var search : byte[:][:]
+var nameservers : netaddr[:]
+
+const __init__ = {
+ hostmap = mkht(strhash, streq)
+ loadhosts()
+ loadresolv()
+}
+
+const resolve = {host
+ -> resolverec(host, DnsA)
+}
+
+const resolvemx = {host
+ -> resolverec(host, DnsMX)
+}
+
+const resolverec = {host, t
+ match hostfind(host)
+ | `Some hinf:
+ -> `Ok slpush([][:], hinf)
+ | `None:
+ -> dnsresolve(host, DnsA)
+ ;;
+}
+
+const hostfind = {host
+ -> htget(hostmap, host)
+}
+
+const loadhosts = {
+ var h
+ var lines
+
+ match slurp(Hostfile)
+ | `Ok d: h = d
+ | `Fail m: ->
+ ;;
+
+ lines = strsplit(h, "\n")
+ for l in lines
+ /* trim comment */
+ match strfind(l, "#")
+ | `Some idx: l = l[:idx]
+ | `None: /* whole line */
+ ;;
+
+ match word(l)
+ | `Some (ip, rest):
+ match ipparse(ip)
+ | `Some addr:
+ addhosts(addr, ip, rest)
+ | `None:
+ /*
+ invalid addresses are ignored: we don't want to break stuff
+ with invalid or unsupported addresses
+ */
+
+ ;;
+ | `None:
+ ;;
+ ;;
+ slfree(lines)
+}
+
+const addhosts = {addr, as, str
+ var hinf
+ var fam
+
+ match addr
+ | `Ipv4 _: fam = sys.Afinet
+ | `Ipv6 _: fam = sys.Afinet6
+ ;;
+ while true
+ match word(str)
+ | `Some (name, rest):
+ str = rest
+ if hthas(hostmap, name)
+ continue
+ ;;
+ hinf = [
+ .fam=fam,
+ .stype = 0,
+ .ttl = 0,
+ .addr = addr
+ ]
+ htput(hostmap, name, hinf)
+ | `None:
+ ->
+ ;;
+ ;;
+}
+
+const loadresolv = {
+ var h
+ var lines
+
+ match slurp(Resolvfile)
+ | `Ok d: h = d
+ | `Fail m: ->
+ ;;
+
+ lines = strsplit(h, "\n")
+ for l in lines
+ match strfind(l, "#")
+ | `Some _idx: l = l[:_idx]
+ | `None:
+ ;;
+
+ match word(l)
+ | `Some ("nameserver", srv):
+ addns(srv)
+ | `Some (_, rest):
+ /* invalid or unrecognized commands */
+ | `None:
+ /* unrecognized lines */
+ ;;
+ ;;
+ slfree(lines)
+}
+
+const addns = {rest
+ match word(rest)
+ | `Some (name, _):
+ match ipparse(name)
+ | `Some addr:
+ nameservers = slpush(nameservers, addr)
+ | `None:
+ /* nothing */
+ ;;
+ | `None:
+ /* nothing */
+ ;;
+}
+
+const word = {s
+ var c, len
+
+ len = 0
+ s = strfstrip(s)
+ for c = decode(s[len:]); c != Badchar && !isblank(c); c = decode(s[len:])
+ len += charlen(c)
+ ;;
+ if len == 0
+ -> `None
+ else
+ -> `Some (s[:len], s[len:])
+ ;;
+}
+
+
+const dnsresolve = {host, t
+ var nsrv
+
+ if !valid(host)
+ -> `Fail (`Badhost)
+ ;;
+ for ns in nameservers
+ nsrv = dnsconnect(ns)
+ if nsrv >= 0
+ -> dnsquery(nsrv, host, t)
+ ;;
+ ;;
+ -> `Fail (`Badsrv)
+}
+
+const dnsconnect = {ns
+ match ns
+ | `Ipv4 addr: -> dnsconnectv4(addr)
+ | `Ipv6 addr: die("don't support ipv6 yet\n")
+ ;;
+}
+
+const dnsconnectv4 = {addr
+ var sa : sys.sockaddr_in
+ var s
+ var status
+
+ s = sys.socket(sys.Afinet, sys.Sockdgram, 0)
+ if s < 0
+ -> -1
+ ;;
+ sa.fam = sys.Afinet
+ sa.port = hosttonet(53)
+ sa.addr = addr
+ status = sys.connect(s, (&sa) castto(sys.sockaddr#), sizeof(sys.sockaddr_in))
+ if status < 0
+ -> -1
+ ;;
+ -> s
+}
+
+const dnsquery = {srv, host, t
+ var id
+ var r
+
+ id = tquery(srv, host, t)
+ r = rquery(srv, id)
+ -> r
+}
+
+const Qr : uint16 = 1 << 0
+const Aa : uint16 = 1 << 5
+const Tc : uint16 = 1 << 6
+const Rd : uint16 = 1 << 7
+const Ra : uint16 = 1 << 8
+
+var nextid : uint16 = 42
+const tquery = {srv, host, t
+ var pkt : byte[512] /* big enough */
+ var off : size
+
+ /* header */
+ off = 0
+ off += pack16(pkt[:], off, nextid) /* id */
+ off += pack16(pkt[:], off, Ra) /* flags */
+ off += pack16(pkt[:], off, 1) /* qdcount */
+ off += pack16(pkt[:], off, 0) /* ancount */
+ off += pack16(pkt[:], off, 0) /* nscount */
+ off += pack16(pkt[:], off, 0) /* arcount */
+
+ /* query */
+ off += packname(pkt[:], off, host) /* host */
+ off += pack16(pkt[:], off, t castto(uint16)) /* qtype: a record */
+ off += pack16(pkt[:], off, 0x1) /* qclass: inet4 */
+
+ sys.write(srv, pkt[:off])
+ -> nextid++
+}
+
+const rquery = {srv, id
+ var pktbuf : byte[1024]
+ var pkt
+ var n
+
+ n = sys.read(srv, pktbuf[:])
+ if n < 0
+ ;;
+ pkt = pktbuf[:n]
+ -> hosts(pkt, id)
+}
+
+const hosts = {pkt, id : uint16
+ var off
+ var v, q, a
+ var i
+ var hinf : hostinfo[:]
+
+ off = 0
+ /* parse header */
+ (v, off) = unpack16(pkt, off) /* id */
+ if v != id
+ -> `Fail (`Badresp)
+ ;;
+ (v, off) = unpack16(pkt, off) /* flags */
+ (q, off) = unpack16(pkt, off) /* qdcount */
+ (a, off) = unpack16(pkt, off) /* ancount */
+ (v, off) = unpack16(pkt, off) /* nscount */
+ (v, off) = unpack16(pkt, off) /* arcount */
+
+ /* skip past query records */
+ for i = 0; i < q; i++
+ off = skipname(pkt, off) /* name */
+ (v, off) = unpack16(pkt, off) /* type */
+ (v, off) = unpack16(pkt, off) /* class */
+ ;;
+
+ /* parse answer records */
+ hinf = slalloc(a castto(size))
+ for i = 0; i < a; i++
+ off = skipname(pkt, off) /* name */
+ (v, off) = unpack16(pkt, off) /* type */
+ (v, off) = unpack16(pkt, off) /* class */
+ (hinf[i].ttl, off) = unpack32(pkt, off) /* ttl */
+ (v, off) = unpack16(pkt, off) /* rdatalen */
+ /* the thing we're interested in: our IP address */
+ hinf[i].addr = `Ipv4 [pkt[off], pkt[off+1], pkt[off+2], pkt[off+3]]
+ off += 4;
+ ;;
+ -> `Ok hinf
+}
+
+
+const skipname = {pkt, off
+ var sz
+
+ for sz = pkt[off] castto(size); sz != 0; sz = pkt[off] castto(size)
+ /* ptr is 2 bytes */
+ if sz & 0xC0 == 0xC0
+ -> off + 2
+ else
+ off += sz + 1
+ ;;
+ ;;
+ -> off + 1
+}
+
+
+const pack16 = {buf, off, v
+ buf[off] = (v & 0xff00) >> 8 castto(byte)
+ buf[off+1] = (v & 0x00ff) castto(byte)
+ -> sizeof(uint16) /* we always write one uint16 */
+}
+
+const unpack16 = {buf, off
+ var v
+
+ v = (buf[off] castto(uint16)) << 8
+ v |= (buf[off + 1] castto(uint16))
+ -> (v, off+sizeof(uint16))
+}
+
+const unpack32 = {buf, off
+ var v
+
+ v = (buf[off] castto(uint32)) << 24
+ v |= (buf[off+1] castto(uint32)) << 32
+ v |= (buf[off+2] castto(uint32)) << 8
+ v |= (buf[off+3] castto(uint32))
+ -> (v, off+sizeof(uint32))
+}
+
+const packname = {buf, off : size, host
+ var i
+ var start
+ var last
+
+ start = off
+ last = 0
+ for i = 0; i < host.len; i++
+ if host[i] == ('.' castto(byte))
+ off += addseg(buf, off, host[last:i])
+ last = i + 1
+ ;;
+ ;;
+ if host[host.len - 1] != ('.' castto(byte))
+ off += addseg(buf, off, host[last:])
+ ;;
+ off += addseg(buf, off, "") /* null terminating segment */
+ -> off - start
+}
+
+const addseg = {buf, off, str
+ buf[off] = str.len castto(byte)
+ slcp(buf[off + 1 : off + str.len + 1], str)
+ -> str.len + 1
+}
+
+const valid = {host : byte[:]
+ var i
+ var seglen
+
+ /* maximum length: 255 chars */
+ if host.len > 255
+ -> false
+ ;;
+
+ seglen = 0
+ for i = 0; i < host.len; i++
+ if host[i] == ('.' castto(byte))
+ seglen = 0
+ ;;
+ if seglen > 63
+ -> false
+ ;;
+ if host[i] & 0x80 != 0
+ -> false
+ ;;
+ ;;
+
+ -> true
+}
diff --git a/lib/std/result.myr b/lib/std/result.myr
new file mode 100644
index 0000000..58ef45b
--- /dev/null
+++ b/lib/std/result.myr
@@ -0,0 +1,9 @@
+use "die.use"
+
+pkg std =
+ type result(@a, @b) = union
+ `Ok @a
+ `Fail @b
+ ;;
+;;
+
diff --git a/lib/std/search.myr b/lib/std/search.myr
new file mode 100644
index 0000000..725e419
--- /dev/null
+++ b/lib/std/search.myr
@@ -0,0 +1,43 @@
+use "cmp.use"
+use "option.use"
+
+pkg std =
+ generic lsearch : (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric)))
+ generic bsearch : (sl : @t[:], val : @t, cmp : (a : @t, b : @t -> order) -> option(@idx::(integral,numeric)))
+;;
+
+/* linear search over a list of values */
+generic lsearch = {sl, val, cmp
+ var i
+
+ for i = 0; i < sl.len; i++
+ match cmp(sl[i], val)
+ | `Equal:
+ -> `Some i
+ | _:
+ /* nothing */
+ ;;
+ ;;
+ -> `None
+}
+
+/* binary search over a sorted list of values. */
+generic bsearch = {sl, val, cmp
+ var hi, lo, mid
+
+ lo = 0
+ hi = sl.len - 1
+
+ while lo <= hi
+ mid = (hi + lo) / 2
+ match cmp(val, sl[mid])
+ | `Before: hi = mid - 1
+ | `After: lo = mid + 1
+ | `Equal:
+ -> `Some mid
+ ;;
+ ;;
+ -> `None
+}
+
+
diff --git a/lib/std/slcp.myr b/lib/std/slcp.myr
new file mode 100644
index 0000000..1035a29
--- /dev/null
+++ b/lib/std/slcp.myr
@@ -0,0 +1,26 @@
+use "die.use"
+use "types.use"
+
+pkg std =
+ generic slcp : (a : @a[:], b : @a[:] -> void)
+;;
+
+generic slcp = {a : @a[:], b : @a[:]
+ var i
+ var addr_a, addr_b
+
+ assert(a.len == b.len, "arguments to slcp() must be of equal length")
+</