+val rnd = ref (Random.rand (0, 0))
+
+fun init () = rnd := Random.rand (SysWord.toInt (Posix.Process.pidToWord (Posix.ProcEnv.getpid ())),
+ SysWord.toInt (Posix.Process.pidToWord (Posix.ProcEnv.getpid ())))
+
+fun randomPassword () = Int.toString (Int.abs (Random.randInt (!rnd)))
+
+fun domainDir dom =
+ String.concatWith "/" ("/afs/hcoop.net/common/etc/domtool/nodes/deleuze" :: List.rev (String.fields (fn ch => ch = #".") dom))
+
+fun readFile fname =
+ let
+ val inf = TextIO.openIn fname
+
+ fun readLines lines =
+ case TextIO.inputLine inf of
+ NONE => String.concat (List.rev lines)
+ | SOME line => readLines (line :: lines)
+ in
+ readLines []
+ before TextIO.closeIn inf
+ end
+
+fun mem (x, ls) = List.exists (fn y => y = x) ls
+
+val allLower = CharVector.map Char.toLower
+
+fun normEmail s = case String.tokens Char.isSpace (allLower s) of
+ s :: _ => s
+ | [] => ""
+
+val s_cutoff = LargeInt.fromInt 60
+val m_cutoff = LargeInt.fromInt (60 * 60)
+val h_cutoff = LargeInt.fromInt (60 * 60 * 24)
+
+fun diffFromNow t =
+ let
+ val secs = Time.toSeconds (Time.- (Time.now (), t))
+ in
+ if LargeInt.< (secs, s_cutoff) then
+ LargeInt.toString secs ^ " seconds"
+ else if LargeInt.< (secs, m_cutoff) then
+ LargeInt.toString (LargeInt.div (secs, s_cutoff)) ^ " minutes"
+ else if LargeInt.< (secs, h_cutoff) then
+ LargeInt.toString (LargeInt.div (secs, m_cutoff)) ^ " hours"
+ else
+ LargeInt.toString (LargeInt.div (secs, h_cutoff)) ^ " days"
+ end
+
+end