Index: trunk/lib/archive.ml
===================================================================
--- trunk/lib/archive.ml	(revision 2)
+++ trunk/lib/archive.ml	(revision 3)
@@ -1,33 +1,13 @@
-(*let module S = Set.Make (Text) in*)
-(*let module M = Map.Make (String) in*)
-(*let module I = Map.Make (Id) in*)
-(*let aggr = I.empty, M.empty, M.empty, M.empty in*)
-(*let fn (id, a, t, k) (n,_) =*)
-(* let id = I.add n.Text.uuid n id in*)
-(* let a =*)
-(*   let f e a = M.update (e.Person.name) (function Some v -> Some (S.add n v) | None -> Some (S.singleton n)) a in*)
-(*   Person.Set.fold f n.Text.authors a in*)
-(* let t =*)
-(*   let f e a = M.update e (function Some v -> Some (S.add n v) | None -> Some (S.singleton n)) a in*)
-(*   String_set.fold f (Text.set "Topics" n) t in*)
-(* let k =*)
-(*   let f e a = M.update e (function Some v -> Some (S.add n v) | None -> Some (S.singleton n)) a in*)
-(*   String_set.fold f (Text.set "Keywords" n) k in*)
-(* (id, a, t, k)*)
+let predicate fn opt = Option.(to_list @@ map fn opt)
 
-module Make (Store : Store.T) = struct
-  include Store
-  let predicate fn opt = Option.(to_list @@ map fn opt)
+let authored query_string =
+  let q = Person.Set.of_query @@ String_set.query query_string in
+  fun n -> Person.Set.predicate q n.Text.authors
 
-  let authored query_string =
-    let q = Person.Set.of_query @@ String_set.query query_string in
-    fun n -> Person.Set.predicate q n.Text.authors
+let keyworded query_string =
+  let q = String_set.query query_string in
+  fun n -> String_set.(predicate q (Text.set "Keywords" n))
 
-  let keyworded query_string =
-    let q = String_set.query query_string in
-    fun n -> String_set.(predicate q (Text.set "Keywords" n))
-
-  let topics query_string =
-    let q = String_set.query query_string in
-    fun n -> String_set.(predicate q (Text.set "Topics" n))
-end
+let topics query_string =
+  let q = String_set.query query_string in
+  fun n -> String_set.(predicate q (Text.set "Topics" n))
Index: trunk/lib/date.ml
===================================================================
--- trunk/lib/date.ml	(revision 2)
+++ trunk/lib/date.ml	(revision 3)
@@ -1,8 +1,14 @@
-type t = { created: Ptime.t option; edited: Ptime.t option }
+type t = { created: string; edited: string }
 let compare = compare
-let rfc_string date = match date with Some t -> Ptime.to_rfc3339 t | None -> ""
-let of_string (rfc : string) = match Ptime.of_rfc3339 rfc with Ok (t,_,_) -> Some t | Error _ -> None
-let listing date = if Option.is_some date.edited then date.edited else date.created
-let pretty_date = function
-  | Some t -> Ptime.to_date t |> fun (y, m, d) -> Printf.sprintf "%04d-%02d-%02d" y m d
-  | None -> ""
+let rfc_string date = date
+let of_string (rfc : string) = rfc
+let listing date = if date.edited <> "" then date.edited else date.created
+let pretty_date date =
+	try Scanf.sscanf date "%4s-%2s-%2s" (fun y m d -> Printf.sprintf "%s %s %s" y m d)
+	with Scanf.Scan_failure s as e -> Printf.fprintf stderr "%s for %s\n" s date; raise e
+let now () = Unix.time () |> Unix.gmtime |>
+	(fun t -> Printf.sprintf "%4d-%02d-%02dT%02d:%02d:%02dZ"
+	 (t.tm_year+1900) (t.tm_mon+1) t.tm_mday t.tm_hour t.tm_min t.tm_sec)
+let to_secs date =
+	Scanf.sscanf date "%4d-%02d-%02dT%02d:%02d:%02d"
+		(fun y mo d h mi s -> (y-1970)*31557600 + mo*2629800 + d*86400 + h*3600 + mi*60 + s)
Index: trunk/lib/dune
===================================================================
--- trunk/lib/dune	(revision 2)
+++ trunk/lib/dune	(revision 3)
@@ -2,3 +2,3 @@
  (name        logarion)
  (public_name logarion)
- (libraries ptime uuidm uri re.str bos text_parse text_parse.parsers msgpck))
+ (libraries text_parse text_parse.parsers unix str msgpck))
Index: trunk/lib/file_store.ml
===================================================================
--- trunk/lib/file_store.ml	(revision 2)
+++ trunk/lib/file_store.ml	(revision 3)
@@ -1,51 +1,64 @@
 type t = string
