// Generated by ReScript, PLEASE EDIT WITH CARE

import * as $$Map from "rescript/lib/es6/map.js";
import * as $$Set from "rescript/lib/es6/set.js";
import * as List from "rescript/lib/es6/list.js";
import * as Misc from "./misc.js";
import * as Curry from "rescript/lib/es6/curry.js";
import * as Format from "./format.js";
import * as Printf from "./printf.js";
import * as Hashtbl from "rescript/lib/es6/hashtbl.js";
import * as Caml_option from "rescript/lib/es6/caml_option.js";
import * as Caml_js_exceptions from "rescript/lib/es6/caml_js_exceptions.js";

function Pair(A, B) {
  var compare = function (param, param$1) {
    var c = Curry._2(A.compare, param[0], param$1[0]);
    if (c !== 0) {
      return c;
    } else {
      return Curry._2(B.compare, param[1], param$1[1]);
    }
  };
  var output = function (oc, param) {
    return Curry._5(Printf.fprintf(oc), " (%a, %a)", A.output, param[0], B.output, param[1]);
  };
  var hash = function (param) {
    return Hashtbl.hash([
                Curry._1(A.hash, param[0]),
                Curry._1(B.hash, param[1])
              ]);
  };
  var equal = function (param, param$1) {
    if (Curry._2(A.equal, param[0], param$1[0])) {
      return Curry._2(B.equal, param[1], param$1[1]);
    } else {
      return false;
    }
  };
  var print = function (ppf, param) {
    return Curry._5(Format.fprintf(ppf), " (%a, @ %a)", A.print, param[0], B.print, param[1]);
  };
  return {
          equal: equal,
          hash: hash,
          compare: compare,
          output: output,
          print: print
        };
}

function Make_map(T) {
  var include = $$Map.Make({
        compare: T.compare
      });
  var empty = include.empty;
  var add = include.add;
  var merge = include.merge;
  var union = include.union;
  var iter = include.iter;
  var fold = include.fold;
  var bindings = include.bindings;
  var find = include.find;
  var filter_map = function (t, f) {
    return Curry._3(fold, (function (id, v, map) {
                  var r = Curry._2(f, id, v);
                  if (r !== undefined) {
                    return Curry._3(add, id, Caml_option.valFromOption(r), map);
                  } else {
                    return map;
                  }
                }), t, empty);
  };
  var of_list = function (l) {
    return List.fold_left((function (map, param) {
                  return Curry._3(add, param[0], param[1], map);
                }), empty, l);
  };
  var disjoint_union = function (eq, print, m1, m2) {
    return Curry._3(union, (function (id, v1, v2) {
                  var ok = eq !== undefined ? Curry._2(eq, v1, v2) : false;
                  if (ok) {
                    return Caml_option.some(v1);
                  }
                  var tmp;
                  if (print !== undefined) {
                    var print$1 = Caml_option.valFromOption(print);
                    tmp = Curry._6(Format.asprintf("Map.disjoint_union %a => %a <> %a"), T.print, id, print$1, v1, print$1, v2);
                  } else {
                    tmp = Curry._2(Format.asprintf("Map.disjoint_union %a"), T.print, id);
                  }
                  return Misc.fatal_error(tmp);
                }), m1, m2);
  };
  var union_right = function (m1, m2) {
    return Curry._3(merge, (function (_id, x, y) {
                  if (x !== undefined) {
                    if (y !== undefined) {
                      return Caml_option.some(Caml_option.valFromOption(y));
                    } else {
                      return Caml_option.some(Caml_option.valFromOption(x));
                    }
                  } else if (y !== undefined) {
                    return Caml_option.some(Caml_option.valFromOption(y));
                  } else {
                    return ;
                  }
                }), m1, m2);
  };
  var union_left = function (m1, m2) {
    return union_right(m2, m1);
  };
  var union_merge = function (f, m1, m2) {
    var aux = function (param, m1, m2) {
      if (m1 !== undefined) {
        if (m2 !== undefined) {
          return Caml_option.some(Curry._2(f, Caml_option.valFromOption(m1), Caml_option.valFromOption(m2)));
        } else {
          return m1;
        }
      } else {
        return m2;
      }
    };
    return Curry._3(merge, aux, m1, m2);
  };
  var rename = function (m, v) {
    try {
      return Curry._2(find, v, m);
    }
    catch (raw_exn){
      var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
      if (exn.RE_EXN_ID === "Not_found") {
        return v;
      }
      throw exn;
    }
  };
  var map_keys = function (f, m) {
    return of_list(List.map((function (param) {
                      return [
                              Curry._1(f, param[0]),
                              param[1]
                            ];
                    }), Curry._1(bindings, m)));
  };
  var print = function (f, ppf, s) {
    var elts = function (ppf, s) {
      return Curry._2(iter, (function (id, v) {
                    return Curry._5(Format.fprintf(ppf), "@ (@[%a@ %a@])", T.print, id, f, v);
                  }), s);
    };
    return Curry._3(Format.fprintf(ppf), "@[<1>{@[%a@ @]}@]", elts, s);
  };
  var T_set = $$Set.Make({
        compare: T.compare
      });
  var keys = function (map) {
    return Curry._3(fold, (function (k, param, set) {
                  return Curry._2(T_set.add, k, set);
                }), map, T_set.empty);
  };
  var data = function (t) {
    return List.map((function (prim) {
                  return prim[1];
                }), Curry._1(bindings, t));
  };
  var of_set = function (f, set) {
    return Curry._3(T_set.fold, (function (e, map) {
                  return Curry._3(add, e, Curry._1(f, e), map);
                }), set, empty);
  };
  var transpose_keys_and_data = function (map) {
    return Curry._3(fold, (function (k, v, m) {
                  return Curry._3(add, v, k, m);
                }), map, empty);
  };
  var transpose_keys_and_data_set = function (map) {
    return Curry._3(fold, (function (k, v, m) {
                  var set;
                  var exit = 0;
                  var set$1;
                  try {
                    set$1 = Curry._2(find, v, m);
                    exit = 1;
                  }
                  catch (raw_exn){
                    var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
                    if (exn.RE_EXN_ID === "Not_found") {
                      set = Curry._1(T_set.singleton, k);
                    } else {
                      throw exn;
                    }
                  }
                  if (exit === 1) {
                    set = Curry._2(T_set.add, k, set$1);
                  }
                  return Curry._3(add, v, set, m);
                }), map, empty);
  };
  return {
          empty: empty,
          is_empty: include.is_empty,
          mem: include.mem,
          add: add,
          update: include.update,
          singleton: include.singleton,
          remove: include.remove,
          merge: merge,
          union: union,
          compare: include.compare,
          equal: include.equal,
          iter: iter,
          fold: fold,
          for_all: include.for_all,
          exists: include.exists,
          filter: include.filter,
          partition: include.partition,
          cardinal: include.cardinal,
          bindings: bindings,
          min_binding: include.min_binding,
          min_binding_opt: include.min_binding_opt,
          max_binding: include.max_binding,
          max_binding_opt: include.max_binding_opt,
          choose: include.choose,
          choose_opt: include.choose_opt,
          split: include.split,
          find: find,
          find_opt: include.find_opt,
          find_first: include.find_first,
          find_first_opt: include.find_first_opt,
          find_last: include.find_last,
          find_last_opt: include.find_last_opt,
          map: include.map,
          mapi: include.mapi,
          filter_map: filter_map,
          of_list: of_list,
          disjoint_union: disjoint_union,
          union_right: union_right,
          union_left: union_left,
          union_merge: union_merge,
          rename: rename,
          map_keys: map_keys,
          print: print,
          T_set: T_set,
          keys: keys,
          data: data,
          of_set: of_set,
          transpose_keys_and_data: transpose_keys_and_data,
          transpose_keys_and_data_set: transpose_keys_and_data_set
        };
}

