<commit_before># Geolix

MaxMind GeoIP2 database reader/decoder.

__Note__: If you are reading this on
[GitHub](https://github.com/elixir-geolix/geolix) then the information in this
file may be out of sync with the [Hex package](https://hex.pm/packages/geolix).
If you are using this library through Hex please refer to the appropriate
documentation on HexDocs (link available on Hex).


## Package Setup

To use Geolix with your projects, edit your `mix.exs` file and add the project
as a dependency:

```elixir
defp deps do
  [
    # ...
    {:geolix, "~> 0.16"}
    # ...
  ]
end
```

### Package Startup (application)

Probably the easiest way to manage startup is by simply
adding `:geolix` to the list of applications:

```elixir
def application do
  [
    applications: [
      # ...
      :geolix
      # ...
    ]
  ]
end
```

### Package Startup (manual supervision)

A second possible approach is to take care of supervision yourself. This
means you should add `:geolix` to your included applications instead:

```elixir
def application do
  [
    included_applications: [
      # ...
      :geolix
      # ...
    ]
  ]
end
```

And also add the appropriate `Geolix.Supervisor` to your hierarchy:

```elixir
# in your application/supervisor
children = [
  # ...
  supervisor(Geolix.Supervisor, [])
  # ...
]
```


## Application Configuration

To get started you need to define one or more `:databases` to use for lookups.
Each database definition is a map with at least two fields:

- `:id` - an identifier for this database, usable to limit lookups to a single
  database if you have defined more than one
- `:adapter` - the adapter module used to handle lookup requests. See the part
  "Adapter Configuration" in this document for additional information

Depending on the adapter you may need to provide additional values.

### Configuration (static)

The most simply way is using a completely static configuration, i.e. for two
databases handled by the pre-packaged adapter `Geolix.Adapter.MMDB2`:

```elixir
config :geolix,
  databases: [
    %{
      id: :city,
      adapter: Geolix.Adapter.MMDB2,
      source: "/absolute/path/to/cities/db"
    },
    %{
      id: :country,
      adapter: Geolix.Adapter.MMDB2,
      source: "/absolute/path/to/countries/db"
    }
  ]
```

### Configuration (dynamic)

If there are any reasons you cannot use a pre-defined configuration you can also
configure an initializer module to be called before starting the top-level
suprevisor or alternatively for each individual database.

This may be the most suitable configuration if you have the database located
in the `:priv_dir` of your application.

```elixir
config :geolix,
  init: {MyInitModule, :my_init_fun_toplevel}

config :geolix,
  databases: [
    %{
      id: :dynamic_country,
      adapter: Geolix.Adapter.MMDB2,
      init: {MyInitModule, :my_init_fun_database}
    }
  ]

defmodule MyInitModule do
  @spec my_init_fun_toplevel() :: :ok
  def my_init_fun_toplevel() do
    priv_dir = to_string(:code.priv_dir(:my_app))

    databases = [
      %{
        id: :dynamic_city,
        adapter: Geolix.Adapter.MMDB2,
        source: priv_dir <> "/GeoLite2-City.mmdb"
      }
      | Application.get_env(:geolix, :databases, [])
    ]

    Application.put_env(:geolix, :databases, databases)
  end

  @spec my_init_fun_database(map) :: map
  def my_init_fun_database(%{id: :dynamic_country} = database) do
    priv_dir = to_string(:code.priv_dir(:my_app))

    %{database | source: priv_dir <> "/GeoLite2-Country.mmdb"}
  end
end
```

Above example illustrates both types of dynamic initialization.

The top-level initializer is called without arguments and expected to always
return `:ok`. At the database level the current database configuration is
passed as the first (and only) parameter and the new, complete configuration
is expected as the return.

If you choose to use the dynamic database initialization the only requirement<commit_msg>uses Application.app_dir/2 in example initializers<commit_after># Geolix

MaxMind GeoIP2 database reader/decoder.

__Note__: If you are reading this on
[GitHub](https://github.com/elixir-geolix/geolix) then the information in this
file may be out of sync with the [Hex package](https://hex.pm/packages/geolix).
If you are using this library through Hex please refer to the appropriate
documentation on HexDocs (link available on Hex).


## Package Setup

To use Geolix with your projects, edit your `mix.exs` file and add the project
as a dependency:

```elixir
defp deps do
  [
    # ...
    {:geolix, "~> 0.16"}
    # ...
  ]
end
```

### Package Startup (application)

Probably the easiest way to manage startup is by simply
adding `:geolix` to the list of applications:

```elixir
def application do
  [
    applications: [
      # ...
      :geolix
      # ...
    ]
  ]
end
```

### Package Startup (manual supervision)

A second possible approach is to take care of supervision yourself. This
means you should add `:geolix` to your included applications instead:

```elixir
def application do
  [
    included_applications: [
      # ...
      :geolix
      # ...
    ]
  ]
end
```

And also add the appropriate `Geolix.Supervisor` to your hierarchy:

```elixir
# in your application/supervisor
children = [
  # ...
  supervisor(Geolix.Supervisor, [])
  # ...
]
```


## Application Configuration

To get started you need to define one or more `:databases` to use for lookups.
Each database definition is a map with at least two fields:

- `:id` - an identifier for this database, usable to limit lookups to a single
  database if you have defined more than one
- `:adapter` - the adapter module used to handle lookup requests. See the part
  "Adapter Configuration" in this document for additional information

Depending on the adapter you may need to provide additional values.

### Configuration (static)

The most simply way is using a completely static configuration, i.e. for two
databases handled by the pre-packaged adapter `Geolix.Adapter.MMDB2`:

```elixir
config :geolix,
  databases: [
    %{
      id: :city,
      adapter: Geolix.Adapter.MMDB2,
      source: "/absolute/path/to/cities/db"
    },
    %{
      id: :country,
      adapter: Geolix.Adapter.MMDB2,
      source: "/absolute/path/to/countries/db"
    }
  ]
```

### Configuration (dynamic)

If there are any reasons you cannot use a pre-defined configuration you can also
configure an initializer module to be called before starting the top-level
suprevisor or alternatively for each individual database.

This may be the most suitable configuration if you have the database located
in the `:priv_dir` of your application.

```elixir
config :geolix,
  init: {MyInitModule, :my_init_fun_toplevel}

config :geolix,
  databases: [
    %{
      id: :dynamic_country,
      adapter: Geolix.Adapter.MMDB2,
      init: {MyInitModule, :my_init_fun_database}
    }
  ]

defmodule MyInitModule do
  @spec my_init_fun_toplevel() :: :ok
  def my_init_fun_toplevel() do
    priv_dir = Application.app_dir(:my_app, "priv")

    databases = [
      %{
        id: :dynamic_city,
        adapter: Geolix.Adapter.MMDB2,
        source: Path.join([priv_dir, "GeoLite2-City.mmdb"])
      }
      | Application.get_env(:geolix, :databases, [])
    ]

    Application.put_env(:geolix, :databases, databases)
  end

  @spec my_init_fun_database(map) :: map
  def my_init_fun_database(%{id: :dynamic_country} = database) do
    priv_dir = Application.app_dir(:my_app, "priv")

    %{database | source: Path.join([priv_dir, "GeoLite2-Country.mmdb"])}
  end
end
```

Above example illustrates both types of dynamic initialization.

The top-level initializer is called without arguments and expected to always
return `:ok`. At the database level the current database configuration is
passed as the first (and only) parameter and the new, complete configuration
is expected as the return.

If you choose to use the dynamic database initialization the only requirement
{'fraction_non_alphanumeric': 0.09572735246209749, 'fraction_numerical': 0.002881844380403458, 'mean_word_length': 3.4717086834733895, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '155856', 'n_tokens_mistral': 2509, 'n_tokens_neox': 2432, 'n_words': 881}