text:
# Legit.jl -- Convert French law in LEGI format to Git & Markdown
# By: Emmanuel Raviart <emmanuel.raviart@data.gouv.fr>
#
# Copyright (C) 2015 Etalab
# https://github.com/etalab/Legit.jl
#
# The Legit.jl package is licensed under the MIT "Expat" License.

empty_element_to_nothing = @compat pipe(
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
    ),
    drop_nothing = true,
  ),
  empty_to_nothing,
  test_nothing,
)

extract_singleton = pipe(
  test_isa(Array),
  test(values -> length(values) == 1; error = N_("Array must be a singleton.")),
  extract_when_singleton,
)

validate_cid = pipe(
  test_isa(String),
  empty_to_nothing,
  test(cid -> ismatch(r"^(JORF|KALI|LEGI)(SCTA|TEXT)\d{12}$", cid); error = N_("Invalid CID.")),
)

validate_date = pipe(
  test_isa(String),
  empty_to_nothing,
  condition(
    test_equal(nothing),
    noop,
    test_equal("0002-11-30"),
    from_value(Date(1960, 8, 7)),
    test_equal("0003-05-19"),
    from_value(Date(1993, 5, 19)),
    test_equal("0050-06-14"),
    from_value(Date(1950, 6, 14)),
    test_equal("0199-03-04"),
    from_value(Date(1999, 3, 4)),
    test_equal("0199-08-01"),
    from_value(Date(1990, 8, 1)),
    test_equal("0881-10-09"),
    from_value(Date(1981, 10, 9)),
    test_equal("0946-01-01"),
    from_value(Date(1946, 1, 1)),
    test_equal("0958-09-10"),
    from_value(Date(1958, 9, 10)),
    test_equal("0988-11-30"),
    from_value(Date(1988, 11, 30)),
    test_equal("1006-06-21"),
    from_value(Date(2006, 6, 21)),
    test_equal("1192-10-19"),
    from_value(Date(1992, 10, 19)),
    test_equal("1193-03-24"),
    from_value(Date(1993, 3, 24)),
    test_equal("2222-02-02"),
    from_value(Date(2222, 2, 2)),
    test_equal("2222-02-22"),
    from_value(Date(2222, 2, 22)),
    test_equal("2999-01-01"),
    from_value(nothing),
    test_equal("5820-10-01"),
    from_value(nothing),
    iso8601_string_to_date,
  ),
)

validate_etat = pipe(
  test_isa(String),
  empty_to_nothing,
  test_in(["ABROGE", "ABROGE_DIFF", "ANNULE", "DISJOINT", "MODIFIE", "MODIFIE_MORT_NE", "PERIME", "TRANSFERE",
    "VIGUEUR", "VIGUEUR_DIFF"]),
)

validate_id = pipe(
  test_isa(String),
  empty_to_nothing,
  test(id -> ismatch(r"^(JORF|KALI|LEGI)(ARTI|CONT|SCTA|TEXT)\d{12}$", id); error = N_("Invalid ID.")),
)

validate_ministere = pipe(
  test_isa(String),
  empty_to_nothing,
  # TODO?
)

validate_nature = pipe(
  test_isa(String),
  empty_to_nothing,
  test_in(["ARRETE", "ARRETEEURO", "Article", "AVIS", "CIRCULAIRE", "CODE", "CONSTITUTION", "CONVENTION", "DECISION",
    "DECISION_EURO", "DECLARATION", "DECRET", "DECRETEURO", "DECRET_LOI", "DELIBERATION", "DIRECTIVE_EURO",
    "INSTRUCTION", "INSTRUCTIONEURO", "LOI", "LOI_CONSTIT", "LOI_ORGANIQUE", "LOI_PROGRAMME", "LOIEURO", "ORDONNANCE",
    "RAPPORT", "REGLEMENTEUROPEEN"]),
)

validate_nor = pipe(
  test_isa(String),
  empty_to_nothing,
  # TODO?
)

validate_num = pipe(
  test_isa(String),
  empty_to_nothing,
  # TODO?
)

validate_origine = pipe(
  test_isa(String),
  test_in(["JORF", "LEGI"]),
)

validate_url = pipe(
  test_isa(String),
  empty_to_nothing,
  test(url -> ismatch(r"^[\dA-Za-z/]+\.xml$", url); error = N_("Invalid URL."))
)

element_to_contenu = test_isa(XMLElement)

element_to_text = @compat pipe(
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
      ),
    ),
    drop_nothing = true,
  ),
  call(element -> get(element, "^text", nothing)),
)

element_singleton_to_text = pipe(
  extract_singleton,
  element_to_text,
)

element_to_lien_article = @compat pipe(
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "@debut" => validate_date,
      "@etat" => validate_etat,
      "@fin" => validate_date,
      "@id" => pipe(
        validate_id,
        require,
      ),
      "@num" => validate_num,
      "@origine" => pipe(
        validate_origine,
        require,
      ),
    ),
    drop_nothing = true,
  ),
)

function element_singleton_to_tm()
  # This converter is defined as a function, because it is recursive.
  return @compat pipe(
    extract_singleton,
    test_isa(Dict),
    struct(
      Dict{String, Any}(
        "^tail" => pipe(
          test_isa(String),
          strip,
          test_nothing,
        ),
        "^text" => pipe(
          test_isa(String),
          strip,
          test_nothing,
        ),
        "TITRE_TM" => pipe(
          test_isa(Array),
          uniform_sequence(
            pipe(
              test_isa(Dict),
              struct(
                Dict{String, Any}(
                  "^tail" => pipe(
                    test_isa(String),
                    strip,
                    test_nothing,
                  ),
                  "^text" => pipe(
                    test_isa(String),
                    strip,
                    require,
                  ),
                  "@debut" => validate_date,
                  "@fin" => validate_date,
                  "@id" => pipe(
                    validate_id,
                    require,
                  ),
                ),
                drop_nothing = true,
              ),
              require,
            ),
          ),
          require,
        ),
        "TM" => convertible::Convertible -> element_singleton_to_tm()(convertible),  # Defer evaluation.
      ),
      drop_nothing = true,
    ),
  )
end

element_singleton_to_contexte = @compat pipe(
  extract_singleton,
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "TEXTE" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "@autorite" => pipe(
              test_isa(String),
              empty_to_nothing,
              test_in(["CONSEIL CONSTITUTIONNEL", "CONSEIL D'ETAT", "COUR DES COMPTES"]),
            ),
            "@cid" => pipe(
              validate_cid,
              require,
            ),
            "@date_publi" => validate_date,
            "@date_signature" => validate_date,
            "@ministere" => validate_ministere,
            "@nature" => validate_nature,
            "@nor" => validate_nor,
            "@num" => validate_num,
            "TITRE_TXT" => pipe(
              test_isa(Array),
              uniform_sequence(
                pipe(
                  test_isa(Dict),
                  struct(
                    Dict{String, Any}(
                      "^tail" => pipe(
                        test_isa(String),
                        strip,
                        test_nothing,
                      ),
                      "^text" => pipe(
                        test_isa(String),
                        strip,
                      ),
                      "@c_titre_court" => pipe(
                        test_isa(String),
                        empty_to_nothing,
                      ),
                      "@debut" => validate_date,
                      "@fin" => validate_date,
                      "@id_txt" => pipe(
                        validate_id,
                        require,
                      ),
                    ),
                    drop_nothing = true,
                  ),
                  require,
                ),
              ),
              require,
            ),
            "TM" => element_singleton_to_tm(),
          ),
          drop_nothing = true,
        ),
        require,
      ),
    ),
    drop_nothing = true,
  ),
)

element_singleton_to_liens = @compat pipe(
  extract_singleton,
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "LIEN" => pipe(
        test_isa(Array),
        uniform_sequence(
          pipe(
            test_isa(Dict),
            struct(
              Dict{String, Any}(
                "^tail" => pipe(
                  test_isa(String),
                  strip,
                  test_nothing,
                ),
                "^text" => pipe(
                  test_isa(String),
                  call(text -> join(split(text), " ")),
                  empty_to_nothing,
                ),
                "@cidtexte" => validate_cid,
                "@datesignatexte" => validate_date,
                "@id" => validate_id,
                "@naturetexte" => validate_nature,
                "@nortexte" => validate_nor,
                "@num" => validate_num,
                "@numtexte" => validate_num,
                "@sens" => pipe(
                  test_isa(String),
                  empty_to_nothing,
                  test_in(["cible", "source"]),
                  require,
                ),
                "@typelien" => pipe(
                  test_isa(String),
                  empty_to_nothing,
                  test_in(["ABROGATION", "ABROGE", "ANNULATION", "ANNULE", "APPLICATION", "CITATION", "CODIFICATION",
                    "CODIFIE", "CONCORDANCE", "CONCORDE", "CREATION", "CREE", "DEPLACE", "DEPLACEMENT", "DISJOINT",
                    "DISJONCTION", "HISTO", "MODIFICATION", "MODIFIE", "PEREMPTION", "PERIME", "PILOTE_SUIVEUR",
                    "RATIFICATION", "RATIFIE", "RECTIFICATION", "SPEC_APPLI", "SUBSTITUTION", "TRANSFERE", "TRANSFERT",
                    "TRANSPOSITION", "TXT_ASSOCIE", "TXT_SOURCE"]),
                  require,
                ),
              ),
              drop_nothing = true,
            ),
            require,
          ),
        ),
      ),
    ),
    drop_nothing = true,
  ),
)

element_singleton_to_meta_commun = @compat pipe(
  extract_singleton,
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "ANCIEN_ID" => element_singleton_to_text,  # TODO?
      "ID" => pipe(
        element_singleton_to_text,
        validate_id,
        require,
      ),
      "NATURE" => pipe(
        element_singleton_to_text,
        validate_nature,
      ),
      "ORIGINE" => pipe(
        element_singleton_to_text,
        validate_origine,
        require,
      ),
      "URL" => pipe(
        element_singleton_to_text,
        validate_url,
        require,
      ),
    ),
    drop_nothing = true,
  ),
)

element_singleton_to_meta_texte_chronicle = @compat pipe(
  extract_singleton,
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "CID" => pipe(
        element_singleton_to_text,
        validate_cid,
        require,
      ),
      "DATE_PUBLI" => pipe(
        element_singleton_to_text,
        validate_date,
      ),
      "DATE_TEXTE" => pipe(
        element_singleton_to_text,
        validate_date,
      ),
      "DERNIERE_MODIFICATION" => pipe(
        element_singleton_to_text,
        validate_date,
      ),
      "NOR" => pipe(
        element_singleton_to_text,
        validate_nor,
      ),
      "NUM" => pipe(
        element_singleton_to_text,
        validate_num,
      ),
      "NUM_SEQUENCE" => pipe(
        element_singleton_to_text,
        input_to_int,
        test_greater_or_equal(0),  # 0 means nothing.
      ),
      "ORIGINE_PUBLI" => pipe(
        element_singleton_to_text,
        empty_to_nothing,
      ),
      "PAGE_DEB_PUBLI" => pipe(
        element_singleton_to_text,
        input_to_int,
        test_greater_or_equal(0),  # 0 means nothing.
      ),
      "PAGE_FIN_PUBLI" => pipe(
        element_singleton_to_text,
        input_to_int,
        test_greater_or_equal(0),  # 0 means nothing.
      ),
      "VERSIONS_A_VENIR" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "VERSION_A_VENIR" => pipe(
              test_isa(Array),
              uniform_sequence(
                pipe(
                  element_to_text,
                  validate_date,
                  require,
                ),
              ),
              empty_to_nothing,
            ),
          ),
          drop_nothing = true,
        ),
      ),
    ),
    drop_nothing = true,
  ),
)

element_singleton_to_nota = @compat pipe(
  extract_singleton,
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "CONTENU" => element_to_contenu,
    ),
    drop_nothing = true,
  ),
)