function Make_set(T) {
  var include = $$Set.Make({
        compare: T.compare
      });
  var empty = include.empty;
  var add = include.add;
  var singleton = include.singleton;
  var iter = include.iter;
  var elements = include.elements;
  var output = function (oc, s) {
    Curry._1(Printf.fprintf(oc), " ( ");
    Curry._2(iter, (function (v) {
            return Curry._3(Printf.fprintf(oc), "%a ", T.output, v);
          }), s);
    return Curry._1(Printf.fprintf(oc), ")");
  };
  var print = function (ppf, s) {
    var elts = function (ppf, s) {
      return Curry._2(iter, (function (e) {
                    return Curry._3(Format.fprintf(ppf), "@ %a", T.print, e);
                  }), s);
    };
    return Curry._3(Format.fprintf(ppf), "@[<1>{@[%a@ @]}@]", elts, s);
  };
  var to_string = function (s) {
    return Curry._2(Format.asprintf("%a"), print, s);
  };
  var of_list = function (l) {
    if (!l) {
      return empty;
    }
    var q = l.tl;
    var t = l.hd;
    if (q) {
      return List.fold_left((function (acc, e) {
                    return Curry._2(add, e, acc);
                  }), Curry._1(singleton, t), q);
    } else {
      return Curry._1(singleton, t);
    }
  };
  var map = function (f, s) {
    return of_list(List.map(f, Curry._1(elements, s)));
  };
  return {
          empty: empty,
          is_empty: include.is_empty,
          mem: include.mem,
          add: add,
          singleton: singleton,
          remove: include.remove,
          union: include.union,
          inter: include.inter,
          diff: include.diff,
          compare: include.compare,
          equal: include.equal,
          subset: include.subset,
          iter: iter,
          fold: include.fold,
          for_all: include.for_all,
          exists: include.exists,
          filter: include.filter,
          partition: include.partition,
          cardinal: include.cardinal,
          elements: elements,
          min_elt: include.min_elt,
          min_elt_opt: include.min_elt_opt,
          max_elt: include.max_elt,
          max_elt_opt: include.max_elt_opt,
          choose: include.choose,
          choose_opt: include.choose_opt,
          split: include.split,
          find: include.find,
          find_opt: include.find_opt,
          find_first: include.find_first,
          find_first_opt: include.find_first_opt,
          find_last: include.find_last,
          find_last_opt: include.find_last_opt,
          output: output,
          print: print,
          to_string: to_string,
          of_list: of_list,
          map: map
        };
}

