4 module Stack = Continuationals.Stack
6 let rt_path () = Helm_registry.get "matita.rt_base_dir"
8 let libdir uid = (rt_path ()) ^ "/users/" ^ uid
10 let utf8_length = Netconversion.ustring_length `Enc_utf8
12 (*** from matitaScript.ml ***)
13 (* let only_dust_RE = Pcre.regexp "^(\\s|\n|%%[^\n]*\n)*$" *)
15 let eval_statement include_paths (* (buffer : GText.buffer) *) status (* script *)
18 let ast,unparsed_text =
21 (* if Pcre.pmatch ~rex:only_dust_RE text then raise Margin; *)
23 GrafiteParser.parsable_statement status
24 (Ulexing.from_utf8_string text) in
25 let ast = MatitaEngine.get_ast status include_paths strm in
27 | `Ast (st, text) -> st, text
29 let floc = match ast with
30 | GrafiteAst.Executable (loc, _)
31 | GrafiteAst.Comment (loc, _) -> loc in
33 let _,lend = HExtlib.loc_of_floc floc in
34 let parsed_text, _parsed_text_len =
35 HExtlib.utf8_parsed_text unparsed_text (HExtlib.floc_of_loc (0,lend)) in
36 let byte_parsed_text_len = String.length parsed_text in
38 String.sub unparsed_text byte_parsed_text_len
39 (String.length unparsed_text - byte_parsed_text_len)
43 MatitaEngine.eval_ast ~include_paths ~do_heavy_checks:false status ("",0,ast)
45 (status, parsed_text, unparsed_txt'),"",(*parsed_text_len*)
46 utf8_length parsed_text
48 (*let save_moo status =
49 let script = MatitaScript.current () in
50 let baseuri = status#baseuri in
51 match script#bos, script#eos with
54 GrafiteTypes.Serializer.serialize ~baseuri:(NUri.uri_of_string baseuri)
56 | _ -> clean_current_baseuri status
59 let sequent_size = ref 40;;
61 let include_paths = ref [];;
65 * <metaname>...</metaname>
72 let _,_,metasenv,subst,_ = s#obj in
73 let render_switch = function
74 | Stack.Open i -> "?" ^ (string_of_int i)
75 | Stack.Closed i -> "<S>?" ^ (string_of_int i) ^ "</S>"
77 let int_of_switch = function
78 | Stack.Open i | Stack.Closed i -> i
80 let sequent = function
82 let meta = List.assoc i metasenv in
83 snd (ApplyTransformation.ntxt_of_cic_sequent
84 ~metasenv ~subst ~map_unicode_to_tex:false !sequent_size s (i,meta))
85 | Stack.Closed _ -> "This goal has already been closed."
87 let render_sequent is_loc acc depth tag (pos,sw) =
88 let metano = int_of_switch sw in
91 (match depth, pos with
92 | 0, 0 -> "<B>" ^ (render_switch sw) ^ "</B>"
94 Printf.sprintf "<B>|<SUB>%d</SUB>: %s</B>" pos (render_switch sw)
95 | 1, pos when Stack.head_tag s#stack = `BranchTag ->
96 Printf.sprintf "|<SUB>%d</SUB> : %s" pos (render_switch sw)
97 | _ -> render_switch sw)
101 Netencoding.Html.encode ~in_enc:`Enc_utf8 ~prefer_name:false () markup in
102 let markup = "<metaname>" ^ markup ^ "</metaname>" in
104 Netencoding.Html.encode ~in_enc:`Enc_utf8 ~prefer_name:false () (sequent sw)
106 let txt0 = "<goal>" ^ sequent ^ "</goal>" in
107 "<meta number=\"" ^ (string_of_int metano) ^ "\">" ^ markup ^
108 txt0 ^ "</meta>" ^ acc
110 let res = "<metasenv>" ^
112 ~env:(render_sequent true) ~cont:(render_sequent false)
113 ~todo:(render_sequent false) "" s#stack) ^
116 (* prerr_endline ("sending metasenv:\n" ^ res); res *)
119 (* let html_of_status s =
120 let _,_,metasenv,subst,_ = s#obj in
121 let txt = List.fold_left
122 (fun acc (nmeta,_ as meta) ->
123 let txt0 = snd (ApplyTransformation.ntxt_of_cic_sequent
124 ~metasenv ~subst ~map_unicode_to_tex:false 80 s meta)
126 prerr_endline ("### txt0 = " ^ txt0);
127 ("<B>Goal ?" ^ (string_of_int nmeta) ^ "</B>\n" ^ txt0)::acc)
130 String.concat "\n\n" txt
133 let html_of_matita s =
134 let patt1 = Str.regexp "\005" in
135 let patt2 = Str.regexp "\006" in
136 let patt3 = Str.regexp "<" in
137 let patt4 = Str.regexp ">" in
138 let res = Str.global_replace patt4 ">" s in
139 let res = Str.global_replace patt3 "<" res in
140 let res = Str.global_replace patt2 ">" res in
141 let res = Str.global_replace patt1 "<" res in
145 let heading_nl_RE = Pcre.regexp "^\\s*\n\\s*";;
148 let s = Pcre.replace ~rex:heading_nl_RE s in
150 let nl_pos = String.index s '\n' in
151 String.sub s 0 nl_pos
155 let read_file fname =
156 let chan = open_in fname in
157 let lines = ref [] in
160 lines := input_line chan :: !lines
162 with End_of_file -> close_in chan);
163 String.concat "\n" (List.rev !lines)
166 let load_index outchan =
167 let s = read_file "index.html" in
168 Http_daemon.respond ~headers:["Content-Type", "text/html"] ~code:(`Code 200) ~body:s outchan
171 let load_doc filename outchan =
172 let s = read_file filename in
174 try String.sub filename (String.length filename - 4) 4 = ".png"
175 with Invalid_argument _ -> false
177 let contenttype = if is_png then "image/png" else "text/html" in
178 Http_daemon.respond ~headers:["Content-Type", contenttype] ~code:(`Code 200) ~body:s outchan
181 let retrieve (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
182 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
183 let env = cgi#environment in
185 let sid = Uuidm.of_string (Netcgi.Cookie.value (env#cookie "session")) in
186 let sid = HExtlib.unopt sid in
187 let uid = MatitaAuthentication.user_of_session sid in
191 ~content_type:"text/xml; charset=\"utf-8\""
194 let filename = libdir uid ^ "/" ^ (cgi # argument_value "file") in
195 (* prerr_endline ("reading file " ^ filename); *)
197 Netencoding.Html.encode ~in_enc:`Enc_utf8 ~prefer_name:false ()
198 (html_of_matita (read_file filename)) in
200 (* html_of_matita (read_file filename) in *)
201 (* prerr_endline ("sending:\nBEGIN\n" ^ body ^ "\nEND"); *)
202 let body = "<response><file>" ^ body ^ "</file></response>" in
203 let baseuri, incpaths =
205 let root, baseuri, _fname, _tgt =
206 Librarian.baseuri_of_script ~include_paths:[] filename in
209 Str.split (Str.regexp " ")
210 (List.assoc "include_paths" (Librarian.load_root_file (root^"/root")))
213 let rc = root :: includes in
214 List.iter (HLog.debug) rc; baseuri, rc
216 Librarian.NoRootFor _ | Librarian.FileNotFound _ -> "",[] in
217 include_paths := incpaths;
218 let status = MatitaAuthentication.get_status sid in
219 MatitaAuthentication.set_status sid (status#set_baseuri baseuri);
222 ~content_type:"text/xml; charset=\"utf-8\""
224 cgi#out_channel#output_string body;
228 ~status:`Internal_server_error
230 ~content_type:"text/html; charset=\"utf-8\""
232 cgi#out_channel#commit_work()
235 let advance0 sid text =
236 let status = MatitaAuthentication.get_status sid in
237 let status = status#reset_disambiguate_db () in
238 let (st,new_statements,new_unparsed),(* newtext TODO *) _,parsed_len =
240 eval_statement !include_paths (*buffer*) status (`Raw text)
242 | HExtlib.Localized (_,e) -> raise e
243 (*| End_of_file -> raise Margin *)
245 let stringbuf = Ulexing.from_utf8_string new_statements in
246 let interpr = GrafiteDisambiguate.get_interpr st#disambiguate_db in
247 let outstr = ref "" in
248 ignore (SmallLexer.mk_small_printer interpr outstr stringbuf);
249 (* prerr_endline ("parser output: " ^ !outstr); *)
250 MatitaAuthentication.set_status sid st;
252 Netencoding.Html.encode ~in_enc:`Enc_utf8 ~prefer_name:false
253 () (html_of_matita !outstr), new_unparsed, st
255 let register (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
256 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
257 let env = cgi#environment in
259 assert (cgi#arguments <> []);
260 let uid = cgi#argument_value "userid" in
261 let userpw = cgi#argument_value "password" in
263 MatitaAuthentication.add_user uid userpw;
264 (* env#set_output_header_field "Location" "/index.html" *)
265 cgi#out_channel#output_string
266 ("<html><head><meta http-equiv=\"refresh\" content=\"2;url=/login.html\">"
267 ^ "</head><body>Redirecting to login page...</body></html>")
269 | MatitaAuthentication.UsernameCollision _ ->
272 ~content_type:"text/html; charset=\"utf-8\""
274 cgi#out_channel#output_string
275 "<html><head></head><body>Error: User id collision!</body></html>"
276 | MatitaFilesystem.SvnError msg ->
279 ~content_type:"text/html; charset=\"utf-8\""
281 cgi#out_channel#output_string
282 ("<html><head></head><body><p>Error: Svn checkout failed!<p><p><textarea>"
283 ^ msg ^ "</textarea></p></body></html>"));
284 cgi#out_channel#commit_work()
287 let login (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
288 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
289 let env = cgi#environment in
291 assert (cgi#arguments <> []);
292 let uid = cgi#argument_value "userid" in
293 let userpw = cgi#argument_value "password" in
294 let pw,_ = MatitaAuthentication.lookup_user uid in
298 let _ = MatitaFilesystem.html_of_library uid in
299 let sid = MatitaAuthentication.create_session uid in
300 (* let cookie = Netcgi.Cookie.make "session" (Uuidm.to_string sid) in
301 cgi#set_header ~set_cookies:[cookie] (); *)
302 env#set_output_header_field
303 "Set-Cookie" ("session=" ^ (Uuidm.to_string sid));
304 (* env#set_output_header_field "Location" "/index.html" *)
305 cgi#out_channel#output_string
306 ("<html><head><meta http-equiv=\"refresh\" content=\"2;url=/index.html\">"
307 ^ "</head><body>Redirecting to Matita page...</body></html>")
313 ~content_type:"text/html; charset=\"utf-8\""
315 cgi#out_channel#output_string
316 "<html><head></head><body>Authentication error</body></html>"
319 cgi#out_channel#commit_work()
323 let logout (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
324 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
325 let env = cgi#environment in
327 let sid = Uuidm.of_string (Netcgi.Cookie.value (env#cookie "session")) in
328 let sid = HExtlib.unopt sid in
329 MatitaAuthentication.logout_user sid;
332 ~content_type:"text/html; charset=\"utf-8\""
334 let text = read_file (rt_path () ^ "/logout.html") in
335 cgi#out_channel#output_string text
339 ~status:`Internal_server_error
341 ~content_type:"text/html; charset=\"utf-8\""
343 cgi#out_channel#commit_work()
346 exception File_already_exists;;
348 let save (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
349 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
350 let env = cgi#environment in
352 let sid = Uuidm.of_string (Netcgi.Cookie.value (env#cookie "session")) in
353 let sid = HExtlib.unopt sid in
354 let status = MatitaAuthentication.get_status sid in
355 let uid = MatitaAuthentication.user_of_session sid in
356 assert (cgi#arguments <> []);
357 let locked = cgi#argument_value "locked" in
358 let unlocked = cgi#argument_value "unlocked" in
359 let filename = libdir uid ^ "/" ^ (cgi # argument_value "file") in
360 let force = bool_of_string (cgi#argument_value "force") in
362 if ((not force) && (Sys.file_exists filename)) then
363 raise File_already_exists;
365 let oc = open_out filename in
366 output_string oc (locked ^ unlocked);
368 if MatitaEngine.eos status unlocked then
370 (* prerr_endline ("serializing proof objects..."); *)
371 GrafiteTypes.Serializer.serialize
372 ~baseuri:(NUri.uri_of_string status#baseuri) status;
373 (* prerr_endline ("adding to the commit queue..."); *)
374 MatitaFilesystem.add_user uid;
375 (* prerr_endline ("done."); *)
379 ~content_type:"text/xml; charset=\"utf-8\""
381 cgi#out_channel#output_string "<response>ok</response>"
383 | File_already_exists ->
384 cgi#out_channel#output_string "<response>cancelled</response>"
387 ~status:`Internal_server_error
389 ~content_type:"text/xml; charset=\"utf-8\""
391 cgi#out_channel#commit_work()
394 let initiate_commit (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
395 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
396 let env = cgi#environment in
398 let errors = MatitaFilesystem.do_global_commit () in
399 prerr_endline ("commit errors: " ^ (String.concat " " errors));
402 ~content_type:"text/xml; charset=\"utf-8\""
404 cgi#out_channel#output_string "<response>ok</response>"
408 ~status:`Internal_server_error
410 ~content_type:"text/xml; charset=\"utf-8\""
412 cgi#out_channel#commit_work()
415 (* returns the length of the executed text and an html representation of the
417 let advance (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
418 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
419 let env = cgi#environment in
421 let sid = Uuidm.of_string (Netcgi.Cookie.value (env#cookie "session")) in
422 let sid = HExtlib.unopt sid in
426 ~content_type:"text/xml; charset=\"utf-8\""
429 let text = cgi#argument_value "body" in
430 (* prerr_endline ("body =\n" ^ text); *)
431 let history = MatitaAuthentication.get_history sid in
432 let parsed_len, new_parsed, new_unparsed, new_status = advance0 sid text in
433 MatitaAuthentication.set_history sid (new_status::history);
434 let txt = output_status new_status in
436 "<response><parsed length=\"" ^ (string_of_int parsed_len) ^ "\">" ^
437 new_parsed ^ "</parsed>" ^ txt
440 (* prerr_endline ("sending advance response:\n" ^ body); *)
443 ~content_type:"text/xml; charset=\"utf-8\""
445 cgi#out_channel#output_string body
449 ~status:`Internal_server_error
451 ~content_type:"text/xml; charset=\"utf-8\""
453 cgi#out_channel#commit_work()
456 let gotoBottom (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
457 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
458 let env = cgi#environment in
460 let sid = Uuidm.of_string (Netcgi.Cookie.value (env#cookie "session")) in
461 let sid = HExtlib.unopt sid in
462 let history = MatitaAuthentication.get_history sid in
464 let rec aux parsed_len parsed_txt text =
466 prerr_endline ("evaluating: " ^ first_line text);
467 let plen,new_parsed,new_unparsed,_new_status = advance0 sid text in
468 aux (parsed_len+plen) (parsed_txt ^ new_parsed) new_unparsed
471 let status = MatitaAuthentication.get_status sid in
472 GrafiteTypes.Serializer.serialize
473 ~baseuri:(NUri.uri_of_string status#baseuri) status;
474 if parsed_len > 0 then
475 MatitaAuthentication.set_history sid (status::history);
476 parsed_len, parsed_txt
477 | _ -> parsed_len, parsed_txt
482 ~content_type:"text/xml; charset=\"utf-8\""
485 let text = cgi#argument_value "body" in
486 (* prerr_endline ("body =\n" ^ text); *)
487 let parsed_len, new_parsed = aux 0 "" text in
488 let status = MatitaAuthentication.get_status sid in
489 let txt = output_status status in
491 "<response><parsed length=\"" ^ (string_of_int parsed_len) ^ "\">" ^
492 new_parsed ^ "</parsed>" ^ txt
496 "<response><parsed length=\"" ^ (string_of_int parsed_len) ^ "\" />" ^ txt
499 (* prerr_endline ("sending goto bottom response:\n" ^ body); *)
502 ~content_type:"text/xml; charset=\"utf-8\""
504 cgi#out_channel#output_string body
505 with Not_found -> cgi#set_header ~status:`Internal_server_error
507 ~content_type:"text/xml; charset=\"utf-8\"" ());
508 cgi#out_channel#commit_work()
511 let retract (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
512 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
513 let env = cgi#environment in
515 let sid = Uuidm.of_string (Netcgi.Cookie.value (env#cookie "session")) in
516 let sid = HExtlib.unopt sid in
520 ~content_type:"text/xml; charset=\"utf-8\""
523 let history = MatitaAuthentication.get_history sid in
524 let new_history,new_status =
526 _::(status::_ as history) ->
528 | [_] -> (prerr_endline "singleton";failwith "retract")
529 | _ -> (prerr_endline "nil"; assert false) in
530 NCicLibrary.time_travel new_status;
531 MatitaAuthentication.set_history sid new_history;
532 MatitaAuthentication.set_status sid new_status;
533 let body = output_status new_status in
536 ~content_type:"text/xml; charset=\"utf-8\""
538 cgi#out_channel#output_string body
539 with _ -> cgi#set_header ~status:`Internal_server_error
541 ~content_type:"text/xml; charset=\"utf-8\"" ());
542 cgi#out_channel#commit_work()
546 let viewLib (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
547 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
548 let env = cgi#environment in
550 let sid = Uuidm.of_string (Netcgi.Cookie.value (env#cookie "session")) in
551 let sid = HExtlib.unopt sid in
555 ~content_type:"text/html; charset=\"utf-8\""
558 let uid = MatitaAuthentication.user_of_session sid in
560 let html = MatitaFilesystem.html_of_library uid in
563 ~content_type:"text/html; charset=\"utf-8\""
565 cgi#out_channel#output_string
568 "<title>XML Tree Control</title>\n" ^
569 "<link href=\"treeview/xmlTree.css\" type=\"text/css\" rel=\"stylesheet\">\n" ^
570 "<script src=\"treeview/xmlTree.js\" type=\"text/javascript\"></script>\n" ^
572 html (* ^ "\n</body></html>" *) );
573 cgi#out_channel#commit_work()
577 let resetLib (cgi : Netcgi1_compat.Netcgi_types.cgi_activation) =
578 let cgi = Netcgi1_compat.Netcgi_types.of_compat_activation cgi in
579 MatitaAuthentication.reset ();
582 ~content_type:"text/html; charset=\"utf-8\""
585 cgi#out_channel#output_string
587 "<title>Matitaweb Reset</title>\n" ^
588 "<body><H1>Reset completed</H1></body></html>");
589 cgi#out_channel#commit_work()
591 open Netcgi1_compat.Netcgi_types;;
593 (**********************************************************************)
594 (* Create the webserver *)
595 (**********************************************************************)
599 let (opt_list, cmdline_cfg) = Netplex_main.args() in
601 let use_mt = ref true in
604 [ "-mt", Arg.Set use_mt,
605 " Use multi-threading instead of multi-processing"
610 (fun s -> raise (Arg.Bad ("Don't know what to do with: " ^ s)))
611 "usage: netplex [options]";
614 Netplex_mt.mt() (* multi-threading *)
616 Netplex_mp.mp() in (* multi-processing *)
619 { Nethttpd_services.dyn_handler = (fun _ -> process1);
620 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
621 dyn_uri = None; (* not needed *)
622 dyn_translator = (fun _ -> ""); (* not needed *)
623 dyn_accept_all_conditionals = false;
627 { Nethttpd_services.dyn_handler = (fun _ -> advance);
628 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
629 dyn_uri = None; (* not needed *)
630 dyn_translator = (fun _ -> ""); (* not needed *)
631 dyn_accept_all_conditionals = false;
634 { Nethttpd_services.dyn_handler = (fun _ -> retract);
635 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
636 dyn_uri = None; (* not needed *)
637 dyn_translator = (fun _ -> ""); (* not needed *)
638 dyn_accept_all_conditionals = false;
641 { Nethttpd_services.dyn_handler = (fun _ -> gotoBottom);
642 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
643 dyn_uri = None; (* not needed *)
644 dyn_translator = (fun _ -> ""); (* not needed *)
645 dyn_accept_all_conditionals = false;
648 { Nethttpd_services.dyn_handler = (fun _ -> retrieve);
649 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
650 dyn_uri = None; (* not needed *)
651 dyn_translator = (fun _ -> ""); (* not needed *)
652 dyn_accept_all_conditionals = false;
655 { Nethttpd_services.dyn_handler = (fun _ -> register);
656 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
657 dyn_uri = None; (* not needed *)
658 dyn_translator = (fun _ -> ""); (* not needed *)
659 dyn_accept_all_conditionals = false;
662 { Nethttpd_services.dyn_handler = (fun _ -> login);
663 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
664 dyn_uri = None; (* not needed *)
665 dyn_translator = (fun _ -> ""); (* not needed *)
666 dyn_accept_all_conditionals = false;
669 { Nethttpd_services.dyn_handler = (fun _ -> logout);
670 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
671 dyn_uri = None; (* not needed *)
672 dyn_translator = (fun _ -> ""); (* not needed *)
673 dyn_accept_all_conditionals = false;
676 { Nethttpd_services.dyn_handler = (fun _ -> viewLib);
677 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
678 dyn_uri = None; (* not needed *)
679 dyn_translator = (fun _ -> ""); (* not needed *)
680 dyn_accept_all_conditionals = false;
683 { Nethttpd_services.dyn_handler = (fun _ -> resetLib);
684 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
685 dyn_uri = None; (* not needed *)
686 dyn_translator = (fun _ -> ""); (* not needed *)
687 dyn_accept_all_conditionals = false;
690 { Nethttpd_services.dyn_handler = (fun _ -> save);
691 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
692 dyn_uri = None; (* not needed *)
693 dyn_translator = (fun _ -> ""); (* not needed *)
694 dyn_accept_all_conditionals = false;
697 { Nethttpd_services.dyn_handler = (fun _ -> initiate_commit);
698 dyn_activation = Nethttpd_services.std_activation `Std_activation_buffered;
699 dyn_uri = None; (* not needed *)
700 dyn_translator = (fun _ -> ""); (* not needed *)
701 dyn_accept_all_conditionals = false;
704 let nethttpd_factory =
705 Nethttpd_plex.nethttpd_factory
706 ~handlers:[ "advance", do_advance
707 ; "retract", do_retract
708 ; "bottom", goto_bottom
710 ; "register", do_register
712 ; "logout", do_logout
713 ; "reset", do_resetlib
714 ; "viewlib", do_viewlib
716 ; "commit", do_commit]
718 MatitaInit.initialize_all ();
719 MatitaAuthentication.deserialize ();
722 Netplex_log.logger_factories (* allow all built-in logging styles *)
723 Netplex_workload.workload_manager_factories (* ... all ways of workload management *)
724 [ nethttpd_factory ] (* make this nethttpd available *)
728 Sys.set_signal Sys.sigpipe Sys.Signal_ignore;