Content-Security-Policy: default-src 'none'
Content-Type: text/plain; charset=UTF-8
Content-Length: 8471
Content-Disposition: inline; filename="footnotes.ml"
Last-Modified: Wed, 22 Jul 2026 13:12:39 GMT
Expires: Sat, 19 Jul 2036 13:12:39 GMT
ETag: "a3ba9cdfd8f41c072bd88114ad11ac905ab26c5f"

open Brr
open Js_of_ocaml
module PM = Prosemirror

let footNoteSpec = object%js

  val mutable group = Jstr.v "inline"
  val mutable content = Jstr.v "inline*" (* The star is very important ! *)
  val mutable inline = Js._true
  val mutable draggable = Js._true
  (*  This makes the view treat the node as a leaf, even though it
      technically has content *)
  val mutable atom = Js._true

  val toDOM
    : (PM.Model.node Js.t -> PM.Model.domOutputSpec Js.t) Js.callback
    = Js.wrap_callback (fun _ ->
        let open PM.Model.Dom_output_spec in
        v "footnote"
          [ hole ])

  val parseDOM
    : PM.Model.parse_rule Js.t Js.js_array Js.t Js.opt
    = Js.some @@ Js.array
      [|PM.Model.ParseRule.tag (Jstr.v "footnote")|]

end