-type item_t = string
-type archive_t = {
-	name: string; archivists: Person.Set.t; id: Id.t;
-	kv: string Store.KV.t; store: t }
+type item_t = t list
 type record_t = Text.t * item_t
 
 let extension = ".txt"
+let def_dir = try Sys.getenv "LOGARION_DIR" with Not_found -> "."
 
 let to_string f =
 	let ic = open_in f in
-	let n = in_channel_length ic in
-	let s = Bytes.create n in
-	really_input ic s 0 n;
+	let s = really_input_string ic (in_channel_length ic) in
 	close_in ic;
-	Bytes.to_string s
+	s
 
-let file path content = let out = open_out path in
-	output_string out content; close_out out
+let fold_file_line fn init file = match open_in file with
+	| exception (Sys_error msg) -> prerr_endline msg; init
+	| file ->
+		let rec read acc = match input_line file with
+			| "" as s | s when String.get s 0 = '#' -> read acc
+			| s -> read (fn s acc)
+			| exception End_of_file -> close_in file; acc
+		in read init
 
-let (//) a b = a ^ "/" ^ b
+let file path str = let o = open_out path in output_string o str; close_out o
 
 let to_text path =
 	if Filename.extension path = extension then
 		(to_string path |> Text.of_string |> Result.map_error (fun m -> path ^": "^ m))
-	else Error "Not txt"
+	else Error (Printf.sprintf "Not txt: %s" path)
 
 let newest (a,_pa) (b,_pb) = Text.newest a b
 let oldest (a,_pa) (b,_pb) = Text.oldest a b
 
-let list_iter fn {store;_} paths =
-	let link f = match to_text (Filename.concat store f)
-		with Ok t -> fn store t f | Error s -> prerr_endline s in
+let list_iter fn dir paths =
+	let link f = match to_text (Filename.concat dir f) with
+		| Ok t -> fn dir t f | Error s -> prerr_endline s in
 	List.iter link paths
 
-let iter_valid_text pred fn p =
-	match to_text p with Error _ -> () | Ok t -> if pred t then fn (t, p)
+module TextMap = Map.Make(Text)
 
-let fold_valid_text pred fn acc p =
-	match to_text p with Error _ -> acc | Ok t -> if pred t then fn acc (t, p) else acc
+type iteration_t = item_t TextMap.t
+let new_iteration = TextMap.empty
 
-let list_fs dir =
+(*let iter_valid_text pred fn path =*)
+(*	match to_text path with Error _ -> () | Ok t -> if pred t then fn (t, p)*)
+
+let fold_valid_text pred it path =
+	match to_text path with Error _ -> it
+	| Ok t -> if pred t then (TextMap.update t
+			(function None -> Some [path] | Some ps -> Some (path::ps)) it
+		) else it
+
+(* Compare file system nodes to skip reparsing? *)
+let list_fs ?(r=false) dir =
+	let valid_dir f = r && String.get f 0 <> '.' && Sys.is_directory f in
+	let expand_dir d = Array.(to_list @@ map (Filename.concat d) (Sys.readdir d)) in
 	let rec loop result = function
-		| [] -> result
-		| f::fs when Sys.is_directory f ->
-			Array.map (Filename.concat f) (Sys.readdir f)
-			|> Array.to_list |> List.append fs |> loop result
+		| f::fs when valid_dir f -> expand_dir f |> List.append fs |> loop result
 		| f::fs -> loop (f::result) fs
-	in loop [] [dir]
+		| [] -> result in
+	let dirs = if dir = "." then Array.to_list (Sys.readdir dir) else
+		if not r then expand_dir dir else [dir] in
+	loop [] dirs
 
 let list_take n =
@@ -55,29 +68,26 @@
 	in take [] n
 
-let iter ?(predicate=fun _ -> true) ?order ?number fn {store;_} =
-	match order with
-	| None -> List.iter (iter_valid_text predicate fn) @@ list_fs store
-	| Some comp ->
-		List.iter fn
-		@@ (match number with None -> (fun x -> x) | Some n -> list_take n)
-		@@ List.fast_sort comp
-		@@ List.fold_left (fold_valid_text predicate (fun a e -> List.cons e a)) []
-		@@ list_fs store
+let fold_sort_take ?(predicate=fun _ -> true) ?(number=None) comp flist =
+	(match number with None -> (fun x -> x) | Some n -> list_take n)
+	@@ List.fast_sort comp @@ TextMap.bindings
+	@@ List.fold_left (fold_valid_text predicate) new_iteration flist
 
-let fold ?(predicate=fun _ -> true) ?order ?number fn acc {store;_} =
-	match order with
-	| None -> List.fold_left (fold_valid_text predicate fn) acc @@ list_fs store
-	| Some comp ->
-		List.fold_left fn acc
-		@@ (match number with None -> (fun x -> x) | Some n -> list_take n)
-		@@ List.fast_sort comp
-		@@ List.fold_left (fold_valid_text predicate (fun a e -> List.cons e a)) []
-		@@ list_fs store
+let iter ?(r=false) ?(dir=def_dir) ?(predicate=fun _ -> true) ?order ?number fn =
+	let flist = list_fs ~r dir in match order with
+	| Some comp -> List.iter fn @@ fold_sort_take ~predicate ~number comp flist
+	| None -> List.iter fn @@ TextMap.bindings @@
+		List.fold_left (fold_valid_text predicate) new_iteration flist
 
-let with_id { store; _ } id =
+let fold ?(r=false) ?(dir=def_dir) ?(predicate=fun _ -> true) ?order ?number fn acc =
+	let flist = list_fs ~r dir in match order with
+	| Some comp -> List.fold_left fn acc @@ fold_sort_take ~predicate ~number comp flist
+	| None -> List.fold_left fn acc @@ TextMap.bindings @@
+		List.fold_left (fold_valid_text predicate) new_iteration flist
+
+let with_id ?(r=false) ?(dir=def_dir) id =
 	let matched acc path =
 		match to_text path with
 		| Error x -> prerr_endline x; acc
-		| Ok text when text.Text.uuid <> id -> acc
+		| Ok text when text.Text.id <> id -> acc
 		| Ok text ->
 			match acc with
@@ -85,82 +95,52 @@
 			| Ok (Some prev) -> if prev = text then acc else Error [text; prev]
 			| Error x -> Error (text :: x)
-	in List.fold_left matched (Ok None) (list_fs store)
+	in List.fold_left matched (Ok None) (list_fs ~r dir)
 
-module Directory = struct
-	let print ?(descr="") dir result =
-		let () = match result with
-			| Ok true -> print_endline ("Created " ^ descr ^ " directory " ^ dir)
-			| Ok false -> print_endline ("Using existing " ^ descr ^ " directory " ^ dir)
-			| Error (`Msg msg) -> prerr_endline @@ "Failed making " ^ descr ^ ". " ^ msg
-		in
-		result
+let with_dir ?(descr="") ?(perm=0o740) dir =
+	let mkdir dir = match Unix.mkdir dir perm with
+	| exception Unix.Unix_error (EEXIST, _, _) -> ()
+	| exception Unix.Unix_error (code, _fn, arg) ->
+		failwith @@ Printf.sprintf "Error %s making %s dir: %s"
+			(Unix.error_message code) descr arg
+	| _ -> () in
+	let rec mkeach path = function [] | [""] -> () | ""::t -> mkeach path t
+		| hd::t -> let d = Filename.concat path hd in mkdir d; mkeach d t in
+	mkeach
+		(if Filename.is_relative dir then "" else "/")
+		(String.split_on_char '/' dir)
 
-	let directory dir = Result.bind (Fpath.of_string dir) Bos.OS.Dir.create
-
-	let rec directories = function
-		| [] -> Ok ()
-		| (d, descr)::tl ->
-			match directory d |> print ~descr d with
-			| Ok _ -> directories tl
-			| Error _ -> Error (d, descr)
-end
-
-let copy ?(recursive = false) src dst =
-	Bos.OS.Cmd.run (Bos.Cmd.(v "cp" %% (on recursive @@ v "-r") % src % dst))
+let rec with_dirs = function [] -> () | (d, descr)::tl -> with_dir ~descr d; with_dirs tl
 
 let versioned_basename_of_title ?(version=0) repo extension (title : string) =
 	let basename = Text.string_alias title in
 	let rec next version =
-		let candidate = repo // basename ^ "." ^ string_of_int version ^ extension in
+		let candidate = Filename.concat repo
+			(basename ^ "." ^ string_of_int version ^ extension) in
 		if Sys.file_exists candidate then next (succ version) else candidate
 	in
 	next version
 
-let uuid_filename repo extension text =
+let id_filename repo extension text =
 	let basename = Text.alias text in
-	let candidate = repo // String.sub (Id.to_string text.uuid) 0 6 ^ "." ^ basename ^ extension in
+	let candidate = Filename.concat repo (text.id ^ "." ^ basename ^ extension) in
 	if Sys.file_exists candidate then Error "Name clash, try again" else Ok candidate
 
-let with_text {store;_} new_text =
-	Result.bind (uuid_filename store extension new_text) @@
-	fun path ->
-		try file path (Text.to_string new_text); Ok (path, new_text) with Sys_error s -> Error s
-
-let basic_config () =
-	"Archive-Name: "
-	^ "\nArchive-ID: " ^ Id.(generate () |> to_string)
-	^ "\nArchivists: " ^ Bos.OS.Env.opt_var "USER" ~absent:""
-	|> Bytes.of_string
-
-let init ?(dotdir=".logarion/") () =
-	match Directory.directories [dotdir, "dotdir"] with
-	| Error (_dir, _desc) -> ()
-	| Ok () ->
-		let config_file =
-			open_out_gen [Open_creat; Open_excl; Open_wronly]
-				0o700 (dotdir // "config") in
-		output_bytes config_file (basic_config ());
-		close_out config_file
+let with_text ?(dir=def_dir) new_text =
+	match id_filename dir extension new_text with
+	| Error _ as e -> e
+	| Ok path ->
+		try file path (Text.to_string new_text); Ok (path, new_text)
+		with Sys_error s -> Error s
 
 module Config = struct
-	type t = archive_t
-	let key_value k v a = match k with
-		| "Archive-Name" -> { a with name = String.trim v }
-		| "Archive-ID" -> { a with id = Option.get (Id.of_string (String.trim v)) }
-		| "Archivists" -> { a with archivists = Person.Set.of_string v }
-		| _ -> { a with kv = Store.KV.add k (String.trim v) a.kv }
+	type t = string Store.KV.t
+	let key_value k v a = Store.KV.add k (String.trim v) a
 end
 
-let of_path store =
+let of_kv_file path =
 	let open Text_parse in
-	let subsyntaxes = [| (module Parsers.Key_value.Make (Config) : Parser.S with type t = Config.t); (module Parsers.Key_value.Make (Config)); |] in
-	let of_string text acc = Parser.parse subsyntaxes { text; pos = 0; right_boundary = String.length text - 1 } acc in
-	Ok (
-		of_string (to_string @@ store ^ "/.logarion/config") {
-			name = "";
-			archivists = Person.Set.empty;
-			id = Id.nil;
-			kv = Store.KV.empty;
-			store = try Sys.getenv "LOGARION_DIR" with Not_found -> "."
-		}
-	)
+	let subsyntaxes = Parsers.Key_value.[|
+		(module Make (Config) : Parser.S with type t = Config.t); (module Make (Config)); |] in
+	let of_string text acc =
+		Parser.parse subsyntaxes { text; pos = 0; right_boundary = String.length text - 1 } acc in
+	of_string (to_string @@ path) Store.KV.empty
Index: trunk/lib/header_pack.ml
===================================================================
--- trunk/lib/header_pack.ml	(revision 2)
+++ trunk/lib/header_pack.ml	(revision 3)
@@ -1,53 +1,56 @@
-type info_t = { version: int; name: string; archivists: string list }
-type text_t = { id: Msgpck.t; time: Msgpck.t; title: Msgpck.t; authors: Msgpck.t }
-type t = { info: info_t; fields: string list; texts: Msgpck.t; peers: Msgpck.t }
+let version = 0
+type info_t = { version: int; id: string; title: string; people: string list; locations: string list }
+type t = { info: info_t; fields: Msgpck.t; texts: Msgpck.t; peers: Msgpck.t }
 
-let of_id id = Msgpck.Bytes (Id.to_bytes id)
-let to_id pck_id = Id.of_bytes Msgpck.(to_bytes pck_id)
+let of_id id = Msgpck.of_string id
+let to_id = Msgpck.to_string
 
 let person p = Msgpck.String (Person.to_string p)
-let persons ps = List.rev @@ Person.Set.fold (fun p a -> person p :: a) ps []
+let persons ps = Msgpck.of_list @@ List.rev @@ Person.Set.fold (fun p a -> person p :: a) ps []
+
+let str = Msgpck.of_string
+let str_list ls = Msgpck.of_list @@ List.map str ls
+let to_str_list x = List.map Msgpck.to_string (Msgpck.to_list x)
 
 let of_set field t =
 	List.rev @@ String_set.fold (fun s a -> Msgpck.String s :: a) (Text.set field t) []
 
-let date = function
-	| None -> Int32.zero
-	| Some date ->
-		let days, ps = Ptime.Span.to_d_ps (Ptime.to_span date) in
-		Int32.add Int32.(mul (of_int days) 86400l) Int64.(to_int32 (div ps 1000000000000L))
+let date = function "" -> Int32.zero | date -> Int32.of_int (Date.to_secs date)
 
-let to_sec = function
-	Msgpck.Int i -> Int32.of_int i | Msgpck.Uint32 i -> i | x -> Msgpck.to_uint32 x
-
-let public_peers () =
-	Peers.fold_file (fun x a -> Msgpck.String x :: a) [] Peers.public_fname
+let to_sec = function Msgpck.Int i -> Int32.of_int i | Msgpck.Uint32 i -> i | x -> Msgpck.to_uint32 x
 
 let fields = Msgpck.(List [String "id"; String "time";  String "title"; String "authors"; String "topics"])
 let to_fields fieldpack = List.map Msgpck.to_string (Msgpck.to_list fieldpack)
 
-let to_pack a t =
+let to_info = function
+	| Msgpck.List (v::id::n::a::ls::[]) ->
+		let people = to_str_list a in
+		let locations = to_str_list ls in
+		Msgpck.({version = to_int v; id = to_string id; title = to_string n; people; locations})
+	| _ -> invalid_arg "Pack header"
+
+let of_info i = let open Msgpck in
+	List [Int i.version; String i.id; String i.title; str_list i.people; str_list i.locations]
+
+let of_text a t =
 	let open Text in
 	Msgpck.(List [
-		Bytes (Id.to_bytes t.uuid); of_uint32 (date (Date.listing t.date));
-		String t.title; List (persons t.authors); List (of_set "topics" t)
+		of_id t.id; of_uint32 (date (Date.listing t.date));
+		String t.title; persons t.authors; List (of_set "topics" t)
 	]) :: a
 
-let pack_filename ?(filename="index.pck") archive =
-	let dir = Store.KV.find "Export-Dir" archive.File_store.kv in (*raises Not_found*)
-	dir ^ "/" ^ filename
+let of_text_list l = Msgpck.List l
 
-let to_info = function
-	| Msgpck.List (v::n::a::[]) ->
-		let archivists = List.map Msgpck.to_string (Msgpck.to_list a) in
-		Msgpck.({version = to_int v; name = to_string n; archivists})
-	| _ -> invalid_arg "Pack header"
+let pack p = Msgpck.List [of_info p.info; p.fields; p.texts; p.peers]
+let string p = Bytes.to_string @@ Msgpck.Bytes.to_string @@ pack p
 
 let unpack = function
-	| Msgpck.List (i::f::texts::[]) ->
-		Some { info = to_info i; fields = to_fields f; texts; peers = Msgpck.List [] }
-	| Msgpck.List (i::f::texts::peers::[]) ->
-		Some { info = to_info i; fields = to_fields f; texts; peers }
-	| _ -> None
+	| Msgpck.List (i::fields::texts::[]) ->
+		Ok { info = to_info i; fields; texts; peers = Msgpck.List [] }
+	| Msgpck.List (i::fields::texts::peers::[]) ->
+		Ok { info = to_info i; fields; texts; peers }
+	| _ -> Error "format mismatch"
+
+let of_string s = unpack @@ snd @@ Msgpck.StringBuf.read s
 
 let list filename = try
@@ -61,24 +64,21 @@
 let contains text = function
 	| Msgpck.List (id::_time::title::_authors::_topics::[]) ->
-		(match Id.of_bytes (Msgpck.to_bytes id) with
-		 | None -> prerr_endline ("Invalid id for " ^ Msgpck.to_string title); false
-		 | Some id -> text.Text.uuid = id)
+		(match to_id id with
+		 | "" -> prerr_endline ("Invalid id for " ^ Msgpck.to_string title); false
+		 | id -> text.Text.id = id)
 	| _ -> prerr_endline ("Invalid record pattern"); false
 
-let pack archive records =
-	let header_pack = List.fold_left to_pack [] records in
-	let info = Msgpck.(List [Int 0; String archive.File_store.name; List (persons archive.archivists)]) in
-	Bytes.to_string @@ Msgpck.Bytes.to_string
-		(List [info; fields; Msgpck.List header_pack; Msgpck.List (public_peers ())])
 
-let add archive records =
-	let fname = pack_filename archive in
-	let append published (t, _f) = if List.exists (contains t) published then published else to_pack published t in
-	match list fname with Error e -> prerr_endline e | Ok published_list ->
-		let header_pack = List.fold_left append published_list records in
-		let archive = Msgpck.(List [Int 0; String archive.File_store.name;
-			List (persons archive.archivists)]) in
-		File_store.file fname @@ Bytes.to_string
-			@@ Msgpck.Bytes.to_string (List [archive; fields; Msgpck.List header_pack])
+(*let pack_filename ?(filename="index.pck") archive =*)
+(*	let dir = Store.KV.find "Export-Dir" archive.File_store.kv in (*raises Not_found*)*)
+(*	dir ^ "/" ^ filename*)
 
-let unpublish _archive _records = ()
+(*let add archive records =*)
+(*	let fname = pack_filename archive in*)
+(*	let append published (t, _f) = if List.exists (contains t) published then published else to_pack published t in*)
+(*	match list fname with Error e -> prerr_endline e | Ok published_list ->*)
+(*		let header_pack = List.fold_left append published_list records in*)
+(*		let archive = Msgpck.(List [*)
+(*			Int 0; String archive.File_store.name; persons archive.people]) in*)
+(*		File_store.file fname @@ Bytes.to_string*)
+(*			@@ Msgpck.Bytes.to_string (List [archive; fields; Msgpck.List header_pack])*)
Index: trunk/lib/id.ml
===================================================================
--- trunk/lib/id.ml	(revision 2)
+++ trunk/lib/id.ml	(revision 3)
@@ -1,9 +1,33 @@
-let random_state = Random.State.make_self_init ()
-type t = Uuidm.t
-let compare = Uuidm.compare
-let to_string = Uuidm.to_string
-let of_string = Uuidm.of_string
-let to_bytes = Uuidm.to_bytes
-let of_bytes = Uuidm.of_bytes
-let generate ?(random_state=random_state) = Uuidm.v4_gen random_state
-let nil = Uuidm.nil
+let random_state = Random.State.make_self_init
+
+(*module UUID = struct*)
+(*type t = Uuidm.t*)
+(*let compare = Uuidm.compare*)
+(*let to_string = Uuidm.to_string*)
+(*let of_string = Uuidm.of_string*)
+(*let to_bytes = Uuidm.to_bytes*)
+(*let of_bytes = Uuidm.of_bytes*)
+(*let generate ?(random_state=random_state ()) = Uuidm.v4_gen random_state*)
+(*let nil = Uuidm.nil*)
+(*end*)
+
+type t = string
+let compare = String.compare	
+let nil = ""
+
+let short ?(len) id =
+	let id_len = String.length id in
+	let l = match len with Some l -> l | None -> if id_len = 36 then 8 else 6 in
+	String.sub id 0 (min l id_len)
+
+let generate ?(len=6) ?(seed=random_state ()) () =
+	let b32 i = char_of_int @@
+		if i < 10 then i+48 else
+		if i < 18 then i+87 else
+		if i < 20 then i+88 else
+		if i < 22 then i+89 else
+		if i < 27 then i+90 else
+		if i < 32 then i+91 else
+		(invalid_arg ("id.char" ^ string_of_int i)) in
+	let c _ = b32 (Random.State.int seed 31) in
+	String.init len c
Index: trunk/lib/peers.ml
===================================================================
--- trunk/lib/peers.ml	(revision 2)
+++ trunk/lib/peers.ml	(revision 3)
@@ -1,9 +1,19 @@
-let public_fname = "peers.pub.conf"
-let private_fname = "peers.priv.conf"
+let text_dir = Filename.concat (Sys.getenv "HOME") ".local/share/texts"
 
-let fold_file fn init file = match open_in file with
-	| exception (Sys_error msg) -> prerr_endline msg; init
-	| file ->
-		let rec read acc = try read (fn (input_line file) acc)
-			with End_of_file -> close_in file; acc in
-		read init
+let fold fn init = match Sys.readdir text_dir with
+	| exception (Sys_error msg) -> prerr_endline msg
+	| dirs ->
+		let read_pack path =
+			let pack_path = Filename.(concat text_dir @@ concat path "index.pck") in
+			match Sys.file_exists pack_path with false -> () | true ->
+				match Header_pack.of_string (File_store.to_string pack_path) with
+				| Error s -> Printf.eprintf "%s %s\n" s pack_path
+				| Ok p -> ignore @@ List.fold_left fn init Header_pack.(p.info.locations)
+		in
+		Array.iter read_pack dirs
+
+let scheme url =
+	let colon_idx = String.index_from url 0 ':' in
+	let scheme = String.sub url 0 colon_idx in
+(*	let remain = String.(sub url (colon_idx+1) (length url - length scheme - 1)) in*)
+	scheme
Index: trunk/lib/person.ml
===================================================================
--- trunk/lib/person.ml	(revision 2)
+++ trunk/lib/person.ml	(revision 3)
@@ -1,16 +1,17 @@
 module Person = struct
   type name_t = string
-  type address_t = Uri.t
+  type address_t = string
   type t = { name: name_t; addresses: address_t list }
   let empty = { name = ""; addresses = [] }
   let compare = Stdlib.compare
-  let to_string p = List.fold_left (fun a e -> a^" <"^Uri.to_string e^">") p.name p.addresses
+  let name_to_string p = p.name
+  let to_string p = List.fold_left (fun a e -> Printf.sprintf "%s <%s>" a e) p.name p.addresses
   let of_string s = match String.trim s with "" -> empty | s ->
-    match Re.Str.(split (regexp " *< *") s) with
+    match Str.(split (regexp " *< *") s) with
     | [] -> empty
     | [n] -> let name = String.trim n in { empty with name }
     | n::adds ->
       let name = String.trim n in
-      let addresses = List.map (fun f -> Uri.of_string @@ String.(sub f 0 (length f -1))) adds in
+      let addresses = List.map (fun f -> String.(sub f 0 (length f -1))) adds in
       { name; addresses }
 end
@@ -20,6 +21,6 @@
 module Set = struct
   include Set.Make(Person)
-  let to_string ?(pre="") ?(sep=", ") s =
-    let str = Person.to_string in
+  let to_string ?(names_only=false) ?(pre="") ?(sep=", ") s =
+    let str = if names_only then Person.name_to_string else Person.to_string in
     let j x a = match a, x with "",_ -> str x | _,x when x = Person.empty -> a | _ -> a^sep^str x in
     fold j s pre
Index: trunk/lib/store.ml
===================================================================
--- trunk/lib/store.ml	(revision 2)
+++ trunk/lib/store.ml	(revision 3)
@@ -4,5 +4,5 @@
 	type t
 	type item_t
-	type archive_t = { name: string; archivists: Person.Set.t; id: Id.t; kv: string KV.t; store: t }
+	type archive_t = { id: Id.t; name: string; archivists: Person.Set.t; kv: string KV.t; store: t }
 	type record_t = Text.t * item_t
 	val of_path: string -> (archive_t, string) result
Index: trunk/lib/string_set.ml
===================================================================
--- trunk/lib/string_set.ml	(revision 2)
+++ trunk/lib/string_set.ml	(revision 3)
@@ -1,5 +1,5 @@
 include Set.Make(String)
 
-let list_of_csv x = Re.Str.(split (regexp " *, *")) (String.trim x)
+let list_of_csv x = Str.(split (regexp " *, *")) (String.trim x)
 let of_string x = of_list (list_of_csv x)
 let to_string ?(pre="") ?(sep=", ") s =
Index: trunk/lib/text.ml
===================================================================
--- trunk/lib/text.ml	(revision 2)
+++ trunk/lib/text.ml	(revision 3)
@@ -1,22 +1,22 @@
 module String_map = Map.Make (String)
 type t = {
-    title: string;
-    uuid: Id.t;
-    authors: Person.Set.t;
-    date: Date.t;
-    string_map: string String_map.t;
-    stringset_map: String_set.t String_map.t;
-    body: string;
-  }
+		id: Id.t;
+		title: string;
+		authors: Person.Set.t;
+		date: Date.t;
+		string_map: string String_map.t;
+		stringset_map: String_set.t String_map.t;
+		body: string;
+	}
 
-let blank ?(uuid=(Id.generate ())) () = {
-    title = "";
-    uuid;
-    authors = Person.Set.empty;
-    date = Date.({ created = None; edited = None});
-    string_map = String_map.empty;
-    stringset_map = String_map.empty;
-    body = "";
-  }
+let blank ?(id=(Id.generate ())) () = {
+		id;
+		title = "";
+		authors = Person.Set.empty;
+		date = Date.({ created = now (); edited = ""});
+		string_map = String_map.empty;
+		stringset_map = String_map.empty;
+		body = "";
+	}
 
 let compare = Stdlib.compare
@@ -29,74 +29,74 @@
 
 let with_kv x (k,v) =
-  let trim = String.trim in
-  match String.lowercase_ascii k with
-  | "body" -> { x with body = String.trim v }
-  | "title"-> { x with title = trim v }
-  | "id"   -> (match Id.of_string v with Some id -> { x with uuid = id } | None -> x)
-  | "author"
-  | "authors" -> { x with authors = Person.Set.of_string (trim v)}
-  | "date"       -> { x with date = Date.{ x.date with created   = Date.of_string v }}
-  | "date-edited"-> { x with date = Date.{ x.date with edited    = Date.of_string v }}
-  | "licences" | "topics" | "keywords" | "series" as k -> with_str_set x k v
-  | k -> { x with string_map = String_map.add k (trim v) x.string_map }
+	let trim = String.trim in
+	match String.lowercase_ascii k with
+	| "body" -> { x with body = String.trim v }
+	| "title"-> { x with title = trim v }
+	| "id"	 -> (match v with "" -> x | s -> { x with id = s })
+	| "author"
+	| "authors" -> { x with authors = Person.Set.of_string (trim v)}
+	| "date"			 -> { x with date = Date.{ x.date with created	 = Date.of_string v }}
+	| "date-edited"-> { x with date = Date.{ x.date with edited		= Date.of_string v }}
+	| "licences" | "topics" | "keywords" | "series" as k -> with_str_set x k v
+	| k -> { x with string_map = String_map.add k (trim v) x.string_map }
 
-let kv_of_string line = match Re.Str.(bounded_split (regexp ": *")) line 2 with
-  | [ key; value ] -> Re.Str.(replace_first (regexp "^#\\+") "" key), value
-  | [ key ] -> Re.Str.(replace_first (regexp "^#\\+") "" key), ""
-  | _ -> "",""
+let kv_of_string line = match Str.(bounded_split (regexp ": *")) line 2 with
+	| [ key; value ] -> Str.(replace_first (regexp "^#\\+") "" key), value
+	| [ key ] -> Str.(replace_first (regexp "^#\\+") "" key), ""
+	| _ -> "",""
 
 let of_header front_matter =
-  let fields = List.map kv_of_string (Re.Str.(split (regexp "\n")) front_matter) in
-  List.fold_left with_kv (blank ~uuid:Id.nil ()) fields
+	let fields = List.map kv_of_string (Str.(split (regexp "\n")) front_matter) in
+	List.fold_left with_kv (blank ~id:Id.nil ()) fields
 
 let front_matter_body_split s =
-  if Re.Str.(string_match (regexp ".*:.*")) s 0
-  then match Re.Str.(bounded_split (regexp "^$")) s 2 with
-       | front::body::[] -> (front, body)
-       | _ -> ("", s)
-  else ("", s)
+	if Str.(string_match (regexp ".*:.*")) s 0
+	then match Str.(bounded_split (regexp "^$")) s 2 with
+			 | front::body::[] -> (front, body)
+			 | _ -> ("", s)
+	else ("", s)
 
 let of_string s =
-  let front_matter, body = front_matter_body_split s in
-  try
-    let note = { (of_header front_matter) with body } in
-    if note.uuid <> Id.nil then Ok note else Error "Missing ID header"
-  with _ -> Error ("Failed parsing" ^ s)
+	let front_matter, body = front_matter_body_split s in
+	try
+		let note = { (of_header front_matter) with body } in
+		if note.id <> Id.nil then Ok note else Error "Missing ID header"
+	with _ -> Error ("Failed parsing" ^ s)
 
 let to_string x = 
-  let has_len v = String.length v > 0 in
-  let s field value = if has_len value then field ^ ": " ^ value ^ "\n" else "" in
-  let a value = if Person.Set.is_empty value then "" else "Authors: " ^ Person.Set.to_string value ^ "\n" in
-  let d field value = match value with Some _ -> field ^ ": " ^ Date.rfc_string value ^ "\n" | None -> "" in
-  let rows =
-    [ s "Title" x.title;
-      a x.authors;
-      d "Date" x.date.Date.created;
-      d "Edited" x.date.Date.edited;
-      s "Licences" (str_set "licences" x);
-      s "Topics"   (str_set "topics" x);
-      s "Keywords" (str_set "keywords" x);
-      s "Series"   (str_set "series" x);
-      s "Abstract" (str "abstract" x);
-      s "ID" (Uuidm.to_string x.uuid);
-      s "Alias" (str "Alias" x) ]
-  in
-  String.concat "" rows ^ "\n" ^ x.body
+	let has_len v = String.length v > 0 in
+	let s field value = if has_len value then field ^ ": " ^ value ^ "\n" else "" in
+	let a value = if Person.Set.is_empty value then "" else "Authors: " ^ Person.Set.to_string value ^ "\n" in
+	let d field value = match value with "" -> "" | s -> field ^ ": " ^ Date.rfc_string s ^ "\n" in
+	let rows = [
+		s "ID" x.id;
+		d "Date"     x.date.Date.created;
+		d "Edited"   x.date.Date.edited;
+		s "Title" x.title;
+		a x.authors;
+		s "Licences" (str_set "licences" x);
+		s "Topics"   (str_set "topics" x);
+		s "Keywords" (str_set "keywords" x);
+		s "Series"   (str_set "series" x);
+		s "Abstract" (str "abstract" x);
+		s "Alias"    (str "Alias" x)
+	] in
+	String.concat "" rows ^ "\n" ^ x.body
 
 let string_alias t =
-  let is_reserved = function
-    | '!' | '*' | '\'' | '(' | ')' | ';' | ':' | '@' | '&' | '=' | '+' | '$'
-      | ',' | '/' | '?' | '#' | '[' | ']' | ' ' | '\t' | '\x00' -> true
-    | _ -> false
-  in
-  let b = Buffer.create (String.length t) in
-  let filter char =
-    let open Buffer in
-    if is_reserved char then (try (if nth b (pred (length b)) <> '-' then add_char b '-') with Invalid_argument _ -> prerr_endline "reserved")
-    else add_char b char
-  in
-  String.(iter filter (lowercase_ascii t));
-  Buffer.contents b
+	let is_reserved = function
+		| '!' | '*' | '\'' | '(' | ')' | ';' | ':' | '@' | '&' | '=' | '+' | '$'
+			| ',' | '/' | '?' | '#' | '[' | ']' | ' ' | '\t' | '\x00' -> true
+		| _ -> false
+	in
+	let b = Buffer.create (String.length t) in
+	let filter char =
+		let open Buffer in
+		if is_reserved char then (try (if nth b (pred (length b)) <> '-' then add_char b '-') with Invalid_argument _ -> prerr_endline "reserved")
+		else add_char b char
+	in
+	String.(iter filter (lowercase_ascii t));
+	Buffer.contents b
 
 let alias t = match str "alias" t with "" -> string_alias t.title | x -> x
-let short_id ?(len=8) t = String.sub (Id.to_string t.uuid) 0 len
+let short_id t = Id.short t.id
Index: trunk/lib/topic_set.ml
===================================================================
--- trunk/lib/topic_set.ml	(revision 2)
+++ trunk/lib/topic_set.ml	(revision 3)
@@ -1,3 +1,3 @@
-let of_string x = Re.Str.(split (regexp " *> *")) (String.trim x)
+let of_string x = Str.(split (regexp " *> *")) (String.trim x)
 
 let topic x =