element_singleton_to_structure = @compat pipe(
  extract_singleton,
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "LIEN_ART" => pipe(
        test_isa(Array),
        uniform_sequence(
          pipe(
            element_to_lien_article,
            require,
          ),
        ),
        call(links -> sort!(links; by = link -> begin
          start_date = get(link, "@debut") do
            return Date(2999, 1, 1)
          end
          stop_date = get(link, "@fin") do
            return Date(2999, 1, 1)
          end
          return (get(link, "@num", ""), min(start_date, stop_date), stop_date, link["@id"])
        end)),
      ),
      "LIEN_SECTION_TA" => pipe(
        test_isa(Array),
        uniform_sequence(
          pipe(
            test_isa(Dict),
            struct(
              Dict{String, Any}(
                "^tail" => pipe(
                  test_isa(String),
                  strip,
                  test_nothing,
                ),
                "^text" => pipe(
                  test_isa(String),
                  strip,
                  require,
                ),
                "@cid" => pipe(
                  validate_cid,
                  require,
                ),
                "@debut" => validate_date,
                "@etat" => validate_etat,
                "@fin" => validate_date,
                "@id" => pipe(
                  validate_id,
                  require,
                ),
                "@niv" => pipe(
                  test_isa(String),
                  input_to_int,
                  test_between(1, 13),
                  require,
                ),
                "@url" => pipe(
                  validate_url,
                  require,
                ),
              ),
              drop_nothing = true,
            ),
            require,
          ),
        ),
      ),
    ),
    drop_nothing = true,
  ),
)

element_singleton_to_versions = @compat pipe(
  extract_singleton,
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "VERSION" => pipe(
        test_isa(Array),
        uniform_sequence(
          pipe(
            test_isa(Dict),
            struct(
              Dict{String, Any}(
                "^tail" => pipe(
                  test_isa(String),
                  strip,
                  test_nothing,
                ),
                "^text" => pipe(
                  test_isa(String),
                  strip,
                  test_nothing,
                ),
                "@etat" => validate_etat,
                "LIEN_ART" => pipe(
                  extract_singleton,
                  element_to_lien_article,
                ),
                "LIEN_TXT" => pipe(
                  extract_singleton,
                  test_isa(Dict),
                  struct(
                    Dict{String, Any}(
                      "^tail" => pipe(
                        test_isa(String),
                        strip,
                        test_nothing,
                      ),
                      "^text" => pipe(
                        test_isa(String),
                        strip,
                        test_nothing,
                      ),
                      "@debut" => validate_date,
                      "@fin" => validate_date,
                      "@id" => pipe(
                        validate_id,
                        require,
                      ),
                      "@num" => validate_num,
                    ),
                    drop_nothing = true,
                  ),
                ),
              ),
              drop_nothing = true,
            ),
            require,
          ),
        ),
        call(versions -> sort!(versions; by = version -> begin
          link = get(version, "LIEN_ART") do
            return version["LIEN_TXT"]
          end
          start_date = get(link, "@debut") do
            return Date(2999, 1, 1)
          end
          stop_date = get(link, "@fin") do
            return Date(2999, 1, 1)
          end
          return (min(start_date, stop_date), link["@id"])
        end)),
        require,
      ),
    ),
    drop_nothing = true,
  ),
)

element_to_article = @compat pipe(
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "BLOC_TEXTUEL" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "CONTENU" => pipe(
              element_to_contenu,
              require,
            ),
          ),
          drop_nothing = true,
        ),
        require,
      ),
      "CONTEXTE" => pipe(
        element_singleton_to_contexte,
        require,
      ),
      "LIENS" => pipe(
        element_singleton_to_liens,
        require,
      ),
      "META" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "META_COMMUN" => pipe(
              element_singleton_to_meta_commun,
              require,
            ),
            "META_SPEC" => pipe(
              extract_singleton,
              test_isa(Dict),
              struct(
                Dict{String, Any}(
                  "^tail" => pipe(
                    test_isa(String),
                    strip,
                    test_nothing,
                  ),
                  "^text" => pipe(
                    test_isa(String),
                    strip,
                    test_nothing,
                  ),
                  "META_ARTICLE" => pipe(
                    extract_singleton,
                    test_isa(Dict),
                    struct(
                      Dict{String, Any}(
                        "^tail" => pipe(
                          test_isa(String),
                          strip,
                          test_nothing,
                        ),
                        "^text" => pipe(
                          test_isa(String),
                          strip,
                          test_nothing,
                        ),
                        "DATE_DEBUT" => pipe(
                          element_singleton_to_text,
                          validate_date,
                          require,
                        ),
                        "DATE_FIN" => pipe(
                          element_singleton_to_text,
                          validate_date,
                        ),
                        "ETAT" => pipe(
                          element_singleton_to_text,
                          validate_etat,
                        ),
                        "NUM" => pipe(
                          element_singleton_to_text,
                          validate_num,
                        ),
                        "TYPE" => pipe(
                          element_singleton_to_text,
                          test_in(["AUTONOME", "ENTIEREMENT_MODIF", "PARTIELLEMENT_MODIF"]),
                        ),
                      ),
                      drop_nothing = true,
                    ),
                    require,
                  ),
                ),
                drop_nothing = true,
              ),
              require,
            ),
          ),
          drop_nothing = true,
        ),
        require,
      ),
      "NOTA" => pipe(
        element_singleton_to_nota,
        require,
      ),
      "VERSIONS" => pipe(
        element_singleton_to_versions,
        require,
      ),
    ),
    drop_nothing = true,
  ),
)

element_to_section_ta = @compat pipe(
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "COMMENTAIRE" => pipe(
        element_singleton_to_text,
        empty_to_nothing,
      ),
      "CONTEXTE" => pipe(
        element_singleton_to_contexte,
        require,
      ),
      "ID" => pipe(
        element_singleton_to_text,
        validate_id,
        require,
      ),
      "STRUCTURE_TA" => pipe(
        element_singleton_to_structure,
        require,
      ),
      "TITRE_TA" => pipe(
        element_singleton_to_text,
        empty_to_nothing,
        require,
      ),
    ),
    drop_nothing = true,
  ),
)

element_to_texte_version = @compat pipe(
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "ABRO" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "CONTENU" => element_to_contenu,
          ),
          drop_nothing = true,
        ),
        require,
      ),
      "META" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "META_COMMUN" => pipe(
              element_singleton_to_meta_commun,
              require,
            ),
            "META_SPEC" => pipe(
              extract_singleton,
              test_isa(Dict),
              struct(
                Dict{String, Any}(
                  "^tail" => pipe(
                    test_isa(String),
                    strip,
                    test_nothing,
                  ),
                  "^text" => pipe(
                    test_isa(String),
                    strip,
                    test_nothing,
                  ),
                  "META_TEXTE_CHRONICLE" => pipe(
                    element_singleton_to_meta_texte_chronicle,
                    require,
                  ),
                  "META_TEXTE_VERSION" => pipe(
                    extract_singleton,
                    test_isa(Dict),
                    struct(
                      Dict{String, Any}(
                        "^tail" => pipe(
                          test_isa(String),
                          strip,
                          test_nothing,
                        ),
                        "^text" => pipe(
                          test_isa(String),
                          strip,
                          test_nothing,
                        ),
                        "AUTORITE" => pipe(
                          extract_singleton,
                          empty_element_to_nothing,
                        ),
                        "DATE_DEBUT" => pipe(
                          element_singleton_to_text,
                          validate_date,
                        ),
                        "DATE_FIN" => pipe(
                          element_singleton_to_text,
                          validate_date,
                        ),
                        "ETAT" => pipe(
                          element_singleton_to_text,
                          validate_etat,
                        ),
                        "LIENS" => element_singleton_to_liens,
                        "MINISTERE" => pipe(
                          element_singleton_to_text,
                          validate_ministere,
                        ),
                        "TITRE" => pipe(
                          element_singleton_to_text,
                          empty_to_nothing,
                          require,
                        ),
                        "TITREFULL" => pipe(
                          element_singleton_to_text,
                          empty_to_nothing,
                          require,
                        ),
                      ),
                      drop_nothing = true,
                    ),
                    require,
                  ),
                ),
                drop_nothing = true,
              ),
              require,
            ),
          ),
          drop_nothing = true,
        ),
        require,
      ),
      "NOTA" => pipe(
        element_singleton_to_nota,
        require,
      ),
      "RECT" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "CONTENU" => element_to_contenu,
          ),
          drop_nothing = true,
        ),
        require,
      ),
      "SIGNATAIRES" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "CONTENU" => element_to_contenu,
          ),
          drop_nothing = true,
        ),
        require,
      ),
      "TP" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "CONTENU" => element_to_contenu,
          ),
          drop_nothing = true,
        ),
        require,
      ),
      "VISAS" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "CONTENU" => element_to_contenu,
          ),
          drop_nothing = true,
        ),
        require,
      ),
    ),
    drop_nothing = true,
  ),
)

element_to_textelr = @compat pipe(
  test_isa(Dict),
  struct(
    Dict{String, Any}(
      "^tail" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "^text" => pipe(
        test_isa(String),
        strip,
        test_nothing,
      ),
      "META" => pipe(
        extract_singleton,
        test_isa(Dict),
        struct(
          Dict{String, Any}(
            "^tail" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "^text" => pipe(
              test_isa(String),
              strip,
              test_nothing,
            ),
            "META_COMMUN" => pipe(
              element_singleton_to_meta_commun,
              require,
            ),
            "META_SPEC" => pipe(
              extract_singleton,
              test_isa(Dict),
              struct(
                Dict{String, Any}(
                  "^tail" => pipe(
                    test_isa(String),
                    strip,
                    test_nothing,
                  ),
                  "^text" => pipe(
                    test_isa(String),
                    strip,
                    test_nothing,
                  ),
                  "META_TEXTE_CHRONICLE" => pipe(
                    element_singleton_to_meta_texte_chronicle,
                    require,
                  ),
                ),
                drop_nothing = true,
              ),
              require,
            ),
          ),
          drop_nothing = true,
        ),
        require,
      ),
      "STRUCT" => pipe(
        element_singleton_to_structure,
        require,
      ),
      "VERSIONS" => pipe(
        element_singleton_to_versions,
        require,
      ),
    ),
    drop_nothing = true,
  ),
)


text:
include("core.jl")

e = ℯ
oo = Inf

eqnRegex = let eqnexp(name) = string("(?<$(name)>", raw"(?:\{.*\})|(?:[^\s]+))"),
    sub_then_sup = string("(?:sub\\s+", eqnexp("a1"), "\\s+sup\\s+", eqnexp("b2"), ")"),
    sup_then_sub = string("(?:sup\\s+", eqnexp("b1"), "\\s+sub\\s+", eqnexp("a2"), ")"),
    indices = "(?:(?:$(sub_then_sup)|$(sup_then_sub))\\s+)?"
    string("^\\s*int\\s+", indices, eqnexp("ex"), "\$") |> Regex
end

eqnRules = Dict(
    "{" => "(",
    "}" => ")",
    r"\s+ sup  \s+"x => "^",
    r"\s+ over \s+"x => "/"
)

function eqnToJulia(ex)
    for rule ∈ eqnRules
        ex = replace(ex, rule)
    end
    Meta.parse(ex)
end

function calculate(int::Expr, (a, b))
    @eval f(x) = $int

    ε = eps(Float64)
    if !isfinite(f(a))
        a += ε
    end
    if !isfinite(f(b))
        b -= ε
    end

    result = f(b) - f(a)
    isfinite(result) ? result : error("функция не интегрируема на заданном интервале.")
end

calculate(int::Expr, bounds::Nothing) = int

calculate(::Nothing, _) = error("неизестный интеграл.")

function wrapInf(x)
    x == Inf  && return :oo
    x == -Inf && return :(-oo)
    x
end
wrap(ex::Expr) = "($(walk(wrapInf, ex)))"
wrap(x) = "$(wrapInf(x))"

try
    print("Введите выражение Eqn: \n> ")
    int = readline()
    m = match(eqnRegex, int)
    m==nothing && error("некорректный ввод.")

    a, b = defaultTo(m["a1"], m["a2"]), defaultTo(m["b1"], m["b2"])
    if (a, b) == (nothing, nothing)
        bounds = nothing
    else
        α, β = eqnToJulia(a), eqnToJulia(b)
        bounds = eval(α), eval(β)
    end

    ex = eqnToJulia(m["ex"])
    integral = integrate(ex, :x)
    result = calculate(integral, bounds)

    if bounds ≠ nothing
        ascii_bounds = " _$(wrap(bounds[1])) ^$(wrap(bounds[2]))"
        result_rounded = round(result * 1000) / 1000
        eq_sign = result_rounded == result ? "=" : "~~"
        print(string("int", ascii_bounds, "$(wrap(ex))dx $(eq_sign) ", result_rounded))
    else
        print(string("int", "$(wrap(ex))dx = ", result))
    end