let footnote_schema pm defaultSchema =

  let nodes = defaultSchema##.spec##.nodes
  and marks = defaultSchema##.spec##.marks in

  let specs = PM.Model.schema_spec
      (nodes##addToEnd (Jstr.v "footnote") (Js.Unsafe.coerce footNoteSpec))
      (Some marks)
      None in

  PM.Model.schema pm
    specs

let build_menu pm schema =
  let menu = PM.Example.buildMenuItems pm schema in

  let itemSpec = PM.Menu.menuItemSpec () in
  itemSpec##.title := Js.some @@ Jstr.v "Insert footnote";
  itemSpec##.label := Js.some @@ Jstr.v "Footnote";
  itemSpec##.select := Js.wrap_meth_callback (fun _ (state:PM.State.editor_state Js.t) ->
      match PM.O.get schema##.nodes "footnote" with
      | None ->  Js._false
      | Some footnote_node ->
        let res = Js.Opt.test @@ PM.Transform.insertPoint
            pm
            state##.doc
            ~pos:state##.selection##.from
            footnote_node
        in
        Js.bool res);

  itemSpec##.run :=
    Js.wrap_meth_callback (fun _this state dispatch _ _ ->
        match PM.O.get schema##.nodes "footnote" with
        | None -> ()
        | Some footnote_node ->

          let from' = PM.State.selection_from state##.selection
          and to' = PM.State.selection_to state##.selection in

          let content =
            if state##.selection##.empty != Js._true
            && from'##sameParent to' = Js._true
            && from'##.parent##.inlineContent = Js._true then (
              from'##.parent##.content##cut
                (from'##.parentOffset)
                (Js.some @@ to'##.parentOffset)
            ) else (
              PM.Model.empty_fragment pm
            ) in
          let new_node = footnote_node##create_withFragmentContent
              Js.null
              (Js.some content)
              Js.null
          in
          dispatch @@
          state##.tr##replaceSelectionWith
            new_node
            Js.null
      );

  let item = PM.Menu.menu_item pm itemSpec in
  let _ = menu##.insertMenu##.content##push item in
  menu

let fromOutside
  : bool PM.State.meta_data Js.t
  = PM.State.create_str_meta_data (Jstr.v "fromOutside")

let footnote_view
  : PM.t -> PM.Model.node Js.t -> PM.View.editor_view Js.t -> (unit -> int) -> < .. > Js.t
  = fun pm init_node outerView get_pos ->

    (* These are used when the footnote is selected *)
    let innerView
      : PM.View.editor_view Js.t Js.opt ref
      = ref Js.null in

    let dispatchInner
      : PM.View.editor_view Js.t -> PM.State.transaction Js.t -> unit
      = fun view tr ->
        let res = view##.state##applyTransaction tr in
        view##updateState res##.state;

        let meta = Js.Optdef.get (tr##getMeta fromOutside) (fun () -> false) in
        if (not meta) then (
          let outerTr = outerView##.state##.tr
          and offsetMap = PM.Transform.offset pm ((get_pos()) + 1) in
          res##.transactions##forEach
            (Js.wrap_callback @@
             fun (elem:PM.State.transaction Js.t) _ _ ->
             elem##.steps##forEach
               (Js.wrap_callback @@ fun (step:PM.Transform.step Js.t) _ _ ->
                let _ = outerTr##step (step##map offsetMap) in
                ()
               ));
          if (outerTr##.docChanged = Js._true) then (
            outerView##dispatch outerTr)
        );
    in
    object%js (_self)

      val mutable node: PM.Model.node Js.t = init_node

      (* The node's representation in the editor (empty, for now) *)
      val dom = El.v (Jstr.v "footnote") []

      method _open =
        (* Append a tooltip to the outer node *)
        let tooltip = El.div []
            ~at:At.([class' (Jstr.v "footnote-tooltip")]) in
        El.append_children _self##.dom
          [ tooltip ];

        let dispatch_fn
          : PM.State.transaction Js.t -> unit
          = fun tr -> outerView##dispatch tr in

        let state_properties = Js.Unsa<style>pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */</style><div class="highlight"><pre><span></span><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
<span class="cp">&lt;!DOCTYPE html&gt;</span>
<span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">DEFAULT_LANG</span> <span class="cp">}}</span><span class="s">&quot;</span> <span class="na">xmlns</span><span class="o">=</span><span class="s">&quot;http://www.w3.org/1999/xhtml&quot;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
  <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}{{</span> <span class="nv">SITENAME</span> <span class="cp">}}{%</span><span class="k">endblock</span><span class="cp">%}</span><span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
  <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">http-equiv</span><span class="o">=</span><span class="s">&quot;Content-Type&quot;</span> <span class="na">content</span><span class="o">=</span><span class="s">&quot;text/html; charset=utf-8&quot;</span> <span class="p">/&gt;</span>
  <span class="p">&lt;</span><span class="nt">link</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;stylesheet&quot;</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;/theme/css/</span><span class="cp">{{</span> <span class="nv">CSS_FILE</span> <span class="cp">}}</span><span class="s">&quot;</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;text/css&quot;</span> <span class="p">/&gt;</span>
  <span class="p">&lt;</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/feeds/all.atom.xml&quot;</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;application/atom+xml&quot;</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;alternate&quot;</span> <span class="na">title</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="s"> - Flux ATOM&quot;</span> <span class="p">/&gt;</span>
  <span class="cp">{%</span> <span class="k">if</span> <span class="nv">tag</span> <span class="cp">%}</span>
    <span class="cp">{%</span> <span class="k">if</span> <span class="nv">TAG_FEED_ATOM</span> <span class="cp">%}</span>
    <span class="p">&lt;</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/</span><span class="cp">{{</span> <span class="nv">TAG_FEED_ATOM</span> <span class="o">%</span> <span class="nv">tag</span><span class="o">|</span><span class="nf">e</span><span class="o">|</span><span class="nf">lower</span> <span class="cp">}}</span><span class="s">&quot;</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;application/atom+xml&quot;</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;alternate&quot;</span> <span class="na">title</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="s"> » </span><span class="cp">{{</span> <span class="nv">tag</span><span class="o">|</span><span class="nf">e</span> <span class="cp">}}</span><span class="s"> - Flux ATOM&quot;</span> <span class="p">/&gt;</span>
    <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
    <span class="cp">{%</span> <span class="k">if</span> <span class="nv">TAG_FEED_RSS</span> <span class="cp">%}</span>
    <span class="p">&lt;</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/</span><span class="cp">{{</span> <span class="nv">TAG_FEED_RSS</span> <span class="o">%</span> <span class="nv">tag</span><span class="o">|</span><span class="nf">e</span><span class="o">|</span><span class="nf">lower</span> <span class="cp">}}</span><span class="s">&quot;</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;application/rss+xml&quot;</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;alternate&quot;</span> <span class="na">title</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="s"> » </span><span class="cp">{{</span> <span class="nv">tag</span> <span class="cp">}}</span><span class="s"> - Flux RSS&quot;</span> <span class="p">/&gt;</span>
    <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
  <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>

  <span class="cp">{%</span> <span class="k">if</span> <span class="nv">category</span>  <span class="cp">%}</span>
    <span class="cp">{%</span> <span class="k">if</span> <span class="nv">CATEGORY_FEED_ATOM</span> <span class="cp">%}</span>
    <span class="p">&lt;</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/</span><span class="cp">{{</span> <span class="nv">CATEGORY_FEED_ATOM</span> <span class="o">%</span> <span class="nv">category</span><span class="o">|</span><span class="nf">lower</span> <span class="cp">}}</span><span class="s">&quot;</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;application/atom+xml&quot;</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;alternate&quot;</span> <span class="na">title</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="s"> » </span><span class="cp">{{</span> <span class="nv">category</span><span class="o">|</span><span class="nf">e</span> <span class="cp">}}</span><span class="s"> - Flux ATOM&quot;</span> <span class="p">/&gt;</span>
    <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
    <span class="cp">{%</span> <span class="k">if</span> <span class="nv">CATEGORY_FEED_RSS</span> <span class="cp">%}</span>
    <span class="p">&lt;</span><span class="nt">link</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITEURL</span> <span class="cp">}}</span><span class="s">/</span><span class="cp">{{</span> <span class="nv">CATEGORY_FEED_RSS</span> <span class="o">%</span> <span class="nv">category</span><span class="o">|</span><span class="nf">lower</span> <span class="cp">}}</span><span class="s">&quot;</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;application/rss+xml&quot;</span> <span class="na">rel</span><span class="o">=</span><span class="s">&quot;alternate&quot;</span> <span class="na">title</span><span class="o">=</span><span class="s">&quot;</span><span class="cp">{{</span> <span class="nv">SITENAME</span> <span class="cp">}}</span><span class="s"> » </span><span class="cp">{{</span> <span class="nv">category</span><span class="o">|</span><span class="nf">e</span> <span class="cp">}}</span><span class="s"> - Flux RSS&quot;</span> <span class="p">/&gt;</span>
    <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
  <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>

  <span class="cp">{%</span> <span class="k">if</span> <span class="nv">GOOGLE_ANALYTICS</span> <span class="cp">%}</span>
  <span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;text/javascript&quot;</span><span class="p">&gt;</span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">gaJsHost</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">((</span><span class="s2">&quot;https:&quot;</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">protocol</span><span class="p">)</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="s2">&quot;https://ssl.&quot;</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="s2">&quot;http://www.&quot;</span><span class="p">);</span>
<span class="w">    </span><span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">unescape</span><span class="p">(</span><span class="s2">&quot;%3Cscript src=&#39;&quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">gaJsHost</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s2">&quot;google-analytics.com/ga.js&#39; type=&#39;text/javascript&#39;%3E%3C/script%3E&quot;</span><span class="p">));</span>
<span class="w">    </span><span class="p">&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="nt">script</span> <span class="na">type</span><span class="o">=</span><span class="s">&quot;text/javascript&quot;</span><span class="p">&gt;</span>
<span class="w">    </span><span class="k">try</span><span class="w"> </span><span class="p">{</span>
<span class="w">        </span><span class="kd">var</span><span class="w"> </span><span class="nx">pageTracker</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">_gat</span><span class="p">.</span><span class="nx">_getTracker</span><span class="p">(</span><span class="s2">&quot;</span><span class="cp">{{</span><span class="nv">GOOGLE_ANALYTICS</span><span class="cp">}}</span><span class="s2">&quot;</span><span class="p">);</span>
<span class="w">    </span><span class="nx">pageTracker</span><span class="p">.</span><span class="nx">_trackPageview</span><span class="p">();</span>
<span class="w">    </span><span class="p">}</span><span class="w"> </span><span class="k">catch</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"> </span><span class="p">{}&lt;/</span><span class="nt">script</span><span class="p">&gt;</span>
  <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
<span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">div</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;page&quot;</span><span class="p">&gt;</span>

<span class="cp">{%</span> <span class="k">include</span> <span class="s1">&#39;header.html&#39;</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">include</span> <span class="s1">&#39;menu.html&#39;</span> <span class="cp">%}</span>

  <span class="p">&lt;</span><span class="nt">section</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;content&quot;</span><span class="p">&gt;</span>
<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span>
<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
  <span class="p">&lt;/</span><span class="nt">section</span><span class="p">&gt;</span> <span class="cm">&lt;!-- /#content --&gt;</span>

  <span class="p">&lt;</span><span class="nt">footer</span> <span class="na">id</span><span class="o">=</span><span class="s">&quot;footer&quot;</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>Propulsé par <span class="p">&lt;</span><span class="nt">a</span> <span class="na">href</span><span class="o">=</span><span class="s">&quot;http://getpelican.com/&quot;</span><span class="p">&gt;</span>Pelican<span class="p">&lt;/</span><span class="nt">a</span><span class="p">&gt;</span>.<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
  <span class="p">&lt;/</span><span class="nt">footer</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span> <span class="cm">&lt;!-- /#page --&gt;</span>
<span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</pre></div>
</code></pre></td></tr></table>
</div> <!-- class=content -->
<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.2.3</a> (<a href='https://git-scm.com/'>git 2.46.0</a>) at 2026-07-22 13:12:39 +0000</div>
</div> <!-- id=cgit -->
</body>
</html>
