| 1 | structure Util :> UTIL = |
| 2 | struct |
| 3 | |
| 4 | datatype 'a flat_element = |
| 5 | BEGIN |
| 6 | | END |
| 7 | | ITEM of 'a |
| 8 | type 'a flat_tree = 'a flat_element list |
| 9 | |
| 10 | fun printInt n = |
| 11 | Web.print (if n < 0 then |
| 12 | "-" ^ Int.toString (~n) |
| 13 | else |
| 14 | Int.toString n) |
| 15 | |
| 16 | fun printReal n = |
| 17 | Web.print (if n < 0.0 then |
| 18 | "-" ^ Real.fmt (StringCvt.FIX (SOME 2)) (~n) |
| 19 | else |
| 20 | Real.fmt (StringCvt.FIX (SOME 2)) n) |
| 21 | |
| 22 | fun id x = x |
| 23 | |
| 24 | fun makeSet f items = |
| 25 | case items of |
| 26 | [] => "()" |
| 27 | | [usr] => "(" ^ f usr ^ ")" |
| 28 | | usr::rest => foldl (fn (usr, s) => s ^ ", " ^ f usr) ("(" ^ f usr) rest ^ ")" |
| 29 | |
| 30 | fun neg (r : real) = ~r |
| 31 | fun add (r1 : real, r2) = r1 + r2 |
| 32 | fun sub (r1 : real, r2) = r1 - r2 |
| 33 | fun mult (r1, r2) = real r1 * r2 |
| 34 | |
| 35 | fun lt (r1 : real, r2) = r1 < r2 |
| 36 | fun ge (r1 : real, r2) = r1 >= r2 |
| 37 | |
| 38 | fun isIdent ch = Char.isLower ch orelse Char.isDigit ch orelse ch = #"-" |
| 39 | |
| 40 | fun validHost s = |
| 41 | size s > 0 andalso size s < 40 andalso List.all isIdent (String.explode s) |
| 42 | |
| 43 | fun validDomain s = |
| 44 | size s > 0 andalso size s < 100 andalso List.all validHost (String.fields (fn ch => ch = #".") s) |
| 45 | |
| 46 | fun validUser s = |
| 47 | size s > 0 andalso size s < 50 andalso List.all |
| 48 | (fn ch => isIdent ch orelse ch = #"." orelse ch = #"_" orelse ch = #"-" orelse ch = #"+") |
| 49 | (String.explode s) |
| 50 | |
| 51 | fun validEmailUser s = |
| 52 | size s > 0 andalso size s < 50 andalso List.all |
| 53 | (fn ch => Char.isAlphaNum ch orelse ch = #"." orelse ch = #"_" orelse ch = #"-" orelse ch = #"+") |
| 54 | (String.explode s) |
| 55 | |
| 56 | fun validEmail s = |
| 57 | (case String.fields (fn ch => ch = #"@") s of |
| 58 | [user, host] => validEmailUser user andalso validDomain host |
| 59 | | _ => false) |
| 60 | |
| 61 | fun whoisUrl dom = String.concat ["http://reports.internic.net/cgi/whois?whois_nic=", dom, "&type=domain"] |
| 62 | |
| 63 | val rnd = ref (Random.rand (0, 0)) |
| 64 | |
| 65 | fun init () = rnd := Random.rand (SysWord.toInt (Posix.Process.pidToWord (Posix.ProcEnv.getpid ())), |
| 66 | SysWord.toInt (Posix.Process.pidToWord (Posix.ProcEnv.getpid ()))) |
| 67 | |
| 68 | fun randomPassword () = Int.toString (Int.abs (Random.randInt (!rnd))) |
| 69 | |
| 70 | fun domainDir dom = |
| 71 | String.concatWith "/" ("/afs/hcoop.net/common/etc/domtool/nodes/deleuze" :: List.rev (String.fields (fn ch => ch = #".") dom)) |
| 72 | |
| 73 | fun readFile fname = |
| 74 | let |
| 75 | val inf = TextIO.openIn fname |
| 76 | |
| 77 | fun readLines lines = |
| 78 | case TextIO.inputLine inf of |
| 79 | NONE => String.concat (List.rev lines) |
| 80 | | SOME line => readLines (line :: lines) |
| 81 | in |
| 82 | readLines [] |
| 83 | before TextIO.closeIn inf |
| 84 | end |
| 85 | |
| 86 | fun mem (x, ls) = List.exists (fn y => y = x) ls |
| 87 | |
| 88 | val allLower = CharVector.map Char.toLower |
| 89 | |
| 90 | fun normEmail s = case String.tokens Char.isSpace (allLower s) of |
| 91 | s :: _ => s |
| 92 | | [] => "" |
| 93 | |
| 94 | val s_cutoff = LargeInt.fromInt 60 |
| 95 | val m_cutoff = LargeInt.fromInt (60 * 60) |
| 96 | val h_cutoff = LargeInt.fromInt (60 * 60 * 24) |
| 97 | |
| 98 | fun diffFromNow t = |
| 99 | let |
| 100 | val secs = Time.toSeconds (Time.- (Time.now (), t)) |
| 101 | in |
| 102 | if LargeInt.< (secs, s_cutoff) then |
| 103 | LargeInt.toString secs ^ " seconds" |
| 104 | else if LargeInt.< (secs, m_cutoff) then |
| 105 | LargeInt.toString (LargeInt.div (secs, s_cutoff)) ^ " minutes" |
| 106 | else if LargeInt.< (secs, h_cutoff) then |
| 107 | LargeInt.toString (LargeInt.div (secs, m_cutoff)) ^ " hours" |
| 108 | else |
| 109 | LargeInt.toString (LargeInt.div (secs, h_cutoff)) ^ " days" |
| 110 | end |
| 111 | |
| 112 | end |