function Make_tbl(T) {
  var include = Hashtbl.Make(T);
  var create = include.create;
  var add = include.add;
  var find = include.find;
  var fold = include.fold;
  var include$1 = $$Map.Make({
        compare: T.compare
      });
  var empty = include$1.empty;
  var add$1 = include$1.add;
  var merge = include$1.merge;
  var union = include$1.union;
  var iter = include$1.iter;
  var fold$1 = include$1.fold;
  var cardinal = include$1.cardinal;
  var bindings = include$1.bindings;
  var find$1 = include$1.find;
  var map = include$1.map;
  var filter_map = function (t, f) {
    return Curry._3(fold$1, (function (id, v, map) {
                  var r = Curry._2(f, id, v);
                  if (r !== undefined) {
                    return Curry._3(add$1, id, Caml_option.valFromOption(r), map);
                  } else {
                    return map;
                  }
                }), t, empty);
  };
  var of_list = function (l) {
    return List.fold_left((function (map, param) {
                  return Curry._3(add$1, param[0], param[1], map);
                }), empty, l);
  };
  var disjoint_union = function (eq, print, m1, m2) {
    return Curry._3(union, (function (id, v1, v2) {
                  var ok = eq !== undefined ? Curry._2(eq, v1, v2) : false;
                  if (ok) {
                    return Caml_option.some(v1);
                  }
                  var tmp;
                  if (print !== undefined) {
                    var print$1 = Caml_option.valFromOption(print);
                    tmp = Curry._6(Format.asprintf("Map.disjoint_union %a => %a <> %a"), T.print, id, print$1, v1, print$1, v2);
                  } else {
                    tmp = Curry._2(Format.asprintf("Map.disjoint_union %a"), T.print, id);
                  }
                  return Misc.fatal_error(tmp);
                }), m1, m2);
  };
  var union_right = function (m1, m2) {
    return Curry._3(merge, (function (_id, x, y) {
                  if (x !== undefined) {
                    if (y !== undefined) {
                      return Caml_option.some(Caml_option.valFromOption(y));
                    } else {
                      return Caml_option.some(Caml_option.valFromOption(x));
                    }
                  } else if (y !== undefined) {
                    return Caml_option.some(Caml_option.valFromOption(y));
                  } else {
                    return ;
                  }
                }), m1, m2);
  };
  var union_left = function (m1, m2) {
    return union_right(m2, m1);
  };
  var union_merge = function (f, m1, m2) {
    var aux = function (param, m1, m2) {
      if (m1 !== undefined) {
        if (m2 !== undefined) {
          return Caml_option.some(Curry._2(f, Caml_option.valFromOption(m1), Caml_option.valFromOption(m2)));
        } else {
          return m1;
        }
      } else {
        return m2;
      }
    };
    return Curry._3(merge, aux, m1, m2);
  };
  var rename = function (m, v) {
    try {
      return Curry._2(find$1, v, m);
    }
    catch (raw_exn){
      var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
      if (exn.RE_EXN_ID === "Not_found") {
        return v;
      }
      throw exn;
    }
  };
  var map_keys = function (f, m) {
    return of_list(List.map((function (param) {
                      return [
                              Curry._1(f, param[0]),
                              param[1]
                            ];
                    }), Curry._1(bindings, m)));
  };
  var print = function (f, ppf, s) {
    var elts = function (ppf, s) {
      return Curry._2(iter, (function (id, v) {
                    return Curry._5(Format.fprintf(ppf), "@ (@[%a@ %a@])", T.print, id, f, v);
                  }), s);
    };
    return Curry._3(Format.fprintf(ppf), "@[<1>{@[%a@ @]}@]", elts, s);
  };
  var T_set = $$Set.Make({
        compare: T.compare
      });
  var keys = function (map) {
    return Curry._3(fold$1, (function (k, param, set) {
                  return Curry._2(T_set.add, k, set);
                }), map, T_set.empty);
  };
  var data = function (t) {
    return List.map((function (prim) {
                  return prim[1];
                }), Curry._1(bindings, t));
  };
  var of_set = function (f, set) {
    return Curry._3(T_set.fold, (function (e, map) {
                  return Curry._3(add$1, e, Curry._1(f, e), map);
                }), set, empty);
  };
  var transpose_keys_and_data = function (map) {
    return Curry._3(fold$1, (function (k, v, m) {
                  return Curry._3(add$1, v, k, m);
                }), map, empty);
  };
  var transpose_keys_and_data_set = function (map) {
    return Curry._3(fold$1, (function (k, v, m) {
                  var set;
                  var exit = 0;
                  var set$1;
                  try {
                    set$1 = Curry._2(find$1, v, m);
                    exit = 1;
                  }
                  catch (raw_exn){
                    var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
                    if (exn.RE_EXN_ID === "Not_found") {
                      set = Curry._1(T_set.singleton, k);
                    } else {
                      throw exn;
                    }
                  }
                  if (exit === 1) {
                    set = Curry._2(T_set.add, k, set$1);
                  }
                  return Curry._3(add$1, v, set, m);
                }), map, empty);
  };
  var T_map_is_empty = include$1.is_empty;
  var T_map_mem = include$1.mem;
  var T_map_update = include$1.update;
  var T_map_singleton = include$1.singleton;
  var T_map_remove = include$1.remove;
  var T_map_compare = include$1.compare;
  var T_map_equal = include$1.equal;
  var T_map_for_all = include$1.for_all;
  var T_map_exists = include$1.exists;
  var T_map_filter = include$1.filter;
  var T_map_partition = include$1.partition;
  var T_map_min_binding = include$1.min_binding;
  var T_map_min_binding_opt = include$1.min_binding_opt;
  var T_map_max_binding = include$1.max_binding;
  var T_map_max_binding_opt = include$1.max_binding_opt;
  var T_map_choose = include$1.choose;
  var T_map_choose_opt = include$1.choose_opt;
  var T_map_split = include$1.split;
  var T_map_find_opt = include$1.find_opt;
  var T_map_find_first = include$1.find_first;
  var T_map_find_first_opt = include$1.find_first_opt;
  var T_map_find_last = include$1.find_last;
  var T_map_find_last_opt = include$1.find_last_opt;
  var T_map_mapi = include$1.mapi;
  var T_map = {
    empty: empty,
    is_empty: T_map_is_empty,
    mem: T_map_mem,
    add: add$1,
    update: T_map_update,
    singleton: T_map_singleton,
    remove: T_map_remove,
    merge: merge,
    union: union,
    compare: T_map_compare,
    equal: T_map_equal,
    iter: iter,
    fold: fold$1,
    for_all: T_map_for_all,
    exists: T_map_exists,
    filter: T_map_filter,
    partition: T_map_partition,
    cardinal: cardinal,
    bindings: bindings,
    min_binding: T_map_min_binding,
    min_binding_opt: T_map_min_binding_opt,
    max_binding: T_map_max_binding,
    max_binding_opt: T_map_max_binding_opt,
    choose: T_map_choose,
    choose_opt: T_map_choose_opt,
    split: T_map_split,
    find: find$1,
    find_opt: T_map_find_opt,
    find_first: T_map_find_first,
    find_first_opt: T_map_find_first_opt,
    find_last: T_map_find_last,
    find_last_opt: T_map_find_last_opt,
    map: map,
    mapi: T_map_mapi,
    filter_map: filter_map,
    of_list: of_list,
    disjoint_union: disjoint_union,
    union_right: union_right,
    union_left: union_left,
    union_merge: union_merge,
    rename: rename,
    map_keys: map_keys,
    print: print,
    T_set: T_set,
    keys: keys,
    data: data,
    of_set: of_set,
    transpose_keys_and_data: transpose_keys_and_data,
    transpose_keys_and_data_set: transpose_keys_and_data_set
  };
  var to_list = function (t) {
    return Curry._3(fold, (function (key, datum, elts) {
                  return {
                          hd: [
                            key,
                            datum
                          ],
                          tl: elts
                        };
                }), t, /* [] */0);
  };
  var of_list$1 = function (elts) {
    var t = Curry._1(create, 42);
    List.iter((function (param) {
            return Curry._3(add, t, param[0], param[1]);
          }), elts);
    return t;
  };
  var to_map = function (v) {
    return Curry._3(fold, add$1, v, empty);
  };
  var of_map = function (m) {
    var t = Curry._1(create, Curry._1(cardinal, m));
    Curry._2(iter, (function (k, v) {
            return Curry._3(add, t, k, v);
          }), m);
    return t;
  };
  var memoize = function (t, f, key) {
    try {
      return Curry._2(find, t, key);
    }
    catch (raw_exn){
      var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
      if (exn.RE_EXN_ID === "Not_found") {
        var r = Curry._1(f, key);
        Curry._3(add, t, key, r);
        return r;
      }
      throw exn;
    }
  };
  var map$1 = function (t, f) {
    return of_map(Curry._2(map, f, Curry._3(fold, add$1, t, empty)));
  };
  return {
          create: create,
          clear: include.clear,
          reset: include.reset,
          copy: include.copy,
          add: add,
          remove: include.remove,
          find: find,
          find_opt: include.find_opt,
          find_all: include.find_all,
          replace: include.replace,
          mem: include.mem,
          iter: include.iter,
          filter_map_inplace: include.filter_map_inplace,
          fold: fold,
          length: include.length,
          stats: include.stats,
          T_map: T_map,
          to_list: to_list,
          of_list: of_list$1,
          to_map: to_map,
          of_map: of_map,
          memoize: memoize,
          map: map$1
        };
}