catch e
    if e isa Meta.ParseError
        println("Ошибка парсинга выражения: $(e.msg)")
    elseif e isa ErrorException
        println("Ошибка: $(e.msg)")
    else
        rethrow()
    end
end

print("\nНажмите любую клавишу")
readline()
nothing

ext: jl


text:
using NetCDF, LinearAlgebra
using Statistics, StatsBase
using PyCall
xr = pyimport("xarray")
#pygui(:qt)
using PyPlot
using MultivariateStats
# eofs = pyimport("eofs")

path = "/Users/milan/Downloads/cams/ieee"
filelist = filter(x->endswith(x,"no2.grib"),readdir(path))
gribfile = xr.open_dataset(joinpath(path,filelist[1]),engine="cfgrib")
no2 = gribfile.no2.values
level = 1:size(no2)[1]

no2m = mean(no2,dims=2)[:,1]
no2mi = median(no2,dims=2)[:,1]
no2min = minimum(no2,dims=2)[:,1]
no2max = maximum(no2,dims=2)[:,1]
no2p10 = [percentile(vec(no2[i,:]),10) for i in level]
no2p90 = [percentile(vec(no2[i,:]),90) for i in level]

## EOF in the vertical
M = fit(PCA,log10.(no2),maxoutdim=50,pratio=0.9999)
no2hat = transform(M,log10.(no2))
no2r = 10f0 .^reconstruct(M,no2hat)

## reconstruction statistics
no2rm = mean(no2r,dims=2)[:,1]
no2rmi = median(no2r,dims=2)[:,1]
no2rmin = minimum(no2r,dims=2)[:,1]
no2rmax = maximum(no2r,dims=2)[:,1]
no2rp10 = [percentile(vec(no2r[i,:]),10) for i in level]
no2rp90 = [percentile(vec(no2r[i,:]),90) for i in level]

## error
decimal_error = abs.(log10.(no2 ./ no2r))

dem = mean(decimal_error,dims=2)[:,1]
demi = median(decimal_error,dims=2)[:,1]
demin = minimum(decimal_error,dims=2)[:,1]
demax = maximum(decimal_error,dims=2)[:,1]
dep10 = [percentile(vec(decimal_error[i,:]),10) for i in level]
dep90 = [percentile(vec(decimal_error[i,:]),90) for i in level]

## highest loadings
P = projection(M)
Ps = zeros(Int64,size(P))
for i in 1:size(Ps)[2]
    Ps[:,i] = sortperm(abs.(P[:,i]))
end
L = zeros(Int64,size(P)[2])
L[1] = Ps[end,1]
for i in 2:length(L)
    j = 0
    while Ps[end-j,i] in L
        j += 1
    end
    L[i] = Ps[end-j,i]
end

## plot
fig,(ax,ax2,ax3) = subplots(1,3,figsize=(10,6),sharey=true)
ax.invert_yaxis()

ax.semilogx(no2m,level,"C0",lw=3,label="mean")
ax.plot(no2mi,level,"C0",lw=1.5,label="median")
ax.fill_betweenx(level,no2min,no2max,color="C0",alpha=0.2,label="Min-max range")
ax.fill_betweenx(level,no2p10,no2p90,color="C0",alpha=0.5,label="10-90% range")

ax2.semilogx(no2rm,level,"C0",lw=3,label="mean")
ax2.plot(no2rmi,level,"C0",lw=1.5,label="median")
ax2.fill_betweenx(level,no2rmin,no2rmax,color="C0",alpha=0.2,label="Min-max range")
ax2.fill_betweenx(level,no2rp10,no2rp90,color="C0",alpha=0.5,label="10-90% range")

for i in level
    xvals = no2[i,(decimal_error[i,:] .>= 0.5f0) .* (decimal_error[i,:] .< 1f0)]
    ax.scatter(xvals,i*ones(length(xvals)),10,"yellow",alpha=0.05)

    xvals = no2[i,(decimal_error[i,:] .>= 1f0) .* (decimal_error[i,:] .< 2f0)]
    ax.scatter(xvals,i*ones(length(xvals)),10,"C1",alpha=0.1)
end

ax.scatter([1,2,3],[0,0,0],10,"yellow",alpha=0.5,label="error > 0.5")
ax.scatter([1,2,3],[0,0,0],10,"C1",alpha=0.5,label="error > 1")

ax3.semilogx(dem,level,"C0",lw=3,label="mean")
ax3.plot(demi,level,"C0",lw=1.5,label="median")
ax3.fill_betweenx(level,demin,demax,color="C0",alpha=0.2,label="Min-max range")
ax3.fill_betweenx(level,dep10,dep90,color="C0",alpha=0.5,label="10-90% range")

cmap = ColorMap("viridis")
for i in 1:length(L)
    ax2.plot([1e-14,1e-13],[L[i],L[i]].-0.5,color=cmap(i/length(L)),lw=2)
    ax2.text(2e-13,L[i],"$i")
end
ax2.text(1.5e-14,8,"modes")

ax.set_title(L"NO$_2$ vertical distribution")
ax2.set_title(L"NO$_2$ reconstructed from 50 PCs")
ax3.set_title("L1 log-error")
ax.set_ylabel("model level")
ax.set_xlabel("mixing ratio kg/kg")
ax2.set_xlabel("mixing ratio kg/kg")
ax.set_ylim(137,1)
ax.legend(loc=2,scatterpoints=3)

ax.set_xlim(1e-14,1e-6)
ax2.set_xlim(1e-14,1e-6)

tight_layout()


text:
module PhysChem

include("chemkinet.jl")
include("solub.jl")
include("reactions.jl")

# export submodule functions to the current level
using .ChemKinet
using .Solub
using .Reactions

end  # module


text:
"""
    ECPInterval <: ConfidenceInterval

Exact Clopper-Pearson type confidence interval based on ordering induced by `estimator`.
"""
struct ECPInterval{TE<:Estimator,TR<:Real} <: ConfidenceInterval

  estimator::TE
  confidence::TR
  limits::Array{TR,3}

  function ECPInterval{TE,TR}(
    estimator::TE,
    confidence::TR,
    k::Integer
  ) where {TE<:Estimator,TR<:Real}

    @checkprob confidence
    d      = design(estimator)
    n1     = interimsamplesize(d)
    nmax   = maximum(samplesize(d))
    limits = fill(NaN, n1 + 1, nmax - n1 + 1, 2)
    supp   = support(d)

    n1     = interimsamplesize(d)
    nmax   = maximum(samplesize(d))
    grid   = collect(linspace(0, 1, k))
    supp   = support(d) # compute p values by hand is faster than calling p()
    tmp    = zeros(Float64, size(supp, 1), k)
    estimates = estimate.(estimator, supp[:, 1], supp[:, 2])
    for i in 1:size(supp, 1)
        tmp[i, :] = pdf.(d, supp[i, 1], supp[i, 2], linspace(0, 1, k))
    end
    probs = [supp samplesize.(d, supp[:, 1]) estimates tmp]
    probs = sortrows(probs, by = x -> x[4], rev = true) # sort in descending order of estimates
    # compute p vals for H0: p < p0
    pvals_leq = probs |> x -> cumsum(x, 1)
    pvals_leq[:, 1:4] = probs[:, 1:4]

    # compute pvals for H0: p > p0
    pvals_geq = sortrows(probs, by = x -> x[4]) |> x -> cumsum(x, 1)
    pvals_geq[:, 1:4] = sortrows(probs, by = x -> x[4])[:, 1:4]
    pvals_geq = sortrows(pvals_geq, by = x -> x[4], rev = true)

    for i in 1:size(supp, 1)
      x1, x2 = supp[i, :]
      limits[x1 + 1, x2 + 1, :] = get_limits(d, x1, x2, confidence, pvals_leq, pvals_geq, grid, k)
    end
    new(estimator, confidence, limits)

  end # inner constructor

end # ECPInterval

"""
    ECPInterval{T<:Real}(
      estimator::Estimator;
      confidence::T = .9,
      k::Integer = 1001
    )

Exact Clopper-Pearson type confidence interval based on ordering induced by `estimator`.

# Parameters

| Parameter    | Description |
| -----------: | :---------- |
| estimator    | estimator object defining the sample space ordering |
| confidence   | confidence level of the interval |
| k            | number of equally spaced grid-points for invertign the test |
"""
function ECPInterval(
  estimator::TE;
  confidence::TR = .9,
  k::Integer = 1001
) where {TE<:Estimator,TR<:Real}

  return ECPInterval{TE,TR}(estimator, confidence, k)

end

Base.show(io::IO, ci::ECPInterval) = print("ECPInterval")

estimator(ci::ECPInterval) = ci.estimator

design(ci::ECPInterval) = ci |> estimator |> design

function get_limits(
  d::Design, x1::T1, x2::T1, confidence::T2, pvals_leq, pvals_geq, grid, k::T1
) where {T1<:Integer, T2<:Real}

  pvals_leq = pvals_leq[(pvals_leq[:, 1] .== x1) .& (pvals_leq[:, 2] .== x2), 5:(k + 4)][1, :]
  pvals_geq = pvals_geq[(pvals_geq[:, 1] .== x1) .& (pvals_geq[:, 2] .== x2), 5:(k + 4)][1, :]

  indlow = findfirst(pvals_leq .>= (1 - confidence)/2.0)
  indlow = indlow == 0 ? 1 : indlow
  indup  = findlast(pvals_geq .>= (1 - confidence)/2.0)
  indup  = indup == 0 ? k : indup
  limits = [grid[indlow]; grid[indup]]
  if indlow == 1
      limits[1] = 0.0
  end
  if indup == k
      limits[2] = 1.0
  end
  if x1 + x2 == 0
      limits[1] = 0.0
  end
  if x1 + x2 == samplesize(d, x1)
      limits[2] = 1.0
  end
  return limits

end

function limits(ci::ECPInterval, x1::T, x2::T) where {T<:Integer}

  ispossible(design(ci), x1, x2) ? nothing : error("x1 x2 combination not possible")
  return convert(Vector{Float64}, view([ci.limits[x1 + 1, x2 + 1, 1] ci.limits[x1 + 1, x2 + 1, 2]], 1:2))

end

max_stars_repo_name: kkmann/binaryTwoStageDesigns

max_issues_repo_name: kkmann/binaryTwoStageDesigns

max_forks_repo_name: kkmann/binaryTwoStageDesigns


text:
module JungleHelperAutoFallingBlockDelayed
using ..Ahorn, Maple

@mapdef Entity "JungleHelper/AutoFallingBlockDelayed" AutoFallingBlockDelayed(x::Integer, y::Integer, width::Integer = 8, height::Integer = 8, tiletype::String = "0",delay::Number=2.0,ShakeDelay::Number=0.5, silent::Bool=false)

const placements = Ahorn.PlacementDict(
	"Delayed Auto-Falling Block (Jungle Helper)" => Ahorn.EntityPlacement(
		AutoFallingBlockDelayed,
		"rectangle",
		Dict{String, Any}(),
		Ahorn.tileEntityFinalizer
	)
)

Ahorn.editingOptions(entity::AutoFallingBlockDelayed) = Dict{String, Any}(
	"tiletype" => Ahorn.tiletypeEditingOptions()
)

Ahorn.minimumSize(entity::AutoFallingBlockDelayed) = 8, 8
Ahorn.resizable(entity::AutoFallingBlockDelayed) = true, true

Ahorn.selection(entity::AutoFallingBlockDelayed) = Ahorn.getEntityRectangle(entity)

Ahorn.renderAbs(ctx::Ahorn.Cairo.CairoContext, entity::AutoFallingBlockDelayed, room::Maple.Room) = Ahorn.drawTileEntity(ctx, room, entity)

end

max_stars_repo_name: Jackal-Celeste/JungleHelper

max_issues_repo_name: Jackal-Celeste/JungleHelper

max_forks_repo_name: Jackal-Celeste/JungleHelper


text:
__precompile__(true)

module BumpFuncs

export
    bump,
    dbump,
    ddbump

include("functions.jl")

end


