diff --git a/README.md b/README.md index ca7b9aa..73867b8 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ including: See https://c-cube.github.io/printbox/ +See the [test/](test/) and [examples/](examples/) directories for illustrations of potential usage. + ## License BSD-2-clauses diff --git a/dune-project b/dune-project index 7329786..020d80a 100644 --- a/dune-project +++ b/dune-project @@ -47,3 +47,17 @@ Printbox allows to print nested boxes, lists, arrays, tables in several formats" (printbox-html (and (= :version))) (odoc :with-test) (mdx (and (>= 1.4) :with-test)))) + +(package + (name printbox-ext-plot) +(synopsis "Printbox extension for plotting") +(description " +Extends Printbox with the ability to print scatter plots, line plots, decision boundaries. +Printbox allows to print nested boxes, lists, arrays, tables in several formats") + (depends (printbox (= :version)) + (printbox-text (and (= :version))) + (printbox-html (and (= :version))) + (printbox-md (and (= :version))) + (tyxml (>= 4.3)) + (odoc :with-test) + (mdx (and (>= 1.4) :with-test)))) diff --git a/printbox-ext-plot.opam b/printbox-ext-plot.opam new file mode 100644 index 0000000..d5aa992 --- /dev/null +++ b/printbox-ext-plot.opam @@ -0,0 +1,39 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +version: "0.11" +synopsis: "Printbox extension for plotting" +description: """ + +Extends Printbox with the ability to print scatter plots, line plots, decision boundaries. +Printbox allows to print nested boxes, lists, arrays, tables in several formats""" +maintainer: ["c-cube" "lukstafi"] +authors: ["Simon Cruanes" "Guillaume Bury" "lukstafi"] +license: "BSD-2-Clause" +homepage: "https://github.com/c-cube/printbox" +bug-reports: "https://github.com/c-cube/printbox/issues" +depends: [ + "dune" {>= "3.0"} + "printbox" {= version} + "printbox-text" {= version} + "printbox-html" {= version} + "printbox-md" {= version} + "tyxml" {>= "4.3"} + "odoc" {with-test} + "mdx" {>= "1.4" & with-test} + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/c-cube/printbox.git" diff --git a/src/PrintBox.ml b/src/PrintBox.ml index 25ea16c..97bb73a 100644 --- a/src/PrintBox.ml +++ b/src/PrintBox.ml @@ -38,6 +38,8 @@ module Style = struct let fg_color c : t = set_fg_color c default end +type ext = .. + type view = | Empty | Text of { @@ -64,6 +66,10 @@ type view = id: string; inner: t; } + | Ext of { + key: string; + ext: ext; + } and t = view @@ -203,6 +209,7 @@ let mk_tree ?indent f root = let link ~uri inner : t = Link { uri; inner } let anchor ~id inner : t = Anchor { id; inner } +let extension ~key ext = Ext { key; ext } (** {2 Simple Structural Interface} *) @@ -219,6 +226,7 @@ module Simple = struct | `Table of t array array | `Tree of t * t list ] + (** The simple interface does not support extensions. *) let rec to_box = function | `Empty -> empty diff --git a/src/PrintBox.mli b/src/PrintBox.mli index 1cde757..d298c56 100644 --- a/src/PrintBox.mli +++ b/src/PrintBox.mli @@ -103,6 +103,12 @@ type t (** Main type for a document composed of nested boxes. @since 0.2 the type [t] is opaque *) +type ext = .. +(** Extensions of the representation. + + @since NEXT_RELEASE +*) + (** The type [view] can be used to observe the inside of the box, now that [t] is opaque. @@ -137,6 +143,10 @@ type view = private id: string; inner: t; } + | Ext of { + key: string; + ext: ext; + } val view : t -> view (** Observe the content of the box. @@ -317,6 +327,12 @@ val anchor : id:string -> t -> t @since 0.11 *) +val extension : key:string -> ext -> t +(** [extension ~key ext] embeds an extended representation [ext] as a box. [ext] must be + recognized by the used backends as an extension registered under [key]. + @since NEXT_RELEASE +*) + (** {2 Styling combinators} *) val line_with_style : Style.t -> string -> t diff --git a/src/printbox-ext-plot/PrintBox_ext_plot.ml b/src/printbox-ext-plot/PrintBox_ext_plot.ml new file mode 100644 index 0000000..41691de --- /dev/null +++ b/src/printbox-ext-plot/PrintBox_ext_plot.ml @@ -0,0 +1,428 @@ +open Tyxml +module B = PrintBox +module H = Html + +type plot_spec = + | Scatterplot of { + points: (float * float) array; + content: B.t; + } + | Scatterbag of { points: ((float * float) * B.t) array } + | Line_plot of { + points: float array; + content: B.t; + } + | Boundary_map of { + callback: float * float -> bool; + content_true: B.t; + content_false: B.t; + } + | Map of { callback: float * float -> B.t } + | Line_plot_adaptive of { + callback: float -> float; + cache: (float, float) Hashtbl.t; + content: B.t; + } +[@@deriving sexp_of] + +type graph = { + specs: plot_spec list; + x_label: string; + y_label: string; + size: int * int; + axes: bool; + prec: int; +} + +let default_config = + { + specs = []; + x_label = "x"; + y_label = "y"; + size = 800, 800; + axes = true; + prec = 3; + } + +type PrintBox.ext += Plot of graph + +let box graph = B.extension ~key:"Plot" (Plot graph) + +let plot_canvas ?canvas ?(size : (int * int) option) ?(sparse = false) + (specs : plot_spec list) = + (* Unfortunately "x" and "y" of a "matrix" are opposite to how we want them displayed -- + the first dimension (i.e. "x") as the horizontal axis. *) + let (dimx, dimy, canvas) : int * int * (int * B.t) list array array = + (* The integer in the cells is the priority number: lower number = more visible. *) + match canvas, size with + | None, None -> invalid_arg "PrintBox_ext_plot.plot: provide ~canvas or ~size" + | None, Some (dimx, dimy) -> dimx, dimy, Array.make_matrix dimy dimx [] + | Some canvas, None -> + let dimy = Array.length canvas in + let dimx = Array.length canvas.(0) in + dimx, dimy, canvas + | Some canvas, Some (dimx, dimy) -> + assert (dimy = Array.length canvas); + assert (dimx = Array.length canvas.(0)); + dimx, dimy, canvas + in + let all_x_points = + specs + |> List.map (function + | Scatterplot { points; _ } -> Array.map fst points + | Scatterbag { points } -> Array.map (fun ((x, _), _) -> x) points + | Line_plot _ -> [||] + | Map _ | Boundary_map _ -> [||] + | Line_plot_adaptive _ -> [||]) + |> Array.concat + in + let given_y_points = + specs + |> List.map (function + | Scatterplot { points; _ } -> Array.map snd points + | Scatterbag { points } -> Array.map (fun ((_, y), _) -> y) points + | Line_plot { points; _ } -> points + | Map _ | Boundary_map _ -> [||] + | Line_plot_adaptive _ -> [||]) + |> Array.concat + in + let minx = + if all_x_points = [||] then + 0. + else + Array.fold_left min all_x_points.(0) all_x_points + in + let maxx = + if given_y_points = [||] then + 1. + else if all_x_points = [||] then + Float.of_int (Array.length given_y_points - 1) + else + Array.fold_left max all_x_points.(0) all_x_points + in + let spanx = maxx -. minx in + let spanx = + if spanx <= epsilon_float then + 1.0 + else + spanx + in + let scale_x x = Float.(to_int (of_int (dimx - 1) *. (x -. minx) /. spanx)) in + let unscale_x i = Float.(of_int i *. spanx /. of_int (dimx - 1)) +. minx in + let extra_y_points = + specs + |> List.map (function + | Line_plot_adaptive { callback; cache; _ } -> + Array.init + (if sparse then + dimx / 5 + else + dimx) + (fun i -> + let x = + unscale_x + (if sparse then + i * 5 + else + i) + in + let y = + match Hashtbl.find_opt cache x with + | Some y -> y + | None -> callback x + in + if not (Hashtbl.mem cache x) then Hashtbl.add cache x y; + y) + | _ -> [||]) + |> Array.concat + in + let all_y_points = Array.append given_y_points extra_y_points in + let miny = + if all_y_points = [||] then + 0. + else + Array.fold_left min all_y_points.(0) all_y_points + in + let maxy = + if all_y_points = [||] then + maxx -. minx + else + Array.fold_left max all_y_points.(0) all_y_points + in + let spany = maxy -. miny in + let spany = + if spany <= epsilon_float then + 1.0 + else + spany + in + let scale_1d y = + try Some Float.(to_int @@ (of_int (dimy - 1) *. (y -. miny) /. spany)) + with Invalid_argument _ -> None + in + let scale_2d (x, y) = + try + Some Float.(scale_x x, to_int (of_int (dimy - 1) *. (y -. miny) /. spany)) + with Invalid_argument _ -> None + in + let spread ~i ~dmj = + if sparse then + i mod 10 = 0 && dmj mod 10 = 0 + else + true + in + let update ~i ~dmj px = + if i >= 0 && dmj >= 0 && i < dimx && dmj < dimy then + canvas.(dmj).(i) <- px :: canvas.(dmj).(i) + in + let prerender_scatter ~priority points = + Array.iter + (fun (p, content) -> + match scale_2d p with + | Some (i, j) -> update ~i ~dmj:(dimy - 1 - j) (priority, content) + | None -> ()) + points + in + let prerender_map ~priority callback = + canvas + |> Array.iteri (fun dmj -> + Array.iteri (fun i _ -> + if spread ~i ~dmj then ( + let x = + Float.(of_int i *. spanx /. of_int (dimx - 1)) +. minx + in + let y = + Float.(of_int (dimy - 1 - dmj) *. spany /. of_int (dimy - 1)) + +. miny + in + update ~i ~dmj (priority, callback (x, y)) + ))) + in + specs + |> List.iteri (fun priority -> function + | Scatterplot { points; content } -> + prerender_scatter ~priority (Array.map (fun p -> p, content) points) + | Scatterbag { points } -> prerender_scatter ~priority points + | Line_plot { points; content } -> + let points = Array.map scale_1d points in + let npoints = Float.of_int (Array.length points) in + let rescale_x i = + Float.(to_int @@ (of_int i *. of_int dimx /. npoints)) + in + (* TODO: implement interpolation if not enough points. *) + points + |> Array.iteri (fun i -> + Option.iter (fun j -> + update ~i:(rescale_x i) + ~dmj:(dimy - 1 - j) + (priority, content))) + | Boundary_map { callback; content_true; content_false } -> + prerender_map ~priority (fun point -> + if callback point then + content_true + else + content_false) + | Map { callback } -> prerender_map ~priority callback + | Line_plot_adaptive { callback; cache; content } -> + canvas.(0) + |> Array.iteri (fun i _ -> + if (not sparse) || i mod 5 = 0 then ( + let x = unscale_x i in + let y = + match Hashtbl.find_opt cache x with + | Some y -> y + | None -> + let y = callback x in + Hashtbl.add cache x y; + y + in + scale_1d y + |> Option.iter (fun j -> + update ~i ~dmj:(dimy - 1 - j) (priority, content)) + ))); + minx, miny, maxx, maxy, canvas + +let concise_float = ref (fun ~prec -> Printf.sprintf "%.*g" prec) + +let plot ~prec ~axes ?canvas ?size ~x_label + ~y_label ~sparse embed_canvas specs = + let minx, miny, maxx, maxy, canvas = + plot_canvas ?canvas ?size ~sparse specs + in + let open PrintBox in + let y_label_l = + List.map Char.escaped @@ List.of_seq @@ String.to_seq y_label + in + if not axes then + embed_canvas canvas + else + grid_l + [ + [ + hlist ~bars:false + [ + align ~h:`Left ~v:`Center @@ lines y_label_l; + vlist ~bars:false + [ + line @@ !concise_float ~prec maxy; + align_bottom @@ line @@ !concise_float ~prec miny; + ]; + ]; + embed_canvas canvas; + ]; + [ + empty; + vlist ~bars:false + [ + hlist ~bars:false + [ + line @@ !concise_float ~prec minx; + align_right @@ line @@ !concise_float ~prec maxx; + ]; + align ~h:`Center ~v:`Bottom @@ line x_label; + ]; + ]; + ] + +let scale_size_for_text = ref (0.125, 0.05) + +let explode s = + let s_len = String.length s in + let rec loop pos = + let char_len = ref 1 in + let cur_len () = PrintBox_text.str_display_width s pos !char_len in + while pos + !char_len <= s_len && cur_len () = 0 do + incr char_len + done; + if cur_len () > 0 then + String.sub s pos !char_len :: loop (pos + !char_len) + else + [] + in + loop 0 + +let flatten_text_canvas ~num_specs canvas = + let outputs = + B.map_matrix + (fun bs -> + (* Fortunately, PrintBox_text does not insert \r by itself. *) + List.map + (fun (prio, b) -> + let lines = + String.split_on_char '\n' @@ PrintBox_text.to_string b + in + prio, List.map explode lines) + bs) + canvas + in + let dimj = Array.length canvas in + let dimi = Array.length canvas.(0) in + let canvas = Array.make_matrix dimj dimi (num_specs, " ") in + let update ~i ~j (prio, box) = + if i >= 0 && i < dimi && j >= 0 && j < dimj then + List.iteri + (fun dj -> + List.iteri (fun di char -> + let j' = j + dj and i' = i + di in + if i' >= 0 && i' < dimi && j' >= 0 && j' < dimj then ( + let old_prio, _ = canvas.(j').(i') in + if prio <= old_prio then canvas.(j').(i') <- prio, char + ))) + box + in + Array.iteri + (fun j row -> + Array.iteri + (fun i boxes -> List.iter (fun box -> update ~i ~j box) boxes) + row) + outputs; + Array.map + (fun row -> String.concat "" @@ List.map snd @@ Array.to_list row) + canvas + +let text_based_handler ~render ext = + match ext with + | Plot { specs; x_label; y_label; size = sx, sy; axes; prec } -> + let cx, cy = !scale_size_for_text in + let size = + Float.(to_int @@ (cx *. of_int sx), to_int @@ (cy *. of_int sy)) + in + render + (B.frame + @@ plot ~prec ~axes ~size ~x_label ~y_label ~sparse:false + (fun canvas -> + B.lines @@ Array.to_list + @@ flatten_text_canvas ~num_specs:(List.length specs) canvas) + specs) + | _ -> invalid_arg "PrintBox_ext_plot.text_handler: unrecognized extension" + +let text_handler = text_based_handler ~render:PrintBox_text.to_string + +let md_handler config = + text_based_handler ~render:(PrintBox_md.to_string config) + +let embed_canvas_html ~num_specs canvas = + let size_y = Array.length canvas in + let size_x = Array.length canvas.(0) in + let cells = + canvas + |> Array.mapi (fun y row -> + row + |> Array.mapi (fun x cell -> + List.map + (fun (priority, cell) -> + let is_framed = + match PrintBox.view cell with + | B.Frame _ | B.Grid (`Bars, _) -> true + | _ -> false + in + let frame = + if is_framed then + ";background-color:rgba(255,255,255,1)" + else + "" + in + let z_index = + ";z-index:" ^ Int.to_string (num_specs - priority) + in + let cell = + PrintBox_html.((to_html cell :> toplevel_html)) + in + H.div + ~a: + [ + H.a_style + ("position:absolute;top:" ^ Int.to_string y + ^ "px;left:" ^ Int.to_string x ^ "px" ^ z_index + ^ frame); + ] + [ cell ]) + cell) + |> Array.to_list |> List.concat) + in + let result = + Array.to_list cells |> List.concat + |> H.div + ~a: + [ + H.a_style @@ "border:thin dotted;position:relative;width:" + ^ Int.to_string size_x ^ ";height:" ^ Int.to_string size_y; + ] + in + PrintBox_html.embed_html result + +let html_handler config ext = + match ext with + | Plot { specs; x_label; y_label; size; axes; prec } -> + (PrintBox_html.to_html ~config + (B.frame + @@ plot ~prec ~axes ~size ~x_label ~y_label ~sparse:true + (embed_canvas_html ~num_specs:(List.length specs)) + specs) + :> PrintBox_html.toplevel_html) + | _ -> invalid_arg "PrintBox_ext_plot.html_handler: unrecognized extension" + +let () = + PrintBox_text.register_extension ~key:"Plot" text_handler; + PrintBox_md.register_extension ~key:"Plot" md_handler; + PrintBox_html.register_extension ~key:"Plot" html_handler diff --git a/src/printbox-ext-plot/PrintBox_ext_plot.mli b/src/printbox-ext-plot/PrintBox_ext_plot.mli new file mode 100644 index 0000000..1fed378 --- /dev/null +++ b/src/printbox-ext-plot/PrintBox_ext_plot.mli @@ -0,0 +1,75 @@ +(* This file is free software. See file "license" for more details. *) + +(** {1 Extend {!PrintBox.t} with plots of scatter graphs and line graphs} *) + +(** Specifies a layer of plotting to be rendered on a graph, where all layers share + the same coordinate space. A coordinate pair has the horizontal position first. *) +type plot_spec = + | Scatterplot of { + points: (float * float) array; + content: PrintBox.t; + } (** Places the [content] box at each of the [points] coordinates. *) + | Scatterbag of { points: ((float * float) * PrintBox.t) array } + (** For each element of [points], places the given box at the given coordinates. *) + | Line_plot of { + points: float array; + content: PrintBox.t; + } + (** Places the [content] box at vertical coordinates [points], + evenly horizontally spread. *) + | Boundary_map of { + callback: float * float -> bool; + content_true: PrintBox.t; + content_false: PrintBox.t; + } + (** At evenly and densely spread coordinates across the graph, places either + [content_true] or [content_false], depending on the result of [callback]. *) + | Map of { callback: float * float -> PrintBox.t } + (** At evenly and densely spread coordinates across the graph, places the box + returned by [callback]. *) + | Line_plot_adaptive of { + callback: float -> float; + cache: (float, float) Hashtbl.t; + content: PrintBox.t; + } + (** At evenly and densely spread horizontal coordinates, places the [content] box + at the vertical coordinate returned by [callback] for the horizontal coordinate + of the placement position. *) +[@@deriving sexp_of] + +type graph = { + specs: plot_spec list; + (** Earlier plots in the list take precedence: in case of overlap, their contents + are on top. For HTML, we ensure that framed boxes and grids with bars are opaque. *) + x_label: string; (** Horizontal axis label. *) + y_label: string; (** Vertical axis label. *) + size: int * int; + (** Size of the graphing area in pixels. Scale for characters is configured by + {!scale_size_for_text}. *) + axes: bool; + (** If false, only the graphing area is output (skipping the axes box). *) + prec: int; (** Precision for numerical labels on axes. *) +} +(** A graph of plot layers, with a fixed rendering size but a coordinate window + that adapts to the specified points. *) + +val default_config : graph +(** A suggested configuration for plotting, with intended use: + [Plot {default_config with specs = ...; ...}]. The default values are: + [{ specs = []; x_label = "x"; y_label = "y"; size = 800, 800; axes = true; prec = 3 }] *) + +type PrintBox.ext += + | Plot of graph + (** PrintBox extension for plotting: scatterplots, linear graphs, decision boundaries... + See {!graph} and {!plot_spec} for details. *) + +val box : graph -> PrintBox.t +(** [box graph] is the same as [PrintBox.extension ~key:"Plot" (Plot graph)]. *) + +val concise_float : (prec:int -> float -> string) ref +(** The conversion function for labeling axes. Defaults to [sprintf "%.*g"]. *) + +val scale_size_for_text : (float * float) ref +(** To provide a unified experience across the text and html backends, we treat + the size specification as measured in pixels, and scale it by [!scale_size_for_text] + to get a size measured in characters. The default value is [(0.125, 0.05)]. *) diff --git a/src/printbox-ext-plot/dune b/src/printbox-ext-plot/dune new file mode 100644 index 0000000..28bc1d1 --- /dev/null +++ b/src/printbox-ext-plot/dune @@ -0,0 +1,7 @@ +(library + (name printbox_ext_plot) + (public_name printbox-ext-plot) + (wrapped false) + (modules PrintBox_ext_plot) + (flags :standard -w +a-3-4-44-29 -safe-string) + (libraries printbox tyxml printbox-text printbox-html printbox-md)) diff --git a/src/printbox-html/PrintBox_html.ml b/src/printbox-html/PrintBox_html.ml index 939349a..1f6e093 100644 --- a/src/printbox-html/PrintBox_html.ml +++ b/src/printbox-html/PrintBox_html.ml @@ -7,6 +7,8 @@ module B = PrintBox module H = Html type 'a html = 'a Html.elt +type toplevel_html = Html_types.li_content_fun html +type PrintBox.ext += Embed_html of toplevel_html let prelude = let l = @@ -105,6 +107,16 @@ module Config = struct let tree_summary x c = { c with tree_summary = x } end +let extensions : (string, Config.t -> PrintBox.ext -> toplevel_html) Hashtbl.t = + Hashtbl.create 4 + +let register_extension ~key handler = + if Hashtbl.mem extensions key then + invalid_arg @@ "PrintBox_html.register_extension: already registered " ^ key; + Hashtbl.add extensions key handler + +let embed_html html = B.extension ~key:"Embed_html" (Embed_html html) + let sep_spans sep l = let len = List.length l in List.concat @@ -201,7 +213,7 @@ let to_html_rec ~config (b : B.t) = (match B.view inner with | B.Empty -> H.a ~a:[ H.a_id id ] [] | _ -> raise Summary_not_supported) - | B.Tree _ | B.Link _ -> raise Summary_not_supported + | B.Tree _ | B.Link _ | B.Ext _ -> raise Summary_not_supported in let loop : 'tags. @@ -243,8 +255,9 @@ let to_html_rec ~config (b : B.t) = | B.Tree (_, b, l) -> let l = Array.to_list l in H.div [ fix b; H.ul (List.map (fun x -> H.li [ fix x ]) l) ] - | B.Anchor _ | B.Link _ -> assert false + | B.Anchor _ | B.Link _ | B.Ext _ -> assert false in + let rec to_html_rec b = match B.view b with | B.Tree (_, b, l) when config.tree_summary -> @@ -259,6 +272,13 @@ let to_html_rec ~config (b : B.t) = | B.Empty -> H.a ~a:[ H.a_id id ] [] | _ -> H.a ~a:[ H.a_id id; H.a_href @@ "#" ^ id ] [ to_html_nondet_rec inner ]) + | B.Ext { key = _; ext = Embed_html result } -> result + | B.Ext { key; ext } -> + (match Hashtbl.find_opt extensions key with + | Some handler -> handler config ext + | None -> + failwith @@ "PrintBox_html.to_html: missing extension handler for " + ^ key) | _ -> loop to_html_rec b and to_html_nondet_rec b = match B.view b with diff --git a/src/printbox-html/PrintBox_html.mli b/src/printbox-html/PrintBox_html.mli index 8972141..e36caf8 100644 --- a/src/printbox-html/PrintBox_html.mli +++ b/src/printbox-html/PrintBox_html.mli @@ -5,6 +5,15 @@ open Tyxml type 'a html = 'a Html.elt +type toplevel_html = Html_types.li_content_fun html + +type PrintBox.ext += + | Embed_html of toplevel_html + (** Injects HTML into a box. It is handled natively by [PrintBox_html]. + NOTE: this extension is unlikely to be supported by other backends! *) + +val embed_html : toplevel_html -> PrintBox.t +(** Injects HTML into a box. NOTE: this is unlikely to be supported by other backends! *) val prelude : [> Html_types.style ] html (** HTML text to embed in the "", defining the style for tables *) @@ -34,6 +43,10 @@ module Config : sig using the [] HTML5 element. *) end +val register_extension : + key:string -> (Config.t -> PrintBox.ext -> toplevel_html) -> unit +(** Add support for the extension with the given key to this rendering backend. *) + val to_html : ?config:Config.t -> PrintBox.t -> [ `Div ] html (** HTML for one box *) diff --git a/src/printbox-md/PrintBox_md.ml b/src/printbox-md/PrintBox_md.ml index 95534e3..99f0b16 100644 --- a/src/printbox-md/PrintBox_md.ml +++ b/src/printbox-md/PrintBox_md.ml @@ -55,6 +55,14 @@ module Config = struct let table_frames c = { c with frames = `As_table } end +let extensions : (string, Config.t -> PrintBox.ext -> string) Hashtbl.t = + Hashtbl.create 4 + +let register_extension ~key handler = + if Hashtbl.mem extensions key then + invalid_arg @@ "PrintBox_text.register_extension: already registered " ^ key; + Hashtbl.add extensions key handler + let style_format c ~no_md ~multiline (s : B.Style.t) = let open B.Style in (* Colors require support for styles: see issue #37 *) @@ -251,6 +259,11 @@ let rec multiline_heuristic c b = | B.Tree (_, header, children) -> Array.length children > 0 || multiline_heuristic c header | B.Link { inner; _ } | B.Anchor { inner; _ } -> multiline_heuristic c inner + | B.Ext { key; ext } -> + (match Hashtbl.find_opt extensions key with + | Some handler -> String.contains (handler c ext) '\n' + | None -> + failwith @@ "PrintBox_html.to_html: missing extension handler for " ^ key) let rec line_of_length_heuristic_exn c b = match B.view b with @@ -305,6 +318,15 @@ let rec line_of_length_heuristic_exn c b = (* INNER *) in line_of_length_heuristic_exn c inner + link_len + | B.Ext { key; ext } -> + (match Hashtbl.find_opt extensions key with + | Some handler -> + let s = handler c ext in + if String.contains s '\n' then + raise Not_found + else + String.length s + | None -> failwith @@ "PrintBox_md: missing extension handler for " ^ key) let is_native_table c rows = let rec header h = @@ -330,6 +352,7 @@ let rec remove_bold b = | B.Tree _ -> assert false | B.Link { inner; uri } -> B.link ~uri @@ remove_bold inner | B.Anchor { inner; id } -> B.anchor ~id @@ remove_bold inner + | B.Ext _ -> (* TODO: non-ideal but avoid complexity for now. *) b let pp c out b = let open Format in @@ -518,6 +541,12 @@ let pp c out b = | _ -> fprintf out {||} id id); loop ~no_block:true ~no_md ~prefix:(prefix ^ " ") inner; pp_print_string out "" + | B.Ext { key; ext } -> + (match Hashtbl.find_opt extensions key with + | Some handler -> pp_print_string out @@ handler c ext + | None -> + failwith @@ "PrintBox_html.to_html: missing extension handler for " + ^ key) in pp_open_vbox out 0; loop ~no_block:false ~no_md:false ~prefix:"" b; diff --git a/src/printbox-md/PrintBox_md.mli b/src/printbox-md/PrintBox_md.mli index 89e9320..30f557a 100644 --- a/src/printbox-md/PrintBox_md.mli +++ b/src/printbox-md/PrintBox_md.mli @@ -72,6 +72,11 @@ module Config : sig Already the case for the {!uniform} config. *) end +val register_extension : + key:string -> (Config.t -> PrintBox.ext -> string) -> unit +(** Add support for the extension with the given key to this rendering backend. + Note: the string returned by the handler can have line breaks. *) + val pp : Config.t -> Format.formatter -> PrintBox.t -> unit (** Pretty-print the Markdown source code into this formatter. *) diff --git a/src/printbox-text/PrintBox_text.ml b/src/printbox-text/PrintBox_text.ml index 1e485f0..4a17682 100644 --- a/src/printbox-text/PrintBox_text.ml +++ b/src/printbox-text/PrintBox_text.ml @@ -4,6 +4,13 @@ module B = PrintBox +let extensions = Hashtbl.create 4 + +let register_extension ~key handler = + if Hashtbl.mem extensions key then + invalid_arg @@ "PrintBox_text.register_extension: already registered " ^ key; + Hashtbl.add extensions key handler + type position = PrintBox.position = { x: int; y: int; @@ -102,7 +109,7 @@ let str_display_len_ = 0 s) let[@inline] set_string_len f = str_display_len_ := f -let[@inline] str_display_width_ s i len : int = !str_display_len_ s i len +let[@inline] str_display_width s i len : int = !str_display_len_ s i len (** {2 Output: where to print to} *) @@ -216,7 +223,7 @@ end = struct Pos.move_x start_pos l | Str_slice { s; i; len } -> O.output_substring out s i len; - let l = str_display_width_ s i len in + let l = str_display_width s i len in Pos.move_x start_pos l | Str_slice_bracket { pre; s; i; len; post } -> O.output_string out pre; @@ -225,7 +232,7 @@ end = struct does not try to mutate the string (which it should have no reason to do), but just to be safe... *) O.output_string out post; - let l = str_display_width_ s i len in + let l = str_display_width s i len in Pos.move_x start_pos l let render ?(indent = 0) (out : O.t) (self : t) : unit = @@ -480,7 +487,7 @@ end = struct | Text { l; style = _; link_with_uri = _ } -> let width = List.fold_left - (fun acc (s, i, len) -> max acc (str_display_width_ s i len)) + (fun acc (s, i, len) -> max acc (str_display_width s i len)) 0 l in { x = width; y = List.length l } @@ -554,7 +561,13 @@ end = struct (* split into lines *) let acc = ref [] in lines_l_ l (fun s i len -> acc := (s, i, len) :: !acc); - Text { l = List.rev !acc; style; link_with_uri = Some uri }) + Text { l = List.rev !acc; style; link_with_uri = Some uri } + | B.Ext { key; ext } -> + (match Hashtbl.find_opt extensions key with + | Some handler -> (of_box ~ansi @@ B.text @@ handler ext).shape + | None -> + failwith @@ "PrintBox_html.to_html: missing extension handler for " + ^ key)) | B.Link { inner; uri } -> (* just encode as a record *) let self = @@ -570,6 +583,12 @@ end = struct | _ -> of_box ~ansi (B.hlist ~bars:false [ B.line uri; inner ]) in self.shape + | B.Ext { key; ext } -> + (match Hashtbl.find_opt extensions key with + | Some handler -> (of_box ~ansi @@ B.text @@ handler ext).shape + | None -> + failwith @@ "PrintBox_html.to_html: missing extension handler for " + ^ key) in { shape; size = lazy (size_of_shape shape) } @@ -793,7 +812,7 @@ end = struct write_vline_ ~ct:`Tree conn_m (Pos.move_y pos' 1) ((size b).y - 1); let child_pos = - Pos.move_x pos' (str_display_width_ s 0 (String.length s)) + Pos.move_x pos' (str_display_width s 0 (String.length s)) in conn_m.m <- render_rec ~ansi b child_pos; if (size b).x > 0 && has_border child_pos conn_m.m then diff --git a/src/printbox-text/PrintBox_text.mli b/src/printbox-text/PrintBox_text.mli index c5c332b..de69147 100644 --- a/src/printbox-text/PrintBox_text.mli +++ b/src/printbox-text/PrintBox_text.mli @@ -5,6 +5,10 @@ This module should be used to output boxes directly to a terminal, or another area of monospace text *) +val register_extension : key:string -> (PrintBox.ext -> string) -> unit +(** Add support for the extension with the given key to this rendering backend. + Note: the string returned by the handler can have line breaks. *) + val set_string_len : (String.t -> int -> int -> int) -> unit (** Set which function is used to compute string length. Typically to be used with a unicode-sensitive length function. @@ -45,3 +49,12 @@ val pp_with : style:bool -> Format.formatter -> PrintBox.t -> unit @param style if true, emit ANSI codes for styling @since 0.3 *) + +(** {2 Support for Representation Extensions} *) + +val str_display_width : String.t -> int -> int -> int +(** [str_display_width s pos len] computes the width in visible characters + of the string [s] starting at string position [pos] and stopping right before [pos + len]. + See {!set_string_len}. + @since NEXT_RELEASE +*) diff --git a/test/dune b/test/dune index 0f86c79..3e96fcb 100644 --- a/test/dune +++ b/test/dune @@ -51,3 +51,39 @@ (modules reg_45) (package printbox-text) (libraries printbox printbox-text)) + +(test + (name extend_md) + (modules extend_md) + (package printbox-md) + (libraries printbox printbox-md)) + +(test + (name extend_html_specific) + (modules extend_html_specific) + (package printbox-html) + (libraries printbox tyxml printbox-html)) + +(test + (name plotting) + (modules plotting) + (package printbox-ext-plot) + (libraries printbox printbox-ext-plot printbox-text printbox-html)) + +(test + (name plotting_half_moons) + (modules plotting_half_moons) + (package printbox-ext-plot) + (libraries printbox printbox-ext-plot printbox-text printbox-html)) + +(test + (name plotting_linear) + (modules plotting_linear) + (package printbox-ext-plot) + (libraries printbox printbox-ext-plot printbox-text printbox-html)) + +(test + (name plotting_nested) + (modules plotting_nested) + (package printbox-ext-plot) + (libraries printbox printbox-ext-plot printbox-text printbox-html)) diff --git a/test/extend_html_specific.expected b/test/extend_html_specific.expected new file mode 100644 index 0000000..2f97395 --- /dev/null +++ b/test/extend_html_specific.expected @@ -0,0 +1,8 @@ + +HTML output simple: +
+ + +HTML output with header: +
Greetings!
+ diff --git a/test/extend_html_specific.ml b/test/extend_html_specific.ml new file mode 100644 index 0000000..ca89320 --- /dev/null +++ b/test/extend_html_specific.ml @@ -0,0 +1,34 @@ +open Tyxml +module B = PrintBox +module H = Html + +(* This tests extensions with HTML-specific support (as well as text backend support). *) + +type B.ext += Hello_html of string | Hello_with_header of string + +let html_handler config ext = + match ext with + | Hello_html txt -> (H.button [ H.txt txt ] :> PrintBox_html.toplevel_html) + | Hello_with_header txt -> + let result = H.button [ H.txt txt ] in + (PrintBox_html.to_html ~config + B.( + tree (text "Greetings!") + [ B.extension ~key:"Embed_html" (PrintBox_html.Embed_html result) ]) + :> PrintBox_html.toplevel_html) + | _ -> invalid_arg "html_handler: unknown extension" + +let () = + PrintBox_html.register_extension ~key:"Hello_world" html_handler + +let test1 = B.extension ~key:"Hello_world" @@ Hello_html "Hello world!" + +let test2 = + B.extension ~key:"Hello_world" @@ Hello_with_header "Hello wide world!" + +let () = + print_endline "\nHTML output simple:"; + print_endline @@ PrintBox_html.to_string test1; + print_endline "\nHTML output with header:"; + print_endline + @@ PrintBox_html.(to_string ~config:Config.(tree_summary true default) test2) diff --git a/test/extend_md.expected b/test/extend_md.expected new file mode 100644 index 0000000..490ab48 --- /dev/null +++ b/test/extend_md.expected @@ -0,0 +1,4 @@ + +Markdown output: +> Hello world! + diff --git a/test/extend_md.ml b/test/extend_md.ml new file mode 100644 index 0000000..1c01bed --- /dev/null +++ b/test/extend_md.ml @@ -0,0 +1,18 @@ +module B = PrintBox + +(* This tests that all backends support extensions that expand into boxes. *) + +type B.ext += Hello_world of string + +let md_handler config ext = + match ext with + | Hello_world txt -> + String.trim PrintBox_md.(to_string config (B.frame @@ B.text txt)) + | _ -> invalid_arg "text_handler: unrecognized extension" + +let () = PrintBox_md.register_extension ~key:"Hello_world" md_handler +let test = B.extension ~key:"Hello_world" @@ Hello_world "Hello world!" + +let () = + print_endline "\nMarkdown output:"; + print_endline @@ PrintBox_md.(to_string Config.default test) diff --git a/test/plotting.expected b/test/plotting.expected new file mode 100644 index 0000000..d6c7ccb --- /dev/null +++ b/test/plotting.expected @@ -0,0 +1,50 @@ +Text output: +┌──┬────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 1│Y:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;│ +│ │::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;│ +│ │:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;│ +│ │::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;│ +│ │,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::::::;;;;;;;;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::M:::::::::::::::::::;;;;;;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::::::::::;;;;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::::;;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::::;│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::::::::::::::│ +│ │,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::::│ +│ │...........,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::::│ +│ │.....................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::::│ +│ │...........................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::::│ +│y │...............................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::::::│ +│ │...................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::::│ +│ │......................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::::::│ +│ │.........................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::::│ +│ │............................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::::│ +│ │..............................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::::│ +│ │................................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::::│ +│ │..................................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::::│ +│ │...................................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::::│ +│ │ ..........................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::::│ +│ │ ......................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::::│ +│ │ ....................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::│ +│ │ ..................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::::│ +│ │ .................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::│ +│ │ ................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::::│ +│ │ ................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::│ +│ │ ...............................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::│ +│ │ ..............................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::│ +│ │ ..............................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::::│ +│ │ ..............................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,::::::::::│ +│ 0│ ..............................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,:::::::::X│ +├──┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ │0 1│ +│ │ x │ +└──┴────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +HTML output: +
y
1
0
:
Y
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
M
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
X
0
1
x
+ diff --git a/test/plotting.ml b/test/plotting.ml new file mode 100644 index 0000000..f2b649d --- /dev/null +++ b/test/plotting.ml @@ -0,0 +1,49 @@ +module B = PrintBox +module BPlot = PrintBox_ext_plot + +(* This tests the printbox-ext-plot extension. *) + +let test ~size = + BPlot.( + box + { + default_config with + size; + specs = + [ + Scatterbag + { + points = + [| + (0., 1.), B.line "Y"; + (1., 0.), B.line "X"; + (0.75, 0.75), B.line "M"; + |]; + }; + Map + { + callback = + (fun (x, y) -> + let s = ((x ** 2.) +. (y ** 2.)) ** 0.5 in + B.line + @@ + if s < 0.3 then + " " + else if s < 0.6 then + "." + else if s < 0.9 then + "," + else if s < 1.2 then + ":" + else + ";"); + }; + ]; + }) + +let () = + print_endline "Text output:"; + print_endline @@ PrintBox_text.to_string + @@ test ~size:BPlot.default_config.size; + print_endline "\nHTML output:"; + print_endline @@ PrintBox_html.to_string @@ test ~size:(800, 800) diff --git a/test/plotting_half_moons.expected b/test/plotting_half_moons.expected new file mode 100644 index 0000000..d2dfd5f --- /dev/null +++ b/test/plotting_half_moons.expected @@ -0,0 +1,50 @@ +Text output: +┌───────┬────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 1.09 │............................#.........................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.............................##.#...##..##..........................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │......................########.###..#.....#.##.....................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.....................#.#..####.#...#.#..##.#...#.....#...........,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │..............#....##########.##....####.#...#.##.#.............,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.............#.#####.###.#.#.#.##....###..##.##..##............,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.................#.#.#####.###...####..#..#.##.#.##.##.......,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.........#....##..##.#..#..####.###......###..##.####.##.##.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.........#.....#...###.##.##...#.#.#.#...#.....#.##.#####.,,#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │..........###....#.#####.##.#..........#..#.....#####..###,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.......#..#.#..#.#....#.....#................#..##...#.#,,#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │......###.###..##.##..........................#....#..###,#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │...#....#.###.##.##..........%.....................##,,#,#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │......#######....#...................%%..........#.,,##,#,###,,,,,,,,,,,,,,,,,,,,,,,,,,,,%,,,,,%,,,,│ +│ │.##.##...##.#...##...............%...%............,,,,##,##,###,#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.#.#.#.###.##.##.................%%...%.........,,,,,,,,###,,,##,,#,,,,,,,,,,,,,,,,,,,,,,,,,%%%,%%,,│ +│ │.....#.#..##...................%..%%%%%........,,,,,,,,,###,###,#,,,,,,,,,,,,,,,,,,,,,,,%%,,,%%%%,,,│ +│ │#.##.###.#.#................%.%...%.%%%......,,,,,,,,,#,,,#,,,,#,,#,,,,,,,,,,,,,,,,,,,,%,,,%,,%,,,,,│ +│ │#####.#...##.................%..%.%.....%...,,,,,,,,,,,,,#,,##,###,##,,,,,,,,,,,,,,,,,%%%,,,,%%,%,%,│ +│y │#.#.###.#.##.................%%.%.%%%..%...,,,,,,,,,,,,#,,,,,,,#,#,#,,,,,,,,,,,,,,,,,,%%,%,,,,,,%,%%│ +│ │##...###..#..................%%..%..%.%..,,,,,,,,,,,,,,,,##,,####,,,,#,,,,,,,,,,,,,,,%,,%,,,%,%,,%%,│ +│ │##......###..........................%%.%,%,,,,,,,,,,,,,,,,,,,,#,####,,,,,,,,,,,,,,,,,,,%%,,,,,%,%%,│ +│ │...#.#.###...................%..%%%%..%,,%,,,,,,,,,,,,,,,,##,,#######,,,,,,,,,,,,,,,,%%%,,,,,%,%,,,,│ +│ │......##.......................%...%.%%%,,,,,,,,,,,,,,,,,#,#,#,,,,,,#,,,,,,,,,,,,,,,,,,%,,%%,,,%%%,,│ +│ │....#..#...........................%,%,,%,,%,,,,,,,,,,,,,,,,#,,,,,,#,,,,,,,,,,,,,,,%,%%%%,,%%,,%,,,,│ +│ │........##.......................%,%%,,,%,%,,,,,,,,,,,,,,,,,,,#,,##,,,,,,,,,,,,,,,%%,,,%,,%%%,%,,,,,│ +│ │#.#............................%.,%,,%,,%%,,,,%%,,,,,,,,,#,,#,,,,,#,#,,,,,,,,,,,,,,,,%%%,%%,,,,,,,,,│ +│ │.#...#.........................,%%%,,%%%%%,%,,,,,,,,,,,,,,,,,#,,,,#,,,,,,,,,,%,,,,,%%%%,%,%,,,%,,,,,│ +│ │..............................,,,,,,,%,,%%%,,,%,%%%,%,,,,#,,,,,,,,,,,,,,,,,,,,%,%,,%,%%,%,%%,,%,,,,,│ +│ │............................,,,,,,%,%%%%%,%,%,%,%,,,,,,%,,,,,,,,,,,,,,,,,,,,,,%%,,%%,%,%,%,,,,%,,,,,│ +│ │...........................,,,,,,,,%,,,%%%%%,%%%,,,,,,,%,,,,,,,,,,,,,,,,%,%%,,%,%%%%%,%%,,,,,,,,,,,,│ +│ │.........................,,,,,,,,,,,,,,,,%,,,,,%%%%%,%,%,%%,,,,,,,,,,%,%%%%%%,%,,%,,,,,,,,,,,,,,,,,,│ +│ │........................,,,,,,,,,,,,%,,,%,%%,%,,,,,,,%,,%%,,%%,%,,,%%%%%%%,,%,%,%,,,,,%%,,,,,,,,,,,,│ +│ │.......................,,,,,,,,,,,,,,,%,,%,%%,%%%,,,,%,%%%,%%,,,%,%%,%,%,%%%,,%%%%%,,,,,,%,,,,,,,,,,│ +│ │.....................,,,,,,,,,,,,,,,,,,%%%%,%,,%,,,,,,,%%%,,%,,%%%%,%%,,,%,%,,%%,,%,,,,,,,,,,,,,,,,,│ +│ │....................,,,,,,,,,,,,,,,,,,,,,,,,,%,,%%,,%,%,%,%%,%%,,,%,,,%,%%,,,%%%,,,%%%,,,,,,,,,,,,,,│ +│ │..................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%,,%%%,,%%%%,,%%%%,,,%%,%%%%%,,,,,,%,,,,,,,,,,,,,,│ +│ │.................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%%%,,,,,,,,%%%%%%,%%,%,,%%,%,,,,%,,,,,,,,,,,,,,,,,,,│ +│ │...............,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%,%%,%%%,%%%,,%%%%,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ -0.794│..............,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%,,,,,,%,,,,,%,,,%,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,│ +├───────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ │-1.25 2.1│ +│ │ x │ +└───────┴────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +HTML output: +
y
1.09
-0.794
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
#
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
#
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
#
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
%
#
#
#
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
#
#
#
%
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
#
#
#
#
#
#
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
%
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
#
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
#
#
%
#
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
%
#
#
#
%
#
#
#
#
#
%
.
.
#
.
.
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
%
#
%
%
#
#
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
%
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
#
#
#
%
%
%
%
#
#
#
#
#
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
%
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
#
%
%
#
%
%
%
#
%
#
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
#
#
#
%
%
%
%
#
#
#
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
#
#
%
#
%
%
%
#
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
%
#
#
#
#
%
#
#
%
#
%
#
%
#
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
%
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
%
#
%
#
#
#
#
%
.
#
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
#
#
%
%
%
#
%
#
%
%
%
#
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
%
#
#
#
%
#
#
%
%
#
#
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
%
#
#
#
%
%
%
#
%
#
#
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
%
#
%
#
%
#
%
%
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
%
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
#
%
%
#
%
%
%
#
#
%
.
.
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
%
#
%
#
#
%
%
%
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
#
%
#
#
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
%
#
%
#
#
%
#
#
%
%
#
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
%
#
%
%
%
%
%
%
%
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
%
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
#
%
%
%
%
.
.
.
.
.
.
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
#
%
#
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
#
%
%
#
%
#
%
#
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
%
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
#
%
#
%
%
#
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
%
%
#
#
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
%
,
%
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
%
%
%
%
#
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
#
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
%
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
%
%
%
%
%
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
%
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
-1.25
2.1
x
+ diff --git a/test/plotting_half_moons.ml b/test/plotting_half_moons.ml new file mode 100644 index 0000000..e58ef95 --- /dev/null +++ b/test/plotting_half_moons.ml @@ -0,0 +1,72 @@ +module B = PrintBox +module BPlot = PrintBox_ext_plot + +module Rand = struct + let rand = ref (1l : Int32.t) + + let rand_int32 () = + let open Int32 in + rand := logxor !rand @@ shift_left !rand 13; + rand := logxor !rand @@ shift_right_logical !rand 17; + rand := logxor !rand @@ shift_left !rand 5; + !rand + + let float_range low high = + let raw = Int32.(to_float @@ rem (rand_int32 ()) 10000l) in + (raw /. 10000. *. (high -. low)) +. low + + let int high = Int32.(to_int @@ rem (rand_int32 ()) (of_int high)) +end + +let noise () = Rand.float_range (-0.1) 0.1 + +(* [Array.split] only available since OCaml 4.12. *) +let array_split x = + let a0, b0 = x.(0) in + let n = Array.length x in + let a = Array.make n a0 in + let b = Array.make n b0 in + for i = 1 to n - 1 do + let ai, bi = x.(i) in + a.(i) <- ai; + b.(i) <- bi + done; + a, b + +(* This tests the printbox-ext-plot extension. *) +let moons data_len = + let npairs = data_len / 2 in + array_split + (Array.init npairs (fun _pos -> + let i = Rand.int npairs in + let v = Float.(of_int (i / 2) *. pi /. of_int npairs) in + let c = cos v and s = sin v in + ( (s +. noise (), c +. noise ()), + (1.0 -. s +. noise (), 0.5 -. c +. noise ()) ))) + +let points1, points2 = moons 1024 +let callback (x, y) = Float.compare x y > 0 + +let test = + BPlot.( + box + { + default_config with + specs = + [ + Scatterplot { points = points1; content = B.line "#" }; + Scatterplot { points = points2; content = B.line "%" }; + Boundary_map + { + content_false = B.line "."; + content_true = B.line ","; + callback; + }; + ]; + }) + +let () = + print_endline "Text output:"; + print_endline @@ PrintBox_text.to_string test; + print_endline "\nHTML output:"; + print_endline @@ PrintBox_html.to_string test diff --git a/test/plotting_linear.expected b/test/plotting_linear.expected new file mode 100644 index 0000000..15ac7c5 --- /dev/null +++ b/test/plotting_linear.expected @@ -0,0 +1,50 @@ +Text output: +┌──┬────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 1│...................................................................................................%│ +│ │.................................................................................................,%,│ +│ │..............................................................................................,,,%,,│ +│ │............................................................................................,,,,%,,,│ +│ │.........................................................................................,,,,,%%,,,,│ +│ │.......................................................................................,,,,,,%,,,,,,│ +│ │....................................................................................,,,,,,,,%,,,,,,,│ +│ │..................................................................................,,,,,,,,%%,,,,####│ +│ │...............................................................................,,,,,,,,,,%,#####,,,,│ +│ │.............................................................................,,,,,,,,,,####,,,,,,,,,│ +│ │..........................................................................,,,,,,,,,,###,,,,,,,,,,,,,│ +│ │........................................................................,,,,,,,,####%%,,,,,,,,,,,,,,│ +│ │.....................................................................,,,,,,,####,,,%,,,,,,,,,,,,,,,,│ +│ │...................................................................,,,,,,###,,,,,%%,,,,,,,,,,,,,,,,,│ +│ │................................................................,,,,,####,,,,,,,%,,,,,,,,,,,,,,,,,,,│ +│ │.............................................................,,,,,###,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,│ +│ │...........................................................,,,,###,,,,,,,,,,,%,,,,,,,,,,,,,,,,,,,,,,│ +│ │........................................................,,,,###,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,│ +│ │......................................................,,,###,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,│ +│y │...................................................,,,###,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.................................................,,###,,,,,,,,,,,,,,,,%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │..............................................,,###,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │............................................,###,,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.........................................,###,,,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.......................................,##,,,,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │....................................,###,,,,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │..................................###,,,,,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │...............................###,,,,,,,,,,,,,,,,,,,,,%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │............................,##,,,,,,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │..........................###,,,,,,,,,,,,,,,,,,,,,,%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.......................,##,,,,,,,,,,,,,,,,,,,,,,%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.....................###,,,,,,,,,,,,,,,,,,,,,%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │..................###,,,,,,,,,,,,,,,,,,,,,%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │................##,,,,,,,,,,,,,,,,,,,,,%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │.............###,,,,,,,,,,,,,,,,,,,,%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │...........##,,,,,,,,,,,,,,,,,,,%%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │........###,,,,,,,,,,,,,,,,,%%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │......##,,,,,,,,,,,,,,,%%%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ │...###,,,,,,,,,,%%%%%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +│ 0│###%%%%%%%%%%%%%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,│ +├──┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ │0 1│ +│ │ x │ +└──┴────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +HTML output: +
y
0.99
0
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
%
,
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
%
,
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
%
,
,
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
%
,
,
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
%
,
,
,
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
#
,
,
,
#
%
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
%
#
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
#
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
#
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
#
%
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
%
#
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
%
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
#
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
%
#
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
%
#
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
#
%
%
#
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
%
#
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
%
#
%
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
#
%
%
#
%
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
#
%
%
#
%
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
#
%
%
%
#
.
.
,
,
,
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
#
%
%
%
%
#
%
.
,
,
,
,
,
,
,
,
%
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
%
%
%
#
%
%
%
%
%
%
%
%
%
#
%
%
%
%
%
0
1
x
+ diff --git a/test/plotting_linear.ml b/test/plotting_linear.ml new file mode 100644 index 0000000..957a30a --- /dev/null +++ b/test/plotting_linear.ml @@ -0,0 +1,38 @@ +module B = PrintBox +module BPlot = PrintBox_ext_plot + +(* This tests the printbox-ext-plot extension. *) + +let test = + BPlot.( + box + { + default_config with + specs = + [ + Line_plot_adaptive + { + callback = (fun x -> sin x); + content = B.line "#"; + cache = Hashtbl.create 20; + }; + Line_plot_adaptive + { + callback = (fun x -> x ** 2.); + content = B.line "%"; + cache = Hashtbl.create 20; + }; + Boundary_map + { + content_false = B.line "."; + content_true = B.line ","; + callback = (fun (x, y) -> x > y); + }; + ]; + }) + +let () = + print_endline "Text output:"; + print_endline @@ PrintBox_text.to_string test; + print_endline "\nHTML output:"; + print_endline @@ PrintBox_html.to_string test diff --git a/test/plotting_nested.expected b/test/plotting_nested.expected new file mode 100644 index 0000000..bd48aae --- /dev/null +++ b/test/plotting_nested.expected @@ -0,0 +1,50 @@ +Text output: +┌──┬─────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 1│┌────────────────────────────────────┐::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; │ +│ ││nice unicode! 💪 │:::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;│ +│ │├────┌─────────┐─────────────────────┤:::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;;;;; │ +│ ││┌───│123456789│┬───────────────────┐│::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;;;;; │ +│ │││oï ├─────────┤────────────────────────────┐::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;;;; │ +│ │││π/2│┌───────┐│code! 💪 │::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;;;;;│ +│ │││τ/4││ ....││────────────────────────────┤::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;;;; │ +│ ││├───│├───────┤│───────┬───────────────────┐│::::::::::::::::::::::::::::::::::::::::::;;;;;;;;;;;;; │ +│ │││ ││. ││d nums:│┌─────────────────┐││::::::::::::::::::::::::::::::::::┌──────────────────── │ +│ │││ │└───────┘│ ││┌───────────────┐│││,,::::::::::::::::::::::::::::::::│nice unicode! 💪 │ +│ │││ └─────────┘ │││┌─────────────┐││││,,,,,,:::::::::::::::::::::::┌───────────────────────── │ +│ │││ ├─│├──────────────┤│││sum=Σ_i a·xᵢ²│││││,,,,,,,,,::::::::::::::::::::│nice unicode! 💪 │ +│ │││ └─││ ││││————— │││││,,,,,,,,,,,,:::::::::::::::::├───────────────────────── │ +│ │││ ││ ││││1+1 │││││,,,,,,,,,,,,,,,::::::::::::::│┌──────────────┬───────── │ +│ │││ ││ 0 │││├─────────────┤││││,,,,,,,,,,,,,,,,,,:::::::::::││oï ωεird nums:│┌──────── │ +│ │││ ││ ├─1 ││││ Ōₒ│││││,,,,,,,,,,,,,,,,,,,,,::::::::││π/2 ││┌─────── │ +│ ││└─────││ └─ω ││││ À │││││,,,,,,,,,,,,,,,,,,,,,,,::::::││τ/4 │││┌────── │ +│ │└──────││ └─ω² │││└─────────────┘││││,,,,,,,,,,,,,,,,,,,,,,,,,::::│├──────────────┤│││sum=Σ_ │ +│ │.......││ ││└───────────────┘│││,,,,,,,,,,,,,,,,,,,,,,,,,,,::││ ││││————— │ +│y │.......││ │└─────────────────┘││,,,,,,,,,,,,,,,,,,,,,,,,,,,,,││ ││││1+1 │ +│ │.......│└──────────────┴───────────────────┘│,,,,,,,,,,,,,,,,,,,,,,,,,,,,,││ 0 │││├────── │ +│ │.......└────────────────────────────────────┘,,,,,,,,,,,,,,,,,,,,,,,,,,,,,││ ├─1 ││││ │ +│ │.........................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,││ └─ω ││││ │ +│ │............................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,││ └─ω² │││└────── │ +│ │..............................................,,,,,,,,,,,,,,,,,,,,,,,,,,,,││ ││└─────── │ +│ │................................................,,,,,,,,,,,,,,,,,,,,,,,,,,││ │└──────── │ +│ │..................................................,,,,,,,,,,,,,,,,,,,,,,,,│└──────────────┴───────── │ +│ │...................................................,,,,,,,,,,,,,,,,,,,,,,,└───────────────────────── │ +│ │ ..................┌─────────┐──────────────────────────┐,,,,,,,,,,,,,,,,,,::::::::::::::: │ +│ │ .............│123456789│de! 💪 │,,,,,,,,,,,,,,,,,,,,::::::::::::::│ +│ │ ..........├─────────┤──────────────────────────┤,,,,,,,,,,,,,,,,,,,,::::::::::::: │ +│ │ .......│┌───────┐│─────┬───────────────────┐│,,,,,,,,,,,,,,,,,,,,::::::::::::: │ +│ │ .....││ ....││nums:│┌─────────────────┐││,,,,,,,,,,,,,,,,,,,,,:::::::::::: │ +│ │ ...│├───────┤│ ││┌───────────────┐│││,,,,,,,,,,,,,,,,,,,,,:::::::::::: │ +│ │ ..││. ││ │││┌─────────────┐││││,,,,,,,,,,,,,,,,,,,,,,::::::::::: │ +│ │ .│└───────┘│─────┤│││sum=Σ_i a·xᵢ²│││││,,,,,,,,,,,,,,,,,,,,,,::::::::::: │ +│ │ └─────────┘ ││││————— │││││,,,,,,,,,,,,,,,,,,,,,,::::::::::: │ +│ │ ││ ││││1+1 │││││,,,,,,,,,,,,,,,,,,,,,,::::::::::: │ +│ │ ││ 0 │││├─────────────┤││││,,,,,,,,,,,,,,,,,,,,,,,:::::::::: │ +│ 0│ ││ ├─1 ││││ Ōₒ│││││,,,,,,,,,,,,,,,,,,,,,,,:::::::::( │ +├──┼─────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ │0 1│ +│ │ x │ +└──┴─────────────────────────────────────────────────────────────────────────────────────────────────────┘ + +HTML output: +
y
1
0
:
nice unicode! 💪
oï ωεird nums:
π/2
τ/4
0
  • 1
  • ω
    • ω²
sum=Σ_i a·xᵢ²
—————
1+1
Ōₒ
À
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
123456789
....
.
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
:
:
:
:
:
nice unicode! 💪
oï ωεird nums:
π/2
τ/4
0
  • 1
  • ω
    • ω²
sum=Σ_i a·xᵢ²
—————
1+1
Ōₒ
À
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
nice unicode! 💪
oï ωεird nums:
π/2
τ/4
0
  • 1
  • ω
    • ω²
sum=Σ_i a·xᵢ²
—————
1+1
Ōₒ
À
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
nice unicode! 💪
oï ωεird nums:
π/2
τ/4
0
  • 1
  • ω
    • ω²
sum=Σ_i a·xᵢ²
—————
1+1
Ōₒ
À
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
;
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
nice unicode! 💪
oï ωεird nums:
π/2
τ/4
0
  • 1
  • ω
    • ω²
sum=Σ_i a·xᵢ²
—————
1+1
Ōₒ
À
123456789
....
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
:
:
:
:
:
:
:
:
(0,0)
(0,1)
(0,2)
(1,0)
(1,1)
(1,2)
(2,0)
(2,1)
(2,2)
0
1
x
+ diff --git a/test/plotting_nested.ml b/test/plotting_nested.ml new file mode 100644 index 0000000..639760e --- /dev/null +++ b/test/plotting_nested.ml @@ -0,0 +1,94 @@ +module B = PrintBox +module BPlot = PrintBox_ext_plot + +(* This tests the printbox-ext-plot extension. *) + +let reg_45 = + B.( + frame + (vlist + [ + text "123456789"; + frame ~stretch:true + (vlist [ text "...." |> align ~h:`Right ~v:`Top; text "." ]); + ])) + +let for_3 = + let n = 3 in + Array.init n (fun i -> Array.init n (fun j -> B.sprintf "(%d,%d)" i j)) + |> B.grid + +let nice_unicode = + B.( + frame + @@ vlist + [ + text "nice unicode! 💪"; + frame + @@ hlist + [ + vlist + [ + text "oï ωεird nums:\nπ/2\nτ/4"; + center_hv + @@ tree (text "0") + [ text "1"; tree (text "ω") [ text "ω²" ] ]; + ]; + frame @@ frame @@ frame + @@ vlist + [ + text "sum=Σ_i a·xᵢ²\n—————\n1+1"; + align_right @@ text "Ōₒ\nÀ"; + ]; + ]; + ]) + +let test ~size = + BPlot.( + box + { + default_config with + size; + specs = + [ + Scatterbag + { points = [| (0.06, 0.95), reg_45; (0.3, 0.3), reg_45 |] }; + Scatterbag + { + points = + [| + (0., 1.), nice_unicode; + (0.08, 0.9), nice_unicode; + (1., 0.), for_3; + (0.3, 0.3), nice_unicode; + (0.75, 0.75), nice_unicode; + (0.8, 0.8), nice_unicode; + |]; + }; + Map + { + callback = + (fun (x, y) -> + let s = ((x ** 2.) +. (y ** 2.)) ** 0.5 in + B.line + @@ + if s < 0.3 then + " " + else if s < 0.6 then + "." + else if s < 0.9 then + "," + else if s < 1.2 then + ":" + else + ";"); + }; + ]; + }) + +let () = + print_endline "Text output:"; + print_endline @@ PrintBox_text.to_string + @@ test ~size:BPlot.default_config.size; + print_endline "\nHTML output:"; + print_endline @@ PrintBox_html.to_string @@ test ~size:(800, 800)