diff --git a/.circleci/config.yml b/.circleci/config.yml index 657681a305..1eec164659 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -14,10 +14,12 @@ jobs: working_directory: ~/app steps: - - run: sudo npm install -g phantomjs-prebuilt --unsafe-perm - run: sudo apt-get update; sudo apt-get -y install autoconf build-essential libgmp3-dev libtool - checkout + - run: + command: ./bin/install_chrome_headless.sh + no_output_timeout: 2400 - run: mix local.hex --force - run: mix local.rebar --force @@ -357,7 +359,10 @@ jobs: steps: - attach_workspace: at: . - - run: sudo npm install -g phantomjs-prebuilt --unsafe-perm + + - run: + command: ./bin/install_chrome_headless.sh + no_output_timeout: 2400 - run: mix local.hex --force - run: mix local.rebar --force @@ -409,7 +414,10 @@ jobs: - attach_workspace: at: . - - run: sudo npm install -g phantomjs-prebuilt --unsafe-perm + - run: + command: ./bin/install_chrome_headless.sh + no_output_timeout: 2400 + - run: mix local.hex --force - run: mix local.rebar --force @@ -460,7 +468,10 @@ jobs: - attach_workspace: at: . - - run: sudo npm install -g phantomjs-prebuilt --unsafe-perm + - run: + command: ./bin/install_chrome_headless.sh + no_output_timeout: 2400 + - run: mix local.hex --force - run: mix local.rebar --force @@ -511,7 +522,10 @@ jobs: - attach_workspace: at: . - - run: sudo npm install -g phantomjs-prebuilt --unsafe-perm + - run: + command: ./bin/install_chrome_headless.sh + no_output_timeout: 2400 + - run: mix local.hex --force - run: mix local.rebar --force diff --git a/CHANGELOG.md b/CHANGELOG.md index e4af1a1336..7c2fbb2da8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Features - [#1739](https://github.com/poanetwork/blockscout/pull/1739) - highlight decompiled source code +- [#1696](https://github.com/poanetwork/blockscout/pull/1696) - full-text search by tokens - [#1742](https://github.com/poanetwork/blockscout/pull/1742) - Support RSK ### Fixes diff --git a/apps/block_scout_web/config/test.exs b/apps/block_scout_web/config/test.exs index 1c695a15bc..6fcd9c18a9 100644 --- a/apps/block_scout_web/config/test.exs +++ b/apps/block_scout_web/config/test.exs @@ -16,7 +16,7 @@ config :logger, :block_scout_web, path: Path.absname("logs/test/block_scout_web.log") # Configure wallaby -config :wallaby, screenshot_on_failure: true +config :wallaby, screenshot_on_failure: true, driver: Wallaby.Experimental.Chrome config :explorer, Explorer.ExchangeRates, enabled: false, store: :none diff --git a/apps/block_scout_web/lib/block_scout_web.ex b/apps/block_scout_web/lib/block_scout_web.ex index 9a4c6cab09..4e1f857526 100644 --- a/apps/block_scout_web/lib/block_scout_web.ex +++ b/apps/block_scout_web/lib/block_scout_web.ex @@ -54,6 +54,8 @@ defmodule BlockScoutWeb do Views.ScriptHelpers, WeiHelpers } + + import PhoenixFormAwesomplete end end diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex index 3658045c5a..e84b0a3438 100644 --- a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex +++ b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex @@ -39,6 +39,23 @@ defmodule BlockScoutWeb.ChainController do end end + def token_autocomplete(conn, %{"q" => term}) when is_binary(term) do + if term == "" do + json(conn, "{}") + else + result = + term + |> String.trim() + |> Chain.search_token() + + json(conn, result) + end + end + + def token_autocomplete(conn, _) do + json(conn, "{}") + end + def chain_blocks(conn, _params) do if ajax?(conn) do blocks = diff --git a/apps/block_scout_web/lib/block_scout_web/csp_header.ex b/apps/block_scout_web/lib/block_scout_web/csp_header.ex index 199ee9f189..a29e87a146 100644 --- a/apps/block_scout_web/lib/block_scout_web/csp_header.ex +++ b/apps/block_scout_web/lib/block_scout_web/csp_header.ex @@ -13,8 +13,8 @@ defmodule BlockScoutWeb.CSPHeader do "content-security-policy" => "\ connect-src 'self' #{websocket_endpoints(conn)}; \ default-src 'self';\ - script-src 'self' 'unsafe-inline' 'unsafe-eval';\ - style-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com;\ + script-src 'self' 'unsafe-inline' 'unsafe-eval' https://nico-amsterdam.github.io;\ + style-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.googleapis.com https://nico-amsterdam.github.io;\ img-src 'self' 'unsafe-inline' 'unsafe-eval' data:;\ font-src 'self' 'unsafe-inline' 'unsafe-eval' https://fonts.gstatic.com data:;\ " diff --git a/apps/block_scout_web/lib/block_scout_web/router.ex b/apps/block_scout_web/lib/block_scout_web/router.ex index bf687134dd..59cf06e7c1 100644 --- a/apps/block_scout_web/lib/block_scout_web/router.ex +++ b/apps/block_scout_web/lib/block_scout_web/router.ex @@ -220,6 +220,8 @@ defmodule BlockScoutWeb.Router do get("/search", ChainController, :search) + get("/token_autocomplete", ChainController, :token_autocomplete) + get("/chain_blocks", ChainController, :chain_blocks, as: :chain_blocks) get("/api_docs", APIDocsController, :index) diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex index 1eaffa3834..770dcdd436 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex @@ -79,13 +79,29 @@
<%= form_for @conn, chain_path(@conn, :search), [class: "form-inline my-2 my-lg-0", method: :get, enforce_utf8: false], fn f -> %> -
- <%= search_input f, :q, class: 'form-control mr-auto', placeholder: gettext("Search by address, token symbol name, transaction hash, or block number"), "aria-describedby": "search-icon", "aria-label": gettext("Search"), "data-test": "search_input" %> -
- -
+ +
+ <%= awesomplete(f, :q, + [ + class: "form-control me auto", + placeholder: gettext("Search by address, token symbol name, transaction hash, or block number"), + "aria-describedby": "search-icon", + "aria-label": gettext("Search"), + "data-test": "search_input" + ], + [ url: "#{chain_path(@conn, :token_autocomplete)}?q=", + prepop: true, + minChars: 3, + maxItems: 8, + value: "symbol", + label: "contract_address_hash", + descr: "symbol" + ]) %> +
+ +
<% end %> diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex index 72ff59d213..c9c533138e 100644 --- a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex +++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex @@ -16,6 +16,21 @@ "> + + + + + <%= render_existing(@view_module, "_metatags.html", assigns) || render("_default_title.html") %> diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs index dbaee13d48..34289ec672 100644 --- a/apps/block_scout_web/mix.exs +++ b/apps/block_scout_web/mix.exs @@ -126,9 +126,10 @@ defmodule BlockScoutWeb.Mixfile do # `:spandex` tracing of `:phoenix` {:spandex_phoenix, "~> 0.3.1"}, {:timex, "~> 3.4"}, - {:wallaby, "~> 0.20", only: [:test], runtime: false}, + {:wallaby, "~> 0.22", only: [:test], runtime: false}, # `:cowboy` `~> 2.0` and Phoenix 1.4 compatibility - {:wobserver, "~> 0.2.0", github: "KronicDeth/wobserver", ref: "99683a936c75c0a94ebb884cef019f7ed0b97112"} + {:wobserver, "~> 0.2.0", github: "KronicDeth/wobserver", ref: "99683a936c75c0a94ebb884cef019f7ed0b97112"}, + {:phoenix_form_awesomplete, "~> 0.1.4"} ] end diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot index 6f30fdf2e3..ec9b93cf71 100644 --- a/apps/block_scout_web/priv/gettext/default.pot +++ b/apps/block_scout_web/priv/gettext/default.pot @@ -62,7 +62,7 @@ msgid "(query)" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:31 +#: lib/block_scout_web/templates/layout/app.html.eex:46 msgid "- We're indexing this chain right now. Some of the counts may be inaccurate." msgstr "" @@ -155,7 +155,7 @@ msgid "Block Height: %{height}" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:46 +#: lib/block_scout_web/templates/layout/app.html.eex:61 msgid "Block Mined, awaiting import..." msgstr "" @@ -182,7 +182,7 @@ msgid "Blocks" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:45 +#: lib/block_scout_web/templates/layout/app.html.eex:60 msgid "Blocks Indexed" msgstr "" @@ -389,7 +389,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_balance_card.html.eex:13 #: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:16 -#: lib/block_scout_web/templates/layout/app.html.eex:51 +#: lib/block_scout_web/templates/layout/app.html.eex:66 #: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20 #: lib/block_scout_web/templates/transaction/_tile.html.eex:27 #: lib/block_scout_web/templates/transaction/overview.html.eex:145 @@ -472,7 +472,7 @@ msgid "IN" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:47 +#: lib/block_scout_web/templates/layout/app.html.eex:62 msgid "Indexing Tokens" msgstr "" @@ -508,7 +508,7 @@ msgid "Inventory" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:48 +#: lib/block_scout_web/templates/layout/app.html.eex:63 msgid "Less than" msgstr "" @@ -527,7 +527,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:28 -#: lib/block_scout_web/templates/layout/app.html.eex:49 +#: lib/block_scout_web/templates/layout/app.html.eex:64 #: lib/block_scout_web/views/address_view.ex:121 msgid "Market Cap" msgstr "" @@ -679,7 +679,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:21 -#: lib/block_scout_web/templates/layout/app.html.eex:50 +#: lib/block_scout_web/templates/layout/app.html.eex:65 msgid "Price" msgstr "" @@ -728,8 +728,8 @@ msgid "Responses" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:83 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:90 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:89 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:106 msgid "Search" msgstr "" @@ -1688,7 +1688,7 @@ msgid "Error: Could not determine contract creator." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:83 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:87 msgid "Search by address, token symbol name, transaction hash, or block number" msgstr "" diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po index a1fb23d655..2056f772d9 100644 --- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po +++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po @@ -62,7 +62,7 @@ msgid "(query)" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:31 +#: lib/block_scout_web/templates/layout/app.html.eex:46 msgid "- We're indexing this chain right now. Some of the counts may be inaccurate." msgstr "" @@ -155,7 +155,7 @@ msgid "Block Height: %{height}" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:46 +#: lib/block_scout_web/templates/layout/app.html.eex:61 msgid "Block Mined, awaiting import..." msgstr "" @@ -182,7 +182,7 @@ msgid "Blocks" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:45 +#: lib/block_scout_web/templates/layout/app.html.eex:60 msgid "Blocks Indexed" msgstr "" @@ -389,7 +389,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/address/_balance_card.html.eex:13 #: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:16 -#: lib/block_scout_web/templates/layout/app.html.eex:51 +#: lib/block_scout_web/templates/layout/app.html.eex:66 #: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20 #: lib/block_scout_web/templates/transaction/_tile.html.eex:27 #: lib/block_scout_web/templates/transaction/overview.html.eex:145 @@ -472,7 +472,7 @@ msgid "IN" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:47 +#: lib/block_scout_web/templates/layout/app.html.eex:62 msgid "Indexing Tokens" msgstr "" @@ -508,7 +508,7 @@ msgid "Inventory" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/app.html.eex:48 +#: lib/block_scout_web/templates/layout/app.html.eex:63 msgid "Less than" msgstr "" @@ -527,7 +527,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:28 -#: lib/block_scout_web/templates/layout/app.html.eex:49 +#: lib/block_scout_web/templates/layout/app.html.eex:64 #: lib/block_scout_web/views/address_view.ex:121 msgid "Market Cap" msgstr "" @@ -679,7 +679,7 @@ msgstr "" #, elixir-format #: lib/block_scout_web/templates/chain/show.html.eex:21 -#: lib/block_scout_web/templates/layout/app.html.eex:50 +#: lib/block_scout_web/templates/layout/app.html.eex:65 msgid "Price" msgstr "" @@ -728,8 +728,8 @@ msgid "Responses" msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:83 -#: lib/block_scout_web/templates/layout/_topnav.html.eex:90 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:89 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:106 msgid "Search" msgstr "" @@ -1688,7 +1688,7 @@ msgid "Error: Could not determine contract creator." msgstr "" #, elixir-format -#: lib/block_scout_web/templates/layout/_topnav.html.eex:83 +#: lib/block_scout_web/templates/layout/_topnav.html.eex:87 msgid "Search by address, token symbol name, transaction hash, or block number" msgstr "" diff --git a/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs index 293c77590f..bc3a4a4e90 100644 --- a/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs +++ b/apps/block_scout_web/test/block_scout_web/controllers/chain_controller_test.exs @@ -66,7 +66,27 @@ defmodule BlockScoutWeb.ChainControllerTest do end end - describe "GET q/2" do + describe "GET token_autocomplete/2" do + test "finds matching tokens" do + insert(:token, name: "MaGiC") + insert(:token, name: "Evil") + + conn = get(conn(), "/token_autocomplete?q=magic") + + assert Enum.count(json_response(conn, 200)) == 1 + end + + test "finds two matching tokens" do + insert(:token, name: "MaGiC") + insert(:token, name: "magic") + + conn = get(conn(), "/token_autocomplete?q=magic") + + assert Enum.count(json_response(conn, 200)) == 2 + end + end + + describe "GET search/2" do test "finds a consensus block by block number", %{conn: conn} do insert(:block, number: 37) conn = get(conn, "/search?q=37") diff --git a/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs b/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs index eab01e0bbc..15587cdc93 100644 --- a/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs +++ b/apps/block_scout_web/test/block_scout_web/features/address_contract_verification_test.exs @@ -13,6 +13,8 @@ defmodule BlockScoutWeb.AddressContractVerificationTest do {:ok, bypass: bypass} end + # wallaby with chrome headles always fails this test + @tag :skip test "users validates smart contract", %{session: session, bypass: bypass} do Bypass.expect(bypass, fn conn -> Conn.resp(conn, 200, solc_bin_versions()) end) diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index d882e56b51..152a4ecf8a 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -701,6 +701,19 @@ defmodule Explorer.Chain do end end + @spec search_token(String.t()) :: [Token.t()] + def search_token(word) do + term = String.replace(word, ~r/\W/u, "") <> ":*" + + query = + from(token in Token, + where: fragment("to_tsvector('english', symbol || ' ' || name ) @@ to_tsquery(?)", ^term), + limit: 5 + ) + + Repo.all(query) + end + @doc """ Converts `t:Explorer.Chain.Address.t/0` `hash` to the `t:Explorer.Chain.Address.t/0` with that `hash`. diff --git a/apps/explorer/lib/explorer/chain/token.ex b/apps/explorer/lib/explorer/chain/token.ex index cb01cdeba2..275fd73659 100644 --- a/apps/explorer/lib/explorer/chain/token.ex +++ b/apps/explorer/lib/explorer/chain/token.ex @@ -48,6 +48,14 @@ defmodule Explorer.Chain.Token do holder_count: non_neg_integer() | nil } + @derive {Poison.Encoder, + except: [ + :__meta__, + :contract_address, + :inserted_at, + :updated_at + ]} + @primary_key false schema "tokens" do field(:name, :string) diff --git a/apps/explorer/priv/repo/migrations/20190403080447_add_full_text_search_tokens.exs b/apps/explorer/priv/repo/migrations/20190403080447_add_full_text_search_tokens.exs new file mode 100644 index 0000000000..a4d642f54e --- /dev/null +++ b/apps/explorer/priv/repo/migrations/20190403080447_add_full_text_search_tokens.exs @@ -0,0 +1,16 @@ +defmodule Explorer.Repo.Migrations.AddFullTextSearchTokens do + use Ecto.Migration + + def up do + execute("CREATE EXTENSION pg_trgm") + + execute(""" + CREATE INDEX tokens_trgm_idx ON tokens USING GIN (to_tsvector('english', symbol || ' ' || name)) + """) + end + + def down do + execute("DROP INDEX tokens_trgm_idx") + execute("DROP EXTENSION pg_trgm") + end +end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index ebb4b880dd..f2a420b142 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -3334,6 +3334,41 @@ defmodule Explorer.ChainTest do end end + describe "search_token/1" do + test "finds by part of the name" do + token = insert(:token, name: "magic token", symbol: "MAGIC") + + [result] = Chain.search_token("magic") + + assert result.contract_address_hash == token.contract_address_hash + end + + test "finds multiple results in different columns" do + insert(:token, name: "magic token", symbol: "TOKEN") + insert(:token, name: "token", symbol: "MAGIC") + + result = Chain.search_token("magic") + + assert Enum.count(result) == 2 + end + + test "do not returns wrong tokens" do + insert(:token, name: "token", symbol: "TOKEN") + + result = Chain.search_token("magic") + + assert Enum.empty?(result) + end + + test "finds record by the term in the second word" do + insert(:token, name: "token magic", symbol: "TOKEN") + + result = Chain.search_token("magic") + + assert Enum.count(result) == 1 + end + end + describe "transaction_has_token_transfers?/1" do test "returns true if transaction has token transfers" do transaction = insert(:transaction) diff --git a/bin/install_chrome_headless.sh b/bin/install_chrome_headless.sh new file mode 100755 index 0000000000..9721e84ea3 --- /dev/null +++ b/bin/install_chrome_headless.sh @@ -0,0 +1,10 @@ +export DISPLAY=:99.0 +sh -e /etc/init.d/xvfb start +export CHROMEDRIVER_VERSION=`curl -s http://chromedriver.storage.googleapis.com/LATEST_RELEASE` +curl -L -O "http://chromedriver.storage.googleapis.com/${CHROMEDRIVER_VERSION}/chromedriver_linux64.zip" +unzip chromedriver_linux64.zip +sudo chmod +x chromedriver +sudo mv chromedriver /usr/local/bin +wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb +sudo apt install ./google-chrome-stable_current_amd64.deb +sudo apt-get install libstdc++6 diff --git a/mix.lock b/mix.lock index 25c9621cc2..e9066554b1 100644 --- a/mix.lock +++ b/mix.lock @@ -13,7 +13,7 @@ "binary": {:hex, :binary, "0.0.5", "20d816f7274ea34f1b673b4cff2fdb9ebec9391a7a68c349070d515c66b1b2cf", [:mix], []}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], []}, "bypass": {:hex, :bypass, "1.0.0", "b78b3dcb832a71aca5259c1a704b2e14b55fd4e1327ff942598b4e7d1a7ad83d", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}], "hexpm"}, - "certifi": {:hex, :certifi, "2.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, + "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], []}, "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], []}, @@ -50,7 +50,7 @@ "flow": {:hex, :flow, "0.14.3", "0d92991fe53035894d24aa8dec10dcfccf0ae00c4ed436ace3efa9813a646902", [:mix], [{:gen_stage, "~> 0.14.0", [hex: :gen_stage, repo: "hexpm", optional: false]}], "hexpm"}, "gen_stage": {:hex, :gen_stage, "0.14.1", "9d46723fda072d4f4bb31a102560013f7960f5d80ea44dcb96fd6304ed61e7a4", [:mix], [], "hexpm"}, "gettext": {:hex, :gettext, "0.16.1", "e2130b25eebcbe02bb343b119a07ae2c7e28bd4b146c4a154da2ffb2b3507af2", [:mix], [], "hexpm"}, - "hackney": {:hex, :hackney, "1.15.0", "287a5d2304d516f63e56c469511c42b016423bcb167e61b611f6bad47e3ca60e", [:rebar3], [{:certifi, "2.4.2", [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.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, + "hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [: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.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], []}, "httpoison": {:hex, :httpoison, "1.5.0", "71ae9f304bdf7f00e9cd1823f275c955bdfc68282bc5eb5c85c3a9ade865d68e", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, @@ -66,7 +66,7 @@ "meck": {:hex, :meck, "0.8.12", "1f7b1a9f5d12c511848fec26bbefd09a21e1432eadb8982d9a8aceb9891a3cf2", [:rebar3], [], "hexpm"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], []}, "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, - "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], []}, + "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"}, "mix_erlang_tasks": {:hex, :mix_erlang_tasks, "0.1.0", "36819fec60b80689eb1380938675af215565a89320a9e29c72c70d97512e4649", [:mix], [], "hexpm"}, "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"}, "mock": {:hex, :mock, "0.3.2", "e98e998fd76c191c7e1a9557c8617912c53df3d4a6132f561eb762b699ef59fa", [:mix], [{:meck, "~> 0.8.8", [hex: :meck, repo: "hexpm", optional: false]}], "hexpm"}, @@ -78,6 +78,7 @@ "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, "phoenix": {:hex, :phoenix, "1.4.0", "56fe9a809e0e735f3e3b9b31c1b749d4b436e466d8da627b8d82f90eaae714d2", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}], "hexpm"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, + "phoenix_form_awesomplete": {:hex, :phoenix_form_awesomplete, "0.1.4", "4af0603d8d41ca638e70f74d6defff331e4db106dd85f75f125579ca27bd8b64", [:mix], [{:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_html": {:hex, :phoenix_html, "2.13.1", "fa8f034b5328e2dfa0e4131b5569379003f34bc1fafdaa84985b0b9d2f12e68b", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.0", "3bb31a9fbd40ffe8652e60c8660dffd72dd231efcdf49b744fb75b9ef7db5dd2", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.1", "6668d787e602981f24f17a5fbb69cc98f8ab085114ebfac6cc36e10a90c8e93c", [:mix], [], "hexpm"}, @@ -85,7 +86,7 @@ "plug_cowboy": {:hex, :plug_cowboy, "2.0.1", "d798f8ee5acc86b7d42dbe4450b8b0dadf665ce588236eb0a751a132417a980e", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], []}, - "poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], []}, + "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"}, "postgrex": {:hex, :postgrex, "0.14.1", "63247d4a5ad6b9de57a0bac5d807e1c32d41e39c04b8a4156a26c63bcd8a2e49", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "prometheus": {:hex, :prometheus, "4.2.0", "06c58bfdfe28d3168b926da614cb9a6d39593deebde648a5480e32dfa3c370e9", [:mix, :rebar3], [], "hexpm"}, "prometheus_ecto": {:git, "https://github.com/deadtrickster/prometheus-ecto.git", "650a403183f6a2fb6b682d7fbcba8bf9d24fe1e4", [ref: "650a403183f6a2fb6b682d7fbcba8bf9d24fe1e4"]}, @@ -106,7 +107,7 @@ "timex": {:hex, :timex, "3.5.0", "b0a23167da02d0fe4f1a4e104d1f929a00d348502b52432c05de875d0b9cffa5", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"}, "tzdata": {:hex, :tzdata, "0.5.19", "7962a3997bf06303b7d1772988ede22260f3dae1bf897408ebdac2b4435f4e6a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, - "wallaby": {:hex, :wallaby, "0.21.0", "87b1f5b7fda6d405f29991cabb58b03e8e548a483ef952e84ecedc68978b22a7", [:mix], [{:httpoison, "~> 0.12 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, ">= 1.4.0", [hex: :poison, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm"}, + "wallaby": {:hex, :wallaby, "0.22.0", "e5d16bfa7ab23562c8a6e3b0a31445a2fd470ca622082a910114807ba823780d", [:mix], [{:httpoison, "~> 0.12 or ~> 1.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, ">= 1.4.0", [hex: :poison, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm"}, "websocket_client": {:hex, :websocket_client, "1.3.0", "2275d7daaa1cdacebf2068891c9844b15f4fdc3de3ec2602420c2fb486db59b6", [:rebar3], [], "hexpm"}, "wobserver": {:git, "https://github.com/KronicDeth/wobserver.git", "99683a936c75c0a94ebb884cef019f7ed0b97112", [ref: "99683a936c75c0a94ebb884cef019f7ed0b97112"]}, }