function Make(T) {
  var include = $$Set.Make({
        compare: T.compare
      });
  var empty = include.empty;
  var add = include.add;
  var singleton = include.singleton;
  var iter = include.iter;
  var elements = include.elements;
  var output = function (oc, s) {
    Curry._1(Printf.fprintf(oc), " ( ");
    Curry._2(iter, (function (v) {
            return Curry._3(Printf.fprintf(oc), "%a ", T.output, v);
          }), s);
    return Curry._1(Printf.fprintf(oc), ")");
  };
  var print = function (ppf, s) {
    var elts = function (ppf, s) {
      return Curry._2(iter, (function (e) {
                    return Curry._3(Format.fprintf(ppf), "@ %a", T.print, e);
                  }), s);
    };
    return Curry._3(Format.fprintf(ppf), "@[<1>{@[%a@ @]}@]", elts, s);
  };
  var to_string = function (s) {
    return Curry._2(Format.asprintf("%a"), print, s);
  };
  var of_list = function (l) {
    if (!l) {
      return empty;
    }
    var q = l.tl;
    var t = l.hd;
    if (q) {
      return List.fold_left((function (acc, e) {
                    return Curry._2(add, e, acc);
                  }), Curry._1(singleton, t), q);
    } else {
      return Curry._1(singleton, t);
    }
  };
  var map = function (f, s) {
    return of_list(List.map(f, Curry._1(elements, s)));
  };
  var Set_is_empty = include.is_empty;
  var Set_mem = include.mem;
  var Set_remove = include.remove;
  var Set_union = include.union;
  var Set_inter = include.inter;
  var Set_diff = include.diff;
  var Set_compare = include.compare;
  var Set_equal = include.equal;
  var Set_subset = include.subset;
  var Set_fold = include.fold;
  var Set_for_all = include.for_all;
  var Set_exists = include.exists;
  var Set_filter = include.filter;
  var Set_partition = include.partition;
  var Set_cardinal = include.cardinal;
  var Set_min_elt = include.min_elt;
  var Set_min_elt_opt = include.min_elt_opt;
  var Set_max_elt = include.max_elt;
  var Set_max_elt_opt = include.max_elt_opt;
  var Set_choose = include.choose;
  var Set_choose_opt = include.choose_opt;
  var Set_split = include.split;
  var Set_find = include.find;
  var Set_find_opt = include.find_opt;
  var Set_find_first = include.find_first;
  var Set_find_first_opt = include.find_first_opt;
  var Set_find_last = include.find_last;
  var Set_find_last_opt = include.find_last_opt;
  var $$Set$1 = {
    empty: empty,
    is_empty: Set_is_empty,
    mem: Set_mem,
    add: add,
    singleton: singleton,
    remove: Set_remove,
    union: Set_union,
    inter: Set_inter,
    diff: Set_diff,
    compare: Set_compare,
    equal: Set_equal,
    subset: Set_subset,
    iter: iter,
    fold: Set_fold,
    for_all: Set_for_all,
    exists: Set_exists,
    filter: Set_filter,
    partition: Set_partition,
    cardinal: Set_cardinal,
    elements: elements,
    min_elt: Set_min_elt,
    min_elt_opt: Set_min_elt_opt,
    max_elt: Set_max_elt,
    max_elt_opt: Set_max_elt_opt,
    choose: Set_choose,
    choose_opt: Set_choose_opt,
    split: Set_split,
    find: Set_find,
    find_opt: Set_find_opt,
    find_first: Set_find_first,
    find_first_opt: Set_find_first_opt,
    find_last: Set_find_last,
    find_last_opt: Set_find_last_opt,
    output: output,
    print: print,
    to_string: to_string,
    of_list: of_list,
    map: map
  };
  var include$1 = $$Map.Make({
        compare: T.compare
      });
  var empty$1 = include$1.empty;
  var add$1 = include$1.add;
  var merge = include$1.merge;
  var union = include$1.union;
  var iter$1 = include$1.iter;
  var fold = include$1.fold;
  var bindings = include$1.bindings;
  var find = include$1.find;
  var filter_map = function (t, f) {
    return Curry._3(fold, (function (id, v, map) {
                  var r = Curry._2(f, id, v);
                  if (r !== undefined) {
                    return Curry._3(add$1, id, Caml_option.valFromOption(r), map);
                  } else {
                    return map;
                  }
                }), t, empty$1);
  };
  var of_list$1 = function (l) {
    return List.fold_left((function (map, param) {
                  return Curry._3(add$1, param[0], param[1], map);
                }), empty$1, l);
  };
  var disjoint_union = function (eq, print, m1, m2) {
    return Curry._3(union, (function (id, v1, v2) {
                  var ok = eq !== undefined ? Curry._2(eq, v1, v2) : false;
                  if (ok) {
                    return Caml_option.some(v1);
                  }
                  var tmp;
                  if (print !== undefined) {
                    var print$1 = Caml_option.valFromOption(print);
                    tmp = Curry._6(Format.asprintf("Map.disjoint_union %a => %a <> %a"), T.print, id, print$1, v1, print$1, v2);
                  } else {
                    tmp = Curry._2(Format.asprintf("Map.disjoint_union %a"), T.print, id);
                  }
                  return Misc.fatal_error(tmp);
                }), m1, m2);
  };
  var union_right = function (m1, m2) {
    return Curry._3(merge, (function (_id, x, y) {
                  if (x !== undefined) {
                    if (y !== undefined) {
                      return Caml_option.some(Caml_option.valFromOption(y));
                    } else {
                      return Caml_option.some(Caml_option.valFromOption(x));
                    }
                  } else if (y !== undefined) {
                    return Caml_option.some(Caml_option.valFromOption(y));
                  } else {
                    return ;
                  }
                }), m1, m2);
  };
  var union_left = function (m1, m2) {
    return union_right(m2, m1);
  };
  var union_merge = function (f, m1, m2) {
    var aux = function (param, m1, m2) {
      if (m1 !== undefined) {
        if (m2 !== undefined) {
          return Caml_option.some(Curry._2(f, Caml_option.valFromOption(m1), Caml_option.valFromOption(m2)));
        } else {
          return m1;
        }
      } else {
        return m2;
      }
    };
    return Curry._3(merge, aux, m1, m2);
  };
  var rename = function (m, v) {
    try {
      return Curry._2(find, v, m);
    }
    catch (raw_exn){
      var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
      if (exn.RE_EXN_ID === "Not_found") {
        return v;
      }
      throw exn;
    }
  };
  var map_keys = function (f, m) {
    return of_list$1(List.map((function (param) {
                      return [
                              Curry._1(f, param[0]),
                              param[1]
                            ];
                    }), Curry._1(bindings, m)));
  };
  var print$1 = function (f, ppf, s) {
    var elts = function (ppf, s) {
      return Curry._2(iter$1, (function (id, v) {
                    return Curry._5(Format.fprintf(ppf), "@ (@[%a@ %a@])", T.print, id, f, v);
                  }), s);
    };
    return Curry._3(Format.fprintf(ppf), "@[<1>{@[%a@ @]}@]", elts, s);
  };
  var T_set = $$Set.Make({
        compare: T.compare
      });
  var keys = function (map) {
    return Curry._3(fold, (function (k, param, set) {
                  return Curry._2(T_set.add, k, set);
                }), map, T_set.empty);
  };
  var data = function (t) {
    return List.map((function (prim) {
                  return prim[1];
                }), Curry._1(bindings, t));
  };
  var of_set = function (f, set) {
    return Curry._3(T_set.fold, (function (e, map) {
                  return Curry._3(add$1, e, Curry._1(f, e), map);
                }), set, empty$1);
  };
  var transpose_keys_and_data = function (map) {
    return Curry._3(fold, (function (k, v, m) {
                  return Curry._3(add$1, v, k, m);
                }), map, empty$1);
  };
  var transpose_keys_and_data_set = function (map) {
    return Curry._3(fold, (function (k, v, m) {
                  var set;
                  var exit = 0;
                  var set$1;
                  try {
                    set$1 = Curry._2(find, v, m);
                    exit = 1;
                  }
                  catch (raw_exn){
                    var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
                    if (exn.RE_EXN_ID === "Not_found") {
                      set = Curry._1(T_set.singleton, k);
                    } else {
                      throw exn;
                    }
                  }
                  if (exit === 1) {
                    set = Curry._2(T_set.add, k, set$1);
                  }
                  return Curry._3(add$1, v, set, m);
                }), map, empty$1);
  };
  var Map_is_empty = include$1.is_empty;
  var Map_mem = include$1.mem;
  var Map_update = include$1.update;
  var Map_singleton = include$1.singleton;
  var Map_remove = include$1.remove;
  var Map_compare = include$1.compare;
  var Map_equal = include$1.equal;
  var Map_for_all = include$1.for_all;
  var Map_exists = include$1.exists;
  var Map_filter = include$1.filter;
  var Map_partition = include$1.partition;
  var Map_cardinal = include$1.cardinal;
  var Map_min_binding = include$1.min_binding;
  var Map_min_binding_opt = include$1.min_binding_opt;
  var Map_max_binding = include$1.max_binding;
  var Map_max_binding_opt = include$1.max_binding_opt;
  var Map_choose = include$1.choose;
  var Map_choose_opt = include$1.choose_opt;
  var Map_split = include$1.split;
  var Map_find_opt = include$1.find_opt;
  var Map_find_first = include$1.find_first;
  var Map_find_first_opt = include$1.find_first_opt;
  var Map_find_last = include$1.find_last;
  var Map_find_last_opt = include$1.find_last_opt;
  var Map_map = include$1.map;
  var Map_mapi = include$1.mapi;
  var $$Map$1 = {
    empty: empty$1,
    is_empty: Map_is_empty,
    mem: Map_mem,
    add: add$1,
    update: Map_update,
    singleton: Map_singleton,
    remove: Map_remove,
    merge: merge,
    union: union,
    compare: Map_compare,
    equal: Map_equal,
    iter: iter$1,
    fold: fold,
    for_all: Map_for_all,
    exists: Map_exists,
    filter: Map_filter,
    partition: Map_partition,
    cardinal: Map_cardinal,
    bindings: bindings,
    min_binding: Map_min_binding,
    min_binding_opt: Map_min_binding_opt,
    max_binding: Map_max_binding,
    max_binding_opt: Map_max_binding_opt,
    choose: Map_choose,
    choose_opt: Map_choose_opt,
    split: Map_split,
    find: find,
    find_opt: Map_find_opt,
    find_first: Map_find_first,
    find_first_opt: Map_find_first_opt,
    find_last: Map_find_last,
    find_last_opt: Map_find_last_opt,
    map: Map_map,
    mapi: Map_mapi,
    filter_map: filter_map,
    of_list: of_list$1,
    disjoint_union: disjoint_union,
    union_right: union_right,
    union_left: union_left,
    union_merge: union_merge,
    rename: rename,
    map_keys: map_keys,
    print: print$1,
    T_set: T_set,
    keys: keys,
    data: data,
    of_set: of_set,
    transpose_keys_and_data: transpose_keys_and_data,
    transpose_keys_and_data_set: transpose_keys_and_data_set
  };
  var include$2 = Hashtbl.Make(T);
  var create = include$2.create;
  var add$2 = include$2.add;
  var find$1 = include$2.find;
  var fold$1 = include$2.fold;
  var include$3 = $$Map.Make({
        compare: T.compare
      });
  var empty$2 = include$3.empty;
  var add$3 = include$3.add;
  var merge$1 = include$3.merge;
  var union$1 = include$3.union;
  var iter$2 = include$3.iter;
  var fold$2 = include$3.fold;
  var cardinal = include$3.cardinal;
  var bindings$1 = include$3.bindings;
  var find$2 = include$3.find;
  var map$1 = include$3.map;
  var filter_map$1 = function (t, f) {
    return Curry._3(fold$2, (function (id, v, map) {
                  var r = Curry._2(f, id, v);
                  if (r !== undefined) {
                    return Curry._3(add$3, id, Caml_option.valFromOption(r), map);
                  } else {
                    return map;
                  }
                }), t, empty$2);
  };
  var of_list$2 = function (l) {
    return List.fold_left((function (map, param) {
                  return Curry._3(add$3, param[0], param[1], map);
                }), empty$2, l);
  };
  var disjoint_union$1 = function (eq, print, m1, m2) {
    return Curry._3(union$1, (function (id, v1, v2) {
                  var ok = eq !== undefined ? Curry._2(eq, v1, v2) : false;
                  if (ok) {
                    return Caml_option.some(v1);
                  }
                  var tmp;
                  if (print !== undefined) {
                    var print$1 = Caml_option.valFromOption(print);
                    tmp = Curry._6(Format.asprintf("Map.disjoint_union %a => %a <> %a"), T.print, id, print$1, v1, print$1, v2);
                  } else {
                    tmp = Curry._2(Format.asprintf("Map.disjoint_union %a"), T.print, id);
                  }
                  return Misc.fatal_error(tmp);
                }), m1, m2);
  };
  var union_right$1 = function (m1, m2) {
    return Curry._3(merge$1, (function (_id, x, y) {
                  if (x !== undefined) {
                    if (y !== undefined) {
                      return Caml_option.some(Caml_option.valFromOption(y));
                    } else {
                      return Caml_option.some(Caml_option.valFromOption(x));
                    }
                  } else if (y !== undefined) {
                    return Caml_option.some(Caml_option.valFromOption(y));
                  } else {
                    return ;
                  }
                }), m1, m2);
  };
  var union_left$1 = function (m1, m2) {
    return union_right$1(m2, m1);
  };
  var union_merge$1 = function (f, m1, m2) {
    var aux = function (param, m1, m2) {
      if (m1 !== undefined) {
        if (m2 !== undefined) {
          return Caml_option.some(Curry._2(f, Caml_option.valFromOption(m1), Caml_option.valFromOption(m2)));
        } else {
          return m1;
        }
      } else {
        return m2;
      }
    };
    return Curry._3(merge$1, aux, m1, m2);
  };
  var rename$1 = function (m, v) {
    try {
      return Curry._2(find$2, v, m);
    }
    catch (raw_exn){
      var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
      if (exn.RE_EXN_ID === "Not_found") {
        return v;
      }
      throw exn;
    }
  };
  var map_keys$1 = function (f, m) {
    return of_list$2(List.map((function (param) {
                      return [
                              Curry._1(f, param[0]),
                              param[1]
                            ];
                    }), Curry._1(bindings$1, m)));
  };
  var print$2 = function (f, ppf, s) {
    var elts = function (ppf, s) {
      return Curry._2(iter$2, (function (id, v) {
                    return Curry._5(Format.fprintf(ppf), "@ (@[%a@ %a@])", T.print, id, f, v);
                  }), s);
    };
    return Curry._3(Format.fprintf(ppf), "@[<1>{@[%a@ @]}@]", elts, s);
  };
  var T_set$1 = $$Set.Make({
        compare: T.compare
      });
  var keys$1 = function (map) {
    return Curry._3(fold$2, (function (k, param, set) {
                  return Curry._2(T_set$1.add, k, set);
                }), map, T_set$1.empty);
  };
  var data$1 = function (t) {
    return List.map((function (prim) {
                  return prim[1];
                }), Curry._1(bindings$1, t));
  };
  var of_set$1 = function (f, set) {
    return Curry._3(T_set$1.fold, (function (e, map) {
                  return Curry._3(add$3, e, Curry._1(f, e), map);
                }), set, empty$2);
  };
  var transpose_keys_and_data$1 = function (map) {
    return Curry._3(fold$2, (function (k, v, m) {
                  return Curry._3(add$3, v, k, m);
                }), map, empty$2);
  };
  var transpose_keys_and_data_set$1 = function (map) {
    return Curry._3(fold$2, (function (k, v, m) {
                  var set;
                  var exit = 0;
                  var set$1;
                  try {
                    set$1 = Curry._2(find$2, v, m);
                    exit = 1;
                  }
                  catch (raw_exn){
                    var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
                    if (exn.RE_EXN_ID === "Not_found") {
                      set = Curry._1(T_set$1.singleton, k);
                    } else {
                      throw exn;
                    }
                  }
                  if (exit === 1) {
                    set = Curry._2(T_set$1.add, k, set$1);
                  }
                  return Curry._3(add$3, v, set, m);
                }), map, empty$2);
  };
  var T_map_is_empty = include$3.is_empty;
  var T_map_mem = include$3.mem;
  var T_map_update = include$3.update;
  var T_map_singleton = include$3.singleton;
  var T_map_remove = include$3.remove;
  var T_map_compare = include$3.compare;
  var T_map_equal = include$3.equal;
  var T_map_for_all = include$3.for_all;
  var T_map_exists = include$3.exists;
  var T_map_filter = include$3.filter;
  var T_map_partition = include$3.partition;
  var T_map_min_binding = include$3.min_binding;
  var T_map_min_binding_opt = include$3.min_binding_opt;
  var T_map_max_binding = include$3.max_binding;
  var T_map_max_binding_opt = include$3.max_binding_opt;
  var T_map_choose = include$3.choose;
  var T_map_choose_opt = include$3.choose_opt;
  var T_map_split = include$3.split;
  var T_map_find_opt = include$3.find_opt;
  var T_map_find_first = include$3.find_first;
  var T_map_find_first_opt = include$3.find_first_opt;
  var T_map_find_last = include$3.find_last;
  var T_map_find_last_opt = include$3.find_last_opt;
  var T_map_mapi = include$3.mapi;
  var T_map = {
    empty: empty$2,
    is_empty: T_map_is_empty,
    mem: T_map_mem,
    add: add$3,
    update: T_map_update,
    singleton: T_map_singleton,
    remove: T_map_remove,
    merge: merge$1,
    union: union$1,
    compare: T_map_compare,
    equal: T_map_equal,
    iter: iter$2,
    fold: fold$2,
    for_all: T_map_for_all,
    exists: T_map_exists,
    filter: T_map_filter,
    partition: T_map_partition,
    cardinal: cardinal,
    bindings: bindings$1,
    min_binding: T_map_min_binding,
    min_binding_opt: T_map_min_binding_opt,
    max_binding: T_map_max_binding,
    max_binding_opt: T_map_max_binding_opt,
    choose: T_map_choose,
    choose_opt: T_map_choose_opt,
    split: T_map_split,
    find: find$2,
    find_opt: T_map_find_opt,
    find_first: T_map_find_first,
    find_first_opt: T_map_find_first_opt,
    find_last: T_map_find_last,
    find_last_opt: T_map_find_last_opt,
    map: map$1,
    mapi: T_map_mapi,
    filter_map: filter_map$1,
    of_list: of_list$2,
    disjoint_union: disjoint_union$1,
    union_right: union_right$1,
    union_left: union_left$1,
    union_merge: union_merge$1,
    rename: rename$1,
    map_keys: map_keys$1,
    print: print$2,
    T_set: T_set$1,
    keys: keys$1,
    data: data$1,
    of_set: of_set$1,
    transpose_keys_and_data: transpose_keys_and_data$1,
    transpose_keys_and_data_set: transpose_keys_and_data_set$1
  };
  var to_list = function (t) {
    return Curry._3(fold$1, (function (key, datum, elts) {
                  return {
                          hd: [
                            key,
                            datum
                          ],
                          tl: elts
                        };
                }), t, /* [] */0);
  };
  var of_list$3 = function (elts) {
    var t = Curry._1(create, 42);
    List.iter((function (param) {
            return Curry._3(add$2, t, param[0], param[1]);
          }), elts);
    return t;
  };
  var to_map = function (v) {
    return Curry._3(fold$1, add$3, v, empty$2);
  };
  var of_map = function (m) {
    var t = Curry._1(create, Curry._1(cardinal, m));
    Curry._2(iter$2, (function (k, v) {
            return Curry._3(add$2, t, k, v);
          }), m);
    return t;
  };
  var memoize = function (t, f, key) {
    try {
      return Curry._2(find$1, t, key);
    }
    catch (raw_exn){
      var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
      if (exn.RE_EXN_ID === "Not_found") {
        var r = Curry._1(f, key);
        Curry._3(add$2, t, key, r);
        return r;
      }
      throw exn;
    }
  };
  var map$2 = function (t, f) {
    return of_map(Curry._2(map$1, f, Curry._3(fold$1, add$3, t, empty$2)));
  };
  var Tbl_clear = include$2.clear;
  var Tbl_reset = include$2.reset;
  var Tbl_copy = include$2.copy;
  var Tbl_remove = include$2.remove;
  var Tbl_find_opt = include$2.find_opt;
  var Tbl_find_all = include$2.find_all;
  var Tbl_replace = include$2.replace;
  var Tbl_mem = include$2.mem;
  var Tbl_iter = include$2.iter;
  var Tbl_filter_map_inplace = include$2.filter_map_inplace;
  var Tbl_length = include$2.length;
  var Tbl_stats = include$2.stats;
  var Tbl = {
    create: create,
    clear: Tbl_clear,
    reset: Tbl_reset,
    copy: Tbl_copy,
    add: add$2,
    remove: Tbl_remove,
    find: find$1,
    find_opt: Tbl_find_opt,
    find_all: Tbl_find_all,
    replace: Tbl_replace,
    mem: Tbl_mem,
    iter: Tbl_iter,
    filter_map_inplace: Tbl_filter_map_inplace,
    fold: fold$1,
    length: Tbl_length,
    stats: Tbl_stats,
    T_map: T_map,
    to_list: to_list,
    of_list: of_list$3,
    to_map: to_map,
    of_map: of_map,
    memoize: memoize,
    map: map$2
  };
  return {
          T: T,
          equal: T.equal,
          hash: T.hash,
          compare: T.compare,
          output: T.output,
          print: T.print,
          $$Set: $$Set$1,
          $$Map: $$Map$1,
          Tbl: Tbl
        };
}

export {
  Pair ,
  Make_map ,
  Make_set ,
  Make_tbl ,
  Make ,
  
}
/* Misc Not a pure module */
