@@ -457,6 +457,7 @@ when = \cond action -> if cond then action else yield {}
457457min = \a b -> if a < b then a else b
458458max = \a b -> if a > b then a else b
459459clamp = \lo hi x -> max lo (min hi x)
460+mod = \n m -> n - n / m * m
460461
461462-- Dedup: keeps first occurrence (O(n^2)).
462463unique = \items -> fold (\acc x -> if elem acc x then acc else union acc [x]) [] items
@@ -544,9 +545,9 @@ mapEach = \items getKey action -> case headOf items of
544545 rest <- mapEach (filter items (\y -> getKey y != getKey x)) getKey action
545546 yield (union [r] rest)
546547
547−-- Hex tokens (modulo lives inside hexDigit, so callers just pass raw bits).
548+-- Hex tokens (callers just pass raw bits).
548549hexDigit : Int -> Text
549−hexDigit = \n -> take 1 (drop (n - n / 16 * 16) "0123456789abcdef")
550+hexDigit = \n -> take 1 (drop (mod n 16) "0123456789abcdef")
550551
551552byteToHex : Int -> Text
552553byteToHex = \n -> hexDigit (n / 16) ++ hexDigit n
@@ -562,12 +563,12 @@ genTokenN = \n -> if n <= 0 then yield "" else do
562563genToken = genTokenN 8
563564
564565tooLong : Text -> Int -> Bool
565−tooLong = \s maxLen -> drop maxLen s != ""
566+tooLong = \s maxLen -> count (chars s) > maxLen
566567
567568isValidHex : Text -> Bool
568569isValidHex = \s ->
569− let n = count (chars s) in
570− n > 0 && n / 2 * 2 == n && all (chars s) (\c -> contains c "0123456789abcdef")
570+ let cs = chars s in
571+ count cs > 0 && mod (count cs) 2 == 0 && all cs (\c -> contains c "0123456789abcdef")
571572
572573normalizeHex : Text -> Text
573574normalizeHex = \s -> bytesToHex (bytesFromHex s)