text:
# Auxilary functions
# Arc functions ────────────────────────────────────────────────────────────────────────────────
"""
    cₐ(a::Arc, x=a.x)

Returns arc cost for arc `a` for arc flow `x`
"""
function cₐ(a::Arc, x=a.x)
    tₒ= a.tₒ
    α = a.α
    β = a.β
    V = a.V
    ϕ = a.ϕ

    t = tₒ * (1 + α * (x/V) ^ β)
    t′= ϕ == 0 || β == 0 ? 0.0 : tₒ * α * β * (x ^ (β - 1))/(V ^ β)

    c = t + ϕ * x * t′
    return c
end

"""
    cₐ′(a::Arc, x=a.x)

Returns first derivative of arc cost wrt arc flow for arc `a` at arc flow `x`
"""
function cₐ′(a::Arc, x=a.x)
    tₒ= a.tₒ
    α = a.α
    β = a.β
    V = a.V
    ϕ = a.ϕ

    t′= β == 0 ? 0.0 : tₒ * α * β * (x ^ (β - 1))/(V ^ β)
    t″ = ϕ == 0 || β == 0 || β == 1 ?  0.0 : tₒ * α * β * (β - 1) * (x ^ (β - 2))/(V ^ β)

    c′ = t′ + ϕ * x * t″
    return c′
end

# Djikstra functions ────────────────────────────────────────────────────────────────────────────────
# NOTE: Node values must match node location (index) in the set of nodes N

"""
    djk(G::Graph, o::Origin)

Djikstra's label setting algorithm

Returns predecessor arc label (index in vector `A`) `Lᵖ` for least cost paths from origin `o` on graph `G`
"""
function djk(G::Graph, o::Origin)
    N = G.N
    A = G.A
    K = G.K
    r = o.n

    Lᵖ = Vector{Int64}(undef, length(N))     # Predecessor label
    Lᶜ = [Inf for _ in N]                    # Cost label
    Lᵖ[r.v] = -1
    Lᶜ[r.v] = 0.0

    X = copy(N)                              # Set of open nodes

    index = findfirst(x -> (x == r), X)::Int64
    t = X[index]
    deleteat!(X, index)
    while !isempty(X)
        i = t.v
        for j in t.H
            k = K[i,j]
            a = A[k]
            l = Lᶜ[i] + a.c
            if l ≤ Lᶜ[j] Lᵖ[j], Lᶜ[j] = k, l
            end
        end
        index = argmin([Lᶜ[n.v] for n in X])
        t = X[index]
        deleteat!(X, index)
    end

    return Lᵖ
end

"""
    tree(G::Graph, o::Origin)

Returns tree for graph `G` rooted at origin `o`
"""
function tree(G::Graph, Lᵖ)
    N = G.N
    A = G.A

    T = Vector{Node}[[] for _ in N]

    for k in Lᵖ
        if k == -1 continue end
        a = A[k]
        t, h = a.t, a.h
        i = t.v
        push!(T[i], h)
    end

    return T
end

"""
    path(G::Graph, Lᵖ, r::Node, s::Node)

Returns path between origin node `r` and destination node `s` on graph `G` using predecessor label `Lᵖ` (for origin node `r`)
"""
function path(G::Graph, Lᵖ, r::Node, s::Node)
    A = G.A

    p = Arc[]

    h = s
    j = h.v
    while j ≠ r.v
        k = Lᵖ[j]
        a = A[k]
        push!(p, a)
        j = a.t.v
    end

    reverse!(p)
    return p
end
# ────────────────────────────────────────────────────────────────────────────────


text:
#### Caching

## Ac'* for QROperatorQ

