diff --git a/Makefile b/Makefile
index 157f5f9..fd96d2b 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ all: build
build:
cd src && $(MAKE)
+ cp src/search.js ext/js/
install:
cd src && $(MAKE) install
diff --git a/ext/js/search.js b/ext/js/search.js
deleted file mode 120000
index 110dbb6..0000000
--- a/ext/js/search.js
+++ /dev/null
@@ -1 +0,0 @@
-../../src/search.js
\ No newline at end of file
diff --git a/src/o2wMisc.ml b/src/o2wMisc.ml
index c880b08..2400a47 100644
--- a/src/o2wMisc.ml
+++ b/src/o2wMisc.ml
@@ -64,3 +64,10 @@ let string_of_timestamp ?(short = false) time =
Printf.sprintf "%s %d" month_str tm.tm_mday
else
Printf.sprintf "%s %d, %d" month_str tm.tm_mday year
+
+let ident_of_timestamp time =
+ let tm = Unix.gmtime time in
+ let open Unix in
+ let month_str = string_of_month tm.tm_mon in
+ let year = 1900 + tm.tm_year in
+ Printf.sprintf "%d%s%d" year month_str tm.tm_mday
diff --git a/src/o2wMisc.mli b/src/o2wMisc.mli
index 35b969a..20495fb 100644
--- a/src/o2wMisc.mli
+++ b/src/o2wMisc.mli
@@ -27,3 +27,6 @@ val string_of_month: int -> string
(** Return the string representation of a timestamp *)
val string_of_timestamp: ?short:bool -> float -> string
+
+(** Return a fragment identifier for a timestamp *)
+val ident_of_timestamp: float -> string
diff --git a/src/o2wPackage.ml b/src/o2wPackage.ml
index 06aab28..a6e266c 100644
--- a/src/o2wPackage.ml
+++ b/src/o2wPackage.ml
@@ -116,7 +116,11 @@ let to_html ~statistics universe pkg_info =
let pkg_homepage = links "Homepage" (OpamFile.OPAM.homepage pkg_opam) in
let pkg_issues = links "Issue Tracker" (OpamFile.OPAM.bug_reports pkg_opam) in
let pkg_tags = list "Tag" (OpamFile.OPAM.tags pkg_opam) in
- let pkg_published = O2wMisc.string_of_timestamp pkg_info.published in
+ let pkg_published = match pkg_info.published with
+ | None -> None
+ | Some timestamp ->
+ Some ("Published",<:html<$str:O2wMisc.string_of_timestamp timestamp$>>)
+ in
let html_conj = <:html<&>> in
let html_disj = <:html<|>> in
let vset_of_name name =
@@ -354,7 +358,7 @@ let to_html ~statistics universe pkg_info =
>>))
in
<:html<
-
$str: pkg_info.name$
+
@@ -370,18 +374,13 @@ let to_html ~statistics universe pkg_info =
$mk_tr pkg_license$
$mk_tr pkg_homepage$
$mk_tr pkg_issues$
- $mk_tr pkg_tags$
$mk_tr pkg_maintainer$
+ $mk_tr pkg_tags$
$mk_tr pkg_depends$
$mk_tr pkg_depopts$
$mk_tr pkg_compiler$
$mk_tr pkg_os$
-
- Published |
-
- $str: pkg_published$
- |
-
+ $mk_tr pkg_published$
$pkg_url$
$pkg_stats$
$pkg_edit$
diff --git a/src/o2wProject.ml b/src/o2wProject.ml
new file mode 100644
index 0000000..7bdca6a
--- /dev/null
+++ b/src/o2wProject.ml
@@ -0,0 +1,336 @@
+(*
+ * Copyright (c) 2014 David Sheets
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *)
+
+let pkg_href = OpamfUniverse.Pkg.href ~href_base:Uri.(of_string "../")
+
+module Field = struct
+ type t = Author | License | Homepage | Maintainer
+
+ let to_string = function
+ | Author -> "authorship"
+ | License -> "license"
+ | Homepage -> "homepage"
+ | Maintainer -> "maintainership"
+end
+
+module Change = struct
+ type change =
+ | Add of (Field.t * string)
+ | Remove of (Field.t * string)
+ | Change of (Field.t * string * string)
+ type t = {
+ change : change;
+ }
+
+ let to_html = Field.(function
+ | { change = Add ((Author | Maintainer) as p,a) } ->
+ <:html<$str:a$ gained $str:to_string p$.>>
+ | { change = Remove ((Author | Maintainer) as p,a) } ->
+ <:html<$str:a$ lost $str:to_string p$.>>
+ | { change = Change ((Author | Maintainer) as p,a,a') } ->
+ <:html<$str:a$ assumed $str:to_string p$
+ from $str:a'$.>>
+ | { change = Add (License,a) } ->
+ <:htmllicensed under $str:a$.>>
+ | { change = Remove (License,a) } ->
+ <:htmllicensed under $str:a$.>>
+ | { change = Change (License,a,a') } ->
+ <:html<License changed to $str:a$
+ from $str:a'$.>>
+ | { change = Add (Homepage,a) } ->
+ <:html<$str:a$ added as
+ homepage.>>
+ | { change = Remove (Homepage,a) } ->
+ <:html<$str:a$ removed as
+ homepage.>>
+ | { change = Change (Homepage,a,a') } ->
+ <:html<Homepage changed to
+ $str:a$
+ from $str:a'$.>>
+ )
+end
+
+module Event = struct
+ type event =
+ | Published of (OpamPackage.Name.t * OpamPackage.Version.t * Change.t list)
+ type t = {
+ timestamp : float;
+ event : event;
+ }
+
+ let to_html name = function
+ | { timestamp; event = Published (name, version, changes) } ->
+ let href = pkg_href name version in
+ let v = OpamPackage.Version.to_string version in
+ let changes_html = match changes with
+ | [] -> <:html<&>>
+ | _ ->
+ let changes_list = List.map (fun c ->
+ <:html<$Change.to_html c$&>>
+ ) changes in
+ <:html<&>>
+ in
+ <:html<
+
+ $str:O2wMisc.string_of_timestamp timestamp$
+
+ Published
+ version $str: v$
+ $changes_html$
+
+ >>
+end
+
+let to_html ~statistics universe name vset =
+ let open OpamfUniverse in
+ let pname = OpamPackage.Name.of_string name in
+
+ let versions = OpamPackage.Version.(List.sort compare (Set.elements vset)) in
+ let packages = List.rev_map (OpamPackage.create pname) versions in
+
+ let opams = List.rev_map (fun pkg ->
+ OpamPackage.version pkg, OpamPackage.Map.find pkg universe.pkgs_opams
+ ) packages in
+
+ let infos = List.rev_map (fun pkg ->
+ OpamPackage.version pkg, OpamPackage.Map.find pkg universe.pkgs_infos
+ ) packages in
+
+ let versions_from_newest = List.rev versions in
+ let previous_version v =
+ let rec prev = function
+ | version::pv::_ when version = v -> Some pv
+ | _::vs -> prev vs
+ | [_] | [] -> None
+ in
+ prev versions_from_newest
+ in
+
+ let latest_v = OpamPackage.Name.Map.find pname universe.max_versions in
+ let latest_p = OpamPackage.create pname latest_v in
+ let latest = OpamPackage.Map.find latest_p universe.pkgs_infos in
+
+ let version_links =
+ List.map
+ (fun version ->
+ let href = pkg_href pname version in
+ let version = OpamPackage.Version.to_string version in
+ if latest.version = version then
+ <:html<
+ latest $str: version$
+ >>
+ else
+ <:html<$str: version$&>>)
+ versions
+ in
+
+ let mk_tr = function
+ | None -> <:html<&>>
+ | Some (title, contents) ->
+ <:html<
+
+ $str: title$ |
+ $contents$ |
+
+ >> in
+
+ let rec pretty_html_list ?(last="and") = function
+ | [] -> <:html<&>>
+ | [a] -> a
+ | [a;b] -> <:html<$a$ $str: last$ $b$>>
+ | h::t -> <:html<$h$, $pretty_html_list ~last t$>>
+ in
+
+ let v_after_link v = match previous_version v with
+ | None -> <:html<&>>
+ | Some v ->
+ let v_href = pkg_href pname v in
+ let v_str = OpamPackage.Version.to_string v in
+ <:html< (after $str: v_str$)>>
+ in
+
+ let span_list name l : (string * Cow.Xml.t) option = match l with
+ | [] -> None
+ | [e, v] -> Some (name, <:html<$e$$v_after_link v$>>)
+ | l ->
+ let l = List.map (fun (e,v) -> <:html<$e$$v_after_link v$>>) l in
+ Some (name ^ "s", pretty_html_list l)
+ in
+
+ let span_strings name lo = match lo with
+ | None -> None
+ | Some l -> span_list name (List.map (fun (s,v) -> (<:html<$str:s$>>, v)) l)
+ in
+
+ let span_links name lo = match lo with
+ | None -> None
+ | Some l -> span_list name (List.map (fun (s,v) ->
+ (<:html< $str: s$ >>,v))
+ l)
+ in
+
+ let tenure valuevs =
+ let rec prev (value, v) = function
+ | [] -> Some (value, v)
+ | (None, version)::vs -> prev (value, version) vs
+ | (v', version)::vs when v' = value -> prev (value, version) vs
+ | (Some _, _)::_ -> Some (value, v)
+ in
+ match valuevs with [] -> None | v::vs -> prev v vs
+ in
+
+ let tenures lists = List.fold_left (fun m (v, items) -> match m with
+ | None -> Some (List.map (fun i -> (i, v)) items)
+ | Some ts -> Some (List.map (fun (i,late_v) ->
+ (i, if items = [] || List.mem i items then v else late_v)
+ ) ts)
+ ) None lists in
+
+ let opam_field span_fn name field_fn =
+ let items = List.rev_map (fun (v, o) -> (v, field_fn o)) opams in
+ span_fn name (tenures items)
+ in
+
+ let proj_author = opam_field span_strings "Author" OpamFile.OPAM.author in
+
+ let proj_license = opam_field span_strings "License" OpamFile.OPAM.license in
+
+ let proj_homepage = opam_field span_links "Homepage" OpamFile.OPAM.homepage in
+
+ let proj_issues =
+ opam_field span_links "Issue Tracker" OpamFile.OPAM.bug_reports
+ in
+
+ let proj_maintainer =
+ opam_field span_strings "Maintainer" OpamFile.OPAM.maintainer
+ in
+
+ let proj_tags = opam_field span_strings "Tag" OpamFile.OPAM.tags in
+
+ let opam_compiler name field_fn =
+ let valuevs = List.rev_map (fun (v, o) -> (field_fn o, v)) opams in
+ match tenure valuevs with
+ | None | Some (None, _) -> None
+ | Some (Some v, version) ->
+ let formula_str = OpamFormula.(
+ string_of_formula (fun (relop,v) ->
+ (string_of_relop relop)^" "^(OpamCompiler.Version.to_string v)
+ ) v
+ ) in
+ Some (name, <:html<$str:formula_str$$v_after_link version$>>)
+ in
+
+ let opam_os name field_fn =
+ let valuevs = List.rev_map (fun (v, o) -> (Some (field_fn o), v)) opams in
+ OpamFormula.(match tenure valuevs with
+ | None | Some (None, _) | Some (Some Empty, _) -> None
+ | Some (Some f, version) ->
+ let formula_str = string_of_formula (fun (b,s) ->
+ if b then s else "!"^s
+ ) f
+ in
+ Some (name, <:html<$str:formula_str$$v_after_link version$>>)
+ )
+ in
+
+ let proj_compiler = opam_compiler "OCaml" OpamFile.OPAM.ocaml_version in
+
+ let proj_os = opam_os "OS" OpamFile.OPAM.os in
+
+ let module StringSet = Set.Make(String) in
+
+ let set_of_list =
+ List.fold_left (fun set v -> StringSet.add v set) StringSet.empty
+ in
+
+ let list_diff field_t field field' = match field, field' with
+ | [], [] -> []
+ | _, _ ->
+ let a = set_of_list field in
+ let b = set_of_list field' in
+ let removes = StringSet.(elements (diff b a)) in
+ let adds = StringSet.(elements (diff a b)) in
+ match adds, removes with
+ | [a], [r] -> [Change.({ change = Change (field_t, a, r)})]
+ | _, _ ->
+ (List.map
+ (fun v -> Change.({ change = Add (field_t, v) }))
+ adds)
+ @(List.map
+ (fun v -> Change.({ change = Remove (field_t, v) }))
+ removes)
+ in
+
+ let opam_list_diff pkg pkg' field_t field_fn =
+ let opam = OpamPackage.Map.find pkg universe.pkgs_opams in
+ let opam' = OpamPackage.Map.find pkg' universe.pkgs_opams in
+ list_diff field_t (field_fn opam) (field_fn opam')
+ in
+
+ let events = List.fold_left OpamfUniverse.(fun l -> function
+ | _, { published = None } -> l
+ | v, { published = Some timestamp } ->
+ let p = OpamPackage.create pname v in
+ let changes = match previous_version v with
+ | None -> []
+ | Some prev ->
+ let prev = OpamPackage.create pname prev in
+ (opam_list_diff p prev Field.Author OpamFile.OPAM.author)
+ @(opam_list_diff p prev Field.License OpamFile.OPAM.license)
+ @(opam_list_diff p prev Field.Maintainer OpamFile.OPAM.maintainer)
+ @(opam_list_diff p prev Field.Homepage OpamFile.OPAM.homepage)
+ in
+ Event.({ timestamp; event=Published (pname, v, changes) }::l)
+ ) [] infos in
+
+ let proj_events = List.map (fun ev ->
+ <:html<$Event.to_html name ev$
&>>
+ ) events in
+
+ <:html<
+ $str: name$
+
+
+
+
+
+ $list: version_links$
+
+
+
+
$latest.descr$
+
+
+
+ $mk_tr proj_author$
+ $mk_tr proj_license$
+ $mk_tr proj_homepage$
+ $mk_tr proj_issues$
+ $mk_tr proj_maintainer$
+ $mk_tr proj_tags$
+
+ $mk_tr proj_compiler$
+ $mk_tr proj_os$
+
+
+
+
Events
+
+ $list:proj_events$
+
+
+ >>
diff --git a/src/o2wUniverse.ml b/src/o2wUniverse.ml
index 8e09088..548af44 100644
--- a/src/o2wUniverse.ml
+++ b/src/o2wUniverse.ml
@@ -19,32 +19,39 @@ open OpamfUniverse
open Cow.Html
open O2wTypes
-let to_page ~statistics universe pkg pkg_info acc =
- match pkg_info with
- | None ->
- Printf.printf "Skipping %s\n%!" (OpamPackage.to_string pkg);
+let pkg_to_page ~statistics universe pkg pkg_info acc =
+ try
+ let page = {
+ page_source = pkg_info.OpamfUniverse.name;
+ page_link = { Cow.Html.text=pkg_info.title;
+ href=Uri.to_string pkg_info.OpamfUniverse.href };
+ page_depth = 3;
+ page_contents = Template.serialize
+ (O2wPackage.to_html ~statistics universe pkg_info)
+ } in
+ page :: acc
+ with e ->
+ Printf.printf "Skipping %s (%s)\n%!" (OpamPackage.to_string pkg)
+ (Printexc.to_string e);
+ Printexc.print_backtrace stdout;
acc
- | Some pkg_info ->
- try
- let page = {
- page_source = pkg_info.OpamfUniverse.name;
- page_link = { Cow.Html.text=pkg_info.title;
- href=Uri.to_string pkg_info.OpamfUniverse.href };
- page_depth = 3;
- page_contents = Template.serialize
- (O2wPackage.to_html ~statistics universe pkg_info)
- } in
- page :: acc
- with e ->
- Printf.printf "Skipping %s (%s)\n%!" (OpamPackage.to_string pkg)
- (Printexc.to_string e);
- Printexc.print_backtrace stdout;
- acc
-(* Create a list of package pages to generate for a universe *)
-let to_pages ~statistics universe =
+(* Create a list of project and package pages to generate for a universe *)
+let to_pages ~statistics ~prefix universe =
+ let projects = OpamPackage.Name.Map.fold (fun name vset acc ->
+ let name = OpamPackage.Name.to_string name in
+ let href = Filename.(concat prefix (concat name "")) in
+ let page = {
+ page_source = name;
+ page_link = { Cow.Html.text=name; href; };
+ page_depth = 2;
+ page_contents = Template.serialize
+ (O2wProject.to_html ~statistics universe name vset)
+ } in
+ page :: acc
+ ) universe.versions [] in
OpamPackage.Map.fold
- (to_page ~statistics universe) universe.pkgs_infos []
+ (pkg_to_page ~statistics universe) universe.pkgs_infos projects
let sortby_links ~links ~default ~active =
let mk_item title =
@@ -89,7 +96,7 @@ let to_html ~content_dir ~sortby_links ~popularity ~active
let packages_html =
List.fold_left (fun acc pkg ->
let info =
- try OpamPackage.Map.find pkg universe.pkgs_infos
+ try Some (OpamPackage.Map.find pkg universe.pkgs_infos)
with Not_found -> None in
match info with
| None -> acc
@@ -98,22 +105,31 @@ let to_html ~content_dir ~sortby_links ~popularity ~active
try
let d = OpamPackage.Name.Map.find (OpamPackage.name pkg)
popularity in
- Printf.sprintf "Downloads: %Ld | Published: %s"
- d (O2wMisc.string_of_timestamp pkg_info.published)
- with Not_found ->
+ [Printf.sprintf "Downloads: %Ld" d]
+ with Not_found -> []
+ in
+ let pkg_published = match pkg_info.published with
+ | Some timestamp -> [
Printf.sprintf "Published: %s"
- (O2wMisc.string_of_timestamp pkg_info.published)
+ (O2wMisc.string_of_timestamp timestamp)
+ ]
+ | None -> []
in
+ let pkg_tooltip = String.concat " | " (pkg_download @ pkg_published) in
let pkg_href = Uri.(resolve "http"
(of_string "../") pkg_info.OpamfUniverse.href) in
<:html<
-
-
+ |
+
$str: pkg_info.name$
|
- $str: pkg_info.version$ |
+
+
+ $str: pkg_info.version$
+
+ |
$str: pkg_info.synopsis$ |
>> :: acc)
diff --git a/src/o2wUniverse.mli b/src/o2wUniverse.mli
index 6c4ce2f..4cdf04b 100644
--- a/src/o2wUniverse.mli
+++ b/src/o2wUniverse.mli
@@ -20,7 +20,7 @@ open OpamTypes
open O2wTypes
(** Create a list of package pages to generate for a repository *)
-val to_pages: statistics:statistics_set option ->
+val to_pages: statistics:statistics_set option -> prefix:string ->
Cow.Html.t OpamfUniverse.t -> page list
(** Generate the list of HTML links for a list of page names *)
diff --git a/src/opam2web.ml b/src/opam2web.ml
index d65e12d..7b2f687 100644
--- a/src/opam2web.ml
+++ b/src/opam2web.ml
@@ -51,7 +51,9 @@ let make_website user_options universe =
let statistics = O2wStatistics.statistics_set user_options.logfiles in
let content_dir = user_options.content_dir in
Printf.printf "++ Building the package pages.\n%!";
- let pages = O2wUniverse.to_pages ~statistics universe in
+ let pages = O2wUniverse.to_pages
+ ~statistics ~prefix:packages_prefix universe
+ in
Printf.printf "++ Building the documentation pages.\n%!";
let menu_of_doc () = O2wDocumentation.to_menu ~content_dir in
Printf.printf "++ Building the blog.\n%!";
diff --git a/src/opam2web.mllib b/src/opam2web.mllib
index e5fcc55..38efd46 100644
--- a/src/opam2web.mllib
+++ b/src/opam2web.mllib
@@ -8,3 +8,4 @@ Compressed
Lexcombinedlog
O2wGlobals
O2wPackage
+O2wProject
diff --git a/src/template.ml b/src/template.ml
index 925c03d..900572d 100644
--- a/src/template.ml
+++ b/src/template.ml
@@ -1,18 +1,19 @@
-(**************************************************************************)
-(* *)
-(* Copyright 2012-2013 OCamlPro *)
-(* Copyright 2012 INRIA *)
-(* *)
-(* All rights reserved.This file is distributed under the terms of the *)
-(* GNU Lesser General Public License version 3.0 with linking *)
-(* exception. *)
-(* *)
-(* OPAM is distributed in the hope that it will be useful, but WITHOUT *)
-(* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *)
-(* or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public *)
-(* License for more details. *)
-(* *)
-(**************************************************************************)
+(*
+ * Copyright (c) 2013-2014 David Sheets
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *)
type param_prop = Default of Cow.Xml.signal list | Mandatory
type field_prop = Optional | Required
diff --git a/src/template.mli b/src/template.mli
index 2d44bc6..26863b1 100644
--- a/src/template.mli
+++ b/src/template.mli
@@ -1,18 +1,19 @@
-(**************************************************************************)
-(* *)
-(* Copyright 2012-2013 OCamlPro *)
-(* Copyright 2012 INRIA *)
-(* *)
-(* All rights reserved.This file is distributed under the terms of the *)
-(* GNU Lesser General Public License version 3.0 with linking *)
-(* exception. *)
-(* *)
-(* OPAM is distributed in the hope that it will be useful, but WITHOUT *)
-(* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *)
-(* or FITNESS FOR A PARTICULAR PURPOSE.See the GNU General Public *)
-(* License for more details. *)
-(* *)
-(**************************************************************************)
+(*
+ * Copyright (c) 2013 David Sheets
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ *)
type param_prop = Default of Cow.Xml.signal list | Mandatory
type field_prop = Optional | Required