Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new configuration option for Schema Registry #45

Merged
merged 8 commits into from
Sep 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@

This library supports convenient encoding and decoding of [Avro](https://avro.apache.org/) messages.

It can read the Avro schema from local files or the [Confluent® Schema
Registry](https://www.confluent.io/confluent-schema-registry), caching
data in memory for performance.
It can read the Avro schema from local files or the [Confluent® Schema Registry](https://www.confluent.io/confluent-schema-registry),
caching data in memory for performance.
It supports reading and writing data Kafka [wire format](https://docs.confluent.io/current/schema-registry/serializer-formatter.html#wire-format)
prefix and from [Object Container Files](https://avro.apache.org/docs/1.8.1/spec.html#Object+Container+Files)
formats. And has [Inter-Schema references](https://github.com/Strech/avrora/wiki/Inter-Schema-references) feature.

Many thanks to the [AvroTurf](https://github.com/dasch/avro_turf) Ruby gem for
the inspiration.
Many thanks to the [AvroTurf](https://github.com/dasch/avro_turf) Ruby gem for the inspiration.

## Add Avrora to your project

Expand All @@ -32,7 +30,7 @@ Add Avrora to `mix.exs` as a dependency:
```elixir
def deps do
[
{:avrora, "~> 0.11"}
{:avrora, "~> 0.13"}
]
end
```
Expand All @@ -45,23 +43,29 @@ Configure the library in `config/config.exs`:
config :avrora,
registry_url: "http://localhost:8081",
registy_auth: {:basic, ["username", "password"]}, # optional
registy_schemas_autoreg: false, # optional: if you want manually register schemas
schemas_path: Path.expand("./priv/schemas"),
names_cache_ttl: :timer.minutes(5) # optional: if you want periodic disk reads
```

- `registry_url` - URL for the Confluent Schema Registry, default `nil`
- `registry_auth` – Credentials to authenticate in Confluent Schema Registry, default `nil`
- `registry_url` - URL for the Schema Registry, default `nil`
- `registry_auth` – Credentials to authenticate in the Schema Registry, default `nil`
- `registy_schemas_autoreg` - Flag for automatic schemas registration in the Schema Registry, default `true`
(since [v0.13](https://github.com/Strech/avrora/releases/tag/v0.13.0))
- `schemas_path` - Base path for locally stored schema files, default `./priv/schemas`
- `names_cache_ttl` - Time in ms to cache schemas by name in memory, default
`:infinity` (since [v0.10.0](https://github.com/Strech/avrora/releases/tag/v0.10.0))
`:infinity` (since [v0.10](https://github.com/Strech/avrora/releases/tag/v0.10.0))

Set `names_cache_ttl` to `:infinity` will cache forever (no more disk reads will
happen). This is safe when schemas are resolved in the Schema Registry by
numeric id or **versioned** name, as it is unique. If you need to reload schema
from the disk periodically, TTL different from `:infinity` ensures that.

If the schema is resolved by name it will be always overwritten with the latest
schema received from Schema Registry (this is a new behavior since [v0.10.0](https://github.com/Strech/avrora/releases/tag/v0.10.0)).
schema received from Schema Registry (this is a new behavior since [v0.10](https://github.com/Strech/avrora/releases/tag/v0.10.0)).

:bulb: Disable automatic schemas registration if you want to avoid storing schemas
and manually control registration process.

## Start cache process

Expand Down
1 change: 1 addition & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ config :avrora,
schemas_path: Path.expand("./test/fixtures/schemas"),
registry_url: nil,
registry_auth: nil,
registry_schemas_autoreg: true,
names_cache_ttl: :infinity

config :logger, :console, format: "$time $metadata[$level] $levelpad$message\n"
15 changes: 10 additions & 5 deletions lib/avrora/config.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ defmodule Avrora.Config do

## Options:

* `schemas_path` path to local schema files, default ./priv/schemas
* `registry_url` URL for Confluent Schema Registry, default nil
* `registry_auth` authentication settings for Confluent Schema Registry, default nil
* `names_cache_ttl` duration to cache global schema names millisecods, default :infinity
* `schemas_path` path to local schema files, default `./priv/schemas`
* `registry_url` URL for Schema Registry, default `nil`
* `registry_auth` authentication settings for Schema Registry, default `nil`
* `registry_schemas_autoreg` automatically register schemas in Schema Registry, default `true`
* `names_cache_ttl` duration to cache global schema names millisecods, default `:infinity`

## Module configuration:
## Internal use interface:

* `file_storage` module which handles files in `schemas_path`, default `Avrora.Storage.File`
* `memory_storage` module which handles memory operations, default `Avrora.Storage.Memory`
Expand All @@ -21,6 +22,7 @@ defmodule Avrora.Config do
@callback schemas_path :: String.t()
@callback registry_url :: String.t() | nil
@callback registry_auth :: tuple() | nil
@callback registry_schemas_autoreg :: boolean()
@callback names_cache_ttl :: integer() | atom()
@callback file_storage :: module()
@callback memory_storage :: module()
Expand All @@ -37,6 +39,9 @@ defmodule Avrora.Config do
@doc false
def registry_auth, do: get_env(:registry_auth, nil)

@doc false
def registry_schemas_autoreg, do: get_env(:registry_schemas_autoreg, true)

@doc false
def names_cache_ttl, do: get_env(:names_cache_ttl, :infinity)

Expand Down
25 changes: 16 additions & 9 deletions lib/avrora/resolver.ex
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,8 @@ defmodule Avrora.Resolver do
@spec resolve(String.t()) :: {:ok, Avrora.Schema.t()} | {:error, term()}
def resolve(name) when is_binary(name) do
with {:ok, schema_name} <- Name.parse(name),
{:ok, nil} <- memory_storage().get(name),
{:ok, schema} <- file_storage().get(name) do
response =
if is_nil(schema_name.version),
do: registry_storage().put(schema_name.name, schema.json),
else: registry_storage().get(name)

case response do
{:ok, nil} <- memory_storage().get(name) do
case resolve_with_registry(schema_name) do
{:ok, schema} ->
with {:ok, schema} <- memory_storage().put(schema.id, schema),
{:ok, schema} <- memory_storage().put(schema_name.name, schema),
Expand All @@ -96,7 +90,7 @@ defmodule Avrora.Resolver do
else: memory_storage().put("#{schema_name.name}:#{schema.version}", schema)
end

{:error, :unconfigured_registry_url} ->
{:reclaim, schema} ->
memory_storage().put(schema_name.name, schema)

{:error, reason} ->
Expand All @@ -105,6 +99,19 @@ defmodule Avrora.Resolver do
end
end

defp resolve_with_registry(schema_name) do
if Config.self().registry_schemas_autoreg() && is_nil(schema_name.version) do
with {:ok, schema} <- file_storage().get(schema_name.origin),
{:error, :unconfigured_registry_url} <-
registry_storage().put(schema_name.name, schema.json),
do: {:reclaim, schema}
else
with {:error, :unconfigured_registry_url} <- registry_storage().get(schema_name.origin),
{:ok, schema} <- file_storage().get(schema_name.origin),
do: {:reclaim, schema}
end
end

defp file_storage, do: Config.self().file_storage()
defp memory_storage, do: Config.self().memory_storage()
defp registry_storage, do: Config.self().registry_storage()
Expand Down
9 changes: 5 additions & 4 deletions lib/avrora/schema/name.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ defmodule Avrora.Schema.Name do
Struct for versioned schema names like `io.confluent.Payment:42`.
"""

defstruct [:name, :version]
defstruct [:origin, :name, :version]

@type t :: %__MODULE__{
origin: String.t(),
name: String.t(),
version: nil | integer()
}
Expand All @@ -18,9 +19,9 @@ defmodule Avrora.Schema.Name do
## Examples

iex> Avrora.Schema.Name.parse("Payment")
{:ok, %Avrora.Schema.Name{name: "Payment", version: nil}}
{:ok, %Avrora.Schema.Name{origin: "Payment", name: "Payment", version: nil}}
iex> Avrora.Schema.Name.parse("io.confluent.Payment:42")
{:ok, %Avrora.Schema.Name{name: "io.confluent.Payment", version: 42}}
{:ok, %Avrora.Schema.Name{origin: "io.confluent.Payment:42", name: "io.confluent.Payment", version: 42}}
"""
@spec parse(String.t()) :: {:ok, t()} | {:error, term()}
def parse(payload) when is_binary(payload) do
Expand All @@ -35,7 +36,7 @@ defmodule Avrora.Schema.Name do
end
end

{:ok, %__MODULE__{name: Enum.at(parts, 0), version: version}}
{:ok, %__MODULE__{origin: payload, name: Enum.at(parts, 0), version: version}}
end
end
end
14 changes: 7 additions & 7 deletions lib/avrora/storage/memory.ex
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,15 @@ defmodule Avrora.Storage.Memory do
TTL is in milliseconds.

## Examples
iex> _ = Avrora.Storage.Memory.start_link()
iex> schema = %Avrora.Schema{id: nil, json: "{}"}
iex> Avrora.Storage.Memory.put("my-key", schema)
...> _ = Avrora.Storage.Memory.start_link()
...> schema = %Avrora.Schema{id: nil, json: "{}"}
...> Avrora.Storage.Memory.put("my-key", schema)
{:ok, %Avrora.Schema{id: nil, json: "{}"}}
iex> {:ok, _} = Avrora.Storage.Memory.expire("my-key", 100)
iex> Avrora.Storage.Memory.get("my-key")
...> {:ok, _} = Avrora.Storage.Memory.expire("my-key", 100)
...> Avrora.Storage.Memory.get("my-key")
{:ok, %Avrora.Schema{id: nil, json: "{}"}}
iex> Process.sleep(200)
iex> Avrora.Storage.Memory.get("my-key")
...> Process.sleep(200)
...> Avrora.Storage.Memory.get("my-key")
{:ok, nil}
"""
@impl true
Expand Down
10 changes: 5 additions & 5 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Avrora.MixProject do
def project do
[
app: :avrora,
version: "0.12.0",
version: "0.13.0",
elixir: "~> 1.6",
description: description(),
package: package(),
Expand Down Expand Up @@ -87,13 +87,13 @@ defmodule Avrora.MixProject do

defp deps do
[
{:jason, "~> 1.2"},
{:jason, "~> 1.0"},
{:erlavro, "~> 2.9.0"},
{:mox, "~> 0.5", only: :test},
{:ex_doc, "~> 0.21", only: :dev, runtime: false},
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
{:dialyxir, "~> 1.0.0", only: :dev, runtime: false},
{:credo, "~> 1.0", only: :dev, runtime: false},
{:excoveralls, "~> 0.11", only: :test}
{:credo, "~> 1.4", only: :dev, runtime: false},
{:excoveralls, "~> 0.13", only: :test}
]
end

Expand Down
25 changes: 13 additions & 12 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
%{
"bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "805abd97539caf89ec6d4732c91e62ba9da0cda51ac462380bbd28ee697a8c42"},
"credo": {:hex, :credo, "1.3.2", "08d456dcf3c24da162d02953fb07267e444469d8dad3a2ae47794938ea467b3a", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b11d28cce1f1f399dddffd42d8e21dcad783309e230f84b70267b1a5546468b6"},
"certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"},
"credo": {:hex, :credo, "1.4.0", "92339d4cbadd1e88b5ee43d427b639b68a11071b6f73854e33638e30a0ea11f5", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1fd3b70dce216574ce3c18bdf510b57e7c4c85c2ec9cad4bff854abaf7e58658"},
"dialyxir": {:hex, :dialyxir, "1.0.0", "6a1fa629f7881a9f5aaf3a78f094b2a51a0357c843871b8bc98824e7342d00a5", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "aeb06588145fac14ca08d8061a142d52753dbc2cf7f0d00fc1013f53f8654654"},
"earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
"earmark_parser": {:hex, :earmark_parser, "1.4.10", "6603d7a603b9c18d3d20db69921527f82ef09990885ed7525003c7fe7dc86c56", [:mix], [], "hexpm", "8e2d5370b732385db2c9b22215c3f59c84ac7dda7ed7e544d7c459496ae519c0"},
"erlavro": {:hex, :erlavro, "2.9.0", "a709780bde5fd16cb3ea759bc34c4fe5276513a8c6eeeab3cf0df7d2ca92dcb2", [:make, :rebar, :rebar3], [{:jsone, "1.4.6", [hex: :jsone, repo: "hexpm", optional: false]}], "hexpm", "fce3428cd395a429c3354700abe2f1592e33a33272870dc2d15d662d4f454afc"},
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"ex_doc": {:hex, :ex_doc, "0.21.3", "857ec876b35a587c5d9148a2512e952e24c24345552259464b98bfbb883c7b42", [:mix], [{:earmark, "~> 1.4", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0db1ee8d1547ab4877c5b5dffc6604ef9454e189928d5ba8967d4a58a801f161"},
"excoveralls": {:hex, :excoveralls, "0.12.3", "2142be7cb978a3ae78385487edda6d1aff0e482ffc6123877bb7270a8ffbcfe0", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "568a3e616c264283f5dea5b020783ae40eef3f7ee2163f7a67cbd7b35bcadada"},
"hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "e0100f8ef7d1124222c11ad362c857d3df7cb5f4204054f9f0f4a728666591fc"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"},
"jason": {:hex, :jason, "1.2.0", "10043418c42d2493d0ee212d3fddd25d7ffe484380afad769a0a38795938e448", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "116747dbe057794c3a3e4e143b7c8390b29f634e16c78a7f59ba75bfa6852e7f"},
"ex_doc": {:hex, :ex_doc, "0.22.2", "03a2a58bdd2ba0d83d004507c4ee113b9c521956938298eba16e55cc4aba4a6c", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "cf60e1b3e2efe317095b6bb79651f83a2c1b3edcb4d319c421d7fcda8b3aff26"},
"excoveralls": {:hex, :excoveralls, "0.13.1", "b9f1697f7c9e0cfe15d1a1d737fb169c398803ffcbc57e672aa007e9fd42864c", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b4bb550e045def1b4d531a37fb766cbbe1307f7628bf8f0414168b3f52021cce"},
"hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"},
"idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"},
"jason": {:hex, :jason, "1.2.1", "12b22825e22f468c02eb3e4b9985f3d0cb8dc40b9bd704730efa11abd2708c44", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "b659b8571deedf60f79c5a608e15414085fa141344e2716fbd6988a084b5f993"},
"jsone": {:hex, :jsone, "1.4.6", "644d6d57befb22c8e19b324dee19d73b1c004565009861a8f64c68b7b9e64dbf", [:rebar3], [], "hexpm", "78eee8bb38f0bee2e73673d71bc75fc6fb01f56f0d23e769a26eee3655487a38"},
"makeup": {:hex, :makeup, "1.0.1", "82f332e461dc6c79dbd82fbe2a9c10d48ed07146f0a478286e590c83c52010b5", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "49736fe5b66a08d8575bf5321d716bac5da20c8e6b97714fec2bcd6febcfa1f8"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.0", "cf8b7c66ad1cff4c14679698d532f0b5d45a3968ffbcbfd590339cb57742f1ae", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "d4b316c7222a85bbaa2fd7c6e90e37e953257ad196dc229505137c5e505e9eff"},
"makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"},
"makeup_elixir": {:hex, :makeup_elixir, "0.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mox": {:hex, :mox, "0.5.2", "55a0a5ba9ccc671518d068c8dddd20eeb436909ea79d1799e2209df7eaa98b6c", [:mix], [], "hexpm", "df4310628cd628ee181df93f50ddfd07be3e5ecc30232d3b6aadf30bdfe6092b"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
"nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm", "13104d7897e38ed7f044c4de953a6c28597d1c952075eb2e328bc6d6f2bfc496"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.5.0", "8516502659002cec19e244ebd90d312183064be95025a319a6c7e89f4bccd65b", [:rebar3], [], "hexpm", "d48d002e15f5cc105a696cf2f1bbb3fc72b4b770a184d8420c8db20da2674b38"},
}
Loading