function mul_pars(Ac::Adjoint{<:Any,<:QROperatorQ},B::AbstractVector,tolerance,maxlength)
    A = parent(Ac)
    T = promote_type(eltype(A),eltype(B))
    mulpars(Operator{T}(A)',Array{T}(B),tolerance,maxlength)
end

include("matrix.jl")
include("ragged.jl")
include("banded.jl")
include("almostbanded.jl")
include("blockbanded.jl")
include("bandedblockbanded.jl")


text:
abstract type AbstractAccretionGeometry{T} end
abstract type AbstractAccretionDisc{T} <: AbstractAccretionGeometry{T} end

function to_cartesian(vec::AbstractVector{T}) where {T}
    SVector{3,T}(to_cartesian(vec[2], vec[3], vec[4])...)
end

function to_cartesian(r, ϕ, θ)
    sinϕ = sin(ϕ)
    (r * sinϕ * cos(θ), r * sinϕ * sin(θ), r * cos(ϕ))
end

function cartesian_line_element(u::ArrayPartition{F,T}, integrator) where {F,T}
    (to_cartesian(integrator.uprev.x[2]), to_cartesian(u.x[2]))
end

function cartesian_line_element(u, integrator)
    (to_cartesian(integrator.uprev), to_cartesian(u))
end

function line_element(u::ArrayPartition{F,T}, integrator) where {F,T}
    @inbounds (@view(integrator.uprev.x[2][2:4]), @view(u.x[2][2:4]))
end

function line_element(u, integrator)
    @inbounds (@view(integrator.uprev[2:4]), @view(u[2:4]))
end


text:
import Pkg
using LanguageServer, LanguageServer.SymbolServer

envpath = dirname(Pkg.Types.Context().env.project_file)

const DEPOT_DIR_NAME = ".julia"
depotpath = if Sys.iswindows()
    joinpath(ENV["USERPROFILE"], DEPOT_DIR_NAME)
else
    joinpath(ENV["HOME"], DEPOT_DIR_NAME)
end

runserver()

max_stars_repo_name: AtsushiSakai/dotfiles

max_issues_repo_name: AtsushiSakai/dotfiles

max_forks_repo_name: AtsushiSakai/dotfiles


text:
using Rotations

"""
    hopper 3D
        orientation representation: modified rodrigues parameters
		similar to Raibert hopper, all mass is located at the body
		x = (px, py, pz, tx, ty, tz, r)
"""
struct Hopper3D{T}
    n::Int
    m::Int
    d::Int

	mb::T # mass of body
    ml::T # mass of leg
    Jb::T # inertia of body
    Jl::T # inertia of leg

    μ::T  # coefficient of friction
    g::T  # gravity

    qL::Vector{T}
    qU::Vector{T}

    nq
    nu
    nc
    nf
    nb

    idx_u
    idx_λ
    idx_b
    idx_ψ
    idx_η
    idx_s

end

# Dimensions
nq = 7 # configuration dimension
nu = 3 # control dimension
nc = 1 # number of contact points
nf = 4 # number of faces for friction cone pyramid
nb = nc * nf
ns = 1

n = 2 * nq
m = nu + nc + nb + nc + nb + 1
d = 0

idx_u = (1:nu)
idx_λ = nu .+ (1:nc)
idx_b = nu + nc .+ (1:nb)
idx_ψ = nu + nc + nb .+ (1:nc)
idx_η = nu + nc + nb + nc .+ (1:nb)
idx_s = nu + nc + nb + nc + nb .+ (1:ns)

# Parameters
g = 9.81 # gravity
μ = 1.0  # coefficient of friction
mb = 10.0 # body mass
ml = 1.0  # leg mass
Jb = 2.5 # body inertia
Jl = 0.25 # leg inertia

# Kinematics
function kinematics(::Hopper3D, q)
	p = view(q, 1:3)
	R = MRP(view(q, 4:6)...)
	p + R*[0.0; 0.0; -1.0 * q[7]]
end

# Methods
function M_func(model::Hopper3D, q)
	Diagonal(@SVector [model.mb + model.ml, model.mb + model.ml, model.mb + model.ml,
					   model.Jb + model.Jl, model.Jb + model.Jl, model.Jb + model.Jl,
					   model.ml])
end

function G_func(model::Hopper3D, q)
	@SVector [0.0, 0.0, (model.mb + model.ml) * model.g, 0.0, 0.0, 0.0, 0.0]
end

function ϕ_func(model::Hopper3D, q)
    @SVector [kinematics(model, q)[3]]
end

function B_func(::Hopper3D, q)
    rot = view(q, 4:6)
    R = MRP(rot...)
    @SMatrix [0.0 0.0 0.0 R[1,1] R[2,1] R[3,1] 0.0;
              0.0 0.0 0.0 R[1,2] R[2,2] R[3,2] 0.0;
			  R[1,3] R[2,3] R[3,3] 0.0 0.0 0.0 1.0]
end

function N_func(model::Hopper3D, q)
	k(z) = [kinematics(model, z)[3]]
    ForwardDiff.jacobian(k, q)
end

function P_func(model::Hopper3D, q)
    map = [1.0 0.0;
           0.0 1.0;
           -1.0 0.0;
           0.0 -1.0]

    k(z) = kinematics(model, z)[1:2]
    map * ForwardDiff.jacobian(k, q)
end

function friction_cone(model::Hopper3D,u)
    λ = u[model.idx_λ]
    b = u[model.idx_b]

    @SVector [model.μ * λ[1] - sum(b[1:4])]
end

function maximum_dissipation(model::Hopper3D, x⁺, u, h)
    q3 = x⁺[model.nq .+ (1:model.nq)]
	q2 = x⁺[1:model.nq]

    ψ = u[model.idx_ψ]
    ψ_stack = ψ[1] * ones(4)
    η = u[model.idx_η]

    P_func(model, q3) * (q3 - q2) / h + ψ_stack - η
end

function fd(model::Hopper3D, x⁺, x, u, w, h, t)
	q3 = view(x⁺, model.nq .+ (1:model.nq))
	q2⁺ = view(x⁺, 1:model.nq)
	q2⁻ = view(x, model.nq .+ (1:model.nq))
	q1 = view(x, 1:model.nq)
	u_ctrl = view(u, model.idx_u)
	λ = view(u, model.idx_λ)
	b = view(u, model.idx_b)

    [q2⁺ - q2⁻;
    ((1.0 / h) * (M_func(model, q1) * (SVector{7}(q2⁺) - SVector{7}(q1))
    - M_func(model, q2⁺) * (SVector{7}(q3) - SVector{7}(q2⁺)))
    + transpose(B_func(model, q3)) * SVector{3}(u_ctrl)
    + transpose(N_func(model, q3)) * SVector{1}(λ)
    + transpose(P_func(model, q3)) * SVector{4}(b)
    - h * G_func(model, q2⁺))]
end

r = 0.7
qL = -Inf * ones(nq)
qU = Inf * ones(nq)
qL[7] = r / 2.0
qU[7] = r

model = Hopper3D(n, m, d,
			mb, ml, Jb, Jl,
			μ, g,
			qL, qU,
            nq, nu, nc, nf, nb,
            idx_u,
            idx_λ,
            idx_b,
            idx_ψ,
            idx_η,
            idx_s)

function visualize!(vis, model::Hopper3D, q;
	Δt = 0.1)

	r_foot = 0.05
	setobject!(vis["body"], Sphere(Point3f0(0),
	   convert(Float32, 0.1)),
	   MeshPhongMaterial(color = RGBA(0, 1, 0, 1.0)))
	setobject!(vis["foot"], Sphere(Point3f0(0),
	   convert(Float32, r_foot)),
	   MeshPhongMaterial(color = RGBA(1, 0, 0, 1.0)))

	r_leg = 0.5 * r_foot
	n_leg = 100
	for i = 1:n_leg
	   setobject!(vis["leg$i"], Sphere(Point3f0(0),
	       convert(Float32, r_leg)),
	       MeshPhongMaterial(color = RGBA(0, 0, 0, 1.0)))
	end
	p_leg = [zeros(3) for i = 1:n_leg]
	anim = MeshCat.Animation(convert(Int,floor(1.0 / Δt)))

	z_shift = [0.0 ; 0.0; r_foot]
	for t = 1:length(q)
	   p_body = q[t][1:3]

	   q_tmp = Array(copy(q[t]))
	   r_range = range(0.0, stop = q[t][7], length = n_leg)
	   for i = 1:n_leg
	       q_tmp[7] = r_range[i]
	       p_leg[i] = kinematics(model, q_tmp)
	   end
	   q_tmp[7] = q[t][7]
	   p_foot = kinematics(model, q_tmp)

	   MeshCat.atframe(anim, t) do
	       settransform!(vis["body"], Translation(p_body + z_shift))
	       settransform!(vis["foot"], Translation(p_foot + z_shift))

	       for i = 1:n_leg
	           settransform!(vis["leg$i"], Translation(p_leg[i] + z_shift))
	       end
	   end
	end
	MeshCat.setanimation!(vis, anim)
end

max_stars_repo_name: zacmanchester/DirectMotionPlanning

max_issues_repo_name: zacmanchester/DirectMotionPlanning

max_forks_repo_name: zacmanchester/DirectMotionPlanning


text:
import LightGraphs: rem_vertex!
import Base: copy

"""
    ZXLayout

A struct for the layout information of `ZXDiagram` and `ZXGraph`.
"""
struct ZXLayout{T<:Integer}
    nbits::Int
    spider_q::Dict{T, Int}
    spider_col::Dict{T, Rational{Int}}
end

ZXLayout(nbits::Integer, spider_q::Dict{T, Int}, spider_col::Dict{T, Rational{Int}}) where {T} = ZXLayout{T}(Int(nbits), spider_q, spider_col)
ZXLayout{T}() where {T} = ZXLayout(0, Dict{T, Int}(), Dict{T, Rational{Int}}())

copy(layout::ZXLayout) = ZXLayout(layout.nbits, copy(layout.spider_q), copy(layout.spider_col))
function rem_vertex!(layout::ZXLayout{T}, v::T) where {T}
    delete!(layout.spider_q, v)
    delete!(layout.spider_col, v)
    return
end

"""
    qubit_loc(layout, v)

Return the qubit number corresponding to the spider `v`.
"""
qubit_loc(layout::ZXLayout{T}, v::T) where T = get(layout.spider_q, v, nothing)

"""
    column_loc(layout, v)

Return the column number corresponding to the spider `v`.
"""
column_loc(layout::ZXLayout{T}, v::T) where T = get(layout.spider_col, v, nothing)

"""
    set_qubit!(layout, v, q)

Set the qubit number of the spider `v`.
"""
function set_qubit!(layout::ZXLayout{T}, v::T, q) where T
    layout.spider_q[v] = q
    return layout
end

"""
    set_qubit!(layout, v, q)

Set the column number of the spider `v`.
"""
function set_column!(layout::ZXLayout{T}, v::T, col) where T
    layout.spider_col[v] = col
    return layout
end

"""
    set_loc!(layout, v, q, col)

Set the location of the spider `v`.
"""
function set_loc!(layout::ZXLayout{T}, v::T, q, col) where T
    set_qubit!(layout, v, q)
    set_column!(layout, v, col)
    return layout
end


text:
using Singular

function add(l1 :: Vector{spoly{A}}, l2 :: Vector{spoly{A}}) where A
  length(l1) == length(l2) || error("vector dimensions not equal")
  ln = length(l1)
  R = parent(l1[1])
  carry = zero(R)
  l3 = [zero(R) for _ in 1:ln]
  for ix in 1:ln
    l3[ix] = carry+l1[ix]+l2[ix]
    #note that xy ∨ xz ∨ yz == xy + xz + yz
    carry = carry*l1[ix]+carry*l2[ix]+l1[ix]*l2[ix]
  end
  return l3
end

function sub(l1 :: Vector{spoly{A}}, l2 :: Vector{spoly{A}}) where A
  length(l1) == length(l2) || error("vector dimensions not equal")
  ln = length(l1)
  R = parent(l1[1])
  carry = one(R)
  l3 = [zero(R) for _ in 1:ln]
  for ix in 1:ln
    l3[ix] = carry+l1[ix]+l2[ix]+one(R)
    #note that xy ∨ xz ∨ yz == xy + xz + yz
    carry = carry*l1[ix]+carry*(l2[ix]+one(R))+l1[ix]*(l2[ix]+one(R))
  end
  return l3
end

function shr(u :: Vector{spoly{A}}; step :: Int = 1) where A
  length(u) > 0 || error("vector dimension equal to zero")
  R = parent(u[1])
  v = [zero(R) for _ in 1:length(u)]
  for ix in 1:length(u)-step
    v[ix] = u[ix+step]
  end
  return v
end

function and(l1 :: Vector{spoly{A}}, l2 :: Vector{spoly{A}}) where A
  length(l1) == length(l2) || error("vector dimensions not equal")
  ln = length(l1)
  R = parent(l1[1])
  l3 = [zero(R) for _ in 1:ln]
  for ix in 1:ln
    l3[ix] = l1[ix]*l2[ix]
  end
  return l3
end

#note: returns a vector of length `length(u)+step`
function shl_ext(u :: Vector{spoly{A}}; step :: Int = 1) where A
  length(u) > 0 || error("vector dimension equal to zero")
  R = parent(u[1])
  v = [zero(R) for _ in 1:(length(u)+step)]
  for ix in step+1:length(u)+step
    v[ix] = u[ix-step]
  end
  return v
end

#note: returns a vector of length `length(l1)+1`
function add_ext(l1 :: Vector{spoly{A}}, l2 :: Vector{spoly{A}}) where A
  length(l1) == length(l2) || error("vector dimensions not equal")
  ln = length(l1)
  R = parent(l1[1])
  carry = zero(R)
  l3 = [zero(R) for _ in 1:ln+1]
  for ix in 1:ln
    l3[ix] = carry+l1[ix]+l2[ix]
    #note that xy ∨ xz ∨ yz == xy + xz + yz
    carry = carry*l1[ix]+carry*l2[ix]+l1[ix]*l2[ix]
  end
  l3[ln+1] = carry
  return l3
end

function mapreduce(l::Vector{spoly{A}}, I::sideal{spoly{A}}) where A
  return map(x->reduce(x,I),l)
end

vars = ["b$ix" for ix in 0:15]
R, b = PolynomialRing(Fp(2), vars)
I = Ideal(R, [b[ix]^2-b[ix] for ix in 1:16])
I = std(I) #compute Gröbner basis of I
(b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15) = b
reduce(b0^2+b1^3, I)

#0f = 00001111
#01 = 00000001
_5555 = [one(R),zero(R),one(R),zero(R),one(R),zero(R),one(R),zero(R),
         one(R),zero(R),one(R),zero(R),one(R),zero(R),one(R),zero(R)]
_3333 = [one(R),one(R),zero(R),zero(R),one(R),one(R),zero(R),zero(R),
         one(R),one(R),zero(R),zero(R),one(R),one(R),zero(R),zero(R)]
_0f0f = [one(R),one(R),one(R),one(R),zero(R),zero(R),zero(R),zero(R),
         one(R),one(R),one(R),one(R),zero(R),zero(R),zero(R),zero(R)]
g = [b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15]

di1 = deepcopy(g);
dx1 = shr(di1);
dx2 = and(dx1,_5555);

#di1 - dx2

di2 = sub(di1,dx2);
di3 = mapreduce(di2,I);
ax1 = deepcopy(di3);
di4 = shr(di3; step=2);
ax2 = and(ax1, _3333);
di5 = and(di4, _3333);
ax3 = mapreduce(ax2, I);
di6 = mapreduce(di5, I);
di7 = add(di6, ax3);
di8 = mapreduce(di7, I);
ax4 = deepcopy(di8);
ax5 = shr(ax4; step=4);
ax6 = add(ax5, di8);
ax7 = mapreduce(ax6, I);
ax8 = and(ax7, _0f0f);
ax9 = mapreduce(ax8, I);
#imul   ax,ax,0x0101
#0x0101 = 0b0000000100000001
ax10 = [ax9[1],ax9[2],ax9[3],ax9[4],ax9[5],ax9[6],ax9[7],ax9[8],
         ax9[9],ax9[10],ax9[11],ax9[12],ax9[13],ax9[14],ax9[15],ax9[16],
         zero(R),zero(R),zero(R),zero(R),zero(R),zero(R),zero(R),zero(R)];
ax11 = shl_ext(ax9; step=8);
ax12 = add_ext(ax10,ax11);
ax13 = mapreduce(ax12, I)
#shr ax, 0x8
ax14 = [ax13[9],ax13[10],ax13[11],ax13[12],
        ax13[13],ax13[14],ax13[15],ax13[16],
        zero(R),zero(R),zero(R),zero(R),
        zero(R),zero(R),zero(R),zero(R)]

function equiv(u::BitVector)
  n = sum(a)
  v = [0 for _ in 1:32]
  v[1] = n % 2
  ix = 1
  while 2^ix <= n
    v[ix+1] = binomial(n,2^ix) % 2
    ix += 1
  end
  return v
end


text:
#=
    Input Parsing (for text) API
    ----------------------------

Parsing is performed by calling:

    parse_input(env, request)

where:
    `env::SearchEnv` is the search environment object
    `request::InternalRequest` is the request

The input_parser is generated by `parse_input` and its signature should be of the form:

    some_input_parser(env, request [;separator=DEFAULT_QUERY_PARSING_SEPARATOR, searchable_filters=[])

where:
    `env::SearchEnv` is the data environment object (i.e. no `searchers` field in the named tuple)
    `request::InternalRequest` is the request
    `separator` is a separator key-value separator
    `searchable_filters` are names of columns in the data whose values are to be added to the search query

The input parser function returns a named tuple with fields:
    • `search::AbstractString` which is the search query
    • `filter::Dict{Symbol, Any}` which represents filtering information
=#
function parse_input(env, request)
    input_parser = safe_symbol_eval(request.input_parser, DEFAULT_INPUT_PARSER_NAME)
    env_data = build_data_env(env)
    return input_parser(env_data, request; searchable_filters=request.searchable_filters)
end

# The pre-parser supports specification of another parser (including itself)
# into the query. It searches for the "magic" pattern, in this case
# `parser_name>`. For example, the query:
#
# "pre_parser> pre_parser> noop_input_parser> query text"
#
# has 3 parser specifications and willrecursively call the pre-parser 2 times until
# another parser, in the case the `noop_input_parser` is ecountered.
# If no other parser is available, it will default to the DEFAULT_INPUT_PARSER_NAME
# by virtue of evaluating an empty parser name.
function pre_parser(env, request, args...; magic=r"^[\s]*[\w]+[\s]*>", kwargs...)
    m = match(magic, request.query)
    parser_name = DEFAULT_INPUT_PARSER_NAME
    if m !== nothing
        request.query = strip(replace(request.query, magic=>""))                # strip parser magic from query
        parser_name = Symbol(strip(replace(m.match, last(magic.pattern)=>"")))  # extract parser name
    end
    input_parser = safe_symbol_eval(parser_name, DEFAULT_INPUT_PARSER_NAME)     # evaluate parser
    @debug "PRE-Parser: selecting \"$(input_parser)\"..."
    return input_parser(env, request; searchable_filters=request.searchable_filters)  # call parser
end

# This function shoud parse an input query and return a Dict with the fields and
# values necessary to filter the data later on.
function base_input_parser(env,
                           request;
                           separator=DEFAULT_QUERY_PARSING_SEPARATOR,
                           searchable_filters=Symbol[])
    @debug "BASE Input Parser: Running..."
    query = request.query
    dbschema = db_create_schema(env.dbdata)

    # Function that removes all tokens containing punctuation from a string
    function remove_punct_tokens(input, punct_regex=r"[\"!?:,.\[\]\(\)\*\&\^\%\$]")
        toks = filter!(token->!occursin(punct_regex, token), split(input))
        return join(toks, " ")
    end

    # Function that parses a string into a type
    function text2type(::Type{T}, valstr::AbstractString) where {T}
        if startswith(valstr, r"(\(|\[|\")") && endswith(valstr, r"(\)|\]|\")")
            return eval(Meta.parse(valstr))  # a vector or tuple, evaluate
        else
            return __parse(T, valstr)  # leave unchanged
        end
    end

    text2searchstring(val::AbstractString) = " " * val  # String get just passed
    text2searchstring(val::NTuple{N,T}) where {N, T<:AbstractString} = " " * join(val, " ")  # concatenate string values
    text2searchstring(val) = ""                 # Other filter values types i.e. Vectors, Numbers are not supported

    # Define expression to match
    #MATCH_EXPR = Regex("\\w+\\s*$separator(\\s*\\w+|\\s*(\\[|\\().*(\\]|\\)))")
    #MATCH_EXPR = Regex("[_a-zA-Z0-9]+$separator[_a-zA-Z0-9\\(\\[\\]\\),\"]+")
    REGEX_ALPHANUM = "_a-zA-Z0-9\\."
    MATCH_EXPR = Regex("[$REGEX_ALPHANUM]+"*
                       "$separator"*
                       "([$REGEX_ALPHANUM]+|"*
                       "\\([$REGEX_ALPHANUM,\"\\s]+\\)|"*
                       "\\[[$REGEX_ALPHANUM,\"\\s]+\\]|"*
                       "\"[$REGEX_ALPHANUM,\\s]+\")")

    # The search query simply is the reminder from the query after
    # removing all key:value(s) matches and tokens that contain punctuation
    search_query = strip(remove_punct_tokens(replace(query, MATCH_EXPR => "")))
    filteronly = isempty(search_query)

    # Initialize filter query for index columns with Colon() i.e. all
    columns = getproperty.(dbschema, :column)
    filter_query = Dict{Symbol, Any}()

    # Populate with other filter conditions and add to any
    # filter values to search_query if the filter field is
    # in searchable_filters
    for m in eachmatch(MATCH_EXPR, query)
        keystr, valstr = strip.(split(m.match, separator))
        key = Symbol(keystr)
        try
            idxkey = findfirst(isequal(key), columns)
            if idxkey != nothing
                # Add to filter
                val = text2type(dbschema[idxkey].coltype, valstr)
                push!(filter_query, key => val)

                # Add to search_query if key is a searchable_filter
                # and there we do not have only filters i.e. empty search_query
                if key in searchable_filters && !filteronly
                    search_query *= text2searchstring(val)
                end
            end
        catch
            @debug "Parse error for key \"$(m.match)\", ignoring..."
        end

    end
    return (search=search_query, filter=filter_query)
end

# Parser that does nothing
function noop_input_parser(env, request, args...; kwargs...)
    @debug "NOOP Input Parser: Running..."
    search_query = request.query
    filter_query = Dict{Symbol, Any}()
    return (search=search_query, filter=filter_query)
end


text:
function find_vasp_files(file)
    if isfile(file)
    else
            return ("$file not exist")
    end
end

function get_bandInfo(inFile="OUTCAR")
    find_vasp_files(inFile)
end

function main()
    get_bandInfo()
end

main()

max_stars_repo_name: yw-fang/julia-band

max_issues_repo_name: yw-fang/julia-band

max_forks_repo_name: yw-fang/julia-band


text:
# License for this file: MIT (expat)
# Copyright 2017-2018, DLR Institute of System Dynamics and Control

"""
    module BouncingBall

Model of a ball bouncing on ground.
"""
module BouncingBall

import ..ModiaMath

mutable struct Model <: ModiaMath.AbstractSimulationModel
    simulationState::ModiaMath.SimulationState

    # Parameters
    h0::Float64   # initial height
    e::Float64    # coefficient of restitution
    g::Float64    # gravity constant

    # Discrete variables
    flying::Bool

    function Model(;h0=1.0, e=0.7, g=9.81)
        @assert(h0 > 0.0)
        @assert(0.0 <= e <= 1.0)
        simulationState = ModiaMath.SimulationState("BouncingBall", getModelResidues!, [h0;0.0], getVariableName;
                                                    nz=1, nw=1)
        new(simulationState, h0, e, g, true)
    end
end

getVariableName(model, vcat, vindex) = ModiaMath.getVariableName(model, vcat, vindex;
                                                               xNames=["h", "v"],
                                                               wNames=["flying"])

function getModelResidues!(m::Model, t::Float64, _x::Vector{Float64}, _derx::Vector{Float64}, _r::Vector{Float64}, _w::Vector{Float64})
    sim = m.simulationState
    if ModiaMath.isInitial(sim)
        if ModiaMath.isLogInfos(sim)
            println("        flying = ", m.flying)
        end
    end
    if ModiaMath.isTerminal(sim)
        if ModiaMath.isLogInfos(sim)
            println("\n      BouncingBall model is terminated (flying = ", m.flying, ")")
        end
        return
    end

    h = _x[1]
    v = _x[2]

    if ModiaMath.edge!(sim, 1, -h, "-h")
        v = -m.e * v
        if v < 0.01
            m.flying = false
            v = 0.0
            if ModiaMath.isLogInfos(sim)
                println("        flying = ", m.flying)
            end
        end
        _x[2] = v    # re-initialize state vector x
    end

    derh = v
    derv = m.flying ? -m.g : 0.0

    _r[1] = derh - _derx[1]
    _r[2] = derv - _derx[2]
    _w[1] = m.flying

    return nothing
end

end


text:
struct GoawayFrame
    last_stream_identifier::UInt32
    error_code::UInt32
    debug_data::Array{UInt8, 1}
end

==(a::GoawayFrame, b::GoawayFrame) =
    a.last_stream_identifier == b.last_stream_identifier &&
    a.error_code == b.error_code &&
    a.debug_data == b.debug_data

function decode_goaway(header, payload)
    @assert header.stream_identifier == 0x0

    last_stream_identifier = (UInt32(payload[1]) << 24 + UInt32(payload[2]) << 16 +
                              UInt32(payload[3]) << 8 + UInt32(payload[4])) & 0x7fffffff
    error_code = UInt32(payload[5]) << 24 + UInt32(payload[6]) << 16 +
        UInt32(payload[7]) << 8 + UInt32(payload[8])
    debug_data = getindex(payload, 9:length(payload))

    return GoawayFrame(last_stream_identifier, error_code, debug_data)
end

function encode_goaway(frame)
    payload::Array{UInt8, 1} = [ UInt8(frame.last_stream_identifier >> 24) & 0x7f;
                                 UInt8(frame.last_stream_identifier >> 16 & 0x000000ff);
                                 UInt8(frame.last_stream_identifier >> 8 & 0x000000ff);
                                 UInt8(frame.last_stream_identifier & 0x000000ff);
                                 UInt8(frame.error_code >> 24);
                                 UInt8(frame.error_code >> 16 & 0x000000ff);
                                 UInt8(frame.error_code >> 8 & 0x000000ff);
                                 UInt8(frame.error_code & 0x000000ff) ]
    append!(payload, frame.debug_data)

    return wrap_payload(payload, GOAWAY, 0x0, 0x0)
end


text:
struct Display
    function create(width, height)
        ccall((glwfCreateWindow, "window.h"))
    end
    function create(width, height, title)
        ccall()
    end


text:
ket_0 = [1;0]
ket_1 = [0;1]

pauli_I = [1 0;0 1]
pauli_X = [0 1;1 0]
pauli_Y = [0 -1im;1im 0]
pauli_Z = [1 0;0 -1]

function commutator(mat1, mat2)
    mat1 * mat2 - mat2 * mat1
end

function expval(mat1, mat2)
    real(tr(mat1'*mat2))
end

function outer_prod(mat1, mat2)
    mat1*mat2'
end

function tr_norm(mat)
    real(tr(sqrt(mat*mat')))
end


text:
struct Box{TT<:Real}
    t::Array{TT, 1}
    ω::Array{TT, 1}
    x::Array{TT, 1}
    Nₜ::Int64
    Nₓ::Int64
    dt::TT
    dx::TT
    n_periods::Int64
end

"""
    function Box(xᵣ::Pair, T; dx, Nₓ, Nₜ, n_periods)

Create a `::Box` object with `Nₜ` transverse nodes, `Nₓ` longitudinal nodes (or `dx` grid spacing in the lontidunal direction, only one option can be specified), of size `[(xᵣ.first), (xᵣ.second)]` in the longitudinal direction and `[(-T*n_periods/2), (T*n_periods/2))`
"""
function Box(xᵣ::Pair, T; dx = 0.0, Nₓ = 0, Nₜ = 256, n_periods = 1)
    @info "Initializing Box with $n_periods period(s) and dx = $dx, Nₜ = $Nₜ."
    T = n_periods * T
    @info "Longitudinal range is [$(xᵣ.first), $(xᵣ.second)], transverse range is [$(-T/2), $(T/2))"
    dt = T / Nₜ
    t = dt * collect((-Nₜ/2:Nₜ/2-1))
    if dx == 0.0 && Nₓ == 0
        throw(ArgumentError("You must specify either dx or Nₓ"))
    elseif dx != 0.0 && Nₓ != 0
        throw(ArgumentError("You must specify either dx or Nₓ, not both."))
    elseif dx == 0.0 && Nₓ != 0
        dx = (xᵣ.second - xᵣ.first)/Nₓ
        x = collect(xᵣ.first:dx:xᵣ.second)
        Nₓ = length(x)
    elseif dx != 0.0 && Nₓ == 0
        x = collect(xᵣ.first:dx:xᵣ.second)
        Nₓ = length(x)
    end

    ω = 2π/T * collect((-Nₜ/2:Nₜ/2-1))

    box = Box(t, ω, x, Nₜ, Nₓ, dt, dx, n_periods)

    @info "Done computing t, x, ω"

    return box
end

struct Sim{TT<:Real, F}
    λ::Complex{TT}
    T::TT
    Ω::TT
    box::Box{TT}
    ψ₀::Array{Complex{TT}, 1}
    T̂::F
    α::TT
    ϵ::TT
    β::TT
    ψ::Array{Complex{TT}, 2}
    ψ̃::Array{Complex{TT}, 2}
    E::Array{TT, 1}
    PE::Array{TT, 1}
    KE::Array{TT, 1}
    N::Array{TT, 1}
    P::Array{TT, 1}
end # Simulation

"""
    function Sim(λ, box::Box, ψ₀::Array{Complex{TT}, 1}, T̂; α = 0.0, ϵ=0.0, β=0.0) where TT <: Rea

Create a `::Sim` object corresponding to eigenvalue `λ` (only used for breathers, ignored for arbitrary initial conditions), initial condition `ψ₀` and algorithm `T̂`. `α` is the Hirota equation parameter and `ϵ` is the Sasa-Satsuma equation parameter. `β` controls pruning.

See also: [`Box`](@ref)
"""
function Sim(λ, box::Box, ψ₀::Array{Complex{TT}, 1}, T̂; α = 0.0, ϵ=0.0, β=0.0) where TT <: Real
    ψ = Array{Complex{TT}}(undef, box.Nₜ, box.Nₓ)
    ψ̃ = similar(ψ)
    E = zeros(box.Nₓ)
    PE = similar(E)
    KE = similar(E)
    N = similar(E)
    P = similar(E)
    if β < 0.0
        throw(ArgumentError("αₚ < 0. Set αₚ = 0 to disable pruning or αₚ = Inf for fixed pruning. See documentation)"))
    end
    if β > 0.0 && box.n_periods == 1
        throw(ArgumentError("Pruning is only applicable when n_periods > 1."))
    end
    # Compute some parameters
    λ, T, Ω = params(λ = λ)
    sim = Sim(λ, T, Ω, box, ψ₀, T̂, α, ϵ, β, ψ, ψ̃, E, PE, KE, N, P)
   return sim
end #init_sim

struct Calc{TT<:Real}
    λ::Vector{Complex{TT}}
    T::Vector{Complex{TT}}
    Ω::Vector{Complex{TT}}
    χ::Vector{Complex{TT}}
    tₛ::Vector{TT}
    xₛ::Vector{TT}
    seed::String # Should be an enum
    box::Box{TT}
    m::TT
    f::Dict{Symbol,TT}
    ψ::Matrix{Complex{TT}}
    ψ̃::Matrix{Complex{TT}}
    E::Vector{TT}
    PE::Vector{TT}
    KE::Vector{TT}
    N::Vector{TT}
    P::Vector{TT}
end # Simulation

"""
    function Calc(λ::Array{Complex{TT}}, tₛ, xₛ, seed, box; m=0.0) where TT <: Real

Create a `::Calc` object with eigenvalues `λ`, shifts `xₛ` and `tₛ` and seeding solution `seed`. `box::Box` is the Box object used for the calculation and `m` is the elliptic parameter for cnoidal solutions. `seed` can have the following values:

`seed = "0"` ``\\implies \\psi_0 = 0``

`seed = "exp"` ``\\implies \\psi_0 = e^{ix}``

`seed = "dn"` ``\\implies \\psi_0 = dn(t, m)e^{ix(1-m/2)}``

`seed = "cn"` ``\\implies \\psi_0 = \\sqrt{m}cn(t, m)e^{ix(m - 1/2)}``

`f::Dict{Symbol, Float64}` is a dictionary of extended NLSE parameters.

See also: [`Box`](@ref)
"""
function Calc(λ::Array{Complex{TT}}, tₛ, xₛ, seed, box; m=0.0, f = Dict(:α=>0.0, :γ=>0.0,:δ=> 0.0)) where TT <: Real
    if ~(length(λ) == length(tₛ) == length(xₛ))
        throw(ArgumentError("Length of shifts and eigenvalue array should be the same."))
    end
    # Elliptic modulus
    @assert m <= 1 && m >= 0
    Ω = similar(λ)
    T = similar(Ω)
    χ = similar(Ω)
    if seed == "0"
        Ω = zeros(Complex{Float64}, length(λ))
        @. χ = 0.5*acos(Ω/2)
    elseif seed == "exp"
        @. Ω = 2*sqrt(1 + λ^2)
        @. χ = 0.5*acos(Ω/2)
    elseif seed == "dn"
        @. Ω = 2*sqrt(1 + (λ - m/4/λ)^2)
        @. χ = 0.5*acos(Ω/2)
    elseif seed == "cn"
        @. Ω = 2*sqrt(m)*sqrt(1 + 1/m*(λ - 1/4/λ)^2)
        @. χ = 0.5*acos(Ω/2/sqrt(m))
    end
    @. T = 2π/Ω

    ψ = Array{Complex{TT}}(undef, box.Nₜ, box.Nₓ)
    ψ̃ = similar(ψ)
    E = zeros(box.Nₓ)
    PE = similar(E)
    KE = similar(E)
    N = similar(E)
    P = similar(E)

    if !haskey(f, :α)
        push!(f, :α => 0.0)
    end
    if !haskey(f, :γ)
        push!(f, :γ => 0.0)
    end
    if !haskey(f, :δ)
        push!(f, :δ => 0.0)
    end

    calc = Calc(λ, T, Ω, χ, tₛ, xₛ, seed, box, m, f, ψ, ψ̃, E, PE, KE, N, P)
end #init_sim

struct Operators{T, DispFunc, FFTPlan, InvFFTPlan}
    K̂::DispFunc
    F̂::FFTPlan
    F̃̂::InvFFTPlan
    B̂::DiffEqBase.DEIntegrator
    B̂B::DiffEqBase.DEIntegrator
    ψ₁::T
    ψ₂::T
    ψ₃::T
end # Simulation

struct Ks
    α::Float64
    ϵ::Float64
    ω::Vector{Float64}
end

@memoize function K_cubic(dx::Real, ω)
    ifftshift(cis.(-dx*ω.^2/2))
end
@memoize function K_hirota(dx::Real, ω, α)
    ifftshift(cis.(-dx*(ω.^2/2 .+ α*ω.^3)))
end
@memoize function K_SS(dx::Real, ω, ϵ)
    ifftshift(cis.(-dx*(ω.^2/2 .- ϵ*ω.^3)))
end

function (K̂::Ks)(dx)
    if K̂.α == 0 && K̂.ϵ == 0
        K_cubic(dx, K̂.ω)
    elseif K̂.α != 0 && K̂.ϵ == 0
        K_hirota(dx, K̂.ω, K̂.α)
    elseif K̂.α == 0 && K̂.ϵ != 0
        K_SS(dx, K̂.ω, K̂.ϵ)
    else
        @error "Only ϵ or α can be nonzero at a time"
    end
end

"""
    function Operators(sim)

Construct appropriate operators for `sim::Sim`. These include the Fourier operator `F̂`, inverse Fourier operator `F̃̂`, dispersion operaotr `K̂`, and Hirota/Sasa-Satsuma operators `B̂` and `B̂B`. This object also includes some arrays for temporary operations in Nystrom integrators.

See also: [`Sim`](@ref)
"""
function Operators(sim)
    # Generate FFT Plans to optimize performance
    @info "Generating FFT plans"
    F̂ = plan_fft!(@view sim.ψ[:, 1]) # 26 allocs
    F̃̂ = plan_ifft!(@view sim.ψ[:, 1]) # 34 allocs

    # This stuff should be user controllable
    t_algo = Tsit5()
    t_order = 2
    # Create the integrator for the Burger term
    if sim.α != 0 && sim.ϵ == 0
        D = CenteredDifference(1, t_order, sim.box.dt, sim.box.Nₜ)
        Q = PeriodicBC(Float64)
        function MB!(du, u,p,t)
            du .= 6*sim.α*D*Q*u.*abs2.(u)
        end
        prob = ODEProblem(MB!, sim.ψ[:, 1], (0, sim.box.dx))
        B̂ = init(prob, t_algo; dt=sim.box.dx,save_everystep=false, adaptive=false)
        B̂B = B̂
    elseif sim.α == 0 && sim.ϵ != 0
        D = CenteredDifference(1, t_order, sim.box.dt, sim.box.Nₜ)
        Q = PeriodicBC(Float64)
        function MS1!(du, u,p,t)
            du .= -6*sim.ϵ*D*Q*u.*abs2.(u)
        end
        prob = ODEProblem(MS1!, sim.ψ[:, 1], (0, sim.box.dx))
        B̂ = init(prob, t_algo; dt=sim.box.dx,save_everystep=false, adaptive=false)
        function MS2!(du, u,p,t)
            du .= -3*sim.ϵ*D*Q*abs2.(u).*u
        end
        prob = ODEProblem(MS2!, sim.ψ[:, 1], (0, sim.box.dx))
        B̂B = init(prob, t_algo; dt=sim.box.dx,save_everystep=false, adaptive=false)
    else
        function M0!(du, u,p,t)
            du .= 0*u
        end
        prob = ODEProblem(M0!, sim.ψ[:, 1], (0, sim.box.dx))
        B̂ = init(prob, t_algo; dt=sim.box.dx,save_everystep=false, adaptive=false)
        B̂B = B̂
    end

    ψ₁ = similar(sim.ψ₀)
    ψ₂ = similar(sim.ψ₀)
    ψ₃ = similar(sim.ψ₀)
    ops = Operators(Ks(sim.α, sim.ϵ, sim.box.ω), F̂, F̃̂, B̂, B̂B, ψ₁, ψ₂, ψ₃)

    return ops
end


text:
export ER3BP
export elliptical_potential, centrifugal_potential

#---------------------------#
# ER3BP EQUATIONS OF MOTION #
#---------------------------#
struct _ER3BP_ODEFunctions{S,F,F2} <: Abstract_ModelODEFunctions
    ode_system :: S
    ode_f      :: F
    ode_stm_f  :: F2
end

function ModelingToolkit.ODESystem(::Type{_ER3BP_ODEFunctions})
    @parameters  μ  # Mass fraction
    @parameters  e  # Eccentricity
    @parameters  f  # True anomaly
    @variables   x(f) y(f) z(f)
    D, D2 = Differential(f), Differential(f)^2
    Dx, Dy, Dz = Differential.((x, y, z))

    # [DeiTos2017, Eqs. 14]
    # NOTE: need to expand the RHS derivatives before calling order-lowering
    ω = elliptical_potential(μ, (x, y, z), f, e)
    return ODESystem([
            D2(x) ~ +2D(y) + Dx(ω),
            D2(y) ~ -2D(x) + Dy(ω),
            D2(z) ~        + Dz(ω)
        ],
        f,
        [x, y, z],
        [μ, e]
    ), []
end

@doc "Centrifugal potential [DeiTos2017, Eq.13; Ichinomiya 2018, Eq. 2.2]"
function centrifugal_potential(μ, (x, y, z))
    r = distance_vectors(μ, (x, y, z))
    0.5*(x^2 + y^2) + (1 - μ)/r[1] + μ/r[2] + 0.5*(1 - μ)*μ
end

@doc "Elliptical potential in barycentric frame [DeiTos2017, Eq. 15]"
function elliptical_potential(μ, (x, y, z), f, e)
    Ω_3 = centrifugal_potential(μ, (x, y, z))
    return (Ω_3 - 0.5*z^2*e*cos(f)) / (1 + e*cos(f))
end

# Build the equations at pre-compile time
const ER3BP_ODEFunctions = _ER3BP_ODEFunctions()

#-------------#
# ER3BP MODEL #
#-------------#
struct ER3BP{O<:_ER3BP_ODEFunctions,P<:R3BPSystemProperties} <: Abstract_R3BPModel
    ode   :: O
    props :: P
end
ER3BP(args...; kwargs...) = ER3BP(ER3BP_ODEFunctions, R3BPSystemProperties(args...; kwargs...))


text:
struct Graph
    n :: Int32 # |V|
    m :: Int32 # |E|
    V :: Array{Int32, 1} # V[i] = Real Index of node i
    E :: Array{Tuple{Int32, Int32, Int32, Float64}, 1} # (ID, u, v, w) in Edge Set
end

function readGraph(fileName, graphType) # Read graph from a file | graphType = [weighted, unweighted]
    # Initialized
    n = 0
    origin = Dict{Int32, Int32}()
    label = Dict{Int32, Int32}()
    edge = Set{Tuple{Int32, Int32, Float64}}()

    getid(x :: Int32) = haskey(label, x) ? label[x] : label[x] = n += 1

    open(fileName) do f1
        for line in eachline(f1)
            # Read origin data from file
            buf = split(line)
            u = parse(Int32, buf[1])
            v = parse(Int32, buf[2])
            if graphType == "weighted"
                w = parse(Float64, buf[3])
            else
                w = 1.0
            end
            if u == v
                continue
            end
            # Label the node
            u1 = getid(u)
            v1 = getid(v)
            origin[u1] = u
            origin[v1] = v
            # Store the edge
            if u1 > v1
                u1, v1 = v1, u1
            end
            push!(edge, (u1, v1, w))
        end
    end

    # Store data into the struct Graph
    m = length(edge)
    V = Array{Int32, 1}(undef, n)
    E = Array{Tuple{Int32, Int32, Int32, Float64}, 1}(undef, m)

    for i = 1 : n
        V[i] = origin[i]
    end

    ID = 0
    for (u, v, w) in edge
        ID = ID + 1
        E[ID] = (ID, u, v, w)
    end

    return Graph(n, m, V, E)
end

function BFS(st, g) # Search from the node st
    q = []
    h = Array{Int8, 1}(undef, size(g, 1))
    fill!(h, 0)
    push!(q, st)
    h[st] = 1
    front = 1
    rear = 1
    while front <= rear
        u = q[front]
        front = front + 1
        for v in g[u]
            if h[v] == 0
                h[v] = 1
                rear = rear + 1
                push!(q, v)
            end
        end
    end
    return q
end

function getLLC(G :: Graph) # Find the largest link clique
    # Create the Link Table
    g = Array{Array{Int32, 1}, 1}(undef, G.n)
    for i = 1 : G.n
        g[i] = []
    end
    for (ID, u, v, w) in G.E
        push!(g[u], v)
        push!(g[v], u)
    end
    # Find the node Set of LLC
    n2 = 0
    S = Array{Int32, 1}(undef, G.n)
    visited = Array{Int8, 1}(undef, G.n)
    fill!(visited, 0)
    for i = 1 : G.n
        if visited[i] == 0
            nodeSet = BFS(i, g)
            for x in nodeSet
                visited[x] = 1
            end
            tn = size(nodeSet, 1)
            if (tn > n2)
                n2 = tn
                for j = 1 : n2
                    S[j] = nodeSet[j]
                end
            end
        end
    end
    # Store the result
    label = Array{Int32, 1}(undef, G.n)
    fill!(label, 0)
    V2 = Array{Int32, 1}(undef, n2)
    for i = 1 : n2
        label[S[i]] = i
        V2[i] = G.V[S[i]]
    end
    E2 = []
    nID = 0
    for (ID, u, v, w) in G.E
        if (label[u] > 0) && (label[v] > 0)
            nID += 1
            push!(E2, (nID, label[u], label[v], w))
        end
    end
    m2 = size(E2, 1)
    return Graph(n2, m2, V2, E2)
end

function printGraph(G, fileName)
    of = open(fileName, "w")
    for (ID, u, v, w) in G.E
        println(of, u, " ", v)
    end
    close(of)
end

function getPc(C; eps = 1e-9)
    A = copy(C)
    n = size(A, 1)
    sort!(A)
    sum = 0.0
    for i = 1 : n
        ts = 0.0
        for j = i-1 : -1 : 1
            if abs(A[i] - A[j]) < eps
                ts += 1.0
            else
                break
            end
        end
        for j = i+1 : n
            if abs(A[i] - A[j]) < eps
                ts += 1.0
            else
                break
            end
        end
        sum += ts
    end
    sum /= (n * (n - 1))
    return (1.0 - sum) * 100
end


text:
@testset "runtestLengthString" begin
    println("Testing runtestLengthString")
    include("../src/bfgaLengthString.jl")
    using .bfgaLengthString

    include("../src/Bf.jl")
    using .BfInterpreter

    @time model = test_serial()
    #@time model = test_parallel()
    prems = model.refSet[length(model.refSet)]
    println("Generation : $(model.params.currentGeneration)")
    println("& fitness : $(model.specific_fitness.fitness(prems, model.instructionsSet))")
    #bfcode :: Array{Float64,1}  = prems.dna
    println("code :  $(prems.program)") #$(join(genesToBfInstructions(bfcode), "") ) ")

    #bft = bfType(prems.dna)
    input1 = "One Two One Two, repeat after me"
    input2 = "The RMA had been infected"
    n1 , n2 = length(input1), length(input2)

    output1, _ = execute(prems.program, input1, model.instructionsSet)
    output2, _ = execute(prems.program, input2, model.instructionsSet)

    @test length(output1) >= 1
    @test Char(n1) == output1[1]
    @test length(output2) >= 1
    @test Char(n2) == output2[1]

    # do the test_parallel after ...
    #test_parallel()
end


text:
# Autogenerated wrapper script for GRASS_jll for powerpc64le-linux-gnu-cxx03
export libgrass_arraystats, libgrass_bitmap, libgrass_btree, libgrass_btree2, libgrass_cairodriver, libgrass_calc, libgrass_ccmath, libgrass_cdhc, libgrass_cluster, libgrass_datetime, libgrass_dbmibase, libgrass_dbmiclient, libgrass_dbmidriver, libgrass_dbstubs, libgrass_dgl, libgrass_dig2, libgrass_display, libgrass_driver, libgrass_dspf, libgrass_g3d, libgrass_gis, libgrass_gmath, libgrass_gpde, libgrass_gproj, libgrass_htmldriver, libgrass_imagery, libgrass_interpdata, libgrass_interpfl, libgrass_iortho, libgrass_lidar, libgrass_linkm, libgrass_lrs, libgrass_manage, libgrass_neta, libgrass_pngdriver, libgrass_psdriver, libgrass_qtree, libgrass_raster, libgrass_rli, libgrass_rowio, libgrass_rtree, libgrass_segment, libgrass_shape, libgrass_sim, libgrass_sqlp, libgrass_stats, libgrass_symb, libgrass_temporal, libgrass_vector, libgrass_vedit

using GDAL_jll
using PROJ_jll
using Cairo_jll
using FreeType2_jll
using LAPACK_jll
using FFTW_jll
using Libiconv_jll
JLLWrappers.@generate_wrapper_header("GRASS")
JLLWrappers.@declare_library_product(libgrass_arraystats, "libgrass_arraystats.7.8.so")
JLLWrappers.@declare_library_product(libgrass_bitmap, "libgrass_bitmap.7.8.so")
JLLWrappers.@declare_library_product(libgrass_btree, "libgrass_btree.7.8.so")
JLLWrappers.@declare_library_product(libgrass_btree2, "libgrass_btree2.7.8.so")
JLLWrappers.@declare_library_product(libgrass_cairodriver, "libgrass_cairodriver.7.8.so")
JLLWrappers.@declare_library_product(libgrass_calc, "libgrass_calc.7.8.so")
JLLWrappers.@declare_library_product(libgrass_ccmath, "libgrass_ccmath.7.8.so")
JLLWrappers.@declare_library_product(libgrass_cdhc, "libgrass_cdhc.7.8.so")
JLLWrappers.@declare_library_product(libgrass_cluster, "libgrass_cluster.7.8.so")
JLLWrappers.@declare_library_product(libgrass_datetime, "libgrass_datetime.7.8.so")
JLLWrappers.@declare_library_product(libgrass_dbmibase, "libgrass_dbmibase.7.8.so")
JLLWrappers.@declare_library_product(libgrass_dbmiclient, "libgrass_dbmiclient.7.8.so")
JLLWrappers.@declare_library_product(libgrass_dbmidriver, "libgrass_dbmidriver.7.8.so")
JLLWrappers.@declare_library_product(libgrass_dbstubs, "libgrass_dbstubs.7.8.so")
JLLWrappers.@declare_library_product(libgrass_dgl, "libgrass_dgl.7.8.so")
JLLWrappers.@declare_library_product(libgrass_dig2, "libgrass_dig2.7.8.so")
JLLWrappers.@declare_library_product(libgrass_display, "libgrass_display.7.8.so")
JLLWrappers.@declare_library_product(libgrass_driver, "libgrass_driver.7.8.so")
JLLWrappers.@declare_library_product(libgrass_dspf, "libgrass_dspf.7.8.so")
JLLWrappers.@declare_library_product(libgrass_g3d, "libgrass_g3d.7.8.so")
JLLWrappers.@declare_library_product(libgrass_gis, "libgrass_gis.7.8.so")
JLLWrappers.@declare_library_product(libgrass_gmath, "libgrass_gmath.7.8.so")
JLLWrappers.@declare_library_product(libgrass_gpde, "libgrass_gpde.7.8.so")
JLLWrappers.@declare_library_product(libgrass_gproj, "libgrass_gproj.7.8.so")
JLLWrappers.@declare_library_product(libgrass_htmldriver, "libgrass_htmldriver.7.8.so")
JLLWrappers.@declare_library_product(libgrass_imagery, "libgrass_imagery.7.8.so")
JLLWrappers.@declare_library_product(libgrass_interpdata, "libgrass_interpdata.7.8.so")
JLLWrappers.@declare_library_product(libgrass_interpfl, "libgrass_interpfl.7.8.so")
JLLWrappers.@declare_library_product(libgrass_iortho, "libgrass_iortho.7.8.so")
JLLWrappers.@declare_library_product(libgrass_lidar, "libgrass_lidar.7.8.so")
JLLWrappers.@declare_library_product(libgrass_linkm, "libgrass_linkm.7.8.so")
JLLWrappers.@declare_library_product(libgrass_lrs, "libgrass_lrs.7.8.so")
JLLWrappers.@declare_library_product(libgrass_manage, "libgrass_manage.7.8.so")
JLLWrappers.@declare_library_product(libgrass_neta, "libgrass_neta.7.8.so")
JLLWrappers.@declare_library_product(libgrass_pngdriver, "libgrass_pngdriver.7.8.so")
JLLWrappers.@declare_library_product(libgrass_psdriver, "libgrass_psdriver.7.8.so")
JLLWrappers.@declare_library_product(libgrass_qtree, "libgrass_qtree.7.8.so")
JLLWrappers.@declare_library_product(libgrass_raster, "libgrass_raster.7.8.so")
JLLWrappers.@declare_library_product(libgrass_rli, "libgrass_rli.7.8.so")
JLLWrappers.@declare_library_product(libgrass_rowio, "libgrass_rowio.7.8.so")
JLLWrappers.@declare_library_product(libgrass_rtree, "libgrass_rtree.7.8.so")
JLLWrappers.@declare_library_product(libgrass_segment, "libgrass_segment.7.8.so")
JLLWrappers.@declare_library_product(libgrass_shape, "libgrass_shape.7.8.so")
JLLWrappers.@declare_library_product(libgrass_sim, "libgrass_sim.7.8.so")
JLLWrappers.@declare_library_product(libgrass_sqlp, "libgrass_sqlp.7.8.so")
JLLWrappers.@declare_library_product(libgrass_stats, "libgrass_stats.7.8.so")
JLLWrappers.@declare_library_product(libgrass_symb, "libgrass_symb.7.8.so")
JLLWrappers.@declare_library_product(libgrass_temporal, "libgrass_temporal.7.8.so")
JLLWrappers.@declare_library_product(libgrass_vector, "libgrass_vector.7.8.so")
JLLWrappers.@declare_library_product(libgrass_vedit, "libgrass_vedit.7.8.so")
function __init__()
    JLLWrappers.@generate_init_header(GDAL_jll, PROJ_jll, Cairo_jll, FreeType2_jll, LAPACK_jll, FFTW_jll, Libiconv_jll)
    JLLWrappers.@init_library_product(
        libgrass_arraystats,
        "lib/libgrass_arraystats.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_bitmap,
        "lib/libgrass_bitmap.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_btree,
        "lib/libgrass_btree.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_btree2,
        "lib/libgrass_btree2.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_cairodriver,
        "lib/libgrass_cairodriver.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_calc,
        "lib/libgrass_calc.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_ccmath,
        "lib/libgrass_ccmath.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_cdhc,
        "lib/libgrass_cdhc.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_cluster,
        "lib/libgrass_cluster.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_datetime,
        "lib/libgrass_datetime.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_dbmibase,
        "lib/libgrass_dbmibase.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_dbmiclient,
        "lib/libgrass_dbmiclient.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_dbmidriver,
        "lib/libgrass_dbmidriver.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_dbstubs,
        "lib/libgrass_dbstubs.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_dgl,
        "lib/libgrass_dgl.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_dig2,
        "lib/libgrass_dig2.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_display,
        "lib/libgrass_display.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_driver,
        "lib/libgrass_driver.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_dspf,
        "lib/libgrass_dspf.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_g3d,
        "lib/libgrass_g3d.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_gis,
        "lib/libgrass_gis.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_gmath,
        "lib/libgrass_gmath.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_gpde,
        "lib/libgrass_gpde.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_gproj,
        "lib/libgrass_gproj.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_htmldriver,
        "lib/libgrass_htmldriver.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_imagery,
        "lib/libgrass_imagery.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_interpdata,
        "lib/libgrass_interpdata.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_interpfl,
        "lib/libgrass_interpfl.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_iortho,
        "lib/libgrass_iortho.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_lidar,
        "lib/libgrass_lidar.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_linkm,
        "lib/libgrass_linkm.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_lrs,
        "lib/libgrass_lrs.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_manage,
        "lib/libgrass_manage.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_neta,
        "lib/libgrass_neta.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_pngdriver,
        "lib/libgrass_pngdriver.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_psdriver,
        "lib/libgrass_psdriver.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_qtree,
        "lib/libgrass_qtree.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_raster,
        "lib/libgrass_raster.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_rli,
        "lib/libgrass_rli.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_rowio,
        "lib/libgrass_rowio.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_rtree,
        "lib/libgrass_rtree.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_segment,
        "lib/libgrass_segment.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_shape,
        "lib/libgrass_shape.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_sim,
        "lib/libgrass_sim.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_sqlp,
        "lib/libgrass_sqlp.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_stats,
        "lib/libgrass_stats.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_symb,
        "lib/libgrass_symb.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_temporal,
        "lib/libgrass_temporal.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_vector,
        "lib/libgrass_vector.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libgrass_vedit,
        "lib/libgrass_vedit.7.8.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
facts("Async") do

    context("async_map") do
        x = Signal(1; name="x")
        t, y = async_map(-, 0, x)
        z = map(yv->2yv, y; name="z")

        @fact value(t) --> nothing
        @fact value(y) --> 0
        @fact value(z) --> 0

        push!(x, 2)
        step()
        step()

        @fact value(y) --> -2
        @fact value(z) --> -4
    end
end


text:
using GraphNeuralNetworks
using Flux
using CUDA
using Flux: gpu, @functor
using LinearAlgebra, Statistics, Random
using NNlib
using LearnBase
using LightGraphs
using Zygote
using Test
using MLDatasets
CUDA.allowscalar(false)

ENV["DATADEPS_ALWAYS_ACCEPT"] = true # for MLDatasets

include("test_utils.jl")

tests = [
    "gnngraph",
    "msgpass",
    "layers/basic",
    "layers/conv",
    "layers/pool",
    "examples/node_classification_cora",
]

!CUDA.functional() && @warn("CUDA unavailable, not testing GPU support")

# Testing all graph types. :sparse is a bit broken at the moment
@testset "GraphNeuralNetworks: graph format $graph_type" for graph_type in (:coo,:sparse,:dense)

    global GRAPH_T = graph_type
    global TEST_GPU = CUDA.functional() && GRAPH_T != :sparse

    for t in tests
        include("$t.jl")

        if TEST_GPU && isfile("cuda/$t.jl")
            include("cuda/$t.jl")
        end
    end
end